I'm trying to automate bouncing mixes and it's all going very well but I have a question. At the moment the script knows that a bounce is finished by waiting for the audio import dialog to appear. At the moment I have had to put a ridiculously long timeout value on that line of the script so that it doesn't matter how long it takes to bounce. This works fine as long as everything goes as planned, but if I cancel the bounce, that means that the audio import dialog never appears and the script is stuck waiting for it and no other scripts can run. The only way to clear the hung state I've found is quitting and restarting SoundFlow. There must be a more elegant way to do this.
Linked from:
- SSreejesh Nair @Sreejesh_Nair
One idea is you could check to see if the bounce dialog has dissappeared after or before the import dialog appears. If it is before then the script can exit.
Andrew Scheps @Andrew_Scheps
Unfortunately the Bounce dialog goes away as soon as the bounce starts. What I really ned to do is wait for the progress window to disappear, but I can't seem to get to it with SoundFLow or Accessibility Inspector so I can't tell the script to wait for it.
Christian Scheuer @chrscheuer2020-02-16 20:39:39.297Z
Hi Andrew. I have a long script that works with the Bounce dialog and is very stable. I'll see if I can get it up here asap.
Andrew Scheps @Andrew_Scheps
Thanks Christian. I thought I could use sf.ui.proTools.waitForNoModals(); Unfortunately this treats the entire sequence of bounce dialog->progress wondow->Audio Import dialog as all one modal so it never goes on to automate the audio import dialog. The script works great as long as I don't cancel the bounce. If I do SoundFlow gets confused and has to be relaunched.
- In reply toAndrew_Scheps⬆:SSreejesh Nair @Sreejesh_Nair
Sure Andrew. Thats what I meant. My bad! I have added a code below modified from Christians code. Maybe it may help?
- In reply toAndrew_Scheps⬆:Andrew Scheps @Andrew_Scheps
And in case I wasn't clear, all of my automation of the bounce dialog and the audio import dialog works great and is absolutely bullet-proof, as long as I don't cancel the bounce. I'm needing to put a ridiculously long wait time on the audio import appearance.
Christian Scheuer @chrscheuer2020-02-16 20:51:40.267Z
Nice yea I just re-read your question. What you need here is essentially some logic that says wait for the audio import dialog to appear OR for all modal windows to be gone (in the event of a cancelled bounce).
That should be doable, it just requires a little more tweaking. Can you share the code you use to wait for the Audio Import dialog? Then I should be able to tweak it for you.Note - you can also always cancel all running SF commands by hitting Ctrl+Shift+Esc (if you use default SoundFlow triggers). If you don't, you can assign your own shortcut to cancelling all running commands in the SoundFlow System package: "Stop All Running Commands" command:
Andrew Scheps @Andrew_Scheps
Ah, very good to know! Here's the part of the script that waits for the audio import to appear (note the long wait time).
//Start bounce sf.ui.proTools.windows.whoseTitle.is('Bounce').first.buttons.whoseTitle.is('Bounce').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Bounce').first.elementWaitFor({ waitType: "Disappear", timeout: 10000, //This can take a while to start sometimes }); //Wait for bounce to finish sf.ui.proTools.windows.whoseTitle.is('Audio Import Options').first.elementWaitFor({ waitType: "Appear", timeout: 1000000, });
Christian Scheuer @chrscheuer2020-02-16 21:11:57.613Z
I think you should be able to do this:
//Start bounce sf.ui.proTools.windows.whoseTitle.is('Bounce').first.buttons.whoseTitle.is('Bounce').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Bounce').first.elementWaitFor({ waitType: "Disappear", timeout: 10000, //This can take a while to start sometimes }); //Wait for bounce to finish (Wait for bounce dialog to appear, then to disappear) sf.ui.proTools.confirmationDialog.elementWaitFor({ timeout: 10000 }); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Disappear', timeout: -1 }); //-1 is endless timeout (cancel by Ctrl+Shift+Esc) //Now that we know the bounce is either cancelled or finished, no need for a long wait time for the Audio Import Options to appear //Let's keep it short. Then the 2nd parameter is the error handling function - it will be called if there's a timeout, which indicates this bounce was cancelled. sf.ui.proTools.windows.whoseTitle.is('Audio Import Options').first.elementWaitFor({ timeout: 2000, }, () => { //Error - so, we timed out. Likely this is due to cancel of bounce log('Bounce cancelled'); //Abort the script silently throw 0; });
Christian Scheuer @chrscheuer2020-02-16 21:16:45.165Z
Oops wait - this had the wrong dialog (I was testing with a consolidate).
Try this instead:
//Start bounce sf.ui.proTools.windows.whoseTitle.is('Bounce').first.buttons.whoseTitle.is('Bounce').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Bounce').first.elementWaitFor({ waitType: "Disappear", timeout: 10000, //This can take a while to start sometimes }); //Wait for bounce to finish (Wait for bounce dialog to appear, then to disappear) var bouncingLabel = sf.ui.proTools.windows.whoseTitle.is('').first.children.whoseRole.is("AXStaticText").whoseValue.is('Bouncing...').first; bouncingLabel.elementWaitFor({ timeout: 10000 }); bouncingLabel.elementWaitFor({ waitType: 'Disappear', timeout: -1 }); //-1 is endless timeout (cancel by Ctrl+Shift+Esc) //Now that we know the bounce is either cancelled or finished, no need for a long wait time for the Audio Import Options to appear var success = sf.ui.proTools.windows.whoseTitle.is('Audio Import Options').first.elementWaitFor({ timeout: 2000, onError: 'Continue' }).success; if (!success) { log('Bounce cancelled'); throw 0; } //Now do something with the Audio Import Options dialog
Andrew Scheps @Andrew_Scheps
Actually, the second one doesn't work. I get an error waiting for bouncingLabel to disappear. First one works fine.
- In reply tochrscheuer⬆:
Andrew Scheps @Andrew_Scheps
This seems to work! Basically, if you cancel then it continues the script, exiting after the unsuccessful 2 second wait for the Audio Import dialog. Thanks!
- In reply toAndrew_Scheps⬆:Andrew Scheps @Andrew_Scheps
Well, I've been using the script and neither of these solutions work. The first one works in the sense that SoundFlow doesn't get stuck waiting for the Audio Import Dialog if I cancel the bounce, but if I let the bounce go ahead the script never continues when the Audio Import Options dialog appears. So, whether Pro Tools doesn't let you know that the bounce dialog has come up or something else weird is happening. If I go back to my original script everything works fine as long as I don't cancel the bounce.
- In reply toAndrew_Scheps⬆:Andrew Scheps @Andrew_Scheps
I think I still don't quite get it and would love a generic way to test for the opening and closing of the Pro Tools progress windows. This comes up on anything that takes a while (bouncing, exporting, consolidating, AS processing etc) and it seems very clumsy to use long wait times. I've tried using the code above and it doesn't work reliably.
Christian Scheuer @chrscheuer2020-02-20 22:55:35.933Z
I think the different processes need different solutions unfortunately (right now). The best way to get to a solution that works for all processes would be to take them one step at a time and look very specifically on why and when they break (preferably send us script examples and a step-by-step on exactly when in the process it fails). This will eventually help us figure out the corner case scenarios which will lead to more stability, and then ultimately from that we can derive a function that could work across all scenarios.
But right now I'm afraid there's no one-solution-fits-all without getting more into the details first.Andrew Scheps @Andrew_Scheps
Here are the two that I'm stuck on at the moment.
-
Bounce to Disk:
As detailed above, when bouncing to disk it can take quite a while. I am always importing the bounce after it finishes so I can have the script wait for the Audio Import dialog to appear but you have to use a wait time of -1 (or at least longer than the bounce will ever take). As we've discussed above, if you cancel the bounce the dialog never appears and SoundFlow is left waiting forever. The code you put above to fix it above doesn't work reliably for me for some reason.
One workaround would be to estimate the bounce time based on the selection length and then adjust a variable wait time to be just long enough that it should work. Not elegant, but I suppose I should try it. -
Export Clips as Files:
This one is trickier because there is no dialog that comes up afterwards, the end of the process is when the progress dialog disappears. You either have to make sure it is the last step in your script so the script has finished before the export, or you would have to put an arbitrarily long wait time that would allow for the longest export you think you would ever do. But of course this approach means you would have to wait that long every time you used the script, even if exporting a short file. Again, I suppose a probable wait time could be calculated based on clip length and source and destination sample rate, but not an ideal solution.
I think what I was saying in my last comment was the "generic" part is that Pro Tools seems to "lock up" while the progress dialogs are on the screen so SoundFLow doesn't actually seem to know about them. You can see how problematic they are if you initiate either a very long bounce or export, then while it is running use the the "choose" function in any action that allows you to click on a UI element to get its ID and you'll see that you can't even select the progress window in most cases. If we can fix this visibility issue with PTs progress windows then this would all be moot.
Let me know if you'd like any more info or code, though I think my code is simplistic enough when it comes to initiating the processes.
Thanks!
Kitch Membery @Kitch2020-02-22 05:45:03.503Z
I've just been perusing over the thread and assuming I understand correctly what you are trying to figure out with the “1. Bounce to disk” issue… the following script sequence may work (I’d have to have a think about how to implement it as it may be above my current javascript knowledge);
- When starting the bounce set up a loop to check if the main window of Pro Tools has regained focus.
- Once the main window of Pro Tools regains focus, have the script check to see if the new bounced file exists in the Bounces folder.
- If the new bounce does not exist have the script terminate.
With this scenario, if the bounce was canceled midway through, the script would see that there is no bounced file created, the script would terminate and therefore not continue to look for the Audio Import dialogue.
If I’m way off the mark… Please ignore these ramblings :-)
Andrew Scheps @Andrew_Scheps
That sounds like an approach that might work! It's WAY over my programming level though.
Kitch Membery @Kitch2020-02-23 01:38:09.236Z
Me too Andrew... although part 3 would look something like this. Assuming you are using the variable "newPlaylistName" from your script.
//Get the directory (folder) of the currently open PT session var sessionDir = sf.ui.proTools.mainWindow.sessionPath.split('/').slice(0, -1).join('/'); //Name of Folder within session directory var folderName = "Bounced Files" //Check to see if the file with variable "newPlaylistName" exists var file = sf.file.exists({path: sessionDir+"/"+folderName+"/"+newPlaylistName+".wav"}); if(!file.exists){ log("File does not exist!") throw("Script Terminated") } else{ log("File exist!") };
As for part 1 and 2... possibly using a javascript "while (false)" loop, that waits for the main window of Pro Tools to be in focus would work.
Back in July, Christian created a post on "How to run a script in background and check for a state" that may be the key to getting it all working. Here is the link.
https://forum.soundflow.org/-824/how-to-run-a-script-in-background-and-check-for-a-stateUnfortunately I'm on a project with a tight deadline at the moment so won't be able attempt a solution for the next week or so.
Andrew Scheps @Andrew_Scheps
Thanks Kitch, this looks like the way to go about it. And I suppose the wait loop shouldn't actually be a background task, but foreground and then check for the bounced file. I have the path and name of the bounced file in variable so that check is very easy to make. Nice one!
This thread might have the skeleton of what I need, I'll report back if I get it working.
https://forum.soundflow.org/-1159/how-to-wait-for-rx7-audio-editor-to-open-before-proceedingKitch Membery @Kitch2020-02-23 10:20:06.016Z
That looks really promising! Keep me posted Andrew.
- In reply toKitch⬆:
Andrew Scheps @Andrew_Scheps
This works perfectly with the code Christian did earlier to track the progress window appearing and disappearing.
//Wait for bounce to finish (Wait for bounce dialog to appear, then to disappear) sf.ui.proTools.confirmationDialog.elementWaitFor({ timeout: 10000 }); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Disappear', timeout: -1 }); //-1 is endless timeout (cancel by Ctrl+Shift+Esc) // See if bounce completed normally or was cancelled by checking for the existence of the bounced file //Check to see if the file with variable "newPlaylistName" exists var file = sf.file.exists({path: bounceDir+"/"+newPlaylistName+".wav"}); if(!file.exists){ log("File does not exist, bounce cancelled!"); throw(0); };
It waits for the progress bar to appear and disappear and then checks to see if the file exists. If it doesn't the bounce must have been cancelled so abort the script, otherwise continue.
The only issue this has is if the bounce happens so fast that the progress dialog doesn't appear, then the script times out waiting for it. In real life there's nothing I bounce that doesn't take long enough for the dialog to appear so it won't come up, but I suppose it's a bit messy.
I've added the same code to watch out for the Export Selected as Files progress dialog to appear and disappear and that works fine. I don't need to test for cancellation on that because nothing else relies on it.
I suppose the real takeaway here is that the simple lines waiting for progress dialog to appear and disappear are the perfect 'generic' code for long processes, it's the testing for whether they were cancelled or not that will have to be specific to each function.
Thanks!
Kitch Membery @Kitch2020-02-23 18:46:53.871Z
Nice work mate! I'd love to see the full script on this one.
Andrew Scheps @Andrew_Scheps
You asked for it...
There is a lot of stuff specific to my workflow and there's a lot that should be tightened up code-wise but it works! I have a variant of this that lets me specify a name and does it slightly differently for printing other types of mixes. Saving me so much time, and I can hit the button and walk away!
// This script prints the next reference mix for a session given some rather stringent parameters: // 1) The Print Track has to be the bottom-most track in the session, including hidden tracks // 2) There has to already be a playlist on the Print track that ends in a revision number that can be incremented. // 3) There has to a clip on the print track that represents the bounce selection, and it has to be the first clip on the track // note: I satisfy 2 and 3 for the first ref by making a playlist whos name ends in "R0" that has a clip group for the desired bounce selection // 4) I always want the mix bounced into the local Bounced Files directory // 5) I always want to export a 44.1/16 bit copy to a folder called " Refs" one level above the session folder // 6) I am always printing a bus called "Print" // I'm sure there is a lot of this that should be separated into functions and made neater, but it does actually work and is pretty bullet proof. sf.ui.proTools.appActivateMainWindow(); // Dialog to remind me which button I just hit on the Stream Deck if (!confirm(`This Script will increment the Print Track playist, bounce and export a ref\nDo you want to continue?`)) throw 0; //Get and Increment Last Number - We'll use this for the new playlist name function getAndIncrementLastNumber(str) { return str.replace(/\d+$/, function (s) { return ++s; }); } // Set variables so Bounce directory can be set back to default if it has been changed var sessionDir = sf.ui.proTools.mainWindow.sessionPath.split('/').slice(0, -1).join('/'); var bounceDir = `${sessionDir}/Bounced Files`; //Make sure our new bounce dir exists sf.system.exec({ commandLine: 'mkdir -p "' + bounceDir + '"' }); // Get name of last track (which has to be the print track) var lastTrackName = sf.ui.proTools.trackNames.slice(-1)[0]; // Scroll the track into view sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: [lastTrackName] }); sf.ui.proTools.selectedTrack.trackScrollToView(); // Select the existing mix if (sf.ui.proTools.getMenuItem('Options', 'Tab to Transient').isMenuChecked) { //Tab to Transient is enabled - disable it sf.ui.proTools.menuClick({ menuPath: ["Options","Tab to Transient"], }); } else { //Tab to Transient is not enabled - good! }; // Select first clip on teh track sf.keyboard.press({ keys: "return, tab, shift+tab", }); // Create name of playlist var newPlaylistName = getAndIncrementLastNumber(lastTrackName); //Duplicate the current playlist sf.ui.proTools.selectedTrack.popupButtons.whoseTitle.is('Playlist selector').first.popupMenuSelect({ menuPath: ["Duplicate..."], }); //Wait for Duplicate Playlist window to appear sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Appear", }); // Put in new playlist name sf.ui.proTools.confirmationDialog.textFields.first.elementSetTextFieldWithAreaValue({ value: newPlaylistName }); //Click OK in Duplicate Playlist window sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('OK').first.elementClick(); //Wait for Duplicate Playlist window to disappear sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); // ------------- Get current session smaple rate ----------- // See if the Session Setup window is open and if not, open it var sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is('Session Setup'); if (sessionSetupWin && sessionSetupWin.exists) { //audio suite window is open } else { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"], }); var sessionSetupDlg = sf.ui.proTools.dialogWaitForManual({ dialogTitle: 'Session Setup' }).dialog; }; // Get the current session sample rate var currentSampleRate = sf.ui.proTools.windows.whoseTitle.is('Session Setup').first.groups.whoseTitle.is('Session Format').first.children.whoseRole.is("AXStaticText").allItems[2].value.value; // Close the Session Setup window sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"], }) //Wait for 'Session Setup' window to disappear sf.ui.proTools.windows.whoseTitle.is('Session Setup').first.elementWaitFor({ waitType: "Disappear", }); //----------------------------------------------------------| // Set up bounce! | //----------------------------------------------------------| // Open bounce to disk dialog sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce to", "Disk..."], looseMatch: true, }); //Wait for the 'Bounce' dialog to appear and assign it to the bounceDlg variable var bounceDlg = sf.ui.proTools.dialogWaitForManual({ dialogTitle: 'Bounce' }).dialog; // The next bit is stolen and adapted from Marco, thanks Marco! //Special code for now (this will change and be made easier) //What this does is get the Children of the bounceDialog, filter them so we only get the popupbuttons, //and then slice the resulting array so the we only get the last 5. //This is needed since there are no names/titles/labels on the 4 buttons used to set up file type, format, bit depth and samplerate //and you don't know how many bounce sources there might be when you open the dialog var popupButtons = bounceDlg.getElements("AXChildren").filter(function (e) { return e.fullRole == "AXPopUpButton" }).slice(-5); //Assign the five buttons coming out of the previous instruction to individual variables var bounceSource = popupButtons[0]; var fileTypeBtn = popupButtons[1]; var formatBtn = popupButtons[2]; var bitDepthBtn = popupButtons[3]; var sampleRateBtn = popupButtons[4]; var deliverFormat = popupButtons[5]; //If the source is not already Print, use the popupMenuSelect action to select it if (bounceSource.value.value != 'Print (Stereo)') sf.ui.proTools.windows.whoseTitle.is('Bounce').first.popupButtons.first.popupMenuSelect({ menuPath: ["bus", "Print*"], useWildcards: true, }); // Set the resot of the bounce parameters if (fileTypeBtn.value.value != 'WAV') fileTypeBtn.popupMenuSelect({ menuPath: ['WAV'] }); if (sampleRateBtn.value.value != currentSampleRate) sampleRateBtn.popupMenuSelect({ menuPath: [currentSampleRate] }); if (formatBtn.value.value != 'Interleaved') formatBtn.popupMenuSelect({ menuPath: ['Interleaved'] }); if (bitDepthBtn.value.value != '24 Bit') bitDepthBtn.popupMenuSelect({ menuPath: ['24 Bit'] }); //Make sure offline and import after bounce are selected sf.ui.proTools.windows.whoseTitle.is('Bounce').first.checkBoxes.whoseTitle.is('Import After Bounce').first.checkboxSet({ targetValue: "Enable", }); sf.ui.proTools.windows.whoseTitle.is('Bounce').first.checkBoxes.whoseTitle.is('Offline').first.checkboxSet({ targetValue: "Enable", }); //--------------------------------------- Set the path to default---------------------------- // again, stolen code, I think from Fokke, thanks! function navigateToInDialog(win, path) { //Open the Go to... sheet sf.keyboard.type({ text: '/' }); //Wait for the sheet to appear var sheet = win.sheets.first.elementWaitFor({ timeout: 500 }, 'Could not find "Go to" sheet in the Save/Open dialog').element; //Set the value of the combo box sheet.comboBoxes.first.value.value = path; //Press OK sheet.buttons.whoseTitle.is('Go').first.elementClick({}, 'Could not click "Go"'); //Wait for sheet to close win.sheets.first.elementWaitFor({ waitForNoElement: true, timeout: 500 }, '"Go to" sheet didn\'t close in time'); } function openDialogFolder(folder) { var openDlg = sf.ui.proTools.windows.whoseTitle.is('Open').first; navigateToInDialog(openDlg, folder); //Click OK openDlg.buttons.whoseTitle.is('Open').first.elementClick(); //Wait for the Open dialog to close openDlg.elementWaitFor({ waitForNoElement: true }); } //Set the bounce directory if necessary var existingDirectory = sf.ui.proTools.windows.whoseTitle.is('Bounce').first.children.whoseRole.is("AXStaticText").allItems[6].value.value; if (existingDirectory !== bounceDir + "/") { sf.ui.proTools.windows.whoseTitle.is('Bounce').first.buttons.whoseTitle.is('Choose...').first.elementClick(); openDialogFolder(bounceDir); } //---------------------------------------------------------------------------- // Use our new playlist name for the file name sf.ui.proTools.windows.whoseTitle.is('Bounce').first.textFields.whoseTitle.is('').first.elementSetTextFieldWithAreaValue({ value: newPlaylistName, }); //Start bounce sf.ui.proTools.windows.whoseTitle.is('Bounce').first.buttons.whoseTitle.is('Bounce').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Bounce').first.elementWaitFor({ waitType: "Disappear", timeout: 10000, //This can take a while to start sometimes }); //Wait for bounce to finish (Wait for bounce dialog to appear, then to disappear) sf.ui.proTools.confirmationDialog.elementWaitFor({ timeout: 10000 }); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Disappear', timeout: -1 }); //-1 is endless timeout (cancel by Ctrl+Shift+Esc) // See if bounce completed normally or was cancelled by checking for the existence of the bounced file //Check to see if the file with variable "newPlaylistName" exists var file = sf.file.exists({path: bounceDir+"/"+newPlaylistName+".wav"}); if(!file.exists){ log("File does not exist, bounce cancelled!"); throw(0); }; // Import mix to session in Clip list var win = sf.ui.proTools.windows.whoseTitle.is('Audio Import Options').first; win.radioButtons.whoseTitle.startsWith('Clip List').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Audio Import Options').first.buttons.whoseTitle.is('OK').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Audio Import Options').first.elementWaitFor({ waitType: "Disappear", }); //----------------------------------------------------------| // Bounce Finished! | // Export ref and get bounced Mix onto Print Track | //----------------------------------------------------------| //Make sure clip list is showing sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Clip List"], targetValue: 'Enable' //or 'Enable' or 'Toggle' }); //----------------------------------------------------------| // Export Mix | //----------------------------------------------------------| //Reselect mix on Print Track //There was code here to re-select it but it never gets deselected in this order of operations... sf.ui.proTools.mainWindow.popupButtons.whoseTitle.is('Clip List').first.popupMenuSelect({ menuPath: ["Export Clips as Files..."], }); var exportDlg = sf.ui.proTools.dialogWaitForManual({ dialogTitle: "Export Selected" }).dialog; //Get the Children of the Export Selected dialog, filter them so we only get the popupbuttons, var popupButtons = exportDlg.getElements("AXChildren").filter(function (e) { return e.fullRole == "AXPopUpButton" }); //Assign thefourthree buttons coming out of the previous instruction to individual variables var sampleRate = popupButtons[0]; var bitDepth = popupButtons[1]; var fileFormat = popupButtons[2]; var fileTypeBtn = popupButtons[3]; //Change any options that aren't right if (fileTypeBtn.value.value != 'WAV') fileTypeBtn.popupMenuSelect({ menuPath: ['WAV'] }); if (fileFormat.value.value != 'Interleaved') fileFormat.popupMenuSelect({ menuPath: ['Interleaved'] }); if (bitDepth.value.value != '16 Bit') bitDepth.popupMenuSelect({ menuPath: ['16 Bit'] }); if (sampleRate.value.value != '44.1 kHz') sampleRate.popupMenuSelect({ menuPath: ['44.1 kHz'] }); //-------------------------------- // Set the export directory to the refs folder - I probably didn't need to copy these and rename them but I haven't gone back to see if anything changed so better safe than sorry //-------------------------------- function navigateToInDialog2(win, path) { //Open the Go to... sheet sf.keyboard.type({ text: '/' }); //Wait for the sheet to appear var sheet = win.sheets.first.elementWaitFor({ timeout: 500 }, 'Could not find "Go to" sheet in the Save/Open dialog').element; //Set the value of the combo box sheet.comboBoxes.first.value.value = path; //Press OK sheet.buttons.whoseTitle.is('Go').first.elementClick({}, 'Could not click "Go"'); //Wait for sheet to close win.sheets.first.elementWaitFor({ waitForNoElement: true, timeout: 500 }, '"Go to" sheet didn\'t close in time'); } function openDialogFolder2(folder) { var openDlg = sf.ui.proTools.windows.whoseTitle.is('Open').first; navigateToInDialog2(openDlg, folder); //Click OK openDlg.buttons.whoseTitle.is('Open').first.elementClick(); //Wait for the Open dialog to close openDlg.elementWaitFor({ waitForNoElement: true }); }; // Set a variable to the desired refs directory in the sessions parent folder var exportDirectory = sf.ui.proTools.mainWindow.sessionPath.split('/').slice(0, -2).join('/') + "/ Refs"; //Make sure our desired export dir exists sf.system.exec({ commandLine: 'mkdir -p "' + exportDirectory + '"' }); //Get the current export directory - I'm sure this can all be done one line but, well, newbie var existingDirectory = sf.ui.proTools.windows.whoseTitle.is('Export Selected').first.children.whoseRole.is("AXStaticText").allItems[5].value.value; var modifiedDirectory = "/"+ existingDirectory.substring(0, existingDirectory.length - 1).split(":").slice (1).join('/'); if (modifiedDirectory !== exportDirectory) { sf.ui.proTools.windows.whoseTitle.is('Export Selected').first.buttons.whoseTitle.is('Choose...').first.elementClick(); openDialogFolder2(exportDirectory); } // Start the Export sf.ui.proTools.windows.whoseTitle.is('Export Selected').first.buttons.whoseTitle.is('Export...').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Export Selected').first.elementWaitFor({ waitType: "Disappear", }); //Wait for export to finish (Wait for progress dialog to appear, then to disappear) sf.ui.proTools.confirmationDialog.elementWaitFor({ timeout: 10000 }); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Disappear', timeout: -1 }); //-1 is endless timeout (cancel by Ctrl+Shift+Esc) // No need to check if I cancelled or not, it's just an external file that nothing else relies on // Get the bounced mix onto the Print track // Use the clip list search function to make it the only displayed clip so we know where it is sf.ui.proTools.mainWindow.popupButtons.whoseTitle.is('Clip List').first.popupMenuSelect({ menuPath: ["Find..."], }); sf.ui.proTools.windows.whoseTitle.is('Find Clips').first.elementWaitFor({ waitType: "Appear", }); sf.ui.proTools.windows.whoseTitle.is('Find Clips').first.textFields.whoseTitle.is('').first.elementSetTextFieldWithAreaValue({ value: newPlaylistName, }); sf.ui.proTools.windows.whoseTitle.is('Find Clips').first.buttons.whoseTitle.is('OK').first.elementClick(); sf.ui.proTools.windows.whoseTitle.is('Find Clips').first.elementWaitFor({ waitType: "Disappear", }); // Place clip on the print track // Open Replace Clip dialog for first clip sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first.children.whoseRole.is("AXRow").whoseValue.is('').allItems[0].children.whoseRole.is("AXCell").allItems[1].children.whoseRole.is("AXStaticText").first.popupMenuSelect({ isRightClick: true, menuPath: ["Replace Clip..."], }); sf.ui.proTools.replaceClipDialog.elementWaitFor({ waitType: "Appear", }); // Make sure we're only replacing the previous mix sf.ui.proTools.replaceClipDialog.radioButtons.whoseTitle.is('original clip only').first.elementClick(); sf.ui.proTools.replaceClipDialog.radioButtons.whoseTitle.is('replacement clip length').first.elementClick(); // Do it sf.ui.proTools.replaceClipDialog.buttons.whoseTitle.is('OK').first.elementClick(); sf.ui.proTools.replaceClipDialog.elementWaitFor({ waitType: "Disappear", }); // Clear the Find in the clip bin sf.ui.proTools.mainWindow.popupButtons.whoseTitle.is('Clip List').first.popupMenuSelect({ menuPath: ["Clear Find"], }); // That's it!
Kitch Membery @Kitch2020-02-23 20:52:10.009Z
Awesome! But why would you walk away when you can sit back and watch all this cool automation. Well for the first bunch of times at least. :-)
Andrew Scheps @Andrew_Scheps
Oh believe me, I’ve watched it plenty!
Kitch Membery @Kitch2020-02-23 20:54:56.060Z
Hahahaha!
Christian Scheuer @chrscheuer2020-02-23 21:33:40.785Z
Holy ####, guys. I love seeing what you're building here together! That script is insane haha.
Kitch Membery @Kitch2020-02-23 21:39:28.666Z
Team work makes the dream work! Now we just have to write a SoundFlow script that edits audio/mixes albums/pays bills & cashes checks for us while we sip on Pina colada's in Fiji :-)
- In reply toAndrew_Scheps⬆:
Raphael Sepulveda @raphaelsepulveda2020-04-22 16:28:37.924Z
Wow, this is god-level scripting.
-
- In reply toAndrew_Scheps⬆:Andrew Scheps @Andrew_Scheps
Soooo, I'm cleaning up this script into functions etc and have decided to fix a few things along the way.
The only real issue with the script (other than not being flexible enough) is this code (courtesy of Christian in a post in this thread) that waits for the bounce to complete before continuing:
//Wait for bounce to finish (Wait for bounce dialog to appear, then to disappear) sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Appear', timeout: 10000 }); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Disappear', timeout: -1 }); //-1 is endless timeout (cancel by Ctrl+Shift+Esc)
The problem is that if the bounce doesn't take more than about 10 seconds the code fails waiting for the bounce dialog to disappear.
If I get rid of the first line of code and only wait for it to disappear it seems to work on shorter bounces but I worry that it isn't very robust to wait for something to disappear that we haven't checked for in the first place. Any thoughts?
- SIn reply toAndrew_Scheps⬆:Sebastian @Sebastian
Hi, I loved this script but since Pro Tools changed some names and places in the Bounce Mix Window the script is not working anymore. Is there someone who updated this script? My scipting is unfortunatly not good enough to get this going.
Andrew Scheps @Andrew_Scheps
Hi @Sebastian , unfortunately a ton has changed in the Bounce Dialog (well basically, everything), so updating this script isn't a small job.
The good news is that I've written an app that does nothing but print mixes and is pretty powerful. We're almost done beta testing it and it should be in the SF store before too long...
- SSebastian @Sebastian
That is good news :) Looking forward to it. Thanks.
- In reply toAndrew_Scheps⬆:Win Winstanley @Win_Winstanley
HI, is there any chance we could get a "Wait For Bounce Dialogue To Close" action added to the menu?
My understanding of coding is minimal/poor at best and inserting this into a Macro would be awesome for my workflow.
Very best. WinKitch Membery @Kitch2022-06-06 19:06:43.740Z
Hi @Win_Winstanley,
Thanks for the great suggestion. For any Ideas and suggestions like this please create a thread in the Ideas Section of the forum, that way it will be logged and considered for future updates of SoundFlow :-)
Thanks in advance.