Bounce Tracks script failing with PT2023.3+ and latest Soundflow
Title
Bounce Tracks script failing with PT2023.3+ and latest Soundflow
What do you expect to happen when you run the script/macro?
main use of this script is to bounce stems based on naming in the comments section of each track
Are you seeing an error?
Could not ensure main window became frontmost after waiting 2000 ms (Bounce Tracks: Line 1)
Comes up as soon as I hit bounce stems. I just updated Soundflow and now this happens, previously the script would run but would preset an error rearranging the windows at the end, but the stems would bounce, originally with an older version of Pro Tools it ran properly
What happens when you run this script?
No matter how I start the script I get the error message as soon as I try to start it
Could not ensure main window became frontmost after waiting 2000 ms (Bounce Tracks: Line 1)
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
{ "inputExpected": "main use of this script is to bounce stems based on naming in the comments section of each track", "inputIsError": true, "inputError": "Could not ensure main window became frontmost after waiting 2000 ms (Bounce Tracks: Line 1)\n\nComes up as soon as I hit bounce stems. I just updated Soundflow and now this happens, previously the script would run but would preset an error rearranging the windows at the end, but the stems would bounce, originally with an older version of Pro Tools it ran properly", "inputWhatHappens": "No matter how I start the script I get the error message as soon as I try to start it\n\nCould not ensure main window became frontmost after waiting 2000 ms (Bounce Tracks: Line 1)\n", "inputHowRun": { "key": "-MpfwYA4I6GGlXgvp5j1", "title": "I clicked the \"Run Script\" or \"Run Macro\" button in SoundFlow" }, "inputImportance": 5, "inputTitle": "Bounce Tracks script failing with PT2023.3+ and latest Soundflow" }
Source
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()
Links
User UID: DfctjZy0W0bRsTARiwy1IVULtWK2
Feedback Key: sffeedback:DfctjZy0W0bRsTARiwy1IVULtWK2:-NikdjdlvS1HuExs95NE
Feedback ZIP: pFw7FEVbYG9A/xJk43qacnwia8+Eabr4h7wma7ahYHmPWxdZ7AhTZX9iguebJxUYtN/5CXMzUjmPiA5yAwqJ3ncUKiBdMmrH+0WQz2bfhVVsXgS3LHdqIKqMf+zv5lNdOebumTRMtQXek9af9K6FTf6U7+cZphfiyHU0wOLYYgkSn7npsa7tquti6URW352nbyzW8Lj5DgQbmRRxFEnvaJ6L2qyUihWmPilTXDjxqmOL15UQ3hI4OS7DZK7kObyUy435WjQguHLkEQqtBUr/pniccE7/a/oNMot4rrFZxBvAFcjqDC4exQm2KADBDiObnHez36W2QsQbtPjb4u5Bdg==
- SSoundFlow Bot @soundflowbot
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. - CIn reply toT_Michaels⬆:chras bretta @chras_bretta
In PT 23.12.0 and latest SF. Mine gets hung up on line 281:
08.02.2024 12:46:48.77 [Backend]: Logging unknown error in action (02) RunCommandAction: Bounce Tracks: Line 28108.02.2024 12:46:48.77 [Backend]: !! Command Error: MASTERS Print CB [user:clg152hf20000us107phzuil9:cknizud3m0004ns10vps6gb90#clmpfxabw0000tp10o2og7l9q]:
Couldn't locate AxElementArrayIndexedItem (Bounce Tracks: Line 281)<< Command: MASTERS Print CB [user:clg152hf20000us107phzuil9:cknizud3m0004ns10vps6gb90#clmpfxabw0000tp10o2og7l9q]
08.02.2024 12:46:48.77 [StartMenu]: StartMenuContainer currentPageKey='home' Line 24630 file:///Applications/SoundFlow.app/Contents/Helpers/SoundFlow.app/Contents/Resources/app.asar//dist/bundle.js
08.02.2024 12:46:48.95 [StartMenu]: StartMenuContainer currentPageKey='home' Line 24630 file:///Applications/SoundFlow.app/Contents/Helpers/SoundFlow.app/Contents/Resources/app.asar//dist/bundle.js
08.02.2024 12:46:51.98 [EditorWindow:Renderer]: Active Focus Container: app Line 33963 file:///Applications/SoundFlow.app/Contents/Helpers/SoundFlow.app/Contents/Resources/app.asar/dist/editor.jsIf @David_Simpson is out there, I'll hire you to update this script!!
- DIn reply toT_Michaels⬆:David Simpson @David_Simpson
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 - TIn reply toT_Michaels⬆:T Michaels @T_Michaels
Thank you so much David! Really appreciate this.
I'm running 2023.9 due to being on Big Sur, stems now bounce although it fails on putting the track size etc back, I don't mind as I always do a save as session for a stem bounce.
Running perfectly on 2024.3, I'm just reluctant to use that since it's not officially supported on Big Sur!
- DDavid Simpson @David_Simpson
Glad to hear it's working for you!
Would you be able to update the script to 2.3.2 and then let me know what the error is when it tries to recall the track sizes?
Cheers!
David- TT Michaels @T_Michaels
Hey David,
2.3.2 installed on latest Soundflow, PT2023.9 on Big Sur
"The command, "84", is not compatible with this version of Pro Tools. (PT_UnknownError) (Bounce Tracks: Line 125)"
- DDavid Simpson @David_Simpson
Thank you!
Should be v2.3.3 up now. Let me know if that fixes it at all.
Cheers!
David- TT Michaels @T_Michaels
On 2023.9 it bounces but when it's restoring the window config it hides the bounced tracks at the end, no error message but no popup window saying complete.
Works normally on 2024.3
- DDavid Simpson @David_Simpson
Cool, was this happening on the previous version of the script too? - v2.3.2
- TT Michaels @T_Michaels
Nope was still doing the bounce but had the error message once finished and putting the window config back, but it wasn't hiding tracks.
- DDavid Simpson @David_Simpson
Does it manage to create a memory location and call it "Track Visibility"?