UAD to UADx converter failing
Title
UAD to UADx converter failing
What do you expect to happen when you run the script/macro?
Convert UAD to UADx
Are you seeing an error?
The script is telling me that i have no comptible UAD plugins so I get stuck in a dialog loop. Seems like the sript is failing at the popup menu so something is wrong with my menu path.
What happens when you run this script?
When I am running the script i am just choosing "single instance".
How were you running this script?
I used a Stream Deck button
How important is this issue to you?
3
Details
{ "inputExpected": "Convert UAD to UADx", "inputIsError": true, "inputError": "The script is telling me that i have no comptible UAD plugins so I get stuck in a dialog loop. Seems like the sript is failing at the popup menu so something is wrong with my menu path.", "inputWhatHappens": "When I am running the script i am just choosing \"single instance\". ", "inputHowRun": { "key": "-MpfwmPg-2Sb-HxHQAff", "title": "I used a Stream Deck button" }, "inputImportance": 3, "inputTitle": "UAD to UADx converter failing" }
Source
//UAD Plugin Arrays
const uadXpluginLookupArray = [
{
uadPluginName: "UAD UA 1176 Rev A",
presetPositionXPercentage: 0.10,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx 1176 Rev A Compressor",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.37,
},
{
uadPluginName: "UAD UA 1176LN Rev E",
presetPositionXPercentage: 0.10,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx 1176LN Rev E Compressor",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.37,
},
{
uadPluginName: "UAD UA 1176AE",
presetPositionXPercentage: 0.10,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx 1176AE Compressor",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.37,
},
{
uadPluginName: "UAD API 2500",
presetPositionXPercentage: 0.09,
presetPositionYPercentage: 0.98,
uadXPluginName: "UADx API 2500 Bus Compressor",
pastePositionXPercentage: 0.35,
pastePositionYPercentage: 0.20,
},
{
uadPluginName: "UAD Brigade Chorus",
presetPositionXPercentage: 0.15,
presetPositionYPercentage: 0.98,
uadXPluginName: "UADx Brigade Chorus",
pastePositionXPercentage: 0.60,
pastePositionYPercentage: 0.18,
},
{
uadPluginName: "UAD Galaxy Tape Echo",
presetPositionXPercentage: 0.12,
presetPositionYPercentage: 0.98,
uadXPluginName: "UADx Galaxy Tape Echo",
pastePositionXPercentage: 0.47,
pastePositionYPercentage: 0.22,
},
{
uadPluginName: "UAD Lexicon 224",
presetPositionXPercentage: 0.28,
presetPositionYPercentage: 0.985,
uadXPluginName: "UADx Lexicon 224 Digital Reverb",
pastePositionXPercentage: 0.81,
pastePositionYPercentage: 0.14,
},
{
uadPluginName: "UAD Neve 1073",
presetPositionXPercentage: 0.33,
presetPositionYPercentage: 0.985,
uadXPluginName: "UADx Neve 1073 Preamp and EQ",
pastePositionXPercentage: 0.75,
pastePositionYPercentage: 0.13,
},
{
uadPluginName: "UAD Pultec EQP-1A",
presetPositionXPercentage: 0.09,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx Pultec EQP-1A EQ",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.27,
},
{
uadPluginName: "UAD Pultec HLF-3C",
presetPositionXPercentage: 0.095,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx Pultec HLF-3C EQ",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.33,
},
{
uadPluginName: "UAD Pultec MEQ-5",
presetPositionXPercentage: 0.095,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx Pultec MEQ-5 EQ",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.33,
},
{
uadPluginName: "UAD Pure Plate",
presetPositionXPercentage: 0.25,
presetPositionYPercentage: 0.985,
uadXPluginName: "UADx Pure Plate Reverb",
pastePositionXPercentage: 0.84,
pastePositionYPercentage: 0.13,
},
{
uadPluginName: "UAD Studio D Chorus",
presetPositionXPercentage: 0.0985,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx Studio D Chorus",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.36,
},
{
uadPluginName: "UAD Teletronix LA-2",
presetPositionXPercentage: 0.0985,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx LA-2 Compressor",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.275,
},
{
uadPluginName: "UAD Teletronix LA-2A Gray",
presetPositionXPercentage: 0.0985,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx LA-2A Gray Compressor",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.275,
},
{
uadPluginName: "UAD Teletronix LA-2A Silver",
presetPositionXPercentage: 0.0985,
presetPositionYPercentage: 0.97,
uadXPluginName: "UADx LA-2A Silver Compressor",
pastePositionXPercentage: 0.38,
pastePositionYPercentage: 0.275,
},
];
function saveSession() {
sf.ui.proTools.menuClick({ menuPath: ['File', 'Save'] });
}
function ensureEditWindowIsFocused() {
//ensure edit window is focused
sf.ui.proTools.menuClick({ menuPath: ['Window', 'Edit'] });
}
function ensureTempoRulerIsVisible() {
//ensure tempo ruler is visible
sf.ui.proTools.menuClick({
menuPath: ["View", "Rulers", "Tempo"],
targetValue: "Enable",
});
}
function hideAllFloatingWindows() {
//Hide all floating windows
sf.ui.proTools.menuClick({
menuPath: ["Window", "Hide All Floating Windows"],
targetValue: "Enable",
});
}
/** @param {{ savePath: string, newSessionName: string }} args */
function saveAs({ savePath, newSessionName }) {
sf.ui.proTools.menuClick({ menuPath: ['File', 'Save As...'] });
// Save Window
const saveWin = sf.ui.proTools.windows.whoseTitle.is("Save").first;
const saveWinSheet = saveWin.sheets.first;
saveWin.elementWaitFor();
// Open the "Go to the folder" sheet
sf.keyboard.press({ keys: 'slash' });
saveWinSheet.elementWaitFor();
const sheet = saveWin.sheets.first;
if (sheet.comboBoxes.first.exists) {
//Set preset name
sheet.comboBoxes.first.value.value = savePath;
//Click "Go"
sheet.buttons.whoseTitle.is('Go').first.elementClick();
} else {
//Set presetPath
sheet.textFields.first.value.value = savePath;
sf.keyboard.press({ keys: 'return' });
}
//give the sheet extra buffer time to appear
sf.wait({ intervalMs: 500 });
// Set name of Save Copy In Session
saveWin.textFields.first.elementSetTextFieldWithAreaValue({
value: newSessionName
});
// Click 'Save' and wait for window to dissapear
saveWin.buttons.whoseTitle.is("Save").first.elementClick();
saveWin.elementWaitFor({ waitType: 'Disappear' });
sf.ui.proTools.waitForNoModals();
}
function saveAsUadx() {
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.mainWindow.invalidate();
const sessionPath = sf.ui.proTools.mainWindow.invalidate().sessionPath;
const sessionParentPath = sessionPath.split("/").slice(0, -1).join("/");
const sessionName = sessionPath.split("/").slice(-1)[0].split(".")[0];
saveAs({
savePath: function () {
const savePath = `${sessionParentPath}`;
if (!sf.file.directoryExists({ path: savePath }).exists) {
sf.file.directoryCreate({ path: savePath });
}
return savePath;
}(),
//amend filename here
newSessionName: `${sessionName}_UADx`,
});
}
//Find all UAD<>UADx Compatiable Tracks
function findAllUadTracks() {
/**
* @param {array} plugNames
* @param {boolean} includeInactive
*/
function selectTrackskWithPlugName(plugNames, includeInactive) {
sf.ui.proTools.trackDeselectAll();
const visibleTrackNames = sf.ui.proTools.visibleTrackNames;
let foundTracks = []
//Loop visible tracks
for (let i = 0; i < visibleTrackNames.length; i++) {
const trackName = visibleTrackNames[i]
const track = sf.ui.proTools.trackGetByName({ name: trackName }).track
const muteBtn = track.buttons.whoseTitle.is("Mute").first
if (!muteBtn.exists) continue;
const isTrackInactive = muteBtn.value.value.startsWith('inactive')
if (isTrackInactive && !includeInactive) continue;
//Loop insert btns
for (let i = 0; i < 9; i++) {
const insertBtn = track.insertButtons[i]
if (!insertBtn.exists) break;// exit insert loop
const insertSelectorBtn = track.insertSelectorButtons[i]
let isInactive
//If u want to include inactive, isInactive = false so will never continue by this reason,
//else, will only go to next step if active
includeInactive ? isInactive = false : isInactive = insertSelectorBtn.value.invalidate().value === "inactive"
if (isInactive) continue;
const plugName = insertBtn.value.invalidate().value
if (plugNames.includes(plugName)) {
foundTracks.push(track.normalizedTrackName)
};
};
};
if (foundTracks.length === 0) { alert(`No active UAD<>UADx Compatiable inserts or tracks found`); throw 0; }
sf.ui.proTools.trackSelectByName({ names: foundTracks });
};
/**
* @param {object} param
* @param {string[]} param.plugNames
* @param {boolean} [param.includeInactive]
*/
function selectTracksWithPlug_in({ plugNames, includeInactive = false }) {
sf.ui.proTools.invalidate();
// Get disabled viwes
const disabled = ["Inserts A-E", "Inserts F-J"].filter(view => !sf.ui.proTools.getMenuItem("View", "Edit Window Views", view).isMenuChecked);
//Enable Disabled Views
disabled.map(view => sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: "Enable" }));
try {
selectTrackskWithPlugName(plugNames, includeInactive)
} catch (err) {
throw err;
} finally {
// Return Views to original state
disabled.map(view => sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: "Disable" }));
}
};
selectTracksWithPlug_in({
plugNames:
["UAD UA 1176 Rev A",
"UAD UA 1176AE",
"UAD UA 1176LN Rev E",
"UAD API 2500",
"UAD Brigade Chorus",
"UAD Galaxy Tape Echo",
"UAD Lexicon 224",
"UAD Neve 1073",
"UAD Pultec EQP-1A",
"UAD Pultec HLF-3C",
"UAD Pultec MEQ-5",
"UAD Pure Plate",
"UAD Studio D Chorus",
"UAD Teletronix LA-2",
"UAD Teletronix LA-2A Gray",
"UAD Teletronix LA-2A Silver"]
});
}
function loadFirstUadPlug() {
function getInsertsInfo() {
const insertInfo = Array(10).fill(0).map((_, index) => {
const track = sf.ui.proTools.selectedTrack;
const insertButton = track.invalidate().insertButtons[index];
const insertButtonValue = insertButton.value.invalidate().value;
const insertSelectorButton = track.invalidate().insertSelectorButtons[index]
const insertSelectorButtonValue = insertSelectorButton.value.invalidate().value;
return {
insertButton,
insertButtonValue,
insertSelectorButton,
insertSelectorButtonValue,
insertIndex: index,
pluginName: insertButtonValue,
//isBypassed: insertSelectorButtonValue.includes('bypassed'),
isActive: !insertSelectorButtonValue.includes('inactive'),
};
});
return insertInfo;
}
//Get an array of usable UAD plugin names
const usablePluginNames = uadXpluginLookupArray.map(item => item.uadPluginName);
const insertsInfo = getInsertsInfo();
//Filter to get all insert slots whose name includes any of the usablePluginNames
const matchingInsertSlots = insertsInfo.filter(btn => {
return usablePluginNames.some((name) => name === btn.pluginName) && btn.isActive === true;
});
sf.ui.proTools.appActivateMainWindow();
//Loop through the matchingInsertSlots
matchingInsertSlots.forEach(insert => {
sf.ui.proTools.selectedTrack.trackInsertToggleShow({
insertNumber: insert.insertIndex + 1,
});
convertUadToUadx();
});
}
function convertUadToUadx() {
//position plugin window so drop down menu has room to drop
const targetWindowXPostion = sf.ui.proTools.mainWindow.buttons.whoseTitle.is("Add Tempo Change").first.frame.x;
const targetWindowYPosition = sf.ui.proTools.mainWindow.gridNudgeCluster.frame.y;
const pluginWindow = sf.ui.proTools.windows.whoseTitle.contains("Plug-in:").first;
//get plugin bypass info - if bypass is active, then move on to the next instance
const pluginBypassInfo = sf.ui.proTools.windows.whoseTitle.startsWith("Plug-in: UAD").first.buttons.whoseTitle.is("Effect Bypass").first.value.invalidate().value;
if (pluginBypassInfo === "on") {
return
}
function setWindowsizeAndPosition(settings) {
const { window, x, y, screenIndex } = settings;
let screenFrame = sf.ui.screens.allScreens[screenIndex].visibleFrame;
window.windowMove({
position: { x, y, }
});
}
setWindowsizeAndPosition({
window: pluginWindow,
x: targetWindowXPostion,
y: targetWindowYPosition,
screenIndex: 0,
});
const targetPluginName = sf.ui.proTools.windows.first.popupButtons.whoseTitle.startsWith('Plug-In Selector').first.value.invalidate().value;
const matchingPluginInfo = uadXpluginLookupArray.find(item => item.uadPluginName === targetPluginName);
const pluginWindowFrame = pluginWindow.frame;
const relativePresetButtonPosition = {
x: pluginWindowFrame.x + pluginWindowFrame.w * matchingPluginInfo.presetPositionXPercentage,
y: pluginWindowFrame.y + pluginWindowFrame.h * matchingPluginInfo.presetPositionYPercentage,
}
function copyUadSetting({ relativePresetButtonPosition }) {
sf.mouse.setPosition({ position: relativePresetButtonPosition });
sf.wait({ intervalMs: 200 });
sf.mouse.click({ position: relativePresetButtonPosition, });
sf.keyboard.press({
keys: "down",
repetitions: 3,
});
sf.keyboard.press({
keys: "return",
});
}
copyUadSetting({
relativePresetButtonPosition
});
const pluginMenuItems = sf.ui.proTools.windows.first.popupButtons.whoseTitle.startsWith("Plug-In Selector").first.popupMenuFetchAllItems().menuItems;
const menuPath = pluginMenuItems.find(mi => mi.element.isMenuChecked).path;
//Get the width to add to the end of the plugin name.
const pluginWidth = menuPath[2].match(/\(([^)]+)\)/)[0];
//Find the matching object in the
const matchingPluginObject = uadXpluginLookupArray.find(plugin => {
return plugin.uadPluginName === menuPath[2].split(" (")[0];
});
//Create the UADx pluing name
const uadxName = `${matchingPluginObject.uadXPluginName} ${pluginWidth}`;
//This is the path to the UADx plugin
const uadXPluginPath = [
menuPath[0],
menuPath[1],
uadxName
];
sf.ui.proTools.appActivateMainWindow();
const relativePasteButtonPosition = {
x: pluginWindowFrame.x + pluginWindowFrame.w * matchingPluginInfo.pastePositionXPercentage,
y: pluginWindowFrame.y + pluginWindowFrame.h * matchingPluginInfo.pastePositionYPercentage
}
function pasteUadx() {
//wait for plugin to appear
sf.ui.proTools.windows.whoseTitle.contains("Plug-in: UADx").first.elementWaitFor({
waitType: "Appear",
});
sf.mouse.click({
position: relativePasteButtonPosition,
});
}
function unlinkedMultiMono() {
/////MULTI MONO STUFF/////
const masterLinkUad = sf.ui.proTools.windows.whoseTitle.contains("Plug-in: UAD").first.buttons.whoseTitle.is("Master Link button");
const targetInsertSlot = sf.ui.proTools.windows.whoseTitle.contains("Plug-in: UAD").first.popupButtons.allItems[4].value.invalidate().value;
const linkStatus = masterLinkUad.first.value.invalidate().value;
const pluginWin = sf.ui.proTools.windows.whoseTitle.contains("Plug-in:").first;
//open multimono plugin instance
function convertMultiMonoUadToUadx() {
pluginWin.popupButtons.allItems[5].popupMenuSelect({
menuPath: uadXPluginPath,
});
}
//duplicate current track
function duplicateTrack() {
sf.ui.proTools.menuClick({
menuPath: ["Track", "Duplicate..."],
});
//Wait for Dialog
sf.ui.proTools.duplicateTracksDialog
//duplicate settings
sf.ui.proTools.trackDuplicateSelected({
duplicateActivePlaylist: false,
duplicateAlternatePlaylists: false,
duplicateAutomation: false,
duplicateGroupAssignments: false,
duplicateInserts: true,
duplicateSends: false,
insertAfterLastSelectedTrack: true,
numberOfDuplicates: 1
})
//Wait for dlg to disappear
sf.ui.proTools.duplicateTracksDialog.elementWaitFor({
waitType: "Disappear",
});
const isThereAnAlertWindow = sf.ui.proTools.windows.whoseDescription.is("alert").first.elementWaitFor({
timeout: 1000,
onError: "Continue",
}).success
if (isThereAnAlertWindow) {
sf.wait({ intervalMs: 200 });
sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick();
}
//wait for main window become active
sf.wait({ intervalMs: 200 });
}
function openTargetInsertSlot() {
var currentInsertSlot = sf.ui.proTools.windows.whoseTitle.startsWith("Plug-in: UAD").first.popupButtons.allItems[4].value.invalidate().value;
const insertSlotsByLetter = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
var letter = currentInsertSlot;
var insertByNumber = insertSlotsByLetter.indexOf(letter) + 1;
sf.ui.proTools.selectedTrack.trackInsertToggleShow({
insertNumber: insertByNumber,
targetValue: "Enable",
waitForInsertWindow: true,
});
}
//L or R channel focused
//copy left channel
function focusLeftChannel() {
if (pluginWin.popupButtons.allItems[3].value.invalidate().value !== "L") {
pluginWin.popupButtons.allItems[3].popupMenuSelect({
menuPath: ["Left"],
});
}
}
//copy right channel
function focusRightChannel() {
if (pluginWin.popupButtons.allItems[3].value.invalidate().value !== "R") {
pluginWin.popupButtons.allItems[3].popupMenuSelect({
menuPath: ["Right"],
});
}
}
function selectTrackAbove() {
sf.ui.proTools.menuClick({
menuPath: ["Edit", "Selection", "Extend Edit Up"],
});
sf.ui.proTools.menuClick({
menuPath: ["Edit", "Selection", "Remove Edit from Bottom"],
});
}
function selectTrackBelow() {
sf.ui.proTools.menuClick({
menuPath: ["Edit", "Selection", "Extend Edit Down"],
});
sf.ui.proTools.menuClick({
menuPath: ["Edit", "Selection", "Remove Edit from Top"],
});
}
function deleteSelectedTrack() {
if (sf.ui.proTools.getMenuItem('Track', 'Delete...').exists) {
sf.ui.proTools.getMenuItem('Track', 'Delete...').elementClick();
sf.ui.proTools.confirmationDialog.invalidate().elementWaitFor();
sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Delete').first.elementClick();
} else if (sf.ui.proTools.getMenuItem('Track', 'Delete').exists) {
sf.ui.proTools.getMenuItem('Track', 'Delete').elementClick();
}
}
focusLeftChannel();
duplicateTrack();
openTargetInsertSlot();
focusLeftChannel();
copyUadSetting({
relativePresetButtonPosition
});
selectTrackAbove();
openTargetInsertSlot();
//launch UADx multimono instance
sf.ui.proTools.windows.whoseTitle.startsWith("Plug-in:").first.popupButtons.allItems[5].popupMenuSelect({
menuPath: uadXPluginPath,
});
sf.ui.proTools.windows.whoseTitle.contains("Plug-in:").first.buttons.whoseTitle.is("Master Link button").first.invalidate();
sf.ui.proTools.windows.whoseTitle.contains("Plug-in:").first.buttons.whoseTitle.is("Master Link button").first.elementClick();
pasteUadx();
selectTrackBelow();
openTargetInsertSlot();
focusRightChannel();
copyUadSetting({
relativePresetButtonPosition
});
selectTrackAbove();
openTargetInsertSlot();
focusRightChannel();
pasteUadx();
//store originally selected track name
const selectedTracks = sf.ui.proTools.selectedTrackNames
selectTrackBelow();
deleteSelectedTrack();
// select original track name
sf.ui.proTools.trackSelectByName({ names: selectedTracks })
}
//load UADx Version
if (menuPath[0] === "multi-mono plug-in" && sf.ui.proTools.windows.whoseTitle.contains("Plug-in: UAD").first.buttons.whoseTitle.is("Master Link button").first.value.invalidate().value === "") {
//selects multi-mono instance unlinked
unlinkedMultiMono();
} else if (menuPath[0] === "multi-mono plug-in") {
//selects multi-mono instance
sf.ui.proTools.windows.whoseTitle.startsWith("Plug-in:").first.popupButtons.allItems[5].popupMenuSelect({
menuPath: uadXPluginPath,
});
pasteUadx();
} else {
//selects multichannel or individual instance
sf.ui.proTools.windows.whoseTitle.startsWith("Plug-in:").first.popupButtons.allItems[4].popupMenuSelect({
menuPath: uadXPluginPath,
});
pasteUadx();
}
//Close plugin window
sf.ui.proTools.menuClick({
menuPath: ["Window", "Hide All Floating Windows"],
targetValue: "Enable",
});
}
//MAIN FUNCTION
function main() {
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.mainWindow.invalidate();
var conversionType = sf.interaction.displayDialog({
buttons: ["Single Instance", "Whole Track", "Entire Session"],
prompt: "What UAD to UADx conversion type do you want?",
title: "Tristan Hoogland's UAD to UADx Converter",
}).button;
if (conversionType === "Single Instance") {
convertSingleInstance();
} else if (conversionType === "Whole Track") {
convertWholeTrack();
} else if (conversionType === "Entire Session") {
convertEntireSession();
}
function convertSingleInstance() {
ensureEditWindowIsFocused();
ensureTempoRulerIsVisible();
//get open plugin focused
function focusOpenPlugin() {
var frontPluginWin = sf.ui.proTools.getFloatingWindowWithTitleStartingWith("Plug-in: UAD").invalidate();
var pluginTrack = frontPluginWin.popupButtons.whoseTitle.is("Track Selector").first.value.invalidate().value
sf.ui.proTools.trackSelectByName({ names: [pluginTrack] });
}
try {
focusOpenPlugin();
convertUadToUadx();
} catch (error) {
var selectPlugin = sf.interaction.displayDialog({
buttons: ["OK", "Cancel"],
cancelButton: "Cancel",
prompt: "Please launch a compatiable UAD<>UADx insert then press OK to proceed.",
title: "Tristan Hoogland's UAD to UADx Converter",
}).button;
if (selectPlugin === "OK") {
convertSingleInstance();
}
}
}
function convertWholeTrack() {
ensureEditWindowIsFocused();
hideAllFloatingWindows();
ensureTempoRulerIsVisible();
function doForAllSelectedTracks(action) {
var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames;
try {
sf.ui.proTools.selectedTrackHeaders.forEach(track => {
track.trackSelect();
action(track);
});
}
finally {
sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames });
}
}
/**@param {AxPtTrackHeader} track */
function trackFunc(track) {
loadFirstUadPlug();
}
doForAllSelectedTracks(trackFunc);
}
function convertEntireSession() {
sf.interaction.displayDialog({
buttons: ["Yes", "Cancel"],
cancelButton: "Cancel",
defaultButton: "Yes",
prompt: "You are about to find and replace ALL active instances of UAD with UADx compatiable plugins. This may take some time." + ("\n") + ("\n") + "Are you sure you want to continue?",
title: "Tristan Hoogland's UAD to UADx Converter",
}).button;
ensureEditWindowIsFocused();
//save current version before proceeding
saveSession();
saveAsUadx();
hideAllFloatingWindows();
ensureTempoRulerIsVisible();
findAllUadTracks();
function doForAllSelectedTracks(action) {
var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames;
try {
sf.ui.proTools.selectedTrackHeaders.forEach(track => {
track.trackSelect();
action(track);
});
}
finally {
sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames });
}
}
/**@param {AxPtTrackHeader} track */
function trackFunc(track) {
loadFirstUadPlug();
}
doForAllSelectedTracks(trackFunc);
//finally deselect all tracks
sf.ui.proTools.trackDeselectAll();
// log("UAD to UADx conversion complete!");
saveSession();
var reopenSession = sf.interaction.displayDialog({
buttons: ["Yes", "No"],
cancelButton: "No",
defaultButton: "No",
prompt: "UAD to UADx conversion complete!" + ("\n") + ("\n") + "Would you like to close and reopen the session?",
title: "Tristan Hoogland's UAD to UADx Converter",
}).button;
if (reopenSession === "Yes") {
sf.ui.proTools.menuClick({
menuPath: ["File", "Close Session"],
});
if (sf.ui.proTools.confirmationDialog.exists) {
sf.ui.proTools.confirmationDialog.elementWaitFor();
sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("Save").first.elementClick();
sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear" });
}
//open most recent session
sf.keyboard.press({
keys: "cmd+shift+o",
});
}
}
sf.interaction.displayDialog({
prompt: "UAD to UADx Conversion complete!"
})
}
main();
Links
User UID: yesbmwLVy0dRQLFNZzxo8kQx4ri2
Feedback Key: sffeedback:yesbmwLVy0dRQLFNZzxo8kQx4ri2:-NVguVw6X0mNrdhRtICE
- SSoundFlow Bot @soundflowbot
Thanks for posting a question or an issue related to the 'UAD to UADx Converter' package.
This package is made by @Tristan. We're auto-tagging them here so that they will hopefully be able to help you. - In reply toBen_Rubin⬆:Ben Rubin @Ben_Rubin
hey @Tristan, are you able to lend any support here?
thanks
bBen Rubin @Ben_Rubin
HI @Tristan checking again to see if you have any time to support this script. Besides the issues I outline above, there are a bunch of new plugins since you wrote this and also v11 of the plugin changes the GUI of the UAD-2 plugins to match the UADx.
thanks in advance
ben- TTristan Hoogland @Tristan
Hey Ben,
Sorry for the radio silence on this - it's been a crazy year since I made this script and I know it's overdue for some updates.
I'll be looking to get back to it later in the month when work quietens down!
Ben Rubin @Ben_Rubin
no worries, i totally get it! glad you may have some time coming up.
best
b- TTristan Hoogland @Tristan
Hey Ben, I don't know if you are still looking for a solution to this, but I'm currently updating it (to work with the new PT as well).
If you have a video of the issue and or a log file to share that'd be great. Shouldn't be difficult to fix. Also updating to work with the updated UAD gui's
Ben Rubin @Ben_Rubin
sure would be great to have. i will make a video as soon as i have a moment. in the middle of a record atm.
- AAdam Lilienfeldt @Adam_Lilienfeldt
Hi @Tristan and @Ben_Rubin
I've taken the liberty of updating @Tristan's incredible script - it's been a fun challenge for me!
It's been tested with the plugins you'll find in the code in Pro Tools 2024.10.2.
I'm still testing it myself, so I've left in quite a lot of logging in the code. I'll remove that at a later point.
Let me know how it works out for you!// Test log to verify script is running log("UAD to UADx Converter Script Starting..."); // Ensure Pro Tools is active and UI is refreshed sf.ui.proTools.appActivate(); sf.ui.proTools.invalidate(); // Get screen resolution information using SoundFlow method const MAX_SCREEN_WIDTH = sf.ui.screens.mainScreen.size.x; const SCREEN_HEIGHT = sf.ui.screens.mainScreen.size.y; log("Current screen resolution: " + MAX_SCREEN_WIDTH + " x " + SCREEN_HEIGHT); // Define the reference resolution (the screen size where coordinates were originally captured) const referenceScreenWidth = 1920; // Update this to your original screen width const referenceScreenHeight = 1080; // Update this to your original screen height log("Reference screen resolution: " + referenceScreenWidth + " x " + referenceScreenHeight); // Calculate scaling factors const scaleX = MAX_SCREEN_WIDTH / referenceScreenWidth; const scaleY = SCREEN_HEIGHT / referenceScreenHeight; log("Screen scaling factors - X: " + scaleX.toFixed(3) + ", Y: " + scaleY.toFixed(3)); // Warn if significant scaling is detected if (Math.abs(scaleX - 1.0) > 0.1 || Math.abs(scaleY - 1.0) > 0.1) { log("WARNING: Significant screen scaling detected! This may affect coordinate accuracy."); log("Consider recalibrating coordinates for this screen resolution."); } //UAD Plugin Arrays const uadXpluginLookupArray = [ { uadPluginName: "UAD UA 1176 Rev A", copyPositionXPercentage: 0.3826, copyPositionYPercentage: 0.2965, uadXPluginName: "UADx 1176 Rev A Compressor", pastePositionXPercentage: 0.4304, pastePositionYPercentage: 0.3799, }, { uadPluginName: "UAD UA 1176AE", copyPositionXPercentage: 0.3826, copyPositionYPercentage: 0.2965, uadXPluginName: "UADx 1176AE Compressor", pastePositionXPercentage: 0.4304, pastePositionYPercentage: 0.3799, }, { uadPluginName: "UAD UA 1176LN Rev E", copyPositionXPercentage: 0.3826, copyPositionYPercentage: 0.2965, uadXPluginName: "UADx 1176LN Rev E Compressor", pastePositionXPercentage: 0.4304, pastePositionYPercentage: 0.3799, }, { uadPluginName: "UAD Teletronix LA-2", copyPositionXPercentage: 0.3816, copyPositionYPercentage: 0.2305, uadXPluginName: "UADx LA-2 Compressor", pastePositionXPercentage: 0.4277, pastePositionYPercentage: 0.2969, }, { uadPluginName: "UAD Teletronix LA-2A Gray", copyPositionXPercentage: 0.3816, copyPositionYPercentage: 0.2305, uadXPluginName: "UADx LA-2A Gray Compressor", pastePositionXPercentage: 0.4277, pastePositionYPercentage: 0.2969, }, { uadPluginName: "UAD Teletronix LA-2A Silver", copyPositionXPercentage: 0.3816, copyPositionYPercentage: 0.2305, uadXPluginName: "UADx LA-2A Silver Compressor", pastePositionXPercentage: 0.4277, pastePositionYPercentage: 0.2969, }, { uadPluginName: "UAD Teletronix LA-2A Legacy", copyPositionXPercentage: 0.3816, copyPositionYPercentage: 0.2305, uadXPluginName: "UADx LA-2A Tube Compressor", pastePositionXPercentage: 0.4277, pastePositionYPercentage: 0.2969, }, { uadPluginName: "UAD UA 175-B", copyPositionXPercentage: 0.3870, copyPositionYPercentage: 0.2905, uadXPluginName: "UADx 175-B Compressor", pastePositionXPercentage: 0.4274, pastePositionYPercentage: 0.3749, }, { uadPluginName: "UAD UA 176", copyPositionXPercentage: 0.3822, copyPositionYPercentage: 0.2869, uadXPluginName: "UADx 176 Compressor", pastePositionXPercentage: 0.4303, pastePositionYPercentage: 0.3846, }, { uadPluginName: "UAD API 2500", copyPositionXPercentage: 0.3548, copyPositionYPercentage: 0.1801, uadXPluginName: "UADx API 2500 Bus Compressor", pastePositionXPercentage: 0.4877, pastePositionYPercentage: 0.2254, }, { uadPluginName: "UAD API Vision Channel Strip", copyPositionXPercentage: 0.7022, copyPositionYPercentage: 0.1199, uadXPluginName: "UADx API Vision Channel Strip", pastePositionXPercentage: 0.7234, pastePositionYPercentage: 0.1540, }, { uadPluginName: "UAD Ampex ATR-102", copyPositionXPercentage: 0.6094, copyPositionYPercentage: 0.1261, uadXPluginName: "UADx Ampex ATR-102 Master Tape", pastePositionXPercentage: 0.5847, pastePositionYPercentage: 0.1474, }, { uadPluginName: "UAD Avalon VT-737sp", copyPositionXPercentage: 0.3039, copyPositionYPercentage: 0.2568, uadXPluginName: "UADx Avalon VT737 Channel Strip", pastePositionXPercentage: 0.3385, pastePositionYPercentage: 0.3308, }, { uadPluginName: "UAD Brigade Chorus", copyPositionXPercentage: 0.6107, copyPositionYPercentage: 0.1633, uadXPluginName: "UADx Brigade Chorus", pastePositionXPercentage: 0.6423, pastePositionYPercentage: 0.2050, }, { uadPluginName: "UAD Capitol Chambers", copyPositionXPercentage: 0.6620, copyPositionYPercentage: 0.1141, uadXPluginName: "UADx Capitol Chambers", pastePositionXPercentage: 0.6355, pastePositionYPercentage: 0.1426, }, { uadPluginName: "UAD Century Tube Channel Strip", copyPositionXPercentage: 0.4884, copyPositionYPercentage: 0.1402, uadXPluginName: "UADx Century Tube Channel Strip", pastePositionXPercentage: 0.5437, pastePositionYPercentage: 0.1864, }, { uadPluginName: "UAD Empirical Labs Distressor", copyPositionXPercentage: 0.3653, copyPositionYPercentage: 0.1896, uadXPluginName: "UADx Empirical Labs Distressor", pastePositionXPercentage: 0.4022, pastePositionYPercentage: 0.1865, }, { uadPluginName: "UAD Fairchild 660", copyPositionXPercentage: 0.3868, copyPositionYPercentage: 0.1635, uadXPluginName: "UADx Fairchild 660 Compressor", pastePositionXPercentage: 0.4255, pastePositionYPercentage: 0.2078, }, { uadPluginName: "UAD Fairchild 670", copyPositionXPercentage: 0.3853, copyPositionYPercentage: 0.1201, uadXPluginName: "UADx Fairchild 670 Compressor", pastePositionXPercentage: 0.4282, pastePositionYPercentage: 0.1471, }, { uadPluginName: "UAD Galaxy Tape Echo", copyPositionXPercentage: 0.4730, copyPositionYPercentage: 0.1915, uadXPluginName: "UADx Galaxy Tape Echo", pastePositionXPercentage: 0.5281, pastePositionYPercentage: 0.2464, }, { uadPluginName: "UAD Hitsville EQ", copyPositionXPercentage: 0.3844, copyPositionYPercentage: 0.2935, uadXPluginName: "UADx Hitsville EQ", pastePositionXPercentage: 0.4286, pastePositionYPercentage: 0.3822, }, { uadPluginName: "UAD Hitsville EQ Mastering", copyPositionXPercentage: 0.3837, copyPositionYPercentage: 0.1111, uadXPluginName: "UADx Hitsville EQ Mastering", pastePositionXPercentage: 0.4288, pastePositionYPercentage: 0.1401, }, { uadPluginName: "UAD Teletronix LA-3A", copyPositionXPercentage: 0.6881, copyPositionYPercentage: 0.2528, uadXPluginName: "UADx LA-3A Compressor", pastePositionXPercentage: 0.6430, pastePositionYPercentage: 0.3340, }, { uadPluginName: "UAD Manley Massive Passive", copyPositionXPercentage: 0.3823, copyPositionYPercentage: 0.2275, uadXPluginName: "UADx Manley Massive Passive EQ", pastePositionXPercentage: 0.4268, pastePositionYPercentage: 0.2972, }, { uadPluginName: "UAD Manley Massive Passive MST", copyPositionXPercentage: 0.3823, copyPositionYPercentage: 0.2275, uadXPluginName: "UADx Manley Massive Passive MST", pastePositionXPercentage: 0.4268, pastePositionYPercentage: 0.2972, }, { uadPluginName: "UAD Manley VOXBOX", copyPositionXPercentage: 0.3835, copyPositionYPercentage: 0.2291, uadXPluginName: "UADx Manley VOXBOX", pastePositionXPercentage: 0.4266, pastePositionYPercentage: 0.2986, }, { uadPluginName: "UAD Manley Variable Mu", copyPositionXPercentage: 0.3849, copyPositionYPercentage: 0.2911, uadXPluginName: "UADx Manley Vari-Mu Compressor", pastePositionXPercentage: 0.4288, pastePositionYPercentage: 0.3818, }, { uadPluginName: "UAD Oxide Tape", copyPositionXPercentage: 0.5647, copyPositionYPercentage: 0.1896, uadXPluginName: "UADx Oxide Tape Recorder", pastePositionXPercentage: 0.6255, pastePositionYPercentage: 0.2459, }, { uadPluginName: "UAD Pultec EQP-1A", copyPositionXPercentage: 0.3863, copyPositionYPercentage: 0.2283, uadXPluginName: "UADx Pultec EQP-1A EQ", pastePositionXPercentage: 0.4261, pastePositionYPercentage: 0.2987, }, { uadPluginName: "UAD Pultec HLF-3C", copyPositionXPercentage: 0.3863, copyPositionYPercentage: 0.2283, uadXPluginName: "UADx Pultec HLF-3C EQ", pastePositionXPercentage: 0.4261, pastePositionYPercentage: 0.2987, }, { uadPluginName: "UAD Pultec MEQ-5", copyPositionXPercentage: 0.3863, copyPositionYPercentage: 0.2283, uadXPluginName: "UADx Pultec MEQ-5 EQ", pastePositionXPercentage: 0.4261, pastePositionYPercentage: 0.2987, }, { uadPluginName: "UAD Pure Plate", copyPositionXPercentage: 0.6544, copyPositionYPercentage: 0.1178, uadXPluginName: "UADx Pure Plate Reverb", pastePositionXPercentage: 0.6377, pastePositionYPercentage: 0.1492, }, { uadPluginName: "UAD Studer A800", copyPositionXPercentage: 0.6069, copyPositionYPercentage: 0.1267, uadXPluginName: "UADx Studer A800 Tape Recorder", pastePositionXPercentage: 0.6348, pastePositionYPercentage: 0.1617, }, { uadPluginName: "UAD Studio D Chorus", copyPositionXPercentage: 0.3854, copyPositionYPercentage: 0.2903, uadXPluginName: "UADx Studio D Chorus", pastePositionXPercentage: 0.4280, pastePositionYPercentage: 0.3791, }, { uadPluginName: "UAD dbx 160", copyPositionXPercentage: 0.6262, copyPositionYPercentage: 0.2490, uadXPluginName: "UADx dbx 160 Compressor", pastePositionXPercentage: 0.6365, pastePositionYPercentage: 0.3233, }, { uadPluginName: "UAD Studio D Chorus", copyPositionXPercentage: 0.3874, copyPositionYPercentage: 0.3700, uadXPluginName: "UADx Studio D Chorus", pastePositionXPercentage: 0.4244, pastePositionYPercentage: 0.3869, }, { uadPluginName: "UAD dbx 160 Compressor", copyPositionXPercentage: 0.5639, copyPositionYPercentage: 0.3251, uadXPluginName: "UADx dbx 160 Compressor", pastePositionXPercentage: 0.6355, pastePositionYPercentage: 0.3188, } ]; function saveSession() { try { sf.ui.proTools.menuClick({ menuPath: ['File', 'Save Session'] }); log("Session saved successfully"); } catch (error) { log("Error saving session: " + error.message); } } function ensureEditWindowIsFocused() { try { sf.ui.proTools.menuClick({ menuPath: ['Window', 'Edit'] }); log("Edit window focused"); } catch (error) { log("Error focusing edit window: " + error.message); } } function ensureTempoRulerIsVisible() { try { sf.ui.proTools.menuClick({ menuPath: ["View", "Rulers", "Tempo"], targetValue: "Enable", }); log("Tempo ruler made visible"); } catch (error) { log("Error making tempo ruler visible: " + error.message); } } function hideAllFloatingWindows() { try { sf.ui.proTools.menuClick({ menuPath: ["Window", "Hide All Floating Windows"], targetValue: "Enable", }); log("All floating windows hidden"); } catch (error) { log("Error hiding floating windows: " + error.message); } } function saveAs({ savePath, newSessionName }) { try { sf.ui.proTools.menuClick({ menuPath: ['File', 'Save Session As...'] }); const saveWin = sf.ui.proTools.windows.whoseTitle.is("Save").first; const saveWinSheet = saveWin.sheets.first; saveWin.elementWaitFor(); sf.keyboard.press({ keys: 'slash' }); saveWinSheet.elementWaitFor(); const sheet = saveWin.sheets.first; if (sheet.comboBoxes.first.exists) { sheet.comboBoxes.first.value.value = savePath; sheet.buttons.whoseTitle.is('Go').first.elementClick(); } else { sheet.textFields.first.value.value = savePath; sf.keyboard.press({ keys: 'return' }); } sf.wait({ intervalMs: 500 }); saveWin.textFields.first.elementSetTextFieldWithAreaValue({ value: newSessionName }); saveWin.buttons.whoseTitle.is("Save").first.elementClick(); saveWin.elementWaitFor({ waitType: 'Disappear' }); sf.ui.proTools.waitForNoModals(); log("Save As completed successfully"); } catch (error) { log("Error in saveAs: " + error.message); } } function expandAllTracks() { var size = "medium"; sf.ui.proTools.appActivate(); var tracksToChangeHeight = sf.ui.proTools.visibleTrackNames if ((!sf.ui.proTools.getMenuItem("Track", "Delete").isEnabled)) { sf.ui.proTools.trackSelectByName({ names: [tracksToChangeHeight[0]] }) sf.ui.proTools.selectedTrack.trackScrollToView(); } else { sf.ui.proTools.trackGetByName({ name: tracksToChangeHeight[0], makeVisible: true }).track.trackScrollToView(); } var f = sf.ui.proTools.selectedTrack.frame; var popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({ anchor: "TopLeft", relativePosition: { x: f.w - 10, y: 5 }, isOption: true, // isShift: true, }).popupMenu; popupMenu.menuClickPopupMenu({ menuPath: [size] }); } function saveAsUadx() { try { log("Starting saveAsUadx..."); sf.ui.proTools.appActivate(); sf.ui.proTools.invalidate().appActivateMainWindow(); const sessionPath = sf.ui.proTools.invalidate().mainWindow.sessionPath; const sessionName = sessionPath.split('/').slice(-1)[0].split('.').slice(0, -1).join('.'); log("Current session name: " + sessionName); // Create UADx version name const uadxSessionName = sessionName + "_UADx"; log("New UADx session name: " + uadxSessionName); // Open Save As dialog sf.ui.proTools.getMenuItem('File', 'Save Session As...').elementClick(); const saveDlgWindow = sf.ui.proTools.windows.whoseTitle.is("Save").first; // Wait for text field to appear saveDlgWindow.textFields.first.elementWaitFor({ waitType: 'Appear', timeout: 3000, pollingInterval: 50, }); // Set the new filename saveDlgWindow.textFields.first.elementSetTextFieldWithAreaValue({ value: uadxSessionName, }); // Click Save saveDlgWindow.buttons.whoseTitle.is("Save").first.elementClick(); // Wait for dialog to disappear saveDlgWindow.textFields.first.elementWaitFor({ waitForNoElement: true, timeout: 3000, pollingInterval: 50, }); log("UADx session saved successfully"); } catch (error) { log("Error in saveAsUadx: " + error.message); } } function findAllUadTracks() { try { log("Starting to find UAD tracks with NEW method..."); function selectTracksWithPlugName(plugNames, includeInactive) { sf.ui.proTools.trackDeselectAll(); const visibleTrackNames = sf.ui.proTools.visibleTrackNames; let foundTracks = []; log("Checking " + visibleTrackNames.length + " visible tracks"); log("Looking for these convertible UAD plugins: " + plugNames.join(", ")); for (let i = 0; i < visibleTrackNames.length; i++) { const trackName = visibleTrackNames[i]; log("Checking track: " + trackName); const track = sf.ui.proTools.trackGetByName({ name: trackName }).track; const muteBtn = track.buttons.whoseTitle.is("Mute").first; if (!muteBtn.exists) { log("No mute button found for track " + trackName); continue; } const isTrackInactive = muteBtn.value.value.startsWith('inactive'); if (isTrackInactive && !includeInactive) { log("Track " + trackName + " is inactive, skipping"); continue; } // Try to access inserts using the track's insert/send structure try { // Look for insert groups in the track const allGroups = track.groups.allItems; log("Track " + trackName + " has " + allGroups.length + " groups"); const insertGroups = allGroups.filter(group => group.title && group.title.value.includes("Inserts")); log("Found " + insertGroups.length + " insert groups on track " + trackName); for (let groupIndex = 0; groupIndex < insertGroups.length; groupIndex++) { const insertGroup = insertGroups[groupIndex]; log("Checking insert group: " + insertGroup.title); const insertButtons = insertGroup.buttons.allItems; log("Insert group has " + insertButtons.length + " buttons"); for (let j = 0; j < insertButtons.length; j++) { const insertBtn = insertButtons[j]; if (!insertBtn.exists || !insertBtn.value) continue; const plugName = insertBtn.value.value; if (plugName === "unassigned") continue; log("Found plugin: " + plugName + " on track: " + trackName); // Check if this plugin is convertible if (plugNames.includes(plugName)) { foundTracks.push(track.normalizedTrackName); log("*** CONVERTIBLE! Added track " + trackName + " to conversion list"); break; // Found a convertible UAD plugin on this track } else if (plugName.startsWith("UAD ")) { log("Found UAD plugin '" + plugName + "' but it's not convertible, skipping"); } } if (foundTracks.includes(track.normalizedTrackName)) break; // Track already added } } catch (insertError) { log("Error accessing inserts for track " + trackName + ": " + insertError.message); } } // Remove duplicates foundTracks = [...new Set(foundTracks)]; if (foundTracks.length === 0) { log("No convertible UAD plugins found in session"); alert("No convertible UAD<>UADx plugins found in session"); throw new Error("No convertible tracks found"); } sf.ui.proTools.trackSelectByName({ names: foundTracks }); log("Found " + foundTracks.length + " tracks with convertible UAD plugins: " + foundTracks.join(", ")); } function selectTracksWithPlugIn({ plugNames, includeInactive = false }) { sf.ui.proTools.invalidate(); const disabled = ["Inserts A-E", "Inserts F-J"].filter(view => !sf.ui.proTools.getMenuItem("View", "Edit Window Views", view).isMenuChecked); disabled.map(view => sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: "Enable" })); try { selectTracksWithPlugName(plugNames, includeInactive); } catch (err) { throw err; } finally { disabled.map(view => sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: "Disable" })); } } // Only search for plugins that are actually convertible (in the lookup array) const convertiblePluginNames = uadXpluginLookupArray.map(item => item.uadPluginName); log("Total convertible plugins in lookup array: " + convertiblePluginNames.length); selectTracksWithPlugIn({ plugNames: convertiblePluginNames, includeInactive: false }); } catch (error) { log("Error in findAllUadTracks: " + error.message); throw error; } } function loadFirstUadPlug() { try { log("Loading first UAD plugin..."); function getInsertsInfo() { const insertInfo = Array(10).fill(0).map((_, index) => { const track = sf.ui.proTools.selectedTrack; const insertButton = track.invalidate().insertButtons[index]; const insertButtonValue = insertButton.value.invalidate().value; const insertSelectorButton = track.invalidate().insertSelectorButtons[index]; const insertSelectorButtonValue = insertSelectorButton.value.invalidate().value; return { insertButton, insertButtonValue, insertSelectorButton, insertSelectorButtonValue, insertIndex: index, pluginName: insertButtonValue, isActive: !insertSelectorButtonValue.includes('inactive'), }; }); return insertInfo; } const usablePluginNames = uadXpluginLookupArray.map(item => item.uadPluginName); const insertsInfo = getInsertsInfo(); const matchingInsertSlots = insertsInfo.filter(btn => { return usablePluginNames.some((name) => name === btn.pluginName) && btn.isActive === true; }); sf.ui.proTools.appActivateMainWindow(); matchingInsertSlots.forEach(insert => { sf.ui.proTools.selectedTrack.trackInsertToggleShow({ insertNumber: insert.insertIndex + 1, }); convertUadToUadx(); }); log("Finished processing UAD plugins on track"); } catch (error) { log("Error in loadFirstUadPlug: " + error.message); } } function convertUadToUadx() { try { log("Starting UAD to UADx conversion..."); const targetWindowXPosition = sf.ui.proTools.mainWindow.buttons.whoseTitle.is("Add Tempo Change").first.frame.x; const targetWindowYPosition = sf.ui.proTools.mainWindow.gridNudgeCluster.frame.y; const pluginWindow = sf.ui.proTools.windows.whoseTitle.contains("Plug-in:").first; const pluginBypassInfo = sf.ui.proTools.windows.whoseTitle.startsWith("Plug-in: UAD").first.buttons.whoseTitle.is("Effect Bypass").first.value.invalidate().value; if (pluginBypassInfo === "on") { log("Plugin is bypassed, skipping..."); return; } function setWindowsizeAndPosition(settings) { const { window, x, y, screenIndex } = settings; window.windowMove({ position: { x, y } }); } setWindowsizeAndPosition({ window: pluginWindow, x: targetWindowXPosition, y: targetWindowYPosition, screenIndex: 0, }); // Try to find the plugin selector button - it might have a different title let pluginSelectorButton = null; let targetPluginName = ""; try { // Try different possible titles for the plugin selector const possibleSelectors = [ 'Plug-In Selector', 'Plugin Selector', 'Plug-in Selector', 'Insert Selector' ]; for (let selectorTitle of possibleSelectors) { const selector = pluginWindow.popupButtons.whoseTitle.startsWith(selectorTitle).first; if (selector.exists) { pluginSelectorButton = selector; targetPluginName = selector.value.invalidate().value; log("Found plugin selector with title containing: " + selectorTitle); break; } } // If we still haven't found it, try getting all popup buttons and find one that looks like a plugin name if (!pluginSelectorButton) { log("Trying to find plugin selector by examining all popup buttons..."); const allPopupButtons = pluginWindow.popupButtons.allItems; log("Found " + allPopupButtons.length + " popup buttons in plugin window"); for (let i = 0; i < allPopupButtons.length; i++) { try { const buttonValue = allPopupButtons[i].value.invalidate().value; log("Popup button " + i + ": " + buttonValue); // Check if this looks like a UAD plugin name if (buttonValue && buttonValue.startsWith("UAD ")) { pluginSelectorButton = allPopupButtons[i]; targetPluginName = buttonValue; log("Found UAD plugin name in popup button " + i + ": " + targetPluginName); break; } } catch (buttonError) { log("Error checking popup button " + i + ": " + buttonError.message); } } } if (!pluginSelectorButton || !targetPluginName) { log("Could not find plugin selector button or plugin name"); return; } } catch (error) { log("Error finding plugin selector: " + error.message); return; } log("Converting plugin: " + targetPluginName); const matchingPluginInfo = uadXpluginLookupArray.find(item => item.uadPluginName === targetPluginName); if (!matchingPluginInfo) { log("Plugin " + targetPluginName + " not found in lookup array"); return; } if (matchingPluginInfo.pastePositionXPercentage === 0.0000 && matchingPluginInfo.pastePositionYPercentage === 0.0000) { log("Plugin " + targetPluginName + " not yet supported for copy/paste"); return; } const pluginWindowFrame = pluginWindow.frame; const relativeCopyButtonPosition = { x: pluginWindowFrame.x + pluginWindowFrame.w * matchingPluginInfo.copyPositionXPercentage, y: pluginWindowFrame.y + pluginWindowFrame.h * matchingPluginInfo.copyPositionYPercentage, }; function copyUadSettings({ relativeCopyButtonPosition }) { log("Copying UAD settings"); sf.mouse.setPosition({ position: relativeCopyButtonPosition }); sf.wait({ intervalMs: 200 }); sf.mouse.click({ position: relativeCopyButtonPosition }); sf.wait({ intervalMs: 500 }); } copyUadSettings({ relativeCopyButtonPosition }); // Get menu information from the plugin selector we found let pluginMenuItems = null; let menuPath = null; try { pluginMenuItems = pluginSelectorButton.popupMenuFetchAllItems().menuItems; // Find all checked menu items const checkedItems = pluginMenuItems.filter(mi => mi.element.isMenuChecked); log("Found " + checkedItems.length + " checked menu items"); // Look for the deepest menu path that matches our target plugin name // This helps avoid picking up default/favorite entries at higher levels let bestMatch = null; let maxDepth = 0; for (let item of checkedItems) { log("Checking item: " + JSON.stringify(item.path)); // Look for the path that contains our target plugin name const pathString = item.path.join(" -> "); if (pathString.includes(targetPluginName)) { const depth = item.path.length; if (depth > maxDepth) { maxDepth = depth; bestMatch = item; } } } if (bestMatch) { menuPath = bestMatch.path; log("Selected best match menu path: " + JSON.stringify(menuPath)); } else { // Fallback to first checked item if no specific match found menuPath = checkedItems[0].path; log("Using fallback menu path: " + JSON.stringify(menuPath)); } log(JSON.stringify(pluginMenuItems)); //Adam } catch (error) { log("Error getting menu items: " + error.message); return; } // Fix: Handle different menu structures for multi-mono vs stereo plugins let pluginWidth = ""; let basePluginName = ""; if (menuPath[0] === "multi-mono plugin" || menuPath[0] === "multi-mono plug-in") { // For multi-mono plugins, the plugin name with width is at the LAST element of the path const pluginNameWithWidth = menuPath[menuPath.length - 1]; log("Multi-mono plugin name with width: " + pluginNameWithWidth); const widthMatch = pluginNameWithWidth.match(/\(([^)]+)\)/); if (widthMatch) { pluginWidth = widthMatch[0]; // e.g., "(mono)" basePluginName = pluginNameWithWidth.split(" (")[0]; // e.g., "UAD UA 1176 Rev A" } else { log("Could not extract width from multi-mono plugin name: " + pluginNameWithWidth); return; } } else { // For stereo/multichannel plugins, the plugin name with width is at menuPath[2] if (menuPath.length < 3 || !menuPath[2]) { log("Unexpected menu structure for stereo plugin: " + JSON.stringify(menuPath)); return; } const pluginNameWithWidth = menuPath[2]; const widthMatch = pluginNameWithWidth.match(/\(([^)]+)\)/); if (widthMatch) { pluginWidth = widthMatch[0]; // e.g., "(stereo)" basePluginName = pluginNameWithWidth.split(" (")[0]; } else { log("Could not extract width from stereo plugin name: " + pluginNameWithWidth); return; } } log("Base plugin name: " + basePluginName + ", Width: " + pluginWidth); const matchingPluginObject = uadXpluginLookupArray.find(plugin => { return plugin.uadPluginName === basePluginName; }); if (!matchingPluginObject) { log("Could not find matching plugin object for: " + basePluginName); return; } let uadXPluginPath = []; if (menuPath[0] === "multi-mono plugin" || menuPath[0] === "multi-mono plug-in") { // For multi-mono, we need to preserve the category structure const uadxName = matchingPluginObject.uadXPluginName + " " + pluginWidth; if (menuPath.length === 3) { // If the original path has 3 levels (includes category), preserve the category uadXPluginPath = [ menuPath[0], // "multi-mono plugin" menuPath[1], // "Dynamics" (or other category) uadxName // "UADx 1176 Rev A Compressor (mono)" ]; } else { // If original path has 2 levels, use 2 levels for UADx too uadXPluginPath = [ menuPath[0], // "multi-mono plugin" uadxName // "UADx 1176 Rev A Compressor (mono)" ]; } } else { // For stereo/multichannel plugins, we need 3 levels const uadxName = matchingPluginObject.uadXPluginName + " " + pluginWidth; uadXPluginPath = [ menuPath[0], menuPath[1], uadxName ]; } log("UADx plugin path: " + JSON.stringify(uadXPluginPath)); sf.ui.proTools.appActivateMainWindow(); function pasteToUadx(pasteInfo) { log("Waiting for UADx plugin to appear..."); try { // Wait for UADx plugin window to appear sf.ui.proTools.windows.whoseTitle.contains("Plug-in: UADx").first.elementWaitFor({ waitType: "Appear", timeout: 5000 }); log("UADx plugin window appeared"); } catch (waitError) { log("Warning: UADx plugin window may not have appeared: " + waitError.message); // Continue anyway as the window might already be there } // Wait for plugin to fully load sf.wait({ intervalMs: 1000 }); // Get the current UADx plugin window frame (it might be different from the UAD window) let uadxPluginWindow = null; try { uadxPluginWindow = sf.ui.proTools.windows.whoseTitle.contains("Plug-in: UADx").first; const uadxWindowFrame = uadxPluginWindow.frame; // Recalculate paste position based on UADx window const updatedPastePosition = { x: uadxWindowFrame.x + uadxWindowFrame.w * pasteInfo.pastePositionXPercentage, y: uadxWindowFrame.y + uadxWindowFrame.h * pasteInfo.pastePositionYPercentage }; log("UADx window frame - x: " + uadxWindowFrame.x + ", y: " + uadxWindowFrame.y + ", w: " + uadxWindowFrame.w + ", h: " + uadxWindowFrame.h); log("Updated paste position - x: " + updatedPastePosition.x + ", y: " + updatedPastePosition.y); // Move mouse to paste position sf.mouse.setPosition({ position: updatedPastePosition }); sf.wait({ intervalMs: 500 }); log("Clicking paste button at position x: " + updatedPastePosition.x + ", y: " + updatedPastePosition.y); sf.mouse.click({ position: updatedPastePosition }); sf.wait({ intervalMs: 500 }); log("Paste operation completed"); } catch (pasteError) { log("Error during paste operation: " + pasteError.message); // Fallback to original position log("Falling back to original paste position"); sf.mouse.setPosition({ position: pasteInfo.originalPastePosition }); sf.wait({ intervalMs: 500 }); sf.mouse.click({ position: pasteInfo.originalPastePosition }); sf.wait({ intervalMs: 500 }); } } const relativePasteButtonPosition = { x: pluginWindowFrame.x + pluginWindowFrame.w * matchingPluginInfo.pastePositionXPercentage, y: pluginWindowFrame.y + pluginWindowFrame.h * matchingPluginInfo.pastePositionYPercentage }; log("Paste button position - x: " + relativePasteButtonPosition.x + ", y: " + relativePasteButtonPosition.y); log("Paste percentages - x: " + matchingPluginInfo.pastePositionXPercentage + ", y: " + matchingPluginInfo.pastePositionYPercentage); // Create paste info object to pass to the function const pasteInfo = { pastePositionXPercentage: matchingPluginInfo.pastePositionXPercentage, pastePositionYPercentage: matchingPluginInfo.pastePositionYPercentage, originalPastePosition: relativePasteButtonPosition }; // Handle different plugin types try { if (menuPath[0] === "multi-mono plug-in" && pluginWindow.buttons.whoseTitle.is("Master Link button").first.value.invalidate().value === "") { log("Processing unlinked multi-mono instance"); // For unlinked multi-mono, always use the deepest available path structure const allPopupButtons = pluginWindow.popupButtons.allItems; if (allPopupButtons.length > 5) { allPopupButtons[5].popupMenuSelect({ menuPath: uadXPluginPath, }); } else { log("Not enough popup buttons for multi-mono selection"); } pasteToUadx(pasteInfo); } else if (menuPath[0] === "multi-mono plug-in" || menuPath[0] === "multi-mono plugin") { log("Processing linked multi-mono instance"); // For linked multi-mono, we need to determine which popup button to use based on path depth const allPopupButtons = pluginWindow.popupButtons.allItems; if (menuPath.length === 3) { // 3-level path means we need to use a category-specific popup button // Try the most likely button indices first (based on empirical testing) const buttonIndicesToTry = [8, 5, 4, 6, 7, 0, 1, 2, 3]; // Start with 8 since it worked let success = false; for (let i = 0; i < buttonIndicesToTry.length && !success && buttonIndicesToTry[i] < allPopupButtons.length; i++) { const buttonIndex = buttonIndicesToTry[i]; try { log("Trying popup button index " + buttonIndex + " for 3-level path"); allPopupButtons[buttonIndex].popupMenuSelect({ menuPath: uadXPluginPath, }); success = true; log("Successfully used popup button index " + buttonIndex); } catch (buttonError) { log("Button index " + buttonIndex + " failed: " + buttonError.message); } } if (!success) { log("All popup buttons failed for 3-level path"); } } else { // 2-level path, use the standard approach if (allPopupButtons.length > 5) { allPopupButtons[5].popupMenuSelect({ menuPath: uadXPluginPath, }); } else { log("Not enough popup buttons for multi-mono selection"); // Fallback: try using the plugin selector we found pluginSelectorButton.popupMenuSelect({ menuPath: uadXPluginPath, }); } } pasteToUadx(pasteInfo); } else { log("Processing multichannel or individual instance"); // Use the plugin selector we found instead of assuming index 4 pluginSelectorButton.popupMenuSelect({ menuPath: uadXPluginPath, }); pasteToUadx(pasteInfo); } } catch (selectionError) { log("Error selecting UADx plugin: " + selectionError.message); return; } sf.ui.proTools.menuClick({ menuPath: ["Window", "Hide All Floating Windows"], targetValue: "Enable", }); log("UAD to UADx conversion completed for this plugin"); } catch (error) { log("Error in convertUadToUadx: " + error.message); } } function main() { try { log("Main function starting..."); sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); var conversionType = sf.interaction.displayDialog({ buttons: ["Single Instance", "Whole Track", "Entire Session"], prompt: "What UAD to UADx conversion type do you want?", title: "Tristan Hoogland's UAD to UADx Converter", }).button; log("Selected conversion type: " + conversionType); if (conversionType === "Single Instance") { convertSingleInstance(); } else if (conversionType === "Whole Track") { convertWholeTrack(); } else if (conversionType === "Entire Session") { convertEntireSession(); } } catch (error) { log("Error in main function: " + error.message); alert("Error occurred: " + error.message); } function convertSingleInstance() { try { log("Starting single instance conversion"); ensureEditWindowIsFocused(); ensureTempoRulerIsVisible(); function focusOpenPlugin() { var frontPluginWin = sf.ui.proTools.getFloatingWindowWithTitleStartingWith("Plug-in: UAD").invalidate(); var pluginTrack = frontPluginWin.popupButtons.whoseTitle.is("Track Selector").first.value.invalidate().value; sf.ui.proTools.trackSelectByName({ names: [pluginTrack] }); } try { focusOpenPlugin(); convertUadToUadx(); } catch (error) { log("No UAD plugin window found, asking user to open one"); var selectPlugin = sf.interaction.displayDialog({ buttons: ["OK", "Cancel"], cancelButton: "Cancel", prompt: "Please launch a compatible UAD<>UADx insert then press OK to proceed.", title: "Tristan Hoogland's UAD to UADx Converter", }).button; if (selectPlugin === "OK") { convertSingleInstance(); } } } catch (error) { log("Error in convertSingleInstance: " + error.message); } } function convertWholeTrack() { try { log("Starting whole track conversion"); ensureEditWindowIsFocused(); hideAllFloatingWindows(); ensureTempoRulerIsVisible(); function doForAllSelectedTracks(action) { var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames; try { sf.ui.proTools.selectedTrackHeaders.forEach(track => { track.trackSelect(); action(track); }); } finally { sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames }); } } function trackFunc(track) { loadFirstUadPlug(); } doForAllSelectedTracks(trackFunc); } catch (error) { log("Error in convertWholeTrack: " + error.message); } } function convertEntireSession() { try { log("Starting entire session conversion"); var proceed = sf.interaction.displayDialog({ buttons: ["Yes", "Cancel"], cancelButton: "Cancel", defaultButton: "Yes", prompt: "You are about to find and replace ALL active instances of UAD with UADx compatible plugins. This may take some time.\n\nAre you sure you want to continue?", title: "Tristan Hoogland's UAD to UADx Converter", }).button; if (proceed !== "Yes") { log("User cancelled session conversion"); return; } ensureEditWindowIsFocused(); saveSession(); saveAsUadx(); hideAllFloatingWindows(); ensureTempoRulerIsVisible(); // Expand all tracks before searching for plugins expandAllTracks(); findAllUadTracks(); function doForAllSelectedTracks(action) { var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames; try { sf.ui.proTools.selectedTrackHeaders.forEach(track => { track.trackSelect(); action(track); }); } finally { sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames }); } } function trackFunc(track) { loadFirstUadPlug(); } doForAllSelectedTracks(trackFunc); sf.ui.proTools.trackDeselectAll(); saveSession(); var reopenSession = sf.interaction.displayDialog({ buttons: ["Yes", "No"], cancelButton: "No", defaultButton: "No", prompt: "UAD to UADx conversion complete!\n\nWould you like to close and reopen the session?", title: "Tristan Hoogland's UAD to UADx Converter", }).button; if (reopenSession === "Yes") { sf.ui.proTools.menuClick({ menuPath: ["File", "Close Session"], }); if (sf.ui.proTools.confirmationDialog.exists) { sf.ui.proTools.confirmationDialog.elementWaitFor(); sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("Save").first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear" }); } sf.keyboard.press({ keys: "cmd+shift+o", }); } } catch (error) { log("Error in convertEntireSession: " + error.message); } } sf.interaction.displayDialog({ prompt: "UAD to UADx Conversion complete!" }); } // Start the script try { main(); } catch (error) { log("Critical error: " + error.message); alert("Critical error occurred: " + error.message); }
Ben Rubin @Ben_Rubin
thanks @Adam_Lilienfeldt, will check it out!
- AIn reply toBen_Rubin⬆:Adam Lilienfeldt @Adam_Lilienfeldt
Hi Tristan!
Is there any chance you'd have time to update this at some point? It seems like this script could be extremely helpful!
As far as I can tell, the current issues lies at the copy/paste functions since the uad UI has changed.
All the best!