No internet connection
  1. Home
  2. Packages
  3. Stem Bounce

I'm getting a Line 80 error

By Jordan Young @Jordan_Young
    2023-03-18 02:08:56.016Z

    Hi David,

    I seem to have a new problem with Stem Bounce. Last week it worked fine and this week, after an update, it seems to be struggling. I've named every track, deleted what isn't names, turned all my groups and whatnot off. I highlight the entire song with all tracks, enter the workflow, and I can get up to the point where I name the stems folder and choose the output. But from there I get a failed error, citing Line 80. "Popup Menu was not found. Bounce Tracks: Line 80. Popup window was not found after waiting 2000ms."

    Any ideas?

    • 9 replies
    1. S
      SoundFlow Bot @soundflowbot
        2023-03-18 02:08:58.812Z

        Thanks for posting a question or an issue related to the 'Stem Bounce' package.
        This package is made by @David_Simpson. We're auto-tagging them here so that they will hopefully be able to help you.

        Please note, that the best way to get help with a script, macro or other content installed from the Store is to select the script you installed, then click the red Need help button, and then click "Get help with this script or macro".
        By using this workflow, the developer of the package will get access to more information so they'll be able to help you quicker.
        You can read more about how to best get help in this article: bit.ly/sfscripthelp

        1. B
          In reply toJordan_Young:
          Bao Pham @Bao_Pham
            2024-03-25 02:40:46.465Z

            Having this exact same issue. I'm currently on 2024.3. was working fine on 2023.12. @David_Simpson could you please update?

            1. B
              In reply toJordan_Young:
              Bao Pham @Bao_Pham
                2024-03-25 02:47:15.638Z

                Here's a link to fix the script, something has changed in the latest protools updates

                I had an issue with the pop up menu as well, and this part of the script should fix the issue. Just need @David_Simpson to kindly update please

                1. In reply toJordan_Young:

                  SF 5.7 now clicks elements in the center middle instead of the top left. While this shouldn't effct most scripts, if you are using relative clicks then you probably need to set the anchor property to "TopLeft".
                  See this post for other options and detailed explanation: Track Height selection not working with PT 2024.3 #post-2

                  1. BBao Pham @Bao_Pham
                      2024-03-25 16:22:55.520Z

                      i'm on 5.7.6, i would change it myself but the script is not open or made available to change. Hopefully @David_Simpson can get to it, but from the looks of past posts he's not very active on here. I may have to look for another stem bouncing package elsewhere, but his is excellent, just doesn't work right now with 2024.3

                    • E
                      In reply toJordan_Young:
                      Edward Sokolowski @Edward_Sokolowski
                        2024-04-06 18:51:20.562Z

                        Would love for this script to be updated, it was so good but PT broke compatibility with it a few versions back.

                        1. T
                          In reply toJordan_Young:
                          T Michaels @T_Michaels
                            2024-04-08 12:35:09.506Z

                            I can't get access to the actual script code anymore, but when I first had this problem and posted it on here I somehow did get to see it. Pasted below, if anyone can help out seems like there'd be a bunch of us here very grateful!

                            sf.ui.proTools.appActivateMainWindow()
                            sf.ui.proTools.windows.invalidate()
                            sf.ui.proTools.mainWindow.invalidate()

                            let bouncedStems = []

                            // FUNCTIONS -------------------------------------------------------------------------------------

                            // SAVE USER CONFIG WINDOW
                            function saveUserWinConfig() {
                            sf.ui.proTools.appActivateMainWindow()
                            sf.ui.proTools.menuClick({ menuPath: ['Window', 'Configurations', 'New Configuration...'] })
                            // Wait for the Mem Location dialog to appear and assign it to the memLocDlg variable
                            const winConfigDlg = sf.ui.proTools.dialogWaitForManual({
                            dialogTitle: 'New Window Configuration'
                            }).dialog

                            // We want to save a window layout
                            winConfigDlg.radioButtons[1].elementClick()
                            
                            // We want to include all windows
                            winConfigDlg.checkBoxes[0].checkboxSet({ targetValue: 'Enable' })
                            
                            // Name the Location Track Visibilty
                            winConfigDlg.textFields.allItems[1].elementSetTextFieldWithAreaValue({ value: 'User Window Setup' })
                            
                            // Get the Location Number and pass it back so we can delete it when we're done
                            const configNumber = winConfigDlg.textFields.allItems[0].value.invalidate().value
                            
                            // Create the Location
                            winConfigDlg.buttons.whoseTitle.is('OK').first.elementClick()
                            
                            sf.ui.proTools.windows.whoseTitle.is('New Window Configuration').first.elementWaitFor({
                                waitType: 'Disappear'
                            })
                            
                            return configNumber
                            

                            }

                            // RECALL AND DELETE WINDOW CONFIG
                            function recallAndDeleteWinConfig(configNumber) {
                            sf.ui.proTools.appActivateMainWindow()
                            sf.ui.proTools.menuClick({
                            menuPath: ['Window', 'Configurations', 'Window Configuration List'],
                            targetValue: 'Enable'
                            })
                            sf.ui.proTools.windows.whoseTitle.is('Window Configurations').first.elementWaitFor()

                            const winConfigWindow = sf.ui.proTools.windows.whoseTitle.is('Window Configurations').first
                            
                            // Recall Window Config which will also leave it selected for deleting
                            const configNumStr = configNumber.toString()
                            
                            let winConfigWords = 'numpad comma, '
                            for (let i = 0; i < configNumStr.length; i++) {
                                winConfigWords = winConfigWords.concat('numpad ' + configNumStr[i] + ', ')
                            }
                            
                            let keys = winConfigWords + 'numpad multiply'
                            sf.keyboard.press({ keys: keys })
                            
                            sf.ui.proTools.windows.whoseTitle.is('Window Configurations').first.buttons.first.popupMenuSelect({
                                menuSelector: items => items.filter(i => i.names[0].match(/^Clear \"/))[0]
                            })
                            
                            sf.ui.proTools.menuClick({
                                menuPath: ['Window', 'Configurations', 'Window Configuration List'],
                                targetValue: 'Disable'  //or 'Enable' or 'Toggle'
                            })
                            
                            sf.ui.proTools.windows.whoseTitle.is('Window Configurations').first.elementWaitFor({
                                waitType: 'Disappear'
                            })
                            

                            }

                            // SET SELECTED TRACKS SIZE
                            function setSelectedTracksSize(size) {
                            const f = sf.ui.proTools.selectedTrack.frame
                            const popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({
                            relativePosition: { x: f.w - 10, y: 5 },
                            isOption: true,
                            isShift: true
                            }).popupMenu

                            popupMenu.menuClickPopupMenu({ menuPath: [size] })
                            

                            }

                            // SAVE CURRENT TRACK VIEW
                            function saveCurrentTrackView() {
                            sf.ui.proTools.appActivateMainWindow()
                            sf.keyboard.press({ keys: 'numpad enter' })
                            sf.ui.proTools.newMemoryLocationDialog.elementWaitFor()

                            //Wait for the Mem Location dialog to appear and assign it to the memLocDlg variable
                            const memLocDlg = sf.ui.proTools.dialogWaitForManual({
                                dialogTitle: 'New Memory Location'
                            }).dialog
                            
                            // We only want to store the track visibilty so clear all check boxes and then check the appropriate one
                            let checkBoxes = memLocDlg.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXCheckBox' })
                            for (let i = 0; i < 6; i++) {
                                checkBoxes[i].checkboxSet({
                                    targetValue: 'Disable'
                                })
                            }
                            
                            checkBoxes[2].checkboxSet({ targetValue: 'Enable' })
                            checkBoxes[3].checkboxSet({ targetValue: 'Enable' })
                            
                            //Name the Location Track Visibilty
                            sf.ui.proTools.newMemoryLocationDialog.textFields.allItems[1].elementSetTextFieldWithAreaValue({
                                value: 'Track Visibility'
                            })
                            //Get the Location Number and pass it back so we can delete it when we're done
                            const locationNumber = sf.ui.proTools.newMemoryLocationDialog.textFields.allItems[2].value.value
                            
                            // Set time Properties to none
                            sf.ui.proTools.newMemoryLocationDialog.radioButtons.allItems[2].elementClick()
                            
                            //Create the Location
                            sf.ui.proTools.newMemoryLocationDialog.buttons.whoseTitle.is('OK').first.elementClick()
                            
                            sf.ui.proTools.newMemoryLocationDialog.elementWaitFor({ waitType: 'Disappear' })
                            
                            return locationNumber
                            

                            }

                            // RECALL AND DELETE TRACK VIEW
                            function recallAndDeleteTrackView(locNumber) {

                            sf.ui.proTools.memoryLocationsGoto({
                                memoryLocationNumber: Number(locNumber)
                            })
                            
                            sf.ui.proTools.memoryLocationsShowWindow()
                            
                            sf.ui.proTools.memoryLocationsWindow.popupButtons.whoseTitle.is('Memory Locations').first.popupMenuSelect({
                                menuSelector: items => items.filter(i => i.names[0].match(/^Clear \"/))[0]
                            })
                            
                            sf.ui.proTools.menuClick({
                                menuPath: ['Window', 'Memory Locations'],
                                targetValue: 'Disable'  //or 'Enable' or 'Toggle'
                            })
                            
                            sf.ui.proTools.memoryLocationsWindow.elementWaitFor({
                                waitType: 'Disappear'
                            })
                            

                            }

                            // SUSPEND GROUPS
                            function suspendGroups(status) {
                            sf.ui.proTools.groupsEnsureGroupListIsVisible()

                            const groupListPopup = sf.ui.proTools.groupsOpenListPopupMenu().popupMenu
                            groupListPopup.menuClickPopupMenu({
                                menuPath: ['Suspend All Groups'],
                                targetValue: status
                            })
                            
                            sf.ui.proTools.appActivateMainWindow()
                            

                            }

                            // LINK TRACK AND EDIT SELECTION
                            function linkTrackAndEditSelection() {
                            if (!sf.ui.proTools.getMenuItem('Options', 'Link Track and Edit Selection').isMenuChecked) {
                            sf.ui.proTools.menuClick({
                            menuPath: ["Options", "Link Track and Edit Selection"],
                            })
                            }
                            }

                            // SETUP SCREEN
                            function setupScreen() {
                            // Make sure we're on the Edit window
                            if (!sf.ui.proTools.getMenuItem('Window', 'Edit').isMenuChecked) {
                            sf.ui.proTools.menuClick({ menuPath: ['Window', 'Edit'] })
                            }

                            // Make sure comments are visible
                            if (!sf.ui.proTools.getMenuItem('View', 'Edit Window Views', 'Comments').isMenuChecked) {
                                sf.ui.proTools.menuClick({ menuPath: ['View', 'Edit Window Views', 'Comments'] })
                            }
                            

                            }

                            // GET SESSION SAMPLE-RATE AND BIT-DEPTH
                            function getSessionFormat() {
                            sf.ui.proTools.menuClick({ menuPath: ['Setup', 'Session'] })

                            let sessionDlg = sf.ui.proTools.dialogWaitForManual({
                                dialogTitle: 'Session Setup'
                            }).dialog
                            
                            sf.ui.proTools.windows.whoseTitle.is('Session Setup').waitFor()
                            
                            let sampleRate = sessionDlg.groups.whoseTitle.is('Session Format').first.children.whoseRole.is('AXStaticText').allItems[2].value.invalidate().value
                            let bitDepth = sessionDlg.groups.whoseTitle.is('Session Format').first.children.whoseRole.is('AXPopUpButton').allItems[1].value.invalidate().value
                            
                            sf.ui.proTools.viewCloseFocusedFloatingWindow()
                            
                            return [sampleRate, bitDepth]
                            

                            }

                            // INPUT STEM PREFIX
                            function inputStemPrefix() {
                            return sf.interaction.popupText({
                            popupIdentifier: 'stemPrefix',
                            title: 'Stem Prefix'
                            }).text
                            }

                            // SELECT BOUNCE OUTPUT
                            function selectBounceOutput() {
                            sf.ui.proTools.menuClick({
                            menuPath: ['File', 'Bounce Mix...'],
                            })

                            let bounceDlg = sf.ui.proTools.dialogWaitForManual({
                                dialogTitle: 'Bounce Mix'
                            }).dialog
                            
                            sf.ui.proTools.windows.whoseTitle.is('Bounce Mix').waitFor()
                            
                            let mainPanelBtns = bounceDlg.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXPopUpButton' })
                            let outputBtn = mainPanelBtns[1]
                            let outputs = outputBtn.popupMenuFetchAllItems().menuItems
                            let outputGroups = []
                            let groupOutputs = []
                            
                            for (let i = 0; i < outputs.length; i++) {
                                const outputGroup = outputs[i].path[0]
                            
                                if (!outputGroups.includes(outputGroup)) {
                                    outputGroups.push(outputGroup)
                                }
                            }
                            
                            let outputGroupsList = []
                            outputGroups.map(outputGroup => outputGroupsList.push({ name: outputGroup }) )
                            
                            sf.ui.proTools.appActivateMainWindow()
                            sf.ui.proTools.windows.whoseTitle.is('Bounce Mix').first.buttons.whoseTitle.is('Cancel').first.elementClick()
                            
                            sf.ui.proTools.waitForNoModals()
                            
                            while (sf.ui.frontmostApp.title.value !== 'Pro Tools') {
                                sf.wait({ intervalMs: 500 })
                            }
                            
                            const selectedOutputGroup = sf.interaction.popupSearch({
                                items: outputGroupsList,
                                title: 'Select output group'
                            }).item.name
                            
                            for (let i = 0; i < outputs.length; i++) {
                                const outputGroup = outputs[i].path[0]
                            
                                if (outputGroup === selectedOutputGroup) {
                                    groupOutputs.push(outputs[i].path[1])
                                }
                            }
                            
                            let groupOutputsList = []
                            groupOutputs.map(groupOutput => groupOutputsList.push({ name: groupOutput }) )
                            
                            const selectedOutput = sf.interaction.popupSearch({
                                items: groupOutputsList,
                                title: 'Select output'
                            }).item.name
                            
                            return [selectedOutputGroup, selectedOutput]
                            

                            }

                            // GET STEM NAMES
                            function getStemNames(selectedTracks) {
                            let stems = []

                            for (let i = 0; i < selectedTracks.length; i++) {
                                const stemName = sf.ui.proTools.trackGetByName({ name: selectedTracks[i] }).track.textFields.first.value.value
                            
                                if (!stems.includes(stemName)) {
                                    stems.push(stemName)
                                }
                            }
                            
                            return stems
                            

                            }

                            // CHANGE TRACK ACTIVITY
                            function changeTrackActivity(status) {
                            if (sf.ui.proTools.getMenuItem('Track', status).exists) {
                            sf.ui.proTools.menuClick({ menuPath: ['Track', status] })
                            }

                            sf.wait()
                            

                            }

                            // SELECT AND SCROLL TO TRACK
                            function selectAndScrollTracks(tracks) {
                            sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] })
                            sf.ui.proTools.confirmationDialog.elementWaitFor()
                            sf.ui.proTools.confirmationDialog.textFields.first.elementSetTextFieldWithAreaValue({ value: tracks[0] })
                            sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('OK').first.elementClick()
                            sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: 'Disappear' })
                            sf.ui.proTools.trackSelectByName({ names: tracks, deselectOthers: true })
                            }

                            // GET TRACK WIDTH
                            function getTrackWidth(track) {
                            var width = track.groups.whoseTitle.is('Audio IO').first.sliders.whoseTitle.contains('Pan').count
                            return width
                            }

                            // SET DYN VALUE
                            function setDynPopupBtn(targetValue) {
                            const btn = sf.ui.proTools.selectedTrack.popupButtons.whoseTitle.startsWith('Voice selector').first

                            btn.popupMenuSelect({
                                menuPath: [targetValue],
                                isOption: true,
                                isShift: true
                            })
                            

                            }

                            // SET TRACK VOICE SELECTOR
                            function setTrackVoiceSelector({ targetValue }) {
                            sf.ui.proTools.appActivateMainWindow()
                            sf.ui.proTools.mainWindow.invalidate()

                            const originalTrackNames = sf.ui.proTools.selectedTrackNames
                            
                            const selectedTrackHeaders = sf.ui.proTools.selectedTrackHeaders
                            
                            const trackInfo = selectedTrackHeaders.map(track => ({
                                trackTitle: track.normalizedTrackName,
                                trackType: track.title.invalidate().value.split(' - ')[1].trim(),
                                trackWidth: getTrackWidth(track)
                            }))
                            
                            setSelectedTracksSize('medium')
                            
                            // @ts-ignore
                            const trackWidths = [...new Set(trackInfo.map(t => t.trackWidth))]
                            
                            trackWidths.forEach(trackWidth => {
                            
                                if (trackWidth > 0 && trackWidth <= 2) {
                                    let trackNames = trackInfo
                                        .filter(track => track.trackWidth === trackWidth)
                                        .map(track => track.trackTitle)
                            
                                    let selectedTrackName = sf.ui.proTools.selectedTrack.normalizedTrackName
                            
                                    selectAndScrollTracks(trackNames)
                            
                                    setDynPopupBtn(targetValue)
                                }
                            })
                            
                            selectAndScrollTracks(originalTrackNames)
                            
                            setSelectedTracksSize('mini')
                            
                            selectAndScrollTracks(originalTrackNames)
                            

                            }

                            // BOUNCE STEMS
                            function bounceStems(selectedTracks, stems, stemPrefix, sessionFormat, bounceOutput) {

                            let firstLoop = true
                            
                            // Loop through stems
                            stems.forEach(stem => {
                                // Deselect all tracks
                                sf.ui.proTools.trackDeselectAll()
                            
                                // Select tracks with stem name in comments
                                selectedTracks.forEach(track => {
                                    const trackComment = sf.ui.proTools.trackGetByName({ name: track }).track.textFields.first.value.value
                            
                                    if (trackComment === stem) {
                                        sf.ui.proTools.trackSelectByName({ names: [track], deselectOthers: false })
                                    }
                                })
                            
                                // Scroll selected tracks into view
                                selectAndScrollTracks(sf.ui.proTools.selectedTracks.names)
                            
                                // Click first selected track (solves selection bug in PT)
                                const trackFrame = sf.ui.proTools.selectedTrack.frame
                                sf.mouse.click({ position: { 'x': trackFrame.x + 45, 'y': trackFrame.y + 10 } })
                            
                                // Make current stem tracks active, solo or dyn off
                                switch (event.props.method) {
                                    case 'Activity':
                                        changeTrackActivity('Make Active')
                                        break
                                    case 'Solo':
                                        sf.keyboard.press({ keys: 'shift+s' })
                                        break
                                    case 'Dyn':
                                        setTrackVoiceSelector({ targetValue: 'dyn' })
                                }
                            
                                if (event.props.exportType === 'Masters') {
                                    // Set selection length if none
                                    if (sf.ui.proTools.selectionGetInfo().isEmpty) {
                                        sf.ui.proTools.mainWindow.groups.whoseTitle.is("Counter Display Cluster").first.textFields.whoseTitle.is("Edit Selection Length").first.elementClick()
                                        sf.keyboard.type({ text: '1' })
                                        sf.keyboard.press({ keys: 'return' })
                                    }
                            
                                    // Select all clips in track
                                    sf.ui.proTools.children.whoseRole.is('AXMenuBar').whoseTitle.is('').first.children.whoseRole.is('AXMenuBarItem').whoseTitle.is('Edit').first.popupMenuSelect({
                                        menuPath: ['Select All']
                                    })
                                }
                            
                                // BOUNCE STEM TO DISK
                                try {
                                    bounceStem(stem, firstLoop, stemPrefix, sessionFormat, bounceOutput)
                                } catch(err) {
                                    // Make current stem tracks inactive
                                    switch (event.props.method) {
                                    case 'Activity':
                                        changeTrackActivity('Make Inactive')
                                        break
                                    case 'Solo':
                                        sf.keyboard.press({ keys: 'shift+s' })
                                        break
                                    case 'Dyn':
                                        setTrackVoiceSelector({ targetValue: 'off' })
                                }
                                    throw err
                                }
                            
                                firstLoop = false
                            
                                // Make current stem tracks inactive
                                switch (event.props.method) {
                                    case 'Activity':
                                        changeTrackActivity('Make Inactive')
                                        break
                                    case 'Solo':
                                        sf.keyboard.press({ keys: 'shift+s' })
                                        break
                                    case 'Dyn':
                                        setTrackVoiceSelector({ targetValue: 'off' })
                                }
                            })
                            
                            return bouncedStems
                            

                            }

                            // BOUNCE STEM
                            function bounceStem(stemName, firstRun, stemPrefix, sessionFormat, output) {

                            // Open Bounce dialogue
                            sf.ui.proTools.menuClick({ menuPath: ['File', 'Bounce Mix...'] })
                            let bounceDlg = sf.ui.proTools.dialogWaitForManual({
                                dialogTitle: 'Bounce Mix'
                            }).dialog
                            
                            //File Name
                            switch (event.props.exportType) {
                                case 'Stems':
                                    bounceDlg.textFields.whoseTitle.is('').first.elementSetTextFieldWithAreaValue({
                                        value: stemPrefix + '_' + event.props.stemSuffix + '_' + stemName
                                    })
                                    break
                                case 'Masters':
                                    bounceDlg.textFields.whoseTitle.is('').first.elementSetTextFieldWithAreaValue({
                                        value: stemName
                                    })
                                    break
                            }
                            
                            if (firstRun === true) {
                                const audioPanel = bounceDlg.groups.whoseTitle.is('Audio').first
                                const locationPanel = bounceDlg.groups.whoseTitle.is('Location').first
                            
                                // Maximise bounce window
                                function maximiseBounceWindow() {
                                    function openAudioPanel() {
                                        if (audioPanel.buttons.whoseTitle.is('Collapser').exists) {
                                            audioPanel.buttons.whoseTitle.is('Collapser').first.elementClick()
                                        }
                                    }
                                    function openLocationPanel() {
                                        if (locationPanel.buttons.whoseTitle.is('Collapser').exists) {
                                            locationPanel.buttons.whoseTitle.is('Collapser').first.elementClick()
                                        }
                                    }
                                    switch (bounceDlg.frame.h) {
                                        case 268:
                                            openAudioPanel()
                                            openLocationPanel()
                                            break
                                        case 406:
                                            openLocationPanel()
                                            break
                                        case 393:
                                            openAudioPanel()
                                            break
                                    }
                                }
                            
                                maximiseBounceWindow()
                            
                                let mainPanelBtns = bounceDlg.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXPopUpButton' })
                                let audioPanelBtns = audioPanel.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXPopUpButton' })
                                let mainCheckboxes = bounceDlg.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXCheckBox' })
                                let audioCheckboxes = audioPanel.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXCheckBox' })
                                let locationCheckboxes = locationPanel.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXCheckBox' })
                                let locationRadios = locationPanel.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXRadioButton' })
                                let locationText = locationPanel.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXTextField' })
                            
                                let fileTypeBtn = mainPanelBtns[0]
                                let outputBtn = mainPanelBtns[1]
                                let formatBtn = audioPanelBtns[1]
                                let bitDepthBtn = audioPanelBtns[2]
                                let sampleRateBtn = audioPanelBtns[3]
                                let mp3CheckBox = audioCheckboxes[0]
                                let padCheckBox = audioCheckboxes[1]
                                let importCheckBox = locationCheckboxes[0]
                                let sessionFolderButton = locationRadios[0]
                                let sessionFolderText = locationText[0]
                                let offlineCheckBox = mainCheckboxes[0]
                            
                                let sampleRate = sessionFormat[0]
                                let bitDepth = sessionFormat[1]
                            
                                //Set Output
                                if (outputBtn.value.invalidate().value != output) {
                                    outputBtn.popupMenuSelect({
                                        menuPath: output,
                                        useWildcards: true
                                    })
                                }
                            
                                //File Type
                                if (fileTypeBtn.value.invalidate().value != event.props.fileType)
                                    fileTypeBtn.popupMenuSelect({ menuPath: [event.props.fileType] })
                            
                                //File Format
                                if (formatBtn.value.value != 'Interleaved')
                                    formatBtn.popupMenuSelect({ menuPath: ['Interleaved'] })
                            
                                if (event.props.fileType !== 'MP3') {
                                    //Bit Depth
                                    if (event.props.bitDepth === 'session') {
                                        if (bitDepthBtn.value.invalidate().value != bitDepth)
                                            bitDepthBtn.popupMenuSelect({ menuPath: [bitDepth] })
                                    } else {
                                        if (bitDepthBtn.value.invalidate().value != event.props.bitDepth)
                                            bitDepthBtn.popupMenuSelect({ menuPath: [event.props.bitDepth] })
                                    }
                            
                                    // Add MP3
                                    mp3CheckBox.checkboxSet({
                                        targetValue: event.props.addMP3 ? 'Enable' : 'Disable',
                                    })
                            
                                    //Import After Bounce
                                    importCheckBox.checkboxSet({
                                        targetValue: 'Disable',
                                    })
                            
                                    // Pad To Frame Boundary
                                    padCheckBox.checkboxSet({
                                        targetValue: 'Disable',
                                    })
                                }
                            
                                //Sample Rate
                                if (event.props.sampleRate === 'session') {
                                    if (sampleRateBtn.value.invalidate().value != sampleRate)
                                        sampleRateBtn.popupMenuSelect({ menuPath: [sampleRate] })
                                } else {
                                    if (sampleRateBtn.value.invalidate().value != event.props.sampleRate)
                                        sampleRateBtn.popupMenuSelect({ menuPath: [event.props.sampleRate] })
                                }
                            
                                // Session Folder
                                sessionFolderButton.elementClick()
                            
                                // Session Folder Name
                                switch (event.props.exportType) {
                                    case 'Stems':
                                        sessionFolderText.elementSetTextFieldWithAreaValue({
                                            value: 'Bounced Files/' + stemPrefix + '_' + event.props.folderSuffix
                                        })
                                        break
                                    case 'Masters':
                                        sessionFolderText.elementSetTextFieldWithAreaValue({
                                            value: 'Bounced Files/'
                                        })
                                        break
                                }
                            
                                // Offline Bounce
                                offlineCheckBox.checkboxSet({
                                    targetValue: event.props.offline
                                })
                                
                            }
                            
                            sf.wait({ intervalMs: 200 })
                            
                            sf.ui.proTools.windows.whoseTitle.is('Bounce Mix').first.buttons.whoseTitle.is('Bounce').first.elementClick()
                            
                            let replaceDlg = sf.ui.proTools.windows.whoseTitle.is("").first.children.whoseRole.is("AXStaticText").whoseValue.matches(/\" already exists\.  Do you want to replace it\?/).first
                            
                            if (replaceDlg.exists) {
                                let yesBtn =  sf.ui.proTools.windows.whoseTitle.is("").first.children.whoseRole.is("AXButton").whoseTitle.is("Yes").first
                                let noBtn =  sf.ui.proTools.windows.whoseTitle.is("").first.children.whoseRole.is("AXButton").whoseTitle.is("No").first
                            
                                switch (event.props.overwriteExistingFiles) {
                                    case 'Yes':
                                        yesBtn.elementClick()
                                        sf.ui.proTools.waitForNoModals()
                                        bouncedStems.push(stemName)
                                        break
                                    case 'No':
                                        noBtn.elementClick()
                                        sf.ui.proTools.windows.whoseTitle.is('Bounce Mix').first.buttons.whoseTitle.is('Cancel').first.elementClick()
                                        sf.ui.proTools.waitForNoModals()
                                        throw 'Stem "' + stemName + '" already exists in ' + stemPrefix + '_' + event.props.folderSuffix
                                    case 'Dismiss':
                                        noBtn.elementClick()
                                        sf.ui.proTools.windows.whoseTitle.is('Bounce Mix').first.buttons.whoseTitle.is('Cancel').first.elementClick()
                                        sf.ui.proTools.waitForNoModals()
                                        return
                                }
                            } else {
                                bouncedStems.push(stemName)
                            }
                            
                            // MP3 dialogue
                            if (event.props.fileType === 'MP3' || event.props.addMP3) {
                                let mp3Dlg = sf.ui.proTools.dialogWaitForManual({
                                    dialogTitle: 'MP3'
                                }).dialog
                            
                                if (firstRun === true) {
                                    let mainMp3Btns = mp3Dlg.getElements('AXChildren').filter(function (e) { return e.fullRole == 'AXPopUpButton' })
                            
                                    let encodingSpeedBtn = mainMp3Btns.length === 4 ? mainMp3Btns[3] : mainMp3Btns[2]
                                    let cbrBtn = mainMp3Btns.length === 4 ? mainMp3Btns[2] : mainMp3Btns[1]
                                    let tagBtn = mainMp3Btns.length === 4 ? mainMp3Btns[1] : mainMp3Btns[0]
                            
                                    if (tagBtn.value.invalidate().value != 'None')
                                        tagBtn.popupMenuSelect({ menuPath: ['None'] })
                            
                                    if (cbrBtn.value.invalidate().value != '320kbit/s')
                                        cbrBtn.popupMenuSelect({ menuPath: ['320kbit/s (' + sessionFormat[0].replace(' k', '000') + ')'] })
                            
                                    if (encodingSpeedBtn.value.invalidate().value != 'Slowest')
                                        encodingSpeedBtn.popupMenuSelect({ menuPath: ['Highest Quality, Slower Encoding Time'] })
                                }
                            
                                sf.ui.proTools.windows.whoseTitle.is('MP3').first.buttons.whoseTitle.is('OK').first.elementClick()
                            }
                            
                            sf.ui.proTools.waitForNoModals()
                            
                            while (sf.ui.frontmostApp.title.value !== 'Pro Tools') {
                                sf.wait({ intervalMs: 500 })
                            }
                            

                            }

                            // MAIN ------------------------------------------------------------------------------------------
                            function main() {
                            // Get selected tracks
                            const selectedTracks = sf.ui.proTools.trackGetSelectedTracks().names
                            const stems = getStemNames(selectedTracks)

                            if (sf.ui.proTools.selectedTracks.trackHeaders.filter(e => e.title.value.includes('Folder')).length > 0 && event.props.method ==='Dyn') {
                                sf.interaction.displayDialog({
                                    title: 'Stem Bouncing Stopped',
                                    prompt: 'Method cannot be set to Dyn On/Off if using folder tracks in your selection.'
                                })
                            
                                return
                            }
                            
                            selectAndScrollTracks(selectedTracks)
                            
                            const stemPrefix = event.props.exportType === 'Stems' ? inputStemPrefix() : ''
                            sf.ui.proTools.appActivateMainWindow()
                            const bounceOutput = selectBounceOutput()
                            
                            // Save the way the user has the screen set up and setup screen
                            const winConfigNum = saveUserWinConfig()
                            const tracksViewNum = saveCurrentTrackView()
                            sf.ui.proTools.viewCloseFloatingWindows()
                            setupScreen()
                            setSelectedTracksSize('mini')
                            suspendGroups('Enable')
                            linkTrackAndEditSelection()
                            switch (event.props.method) {
                                case 'Activity':
                                    changeTrackActivity('Make Inactive')
                                    break
                                case 'Solo':
                                    sf.ui.proTools.mainWindow.counterDisplay.mouseClickElement({
                                        relativePosition: { x: 299, y: 67 }
                                    })
                                    break
                                case 'Dyn':
                                    setTrackVoiceSelector({ targetValue: 'off' })
                            }
                            
                            // Get session format
                            const sessionFormat = getSessionFormat()
                            
                            // Bounce stems
                            try {
                                bounceStems(selectedTracks, stems, stemPrefix, sessionFormat, bounceOutput)
                            } catch(err) {
                                // Error dialogue
                                sf.interaction.displayDialog({
                                    title: 'Stems Bouncing Stopped',
                                    prompt: err
                                })
                            }
                            
                            // Finish and cleanup
                            selectAndScrollTracks(selectedTracks)
                            switch (event.props.method) {
                                case 'Activity':
                                    changeTrackActivity('Make Active')
                                    break
                                case 'Solo':
                                    sf.ui.proTools.mainWindow.counterDisplay.mouseClickElement({
                                        relativePosition: { x: 299, y: 67 }
                                    })
                                    break
                                case 'Dyn':
                                    setTrackVoiceSelector({ targetValue: 'dyn' })
                            }
                            suspendGroups('Disable')
                            recallAndDeleteTrackView(tracksViewNum)
                            recallAndDeleteWinConfig(winConfigNum)
                            
                            // Complete dialogue
                            sf.interaction.displayDialog({
                                title: 'Stems Complete',
                                prompt: 'Bounced ' + bouncedStems.length + ' ' + event.props.exportType.toLowerCase() + ' of ' + stems.length + '.'
                            })
                            

                            }

                            main()

                            1. T
                              In reply toJordan_Young:
                              T Michaels @T_Michaels
                                2024-04-08 12:36:33.569Z

                                Sorry that formatted weird, go on my profile and see my first post for a cleaner version

                                1. D
                                  In reply toJordan_Young:
                                  David Simpson @David_Simpson
                                    2024-04-14 10:33:18.314Z

                                    Hi all,

                                    Apologies for the delay in getting to this. I've now updated the script to work with Pro Tools 2024.3 so let me know if you're still having issues and I'll try my best to get to them.

                                    Cheers!
                                    David