No internet connection
  1. Home
  2. How to

Logic Pro X: Bounce selected tracks in place, hiding the original tracks and turn them off

By Johan Nordin @Johan_Nordin
    2021-11-28 22:54:14.822Z

    Hello! I've borrowed the brilliant script from this thread:
    Logic Pro X: How to automate printing tracks

    The things I've added to the script:

    1. Hide the original tracks
    2. Turn the original track off

    Things I would like some help adding:

    1. Keep the original track name (without the "_bip" ending)
    2. Only 'bounce in place' SELECTED tracks
    3. Bounce every region on the tracks separately and add them back to the same track (as they where laid out on the original track)
    4. Making the script more correct and neat

    I am really new to coding so sorry for some bad code. :)
    Best, Johan

    var app = sf.ui.app('com.apple.logic10')
    
    //Hide hidden tracks
    sf.ui.app('com.apple.logic10').menuClick({
        menuPath: ["Track","Hide Hidden Tracks"],
        onError: "Continue",
    });
    
    function checkTrackName() {
        sf.clipboard.clear();
        app.getMenuItem('Track', 'Rename Track').elementClick();
        app.getMenuItem('Edit', 'Copy').elementClick();
        sf.keyboard.press({ keys: 'escape' })
        var trackName = sf.clipboard.waitForText().text;
        sf.wait({ intervalMs: 100 })
        return trackName
    }
    
    function checkForRegionsOnSelectedTrack() {
        app.getMenuItem('Edit', 'Select', 'Deselect All').elementClick();
        sf.keyboard.press({ keys: 'right' })
        sf.wait({ intervalMs: 500 })
        if (app.getMenuItem('Edit', 'Repeat', 'Once').isEnabled)
            return true
        else return false
    }
    
    function checkForLastTrack() {
        var oldTrackName = checkTrackName()
        sf.keyboard.press({ keys: 'down' })
        var newTrackName = checkTrackName();
        if (oldTrackName == newTrackName)
            return true
        else return false
    }
    
    function waitForBounceToComplete() {
        while (true) {
            try {
                if (!app.windows.whoseTitle.is('Logic Pro X').first.exists) {
                    //We didn't get an error - and the modal popup doesn't exist.
                    //Break out, the bounce is complete
                    break;
                }
            } catch (err) {
                //We got an error. Logic is still busy. Continue with another loop
            }
    
            //Wait a bit before continuing
            sf.wait({ intervalMs: 200 });
        }
    }
    
    function bounceRegions() {
        sf.keyboard.press({ keys: "alt+shift+n", });
        app.getMenuItem('File', 'Bounce', 'Regions in Place…').elementClick();
        app.mainWindow.sheets.first.elementWaitFor();
        app.mainWindow.sheets.first.checkBoxes.whoseTitle.is('Bypass Effect Plug-ins').first.checkboxSet({ targetValue: "Enable", });
        app.mainWindow.sheets.first.checkBoxes.whoseTitle.is('Include Audio Tail in File').first.checkboxSet({ targetValue: "Enable", });
        app.mainWindow.sheets.first.checkBoxes.whoseTitle.is('Include Audio Tail in Region').first.checkboxSet({ targetValue: "Enable", });
        app.mainWindow.sheets.first.buttons.whoseTitle.is('OK').first.elementClick({
            asyncSwallow: true
        });
    
        //Wait for the progress window to appear
        sf.wait({ intervalMs: 2000 });
    
        //Wait for the progress window to disappear
        waitForBounceToComplete();
    
        //Select original track
        sf.keyboard.press({
        keys: "up",
        });
    
        //Turn original track off
        sf.keyboard.press({
        keys: "alt+m",
        });
    
        //Hide original track
        sf.ui.app('com.apple.logic10').menuClick({
            menuPath: ["Track","Hide Selected Track(s)"],
        });
    }
    
    function main() {
        while (true) {
            if (checkForRegionsOnSelectedTrack()) {
                app.getMenuItem('Edit', 'Select', 'All Following of Same Track').elementClick();
                sf.wait({ intervalMs: 100 })
                bounceRegions()
            }
            if (checkForLastTrack()) {
                log('Command Finished', 'Last Track Reached')
                break;
            }
        }
    }
    
    main();
    
    • 6 replies
    1. A
      Alex Oldroyd @Alex_Oldroyd8
        2022-04-09 17:56:21.610Z

        Hi @Johan_Nordin

        Your script is great. Did you ever work out how to only include selected tracks?

        1. JJohan Nordin @Johan_Nordin
            2022-04-10 18:04:06.814Z

            No, unfortunately not.

            1. AAlex Oldroyd @Alex_Oldroyd8
                2022-04-21 23:44:15.032Z

                I think I've done it, @Johan_Nordin !

                This will bounce all selected tracks and name as the track, followed by the Alternative name. you can of course adjust to bip instead of Bounce.

                Let me know if it works :)

                const app = sf.ui.app('com.apple.logic10')
                const logic = sf.ui.app("com.apple.logic10");
                logic.appActivateMainWindow()
                
                
                function waitForBounceToComplete() {
                    while (true) {
                        try {
                            if (checkTrackName()) {
                                //We didn't get an error - and the modal popup doesn't exist.
                                //Break out, the bounce is complete
                                sf.keyboard.press({ keys: 'escape' })
                                break;
                            }
                        } catch (err) {
                            //We got an error. Logic is still busy. Continue with another loop
                        }
                
                        //Wait a bit before continuing
                        sf.wait({ intervalMs: 200 });
                    }
                
                }
                
                function bounceRegions() {
                    const soloButtonMixer = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Inspector").first.children.whoseRole.is("AXList").first.groups.allItems[3].children.whoseRole.is("AXLayoutArea").whoseDescription.is("Mixer").first.children.whoseRole.is("AXLayoutItem").first.buttons.whoseDescription.is("solo").first;
                    // Get Selected Track and Project Name
                    const trackArea = logic.mainWindow.groups.whoseDescription.is('Tracks').first.groups.whoseDescription.is('Tracks');
                    const trackHeaders = trackArea.allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is('Tracks header').first;
                    const selectedTrackName = trackHeaders.getElements('AXSelectedChildren').first.getString("AXDescription").match(/“(.*)”/)[1]
                    const projectName = logic.mainWindow.getElement("AXTitleUIElement").value.invalidate().value.split(" - ")[0];
                    soloButtonMixer.mouseClickElement({
                        anchor: "MidCenter",
                        isOption: true,
                    });
                    app.getMenuItem('File', 'Bounce', 'Project or Section…').elementClick();
                    app.children.whoseRole.is("AXWindow").first.scrollAreas.first.tables.first.children.whoseRole.is("AXRow").first.children.whoseRole.is("AXCell").first.checkBoxes.first.checkboxSet({
                        targetValue: "Enable",
                        onError: "Continue",
                    });
                    app.children.whoseRole.is("AXWindow").first.scrollAreas.first.tables.first.children.whoseRole.is("AXRow").first.children.whoseRole.is("AXCell").allItems[1].getElement("AXTitleUIElement").mouseClickElement({
                        anchor: "MidCenter",
                        onError: "Continue",
                    });
                    app.children.whoseRole.is("AXWindow").first.scrollAreas.first.tables.first.children.whoseRole.is("AXRow").allItems[1].children.whoseRole.is("AXCell").first.checkBoxes.first.checkboxSet({
                        targetValue: "Disable",
                        onError: "Continue",
                    });
                    app.children.whoseRole.is("AXWindow").first.scrollAreas.first.tables.first.children.whoseRole.is("AXRow").allItems[2].children.whoseRole.is("AXCell").first.checkBoxes.first.checkboxSet({
                        targetValue: "Disable",
                        onError: "Continue",
                    });
                    app.children.whoseRole.is("AXWindow").first.scrollAreas.first.tables.first.children.whoseRole.is("AXRow").allItems[3].children.whoseRole.is("AXCell").first.checkBoxes.first.checkboxSet({
                        targetValue: "Disable",
                        onError: "Continue",
                    });
                    app.children.whoseRole.is("AXWindow").first.groups.first.checkBoxes.whoseTitle.is("Add to Project").first.checkboxSet({
                        targetValue: "Disable",
                        onError: "Continue",
                    });
                    app.children.whoseRole.is("AXWindow").first.groups.first.popupButtons.allItems[1].popupMenuSelect({
                        menuPath: ["Wave"],
                        onError: "Continue",
                    });
                    sf.ui.app("com.apple.logic10").windows.first.buttons.whoseTitle.is("OK").first.elementClick();
                
                
                    //Wait for the progress window to appear
                    sf.wait({ intervalMs: 2000 });
                
                    // Set the "Save as..." Field
                    logic.windows.first.textFields.first.elementSetTextAreaValue({
                        value: `${selectedTrackName} ${projectName}`
                    });
                
                    sf.ui.app("com.apple.logic10").windows.first.buttons.whoseTitle.is("Bounce").first.elementClick();
                
                    //Wait for the progress window to disappear
                    waitForBounceToComplete();
                    sf.keyboard.press({ keys: 'escape' })
                }
                
                function checkTrackName() {
                    sf.clipboard.clear();
                    app.getMenuItem('Track', 'Rename Track').elementClick();
                    app.getMenuItem('Edit', 'Copy').elementClick();
                    sf.keyboard.press({ keys: 'escape' })
                    var trackName = sf.clipboard.waitForText().text;
                    sf.wait({ intervalMs: 100 })
                    return trackName
                } 
                
                function doForEachSelectedTrack(functionToDo) {
                    const logic = sf.ui.app('com.apple.logic10');
                    const trackArea = logic.mainWindow.groups.whoseDescription.is('Tracks').first.groups.whoseDescription.is('Tracks');
                    const trackHeaders = trackArea.allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is('Tracks header').first;
                    //Get Selected track names
                    const selectedTrackNames = trackHeaders.getElements('AXSelectedChildren').map(trackHeader => trackHeader.getString("AXDescription").match(/“(.*)”/)[1]);
                    selectedTrackNames.forEach(item => functionToDo(item));
                }
                
                function selectTrackAndPerformFunction(trackName) {
                    let originalMousePosition = sf.mouse.getPosition().position;
                
                    const logicApp = sf.ui.app("com.apple.logic10");
                
                    const trackToSelect = () => {
                        const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first
                            .groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1]
                            .scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children;
                
                        const trackToSelect = trackHeaders.find(x => x.textFields.whoseDescription.is(trackName).first.exists);
                        return trackToSelect
                    }
                
                    if (!trackToSelect()) {
                        log(`Track with the name '${trackName}' not found`)
                        throw 0;
                    }
                
                    const mainWindowFrame = logicApp.mainWindow.frame;
                    const logicRulerFrame = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1]
                        .splitGroups.first.splitGroups.first.scrollAreas.first.frame;
                
                    const trackFrame = trackToSelect().frame;
                    const mainWindowTotalY = (mainWindowFrame.y + mainWindowFrame.h);
                    const offWindowBottom = ((trackFrame.y + trackFrame.h) > (mainWindowFrame.y + mainWindowFrame.h));
                    const offScreenTop = (trackFrame.y < logicRulerFrame.y + logicRulerFrame.h);
                
                    const trackAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first
                        .groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame;
                
                    const middleOfTrackHeaderPane = { x: trackAreaFrame.x + (trackAreaFrame.w / 2), y: trackAreaFrame.y + (trackAreaFrame.h / 2) };
                
                    sf.mouse.setPosition({ position: middleOfTrackHeaderPane })
                
                    if (offWindowBottom) {
                        sf.mouse.setPosition({ position: middleOfTrackHeaderPane })
                        sf.mouse.scroll({
                            delta: -(trackFrame.y + trackFrame.h - mainWindowTotalY),
                            delta2: 0,
                            unit: "Pixel"
                        })
                    }
                
                    else if (offScreenTop) {
                        sf.mouse.setPosition({ position: middleOfTrackHeaderPane })
                        sf.mouse.scroll({
                            delta: ((logicRulerFrame.y + logicRulerFrame.h) - trackFrame.y),
                            delta2: 0,
                            unit: "Pixel"
                        })
                    }
                
                    trackToSelect().mouseClickElement({
                        relativePosition: { x: (trackFrame.w / 2), y: 5 }
                    })
                
                    sf.mouse.setPosition({ position: originalMousePosition })
                
                    bounceRegions();
                }
                
                doForEachSelectedTrack(selectTrackAndPerformFunction);
                
                
                1. In reply toJohan_Nordin:
                  AAlex Oldroyd @Alex_Oldroyd8
                    2022-04-23 01:06:12.870Z

                    Hey @Johan_Nordin - I've worked on your code with a lot of help from @Kitch . This bounces in place the selected tracks and then turns them off, mutes and hides them.

                    const app = sf.ui.app('com.apple.logic10')
                    const logic = sf.ui.app("com.apple.logic10");
                    logic.appActivateMainWindow()
                    
                    function logTrackNameAsNote() {
                        /**
                         * @param {object} obj
                         * @param {'Library'|'Inspector'|'Quick Help'|'Toolbar'|'Smart Controls'|'Mixer'|'Editors'} obj.viewName
                         * @param {'Enable'|'Disable'|'Toggle'} [obj.targetValue]
                         */
                    
                        function setViews({ viewName, targetValue }) {
                            const logic = sf.ui.app("com.apple.logic10");
                            const controlBar = logic.mainWindow.groups.whoseDescription.is("Control Bar").first;
                            const viewButton = controlBar.checkBoxes.whoseTitle.is(viewName).first;
                    
                            viewButton.checkboxSet({ targetValue, });
                        }
                    
                        /**
                         * @param {object} obj
                         * @param {'Quick Help'|'Region'|'Groups'|'Track'} obj.inspectorName
                         * @param {'Enable'|'Disable'|'Toggle'} [obj.targetValue]
                         */
                    
                        function ensureInspector({ inspectorName, targetValue = "Toggle" }) {
                            const logic = sf.ui.app('com.apple.logic10');
                            const mainWin = logic.mainWindow;
                            const inspector = mainWin.groups.whoseDescription.is('Inspector').first;
                            const inspectorList = inspector.childrenByRole("AXList").first;
                    
                            const inspectorRow = inspectorList.groups.filter(e =>
                                e.childrenByRole("AXStaticText").whoseValue.is(inspectorName + ":").first.exists ||
                                e.childrenByRole("AXStaticText").whoseValue.is(inspectorName).first.exists,
                            )[0];
                    
                            const disclosureTriangle = inspectorRow.childrenByRole("AXDisclosureTriangle").first;
                    
                            const isInspectorOpen = disclosureTriangle.value.invalidate().intValue === 1;
                    
                            switch (true) {
                                case targetValue === "Enable" && !isInspectorOpen:
                                    disclosureTriangle.elementClick();
                                    break;
                                case targetValue === "Disable" && isInspectorOpen:
                                    disclosureTriangle.elementClick();
                                    break;
                                case targetValue === "Toggle":
                                    disclosureTriangle.elementClick();
                                    break;
                            }
                        }
                    
                        function openNotePad() {
                            const logic = sf.ui.app("com.apple.logic10");
                            logic.appActivateMainWindow();
                    
                            setViews({
                                viewName: "Note Pads",
                                targetValue: "Enable",
                            });
                    
                        }
                    
                        function closeNotePad() {
                            const logic = sf.ui.app("com.apple.logic10");
                            logic.appActivateMainWindow();
                    
                            setViews({
                                viewName: "Note Pads",
                                targetValue: "Disable",
                            });
                    
                        }
                    
                        function logTrackName() {
                            const selectedTrackName = trackHeaders.getElements('AXSelectedChildren').first.getString("AXDescription").match(/“(.*)”/)[1]
                            logic.appActivateMainWindow()
                            sf.ui.app("com.apple.logic10").mainWindow.groups.allItems[3].groups.whoseDescription.is("Project").first.scrollAreas.first.textAreas.first.mouseClickElement({
                                anchor: "MidCenter",
                                clickCount: 2,
                            });
                    
                            sf.keyboard.press({
                                keys: "right, return",
                            });
                    
                    
                            sf.keyboard.type({
                                text: selectedTrackName;
                            });
                    
                        }
                    
                    
                    
                        openNotePad();
                    
                        logTrackName();
                    
                        closeNotePad();
                    }
                    
                    function waitForBounceToComplete() {
                        while (true) {
                            try {
                                if (checkTrackName()) {
                                    //We didn't get an error - and the modal popup doesn't exist.
                                    //Break out, the bounce is complete
                                    sf.keyboard.press({ keys: 'escape' })
                                    break;
                                }
                            } catch (err) {
                                //We got an error. Logic is still busy. Continue with another loop
                            }
                    
                            //Wait a bit before continuing
                            sf.wait({ intervalMs: 200 });
                        }
                    
                    }
                    
                    function bounceRegions() { 
                        sf.wait({
                            intervalMs: 1000,
                        });    
                        sf.keyboard.press({
                            keys: "down",
                        });
                        sf.keyboard.press({
                            keys: "up",
                        });
                        sf.keyboard.press({ keys: "alt+shift+n", });
                        app.getMenuItem('File', 'Bounce', 'Regions in Place…').elementClick();
                        app.mainWindow.sheets.first.elementWaitFor();
                        app.mainWindow.sheets.first.checkBoxes.whoseTitle.is('Bypass Effect Plug-ins').first.checkboxSet({ targetValue: "Disable", });
                        app.mainWindow.sheets.first.checkBoxes.whoseTitle.is('Include Audio Tail in File').first.checkboxSet({ targetValue: "Enable", });
                        app.mainWindow.sheets.first.checkBoxes.whoseTitle.is('Include Audio Tail in Region').first.checkboxSet({ targetValue: "Enable", });
                        app.mainWindow.sheets.first.buttons.whoseTitle.is('OK').first.elementClick({
                            asyncSwallow: true
                        });
                    
                        //Wait for the progress window to disappear
                        waitForBounceToComplete();
                    
                        sf.wait({
                            intervalMs: 1000,
                        });
                    
                    
                        //Select original track
                        sf.keyboard.press({
                            keys: "up",
                        });
                    
                    
                        //Turn original track off
                        sf.keyboard.press({
                            keys: "alt+m",
                        });
                    
                        //Mute original track
                        sf.keyboard.press({
                            keys: "m",
                        });
                    
                        //Hide original track
                        sf.ui.app('com.apple.logic10').menuClick({
                            menuPath: ["Track", "Hide Selected Track(s)"],
                        });
                        
                    
                    }
                    
                    function checkTrackName() {
                        sf.clipboard.clear();
                        app.getMenuItem('Track', 'Rename Track').elementClick();
                        app.getMenuItem('Edit', 'Copy').elementClick();
                        sf.keyboard.press({ keys: 'escape' })
                        var trackName = sf.clipboard.waitForText().text;
                        sf.wait({ intervalMs: 100 })
                        return trackName
                    } 
                    
                    function doForEachSelectedTrack(functionToDo) {
                        const logic = sf.ui.app('com.apple.logic10');
                        const trackArea = logic.mainWindow.groups.whoseDescription.is('Tracks').first.groups.whoseDescription.is('Tracks');
                        const trackHeaders = trackArea.allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is('Tracks header').first;
                        //Get Selected track names
                        const selectedTrackNames = trackHeaders.getElements('AXSelectedChildren').map(trackHeader => trackHeader.getString("AXDescription").match(/“(.*)”/)[1]);
                        selectedTrackNames.forEach(item => functionToDo(item));
                    }
                    
                    function selectTrackAndPerformFunction(trackName) {
                        let originalMousePosition = sf.mouse.getPosition().position;
                    
                        const logicApp = sf.ui.app("com.apple.logic10");
                    
                        const trackToSelect = () => {
                            const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first
                                .groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1]
                                .scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children;
                    
                            const trackToSelect = trackHeaders.find(x => x.textFields.whoseDescription.is(trackName).first.exists);
                            return trackToSelect
                        }
                    
                        if (!trackToSelect()) {
                            log(`Track with the name '${trackName}' not found`)
                            throw 0;
                        }
                    
                        const mainWindowFrame = logicApp.mainWindow.frame;
                        const logicRulerFrame = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1]
                            .splitGroups.first.splitGroups.first.scrollAreas.first.frame;
                    
                        const trackFrame = trackToSelect().frame;
                        const mainWindowTotalY = (mainWindowFrame.y + mainWindowFrame.h);
                        const offWindowBottom = ((trackFrame.y + trackFrame.h) > (mainWindowFrame.y + mainWindowFrame.h));
                        const offScreenTop = (trackFrame.y < logicRulerFrame.y + logicRulerFrame.h);
                    
                        const trackAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first
                            .groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame;
                    
                        const middleOfTrackHeaderPane = { x: trackAreaFrame.x + (trackAreaFrame.w / 2), y: trackAreaFrame.y + (trackAreaFrame.h / 2) };
                    
                        sf.mouse.setPosition({ position: middleOfTrackHeaderPane })
                    
                        if (offWindowBottom) {
                            sf.mouse.setPosition({ position: middleOfTrackHeaderPane })
                            sf.mouse.scroll({
                                delta: -(trackFrame.y + trackFrame.h - mainWindowTotalY),
                                delta2: 0,
                                unit: "Pixel"
                            })
                        }
                    
                        else if (offScreenTop) {
                            sf.mouse.setPosition({ position: middleOfTrackHeaderPane })
                            sf.mouse.scroll({
                                delta: ((logicRulerFrame.y + logicRulerFrame.h) - trackFrame.y),
                                delta2: 0,
                                unit: "Pixel"
                            })
                        }
                    
                        trackToSelect().mouseClickElement({
                            relativePosition: { x: (trackFrame.w / 2), y: 5 }
                        })
                    
                        sf.mouse.setPosition({ position: originalMousePosition })
                    
                        try{
                            bounceRegions();
                        }
                    
                        catch(err){
                            logTrackNameAsNote();
                        }
                    }
                    
                    doForEachSelectedTrack(selectTrackAndPerformFunction);
                    
                    
                    1. JJohan Nordin @Johan_Nordin
                        2022-04-25 20:50:27.848Z

                        WOW! Thank you so much. Really nice job. :)

                        I tried with som apple loops and one of them gave the track a name that made the script fail.

                        25.04.2022 22:45:41.21 [Backend]: [LOG] Track with the name '12 String Acoustic Guitar' not found

                        Could it be that the name includes numbers?

                        Best, Johan

                        1. AAlex Oldroyd @Alex_Oldroyd8
                            2022-04-26 12:02:55.914Z

                            Hmmm i don't know - i haven't come across that. Does it point to a specific line of text that cause it to fail? Does it work if you take the '12' out?