No internet connection
  1. Home
  2. Support

Selecting multiple tracks by name with wildcards

By Graham Archer @Graham_Archer
    2019-09-17 20:22:48.931Z

    Hi there,

    I think this must be a syntax problem but I've looked at a couple of other posts relating to selecting multiple tracks by name but I can't seem to get it to work. Here's what I have currently:

    sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: ['SNARE','SNR','KICK','RIDE','HH'] });

    It seems to be selecting the number of tracks that are in the array but not the correct tracks. Any help would be much appreciated!

    Thanks in advance!

    Solved in post #7, click to view
    • 21 replies

    There are 21 replies. Estimated reading time: 18 minutes

    1. Hm, your code is right. This could be due to caching in SoundFlow though, for example if you move tracks around etc.
      To invalidate the cache, insert this line at the top of your script:

      sf.ui.proTools.mainWindow.invalidate();
      
      1. GGraham Archer @Graham_Archer
          2019-09-18 08:10:01.218Z

          Thanks @chrscheuer I'll try that. Whilst doing a number of revisions to the code last night I had to quit and restart SF quite a few times in order for the new code to take effect. I tried restarting SF from the Advanced menu item but it didn't seem to help - a full on quit and start the app again and then Open SoundFlow did though.

          One other question I had was how do I selected tracks that 'contains word' rather than 'is the exact word'? As in I'm using this code:

          sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: ['SNARE','SNR','KICK','RIDE','HH'] });

          But I want SF to select a track called 'SNARE DRUM' and I don't have that in names, but I do have 'SNARE'.

          Thanks in advance!

          1. Thanks chrscheuer I'll try that. Whilst doing a number of revisions to the code last night I had to quit and restart SF quite a few times in order for the new code to take effect. I tried restarting SF from the Advanced menu item but it didn't seem to help - a full on quit and start the app again and then Open SoundFlow did though.

            Thank you for reporting this Graham. I've filed a bug report for this.

            One other question I had was how do I selected tracks that 'contains word' rather than 'is the exact word'? As in I'm using this code:
            sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: ['SNARE','SNR','KICK','RIDE','HH'] });

            I don't think the trackSelectByName supports wildcards but we could build a script that does this.

            1. GGraham Archer @Graham_Archer
                2019-09-18 08:36:28.184Z

                Hey @chrscheuer ok cool. Yeah I think wildcards would be more powerful and general in this context. I don't always know in advance what the tracks names are going to be called and so 'contains name' would be a lot more useful I think.

                1. In reply tochrscheuer:
                  GGraham Archer @Graham_Archer
                    2019-10-19 22:56:42.219Z

                    Hey @chrscheuer, are wildcards a relatively easy thing to implement in trackSelectByName? If so, do you have a timeline for that?

                    Please let me know when you have a moment.

                    Many thanks,

                    1. This script implements wildcards:

                      
                      function selectTracksByNameWithWildcard(trackNames = []) {
                      
                          function matchWildcard(str, rule) {
                              var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
                              return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$", "i").test(str);
                          }
                      
                          var allNames = sf.ui.proTools.trackNames;
                      
                          var namesToSelect = allNames.filter(n => trackNames.some(tn => matchWildcard(n, tn)));
                      
                          sf.ui.proTools.trackSelectByName({
                              names: namesToSelect,
                              deselectOthers: true,
                          });
                      }
                      
                      selectTracksByNameWithWildcard([
                          'SNARE*',
                          'SNR*',
                          'KICK*',
                          'RIDE*',
                          'HH*'
                      ]);
                      

                      Note this requires SoundFlow 3.1 - you can download it manually from here: soundflow.org/download
                      The auto-update will update all existing installations later this week.

                      Reply1 LikeSolution
                      1. GGraham Archer @Graham_Archer
                          2019-10-21 21:07:53.742Z

                          Thank you @chrscheuer this is so good! I've just been testing it - I needed to put a * before the name as well. So:
                          selectTracksByNameWithWildcard([ '*SNARE*', '*SNR*', '*KICK*', '*RIDE*', '*HH*' ]);
                          But it's great!

                          1. Nice. Yea the "*" represents any number of characters, so if you want it to match things where something comes before SNARE in the name - for example "Lsnare1" you need star signs on both sides. Anyway - good that it works :)

                            1. GGraham Archer @Graham_Archer
                                2019-12-11 00:07:12.409Z

                                Hey @chrscheuer, I have one other question on this - I'm getting an error when none of the keywords are found in any track name in the session. The error message is:

                                Error: One or more errors occurred. (Expression Failed: Pro Tools: Selected Track Header)

                                Is there any way to return a notification just saying something like "There are no drum tracks in the session" and have it not flag an error (and therefore stop the rest of my script)?

                                I just wondered if you've come across this and how to solve it - apologies I'm not quite sure how to de-bug it!

                                Thanks in advance!

                                Graham

                                1. Yes you can do error handling in many different ways with SoundFlow.

                                  You could for example change this:

                                      sf.ui.proTools.trackSelectByName({
                                          names: namesToSelect,
                                          deselectOthers: true,
                                      });
                                  

                                  to:

                                      sf.ui.proTools.trackSelectByName({
                                          names: namesToSelect,
                                          deselectOthers: true,
                                      }, err => { log('There are no drum tracks in the session'); });
                                  
                                  1. You can read more about error handling in general here:
                                    https://soundflow.org/docs/how-to/custom-commands/error-handling

                                    1. GGraham Archer @Graham_Archer
                                        2019-12-12 10:19:03.262Z

                                        Hey @chrscheuer hmmmm I'm tried that and it doesn't seem to throw up the 'There are no drum tracks in the session' log and move on to the rest of the script.

                                        `//SET TRACK HEIGHT TO SMALL
                                        var size = 'micro';
                                        var f = sf.ui.proTools.selectedTrack.frame;
                                        var popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({
                                        relativePosition: { x: f.w - 10, y: 5 },
                                        isOption: true,
                                        }).popupMenu;
                                        popupMenu.menuClickPopupMenu({
                                        menuPath: [size]
                                        });
                                        //SET INPUT TO NO INPUT
                                        sf.ui.proTools.selectedTrack.trackInputSelect({
                                        inputPath: ['no input'],
                                        selectForAllSelectedTracks: true
                                        });
                                        sf.wait({ intervalMs: 500, });

                                        //
                                        sf.ui.proTools.appActivateMainWindow();
                                        function setOutput(name, outputPath) {
                                        var track = sf.ui.proTools.trackGetByName({ name: name, makeVisible: true }).track;
                                        track.trackSelect();
                                        track.trackScrollToView();
                                        track.trackOutputSelect({
                                        outputPath: outputPath
                                        });
                                        }
                                        function selectTracksByNameWithWildcard(trackNames = []) {
                                        function matchWildcard(str, rule) {
                                        var escapeRegex = (str) => str.replace(/([.+?^=!:${}()|[]/\])/g, "\$1");
                                        return new RegExp("^" + rule.split("
                                        ").map(escapeRegex).join(".*") + "$", "i").test(str);
                                        }
                                        var allNames = sf.ui.proTools.trackNames; //variable containing all track names
                                        var namesToSelect = allNames.filter(n => trackNames.some(tn => matchWildcard(n, tn))); //
                                        sf.ui.proTools.trackSelectByName({
                                        names: namesToSelect,
                                        deselectOthers: true,
                                        }, err => { log('There are no drum tracks in the session'); });
                                        }
                                        //DRUMS
                                        selectTracksByNameWithWildcard([
                                        'SNARE', 'KICK', 'TOM', 'DRUM', 'HAT'
                                        ]);
                                        sf.ui.proTools.colorsSelect({//COLOUR DRUMS
                                        colorTarget: "Tracks",
                                        colorBrightness: "Dark",
                                        colorNumber: 8,
                                        });
                                        //DRUMS OUTPUT SELECT
                                        sf.ui.proTools.selectedTrack.trackOutputSelect({
                                        outputPath: ['bus', ' (Stereo)'],
                                        selectForAllSelectedTracks: true
                                        });
                                        //DRUMS CAPITALISE NAMES
                                        sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => {
                                        track.trackSelect();
                                        track.trackRename({
                                        renameFunction: oldName => oldName.toUpperCase(),
                                        });
                                        });
                                        //DRUMS COPY TRACK NAME TO COMMENTS BOX
                                        selectTracksByNameWithWildcard([
                                        'SNARE', 'KICK', 'TOM', 'DRUM', 'HAT'
                                        ]);
                                        function setComment(trackHeader, text) {
                                        var commentsField = trackHeader.textFields.whoseTitle.startsWith('Comments').first;
                                        commentsField.mouseClickElement();
                                        sf.keyboard.press({ keys: 'cmd+a' });
                                        sf.keyboard.type({ text: text });
                                        sf.keyboard.press({ keys: 'return' });
                                        }
                                        function setCommentsToTrackNames() {
                                        var tracks = sf.ui.proTools.selectedTracks.trackHeaders;
                                        for (var i = 0; i < tracks.length; i++) {
                                        var track = tracks[i];
                                        setComment(track, track.normalizedTrackName);
                                        }
                                        }
                                        setCommentsToTrackNames();
                                        log('Drums Completed');
                                        sf.wait({ intervalMs: 500, });`

                                        I've got a dead simple Pro Tools session with a few tracks in that don't have keywords SNARE, KICK, TOM, DRUM, HAT and I'm just trying to get the script to not fail. Have you any ideas? Basically it works great when those keywords are present.

                                        Thanks in advance!

                                        Graham

                              • In reply tochrscheuer:
                                AAlex Oldroyd @Alex_Oldroyd8
                                  2022-01-26 23:16:39.796Z

                                  Hi Christian. I'm trying to incorporate wildcards into some logic scripts. Is there any chance you or kitch could do a video on them? THanks

                                  1. Hi Alex,

                                    That's a good idea. We don't have a good system for planning which videos to do, so I'll just tag @Kitch here for now.

                                    1. AAlex Oldroyd @Alex_Oldroyd8
                                        2022-01-26 23:50:33.345Z

                                        Thanks Christian. And yes @Kitch if you're not already sick of me - how would i implement wildcards into this script: Select a track in Logic Pro X #post-20

                                        1. Kitch Membery @Kitch2022-01-26 23:51:54.307Z

                                          @Alex_Oldroyd8 Taking a look now. :-)

                                          1. AAlex Oldroyd @Alex_Oldroyd8
                                              2022-01-26 23:54:28.403Z

                                              🥳

                                            • In reply toAlex_Oldroyd8:
                                              Kitch Membery @Kitch2022-01-26 23:54:15.608Z

                                              Actually this is different to the Bus Selection wildcard question. Let's address that one first.

                                              1. AAlex Oldroyd @Alex_Oldroyd8
                                                  2022-01-26 23:54:52.997Z

                                                  haha sorry 😬 too many questions

                                          2. In reply tochrscheuer:
                                            Jjulien creus @julien_creus
                                              2023-07-03 18:59:52.188Z2023-07-05 22:03:10.489Z

                                              Hello @chrscheuer , Thanks for this script which is very useful to me! Would you know any way to improve it so that the track selection is only made within Visible and Active tracks? I already found this perfect script from @raphaelsepulveda which works perfectly for selecting all the visible and active tracks, but didn't manage to make it work together with your script using wildcard... Here is the script for selecting all visible and active tracks, in case it is useful somehow...if one of you guys have any clue on how to do this, that would be of great help!!!
                                              Thanks a lot 🙏

                                              function isTrackActive({ track }) {
                                                  if (track.muteButton.exists) {
                                                      return track.muteButton.value.value !== 'inactive';
                                                  }
                                                  return track.outputWindowButton.value.value !== 'inactive';
                                              }
                                              
                                              function getVisibleActiveTracks() {
                                                  const visibleTracks = sf.ui.proTools.invalidate().visibleTracks;
                                                  let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] };
                                              
                                                  visibleTracks.trackHeaders.forEach((trackHeader, i) => {
                                                      if (isTrackActive({ track: trackHeader })) {
                                                          visibleActiveTracks["trackHeaders"].push(trackHeader)
                                                          visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i])
                                                          visibleActiveTracks["names"].push(visibleTracks.names[i])
                                                      }
                                                  });
                                              
                                                  return visibleActiveTracks
                                              }
                                              
                                              function selectTrack(trackListItem) {
                                                  trackListItem.children.whoseRole.is("AXCell").allItems[1].buttons.first.elementClick();
                                              }
                                              
                                              function selectAllVisibleActiveTracks() {
                                                  sf.ui.proTools.appActivateMainWindow();
                                                  sf.ui.proTools.trackDeselectAll();
                                                  getVisibleActiveTracks().trackListItems.forEach(selectTrack)
                                              }
                                              
                                              selectAllVisibleActiveTracks();
                                              
                                              1. Here ya go!

                                                function isTrackActive({ track }) {
                                                    if (track.muteButton.exists) {
                                                        return track.muteButton.value.value !== 'inactive';
                                                    }
                                                    return track.outputWindowButton.value.value !== 'inactive';
                                                }
                                                
                                                function getVisibleActiveTracks() {
                                                    const visibleTracks = sf.ui.proTools.invalidate().visibleTracks;
                                                    let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] };
                                                
                                                    visibleTracks.trackHeaders.forEach((trackHeader, i) => {
                                                        if (isTrackActive({ track: trackHeader })) {
                                                            visibleActiveTracks["trackHeaders"].push(trackHeader)
                                                            visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i])
                                                            visibleActiveTracks["names"].push(visibleTracks.names[i])
                                                        }
                                                    });
                                                
                                                    return visibleActiveTracks
                                                }
                                                
                                                function matchWildcard(str, rule) {
                                                    var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
                                                    return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$", "i").test(str);
                                                }
                                                
                                                function selectVisibleActiveTracksByNameWithWildcard(trackNames = []) {
                                                    const visibleActiveTrackNames = getVisibleActiveTracks().names;
                                                
                                                    const namesToSelect = visibleActiveTrackNames.filter(n => trackNames.some(tn => matchWildcard(n, tn)));
                                                
                                                    sf.ui.proTools.trackSelectByName({
                                                        names: namesToSelect,
                                                        deselectOthers: true,
                                                    });
                                                }
                                                
                                                selectVisibleActiveTracksByNameWithWildcard([
                                                    'SNARE*',
                                                    'SNR*',
                                                    'KICK*',
                                                    'RIDE*',
                                                    'HH*'
                                                ]);