Hello,
Is here a way to script a toggle of automation lane to show only the available sends?
a adaptation of this, i guess:
https://forum.soundflow.org/-1750
Thank you so much
- samuel henriques @samuel_henriques
Any ideas for this?
Christian Scheuer @chrscheuer2020-08-27 09:23:40.174Z
Try this:
function showAutomationLanes() { function getLanes() { return sf.ui.proTools.mainWindow.children.invalidate().whoseTitle.endsWith("Automation Lane").filter(f => f.title.value.indexOf(selectedTrackTitle) === 0); } var selectedTrackTitle = sf.ui.proTools.selectedTrack.title.invalidate().value; var originalLaneCount = getLanes().length; if (originalLaneCount == 0) { sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first.elementClick(); var i = 0; while (getLanes().length == originalLaneCount) { sf.wait({ intervalMs: 100 }); if (++i >= 20) throw "Could not show automation lanes"; } } } function addAutomationLane() { function getLanes() { return sf.ui.proTools.mainWindow.children.invalidate().whoseTitle.endsWith("Automation Lane").filter(f => f.title.value.indexOf(selectedTrackTitle) === 0); } var selectedTrackTitle = sf.ui.proTools.selectedTrack.title.invalidate().value; var lanes = getLanes(); var originalLaneLength = lanes.length; if (originalLaneLength == 4) return false; var i = 0; while (lanes.length == originalLaneLength) { var couldAdd = lanes.some(lane => { var addBtn = lane.children.whoseTitle.is('Add automation lane below this one').first; if (addBtn.exists) { addBtn.elementClick(); return true; } }); if (couldAdd) return true; sf.wait({ intervalMs: 100 }); lanes = getLanes(); if (++i >= 20) throw "Could not add automation lane"; } } function showAllAutomationLanes() { showAutomationLanes(); addAutomationLane(); addAutomationLane(); addAutomationLane(); } function assignAutomationLanesToSends() { function getLanes() { return sf.ui.proTools.mainWindow.children.invalidate().whoseTitle.endsWith("Automation Lane").filter(f => f.title.value.indexOf(selectedTrackTitle) === 0); } var selectedTrackTitle = sf.ui.proTools.selectedTrack.title.invalidate().value; var lanes = getLanes(); lanes.sort((a, b) => a.frame.y - b.frame.y); var sendNames = ['a', 'b', 'c', 'd', 'e']; for (var i = 0; i < lanes.length; i++) { let lane = lanes[i]; lane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.filter(item => { var m = item.path[0].match('\\(snd ' + sendNames[i] + '\\)'); if (!m) return false; return item.path[1] === 'level'; })[0], }); } } showAllAutomationLanes(); assignAutomationLanesToSends();
samuel henriques @samuel_henriques
Hello and thank you,
I changed it so it only opens one automation lane and works if the send is on a. And doesn't toggle though. But if you could change it to to it on all selected tracks, I can use this script once and then use the toggle view after that.
I'm only using one send per track in this case, on different sends, for example dialog a, music b....function showAllAutomationLanes() { showAutomationLanes();
I just deleted the "addAutomationLane" lines
Thank you so much
Christian Scheuer @chrscheuer2020-08-27 11:13:19.762Z
Hi Samuel,
I may have misunderstood what you wanted the script to do. Can you clarify in even more detail what the behavior is that you're looking for?
You said "sends" in plural, so I assumed you wanted it to show all send automation lanes for the selected track - but it appears you want to show only 1 send but for multiple tracks - and you don't want it to open the extra automation lane, you just want it to work like toggling volume? Or do you want it to open extra automation lanes?samuel henriques @samuel_henriques
Hey Christian,
Sorry I didn't explain well.I'm only using one send on each track, but some tracks I use send a other b, or c...Its just organisation for me.
I would like to toggle the automation view and see the volume of the send only.
Because I'm using only one send, only one line will show. But I don't ming to see the volume of the other send in the case they exist.
This might be to complicated and impractical to use if its a series of menu-sub menu thing, so, If I could make all selected tracks change from showing fader volume ( the default automation view) to the volume of any available send (in my case only one is available),
I would use that script once, and then case by case as I need, I can toggle show automation lanes, and only send volume will be showing.
Thats because pro tools won't change them all if I press alt+click the automation lane I want...Hope it's clearer and thank you very much fo the patience
Christian Scheuer @chrscheuer2020-08-27 12:49:38.932Z
Thank you for this further explanation.
So, if I understand you correctly, it should do this:- For each selected track, swap the automation view to view the send level for the first send that is assigned on the track.
samuel henriques @samuel_henriques
Yes, automation view on the automation lanes.
sounds great.....hope its not a big headache
Christian Scheuer @chrscheuer2020-08-27 14:30:39.398Z
What do you mean by automation view on the automation lanes?
Christian Scheuer @chrscheuer2020-08-27 14:33:58.280Z
I think I need a couple of screenshots of what you mean to be sure.
- In reply tochrscheuer⬆:
samuel henriques @samuel_henriques
again, sorry for poor explanation
Automation on the Lane view selector
Thank you
Christian Scheuer @chrscheuer2020-08-27 14:39:25.985Z
Gotcha, thank you for clarifying. And when you talked about toggle behavior, what did you mean by that?
samuel henriques @samuel_henriques
this will toggle Show/ hide of automation lanes
sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first.elementClick();
Instead of fader volume, witch is PT default, I'd like to see the send volume
At this stage it looks easier just to change all tracks to have send volume, and then as need access, I'll show/hide automation lane with the command
Kitch Membery @Kitch2020-08-29 00:06:20.800Z
Is this the kind of thing you are after @samuel_henriques?
@chrscheuer's script is way cooler but this should get the job done for what I think you are after.
My script does the following;
- Opens the the automation lanes for each of the selected tracks.
- Toggle the lane view between the first instantiated send on the track & the track volume (per track).
- Repeats step 2 for all selected tracks.
- Restores original track selection.
function showAutomationLanes() { //If any automation lane for selected tracks are hidden, show them. const showAutomationLaneBtn = sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first; if (showAutomationLaneBtn.value.invalidate().value !== "Selected") { showAutomationLaneBtn.mouseClickElement({ isShift: true, isOption: true, }); } else { showAutomationLaneBtn.mouseClickElement(); showAutomationLaneBtn.mouseClickElement({ isShift: true, isOption: true, }); } } function main() { //Invalidate Pro Tools main window. sf.ui.proTools.mainWindow.invalidate(); //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Scroll first selected track to into view sf.ui.proTools.selectedTrack.trackScrollToView(); //Show automation Lanes showAutomationLanes(); //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); //Fetch track title let selectedTrackTitle = track.title.invalidate().value; //Fist automation lane on selected track let automationLane = sf.ui.proTools.mainWindow.children.whoseTitle.endsWith("Automation Lane").filter(f => f.title.invalidate().value.indexOf(selectedTrackTitle) === 0)[0]; const currentVisibleLane = automationLane.popupButtons.whoseTitle.is('Lane view selector').first.value.invalidate().value; //String to identify sends. const sendSearchString = '(snd '; //Toggle between 'volume' and 'send' (first available send). if (automationLane.popupButtons.whoseTitle.is('Lane view selector').first.value.invalidate().value !== "level") { automationLane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.filter(item => item.path[0].indexOf(sendSearchString) >= 0)[0], onError: 'Continue', }); } else { automationLane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuPath: ['volume'], }); } }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); } main();
The send/volume toggle behavior may not be what you want but that can be adjusted.
Rock on!
samuel henriques @samuel_henriques
Hello Kitch,
This works great, the toggle I meant was open and close view, but this works as well.
This way I can make the automation line of the send on all tracks and then I use the Show/Hide command on a key, and the send line is always there.Awesome work!!
Thank you so much.Kitch Membery @Kitch2020-08-29 09:21:42.574Z
Great... Glad I could help.
You can easily remove the toggle function by replace this part;
//Toggle between 'volume' and 'send' (first available send). if (automationLane.popupButtons.whoseTitle.is('Lane view selector').first.value.invalidate().value !== "level") { automationLane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.filter(item => item.path[0].indexOf(sendSearchString) >= 0)[0], onError: 'Continue', }); } else { automationLane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuPath: ['volume'], }); }
With this;
//Set the first automation lane to the first available 'send'. automationLane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.filter(item => item.path[0].indexOf(sendSearchString) >= 0)[0], onError: 'Continue', });
:-)
Kris Crunk @Kris_Crunk
Can the above code be edited so when I click on a button for one or multiple instrument tracks the mod wheel lane opens?
Kitch Membery @Kitch2021-01-30 04:57:09.883Z
Will take a look this weekend @Kris_Crunk. :-)
- In reply toKris_Crunk⬆:
Kitch Membery @Kitch2021-01-30 11:42:37.850Z
Here ya go @Kris_Crunk :-)
function showAutomationLanes() { //If any automation lane for selected tracks are hidden, show them. const showAutomationLaneBtn = sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first; if (showAutomationLaneBtn.value.invalidate().value !== "Selected") { showAutomationLaneBtn.mouseClickElement({ isShift: true, isOption: true, }); } else { showAutomationLaneBtn.mouseClickElement(); showAutomationLaneBtn.mouseClickElement({ isShift: true, isOption: true, }); } } function main() { //Invalidate Pro Tools main window. sf.ui.proTools.mainWindow.invalidate(); //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Scroll first selected track to into view sf.ui.proTools.selectedTrack.trackScrollToView(); //Show automation Lanes showAutomationLanes(); //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); //Fetch track title let selectedTrackTitle = track.title.invalidate().value; //Fist automation lane on selected track let automationLane = sf.ui.proTools.mainWindow.children.whoseTitle.endsWith("Automation Lane").filter(f => f.title.invalidate().value.indexOf(selectedTrackTitle) === 0)[0]; let laneSelectorString = 'mod wheel'; //Select lane automationLane.popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.filter(i => i.path[0].indexOf('controllers') >= 0 && i.path[1].split(' (').slice(0, -1).join() === laneSelectorString)[0], }); }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); } main();
Let me know if it works for you. :-)
Kris Crunk @Kris_Crunk
Awesome thanks so much!
- In reply toKitch⬆:
Chris Shaw @Chris_Shaw2022-04-01 20:48:34.573Z
@Kitch,
I'm tryin to modify your script to show specific lanes for a specific plugin. THis is what I got so far (there's a bunch of logging as well). The first iteration of the loop works but fails afterwards. I'm invalidating but i can't get SF to click the popup of the new lane created by a previous Add Lane button click.
I'm sure it's something silly:function showautomationLaness() { //If any automation lane for selected tracks are hidden, show them. const showautomationLanesBtn = sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first; if (showautomationLanesBtn.value.invalidate().value !== "Selected") { showautomationLanesBtn.mouseClickElement({ isShift: true, isOption: true, }); } else { showautomationLanesBtn.mouseClickElement(); showautomationLanesBtn.mouseClickElement({ isShift: true, isOption: true, }); } } function main() { //Invalidate Pro Tools main window. sf.ui.proTools.mainWindow.invalidate(); //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Scroll first selected track to into view sf.ui.proTools.selectedTrack.trackScrollToView(); //Show automation Lanes showautomationLaness(); //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); // Get add lane Button for track function getLanes() { return sf.ui.proTools.mainWindow.children.invalidate().whoseTitle.endsWith("Automation Lane").filter(f => f.title.value.indexOf(track.title.value) === 0); } //Scroll track into View track.trackScrollToView(); //Fetch track title let selectedTrackTitle = track.title.invalidate().value; let pluginName = "FabFilter Pro-Q 3" let laneSelectorNames = ["Band 1 Gain", "Band 2 Gain", "Band 1 Frequency", "Band 5 Gain"]; //Select lanes for (var i = 0; i < laneSelectorNames.length; i++) { log("loop#: ", i) //Current automation lane on selected track let automationLanes = sf.ui.proTools.mainWindow.invalidate().children.whoseTitle.endsWith("Automation Lane").filter(f => f.title.invalidate().value.indexOf(selectedTrackTitle) === 0); log(automationLanes) log(laneSelectorNames[i]) log("Trying to select popoup at: ", automationLanes[i]) automationLanes[i].popupButtons.whoseTitle.is('Lane view selector')[i].popupMenuSelect({ menuPath: ["*"+pluginName, laneSelectorNames[i]], useWildcards: true }); log("Lane Selected") sf.wait({ intervalMs: 1000 }) if (i != laneSelectorNames.length - 1) { var addLnBtn = getLanes() log(addLnBtn[0].title.value) sf.ui.proTools.mainWindow.invalidate().groups.whoseTitle.is(addLnBtn[0].title.value).first.buttons.whoseTitle.is("Add automation lane below this one").first.elementClick(); automationLanes = null } log("End Of loop ", i) } }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); } main(); // const currentLane = sf.ui.proTools.selectedTrack.popupButtons.whoseTitle.is("Track View selector").first.value.invalidate().value // var setLaneTo = (currentLane.includes("Gain"))? "Band 1 Frequency" : "Band 1 Gain" // log (setLaneTo) // sf.ui.proTools.selectedTrack.popupButtons.whoseTitle.is("Track View selector").first.popupMenuSelect({ // menuPath: ["*FabFilter Pro-Q 3",setLaneTo], // useWildcards: true, // });
Kitch Membery @Kitch2022-04-01 20:50:22.208Z
Chris Shaw @Chris_Shaw2022-04-01 20:54:06.875Z
No rush. Just helping a user.
- In reply toChris_Shaw⬆:
Kitch Membery @Kitch2022-04-01 22:59:21.939Z
@Chris_Shaw, Legend!
Here you go... :-)
const pluginName = "FabFilter Pro-Q 3" const laneSelectorNames = ["Band 1 Gain", "Band 2 Gain"]; function showautomationLaness() { //If any automation lane for selected tracks are hidden, show them. const showautomationLanesBtn = sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first; if (showautomationLanesBtn.value.invalidate().value !== "Selected") { showautomationLanesBtn.mouseClickElement({ isShift: true, isOption: true, }); } else { showautomationLanesBtn.mouseClickElement(); showautomationLanesBtn.mouseClickElement({ isShift: true, isOption: true, }); } } function openAutomationLanes({ trackName, laneIndex, pluginName, laneSelectorName }) { //Fist automation lane on selected track let automationLane = sf.ui.proTools.mainWindow.children.whoseTitle.endsWith("Automation Lane") .filter(f => f.title.invalidate().value.indexOf(trackName) === 0); //Set the first automation lane to the first available 'send'. automationLane[laneIndex].popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.find(item => item.path[0].endsWith(pluginName) && item.path[1] === laneSelectorName), }); } function getAutomationLanes(track) { return sf.ui.proTools.mainWindow.children.invalidate().whoseTitle.endsWith("Automation Lane").filter(f => f.title.value.indexOf(track.title.value) === 0); } function main() { //Invalidate Pro Tools main window. sf.ui.proTools.mainWindow.invalidate(); //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Scroll first selected track to into view sf.ui.proTools.selectedTrack.trackScrollToView(); //Show automation Lanes showautomationLaness(); //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); //Fetch track title let selectedTrackTitle = track.title.invalidate().value; //Select lanes for (var i = 0; i < laneSelectorNames.length; i++) { //Current automation lane on selected track. let automationLanes = sf.ui.proTools.mainWindow.invalidate().children.whoseTitle.endsWith("Automation Lane").filter(f => f.title.invalidate().value.indexOf(selectedTrackTitle) === 0); openAutomationLanes({ trackName: track.normalizedTrackName, laneIndex: i, pluginName, laneSelectorName: laneSelectorNames[i], }); sf.wait({ intervalMs: 1000 }) if (i != laneSelectorNames.length - 1) { var addLnBtn = getAutomationLanes(track) sf.ui.proTools.mainWindow.invalidate().groups.whoseTitle.is(addLnBtn[0].title.value).first.buttons.whoseTitle.is("Add automation lane below this one").first.elementClick(); automationLanes = null } } }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); } main();
It could use some improvement but this should do the trick. :-)
Rock on!
Chris Shaw @Chris_Shaw2022-04-01 23:49:39.491Z
Getting an error at the moment:
01.04.2022 18:48:43.10 <info> [Backend]: JavaScript error with InnerException: null !! Command Error: test3 [user:cki0lfpum0002hx10oh37c1m2:cl1ci6hk70000jd10lcuudrq7]: TypeError: Cannot read property 'popupButtons' of undefined (test3 line 27)
I'll sort it tomorrow.
Thanks!Kitch Membery @Kitch2022-04-02 00:24:04.642Z
Weird... Let me know how you go with it. It's working for me.
Chris Shaw @Chris_Shaw2022-04-02 17:01:36.018Z
It only seems to work on my end if I get rid of the filtering in the first part of this function:
function openAutomationLanes({ trackName, laneIndex, pluginName, laneSelectorName }) { //Fist automation lane on selected track let automationLane = sf.ui.proTools.mainWindow.invalidate().children.whoseTitle.endsWith("Automation Lane") .filter(f => f.title.invalidate().value.indexOf(trackName) === 0); //Set the first automation lane to the first available 'send'. automationLane[laneIndex].popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.find(item => item.path[0].endsWith(pluginName) && item.path[1] === laneSelectorName), }); }
If I put
log (automationLane[0])
after the first line (after the filtering) it returns[]
Chris Shaw @Chris_Shaw2022-04-02 17:08:29.783Z
Aha!. Partially my fault - I didn't have band2 gain set for automation on ProQ3.
Also, changing the filter function slightly seems to make it more stable:
.filter(f => f.title.invalidate().value.indexOf(trackName) === 0);
is now:
.filter(f => f.title.invalidate().value.indexOf(trackName) >= 0);
Chris Shaw @Chris_Shaw2022-04-02 17:10:43.345Z
Thanks for your help!🙌
//CS//
Kitch Membery @Kitch2022-04-02 17:14:18.406Z
Nice one. Glad to help brother!
- In reply toChris_Shaw⬆:
Kitch Membery @Kitch2022-04-02 17:11:51.533Z
Ah yeah cool. I see that may be causing a problem. I’m away from the studio right now will take a look this afternoon :-)
- In reply toKitch⬆:CChristopher Cleator @Christopher_Cleator
Hey @kitch I know it’s an older script, but it’s a great one. Thanks! I just have one question.. I’ve made 5 stream deck buttons to correspond to showing each Send level from A-E, and have changed the else ‘volume’ in the toggle function to ‘hide all automation lanes’. Basically makes a show/hide button for each send level lane. I’m wondering though, if there might be a way that by pressing Send B level when Send A level is currently open, it could simply switch between sends, rather than hide the first and then have to press again to get send B level. Or even better yet.. If Send A lane is open, then add Send B under Send A. Hope that makes sense.
Kitch Membery @Kitch2025-05-08 18:45:29.802Z
Great idea!
This would require a more in-depth script, I'll endeavor to work out a solution for this next week sometime. :-)