No internet connection
  1. Home
  2. Script Sharing

Spanner to Dolby Atmos Object Converter

By Sreejesh Nair @Sreejesh_Nair
    2023-11-15 19:17:37.002Z2023-11-17 20:26:05.240Z

    I made a script as part of my Dolby Atmos Package as a utility where it will copy Spanner's automation into individual Object Auxes as pan automation. As some little features, I made it into a template and added fun things like identifying the spanner insert on the track by converting the insert number into the insert alphabet, intelligently calculating pan width from the user input by not including LFE in the object count, displaying automation lanes, programmatically reaching the adjacent tracks etc. Hope this script helps with some ideas as well.

    // Extract track width from event properties
    const { trWidth } = event.props;
    
    // Calculate the number of pan automation channels based on track width
    const panCount = calculatePanCount(trWidth);
    
    // Function to calculate the number of channels from the track format
    function calculatePanCount(format) {
        return format.split('.').reduce((count, part) =>
            count + (part !== "1" || format === "1" ? parseInt(part, 10) : 0), 0);
    }
    
    // Function to ensure all inserts (A-J) are displayed in the Pro Tools UI
    let disFlags = [0, 0];
    function ensureAllInsertsAreDisplayed() {
        ['Inserts A-E', 'Inserts F-J'].forEach((item, index) => {
            if (!sf.ui.proTools.getMenuItem('View', 'Edit Window Views', item).isMenuChecked) {
                sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", item] });
                disFlags[index] = 1;
            }
        });
    }
    
    // Function to find the insert slot (letter) of the Spanner plugin
    function getSpannerInsertLetter() {
        for (let i = 0; i < 10; i++) {
            const pluginName = sf.ui.proTools.selectedTrack.insertButtons[i].value.invalidate().value;
            if (pluginName === "Spanner") {
                return String.fromCharCode(97 + i);  // Convert insert number (0-9) to 'a'-'j'
            }
        }
        return null; // Return null if Spanner is not found
    }
    
    // Function to select a specific automation lane of the Spanner plugin
    function selectSpannerAutomationLane(laneName) {
        const insertLetter = getSpannerInsertLetter();
        if (!insertLetter) {
            alert("Spanner plugin not found in the selected track.");
            throw 0;
        }
    
        sf.ui.proTools.selectedTrack.trackDisplaySelect({
            displayPath: [` (fx ${insertLetter}) Spanner`, laneName],
        });
        return true;
    }
    
    // Function to select a track relative to the currently selected track
    function selectTrackDelta(delta) {
        const selectedTrackName = sf.ui.proTools.selectedTrackNames[0];
        const visibleTrackNames = sf.ui.proTools.visibleTrackNames;
        const newTrackIndex = visibleTrackNames.findIndex(n => n === selectedTrackName) + delta;
    
        if (newTrackIndex >= 0 && newTrackIndex < visibleTrackNames.length) {
            sf.ui.proTools.trackSelectByName({ names: [visibleTrackNames[newTrackIndex]] });
        }
    }
    
    // Function to determine which pan automation lane to paste into
    function selectPanAutomationLaneForPasting(spannerLaneName) {
        const laneMap = { "PanX_": ["front pos", "rear pos"], "PanY_": ["f/r pos"], "PanZ_": ["height"] };
        let lanes = [];
        for (const [key, value] of Object.entries(laneMap)) {
            if (spannerLaneName.startsWith(key)) {
                lanes = value;
                break;
            }
        }
    
        // Select the first lane in the array
        if (lanes.length > 0) {
            sf.ui.proTools.selectedTrack.trackDisplaySelect({ displayPath: ['pan', lanes[0]] });
        }
    
        return lanes;
    }
    
    
    
    // Function to perform a paste operation
    function panPaste() {
        sf.keyboard.press({ keys: "ctrl+cmd+v" });
    }
    
    // Function to check if there is a selection in Pro Tools
    function checkSelectionLength() {
        const selection = sf.ui.proTools.selectionGet();
        const selectionLength = selection.selectionLength.split(":").slice(2).join(".");
        return parseFloat(selectionLength) !== 0;
    }
    
    // Array of Spanner lane names to process
    const spannerLaneNames = [
        "PanX_L", "PanY_L", "PanZ_L", "PanX_C", "PanY_C", "PanZ_C",
        "PanX_R", "PanY_R", "PanZ_R", "PanX_Lsr", "PanY_Lsr", "PanZ_Lsr",
        "PanX_Rsr", "PanY_Rsr", "PanZ_Rsr", "PanX_Lss", "PanY_Lss", "PanZ_Lss",
        "PanX_Rss", "PanY_Rss", "PanZ_Rss", "PanX_Lst", "PanY_Lst", "PanZ_Lst",
        "PanX_Rst", "PanY_Rst", "PanZ_Rst", "PanX_Ltf", "PanY_Ltf", "PanZ_Ltf",
        "PanX_Rtf", "PanY_Rtf", "PanZ_Rtf", "PanX_Ltr", "PanY_Ltr", "PanZ_Ltr",
        "PanX_Rtr", "PanY_Rtr", "PanZ_Rtr", "PanX_Lw", "PanY_Lw", "PanZ_Lw",
        "PanX_Rw", "PanY_Rw", "PanZ_Rw"
    ];
    
    // Activate Pro Tools main window and ensure all inserts are displayed
    sf.ui.proTools.appActivateMainWindow();
    sf.ui.proTools.invalidate();
    ensureAllInsertsAreDisplayed();
    
    // Check for selection length before starting the process
    if (!checkSelectionLength()) {
        alert("There is no selection length in Pro Tools.");
        throw 0;
    } else {
        selectTrackDelta(0); // Start with the Spanner track selected
        let currentDelta = 1; // Initialize track increment
    
        // Filter spannerLaneNames based on trWidth
        const filteredSpannerLaneNames = trWidth === "2.0" || trWidth === "2" ?
            spannerLaneNames.filter(name =>
                ["PanX_L", "PanY_L", "PanZ_L", "PanX_R", "PanY_R", "PanZ_R"].includes(name.split('_').slice(0, 2).join('_'))
            ) : spannerLaneNames;
    
        for (let i = 0; i < filteredSpannerLaneNames.length; i++) {
            // Halt process if currentDelta exceeds available tracks
            if (currentDelta > panCount) {
                break;
            }
    
            // Process each Spanner lane
            if (selectSpannerAutomationLane(filteredSpannerLaneNames[i])) {
                let trackIdentifier = filteredSpannerLaneNames[i].split('_').pop();  //To display the Pan Channel
                sf.keyboard.press({ keys: "cmd+c" });  // Copy automation data
                selectTrackDelta(currentDelta);  // Move to target track for pasting
    
                // Determine target pan lane(s) and paste automation data
                const panLanes = selectPanAutomationLaneForPasting(filteredSpannerLaneNames[i]);
                panLanes.forEach((lane, index) => {
                    sf.ui.proTools.selectedTrack.trackDisplaySelect({
                        displayPath: ['pan', lane],
                    });
                    if (index > 0) {
                        sf.wait({ intervalMs: 500 }); // Wait between lane selections
                    }
                    panPaste();
                });
    
                // Reset to Spanner track and increment delta after processing each set of three lanes
                selectTrackDelta(-currentDelta);
                if ((i + 1) % 3 === 0) {
                    log(`Pasted ${trackIdentifier} Channel`);
                    currentDelta++;
                }
            }
        }
    }
    
    alert(`Completed Spanner conversion for ${trWidth}`);
    
    • 0 replies