Activating or Deactivating all plugins on a single track.
Title
Activating or Deactivating all plugins on a single track.
What do you expect to happen when you run the script/macro?
Hi,
I route my Pro Tools tracks through an AUX track that contains my mastering plugins. Depending on the session, this AUX track might have 3, 5, 6, or any number of plugins.
When I'm mixing and want to add another instrument track, I temporarily disable the plugins on the AUX track to avoid latency while playing live. Once I'm done recording, I re-enable the plugins.
I have two scripts that activate or deactivate up to 10 plugins (slots A–J) on the AUX track, and both work well—provided that all 10 plugin slots are in use. However, if there are fewer than 10 plugins, I receive error messages.
How can I modify the script to dynamically handle only the number of plugins that are actually present on the AUX track, and avoid errors when fewer than 10 are in use?
Thanks!
Are you seeing an error?
When deactivating, it says: Deactivate all plugins on a single track failed.
Could not open popup menu Deactivate all plugins on a single track : Line 40
This makes sense because I don't have any plugins to deactivate from Inserts F-J
What happens when you run this script?
When I run the script, it will deactivate all 10 plugins IF I have 10 plugins instantiated. Anything less than 10 plugins, and I will see a failed message.
How were you running this script?
I clicked the "Run Script" or "Run Macro" button in SoundFlow
How important is this issue to you?
5
Details
{ "inputExpected": "Hi,\n\nI route my Pro Tools tracks through an AUX track that contains my mastering plugins. Depending on the session, this AUX track might have 3, 5, 6, or any number of plugins.\n\nWhen I'm mixing and want to add another instrument track, I temporarily disable the plugins on the AUX track to avoid latency while playing live. Once I'm done recording, I re-enable the plugins.\n\nI have two scripts that activate or deactivate up to 10 plugins (slots A–J) on the AUX track, and both work well—provided that all 10 plugin slots are in use. However, if there are fewer than 10 plugins, I receive error messages.\n\nHow can I modify the script to dynamically handle only the number of plugins that are actually present on the AUX track, and avoid errors when fewer than 10 are in use?\n\nThanks!", "inputIsError": true, "inputError": "When deactivating, it says: Deactivate all plugins on a single track failed.\n\nCould not open popup menu Deactivate all plugins on a single track : Line 40\n\nThis makes sense because I don't have any plugins to deactivate from Inserts F-J", "inputWhatHappens": "When I run the script, it will deactivate all 10 plugins IF I have 10 plugins instantiated. Anything less than 10 plugins, and I will see a failed message.", "inputHowRun": { "key": "-MpfwYA4I6GGlXgvp5j1", "title": "I clicked the \"Run Script\" or \"Run Macro\" button in SoundFlow" }, "inputImportance": 5, "inputTitle": "Activating or Deactivating all plugins on a single track." }
Source
sf.ui.proTools.appActivateMainWindow();
const insertA = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts A-E').first.buttons.whoseTitle.is('Insert Assignment A').first
insertA.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertB = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts A-E').first.buttons.whoseTitle.is('Insert Assignment B').first
insertB.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertC = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts A-E').first.buttons.whoseTitle.is('Insert Assignment C').first
insertC.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertD = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts A-E').first.buttons.whoseTitle.is('Insert Assignment D').first
insertD.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertE = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts A-E').first.buttons.whoseTitle.is('Insert Assignment E').first
insertE.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertF = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts F-J').first.buttons.whoseTitle.is('Insert Assignment F').first
insertF.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertG = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts F-J').first.buttons.whoseTitle.is('Insert Assignment G').first
insertG.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertH = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts F-J').first.buttons.whoseTitle.is('Insert Assignment H').first
insertH.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertI = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts F-J').first.buttons.whoseTitle.is('Insert Assignment I').first
insertI.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
const insertJ = sf.ui.proTools.selectedTrack.groups.whoseTitle.is('Inserts F-J').first.buttons.whoseTitle.is('Insert Assignment J').first
insertJ.popupMenuSelect({
isRightClick: true,
menuPath: ["Make Active"],
targetValue: "Enable",
});
Links
User UID: S45xHsbBfQb9iI0ItOGS2OnVpod2
Feedback Key: sffeedback:S45xHsbBfQb9iI0ItOGS2OnVpod2:-OQeghOEt3Kfq6LGNiJN
Feedback ZIP: SBeO0w/QRZ2CtFyaBuofv+xUg5/DBUSXNnKZYugY/L9E+J++7rVpXFIQ5DsvFliOJ5oEwVhRs+8ahqfBW+gpfo7AVoV3m27rykfDxFjDZ5nr85fL44Va13sYf4erKKbn8bCA/ly7fGQPd5ZRXQRUvefYSjIIBu6HBzJHJ+suqh8L+kfsW58jjaGVsOaM4xmd5rigcDBBEXqdZyz7V/HrJz+8TVSfO1Cpz//kbbzjqBOcAXSkGlG+kvh45K5yav7iRFll392bZtDbSWCQQ0T1XlxwgWTAByrCI8OZHUgP1nK+cPp/V+kCbp0K2VI5EBLnEI2HfoL5OV6cvgagdtwfGw==
- Chad Wahlbrink @Chad2025-05-20 01:26:42.563Z2025-05-23 18:33:07.638Z
Hi, @Dean,
Thanks for this!
Okay, let's try a similar method to the one I shared before, but let's try using the right-click menu, like you are in your version, instead of the mouse-click action I was using previously.
Let me know if this helps.
/** * Activate/Deactivate All Inserts on Selected Track */ if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); /** * Activate or Deactivate Inserts * @param {'Activate'|'Deactivate'} activateOrDeactivate */ function activateOrdeactivateActiveInserts(activateOrDeactivate) { // Show inserts const aEInsertMenuPath = ['View', 'Edit Window Views', 'Inserts A-E']; const fJInsertMenuPath = ['View', 'Edit Window Views', 'Inserts F-J']; const insertsAEWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Inserts A-E').isMenuChecked; const insertsFJWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Inserts F-J').isMenuChecked; if (!insertsAEWasChecked) { sf.ui.proTools.menuClick({ menuPath: aEInsertMenuPath, targetValue: "Enable" }); } if (!insertsFJWasChecked) { sf.ui.proTools.menuClick({ menuPath: fJInsertMenuPath, targetValue: "Enable" }); } let selectedTrack = sf.ui.proTools.selectedTrack.invalidate(); selectedTrack.trackScrollToView(); let inserts, menuPath; if (activateOrDeactivate == 'Deactivate') { // Array of Active Inserts - Active Inserts value is just "" or "open" (if plugin window is open) // The title.value of an active insert is something like "Insert selector A" // So we are mapping the active inserts to their Insert Selector names and then just slicing the last letter or "A" inserts = selectedTrack.insertSelectorButtons.filter(x => x.value.value == "" || x.value.value == "open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Inactive']; } else if (activateOrDeactivate == 'Activate') { // Array of Inactive Inserts - Inactive Inserts are "inactive", "inactive and open", or "unassigned" inserts = selectedTrack.insertSelectorButtons.filter(x => x.value.value == "inactive" || x.value.value == "inactive and open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Active']; } // Filter Insert Buttons by Active Inserts let insertButtons = selectedTrack.insertButtons.filter(insert => inserts.includes(insert.title.value.slice(-1))); // Deactivate each Active Insert insertButtons.forEach((insert) => { // Map to the current selector button based on A,B,C,D,E,F,G,H,I,J let currentSelectorButton = selectedTrack.insertSelectorButtons.find(insertSelectorButton => insertSelectorButton.title.value.slice(-1) == insert.title.value.slice(-1)); // Make Active or Inactive insert.invalidate().popupMenuSelect({ isRightClick: true, menuPath: menuPath, }); // Wait for the plug-in to deactivate if (activateOrDeactivate == 'Deactivate') { sf.waitFor({ callback: () => { currentSelectorButton.invalidate(); return currentSelectorButton.value.value == "inactive" || currentSelectorButton.value.value == "inactive and open"; }, timeout: 30000 }, `Failed waiting`); } // Wait for the plug-in to activate else if (activateOrDeactivate == 'Activate') { sf.waitFor({ callback: () => { currentSelectorButton.invalidate(); return currentSelectorButton.value.value == "" || currentSelectorButton.value.value == "open"; }, timeout: 30000 }, `Failed waiting`); } }) // Set Menus Back if (!insertsAEWasChecked) { sf.ui.proTools.menuClick({ menuPath: aEInsertMenuPath, targetValue: "Disable" }); } // Set Menus Back if (!insertsFJWasChecked) { sf.ui.proTools.menuClick({ menuPath: fJInsertMenuPath, targetValue: "Disable" }); } } activateOrdeactivateActiveInserts("Deactivate");
Change the last line to this for "Activate" all inserts.
activateOrdeactivateActiveInserts("Activate");
- DIn reply toDean⬆:Dean Landon @Dean
Chad, you’re a genius! Thank you so much for your help with this issue. I’ve been searching online for this script for quite some time, and it’s perfect. Thanks again!
Chad Wahlbrink @Chad2025-05-20 14:42:50.762Z
Great! Glad to hear it, @Dean
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, I’m having an issue with the script today. I started a new session, and I have plugins on the AUX tracks, but I keep getting the same failed message. Any thoughts as to why this is happening? Thanks!
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, after 2 days I keep getting the same failed message. Any thoughts as to why this might be happening? Thanks
- DIn reply toDean⬆:Dean Landon @Dean
Okay, I believe I understand the issue. I have five plugins in inserts A-E, and the F-J insert column is not activated. When I activate the F-J column, the script functions correctly.
Is there a way to modify the existing script to ensure that the command works regardless of whether inserts A-E or A-E and F-J are activated?
Thank again for your help.
Chad Wahlbrink @Chad2025-05-23 02:19:07.390Z
Hi, @Dean,
Sorry for the delay in responding to this!
I made changes to the script above to accommodate this. Copy the code from here again and give it a go:
It seems that the
insertSelectorButtons
object wants all of the inserts to be shown to read their state, so I am just showing/hiding those temporarily if they are hidden.This version will also scroll the selected track into view first to ensure it runs properly. If you wanted to have it be a named track, you could also do that, just let me know.
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, thanks for modifying the script.
I noticed something. If I have plugins on A-E but not on F-J, and the F-J Insert window is closed, when I deactivate or activate the command, it first opens and closes F-J before running the command.
Is it possible to configure SoundFlow to know that if I have only 1 to 5 plugins, it shouldn’t open the F-J Insert window? If I have more than 5 plugins, it should automatically activate and deactivate the plugins in A-E and F-J?
Also, when I try to activate the plugins, there’s a failed Line 78 message that pops up.
Thanks again for your help. I really appreciate it.
Chad Wahlbrink @Chad2025-05-23 03:16:22.080Z2025-05-23 18:30:20.503Z
Hi, @Dean,
I think the error you are seeing results from the "timeout" in lines 77 and 87 not being long enough. I made the timeout 5000ms (instead of 1000) on the updated version above:
Activating or Deactivating all plugins on a single track. #post-2Also – I was wrong, you can do what you are asking! This version of the script should activate/deactivate only for the visible inserts on the track:
/** * Activate/Deactivate All Visible Inserts on Selected Track */ if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); /** * Activate or Deactivate Inserts * @param {'Activate'|'Deactivate'} activateOrDeactivate */ function activateOrdeactivateActiveInserts(activateOrDeactivate) { const insertsAEWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Inserts A-E').isMenuChecked; const insertsFJWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Inserts F-J').isMenuChecked; let selectedTrack = sf.ui.proTools.selectedTrack.invalidate(); let insertSelectorButtons; let insertButtons; if (insertsAEWasChecked && !insertsFJWasChecked) { insertSelectorButtons = selectedTrack.insertSelectorButtons.slice(0, 5); insertButtons = selectedTrack.insertButtons.slice(0, 5); } else if (!insertsAEWasChecked && insertsFJWasChecked) { insertSelectorButtons = selectedTrack.insertSelectorButtons.slice(5,10); insertButtons = selectedTrack.insertButtons.slice(5,10); } else if (!insertsAEWasChecked && !insertsFJWasChecked){ log('No Inserts are Visible Currently. Show Inserts A-E or Inserts F-J and run again.'); throw 0; } else { insertSelectorButtons = selectedTrack.insertSelectorButtons; insertButtons = selectedTrack.insertButtons; } selectedTrack.trackScrollToView(); let inserts, menuPath; if (activateOrDeactivate == 'Deactivate') { // Array of Active Inserts - Active Inserts value is just "" or "open" (if plugin window is open) // The title.value of an active insert is something like "Insert selector A" // So we are mapping the active inserts to their Insert Selector names and then just slicing the last letter or "A" inserts = insertSelectorButtons.filter(x => x.value.value == "" || x.value.value == "open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Inactive']; } else if (activateOrDeactivate == 'Activate') { // Array of Inactive Inserts - Inactive Inserts are "inactive", "inactive and open", or "unassigned" inserts = insertSelectorButtons.filter(x => x.value.value == "inactive" || x.value.value == "inactive and open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Active']; } // Filter Insert Buttons by Active Inserts insertButtons = insertButtons.filter(insert => inserts.includes(insert.title.value.slice(-1))); // Deactivate each Active Insert insertButtons.forEach((insert) => { // Map to the current selector button based on A,B,C,D,E,F,G,H,I,J let currentSelectorButton = insertSelectorButtons.find(insertSelectorButton => insertSelectorButton.title.value.slice(-1) == insert.title.value.slice(-1)); // Make Active or Inactive insert.invalidate().popupMenuSelect({ isRightClick: true, menuPath: menuPath, }); // Wait for the plug-in to deactivate if (activateOrDeactivate == 'Deactivate') { sf.waitFor({ callback: () => { currentSelectorButton.invalidate(); return currentSelectorButton.value.value == "inactive" || currentSelectorButton.value.value == "inactive and open"; }, timeout: 30000 }, `Failed waiting`); } // Wait for the plug-in to activate else if (activateOrDeactivate == 'Activate') { sf.waitFor({ callback: () => { currentSelectorButton.invalidate(); return currentSelectorButton.value.value == "" || currentSelectorButton.value.value == "open"; }, timeout: 30000 }, `Failed waiting`); } }); } activateOrdeactivateActiveInserts("Deactivate");
- DIn reply toDean⬆:Dean Landon @Dean
Thanks Chad for modifying the script, but there seems to be another failed message.
- In reply toDean⬆:
Chad Wahlbrink @Chad2025-05-23 03:34:36.959Z
Sorry about that @Dean!
Updated now.
I was accounting for the scenarios where one set of inserts was shown or the other, but this one will handle all cases better...
- DIn reply toDean⬆:Dean Landon @Dean
No problem, Chad. I appreciate the help.
I'm not at the studio at the moment, but will definitely give this a try in the morning. Thanks again for your time.
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, I tried your last script, and the Deactivate function works perfectly. However, when I activate the plugins, I receive a failed message at Line 80.
I believe I understand the issue. The third plugin in slot C is the UnFairchild, which takes a bit longer than most plugins to activate. This is when the failed message appears. After the failed message, I can run the command again, and it continues to activate the remaining plugins. Is there a way to manage this? Thanks so much. I appreciate your help.
Chad Wahlbrink @Chad2025-05-23 18:32:50.620Z
Hi, @Dean,
Great!
Yes, that line is a "timeout" to ensure the plug-in activates or deactivates. If the plugin had taken longer than 5 seconds to come online, it would have timed out before. The best way to mitigate this would be to raise the timeout value in lines 75 and 85 to a larger number.
I've raised it to 30000 or 30 seconds in the scripts above, so give that a shot. It will complete once it recognizes the plugin is active or inactive, so it's okay to have large values like this in the timeout.
- DIn reply toDean⬆:Dean Landon @Dean
Thank you Chad. I'll give that a try.
- DIn reply toDean⬆:Dean Landon @Dean
Strange, I'm still getting the same failed Line 80 message with the new script. I wonder why...
Chad Wahlbrink @Chad2025-05-23 20:51:51.838Z
@Dean, very strange. I'm not sure why it would work here. Does it only fail on the track with the unfairchild on it?
You can try removing those checks. Since that version of the script doesn't show/hide the inserts, it may not be necessary:
/** * Activate/Deactivate All Visible Inserts on Selected Track */ if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); /** * Activate or Deactivate Inserts * @param {'Activate'|'Deactivate'} activateOrDeactivate */ function activateOrdeactivateActiveInserts(activateOrDeactivate) { const insertsAEWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Inserts A-E').isMenuChecked; const insertsFJWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Inserts F-J').isMenuChecked; let selectedTrack = sf.ui.proTools.selectedTrack.invalidate(); let insertSelectorButtons; let insertButtons; if (insertsAEWasChecked && !insertsFJWasChecked) { insertSelectorButtons = selectedTrack.insertSelectorButtons.slice(0, 5); insertButtons = selectedTrack.insertButtons.slice(0, 5); } else if (!insertsAEWasChecked && insertsFJWasChecked) { insertSelectorButtons = selectedTrack.insertSelectorButtons.slice(5,10); insertButtons = selectedTrack.insertButtons.slice(5,10); } else if (!insertsAEWasChecked && !insertsFJWasChecked){ log('No Inserts are Visible Currently. Show Inserts A-E or Inserts F-J and run again.'); throw 0; } else { insertSelectorButtons = selectedTrack.insertSelectorButtons; insertButtons = selectedTrack.insertButtons; } selectedTrack.trackScrollToView(); let inserts, menuPath; if (activateOrDeactivate == 'Deactivate') { // Array of Active Inserts - Active Inserts value is just "" or "open" (if plugin window is open) // The title.value of an active insert is something like "Insert selector A" // So we are mapping the active inserts to their Insert Selector names and then just slicing the last letter or "A" inserts = insertSelectorButtons.filter(x => x.value.value == "" || x.value.value == "open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Inactive']; } else if (activateOrDeactivate == 'Activate') { // Array of Inactive Inserts - Inactive Inserts are "inactive", "inactive and open", or "unassigned" inserts = insertSelectorButtons.filter(x => x.value.value == "inactive" || x.value.value == "inactive and open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Active']; } // Filter Insert Buttons by Active Inserts insertButtons = insertButtons.filter(insert => inserts.includes(insert.title.value.slice(-1))); // Deactivate each Active Insert insertButtons.forEach((insert) => { // Make Active or Inactive insert.invalidate().popupMenuSelect({ isRightClick: true, menuPath: menuPath, }); }); } activateOrdeactivateActiveInserts("Activate");
- In reply toDean⬆:
Chad Wahlbrink @Chad2025-05-23 20:52:31.497Z
If that doesn't work, can you take a screen recording and share a Google Drive or Dropbox link?
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, this performed perfectly. What was added to make this work?
Thanks again!
Chad Wahlbrink @Chad2025-05-23 21:50:40.193Z
Awesome! I removed line 68 to 87 from this version:
Those are checks to make sure that the plug-in is activated or deactivated before moving on, but that was only really necessary for the longer script that opens up the hidden inserts. Something with the menus changing needed some extra checks for it to work well on my computer when I was testing it last night.
But for the version that is just doing visible inserts, we may not need to check that the plugin was activated or deactivated.
- DIn reply toDean⬆:Dean Landon @Dean
Got it. Well thanks again for all your help. I appreciate it. :)