Desired Workflow
I would like to be able to create a macro for this process. Either creating a 1 frame beep every 1 second for a total of 3 times and have the new file end where my cursor is currently located.
Or
Use a precreated file called "Varible" (in this case "Beeps_3s") and from the workspace, search for the file, right click it and spot to current edit insertion point. Then "Control + Command" click it to move the end of the file to the start. I firgured out how to open Workspace, but I can't seem to click the search field in the workspace.
Question
See the "desired workflow" for a better description of what I'm aiming for. But essential I'd like to either create beeps or place a premade beep file at the current edit insertion point and then "control + command" click the file to move the end to where the file starts. Which workflow would work better? I'm new to programming so my script is rather underwhelming as I can only figure out how to open the workspace window, but. I can't seem to get past this step. Also I am new to the platform so I apologieze if any of the info is redundant or incomplete.
Command Info
ID: user:default:ckes2a0qn000k4v10ewdkx30i
Name: ADR Tone
Source
sf.ui.proTools.menuClick({
menuPath: ["Window", "New Workspace", "Default"]
})
if sf.ui.proTools.appActivateMainWindow({}) == "Workspace: Volumes"
sf.ui.proTools.elementClick({ "text entry area"})
Links
User UID: ufhmuj54Gub8GcCObOqrsT5G2D13
Feedback Key: sffeedback:ufhmuj54Gub8GcCObOqrsT5G2D13:-MGb4i9WK8Cq7yescm3-
- Walter Everton @WalterEverton
Ok, so a quick update, I did figure out in a macro how to select the search field in Workspaces (I think), but I can't seem to type in it. Here is the updated script, if it helps anyone.
sf.ui.proTools.menuClick({ menuPath: ["Window", "New Workspace", "Default"] }); sf.ui.proTools.windows.whoseTitle.is('Workspace: Search In Volumes').first.textFields.whoseTitle.is('text search').first.elementClick(); sf.keyboard.type({ text: "Beeps_3s", }); sf.keyboard.press({ keys: "return", }); sf.ui.proTools.popupMenuSelect({ "Beeps_3s.wav" }):
Side note, how do I paste scripts into a reply? It definately doesn't look right.
Christian Scheuer @chrscheuer2020-09-07 09:05:24.021Z
To paste scripts into the forum, make a line with three backticks:
```
before and after the script code :)To make a search in the Workspace, you can do something like this:
var win = sf.ui.proTools.windows.whoseTitle.startsWith('Workspace:').first; win.elementWaitFor(); win.elementRaise(); win.textFields.whoseTitle.is('text search').first.mouseClickElement(); sf.keyboard.type({ text: "Beeps_3s", }); sf.keyboard.press({ keys: "return", });
However, since we'll have to wait for the search to complete before being able to right click and spot it, I'm not sure if that's the best way to do it in SF.
Christian Scheuer @chrscheuer2020-09-07 09:13:32.773Z
If you wanna wait for a result to appear in the workspace and spot the first file, something like this could work.
I'm not sure how stable this will be though.function spotToEditInsertion(timeout = 5000) { var start = (new Date).valueOf(); while (true) { var table = sf.ui.proTools.windows.whoseTitle.startsWith('Workspace:').first.tables.whoseTitle.is('TextGridView').allItems[3]; var rows = table.childrenByRole('AXRow'); if (rows.length >= 1) { rows[0].children.first.popupMenuSelect({ isRightClick: true, menuPath: ['Spot to Edit Insertion'], }); break; } var now = (new Date).valueOf(); if (now - start >= timeout) throw 'Could not find file in time'; sf.wait({ intervalMs: 500, }); } } spotToEditInsertion();
Walter Everton @WalterEverton
Ya you are correct Christian, it isn't terribly stable. It's having trouble opening the popup menu. Since I know what the path is maybe that would be a better way to navigate to it in workspace? I'm going to think on it and see if I can come up with something and post back here.
Walter Everton @WalterEverton
So some progress made. However I have to be in ProTool for the pop-up menu to work properly. So when I assigned a test button to my Stream Deck I was able to have the script run all the way through to spotting the clip to the timeline (assuming I have selected the place it needs to go obviously).
The next challenge is to "control + command" click the file that was just spotted to the edit insert location. Any ideas on how that would be accomplished? I can't seem to find the UI element via the accessibility inspector so I have no idea how to accomplish this.
menuPath: ["Window", "New Workspace", "Default"] }); sf.ui.proTools.windows.whoseTitle.is('Workspace: Volumes').first.tables.whoseTitle.is('TextGridView').allItems[1].children.whoseRole.is("AXColumn").whoseTitle.is('TTextGridView_Column ').first.children.whoseRole.is("AXRow").whoseValue.is('# 0 row Workspace. ').first.children.whoseRole.is("AXCell").first.children.whoseRole.is("AXStaticText").whoseTitle.is('Sound Libraries').first.elementClick(); function spotToEditInsertion(timeout = 50000) { var start = (new Date).valueOf(); while (true) { var table = sf.ui.proTools.windows.whoseTitle.startsWith('Workspace:').first.tables.whoseTitle.is('TextGridView').allItems[3]; var rows = table.childrenByRole('AXRow'); if (rows.length >= 1) { rows[0].children.first.popupMenuSelect({ isRightClick: true, menuPath: ['Spot to Edit Insertion'], }); break; } var now = (new Date).valueOf(); if (now - start >= timeout) throw 'Could not find file in time'; sf.wait({ intervalMs: 500, }); } } spotToEditInsertion(); var win = sf.ui.proTools.windows.whoseTitle.startsWith('Workspace:').first; sf.wait({ intervalMs: 100 }); sf.ui.proTools.waitForNoModals(); win.windowClose(); /*sf.keyboard.modifiers({ isControl: true, isCommand: true, });*/
Christian Scheuer @chrscheuer2020-09-08 05:42:05.821Z
Hi Walter,
I think we need to look at this wholly differently in order to get something that will work reliably. SoundFlow has some built-in internal support for spotting files directly to the timeline that I think could be leveraged.
And even if we didn't use that approach, I think using length and timecode/samples information about where to position the clip(s) on your timeline would be far superior to using control+command to try to click on the clips. The reason for the latter being that we can't read where clips are located visually on the timeline.Can you help us zoom back a little bit and show us a screenshot of how you'd like the beeps to end up on the timeline vs. where your cursor is originally? I think using Workspace is never going to be stable, so I'd rather help you come up with a solution that will work more reliably.
Christian Scheuer @chrscheuer2020-09-08 05:46:23.754Z
Oh, I see your original post now.
This here will be much more stable to implement directly:Either creating a 1 frame beep every 1 second for a total of 3 times and have the new file end where my cursor is currently located.
There are 2 good ways to do this IMO. Either 1) generate this file every time (will always work but is a bit slow and means a lot of small beep files will end up in your session), or, 2) have a pre-generated countdown file already positioned somewhere in the session on the same track where you need it, for example on 10:00:00:00 or something like that. Then, the script would:
- Remember where you are
- Go to 10:00:00:00 and select the countdown clip
- Copy it
- Go back to where you were, backing up the length of the countdown clip
- Paste it
This would be fast and reliable.
Walter Everton @WalterEverton
I like your second suggestion. I'll give it a shot and report back.
Christian Scheuer @chrscheuer2020-09-08 06:37:29.020Z
Awesome :)
This should do it - assuming the "Beeps" track is called "Beeps" and that there's a 3 second long beep file at 10:00:00:00 on that track.
Note this script even supports that you have a different track selected when you start the script.//Remember current track selection var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames.slice(); //Remember where we are var originalSelection = sf.ui.proTools.selectionGetInSamples(); try { //Make sure to select track Beeps sf.ui.proTools.trackSelectByName({ names: ['Beeps'], deselectOthers: true }); //Go to 10:00:00:00 and select 3 seconds worth of beeps sf.ui.proTools.selectionSet({ selectionStart: '10:00:00:00', selectionLength: '00:00:03:00', }); //Edit->Copy sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Copy'], looseMatch: true }); //Go back to where we were, minus 3 seconds sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(originalSelection.selectionStart) - 48000 * 3, selectionLength: 0, }); //Edit->Paste sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Paste'], looseMatch: true }); //Collapse selection to the right sf.keyboard.press({ keys: 'up' }); } finally { //Restore original track selection sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames, deselectOthers: true }); }
Walter Everton @WalterEverton
OMG thank you so much this helps alot. HOWEVER, sadly this isn't working. When I click run in Soundflow, my StreamDeck button assigned to this script, or the keybinding (just incase something wasn't workign quite right) nothing happens when I run the script. And in reviewing you script, I wonder if the remeber were we are part of the script makes sense. Won't this be location dependent? So wouldn't it make more sense to do something like
var CurrentLocation = sf.ui.proTools.mainWindow.groups.whoseTitle.is('Counter Display Cluster')
and getting/reading the value of the Main Counter in that diplay cluster (I could have the name of the UI element wrong though, having trouble pinning it down with the UI element selector. This picture may help, its the Acces. Inspector in OSX.Christian Scheuer @chrscheuer2020-09-08 07:07:10.819Z
Hi Walter
The built-in SoundFlow functions I use here have much deeper integration than directly reading the Counter Display Cluster, so no need to resort to that.
But it's odd it doesn't work for you - the script works just fine on my end. Here you can see it in action:Christian Scheuer @chrscheuer2020-09-08 07:10:23.774Z
FWIW this wouldn't work if you try to run it when PT is not in focus. To ensure PT is in focus, ie. when wanting to run it from "Run Command" button in SF, always start the script with:
sf.ui.proTools.appActivateMainWindow();
I don't really get why you wouldn't see any result of the script at all though. It isn't really the type of script that would silently fail.
Walter Everton @WalterEverton
Ya it's strange, I'll keep that in mind when I run from SF. Thanks for writing that script for me. I definitely still feel a bit overwhelmed by my lack of knowledge of JavaScript. But seeing examples is helping :).
Christian Scheuer @chrscheuer2020-09-08 07:32:38.026Z
:)
If you haven't already walked through the Learning SoundFlow tutorials here, they're great - in particular the last 2 are interesting for UI automation.
Typically, learning scripts is best done by making macros and then converting them to scripts.Walter Everton @WalterEverton
Yep I have learned that over this weekend. Thanks again Christian! (Oh also btw if you haven't seen it there are some bugs in the script, however they aren't deal breaking so it will work very well in it's current state, I made a post below about it).
- In reply tochrscheuer⬆:
Walter Everton @WalterEverton
Lol ok, when I copied and pasted your script it didn't copy a ";" at the end so that is why nothing happened. Thank you Christian for your help!
Christian Scheuer @chrscheuer2020-09-08 07:18:53.654Z
Yay!! Success :D Awesome - thanks for a great chat on how to best implement it!
- In reply tochrscheuer⬆:
Walter Everton @WalterEverton
Hey Christian, I wanted to mention a couple of things while I have been testing the script over the past few minuets. None of these are game changers but they are odd.
1 - As I think it is normal behavior. The script makes ProTools switch to samples to preform some calculations, and then copies and pastes the file to the sample location. However for some reason that location seems to be 144samples off (in the positive direction). I think if it is remaining consistent it'll be an easy off set however it is curious it is happening at all.2 - The track agnostic starting location doesn't seem to be working, I have to make sure I'm in the track that has the beeps in it. But beyond that it doesn't seems to matter which track I'm in. This is kinda nice though, because that means I can rename beeps to correspond to actors names and create tracks for them. But that being said the original script isn't working as intended. But could it be changes to just use the track that starts with "Beeps" and ignore the rest of the name?
Walter Everton @WalterEverton
144 sample error fixed like this. Still am not sure why its happening, but this offsets it.
sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(originalSelection.selectionStart) - 48000 * 3 - 144, selectionLength: 0, });
- In reply toWalterEverton⬆:
Christian Scheuer @chrscheuer2020-09-08 07:47:11.454Z
The calculation will go from wherever you are originally positioned and calculate/move 48000 * 3 samples to the left of that, so the script is assuming you're on 48 kHz. Make sure to check your file is exactly 144000 samples long (ie. 3 full seconds). It may be that if you're on drop frame or otherwise fractional timecode that this number needs to be adjusted, and I can see 144 samples off as being exactly 1/1000 off, so maybe it just needs to be offset by that as you suggest.
The track agnostic starting location doesn't seem to be working, I have to make sure I'm in the track that has the beeps in it.
Try to explain what happens when you don't. Can you notice anything different in your setup from my video? In my video you can see it moving to the "Beeps" track and back. Do you have link track and edit selection on?
Christian Scheuer @chrscheuer2020-09-08 07:48:45.882Z
And yea, you should be able to just remove the two trackSelectByName calls to let it operate on the currently selected track instead if you prefer.
- In reply tochrscheuer⬆:
Walter Everton @WalterEverton
I mean other than my MANY more tracks I don't see anything different from your session. Other than that behavior not working on my end of jumping to the beeps track and back.
I bet you that is it. I'm working in 23.98 so that is 24 drop frame.
Edit: I should have just looked before I replied. Ya that is why the offset was needed, the file was too long by 144 samples. Once fixed the script will function properly in that respect.Christian Scheuer @chrscheuer2020-09-08 08:02:07.309Z
Hm ok. Is the "Beeps" track called exactly Beeps?
You say it's not working - can you describe that in more detail? What actually happens?
"Not working" is an extremely broad definition. Can you screen record it?Walter Everton @WalterEverton
How would you make sure that "Link track...." is checked? I can toggle it, but what if it already is enabled. Then this script just toggles it off and then on again making it useless.
menuPath: ["Options","Link Track and Edit Selection"], });
- In reply tochrscheuer⬆:
Walter Everton @WalterEverton
This is what I came up with, but it's not working. I assume I wrote something wrong.
//Make sure Link Track and Edit Selection is checked if ( sf.ui.proTools.getMenuItem('Options', 'Link Track and Edit Selection').isMenuChecked) sf.ui.proTools.menuClick({ menuPath: ["Options", "Link Track and Edit Selection"], }) ) else (); //Remember current track selection var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames.slice(); //Remember where we are var originalSelection = sf.ui.proTools.selectionGetInSamples(); try { //Make sure to select track Beeps -- //does not seem to be working, you must select track that has your beeps in it first sf.ui.proTools.trackSelectByName({ names: ['Beeps'], deselectOthers: true }); //Go to 00:00:00:00 and select 3 seconds worth of beeps sf.ui.proTools.selectionSet({ selectionStart: '00:00:00:00', selectionLength: '00:00:03:00', }); //Edit->Copy sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Copy'], looseMatch: true }); //Go back to where we were, minus 3 seconds sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(originalSelection.selectionStart) - 48000 * 3 - 144, selectionLength: 0, }); //Edit->Paste sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Paste'], looseMatch: true }); //Collapse selection to the right sf.keyboard.press({ keys: 'up' }); } finally { //Restore original track selection sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames, deselectOthers: true }); }; sf.ui.proTools.menuClick({ menuPath: ["Options", "Link Track and Edit Selection"], });
Christian Scheuer @chrscheuer2020-09-08 08:49:31.395Z
Nice.
I would write it like this:
//Ensure Link Track and Edit Selection is ON var wasLinked = sf.ui.proTools.getMenuItem('Options', 'Link Track and Edit Selection').isMenuChecked; if (!wasLinked) { sf.ui.proTools.menuClick({ menuPath: ["Options", "Link Track and Edit Selection"], }); } //Remember current track selection var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames.slice(); //Remember where we are var originalSelection = sf.ui.proTools.selectionGetInSamples(); try { //Make sure to select track Beeps sf.ui.proTools.trackSelectByName({ names: ['Beeps'], deselectOthers: true }); //Go to 10:00:00:00 and select 3 seconds worth of beeps sf.ui.proTools.selectionSet({ selectionStart: '10:00:00:00', selectionLength: '00:00:03:00', }); //Edit->Copy sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Copy'], looseMatch: true }); //Go back to where we were, minus 3 seconds sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(originalSelection.selectionStart) - 48000 * 3, selectionLength: 0, }); //Edit->Paste sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Paste'], looseMatch: true }); //Collapse selection to the right sf.keyboard.press({ keys: 'up' }); } finally { //Restore original track selection sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames, deselectOthers: true }); //Restore Link Track and Edit selection if (!wasLinked) { sf.ui.proTools.menuClick({ menuPath: ["Options", "Link Track and Edit Selection"], }); } }
Walter Everton @WalterEverton
Perfect! This one does it! Again I cannot thank you enough for your help Christian.
- In reply tochrscheuer⬆:
Walter Everton @WalterEverton
And I got the track jumping fixed by linking track and edit selection. You are correct again. So no problems with the script! Just the user! :) I knew I was doing something wrong.
- In reply tochrscheuer⬆:
Walter Everton @WalterEverton
Sure thing, I'd be happy to go at this another way. The Workspace way was feeling very cluncky, and not well thought out.
- In reply toWalterEverton⬆:Walter Everton @WalterEverton
Update to this code. This now searches for any track that starts with "Beeps" in the track name. So make sure you don't have tracks labeled beeps that you don't want the script to find. This also fixes the issue where the script wouldn't run correctly because tracks were stored in cache (or something along those lines).
//Clear the track Cache sf.ui.proTools.mainWindow.invalidate(); //Ensure Link Track and Edit Selection is ON var wasLinked = sf.ui.proTools.getMenuItem('Options', 'Link Track and Edit Selection').isMenuChecked; if (!wasLinked) { sf.ui.proTools.menuClick({ menuPath: ["Options", "Link Track and Edit Selection"], }); } //Remember current track selection var originallySelectedTrackNames = sf.ui.proTools.selectedTrackNames.slice(); //Remember where we are var originalSelection = sf.ui.proTools.selectionGetInSamples(); try { //Make sure to select track Beeps const trackName = sf.ui.proTools.trackNames.filter(n => n.startsWith('Beeps'))[0]; if (!trackName) throw `Couldn't find a track starting with "Beeps"`; sf.ui.proTools.trackSelectByName({ names: [trackName] }); //Go to 00:00:00:00 and select 3 seconds worth of beeps sf.ui.proTools.selectionSet({ selectionStart: '00:00:00:00', selectionLength: '00:00:03:00', }); //Edit->Copy sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Copy'], looseMatch: true }); //Go back to where we were, minus 3 seconds sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(originalSelection.selectionStart) - 48000 * 3, selectionLength: 0, }); //Edit->Paste sf.ui.proTools.menuClick({ menuPath: ['Edit', 'Paste'], looseMatch: true }); //Collapse selection to the right sf.keyboard.press({ keys: 'up' }); } finally { //Restore original track selection sf.ui.proTools.trackSelectByName({ names: originallySelectedTrackNames, deselectOthers: true }); //Restore Link Track and Edit selection //Ensure Link Track and Edit Selection is ON if (!wasLinked) { sf.ui.proTools.menuClick({ menuPath: ["Options", "Link Track and Edit Selection"], }); } }