Improving Stability of Track Workflow Automation Script in Pro Tools
Hi,
I’m reaching out for assistance with a SoundFlow script I’ve written to automate several actions in Pro Tools. While the core functionality is in place, the script is currently unstable and doesn’t consistently execute all the intended steps. I’d really appreciate your help in making it more reliable and efficient.
Here’s what the script is meant to do:
Change the color of selected tracks to a desired one.
Move the selected track(s) to a specific folder track.
Assign the selected track(s) to a specific group.
Below is the current version of the script:
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.colorsSelect({
colorBrightness: "Light",
colorNumber: 9,
});
sf.ui.proTools.selectedTrack.trackOutputSelect({
outputPath: ["bus", "bus menu 1-128", "01_STEM (Stereo)"],
selectForAllSelectedTracks: true,
});
sf.ui.proTools.selectedTrack.titleButton.popupMenuSelect({
isRightClick: true,
menuPath: ["Move to...", "01_STEM"]
});
sf.keyboard.press({
keys: "ctrl+cmd+g",
});
sf.ui.proTools.windows.whoseTitle.is('Modify Groups').first.popupButtons.whoseTitle.is('GroupIDView').first.popupMenuSelect({
menuPath: ["4", "b - VCA 01 (VCA 01)"],
targetValue: "Enable",
});
sf.ui.proTools.windows.whoseTitle.is("Modify Groups").first.buttons.whoseTitle.is("Add").first.elementClick();
sf.ui.proTools.windows.whoseTitle.is("Modify Groups").first.buttons.whoseTitle.is("OK").first.elementClick();
Could you help me identify what might be causing the instability and how best to improve the flow, especially with handling UI delays or element availability?
Thanks in advance for your support!
Chris Shaw @Chris_Shaw2025-06-08 20:48:01.020Z2025-06-09 18:33:35.340ZHey @STEPHANE_BRIAND,
I refactored the script so that it can be reused by changing the constants at the start of the script.
I make use of themenuSelectorfunction inside of thepopupMenuSelectfunctions to filter the popup menu items so it selects the menu path of your desired folder input, "Move to..." folder, and VCA group name.
Additionally there are a couple ofmainWindow.invalidate()calls to refresh the cache to ensure stability and I swapped keyboard presses with menu select commands.// CONSTANTS const targetFolderName = "01_STEM" const targetVcaName = "VCA 01" /** * @typedef {Object} TrackColor * @property {"Light" | "Medium" | "Dark"} colorBrightness - Brightness level of the track color. * @property {number} colorNumber - Numeric identifier for the track color (typically 1–127). */ /** @type {TrackColor} */ const newTrackColor = { colorBrightness: "Light", colorNumber: 9, }; // Main // sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); sf.ui.proTools.selectedTrack.trackScrollToView() // Set selected tracks' color sf.ui.proTools.colorsSelect(newTrackColor); // Set track outputs to folder input sf.ui.proTools.selectedTrack.outputPathButton.popupMenuSelect({ menuPath:[`track`,`${targetFolderName}*`], useWildcards:true, isShift: true, isOption: true }) // We need to refresh main window cache because values have changed sf.ui.proTools.mainWindow.invalidate() // Move tracks to target folder by finding popup menu item that contains target folder's name sf.ui.proTools.selectedTrack.titleButton.popupMenuSelect({ isRightClick: true, menuSelector: items => items.find(i => i.path[0] == "Move to..." && i.path[1] && i.path[1].endsWith(targetFolderName)), },); // Tracks have moved so we need to refresh the main window cache sf.ui.proTools.mainWindow.invalidate() // Open Modify Groups window sf.ui.proTools.mainWindow.groupListPopupButton.popupMenuSelect({ menuPath: ["Modify Groups"] }) // Define Modify Groups window const modifyGroupsWindow = sf.ui.proTools.windows.whoseTitle.is('Modify Groups').first; // Wait for Modify Groups window modifyGroupsWindow.elementWaitFor() // Define Modify Groups window buttons const groupAddButton = modifyGroupsWindow.buttons.whoseTitle.is("Add").first const groupIdViewButton = modifyGroupsWindow.popupButtons.whoseTitle.is('GroupIDView').first /// Wait for "Add" button to be enabled before proceeding sf.waitFor({ callback: () => groupAddButton.invalidate().isEnabled }) // Get current groupID view button value (for later comparison) const originalGroupIdViewButtonValue = groupIdViewButton.value.invalidate().value // Select target VCA group from popup menu by filtering popup items for the one that contains the target VCA's group name groupIdViewButton.popupMenuSelect({ menuSelector: items => items.find(i => i.path[1] && i.path[1].endsWith(`(${targetVcaName})`)), targetValue: "Enable", }); // Wait for groupID button value to change sf.waitFor({ callback: () => groupIdViewButton.value.invalidate().value !== originalGroupIdViewButtonValue }) //Add tracks to group and close Modify Groups window groupAddButton.elementClick(); modifyGroupsWindow.buttons.whoseTitle.is("OK").first.elementClick();- SIn reply toSTEPHANE_BRIAND⬆:STEPHANE BRIAND @STEPHANE_BRIAND
Hi Chris,
Thanks a lot for the updated script — I really appreciate the time and effort you put into refactoring it!
This will definitely make my workflow smoother. Thanks again for sharing it!
I’ll test it out tomorrow and let you know how it goes.Thanks again!
Best,
Stéphane