No internet connection
  1. Home
  2. How to

Help me complete this script to sort tracks

By Hendrick Valera @Hendrick_Valera
    2021-12-02 03:56:29.258Z

    Hey everyone,

    I've been using this script that helps me sort the order of tracks based on which one has transient information first.

    function moveTracksToTop(selectedTracks, trackNames) {
    
        //  Safety deselect all
        sf.ui.proTools.trackDeselectAll()
    
        //  Get possition of first track
        let firstTrackPosition = sf.ui.proTools.trackGetByName({ name: selectedTracks[0] }).track.frame
    
    
        //  Safety deselect all
        sf.ui.proTools.trackDeselectAll()
    
        for (let i = 0; i < trackNames.length; i++) {
    
            sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.trackScrollToView()
    
            const elementPosition = sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.frame
    
            sf.mouse.simulateDrag({
                startPosition: { "x": elementPosition.x + 20, "y": elementPosition.y + 15 },
                endPosition: { "x": elementPosition.x + 20, "y": firstTrackPosition.y },
            });
    
            sf.ui.proTools.invalidate()
        }
    }
    
    
    function getTrackNameTransientTime(selectedTracks) {
    
        let startTime
        let trackList = []
    
        sf.ui.proTools.menuClick({ menuPath: ["Options", "Tab to Transient"], targetValue: "Enable" })
    
        for (let i = 0; i < selectedTracks.length; i++) {
    
            sf.ui.proTools.trackSelectByName({ names: [selectedTracks[i]] })
    
            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"] });
    
            sf.keyboard.press({ keys: "tab" });
    
            startTime = sf.ui.proTools.selectionGetInSamples().selectionStart
    
            trackList[i] = {
                trackName: selectedTracks[i],
                startTime: +startTime
            }
        }
        return trackList
    }
    
    
    function main() {
    
        sf.ui.proTools.appActivateMainWindow();
        sf.ui.proTools.invalidate()
    
        const selectedTracks = sf.ui.proTools.selectedTrackNames
    
        const trackList = getTrackNameTransientTime(selectedTracks)
    
        // ///  Sort array of objects by property. ? 1:-1 ascending / ? -1:1 descending 
        const tracksToMove = trackList.sort((a, b) => (a.startTime > b.startTime) ? 1 : -1).map(track => track.trackName)
    
        moveTracksToTop(selectedTracks, tracksToMove)
    
        sf.ui.proTools.trackSelectByName({ names: selectedTracks })
    
        if (sf.ui.proTools.selectedTrackNames.join(",") != tracksToMove.reverse().toString()) {
            main()
        } else {
            alert("Sorted!")
        }
    }
    main()
    

    Before triggering, however, I find myself changing the track size from Medium to Mini and then back to Medium after it's done sorting. So I'd like to add these actions to the script.

    Once I have a track selection, the order of action would be:

    1. Change track size from X to Mini
    2. Perform the sorting
    3. Change the track size from Mini to X

    I saw that Andrew Scheps has a package called "Screen Layout Helper Functions" and this could possibly help me in the portion of creating and recalling a snapshot of the original track sizes but I don't know how to connect all these pieces together.

    I would highly appreciate the help on this!!

    @Kitch this is what we briefly talked about today!

    PS.: These are some posts I've found in the forum that could also help in finding pieces of this puzzle

    Solved in post #2, click to view
    • 13 replies

    There are 13 replies. Estimated reading time: 22 minutes

    1. samuel henriques @samuel_henriques
        2021-12-03 16:59:27.101Z

        Hello Hendrick,

        try this

        /**
        * @param {any[]} selectedTracks
        * @param {string | any[]} trackNames
        */
        function moveTracksToTop(selectedTracks, trackNames) {
        
            //  Safety deselect all
            sf.ui.proTools.trackDeselectAll()
        
            //  Get position of first track
            let firstTrackPosition = sf.ui.proTools.trackGetByName({ name: selectedTracks[0] }).track.frame
        
        
            //  Safety deselect all
            sf.ui.proTools.trackDeselectAll()
        
            for (let i = 0; i < trackNames.length; i++) {
        
                sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.trackScrollToView()
        
                const elementPosition = sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.frame
        
                sf.mouse.simulateDrag({
                    startPosition: { "x": elementPosition.x + 20, "y": elementPosition.y + 10 },
                    endPosition: { "x": elementPosition.x + 20, "y": firstTrackPosition.y },
                });
        
                sf.ui.proTools.invalidate()
            }
        }
        
        
        /**
        * @param {string | any[]} selectedTracks
        */
        function getTrackNameTransientTime(selectedTracks) {
        
            let startTime
            let trackList = []
        
            sf.ui.proTools.menuClick({ menuPath: ["Options", "Tab to Transient"], targetValue: "Enable" })
        
            for (let i = 0; i < selectedTracks.length; i++) {
        
                sf.ui.proTools.trackDeselectAll()
        
                sf.ui.proTools.trackSelectByName({ names: [selectedTracks[i]] })
        
                sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"] });
        
                sf.keyboard.press({ keys: "tab" });
        
                startTime = sf.ui.proTools.selectionGetInSamples().selectionStart
        
                trackList[i] = {
                    trackName: selectedTracks[i],
                    startTime: +startTime
                }
            }
            return trackList
        }
        
        
        /**
        * @param {number} h
        */
        function getCurrentTrackHeight(h) {
            let originalTrackHeight;
        
            switch (true) {
                case (h <= 16):
                    originalTrackHeight = 'micro';
                    break;
                case (h === 23):
                    originalTrackHeight = 'mini';
                    break;
                case (h >= 43 && h <= 61):
                    originalTrackHeight = 'small';
                    break;
                case (h >= 79 && h <= 116):
                    originalTrackHeight = 'medium';
                    break;
                case (h >= 135 && h <= 235):
                    originalTrackHeight = 'large';
                    break;
                case (h >= 257 && h <= 420):
                    originalTrackHeight = 'jumbo';
                    break;
                case (h > 440):
                    originalTrackHeight = 'extreme';
                    break;
            };
            return originalTrackHeight
        
        };
        
        /**
        * @param {string} size
        */
        function setTrackSize(size) {
        
            const selectedTrackNames = sf.ui.proTools.selectedTrackNames
        
            const firstSelected = sf.ui.proTools.trackGetByName({ name: selectedTrackNames[0] }).track
        
            firstSelected.trackScrollToView()
        
            sf.ui.proTools.trackSelectByName({ names: selectedTrackNames })
        
        
            const f = sf.ui.proTools.selectedTrack.frame
        
            if (getCurrentTrackHeight(f.h) != size) {
        
                const popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({
                    relativePosition: { x: f.w - 10, y: 5 },
                    isOption: true,
                    isShift: true,
                }).popupMenu;
        
                popupMenu.menuClickPopupMenu({
                    menuPath: [size]
                });
            }
        }
        
        
        function main() {
        
            sf.ui.proTools.appActivateMainWindow();
            sf.ui.proTools.invalidate()
        
            const originalTrackHeight = getCurrentTrackHeight(sf.ui.proTools.selectedTrack.frame.h)
        
            setTrackSize("micro")
        
            const selectedTracks = sf.ui.proTools.selectedTrackNames
        
            const trackList = getTrackNameTransientTime(selectedTracks)
        
            // ///  Sort array of objects by property. ? 1:-1 ascending / ? -1:1 descending 
            const tracksToMove = trackList.sort((a, b) => (a.startTime > b.startTime) ? 1 : -1).map(track => track.trackName)
        
            try {
        
                moveTracksToTop(selectedTracks, tracksToMove)
        
                sf.ui.proTools.trackSelectByName({ names: selectedTracks })
        
                //  Check if order is correct, if not, repeat.
                if (sf.ui.proTools.selectedTrackNames.join(",") != tracksToMove.reverse().toString()) { main() }
        
            } catch (err) { log("An error occurred trying to sort tracks.") }
        
            setTrackSize(originalTrackHeight)
        
            alert("Sorted!")
        }
        
        
        
        
        main()
        
        
        
        
        
        
        
        
        Reply1 LikeSolution
        1. HHendrick Valera @Hendrick_Valera
            2021-12-03 17:48:44.866Z

            This is perfect!! Thank you so much Samuel!! you are the best :)

            Since the resulting size before sorting is now micro I changed the code a little because the place where it clicks to drag happens to open a menu, so I just moved the X-axis a little to the right so it clicks on the track name when dragging.

            /**
            * @param {any[]} selectedTracks
            * @param {string | any[]} trackNames
            */
            function moveTracksToTop(selectedTracks, trackNames) {
            
                //  Safety deselect all
                sf.ui.proTools.trackDeselectAll()
            
                //  Get position of first track
                let firstTrackPosition = sf.ui.proTools.trackGetByName({ name: selectedTracks[0] }).track.frame
            
            
                //  Safety deselect all
                sf.ui.proTools.trackDeselectAll()
            
                for (let i = 0; i < trackNames.length; i++) {
            
                    sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.trackScrollToView()
            
                    const elementPosition = sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.frame
            
                    sf.mouse.simulateDrag({
                        startPosition: { "x": elementPosition.x + 40, "y": elementPosition.y + 10 },
                        endPosition: { "x": elementPosition.x + 40, "y": firstTrackPosition.y },
                    });
            
                    sf.ui.proTools.invalidate()
                }
            }
            
            
            /**
            * @param {string | any[]} selectedTracks
            */
            function getTrackNameTransientTime(selectedTracks) {
            
                let startTime
                let trackList = []
            
                sf.ui.proTools.menuClick({ menuPath: ["Options", "Tab to Transient"], targetValue: "Enable" })
            
                for (let i = 0; i < selectedTracks.length; i++) {
            
                    sf.ui.proTools.trackDeselectAll()
            
                    sf.ui.proTools.trackSelectByName({ names: [selectedTracks[i]] })
            
                    sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"] });
            
                    sf.keyboard.press({ keys: "tab" });
            
                    startTime = sf.ui.proTools.selectionGetInSamples().selectionStart
            
                    trackList[i] = {
                        trackName: selectedTracks[i],
                        startTime: +startTime
                    }
                }
                return trackList
            }
            
            
            /**
            * @param {number} h
            */
            function getCurrentTrackHeight(h) {
                let originalTrackHeight;
            
                switch (true) {
                    case (h <= 16):
                        originalTrackHeight = 'micro';
                        break;
                    case (h === 23):
                        originalTrackHeight = 'mini';
                        break;
                    case (h >= 43 && h <= 61):
                        originalTrackHeight = 'small';
                        break;
                    case (h >= 79 && h <= 116):
                        originalTrackHeight = 'medium';
                        break;
                    case (h >= 135 && h <= 235):
                        originalTrackHeight = 'large';
                        break;
                    case (h >= 257 && h <= 420):
                        originalTrackHeight = 'jumbo';
                        break;
                    case (h > 440):
                        originalTrackHeight = 'extreme';
                        break;
                };
                return originalTrackHeight
            
            };
            
            /**
            * @param {string} size
            */
            function setTrackSize(size) {
            
                const selectedTrackNames = sf.ui.proTools.selectedTrackNames
            
                const firstSelected = sf.ui.proTools.trackGetByName({ name: selectedTrackNames[0] }).track
            
                firstSelected.trackScrollToView()
            
                sf.ui.proTools.trackSelectByName({ names: selectedTrackNames })
            
            
                const f = sf.ui.proTools.selectedTrack.frame
            
                if (getCurrentTrackHeight(f.h) != size) {
            
                    const popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({
                        relativePosition: { x: f.w - 10, y: 5 },
                        isOption: true,
                        isShift: true,
                    }).popupMenu;
            
                    popupMenu.menuClickPopupMenu({
                        menuPath: [size]
                    });
                }
            }
            
            
            function main() {
            
                sf.ui.proTools.appActivateMainWindow();
                sf.ui.proTools.invalidate()
            
                const originalTrackHeight = getCurrentTrackHeight(sf.ui.proTools.selectedTrack.frame.h)
            
                setTrackSize("micro")
            
                const selectedTracks = sf.ui.proTools.selectedTrackNames
            
                const trackList = getTrackNameTransientTime(selectedTracks)
            
                // ///  Sort array of objects by property. ? 1:-1 ascending / ? -1:1 descending 
                const tracksToMove = trackList.sort((a, b) => (a.startTime > b.startTime) ? 1 : -1).map(track => track.trackName)
            
                try {
            
                    moveTracksToTop(selectedTracks, tracksToMove)
            
                    sf.ui.proTools.trackSelectByName({ names: selectedTracks })
            
                    //  Check if order is correct, if not, repeat.
                    if (sf.ui.proTools.selectedTrackNames.join(",") != tracksToMove.reverse().toString()) { main() }
            
                } catch (err) { log("An error occurred trying to sort tracks.") }
            
                setTrackSize(originalTrackHeight)
            
                alert("Sorted!")
            }
            
            
            
            
            main()
            
            
            1. Kitch Membery @Kitch2021-12-03 21:46:28.456Z

              @Hendrick_Valera & @samuel_henriques,

              I'd love a video of this script in action for social media if you have some time to make one. (If so email me a link at support@SoundFlow.org). No worries if you are too busy though :-)

              Cool workflow!

              1. samuel henriques @samuel_henriques
                  2021-12-04 19:32:07.355Z

                  @Hendrick_Valera if you could do it in a real session would be really cool.

                  1. In reply toKitch:
                    HHendrick Valera @Hendrick_Valera
                      2021-12-04 19:57:51.608Z

                      I don't have a deck to record with my phone so I just used the phone app and screen recorded the action! Here it is @Kitch @samuel_henriques

                      https://drive.google.com/file/d/12tuuAz2WTtJjB3xwkoGItVQUR1YKjPzj/view?usp=sharing

                      1. samuel henriques @samuel_henriques
                          2021-12-04 21:09:35.013Z

                          I managed to do one as well.
                          I kept the track size just so its easier to see it working

                          https://drive.google.com/file/d/1OBX1nUfptRVN6msbs347ss3DvhT1_pub/view?usp=sharing

                        • In reply toKitch:
                          Kitch Membery @Kitch2021-12-04 23:19:38.894Z

                          @Hendrick_Valera & @samuel_henriques,

                          Thank you gentlemen! Much appreciated!!

                          Great work.
                          Rock on!

                      2. Kitch Membery @Kitch2021-12-03 21:40:23.283Z
                      3. In reply toHendrick_Valera:
                        Chris Shaw @Chris_Shaw2021-12-08 19:49:10.794Z2021-12-08 23:34:23.037Z

                        LOVE THIS SCRIPT!
                        I made an addition to ask the user which order they'd prefer which then inverts the sort order with a -1 multiplier:
                        (change the default button to whatever you like)

                        /**
                        * @param {any[]} selectedTracks
                        * @param {string | any[]} trackNames
                        */
                        function moveTracksToTop(selectedTracks, trackNames) {
                        
                            //  Safety deselect all
                            sf.ui.proTools.trackDeselectAll()
                        
                            //  Get position of first track
                            let firstTrackPosition = sf.ui.proTools.trackGetByName({ name: selectedTracks[0] }).track.frame
                        
                        
                            //  Safety deselect all
                            sf.ui.proTools.trackDeselectAll()
                        
                            for (let i = 0; i < trackNames.length; i++) {
                        
                                sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.trackScrollToView()
                        
                                const elementPosition = sf.ui.proTools.trackGetByName({ name: trackNames[i] }).track.frame
                        
                                sf.mouse.simulateDrag({
                                    startPosition: { "x": elementPosition.x + 20, "y": elementPosition.y + 10 },
                                    endPosition: { "x": elementPosition.x + 20, "y": firstTrackPosition.y },
                                });
                        
                                sf.ui.proTools.invalidate()
                            }
                        }
                        
                        
                        /**
                        * @param {string | any[]} selectedTracks
                        */
                        function getTrackNameTransientTime(selectedTracks) {
                        
                            let startTime
                            let trackList = []
                        
                            sf.ui.proTools.menuClick({ menuPath: ["Options", "Tab to Transient"], targetValue: "Enable" })
                        
                            for (let i = 0; i < selectedTracks.length; i++) {
                        
                                sf.ui.proTools.trackDeselectAll()
                        
                                sf.ui.proTools.trackSelectByName({ names: [selectedTracks[i]] })
                        
                                sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"] });
                        
                                sf.keyboard.press({ keys: "tab" });
                        
                                startTime = sf.ui.proTools.selectionGetInSamples().selectionStart
                        
                                trackList[i] = {
                                    trackName: selectedTracks[i],
                                    startTime: +startTime
                                }
                            }
                            return trackList
                        }
                        
                        
                        /**
                        * @param {number} h
                        */
                        function getCurrentTrackHeight(h) {
                            let originalTrackHeight;
                        
                            switch (true) {
                                case (h <= 16):
                                    originalTrackHeight = 'micro';
                                    break;
                                case (h === 23):
                                    originalTrackHeight = 'mini';
                                    break;
                                case (h >= 43 && h <= 61):
                                    originalTrackHeight = 'small';
                                    break;
                                case (h >= 79 && h <= 116):
                                    originalTrackHeight = 'medium';
                                    break;
                                case (h >= 135 && h <= 235):
                                    originalTrackHeight = 'large';
                                    break;
                                case (h >= 257 && h <= 420):
                                    originalTrackHeight = 'jumbo';
                                    break;
                                case (h > 440):
                                    originalTrackHeight = 'extreme';
                                    break;
                            };
                            return originalTrackHeight
                        
                        };
                        
                        /**
                        * @param {string} size
                        */
                        function setTrackSize(size) {
                        
                            const selectedTrackNames = sf.ui.proTools.selectedTrackNames
                        
                            const firstSelected = sf.ui.proTools.trackGetByName({ name: selectedTrackNames[0] }).track
                        
                            firstSelected.trackScrollToView()
                        
                            sf.ui.proTools.trackSelectByName({ names: selectedTrackNames })
                        
                        
                            const f = sf.ui.proTools.selectedTrack.frame
                        
                            if (getCurrentTrackHeight(f.h) != size) {
                        
                                const popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({
                                    relativePosition: { x: f.w - 10, y: 5 },
                                    isOption: true,
                                    isShift: true,
                                }).popupMenu;
                        
                                popupMenu.menuClickPopupMenu({
                                    menuPath: [size]
                                });
                            }
                        }
                        
                        
                        function main() {
                        
                            sf.ui.proTools.appActivateMainWindow();
                            sf.ui.proTools.invalidate()
                        
                            var sortAnswer = sf.interaction.displayDialog({
                                title: 'Select display order',
                                prompt: "Where do want the first entrance to be?",
                                buttons: ["Cancel", "Top", "Bottom"],
                                defaultButton: "Top"
                            }).button
                        
                            var sortInverter = (sortAnswer == "Top") ? -1 : 1;
                            const originalTrackHeight = getCurrentTrackHeight(sf.ui.proTools.selectedTrack.frame.h)
                        
                            setTrackSize("micro")
                        
                            const selectedTracks = sf.ui.proTools.selectedTrackNames
                        
                            const trackList = getTrackNameTransientTime(selectedTracks)
                        
                            // ///  Sort array of objects by property. ? 1:-1 ascending / ? -1:1 descending 
                            const tracksToMove = trackList.sort((a, b) => (a.startTime > b.startTime) ? 1 * sortInverter : -1 * sortInverter).map(track => track.trackName)
                        
                            try {
                        
                                moveTracksToTop(selectedTracks, tracksToMove)
                        
                                sf.ui.proTools.trackSelectByName({ names: selectedTracks })
                        
                                //  Check if order is correct, if not, repeat.
                                if (sf.ui.proTools.selectedTrackNames.join(",") != tracksToMove.reverse().toString()) { main() }
                        
                            } catch (err) { log("An error occurred trying to sort tracks.") }
                        
                            setTrackSize(originalTrackHeight)
                        
                            alert("Sorted!")
                        }
                        
                        
                        
                        
                        main()
                        
                        1. M
                          In reply toHendrick_Valera:
                          Matt Neveu @Matt_Neveu
                            2024-05-02 17:25:09.014Z

                            I am having issues with line 115 not being able to execute. I think it might be something with that popup menu not being found any ideas o how to fix this Thanks so much!

                            1. try inserting this at line 116:

                              anchor: "TopLeft",
                              

                              Don't forget the comma at the end

                            2. M
                              In reply toHendrick_Valera:
                              Matt Neveu @Matt_Neveu
                                2024-05-03 14:48:54.144Z

                                Awesome thanks so much!

                                1. D
                                  In reply toHendrick_Valera:
                                  Dave Weingarten @Dave_Weingarten
                                    2025-02-19 05:56:49.834Z

                                    @Chris_Shaw I can't get this to work for some reason. Also stuck at line 115 and tried the script you suggested at line 116. Maybe I'm dealing with too many tracks at once? Thank you!