Temp Scroll to Track command?
Hi Flowers
I really love the create temp marker and go to temp marker commands in Soundflow and use them all the time.
I wondered could there be similar temp scroll commands to get between tracks vertically?
The first command would look at the currently selected track and store that into memory, the second would scroll to the stored
track position.
If anyone could help me creating a script like that I'd be very grateful.
- OOwen Granich-Young @Owen_Granich_Young
Yeah I can help you out I have most of this built already for a ‘iso pull’ script I’ve been using when I have to go back to dallies and copy down an iso to a previous track.
Do you want a searchable ‘go to other track drop down menu, and remember my current track’ or a fixed ‘I always need to go to this track but remember my current track’
- In reply toMartin_Pavey⬆:Chris Shaw @Chris_Shaw2025-04-23 15:02:41.349Z2025-04-23 15:12:05.899Z
This will store a temp target scroll track:
sf.ui.proTools.appActivate() const newTargetScrollTrack = sf.ui.proTools.selectedTrackNames[0] globalState.targetScrollTrack = newTargetScrollTrack; sf.interaction.notify({ title: "New temp scroll track is:", message: newTargetScrollTrack })
This will recall it.
(If no temp track is stored it will store it)sf.ui.proTools.appActivate() function csScrollToTrack(trackName) { var confirmationDialogWin = sf.ui.proTools.confirmationDialog; var scrollTargetTrack = (typeof trackName == "object") ? trackName[0] : trackName; try { sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); confirmationDialogWin.elementWaitFor({ timeout: 100 }); } catch (err) { sf.ui.proTools.refreshMenuItems() sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); const dlg = sf.ui.proTools.confirmationDialog; sf.waitFor({ callback: () => { dlg.invalidate(); return dlg.buttons.whoseTitle.is("OK").first.exists; }, timeout: 1000 }, `Failed waiting for the scroll track dialog`); } confirmationDialogWin.textFields.first.elementSetTextFieldWithAreaValue({ value: scrollTargetTrack, useMouseKeyboard: true }); sf.waitFor({ callback: () => confirmationDialogWin.textFields.first.value.invalidate().value == scrollTargetTrack }) confirmationDialogWin.buttons.whoseTitle.is('OK').first.elementClick(); confirmationDialogWin.elementWaitFor({ waitType: 'Disappear' }); }; const storeScrollTrack = event.keyboardState.hasAlt; const newTargetScrollTrack = sf.ui.proTools.selectedTrackNames[0] const {targetScrollTrack} = globalState; if (!targetScrollTrack ) { globalState.targetScrollTrack = newTargetScrollTrack sf.interaction.notify({ title: "New temp scroll track is:", message: newTargetScrollTrack }) throw 0 } csScrollToTrack(targetScrollTrack)
Chris Shaw @Chris_Shaw2025-04-23 15:11:38.271Z
You can also combine these two scripts.
If you put this on a stream deck button then pressing it will scroll to the stored track. Pressing it with the option key held will store a new scroll track.If you want to use a keyboard trigger then assign two triggers and make sure that the second trigger contains the option key:
sf.ui.proTools.appActivate() function csScrollToTrack(trackName) { var confirmationDialogWin = sf.ui.proTools.confirmationDialog; var scrollTargetTrack = (typeof trackName == "object") ? trackName[0] : trackName; try { sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); confirmationDialogWin.elementWaitFor({ timeout: 100 }); } catch (err) { sf.ui.proTools.refreshMenuItems() sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); const dlg = sf.ui.proTools.confirmationDialog; sf.waitFor({ callback: () => { dlg.invalidate(); return dlg.buttons.whoseTitle.is("OK").first.exists; }, timeout: 1000 }, `Failed waiting for the scroll track dialog`); } confirmationDialogWin.textFields.first.elementSetTextFieldWithAreaValue({ value: scrollTargetTrack, useMouseKeyboard: true }); sf.waitFor({ callback: () => confirmationDialogWin.textFields.first.value.invalidate().value == scrollTargetTrack }) confirmationDialogWin.buttons.whoseTitle.is('OK').first.elementClick(); confirmationDialogWin.elementWaitFor({ waitType: 'Disappear' }); }; const storeScrollTrack = event.keyboardState.hasAlt; const newTargetScrollTrack = sf.ui.proTools.selectedTrackNames[0] const {targetScrollTrack} = globalState; if (!targetScrollTrack || storeScrollTrack) { globalState.targetScrollTrack = newTargetScrollTrack sf.interaction.notify({ title: "New temp scroll track is:", message: newTargetScrollTrack }) throw 0 } csScrollToTrack(targetScrollTrack)
- MIn reply toMartin_Pavey⬆:Martin Pavey @Martin_Pavey
Oh wow!
I was just thanking Owen and you've come up with these Chris..thanks so much, I'll give them a shot.
I love this forum!- MMartin Pavey @Martin_Pavey
That is perfect Chris.
I owe you a beer!
- MIn reply toMartin_Pavey⬆:Martin Pavey @Martin_Pavey
Ah, Sorry, I spoke too soon.
I can't run 2 of these discreetly to have 2 assignable temp scroll tracks available.
If i put them on separate Streamdeck keys and assign one, it assigns the other.
Is it possible to have 2 discreet memories?
TaChris Shaw @Chris_Shaw2025-04-24 16:18:16.221Z2025-04-24 16:55:42.497Z
Here's a version that you can use to store as many scroll-to tracks as you need.
Make a copy the script for each scroll track button you need to create and change the value ofconst storedScrollTrackNumber
. Rename the scripts as necessary, place them on your stream deck and you should be good to go.const storedScrollTrackNumber = 1; // <<---- change this for each track / button you want to store sf.ui.proTools.appActivate() function csScrollToTrack(trackName) { var confirmationDialogWin = sf.ui.proTools.confirmationDialog; var scrollTargetTrack = (typeof trackName == "object") ? trackName[0] : trackName; try { sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); confirmationDialogWin.elementWaitFor({ timeout: 100 }); } catch (err) { sf.ui.proTools.refreshMenuItems() sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); const dlg = sf.ui.proTools.confirmationDialog; sf.waitFor({ callback: () => { dlg.invalidate(); return dlg.buttons.whoseTitle.is("OK").first.exists; }, timeout: 1000 }, `Failed waiting for the scroll track dialog`); } confirmationDialogWin.textFields.first.elementSetTextFieldWithAreaValue({ value: scrollTargetTrack, useMouseKeyboard: true }); sf.waitFor({ callback: () => confirmationDialogWin.textFields.first.value.invalidate().value == scrollTargetTrack }) confirmationDialogWin.buttons.whoseTitle.is('OK').first.elementClick(); confirmationDialogWin.elementWaitFor({ waitType: 'Disappear' }); }; const storeScrollTrack = event.keyboardState.hasAlt; if (!globalState.targetScrollTracks) globalState.targetScrollTracks = {}; const { targetScrollTracks } = globalState; if (!targetScrollTracks[storedScrollTrackNumber] || storeScrollTrack) { const newTargetScrollTrack = sf.ui.proTools.selectedTrackNames[0]; globalState.targetScrollTracks[storedScrollTrackNumber] = newTargetScrollTrack; sf.interaction.notify({ title: `New temp scroll track #${storedScrollTrackNumber} is:`, message: targetScrollTracks[storedScrollTrackNumber] }) throw 0 } csScrollToTrack(targetScrollTracks[storedScrollTrackNumber])
Chris Shaw @Chris_Shaw2025-04-24 16:59:02.457Z
Instead of making copies of the script and renaming them for each button you want to create you could convert it into a command template and use presets instead.
A walkthrough on how to do this is available here:
https://soundflow.org/docs/how-to/custom-commands/command-templates- MMartin Pavey @Martin_Pavey
Thanks Chris
This is next level stuff, you're a guru!I had a look at the Command Template stuff but it made my head hurt.
I'll need to set aside some proper time for it and flippin' mixing gets in the way.All the best
Martin
Chris Shaw @Chris_Shaw2025-04-24 17:21:38.668Z
Command templates are great but it takes a minute to wrap your head around creating them