Title
Popupsearch disappears
What do you expect to happen when you run the script/macro?
Script (written by Kitch), should take the output paths from a selected track and present them in the popupsearch
Everything appears to work except the popupsearch window disappears as soon as it is opened, preventing selection of an 'outputPath'.
Have tried invalidating in numerous spots but can't seem to get the popupsearch window to stay visible.
Are you seeing an error?
What happens when you run this script?
popupsearch window should allow for selection of an output
instead popupwindow appears momentarily (looks like it is displaying the stored outputs), but disappears before menu selection is possible
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": "Script (written by Kitch), should take the output paths from a selected track and present them in the popupsearch\n\nEverything appears to work except the popupsearch window disappears as soon as it is opened, preventing selection of an 'outputPath'.\n\nHave tried invalidating in numerous spots but can't seem to get the popupsearch window to stay visible.",
"inputIsError": false,
"inputWhatHappens": "popupsearch window should allow for selection of an output\n\ninstead popupwindow appears momentarily (looks like it is displaying the stored outputs), but disappears before menu selection is possible",
"inputHowRun": {
"key": "-MpfwYA4I6GGlXgvp5j1",
"title": "I clicked the \"Run Script\" or \"Run Macro\" button in SoundFlow"
},
"inputImportance": 5,
"inputTitle": "Popupsearch disappears"
}
Source
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.mainWindow.invalidate();
const menuItems = sf.ui.proTools.selectedTrack.outputPathButton.popupMenuFetchAllItems({ dismissMenu: true, }).menuItems
const outputPaths = menuItems
.filter(outputs => outputs.path[0] === "bus" || outputs.path[0] === "output")
.map(output => ({
name: output.path.join(" → "),
path: output.path,
}));
const selectedOutputPath = sf.interaction.popupSearch({
title: "Which Output would you like to add to?",
items: outputPaths,
}).item.path;
log(selectedOutputPath);
Links
User UID: sKu19XXNXHYSdEMmZtHz8CozbdS2
Feedback Key: sffeedback:sKu19XXNXHYSdEMmZtHz8CozbdS2:-NfKf2DouZ5tIiLYVY4L
Feedback ZIP: oGsS7wjWTjTeaRjWZR12IUcyW0+a5nqy7PuDqIqRjXz0S5YuHuNCTINS5YfTl0zSaifYdk8tftmoI0id72IAFRKQgSBE4szB/pDScrfueQhUVpoTiZdItlNsM5x5g6IUMUKgj4+yRp+UQg+fkh1cxSLCKjztmOYnK/wUfuf1m+rWv1w9mkfakohFc94tdU42v4Ym3DaWVRN3CBw/TVcuVdx8I1Ix8rgJhClj9y2pmlrfaC7RNb9K8EDfv2LwUvbwNAgfOrR6MRvfMYctIKtGdszl9EbvspcEpgd0SYTYUvWWo+TGTlCx5QuyIK4RP/8v3XmFtZgG2nfBc6/6P/EFrcrpUl4nLeeE6wTx7ufFhTo=
Linked from:
Chad Wahlbrink @Chad2023-09-27 13:08:17.494Z2023-09-27 21:53:49.310ZHey @Forrester_Savell!
The script you provided does not seem to include the step of selecting the output from the output path button. Try this script:sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); const menuItems = sf.ui.proTools.selectedTrack.outputPathButton.popupMenuFetchAllItems().menuItems const outputPaths = menuItems .filter(outputs => outputs.path[0] === "bus" || outputs.path[0] === "output") .map(output => ({ name: output.path.join(" → "), path: output.path, })); const selectedOutputPath = sf.interaction.popupSearch({ title: "Which Output would you like to add to?", items: outputPaths, }).item.path; //Get focus back sf.wait({ intervalMs: 50 }); sf.ui.proTools.appActivate(); sf.wait({ intervalMs: 50 }); sf.ui.proTools.selectedTrack.trackOutputSelect({ outputPath: selectedOutputPath, selectForAllSelectedTracks: true });
In reply toForrester_Savell⬆:Chad Wahlbrink @Chad2023-09-27 13:11:53.897ZAlso, I'd be curious if you can get the intended result from the built-in SoundFlow Action under Pro Tools > Track Input, Output & Pan > Select Track Output (Search)

