No internet connection
  1. Home
  2. Script Sharing

Auto_Align Post Macro by @Owen_Granich_Young

By Jason Freeman @Jason_Freeman
    2024-04-05 18:01:25.248Z

    @Owen_Granich_Young
    Per our convo on the sound radix forum, could you please post your auto-align post reference track macro, please and thank you!!

    • 12 replies

    There are 12 replies. Estimated reading time: 37 minutes

    1. O
      Owen Granich-Young @Owen_Granich_Young
        2024-04-05 18:18:00.630Z2025-12-18 23:56:10.209Z

        You bet Jason!

        Here's the one for ADR, highlight all the tracks and then press the button and it selects all the even tracks and processes them to the track above them. (Currently Y on my keyboard that's how much I'm using it, lol) This also works for a single pair if you highlight two tracks it will auto align the bottom one to the top one.

        const firstAudioSuiteWindow = sf.ui.proTools.firstAudioSuiteWindow;
        const originalTimelineSeleciton = sf.app.proTools.getTimelineSelection();
        
        function setupAndRestore(callback) {
            sf.ui.proTools.appActivateMainWindow();
            sf.ui.proTools.invalidate();
        
            const videoWindowMenuItem = sf.ui.proTools.getMenuItem('Window', 'Video');
        
            const initialViews = {
                isVideoWinOpen: videoWindowMenuItem.getString('AXMenuItemMarkChar') === ('-') || videoWindowMenuItem.isMenuChecked,
                isFloatingWindowsEnabled: sf.ui.proTools.getMenuItem('Window', 'Hide All Floating Windows').isMenuChecked,
            }
        
            const { isVideoWinOpen, isFloatingWindowsEnabled } = initialViews;
        
            if (isVideoWinOpen) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Video'], }); }
            if (!isFloatingWindowsEnabled) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Hide All Floating Windows'], }); }
        
            try {
        
                callback();
        
            } finally {
        
                const modifiedViews = {
                    isVideoWinOpen: (videoWindowMenuItem.getString('AXMenuItemMarkChar') === ('-') || videoWindowMenuItem.isMenuChecked) !== initialViews.isVideoWinOpen,
                    isFloatingWindowsEnabled: sf.ui.proTools.getMenuItem('Window', 'Hide All Floating Windows').isMenuChecked !== initialViews.isFloatingWindowsEnabled,
                }
        
                const { isVideoWinOpen, isFloatingWindowsEnabled } = modifiedViews;
        
                if (isVideoWinOpen) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Video'], }); }
                if (isFloatingWindowsEnabled) { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Hide All Floating Windows'], }); }
            }
        }
        
        function getPrecedingTrackName() {
            const tracks = sf.app.proTools.tracks.invalidate().allItems;
            const visibleTrackNames = tracks.filter(t => !t.isHidden).map(t => t.name);
            const selectedTrackName = tracks.find(t => !t.isHidden && t.isSelected).name;
            const selectedTrackIndex = visibleTrackNames.indexOf(selectedTrackName);
            return visibleTrackNames[selectedTrackIndex - 1];
        }
        
        function doForAllSelectedTracks(action) {
            const tracks = sf.app.proTools.tracks.invalidate().allItems;
        
            var originallySelectedTrackNames = tracks.filter(t => !t.isHidden && t.isSelected).map(t => t.name);
        
            try {
                originallySelectedTrackNames.forEach(trackName => {
                    sf.app.proTools.selectTracksByName({ trackNames: [trackName] });
                    action();
                });
            }
            finally {
                sf.app.proTools.selectTracksByName({ trackNames: originallySelectedTrackNames });
            }
        }
        
        function autoAlignEachSet() {
            const selectedTrackName = sf.app.proTools.tracks.invalidate().allItems.find(t => !t.isHidden && t.isSelected);
        
            const sideChainButton = firstAudioSuiteWindow.popupButtons.getByTitle("Key Input");
        
            if (sideChainButton.exists && selectedTrackName) {
        
                const precedingTrackName = getPrecedingTrackName();
        
                sideChainButton.popupMenuSelect({ menuPath: [precedingTrackName], });
        sf.wait({ intervalMs: 100 })
            }
        
            firstAudioSuiteWindow.audioSuiteRender();
        
            sf.ui.proTools.waitForNoModals();
        
            const { inTime, outTime } = originalTimelineSeleciton;
        
            sf.app.proTools.setTimelineSelection({ inTime, outTime, });
        }
        
        function main() {
            setupAndRestore(() => {
                const isAutoAlignPostOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
        
                const selectedTrackNames = sf.app.proTools.tracks.invalidate().allItems.filter(t => !t.isHidden && t.isSelected).map(t => t.name);
        
                const everyOtherTrackNames = selectedTrackNames.filter((_, index) => index % 2 === 1);
        
                sf.app.proTools.selectTracksByName({ trackNames: everyOtherTrackNames, selectionMode: "Replace" });
        
                if (isAutoAlignPostOpen) {
        
                    sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
        
                } else {
        
                    sf.ui.proTools.audioSuiteOpenPlugin({ category: "Other", name: "Auto-Align Post", });
                }
        
                firstAudioSuiteWindow.audioSuiteSetOptions({
                    processingInputMode: 'ClipByClip',
                    processingOutputMode: `CreateIndividualFiles`,
                });
        
                doForAllSelectedTracks(autoAlignEachSet)
        
                if (!isAutoAlignPostOpen) {
                    firstAudioSuiteWindow.windowClose({}, `Could not find Audiosuite Window`);
                }
            });
        }
        
        main();
        

        And this one select the tracks you want auto aligned (say a few character's lav mics) and they will all align to the track ABOVE the ones selected. It's a little funky that this one you don't select the guide track as the top most, but I think I'm ok with it.

        function getBeforeSelectedTrackName() {
        
            const visibleTrackNames = sf.ui.proTools.visibleTrackNames
        
            const selectedTrackName = sf.ui.proTools.selectedTrackNames[0]
        
            const selectedTrackIndex = visibleTrackNames.indexOf(selectedTrackName)
        
            return visibleTrackNames[selectedTrackIndex - 1]
        
        }
        
        function main() {
            sf.ui.proTools.appActivateMainWindow();
            sf.ui.proTools.invalidate();
            const aApostIsOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
        
            if (aApostIsOpen) {
                sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
            } else {
                sf.ui.proTools.audioSuiteOpenPlugin({
                    category: "Other",
                    name: "Auto-Align Post",
                });
            }
        
            let win = sf.ui.proTools.firstAudioSuiteWindow
        
        
            win.audioSuiteSetOptions({
                processingInputMode: 'ClipByClip',
                processingOutputMode: `CreateIndividualFiles`,
            });
        
            const selectedTrackName = sf.ui.proTools.selectedTrackNames[0]
            const sideChainButton = win.popupButtons.allItems[4]
        
            if (sideChainButton.exists && selectedTrackName) {
                sideChainButton.popupMenuSelect({
                    menuPath: [getBeforeSelectedTrackName()],
                });
            }
        sf.wait({ intervalMs: 100 })
            win.audioSuiteRender();
        
            sf.ui.proTools.waitForNoModals();
        
            if(!aApostIsOpen){
            win.windowClose({}, `Could not find Audiosuite Window`);
            }
        }
        
        main();
        

        Happy Aligning
        Owen

        EDIT UPDATE SCRIPT 1 SDK FIXED up Thanks to @Kitch

        1. OOwen Granich-Young @Owen_Granich_Young
            2025-05-13 16:18:03.324Z2025-12-18 23:54:58.851Z

            Searchable option :

            function popupTrackSearch() {
                const getTracks = () => sf.app.proTools.tracks.invalidate().allItems;
            
                // Fetch all tracks in the session
                const allTracks = getTracks();
            
                // Filter for all audio tracks in the session
                const sessionAudioTracks = allTracks.filter(t => t.type.endsWith("Audio"));
            
                // Create popup with track names
                const keyTrack = sf.interaction.popupSearch({
                    title: `Key Track`,
                    items: sessionAudioTracks.map(track => ({ name: track.name })),
                }).item.name;
            
                return keyTrack
            }
            
            
            function main() {
                sf.ui.proTools.appActivateMainWindow();
                sf.ui.proTools.invalidate();
                let targetTrack = popupTrackSearch();
                const aApostIsOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
            
                if (aApostIsOpen) {
                    sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
                } else {
                    sf.ui.proTools.audioSuiteOpenPlugin({
                        category: "Other",
                        name: "Auto-Align Post",
                    });
                }
            
                let win = sf.ui.proTools.firstAudioSuiteWindow
            
            
                win.audioSuiteSetOptions({
                    processingInputMode: 'ClipByClip',
                    processingOutputMode: `CreateIndividualFiles`,
                });
            
                const selectedTrackName = sf.ui.proTools.selectedTrackNames[0]
                const sideChainButton = win.popupButtons.allItems[4]
            
                if (sideChainButton.exists && selectedTrackName) {
                    sideChainButton.popupMenuSelect({
                        menuPath: [targetTrack],
                    });
                }
            sf.wait({ intervalMs: 100 })
                win.audioSuiteRender();
            
                sf.ui.proTools.waitForNoModals();
            
                if (!aApostIsOpen) {
                    win.windowClose({}, `Could not find Audiosuite Window`);
                }
            }
            
            main();
            

            Also I've stopped using the 2nd script here and swapped to this one instead, it aligns all material to the top most selected track, which I find more useful especially if the tracks aren't DIRECTLY below the one that they need aligning to.

            sf.ui.proTools.appActivateMainWindow();
            sf.ui.proTools.invalidate();
            
            ///GET TRACK INFO ALL
            let trckInfo = sf.app.proTools.tracks.invalidate().allItems.map(m => {
                let mappedProps = {};
            
                for (let prop in m) {
                    const itemsToSkip = ["Parent", "FriendlyNodeName", "SupportsAutoUpdate"];
            
                    if (!itemsToSkip.includes(prop)) {
                        const lowerCasePropName = prop.slice(0, 1).toLowerCase() + prop.slice(1);
                        mappedProps[lowerCasePropName] = m[prop];
                    }
                }
                return mappedProps;
            });
            //// Get Selected Tracks as Name Only String Array
            let slctdTrcks = trckInfo.filter(track => track.isSelected === true).map(track => track.name)
            ///deselect top track
            sf.app.proTools.selectTracksByName({ trackNames: [slctdTrcks[0]], selectionMode: "Subtract" })
            ///Check Status of Auto Align
            const aApostIsOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
            if (aApostIsOpen) {
                sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
            } else {
                sf.ui.proTools.audioSuiteOpenPlugin({ category: "Other", name: "Auto-Align Post", });
            }
            /// Define Auto-Align Window
            let win = sf.ui.proTools.firstAudioSuiteWindow
            /// Set Processing Options
            win.audioSuiteSetOptions({ processingInputMode: 'ClipByClip', processingOutputMode: `CreateIndividualFiles`, });
            const sideChainButton = win.popupButtons.allItems[4]
            /// Set Sidechain to Work Track 1 if It's not set
            if (sideChainButton.title.value != slctdTrcks[0]) { sideChainButton.popupMenuSelect({ menuPath: [slctdTrcks[0]] }) };
            sf.wait({ intervalMs: 100 })
            /// Render Auto-Align
            win.audioSuiteRender();
            /// Wait For Render to Finish
            sf.ui.proTools.waitForNoModals();
            /// Re-Close Auto Align if it was Open
            if (!aApostIsOpen) { win.windowClose({}, `Could not find Audiosuite Window`); }
            
            1. JJason Freeman @Jason_Freeman
                2025-06-24 16:13:21.091Z

                Thank you for posting this! I literally was going to see if I could figure out how to modify the old code to do exactly this today. Saved me a bunch of time this morning!

                1. A couple more from today :

                  Just a super basic 'fixed track one' change your target track at the top, or better yet convert it to a template : https://soundflow.org/docs/how-to/custom-commands/command-templates

                  //// CHANGE YOUR SINGLE TARGET TRACK HERE :
                  
                  let keyTrack = 'DIA A 1'
                  
                  sf.ui.proTools.appActivateMainWindow();
                  sf.ui.proTools.invalidate();
                  
                  ///Check Status of Auto Align
                  const aApostIsOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
                  if (aApostIsOpen) {
                      sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
                  } else {
                      sf.ui.proTools.audioSuiteOpenPlugin({ category: "Other", name: "Auto-Align Post", });
                  }
                  /// Define Auto-Align Window
                  let win = sf.ui.proTools.firstAudioSuiteWindow
                  /// Set Processing Options
                  win.audioSuiteSetOptions({ processingInputMode: 'ClipByClip', processingOutputMode: `CreateIndividualFiles`, });
                  const sideChainButton = win.popupButtons.allItems[4]
                  /// Set Sidechain to Work Track 1 if It's not set
                  if (sideChainButton.title.value != keyTrack) { sideChainButton.popupMenuSelect({ menuPath: [keyTrack] }) };
                  sf.wait({intervalMs : 100})
                  /// Render Auto-Align
                  win.audioSuiteRender();
                  /// Wait For Render to Finish
                  sf.ui.proTools.waitForNoModals();
                  /// Re-Close Auto Align if it was Open
                  if (!aApostIsOpen) { win.windowClose({}, `Could not find Audiosuite Window`); }
                  

                  And then a fun one that cycles through an array of tracks and finds the first one with clips and aligns to that :

                  //// DEFINE THE TRACKS YOU WANT TO CHECK THROUGH HERE
                  
                  let keyTrackArray = ['DIA A 1', 'DIA B 1']
                  
                  sf.ui.proTools.appActivateMainWindow();
                  sf.ui.proTools.invalidate();
                  
                  ///GET TRACK INFO ALL
                  let trckInfo = sf.app.proTools.tracks.invalidate().allItems.map(m => {
                      let mappedProps = {};
                  
                      for (let prop in m) {
                          const itemsToSkip = ["Parent", "FriendlyNodeName", "SupportsAutoUpdate"];
                  
                          if (!itemsToSkip.includes(prop)) {
                              const lowerCasePropName = prop.slice(0, 1).toLowerCase() + prop.slice(1);
                              mappedProps[lowerCasePropName] = m[prop];
                          }
                      }
                      return mappedProps;
                  });
                  
                  
                  /**
                   * Returns the first track in keyTrackArray that contains clips.
                   * If none contain clips, returns null.
                   */
                  function getFirstKeyTrackWithClips(keyTrackArray) {
                      for (let i = 0; i < keyTrackArray.length; i++) {
                          const trackName = keyTrackArray[i];
                  
                          // Select the track
                          sf.app.proTools.selectTracksByName({ trackNames: [trackName] });
                  
                          // Fetch clip info
                          const clipInfo = sf.app.proTools.getSelectedClipInfo();
                  
                          // If this track has clips, return it
                          if (clipInfo.clips && clipInfo.clips.length > 0) {
                              return trackName;
                          }
                      }
                  
                      // No tracks had clips
                      return null;
                  }
                  
                  function autoAlignToTrackWithClipsFromArray(keyTrackArray) {
                      //// Get Selected Tracks as Name Only String Array
                      let slctdTrcks = trckInfo.filter(track => track.isSelected === true).map(track => track.name)
                      //// Get Keytrack from Array with Clips
                      let targetKeyTrack = getFirstKeyTrackWithClips(keyTrackArray);
                      
                      //// Reselect orginal tracks for aligning
                      sf.app.proTools.selectTracksByName({trackNames : slctdTrcks})
                  
                      ///Check Status of Auto Align
                      const aApostIsOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
                      if (aApostIsOpen) {
                          sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
                      } else {
                          sf.ui.proTools.audioSuiteOpenPlugin({ category: "Other", name: "Auto-Align Post", });
                      }
                  
                      /// Define Auto-Align Window
                      let win = sf.ui.proTools.firstAudioSuiteWindow
                      /// Set Processing Options
                  
                      win.audioSuiteSetOptions({ processingInputMode: 'ClipByClip', processingOutputMode: `CreateIndividualFiles`, });
                      const sideChainButton = win.popupButtons.allItems[4]
                      
                      /// Set Sidechain to Target Key Track
                      if (sideChainButton.title.value != slctdTrcks[0]) { sideChainButton.popupMenuSelect({ menuPath: [targetKeyTrack] }) };
                      
                      /// Waif for computers that are too fast
                      sf.wait({ intervalMs: 100 })
                  
                      /// Render Auto-Align
                      win.audioSuiteRender();
                  
                      /// Wait For Render to Finish
                      sf.ui.proTools.waitForNoModals();
                      
                      /// Re-Close Auto Align if it was Open
                      if (!aApostIsOpen) { win.windowClose({}, `Could not find Audiosuite Window`); }
                  }
                  
                  autoAlignToTrackWithClipsFromArray(keyTrackArray)
                  
                  1. Ok one more... this functions Kind of like searchable options but only for the tracks you have selected so If you have DX 1 - DX 9 selected it will prompt you with those track names and you pick which one will be they key track. Script deselects that one and runs align to it on the rest.

                    function popupTrackSearch() {
                        let trckInfo = sf.app.proTools.tracks.invalidate().allItems.map(function (m) {
                            var mappedProps = {};
                            var itemsToSkip = ["Parent", "FriendlyNodeName", "SupportsAutoUpdate"];
                    
                            for (var prop in m) {
                                if (itemsToSkip.indexOf(prop) === -1) {
                                    var lowerCasePropName = prop.slice(0, 1).toLowerCase() + prop.slice(1);
                                    mappedProps[lowerCasePropName] = m[prop];
                                }
                            }
                            return mappedProps;
                        });
                    
                        // Fetch all tracks in the session
                    
                        let slctdTrcks = trckInfo.filter(track => track.isSelected === true)
                    
                        // Create popup with track names
                        const keyTrack = sf.interaction.popupSearch({
                            title: `Key Track`,
                            items: slctdTrcks.map(track => ({ name: track.name })),
                        }).item.name;
                    
                        return keyTrack
                    }
                    
                    
                    
                    function main() {
                        sf.ui.proTools.appActivateMainWindow();
                        sf.ui.proTools.invalidate();
                    
                        let targetTrack = popupTrackSearch();
                    
                        sf.app.proTools.selectTracksByName({ trackNames: [targetTrack], selectionMode: "Subtract" })
                    
                        const aApostIsOpen = sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.exists
                    
                        if (aApostIsOpen) {
                            sf.ui.proTools.windows.whoseTitle.is("Audio Suite: Auto-Align Post").first.elementRaise();
                        } else {
                            sf.ui.proTools.audioSuiteOpenPlugin({
                                category: "Other",
                                name: "Auto-Align Post",
                            });
                        }
                    
                        let win = sf.ui.proTools.firstAudioSuiteWindow
                    
                    
                        win.audioSuiteSetOptions({
                            processingInputMode: 'ClipByClip',
                            processingOutputMode: `CreateIndividualFiles`,
                        });
                    
                        const selectedTrackName = sf.ui.proTools.selectedTrackNames[0]
                        const sideChainButton = win.popupButtons.allItems[4]
                    
                        if (sideChainButton.exists && selectedTrackName) {
                            sideChainButton.popupMenuSelect({
                                menuPath: [targetTrack],
                            });
                        }
                    
                        sf.wait({ intervalMs: 100 })
                    
                        win.audioSuiteRender();
                    
                        sf.ui.proTools.waitForNoModals();
                    
                        if (!aApostIsOpen) {
                            win.windowClose({}, `Could not find Audiosuite Window`);
                        }
                    }
                    
                    main();
                    
                    1. Ok last one I swear. Credit to @dario.ramaglia and @Chris_Shaw for this one. Dynamic Stream Deck Takeover version.

                      Important you MUST change line 3 to reflect YOUR Streamdeck's Serial Number for the Streamdeck you want the script to run on.

                      // === USER-DEFINED PRESET NAME (CHANGE PER SCRIPT INSTANCE) ===
                      const presetName = "TEST";  // <---- CHANGE THIS PER SCRIPT VERSION
                      const yourStreamDeck = 'AL49I2C09520' // <------- PLACE YOUR STREAMDECK SERIAL NUMBER HERE
                      

                      This script ONLY functions WITH a Streamdeck.

                      STEP ONE : HOLD CMD+Press button while you have the tracks you want displayed Selected - This will store the tracks you want as possible KeyTracks for Auto-Align
                      STEP TWO : Press button normally, your target Streamdeck will be taken over by buttons that reflect those tracks + Next Previous and Cancel button.
                      STEP THREE : Highlight track you want aligned and press the button for the track you want them aligned to. Repeat Step 3 until you are done aligning tracks.
                      STEP FOUR: Press Cancel to exit dynamic Deck.

                      WARNING - if you close the Auto-Align Audiosuite Window the next button press will throw an error and cancel out the Dynamic Deck.

                      // === USER-DEFINED PRESET NAME (CHANGE PER SCRIPT INSTANCE) ===
                      const presetName = "TEST";  // <---- CHANGE THIS PER SCRIPT VERSION
                      const yourStreamDeck = 'AL49I2C09520' // <------- PLACE YOUR STREAMDECK SERIAL NUMBER HERE
                      
                      // === JSON PATH FOR KEY TRACK STORAGE ===
                      const keyTrackJsonPath = sf.soundflow.thisPackage.getDirectory().path + "/keyTrackArrays.json";
                      
                      // === MODIFIER CHECK ===
                      const modifierState = event.keyboardState.asString;
                      
                      // ------------------------------------------------------------
                      // SAVE MODE β€” CMD HELD: Save selected tracks into preset
                      // ------------------------------------------------------------
                      function saveKeyTrackArray() {
                          const selectedTracks = sf.app.proTools.tracks.invalidate().allItems
                              .filter(function (t) { return t.isSelected; })
                              .map(function (t) { return t.name; });
                      
                          if (!selectedTracks.length) {
                              throw "❌ No selected tracks to save as key tracks.";
                          }
                      
                          let jsonData = {};
                          if (sf.file.exists({ path: keyTrackJsonPath }).exists) {
                              jsonData = sf.file.readJson({ path: keyTrackJsonPath }).json || {};
                          }
                      
                          jsonData[presetName] = selectedTracks;
                      
                          sf.file.writeJson({
                              path: keyTrackJsonPath,
                              json: jsonData
                          });
                      
                          log("πŸ’Ύ Saved keyTrackArray preset '" + presetName + "': " + selectedTracks.join(", "));
                      }
                      
                      // ------------------------------------------------------------
                      // LOAD MODE β€” Normal run: Load tracks from specific preset
                      // ------------------------------------------------------------
                      function loadKeyTrackArray() {
                          if (!sf.file.exists({ path: keyTrackJsonPath }).exists) {
                              throw "❌ No keyTrackArrays.json found β€” hold CMD to save a preset first.";
                          }
                      
                          const data = sf.file.readJson({ path: keyTrackJsonPath }).json;
                      
                          if (!data[presetName]) {
                              throw "❌ Preset '" + presetName + "' does not exist β€” hold CMD to save key tracks for this preset.";
                          }
                      
                          return data[presetName];
                      }
                      
                      
                      
                      function main() {
                          if (modifierState === "cmd") {
                              saveKeyTrackArray();
                              return;
                          }
                          //Open or Focus Auto-Align Post
                      
                          var asWin = sf.ui.proTools.getAudioSuiteWindow("Auto-Align Post");
                          if (!asWin.exists) {
                              asWin = sf.ui.proTools.audioSuiteOpenPlugin({
                                  category: "Other",
                                  name: "Auto-Align Post",
                              }).window;
                          }
                      
                          //Focus AAP
                      
                          var asWin = sf.ui.proTools.getAudioSuiteWindow("Auto-Align Post");
                          asWin.elementRaise();
                      
                      
                          //Set Processing Options
                      
                          asWin.audioSuiteSetOptions({
                              processingInputMode: "ClipByClip",
                              processingOutputMode: "CreateIndividualFiles"
                          });
                      
                          //Select SideChain
                          let trackNames = loadKeyTrackArray();
                      
                          ///Title Shortener
                          function shortenTitle(s) {
                              var res = '', i = 0;
                              while (s.length > 0 && i < 3) {
                                  if (i > 0) res += '\n';
                                  res += s.substring(0, 8);
                                  s = s.substring(8);
                                  i++;
                              }
                              return res;
                          }
                      
                      
                          // ----- PAGED STREAM DECK SELECTOR WITH PERSISTENT MENU -----
                      
                          function chunkIntoPages(array, size) {
                              const pages = [];
                              for (let i = 0; i < array.length; i += size) {
                                  pages.push(array.slice(i, i + size));
                              }
                              return pages;
                          }
                      
                          const streamDeck = sf.devices.streamDeck.getDeviceBySerialNumber(yourStreamDeck);
                      
                          // Determine deck size
                          const cols = streamDeck.columnCount;
                          const rows = streamDeck.rowCount;
                          const totalButtons = cols * rows;
                      
                          // Reserved buttons
                          const RESERVED = ["β¬…οΈŽ Prev", "➑︎ Next", "Cancel"];
                          const usableButtons = totalButtons - RESERVED.length;
                      
                          // Page data
                          const trackPages = chunkIntoPages(trackNames, usableButtons);
                      
                          let currentPage = 0;
                          let selectedName = null;
                      
                          streamDeck.doWithSeizedDevice({
                              action: () => {
                      
                                  // ⭐ OUTER LOOP β€” keeps the menu open after each track selection
                                  while (true) {
                      
                                      let trackChosen = false;
                      
                                      // ⭐ INNER LOOP β€” handles page navigation
                                      while (true) {
                                          const pageItems = trackPages[currentPage].map(name => {
                                              let color;
                                              if (name.indexOf('Boom') >= 0)
                                                  color = { r: 74, g: 0, b: 106 };
                                              else if (name.indexOf('Radio') >= 0)
                                                  color = { r: 22, g: 100, b: 106 };
                                              else if (name.indexOf('Lav') >= 0)
                                                  color = { r: 22, g: 100, b: 106 };
                                              else if (name.indexOf(' ') >= 0)
                                                  color = { r: 142, g: 15, b: 8 };
                      
                                              return {
                                                  title: shortenTitle(name),
                                                  value: name,
                                                  color
                                              };
                                          });
                      
                                          // Fill empty space
                                          while (pageItems.length < usableButtons) {
                                              pageItems.push({
                                                  title: "",
                                                  value: null,
                                                  color: { r: 0, g: 0, b: 0 }
                                              });
                                          }
                      
                                          // Reserved buttons (gold)
                                          const gold = { r: 119, g: 93, b: 32 };
                      
                                          pageItems.push({ title: "β¬…οΈŽ Prev", value: "Prev", color: gold });
                                          pageItems.push({ title: "➑︎ Next", value: "Next", color: gold });
                                          pageItems.push({ title: "Cancel", value: "Cancel", color: gold });
                      
                                          const selection = streamDeck.showModal({ items: pageItems }).selectedItem;
                                          if (!selection) return;
                      
                                          if (selection.value === "Cancel") {
                                              return; // EXIT ENTIRE SCRIPT
                                          }
                      
                                          if (selection.value === "Next") {
                                              currentPage = (currentPage + 1) % trackPages.length;
                                              continue;
                                          }
                      
                                          if (selection.value === "Prev") {
                                              currentPage = (currentPage - 1 + trackPages.length) % trackPages.length;
                                              continue;
                                          }
                      
                                          // A track was chosen
                                          selectedName = selection.value;
                                          trackChosen = true;
                                          break;
                                      }
                      
                                      // ⭐ Do your Auto-Align Post logic for THIS track
                                      if (trackChosen) {
                                          // Set Key Input
                                          sf.ui.proTools.appActivate();
                                          let keyInputBtn = sf.ui.proTools.firstAudioSuiteWindow
                                              .invalidate().popupButtons.whoseTitle.is('Key Input').first;
                      
                                          keyInputBtn.popupMenuSelect({ menuPath: [selectedName] });
                      
                                          sf.wait({ intervalMs: 100 });
                      
                                          // Render
                                          asWin.audioSuiteRender();
                      
                                          // ⭐ Loop continues automatically β€” the menu reappears
                                      }
                                  }
                              }
                          });
                      }
                      
                      main()
                      
              • J
                Jason Freeman @Jason_Freeman
                  2024-04-05 18:37:11.088Z

                  Amazing! Im going to give these a try right now.

                  1. JJason Freeman @Jason_Freeman
                      2024-04-05 19:24:29.316Z

                      OMG! This is EXACTLY what I have been looking for! You just saved me countless amounts of clicking and moving clips around. THANK YOU!

                    • D
                      danielkassulke @danielkassulke
                        2024-04-06 08:10:14.781Z

                        @Owen_Granich_Young this code absolutely rips. Thanks!

                        1. Just cobbled together from @samuel_henriques and @Kitch code. @Brian_Armstrong got me building it in the first place. I’ve actually never owned auto align without it, I can’t imagine using it with out lol. So many clicks.

                          Bests
                          Owen

                        2. C
                          codebrainzero @codebrainzero
                            2024-08-17 17:28:33.640Z

                            Amazing work here. Been using AA for some time now and didn't think it could get better...

                            1. Thanks @codebrainzero -- here's an alternate (a little slower) approach that adds handles to the material.