No internet connection
  1. Home
  2. How to

Select Tracks that are located between two defined tracks

By Thomas Gloor @Thomas_Gloor
    2022-04-16 13:20:55.850Z2022-04-16 13:44:51.240Z

    Hi everyone,

    I'm trying to write a code to help me prepare mixing sessions and I'm looking for a way to select all tracks that are positionned between 2 other tracks like so

    TRACK A
    track to select 1
    track to select 2
    track to select 3
    etc.
    TRACK B

    TRACK A & TRACK B are always in my template.

    Is there a way to tell sound flow to select all tracks that are between TRACK A & TRACK B?

    Any input welcome!

    Thank you!

    • 22 replies

    There are 22 replies. Estimated reading time: 20 minutes

    1. Raphael Sepulveda @raphaelsepulveda2022-04-16 19:15:30.152Z2022-04-18 17:50:16.314Z

      @Thomas_Gloor, here you go!

      /** @param {{ trackA: string, trackB: string, includeHidden?: boolean }} args */
      function selectTracksBetween({ trackA, trackB, includeHidden = false }) {
          function getTrackIndex(trackName) {
              const trackIndex = allTrackNames.indexOf(trackName);
              if (trackIndex === -1) throw `${trackName} not found in session`;
              return trackIndex;
          }
      
          sf.ui.proTools.appActivateMainWindow();
          sf.ui.proTools.mainWindow.invalidate();
      
          const allTrackNames = includeHidden ? sf.ui.proTools.trackNames : sf.ui.proTools.visibleTrackNames;
      
          const trackIndexes = Object
              .values(arguments[0])
              .map(getTrackIndex)
              .sort((a, b) => a - b);
      
          trackIndexes[0]++;
      
          const trackRange = allTrackNames.slice(...trackIndexes);
      
          sf.ui.proTools.trackSelectByName({ names: trackRange, deselectOthers: true });
      }
      
      selectTracksBetween({
          trackA: "Track A", // Insert track names here
          trackB: "Track B"
      });
      
      1. TThomas Gloor @Thomas_Gloor
          2022-04-16 19:17:15.829Z

          Hey @raphaelsepulveda

          Thank you very much for taking the time to do this! I will try it as soon as I'm back at the studio!

          I'm trying to up my very poor Javascript game (tutorials, online courses, etc...) but also want to move forward and turns out every idea I have is pretty complicated haha

          Best,

          T.

          1. Let me know how it works out when you do!

            Oh, yeah I know how that is. One function at a time gets it done eventually!

            1. TThomas Gloor @Thomas_Gloor
                2022-04-17 09:41:01.680Z2022-04-17 14:06:24.341Z

                Thanks! Will do tomorrow.

                Let you know! One last question though @raphaelsepulveda

                If I wanted to use that script more than one time within a bigger script, but let's say the first time it selects between tracks A and B but the second time between C and D, can I simply copy/paste the script twice and change the name of the tracks?

                1. You would only need to copy/paste the function call and modify it accordingly, like so:

                  selectTracksBetween({
                      trackA: "Track C",
                      trackB: "Track D"
                  });
                  

                  I suggest you put the function definition—the part that starts with function—at the top of your script since none of the code in it gets executed until you call it, like shown above.

                  1. TThomas Gloor @Thomas_Gloor
                      2022-04-17 17:18:27.021Z

                      OK! I get it. Thank you so much.

                      While we are talking about selections, would you have an idea of a way I could use to select all tracks in the session that start with a particular character? in a CASE SENSITIVE manner?

                      Thank you again for your time, it's awsome :)

                      1. Yeah! Check it out here Script Sharing - Select Tracks Whose Name Starts with Prefix

                        I created a new thread for it so other people looking for that can easily find it when searching the forum.

                        1. TThomas Gloor @Thomas_Gloor
                            2022-04-18 14:35:51.913Z

                            Thanks @raphaelsepulveda

                            I tried both scripts and the both work perfectly. You are definately the "Track Selection MVP" haha

                            One thing about the "select between 2 tracks" script. Is it possible to have it ignore hidden tracks?
                            Not a major problem that it doesn't, but I imagine it could be depending on the situation.

                            Best

                            T

                            1. Yeah for sure! Sorry totally forgot about hidden tracks lol

                              I updated the code above. Now, by default, it will ignore hidden tracks with the same function call as before, but if you did want to include them, you'd do the call like this:

                              selectTracksBetween({
                                  trackA: "Track A",
                                  trackB: "Track B",
                                  includeHidden: true
                              });
                              
                              1. TThomas Gloor @Thomas_Gloor
                                  2022-04-18 18:54:37.201Z

                                  Hey @raphaelsepulveda

                                  Thank you so much for changing it so fast! You're of GREAT help.

                                  1. Eric Huergo @Eric_Huergo
                                      2023-02-24 03:13:28.856Z

                                      Hey @raphaelsepulveda , first off thanks for all of the help on the forums - I've seen you around everywhere for a while now!!

                                      I was just wondering. If I wanted to modify the following script to select everything in between the tracks but also the tracks designated "trackA" and "trackB" themselves. AND, simultaneously make sure to include all hidden tracks in the selection. What would be a good way of achieving that result? I've been scratching my head at it for a while but keep getting errors! Any help would be greatly appreciated! :)

                                      Your code I'm trying to modify:

                                      /** @param {{ trackA: string, trackB: string, includeHidden?: boolean }} args */
                                      function selectTracksBetween({ trackA, trackB, includeHidden = false }) {
                                          function getTrackIndex(trackName) {
                                              const trackIndex = allTrackNames.indexOf(trackName);
                                              if (trackIndex === -1) throw `${trackName} not found in session`;
                                              return trackIndex;
                                          }
                                      
                                          sf.ui.proTools.appActivateMainWindow();
                                          sf.ui.proTools.mainWindow.invalidate();
                                      
                                          const allTrackNames = includeHidden ? sf.ui.proTools.trackNames : sf.ui.proTools.visibleTrackNames;
                                      
                                          const trackIndexes = Object
                                              .values(arguments[0])
                                              .map(getTrackIndex)
                                              .sort((a, b) => a - b);
                                      
                                          trackIndexes[0]++;
                                      
                                          const trackRange = allTrackNames.slice(...trackIndexes);
                                      
                                          sf.ui.proTools.trackSelectByName({ names: trackRange, deselectOthers: true });
                                      }
                                      
                                      selectTracksBetween({
                                          trackA: "Track A",
                                          trackB: "Track B"
                                      });
                                      
                                      1. @Eric_Huergo,hanks for the kind words!, Always happy to help :D

                                        This small adjustment should do the trick!

                                        /** @param {{ trackA: string, trackB: string, includeTargetTracks?: boolean, includeHidden?: boolean }} args */
                                        function selectTracksBetween({ trackA, trackB, includeTargetTracks = false, includeHidden = false }) {
                                            function getTrackIndex(trackName) {
                                                const trackIndex = allTrackNames.indexOf(trackName);
                                                if (trackIndex === -1) throw `${trackName} not found in session`;
                                                return trackIndex;
                                            }
                                        
                                            sf.ui.proTools.appActivateMainWindow();
                                            sf.ui.proTools.mainWindow.invalidate();
                                        
                                            const allTrackNames = includeHidden ? sf.ui.proTools.trackNames : sf.ui.proTools.visibleTrackNames;
                                        
                                            const trackIndexes = [trackA, trackB]
                                                .map(getTrackIndex)
                                                .sort((a, b) => a - b);
                                        
                                            trackIndexes[+includeTargetTracks]++;
                                        
                                            const trackRange = allTrackNames.slice(...trackIndexes);
                                        
                                            sf.ui.proTools.trackSelectByName({ names: trackRange, deselectOthers: true });
                                        }
                                        
                                        selectTracksBetween({
                                            trackA: "Audio 1",
                                            trackB: "Audio 15",
                                            includeTargetTracks: true,
                                            includeHidden: true
                                        });
                                        
                                        1. Eric Huergo @Eric_Huergo
                                            2023-02-24 18:39:14.930Z2023-02-24 21:27:37.948Z

                                            @raphaelsepulveda , Increíble! :p
                                            The change definitely took care of selecting the appropriate range of tracks in my scenario!! This being said, when the script reaches a hidden track now, it fails and I get the following error in the log:

                                            Could not make track visible (   --  Workspace: Line 22)
                                                Track ' _st_06_HI_ARPS' did not show up after several attempts
                                            

                                            In this instance it crashes when it reaches the track " _st_06_HI_ARPS", but the same is true with any track I try. The script seems to select and unhide the first hidden track it encounters, after which the script immediately fails and I get the error I included above.

                                            My best guess at the moment is that maybe this means that when the script encounters a hidden track it shows and selects it but that somehow this breaks the loop of selecting the rest of the tracks?

                                            Any idea how I might be able to get past this?

                                            Many thanks. :)

                                            • Eric

                                            Additionally, maybe I should mention that the hidden tracks are located within a folder track - is there a chance this is part of the issue?

                                            1. Oh no. This seems to be an issue with the trackSelectByName() function.

                                              Yes, the normal behavior would be for it to unhide the track and then select it. This is all handled by that function. It waits for the track to appear before moving on but, for some reason, it's not detecting that the track has been unhidden. Unfortunately, I'm not able to make the error happen on my end.

                                              Let's distill it down. If you run this by itself, do you still get the error?

                                              sf.ui.proTools.trackSelectByName({ names: [" _st_06_HI_ARPS"], deselectOthers: true });
                                              

                                              If so, could you log a bug report immediately after getting the error, so we can take a closer look? A screen recording of it happening would also be helpful, which you can put on the report after you've filed it.

                                              1. Eric Huergo @Eric_Huergo
                                                  2023-02-24 22:01:01.843Z

                                                  Dang, unfortunately still get the error. Managed to submit a bug report though!

                                                  1. Eric Huergo @Eric_Huergo
                                                      2023-02-24 22:37:54.860Z

                                                      Alright @raphaelsepulveda , turns out I made a very silly mistake and didn't catch a simple, silly mistake.

                                                      At some point a space ended up before the track name and so was not able to find the track because, well.... it wasn't there.

                                                      Needless to say, if I now run the following script:

                                                      /** @param {{ trackA: string, trackB: string, includeTargetTracks?: boolean, includeHidden?: boolean }} args */
                                                      function selectTracksBetween({ trackA, trackB, includeTargetTracks = false, includeHidden = false }) {
                                                          function getTrackIndex(trackName) {
                                                              const trackIndex = allTrackNames.indexOf(trackName);
                                                              if (trackIndex === -1) throw `${trackName} not found in session`;
                                                              return trackIndex;
                                                          }
                                                      
                                                          sf.ui.proTools.appActivateMainWindow();
                                                          sf.ui.proTools.mainWindow.invalidate();
                                                      
                                                          const allTrackNames = includeHidden ? sf.ui.proTools.trackNames : sf.ui.proTools.visibleTrackNames;
                                                      
                                                          const trackIndexes = [trackA, trackB]
                                                              .map(getTrackIndex)
                                                              .sort((a, b) => a - b);
                                                      
                                                          trackIndexes[+includeTargetTracks]++;
                                                      
                                                          const trackRange = allTrackNames.slice(...trackIndexes);
                                                      
                                                          sf.ui.proTools.trackSelectByName({ names: trackRange, deselectOthers: true });
                                                      }
                                                      
                                                      selectTracksBetween({
                                                          trackA: ">> STEREO FD <<",
                                                          trackB: "_99_Click",
                                                          includeTargetTracks: true,
                                                          includeHidden: true
                                                      });
                                                      

                                                      it will run fine until it encounters the first hidden track. It then proceeds to unhide it and the script stops running and shows me the following in the error log:

                                                      24.02.2023 14:36:35.88 <info> [Backend]: Logging error in action (01) TrackMakeVisibleByListItemAction: Track ' _st_08_KEYS' did not show up after several attempts
                                                      Logging error in action (01) SelectTracksByNameAction: Could not make track visible
                                                      
                                                      24.02.2023 14:36:35.88 <info> [Backend]: !! Command Error:    --  Workspace [user:cldav56zg00006p10fry8qf84:cldkjdllg0000td106m00l1af]:
                                                      Could not make track visible (   --  Workspace: Line 22)
                                                          Track ' _st_08_KEYS' did not show up after several attempts
                                                      

                                                      Any idea what I might be doing wrong?

                                                      1. This seems to be the same error from before. It wasn't your fault that the space was added before the track name, SoundFlow is reporting that that's actually the track name.

                                                        Ahhhh, you know what, I bet you have track numbers enabled. If you do, try turning it off and run the script again.

                                                        1. Eric Huergo @Eric_Huergo
                                                            2023-02-24 22:54:33.852Z

                                                            BOOM! You called it, works like a charm now!

                                                            Now I just have to make a function that stores the value of whether track numbers are enabled or not, make it so that before this part of the script runs track numbers are turned off, and afterwards set the state of Track Numbers to whatever the value was set as in the function!

                                                            Thanks so much dude!!! Lo aprecio un chingo!. ;)

                                                            1. Hahah, no hay problema, hermano! :D Let me know if you need help with that.

                                                              In the meantime, I was able to repro the source of the problem and posted my findings on your bug report from earlier. Could you remove the "Solved" status of it so that we can still keep track of it?

                                                              1. Eric Huergo @Eric_Huergo
                                                                  2023-02-24 23:35:38.888Z

                                                                  Claro que si! Just removed the "Solved" status. ;)

                                                                  For the track numbers part, would you just go the globalstate way or what method do you think would work best? :p

                                                                  1. I'd approach it like this:

                                                                    /** @param {{ trackA: string, trackB: string, includeTargetTracks?: boolean, includeHidden?: boolean }} args */
                                                                    function selectTracksBetween({ trackA, trackB, includeTargetTracks = false, includeHidden = false }) {
                                                                        function getTrackIndex(trackName) {
                                                                            const trackIndex = allTrackNames.indexOf(trackName);
                                                                            if (trackIndex === -1) throw `${trackName} not found in session`;
                                                                            return trackIndex;
                                                                        }
                                                                    
                                                                        sf.ui.proTools.appActivateMainWindow();
                                                                        sf.ui.proTools.mainWindow.invalidate();
                                                                    
                                                                        const allTrackNames = includeHidden ? sf.ui.proTools.trackNames : sf.ui.proTools.visibleTrackNames;
                                                                    
                                                                        const trackIndexes = [trackA, trackB]
                                                                            .map(getTrackIndex)
                                                                            .sort((a, b) => a - b);
                                                                    
                                                                        trackIndexes[+includeTargetTracks]++;
                                                                    
                                                                        const trackRange = allTrackNames.slice(...trackIndexes);
                                                                    
                                                                        sf.ui.proTools.trackSelectByName({ names: trackRange, deselectOthers: true });
                                                                    }
                                                                    
                                                                    /** Ensures a menu item is menu checked (or not) while an action takes place.
                                                                     * @param {{ 
                                                                     * menuItemPath: [string, string, string?, string?, string?, string?], 
                                                                     * doWithout?: boolean, // Ensures the menu item is NOT menu checked
                                                                     * callback: function
                                                                     * }} args */
                                                                    function doWithMenuItemToggle({ menuItemPath, doWithout = false, callback }) {
                                                                        const menuItem = sf.ui.proTools.getMenuItem(...menuItemPath);
                                                                        const isMenuItemChecked = menuItem.isMenuChecked;
                                                                    
                                                                        if (!isMenuItemChecked && !doWithout || isMenuItemChecked && doWithout) {
                                                                            menuItem.elementClick();
                                                                        }
                                                                    
                                                                        callback();
                                                                    
                                                                        if (!isMenuItemChecked && !doWithout || isMenuItemChecked && doWithout) {
                                                                            menuItem.elementClick();
                                                                        }
                                                                    }
                                                                    
                                                                    doWithMenuItemToggle({
                                                                        menuItemPath: ["View", "Track Number"],
                                                                        doWithout: true,
                                                                        callback: () => {
                                                                            selectTracksBetween({
                                                                                trackA: ">> STEREO FD <<",
                                                                                trackB: "_99_Click",
                                                                                includeTargetTracks: true,
                                                                                includeHidden: true
                                                                            });
                                                                        }
                                                                    });
                                                                    

                                                                    PS. This could've been simpler but I prefer to write reusable functions I can implement in other scripts 🤘🏼

                                                                    1. Eric Huergo @Eric_Huergo
                                                                        2023-02-25 02:15:20.300Z

                                                                        Wow, thank you so much! Will definitely be applying this technique with other values further down the line!

                                                                        The part of the script that I've been struggling with is now fully running now thanks to you!

                                                                        Lo aprecio demasiado! Un abrazo y enserio muchas gracias! <3