No internet connection
  1. Home
  2. How to

add a hardware I/O on insert of an audio track , open a new audio track from its send

By Tom Mochiach @Tom_Mochiach
    2025-01-30 18:34:23.796Z

    Hello,I want to be able to automate the following:
    add a hardware plugin I/O on next available insert of an audio track , then open a new audio track from its send at nominal volume, record enabeled.
    any chance ?

    • 10 replies

    There are 10 replies. Estimated reading time: 20 minutes

    1. Chad Wahlbrink @Chad2025-01-30 21:51:08.256Z

      Note, I think we tackled this on this thread:

      Script is here:
      Create New Stereo Send From Selected Track (First available send-intelligent) #post-12

      @Tom_Mochiach - let me know if this is accomplishes what you are after.

      1. TTom Mochiach @Tom_Mochiach
          2025-01-30 22:05:04.798Z

          Hi
          I first got this

          and when recopy and paste the script I now get this

          am I doing anything wrong?
          Reply

          1. Chad Wahlbrink @Chad2025-01-30 22:15:46.550Z

            Hi @Tom_Mochiach, let's keep the conversation here now.

            I was not accounting for Mono hardware inserts well before, which is why you were seeing the "toLowerCase" error.

            You will need to set the parameters in lines 2 and 3 according to the insert you are adding. The naming is case-sensitive for the hardwareInsert path.

            If you are curious - the path of mono i/o inserts seems to add four spaces to the front of the insert name - I think because of how Pro Tools handles "Sub-paths." Regardless, I'm accounting for that with:

            
            let hardwareInsert = ['i/o', 'H3000 HW.L (Mono)']
            let monoOrStereo = 'Mono'
            
            // If Mono, add 4 spaces to the front of the name 
            if(monoOrStereo === 'Mono'){
                hardwareInsert = ['i/o', ('    ' + hardwareInsert[1])]
            }
            

            Below is an updated version of the script:

            
            let hardwareInsert = ['i/o', 'H3000 HW.L (Mono)']
            let monoOrStereo = 'Mono'
            
            // If Mono, add 4 spaces to the front of the name 
            if(monoOrStereo === 'Mono'){
                hardwareInsert = ['i/o', ('    ' + hardwareInsert[1])]
            }
            
            ///////////////////////////////////////
            
            /**
            * @param {string} sendAssignment
            */
            function assignToNewTrack(sendAssignment) {
                const selectedTracks = sf.ui.proTools.selectedTrackNames
                sf.ui.proTools.trackGetByName({ name: selectedTracks[selectedTracks.length - 1] }).track.groups.whoseTitle.is(getGroup("Sends", sendAssignment)).first.buttons.whoseTitle.is(`Send Assignment ${sendAssignment}`).first.popupMenuSelect({
                    isShift: true,
                    isOption: true,
                    menuPath: ["new track..."],
                });
            }
            
            function moveSendWinOutOfSlots() {
                sf.ui.proTools.invalidate()
            
                const sendWin = sf.ui.proTools.mainTrackOutputWindow.elementWaitFor().element
                const sendWinPos = sendWin.position.x
                const sendSlots = sf.ui.proTools.selectedTrack.groups.whoseTitle.is("Inserts A-E").first
                const sendSlotsPos = sendSlots.position.x
            
                if (sendWinPos - sendSlotsPos < 450 && sendSlotsPos - sendWinPos < 170) {
                    sendWin.windowMove({
                        position: {
                            y: sendWin.position.y,
                            x: sendSlotsPos + 450
                        }
                    })
                }
            }
            
            /**
            * @param {'Insert'|'Send'} slotType
            * @param {array} [defaultUsedSlots] = [] - If parameter is not used, default is []
            */
            function getFirstFreeInsertOrSend(slotType, defaultUsedSlots) {
            
                let buttons
                slotType == "Insert" ? buttons = "insertButtons" : buttons = "sendButtons"
            
                const selectedTracks = sf.ui.proTools.selectedTrackHeaders
                const sendLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
                let sendAssignmentList = defaultUsedSlots || []
                try {
                    for (let i = 0; i < selectedTracks.length; i++) {
                        let trackInfo = sf.ui.proTools.trackGetByName({ name: selectedTracks[i].normalizedTrackName })
                            // .insertButtons or .sendButtons
                            .track[buttons].filter(x => x.value.invalidate().value != "unassigned").map(x => x.title.invalidate().value.split(" ")[2])
                        sendAssignmentList.push(...trackInfo)
                    }
                } catch (err) { }
                const firstFreeSend = sendLetters.filter(letter => sendAssignmentList.indexOf(letter) === -1)[0]
            
                if (firstFreeSend) {
                    return firstFreeSend
                } else {
                    if (slotType == "Insert") { alert(`Must have at least one free ${slotType} slot.`) }
                    else if (slotType == "Send") { alert(`Must have at least one free ${slotType} slot, that is the same for selected tracks.`) }
                    throw 0
                };
            };
            
            /**
            * @param {string} sendLetter
            * @param {'Inserts'|'Sends'} slotType
            */
            function getGroup(slotType, sendLetter) {
                let group
                sendLetter.toLowerCase().charCodeAt(0) - 97 <= 4 ? group = `${slotType} A-E` : group = `${slotType} F-J`
                return group
            }
            
            function newTrackSettings(trackName) {
                const newTrackWin = sf.ui.proTools.windows.whoseTitle.startsWith("New Track").first.elementWaitFor().element;
            
                const format = newTrackWin.popupButtons.allItems[2];
                const type = newTrackWin.popupButtons.allItems[0];
                const timeBase = newTrackWin.popupButtons.allItems[1];
            
                if (format.value.invalidate().value != monoOrStereo) { format.popupMenuSelect({ menuPath: [monoOrStereo] }); }
                if (type.value.invalidate().value != "Audio Track") { type.popupMenuSelect({ menuPath: ["Audio Track"] }); }
                if (timeBase.value.invalidate().value != "Samples") { timeBase.popupMenuSelect({ menuPath: ["Samples"] }); }
            
                newTrackWin.checkBoxes.whoseTitle.is("Create next to current track").first.checkboxSet({ targetValue: "Enable" });
            
                newTrackWin.textFields.whoseTitle.is("Track Name").first.elementSetTextFieldWithAreaValue({ value: trackName });
            
                newTrackWin.buttons.whoseTitle.is("Create").first.elementClick();
            
                newTrackWin.elementWaitFor({ waitType: "Disappear",});
            }
            
            /**
             * @param {'Enable'|'Disable'} targetValue
             * @param {array} [viewsNames] = [] - If parameter is not used, default is set inside
             */
            function setWindowViews(targetValue, viewsNames) {
                let views = viewsNames || ["Inserts A-E", "Inserts F-J", "Sends A-E", "Sends F-J"]
            
                views.forEach(view => {
                    sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: targetValue })
                })
            }
            
            const getSelectedTrackOut = (trackName) => sf.ui.proTools.trackGetByName({ name: trackName }).track.outputPathButton.title.invalidate().value.split('\n')[1].trim();
            
            let insertSlot;
            let firstFreeSend;
            
            function actions() {
            
                // Original Selected Tracks
                const originalSelectedTracks = sf.ui.proTools.selectedTrackNames
            
                // Save first selected track output on variable
                const firstSelectedOut = getSelectedTrackOut(originalSelectedTracks[0])
            
                // Add 'pt' to new track name
                const newTrackName = originalSelectedTracks[0] + ' pt';
            
                // Get free insert slot
                insertSlot = getFirstFreeInsertOrSend("Insert");
            
                // Open Hardware Insert on Source Track
                sf.ui.proTools.selectedTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
                    .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`)
                    .first.popupMenuSelect({
                        menuPath: hardwareInsert,
                    }, `Could not add hardware insert`);
            
                // Wait for new Hardware Insert to be Added
                while (true) {
                    const plugIsOpen = sf.ui.proTools.selectedTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
                        .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`).first
                        .value.invalidate().value != "unassigned"
            
                    if (!plugIsOpen) {
                        sf.wait({ intervalMs: 1000 })
                    } else {
                        break;
                    }
                }
            
                //  Get free sends on source track
                firstFreeSend = getFirstFreeInsertOrSend("Send");
            
                // Assign new send to new track
                assignToNewTrack(firstFreeSend);
            
                // New track setting and wait for track name
                newTrackSettings(newTrackName);
            
                // If new send win is blocking the inserts or sends, move win away
                moveSendWinOutOfSlots();
            
                // Solo safe new Aux
                const selectedTracks = sf.ui.proTools.selectedTrackNames
                const auxTrack = sf.ui.proTools.trackGetByName({ name: selectedTracks[selectedTracks.length - 1] }).track
            
                auxTrack.trackSelect()
                auxTrack.trackScrollToView()
            
                // Aux Tracks now default to solo safe status - so this is irrelevant unless you want your aux return to be NOT solo safed.
                // auxTrack.buttons.whoseTitle.is("Solo").first.mouseClickElement({ isCommand: true })
            
                // set new aux output
                if (getSelectedTrackOut(auxTrack.normalizedTrackName) != firstSelectedOut) {
                    auxTrack.trackOutputSelect({ outputSelector: items => items.filter(item => item.element.title.value.includes(firstSelectedOut))[0] })
                }
            
                // Set Track Record Enable
                if (sf.ui.proTools.selectedTrack.buttons.whoseTitle.is("Track Record Enable").first.value.value !== 'on state') {
                    sf.ui.proTools.selectedTrack.buttons.whoseTitle.is("Track Record Enable").first.elementClick();
                }
            
                // Set Record Track to Mute
                sf.ui.proTools.selectedTrack.trackSetMute({ targetValue: "Enable" });
            
                // Set Send to Full Volume
                sf.ui.proTools.mainTrackOutputWindow.invalidate().textFields.whoseTitle.is("Volume Numerical").first.elementSetTextFieldWithAreaValue({ value: '0.0', useMouseKeyboard: true })
                sf.keyboard.press({ keys: 'enter' })
            
                sf.ui.proTools.trackSelectByName({ names: originalSelectedTracks })
            }
            
            function main() {
            
                sf.ui.proTools.appActivateMainWindow();
                sf.ui.proTools.invalidate();
            
                const isActiveInsGroupFEdit = sf.ui.proTools.getMenuItem("View", "Edit Window Views", "Inserts F-J").isMenuChecked
            
                const isActiveSendGroupFEdit = sf.ui.proTools.getMenuItem("View", "Edit Window Views", "Sends F-J").isMenuChecked
            
                const isEditWin = sf.ui.proTools.focusedWindow.title.value.startsWith("Edit")
                if (!isEditWin) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Edit"] }) }
            
                // Close expanded sends
                sf.ui.proTools.menuClick({ menuPath: ["View", "Expanded Sends", "None"], targetValue: "Enable" })
            
                setWindowViews("Enable");
            
                try {
                    actions()
                } catch (err) { throw err }
                finally {
            
                    //  Go to mix if needed
                    if (!isEditWin) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Mix"] }) }
            
                    // Close Inserts Views if not needed
                    if (insertSlot.toLowerCase().charCodeAt(0) - 97 <= 4 && (/* !isActiveInsGroupFMix || */ !isActiveInsGroupFEdit)) {
                        // if (!isActiveInsGroupFMix) { setWindowViews("Disable", ["Inserts F-J"]) }
                        if (!isActiveInsGroupFEdit) { setWindowViews("Disable", ["Inserts F-J"]) }
                    }
            
                    // Close Sends F-J if not needed
                    if (firstFreeSend.toLowerCase().charCodeAt(0) - 97 <= 4 && (/* !isActiveSendGroupFMix || */ !isActiveSendGroupFEdit)) {
                        //  if (!isActiveSendGroupFMix) { setWindowViews("Disable", ["Sends F-J"]) }
                        if (!isActiveSendGroupFEdit) { setWindowViews("Disable", ["Sends F-J"]) }
                    }
            
                }
            }
            
            main()
            
            1. TTom Mochiach @Tom_Mochiach
                2025-01-30 22:25:23.060Z2025-01-30 22:32:36.542Z

                Im sorry I do not really understand what to do
                and you worked so hard on it
                still doesn't work here
                I have mono and stereo hardwares , can you post one option set so I can see if it works?
                because I do not know how exactly to change the script myself.. thank you so much

                1. Chad Wahlbrink @Chad2025-01-30 22:37:48.411Z
                  1. TTom Mochiach @Tom_Mochiach
                      2025-01-30 22:45:22.832Z
                      1. TTom Mochiach @Tom_Mochiach
                          2025-01-30 22:50:48.391Z

                          I have a progress here....
                          will update I a second

                          1. TTom Mochiach @Tom_Mochiach
                              2025-01-30 22:56:11.445Z

                              AMAZING ITS ALL WORKING - YOU ARE A GENIUS!!!

                              1. Chad Wahlbrink @Chad2025-01-30 23:17:36.541Z

                                Glad to hear it!

                                1. TTom Mochiach @Tom_Mochiach
                                    2025-02-02 13:04:45.678Z

                                    on the same topic (almost), I have a problem of latency when using the Chandler summing and I want to record some new instrument

                                    my solution is to make a send from that track that its output goes to the chandler , then when recording, I hear it through 1-2 ,and when listening to what iv just recorded I listen from the new track's send that goes to the summing along with all other tracks
                                    my English is not that great and anyway it is easier to look at I guess
                                    it looks like this:

                                    can you automate opening both the brown tracks (with their state of pre fader send, input monitoring and record enable using one command?
                                    and another command to switch mutes between them?

                                    or if you have a more elegant solution of course
                                    Thank you