Extend all clips by 'x' & Batch Fade using Batch Fade preset (whole timeline)
Reading the below thread I thought I'd found what I was thinking in my head but the code basically batch fades using one of the 6 presets. Even though it does extend the selection (not the clip) but 'x'
I want to;
After selecting a whole timeline of clips
- Extend all clips by 'x'
- Batch Fade all clips using a fade preset.
Before

After

Anyone have any ideas?
Linked from:
- Script that extends each clip in selection by one frame on the head and tail, then applies a two frame fade in and fade out?
- How do you repeat a script until there are no clips left in timeline?
- How to create an "Apply Fade" option that would also extend the handles on both end of a Clip?
- ProTools BG extend and add 1 frame fade
- Extend all clips by 'x' & Batch Fade using Batch Fade preset (whole timeline)
- samuel henriques @samuel_henriques
Hey Jason,
Didn't have time to test it too much, let me know how its working
Set frames to extend and preset number on the lines like this at the end of the script:
trimToFillSelection(10); createFades(1);
Here you go:
function getSessionFormat() { let sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first const isSessionSetupOpen = sessionSetupWin.exists if (!isSessionSetupOpen) { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] }); }; sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first const sessionFormatGroup = sessionSetupWin.groups.whoseTitle.is("Session Format").first const timeCodeRate = +sessionFormatGroup.popupButtons.allItems[2].value.invalidate().value.split(' ')[0]; const sampleRateStaticTextElement = sessionFormatGroup.children.whoseRole.is("AXStaticText").allItems[2].value.invalidate().value.split(' ')[0]; const sampleRate = Number(sampleRateStaticTextElement) * 1000 if (!isSessionSetupOpen) { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] }) }; return { sampleRate, timeCodeRate } }; function copyAllAutomation() { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Copy Special", "All Automation"] }); }; function pasteAllAutomation() { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste Special", "Repeat to Fill Selection"] }); }; /** * @param {number} extendFrames * @param {{ sampleRate: number; timeCodeRate: number; }} sessionFormat */ function trimToFillSelection(sessionFormat, extendFrames) { const extendAmount = Math.round(sessionFormat.sampleRate / sessionFormat.timeCodeRate * extendFrames) const currentSelection = sf.ui.proTools.selectionGetInSamples() sf.ui.proTools.selectionSetInSamples({ selectionStart: +currentSelection.selectionStart - extendAmount, selectionEnd: +currentSelection.selectionEnd + extendAmount, }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Trim Clip", "To Fill Selection"] }); }; /** * @param {1|2|3|4|5} preset */ function createFades(preset) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Fades", "Create..."], }); const batchFadesWin = sf.ui.proTools.windows.whoseTitle.is('Batch Fades').first.elementWaitFor({}, "Batch Fades Win Didn\'t Open.").element batchFadesWin.buttons.whoseTitle.is("Fade Preset Toggle").allItems[preset - 1].elementClick(); batchFadesWin.buttons.whoseTitle.is('OK').first.elementClick(); batchFadesWin.elementWaitFor({ waitType: "Disappear" }, "Batch Fades Win Didn\'t Close.") }; function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); const sessionFormat = getSessionFormat() //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); sf.ui.proTools.clipDoForEachSelectedClip({ action: () => { copyAllAutomation(); trimToFillSelection(sessionFormat, 10); //Set Number of Frames pasteAllAutomation(); createFades(1); // Set Preset Number }, onError: "Continue", }); }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); }; main();
Jason King @Jason_King
Wow. Will try it. Thanks Samuel
Why do you need to set sample and frame rate?
Frame Rates change for us depending on the project.
So I tried it. It kinda works.
- On tracks that are checker-boarded (like above) the start and ends are extended by different amounts ranging from 19frames - 19sec & 9 frames.
- On tracks that have the same region copied to multiple tracks starting in the same spot the start is extended 19 frames and the ends are extended 14 frames.
It seems to shift the grid between timecode and min:sec at different points
I think you're on the right track Samuel
samuel henriques @samuel_henriques
Hello Jason,
Just updated a version that knows sample rate and frame rate so you don't have to set it up.
Can't find a way reproduce that behaviour.
Could you make a screen capture of the script working?
I might spot something.Jason King @Jason_King
Thanks Samuel, the code doesn't seem to work at all now.
See my screen capture.
samuel henriques @samuel_henriques
Hello Jason,
You must copy all script lines starting atfunction getSessionFormat()
Jason King @Jason_King
I have that>
samuel henriques @samuel_henriques
You must delete line 1 and 2.
To set frames and preset is at the end of the script.
Jason King @Jason_King
That was it.
You're a genius Samuel. Works!
So how do you change the amount it it extends the clips and how do you choose the fade preset?
Never mind. It's the same as your original post
Jason King @Jason_King
@samuel_henriques Should I post this as solved? Or do you think the script could be optimised?
samuel henriques @samuel_henriques
I think, if this is what you were looking for, you can mark it. If you find anything in the future that could be improved, you can always come back to this post.
Jason King @Jason_King
Ok cool.
Thanks Samuel. You have saved me hours of time per mix.
Jason King @Jason_King
Wait....
@samuel_henriques one more thing. Can you add the function for all automation follow the extension of the clip?
samuel henriques @samuel_henriques
Sure, updated above.
Jason King @Jason_King
You're a master!
Thanks @samuel_henriques 🤘🏻
- In reply tosamuel_henriques⬆:OOwen Granich-Young @Owen_Granich_Young
@samuel_henriques thanks for making THE version of this script, I have a few clunky ones that have worked with extra manual steps between for this function. Much nicer to have the 'Samuel special' version though!
Bests,
OwenJason King @Jason_King
So good. This is a great script.
- In reply toJason_King⬆:Jason King @Jason_King
Hey @samuel_henriques I just started getting this error.
My code hasn't changed.
function getSessionFormat() { let sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first const isSessionSetupOpen = sessionSetupWin.exists if (!isSessionSetupOpen) { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] }); }; sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first const sessionFormatGroup = sessionSetupWin.groups.whoseTitle.is("Session Format").first const timeCodeRate = +sessionFormatGroup.popupButtons.allItems[2].value.invalidate().value const sampleRateStaticTextElement = sessionFormatGroup.children.whoseRole.is("AXStaticText").allItems[2].value.invalidate().value.split(' ')[0]; const sampleRate = Number(sampleRateStaticTextElement) * 1000 if (!isSessionSetupOpen) { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] }) }; return { sampleRate, timeCodeRate } }; function copyAllAutomation() { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Copy Special", "All Automation"] }); }; function pasteAllAutomation() { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste Special", "Repeat to Fill Selection"] }); }; /** * @param {number} extendFrames * @param {{ sampleRate: number; timeCodeRate: number; }} sessionFormat */ function trimToFillSelection(sessionFormat, extendFrames) { const extendAmount = sessionFormat.sampleRate / sessionFormat.timeCodeRate * extendFrames const currentSelection = sf.ui.proTools.selectionGetInSamples() sf.ui.proTools.selectionSetInSamples({ selectionStart: +currentSelection.selectionStart - extendAmount, selectionEnd: +currentSelection.selectionEnd + extendAmount, }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Trim Clip", "To Fill Selection"] }); }; /** * @param {1|2|3|4|5} preset */ function createFades(preset) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Fades", "Create..."], }); const batchFadesWin = sf.ui.proTools.windows.whoseTitle.is('Batch Fades').first.elementWaitFor({}, "Batch Fades Win Didn\'t Open.").element batchFadesWin.buttons.whoseTitle.is("Fade Preset Toggle").allItems[preset - 1].elementClick(); batchFadesWin.buttons.whoseTitle.is('OK').first.elementClick(); batchFadesWin.elementWaitFor({ waitType: "Disappear" }, "Batch Fades Win Didn\'t Close.") }; function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); const sessionFormat = getSessionFormat() //Get selected tracks const originalTracks = sf.ui.proTools.selectedTrackNames; //Do for each track. sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => { //Select track track.trackSelect(); //Scroll track into View track.trackScrollToView(); sf.ui.proTools.clipDoForEachSelectedClip({ action: () => { copyAllAutomation(); trimToFillSelection(sessionFormat, 5); //Set Number of Frames pasteAllAutomation(); createFades(4); // Set Preset Number }, onError: "Continue", }); }); //Restore previously selected tracks sf.ui.proTools.trackSelectByName({ names: originalTracks }); }; main();
Any ideas?
samuel henriques @samuel_henriques
Hello Jason,
Still works here, the one I had and I tried the one you just posted, they both work the same way.
this is the same behaviour you had when the script looked like this:
Extend all clips by 'x' & Batch Fade using Batch Fade preset (whole timeline) #post-7@Owen_Granich_Young are you getting this error?
- OOwen Granich-Young @Owen_Granich_Young
I haven't been using it. Mostly Cutting ADR right now, next time I'm in BG mode I'll report back.
- In reply tosamuel_henriques⬆:
Jason King @Jason_King
Doesn't work here. Tried it on my work machine and at my home studio. Although it behaves differently with 25fps & 29.
samuel henriques @samuel_henriques
Could you check what you get if you run this part of the code, please?
function getSessionFormat() { let sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first const isSessionSetupOpen = sessionSetupWin.exists if (!isSessionSetupOpen) { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] }); }; sessionSetupWin = sf.ui.proTools.windows.whoseTitle.is("Session Setup").first const sessionFormatGroup = sessionSetupWin.groups.whoseTitle.is("Session Format").first const timeCodeRate = +sessionFormatGroup.popupButtons.allItems[2].value.invalidate().value const sampleRateStaticTextElement = sessionFormatGroup.children.whoseRole.is("AXStaticText").allItems[2].value.invalidate().value.split(' ')[0]; const sampleRate = Number(sampleRateStaticTextElement) * 1000 if (!isSessionSetupOpen) { sf.ui.proTools.menuClick({ menuPath: ["Setup", "Session"] }) }; return { sampleRate, timeCodeRate } }; log(getSessionFormat())
Jason King @Jason_King
samuel henriques @samuel_henriques
Just updated above, can you try, please?
here:
Extend all clips by 'x' & Batch Fade using Batch Fade preset (whole timeline) #post-2Jason King @Jason_King
The original or the one just above here?
A general question though. Why does the script need sample settings? Can we just make it advance frames?
Jason King @Jason_King
@samuel_henriques OK. So.
It works in a 25fps session. BUT not in 23.97fps session
Why does the script need sample settings/session settings? Can't it work just using frames? This making the script faster and also universal.
samuel henriques @samuel_henriques
Hello Jason,
Just updated on my original post: Extend all clips by 'x' & Batch Fade using Batch Fade preset (whole timeline) #post-2
This wasn't a thoroughly tested script so some details weren't taken in consideration. What I fixed yesterday was the decimals in the frame rates with decimals (ex.23.976), it was calculating an impossible number for pro tools to understand. Today I found the drop frame options leave the letters df on the value, that needs to be cleaned.
Why does the script need sample settings/session settings? Can't it work just using frames? This making the script faster and also universal.
The script takes a selection - tc start and tc end - and calculates what is the start minus the frames you input and what is the end plus the frames you input.
The script then calculates the frame duration in samples and applies that duration before and after the selection.
I could build and timecode calculator to figure what is the start/end timecode plus/minus the number of frames you input, and you would still need to know what frame rate you are in.
Unless you want an approximate frames amount to extend, for example decide the frame length is always 1920 samples - witch is only true for 25f 48k session.
A frame at 48k, 23.976 is 2002 samples, for example.Jason King @Jason_King
Jason King @Jason_King
@samuel_henriques do you think it's rock solid now?
samuel henriques @samuel_henriques
Can't say if it's perfect. But let me know if you find something to improve and I'll try to do it.
Jason King @Jason_King
Ok cool.
Thanks Samuel
Jason King @Jason_King
@samuel_henriques is there a way to get the code to not break up clip groups? So the fades created are on any clip groups as well as any single tracks?
This would also speed up the time it takes for the code carry out all its tasks.
samuel henriques @samuel_henriques
I didn't quite get it. Would you like to leave untouched clips or clip groups with fades?
Jason King @Jason_King
Try it. Group some clips and run the code.
The script will fade each clip rather than the grouped clips as a whole.
As you know when you group clips and you use the fade tool to make a fade it fades the whole clip group rather than each clip.
If you could somehow get the script to address grouped clips like the fade tool does it would run much faster for people who use clip groups. Especially for Backgrounds.
samuel henriques @samuel_henriques
Got it, you are correct, this script is doing the process for each clip.
But you would still want to extend the first and last clip, correct?Jason King @Jason_King
Yes. How it is working is fantastic. Don't change anything.
Just wondering if you can add in a feature that if it finds clip groups it fades the clip group rather than the individual clips?
samuel henriques @samuel_henriques
Got it, I'll think about it.
- In reply tosamuel_henriques⬆:OOwen Granich-Young @Owen_Granich_Young
Hey guys, reviving this, it's working, however it's kinda a slow approach, wanted to run an idea by you Sam and see if it could work.
Instead of going clip by clip, by switching grabber tools you could do the function much faster. No idea if this is possible, I was doing this as 2 separate steps before with manual controls between.
Idea would be this:
User highlights selection to be Extend and faded -
Scripts switches to object grabber and re-selects that whole section.
When in object grabber Option - and command + will extend all the self contained regions
Script the switches to Time Grabber (or reselects original selection if they highlighted a larger area)
Triggers Fader preset 1 (which obviously has to be set correctly as before)This is faster because it's not going to every single clip and individually extending them. But I don't know how to get it to reselect with grabber tool or if that's possible at all.
Video of workflow performed manually attached.
Thoughts?samuel henriques @samuel_henriques
excellent idea, try this:
/** * @param {1|2|3|4|5} preset */ function createFades(preset) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Fades", "Create..."] }); const batchFadesWin = sf.ui.proTools.windows.whoseTitle.is('Batch Fades').first; batchFadesWin.elementWaitFor({}, "Batch Fades Win Didn\'t Open."); batchFadesWin.buttons.whoseTitle.is(`Fade Preset Toggle ${preset}`).first.elementClick(); batchFadesWin.buttons.whoseTitle.is('OK').first.elementClick(); batchFadesWin.elementWaitFor({ waitType: "Disappear" }, "Batch Fades Win Didn\'t Close."); }; function nudgeValue() { const nudgeBtn = sf.ui.proTools.mainWindow.gridNudgeCluster.nudgeControls const nudgeValue = nudgeBtn.nudgeValue.invalidate().value.value // If has 3x : it is Timecode if (nudgeValue.split(":").length == 4) { // If not 1 frame, set 1 frame if (!nudgeValue.endsWith("01.00")) sf.ui.proTools.nudgeSet({ value: "00:00:00:01.00" }); } else { nudgeBtn.nudgeValuePopupButton.popupMenuSelect({ menuPath: ["Timecode"], }); sf.ui.proTools.nudgeSet({ value: "00:00:00:01.00" }); } } function extendSelectionOnEitherSide(frameCount) { nudgeValue(); sf.keyboard.press({ keys: 'alt+numpad minus', repetitions: frameCount, fast: true }); sf.keyboard.press({ keys: 'cmd+numpad plus', repetitions: frameCount, fast: true }); }; function getOriginalToolSelection() { // Get original Tools Selection const originalToolSelection = sf.ui.proTools.mainWindow.cursorToolCluster.buttons.filter(btn => btn.title.value == "Smart tool" || btn.title.value == "Trim tool" || btn.title.value == "Selector tool" || btn.title.value.startsWith("Grabber tool") ).filter(btn => btn.value.invalidate().value === "Selected") return originalToolSelection }; function setOriginalToolSelection(originalToolSelection) { ///Set Original Tools Selection originalToolSelection.map(selBtn => selBtn.title.value).indexOf("Smart Tool") > 0 ? originalToolSelection.filter(selBtn => selBtn.title.value === "Smart Tool")[0].elementClick() : originalToolSelection[0].elementClick() }; function setGrabberObjectTool() { const grabberToolToolBtn = sf.ui.proTools.mainWindow.groups.allItems[2].buttons.whoseTitle.startsWith('Grabber tool').first grabberToolToolBtn.elementClick(); grabberToolToolBtn.popupMenuSelect({ isRightClick: true, menuPath: ['Object'] }); }; /** * @param {object} param * @param {number} param.extendFrames * @param {1|2|3|4|5} param.fadesPreset */ function main({ extendFrames, fadesPreset }) { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); // Save tool selection to use at the end const originalToolSelection = getOriginalToolSelection(); // Get selected tracks names const selectedTrackNames = sf.ui.proTools.selectedTrackNames // Select grabber object tool setGrabberObjectTool(); //Select tracks again to so they are selected as object sf.ui.proTools.trackSelectByName({ names: selectedTrackNames }); //Extend clips extendSelectionOnEitherSide(extendFrames); //Select smart tool sf.ui.proTools.toolsSelect({ tool: "Smart" }); //Select tracks again to loose object selection sf.ui.proTools.trackSelectByName({ names: selectedTrackNames }); //Reset pt menus so fades are available sf.keyboard.press({ keys: 'n', repetitions: 2, fast: true }); //Batch fades create createFades(fadesPreset); //Set original tools selection setOriginalToolSelection(originalToolSelection); } main({ extendFrames: 5, fadesPreset: 1 });
- OOwen Granich-Young @Owen_Granich_Young
CLOSE!
Failing on Line 10 and line 12... different times I run it... need a wait for UI element maybe?20.10.2022 18:56:25.14 <info> [Backend]: #StreamDeck: KeyDown (4,2) -> Same Hen Batach Extend and Fade v3 20.10.2022 18:56:25.14 <info> [Backend]: >> Command: Same Hen Batach Extend and Fade v3 [user:cks7wof7200001o102k4hfaq1:cl9hu64t300050110qd6hw6uy] 20.10.2022 18:56:25.29 <info> [Backend]: Mouse current pos is: (1135.98046875, 812.98046875) Right-clicking with mouse here: (404, 63) 20.10.2022 18:56:25.30 <info> [Backend]: Moving back... 20.10.2022 18:56:25.30 <info> [Backend]: Position is now: (1135.98046875, 812.98046875) 20.10.2022 18:56:25.32 <info> [Backend]: PopupMenu full role:AXMenu 20.10.2022 18:56:25.32 <info> [Backend]: Clicking popup menu element: Object 20.10.2022 18:56:26.85 <info> [Backend]: Logging error in action (01) ClickButtonAction: ClickButtonAction requires UIElement 20.10.2022 18:56:26.85 <info> [Backend]: !! Command Error: Same Hen Batach Extend and Fade v3 [user:cks7wof7200001o102k4hfaq1:cl9hu64t300050110qd6hw6uy]: ClickButtonAction requires UIElement (Same Hen Batach Extend and Fade v3: Line 12)
- OOwen Granich-Young @Owen_Granich_Young
Mojave 10.14.6 PT 2021.12
- In reply tosamuel_henriques⬆:
Jason King @Jason_King
This script above doesn't seem to work for me.
- OOwen Granich-Young @Owen_Granich_Young
You can't already be in object grabber (or the batch fade can't trigger), try that Jason. But for me it's still failing at 12, trying to press the preset button for some reason.
samuel henriques @samuel_henriques
Hey guys, needed a few tweaks.
Just updated, please try and let me know how it works for you.- OOwen Granich-Young @Owen_Granich_Young
Line 12 is still sticking for me, but it's still faster then anything else I have to just press 1 and press enter at the end :P
I assume its a PT 2021.12 thing...
samuel henriques @samuel_henriques
try to use the picker on the preset number and replace that line.
depending how you do it you might have to add.elementClick();
at the end- OOwen Granich-Young @Owen_Granich_Young
My computer also melted yesterday so I eneded up having to upgrade to 2022.9, so this comment may be moot anyways.
@Jason_King did you ever get this version working on your end?
- In reply tosamuel_henriques⬆:
Jason King @Jason_King
I've been using the original code above for months now and it saves me a TON of time. I usually select the BG sub (folder) and execute the script so the code works faster as it doesn't have to address each clip one by one; but rather all clips/clip groups. It would be great to be able to select all layers/subgroups and do it all in one pass.
I'll try this new code on Monday. What is the "picker on the preset number"?
But after getting Covid a couple of weeks ago and having to work remotely at home on PT 22.9 & macOS 12.6 the original code above does NOT work at all. It works just fine on PT 21.12.
24.10.2022 10:13:39.100 <info> [Backend]: #App: Activate "com.avid.ProTools" -> Do Nothing (Swallow Input) [cl5j1q2jb0003jn10hxcd8d58] #App: Activate "com.avid.ProTools" -> Mini Configs Page [cl5uhfzy5000oga10uono1e41] 24.10.2022 10:13:39.100 <info> [Backend]: [AxDeckInstance] InstanceShow: user:cl5udjfqw0005ga1043cnw6vj:cl5udjnpy0006ga10fnji4ytb:streamDeckHid.BL52K1B02075.1398bc04-c24d-45a5-b9a7-9cda0b0ce641 (Mini Configs Page) Device: 'BL52K1B02075' [AxDeckInstance] TriggerDraw: user:cl5udjfqw0005ga1043cnw6vj:cl5udjnpy0006ga10fnji4ytb:streamDeckHid.BL52K1B02075.1398bc04-c24d-45a5-b9a7-9cda0b0ce641 (Mini Configs Page) Device: 'BL52K1B02075' [AxStreamDeckDevice id#1] Device 'BL52K1B02075' -> ShowDeckInstance: user:cl5udjfqw0005ga1043cnw6vj:cl5udjnpy0006ga10fnji4ytb:streamDeckHid.BL52K1B02075.1398bc04-c24d-45a5-b9a7-9cda0b0ce641 [AxStreamDeckDevice id#1] DrawInstance. instance 'user:cl5udjfqw0005ga1043cnw6vj:cl5udjnpy0006ga10fnji4ytb:streamDeckHid.BL52K1B02075.1398bc04-c24d-45a5-b9a7-9cda0b0ce641' 24.10.2022 10:13:43.28 <info> [Backend]: #StreamDeck: KeyDown (6,3) -> BG Fade Stretcher Copy 24.10.2022 10:13:43.28 <info> [Backend]: >> Command: BG Fade Stretcher Copy [user:cl5g0p6h3000pzs10l5ghu0h5:cl9hu6g0d0000d310c92wnw8q] Checking for running apps with bundle 'com.avid.ProTools' 24.10.2022 10:13:43.28 <info> [Backend]: NSArray.ArrayFromHandle count = 1 24.10.2022 10:13:43.37 <info> [Backend]: Mouse current pos is: (1048.21875, 364.73828125) Clicking with mouse here: (13, 60) 24.10.2022 10:13:43.37 <info> [Backend]: Moving mouse back to: (1048.21875, 364.73828125) 24.10.2022 10:13:43.38 <info> [Backend]: Position is now: (1048.21875, 364.73828125) 24.10.2022 10:13:43.41 <info> [Backend]: ProTools version: 21.12.0.97 class: PT2021_6 ProTools processID: 1914 24.10.2022 10:13:43.41 <info> [Backend]: ProTools version: 21.12.0.97 class: PT2021_6 ProTools processID: 1914 24.10.2022 10:13:43.65 <info> [Backend]: Mouse current pos is: (1048.21875, 364.73828125) Right-clicking with mouse here: (405, 63) 24.10.2022 10:13:43.65 <info> [Backend]: Moving back... 24.10.2022 10:13:43.66 <info> [Backend]: Position is now: (1048.21875, 364.73828125) 24.10.2022 10:13:43.67 <info> [Backend]: PopupMenu full role:AXMenu 24.10.2022 10:13:43.67 <info> [Backend]: Clicking popup menu element: Object 24.10.2022 10:13:45.74 <info> [Backend]: Still running another command. Wait for its completion. Cmd received: user:cl5g6muun000uzs10gtijx8qo:cl5g6r1zo000xzs104zfhlp32 24.10.2022 10:13:45.74 <info> [Backend]: Still running another command. Wait for its completion. Cmd received: user:cl5g6muun000uzs10gtijx8qo:cl5g6r1zo000xzs104zfhlp32 24.10.2022 10:13:48.00 <info> [Backend]: Logging error in action (01) WaitForElementAction: Element was not found or removed after waiting 2000 ms 24.10.2022 10:13:48.01 <info> [Backend]: !! Command Error: BG Fade Stretcher Copy [user:cl5g0p6h3000pzs10l5ghu0h5:cl9hu6g0d0000d310c92wnw8q]: Batch Fades Win Didn't Open. (BG Fade Stretcher Copy: Line 7) Element was not found or removed after waiting 2000 ms << Command: BG Fade Stretcher Copy [user:cl5g0p6h3000pzs10l5ghu0h5:cl9hu6g0d0000d310c92wnw8q] 24.10.2022 10:13:51.89 <info> [Backend]: [SF_FIREBASE_WS]: Sending keep-alive
Thats on PT 21.12
- SIn reply toJason_King⬆:Steve Bissinger @sbiss2022-10-26 20:47:26.512Z
I am trying to sort through this very long thread and understand how it works. Is there a final version of this that works that someone could post. My understanding of this workflow if that, if I've cut BG's through a reel with hard cuts (no fades) on any clips, this will go through all selected tracks and extend the head/tail a specific amount and apply a batch fade preset to each clip. Is that correct? So the fade preset I would need to set would be in the Batch Fades window? And do I select the tracks or do I need to highlight all the clips I want effected?
- OOwen Granich-Young @Owen_Granich_Young
Hey Steve here's the one I'm using and it's all working.
/** * @param {1|2|3|4|5} preset */ function createFades(preset) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Fades", "Create..."] }); const batchFadesWin = sf.ui.proTools.windows.whoseTitle.is('Batch Fades').first; batchFadesWin.elementWaitFor({}, "Batch Fades Win Didn\'t Open."); batchFadesWin.buttons.whoseTitle.is(`Fade Preset Toggle ${preset}`).first.elementClick(); batchFadesWin.buttons.whoseTitle.is('OK').first.elementClick(); batchFadesWin.elementWaitFor({ waitType: "Disappear" }, "Batch Fades Win Didn\'t Close."); }; function nudgeValue() { const nudgeBtn = sf.ui.proTools.mainWindow.gridNudgeCluster.nudgeControls const nudgeValue = nudgeBtn.nudgeValue.invalidate().value.value // If has 3x : it is Timecode if (nudgeValue.split(":").length == 4) { // If not 1 frame, set 1 frame if (!nudgeValue.endsWith("01.00")) sf.ui.proTools.nudgeSet({ value: "00:00:00:01.00" }); } else { nudgeBtn.nudgeValuePopupButton.popupMenuSelect({ menuPath: ["Timecode"], }); sf.ui.proTools.nudgeSet({ value: "00:00:00:01.00" }); } } function extendSelectionOnEitherSide(frameCount) { nudgeValue(); sf.keyboard.press({ keys: 'alt+numpad minus', repetitions: frameCount, fast: true }); sf.keyboard.press({ keys: 'cmd+numpad plus', repetitions: frameCount, fast: true }); }; function getOriginalToolSelection() { // Get original Tools Selection const originalToolSelection = sf.ui.proTools.mainWindow.cursorToolCluster.buttons.filter(btn => btn.title.value == "Smart tool" || btn.title.value == "Trim tool" || btn.title.value == "Selector tool" || btn.title.value.startsWith("Grabber tool") ).filter(btn => btn.value.invalidate().value === "Selected") return originalToolSelection }; function setOriginalToolSelection(originalToolSelection) { ///Set Original Tools Selection originalToolSelection.map(selBtn => selBtn.title.value).indexOf("Smart Tool") > 0 ? originalToolSelection.filter(selBtn => selBtn.title.value === "Smart Tool")[0].elementClick() : originalToolSelection[0].elementClick() }; function setGrabberObjectTool() { const grabberToolToolBtn = sf.ui.proTools.mainWindow.groups.allItems[2].buttons.whoseTitle.startsWith('Grabber tool').first grabberToolToolBtn.elementClick(); grabberToolToolBtn.popupMenuSelect({ isRightClick: true, menuPath: ['Object'] }); }; /** * @param {object} param * @param {number} param.extendFrames * @param {1|2|3|4|5} param.fadesPreset */ function main({ extendFrames, fadesPreset }) { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); // Save tool selection to use at the end const originalToolSelection = getOriginalToolSelection(); // Get selected tracks names const selectedTrackNames = sf.ui.proTools.selectedTrackNames // Select grabber object tool setGrabberObjectTool(); //Select tracks again to so they are selected as object sf.ui.proTools.trackSelectByName({ names: selectedTrackNames }); //Extend clips extendSelectionOnEitherSide(extendFrames); //Select smart tool sf.ui.proTools.toolsSelect({ tool: "Smart" }); //Select tracks again to loose object selection sf.ui.proTools.trackSelectByName({ names: selectedTrackNames }); //Reset pt menus so fades are available sf.keyboard.press({ keys: 'n', repetitions: 2, fast: true }); //Batch fades create createFades(fadesPreset); //Set original tools selection setOriginalToolSelection(originalToolSelection); } main({ extendFrames: 1, fadesPreset: 3 });
And your understanding of the workflow is correct you will need to make your batchfade preset correct. In my case I want to extend all one frame and drop two frame fades throughout and not mess with existing crossfade lengths so my preset looks like this:
you highlight a selection of clips in order for it to work on them. Selecting a track only will do nothing.
Hope that helps!
Owen- SSteve Bissinger @sbiss2022-10-26 23:48:20.453Z
Thanks! I'm getting a consistent error though...line 10. I'm a pretty basic coder so this code is a bit above my head. Not sure how to figure out the error. Any ideas?
- In reply toOwen_Granich_Young⬆:
Jason King @Jason_King
As I mentioned above this code doesn't work with PT 21.12.
AND the original code above works with PT 21.1 but NOT with PT 22.9 (Current).
- SSteve Bissinger @sbiss2022-10-27 00:12:48.670Z
Ah! Sorry for not seeing that. Well that's a bummer. Anyway, thanks for your quick reply.