How to show specific automation lanes for a plug-in? (Same lanes and plug-in every time)
Hello,
Is there a way to show specific plug-in automation lanes for a selected track?
I have the FabFilter Pro-Q-3 plug on just about every track in every project I do. Part of my workflow involves adjusting Gain and Frequency of Band 1 via track automation (via mouse).

I access the same Band and controls on every track by clicking "show/hide automation lanes" in PT and then selecting those specific lanes. This is a bit maddening, because I have to do it many times when I first set up a session. It's a ton of clicking,
Is there a way to use "Toggle Automation Lanes" (or another command) to show just these two automation lanes?
It'll be the same lanes every time, but on any track in the session.
Best,
-R
- In reply toRob_Byers⬆:Chris Shaw @Chris_Shaw2022-03-22 20:35:24.299Z2022-03-22 20:54:34.962Z
This will toggle the automation lane between band 1 gain and band 1 frequency on the first instance of ProQ-3 on the selected track:
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" sf.ui.proTools.selectedTrack.popupButtons.whoseTitle.is("Track View selector").first.popupMenuSelect({ menuPath: ["*FabFilter Pro-Q 3",setLaneTo], useWildcards: true, });
- In reply toRob_Byers⬆:Ben Rubin @Ben_Rubin
@Chris_Shaw, is there a way to make a script that will show all used automation lanes for a selected track? That could be really helpful to me.
Chris Shaw @Chris_Shaw2022-03-31 02:51:37.823Z
You want to show all the automation lanes in the edit window or a list of all used automation lanes like the above scripts?
Ben Rubin @Ben_Rubin
I'd love to be able to show all of the used automation lanes in the area when you flip the triangle (show/hide automation) on a selected track. So i can see all the automation written to any parameter on a selected track. is that clearer?
Also just grabbed the other automation lane scripts from that other thread. thanks for those!
Chris Shaw @Chris_Shaw2022-03-31 19:41:47.873Z
@Ben_Rubin I'm not sure this is possible. Visually you can tell which lanes have automation on them because the automation name is either orange or in bold type. Unfortunately SF cannot read whether or not the text is bold or orange because PT accessibility / UI doesn't report it.
If you have other ideas… :)
Ben Rubin @Ben_Rubin
I don't but I'l think about it.
- RRob Byers @Rob_Byers
Chris, THANK YOU for investing time in to this riddle. It's good to know it might help others as well!
What Ben is looking for is similar to what I was hoping for, as well — showing used automation lanes.
Actually, my preference would be a macro to show two specific automation lanes for the selected track (always the same two lanes) — FabFilter ProQ3 Band 1 Gain and Band 1 Frequency. Do you think that is possible?
Chris Shaw @Chris_Shaw2022-04-02 17:17:19.066Z
Hey @Rob_Byers ,
With a lot of help from @Kitch I was able to throw this together. To change the plugin and the automation lanes you want to show just edit the first two variables in the script. (Note, as written below it will open lanes for three parameters).
Two things to keep in mind:
- only run the script once. Repeated use on the same track(s) will just add other random automation lanes.
- It will only show these lanes for the first instance of the plugin.
const pluginName = "FabFilter Pro-Q 3" const laneSelectorNames = ["Band 1 Gain", "Band 1 Frequency","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.invalidate().children.whoseTitle.endsWith("Automation Lane") .filter(f => f.title.invalidate().value.indexOf(trackName) >= 0); //Set the first automation lane to the first available plug-in parameter. 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++) { openAutomationLanes({ trackName: track.normalizedTrackName, laneIndex: i, pluginName, laneSelectorName: laneSelectorNames[i], }); 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(); } } }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); } main();
- RRob Byers @Rob_Byers
@Chris_Shaw and @Kitch thank you so much! This is exactly what I was hoping for.
I see what you mean about the random behavior when using the command twice. Noted!
I'm going to dig in to this a bit and see if it can be tweaked to add an additional lane from another plugin (Ozone Imager).
This is really, really great. Another example of Soundflow pulling through for its users. Thank you.
-R
Chris Shaw @Chris_Shaw2022-04-03 18:28:36.325Z
Just replace the plugin name and parameters in the first couple of lines of code.
Glad it works.
- SSeàn Frost @Sean_Frost9
Hi Chris, I've just stumbled across this script and it looks really close to what I'm after. I had a go myself at modifying this to use with Slate Digital MetaTune, but couldn't get the behaviour I expected, maybe you can point me in the right direction.
I assumed i could change the parameters at the top to be:
const pluginName = "MetaTune"
const laneSelectorNames = ["Speed", "C", "C#", "D", "D#", "E", "F", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B" ];It half works, but this just brings up 3 lanes for "speed, stabilize note, and C", and note the parameters i added above.
I knew it couldn't be that easy but I had hoped!
What should I be doing instead to make this script work for me?Many thanks in advance!
Chris Shaw @Chris_Shaw2022-09-26 19:39:00.748Z
Hey @Sean_Frost9 ,
You were almost there but you didn't spell all of the automation lane names properly.
try using this instead:const pluginName = "MetaTune" const laneSelectorNames = ["C", "C#/Db", "D", "D#", "E", "F", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb", "B", "Speed"];
Chris Shaw @Chris_Shaw2022-09-26 20:05:16.986Z
Remember - The automation lane names must match the names of a plug-in's automation names:
- In reply toRob_Byers⬆:Linus Gidstedt @Linus_Gidstedt
This is an awesome script! But it keeps breaking when it reaches the track at the bottom of the screen. It seems like it won't scroll the selected track into view. Any thought on what might be wrong?
Linus Gidstedt @Linus_Gidstedt
Changing
track.trackScrollToView();
to
//Scroll track into View track.titleButton.popupMenuSelect({ isRightClick: true, menuPath: ['Scroll Into View'] });
works much better. Can someone explain why? What is
trackScrollToView()
actually doing?
- In reply toRob_Byers⬆:Linus Gidstedt @Linus_Gidstedt
Hi @Kitch and @Chris_Shaw!
I have used a modified version of this script that has worked perfectly until recently and I can't figure out what is wrong. I receive different error messages but mainly this one20.02.2025 09:38:33.18 [Backend]: Logging unknown error in action (02) RunCommandAction: Add automation lanes: Line 96
!! Command Error: FabFilter Pro-Q 3 Hi/Low-cut [user:cl8xixz1k0003pc10laehwxw9:clau99uxz00003k10e2ohewuz#clawyqcaq00033k106c5tqgma]:
ClickButtonAction requires UIElement
Couldn't get item #0 as the array's parent node wasn't found - sf.ui.app('com.avid.ProTools')..groups.whoseTitle.is('SFX 5.1A - Audio Track - volume Automation Lane').first.buttons (AxElementArrayIndexedItem)It is very intermittent and the script always works the second time I run it on the same track or if the first Automation lane is already correct. I don't know if it can be a problem related to folder tracks, an invalidation problem or something Avid changed in Pro Tools?
Here is the whole script
sf.ui.proTools.appActivateMainWindow(); const { pluginName, laneSelectorNames } = event.props; //Set Scroll Into View Key Command const scrollIntoView = () => sf.keyboard.press({ keys: "shift+ctrl+option+command+s" }); /* function scrollIntoView() { sf.ui.proTools.selectedTrack.titleButton.popupMenuSelect({ isRightClick: true, menuPath: ["Scroll Into View"], }) } */ 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 }) { //First 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 plug-in parameter. automationLane[laneIndex].popupButtons.whoseTitle.is('Lane view selector').first.popupMenuSelect({ menuSelector: items => items.find(item => item.path[0].endsWith(pluginName) && item.path[1] === laneSelectorName), onError: "Continue" }); } /** * @param {AxPtTrackHeader} track */ 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() { //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; const originalFirstTracks = [originalTracks[0]]; //Invalidate Pro Tools main window. sf.ui.proTools.mainWindow.invalidate(); //Scroll first selected track into view sf.ui.proTools.trackSelectByName({ names: originalFirstTracks }); sf.ui.proTools.selectedTrack.trackScrollToView(); sf.ui.proTools.trackSelectByName({ names: originalTracks }); //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(); scrollIntoView(); var removeLnBtn = getAutomationLanes(track); sf.ui.proTools.mainWindow.invalidate().groups.whoseTitle.is(removeLnBtn[0].title.value).first.buttons.whoseTitle.is("Remove this automation lane").first.elementClick(); //Fetch track title //let selectedTrackTitle = track.title.invalidate().value; //Select lanes for (var i = 0; i < laneSelectorNames.length; i++) { openAutomationLanes({ trackName: track.normalizedTrackName, laneIndex: i, pluginName, laneSelectorName: laneSelectorNames[i], }); 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(); } } }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalFirstTracks }); scrollIntoView(); sf.ui.proTools.trackSelectByName({ names: originalTracks }); sf.ui.proTools.selectedTrack.children.whoseTitle.is('Show/hide automation lanes').first.mouseClickElement({ isShift: true, isOption: true, }); } main();
Linus Gidstedt @Linus_Gidstedt
I got it to work by adding a wait right before adding a new automation lane
sf.wait({ intervalMs: 100 }); if (i != laneSelectorNames.length - 1) { var addLnBtn = getAutomationLanes(track) sf.ui.proTools.mainWindow.invalidate().groups.whoseTitle.is(addLnBtn[i].title.value).first.buttons.whoseTitle.is("Add automation lane below this one").first.elementClick(); }
Is there a better way to handle this?
- In reply toRob_Byers⬆:Linus Gidstedt @Linus_Gidstedt
Another question: Is there a way to check if the plugin exists as an insert before trying to select automation lanes? And skip that track if it doesn't exist.