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

Protools "deselect tracks" not working

By Rob Sannen @Rob_Sannen
    2026-02-12 12:07:29.555Z

    Title

    Protools "deselect tracks" not working

    Content type

    script

    Content name

    Test Script Tim Artist Archive

    Content package

    Tim Test

    Version info

    OS: macOS 15.6.1
    SoundFlow: 6.0.6
    Pro Tools: 24.10.3.210

    What do you expect to happen when you run the script?

    Rename audio files based on prefilled information

    Are you seeing an error?

    error on line 232 can't deselect tracks

    What happens when you run the script?

    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

    {
        "textExpected": "Rename audio files based on prefilled information",
        "textError": "error on line 232\ncan't deselect tracks",
        "inputHowRun": "I clicked the Run Script or Run Macro button in SoundFlow",
        "inputImportance": 5,
        "textTitle": "Protools \"deselect tracks\" not working"
    }

    Source

    const projectDir = sf.ui.proTools.mainWindow.sessionPath.split('/').slice(0, -1).join('/');
    const tempoMapFileName = 'tempomap.txt'
    
    function sanitisedArtistTrackName(artist, songTitle, bpm, instrumentName, sampleRate, bitDepth) {
        let rawNameString = `${artist} - ${songTitle} - ${String(bpm).trim()} - ${instrumentName} - ${String(sampleRate).trim()}${bitDepth}`;
        rawNameString = rawNameString.replace(/[\?\*\.\'\"']/g, "_");
        rawNameString = rawNameString.replace(/[\\]/g, "");
        return rawNameString.toLowerCase();
    }
    
    function extractNumber(str) {
        // Extract the first number found in the string
        const match = str.match(/-?\d+/);
        if (!match) {
            throw new Error("No number found in the string");
        }
        const num = match[0];
        return num;
    }
    
    function singlePressKey(key) {
            sf.keyboard.press({
            keys: key,
            repetitions: 1
        });
    }
    
    function formatExtractedNumber(str) {
        // Extract the first number found in the string
        const match = str.match(/\d+/);
        if (!match) {
            throw new Error("No number found in the string");
        }
        const num = match[0];
        // Convert the extracted number to a string and pad it
        return num.toString().padStart(3, '0');
    }
    
    function getTempoWriteMap() {
    
        let selection = sf.ui.proTools.selectionGet()
        let {inTime, outTime} = sf.app.proTools.getTimelineSelection();
    
        let originalOut = outTime;
    
        
    
        let offsetBars = extractNumber(selection.mainCounter) - 1;
    
        sf.ui.proTools.nudgeSet({executionMode: "Foreground", value: "0|0|480"});
    
        //workaround for bug - nudgeSet does set value but not mode
        const nudgeBtn = sf.ui.proTools.mainWindow.gridNudgeCluster.nudgeControls
        nudgeBtn.nudgeValuePopupButton.popupMenuSelect({ menuPath: ["Bars|Beats"] });
        
    
        singlePressKey('return');
        sf.ui.proTools.mainWindow.invalidate();
        sf.ui.proTools.selectionSet(
            {
                selectionStart: selection.selectionStart,
                selectionEnd: selection.selectionStart
            }
        );
    
        singlePressKey('period');
        singlePressKey('comma');
    
        sf.ui.proTools.mainWindow.invalidate();
    
    
        let tempoField = prepareTempoField()
        let i = 0;
        let currentTimePos = inTime;
        let curSelection;
        let oldTempo = _getTempo(tempoField);
        let newTempo;
        let tempoMapRaw = new Array();
        tempoMapRaw.push(`${selection.mainCounter}: ${oldTempo}`); 
    
        while(Number(currentTimePos) < Number(originalOut)) {
            singlePressKey('period');
            newTempo = _getTempo(tempoField);
            if(Number(newTempo) != Number(oldTempo)){
                curSelection = sf.ui.proTools.selectionGet();
                oldTempo = newTempo;
                tempoMapRaw.push(`${curSelection.mainCounter}: ${newTempo}`); 
            }
            let {inTime, outTime} = sf.app.proTools.getTimelineSelection();
            currentTimePos = inTime;
            sf.ui.proTools.mainWindow.invalidate();
        }
    
        sf.ui.proTools.selectionSet(
            {
                selectionStart: selection.selectionStart,
                selectionEnd: selection.selectionEnd
            }
        );
    
    
        if(tempoMapRaw.length > 1) {
            let tempoMapSanatised = new Array();
            var count = 0;       
            tempoMapRaw.forEach( bar => {
    
    
                if(count == 0)
                {
                    bar = bar.replace(/  -?\d+\| \d+\| \d+/, '1| 0| 000')
                }
                else
                {         
                    let originalBar = extractNumber(bar)
                    let match = bar.replace(/-?\d+/, '');
    
                    bar = String(originalBar - offsetBars) + match.trim()
                }
                tempoMapSanatised.push(bar);
                count++;
            })
    
            var text = tempoMapSanatised.join('\n');
            var fullTempoMapPath =  [projectDir, tempoMapFileName].join('/');
            if(sf.file.exists({path: fullTempoMapPath})) {
                sf.file.delete({path: fullTempoMapPath})
            }
            sf.file.writeText({path: fullTempoMapPath, text: text})
            log(`Various BPM - created Tempo Map at ${fullTempoMapPath}`);
            return 'variousBPM see tempomap file';
        }
        else {
            return String(oldTempo).replace('.', '_') + 'bpm'
    
        }
    }
    
    function prepareTempoField() {
        //Check if MIDI Controls Cluster is visible and if not open it.
        sf.ui.proTools.appActivateMainWindow();
        sf.ui.proTools.mainWindow.invalidate();
    
        const midiControlCluster = sf.ui.proTools.mainWindow.midiControlCluster;
        const tempoField = midiControlCluster.getFirstWithTitle('Tempo value');
    
        if (!tempoField.exists) {
            //Open the Toolbar Options Menu
            sf.ui.proTools.mainWindow.toolbarOptionsMenuButton.elementClick();
    
            const zoomControls = sf.ui.proTools.windows.whoseTitle.endsWith("Zoom Controls").first;
    
            //Wait for the Toolbar Options Menu to be open (by waiting for first menu Item)
            zoomControls.elementWaitFor();
    
            //Enable MIDI Controls
            zoomControls.menuItems.whoseTitle.is("MIDI Controls").first.elementClick();
    
            //Close the Toolbar Options Menu
            sf.ui.proTools.appActivateMainWindow();
    
            //The main window changed because the midi cluster was added,
            //so invalidate the main window
            sf.ui.proTools.mainWindow.invalidate();
        }
    
            // Enable Bars|Beats view
            sf.ui.proTools.menuClick({
                menuPath: [
                    "View", "Main Counter",  "Bars|Beats",
                ]
            }, `Could not find the menu item in Pro Tools`);
    
        return tempoField;
    }
    
    function _getTempo(tempoField) {
        //Collect BPM into variable beatsPerMinute
        return tempoField.value.invalidate().value;
    }
    
    
    function getTempo() {
        let tempoField = prepareTempoField(); 
        return _getTempo(tempoField);
    }
    
    function getPTVersion() {
        const versNumberArray = sf.ui.proTools.appVersion.split(".")
        let [year, month, increment] = versNumberArray
        month = "0" + month.slice(-2)
        increment = "0" + increment.slice(-2)
        let versionNumber = Number(year + month + increment)
        return versionNumber
    }
    
    const PACKAGE_DIRECTORY = sf.soundflow.thisPackage.getDirectory().path;
    const previousValuesPath = `${PACKAGE_DIRECTORY}/Previous_Entries_Artist_Archive.json`
    
    
    //          ////////////////
    //          ///// MAIN /////
    //          ////////////////
    
    sf.ui.proTools.appActivateMainWindow()
    
    // Check for and load previous entries
    let prevArtist, prevSongTitle;
    if (sf.file.exists({ path: previousValuesPath }).exists) {
        let previousEntries = sf.file.readJson({ path: previousValuesPath }).json;
        ({
            prevArtist,
            prevSongTitle
        } = previousEntries)
    }
    
    // Instruct user to select tracks to be renamed
    sf.interaction.displayDialog({
        prompt: "Select tracks in session to be renamed and click OK",
        buttons: ["Cancel", "OK"],
        defaultButton: "OK"
    }).text
    
    // Show only selected tracks
    const trackListPopupBtn = sf.ui.proTools.mainWindow.trackListPopupButton
    trackListPopupBtn.popupMenuSelect({ menuPath: ["Show Only Selected Tracks"] });
    
    // get artist name from user
    const artist = sf.interaction.displayDialog({
        prompt: "Enter artist name:",
        defaultAnswer: prevArtist ? prevArtist : "<Band Name>",
        buttons: ["Cancel", "OK"],
        defaultButton: "OK"
    }).text
    
    // get Song name from user
    const songTitle = sf.interaction.displayDialog({
        prompt: "Enter song title:",
        defaultAnswer: prevSongTitle ? prevSongTitle : "<Song Title>",
        buttons: ["Cancel", "OK"],
        defaultButton: "OK"
    }).text
    
    const { button } = sf.interaction.displayDialog({
        buttons: ['Single', 'Various', 'Cancel'],
        defaultButton: 'Single',
        cancelButton: 'Cancel',
        prompt: 'Does this song contain various BPM?',
    });
    
    const variousBPM = button === 'Various'
    
    // Get sample rate and bit depth from Session Setup window
    //      Open Session Setup if neccessary
    const sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first
    
    if (!sessionSetupWin.exists) {
        sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] })
        sessionSetupWin.elementWaitFor()
    }
    //      Get sample rate
    const sampleRate = sessionSetupWin.groups.whoseTitle.is("Session Format").first
        .children.whoseRole.is("AXStaticText").allItems[2].value.invalidate().value
        .split(" k")[0] + "k"
    
    //      Get bit depth
    const bitDepth = sessionSetupWin.groups.whoseTitle.is("Session Format").first.
        popupButtons.allItems[1].value.invalidate().value.split(" B")[0] + "b";
    
    //Close Session Info window
    sessionSetupWin.windowClose()
    sessionSetupWin.elementWaitFor({ waitType: "Disappear" })
    
    //Save entries to disk to reuse on next run
    const previousEntries = {
        prevArtist: artist,
        prevSongTitle: songTitle
    }
    sf.file.writeJson({ json: previousEntries, path: previousValuesPath })
    
    // Ensure time line and edit selection are linked
    var linkeTimeLineAndEditBtn = sf.ui.proTools.mainWindow.cursorToolCluster.buttons
        .whoseTitle.is("Link Track and Edit Selection").first
    if (linkeTimeLineAndEditBtn.value.invalidate().value !== "Selected") linkeTimeLineAndEditBtn.elementClick();
    
    var tempo;
    if(variousBPM) {
         tempo = getTempoWriteMap();
    }
    else {
        tempo = getTempo();
    }
    // Have user confirm entries
    sf.interaction.displayDialog({
        title: "Confirm Rename Tracks",
        prompt: `Confirm entries before proceeding.
    
    (Cancel to start over)
    
    Artist: ${artist}
    
    Song Title: ${songTitle}
    
    Tempo: ${tempo}
    
    Sample Rate: ${sampleRate}
    
    Bit Depth: ${bitDepth}
    -----------
    Sample Track Name = ${sanitisedArtistTrackName(artist, songTitle, tempo, "Kick_In", sampleRate, bitDepth)}`,
        buttons: ["Cancel", "OK"],
        defaultButton: "OK"
    });
    
    linkeTimeLineAndEditBtn = sf.ui.proTools.mainWindow.cursorToolCluster.buttons
        .whoseTitle.is("Link Track and Edit Selection").first
    if (linkeTimeLineAndEditBtn.value.invalidate().value !== "Selected") linkeTimeLineAndEditBtn.elementClick();
    
    // Get visible track headers
    let selectedTrackHeaders = sf.ui.proTools.visibleTrackHeaders;
    
    //Scroll to view first track
    sf.ui.proTools.trackDeselectAll()
    sf.ui.proTools.trackSelectByName({ names: [selectedTrackHeaders[0].normalizedTrackName] })
    sf.ui.proTools.selectedTrack.trackScrollToView()
    
    // Open rename window
    selectedTrackHeaders[0].popupButtons.first.mouseClickElement({ clickCount: 2 })
    
    // Wait for rename window
    sf.ui.proTools.windows.whoseTitle.is(selectedTrackHeaders[0].popupButtons.first.value.invalidate().value).first.elementWaitFor();
    
    //Get the elements of text fields and buttons  from rename window
    const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x)
    const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x)
    
    let previousName = '';
    let fulltrackName = '';
    let oldTrackName = '';
    //Rename Tracks
    selectedTrackHeaders.forEach(track => {
        // Construct track name
    
        while (previousName == trackName.value.invalidate().value)
        {
            sf.wait({ intervalMs: 2 })
        }
    
        oldTrackName = trackName.value.invalidate().value
        fulltrackName = `${sanitisedArtistTrackName(artist, songTitle, tempo, oldTrackName, sampleRate, bitDepth)}`;
     
    
    
        do { // Set new track name
            trackName.elementSetTextFieldWithAreaValue({
                value: fulltrackName,
            });
        }
        while(trackName.value.invalidate().value != fulltrackName)
        
        // If it's the last track press ok, else press next
        if (selectedTrackHeaders.indexOf(track) == selectedTrackHeaders.length - 1) {
            ok.elementClick()
        } else {
            next.elementClick()
        };
    })
    
    // ask user to confirm new track names before proceeding
    const confirmTrackNames = sf.interaction.displayDialog({
        title: "Confirm Rename Audio Files",
        prompt: `Please review and confirm track names before proceeding to renaming audio files.
    
    (You may need to make the track list wider to see full track names.)
    
    You can revert to the last saved version of the session if you would like to start again.
    
    You may also manually rename any mislabeled tracks before clicking "Proceed"`,
        buttons: ["Cancel", "Revert", "Proceed"]
    }).button;
    
    // Revert to saved if requested
    if (confirmTrackNames == "Revert") {
        sf.ui.proTools.menuClick({ menuPath: ["File", "Revert"], looseMatch: true })
        throw 0
    }
    
    // Rename Audio Files
    sf.ui.proTools.mainWindow.invalidate();
    
    // refresh track headers
    selectedTrackHeaders = sf.ui.proTools.visibleTrackHeaders
    
    if (getPTVersion() < 230600) {
    
        // If running older version of proTools run the following:
    
        const refreshMenus = () => sf.keyboard.press({ keys: "n", repetitions: 2, fast: true })
        selectedTrackHeaders.forEach(track => {
    
            sf.ui.proTools.trackSelectByName({ names: [track.normalizedTrackName] })
            refreshMenus()
            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"] })
            refreshMenus()
            sf.ui.proTools.menuClick({ menuPath: ["Clip", "Rename..."] })
    
            const clipNameWindow = sf.ui.proTools.windows.whoseTitle.is("Name").first
            clipNameWindow.elementWaitFor()
    
            //Define clip rename window elements
            const nameGroup = clipNameWindow.groups.whoseTitle.is("Name").first
            const clipNameField = nameGroup.textFields.first;
            const clipAndDiskBtn = nameGroup.radioButtons.whoseTitle.is("name clip and disk file").first;
            const nameOkBtn = clipNameWindow.buttons.whoseTitle.is("OK").first
    
            while (true) {
                if (clipNameField.value.invalidate().value !== track.normalizedTrackName) {
                    clipNameField.elementClick()
                    sf.keyboard.press({
                        keys: "backspace",
                        repetitions: 2
                    });
    
                    sf.wait({ intervalMs: 25 })
                    clipNameField.elementSetTextFieldWithAreaValue({ value: track.normalizedTrackName, useMouseKeyboard: true })
                    sf.wait({ intervalMs: 300 })
                    clipAndDiskBtn.elementClick()
                } else { break; }
            }
            nameOkBtn.elementClick()
        })
    } else {
        // If new version of PT run this
        selectedTrackHeaders.forEach(track => {
            //sf.app.proTools.selectAllClipsOnTrack({ trackName: track.normalizedTrackName });
            sf.ui.proTools.trackSelectByName({ names: [track.normalizedTrackName] })
    
            sf.ui.proTools.mainWindow.invalidate();
    
            let selectedClip = sf.app.proTools.getSelectedClipInfo().clips
      //      log(selectedClip)
            let { inTime, outTime } = sf.app.proTools.getTimelineSelection()
      //      log(`In Time: ${inTime}; Out Time: ${outTime}`)
     //       selectedClip.forEach(clip => {
      //          log(`Clip: In Time: ${clip.startTime}; Out Time: ${clip.endTime}`)
       //     })
            let hasSelectedClip = selectedClip.filter(clip => clip.startTime >= inTime && clip.endTime <= outTime).length > 0
            if(hasSelectedClip) {
                sf.app.proTools.renameSelectedClip({ newName: track.normalizedTrackName, renameFile: true })
            }
        })
        sf.app.proTools.refreshAllModifiedAudioFiles()
    }
    // Show previously selected tracks
    trackListPopupBtn.popupMenuSelect({ menuPath: ["Restore Previously Shown Tracks"] });
    
    sf.interaction.notify({ title: "Rename track and clips complete!" })
    

    Links

    User UID: bfBv1LrWwjVtTpPyywxpGsl1VGY2

    Feedback Key: sffeedback:bfBv1LrWwjVtTpPyywxpGsl1VGY2:-OlGjwaoaQTXVN8ju5tQ

    Feedback ZIP: 0ZOfxVLBqXxtQG0yxwckvUVPVWYhXYNeTzpuQYbuMI1FokwC8xfmwviwGbIDxNE88bjSBSROwdKHl/wwzMcS/I6nXis6sU+Mu4d0COdYOosxdLj57CxK2c9xEM4PYtG8yjcwduxDbEnIJ4xLK/vuUlMSWuf5JHWoihrkh3m9Tfj1h1fjmg6tmuGoHI0eBgI0Adr6A+Y/o41LhNg6n4SAdmvbKbMm0FQdKIx6wvFy/U9pWxSMdB8EjGho8vQaTdKx6FNgShR48MjD+eP+1XtJWmhlNQc8b9dx/40vr9hk61/5t50bCiTQ+mSSuvOrcS4M2bwhKAk/sLbRhF2wRZh99WeuFuukKtNhWe0K6nvGteQ=

    • 7 replies
    1. In reply toRob_Sannen:

      I believe you're referring to line 322.
      You may not need to deselect tracks since you're selecting tracks immediately afterward.
      Try commenting / removing sf.ui.proTools.trackDeselectAll.
      If this doesn't work then also change the next line to this:

      sf.ui.proTools.trackSelectByName({
          names: [selectedTrackHeaders[0].normalizedTrackName],
          deselectOthers: true
      })
      
      1. R
        In reply toRob_Sannen:
        Rob Sannen @Rob_Sannen
          2026-02-17 00:11:26.405Z

          Thanks for your reply!

          Line 322 is the correct one. The

          sf.ui.proTools.trackDeselectAll
          

          was only added as a debug measure, originally (and when commenting out the deselect) the exact same error occured in the next line:

          sf.ui.proTools.trackSelectByName({ names: [selectedTrackHeaders[0].normalizedTrackName] })
          

          Unfortunately your suggestion didn´t solve the issue.

          1. Chad Wahlbrink @Chad2026-02-17 21:01:52.007Z

            Hi, @Rob_Sannen,

            As a first troubleshooting step, could you please manually update to the latest version of SoundFlow here and see if that resolves your issue?

            https://soundflow.org/account/install

            If not, could you provide a quick screen recording of the behavior and share the link via Google Drive or Dropbox? That would be really helpful for narrowing down the issue you are experiencing.

            1. RRob Sannen @Rob_Sannen
                2026-02-18 08:36:34.411Z

                hi Chad,

                Please find a link of the screen recording below.

                https://drive.google.com/file/d/1rxBcXOXzpZLNzc5Excu7_Y3-Gveqnci8/view?usp=drive_link

                Bests,
                Rob

                1. Chad Wahlbrink @Chad2026-02-27 21:45:41.215Z

                  Thanks, @Rob_Sannen,

                  I'm currently unable to reproduce this issue, but I do see it happening in your video. I attempted to run your script on Pro Tools 2025.10.4.2 (what I had on hand) and Pro Tools 2025.12.1 and it worked in both scenarios.

                  A few more questions for you.

                  The error in the logs are:

                  12.02.2026 13:05:57.38 <info> [Backend]: ProTools version: 24.10.3.210 class: PT2024_10
                  ProTools processID: 75556
                  
                  12.02.2026 13:05:57.38 <info> [Backend]: Pro Tools language: English
                  
                  12.02.2026 13:05:57.38 <info> [Backend]: Logging error in action (01) PtAppSelectTracksByNameAction: This command requires Pro Tools to run in Rosetta / x64 mode
                  
                  12.02.2026 13:05:57.38 <info> [Backend]: Logging error in action (01) DeselectTracksAction: Could not deselect tracks
                  
                  12.02.2026 13:05:57.38 <info> [Backend]: !! Command Error: Test Script Tim Artist Archive [user:cm94t6d3j0000ah10q9rkihd6:cm9bxmhyw0001uc102clk0nik]:
                  Could not deselect tracks (Test Script Tim Artist Archive: Line 322)
                      This command requires Pro Tools to run in Rosetta / x64 mode
                  
                  
                  12.02.2026 13:05:57.38 <info> [Backend]: << Command: Test Script Tim Artist Archive [user:cm94t6d3j0000ah10q9rkihd6:cm9bxmhyw0001uc102clk0nik]
                  

                  Can you provide more details on what type of computer you are running this on? What kind of mac? I've never seen the This command requires Pro Tools to run in Rosetta / x64 mode error before, but this suggests there may be some kind of system issue we are missing.

                  Other options to try:

                  As Chris suggested, try changing lines 318 to 324 to this, which also works here for me:

                  // Get visible track headers
                  let selectedTrackHeaders = sf.ui.proTools.visibleTrackHeaders;
                  
                  //Scroll to view first track
                  // sf.ui.proTools.trackDeselectAll()
                  sf.ui.proTools.trackSelectByName({ names: [selectedTrackHeaders[0].normalizedTrackName], deselectOthers: true })
                  sf.ui.proTools.selectedTrack.trackScrollToView();
                  

                  OR

                  Simplify to this, since sf.ui.proTools.selectedTrack.trackScrollToView(); will automatically deselect the other tracks and only apply to the first selected track - changed selectedTrackHeaders to sf.ui.proTools.selectedTrackHeaders; as well:

                  // Get selected track headers
                  let selectedTrackHeaders = sf.ui.proTools.selectedTrackHeaders;
                  
                  //Scroll to view first track
                  sf.ui.proTools.selectedTrack.trackScrollToView();
                  

                  Let me know if any of those options get you in the right direction.

                  1. Chad Wahlbrink @Chad2026-02-27 21:47:39.107Z

                    Finally, I would tweak the end of your script to read like this:

                    else {
                        // If new version of PT run this
                        selectedTrackHeaders.forEach(track => {
                            //sf.app.proTools.selectAllClipsOnTrack({ trackName: track.normalizedTrackName });
                            sf.ui.proTools.trackSelectByName({ names: [track.normalizedTrackName] })
                    
                            sf.ui.proTools.mainWindow.invalidate();
                    
                            let selectedClip = sf.app.proTools.getSelectedClipInfo().clips
                            //      log(selectedClip)
                            let { inTime, outTime } = sf.app.proTools.getTimelineSelection()
                            //      log(`In Time: ${inTime}; Out Time: ${outTime}`)
                            //       selectedClip.forEach(clip => {
                            //          log(`Clip: In Time: ${clip.startTime}; Out Time: ${clip.endTime}`)
                            //     })
                            let hasSelectedClip = selectedClip.filter(clip => clip.startTime >= Number(inTime) && clip.endTime <= Number(outTime)).length > 0
                            if (hasSelectedClip) {
                                sf.app.proTools.renameSelectedClip({ newName: track.normalizedTrackName, renameFile: true })
                            }
                        })
                        sf.app.proTools.refreshAllModifiedAudioFiles()
                    }
                    // Show previously selected tracks
                    trackListPopupBtn.popupMenuSelect({ menuPath: ["Restore Previously Shown Tracks"] });
                    
                    sf.interaction.notify({ title: "Rename track and clips complete!" })
                    

                    This line is what changed:

                     let hasSelectedClip = selectedClip.filter(clip => clip.startTime >= Number(inTime) && clip.endTime <= Number(outTime)).length > 0
                    
            2. Progress
            3. S
              SoundFlow Bot @soundflowbot
                2026-02-12 18:14:28.227Z
                SoundFlow support ticket: SFSUP-110