Title
ClipBeGone (delete when clips shorter than length).
What do you expect to happen when you run the script/macro?
This script is for clearing clips shorter than 8000 samples long, as they are created accidentally by my editing workflow and are time consuming to find manually. I expect the script to select each clip, to create a variable of selectionLength, and to do a comparison of var
Are you seeing an error?
What happens when you run this script?
Everything seems to work properly regarding moving through each clip on the timeline in my track. However, the clips under 8000 samples are not deleted. These lines seem to be ignored or not valid:
if (cliplength <= 8000) {
sf.keyboard.press({ keys: 'delete' });
}}
But there is no error, and the function carries on.
How were you running this script?
I used a keyboard shortcut within the target app
How important is this issue to you?
3
Details
{ "inputExpected": "This script is for clearing clips shorter than 8000 samples long, as they are created accidentally by my editing workflow and are time consuming to find manually. I expect the script to select each clip, to create a variable of selectionLength, and to do a comparison of varSource
sf.keyboard.press({ keys: "cmd+a, alt+shift+h", }); sf.wait({ intervalMs: 32, }); sf.ui.proTools.windows.whoseTitle.is("Space Clips").first.popupButtons.first.popupMenuSelect({ menuPath: ["Samples"], }); sf.keyboard.type({ text: "24000", }); sf.wait({ intervalMs: 256, }); sf.keyboard.press({ keys: "return", }); sf.wait({ intervalMs: 32, }); function checkClipLengths() { sf.ui.proTools.clipSelectNextFullClip(); sf.wait({ intervalMs: 32, }); var cliplength = sf.ui.proTools.selectionGetInSamples().selectionLength; sf.wait({ intervalMs: 32, }); if (cliplength <= 8000) { sf.keyboard.press({ keys: 'delete' }); }} sf.wait({ intervalMs: 64, }); sf.ui.proTools.clipDoForEachClipInTrack({ action: clip => checkClipLengths() });
Links
User UID: hMEBO84NZbXqVbqYJzU5ZyTNHGN2
Feedback Key: sffeedback:hMEBO84NZbXqVbqYJzU5ZyTNHGN2:-NEwLfatgH9yjU4yEIZ1
- Brenden @nednednerb
By the way, everything above the "function" is an attempted work around to try spacing the clips then doing the function. It seems to do the same thing with or without, and the clip does not delete.
A fancy aspect to this, is before I created the function to make the operation repeat through EachClipInTrack, the script worked when tested and selected the NextFullClip, deleted it, and did not carry on. Making it carry on, something happened.
I forget what else changed since that one moment!
- In reply tonednednerb⬆:Raphael Sepulveda @raphaelsepulveda2022-10-21 21:39:13.289Z2022-10-21 22:33:07.230Z
Hey @nednednerb,
Give this a shot:
sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); sf.ui.proTools.mainCounterDoWithValue({ targetValue: "Samples", action: () => sf.ui.proTools.clipDoForEachClipInTrack({ action: () => { const cliplength = sf.ui.proTools.selectionGet().selectionLength; if (cliplength <= 8000) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Clear"] }); } } }) });
Brenden @nednednerb
Hi, that works perfectly.
Now I am curious why mine almost worked but didn't quite delete. Even if my code was more cumbersome, I'd be highly interested in understanding where I went wrong and why your solution was foolproof. I pieced together some tutorials and I'm very much a javascript newb.
Understanding where my script went wrong and how I could fix it, even if not optimal, would be good for learning.
By the way, while waiting for your response, I got my script to this point:
function checkClipLengths() { sf.ui.proTools.clipSelectNextFullClip(); sf.wait({ intervalMs: 32, }); var clipLength = sf.ui.proTools.selectionGetInSamples().selectionLength; sf.wait({ intervalMs: 128, }); if (clipLength < 8000) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Clear"] }); } else { log("error") } } sf.wait({ intervalMs: 64, }); sf.ui.proTools.clipDoForEachClipInTrack({ action: clip => checkClipLengths() });
When I run this version, I got 3 errors. Which since I ran the macro with 3 long clips and only 1 clip 1600 samples long, It is seeming to say my variable and comparison were true once, but I did not get the delete.
Very interesting...
Raphael Sepulveda @raphaelsepulveda2022-10-21 22:30:41.026Z
Yeah, no problem.
The main thing messing with your script is
sf.ui.proTools.clipSelectNextFullClip();
.
That line is not necessary sincesf.ui.proTools.clipDoForEachClipInTrack()
is already going through each clip for you.Below is your script with the things it doesn't need commented out. You were very close!
function checkClipLengths() { // sf.ui.proTools.clipSelectNextFullClip(); // sf.wait({ // intervalMs: 32, // }); var clipLength = sf.ui.proTools.selectionGetInSamples().selectionLength; // sf.wait({ // intervalMs: 128, // }); if (clipLength < 8000) { sf.ui.proTools.menuClick({ menuPath: ["Edit", "Clear"] }); } /* else { log("error") } */ } // sf.wait({ // intervalMs: 64, // }); sf.ui.proTools.clipDoForEachClipInTrack({ action: () => checkClipLengths() });
A couple pointers for future reference:
- Start your scripts with these two lines to avoid a myriad of bugs
sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate();
- Avoid keyboard shortcuts. Use
sf.ui.proTools.menuClick();
to find a menu item equivalent, when possible!
Brenden @nednednerb
Hi Raphael,
Thank you for your pointers. Regarding
.menuClick()
that makes total sense. I was having some issues with UI clicks and KeyPresses that needed Wait time and could be a bit "click or miss", Using Menu options seems to make more sense for items which exist on the menu! I can see there could still need to be Wait time for some options here, and some places where UI clicks are needed but less optimal.The other pointer you make regarding appActivateMainWindow and invalidate:
As a guess, even when Finder might be focused on PT, maybe some Audiosuite plug-in etc is open, or some other dialog or input field is active, the first line about appActivateMainWIndow sounds like it focuses on the Edit Window.However, I am less clear on mainWindow.invalidate. It sounds like invalidate on a sf.ui call means some kind of "clearing" of some other parameter.
If you know of a lengthier article or another thread which gets into explaining to add these two lines in more detail, please share a link and happily be lazy about responding at length here
: )
Raphael Sepulveda @raphaelsepulveda2022-10-24 23:36:23.787Z
I can see there could still need to be Wait time for some options here, and some places where UI clicks are needed but less optimal.
Yes, best practices is to implement dynamic waits—using
elementWaitFor()
—instead of static ones—sf.wait()
;
For example, the snippet below clicks on the output button of the selected track using UI automation and waits for the output window to show up:sf.ui.proTools.selectedTrack.outputPathButton.elementClick(); sf.ui.proTools.mainTrackOutputWindow.elementWaitFor({ waitType: "Appear" });
Doing it this way eliminates any issues that span from wait time inconsistencies.
You can search the forum forelementWaitFor()
to see how it's used across more situations!
appActivateMainWIndow sounds like it focuses on the Edit Window.
It makes PT the focused application by simulating a click on the top left corner of the main window. In PT this could be either the Edit or Mix window, whichever is upfront.
Some actions can act unexpectedly and fail if we don't make sure that PT is focused.
A usual situation that comes to mind is the one where you're testing out a script/macro you're working on and you trigger it by clicking on the "Run Command" button on the SoundFlow editor.
When you do that, SF is still the focused app as the script is starting, so things can get hairy, especially if the script starts with something like keyboard simulation lol
By addingsf.ui.proTools.appActivateMainWindow();
you're making sure PT will be in the ideal state to accept automation from SF.
I am less clear on mainWindow.invalidate. It sounds like invalidate on a sf.ui call means some kind of "clearing" of some other parameter.
The best thread to read about invalidation in length is this one.
The TLDR is, usesf.ui.proTools.mainWindow.invalidate();
to clear SF's Edit window cache and make sure it's working with current data.Brenden @nednednerb
Raphael,
Your advice and details are incredibly helpful. Taking such time between your Team members and Ambassadors to help these
onBoarders() {
thisFeat !=an easy feat
;
}
hah!I've come back to your last post a few times to understand more each time. Thanks again for being very helpful. Good model of operations. I'm still enjoying the free trial, but SoundFlow has definitely earned me as a customer. I've actually been imagining Pro Tools automation since long before hearing about SoundFlow. It's such a natural fit for my workflows. Some parts need my attention to unique details, other parts are routines of 50 of the same steps each and every time! I can see this learning curve will always be worth its cost in saving time and many types of "energy."
Raphael Sepulveda @raphaelsepulveda2022-10-26 19:09:32.627Z
Awesome to hear! Always happy to help 🤘🏼