By TK_Delay @TK_Delay
Hello to the collective knowledge.
I'm trying to write a toggle script where I cut a clip from a track, insert it into an "AUTOMATOR" track and set automation modalities (Toggle Action 1).
Then I want to write the automation in Toggle 2 and insert the clip into the original track.
Toggle 1 works perfectly. But in Toggle 2 it doesn't work to put the clip back onto its original track.
Any idea for a solution?
// Define the plugin and track names from the event properties.
const { pluginName, trackName } = event.props;
/// Store the originally selected track names into a variable before any actions change the selection
const originalSelectedTracks = sf.ui.proTools.selectedTrackNames
// Check if the global state is undefined, which means this is the first toggle. Set it to 1 (initial state).
if (globalState.INSAutoA === undefined) {
globalState.INSAutoA = 1;
}
/////////////////////////////////////////// TOGGLE ACTION 1 ////////////////////////////////////////////////////////////
else if (globalState.INSAutoA === 1)
{
// Activate the main window of Pro Tools to ensure focus.
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.mainWindow.invalidate();
// Enable automation preview mode (this allows automation changes to be previewed without being written).
sf.ui.proTools.automationPreview();
// Cut the selected clip from the current track.
// It's important that this happens before switching tracks so the clip can be pasted later.
sf.keyboard.press({
keys: "cmd+x",
});
// Make the PFX Cutter Tracks visible by opening the track search function.
sf.keyboard.press({
keys: "cmd+alt+f",
});
// Type in the search text to find the "AUTOMATOR" track.
sf.keyboard.type({
text: "AUTOMATOR",
});
// Press Enter to select the track.
sf.keyboard.press({
keys: "numpad enter",
});
// Select the "AUTOMATOR" track to make it the active track.
sf.ui.proTools.trackGetByName({ name: "AUTOMATOR", makeVisible: true }).track.trackSelect();
// Paste the previously cut clip into the "AUTOMATOR" track and confirm the action with the "e" key.
sf.keyboard.press({
keys: "cmd+v, e",
});
/**
* Function to open a plugin on the given track.
* @param {{ trackName?: string, pluginName: string }} args
*/
function openPlugin({ trackName, pluginName: targetPluginName }) {
let insertIndex; // Will hold the index of the plugin on the track.
// Ensure the Pro Tools window is updated to reflect changes.
sf.ui.proTools.mainWindow.invalidate();
// Get the track by name or fall back to the currently selected track if no name is provided.
const track = trackName
? sf.ui.proTools.trackGetByName({ name: trackName }).track
: sf.ui.proTools.selectedTrack;
// Manually fetch the insert buttons (avoiding issues with hidden tabs) for inserts A-E and F-J.
const insertButtons = function () {
const insertButtonsAE = track.groups.whoseTitle.is("Inserts A-E").first.children.whoseTitle.startsWith("Insert Assignment").map(ib => ib);
const insertButtonsFJ = track.groups.whoseTitle.is("Inserts F-J").first.children.whoseTitle.startsWith("Insert Assignment").map(ib => ib);
return [...insertButtonsAE, ...insertButtonsFJ];
}();
// Find the plugin by its name in the inserts of the track.
const pluginNames = insertButtons.map(ib => ib.value.value);
pluginNames.find((pluginName, i) => {
if (pluginName.includes(targetPluginName)) {
insertIndex = i; // Save the index of the plugin.
return true;
}
});
// If the plugin is not found in any inserts, throw an error.
if (insertIndex === undefined) {
throw `No insert with the name "${targetPluginName}" found on track "${track.normalizedTrackName}".`;
}
// Check if the plugin window is already open.
const pluginWindow = sf.ui.proTools.windows.whoseTitle.startsWith(`Plug-in: ${targetPluginName}`).first;
if (pluginWindow.exists) {
// If the window is already open, toggle the bypass and bring the window to the front.
if (pluginWindow.buttons.whoseTitle.is("Effect Bypass").first.exists) {
pluginWindow.buttons.whoseTitle.is("Effect Bypass").first.elementClick();
}
// Bring the plugin window to the front.
pluginWindow.elementRaise();
} else {
// If the plugin window is not already open, click the insert button to open it.
track.insertButtons[insertIndex].elementClick();
// Wait for the plugin window to appear.
const pluginWin = sf.ui.proTools.windows.whoseTitle.startsWith(`Plug-in: ${targetPluginName}`).waitFor().element;
// Toggle the bypass of the plugin (enable/disable).
pluginWin.buttons.whoseTitle.is("Effect Bypass").first.elementClick();
// Click the target button to bring the plugin into focus (optional step depending on workflow).
pluginWin.buttons.whoseTitle.is("Target button").first.elementClick();
}
}
openPlugin({
trackName: trackName, // Optional: provide track name.
pluginName: pluginName // Use the defined plugin name.
});
// Show a notification to the user that automation is now in preview mode.
sf.interaction.notify({
title: "--== AUTOMATION PREVIEW ==--",
});
globalState.INSAutoA = 2; // Update global state to indicate the next action will be Toggle Action 2.
}
///////////////////////////////////////////// END OF TOGGLE ACTION 1 //////////////////////////////////////
///////////////////////////////////////////// TOGGLE ACTION 2 ////////////////////////////////////////////////////////////
else if (globalState.INSAutoA === 2)
{
// Activate the main window to ensure focus is on Pro Tools.
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.mainWindow.invalidate();
// Check if a clip is selected by reading the selection length.
var startTime = sf.ui.proTools.mainWindow.counterDisplay.textFields.whoseTitle.is("Edit Selection Length").first;
// If no selection is made, log an error message and stop the script.
if (startTime.invalidate().value.value == "00:00:00:00") {
log("No clip selected", startTime.invalidate().value.value);
throw (0);
} else {
// Write all changed automation data to the selected area.
sf.ui.proTools.automationWriteAutoToSelectionAndClear({
autoConfirmation: true,
});
// Close the plugin window if it is open.
sf.ui.proTools.floatingWindows.whoseTitle.startsWith("Plug-in: " + pluginName).allItems.forEach(function (win) {
try { win.windowClose(); } catch (err) { }
});
// Cut the clip from the "AUTOMATOR" track.
sf.keyboard.press({
keys: "e, cmd+a, cmd+x",
});
// Select the originally selected track(s) using the previously stored track names.
sf.ui.proTools.trackSelectByName({ names: originalSelectedTracks });
// Make the original track visible and select it.
sf.ui.proTools.trackGetByName({ name: originalSelectedTracks, makeVisible: true }).track.trackSelect();
// Paste the clip back into the original track.
sf.keyboard.press({
keys: "cmd+v",
});
// Show a notification that automation is back to normal (no preview mode).
sf.interaction.notify({
title: "--== AUTOMATION NORMAL ==--",
});
log(originalSelectedTracks);
globalState.INSAutoA = 1; // Reset global state to 1, ready for the next cycle.
}
}
////////////////////////////////////////////////// END OF TOGGLE ACTION 2 ////////////////////////////////////////////////////
- TTK_Delay @TK_Delay
This slightly shorter script works so far.
But only if I insert the clip twice in line 38.
Strange...sf.ui.proTools.appActivate(); /// Get Selected track names to variable const originalSelectedTracks = sf.ui.proTools.selectedTrackNames sf.keyboard.press({ keys: "cmd+x", }); // Make the PFX Cutter Tracks visible by opening the track search function. sf.keyboard.press({ keys: "cmd+alt+f", }); // Type in the search text to find the "AUTOMATOR" track. sf.keyboard.type({ text: "AUTOMATOR", }); // Press Enter to select the track. sf.keyboard.press({ keys: "numpad enter", }); sf.ui.proTools.trackGetByName({ name: "AUTOMATOR", makeVisible: true }).track.trackSelect(); sf.keyboard.press({ keys: "cmd+v, cmd+c", }); // Select track by name using variable selectedTracks sf.ui.proTools.trackSelectByName({ names: originalSelectedTracks }) sf.ui.proTools.selectedTrack.trackScrollToView(); sf.keyboard.press({ keys: "cmd+v, cmd+v", });
- TIn reply toTK_Delay⬆:TK_Delay @TK_Delay
Solution:
/////////////////////////////////////// INSERT Automation via AUTOMATOR-Track TOGGLE ///////////////////////////////////////////////////////////////// /** * Toggle Action 1: Save the currently selected track * Activate PREVIEW * Check if a clip is selected * Cut the selected clip(s) and paste them onto the "AUTOMATOR" track * Open Insert on the track and wait for the plugin window to appear * Toggle the Insert bypass (On/Off) * Display notification "--== AUTOMATION PREVIEW ==--" * * Toggle Action 2: If no selection is made, abort the script. * Write all changed automation data into the selection area and deactivate PREVIEW * Close the plugin window * Cut the selected clip(s) and paste them back onto the original track * Display notification "--== AUTOMATION NORMAL ==--" */ // Define the plugin and track names from the event properties. const { pluginName, trackName } = event.props; // Check if the global state is undefined, which means this is the first toggle. Set it to 1 (initial state). if (globalState.INSAutoA === undefined) { globalState.INSAutoA = 1; } /////////////////////////////////////////// TOGGLE ACTION 1 //////////////////////////////////////////////////////////// else if (globalState.INSAutoA === 1) { // Check if a clip is selected by reading the selection length. var startTime = sf.ui.proTools.mainWindow.counterDisplay.textFields.whoseTitle.is("Edit Selection Length").first; // If no selection is made, log an error message and stop the script. if (startTime.invalidate().value.value == "00:00:00:00") { log("No clip selected", startTime.invalidate().value.value); throw (0); } else { // Save the originally selected tracks. const selectedTrackName = sf.ui.proTools.selectedTrackNames[0]; globalState.selectedTracks = selectedTrackName; // Activate the main Pro Tools window to ensure correct focus. sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); // Activate automation preview mode. sf.ui.proTools.automationPreview(); // Cut the selected clip. sf.keyboard.press({ keys: "cmd+x", }); // Open the track search function. sf.keyboard.press({ keys: "cmd+alt+f", }); // Type "AUTOMATOR" to find the track. sf.keyboard.type({ text: "AUTOMATOR", }); // Select the track by pressing Enter. sf.keyboard.press({ keys: "numpad enter", }); // Select the "AUTOMATOR" track to make it active. sf.ui.proTools.trackGetByName({ name: "AUTOMATOR", makeVisible: true }).track.trackSelect(); // Paste the previously cut clip onto the "AUTOMATOR" track and confirm with "e". sf.keyboard.press({ keys: "cmd+v, e", }); /** * Function to open a plugin on the specified track. * @param {{ trackName?: string, pluginName: string }} args */ function openPlugin({ trackName, pluginName: targetPluginName }) { let insertIndex; // Store the index of the plugin on the track. // Refresh the Pro Tools window to reflect changes. sf.ui.proTools.mainWindow.invalidate(); // Get the track either by name or use the currently selected track. const track = trackName ? sf.ui.proTools.trackGetByName({ name: trackName }).track : sf.ui.proTools.selectedTrack; // Manually retrieve Insert buttons for A-E and F-J to avoid tabs. const insertButtons = function () { const insertButtonsAE = track.groups.whoseTitle.is("Inserts A-E").first.children.whoseTitle.startsWith("Insert Assignment").map(ib => ib); const insertButtonsFJ = track.groups.whoseTitle.is("Inserts F-J").first.children.whoseTitle.startsWith("Insert Assignment").map(ib => ib); return [...insertButtonsAE, ...insertButtonsFJ]; }(); // Search for the plugin in the track's Insert. const pluginNames = insertButtons.map(ib => ib.value.value); pluginNames.find((pluginName, i) => { if (pluginName.includes(targetPluginName)) { insertIndex = i; // Store the plugin's index. return true; } }); // If the plugin is not found, throw an error. if (insertIndex === undefined) { throw `No Insert found with the name "${targetPluginName}" on track "${track.normalizedTrackName}".`; } // Check if the plugin window is already open. const pluginWindow = sf.ui.proTools.windows.whoseTitle.startsWith(`Plug-in: ${targetPluginName}`).first; if (pluginWindow.exists) { // If the window is already open, toggle the bypass and bring the window to the foreground. if (pluginWindow.buttons.whoseTitle.is("Effect Bypass").first.exists) { pluginWindow.buttons.whoseTitle.is("Effect Bypass").first.elementClick(); } // Bring the plugin window to the foreground. pluginWindow.elementRaise(); } else { // If the plugin window is not open, click the Insert button to open it. track.insertButtons[insertIndex].elementClick(); // Wait for the plugin window to appear. const pluginWin = sf.ui.proTools.windows.whoseTitle.startsWith(`Plug-in: ${targetPluginName}`).waitFor().element; // Toggle the plugin's bypass (enable/disable). pluginWin.buttons.whoseTitle.is("Effect Bypass").first.elementClick(); // Click the Target button to focus the plugin (optional). pluginWin.buttons.whoseTitle.is("Target button").first.elementClick(); } } // Open the FabFilter Pro-Q 3 plugin on the "AUTOMATOR" track. openPlugin({ pluginName: pluginName }); // Show a notification that automation is now in preview mode. sf.interaction.notify({ title: "--== AUTOMATION PREVIEW ==--", }); globalState.INSAutoA = 2; } } ///////////////////////////////////////////// END OF TOGGLE ACTION 1 ////////////////////////////////////// ///////////////////////////////////////////// TOGGLE ACTION 2 //////////////////////////////////////////////////////////// else if (globalState.INSAutoA === 2) { // Activate the main window to ensure focus is on Pro Tools. sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); // Check if a clip is selected by reading the selection length. var startTime = sf.ui.proTools.mainWindow.counterDisplay.textFields.whoseTitle.is("Edit Selection Length").first; // If no selection is made, log an error message and stop the script. if (startTime.invalidate().value.value == "00:00:00:00") { log("No clip selected", startTime.invalidate().value.value); throw (0); } else { // Write all changed automation data to the selected area. sf.ui.proTools.automationWriteAutoToSelectionAndClear({ autoConfirmation: true, }); // Close the plugin window if it is open. sf.ui.proTools.floatingWindows.whoseTitle.startsWith("Plug-in: " + pluginName).allItems.forEach(function (win) { try { win.windowClose(); } catch (err) { } }); // Cut the clip from the "AUTOMATOR" track. sf.keyboard.press({ keys: "e, cmd+a, cmd+x", }); /// SET Selected Tracks /** @param {{trackName:string}} obj */ function scrollToTrack({ trackName }) { sf.ui.proTools.appActivateMainWindow(); var originalClipboardText = sf.clipboard.getText().text || ''; sf.ui.proTools.menuClick({ menuPath: ["Track", "Scroll to Track..."], }); sf.ui.proTools.confirmationDialog.elementWaitFor(); sf.clipboard.setText({ text: trackName, }); sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Paste'] }); sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("OK").first.elementClick(); sf.clipboard.setText({ text: originalClipboardText, }); } scrollToTrack({ trackName: globalState.selectedTracks }); // Paste the clip back into the original track. sf.keyboard.press({ keys: "cmd+v", }); // Show a notification that automation is back to normal (no preview mode). sf.interaction.notify({ title: "--== AUTOMATION NORMAL ==--", }); globalState.INSAutoA = 1; // Reset global state to 1, ready for the next cycle. } } ////////////////////////////////////////////////// END OF TOGGLE ACTION 2 ////////////////////////////////////////////////////