No internet connection
  1. Home
  2. How to

Script Keeps Throwing Error - Can't Figure it Out

By Philip weinrobe @Philip_weinrobe
    2022-01-26 21:35:43.746Z

    hi everyone
    so many people here helped me w this script! it creates an aux and adds an insert and routes it all nicely blah blah blah. this script works perfectly after pro tools restarts for anywhere up to about 1 - 2 hours of use. Then it crashes and i have to restart pro tools again to make it work. restarting soundflow doesn't seem to help (or running soundflow invalidate macro).

    this is the error message i keep getting:
    26.01.2022 16:33:15.05 [Backend]: !! Command Error: Create Aux and Add Insert MACRO [user:default:ckvjqw5s40000kh102j0b0425]:
    Error running command package:cktsrvilz00021o10qn3eid79 (Create Aux and Add Insert MACRO: Line 10)
    TypeError: Cannot read property 'toLowerCase' of undefined
    (Create Aux + Add Insert line 244)

    this is the script (sorry, it's a long one!)

    /**
    * @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
                }
            })
        }
    }
    
    function getFirstFreeSend() {
        const selectedTracks = sf.ui.proTools.selectedTrackHeaders
        const sendLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
        let sendAssignmentList = []
        for (let i = 0; i < selectedTracks.length; i++) {
            let trackInfo = sf.ui.proTools.trackGetByName({ name: selectedTracks[i].normalizedTrackName })
                .track.sendButtons.filter(x => x.value.invalidate().value != "unassigned").map(x => x.title.invalidate().value.split(" ")[2])
            sendAssignmentList.push(...trackInfo)
        }
    
        const firstFreeSend = sendLetters.filter(letter => sendAssignmentList.indexOf(letter) === -1)[0]
    
        if (firstFreeSend) {
            return firstFreeSend
        } else {
            alert("Must have at least one free send, that is the same for all tracks.")
            throw 0
        };
    };
    
    
    /**
    * @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() {
        const newTrackWin = sf.ui.proTools.windows.whoseTitle.is("New Track").first.elementWaitFor().element
    
        const format = newTrackWin.popupButtons.whoseTitle.is("Stereo").first
        const type = newTrackWin.popupButtons.whoseTitle.is("Aux Input").first
        const timeBase = newTrackWin.popupButtons.whoseTitle.is("Samples").first
    
        if (format.value.invalidate().value != "Stereo") { format.popupMenuSelect({ menuPath: ["Stereo"] }); }
        if (type.value.invalidate().value != "Aux Input") { type.popupMenuSelect({ menuPath: ["Aux Input"] }); }
        if (timeBase.value.invalidate().value != "Samples") { timeBase.popupMenuSelect({ menuPath: ["Samples"] }); }
    
        newTrackWin.checkBoxes.whoseTitle.is("Create next to current track").first.checkboxSet({ targetValue: "Enable" });
    
        //  Wait to name track and press ok
        newTrackWin.elementWaitFor({ waitType: "Disappear", timeout: -1 })
        sf.ui.proTools.invalidate()
    }
    
    
    // function setWindowViews() {
    //     const views = ["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: "Enable" })
    //         sf.ui.proTools.menuClick({ menuPath: ["View", "Mix Window Views", view], targetValue: "Enable" })
    //     })
    // }
    
    
    /**
     * @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 })
           // sf.ui.proTools.menuClick({ menuPath: ["View", "Mix Window Views", view], targetValue: targetValue })
        })
    }
    
    
    // function closeWindowViews(views) {
    //     views.forEach(view => {
    //         sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: "Disable" })
    //         sf.ui.proTools.menuClick({ menuPath: ["View", "Mix Window Views", view], targetValue: "Disable" })
    //     })
    // }
    
    const getSelectedTrackOut = (trackName) => sf.ui.proTools.trackGetByName({ name: trackName }).track.outputPathButton.title.invalidate().value.split('\n')[1].trim();
    
    
    
    let insertSlot
    let firstFreeSend
    function actions() {
    
        const originalSelectedTracks = sf.ui.proTools.selectedTrackNames
    
        // Save first selected track output on variable
        const firstSelectedOut = getSelectedTrackOut(originalSelectedTracks[0])
    
        //  Get free sends
        firstFreeSend = getFirstFreeInsertOrSend("Send")
    
        // Assign new send to new track
        assignToNewTrack(firstFreeSend)
    
        // New track setting and wait for track name
        newTrackSettings()
    
        // If new send win is blocking the inserts or sends, move win away
        moveSendWinOutOfSlots()
    
        // Expand created send
        sf.ui.proTools.menuClick({ menuPath: ["View", "Expanded Sends", `Send ${firstFreeSend}`], targetValue: "Enable" })
    
        // 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()
        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.path[1] === firstSelectedOut)[0] })
        }
    
        // Get free insert slot after A
        insertSlot = getFirstFreeInsertOrSend("Insert", ["A"])
    
    
        // Open search...
        auxTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
            .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`)
            .first.popupMenuSelect({
                menuPath: ["search..."],
            });
    
    
        // Wait to open new plug
        while (true) {
            const plugIsOpen = auxTrack.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;
            }
        }
        sf.ui.proTools.trackSelectByName({ names: originalSelectedTracks })
    }
    
    
    
    
    function main() {
    
        sf.ui.proTools.appActivateMainWindow();
        sf.ui.proTools.invalidate();
    
       // const isActiveInsGroupFMix = sf.ui.proTools.getMenuItem("View", "Mix Window Views", "Inserts F-J").isMenuChecked
        const isActiveInsGroupFEdit = sf.ui.proTools.getMenuItem("View", "Edit Window Views", "Inserts F-J").isMenuChecked
    
       // const isActiveSendGroupFMix = sf.ui.proTools.getMenuItem("View", "Mix Window Views", "Sends 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 expand created 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 replies
    1. samuel henriques @samuel_henriques
        2022-01-26 22:36:57.083Z

        Hello Philip,
        This was my code.

        try this, if you are still getting errors send a screen recording so I can try to figure out better.

        
        /**
        * @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
                    }
                })
            }
        }
        
        function getFirstFreeSend() {
            const selectedTracks = sf.ui.proTools.selectedTrackHeaders
            const sendLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
            let sendAssignmentList = []
            for (let i = 0; i < selectedTracks.length; i++) {
                let trackInfo = sf.ui.proTools.trackGetByName({ name: selectedTracks[i].normalizedTrackName })
                    .track.sendButtons.filter(x => x.value.invalidate().value != "unassigned").map(x => x.title.invalidate().value.split(" ")[2])
                sendAssignmentList.push(...trackInfo)
            }
        
            const firstFreeSend = sendLetters.filter(letter => sendAssignmentList.indexOf(letter) === -1)[0]
        
            if (firstFreeSend) {
                return firstFreeSend
            } else {
                alert("Must have at least one free send, that is the same for all tracks.")
                throw 0
            };
        };
        
        
        /**
        * @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() {
        
            const newTrackWin = sf.ui.proTools.windows.whoseTitle.is("New Track").first.elementWaitFor().element
        
            ///  Popup butons to variables
            const [type, timeBase, format] = newTrackWin.popupButtons.map(x => x)
        
            if (format.title.invalidate().value != "Stereo") { format.popupMenuSelect({ menuPath: ["Stereo"] }); }
            if (type.title.invalidate().value != "Aux Input") { type.popupMenuSelect({ menuPath: ["Aux Input"] }); }
            if (timeBase.title.invalidate().value != "Samples") { timeBase.popupMenuSelect({ menuPath: ["Samples"] }); }
        
            newTrackWin.checkBoxes.whoseTitle.is("Create next to current track").first.checkboxSet({ targetValue: "Enable" });
        
            //  Wait to name track and press ok
            newTrackWin.elementWaitFor({ waitType: "Disappear", timeout: -1 })
            sf.ui.proTools.invalidate()
        }
        
        /**
         * @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 })
                // sf.ui.proTools.menuClick({ menuPath: ["View", "Mix 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() {
        
            const originalSelectedTracks = sf.ui.proTools.selectedTrackNames
        
            // Save first selected track output on variable
            const firstSelectedOut = getSelectedTrackOut(originalSelectedTracks[0])
        
            //  Get free sends
            firstFreeSend = getFirstFreeInsertOrSend("Send")
        
            // Assign new send to new track
            assignToNewTrack(firstFreeSend)
        
            // New track setting and wait for track name
            newTrackSettings()
        
            // If new send win is blocking the inserts or sends, move win away
            moveSendWinOutOfSlots()
        
            // Expand created send
            sf.ui.proTools.menuClick({ menuPath: ["View", "Expanded Sends", `Send ${firstFreeSend}`], targetValue: "Enable" })
        
            // 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()
            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] })
            }
        
            // Get free insert slot after A
            insertSlot = getFirstFreeInsertOrSend("Insert", ["A"])
        
        
            // Open search...
            auxTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
                .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`)
                .first.popupMenuSelect({
                    menuPath: ["search..."],
                });
        
        
            // Wait to open new plug
            while (true) {
                const plugIsOpen = auxTrack.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;
                }
            }
            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 expand created sends
            sf.ui.proTools.menuClick({ menuPath: ["View", "Expanded Sends", "None"], targetValue: "Enable" })
        
            setWindowViews("Enable")
        
            try {
                actions()
            } catch (err) { }
            finally {
        
                //  Go to mix if needed
                if (!isEditWin) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Mix"] }) }
        
                if (insertSlot) {
                    // Close Inserts Views if not needed
                    if (insertSlot.toLowerCase().charCodeAt(0) - 97 <= 4 && (!isActiveInsGroupFEdit)) {
                        if (!isActiveInsGroupFEdit) { setWindowViews("Disable", ["Inserts F-J"]) }
                    }
                }
        
                if (firstFreeSend) {
                    // Close Sends F-J if not needed
                    if (firstFreeSend.toLowerCase().charCodeAt(0) - 97 <= 4 && (!isActiveSendGroupFEdit)) {
                        if (!isActiveSendGroupFEdit) { setWindowViews("Disable", ["Sends F-J"]) }
                    }
                }
            }
        }
        
        main()