autoitaudacity

Making AutoIT wait until Audacity completes command


I have a script that I'd like to use to automate processes in Audacity. I have it set up so that all the functions I want to do in Audacity are keyboard shortcuts (since I don't think Audacity uses standard window menus like is required for WinMenuSelectItem()) In other words, my whole code consists of multiple instances of the Send() command. The problem is, AutoIT executes the code too fast. I've tried using WinWait(), but the processes take variable amounts of time. I've also tried ShellExecuteWait() and RunWait()Is there a way to get it to wait until the program isn't doing something, and then execute my send commands? Here's some of my code

Run("C:\Program Files (x86)\Audacity\audacity.exe")
; wait until it's active
WinWaitActive("Audacity")

; get the dialogue box to go away
Send("{ENTER}")
RunWait("Audacity")

; open files
Send("^o")
RunWait("Audacity")

; open the certain file & press enter
Send("test.wav")
RunWait("Audacity")
Send("{ENTER}")
RunWait("Audacity")

; select left boundary of silence period
Send("[")
RunWait("Audacity")
Send("000000100{ENTER}")
RunWait("Audacity")

; select right boundary of silence period
Send("]")
RunWait("Audacity")
Send("200000000{ENTER}")
RunWait("Audacity")

Solution

  • ; Use for debugging issues. Systray icon show current line.
    Opt('TrayIconDebug', 1)
    
    ; Delay default: 250s
    Opt('WinWaitDelay', 400)
    
    ; Delay default: 5s
    Opt('SendKeyDelay', 100)
    
    ; Path of the wav file.
    $sInFile = @WorkingDir & '\test.wav'
    
    ; Optional permanent change of splash screen setting.
    _SplashScreen(True)
    
    ; Run Audacity and argument of the wav file.
    $iPid = Run('"C:\Program Files (x86)\Audacity\audacity.exe" "' & $sInFile & '"')
    
    ; Check if Run Audacity failed.
    If @error Then
        MsgBox(0x40030, @ScriptName, 'Failed to run Audacity')
        Exit 1
    EndIf
    
    ; Wait for main window to get handle. Title is the filename with no extension.
    $hMainWindow = WinWait('[TITLE:test; CLASS:wxWindowNR]', '', 10)
    
    ; Check allowed timeout of window.
    If Not $hMainWindow Then
        MsgBox(0x40030, @ScriptName, 'Audacity window not detected.')
        Exit 1
    EndIf
    
    ; If splash screen setting not 0 then handle the window.
    If _SplashScreen() Then
        AdlibRegister('_WelcomeWindow')
        WinWait('Welcome to Audacity', '', 3)
        AdlibUnRegister('_WelcomeWindow')
    EndIf
    
    ; Send '[' to main window to trigger Left Boundary window.
    ControlSend($hMainWindow, '', '', '[')
    
    ; Get handle of Left Boundary window.
    $hMsgWindow = WinWait('Set Left Selection Boundary', '', 5)
    
    ; Check allowed timeout of window.
    If Not $hMsgWindow Then
        MsgBox(0x40030, @ScriptName, 'Selection Boundary window not detected.')
        Exit 1
    EndIf
    
    ; Activate window, set time and click OK.
    If WinActivate($hMsgWindow) Then
        ControlSend($hMsgWindow, '', 'wxWindowNR1', '{LEFT 3}1'); 1000
        ControlClick($hMsgWindow, '', 'Button2'); OK
    EndIf
    
    ; Send ']' to main window to trigger Right Boundary window.
    ControlSend($hMainWindow, '', '', ']')
    
    ; Get handle of Right Boundary window.
    $hMsgWindow = WinWait('Set Right Selection Boundary', '', 5)
    
    ; Check allowed timeout of window.
    If Not $hMsgWindow Then
        MsgBox(0x40030, @ScriptName, 'Selection Boundary window not detected.')
        Exit 1
    EndIf
    
    ; Activate window, set time and click OK.
    If WinActivate($hMsgWindow) Then
        ; Audacity shows 1000 and focus is on the 1st non zero digit which is 1.
        ControlSend($hMsgWindow, '', 'wxWindowNR1', '2'); 2000
        ControlClick($hMsgWindow, '', 'Button2'); OK
    EndIf
    
    ; More code to do.
    Sleep(1000)
    
    MsgBox(0x40040, @ScriptName, 'End of automation.' & @CRLF & @CRLF & _
         'You can close Audacity to finish.')
    
    ; Wait for Audacity process to close.
    ProcessWaitClose($iPid)
    
    Exit
    
    Func _WelcomeWindow()
        ; Used by AdlibRegister to handle the Welcome window.
    
        ; Welcome window hides if closed so need to check if exist and is visible (2).
        If WinExists('Welcome to Audacity') Then
            If BitAND(WinGetState('Welcome to Audacity'), 2) Then
                WinClose('Welcome to Audacity')
            Else
                AdlibUnRegister('_WelcomeWindow')
            EndIf
        EndIf
    EndFunc
    
    Func _SplashScreen($bDisable = False)
        ; Write to audacity.cfg to disable splash screen.
        Local $sIniFile = @AppDataDir & '\Audacity\audacity.cfg'
    
        If IniRead($sIniFile, 'GUI', 'ShowSplashScreen', '1') = '1' Then
            If $bDisable Then
                ; Return 1 if ini file change is success.
                If IniWrite($sIniFile, 'GUI', 'ShowSplashScreen', '0') Then
                    Return 1
                EndIf
            Else
                ; Return 1 if check for splash screen is enabled.
                Return 1
            EndIf
        EndIf
    EndFunc
    

    Opt() is used to slow down the wait of windows and the sends. Also added Opt('TrayIconDebug', 1) for debugging though if the script is considered good then you can remove that Opt().

    ControlSend() is used instead of Send() as ControlSend() targets windows and controls based of title, text, etc. The Opt() delays are not required though was added to demonstrate the usage, though perhaps Audacity may struggle to keep with the speed that AutoIt can automate. If possible, suggest use of Control*() functions for automation.

    Storing window handles in a variable can help save retyping titles in the code. WinWait() returns a window handle which is ideal and if the timeout parameter is used, then 0 indicates the window not found so automation can be aborted.

    The Classname of the main window is not enough on its own as Audacity creates many invisible windows with the same Classname. So, the title may need to be used as well. The title could be used alone though titled by filename may not be unique at times. See Window Titles and Text Advanced for usage.

    WinActivate() is used on the Boundary windows although it may not be needed as control*() usually do not need active windows. Standard Msgboxes in comparison may require to be active to accept messages sent to them.

    ShellExecuteWait() and RunWait() are no good for automation as they block the script from continuing until the executed process has finished. So use ShellExecute() or Run() instead. The repetitive use of RunWait("Audacity") seems like desperation to correct the behavior perhaps, though flawed. Waiting for windows to appear is how to control flow and then functions such as ControlCommand() can detect state of controls.

    ControlClick() is used on the buttons. CtrlID of Classname Button2 is used though if the script is always for English users then you can use the text which would be OK for the OK button.

    The ProcessWaitClose($iPid) is optional. It is sometimes useful to wait for the program being automated to exit before the script exits.

    You comment "get the dialogue box to go away" in you code after starting Audacity. You can change the setting on the dialogue box or Preferences -> Interface options. Advice disabling as it is a future problem to keep handling. I added some code to disable the setting in the audacity.cfg file. If not preferred to disable with _SplashScreen(True) or done manually then the AdLibRegister('_WelcomeWindow') call will handle closing the window. Note that the Welcome window does not close but rather hides.

    _SplashScreen(True) changes splash setting to 0 to disable the splash.

    _SplashScreen(False) or _SplashScreen() does no change of settings. The call returns 1 if splash is enabled else 0.