No internet connection
  1. Home
  2. How to

Go to memory selection named "_"

By danielkassulke @danielkassulke
    2023-05-25 08:10:55.830Z

    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

    • 19 replies

    There are 19 replies. Estimated reading time: 17 minutes

    1. 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" });
      
      1. Ddanielkassulke @danielkassulke
          2023-05-25 19:58:31.792Z

          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?

          1. Kitch Membery @Kitch2023-05-25 20:00:03.057Z

            Hi @danielkassulke,

            I've not tested it, but did my script not do that?

            1. Ddanielkassulke @danielkassulke
                2023-05-25 20:03:01.342Z

                No, it's navigating to markers of that name only, regardless of presence of a memory selection named "BNC".

                1. 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. :-)

                  1. 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" });
                    
                    1. Ddanielkassulke @danielkassulke
                        2023-05-25 20:38:36.965Z

                        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.

                        1. 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,
                          });
                          
                          1. Ddanielkassulke @danielkassulke
                              2023-05-25 20:51:14.288Z

                              @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.

                              1. 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.

                                1. 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,
                                  });
                                  
                                  
                                  1. Ddanielkassulke @danielkassulke
                                      2023-05-25 21:11:08.148Z

                                      Bingo! This is it. Thanks so much K! Worth me flagging in the ideas subforum to have this simplified as a macro you think?

                                      1. Kitch Membery @Kitch2023-05-25 21:12:53.931Z

                                        For sure... Tag me in the post when you do so. :-)

                                        Glad it worked, champion!

                                        1. Ddanielkassulke @danielkassulke
                                            2023-08-22 04:14:31.435Z

                                            @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!

                                            1. 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

                                              1. Ddanielkassulke @danielkassulke
                                                  2023-08-22 20:46:58.226Z

                                                  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!

                                                  1. 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. :-)

                                                    1. Ddanielkassulke @danielkassulke
                                                        2023-08-22 21:20:06.850Z

                                                        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.

                                                        1. 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.