Hi there,
I think this must be a syntax problem but I've looked at a couple of other posts relating to selecting multiple tracks by name but I can't seem to get it to work. Here's what I have currently:
sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: ['SNARE','SNR','KICK','RIDE','HH'] });
It seems to be selecting the number of tracks that are in the array but not the correct tracks. Any help would be much appreciated!
Thanks in advance!
Linked from:
- Christian Scheuer @chrscheuer2019-09-18 03:04:30.701Z
Hm, your code is right. This could be due to caching in SoundFlow though, for example if you move tracks around etc.
To invalidate the cache, insert this line at the top of your script:sf.ui.proTools.mainWindow.invalidate();
- GGraham Archer @Graham_Archer
Thanks @chrscheuer I'll try that. Whilst doing a number of revisions to the code last night I had to quit and restart SF quite a few times in order for the new code to take effect. I tried restarting SF from the Advanced menu item but it didn't seem to help - a full on quit and start the app again and then Open SoundFlow did though.
One other question I had was how do I selected tracks that 'contains word' rather than 'is the exact word'? As in I'm using this code:
sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: ['SNARE','SNR','KICK','RIDE','HH'] });
But I want SF to select a track called 'SNARE DRUM' and I don't have that in names, but I do have 'SNARE'.
Thanks in advance!
Christian Scheuer @chrscheuer2019-09-18 08:24:16.355Z
Thanks chrscheuer I'll try that. Whilst doing a number of revisions to the code last night I had to quit and restart SF quite a few times in order for the new code to take effect. I tried restarting SF from the Advanced menu item but it didn't seem to help - a full on quit and start the app again and then Open SoundFlow did though.
Thank you for reporting this Graham. I've filed a bug report for this.
One other question I had was how do I selected tracks that 'contains word' rather than 'is the exact word'? As in I'm using this code:
sf.ui.proTools.trackSelectByName({ deselectOthers: true, names: ['SNARE','SNR','KICK','RIDE','HH'] });I don't think the trackSelectByName supports wildcards but we could build a script that does this.
- GGraham Archer @Graham_Archer
Hey @chrscheuer ok cool. Yeah I think wildcards would be more powerful and general in this context. I don't always know in advance what the tracks names are going to be called and so 'contains name' would be a lot more useful I think.
- In reply tochrscheuer⬆:GGraham Archer @Graham_Archer
Hey @chrscheuer, are wildcards a relatively easy thing to implement in trackSelectByName? If so, do you have a timeline for that?
Please let me know when you have a moment.
Many thanks,
Christian Scheuer @chrscheuer2019-10-21 08:58:00.926Z
This script implements wildcards:
function selectTracksByNameWithWildcard(trackNames = []) { function matchWildcard(str, rule) { var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$", "i").test(str); } var allNames = sf.ui.proTools.trackNames; var namesToSelect = allNames.filter(n => trackNames.some(tn => matchWildcard(n, tn))); sf.ui.proTools.trackSelectByName({ names: namesToSelect, deselectOthers: true, }); } selectTracksByNameWithWildcard([ 'SNARE*', 'SNR*', 'KICK*', 'RIDE*', 'HH*' ]);
Note this requires SoundFlow 3.1 - you can download it manually from here: soundflow.org/download
The auto-update will update all existing installations later this week.- GGraham Archer @Graham_Archer
Thank you @chrscheuer this is so good! I've just been testing it - I needed to put a * before the name as well. So:
selectTracksByNameWithWildcard([ '*SNARE*', '*SNR*', '*KICK*', '*RIDE*', '*HH*' ]);
But it's great!Christian Scheuer @chrscheuer2019-10-21 21:59:25.935Z
Nice. Yea the "*" represents any number of characters, so if you want it to match things where something comes before SNARE in the name - for example "Lsnare1" you need star signs on both sides. Anyway - good that it works :)
- GGraham Archer @Graham_Archer
Hey @chrscheuer, I have one other question on this - I'm getting an error when none of the keywords are found in any track name in the session. The error message is:
Error: One or more errors occurred. (Expression Failed: Pro Tools: Selected Track Header)
Is there any way to return a notification just saying something like "There are no drum tracks in the session" and have it not flag an error (and therefore stop the rest of my script)?
I just wondered if you've come across this and how to solve it - apologies I'm not quite sure how to de-bug it!
Thanks in advance!
Graham
Christian Scheuer @chrscheuer2019-12-11 10:40:16.233Z
Yes you can do error handling in many different ways with SoundFlow.
You could for example change this:
sf.ui.proTools.trackSelectByName({ names: namesToSelect, deselectOthers: true, });
to:
sf.ui.proTools.trackSelectByName({ names: namesToSelect, deselectOthers: true, }, err => { log('There are no drum tracks in the session'); });
Christian Scheuer @chrscheuer2019-12-11 10:40:37.343Z
You can read more about error handling in general here:
https://soundflow.org/docs/how-to/custom-commands/error-handling- GGraham Archer @Graham_Archer
Hey @chrscheuer hmmmm I'm tried that and it doesn't seem to throw up the 'There are no drum tracks in the session' log and move on to the rest of the script.
`//SET TRACK HEIGHT TO SMALL
var size = 'micro';
var f = sf.ui.proTools.selectedTrack.frame;
var popupMenu = sf.ui.proTools.selectedTrack.popupMenuOpenFromElement({
relativePosition: { x: f.w - 10, y: 5 },
isOption: true,
}).popupMenu;
popupMenu.menuClickPopupMenu({
menuPath: [size]
});
//SET INPUT TO NO INPUT
sf.ui.proTools.selectedTrack.trackInputSelect({
inputPath: ['no input'],
selectForAllSelectedTracks: true
});
sf.wait({ intervalMs: 500, });//
sf.ui.proTools.appActivateMainWindow();
function setOutput(name, outputPath) {
var track = sf.ui.proTools.trackGetByName({ name: name, makeVisible: true }).track;
track.trackSelect();
track.trackScrollToView();
track.trackOutputSelect({
outputPath: outputPath
});
}
function selectTracksByNameWithWildcard(trackNames = []) {
function matchWildcard(str, rule) {
var escapeRegex = (str) => str.replace(/([.+?^=!:${}()|[]/\])/g, "\$1");
return new RegExp("^" + rule.split("").map(escapeRegex).join(".*") + "$", "i").test(str);
}
var allNames = sf.ui.proTools.trackNames; //variable containing all track names
var namesToSelect = allNames.filter(n => trackNames.some(tn => matchWildcard(n, tn))); //
sf.ui.proTools.trackSelectByName({
names: namesToSelect,
deselectOthers: true,
}, err => { log('There are no drum tracks in the session'); });
}
//DRUMS
selectTracksByNameWithWildcard([
'SNARE', 'KICK', 'TOM', 'DRUM', 'HAT'
]);
sf.ui.proTools.colorsSelect({//COLOUR DRUMS
colorTarget: "Tracks",
colorBrightness: "Dark",
colorNumber: 8,
});
//DRUMS OUTPUT SELECT
sf.ui.proTools.selectedTrack.trackOutputSelect({
outputPath: ['bus', ' (Stereo)'],
selectForAllSelectedTracks: true
});
//DRUMS CAPITALISE NAMES
sf.ui.proTools.selectedTracks.trackHeaders.slice().map(track => {
track.trackSelect();
track.trackRename({
renameFunction: oldName => oldName.toUpperCase(),
});
});
//DRUMS COPY TRACK NAME TO COMMENTS BOX
selectTracksByNameWithWildcard([
'SNARE', 'KICK', 'TOM', 'DRUM', 'HAT'
]);
function setComment(trackHeader, text) {
var commentsField = trackHeader.textFields.whoseTitle.startsWith('Comments').first;
commentsField.mouseClickElement();
sf.keyboard.press({ keys: 'cmd+a' });
sf.keyboard.type({ text: text });
sf.keyboard.press({ keys: 'return' });
}
function setCommentsToTrackNames() {
var tracks = sf.ui.proTools.selectedTracks.trackHeaders;
for (var i = 0; i < tracks.length; i++) {
var track = tracks[i];
setComment(track, track.normalizedTrackName);
}
}
setCommentsToTrackNames();
log('Drums Completed');
sf.wait({ intervalMs: 500, });`I've got a dead simple Pro Tools session with a few tracks in that don't have keywords SNARE, KICK, TOM, DRUM, HAT and I'm just trying to get the script to not fail. Have you any ideas? Basically it works great when those keywords are present.
Thanks in advance!
Graham
- In reply tochrscheuer⬆:AAlex Oldroyd @Alex_Oldroyd8
Hi Christian. I'm trying to incorporate wildcards into some logic scripts. Is there any chance you or kitch could do a video on them? THanks
Christian Scheuer @chrscheuer2022-01-26 23:44:57.657Z
Hi Alex,
That's a good idea. We don't have a good system for planning which videos to do, so I'll just tag @Kitch here for now.
- AAlex Oldroyd @Alex_Oldroyd8
Thanks Christian. And yes @Kitch if you're not already sick of me - how would i implement wildcards into this script: Select a track in Logic Pro X #post-20
Kitch Membery @Kitch2022-01-26 23:51:54.307Z
@Alex_Oldroyd8 Taking a look now. :-)
- AAlex Oldroyd @Alex_Oldroyd8
🥳
- In reply toAlex_Oldroyd8⬆:
Kitch Membery @Kitch2022-01-26 23:54:15.608Z
Actually this is different to the Bus Selection wildcard question. Let's address that one first.
- AAlex Oldroyd @Alex_Oldroyd8
haha sorry 😬 too many questions
- In reply tochrscheuer⬆:Jjulien creus @julien_creus
Hello @chrscheuer , Thanks for this script which is very useful to me! Would you know any way to improve it so that the track selection is only made within Visible and Active tracks? I already found this perfect script from @raphaelsepulveda which works perfectly for selecting all the visible and active tracks, but didn't manage to make it work together with your script using wildcard... Here is the script for selecting all visible and active tracks, in case it is useful somehow...if one of you guys have any clue on how to do this, that would be of great help!!!
Thanks a lot 🙏function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks } function selectTrack(trackListItem) { trackListItem.children.whoseRole.is("AXCell").allItems[1].buttons.first.elementClick(); } function selectAllVisibleActiveTracks() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.trackDeselectAll(); getVisibleActiveTracks().trackListItems.forEach(selectTrack) } selectAllVisibleActiveTracks();
Raphael Sepulveda @raphaelsepulveda2023-07-05 22:42:55.296Z
Here ya go!
function isTrackActive({ track }) { if (track.muteButton.exists) { return track.muteButton.value.value !== 'inactive'; } return track.outputWindowButton.value.value !== 'inactive'; } function getVisibleActiveTracks() { const visibleTracks = sf.ui.proTools.invalidate().visibleTracks; let visibleActiveTracks = { trackHeaders: [], trackListItems: [], names: [] }; visibleTracks.trackHeaders.forEach((trackHeader, i) => { if (isTrackActive({ track: trackHeader })) { visibleActiveTracks["trackHeaders"].push(trackHeader) visibleActiveTracks["trackListItems"].push(visibleTracks.trackListItems[i]) visibleActiveTracks["names"].push(visibleTracks.names[i]) } }); return visibleActiveTracks } function matchWildcard(str, rule) { var escapeRegex = (str) => str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); return new RegExp("^" + rule.split("*").map(escapeRegex).join(".*") + "$", "i").test(str); } function selectVisibleActiveTracksByNameWithWildcard(trackNames = []) { const visibleActiveTrackNames = getVisibleActiveTracks().names; const namesToSelect = visibleActiveTrackNames.filter(n => trackNames.some(tn => matchWildcard(n, tn))); sf.ui.proTools.trackSelectByName({ names: namesToSelect, deselectOthers: true, }); } selectVisibleActiveTracksByNameWithWildcard([ 'SNARE*', 'SNR*', 'KICK*', 'RIDE*', 'HH*' ]);