No internet connection
  1. Home
  2. How to

Error when running with track of mono output

By Masayoshi Sugai @Masayoshi_Sugai
    2021-10-03 08:01:27.876Z

    Hi There!

    I'm running into a problem with the script below.

    //memory original window
    let originalWin = sf.ui.proTools.focusedWindow.title.value.split(":").slice(0, 1).join(":")
    
    
    /**
     * @param {array} path - menu full path
     * @param {'Enable'|'Disable'} targetValue
     */
    function menuClick(path, targetValue) {
        sf.ui.proTools.menuClick({ menuPath: path, targetValue: targetValue });
    }
    
    
    // Make sure track lis is visible
    sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Track List"], targetValue: "Enable" })
    
    // Get all items from track list
    const trackList = sf.ui.proTools.trackListItems
    
    // Get all selected tracks
    const selectedTracks = sf.ui.proTools.selectedTrackNames
    
    // Scroll first track to view
    const indexOfFirstSelected = trackList.findIndex(x => x.normalizedTrackName == selectedTracks[0])
    trackList[indexOfFirstSelected].children.whoseRole.is("AXCell").allItems[1].buttons.first.mouseClickElement({ isControl: true, isShift: true })
    
    // Select original selection
    sf.ui.proTools.trackSelectByName({ names: selectedTracks });
    
    
    
    /**
    * @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 })
        sf.ui.proTools.colorsSelect({
            colorNumber: 20,
        });
    
    
        // 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"])
        
        ///Wait
        sf.wait({
            intervalMs: 100,
        });
    
        // 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"]) }
            }
    
        }
    }
    
    
    //show original window
    sf.ui.proTools.menuClick({ menuPath: ["Window", originalWin] });
    
    main()
    

    When running this script, if the output of the first selected track is mono, the following error will occur.

    : Logging error in action (01) PopupMenuSelectAction: No menu item was returned by menuSelector callback
    Logging error in action (01) TrackSelectOutputAction: Could not select output menu item:''

    It seems it will stop at the command to select "search ..." from the Insert menu of the newly created AUX track.

    It works well when the output of the first selected track is stereo.
    If anyone can help me figure out what's causing this, I'd appreciate it!

    Solved in post #4, click to view
    • 4 replies
    1. Hi Masayoshi,

      This indicates that the callback function for outputSelector doesn't return any item.

      auxTrack.trackOutputSelect({ outputSelector: items => items.filter(item => item.path[1] === firstSelectedOut)[0] })

      If you need more help with this, I'd recommend that you log the values of items and of firstSelectedOut. This will help you figure out why there's a mismatch there. Most likely, the comparison doesn't properly take into account how PT formats the value of outputs here.

      If you want even better help, try to isolate the issue into a short script that others can run. It's often much more easy to help with short scripts vs. something very complex :)

      1. samuel henriques @samuel_henriques
          2021-10-03 23:06:26.963Z

          Hey Masayoshi,

          I'm sorry you are having trouble with this code, I think its all mine. I'll have some time tomorrow to figure out the problem.

          Thank you Christian, I hope I can figure this out.

          1. samuel henriques @samuel_henriques
              2021-10-03 23:33:35.999Z

              Got it, Christian was correct, the callback was wrong. Hope it's better now.
              Updated on the original thread:
              Create New Track from Send Menu on Selected Tracks Script Help #post-6

              Reply1 LikeSolution
              1. MMasayoshi Sugai @Masayoshi_Sugai
                  2021-10-04 16:41:58.535Z

                  It worked perfectly!
                  Thank you Samuel !!!