Go to memory selection named "_"
Hey all,
Has anyone found an elegant solution to navigating to a memory selection (not a marker) by name, either with a prompt or a string stored somewhere in their script? In my case, I want the script to go to the memory selection "BNC", which I would rather use than a prompt to go to that memory selection, because I will always be using the "BNC" selection so the prompt is redundant.
I'm trying to incorporate it into a script that will help me print mixes in real time. Everything in this workflow is working except this*:
Open PT
Go to REF BUS audio track
Record enable REF BUS audio track
Go to "BNC" memory selection [selects entire timeline of edit window]*
Hit play on the transport
I've tried incorporating code from here:
How to use Search Markers with Selection Memory Locations?
and this snippet:
memoryLocationsFetchResult = sf.proTools.memoryLocationsFetchFromPtx();
I've also tried snippets of Raphael's marker utilities and Owen's advanced memory locations with no luck so far. I'm hoping there is a simple solution akin to this:
sf.ui.proTools.memoryLocationsGoto();
but for memory selections
- Kitch Membery @Kitch2023-05-25 17:14:59.548Z
Hi @danielkassulke,
This script will allow you to select a memory location by name.
/** * @param {function} callback */ function setupRestore(callback) { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); const isMemoryLocationsWindowOpen = sf.ui.proTools.memoryLocationsWindow.exists; try { callback(); } finally { if (!isMemoryLocationsWindowOpen) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Memory Locations"], targetValue: "Disable", }); } } } /** * @param {object} obj * @param {string} obj.name */ function selectMemoryLocationByName({ name }) { setupRestore(() => { sf.ui.proTools.appActivateMainWindow(); const locations = sf.proTools.memoryLocationsFetchFromGui().collection["List"].map(ml => ml); let targetLocation = locations.find(location => location.name === name); sf.ui.proTools.memoryLocationsGoto({ memoryLocationNumber: targetLocation.number }); }); } selectMemoryLocationByName({ name: "BNC" });
- Ddanielkassulke @danielkassulke
hey @Kitch !
Thanks for this. I'm actually looking to select a memory selection as distinct from a memory location (see pic). Is there an equivalent memoryLocationsFetchFromGui for selections? Seemingly a lot of the marker-specific macros/threads/packages are location rather than selection specific, so it's been tricky building this from the ground up. Do you think it would be possible in future to have a macro that goes to a marker selection?
Kitch Membery @Kitch2023-05-25 20:00:03.057Z
Hi @danielkassulke,
I've not tested it, but did my script not do that?
- Ddanielkassulke @danielkassulke
No, it's navigating to markers of that name only, regardless of presence of a memory selection named "BNC".
Kitch Membery @Kitch2023-05-25 20:06:35.389Z
Ahh, I see...
I'll take a look at it later today and see if I can get it to work. :-)
- In reply todanielkassulke⬆:
Kitch Membery @Kitch2023-05-25 20:21:11.161Z
Give this a go :-)
/** * @param {function} callback */ function setupRestore(callback) { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); const isMemoryLocationsWindowOpen = sf.ui.proTools.memoryLocationsWindow.exists; try { callback(); } finally { if (!isMemoryLocationsWindowOpen) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Memory Locations"], targetValue: "Disable", }); } } } function getMemoryLocations() { sf.ui.proTools.appActivateMainWindow(); let memoryLocationsWindow = sf.ui.proTools.memoryLocationsWindow; let table = memoryLocationsWindow.invalidate().tables.first; if (!table.exists) throw 'Could not find memory locations table'; const columns = memoryLocationsWindow.table.childrenByRole("AXColumn") .map(col => col.title.invalidate().value.trim()); const numberColumnIndex = columns.indexOf("Numeration"); const nameColumnIndex = columns.indexOf("Name"); let items = table.childrenByRole("AXRow").map(row => { let getCellValue = (columnIndex) => row.children[columnIndex].children[0].title.value; return { row, num: getCellValue(numberColumnIndex).replace("Selected. ", ""), name: getCellValue(nameColumnIndex).replace("Selected. ", ""), } }); return items; } /** * @param {object} obj * @param {string} obj.name */ function selectMemorySelectionByName({ name }) { setupRestore(() => { let memoryLocations = getMemoryLocations(); let targetMemorySelection = memoryLocations.filter(item => item.name === name)[0]; targetMemorySelection.row.elementClick(); }); } selectMemorySelectionByName({ name: "BNC" });
- Ddanielkassulke @danielkassulke
Hey Kitch,
Thanks for your speedy replies! I'm getting the following error message: Could not find memory locations table (Go To Selection Name line 27). That error is only thrown when the memory location window isn't open. When open, it is still navigating to a marker, and it seems to go to the first marker (HH:MM:SS rather than marker number) in the session, regardless of marker name.
Kitch Membery @Kitch2023-05-25 20:45:04.264Z
Sorry, @danielkassulke, I'm juggling a few things and I realized that some of the code is outdated.
Try this :-)
function getMemoryLocations() { sf.ui.proTools.appActivateMainWindow(); let memoryLocationsWindow = sf.ui.proTools.memoryLocationsWindow; let table = memoryLocationsWindow.invalidate().tables.first; if (!table.exists) throw 'Could not find memory locations table'; const columns = memoryLocationsWindow.table.childrenByRole("AXColumn") .map(col => col.title.invalidate().value.trim()); const numberColumnIndex = columns.indexOf("Numeration"); const nameColumnIndex = columns.indexOf("Name"); let items = table.childrenByRole("AXRow").map(row => { let getCellValue = (columnIndex) => row.children[columnIndex].children[0].title.value; return { row, num: getCellValue(numberColumnIndex).replace("Selected. ", ""), name: getCellValue(nameColumnIndex).replace("Selected. ", ""), } }); return items; } /** * @param {object} obj * @param {string} obj.name */ function selectMemorySelectionByName({ name }) { let memoryLocations = getMemoryLocations(); let targetMemorySelection = memoryLocations.filter(item => item.name === name)[0]; targetMemorySelection.row.elementClick(); } sf.ui.proTools.memoryLocationsEnsureWindow({ action:()=> selectMemorySelectionByName({ name: "BNC" }), restoreWindowOpenState:true, });
- Ddanielkassulke @danielkassulke
@Kitch please don't apologise! I'm extremely grateful for your support and patience. Updated code is error-free now, but still only dealing with that first marker in the session, rather than a selection.
Kitch Membery @Kitch2023-05-25 21:05:12.449Z
Hmmm... I see that if there are no other makers other than the selection marker the script works.
I'll have to do a deep dive into this to see what's happening.
- In reply todanielkassulke⬆:
Kitch Membery @Kitch2023-05-25 21:09:24.483Z
Here's a slightly different approach. Have not done much testing so let me know how it goes.
function getMemoryLocations() { sf.ui.proTools.appActivateMainWindow(); let memoryLocationsWindow = sf.ui.proTools.memoryLocationsWindow; let table = memoryLocationsWindow.invalidate().tables.first; if (!table.exists) throw 'Could not find memory locations table'; const columns = memoryLocationsWindow.table.childrenByRole("AXColumn") .map(col => col.title.invalidate().value.trim()); const numberColumnIndex = columns.indexOf("Numeration"); const nameColumnIndex = columns.indexOf("Name"); let items = table.childrenByRole("AXRow").map(row => { let getCellValue = (columnIndex) => row.children[columnIndex].children[0].title.value; return { row, num: getCellValue(numberColumnIndex).replace("Selected. ", ""), name: getCellValue(nameColumnIndex).replace("Selected. ", ""), } }); return items; } /** * @param {object} obj * @param {string} obj.name */ function selectMemorySelectionByName({ name }) { let memoryLocations = getMemoryLocations(); let targetMemorySelection = memoryLocations.filter(item => item.name === name)[0]; let memoryLocationNumber = Number(targetMemorySelection.num); sf.ui.proTools.memoryLocationsGoto({memoryLocationNumber}); } sf.ui.proTools.memoryLocationsEnsureWindow({ action:()=> selectMemorySelectionByName({ name: "BNC" }), restoreWindowOpenState:true, });
- Ddanielkassulke @danielkassulke
Bingo! This is it. Thanks so much K! Worth me flagging in the ideas subforum to have this simplified as a macro you think?
Kitch Membery @Kitch2023-05-25 21:12:53.931Z
For sure... Tag me in the post when you do so. :-)
Glad it worked, champion!
- Ddanielkassulke @danielkassulke
@raphaelsepulveda sorry for cross-thread spamming you - totally slipped my mind that I had a 2023.3 version of this up and running. I understand the only functional difference here vs 2023.6 is a change in the structure of the memory location window, but I am totally clueless as to how to actually derive and scrape the column / cell data to update scripts like this. I've started pulling info from accessibility inspector, but would appreciate some advice on how to interpret it meaningfully:
This is what I'm seeing:
Pro Tools (application) [DFW_NSApplication]
Memory Locations (floating window) [DFW_NSPanel]
Memory Locations (Table) [VO_Table]
(Row) [VO_Row]
(Row) [VO_Row]
(Row) [VO_Row]
Sharing Merging (Column) [VO_Column]
Numeration (Column) VO_Column]
Name (Column) [VO_Column]
Name (Column) [VO_Column]
Main Counter (Column) [VO_Column]
Sub Counter (Column) [VO_Column]
State (Column) [VO_Column]
State (Column) [VO_Column]
State (Column) [VO_ Column]
State (Column) [VO_Column]
State (Column) [VO_ Column]
State (Column) [VO_Column]
State (Column) [VO_ Column]
State (Column) [VO_Column]
State (Column) [VO_Column]
Comments (Column) [VO_Column]
Memory Locations (pop up button) [VO_PopupButtoni]
Memory Locations (Table) [VO_Table]
(close button) [_NSThemeCloseWidgetCell]
(zoom button) [_NSThemeZoomWidgetCell]
(minimize button) [_NSThemeWidgetCell]
Memory Locations (text) [NSAccessibilityReparentingCellProxy]The short of it is that I'd love to be able to update this for the newest V of PT, but the long of it is I want to figure out how to do this myself!
Raphael Sepulveda @raphaelsepulveda2023-08-22 14:59:57.144Z
This is a bit tricky to explain here, but it all comes down to exploring the elements through Accessibility Inspector until you find the data you're looking for and then translating that to SF.
For example, if we wanted to get the name of the first Memory Location, after clicking around for a few mins in Accessibility Inspector you'll find it in:
- The second Memory Location (Table)
-
- The first element of type Row
-
-
- The third element of type Cell
-
-
-
-
- The first, and only child element of type StaticText
-
-
In SF, that translates to:
const firstMemLocName = sf.ui.proTools.memoryLocationsWindow.tables.whoseTitle.is("Memory Locations").allItems[1] .children.whoseRole.is("AXRow").first .children.whoseRole.is("AXCell").allItems[2] .children.whoseRole.is("AXStaticText").first .title.value; log(firstMemLocName);
You should join the next SF Zoom Weekly Hangout so that Kitch can show this to you. It's much easier to understand that way.
https://soundflow.org/hangout- Ddanielkassulke @danielkassulke
Thanks, @raphaelsepulveda . This helps a lot. Have always wanted to but I think the zoom hangouts skew towards Northern Hemisphere / US time zones. I'm based in Australia!
Kitch Membery @Kitch2023-08-22 20:51:13.334Z
Hi Daniel,
I'll be in Kingscliff the second half of September, so maybe we can do a Southern Hemisphere SoundFlow Zoom hangout. :-)
- Ddanielkassulke @danielkassulke
Would love this, and if you are tempted to swing by Brisb in late Sept, please reach out! Also, out of curiosity - do the Zoom hangouts get recorded? I'd be happy to watch through them if so.
Kitch Membery @Kitch2023-08-22 21:23:53.667Z
A trip to Brizzy might be on the cards :-)
Unfortunately, we don't record the hangouts but If I get a moment I'll see if I can put together a video on how to map and filter the memory locations table as Raphael explained.