Improving bouncing script to match session name
Hi, I just discovered SoundFlow and I am starting building my first script for bouncing.
I was able to put something together between built in commands and pieces of code from the forum.
Script is working but I cannot find a way to have the bounce name matching the session name. As of now, it is keeping the previous bounce name.
Here is my script:
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package"
sf.soundflow.runCommand({
commandId: 'package:ckyjbd5e800006310zzo5lx3k',
props: {}
});
sf.ui.proTools.menuClick({
menuPath: ["File","Bounce Mix..."],
});
sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.groups.whoseTitle.is("Location").first.elementWaitFor({
executionMode: "Foreground",
onCancel: "ThrowError",
});
sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.whoseTitle.is("").first.elementClick();
sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick();
sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick();
sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementWaitFor();
sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick();
//Calling command "Open "Bounced Folder" of current session" from package "Marko Fazio - Package"
sf.soundflow.runCommand({
commandId: 'package:ckyjj7g1y000e7m10018hunqq',
props: {}
});
I found this piece of code on the forum but don't know how to integrate it:
var sessionPath = sf.ui.proTools.mainWindow.sessionPath;
var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.');
log(sessionName);
Thank you for your help!
- Raphael Sepulveda @raphaelsepulveda2022-01-18 05:54:43.607Z
Hey @Marko_Fazio, welcome to the forum!
This is great for being your first script!
Below is how to implement the
sessionName
:sf.ui.proTools.appActivateMainWindow(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); //Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); //Calling command "Open "Bounced Folder" of current session" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjj7g1y000e7m10018hunqq', props: {} });
Also, check out the following video to learn how to quote code here on the forum!
https://youtu.be/FRLCp6Sf9AI?t=117- MMarko Fazio @Marko_Fazio
Hey, thank you very much for your response and for the link.
I tried to paste the code above but it does not seem to work. I renamed my session as "test" so in theory it should rename to that same name but the file name in the bounce dialog box stays the same as the previous bounce.
Raphael Sepulveda @raphaelsepulveda2022-01-18 20:58:24.760Z
Mmm.. that's odd. Let's break it down to the basics.
Try the code below. It should only open the Bounce Mix window and put it in the name of the session in the text field. Does that work?
sf.ui.proTools.appActivateMainWindow(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName });
- MMarko Fazio @Marko_Fazio
Ok, so the first bounce worked. BUT if I do a Save As, rename the session from 1.5 to 1.6 for example, then the previous name of the session is still in the text field and PT is asking if I want to replace the previous version. For some reason, it does not picjed on the new name of the session.
Any idea of what is happening?Raphael Sepulveda @raphaelsepulveda2022-01-19 00:19:34.475Z
Yes, we can use
sf.ui.proTools.mainWindow.invalidate();
right belowsf.ui.proTools.appActivateMainWindow();
to refresh the session cache and get an updated session name.Ok, so if that previous script worked then rearranging the commands on the full script should do the trick. Try this:
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); //Calling command "Open "Bounced Folder" of current session" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjj7g1y000e7m10018hunqq', props: {} });
- MMarko Fazio @Marko_Fazio
Hey, great it is working, thank you. The little drawback is that when I try to cancel the bounce, it automatically retrigger the macro and re-export. Any idea what it is?
Raphael Sepulveda @raphaelsepulveda2022-01-19 04:02:15.536Z
I'm not sure why it would be doing that but you can cancel any ongoing SoundFlow processing by pressing ctrl+shift+esc.
- MMarko Fazio @Marko_Fazio
Thanks.
One more thing. I was testing the script and I noticed that the "bounced files" folder did not open for some reason. Is there some script that should specify to wait for the bounce to finish to start opening the folder?Raphael Sepulveda @raphaelsepulveda2022-01-19 19:12:18.304Z
Mmm... opening the bounce folder shouldn't be held up while the bounce is taking place rather it should open immediately after the bounce starts.
Since I'm not sure what code you're running on your "Open Bounced Folder" command let's replace it.
At the end of the script, remove this:
//Calling command "Open "Bounced Folder" of current session" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjj7g1y000e7m10018hunqq', props: {} });
...and replace it with this:
const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.file.open({ path: bounceFolder });
You should expect the Bounced Files folder to be opened as soon as the bounce begins.
- MMarko Fazio @Marko_Fazio
Thank you, it seems to be working now. :)
Quick general question. So now that I have a good script, I can use that as a building block for expanding it. Correct? I could add other actions after it, right?
Raphael Sepulveda @raphaelsepulveda2022-01-21 01:10:42.994Z2022-01-21 22:20:11.906Z
That's a good question!
Currently, this script finishes as soon it starts bouncing. To make it compatible with other actions we need to make sure the bounce is finished before continuing, that way any additional actions you add won't fail because the bounce is still happening.
I've made the necessary changes below!
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor({ waitType: 'Disappear' }); sf.ui.proTools.waitForNoModals(); // Wait for the bounce to finish sf.file.open({ path: bounceFolder });
- MMarko Fazio @Marko_Fazio
Thank you very much. This is working so far! The last action I would like to implement is duplicating the bounced file from the Bounced Folder to a specific Dropbox folder. Is there a way to implement this?
Raphael Sepulveda @raphaelsepulveda2022-01-21 22:19:47.587Z
Yeah, this should do!
Put it below the code you already have and make sure to fill in the
targetFolderPath
with the path to your desired Dropbox folder.// COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = 'ENTER TARGET PATH HERE'; // Wait for bounce to appear in Bounced Files folder sf.file.waitFor({ path: `${bounceFolder}/${sessionName}.wav` }); // Get all files that match the session name in the Bounced Files folder (wav and mp3) const bouncedFilePaths = sf.file.directoryGetFiles({ path: bounceFolder, searchPattern: `${sessionName}.*` }).paths; // Move files to Target Folder bouncedFilePaths.forEach(filePath => { const fileName = filePath.split('/').slice(-1)[0]; sf.file.copy({ sourcePath: filePath, destinationPath: `${targetFolderPath}/${fileName}` }); });
- MMarko Fazio @Marko_Fazio
Thanks for the response.
It does not seems to work so far.
Is that the correct way of putting the file path?// COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = 'Marko Fazio Music Laptop/Users/markofaziomusiclaptop/Dropbox/Mixes In Progress';
Raphael Sepulveda @raphaelsepulveda2022-01-22 02:35:09.107Z
I think it should be:
const targetFolderPath = '/Users/markofaziomusiclaptop/Dropbox/Mixes In Progress';
One way to know for sure is to select the folder in Finder and press opt+cmd+c. This will copy the correct path to the clipboard!
- MMarko Fazio @Marko_Fazio
Does not seems to work. Here is where I am so far ( I changed the path name because I reorganized Dropbox)
sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.file.open({ path: bounceFolder }); // COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = '/Users/markofaziomusiclaptop/Dropbox/03\ -\ Mixes\ In\ Progress'; // Wait for bounce to appear in Bounced Files folder sf.file.waitFor({ path: `${bounceFolder}/${sessionName}.wav` }); // Get all files that match the session name in the Bounced Files folder (wav and mp3) const bouncedFilePaths = sf.file.directoryGetFiles({ path: bounceFolder, searchPattern: `${sessionName}.*` }).paths; // Move files to Target Folder bouncedFilePaths.forEach(filePath => { const fileName = filePath.split('/').slice(-1)[0]; sf.file.copy({ sourcePath: filePath, destinationPath: `${targetFolderPath}/${fileName}` }); });
Raphael Sepulveda @raphaelsepulveda2022-01-22 20:44:05.741Z
Ah, there were a couple of lines missing. Here's what the whole script should look like:
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); // BOUNCE ///////////////////////////////////////////////////////////////////////// sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor({ waitType: 'Disappear' }); sf.ui.proTools.waitForNoModals(); // Wait for the bounce to finish // OPEN SESSION BOUNCED FILES FOLDER //////////////////////////////////////////////// const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.file.open({ path: bounceFolder }); // COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = '/Users/markofaziomusiclaptop/Dropbox/03 - Mixes In Progress'; // Wait for bounce to appear in Bounced Files folder sf.file.waitFor({ path: `${bounceFolder}/${sessionName}.wav` }); // Get all files that match the session name in the Bounced Files folder (wav and mp3) const bouncedFilePaths = sf.file.directoryGetFiles({ path: bounceFolder, searchPattern: `${sessionName}.*` }).paths; // Move files to Target Folder bouncedFilePaths.forEach(filePath => { const fileName = filePath.split('/').slice(-1)[0]; sf.file.copy({ sourcePath: filePath, destinationPath: `${targetFolderPath}/${fileName}` }); });
I noticed on that last post that the folder name was "03\ -\ Mixes\ In\ Progress". Was that intentional? The backslash ("\") is a special character in JavaScript and should be avoided. If the name of the folder is just "03 - Mixes In Progress" then the way I put it in the script above will work. Give it a shot and let me know!
- MMarko Fazio @Marko_Fazio
Hey, thank you for your response. I tried again with the new code but it doesn't work.
Here are the log info:25.01.2022 14:15:22.61 <info> [Backend]: >> Command: Bounce Mp3 - offline [user:default:ckyl09pui0000px10cjo1in9i] 25.01.2022 14:15:22.75 <info> [Backend]: Clicking with mouse here: 72, 28 25.01.2022 14:15:22.80 <info> [Backend]: Typing some keys... 25.01.2022 14:15:23.02 <info> [Backend]: Clicking with mouse here: 72, 28 25.01.2022 14:15:23.05 <info> [Backend]: Typing some keys... 25.01.2022 14:15:23.35 <info> [Backend]: Clicking with mouse here: 72, 28 25.01.2022 14:15:32.80 <info> [Backend]: Logging error in action (01) WaitForFileAction: File was not found or removed after waiting 5000 ms 25.01.2022 14:15:32.80 <info> [Backend]: !! Command Error: Bounce Mp3 - offline [user:default:ckyl09pui0000px10cjo1in9i]: File was not found or removed after waiting 5000 ms (Bounce Mp3 - offline: Line 42) << Command: Bounce Mp3 - offline [user:default:ckyl09pui0000px10cjo1in9i] 25.01.2022 14:15:34.50 <info> [Backend]: [SF_FIREBASE_WS]: Sending keep-alive 25.01.2022 14:16:19.50 <info> [Backend]: [SF_FIREBASE_WS]: Sending keep-alive
Raphael Sepulveda @raphaelsepulveda2022-01-25 22:22:22.105Z
Does it work if you remove this from the script?
sf.file.waitFor({ path: `${bounceFolder}/${sessionName}.wav` });
- M
Raphael Sepulveda @raphaelsepulveda2022-01-25 22:51:01.568Z
Oh man, what a bummer. According to the log, the script waited 5 secs after the bounce completed but it did not find a wav file of the bounce in the Bounced Files folder.
Could you do a screen recording of the script running? Maybe I can pick up on what's going on there.
- MMarko Fazio @Marko_Fazio
A ok, maybe it's because it's waiting for a waw file, it should be an mp3 for this script. You think that's what it is?
Raphael Sepulveda @raphaelsepulveda2022-01-26 05:28:56.464Z
Ah, I had assumed you were doing a wav and an mp3 bounce.
Try this version below. Now it just waits for a file with the name of the session to show up in the Bounced Files folder—no matter the extension. I also changed something else that may help.
Hopefully it works this time, if not then a screen recording along with error logs will help.
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); // BOUNCE ///////////////////////////////////////////////////////////////////////// sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor({ waitType: 'Disappear' }); sf.ui.proTools.waitForNoModals(); // Wait for the bounce to finish // OPEN SESSION BOUNCED FILES FOLDER //////////////////////////////////////////////// const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.file.open({ path: bounceFolder }); // COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = "/Users/markofaziomusiclaptop/Dropbox/03 - Mixes In Progress"; let bouncedFilePaths = []; // Wait for bounce to appear in Bounced Files folder sf.waitFor({ callback: () => { bouncedFilePaths = sf.file.directoryGetFiles({ path: bounceFolder, searchPattern: `${sessionName}.*` }).paths; return !!bouncedFilePaths.length; } }); // Move files to Target Folder bouncedFilePaths.forEach(filePath => { const fileName = filePath.split('/').slice(-1)[0]; sf.file.copy({ sourcePath: filePath, destinationPath: `${targetFolderPath}/${fileName}` }); });
- MMarko Fazio @Marko_Fazio
Yes!, It worked! Thank you so much. Is there a way to convert back the script into small actions (from code to non-code). It would be nice be able to use some part of this macro for future new macros.
Raphael Sepulveda @raphaelsepulveda2022-01-26 23:29:43.484Z
Glad it finally worked! Thanks for your patience with this.
Unfortunately, scripts can't be turned into macro commands at this time but you can definitely reuse the code for other things.
If you need help with that just make a new post on the forum and we'll be right on it!- MMarko Fazio @Marko_Fazio
Ok, thank you.
I have another quick question regarding this script. I would love to make a variation of it for bouncing wav files at the corresponding sample rate of the session in 24bit. Is that easy to create an alternative version?Raphael Sepulveda @raphaelsepulveda2022-01-28 23:02:54.991Z
Yeah!
What I would do is make another Quick Preset that is set to bounce a wav file at 24bit and then use this modified script.
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); // BOUNCE ///////////////////////////////////////////////////////////////////////// const quickPresetNumber = 2; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").allItems[quickPresetNumber - 1].elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor({ waitType: 'Disappear' }); sf.ui.proTools.waitForNoModals(); // Wait for the bounce to finish // OPEN SESSION BOUNCED FILES FOLDER //////////////////////////////////////////////// const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.file.open({ path: bounceFolder }); // COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = "/Users/markofaziomusiclaptop/Dropbox/03 - Mixes In Progress"; let bouncedFilePaths = []; // Wait for bounce to appear in Bounced Files folder sf.waitFor({ callback: () => { bouncedFilePaths = sf.file.directoryGetFiles({ path: bounceFolder, searchPattern: `${sessionName}.*` }).paths; return !!bouncedFilePaths.length; } }); // Move files to Target Folder bouncedFilePaths.forEach(filePath => { const fileName = filePath.split('/').slice(-1)[0]; sf.file.copy({ sourcePath: filePath, destinationPath: `${targetFolderPath}/${fileName}` }); });
I set this one up to press Quick Preset 2 but you can change it to whatever you like in this line:
const quickPresetNumber = 2;
- MMarko Fazio @Marko_Fazio
Great, it seems to be working. Thanks so much.
- MMarko Fazio @Marko_Fazio
By the way, I like to keep me session clean looking at the end of a bounce. I found this command on the forum to close all session folders at once. I am trying to integrate it to this script as well.
I tried to incorporate it without success. The script works on its own though. I would love to close all of the folders when the bounce is done. see what I mean?
function selectAllTracks() { var trackHeader = sf.ui.proTools.trackGetAllTracks().trackListItems[0].header; trackHeader.trackSelect(); trackHeader.trackScrollToView(); sf.ui.proTools.trackDeselectAll(); if (sf.ui.proTools.mainWindow.groups.allItems[7].popupButtons.first.exists) { sf.ui.proTools.mainWindow.groups.allItems[7].popupButtons.first.mouseClickElement({ isOption: true }); } else if (sf.ui.proTools.trackListItems[0].children.allItems[1].buttons.first.exists) { sf.ui.proTools.trackListItems[0].children.allItems[1].buttons.first.mouseClickElement({ isOption: true }); } else { alert(`Couldn't select all tracks for some reason`) throw 0; } } //this function here is all Christian. He's literally the best. function trackSize() { var size = 'small'; var f = sf.ui.proTools.selectedTrack.frame; var popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({ relativePosition: { x: f.w - 10, y: 5 }, isOption: true, isShift: true, }).popupMenu; popupMenu.menuClickPopupMenu({ menuPath: [size] }); } sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var originalSelection = sf.ui.proTools.selectedTrackNames; selectAllTracks(); var selectedTracks = sf.ui.proTools.selectedTrackNames; var folderTracks = selectedTracks.filter(n => n.match(/fld/i)) trackSize(); for (var i = 0; i < folderTracks.length; i++) { sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: [folderTracks[i]] }); if (sf.ui.proTools.selectedTrack.children.whoseRole.is("AXDisclosureTriangle").whoseTitle.is('Close Folder').first.exists) { sf.ui.proTools.selectedTrack.trackScrollToView(); sf.ui.proTools.selectedTrack.children.whoseRole.is("AXDisclosureTriangle").first.mouseClickElement({ isOption: true, }); break; } } sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: originalSelection });
Raphael Sepulveda @raphaelsepulveda2022-01-29 04:40:23.648Z
Have you tried putting this script before the bounce script instead of after? It should work that way. Just like you did with the "Selection between 2 markers" script.
- MMarko Fazio @Marko_Fazio
I just tried and it does not seem to work.
Here is the log info29.01.2022 00:30:01.16 <info> [Backend]: [ServerController] Running command from sfgui: 'Bounce Mp3 - offline Copy' (user:default:ckyzkndzk0005x810jvos71nx) >> Command: Bounce Mp3 - offline Copy [user:default:ckyzkndzk0005x810jvos71nx] 29.01.2022 00:30:01.16 <info> [Backend]: Checking for running apps with bundle 'com.avid.ProTools' NSArray.ArrayFromHandle count = 1 29.01.2022 00:30:01.49 <info> [Backend]: Error in WaitOnAsync: System.NullReferenceException: Object reference not set to an instance of an object. at SoundFlow.Shortcuts.Automation.Actions.AppActivateMainWindowAction.<>c__DisplayClass19_1.<Impl>b__1() + 0x50 at SoundFlow.Shortcuts.Automation.Actions.Wait.<WaitOnAsync>d__0.MoveNext() + 0x20 Logging error in action (01) AppActivateMainWindowAction: Could not ensure main window became frontmost after waiting 2000 ms 29.01.2022 00:30:01.49 <info> [Backend]: !! Command Error: Bounce Mp3 - offline Copy [user:default:ckyzkndzk0005x810jvos71nx]: Could not ensure main window became frontmost after waiting 2000 ms (Bounce Mp3 - offline Copy: Line 34) << Command: Bounce Mp3 - offline Copy [user:default:ckyzkndzk0005x810jvos71nx] 29.01.2022 00:30:28.75 <info> [Backend]: [SF_FIREBASE_WS]: Sending keep-alive
Raphael Sepulveda @raphaelsepulveda2022-01-29 22:26:47.894Z
Ah, the action that is failing is
sf.ui.proTools.appActivateMainWindow();
That error usually happens if you have a window covering the top left of the Pro Tools Edit window. Can you check if that is the case?Also, I took a look at the close folder script you sent before and that one didn't work at all for me so I revamped it to make sure it's all in working order for you. Use this one instead:
function closeAllFolders() { function setAllTrackSize(size) { function determineTopMostEditTrack() { sf.ui.proTools.mainWindow.invalidate(); const editTimeLineTopY = sf.ui.proTools.mainWindow.timelineFocusButton.frame.y; return sf.ui.proTools.visibleTrackHeaders.filter(h => h.frame.y >= editTimeLineTopY)[0]; }; if (!sf.ui.proTools.selectedTracks.count) { determineTopMostEditTrack().trackScrollToView() } else { sf.ui.proTools.selectedTrack.trackScrollToView(); } const f = sf.ui.proTools.selectedTrack.frame; const popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({ relativePosition: { x: f.w - 10, y: 5 }, isOption: true, }).popupMenu; popupMenu.menuClickPopupMenu({ menuPath: [size] }); } function closeFolders() { const allTrackHeaders = sf.ui.proTools.visibleTracks.trackHeaders; const folderTrackHeaders = allTrackHeaders.filter(th => th.title.value.includes("Folder")); setAllTrackSize('small'); const firstFolderWithAvailableCloseBtn = folderTrackHeaders.find(folderHeader => { return folderHeader.children.whoseRole.is("AXDisclosureTriangle").whoseDescription.is("Close Folder").first.exists; }); if (firstFolderWithAvailableCloseBtn) { firstFolderWithAvailableCloseBtn.trackScrollToView(); firstFolderWithAvailableCloseBtn.openCloseFolderButton.mouseClickElement({ isOption: true, }); } } sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); closeFolders(); } closeAllFolders();
- MMarko Fazio @Marko_Fazio
Great, it is working! Thank you so much
Raphael Sepulveda @raphaelsepulveda2022-01-30 03:47:03.578Z
Awesome!
- MMarko Fazio @Marko_Fazio
Hello,
I just updated ProTools and my script is not working anymore. I have an error saying ClickButtonAction requires UI Element (line 23)
Thank you for your help.
//Calling command "Selection between 2 markers" from package "Marko Fazio - Package" sf.soundflow.runCommand({ commandId: 'package:ckyjbd5e800006310zzo5lx3k', props: {} }); // BOUNCE ///////////////////////////////////////////////////////////////////////// sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var sessionPath = sf.ui.proTools.mainWindow.sessionPath; var sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); sf.ui.proTools.menuClick({ menuPath: ["File", "Bounce Mix..."], }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Bounce").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("MP3").first.elementWaitFor({ waitType: 'Disappear' }); sf.ui.proTools.waitForNoModals(); // Wait for the bounce to finish // OPEN SESSION BOUNCED FILES FOLDER //////////////////////////////////////////////// const sessionFolder = sessionPath.split('/').slice(0, -1).join('/'); const bounceFolder = `${sessionFolder}/Bounced Files`; sf.file.open({ path: bounceFolder }); // COPY BOUNCES TO TARGET FOLDER /////////////////////////////////////////////////// const targetFolderPath = "/Users/markofaziomusiclaptop/Dropbox/03 - Mixes In Progress"; let bouncedFilePaths = []; // Wait for bounce to appear in Bounced Files folder sf.waitFor({ callback: () => { bouncedFilePaths = sf.file.directoryGetFiles({ path: bounceFolder, searchPattern: `${sessionName}.*` }).paths; return !!bouncedFilePaths.length; } }); // Move files to Target Folder bouncedFilePaths.forEach(filePath => { const fileName = filePath.split('/').slice(-1)[0]; sf.file.copy({ sourcePath: filePath, destinationPath: `${targetFolderPath}/${fileName}` }); });
Raphael Sepulveda @raphaelsepulveda2022-09-10 23:26:59.629Z
@Marko_Fazio, seems like Pro Tools changed the name of that button slightly.
Try replacing line 23 with this one:
sf.ui.proTools.windows.whoseTitle.is("Bounce Mix").first.buttons.whoseTitle.is("Preset Toggle 1").first.elementClick();
- MMarko Fazio @Marko_Fazio
Thank you, it's working!
- MIn reply toMarko_Fazio⬆:Marko Fazio @Marko_Fazio
I have a question regarding another script that would be based on this one.
How difficult would it be to bounce stems back to back with renaming capabilities. So far, I found a script that works for stemming but it does require to manually solo each stem and "save as". It would be nice to be able to have a script that can do inside the same session:- solo each stems one by one
- open the bounce dialogue box
- rename
- wait for the bounce to finish
- repeats on a per stem basis.
Is that even possible?
Raphael Sepulveda @raphaelsepulveda2022-01-30 03:59:22.738Z
Yes, it's definitely possible!
Although it's a bit of a complex subject, it's one that has been discussed at length on the forum. I'd suggest starting by checking out the offerings in the store. If you type "bounce" into the store search, all relevant scripts will come up. From what I've heard Bounce Tracks by @David_Simpson is a popular one!
- MMarko Fazio @Marko_Fazio
Thank you. I will check it out. If I want to keep on asking question about this topic after I do more research on the store, can I keep this thread going? Or do you recommend to start a new one?
Raphael Sepulveda @raphaelsepulveda2022-01-30 05:42:51.642Z
It would be best to start a new one focused on that topic so that other users can find it more easily!