Split Into Mono Script Failing
By Philip weinrobe @Philip_weinrobe
Hi Genius Folks
I have this handy little script that I put together from folks here that splits a stereo track into mono and keeps only one side and cleans it all up nicely but it now fails due to some pro tools/soundflow updates that i can't quite track down.
can anyone please take a look at this and bring it into the modern world?
it is very very useful!
sf.ui.proTools.appActivate();
sf.ui.proTools.invalidate();
// Place the following two functions at the top of your script:
// #1
function mainWindowStatus() {
if (sf.ui.proTools.getMenuItem('Window', 'Mix').isMenuChecked) {
sf.ui.proTools.menuClick({
menuPath: ["Window", "Edit"],
});
return "Mix";
} else {
return "Edit";
}
}
//#2
function returnToStartingMainWIndow(mainWindow) {
if (mainWindow =="Mix") {
sf.ui.proTools.menuClick({
menuPath: ["Window", "Mix"],
});
}
}
/// Place this line at the top of your script
let startingWindow = mainWindowStatus();
//Activate Pro Tools
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.invalidate();
//Do batch rename all selected tracks
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.selectedTrack.titleButton.popupMenuSelect({
isRightClick: true,
menuPath: ['Batch Rename...']
});
//Batch rename setting 'add "_ORIGINAL!"'
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Replace').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Trim').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Add').first.checkboxSet({
targetValue: "Enable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Prefix:').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Insert:').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Suffix:').first.checkboxSet({
targetValue: "Enable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Numbering').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.textFields.whoseTitle.is('').allItems[9].elementSetTextFieldWithAreaValue({
value: "_ORIGINAL!",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.buttons.whoseTitle.is('OK').first.elementClick();
//split into mono all selected tracks
sf.ui.proTools.menuClick({
menuPath: ["Track","Split into Mono"],
});
sf.ui.proTools.waitForNoModals();
sf.wait({
intervalMs: 50,
});
sf.ui.proTools.trackDeselectAll();
sf.wait({
intervalMs: 50,
});
//select named "_ORIGINAL!.R"
var trackNamesR = sf.ui.proTools.trackNames.filter(n => n.match(/(_ORIGINAL!.R)/i));
sf.ui.proTools.trackSelectByName({
names: trackNamesR,
deselectOthers: true,
});
//Delete it
sf.ui.proTools.trackDelete();
sf.ui.proTools.windows.whoseTitle.is('').first.buttons.whoseTitle.is('Delete').first.elementClick();
sf.ui.proTools.waitForNoModals();
sf.wait({
intervalMs: 50,
});
sf.ui.proTools.trackDeselectAll();
sf.wait({
intervalMs: 50,
});
//select named "_ORIGINAL!.L"
var trackNamesL = sf.ui.proTools.trackNames.filter(n => n.match(/(_ORIGINAL!.L)/i));
sf.ui.proTools.trackSelectByName({
names: trackNamesL,
deselectOthers: true,
});
//Do Batch rename all selected tracks
sf.keyboard.press({
keys: "alt+shift+r",
});
//Batch rename setting 'delete "_ORIGINAL!.L"'
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Replace').first.checkboxSet({
targetValue: "Enable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Clear Existing Name').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Regular Expressions').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Trim').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Add').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.checkBoxes.whoseTitle.is('Numbering').first.checkboxSet({
targetValue: "Disable",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.textFields.whoseTitle.is('').first.elementSetTextFieldWithAreaValue({
value: "_ORIGINAL!.L",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.textFields.whoseTitle.is('').allItems[1].elementSetTextFieldWithAreaValue({
value: "",
});
sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first.buttons.whoseTitle.is('OK').first.elementClick();
sf.ui.proTools.waitForNoModals();
sf.wait({
intervalMs: 50,
});
sf.ui.proTools.trackDeselectAll();
sf.wait({
intervalMs: 50,
});
//select original stereo tracks
var trackNamesOriginal = sf.ui.proTools.visibleTrackNames.filter(n => n.match(/(_ORIGINAL!)/i));
sf.ui.proTools.trackSelectByName({
names: trackNamesOriginal,
deselectOthers: true,
});
//Hide and Inactive it
if (trackNamesOriginal.length > 0){
sf.ui.proTools.trackHideAndMakeInactiveSelected();
}
// end your script with this line
returnToStartingMainWIndow(startingWindow);
- Kitch Membery @Kitch2024-12-17 23:26:15.793Z2024-12-17 23:37:56.868Z
Hi @Philip_weinrobe,
Take this for a spin legend!
sf.ui.proTools.appActivate(); sf.ui.proTools.invalidate(); sf.app.proTools.invalidate(); function doWithEditWindowFocused(action) { const frontMostProToolsWindow = sf.ui.proTools.windows.first; const frontMostProToolsWindowTitle = frontMostProToolsWindow.title.invalidate().value.split(":")[0]; if (frontMostProToolsWindowTitle !== "Edit") { sf.ui.proTools.menuClick({ menuPath: ["Window", "Edit"] }); } try { action(); } catch (err) { throw err; } finally { // Restore Window frontMostProToolsWindow.elementRaise(); } } /** * @param {Object} obj * @param {string} obj.dialogText * @param {string} obj.buttonName */ function dismissDialog({ dialogText, buttonName }) { try { const dlg = sf.ui.proTools.confirmationDialog; dlg.elementWaitFor({ timeout: 200, onError: "Continue" }); if (dlg.children.whoseRole.is("AXStaticText").whoseValue.contains(dialogText).first.exists) { dlg.buttons.whoseTitle.is(buttonName).first.elementClick(); dlg.elementWaitFor({ waitForNoElement: true }); } } catch (err) { throw `There was an error Dismissing the dialog.\n${err}`; } } function splitTracksToMono() { try { sf.ui.proTools.menuClick({ menuPath: ["Track", "Split into Mono"], }); sf.ui.proTools.waitForNoModals(); } catch (err) { throw `Failed to split tracks into mono.\n${err}`; } } function batchRenameOriginalTracks() { try { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.selectedTrack.titleButton.popupMenuSelect({ isRightClick: true, menuPath: ['Batch Rename...'] }); const renameWindow = sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first; renameWindow.elementWaitFor(); const setCheckboxByName = ({ name, targetValue }) => renameWindow.checkBoxes.whoseTitle.is(name).first.checkboxSet({ targetValue }); //Batch rename setting 'add "_ORIGINAL!"' setCheckboxByName({ name: "Replace", targetValue: "Disable", }); setCheckboxByName({ name: "Trim", targetValue: "Disable", }); setCheckboxByName({ name: "Add", targetValue: "Enable", }); setCheckboxByName({ name: "Prefix:", targetValue: "Disable", }); setCheckboxByName({ name: "Insert:", targetValue: "Disable", }); setCheckboxByName({ name: "Suffix:", targetValue: "Enable", }); setCheckboxByName({ name: 'Numbering', targetValue: "Disable", }); const suffixTextField = renameWindow.textFields.whoseTitle.is('').allItems[9] suffixTextField.elementSetTextFieldWithAreaValue({ value: "_ORIGINAL!", }); // Click OK renameWindow.buttons.whoseTitle.is('OK').first.elementClick(); } catch (err) { throw `Failed batch renaming original tracks.\n${err}`; } } function deleteRightChannelTracks() { try { const rightChannelTrackNames = sf.app.proTools.tracks.allItems .filter(track => track.name.match(/(_ORIGINAL!.R)/i)) .map(track => track.name); // Select tracks with named "_ORIGINAL!.R" sf.app.proTools.selectTracksByName({ trackNames: rightChannelTrackNames }); // Invalidate the main window as tracks have changed sf.ui.proTools.mainWindow.invalidate(); // Delete Right Channel Tracks sf.ui.proTools.trackDelete(); dismissDialog({ dialogText: "Do you still want to delete these tracks?", buttonName: "Delete" }); sf.ui.proTools.waitForNoModals(); } catch (err) { throw `Failed to delete right channel tracks.\n${err}`; } } function batchRemoveSuffix() { try { const rightChannelTrackNames = sf.app.proTools.tracks.allItems .filter(track => track.name.match(/(_ORIGINAL!.L)/i)) .map(track => track.name); // Select Left Channel Tracks sf.app.proTools.selectTracksByName({ trackNames: rightChannelTrackNames }); sf.ui.proTools.appActivateMainWindow(); const renameWindow = sf.ui.proTools.windows.whoseTitle.is('Batch Track Rename').first; sf.ui.proTools.selectedTrack.titleButton.popupMenuSelect({ isRightClick: true, menuPath: ['Batch Rename...'] }); renameWindow.elementWaitFor(); const setCheckboxByName = ({ name, targetValue }) => renameWindow.checkBoxes.whoseTitle.is(name).first.checkboxSet({ targetValue }); //Batch rename setting 'delete "_ORIGINAL!.L"' setCheckboxByName({ name: 'Replace', targetValue: "Enable", }); setCheckboxByName({ name: 'Clear Existing Name', targetValue: "Disable", }); setCheckboxByName({ name: 'Regular Expressions', targetValue: "Disable", }); setCheckboxByName({ name: 'Trim', targetValue: "Disable", }); setCheckboxByName({ name: 'Add', targetValue: "Disable", }); setCheckboxByName({ name: 'Numbering', targetValue: "Disable", }); // Set Find field Text const findTextField = renameWindow.textFields.whoseTitle.is('').allItems[0] findTextField.elementSetTextFieldWithAreaValue({ value: "_ORIGINAL!.L", }); // Clear Replace field text const replaceTextField = renameWindow.textFields.whoseTitle.is('').allItems[1] replaceTextField.elementSetTextFieldWithAreaValue({ value: "", }); // Click OK renameWindow.buttons.whoseTitle.is('OK').first.elementClick(); sf.ui.proTools.waitForNoModals(); } catch (err) { throw `Failed to remove "_ORIGINAL!.L" suffix.\n${err}`; } } function selectAndHideOriginalTracks() { try { const originalTrackNames = sf.app.proTools.tracks.allItems .filter(track => track.name.match(/(_ORIGINAL!)/i)) .map(track => track.name); sf.app.proTools.selectTracksByName({ trackNames: originalTrackNames }); //Hide and Inactive it sf.app.proTools.setTrackHiddenState({ trackNames: originalTrackNames, enabled: true, onError: "Continue", }); } catch (err) { throw `Failed selecting and hiding tracks.\n${err}`; } } function main() { doWithEditWindowFocused(() => { batchRenameOriginalTracks(); splitTracksToMono(); deleteRightChannelTracks(); batchRemoveSuffix(); selectAndHideOriginalTracks(); }); } main();
Note: I've not done much testing on this one, so proceed with caution :-)
[UPDATED]
- PPhilip weinrobe @Philip_weinrobe
just getting around to this and it's failing at the delete window.
<< Command: _UTIL stereo to mono LEFT [user:default:cl0fw35j700049d10ujgy3vxl] 16.07.2025 11:38:24.27 <info> [EditorWindow:Renderer]: Active Focus Container: code Line 33963 file:///Applications/SoundFlow.app/Contents/Helpers/SoundFlow.app/Contents/Resources/app.asar/dist/editor.js 16.07.2025 11:38:29.81 <info> [Backend]: [KeyboardInterfaceController] #Key: command+shift+backspace (51) -> Delete Track(s) [ckyg7d7fh000l8w10n3dw59bn] 16.07.2025 11:38:29.81 <info> [Backend]: >> Command: Delete Track(s) [user:default:ckx2amtqg00001710vnn369xb] Executing SelectedTrackDeleteAction 16.07.2025 11:38:29.82 <info> [Backend]: Logging error in action (01) ClickMenuAction: Could not find menu item: Track->Delete 16.07.2025 11:38:29.82 <info> [Backend]: << Command: Delete Track(s) [user:default:ckx2amtqg00001710vnn369xb] 16.07.2025 11:38:32.08 <info> [EditorWindow:Renderer]: Active Focus Container: code Line 33963 file:///Applications/SoundFlow.app/Contents/Helpers/SoundFlow.app/Contents/Resources/app.asar/dist/editor.js 16.07.2025 11:38:56.24 <info> [EditorWindow:Renderer]: Active Focus Container: code Line 33963 file:///Applications/SoundFlow.app/Contents/Helpers/SoundFlow.app/Contents/Resources/app.asar/dist/editor.js 16.07.2025 11:39:06.70 <info> [Backend]: [SF_FIREBASE_WS]: Sending keep-alive