No internet connection
  1. Home
  2. Macro and Script Help

Popupsearch disappears

By Forrester Savell @Forrester_Savell
    2023-09-27 08:05:47.099Z

    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=

    Solved in post #9, click to view
    • 16 replies

    There are 16 replies. Estimated reading time: 26 minutes

    1. Chad Wahlbrink @Chad2023-09-27 13:08:17.494Z2023-09-27 21:53:49.310Z

      Hey @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 });
      
      1. Chad Wahlbrink @Chad2023-09-27 13:11:53.897Z

        Also, 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)

        1. F
          Forrester Savell @Forrester_Savell
            2023-09-27 19:49:02.460Z

            Hi @Chad

            Thanks for looking into this.
            Still getting the same issue with your script, the popup window disappears straight away. I was calling the selectedOutputPath in 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

            1. 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:

              1. FForrester Savell @Forrester_Savell
                  2023-09-27 21:16:14.246Z

                  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) PopupSearchAction

                  28.09.2023 07:18:01.64 [Application]: this.popupWindow.on(hide)"

                  1. FForrester Savell @Forrester_Savell
                      2023-09-27 21:23:41.111Z

                      I've updated to SF 5.4.8 and the behaviour is the same.

                      1. Chad Wahlbrink @Chad2023-09-27 21:53:07.147Z

                        Hey @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();
                        
                        1. FForrester Savell @Forrester_Savell
                            2024-06-14 04:49:30.831Z

                            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();
                            
                            1. Chad Wahlbrink @Chad2024-06-17 14:39:55.967Z

                              Hey @Forrester_Savell!

                              The reason you are seeing errors is that the sf.interaction.popupSearch() command is set up to search an object with a property called name. 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().menuItems is an array of objects) and converting it to an array of arrays. This is because the path property of the menuItems object you get from .popupMenuFetchAllItems().menuItems is an array.

                              The original code maps the array of menuItems objects to a new array of objects with two properties, name and path. The critical part of mapping an array for a SoundFlow popupsearch is having a name property. If the sf.interaction.popupSearch() command is called on an array of objects that do not have the name property, 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 feed sf.interaction.popupSearch() an array of arrays, instead of an array of objects with the name property.

                              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:

                              1. 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();
                                
                                1. Chad Wahlbrink @Chad2024-06-17 14:51:02.397Z

                                  The part that filters the name to just the actual output name is line 12.

                                  item.names[item.names.length - 1]
                                  

                                  The output of popupMenuFetchAllItems().menuItems is an array of objects with the properties Path, Names, Delimiter, and Element. 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, name and path, I'm using item.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 the names prop to create a new array of objects with a name prop, but they are referencing different things in this instance.

                                  I hope that helps!

                                  1. FForrester Savell @Forrester_Savell
                                      2024-06-17 23:05:30.670Z2024-06-17 23:49:04.982Z

                                      @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 the sf.interaction.popupSearch() property items that is referencing the filteredItems array of objects, only display the name property?
                                      How does it use the path property? Is it assigning the name for each path in the array, therefore that's why it needs the path property? Following this thought, why does it need the path at all? I did some experimenting and this script works where its simply referencing the name property. Is there a reason why you wouldn't use just the name property 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 name and path is 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!!

                                      1. Chad Wahlbrink @Chad2024-06-18 03:33:54.283Z

                                        Hey @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 call sf.ui.proTools.selectedTrack.trackOutputSelect() at the end. When we call sf.ui.proTools.selectedTrack.trackOutputSelect(), that method looks for an outputPath property 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 call outputPathButton.popupMenuFetchAllItems().menuItems, which gives us the array of objects with the properties Path, Names, Delimiter, and Element. In this instance, the Path property and the Names property are equivalent.

                                        It does make sense that Path and Names are 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 a name property, as we discovered earlier. The other piece to this puzzle, though, is that sf.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.names as an array to feed sf.ui.proTools.selectedTrack.trackOutputSelect() at the end of the script, but if we feed this version of the items object to sf.interaction.popupSearch(), it will fail because we have just given sf.interaction.popupSearch() an array of objects with name props 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 names prop outputted from outputPathButton.popupMenuFetchAllItems().menuItems into strings that can be used by sf.interaction.popupSearch().

                                        Because we need an array of objects with a name prop of type string to feed sf.interaction.popupSearch() and then we inevitably also need an array to give sf.ui.proTools.selectedTrack.trackOutputSelect() at the end of the script, we will need to have an array of objects with both a name and a path property. 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 name prop as a "searchable" string, but that string can also be linked to a more complicated array, which we will need to feed sf.ui.proTools.selectedTrack.trackOutputSelect() in the end.

                              2. Chad Wahlbrink @Chad2023-09-27 21:55:15.592Z

                                We can also try the script from this post again:

                                I tweaked it slightly to remove the { dismissMenu: true, } bit from line 4

                                Reply1 LikeSolution
                                1. FForrester Savell @Forrester_Savell
                                    2023-09-27 22:26:00.358Z

                                    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!!!!

                                    1. Chad Wahlbrink @Chad2023-09-28 00:55:53.475Z

                                      Glad 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!