Copy track name and paste to PT scribble strip...
I would like to create a scipt that goes from left-right (or top-bottom depending on the window I guess) and copies the track name and pastes to the scribble strip in Pro Tools. Reason being is that things start to get a little dicey with the track names in tracking sessions where there are a load of playlists, etc... Easier to find on the scribble.
What's the best way to go about this? Thanks!!
Linked from:
- samuel henriques @samuel_henriques
Hello @Dan_Bozek,
Is the scribble strip is the area called comments in pro tools?
If I understood, would like to add to the comments the track name, every time you create a new playlist, so you get a list of the track names/playlist names on that track?
The way to format text in that area is quite tricky, would you send a picture of it, with a few names to have an idea of how it looks once you start filling it?
- DIn reply toDan_Bozek⬆:Dan Bozek @Dan_Bozek
Yes, "comments." Sorry. I always call it scribble strip out of old habits. So I only want it copied and pasted ONCE at the beginning of my set up so that the track name in the comments remains unchanged as Pro Tools starts adding prefexes and suffexes to the actual track name box.
I'm thinking it could be done with keyboard shortcuts in in the box that pops up when you double click a track to rename—you can get to comments there with a tab key press—but I don't know how to script to open that box and I'm really bad with repeating tasks still. Ha ha.
samuel henriques @samuel_henriques
ahh, good, only at the start. just a moment please.
samuel henriques @samuel_henriques
Here you go,
Let me know if this is it.
function setComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get visible Tracks const visibleTracks = sf.ui.proTools.visibleTrackHeaders //Scrool to view first track visibleTracks[0].trackScrollToView() // Open rename window visibleTracks[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(visibleTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements of text fields and buttons const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) // Loop all tracks for (let i = 0; i < visibleTracks.length; i++) { if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { // Set track name in Cmments while (true) { if (trackName.value.invalidate().value != comments.value.invalidate().value) { comments.elementSetTextFieldWithAreaValue({ value: trackName.value.invalidate().value, }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; // If its the last track press ok, else press next if (i === visibleTracks.length - 1) { ok.elementClick() } else { next.elementClick() }; }; }; const hasAlt = event.keyboardState.hasAlt setComments(hasAlt)
samuel henriques @samuel_henriques
This works with the edit window,
- In reply tosamuel_henriques⬆:TThomas Gloor @Thomas_Gloor
hey @samuel_henriques
One question! What purpose does the WHILE loop serve and what condition must be TRUE? I'm not sure I get it.
Thanks!samuel henriques @samuel_henriques
Hello Thomas,
Is this case I want to make sure the track name was set correctly on the comments area.
So the loop checks if the track name is not equal (!=) to the comments, set the track name in comments. When I was writing this I noticed some times it would fail to set the comments, so this would make sure comments are correct before moving to the next track.- TThomas Gloor @Thomas_Gloor
OK! I get it! Thank you
I did some further modifications to the script (I use "-" and "_" as process name separators, which I don't want copied to comments) so I added an if statement to splice the track name and notice sometimes the while loop made the script fail. I'll see if it comes back!
Best
- In reply tosamuel_henriques⬆:AAlexander Buck @Alexander_Buck
Hello Samuel,
I'm reviving this old thread and wanted to ask if you could modify the script so that it works for selected tracks instead of all tracks.
The background is that I want to insert a value from a variable into the comment field of selected tracks, and I have modified your script for this purpose.Thanks for your help!
Best,
Alexfunction setComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get visible Tracks const visibleTracks = sf.ui.proTools.visibleTrackHeaders //Scrool to view first track visibleTracks[0].trackScrollToView() // Open rename window visibleTracks[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(visibleTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements of text fields and buttons const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) // Loop all tracks for (let i = 0; i < visibleTracks.length; i++) { if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { // Set track name in Cmments while (true) { if (trackName.value.invalidate().value != comments.value.invalidate().value) { comments.elementSetTextFieldWithAreaValue({ value: trackName.value.invalidate().value, }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; // If its the last track press ok, else press next if (i === visibleTracks.length - 1) { ok.elementClick() } else { next.elementClick() }; }; }; const hasAlt = event.keyboardState.hasAlt setComments(hasAlt)
samuel henriques @samuel_henriques
hello
Here's a version for selected tracks.
Also improved the mouse position to open the track name, I'm having problems with it.
Here you go:function setComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get visible Tracks const selectedTracks = sf.ui.proTools.selectedTrackHeaders //Scrool to view first track selectedTracks[0].trackScrollToView() // Open rename window selectedTracks[0].popupButtons.first.mouseClickElement({ clickCount: 2, relativePosition: { x: +2, y: +5 } }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements of text fields and buttons const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) // Loop all tracks for (let i = 0; i < selectedTracks.length; i++) { if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { // Set track name in Cmments while (true) { if (trackName.value.invalidate().value != comments.value.invalidate().value) { comments.elementSetTextFieldWithAreaValue({ value: trackName.value.invalidate().value, }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; // If its the last track press ok, else press next if (i === selectedTracks.length - 1) { ok.elementClick() } else { next.elementClick() }; }; }; const hasAlt = event.keyboardState.hasAlt setComments(hasAlt)
- In reply tosamuel_henriques⬆:AAndrés Giraldo @Andres_Giraldo
Works great. Thanks!
- DIn reply toDan_Bozek⬆:Dan Bozek @Dan_Bozek
Wow. You're fast!! I got distracted and forgot to come back and look at the forum.
With the most recent version of PT, it starts to work and then hangs on line 14.
samuel henriques @samuel_henriques
Hello Dan,
Not sure why it was hanging, I have 2021.6 as well, but anyway, I made some improvements.
Updated above.
If the name was too long, it could fail to write it.If you are using a surface or deck, just press alt and the button at same time to clear the comments.
If you are using the keyboard just make sure you create a new trigger adding alt,. Here I'm using F16 to trigger it:
- DDan Bozek @Dan_Bozek
Works like a champ now!! Thank you so much!!
samuel henriques @samuel_henriques
Awesome!
- TThomas Gloor @Thomas_Gloor
Hey Samuel,
Could you explain why the alt button?
Thank you very much!
samuel henriques @samuel_henriques
Hello Thomas,
Just if you need to clear all the names from the comments. I needed it when I was testing, to repeat the script, and thought it could be useful.- TThomas Gloor @Thomas_Gloor
OK got it!
So if you don't press ALT will it run without clearing the names? Or won't it run at all?
samuel henriques @samuel_henriques
It will work as expected without pressing alt. And if you press alt it will clear all comments.
If you prefer I can remove it.
- In reply tosamuel_henriques⬆:TThomas Gloor @Thomas_Gloor
OH! Nevermind!
It's brilliant! Alt clears it. Without Alt fills it. GREAT!
I'm gonna look into it addid that hasAlt for other scripts!
samuel henriques @samuel_henriques
Cool, if you search the forum for modifier keys, you'll find more examples on how to use this.
- In reply toDan_Bozek⬆:Chris Shaw @Chris_Shaw2021-07-06 19:38:56.074Z2021-07-06 19:53:53.525Z
WOW. Much faster than the script I have .
👍
- In reply toDan_Bozek⬆:Chris Shaw @Chris_Shaw2021-08-17 20:07:45.083Z
Now I need a script that does the opposite: Copy comment to track name.
Or copies first clip name in a track to track name.samuel henriques @samuel_henriques
Hello Chris,
Have you done these?Chris Shaw @Chris_Shaw2022-10-29 19:22:18.232Z
I have one but it's very slow.
I'm sure it'd be easy to modify your script - I think you'd just need to switch which text field gets copied to the other.Chris Shaw @Chris_Shaw2022-10-29 19:25:24.525Z2022-10-29 20:25:05.956Z
@samuel_henriques
this does it:
I added a check to see if the comments field is empty. It skips the track if it is.sf.ui.proTools.mainWindow.invalidate() function setComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get selected Tracks const selectedTracks = sf.ui.proTools.selectedTrackHeaders //Scroll to view first track selectedTracks[0].trackScrollToView() // Open rename window selectedTracks[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements of text fields and buttons const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) // Loop all tracks for (let i = 0; i < selectedTracks.length; i++) { if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { //Check if comments field is not empty before proceeding if (comments.value.invalidate().value.trim().length !== 0) { // Set track name in Comments while (true) { if (comments.value.invalidate().value != trackName.value.invalidate().value) { trackName.elementSetTextFieldWithAreaValue({ value: comments.value.invalidate().value, }); sf.wait({ intervalMs: 5 }) } else { break; } }; } }; // If its the last track press ok, else press next if (i === selectedTracks.length - 1) { ok.elementClick() } else { next.elementClick() }; }; }; const hasAlt = event.keyboardState.hasAlt setComments(hasAlt)
samuel henriques @samuel_henriques
Here's the same comments to track name. and will fix in case the new track name exists.
Monday I'll try "first clip on track to track name or comments"btw, heard your awesome recording studio rockstars podcast, and was really cool that somehow, something I did helped on a Bob Dylan record :).
function doesTracknameExist(newTrackName) { let newName const confirmationDialog = sf.ui.proTools.invalidate().confirmationDialog const trackNameExistsDial = confirmationDialog.buttons.whoseTitle.is("OK").first if (trackNameExistsDial.exists) { let append = ".cmt1" //Check if was renamed here let matchWasNumberedHere = newTrackName.match(/[.](cmt)\d+$/i) if (matchWasNumberedHere) { let lastNumber = +newTrackName.match(/\d+$/)[0] let cleanName = newTrackName.replace(matchWasNumberedHere[0], "") newName = `${cleanName}.cmt${++lastNumber}` } else { newName = `${newTrackName}${append}` }; trackNameExistsDial.elementClick(); trackNameExistsDial.elementWaitFor({ waitType: "Disappear" }, "Confirmation dial did\'t close.") return newName; }; return; }; function setTrackNameFromComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get visible Tracks const selectedTracksH = sf.ui.proTools.selectedTrackHeaders //Scrool to view first track selectedTracksH[0].trackScrollToView() // Open rename window selectedTracksH[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracksH[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements for text fields and buttons let [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x); let [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) let newTrackName let repeatIteration = false // Loop all tracks for (let i = 0; i < selectedTracksH.length; i++) { //User cancel if (event.keyboardState.hasAlt && event.keyboardState.hasCommand) { throw 0 } if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { //Save if first iteration if (!repeatIteration) { newTrackName = comments.value.invalidate().value } // Set track name in Cmments while (true) { //skip if comments are empty if (comments.value.invalidate().value.trim().length === 0) break; if (trackName.value.invalidate().value != newTrackName) { trackName.invalidate().elementSetTextFieldWithAreaValue({ value: newTrackName, }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; // If its the last track press ok, else press next if (i === selectedTracksH.length - 1) { ok.elementClick() } else { next.elementClick(); }; //Fix if track name exists const trackNameExists = doesTracknameExist(newTrackName) if (trackNameExists) { newTrackName = trackNameExists i-- repeatIteration = true; } else { repeatIteration = false; } }; }; //Alt will clear all comments const hasAlt = event.keyboardState.hasAlt setTrackNameFromComments(hasAlt)
- In reply toChris_Shaw⬆:
samuel henriques @samuel_henriques
Hello Chris,
This does first clip in track to track name or comments. Be aware, I didn't fix if there is no clip in track.
Choose here:function getClipName() { sf.ui.proTools.menuClick({ menuPath: ["Clip", "Rename..."] }); const renameWin = sf.ui.proTools.windows.whoseTitle.is("Name").first renameWin.elementWaitFor({}, 'Rename Clip Window Not Found.'); const clipName = renameWin.groups.first.textFields.first.value.invalidate().value; renameWin.buttons.whoseTitle.is("Cancel").first.elementClick(); renameWin.elementWaitFor({ waitType: "Disappear" }, 'Rename Clip Window Failed to Close.'); return clipName; } function doesTracknameExist(newTrackName) { let newName const confirmationDialog = sf.ui.proTools.invalidate().confirmationDialog const trackNameExistsDial = confirmationDialog.buttons.whoseTitle.is("OK").first if (trackNameExistsDial.exists) { let append = ".dup1" //Check if was renamed here let matchWasNumberedHere = newTrackName.match(/[.](dup)\d+$/i) if (matchWasNumberedHere) { let lastNumber = +newTrackName.match(/\d+$/)[0] let cleanName = newTrackName.replace(matchWasNumberedHere[0], "") newName = `${cleanName}.cmt${++lastNumber}` } else { newName = `${newTrackName}${append}` }; trackNameExistsDial.elementClick(); trackNameExistsDial.elementWaitFor({ waitType: "Disappear" }, "Confirmation dial did\'t close.") return newName; }; return; }; /** * @param {AxPtTrackHeader[]} tracksH */ function getFirstClipName(tracksH) { const namesObj = {} const returnToZeroBtn = sf.ui.proTools.mainWindow.transportViewCluster.groups.whoseTitle.is("Normal Transport Buttons").first.buttons.whoseTitle.is("Return to Zero").first const returnToZero = () => returnToZeroBtn.exists ? returnToZeroBtn.elementClick() : sf.keyboard.press({ keys: "return" }); const selectNextClip = () => sf.keyboard.press({ keys: "ctrl+tab" }); const isClipFade = () => sf.ui.proTools.getMenuItem("Edit", "Mute").exists // Loop all tracks for (let i = 0; i < tracksH.length; i++) { const thisTrack = tracksH[i] thisTrack.trackSelect(); thisTrack.trackScrollToView(); //Go to Zero returnToZero() //Select First Clip selectNextClip(); if (isClipFade()) selectNextClip(); // Get Clip Name const clipName = getClipName(); namesObj[thisTrack.normalizedTrackName] = clipName.split(".")[0] }; // Select Original Selection sf.ui.proTools.trackSelectByName({ names: tracksH.map(th => th.normalizedTrackName) }); return namesObj }; /** * @param {Object} param * @param {Object} param.names * @param {'Track Name'|'Track Comments'} [param.setTextArea] */ function setTrackNameOrComments({ setTextArea, names: namesObj }) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get visible Tracks const selectedTracksH = sf.ui.proTools.selectedTrackHeaders //Scrool to view first track selectedTracksH[0].trackScrollToView() // Open rename window selectedTracksH[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracksH[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements for text fields and buttons let [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x); let [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) let textArea = setTextArea === "Track Name" ? trackName : comments let newTextValue let repeatIteration = false // Loop all tracks for (let i = 0; i < selectedTracksH.length; i++) { const thisTrack = selectedTracksH[i] //User cancel if (event.keyboardState.hasAlt && event.keyboardState.hasCommand) { throw 0 } //Save if first iteration if (!repeatIteration) { newTextValue = namesObj[thisTrack.normalizedTrackName] } // Set track name in Cmments while (true) { if (textArea.value.invalidate().value !== newTextValue) { textArea.invalidate().elementSetTextFieldWithAreaValue({ value: newTextValue, }); sf.wait({ intervalMs: 5 }) } else { break; } }; // If its the last track press ok, else press next if (i === selectedTracksH.length - 1) { ok.elementClick() } else { next.elementClick(); }; //Fix if track name exists const trackNameExists = doesTracknameExist(newTextValue) if (trackNameExists) { newTextValue = trackNameExists i-- repeatIteration = true; } else { repeatIteration = false; } }; }; const selectedTrackHeaders = sf.ui.proTools.selectedTrackHeaders const clipsNames = getFirstClipName(selectedTrackHeaders) setTrackNameOrComments({ setTextArea: "Track Name", names: clipsNames })
- TIn reply toDan_Bozek⬆:Thomas Gloor @Thomas_Gloor
Hi everyone! I did a little modification on this script. It now works for ALL TRACKS or for SELECTED TRACKS ONLY
Enjoy!
///////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////TRACK NAME TO COMMENTS 1.1.0////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// const pt = sf.ui.proTools const hasAlt = event.keyboardState.hasAlt pt.appActivateMainWindow(); pt.mainWindow.invalidate(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////INSTRUCTIONS///////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// let forSelected = sf.interaction.displayDialog({ buttons: ["All Tracks", "Selected Tracks"], defaultButton: "All Tracks", title: "Copy track name to comments", prompt: "Do for all tracks or only for selected tracks?", giveUpAfterSeconds: -1, }).button ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////CONST / VARIABLES / USER DEFINED///////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////MAIN SCRIPT//////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////// setCommentsForSelectedTracks({ hasAlt, applyTo: forSelected }); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////FUNCTIONS////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////COPY SELECTED TRACKS TO COMMENTS /** @param {{hasAlt: boolean, applyTo: string}} args */ function setCommentsForSelectedTracks({ hasAlt, applyTo }) { let tracks if (applyTo === "All Tracks") { tracks = pt.visibleTrackHeaders } else if (applyTo === "Selected Tracks") { tracks = pt.selectedTrackHeaders } tracks[0].trackScrollToView() tracks[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) sf.ui.proTools.windows.whoseTitle.is(tracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); let [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) let [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) //////////////////////////////////////////////////LOOP ALL TRACKS for (let i = 0; i < tracks.length; i++) { if (hasAlt) { comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { while (true) { if (trackName.value.invalidate().value != comments.value.invalidate().value) { comments.elementSetTextFieldWithAreaValue({ value: trackName.value.invalidate().value, }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; if (i === tracks.length - 1) { ok.elementClick() } else { next.elementClick() }; }; };
samuel henriques @samuel_henriques
Hey @Ben_Rubin,
Here is a version that will prepend the track name to the existing comments.
function setComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get selected Tracks const selectedTracks = sf.ui.proTools.selectedTrackHeaders //Scrool to view first track selectedTracks[0].trackScrollToView() // Open rename window selectedTracks[0].titleButton.mouseClickElement({ clickCount: 2, relativePosition: { x: 10, y: 10 } }); // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements of text fields and buttons const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) // Loop all tracks for (let i = 0; i < selectedTracks.length; i++) { let newCommments = trackName.value.invalidate().value + " " + comments.value.invalidate().value if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { // Set track name in Comments while (true) { if (comments.value.invalidate().value !== newCommments) { comments.elementSetTextFieldWithAreaValue({ value: newCommments }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; // If its the last track press ok, else press next if (i === selectedTracks.length - 1) { ok.elementClick() } else { next.elementClick() }; // Use a bit of a wait if there are errors of not finding the comments area sf.wait({ intervalMs: 10 }) }; sf.ui.proTools.trackSelectByName({ names: selectedTracks.map(n => n.normalizedTrackName) }) }; const hasAlt = event.keyboardState.hasAlt; setComments(hasAlt);
Ben Rubin @Ben_Rubin
thanks so much for this and thanks for posting in the right place! There really needs to be a easy-to-find repository of all these great scripts in the forum.
- In reply tosamuel_henriques⬆:
Ben Rubin @Ben_Rubin
hey @samuel_henriques,
this amazing script of yours has broken in PT 2023.6. (I just reverted to 2023.3 to see if it worked, and it did.)
it is failing at this line:
sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor();
not sure why.thanks
benChris Shaw @Chris_Shaw2023-06-12 20:30:17.125Z
Hey Ben,
You can fix this by replacing the//Scroll to first track
bit of code (lines 8&9)
With this://Scroll to view first track sf.ui.proTools.trackSelectByName({ names: [selectedTracks[0].normalizedTrackName] }) sf.ui.proTools.selectedTrack.trackScrollToView()
Ben Rubin @Ben_Rubin
Thank you, @Chris_Shaw!!! Totally worked. I actually had that line of code off for some reason and was working fine without it. But that fixed it. Are you able to explain what changed? I'm just curious.
Chris Shaw @Chris_Shaw2023-06-13 15:41:54.910Z
I'm not 100% sure.
I've always found that.trackScrollTo
can be unreliable sometimes and only works under ideal situations (with only one track selected).
I haven't had the time to investigate it further in order to file a bug report.Ben Rubin @Ben_Rubin
Thanks for the reply. Would you suggest just replacing "trackscrollto" globally? I've noticed on a lot of my scripts that i ended up turning it off, but makes sense why it would be there.
Chris Shaw @Chris_Shaw2023-06-13 23:28:56.580Z2023-06-14 23:11:58.986Z
I use this for most of my scripts. You may have to get track names before running and reselect them afterwards if you have more than one track selected :
function csScrollToTrack(trackName) { var confirmationDialogWin = sf.ui.proTools.confirmationDialog; var scrollTrack = (typeof trackName == "object") ? trackName[0] : trackName; try { sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); confirmationDialogWin.elementWaitFor({ timeout: 100 }); } catch (err) { sf.keyboard.press({ keys: "n", repetitions: 2 }); sf.ui.proTools.menuClick({ menuPath: ['Track', 'Scroll to Track...'] }); confirmationDialogWin.elementWaitFor({}, `Could not find Scroll to track Dialog`); } confirmationDialogWin.textFields.first.elementSetTextFieldWithAreaValue({ value: scrollTrack, useMouseKeyboard: true }); confirmationDialogWin.buttons.whoseTitle.is('OK').first.elementClick(); confirmationDialogWin.elementWaitFor({ waitType: 'Disappear' }); };
Chris Shaw @Chris_Shaw2023-06-13 23:30:06.788Z
What's cool about this script is that you can pass either a single track name or an array of track names (it will scroll to the first track in the array).
- In reply toChris_Shaw⬆:
Ben Rubin @Ben_Rubin
This is great and turns out I already have it in some scripts so I'm assuming you've posted this elsewhere in the forum. Will start using more broadly.
- In reply toChris_Shaw⬆:
Ben Rubin @Ben_Rubin
As it turns out, even after adding @chris_shaw's code, the script was still failing.
Today I solved it by replacing// Open rename window selectedTracks[0].popupButtons.first.mouseClickElement({ clickCount: 2 }) // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor();
with
try { sf.ui.proTools.selectedTrack.trackOpenRenameDialog(); } catch (e) { // Access the Rename dialog by double-clicking the track's title sf.ui.proTools.selectedTrack.titleButton.mouseClickElement({ clickCount: 2, }); // Wait for Rename win to open while (!sf.ui.proTools.windows.first.children.whoseRole.is("AXStaticText").whoseValue.is('Name the track:').first.exists) { sf.wait({ intervalMs: 100 }); }; };
(this is code that I cannot take credit for writing. it's from somewhere on this forum.)
samuel henriques @samuel_henriques
Hello Ben,
Chris's is a better way to scroll and it's good to use.
But I think the initial problem is that the mouse click is failing after 2023.6. The position where its clicking off.
Usingsf.ui.proTools.selectedTrack.trackOpenRenameDialog();
even if more stable is a bit slower.this will try clicking to open track rename, but if it fails, will try using the menu.
// Open rename window selectedTracks[0].titleButton.mouseClickElement({ clickCount: 2, relativePosition: { x: 10, y: 3 } }); try { // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].titleButton.value.invalidate().value).first.elementWaitFor(); } catch (err) { sf.ui.proTools.selectedTrack.trackOpenRenameDialog(); }
Jack Green @Jack_Green
Hey Sam,
Im trying to adapt this code to allow me to put a custom prepend in front of the comments. Works perfectly but for some reason the last selected track gets the prepend twice?
Thanks in advance for your help and for the original code
function setComments(hasAlt) { sf.ui.proTools.appActivateMainWindow() sf.ui.proTools.invalidate() //Get selected Tracks const selectedTracks = sf.ui.proTools.selectedTrackHeaders //Scrool to view first track sf.ui.proTools.trackSelectByName({ names: [selectedTracks[0].normalizedTrackName] }) sf.ui.proTools.selectedTrack.trackScrollToView() // Open rename window selectedTracks[0].titleButton.mouseClickElement({ clickCount: 2, relativePosition: { x: 10, y: 3 } }); try { // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].titleButton.value.invalidate().value).first.elementWaitFor(); } catch (err) { sf.ui.proTools.selectedTrack.trackOpenRenameDialog(); } // Wait for rename window sf.ui.proTools.windows.whoseTitle.is(selectedTracks[0].popupButtons.first.value.invalidate().value).first.elementWaitFor(); //Get the elements of text fields and buttons const [trackName, comments] = sf.ui.proTools.focusedWindow.invalidate().textFields.map(x => x) const [ok, cncl, pr, next] = sf.ui.proTools.focusedWindow.buttons.map(x => x) // Loop all tracks for (let i = 0; i < selectedTracks.length; i++) { let newCommments = prepend.text + comments.value.invalidate().value if (hasAlt) { // Clear comments comments.elementSetTextFieldWithAreaValue({ value: '', }); } else { // Set track name in Comments while (true) { if (comments.value.invalidate().value !== newCommments) { comments.elementSetTextFieldWithAreaValue({ value: newCommments }); sf.wait({ intervalMs: 5 }) } else { break; } }; }; // If its the last track press ok, else press next if (i === selectedTracks.length - 1) { ok.elementClick() } else { next.elementClick() }; }; }; const prepend = sf.interaction.displayDialog({ prompt: "Prepend with?", title: "Track Comment Prepend", defaultAnswer: "", buttons: ["OK", "Cancel"], defaultButton: "OK", }); if (prepend.button === "Cancel") throw 0; const hasAlt = event.keyboardState.hasAlt; setComments(hasAlt);
Jack Green @Jack_Green
Update not just the last comment seems very random what gets the double hit ..
Its seems to copy the last comment as well? e.g.
Comment 1 : One
Comment 2 : Two
Prepend : TestResults sometimes in ...
Track 1:Test One
Track 2: Test Test Onesamuel henriques @samuel_henriques
Hello Jack,
I manages to find a few things to improve, I updated here,
Copy track name and paste to PT scribble strip... #post-23
just add your prepend bit. I managed to replicate your problem, it could be that the script too fast and there was no time to read info properly.
This was done a few protools versions ago and something might have changed.
adding just 10ms to the time it takes working on the track did id for me, try to add more if you still have problems.
- In reply toThomas_Gloor⬆:DDaniel Holsinger @Daniel_Holsinger
How can I modify these to and individual selection on a button without the prompt? So two separate codes