I guess you'll have to do that with the "Get Selection" action and then do JavaScript magic.
(The solution has a bonus to extend the automation of a selection by 1 sec.)
Linked from:
Kitch Membery @Kitch2020-07-24 20:54:24.237ZHi Danny,
Can you explain your full workflow? As there may be a better way to achieve what you are after. The more detail the better. :-)
Rock on!
In reply toDanny_van_Spreuwel⬆:Danny @Danny_van_SpreuwelI have a selection. Most of the time this selection is made by double clicking a clip. To write automation with a bit of slack before and after the selection I extend the selection and then write the automation.
Kitch Membery @Kitch2020-07-24 22:25:49.004ZI see.. One more quick question before I answer... Is your main counter set to "Mins:sec"?
- In reply toDanny_van_Spreuwel⬆:
Kitch Membery @Kitch2020-07-24 22:31:31.046ZIf your "Main Counter" is in Mins:Secs mode then this should do the trick;
function extendSelection() { const originalSelection = sf.ui.proTools.selectionGet(); const counterValue = sf.ui.proTools.mainWindow.counterDisplay.mainCounter.value.invalidate().value; let clipStartPoint = originalSelection.selectionStart; let clipEndtPoint = originalSelection.selectionEnd; function timeAdjust(selectionTime) { let startTime = { mins: selectionTime.split(':')[0], secs: selectionTime.split(':')[1].split('.')[0], ms: selectionTime.split('.')[1], } return { start: startTime.mins + ':' + (Number(startTime.secs) - 1) + '.' + startTime.ms, end: startTime.mins + ':' + (Number(startTime.secs) + 1) + '.' + startTime.ms, } } sf.ui.proTools.selectionSet({ selectionStart: timeAdjust(clipStartPoint).start, selectionEnd: timeAdjust(clipEndtPoint).end, }); } extendSelection();
Dustin Harris @Dustin_HarrisOhh that is lovely. .split(“:”)[x] is so much nicer than a bunch of .slice(x,y). I’ll be updating a bunch of scripts in the morning :)
- In reply toKitch⬆:
Danny @Danny_van_SpreuwelWow. Thank you for this script. My main counter is set to TC. Does that make the calculation more complicated? I can image that subtracting 1 sec of a TC 01:00:00:00 would be a challenge.
Kitch Membery @Kitch2020-07-25 08:51:47.161ZYes and I think the same thing might occur in my script above. I did not think of that scenario. I may need a few days to think about it. Sorry bout that Danny.
Danny @Danny_van_SpreuwelNo need for sorry. You already made a fantastic first draft in a zippy.
Maybe we need to use Pro Tools to do the time calculation. Meaning that we might need to skip the JavaScript and use keyboard keys to enter the selection fields. I thought it would be more safer to dive into JavaScript instead of the key simulations.
What I found, and also reported to the SoundFlow company, is that I think Pro Tools changed the way of working of the calculation method in the selection fields. The default "select between macros" action isn't working properly anymore in PT 2020.5. When entering a timecode in the selection field ("/") and use "+ 2 0 0 / " it doesn't automatically calculates anymore. You need to "enter" first and then go to the next field with "/". Unfortunately after the "enter" command the cursor exits the selection fields.
Andrew Scheps @Andrew_SchepsI have a feeling the better way to do this is check the session's sample rate and then you can easily add 1 second's worth of samples to either side of the selection no matter what time format you like to display. And if you always work at one sample rate then you can just set a constant and don't have to open the session setup window to look.
Kitch Membery @Kitch2020-07-25 22:06:50.741ZGood call!
Andrew Scheps @Andrew_SchepsSomething like:
const oneSec = 48000; var selection = sf.ui.proTools.selectionGetInSamples(); sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(selection.selectionStart) - oneSec, selectionEnd: Number(selection.selectionStart) + oneSec });
Kitch Membery @Kitch2020-07-25 22:11:37.701ZBam!!!!
- In reply toAndrew_Scheps⬆:
Kitch Membery @Kitch2020-07-25 22:14:51.355ZSmall correction;
The selectioinEnd was calculating from the selectionStart.
const oneSec = 48000; var selection = sf.ui.proTools.selectionGetInSamples(); sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(selection.selectionStart) - oneSec, selectionEnd: Number(selection.selectionEnd) + oneSec });
Andrew Scheps @Andrew_SchepsDuh, thanks for fixing!
Kitch Membery @Kitch2020-07-25 22:19:26.305ZYour global thinking solved the riddle!
- In reply toKitch⬆:
Danny @Danny_van_SpreuwelKitch and Andrew, this is fantastic. Great work guys. My script of extending the selection and write automation would be something like this:
var selection = sf.ui.proTools.selectionGetInSamples(); sf.keyboard.press({ keys: "shift+slash", }); sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(selection.selectionStart) - oneSec, selectionEnd: Number(selection.selectionEnd) + oneSec }); sf.ui.proTools.menuClick({ menuPath: ["Edit","Automation","Write to All Enabled"], }); sf.keyboard.press({ keys: "shift+slash", });
Danny @Danny_van_SpreuwelMmmm, how do you get that fancy code formatting in your post?
Kitch Membery @Kitch2020-07-25 22:32:12.702ZCheck this post regarding formatting.
https://forum.soundflow.org/-1468#post-9
- In reply toDanny_van_Spreuwel⬆:
Kitch Membery @Kitch2020-07-25 22:33:10.523ZNice one. What does "Shift+Slash" do?
Danny @Danny_van_SpreuwelIt links and breaks the Timeline and Edit selection.
Kitch Membery @Kitch2020-07-25 22:38:13.022ZIs it activating or deactivating the the "Link timeline and Edit Selection" in this script?
Danny @Danny_van_SpreuwelIt's deactivating. Actually the shift-slash toggles this mode. In most cases the link is activated. Otherwise you need to check first what the status is of this function.
Kitch Membery @Kitch2020-07-25 22:50:17.668Z2020-07-25 23:01:55.375ZGotya! It's best to replace the key press with UI scripting for stability :-)
So... To activate;
const btn = sf.ui.proTools.mainWindow.cursorToolCluster.buttons.whoseTitle.is('Link Timeline and Edit Selection').first; //This will activate the button if (btn.value.invalidate().value !== 'Selected') { btn.elementClick(); }&
To inactive;
const btn = sf.ui.proTools.mainWindow.cursorToolCluster.buttons.whoseTitle.is('Link Timeline and Edit Selection').first; //This will deactivate the button if (btn.value.invalidate().value === 'Selected') { btn.elementClick(); }
Danny @Danny_van_SpreuwelIt's getting better and better. Here's the version with the UI element:
const oneSec = 48000; const btn = sf.ui.proTools.mainWindow.groups.whoseTitle.is('Cursor Tool Cluster').first.buttons.whoseTitle.is('Link Timeline and Edit Selection').first; var selection = sf.ui.proTools.selectionGetInSamples(); //Deactivate link Timeline and Edit selection if (btn.value.invalidate().value === 'Selected') { btn.elementClick(); } sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(selection.selectionStart) - oneSec, selectionEnd: Number(selection.selectionEnd) + oneSec }); sf.ui.proTools.menuClick({ menuPath: ["Edit","Automation","Write to All Enabled"], }); //Activate link Timeline and Edit selection if (btn.value.invalidate().value !== 'Selected') { btn.elementClick(); }
Kitch Membery @Kitch2020-07-25 23:09:59.879ZYes you got it! My most recent post just wraped it in a reusable function :-)
- In reply toDanny_van_Spreuwel⬆:
Kitch Membery @Kitch2020-07-25 23:08:29.288ZAll together it should look like this (I've not tested it though);
function writeToBufferedSelection() { const oneSec = 48000; const btn = sf.ui.proTools.mainWindow.cursorToolCluster.buttons.whoseTitle.is('Link Timeline and Edit Selection').first; const selection = sf.ui.proTools.selectionGetInSamples(); if (btn.value.invalidate().value === 'Selected') { btn.elementClick(); } sf.ui.proTools.selectionSetInSamples({ selectionStart: Number(selection.selectionStart) - oneSec, selectionEnd: Number(selection.selectionEnd) + oneSec }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Automation", "Write to All Enabled"], }); if (btn.value.invalidate().value !== 'Selected') { btn.elementClick(); } } writeToBufferedSelection();
Danny @Danny_van_SpreuwelYou mean this function can be used in other SoundFlow scripts?
Kitch Membery @Kitch2020-07-25 23:13:54.426ZNot quite... The function can be called multiple times by using the call ie
writeToBufferedSelection();but the function code still needs to live within the comand that you are using.
Danny @Danny_van_SpreuwelAha. Check. I was wondering how to make snippets of reusable codes. Can you call a script within a script?
Kitch Membery @Kitch2020-07-25 23:32:13.469ZYes you can do this by using a "Run Command" action from the "Macro Editor" by copying and pasting the "Command ID" you want to use from the Command menu in SoundFlow.
Then by clicking the "Copy as Javascript" ie "..." you can paste the code into the command you want to add it to.

- In reply toKitch⬆:
Dustin Harris @Dustin_HarrisFWIW, I did make a function for adding and subtracting timecode.. I'm sure there is a slicker way to code it, but here it is if it helps anyone:
function timeCodeAddSubtract(time, offset) { //offset is whole number in seconds var hours = time.slice(0, 2); var minutes = time.slice(3, 5); var seconds = time.slice(6, 8); var frames = time.slice(09, 11); seconds = (+seconds + +offset); if (seconds < 0) { minutes = (+minutes - 1); seconds = (60 + seconds); } else if (seconds >= 60) { minutes = (+minutes + 1); seconds = (seconds - 60); } if (minutes < 0) { hours = (hours - 1); minutes = (60 + minutes); } else if (minutes >= 60) { hours = (hours + 1); minutes = (minutes - 60); } seconds = String(seconds); minutes = String(minutes); hours = String(hours); function AddZeros(value) { if (value.length == 1) value = String(`0${value}`); return value; } seconds = AddZeros(seconds); minutes = AddZeros(minutes); hours = AddZeros(hours); var output = (`${hours}:${minutes}:${seconds}:${frames}`); return output; }
Kitch Membery @Kitch2020-07-26 03:16:48.694ZGreat stuff!
Dustin Harris @Dustin_Harrisostensibly I could turn this:
var hours = time.slice(0, 2); var minutes = time.slice(3, 5); var seconds = time.slice(6, 8); var frames = time.slice(9, 11);into this?
var hours = time.split(':')[0]; var minutes = time.split(':')[1]; var seconds = time.split(':')[2]; var frames = time.split(':')[3];(I should check if it throws a ';' in for drop frame though)