Remove all inactive plugins/sends
good evening friends
Is there a way to have soundflow scan and remove inactive plugins and or sends throughout all tracks of a pro tools session?
Linked from:
- samuel henriques @samuel_henriques
hello @dex_green,
this will remove inactive inserts and sends on all selected tracks.
hope it works for you.function dismissDialg() { if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Remove').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Remove').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Change').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Change').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } } function removeInactive({ inserts = true, sends = true }) { if (inserts) { //remove inactive inserts try { for (var i = 0; i < 10; i++) { dismissDialg() if (sf.ui.proTools.selectedTrack.insertSelectorButtons[i].invalidate().value.value.startsWith("inactive")) { sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({ insertOrSend: "Insert", pluginNumber: i + 1, pluginPath: ['no insert'] }); dismissDialg() } } } catch (err) { } } if (sends) { //remove inactive sends try { for (var i = 0; i < 10; i++) { dismissDialg() if (sf.ui.proTools.selectedTrack.sendSelectorButtons[i].invalidate().value.value.startsWith("inactive")) { sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({ insertOrSend: "Send", pluginNumber: i + 1, pluginPath: ['no send'] }); dismissDialg() } } } catch (err) { } } } function enableMenus(currentValue) { sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", currentValue], targetValue: "Enable" }); } const menus = [ "Inserts A-E", "Inserts F-J", "Sends A-E", "Sends F-J" ] /** * @param {Object} [arg] * @param {boolean} [arg.inserts] * @param {boolean} [arg.sends] */ function removeInactiveInserts_Sends(arg) { //Activate Pro Tools sf.ui.proTools.appActivate(); sf.ui.proTools.invalidate(); //Enable view of Inserts and Sends menus.forEach(enableMenus) sf.ui.proTools.invalidate(); //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { const vcaTrack = track.title.value.endsWith("VCA Track ") const basicFolder = track.title.value.endsWith("Basic Folder Track ") const midiTrack = track.title.value.endsWith("MIDI Track ") if (!vcaTrack && !basicFolder && !midiTrack) { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); removeInactive(arg || {}) } }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); } removeInactiveInserts_Sends()
samuel henriques @samuel_henriques
UPDATE: needed more dismiss dialog
- In reply tosamuel_henriques⬆:Ddex green @dex_green
thank you for this Samuel! For some reason it doesn't run on my system.
samuel henriques @samuel_henriques
oi...
nothing happens when select a track with inactive inserts or sends?samuel henriques @samuel_henriques
Are you using mix or edit window?
- Ddex green @dex_green
arg....rookie mistake from the mix window!
it works....and you rule sir!
will be nice for cleaning up around the place
samuel henriques @samuel_henriques
awesome!!
samuel henriques @samuel_henriques
if you want, I guess I can put in a line to call the edit window first.
- Ddex green @dex_green
aw man.... totally not necessary. Only if you get inspired!
thank you for taking the time
love this one
samuel henriques @samuel_henriques
Hahaha, I'll leave it for you.
Have fun.Brett Ryan Stewart @Brett_Ryan_Stewart
Hi @samuel_henriques thanks for this code!
I'm no code expert in the slightest and wondering what I'd need to take out of this script in order to make it two separate commands:
1 that removes inactive inserts
1 that removes inactive sendsRight now it takes out both inserts and sends :-)
samuel henriques @samuel_henriques
Hello Brett,
I think this should do it, let me know if it works.
Make a copy of the script, and change this part:const menus = [ "Inserts A-E", "Inserts F-J", "Sends A-E", "Sends F-J" ]
On the new remove the inserts :
const menus = [ "Inserts A-E", "Inserts F-J" ]
On the new remove sends:
const menus = [ "Sends A-E", "Sends F-J" ]
Also, there are two parts of the script with a comments,
On your new script remove sends delete the part, from
//remove inactive inserts
, all the way to the line just before//remove inactive sends
(keep this line)and on your new script remove inserts, delete from
//remove inactive sends
all the way to the line just beforefunction enableMenus(currentValue) {
(keep this line)Brett Ryan Stewart @Brett_Ryan_Stewart
Thanks @samuel_henriques
So i got the Remove Sends to work. For whatever reason the Remove Inserts is not working. I think i followed your instructions but can you peak at this code as see if I missed something?function dismissDialg() { if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Remove').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Remove').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Change').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Change').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } } function removeInactive() { //remove inactive inserts for (var i = 0; i < 10; i++) { dismissDialg() if (sf.ui.proTools.selectedTrack.insertSelectorButtons[i].invalidate().value.value.startsWith("inactive")) { sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({ insertOrSend: "Insert", pluginNumber: i + 1, pluginPath: ['no insert'] }); dismissDialg() } } function enableMenus(currentValue) { sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", currentValue], targetValue: "Enable" }); } const menus = [ "Inserts A-E", "Inserts F-J" ] //Activate Pro Tools sf.ui.proTools.appActivate(); sf.ui.proTools.invalidate(); //Enable view of Inserts and Sends menus.forEach(enableMenus) sf.ui.proTools.invalidate(); //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); removeInactive() }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks });
samuel henriques @samuel_henriques
Add on } on the line before
function enableMenus(currentValue) {Brett Ryan Stewart @Brett_Ryan_Stewart
Boom that did it. Thank you so much Samuel!
samuel henriques @samuel_henriques
Awesome!
- In reply tosamuel_henriques⬆:Rroom1252021 @room1252021
Thanks for this super useful script.
It works extremely well for me.The only problem is that having VCA tracks between the audio tracks breaks it, cause VCAs don't have inserts.
Any way to have it skip VCA and Master Faders?To reproduce:
- Create 2 audio tracks
- Add a VCA track between the 2 audio tracks.
- Select all 3 tracks and run the script.
Thanks again!
15.02.2024 14:39:11.92 <info> [Backend]: Could not get UIElement for AxPtTrackInsertSendSelectorButton: Could not get trackInserts/Sends. { "title": "VCA IO", "description": null, "role": "AXGroup", "fullRole": "AXGroup",
samuel henriques @samuel_henriques
Just updated the original with a fix. If it encounters any track without inserts shouldn't break now.
Also, added the to choose if you don't want inserts or sends. Default is always remove both.
User can add {} between the () in the function call and press F2, to get the optionsThen set false to inserts or sends.
- In reply toroom1252021⬆:
samuel henriques @samuel_henriques
Also, just for your request of ignoring Master Faders
replace line 105 with:
const masterTrack = track.title.value.endsWith("Master Track ") if (!vcaTrack && !basicFolder && !midiTrack && !masterTrack) {
- Rroom1252021 @room1252021
Thanks Samuel,
This is great.
- In reply tosamuel_henriques⬆:EErik Groysman @Erik_Groysman
This is incredible! Is there any way to make this all work for 'Micro' and 'Mini' sized tracks?
It doesn't appear to make those react.Thank you!!
- AIn reply todex_green⬆:Andrew Maury @Andrew_Maury
thanks for all this! is anyone able to post the final script that works?
samuel henriques @samuel_henriques
Hello Andrew,
the original works
remove all inactive plugins/sends #post-2samuel henriques @samuel_henriques
Here's a version that might me a little faster,
/** * @param {Object} trackHeader - Track Header * @returns {Object} * @property {number} trackHeight * @property {'micro'|'mini'|'small'|'medium'|'large'|'jumbo'|'extreme'|'fit to window' } trackSize */ function getCurrentTrackHeight(trackHeader) { let h = trackHeader.frame.h let originalTrackHeight; switch (true) { case (h <= 16): originalTrackHeight = 'micro'; break; case (h === 23): originalTrackHeight = 'mini'; break; case (h >= 43 && h <= 61): originalTrackHeight = 'small'; break; case (h >= 79 && h <= 116): originalTrackHeight = 'medium'; break; case (h >= 135 && h <= 235): originalTrackHeight = 'large'; break; case (h >= 257 && h <= 420): originalTrackHeight = 'jumbo'; break; case (h > 440): originalTrackHeight = 'extreme'; break; } return { trackHeight: h, trackSize: originalTrackHeight } } /** * @param {'micro'|'mini'|'small'|'medium'|'large'|'jumbo'|'extreme'|'fit to window' } size */ function setTrackSize(size) { const selectedTrackH = sf.ui.proTools.selectedTrackHeaders[0] const hasHeaderHeightPopup = selectedTrackH.frame.h <= 79 try { selectedTrackH.popupMenuSelect({ anchor: "MidRight", relativePosition: { x: - 10, y: 0 }, menuPath: [size], onError: "Continue", }) } catch (err) { // Try header left poput if (hasHeaderHeightPopup) { sf.ui.proTools.selectedTrack.popupButtons.allItems[2].popupMenuSelect({ menuPath: ["Track Height", size], }); }; }; }; function dismissDialg() { if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Remove').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Remove').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Change').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Change').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); }; }; function getInsertAndSendInfo() { let infoObj = { inserts: [], sends: [] }; for (var i = 0; i < 10; i++) { const insertBtn = sf.ui.proTools.selectedTrack.insertSelectorButtons[i]; if (insertBtn.exists) { if (insertBtn.invalidate().value.value.startsWith("inactive")) { infoObj.inserts.push(i + 1); }; }; const sendBtn = sf.ui.proTools.selectedTrack.sendSelectorButtons[i]; if (sendBtn.exists) { if (sendBtn.invalidate().value.value.startsWith("inactive")) { infoObj.sends.push(i + 1) }; }; }; return infoObj }; /** * @param {string[]} letterArr */ function convertLetterToNumber(letterArr) { let newArr = [] const letterRange = "ABCDEFGHIJ" letterArr.forEach(letter => { if (letterRange.includes(letter.toUpperCase())) { let number = letterRange.indexOf(letter.toUpperCase()) + 1 if (!newArr.includes(number)) newArr.push(number); } }) return newArr; }; /** * @param {Object} param * @param {Object} param.ins_sendInfo * @param {array} param.ignoreInserts * @param {array} param.ignoreSends */ function removeInactive({ ins_sendInfo, ignoreInserts = [], ignoreSends = [] }) { ignoreInserts = convertLetterToNumber(ignoreInserts) ignoreSends = convertLetterToNumber(ignoreSends) const inserts = ins_sendInfo.inserts.filter(ins => !ignoreInserts.includes(ins)) const sends = ins_sendInfo.sends.filter(send => !ignoreSends.includes(send)) if (inserts) { inserts.forEach(insert => { dismissDialg(); sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({ insertOrSend: "Insert", pluginNumber: insert, pluginPath: ['no insert'] }); dismissDialg(); }); }; if (sends) { sends.forEach(send => { dismissDialg(); sf.ui.proTools.selectedTrack.trackInsertOrSendSelect({ insertOrSend: "Send", pluginNumber: send, pluginPath: ['no send'] }); dismissDialg() }); }; }; function enableMenus(currentValue) { sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", currentValue], targetValue: "Enable" }); } const menus = [ "Inserts A-E", "Inserts F-J", "Sends A-E", "Sends F-J" ] const forbidenHeights = [79, 61, 23, 16] function main() { //Activate Pro Tools sf.ui.proTools.appActivate(); sf.ui.proTools.invalidate(); //Enable view of Inserts and Sends menus.forEach(enableMenus) sf.ui.proTools.invalidate(); //Get selected tracks const originalTracksH = sf.ui.proTools.selectedTrackHeaders; try { //Do for each track for (var i = 0; i < originalTracksH.length; i++) { const thisTrack = originalTracksH[i] //Select track thisTrack.trackSelect(); //Scroll track into View thisTrack.trackScrollToView(); const thisTracksize = getCurrentTrackHeight(thisTrack) // Resize if needed if (forbidenHeights.includes(thisTracksize.trackHeight)) { setTrackSize("small") } const inactive = getInsertAndSendInfo() removeInactive({ ins_sendInfo: inactive, ignoreInserts: [], ignoreSends: [] }) // Resize if changed if (forbidenHeights.includes(thisTracksize.trackHeight)) { setTrackSize(thisTracksize.trackSize) } }; } finally { //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracksH.map(th => th.normalizedTrackName) }); } }; main()
Ben Rubin @Ben_Rubin
hey @samuel_henriques, thanks for this great script. how would I modify it if i wanted to omit inserts A and J?
thanks much
ben
samuel henriques @samuel_henriques
Hello Ben
Updated above,
Just change line 144
removeInactive({ ins_sendInfo: inactive, ignoreInserts: [], ignoreSends: [] })
toremoveInactive({ ins_sendInfo: inactive, ignoreInserts: ["A", "J"], ignoreSends: [] });
Ben Rubin @Ben_Rubin
thanks so much works great!
- In reply tosamuel_henriques⬆:
Chad Wahlbrink @Chad2023-12-08 17:46:32.618Z
@samuel_henriques - this is one of the most useful scripts on this whole forum!!! Thank you for this. <3
- Rroom1252021 @room1252021
Agreed!
- AIn reply todex_green⬆:Alexis Cuadrado @Alexis_Cuadrado
OMG, This is otherworldly!
THANK YOU! - EIn reply todex_green⬆:Erik Groysman @Erik_Groysman
This is incredible! Is there any way to make this work for 'Micro' and 'Mini' sized tracks?
It doesn't react to those sized tracks.Thank you!!
samuel henriques @samuel_henriques
Not yet, the inserts must be visible so SF can see them and read the info.
But maybe in the future if avid adds the functionality to the SDK.- EErik Groysman @Erik_Groysman
Understood. Is there a way you can make the script check the track size, increase it only if necessary, and then set it back to the previous state?
samuel henriques @samuel_henriques
yes, that would be one solution, let me think about it. I should have some parts of the code for that.
- In reply toErik_Groysman⬆:
samuel henriques @samuel_henriques
UPDATED remove all inactive plugins/sends #post-20
When it need to change size, it will set it back as it was but from the options available on the menuis you are using a size that is in between the menu options, it will choose the most similar menu size.
- EErik Groysman @Erik_Groysman
So cool! Thank you so much! Last thing is, I was using the script at the top of the thread and now I can't figure out the correct/best way to not remove the sends?
samuel henriques @samuel_henriques
on line 222 where it says
ignoreSends
add the send letters you want to ignore. It works for inserts as wellignoreSends: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
- EErik Groysman @Erik_Groysman
Thank you!! I was doing it on line 138!
- SIn reply todex_green⬆:Sean McDonald @Sean_McDonald5
Hi All!
First, thanks for this!secondly...
Ive noticed that in my usage, the script "takes over" the computer.meaning....If I run the SF PT script, then I try to multitask, like compose an email in the Mail app, while the script is running, PT keeps jumping to the front.
hopefully that makes sense.
is this expected behaviour, or is there a work around?
thanks,
Sean- FForrester Savell @Forrester_Savell
Yes this is expected behaviour. Soundflow works by interacting with the ProTools GUI, like an automated user (clicking, typing etc but a lot faster than we can do it!). So you can't multi-task while scripts are running, as SF needs to work with the PT app visible. Some scripts, like this one, will try to ensure the PT window is always visible, hence the switching back to PT all the time. Others, you might have noticed will just fail if you switch away from ProTools, as they can't find the element on the PT window they're trying to interact with.
Hope that helps.
Forrester
- SSean McDonald @Sean_McDonald5
Thanks Forrester,
Totally makes sense.Much appreciated!
- In reply toForrester_Savell⬆:SSean McDonald @Sean_McDonald5
Bonus question!!!!!!
Is it possible to amend this script to "ignore" any instances of Melodyne?
As I like to keep those inactive inserts with the transfer data when Im archiving the session.
thanks again guys!
- SIn reply todex_green⬆:Sean McDonald @Sean_McDonald5
Is it possible to add a "Melodyne Exemption" to the clear all inactive plugs in this otherwise incredible script?
thanks guys!
- FForrester Savell @Forrester_Savell
On line 222 of Samuels script above, there's the option to ignore Inserts. The easiest solution, if possible with your plugin allocations, is you could set your session up so that only Melodyne plugins are placed on the 'a' insert. You then enter 'a' into the ignoreInserts square brackets to tell the script to ignore that insert.
So line 222 would look like this:
removeInactive({ ins_sendInfo: inactive, ignoreInserts: ['a'], ignoreSends: [] })
Of course any other plugins that are inactive on other tracks 'a' insert slot will also be ignored.
Hope that helps.
- SSean McDonald @Sean_McDonald5
Thanks Forrester!!!!
Im gonna dive in and try to change that as you suggested.One other thing Ive noticed is that the complete "removal" is not always successful.
Sometimes the script skips members of a selected group of tracks.
Ive been of the habit off selecting all, getting lunch and coming back to a hopefully cleared out session, but most of the time there are rouge tracks still inactive plugs/ sends.
Any idea why it might be missing some?
THANKS!!
- SSreejesh Nair @Sreejesh_Nair
I’ve had that issue occasionally. The best way is to add an sf.wait for 250 ms. It resolves the problem.
- SSean McDonald @Sean_McDonald5
Thanks!
dumb guy here, can you detail how/ where I would make that change?Thanks Sreejesh!
- FForrester Savell @Forrester_Savell
I've written a script to Batch Remove All Inactive Plugins & Sends: Remove Inactive Inserts or Sends or both #post-6 that you might want to try.
It includes an option to define plugins you want to exclude and its been pretty robust, in that it will do entire sessions without breaking, at least for me.
Keen to hear if anyone else has success with it.- SSean McDonald @Sean_McDonald5
Thanks Forrester,
I installed the script and got this error when I ran it:
what might have I messed up?thanks
- FForrester Savell @Forrester_Savell
Thanks for the info Sean. I've replied and updated script in the forum link above.
- SSean McDonald @Sean_McDonald5
Forrester,
thanks again for this script!
SUCH a time saver.Much appreciated!