Hey all. Been digging deep in here and online and have already put some very deep Logic Pro scripts together.
One thing continues to evade me tho - is there a way to have sound flow select a track in the edit or mix window? I can’t seem to make it happen.
I can use UI Element scripts to select anything i want in a channel but I need to be able to select a channel by name.
Example - I have a track named STEM MASTER in every session. It would be amazing if there was some code that would allow me to get sound flow to select that channel
Thanks for any help!
- Dustin Harris @Dustin_Harris
Heyya @Matt_Hennessy here's my start on it; so far this will only select a sing track that is on screen. I'll have to deal with multiple track selections and scrolling tracks into view later :)
Edited: added scrolling into view (I hope)
function selectTrackInLogic({ trackName }) { const logicApp = sf.ui.app("com.apple.logic10"); function trackToSelect() { const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children; const trackToSelect = trackHeaders.filter(x => x.textFields.whoseDescription.is(trackName).first.exists)[0]; return trackToSelect } let mainWindowScreen = logicApp.mainWindow.windowGetScreen().screen let ruler = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.first.scrollAreas.first.frame; if (!trackToSelect()) { log("Track Name Not Found") throw 0; } let frame = trackToSelect().frame let offscreenBottom = ((frame.y + frame.h) > mainWindowScreen.visibleFrame.h) if (offscreenBottom) { sf.mouse.scroll({ delta: -(frame.y + frame.h - mainWindowScreen.visibleFrame.h), delta2: 0, unit: "Pixel" }) } let offScreenTop = (frame.y < ruler.y + ruler.h) if (offScreenTop) { sf.mouse.scroll({ delta: ((ruler.y + ruler.h) - frame.y), delta2: 0, unit: "Pixel" }) } trackToSelect().mouseClickElement({ relativePosition: { x: (frame.w / 2), y: 5 } }) } const logicApp = sf.ui.app("com.apple.logic10"); logicApp.appActivateMainWindow(); selectTrackInLogic({ trackName: "Audio 48" })
- MMatt Hennessy @Matt_Hennessy
This is amazing.
So in the case of this script I just change the “audio 1” in the last line to read the name of track I’m trying to select?
Dustin Harris @Dustin_Harris
that's right... and I think I've got working now with scrolling into view, let me know if it's reliable...
- MIn reply toMatt_Hennessy⬆:Matt Hennessy @Matt_Hennessy
I’ll dive in tomorrow first thing. Away from the studio today. Will report back then. Thank you so much 🙏🏼
- MIn reply toMatt_Hennessy⬆:Matt Hennessy @Matt_Hennessy
So this is working fine assuming the track is on screen. Not working here if track is of screen
Theres also a slight issue that it clicks right were the track alternative selector is depending on the track sizing. Working to get that recreated consistently and Ill report back.
Thank!!!
Dustin Harris @Dustin_Harris
Hmmmm the scrolling not working… do you happen to use natural scrolling direction? Also my track selection code is a bit hacky, let me see if there is a better way to do it…
- MMatt Hennessy @Matt_Hennessy
Hahaha busted I DO use natural scrolling direction.
Dustin Harris @Dustin_Harris
Sweet, maybe that’s it then… I’ll send a new script in the morning with the sf.mouse.scroll polarities flipped and see if that helps…
Dustin Harris @Dustin_Harris
before I mess with scrolling direction, try this and let me know what happens. I discovered my code wouldn't work with certain multi monitor configurations, so this might help:
function selectTrackInLogic({ trackName }) { let originalMousePosition = sf.mouse.getPosition().position; const logicApp = sf.ui.app("com.apple.logic10"); const trackToSelect = () => { const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children; const trackToSelect = trackHeaders.filter(x => x.textFields.whoseDescription.is(trackName).first.exists)[0]; return trackToSelect } if (!trackToSelect()) { log(`Track with the name '${trackName}' not found`) throw 0; } const mainWindowFrame = logicApp.mainWindow.frame; const logicRulerFrame = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.first.scrollAreas.first.frame; const trackFrame = trackToSelect().frame; const mainWindowTotalY = (mainWindowFrame.y + mainWindowFrame.h); const offWindowBottom = ((trackFrame.y + trackFrame.h) > (mainWindowFrame.y + mainWindowFrame.h)); const offScreenTop = (trackFrame.y < logicRulerFrame.y + logicRulerFrame.h); const trackAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame; const middleOfTrackHeaderPane = { x: trackAreaFrame.x + (trackAreaFrame.w / 2), y: trackAreaFrame.y + (trackAreaFrame.h / 2) }; sf.mouse.setPosition({ position: middleOfTrackHeaderPane }) if (offWindowBottom) { sf.mouse.setPosition({ position: middleOfTrackHeaderPane }) sf.mouse.scroll({ delta: -(trackFrame.y + trackFrame.h - mainWindowTotalY), delta2: 0, unit: "Pixel" }) } else if (offScreenTop) { sf.mouse.setPosition({ position: middleOfTrackHeaderPane }) sf.mouse.scroll({ delta: ((logicRulerFrame.y + logicRulerFrame.h) - trackFrame.y), delta2: 0, unit: "Pixel" }) } trackToSelect().mouseClickElement({ relativePosition: { x: (trackFrame.w / 2), y: 5 } }) sf.mouse.setPosition({ position: originalMousePosition }) } const logicApp = sf.ui.app("com.apple.logic10"); logicApp.appActivateMainWindow(); selectTrackInLogic({ trackName: "Audio 100" })
- MMatt Hennessy @Matt_Hennessy
That works perfectly Thank you so much @Dustin_Harris
Amazing work
Dustin Harris @Dustin_Harris
I just realized this will only work when the arrange window is full screen. I’ll tweak it to work with any window size…
- In reply toMatt_Hennessy⬆:
Dustin Harris @Dustin_Harris
ok @Matt_Hennessy , I changed some stuff to make it a little more tolerant to window views and what not. The above script (I edited the post) and let me know how it works for you.
Dustin Harris @Dustin_Harris
and @Matt_Hennessy just to satisfy my own curiosity, I made a popup list of all the track names that is searchable then selects the track you select in the list.
function selectTrackInLogic({ trackName }) { let originalMousePosition = sf.mouse.getPosition().position; const logicApp = sf.ui.app("com.apple.logic10"); const trackToSelect = () => { const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first .groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1] .scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children; const trackToSelect = trackHeaders.find(x => x.textFields.whoseDescription.is(trackName).first.exists); return trackToSelect } if (!trackToSelect()) { log(`Track with the name '${trackName}' not found`) throw 0; } const mainWindowFrame = logicApp.mainWindow.frame; const logicRulerFrame = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1] .splitGroups.first.splitGroups.first.scrollAreas.first.frame; const trackFrame = trackToSelect().frame; const mainWindowTotalY = (mainWindowFrame.y + mainWindowFrame.h); const offWindowBottom = ((trackFrame.y + trackFrame.h) > (mainWindowFrame.y + mainWindowFrame.h)); const offScreenTop = (trackFrame.y < logicRulerFrame.y + logicRulerFrame.h); const trackAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first .groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame; const middleOfTrackHeaderPane = { x: trackAreaFrame.x + (trackAreaFrame.w / 2), y: trackAreaFrame.y + (trackAreaFrame.h / 2) }; sf.mouse.setPosition({ position: middleOfTrackHeaderPane }) if (offWindowBottom) { sf.mouse.setPosition({ position: middleOfTrackHeaderPane }) sf.mouse.scroll({ delta: -(trackFrame.y + trackFrame.h - mainWindowTotalY), delta2: 0, unit: "Pixel" }) } else if (offScreenTop) { sf.mouse.setPosition({ position: middleOfTrackHeaderPane }) sf.mouse.scroll({ delta: ((logicRulerFrame.y + logicRulerFrame.h) - trackFrame.y), delta2: 0, unit: "Pixel" }) } trackToSelect().mouseClickElement({ relativePosition: { x: (trackFrame.w / 2), y: 5 } }) sf.mouse.setPosition({ position: originalMousePosition }) } function getTrackNames() { let tracks = sf.ui.app("com.apple.logic10").invalidate().mainWindow.groups.whoseDescription.is("Tracks") .first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1] .scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children; let trackNames = (tracks.map(x => x.textFields.whoseRole.is('AXTextField').first.getString('AXDescription'))) return trackNames } function main() { const logicApp = sf.ui.app("com.apple.logic10"); logicApp.appActivateMainWindow(); let trackNames = getTrackNames(); let selectedTrackName = sf.interaction.popupSearch({ items: trackNames.map(name => ({ name })) }).item.name logicApp.appActivateMainWindow(); selectTrackInLogic({ trackName: selectedTrackName }) } main();
- In reply toDustin_Harris⬆:MMatt Hennessy @Matt_Hennessy
🤯🤯🤯 wow man that is dope. Ima try and run it today and see how it goes.
The pervious script is working exactly as intended tho I did flip it out to the newer code to deal with window size. I’m always at full screen so it was a non Issue here. Always helps to be more complaint tho.
I also incorporated your script into a munch larger script I had that moves thru a series of tracks until it hits that STEM MASTER track and bounces all th stems as needed. Being able to select STEM MASTER got me around one of the last absolute position clicks I had in there and it’s running great so far.
Thanks for all your help on this. ❤️❤️❤️
Dustin Harris @Dustin_Harris
Awesome, that sweet to hear! 🤟 You're temping me to come up with more scripts for Logic hahahaha
-D
- In reply toMatt_Hennessy⬆:MMatt Hennessy @Matt_Hennessy
Actualy @Dustin_Harris I spoke too soon - The Newest version of the select track code does not work on my setup if the track name in question is ofscreen. The version I have below does. regardless of window size, fullscreen vs smaller, multiple monitors.. this works.
The popup menu version also does not select the track if its offscreen. The popup manu shows the track but if i click it and the track of offscrenn it does nothing.
Here is the working code I have running
function selectTrackInLogic({ trackName }) { let originalMousePosition = sf.mouse.getPosition().position const logicApp = sf.ui.app("com.apple.logic10"); function trackToSelect() { const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children; const trackToSelect = trackHeaders.filter(x => x.textFields.whoseDescription.is(trackName).first.exists)[0]; return trackToSelect } let mainWindowScreen = logicApp.invalidate().mainWindow.windowGetScreen().screen let ruler = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.first.scrollAreas.first.frame; if (!trackToSelect) { log("Track Name Not Found") throw 0; } let frame = trackToSelect().frame let offscreenBottom = ((frame.y + frame.h) > (mainWindowScreen.visibleFrame.y + mainWindowScreen.visibleFrame.h)) if (offscreenBottom) { let arrangeAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame sf.mouse.setPosition({ position: { x: arrangeAreaFrame.x + (arrangeAreaFrame.w / 2), y: arrangeAreaFrame.y + (arrangeAreaFrame.h / 2) } }) sf.mouse.scroll({ delta: -(frame.y + frame.h - mainWindowScreen.visibleFrame.y + mainWindowScreen.visibleFrame.h + mainWindowScreen.visibleFrame.h), delta2: 0, unit: "Pixel" }) } let offScreenTop = (frame.y < ruler.y + ruler.h) if (offScreenTop) { let arrangeAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame sf.mouse.setPosition({ position: { x: arrangeAreaFrame.x + (arrangeAreaFrame.w / 2), y: arrangeAreaFrame.y + (arrangeAreaFrame.h / 2) } }) sf.mouse.scroll({ delta: ((ruler.y + ruler.h) - frame.y), delta2: 0, unit: "Pixel" }) } trackToSelect().mouseClickElement({ relativePosition: { x: (frame.w / 2), y: 5 } }) sf.mouse.setPosition({position: originalMousePosition}) } const logicApp = sf.ui.app("com.apple.logic10"); logicApp.appActivateMainWindow(); selectTrackInLogic({ trackName: "STEM MASTER" })
Dustin Harris @Dustin_Harris
Strange... maybe I'm overthinking some parts in how the screen coordinates relate to each other. Keep using the code that is working and I'll try to figure out what has gone wrong :)
- MMatt Hennessy @Matt_Hennessy
Sounds great.
- In reply toDustin_Harris⬆:AAlex Oldroyd @Alex_Oldroyd8
Hey Dustin
This script is great. I'm just trying to work out how to include wildcards and multiple track selection like the pro tools script in this thread: Selecting multiple tracks by name with wildcards #post-7 but I'm struggling to translate Pro Tools to Logic. Any help would be much appreciated! :)
- OOscar Fogelstrom @Oscar_Fogelstrom
I'm interested in this too:)!
- In reply toDustin_Harris⬆:OOscar Fogelstrom @Oscar_Fogelstrom
Yeah, this is not working for me either if the track is offscreen
- In reply toDustin_Harris⬆:OOscar Fogelstrom @Oscar_Fogelstrom
Ok just to clarify, this is what happens:
- If the track is in a open folder and visible, it works as intended
- If the track is in a open folder but not visible onscreen, the track name is listed in the search list and can be searched, but the selection does not move to that track
- If the track is in a collapsed folder nothing happens
- In reply toMatt_Hennessy⬆:Jesper Ankarfeldt @JesperA2021-12-27 19:10:57.335Z
Hey hey.
I don't have Logic currently on my new Macbook, but you should be able to select tracks without using mouse click.
Maybe @Dustin_Harris can confirm / help. But here's some code I had for that:var specificTrackName = 'TrackName' // Put your trackname here. var app = sf.ui.app("com.apple.logic10") function getTrackSections() { return app.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems } function getTracks() { var trackSections = getTrackSections() return trackSections[1].scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children.whoseRole.is("AXLayoutItem") } var tracks = getTracks() var trackNamesWithNumber = tracks.map(x => x.getString("AXDescription")) var trackNames = tracks.map(x => x.textFields.first.getString("AXDescription")) //tracks[0].elementClick() // Should select the first track. This is a good thing to try for understanding the function. let specificTrack = tracks.filter(x => x.textFields.first.getString("AXDescription").match(specificTrackName))[0] // Filters for the track name. specificTrack.elementClick(); // Select the specific track
- OOscar Fogelstrom @Oscar_Fogelstrom
Hey Jesper, this doesn't work for me. I get:
"TypeError: Cannot read property 'elementClick' of undefined"Jesper Ankarfeldt @JesperA2022-01-31 08:42:26.328Z
Hey Oscar.
It must be because it either doesn't get the track section or the getTracks right.
Or maybe it's because the track is in a folders or something.Could you try instead of doing the specificTrack.elementClick() then do:
log(tracks.length)
Just to make sure it gets the tracks.
Also, maybe try to make just a simple session with 5 tracks, to see if it works in that one. Then we can figure out why it's not getting the tracks.
Ps. I was on my way to swap to Logic and had started building my most essential functions from Nuendo, but abandon the project when I realized that Logic still does't handle more than 1 video file.
So I haven't used the code that thoroughly, so there could be some pitfalls :)- OOscar Fogelstrom @Oscar_Fogelstrom
thanks, let me check
- MIn reply toMatt_Hennessy⬆:Mark Murphy @Mark_Murphy
Hi Guys, this is exactly what I need for my template however when I run this script it just records enables the instrument track it doesn't select it which is what I need? It will select a folder track but this has issues for me as it then enables all the tracks below it which is not ideal. Many thanks, Mark.
- MMark Murphy @Mark_Murphy
Sorry the track was too zoomed out too far, it's fine when it's bigger.
- MMatt Hennessy @Matt_Hennessy
Yes I was just gonna tell you that. It needs the space to click on the track header and if your too zoomed out it’s problematic.
Takes a bit to get used to a workflow where you remember that but eventually becomes more second nature
Glad it’s working
- MIn reply toMatt_Hennessy⬆:Mark Murphy @Mark_Murphy
I have successfully managed to achieve what I was hoping to do with the aid of some midi cc"s and implementing some key commands responding to midi cc's on my streamdeck. This allows me to navigate anywhere with my large composer session no matter what is onscreen. I did this by first saving/locking screenset 1 where all my track stacks are zoomed out (small) and viewable on my main monitor. I then opened Key commands - edit assignments and find the Recall Screenset 1 command and learn/assign it to Sound Flow Midi CC2:
sf.midi.sendCC({
midiCC: 2,
value: 127,
});
Then again in Key Commands locate Open/Close Track Stacks and assign this to Sound Flow Midi CC3:
sf.midi.sendCC({
midiCC: 3,
value: 127,
});So now if you run this older script from this post topped and tailed with these midi CC's you get a functioning session navigation!!! It's essentially zooming out so it can see all your tracks then just opening the track stack that you specify in the script. it's handy because with this you can just hit the button again and it will either open or close the current track stack. You just need to change the name of the track stack at the end of the script in order to select the tracks within your template. I am soo chuffed with this!!!!!
sf.midi.sendCC({
midiCC: 2,
value: 127,
});function selectTrackInLogic({ trackName }) {
let originalMousePosition = sf.mouse.getPosition().position const logicApp = sf.ui.app("com.apple.logic10"); function trackToSelect() { const trackHeaders = logicApp.invalidate().mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.first.groups.whoseDescription.is("Tracks header").first.children; const trackToSelect = trackHeaders.filter(x => x.textFields.whoseDescription.is(trackName).first.exists)[0]; return trackToSelect } let mainWindowScreen = logicApp.invalidate().mainWindow.windowGetScreen().screen let ruler = logicApp.mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.first.scrollAreas.first.frame; if (!trackToSelect) { log("Track Name Not Found") throw 0; } let frame = trackToSelect().frame let offscreenBottom = ((frame.y + frame.h) > (mainWindowScreen.visibleFrame.y + mainWindowScreen.visibleFrame.h)) if (offscreenBottom) { let arrangeAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame sf.mouse.setPosition({ position: { x: arrangeAreaFrame.x + (arrangeAreaFrame.w / 2), y: arrangeAreaFrame.y + (arrangeAreaFrame.h / 2) } }) sf.mouse.scroll({ delta: -(frame.y + frame.h - mainWindowScreen.visibleFrame.y + mainWindowScreen.visibleFrame.h + mainWindowScreen.visibleFrame.h), delta2: 0, unit: "Pixel" }) } let offScreenTop = (frame.y < ruler.y + ruler.h) if (offScreenTop) { let arrangeAreaFrame = sf.ui.app("com.apple.logic10").mainWindow.groups.whoseDescription.is("Tracks").first.groups.whoseDescription.is("Tracks").allItems[1].splitGroups.first.splitGroups.allItems[1].scrollAreas.allItems[1].frame sf.mouse.setPosition({ position: { x: arrangeAreaFrame.x + (arrangeAreaFrame.w / 2), y: arrangeAreaFrame.y + (arrangeAreaFrame.h / 2) } }) sf.mouse.scroll({ delta: ((ruler.y + ruler.h) - frame.y), delta2: 0, unit: "Pixel" }) } trackToSelect().mouseClickElement({ relativePosition: { x: (frame.w / 2), y: 5 } }) sf.mouse.setPosition({position: originalMousePosition})
}
const logicApp = sf.ui.app("com.apple.logic10");
logicApp.appActivateMainWindow();
selectTrackInLogic({ trackName: "Dance Drums" })
sf.midi.sendCC({
midiCC: 3,
value: 127,
});