- FIn reply toForrester_Savell⬆:Forrester Savell @Forrester_Savell
Hi @Chad
Thanks for looking into this.
Still getting the same issue with your script, the popup window disappears straight away. I was calling theselectedOutputPathin a larger script, this was just running as a function.The Pro Tools > Track Input, Output & Pan > Select Track Output (Search) macro works great, except it includes a bunch of information I don't want, like 'track'. The window does stay visible though.
Is there a way to truncate the results of
trackOutputSearch(), like I was doing in my first script?Forrester
Chad Wahlbrink @Chad2023-09-27 20:28:44.264Z@Forrester_Savell, I'm having trouble replicating this on my system. To clarify, the SF interaction popup is the one disappearing straight away? Or is the popup from the output selector disappearing?
A few other things – can we have you update SoundFlow to 5.4.8 here: https://my.soundflow.org/install
Then, can you try running this shorter snippet:sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); const menuItems = sf.ui.proTools.selectedTrack.outputPathButton.popupMenuFetchAllItems({ dismissMenu: true, }).menuItems const outputPaths = menuItems .filter(outputs => outputs.path[0] === "bus" || outputs.path[0] === "output") .map(output => ({ name: output.path.join(" → "), path: output.path, })); log(outputPaths);Does this appear to log your outputs as an array of objects? That may help us troubleshoot why the interaction popup may be failing.
To access the full log, you can click "open log" here:
- FForrester Savell @Forrester_Savell
Hey @Chad
So I was making a video to show you exactly what was happening and I've found the window disappearing issue is related to mouse position or possibly mouse movement. If I run the command and move the mouse around over where the menu appears, I can get the window to stay visible.
We're talking about the SF interaction popup window, you'll see in the video. The video shows me experimenting with where I place the mouse. On subsequent tries, there doesn't seem to be a specific mouse position, just that it is actively moving over the window menu allows it to stay open.
Video also shows the array of objects as expected, plus the full selection of outputs display correctly when the window remains open.
https://forrestersavell.filemail.com/d/xmkzgkbkldqdhak
Let me know if you need any info from the full log. I see this written a bit, not sure if relevant
"28.09.2023 07:18:01.64 [Backend]: Throwing error from cancellation in action (00) PopupAction
Throwing error from cancellation in action (00) PopupSearchAction28.09.2023 07:18:01.64 [Application]: this.popupWindow.on(hide)"
- FForrester Savell @Forrester_Savell
I've updated to SF 5.4.8 and the behaviour is the same.
- In reply toForrester_Savell⬆:
Chad Wahlbrink @Chad2023-09-27 21:53:07.147ZHey @Forrester_Savell,
I'm sorry you are seeing this issue persist! I'm curious to try this other version of the script. This is the one that I have used personally for the last couple of years. Just a slight tweak on the approach overall:if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); function outputSearch() { let outputPathButton = sf.ui.proTools.selectedTrack.outputPathButton; // Fetch all menu items let items = outputPathButton.popupMenuFetchAllItems().menuItems.map(function (item) { return { name: item.names.join(' > '), path: item.names }; }); let filteredResults = items.filter(function (str) { return !str.name.includes('track'); }); // Search let chosenPath = sf.interaction.popupSearch({ items: filteredResults, title: 'Search for a Track Output', }).item.path; //Get focus back sf.wait({ intervalMs: 100 }); sf.ui.proTools.appActivate(); sf.wait({ intervalMs: 50 }); // Select Chosen Path sf.ui.proTools.selectedTrack.trackOutputSelect({ outputPath: chosenPath, selectForAllSelectedTracks: true }); sf.ui.proTools.invalidate(); } outputSearch();- FForrester Savell @Forrester_Savell
Hi @Chad
Can you help me understand how to remove the 'path' from the list of outputs that this script creates (i.e. remove the 'bus -> bus menu 1-128 ->' part). I would like the list to display the final output or bus names with the (Mono) or (Stereo), but without the path cluttering the list.
When I go back to basics and just to either remove the name or the path, I get errors in the popupSearch.
if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); function outputSearch() { let outputPathButton = sf.ui.proTools.selectedTrack.outputPathButton; // Fetch all menu items let items = outputPathButton.popupMenuFetchAllItems().menuItems.map(item => item.path) //.map(function (item) { /* return { name: item.names.join(' > '), path: item.names }; }); */ log (items) //let filteredResults = items.filter(function (str) { return !str.path.includes('track'); }); // Search let chosenPath = sf.interaction.popupSearch({ items: items, title: 'Search for a Track Output', }).item.path; //Get focus back sf.wait({ intervalMs: 100 }); sf.ui.proTools.appActivate(); sf.wait({ intervalMs: 50 }); // Select Chosen Path sf.ui.proTools.selectedTrack.trackOutputSelect({ outputPath: chosenPath, selectForAllSelectedTracks: true }); sf.ui.proTools.invalidate(); } outputSearch();
Chad Wahlbrink @Chad2024-06-17 14:39:55.967ZHey @Forrester_Savell!
The reason you are seeing errors is that thesf.interaction.popupSearch()command is set up to search an object with a property calledname. In your version of the script above, when you are mapping.map(item => item.path), you are taking an array of objects (the output of.popupMenuFetchAllItems().menuItemsis an array of objects) and converting it to an array of arrays. This is because thepathproperty of themenuItemsobject you get from.popupMenuFetchAllItems().menuItemsis an array.
The original code maps the array ofmenuItemsobjects to a new array of objects with two properties,nameandpath. The critical part of mapping an array for a SoundFlow popupsearch is having anameproperty. If thesf.interaction.popupSearch()command is called on an array of objects that do not have thenameproperty, it will fail and error out. This is just how that specific function was setup in SoundFlow, but it does explain why you would see errors if you are attempting to feedsf.interaction.popupSearch()an array of arrays, instead of an array of objects with thenameproperty.
I hope that makes sense! If you are interested in learning more about array and object data types, I'd suggest watching some of Steve Griffith's Javascript videos on YouTube:- In reply toForrester_Savell⬆:
Chad Wahlbrink @Chad2024-06-17 14:41:40.913Z@Forrester_Savell, here's a script that should work as you are expecting:
if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); function outputSearch() { let outputPathButton = sf.ui.proTools.selectedTrack.outputPathButton; // Fetch all menu items let items = outputPathButton.popupMenuFetchAllItems().menuItems.map(function (item) { return { name: item.names[item.names.length - 1], path: item.path }; }); let filteredResults = items.filter(function (str) { return !str.path.includes('track'); }); // Search let chosenPath = sf.interaction.popupSearch({ items: filteredResults, title: 'Search for a Track Output', }).item.path; //Get focus back sf.wait({ intervalMs: 100 }); sf.ui.proTools.appActivate(); sf.wait({ intervalMs: 50 }); // Select Chosen Path sf.ui.proTools.selectedTrack.trackOutputSelect({ outputPath: chosenPath, selectForAllSelectedTracks: true }); sf.ui.proTools.invalidate(); } outputSearch();
Chad Wahlbrink @Chad2024-06-17 14:51:02.397ZThe part that filters the name to just the actual output name is line 12.
item.names[item.names.length - 1]The output of
popupMenuFetchAllItems().menuItemsis an array of objects with the propertiesPath,Names,Delimiter, andElement. When I run:log(sf.ui.proTools.selectedTrack.outputPathButton.popupMenuFetchAllItems().menuItems)I get an array like this:
[{ "Path": [ "output", "A VIRTUAL 1-2 (Stereo) -> VIRTUAL 1-2" ], "Names": [ "output", "A VIRTUAL 1-2 (Stereo) -> VIRTUAL 1-2" ], "Delimiter": " -> ", "Element": "{\"title\":\"A VIRTUAL 1-2 (Stereo) -> VIRTUAL 1-2\",\"role\":\"AXMenuItem\",\"fullRole\":\"AXMenuItem\"}" }, { "Path": [ "output", " A VIRTUAL 1 (Mono)" ], "Names": [ "output", " A VIRTUAL 1 (Mono)" ], "Delimiter": " -> ", "Element": "{\"title\":\" A VIRTUAL 1 (Mono)\",\"role\":\"AXMenuItem\",\"fullRole\":\"AXMenuItem\"}" }, ... ... ... ... ]So when I map this array of objects with 4 properties to a new array of objects with just two properties,
nameandpath, I'm usingitem.names[item.names.length - 1]to assign the last slot of each array of "names" to the name prop and then leave the path intact so that I can call it later in line 23 when I've selected the object I want to route to.
This kind of manipulation gets slightly muddied by using the output of an array of objects with thenamesprop to create a new array of objects with anameprop, but they are referencing different things in this instance.
I hope that helps!- FForrester Savell @Forrester_Savell
@Chad thanks so much. Appreciate you going into the details on this and helping me understand. Definitely makes sense now that the
sf.interaction.popupSearch()needs to see a name property.The only part that I'm still a little fuzzy on is line 23.
Does thesf.interaction.popupSearch()propertyitemsthat is referencing thefilteredItemsarray of objects, only display thenameproperty?
How does it use thepathproperty? Is it assigning thenamefor eachpathin the array, therefore that's why it needs thepathproperty? Following this thought, why does it need thepathat all? I did some experimenting and this script works where its simply referencing thenameproperty. Is there a reason why you wouldn't use just thenameproperty such as below:if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); function outputSearch() { let outputPathButton = sf.ui.proTools.selectedTrack.outputPathButton; // Fetch all menu items let items = outputPathButton.popupMenuFetchAllItems().menuItems.map(function (item) { return { name: item.names[item.names.length - 1], //path: item.path }; }); let filteredResults = items.filter(function (str) { return !str.name.includes('track'); }); // Search let chosenPath = sf.interaction.popupSearch({ items: filteredResults, title: 'Search for a Track Output', }).item.name; //Get focus back sf.wait({ intervalMs: 100 }); sf.ui.proTools.appActivate(); sf.wait({ intervalMs: 50 }); // Select Chosen Path sf.ui.proTools.selectedTrack.trackOutputSelect({ outputPath: chosenPath, selectForAllSelectedTracks: true }); sf.ui.proTools.invalidate(); } outputSearch();I think this script is what I thought I was doing in my first attempt. I felt that having both
nameandpathis redundant, as they seem to be referencing much the same information, at least as far as the names of the bus/outputs is concerned.Thanks for your time!!
Chad Wahlbrink @Chad2024-06-18 03:33:54.283ZHey @Forrester_Savell!
Let's see if we can clear up the fuzziness. It may help to start with the premise that the ultimate goal of this particular script is to callsf.ui.proTools.selectedTrack.trackOutputSelect()at the end. When we callsf.ui.proTools.selectedTrack.trackOutputSelect(), that method looks for anoutputPathproperty of the array type. Therefore, our ultimate goal is to end up with an array by the end of the script.
Then, starting from the top, we first calloutputPathButton.popupMenuFetchAllItems().menuItems, which gives us the array of objects with the propertiesPath,Names,Delimiter, andElement. In this instance, thePathproperty and theNamesproperty are equivalent.
It does make sense thatPathandNamesare somewhat redundant in the resulting mapped object from that part of the script, however, there's an important change happening here.
sf.interaction.popupSearch()needs an array to search, and specifically, it expects an array of objects that contain anameproperty, as we discovered earlier. The other piece to this puzzle, though, is thatsf.interaction.popupSearch()expects that name to be a String, not an array. This means if we were to call something like this:let items = outputPathButton.popupMenuFetchAllItems().menuItems.map(function (item) { return { name: item.names, }; });Yes, we could potentially get away with using the
item.namesas an array to feedsf.ui.proTools.selectedTrack.trackOutputSelect()at the end of the script, but if we feed this version of theitemsobject tosf.interaction.popupSearch(), it will fail because we have just givensf.interaction.popupSearch()an array of objects withnameprops holding arrays and not strings.
Therefore to keep the flow of the script moving we are using calls like:item.names.join(' > ')or
item.names[item.names.length - 1]These convert the array from the
namesprop outputted fromoutputPathButton.popupMenuFetchAllItems().menuItemsinto strings that can be used bysf.interaction.popupSearch().
Because we need an array of objects with anameprop of type string to feedsf.interaction.popupSearch()and then we inevitably also need an array to givesf.ui.proTools.selectedTrack.trackOutputSelect()at the end of the script, we will need to have an array of objects with both anameand apathproperty. Like this:let items = outputPathButton.popupMenuFetchAllItems().menuItems.map(function (item) { return { name: item.names[item.names.length - 1], path: item.path }; });Maybe the simplest way of thinking about it is that we can use the
nameprop as a "searchable" string, but that string can also be linked to a more complicated array, which we will need to feedsf.ui.proTools.selectedTrack.trackOutputSelect()in the end.
- In reply toForrester_Savell⬆:
Chad Wahlbrink @Chad2023-09-27 21:55:15.592ZWe can also try the script from this post again:
I tweaked it slightly to remove the
{ dismissMenu: true, }bit from line 4- FForrester Savell @Forrester_Savell
Legendary @Chad
Both those options work now. I think the key is the removal of
{ dismissMenu: true, }in both scripts that are working.Interestingly, the original script with that line included works fine on my laptop running Ventura & PT 2023.9. My main mix rig is Catalina & PT2023.6 which is where it wasn't working.
Either way, all solved now so thanks for all the insight and help!!!!
Chad Wahlbrink @Chad2023-09-28 00:55:53.475ZGlad to hear, @Forrester_Savell! Yes, I think that breaking must be something Catalina-specific. I'm running Monterey and couldn't break it with or without the
dismissMenu: true, but glad it's working on your end now!