No internet connection
  1. Home
  2. How to

Trackselectbyname causes Edit Menu to grey out

By Forrester Savell @Forrester_Savell
    2024-07-17 23:40:48.845Z

    I've a script that has been working fine until recently (perhaps PT2024.6 or SF5.8?). It sets up a stereo track for reverse fx from a selected mono track

    However, after copying clips and then creating new tracks and selecting the top one, it seems to be failing at pasting the clips. I've discovered that once it runs the app.trackSelectByName({names: [newlyCreatedTracks[0].normalizedTrackName] the Edit Menu is mostly greyed out. I've tried a few kinds of invalidating (sf.ui.proTools.windows.invalidate(); etc) but can't seem to get the Edit menu to reactivate. If I manually facilitate a keypress (such as ; or p) to move the selection up and down, the Edit menu comes back online and I am able to get the copied clips to Paste.

    Is there a way to reactivate the Edit menu and allow access to the Paste command, without putting in a random keypress? The first paste attempt on the script below Line 247 is where it stops working

    const app = sf.ui.proTools;
    
    app.appActivateMainWindow()
    app.invalidate()
    
    function scrollToTrackNamed(trackName, selectedTracks) {
        // Open scroll to track dialog and enter track name
        app.menuClick({ menuPath: ['Track', 'Scroll to Track...'] });
        var confirmationDialogWin = app.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
        //app.trackSelectByName({ names: selectedTracks })
    };
    
    
    
    function saveUserWinConfig() {
        app.appActivateMainWindow();
        app.menuClick({
            menuPath: ["Window", "Configurations", "New Configuration..."],
        });
        //Wait for the Window Config dialog to appear and assign it to the memLocDlg variable
        var winConfigDlg = app.dialogWaitForManual({
            dialogTitle: 'New Window Configuration'
        }).dialog;
        //We want to save a window layout
        winConfigDlg.radioButtons[1].elementClick()
        //We want to include all windows
        winConfigDlg.checkBoxes[0].checkboxSet({
            targetValue: 'Enable',
        })
        //Name the Location Track Visibilty
        winConfigDlg.textFields.allItems[1].elementSetTextFieldWithAreaValue({
            value: "User Window Setup",
        });
    
        //Get the Location Number and pass it back so we can delete it when we're done
        var configNumber = winConfigDlg.textFields.allItems[0].value.invalidate().value;
    
        //Create the Location
        winConfigDlg.buttons.whoseTitle.is('OK').first.elementClick();
    
        app.windows.whoseTitle.is('New Window Configuration').first.elementWaitFor({
            waitType: "Disappear",
        });
    
        return configNumber
    }
    
    function recallAndDeleteWinConfig(configNumber) {
        app.appActivateMainWindow();
        app.menuClick({
            menuPath: ["Window", "Configurations", "Window Configuration List"],
            targetValue: 'Enable',
        });
        app.windows.whoseTitle.is('Window Configurations').first.elementWaitFor();
    
        var winConfigWindow = app.windows.whoseTitle.is('Window Configurations').first
    
        // Recall Window Config which will also leave it selected for deleting
        const configNumStr = configNumber.toString();
    
        let winConfigWords = 'numpad comma, ';
        for (var i = 0; i < configNumStr.length; i++) {
            winConfigWords = winConfigWords.concat('numpad ' + configNumStr[i] + ", ")
        }
    
        let keys = winConfigWords + "numpad multiply";
    
        sf.keyboard.press({
            keys: keys,
        });
        app.windows.whoseTitle.is('Window Configurations').first.buttons.first.popupMenuSelect({
            menuSelector: items => items.filter(i => i.names[0].match(/^Clear \"/))[0]
        });
    
        app.menuClick({
            menuPath: ["Window", "Configurations", "Window Configuration List"],
            targetValue: 'Disable'  //or 'Enable' or 'Toggle'
        });
        app.windows.whoseTitle.is('Window Configurations').first.elementWaitFor({
            waitType: "Disappear",
        });
    
    }
    
    
    function createTracks(trackName) {
        app.menuClick({
            menuPath: ['Track', 'New...']
        });
        const newTrackWin = app.windows.whoseTitle.is("New Tracks").first
    
        newTrackWin.elementWaitFor();
    
        const numberField = newTrackWin.textFields.whoseTitle.is('Number of new tracks').first;
    
        const numberOfTracks = '2';
    
        if (numberField.value.invalidate().value.trim() !== numberOfTracks) {
            numberField.elementClick();
    
            sf.keyboard.type({ text: numberOfTracks });
    
            var i = 0;
            while (numberField.value.invalidate().value !== numberOfTracks) {
                sf.wait({ intervalMs: 30 });
            };
        }
    
        newTrackWin.popupButtons.whoseDescription.is("Track format").first.popupMenuSelect({
            menuPath: ["Mono"]
        });
    
        newTrackWin.popupButtons.whoseDescription.is("Track type").first.popupMenuSelect({
            menuPath: ["Audio Track"]
        });
    
        newTrackWin.buttons.whoseTitle.is("Add row").first.elementClick();
    
        newTrackWin.popupButtons.allItems[3].popupMenuSelect({
            menuPath: ['Stereo']
        })
    
        newTrackWin.popupButtons.allItems[4].popupMenuSelect({
            menuPath: ["Audio Track"]
        });
    
        newTrackWin.textFields.whoseTitle.is("Track Name").allItems[1].elementSetTextFieldWithAreaValue({
            value: 'reverses ' + trackName,
        });
    
        newTrackWin.buttons.whoseTitle.is("Create").first.elementClick();
    
    
    };
    
    function recallPlugins() {
    
        const presetName = "reverses"
    
        const tracks = app.selectedTrackHeaders
    
        //Scroll firsr track to View
        tracks[0].trackScrollToView()
        app.selectedTrack.insertSelectorButtons[0].popupMenuSelect({
    
            menuPath: ["recall inserts", "Mix Templates", "VOCALS", presetName],
        })
    
        if (app.confirmationDialog.buttons.whoseTitle.is("Change").first.exists) {
            app.confirmationDialog.buttons.whoseTitle.is("Change").first.elementClick();
        }
    
        //dismissConfirmationDialog("OK")
    
    };
    
    function getSelection() {
    
        const timelineSelection = app.selectionGet();
        let originalSelectionSamples = app.selectionGetInSamples();
        if (originalSelectionSamples.selectionLength === 0) {
            sf.interaction.displayDialog({
                prompt: 'Make a selction on the track to be reversed.',
                giveUpAfterSeconds: 2
            })
    
            throw 0
        };
        return timelineSelection
    }
    
    
    function main() {
        //Store window config for recall
        saveUserWinConfig()
    
        //Hide Windows
        if (app.getMenuItem('Window', 'Hide All Floating Windows').isEnabled && !app.getMenuItem('Window', 'Hide All Floating Windows').isMenuChecked) {
            app.menuClick({ menuPath: ['Window', 'Hide All Floating Windows'] });
        }
    
        //Get timeline selection
        const originalSelection = getSelection()
    
        //store selected track name for use
        const trackName = app.selectedTrack.normalizedTrackName;
    
        //log(trackName)
    
        //Change state of Automation Follows Edit to OFF
        app.menuClick({
            menuPath: ["Options", "Automation Follows Edit"],
            targetValue: 'Disable',
        });
    
        // Change all selected (Audio)tracks to Waveform
        try {
            app.selectedTrack.trackDisplaySelect({
                displayPath: ["waveform"],
                selectForAllSelectedTracks: true
            })
        } catch (err) {
            sf.interaction.displayDialog({
                prompt: 'Select the track to be reversed.',
                giveUpAfterSeconds: 2
            });
            throw 0
        }
    
        // define track output selector
        const audioOutput = app.selectedTrack.groups.whoseTitle.is("Audio IO")
        const trackOutput = audioOutput.first.popupButtons.allItems[1]
    
        // get ouput of first track
        let outputPaths = trackOutput.popupMenuFetchAllItems().menuItems
        const outputPath = outputPaths.map((mi, i) => ({ menuItem: mi, index: i })).filter(m => m.menuItem.element.isMenuChecked)[0].menuItem.path;
    
        app.appActivateMainWindow();
    
        //Select the entire track to be stored in the "reverse" track's first playlist
        app.menuClick({ menuPath: ['Edit', 'Select All'] });
    
        app.menuClick({ menuPath: ['Edit', 'Copy'] });
    
        //Creates 2x temp mono and a stereo track to stereoize mono vocal track
        createTracks(trackName);
    
        const newlyCreatedTracks = app.selectedTrackHeaders;
    
        //Select first temp mono track and paste
        app.trackSelectByName({
            names: [newlyCreatedTracks[0].normalizedTrackName
            ]
        });
        app.windows.invalidate();
    
        app.menuClick({
            menuPath: ['Edit', 'Paste']
        });
    
    
        if (app.confirmationDialog.buttons.whoseTitle.is("OK").first.exists) {
            app.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick();
            app.confirmationDialog.buttons.whoseTitle.is("OK").first.elementWaitFor({ waitType: "Disappear" });
        };
    
        //Select second temp mono track and paste
        app.trackSelectByName({ names: [newlyCreatedTracks[1].normalizedTrackName] });
    
        app.menuClick({
            menuPath: ['Edit', 'Paste']
        });
        if (app.confirmationDialog.buttons.whoseTitle.is("OK").first.exists) {
            app.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick();
            app.confirmationDialog.buttons.whoseTitle.is("OK").first.elementWaitFor({ waitType: "Disappear" });
        };
    
        //Select both mono tracks to copy to stereo track
        app.menuClick({
            menuPath: ['Edit', 'Selection', 'Extend Edit Up']
        });
    
        app.menuClick({ menuPath: ['Edit', 'Copy'] });
    
        app.trackSelectByName({ names: [newlyCreatedTracks[2].normalizedTrackName] });
    
        app.menuClick({ menuPath: ['Edit', 'Paste'] });
    
    
        // Set Original Selection
        app.selectionSet({
            selectionStart: originalSelection.selectionStart,
            selectionEnd: originalSelection.selectionEnd
        });
    
        //Copy original selection on stereo track, create new playlist and paste
    
        app.menuClick({ menuPath: ['Edit', 'Copy'] });
    
        //app.appActivateMainWindow()
    
        scrollToTrackNamed('reverses ' + trackName)
    
        app.selectedTrack.popupButtons.whoseTitle.is('Playlist selector').first.popupMenuSelect({
            menuPath: ["New..."],
            relativePosition: { x: 5, y: 5 }
        });
    
        app.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick();
    
        app.trackSelectByName({ names: ['reverses ' + trackName + '.01'] });
    
        app.appActivateMainWindow()
    
        app.menuClick({ menuPath: ['Edit', 'Paste'] });
    
        //Load Track preset for reverse FX
        recallPlugins()
    
        //Additional clear for Windows due to Eucon/PT bug
        if (app.getMenuItem('Window', 'Hide All Floating Windows').isEnabled && !app.getMenuItem('Window', 'Hide All Floating Windows').isMenuChecked) {
            app.menuClick({ menuPath: ['Window', 'Hide All Floating Windows'] });
        }
        //Route reverses stereo track to same as originally selected track
        app.selectedTrack.groups.whoseTitle.is("Audio IO").first.
            popupButtons.whoseTitle.contains("Audio Output").first.popupMenuSelect({
                menuPath: outputPath,
            });
    
        //Delete the two temp mono tracks
        app.trackSelectByName({ names: [newlyCreatedTracks[0].normalizedTrackName, newlyCreatedTracks[1].normalizedTrackName] });
    
        app.trackDelete();
    
        app.windows.first.buttons.whoseTitle.is("Delete").first.elementClick();
    
        scrollToTrackNamed(trackName)
    
        //recallAndDeleteWinConfig(saveUserWinConfig)
        
        app.audioSuiteOpenPlugin({
            category: 'Reverb',
            name: 'MannyM Reverb Stereo',
        }).window;
    
    };
    
    main()
    
    
    Solved in post #2, click to view
    • 8 replies
    1. Hey @Forrester_Savell, try replacing all instances of:

      app.menuClick({ menuPath: ['Edit', 'Copy'] });
      
      app.menuClick({ menuPath: ['Edit', 'Paste'] });
      

      with:

      sf.app.proTools.copy();
      
      sf.app.proTools.paste();
      

      These are SDK commands that talk directly to Pro Tools, so no invalidating should be required.

      Haven't tested your script to make sure it works, but that is the first thing I'd try.

      Reply1 LikeSolution
      1. FForrester Savell @Forrester_Savell
          2024-07-18 02:44:00.720Z

          Nailed it, thanks @raphaelsepulveda

          Serendipitous that you replied, as I saw your Insta story on exactly the same script idea, which reminded me I had this one and to use it more often!

          1. Awesome!! Definitely beats doing it manually, that’s for sure!

        • S
          SoundFlow Bot @soundflowbot
            2024-07-18 15:31:46.938Z

            This report was now added to the internal issue tracked by SoundFlow as SF-1368

            1. Chad Wahlbrink @Chad2024-07-18 15:37:26.675Z

              Hey @Forrester_Savell,

              I'm glad Raphael's suggestion helped! We are tracking this issue with sf.ui.proTools.trackSelectByName() not updating menus in SF 5.8.0. Thanks for this post to further confirm the behavior.

              In this other post, @Jack_Green discovered that using sf.keyboard.press({ keys: 'left' }); will reset the Pro Tools menu state with the new selection if invalidate() does not. This is not an ideal solution, as it's using keyboard simulation, but it could help navigate this issue until we get a fix.

              1. FForrester Savell @Forrester_Savell
                  2024-07-18 21:50:08.826Z

                  Thanks for the update @Chad

                  After Raphael solved the copy/paste issue, I found that post by @Jack_Green yesterday and used that workaround line because I have the trackDelete() on Line 323 in the above code which wasn't working either.

                  Glad we've this forum and community to help each other!

                • S
                  SoundFlow Bot @soundflowbot
                    2024-12-10 23:51:28.456Z

                    Linked issue SF-1368 updated: This should be fixed in the next release of SoundFlow.

                    1. S
                      SoundFlow Bot @soundflowbot
                        2024-12-10 23:51:33.273Z

                        The linked internal issue SF-1368 has been marked as Done