My goal with this script is to render each clip in a selection with an audiosuite plugin, in my case with Nugen LMCorrect2.
So it acts lika a batch normalization. I have found some useful text snippet that I glued together but I recognized a strange behaviour using the function sf.ui.proTools.clipDoForEachSelectedClip()
.
The scripts cycles clip by clip through the section but only the first one gets rendered. The following ones only gets analyzed. I have create a video of the behaviour.
https://www.dropbox.com/s/xl1bkh9e6p4viw7/Batch_LmCorrect2.mov?dl=0
// open NUGEN LMCorrect2
var asWin = sf.ui.proTools.getAudioSuiteWindow("LMCorrect2");
if (!asWin.exists) {
asWin = sf.ui.proTools.audioSuiteOpenPlugin({
category: 'Sound Field',
name: 'NUGEN LMCorrect2'
}).window;
}
// wait for Audiosuite plugin to appear
sf.ui.proTools.firstAudioSuiteWindow.elementWaitFor({
waitType: "Appear",
});
// load preset
asWin.audioSuiteSelectPreset({
presetMenuPath: ["EBU-R128-23LUFS-3TP"]
});
// set options
asWin.audioSuiteSetOptions({
processingInputMode: "EntireSelection",
processingOutputMode: "CreateContinuousFile"
});
// set input mode
sf.ui.proTools.firstAudioSuiteWindow.popupButtons.whoseTitle.is('input mode').first.popupMenuSelect({
menuPath: ["multi-input mode"]
});
// audio suite procees function.
// Analyze -> Wait until it is done -> Render
function analyzeAndRenderWithLMCorrect2() {
sf.engine.checkForCancellation();
asWin.getFirstWithTitle("Analyze").elementClick();
sf.ui.proTools.waitForNoModals();
asWin.audioSuiteRender();
}
//
sf.ui.proTools.mainCounterDoWithValue({
targetValue: 'Samples',
action: () => {
var oldSelection = sf.ui.proTools.selectionGetInSamples();
try {
//analyzeAndRenderWithLMCorrect2();
sf.ui.proTools.clipDoForEachSelectedClip({
action: analyzeAndRenderWithLMCorrect2,
});
} finally {
sf.ui.proTools.selectionSetInSamples({
selectionStart: oldSelection.selectionStart,
selectionLength: oldSelection.selectionLength
});
}
}
});
I get an error message in line 45 that says 'DoMainCounterAction'.
Can someone help me out with this batch?
- Stefan Möhl @Stefan_Mohl
I'm already one step ahead. The clips must be real files and not edited clips. Then the batch conversion works for each clip but not on each pass. Sometimes it is working sometimes it only analyzes and then jumps to the next clip without rendering. Is this a timing issue?
It would be great if this would also work with edited clips that are cut at the front and back.
Can I find some documention how exactly does the functionsf.ui.proTools.clipDoForEachSelectedClip({ action: myfunction});
work?
Meanwhile I have edited my script by creating real duplicate files with handle lenght set to 0 before the next step.I am not sure if this workflow make sense but it would be wonderful to have a batch converter in-the-box in ProTools.
sf.ui.proTools.appActivateMainWindow(); // create real files var asWinDuplicate = sf.ui.proTools.getAudioSuiteWindow("Duplicate"); if (!asWinDuplicate.exists) { asWinDuplicate = sf.ui.proTools.audioSuiteOpenPlugin({ category: "Other", name: "Duplicate", }).window; } // wait for Audiosuite plugin to appear sf.ui.proTools.firstAudioSuiteWindow.elementWaitFor({ waitType: "Appear", }); //Change processing modes asWinDuplicate.audioSuiteSetOptions({ processingInputMode: "ClipByClip", processingOutputMode: "CreateIndividualFiles" }); //Select Handle Length sf.ui.proTools.firstAudioSuiteWindow.textFields.whoseTitle.is('Processing Handle Length in Seconds').first.elementClick(); //Change Value to 0 sf.keyboard.type({ text: "0", }); //Press Enter/Return sf.keyboard.press({ keys: "return", }); asWinDuplicate.audioSuiteRender(); sf.ui.proTools.waitForNoModals(); asWinDuplicate.windowClose(); sf.ui.proTools.firstAudioSuiteWindow.elementWaitFor({ waitType: "Disappear", }); /**Start Nugen */ // open NUGEN LMCorrect2 var asWin = sf.ui.proTools.getAudioSuiteWindow("LMCorrect2"); if (!asWin.exists) { asWin = sf.ui.proTools.audioSuiteOpenPlugin({ category: 'Sound Field', name: 'NUGEN LMCorrect2' }).window; } // wait for Audiosuite plugin to appear sf.ui.proTools.firstAudioSuiteWindow.elementWaitFor({ waitType: "Appear", }); // load preset asWin.audioSuiteSelectPreset({ presetMenuPath: ["EBU-R128-23LUFS-3TP"] }); // set options asWin.audioSuiteSetOptions({ processingInputMode: "EntireSelection", processingOutputMode: "CreateContinuousFile" }); // set input mode sf.ui.proTools.firstAudioSuiteWindow.popupButtons.whoseTitle.is('input mode').first.popupMenuSelect({ menuPath: ["multi-input mode"] }); // audio suite procees function. // Analyze -> Wait until it is done -> Render function analyzeAndRenderWithLMCorrect2() { sf.engine.checkForCancellation(); asWin.getFirstWithTitle("Analyze").elementClick(); sf.ui.proTools.waitForNoModals(); asWin.audioSuiteRender(); } sf.ui.proTools.mainCounterDoWithValue({ targetValue: 'Samples', action: () => { var oldSelection = sf.ui.proTools.selectionGetInSamples(); try { //analyzeAndRenderWithLMCorrect2(); sf.ui.proTools.clipDoForEachSelectedClip({ action: analyzeAndRenderWithLMCorrect2, }); } finally { sf.ui.proTools.selectionSetInSamples({ selectionStart: oldSelection.selectionStart, selectionLength: oldSelection.selectionLength }); } } }); /* sf.ui.proTools.clipDoForEachSelectedClip({ action: analyzeAndRenderWithLMCorrect2, }); */
Christian Scheuer @chrscheuer2020-07-12 23:05:23.296Z
Hi Stefan
I saw your post and was gonna comment. The clipDoForEachSelectedClip action works with a variety of half-sufficient information from Pro Tools and tries to patch it together to form a whole. This works reliably for 80-90% of cases but not for all corner cases.
Building something that works for all corner cases, including all types of fades in and out, cross-fades, with and without margin from fade to clip boundaries, and with or without empty space between clips - is not currently supported by the function. It only works for most cases right now.We will hopefully update the action to be more controllable in the future, but for now, simply due to the lack of information from Pro Tools, it has its limits. You could try to replace it with your own logic, that might be easier to get going for the specific use cases you're mostly encountering. But again, it's a rabbit hole to go down trying to build something that works for all types of clips, since there simply is not enough info available yet to always determine what the selection contains.
Stefan Möhl @Stefan_Mohl
Hi Christian,
thanks for your feedback.I updated the script and added two lines after analyze and render and check if the process window disappeared. This seems to work stable after some testing.
https://www.dropbox.com/s/ksb9r92yiyo34z7/Batch_LmCorrect2_v2.mov?dl=0Only after finishing all processing I still get an error message from Soundflow:
DoMainCounterAction
I assume it is as you mentioned the lack of information from ProTools.
Can I catch this exception in my script.Here is the code
/* This script renders all clips in a track with NUGEN´s LMCorrect2 with a user preset called "EBU-R128-23LUFS-3TP" Works only on files, cutted clips and group slips without fades */ /**Start Nugen */ // open NUGEN LMCorrect2 var asWin = sf.ui.proTools.getAudioSuiteWindow("LMCorrect2"); if (!asWin.exists) { asWin = sf.ui.proTools.audioSuiteOpenPlugin({ category: 'Sound Field', name: 'NUGEN LMCorrect2' }).window; } // wait for Audiosuite plugin to appear sf.ui.proTools.firstAudioSuiteWindow.elementWaitFor({ waitType: "Appear" }); // load preset asWin.audioSuiteSelectPreset({ presetMenuPath: ["EBU-R128-23LUFS-3TP"] }); // set options asWin.audioSuiteSetOptions({ processingInputMode: "EntireSelection", processingOutputMode: "CreateContinuousFile" }); // set input mode sf.ui.proTools.firstAudioSuiteWindow.popupButtons.whoseTitle.is('input mode').first.popupMenuSelect({ menuPath: ["multi-input mode"] }); // audio suite procees function. // Analyze -> Wait until it is done -> Render function analyzeAndRenderWithLMCorrect2() { sf.engine.checkForCancellation(); asWin.getFirstWithTitle("Analyze").elementClick(); sf.ui.proTools.waitForNoModals(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); asWin.audioSuiteRender(); sf.ui.proTools.waitForNoModals(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } sf.ui.proTools.mainCounterDoWithValue({ targetValue: 'Samples', action: () => { var oldSelection = sf.ui.proTools.selectionGetInSamples(); try { //analyzeAndRenderWithLMCorrect2(); sf.ui.proTools.clipDoForEachSelectedClip({ action: analyzeAndRenderWithLMCorrect2, }); } finally { sf.ui.proTools.selectionSetInSamples({ selectionStart: oldSelection.selectionStart, selectionLength: oldSelection.selectionLength }); } } }); /* sf.ui.proTools.clipDoForEachSelectedClip({ action: analyzeAndRenderWithLMCorrect2, }); */
Do I need to switch the main counter to samples. I saw that code snippet on another script and copied it to my script or is it ok to use just the last two lines in the comments. In my tests I can see any differences.
Is it possible to get the number of selected clips in a track with a specific function? If this is possible I could be a loop with the number of clips.
The functionsf.ui.proTools.clipGetSpottingInfo().
gives a lot of information but I can´t find a return value for the amount.Christian Scheuer @chrscheuer2020-07-15 01:59:51.014Z
You can add a
onError: 'Continue'
property to yourmainCounterDoWithValue
action to swallow the error, if you want.Christian Scheuer @chrscheuer2020-07-15 02:00:15.715Z
Is it possible to get the number of selected clips in a track with a specific function? If this is possible I could be a loop with the number of clips.
No, not at this time. You're running the best version of this that we have right now.
Christian Scheuer @chrscheuer2020-07-15 02:01:02.984Z
Do I need to switch the main counter to samples. I saw that code snippet on another script and copied it to my script or is it ok to use just the last two lines in the comments. In my tests I can see any differences.
I don't think you manually need to do this, no. But your code looks great as it is now, so I wouldn't remove it either.
Code that ensures stability is generally good.- In reply tochrscheuer⬆:
Stefan Möhl @Stefan_Mohl
Hi Christian,
I found a way to get the clip count of a selection
// make sure clip list is visible if (sf.ui.proTools.getMenuItem('View','Other Displays','Clip List').isMenuChecked == false) { sf.ui.proTools.menuClick({ menuPath: ["View","Other Displays","Clip List"], }); } // get clip cout from selection .-) finally var selectedClipRows = sf.ui.proTools.mainWindow.clipListView.getElements('AXSelectedRows'); var numClips = Number(selectedClipRows.count) log (numClips);
- In reply toStefan_Mohl⬆:Stefan Möhl @Stefan_Mohl
I updated the script and it works like charm.
https://www.dropbox.com/s/1xxrgoeycb3iw9d/Batch_LmCorrect2_v3.mov?dl=0
Mandatory for the script is that I assume we don´t have fades on each clip. It also checks if tab to transinet is off and the clip list is visible. I use it for e.g on final mixes that have to be delivered to -23 LUFS level in Germany./* Batch converter with NUGEN LMCorrect2 DESC: This script analyzes each clip in a selection on a track and analzes and render each track with NUGEN LMCorrect2 Audiosuite plugin. The clip can be real files,cutted clip or group clips. MANDATORY: 1. No Fades on each clip */ sf.ui.proTools.appActivateMainWindow(); // place the cursor BEFORE the clips ou like to render /* var strClips = prompt("How many clips do you want to render?", "1"); if (!strClips) throw 0; */ /**Start Nugen */ // open NUGEN LMCorrect2 var asWin = sf.ui.proTools.getAudioSuiteWindow("LMCorrect2"); if (!asWin.exists) { asWin = sf.ui.proTools.audioSuiteOpenPlugin({ category: 'Sound Field', name: 'NUGEN LMCorrect2' }).window; } // wait for Audiosuite plugin to appear sf.ui.proTools.firstAudioSuiteWindow.elementWaitFor({ waitType: "Appear" }); // load preset asWin.audioSuiteSelectPreset({ presetMenuPath: ["EBU-R128-23LUFS-3TP"] }); // set options asWin.audioSuiteSetOptions({ processingInputMode: "EntireSelection", processingOutputMode: "CreateContinuousFile" }); // set input mode sf.ui.proTools.firstAudioSuiteWindow.popupButtons.whoseTitle.is('input mode').first.popupMenuSelect({ menuPath: ["multi-input mode"] }); // make sure tabtoTransient is off if (sf.ui.proTools.getMenuItem('Options', 'Tab to Transient').isMenuChecked == true) { sf.ui.proTools.menuClick({ menuPath: ["Options", "Tab to Transient"], }); } // make sure clip list is visible if (sf.ui.proTools.getMenuItem('View','Other Displays','Clip List').isMenuChecked == false) { sf.ui.proTools.menuClick({ menuPath: ["View","Other Displays","Clip List"], }); } // get clip cout from selection .-) finally var selectedClipRows = sf.ui.proTools.mainWindow.clipListView.getElements('AXSelectedRows'); var numClips = Number(selectedClipRows.count) log (numClips); // save last selection //Set main Counter to samples view for sample accuracy sf.ui.proTools.mainCounterSetValue({ targetValue: 'Samples' }); var oldSelection = sf.ui.proTools.selectionGetInSamples(); for (var i = 0; i < numClips; i++) { sf.keyboard.press({ keys: "ctrl+tab" }); analyzeAndRenderWithLMCorrect2(); }; // audio suite procees function. // Analyze -> Wait until it is done -> Render function analyzeAndRenderWithLMCorrect2() { sf.engine.checkForCancellation(); asWin.getFirstWithTitle("Analyze").elementClick(); sf.ui.proTools.waitForNoModals(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); asWin.audioSuiteRender(); sf.ui.proTools.waitForNoModals(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", }); } // restore selection sf.ui.proTools.selectionSetInSamples({ selectionStart: oldSelection.selectionStart, selectionLength: oldSelection.selectionLength }); //Set main Counter back to Timecode view sf.ui.proTools.mainCounterSetValue({ targetValue: 'Timecode' });
Christian Scheuer @chrscheuer2020-07-16 10:02:51.798Z
AWESOME! Thanks for sharing :)
- SIn reply toStefan_Mohl⬆:Sergio PinkNoise @Sergio_PinkNoise
Great script, thanks for sharing!
Now that Nugen has the option "Copy Source to Target" I´m trying this script but matching Clips on one track to the ones on the other track.
Let´s say you´ve got a track with original files (VO) and, on the lower track, you´ve got the dubbed version that need to be matched to the VO.
The logic it´s pretty easy: select VO clip> analyze it>Copy souce to target>select the clip below>analyze>Render.
Then you could write the code to: go up+select next clip, etc...by using "press key" for commands on PT (ctrl+tab, P, semicolon...) so you could process a batch.The problem with that, is the step for "Copy Source to Target". I´ve tried to get that button by picking it using "Click UI Element" , since the button is inside the plugin interface and has no external button, the message I get is: "sf.ui.proTools.firstAudioSuiteWindow.groups.whoseTitle.is('PluginView').first.elementClick();". So no button is picked (PluginView)
I´ve also tried the "mouse position" combined with "mouse click" but same result.Any thoughts?
Here´s a video in order to make myself clear :):
https://vimeo.com/461351064Thanks!
- In reply toSergio_PinkNoise⬆:SSergio PinkNoise @Sergio_PinkNoise
Here´s a not vey clean solution :):
sf.ui.proTools.appActivateMainWindow();
var selectedClipRows = sf.ui.proTools.mainWindow.clipListView.getElements('AXSelectedRows');
var numClips = Number(selectedClipRows.count)
log(numClips);var selectedClipRows = sf.ui.proTools.mainWindow.clipListView.getElements('AXSelectedRows');
var numClips = Number(selectedClipRows.count)
log(numClips);for (var i = 0; i < numClips; i++) {
sf.keyboard.press({ keys: "tab,p,ctrl+tab", }); sf.ui.proTools.firstAudioSuiteWindow.buttons.whoseTitle.is('Analyze').first.elementClick(); sf.ui.proTools.waitForNoModals(); sf.mouse.setPosition({ position: { "x": 223, "y": 257 }, }); sf.mouse.click({ position: { "x": 223, "y": 257 }, }); sf.keyboard.press({ keys: "alt+tab, semicolon, ctrl+tab", }); sf.ui.proTools.firstAudioSuiteWindow.buttons.whoseTitle.is('Analyze').first.elementClick(); sf.ui.proTools.waitForNoModals(); sf.ui.proTools.firstAudioSuiteWindow.buttons.whoseTitle.is('Render').first.elementClick();