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.838Z2025-06-13 01:08:06.114Z
@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, timeout: 10000, }); }); } 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. :)
- CIn reply toDean⬆:Cédric Culnaërt @CedricC
Hello,
Thanx, that's brillant !
Just noticed wasn't workin' with bypassed ones, so here's my modest contribution (I use option modifier to switch in "deactivate mode")/** * 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(); const modifierState = event.keyboardState; /** * 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" || x.value.value == "bypassed" || x.value.value == "bypassed and 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" || x.value.value == "inactive and bypassed").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, }); }); } switch (true) { case (!modifierState.hasAlt): activateOrdeactivateActiveInserts("Activate"); break case (modifierState.hasAlt): activateOrdeactivateActiveInserts("Deactivate"); break }
Chad Wahlbrink @Chad2025-06-11 19:45:01.306Z
very nice!
- CIn reply toDean⬆:Cédric Culnaërt @CedricC
And here's same thing for the sends :
/** * Activate/Deactivate Allsends on Selected Track */ if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); const modifierState = event.keyboardState; /** * Activate or Deactivate Sends * @param {'Activate'|'Deactivate'} activateOrDeactivate */ function activateOrdeactivateActiveISends(activateOrDeactivate) { const sendsAEWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Sends A-E').isMenuChecked; const sendsFJWasChecked = sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Sends F-J').isMenuChecked; let selectedTrack = sf.ui.proTools.selectedTrack.invalidate(); let sendSelectorButtons; let sendButtons; if (sendsAEWasChecked && !sendsFJWasChecked) { sendSelectorButtons = selectedTrack.sendSelectorButtons.slice(0, 5); sendButtons = selectedTrack.sendButtons.slice(0, 5); } else if (!sendsAEWasChecked && sendsFJWasChecked) { sendSelectorButtons = selectedTrack.sendSelectorButtons.slice(5, 10); sendButtons = selectedTrack.sendButtons.slice(5, 10); } else if (!sendsAEWasChecked && !sendsFJWasChecked) { log('No Inserts are Visible Currently. Show Inserts A-E or Inserts F-J and run again.'); throw 0; } else { sendSelectorButtons = selectedTrack.sendSelectorButtons; sendButtons = selectedTrack.sendButtons; } selectedTrack.trackScrollToView(); let sends, menuPath; if (activateOrDeactivate == 'Deactivate') { // Array of Active Sends - Active Sends value is "" or "open" or "muted and open" or "muted" // The title.value of an active send is something like "Send selector A" // So we are mapping the active Sends to their Insert Selector names and then just slicing the last letter or "A" sends = sendSelectorButtons.filter(x => x.value.value == "" || x.value.value == "open" || x.value.value == "muted and open"|| x.value.value == "muted").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Inactive']; } else if (activateOrDeactivate == 'Activate') { // Array of Inactive Sends - Inactive Sends are "inactive", "inactive and open", or "unassigned", or "inactive and muted", or "inactive and muted and open" sends = sendSelectorButtons.filter(x => x.value.value == "inactive" || x.value.value == "inactive and open" || x.value.value == "inactive and muted" || x.value.value == "inactive and muted and open").map(x => x.title.value).map(x => x.slice(-1)); menuPath = ['Make Active']; } // Filter Send Buttons by Active Sends sendButtons = sendButtons.filter(send => sends.includes(send.title.value.slice(-1))); // Deactivate each Active Send sendButtons.forEach((send) => { // Make Active or Inactive send.invalidate().popupMenuSelect({ isRightClick: true, menuPath: menuPath, }); }); } switch (true) { case (!modifierState.hasAlt): activateOrdeactivateActiveISends("Activate"); break case (modifierState.hasAlt): activateOrdeactivateActiveISends("Deactivate"); break }
Hope will help someone !
Have a great day
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, I was wondering if you could help me with this issue.
Your script is fantastic, and I use it all the time. However, as an optional feature, could you create another script that doesn’t require me to highlight the track I’m deactivating or activating the plugins for? I’d like to keep using the script you created above, but also have the option to use another script that doesn’t require me to click on a specific track to run it. Would that be possible? I’d really appreciate it.
The specific track I need to activate and deactivate is called:
MASTER PLUGINS
Thanks a lot!
Chad Wahlbrink @Chad2025-06-11 19:58:04.936Z2025-06-13 01:06:55.616Z
Hi @Dean,
This version will select the track called "MASTER PLUGINS", Activate or Deactivate plugins, and then re-select the previously selected track. The track has to be in view for the plugins to be activated or deactivated, so it has to be shown at least temporarily.
/** * 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 trackToModify; try { sf.app.proTools.selectTracksByName({ trackNames: [trackToSelect], selectionMode: 'Replace' }); trackToModify = sf.ui.proTools.selectedTrack.invalidate(); trackToModify.trackScrollToView(); } catch (err) { throw `Could Not Select Track with Name: '${trackToSelect}'` } let insertSelectorButtons; let insertButtons; if (insertsAEWasChecked && !insertsFJWasChecked) { insertSelectorButtons = trackToModify.insertSelectorButtons.slice(0, 5); insertButtons = trackToModify.insertButtons.slice(0, 5); } else if (!insertsAEWasChecked && insertsFJWasChecked) { insertSelectorButtons = trackToModify.insertSelectorButtons.slice(5, 10); insertButtons = trackToModify.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 = trackToModify.insertSelectorButtons; insertButtons = trackToModify.insertButtons; } 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" || x.value.value == "bypassed" || x.value.value == "bypassed and 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" || x.value.value == "inactive and bypassed").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, timeout: 10000, }); }); sf.app.proTools.selectTracksByName({ trackNames: currentSelectedTracks, selectionMode: 'Replace' }); sf.ui.proTools.selectedTrack.invalidate().trackScrollToView(); } let currentSelectedTracks = sf.app.proTools.tracks.invalidate().allItems.filter(track => track.isSelected).map(track => track.name); // Track to Select let trackToSelect = 'MASTER PLUGINS'; activateOrdeactivateActiveInserts("Deactivate");
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, thank you for the script, but I’m a bit confused.
Let’s say I have a 300-track session. I keep the MASTER PLUGINS tracks at the bottom before I print a track.
As per your original script, if I select the drum track, which is all the way at the top, I have to scroll all the way down to select the MASTER PLUGINS track and run your script to deactivate or activate it.
What I’m looking for is to select the drum track all the way at the top and then run your script to deactivate or activate the MASTER PLUGINS track. This way, I don’t have to scroll all the way down to do so. Does that make sense?
Chad Wahlbrink @Chad2025-06-12 02:54:15.670Z
@Dean, the script I shared today will work as follows:
- Select the drums track at the top of your session
- Run the script
- The script will select the MASTER PLUGINS track and scroll it into view to deactivate or activate.
- The script then re-selects the drum track and scrolls it into view again.
I only meant that it’s not currently possible to deactivate or reactivate plugins on a track without that track being visible. Because it’s scripted to return to the originally selected track, though, this shouldn’t be a huge issue. However if this is not working as I described, let me know.
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, thank you for the explanation. I'll give it a try tomorrow when I get to the studio.
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad,
The script works great, thank you.
One thing I’ve noticed is that when I have the Kick highlighted and run your script, it deactivates the MASTER PLUGINS but then highlights a different track instead of the Kick I was working on. Is it not possible to revert to the original track after running your script? Thanks!
Chad Wahlbrink @Chad2025-06-12 19:50:02.722Z
That's interesting! Is that "Kick" track nested in a track folder? Which track is being selected instead of "Kick"?
- DIn reply toDean⬆:Dean Landon @Dean
Whether I highlight the Kick, Snare, or any of the tracks above Guitar NO, and run the deactivate or activate plugins using the script, the script ends up highlighting the Guitar NO tracks. (See screenshot.)
The same issue occurs if I select a track below the GUITAR NO track. After running the script, it highlights the track that is 19-90 below it.
Additionally, it’s a random issue, but when I activate the script, I get a failed message with Line 67. I believe this has something to do with the Unfairchild plugin taking longer than the other plugins to activate. Thanks!
Chad Wahlbrink @Chad2025-06-12 22:08:22.357Z
Hi @Dean,
I updated the script here. I extended the timeout in line 70 to hopefully accommodate the Unfairchild. I can't get any plug-in to fail on my machine with this script, but I don't own that particular plug-in.
I also can't get it to have an issue with reselecting the correct track. Are you using an external controller? It looks like you may be in your screenshot. I'd guess that it's possible that the control surface you are using is not syncing up with the SoundFlow commands to select/scroll tracks. However, I tested this with my Avid S1, and it wasn't an issue.
If you want to troubleshoot together, feel free to contact support@soundflow.org, and we can hop on a short Zoom call at some point.
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad,
Thank you for fixing the Unfairchild issue.
Regarding the external control, I do have an extensive S1/iPad system pictured below. You said: it's possible that the control surface you are using is not syncing up with the SoundFlow commands to select/scroll tracks.
I'll look into that. Thanks again!
Chad Wahlbrink @Chad2025-06-13 01:10:24.385Z
Epic setup!
- DDean Landon @Dean
Thanks Chad. 😊
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, the select/scroll you're referring to, is that a setting in EuCon? Thank you
Chad Wahlbrink @Chad2025-06-13 01:13:16.275Z
Hi @Dean,
I updated the script once more. I changed the track selection methods so they use the Pro Tools SDK, and I'm curious if those will work better for you.
Otherwise, I think we would need to have a Zoom call to test it in real time. I'd also try testing with and without Eucon enabled to confirm that it is not conflicting. However, it shouldn't be an issue if your controllers are all Eucon-based. I tried changing the track selection and bank-to-selection settings on my Eucontrol setup and couldn't make it break the track selection with SoundFlow.
- DIn reply toDean⬆:Dean Landon @Dean
Hi Chad, I believe I’ve identified the issue. In Pro Tools, I modified all the track sizes to Micro and retained the two primary tracks, Kick and MASTER PLUGINS, at Medium. Consequently, I could now view all the tracks on my 27-inch Apple Display.
With the Kick track highlighted, I executed your latest script. It successfully deactivated the plugins in the MASTER PLUGINS tracks and then highlighted the Kick track once more. However, this process will only work if all the tracks are visible.
Thanks!
Chad Wahlbrink @Chad2025-06-13 14:07:00.198Z
Hi @Dean,
Thanks for the update. If you are happy with the current functionality, then that's great!
Having to have the tracks visible indicates the
sf.ui.proTools.selectedTrack.invalidate().trackScrollToView();
method is not acting as expected.Having the tracks visible for the script I shared to work shouldn't be necessary. If you wish to troubleshoot that further, contact me at support@soundflow.org for a quick Zoom, and we can look together.
- DDean Landon @Dean
Hi Chad, for the time being, I'll work with the current script. I think it'll work for what I'm trying to do. As I mentioned in my previous post, it does work as intended, if "all" tracks are visible. Maybe one day we can figure out how to make it work without having all tracks visible. Thanks again for all your help. I do appreciate it.
Chad Wahlbrink @Chad2025-06-13 18:25:32.072Z
Sounds good, @Dean ! Happy to help