No internet connection
  1. Home
  2. Macro and Script Help

Rx Connect Sending Early Before Settings Established (Sonoma 14.6)

By Ben Rauscher @Ben_Rauscher
    2024-08-06 17:17:17.703Z

    Title

    Rx Connect Sending Early Before Settings Established (Sonoma 14.6)

    What do you expect to happen when you run the script/macro?

    Sent a clip to Rx with the designated setting.

    Are you seeing an error?

    What happens when you run this script?

    Pro Tools will pre-emptively send the clip before SoundFlow implements the correct settings. Specifically, when switching from Clip-by-Clip / Individual Files / Mono Input to Entire Selection / Continuous File / Multi Input. PT will submit the first settings, but when re-sending a second time, Rx will properly receive it.

    How were you running this script?

    I used a keyboard shortcut within the target app

    How important is this issue to you?

    5

    Details

    {
        "inputExpected": "Sent a clip to Rx with the designated setting.",
        "inputIsError": false,
        "inputWhatHappens": "Pro Tools will pre-emptively send the clip before SoundFlow implements the correct settings. Specifically, when switching from Clip-by-Clip / Individual Files / Mono Input to Entire Selection / Continuous File / Multi Input. PT will submit the first settings, but when re-sending a second time, Rx will properly receive it.",
        "inputHowRun": {
            "key": "-Mpfwh4RkPLb2LPwjePT",
            "title": "I used a keyboard shortcut within the target app"
        },
        "inputImportance": 5,
        "inputTitle": "Rx Connect Sending Early Before Settings Established (Sonoma 14.6)"
    }

    Source

    if (!sf.ui.proTools.isRunning) throw `Pro Tools is not running`;
    
    const {
        rxConnectVersion,
        selectionReference,
        copyAction,
        copyTargetTrackName,
        copyTargetTrackNameMatch,
        useInPlaylist,
        presetPath,
        processingOutputMode,
        processingInputMode,
        inputMode,
        previewProcessing,
        bypass,
        previewVolume,
        learn,
        wholeFile,
        processingHandleLength,
        render,
        compositeView,
    } = event.props;
    
    // Bail out if copy action exists but no track name is specified.
    if (copyAction) {
        if (copyTargetTrackName === null || copyTargetTrackName === "" || copyTargetTrackName === undefined) {
            throw `The "RX Connect: Send to iZotope" preset has no specified "Copt Target Track Name"`;
        } else if (copyTargetTrackNameMatch === null || copyTargetTrackNameMatch === "" || copyTargetTrackNameMatch === undefined) {
            throw `The "RX Connect: Send to iZotope" preset has no specified "Copt Target Track Name Match"`;
        }
    }
    
    const rxConnectNames = [
        'RX 10 Connect',
        'RX 9 Connect',
        'RX 8 Connect',
        'RX 7 Connect',
        'RX 6 Connect',
    ];
    
    function openRxConnect(version) {
        let audioSuiteWindow = sf.ui.proTools.windows.invalidate().whoseTitle.is(`Audio Suite: ${version}`).first;
    
        if (!audioSuiteWindow.exists) {
            audioSuiteWindow = sf.ui.proTools.audioSuiteOpenPlugin({
                category: 'Noise Reduction',
                name: version
            }, `Unable to open ${rxConnectVersion}`).window;
        }
        return audioSuiteWindow;
    }
    
    function naturalCompare(a, b) {
        const aNum = parseInt(a.match(/\d+/)[0]);
        const bNum = parseInt(b.match(/\d+/)[0]);
        return aNum - bNum;
    }
    
    function getRxConnectWindow() {
        let win;
        const rxSubPaths = ["iZotope", "iZotope, Inc", "Noise Reduction"];
    
        function getLatest() {
            const latestRxVersionName = sf.ui.proTools.getMenuItem("AudioSuite").getMenuItem("Noise Reduction").children.first.children.filter(asName => {
                return asName.title.invalidate().value.startsWith("RX") && asName.title.invalidate().value.endsWith("Connect")
            }).map(e => e.title.invalidate().value).sort(naturalCompare).reverse()[0];
    
            if (!latestRxVersionName) throw `iZotope RX (6-10) Connect not installed`;
    
            //Open and get the latest RX Connect version's AudioSuite window
            return openRxConnect(latestRxVersionName);
        }
    
        if (rxConnectVersion === "Currently Open Version") {
    
            let firstOpenRxConnectWindow = sf.ui.proTools.windows.filter(w => {
                let title = w.title.invalidate().value;
                return title.startsWith("Audio Suite: RX") && title.endsWith("Connect")
            })[0];
    
            //Return RX Connect Window
            win = firstOpenRxConnectWindow;
    
            if (!win || !win.exists)
                win = getLatest();
        }
        else if (rxConnectVersion === "Latest Available Version") {
    
            win = getLatest();
    
        } else {
    
            //Check for existance of specified RX Connect pluggin
            let hasSpecifiedRxConnectVersion = rxSubPaths.some(subPath => {
                return sf.ui.proTools.getMenuItem("AudioSuite", subPath, rxConnectVersion).exists
            });
    
            //If the RX Conneect version does not exist throw error
            if (!hasSpecifiedRxConnectVersion) throw `${rxConnectVersion} not installed`;
    
            //Open Given version AudioSuite Win
            win = openRxConnect(rxConnectVersion);
        }
    
        return win;
    }
    
    function createSelectionCopy() {
        const pasteToFirstTrackWithSpace = () => {
            sf.ui.proTools.mainWindow.invalidate();
    
            const originalTrack = sf.ui.proTools.selectedTrack;
    
            // Filter the tracks list for backup (copy) tracks
            let backupTrackNames = sf.ui.proTools.trackNames.filter(name => name.startsWith(copyTargetTrackName));
    
            for (const trackName of backupTrackNames) {
                const track = sf.ui.proTools.trackGetByName({ name: trackName }).track;
    
                track.trackSelect();
    
                sf.keyboard.press({ keys: "left" });
    
                if (!sf.ui.proTools.getMenuItem("Edit", "Trim Clip").isEnabled) {
                    pasteSelection();
                    break;
                }
    
                if (trackName === backupTrackNames[backupTrackNames.length - 1]) {
                    originalTrack.trackSelect();
                    throw "There is no empty space on the backup (copy) track(s)";
                }
            }
        }
    
        const refreshProToolsMenu = () => sf.keyboard.press({ keys: "left" });
    
        const copySelection = () => {
            refreshProToolsMenu();
            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Copy"] });
        }
    
        const pasteSelection = () => {
            refreshProToolsMenu();
            sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste"] });
        }
    
        const separateSelection = () => {
            refreshProToolsMenu();
    
            if (sf.ui.proTools.getMenuItem("Edit", "Trim Clip", "To Selection").isEnabled) {
                sf.ui.proTools.menuClick({ menuPath: ["Edit", "Separate Clip", "At Selection"] });
            }
        }
    
        const muteClips = () => {
            refreshProToolsMenu();
    
            const unMuteClipsMenuItem = () => sf.ui.proTools.getMenuItem("Edit", "Unmute Clips");
            const muteClipsMenuItem = () => sf.ui.proTools.getMenuItem("Edit", "Mute Clips");
    
            if (unMuteClipsMenuItem().exists) {
                unMuteClipsMenuItem().elementClick();
            }
            muteClipsMenuItem().elementClick();
        }
    
        /** This function uses trackGetByName to select the track with a matching name */
        function selectTrackByName(name) {
            const track = () => sf.ui.proTools.trackGetByName({ name }).track;
    
            if (track().exists) {
                track().trackSelect();
            } else {
                throw `The track named "${name}" does not exist`
            }
        }
    
        sf.ui.proTools.appActivateMainWindow();
    
        if (copyAction === "ProcessOriginalMutedCopy") {
    
            const originalTrack = sf.ui.proTools.selectedTrack;
    
            copySelection(); // Copy the Selection
    
            if (copyTargetTrackNameMatch === "Equals") {
                // Added Temporarily
                selectTrackByName(copyTargetTrackName);
            } else if (copyTargetTrackNameMatch === "Starts With") {
                // Future implementation
                //pasteToFirstTrackWithSpace(); // Paste to first available backup (copy) track
            }
    
            pasteSelection();
    
            muteClips(); // Mute the selection
    
            originalTrack.trackSelect();
    
            sf.wait({ intervalMs: 20 });
    
        } else if (copyAction === "MuteOriginalProcessCopy") {
    
            copySelection(); // Copy the Selection
    
            separateSelection(); // Separate Selection if part of a full clip
    
            muteClips(); // Mute the selection
    
    
            if (copyTargetTrackNameMatch === "Equals") {
                // Added Temporarily
                selectTrackByName(copyTargetTrackName);
            } else if (copyTargetTrackNameMatch === "Starts With") {
                // Future implementation
                //pasteToFirstTrackWithSpace(); // Paste to first available backup (copy) track
    
            }
    
            pasteSelection();
        }
    }
    
    function setAudioSuiteSettings() {
        sf.ui.proTools.appActivateMainWindow();
        sf.ui.proTools.mainWindow.invalidate();
    
        const firstAudioSuiteWindow = sf.ui.proTools.firstAudioSuiteWindow;
    
        // Header Elements
        const selectionReferencePopUpBtn = firstAudioSuiteWindow.invalidate().getFirstWithTitle("Selection Reference");
        const useProcessedOutputInPlaylistBtn = firstAudioSuiteWindow.getFirstWithTitle("Use Processed Output In Playlist");
        const presetPopUpBtn = firstAudioSuiteWindow.getFirstWithTitle("Preset");
        const processingOutputModePopUpBtn = firstAudioSuiteWindow.getFirstWithTitle("Processing Output Mode");
        const processingInputModePopUpBtn = firstAudioSuiteWindow.getFirstWithTitle("Processing Input Mode");
        const inputModePopUpBtn = firstAudioSuiteWindow.getFirstWithTitle("input mode");
    
        // Footer Elements
        const previewProcessingBtn = firstAudioSuiteWindow.buttons.whoseTitle.is("Preview Processing").first;
        const bypassBtn = firstAudioSuiteWindow.buttons.whoseTitle.is("Bypass").first;
        const previewVolumeSlider = firstAudioSuiteWindow.sliders.whoseTitle.is("Preview Volume").first;
        const learnBtn = firstAudioSuiteWindow.buttons.whoseTitle.is("Analyze").first;
        const wholeFileBtn = firstAudioSuiteWindow.buttons.whoseTitle.is("WHOLE FILE").first;
        const processingHandleLengthTextField = firstAudioSuiteWindow.textFields.whoseTitle.is("Processing Handle Length in Seconds").first;
        const renderBtn = firstAudioSuiteWindow.buttons.whoseTitle.is("Render").first;
    
        // Set Header Settings
    
        // Set Selection Reference ('playlist'|'cliplist')
        if (selectionReference !== undefined && selectionReferencePopUpBtn.value.invalidate().value !== selectionReference) {
            selectionReferencePopUpBtn.popupMenuSelect({
                menuPath: [selectionReference],
            });
        }
    
        // Set "USE IN PLAYLIST" button (boolean)
        let isUsedInPlaylist = useProcessedOutputInPlaylistBtn.value.invalidate().value === "Selected";
        if (useInPlaylist !== undefined && isUsedInPlaylist !== useInPlaylist) {
            useProcessedOutputInPlaylistBtn.elementClick();
        }
    
        // Set AudioSuite Preset
        if (presetPath !== undefined && presetPath !== "") {
            presetPopUpBtn.popupMenuSelect({
                menuPath: presetPath,
            });
        }
    
        // Set AudioSuite Processing Output Mode ('overwrite files'|'create individual files'|'create continuous file')
        if (processingOutputMode !== undefined && processingOutputModePopUpBtn.value.invalidate().value !== processingOutputMode) {
            processingOutputModePopUpBtn.popupMenuSelect({
                menuPath: [processingOutputMode],
            });
    
            //Hack needed to close popup menu.
            sf.ui.proTools.appActivateMainWindow();
        }
    
        // Set AudioSuite Processing Input Mode ('clip-byclip'|'entire-selection')
        if (processingInputMode !== undefined && processingInputModePopUpBtn.value.invalidate().value !== processingInputMode) {
            processingInputModePopUpBtn.popupMenuSelect({
                menuPath: [processingInputMode],
            });
        }
    
        // Set AudioSuite "Input Mode" ('mono mode'|'multi-input mode')
        if (inputMode !== undefined && inputModePopUpBtn.value.invalidate().value !== inputMode) {
            inputModePopUpBtn.popupMenuSelect({
                menuPath: [inputMode],
            });
        }
    
        // Set Footer Settings
    
        // Press "Preview Processing" Button
        if (previewProcessing !== undefined && previewProcessingBtn.exists && previewProcessingBtn.value.invalidate().value === "Selected" !== previewProcessing) {
            previewProcessingBtn.elementClick();
        }
    
        //Set "Bypass" button state
        if (bypass !== undefined && bypassBtn.exists && bypassBtn.value.invalidate().value === "Selected" !== bypass) {
            bypassBtn.elementClick();
        }
    
        //Set "Preview Volume" (Not Tested)
        if (previewVolume !== undefined && previewVolumeSlider.exists && previewVolumeSlider.value.invalidate().value !== previewVolume) {
            previewVolumeSlider.value.value = previewVolume;
        }
    
        //Click "Learn" button
        if (learn !== undefined && learnBtn.exists && learnBtn.value.invalidate().value !== learn) {
            learnBtn.elementClick();
            sf.ui.proTools.waitForNoModals();
        }
    
        //Set "WHOLE FILE" button state
        if (wholeFile !== undefined && wholeFileBtn.exists && (wholeFileBtn.value.invalidate().value === "Selected" !== wholeFile)) {
            wholeFileBtn.elementClick();
        }
    
        /**
         * @param {object} obj
         * @param {AxElement} obj.handleField
         * @param {number} obj.value
         */
        function setHandleLengthValue({ handleField, value }) {
            handleField.elementWaitFor();
    
            const formatedValue = value.toFixed(2).toString().padStart(7).toString();
    
            if (handleField.value.invalidate().value !== formatedValue) {
                // Get clipboard text
                const oldClipboardText = sf.clipboard.getText().text || "";
    
                try {
                    sf.clipboard.setText({ text: formatedValue });
                    handleField.elementClick();
                    sf.keyboard.press({ keys: "cmd+v", });
    
                    let i = 0;
                    do {
                        sf.wait({ intervalMs: 100 });
                        i++
                        if (i >= 20) { throw `Could not update the number field` }
                    } while (handleField.value.invalidate().value !== formatedValue);
    
                    sf.keyboard.press({ keys: 'return' });
                } finally {
                    // Restore Clipboard text
                    sf.clipboard.setText({ text: oldClipboardText });
                }
            }
        }
    
        //Set Processing Handle Length
        if (processingHandleLength && processingHandleLengthTextField.exists) {
            setHandleLengthValue({
                handleField: processingHandleLengthTextField,
                value: processingHandleLength,
            });
        }
    
        //Click Render
        if (render) {
            renderBtn.elementClick();
            firstAudioSuiteWindow.elementWaitFor({ waitForNoElement: true });
            sf.ui.proTools.waitForNoModals();
        }
    }
    
    /** 
     * @param {object} obj
     * @param {'Enable'|'Disable'|'Toggle'} obj.targetValue
     */
    function setCompositeView({ targetValue }) {
        const izotope = sf.ui.izotope;
    
        izotope.invalidate();
        izotope.appActivateMainWindow();
    
        const compositViewBtn = izotope.mainWindow.buttons.whoseDescription.is("Composite View").first;
        const compositeTab = izotope.mainWindow.getFirstWithDescription("Composite Tab");
        const clickCompositeBtn = () => compositViewBtn.elementClick({ onError: "Continue" });
    
        switch (targetValue) {
            case "Enable":
                if (!compositeTab.exists) clickCompositeBtn();
                break;
            case "Disable":
                if (compositeTab.exists) clickCompositeBtn();
                break;
            case "Toggle":
                clickCompositeBtn();
                break;
        }
    }
    
    //Wait for iZotope to be in focus.
    function activateAndWaitForiZotope() {
        let tries = 0;
        while (!sf.ui.frontmostApp.title.value || !sf.ui.frontmostApp.title.value.includes("iZotope") && tries < 20) {
            sf.wait({ intervalMs: 200 });
            tries++;
        }
        if (tries === 40) throw `Could not activate iZotope RX`;
    }
    
    function main() {
        const win = getRxConnectWindow();
    
        // Make Unprocessed Copy 
        if (copyAction) {
            createSelectionCopy();
        }
    
        setAudioSuiteSettings();
    
        win.getFirstWithTitle("Analyze").elementClick();
    
        activateAndWaitForiZotope();
    
        //Set to Composite View option
        if (compositeView !== undefined && compositeView) {
            setCompositeView({ targetValue: compositeView });
        }
    }
    
    main();
    

    Links

    User UID: TnhuNKPrVzSFfAusX111YfbM4T82

    Feedback Key: sffeedback:TnhuNKPrVzSFfAusX111YfbM4T82:-O3cgUTZy0s6uXLpWci9

    Feedback ZIP: QMPvYoKtlXvH6ox4bN0rzcH59DoylyhisKJ6+elJUh0rRySH7Xotp/oXX2qFndfflAEE6V54HN/Ct2kcMBg/FT3kWsJ2lJzlWkSOAVyThD1xU6iU77eDdfW4uiJ75ktHBt3pI1PIRhRqOW1BK7QrOI7r7AMeInfW2+VKo9r/OXIx8PC8GN9Rt3PmaZ3qKLf0bDFZmL93tw3tmR1o6OFZDj+062ILWIAkS/e3Gv8OvPvFtUQ6E3PkGbXE2O9NSYIHK2S5pZt8zF9ySYh+r15mrqcAnUMUSG8hyBKTPnvYPDPAfHucu1GzMlIEa+cZcRsTVIoq0mOuBw51psP/3jDVQLCXRT392ShpR2LJJ82oLq8=

    Solved in post #2, click to view
    • 2 replies
    1. Dustin Harris @Dustin_Harris
        2024-08-07 13:09:18.294Z

        this is a very quick and dirty fix attempt, but try replacing the above lines 280 through 292 inclusive with this and see if it solves the issue? (back up your original script first :) )

        // Set AudioSuite Processing Input Mode ('clip-byclip'|'entire-selection')
        if (processingInputMode !== undefined && processingInputModePopUpBtn.value.invalidate().value !== processingInputMode) {
            processingInputModePopUpBtn.popupMenuSelect({
                menuPath: [processingInputMode],
            });
            while (processingInputModePopUpBtn.value.invalidate().value !== processingInputMode) sf.wait({ intervalMs: 100 })
        }
        
        // Set AudioSuite "Input Mode" ('mono mode'|'multi-input mode')
        if (inputMode !== undefined && inputModePopUpBtn.value.invalidate().value !== inputMode) {
            inputModePopUpBtn.popupMenuSelect({
                menuPath: [inputMode],
            });
            while (inputModePopUpBtn.value.invalidate().value !== inputMode) sf.wait({ intervalMs: 100 })
        }
        
        ReplySolution
        1. B
          In reply toBen_Rauscher:
          Ben Rauscher @Ben_Rauscher
            2024-08-07 18:48:19.007Z

            Thank you Dustin; this is working properly again. I made an editable copy of the command from the iZotope package, and replaced the code as directed.