Can't seem to find a solution that works here-
For context:
I've created a larger script to deal with archiving a session- Before it gets into "Save Copy In", I'd like it to select all the visible tracks. (it's already hidden inactive and only showing what I am using in the session) This way in the "save copy in" dialog I can check "Selected tracks only".
I've gotten as far as selecting the ALL group, however it would then require clicking somewhere in the timeline to select all the visible tracks- Which would work except if it clicks on an aux, it will only select auxes. It needs to click on an audio track to grab all of the tracks-
If I use "click ui element" "First button", it selects even the unused tracks, which won't work for me here.
There must be a simpler way to select all tracks, or select active tracks in a group, no?
My other thought is to do a "Save as" and delete the inactive tracks first; but then of course I need to only show inactive tracks and still select/delete them...
- Raphael Sepulveda @raphaelsepulveda2021-09-02 18:22:42.254Z
Hey Joe,
The following script will select all visible and active tracks for ya!
const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; /** @param {{ track: AxPtTrackHeader}} arg */ function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks } /** @param {AxPtTrackListItem} trackListItem */ function selectTrack(trackListItem) { trackListItem.children.whoseRole.is("AXCell").allItems[1].buttons.first.elementClick(); } function selectAllVisibleActiveTracks() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.trackDeselectAll(); getVisibleActiveTracks().trackListItems.forEach(selectTrack) } selectAllVisibleActiveTracks();
Joe Costable @Joe_Costable
Awesome- Thank you!
- In reply toraphaelsepulveda⬆:
Brett Ryan Stewart @Brett_Ryan_Stewart
Hey @raphaelsepulveda ! How can this script be tweaked to just select all visible tracks regardless of active state?
Raphael Sepulveda @raphaelsepulveda2022-04-20 20:46:33.396Z
@Brett_Ryan_Stewart, something simple like this should do!
sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); sf.ui.proTools.trackSelectByName({ names: sf.ui.proTools.visibleTrackNames });
Brett Ryan Stewart @Brett_Ryan_Stewart
You're the best Raphael, thank you!
- In reply toraphaelsepulveda⬆:
Yujiro Yonetsu @Yujiro_Yonetsu
Hello,
Excuse me for cutting in.I am taking advantage of your nice script too and trying to incorporate this into a script that works across multiple sessions.
But for some reason it does not work.
Error Message says
"ReferenceError: visibleTracks is not denied"The script I am making is so long that I hesitate to reproduce it here, but in the meantime, here it is
The error occurs at line 595.Script for routing and coloring tracks while automatically switching between multiple sessions.
const specificName = event.props.specificName ///////////////////////Basci function //comfirmation dialog function dismissConfirmationDialog(btn) { if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is(btn).first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is(btn).first.elementClick(); } }; //save color to preset function saveTrackPreset() { const tracks = sf.ui.proTools.selectedTrackHeaders sf.file.directoryCreate({ path: "~/Documents/Pro Tools/Track Presets/Avid/SF" }) const presetName = "SF_TrackColorTemp" //Scroll firsr track to View tracks[0].trackScrollToView() sf.ui.proTools.menuClick({ menuPath: ["Track", "Save Track Preset..."] }) const saveTrackPresetWin = sf.ui.proTools.windows.whoseTitle.is("Save Track Preset ").first.elementWaitFor({}, "Save Track Preset Win didn't Open.").element // Category, choose SF folder if (saveTrackPresetWin.popupButtons.first.value.invalidate().value != "SF") { saveTrackPresetWin.popupButtons.first.popupMenuSelect({ menuPath: ["Avid", "SF"] }); } // Name preset saveTrackPresetWin.textFields.first.elementSetTextFieldWithAreaValue({ value: presetName }); //Disable all checkboxes saveTrackPresetWin.checkBoxes.map(cb => cb.checkboxSet({ targetValue: "Disable" })) ///// //Open track data to recall sf.ui.proTools.windows.whoseTitle.is("Save Track Preset ").first.buttons.whoseTitle.is("Track Data to Recall...").first.elementClick(); const trackDataToRecallWin = sf.ui.proTools.windows.whoseTitle.is("Track Data to Recall").first.elementWaitFor({}, "Track Data to Recall Win didn't Open.").element //Disable all checkboxes trackDataToRecallWin.groups.map(gr => gr.checkBoxes.map(cb => cb.checkboxSet({ targetValue: "Disable" }))) // Set no offset trackDataToRecallWin.groups.whoseTitle.is("Track Offset Options").first.radioButtons.whoseTitle.is("No Offset").first.checkboxSet({ targetValue: "Disable", }); // Enable track colors trackDataToRecallWin.groups.whoseTitle.is("Track Data").first.checkBoxes.whoseTitle.is("Track Colors").first.checkboxSet({ targetValue: "Enable", }); // Ok trackDataToRecallWin.buttons.whoseTitle.is("OK").first.elementClick(); trackDataToRecallWin.elementWaitFor({ waitType: "Disappear" }) ///// saveTrackPresetWin.buttons.whoseTitle.is("OK").first.elementClick(); saveTrackPresetWin.elementWaitFor({ waitType: "Disappear" }) dismissConfirmationDialog("Replace") } //coloring by preset function recallTrackPreset() { const presetName = "SF_TrackColorTemp" const tracks = sf.ui.proTools.invalidate().selectedTrackHeaders if (sf.ui.proTools.confirmationDialog.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick(); } tracks[0].popupButtons.first.popupMenuSelect({ menuPath: ["Recall Track Preset", "Avid", "SF", presetName], isRightClick: true }) dismissConfirmationDialog("OK") }; //select only audio track in folder /** * @param {AxPtTrackHeader} track */ function getTrackDepth(track) { return Math.floor((track.titleButton.frame.x - track.frame.x) / 15); } function getTrackFolderStructure() { var root = { children: [] }; var stack = []; stack[0] = root; var flatList = sf.ui.proTools.visibleTrackHeaders.map(t => ({ track: t, depth: getTrackDepth(t) })); for (var i = 0; i < flatList.length; i++) { var flatItem = flatList[i]; var node = { name: flatItem.track.normalizedTrackName, type: flatItem.track.title.value.match(/ - (.*)$/)[1].trim().replace(/track$/i, '').trim().toLowerCase(), track: flatItem.track, children: [] }; stack[flatItem.depth] = node; stack[flatItem.depth - 1].children.push(node); } return root; } function findNearestParentFolder(root, trackName) { var folderStack = []; function walk(node) { var isFolder = node.type && node.type.indexOf('folder') >= 0; if (isFolder) { folderStack.push(node); } if (node.name === trackName) { return folderStack.slice(-1)[0]; } for (var i = 0; i < node.children.length; i++) { var res = walk(node.children[i]); if (res) return res; } if (isFolder) { folderStack.pop(); } } return walk(root); } /** * @return {AxPtTrackHeader[]} */ function getTracksInCurrentFolderOfType(trackType) { sf.ui.proTools.mainWindow.invalidate(); var root = getTrackFolderStructure(); var nearestFolder = findNearestParentFolder(root, sf.ui.proTools.selectedTrack.normalizedTrackName); if (!nearestFolder) return []; return nearestFolder.children.filter(i => i.type === trackType).map(i => i.track); } function selectTracksInCurrentFolderOfType(trackType) { sf.ui.proTools.trackSelectByName({ names: getTracksInCurrentFolderOfType('audio').map(t => t.normalizedTrackName), }); } function getInputPathOfSelectedTrack() { sf.ui.proTools.appActivateMainWindow(); var path = sf.ui.proTools.selectedTrack.inputPathButton.popupMenuFetchAllItems().menuItems.filter(mi => mi.element.isMenuChecked)[0].names; sf.ui.proTools.appActivateMainWindow(); return path; } ////////////////////////Basic function ///////function for multiple function closeWindows() { //Close audio plug-in windows sf.ui.proTools.floatingWindows.whoseTitle.startsWith('Plug-in:').allItems.forEach(function (win) { try { win.windowClose(); } catch (err) { } }); //Close audio suite windows sf.ui.proTools.floatingWindows.whoseTitle.startsWith('Audio Suite').allItems.forEach(function (win) { try { win.windowClose(); } catch (err) { } }); //close task manager if (sf.ui.proTools.windows.whoseTitle.is("Task Manager").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Task Manager").first.getElement("AXCloseButton").elementClick(); sf.ui.proTools.windows.whoseTitle.is("Task Manager").first.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 300, }); //close memory location if (sf.ui.proTools.memoryLocationsWindow.exists) { sf.ui.proTools.memoryLocationsWindow.getElement("AXCloseButton").elementClick(); sf.ui.proTools.memoryLocationsWindow.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 300, }); //close transport if (sf.ui.proTools.getMenuItem('Window', 'Transport').isMenuChecked) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Transport'], }); } sf.wait({ intervalMs: 200, }); //close Big Counter if (sf.ui.proTools.getMenuItem('Window', 'Big Counter').isMenuChecked) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Big Counter'], }); } sf.wait({ intervalMs: 200, }); //close Automation setting if (sf.ui.proTools.automationWindow.exists) { sf.ui.proTools.automationWindow.getElement("AXCloseButton").elementClick(); sf.ui.proTools.automationWindow.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 300, }); //close Color Palette if (sf.ui.proTools.colorPaletteWindow.exists) { sf.ui.proTools.colorPaletteWindow.getElement("AXCloseButton").elementClick(); sf.ui.proTools.colorPaletteWindow.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 300, }); //close System Usage if (sf.ui.proTools.windows.whoseTitle.is("System Usage").first.exists) { sf.ui.proTools.windows.whoseTitle.is("System Usage").first.getElement("AXCloseButton").elementClick(); sf.ui.proTools.windows.whoseTitle.is("System Usage").first.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 300, }); //close sessionsetup if (sf.ui.proTools.windows.whoseTitle.is("Session Setup").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Setup").first.getElement("AXCloseButton").elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Setup").first.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 300, }); //Hide all floating windows if (sf.ui.proTools.getMenuItem('Window', 'Hide All Floating Windows').isMenuChecked) { } else { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Hide All Floating Windows'], }); } sf.wait({ intervalMs: 200, }); } function closeOutputWindow() { if (sf.ui.proTools.mainTrackOutputWindow.exists) { sf.ui.proTools.mainTrackOutputWindow.windowClose(); } sf.wait({ intervalMs: 90, }); } function saveAndClose() { sf.ui.proTools.windows.whoseTitle.is("Task Manager").first.elementWaitFor({ waitType: "Appear", }); if (sf.ui.proTools.windows.whoseTitle.is("Task Manager").first.tables.whoseTitle.is("Active Tasks.").first.children.whoseRole.is("AXColumn").whoseTitle.is("TTextGridView_Column ").first.children.whoseRole.is("AXRow").whoseValue.is("# 0 row Queued. ").first.children.whoseRole.is("AXCell").first.children.whoseRole.is("AXStaticText").first.value.invalidate().value == "") { //// save and exit procedures if ((sf.ui.proTools.mainWindow.invalidate().sessionPath !== null || sf.ui.proTools.getMenuItem('File', 'Close Session').isEnabled) || sf.ui.proTools.confirmationDialog.exists) { sf.wait({ intervalMs: 90, }); sf.ui.proTools.menuClick({ menuPath: ["File", "Save"] }); sf.ui.proTools.menuClick({ menuPath: ["File", "Close Session"] }); if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Save').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Save').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", onError: "Continue" }); } sf.ui.proTools.waitForNoModals(); } } else { sf.wait({ intervalMs: 90, }); sf.keyboard.press({ keys: "cmd+shift+3", }); sf.wait({ intervalMs: 90, }); if ((sf.ui.proTools.mainWindow.invalidate().sessionPath !== null || sf.ui.proTools.getMenuItem('File', 'Close Session').isEnabled) || sf.ui.proTools.confirmationDialog.exists) { sf.wait({ intervalMs: 90, }); sf.ui.proTools.menuClick({ menuPath: ["File", "Save"] }); sf.ui.proTools.menuClick({ menuPath: ["File", "Close Session"] }); if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Save').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Save').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", onError: "Continue" }); } if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Close').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Close').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", onError: "Continue" }); } sf.ui.proTools.waitForNoModals(); } } sf.wait({ intervalMs: 500 }) } function waitForOpenSession() { while (true) { if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.elementWaitFor({ waitType: "Disappear", }); } sf.wait({ intervalMs: 3000 }) if (sf.ui.proTools.windows.whoseTitle.is("Missing Files").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing Files").first.radioButtons.whoseTitle.is("Automatically Find & Relink").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing Files").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing Files").first.elementWaitFor({ waitType: "Disappear", }); sf.wait({ intervalMs: 3000, }); //show edit window sf.ui.proTools.menuClick({ menuPath: ["Window", "Edit"] }); sf.wait({ intervalMs: 3000, }); sf.ui.proTools.mainWindow.counterDisplay.mouseClickElement({ relativePosition: { x: 237, y: 66 }, }); sf.ui.proTools.windows.whoseTitle.is("Relink").first.elementWaitFor({ waitType: "Appear", }); sf.wait({ intervalMs: 90, }); sf.keyboard.press({ keys: "cmd+shift+3", }); sf.wait({ intervalMs: 90, }); sf.ui.proTools.windows.whoseTitle.is("Relink").first.getElement("AXCloseButton").elementClick(); } sf.wait({ intervalMs: 500 }) if ((sf.ui.proTools.mainWindow.invalidate().sessionPath !== null || sf.ui.proTools.getMenuItem('File', 'Close Session').isEnabled) ) { log("session open") break; } sf.wait({ intervalMs: 500 }) } } function closeTaskManager() { if (sf.ui.proTools.getMenuItem('Window', 'Task Manager').isMenuChecked) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Task Manager'], }); } } function movetaskmanager() { var taskManager = sf.ui.proTools.windows.whoseTitle.is("Task Manager").first.frame; sf.mouse.simulateDrag({ startPosition: { "x": taskManager.x + 119, "y": taskManager.y + 8 }, endPosition: { "x": taskManager.x + 1000, "y": taskManager.y + 700 }, }); } ////////////////////////////////function for multiple //active finder sf.ui.app('com.apple.finder').appActivateMainWindow(); //search session function getMakeStemSessions(selectedFolders) { const sessionPath = sf.file.directoryGetFiles({ searchPattern: "*" + specificName, path: selectedFolders, isRecursive: true, }).paths[0] allPath.push(sessionPath) } let allPath = [] sf.ui.finder.selectedPaths.forEach(getMakeStemSessions) ////start dialog const myDialog = sf.interaction.displayDialog({ buttons: ["Cancel", "OK"], defaultButton: "OK", cancelButton: "Cancel", title: "Are you ready?", prompt: allPath.length + " Songs, right?" }); ////////////////////////////////////////////////Main if (myDialog.button == "OK") { sf.ui.proTools.appActivate(); sf.wait({ intervalMs: 300, }); closeTaskManager(); sf.wait({ intervalMs: 90, }); for (var i = 0; i < allPath.length; i++) { //session open sf.file.open({ path: allPath[i], applicationPath: "/Applications/Pro Tools.app", }); // Wait fo menus to become enabled, thus sessioon is fully opened waitForOpenSession(); sf.wait({ intervalMs: 1000, }); /////////////////////////////////////////////////////////////////////session start prepare //focus protools sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); sf.wait({ intervalMs: 90, }); closeWindows(); closeOutputWindow(); //go to Edit Win const isEditWin = sf.ui.proTools.focusedWindow.title.value.startsWith("Edit") if (!isEditWin) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Edit"] }) } sf.keyboard.press({ keys: "p", }); sf.ui.proTools.selectedTrack.invalidate().trackScrollToView(); //set track height sf.ui.proTools.menuClick({ menuPath: ["Edit", "Selection", "Extend Edit Up"], }); sf.wait({ intervalMs: 80, }); let trackHeaderFrameWidth = sf.ui.proTools.selectedTrack.frame.w sf.ui.proTools.invalidate().selectedTrack.popupMenuSelect({ relativePosition: { x: trackHeaderFrameWidth - 10, y: 10 }, menuPath: ['small'], isOption: true, }); sf.wait({ intervalMs: 80, }); //close all folder tracks function selectAllFolderTracks() { var visibleTracks = sf.ui.proTools.invalidate().trackGetVisibleTracks().names var firstTrackFound; let foundTracks = []; while (true) { sf.ui.proTools.trackDeselectAll(); for (var i = 0; i < visibleTracks.length; i++) { var trackIsFolder = sf.ui.proTools.trackGetByName({ name: visibleTracks[i] }).track.children.whoseRole.is("AXDisclosureTriangle").whoseTitle.is('Close Folder') if (trackIsFolder.exists) if (trackIsFolder) { if (!firstTrackFound) { // Scroll to first track found sf.ui.proTools.trackGetByName({ name: visibleTracks[i], }).track.trackScrollToView(); firstTrackFound = !firstTrackFound; } else { sf.ui.proTools.trackSelectByName({ names: [visibleTracks[i]], deselectOthers: false }); } foundTracks.push(visibleTracks[i]); } } if (foundTracks.length !== 0) { break; } throw 0; } } function closeAllFolderTracks() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.windows.invalidate(); selectAllFolderTracks() const selectedTracks = sf.ui.proTools.selectedTrackNames.reverse() for (var i = 0; i < selectedTracks.length; i++) { sf.ui.proTools.invalidate().trackGetByName({ name: selectedTracks[i] }).track.folderTrackSetOpen({ targetValue: 'Disable', }); } } closeAllFolderTracks() //select all tracks sf.keyboard.press({ keys: "return", }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"], }); //select only active track const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; /** @param {{ track: AxPtTrackHeader}} arg */ function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks } /** @param {AxPtTrackListItem} trackListItem */ function selectTrack(trackListItem) { trackListItem.children.whoseRole.is("AXCell").allItems[1].buttons.first.elementClick(); } function selectAllVisibleActiveTracks() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.trackDeselectAll(); getVisibleActiveTracks().trackListItems.forEach(selectTrack) } selectAllVisibleActiveTracks(); //select only routing folder const selectedHeaders = sf.ui.proTools.selectedTrackHeaders sf.ui.invalidate().proTools.trackSelectByName({ names: selectedHeaders.filter(t => t.title.value.endsWith("Routing Folder Track ")).map(t => t.normalizedTrackName) }) ///////////////////////////////////////////do for all selected track function doForAllSelectedTracks(action) { var originallySelectedTrackNames = sf.ui.proTools.invalidate().selectedTrackNames; try { sf.ui.proTools.selectedTrackHeaders.forEach(track => { track.trackSelect(); action(track); }); } finally { sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames }); } } //LOOP CONTENTS /**@param {AxPtTrackHeader} track */ function trackFunc(track) { if (sf.ui.proTools.confirmationDialog.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick(); } // if visible, hide floating windows const areFloatingWindowsVisible = sf.ui.proTools.getMenuItem('Window', 'Hide All Floating Windows').isEnabled if (areFloatingWindowsVisible) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Hide All Floating Windows'] }) }; const origSelectedTracks = sf.ui.proTools.selectedTrackNames; const firstSelectedTrack = origSelectedTracks[0]; //TO SCROLL /** * @param {string} trackName * @param {string[]} selectedTracks */ function scrollToTrackNamed(trackName, selectedTracks) { // Open scroll to track dialog and enter track name sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); var confirmationDialogWin = sf.ui.proTools.confirmationDialog; confirmationDialogWin.elementWaitFor(); confirmationDialogWin.textFields.first.elementSetTextFieldWithAreaValue({ value: trackName }); confirmationDialogWin.buttons.whoseTitle.is('OK').first.elementClick(); confirmationDialogWin.elementWaitFor({ waitType: 'Disappear' }); //Re-select originally selected tracks sf.ui.proTools.trackSelectByName({ names: origSelectedTracks }) }; scrollToTrackNamed(firstSelectedTrack, origSelectedTracks); sf.ui.proTools.trackSelectByName({ names: origSelectedTracks }) //Make sure current folder is open sf.ui.proTools.selectedTrack.folderTrackSetOpen({ targetValue: "Enable", }); //Get the input path of this folder var folderInputPath = getInputPathOfSelectedTrack(); var folderInputPathTrue = folderInputPath[1].split(" (").slice(0, -1).join(""); /// store selected track names //const selectedTracks = sf.ui.proTools.selectedTrackNames // Save track color as preset saveTrackPreset() //Select all audio tracks in folder selectTracksInCurrentFolderOfType('audio'); const childSelectedTracks = sf.ui.proTools.selectedTrackNames; //Select all audio tracks in folder //selectTracksInCurrentFolderOfType('audio'); // Recall Color try { recallTrackPreset() } catch (err) { } sf.ui.proTools.trackSelectByName({ names: childSelectedTracks }) //Route all selected tracks to the folder //sf.ui.proTools.selectedTrack.trackOutputSelect({ // outputPath: ["bus", folderInputPathTrue + " (Stereo)"], // selectForAllSelectedTracks: true, //}); //if (sf.ui.proTools.selectedTrackNames.slice().length != 0) // sf.ui.proTools.selectedTrack.trackOutputSelect({ // outputSelector: items => items.filter(p => p.path[1] && p.path[1].split("(").slice(0, 1).join("(") === folderInputPathTrue)[0], // selectForAllSelectedTracks: true // }); else { } //log(sf.ui.proTools.selectedTrackNames.slice().length) try { sf.ui.proTools.selectedTrack.trackOutputSelect({ outputSelector: items => items.filter(p => p.path[1] && p.path[1].split("(").slice(0, 1).join("(") === folderInputPathTrue)[0], selectForAllSelectedTracks: true }); } catch (err) { } // Recall Color //recallTrackPreset() } doForAllSelectedTracks(trackFunc); if (sf.ui.proTools.confirmationDialog.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick(); } sf.wait({ intervalMs: 3000, }); /// Need task manager to close sessions if (!sf.ui.proTools.getMenuItem("Window", "Task Manager").isMenuChecked) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Task Manager"], targetValue: "Enable" }); } saveAndClose() closeWindows(); sf.ui.proTools.mainWindow.elementWaitFor({ waitType: "Disappear", timeout: -1 }); } } log("FINISH")
Raphael Sepulveda @raphaelsepulveda2022-06-25 17:42:47.069Z2022-06-25 18:28:21.431Z
Hey @Yujiro_Yonetsu, the first thing I would do to troubleshoot this is to isolate the part that is giving you the error and make sure it works on its own.
Open one of your sessions and run the script below. Does it successfully log data regarding the visible tracks?
sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); //select only active track const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; /** @param {{ track: AxPtTrackHeader}} arg */ function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks; } log(getVisibleActiveTracks())
If that doesn't work, then I would try placing the following code on line 574 of the full script:
sf.ui.proTools.mainWindow.invalidate();
That's right before the code regarding visibleTracks.I'm suggesting that because you're closing folders in the previous part and that's going to change the track structure. Invalidating here will make sure that SoundFlow has refreshed its awareness of the tracks running the next part.
Hopefully that helps!
Yujiro Yonetsu @Yujiro_Yonetsu
Hello
Thanks for your help.It acquires the header correctly in a single session.
But I still get the same error when I put it in a script for multiple sessions......visibleTracks.trackHeaders.forEach((trackHeader, i) => {
As before, this line produces an error.
Is there any solution?Raphael Sepulveda @raphaelsepulveda2022-06-25 18:31:26.911Z
Sorry if it didn't come across before but can you try adding
sf.ui.proTools.mainWindow.invalidate();
before this://select only active track const visibleTracks = sf.ui.proTools.invalidate().visibleTracks;
Yujiro Yonetsu @Yujiro_Yonetsu
I'm trying to do exactly what you've described, but it's not working.
Here is a partial excerpt.
//select all tracks sf.keyboard.press({ keys: "return", }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"], }); sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); //select only active track const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; /** @param {{ track: AxPtTrackHeader}} arg */ function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks; } log(getVisibleActiveTracks()) /** @param {AxPtTrackListItem} trackListItem */ function selectTrack(trackListItem) { trackListItem.children.whoseRole.is("AXCell").allItems[1].buttons.first.elementClick(); } function selectAllVisibleActiveTracks() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.trackDeselectAll(); getVisibleActiveTracks().trackListItems.forEach(selectTrack) } selectAllVisibleActiveTracks();
Raphael Sepulveda @raphaelsepulveda2022-06-25 22:00:01.016Z
Ok, gotcha. I think I know why this is happening. Try this.
Take this line:
const visibleTracks = sf.ui.proTools.invalidate().visibleTracks;
And put it inside the
getVisibleActiveTracks()
function, like so:function getVisibleActiveTracks() { const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks }
Yujiro Yonetsu @Yujiro_Yonetsu
Thank you!
I don't understand how it happened, but it's solved :)- In reply toraphaelsepulveda⬆:Jjulien creus @julien_creus
Hello @raphaelsepulveda ! Thanks for your help on all those topics, and sorry for chiming in that late on this one! I'm trying to use it as part of a bigger script but seems like I'm facing an issue: The main idea is, as part of a session prep script, to select all visible and active tracks (which would be my template tracks), and setup their track height to medium. (Later on, open all folder tracks, and move tracks inside them). In my template, I do have 3 levels of routing folder tracks.
Let's say,
ALL VOCALS
- LEAD
- ADD VOCALS
-- BVS
-- HARMOS
-- ADLIBSUsing your script for the selection part, looks like level three folders (BVS, HARMOS and ADLIBS in my example) aren't selected....
Here is the overall script: would you have any idea on what's going on?
Thanks in advance!!//SELECT AND SETUP VISIBLE AND ACTIVE TRACKS HEIGHT function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks } function selectTrack(trackListItem) { trackListItem.children.whoseRole.is("AXCell").allItems[1].buttons.first.elementClick(); } function setVisibleTracksHeight(size) { // Make sure track lis is visible sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Track List"], targetValue: "Enable" }) // Get all items from track list const trackList = sf.ui.proTools.trackListItems sf.ui.proTools.trackDeselectAll(); getVisibleActiveTracks().trackListItems.forEach(selectTrack); // Get all selected tracks const selectedTracks = sf.ui.proTools.selectedTrackNames // Scroll first track to view const indexOfFirstSelected = trackList.findIndex(x => x.normalizedTrackName == selectedTracks[0]) trackList[indexOfFirstSelected].children.whoseRole.is("AXCell").allItems[1].buttons.first.mouseClickElement({ isControl: true, isShift: true }) // Select original selection sf.ui.proTools.trackSelectByName({ names: selectedTracks }); //Setup track height var f = sf.ui.proTools.selectedTrack.frame; var popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({ relativePosition: { x: f.w - 10, y: 5 }, isOption: true, isShift: true, }).popupMenu; popupMenu.menuClickPopupMenu({ menuPath: [size] }); setVisibleTracksHeight("medium");
Raphael Sepulveda @raphaelsepulveda2023-07-03 20:45:34.773Z
Hey @julien_creus, besides a
}
being missing on line 58—which I'm sure was just a mistake while posting it on the forum—I don't see anything else that would prevent the script from selecting folders of all levels as long as they're visible. Are the folders containing the level three folders open? If you could post a short video of the script running, that'll help a lot!- Jjulien creus @julien_creus
Hey Raphael! Thanks for your answer! Sure the "{" was a copy/paste mistake =) Here's a quick video of the issue (sorry as it goes quite fast). I made the track height move to medium, and then back to small. Parent folders are also opened yes.
As you can see, the script seems to toggle the open/close state of those 3rd level folder (you can see the "open folder" arrows changing while the script runs during my video on F111 & F112).
https://we.tl/t-rUf5C5ZN8oRaphael Sepulveda @raphaelsepulveda2023-07-04 04:48:12.397Z
@julien_creus, thanks for the video, I was able to replicate it!
The issue is that your track list width on the left side is too narrow. This script interacts with that area so what you have to do is make it a bit wider until you can see more of the name of the folders that aren't getting selected. That should fix your problem!
- Jjulien creus @julien_creus
Yesss! It did, thanks a lot for your help! I'll be looking for a way to adapt the track list width to its content then =) that's perfect! I guess it would be another topic, but If by chance you have any leads about that?
Raphael Sepulveda @raphaelsepulveda2023-07-04 16:08:22.450Z
That you would have to do manually. I'd suggest just having a set width that covers all situations. It doesn't have to display the whole name of the tracks, this particular script needs just enough to perform an action on it. You can identify how much that is by experimenting with this script and adjusting the width a bit at a time until it starts working correctly.
Now that I think about it, once you find that width then you can save a Window Configuration and import it into your other sessions to recall that width exactly.