add a hardware I/O on insert of an audio track , open a new audio track from its send
Hello,I want to be able to automate the following:
add a hardware plugin I/O on next available insert of an audio track , then open a new audio track from its send at nominal volume, record enabeled.
any chance ?
- Chad Wahlbrink @Chad2025-01-30 21:51:08.256Z
Note, I think we tackled this on this thread:
Script is here:
Create New Stereo Send From Selected Track (First available send-intelligent) #post-12@Tom_Mochiach - let me know if this is accomplishes what you are after.
- TTom Mochiach @Tom_Mochiach
Hi
I first got thisand when recopy and paste the script I now get this
am I doing anything wrong?
ReplyChad Wahlbrink @Chad2025-01-30 22:15:46.550Z
Hi @Tom_Mochiach, let's keep the conversation here now.
I was not accounting for Mono hardware inserts well before, which is why you were seeing the "toLowerCase" error.
You will need to set the parameters in lines 2 and 3 according to the insert you are adding. The naming is case-sensitive for the
hardwareInsert
path.If you are curious - the path of mono i/o inserts seems to add four spaces to the front of the insert name - I think because of how Pro Tools handles "Sub-paths." Regardless, I'm accounting for that with:
let hardwareInsert = ['i/o', 'H3000 HW.L (Mono)'] let monoOrStereo = 'Mono' // If Mono, add 4 spaces to the front of the name if(monoOrStereo === 'Mono'){ hardwareInsert = ['i/o', (' ' + hardwareInsert[1])] }
Below is an updated version of the script:
let hardwareInsert = ['i/o', 'H3000 HW.L (Mono)'] let monoOrStereo = 'Mono' // If Mono, add 4 spaces to the front of the name if(monoOrStereo === 'Mono'){ hardwareInsert = ['i/o', (' ' + hardwareInsert[1])] } /////////////////////////////////////// /** * @param {string} sendAssignment */ function assignToNewTrack(sendAssignment) { const selectedTracks = sf.ui.proTools.selectedTrackNames sf.ui.proTools.trackGetByName({ name: selectedTracks[selectedTracks.length - 1] }).track.groups.whoseTitle.is(getGroup("Sends", sendAssignment)).first.buttons.whoseTitle.is(`Send Assignment ${sendAssignment}`).first.popupMenuSelect({ isShift: true, isOption: true, menuPath: ["new track..."], }); } function moveSendWinOutOfSlots() { sf.ui.proTools.invalidate() const sendWin = sf.ui.proTools.mainTrackOutputWindow.elementWaitFor().element const sendWinPos = sendWin.position.x const sendSlots = sf.ui.proTools.selectedTrack.groups.whoseTitle.is("Inserts A-E").first const sendSlotsPos = sendSlots.position.x if (sendWinPos - sendSlotsPos < 450 && sendSlotsPos - sendWinPos < 170) { sendWin.windowMove({ position: { y: sendWin.position.y, x: sendSlotsPos + 450 } }) } } /** * @param {'Insert'|'Send'} slotType * @param {array} [defaultUsedSlots] = [] - If parameter is not used, default is [] */ function getFirstFreeInsertOrSend(slotType, defaultUsedSlots) { let buttons slotType == "Insert" ? buttons = "insertButtons" : buttons = "sendButtons" const selectedTracks = sf.ui.proTools.selectedTrackHeaders const sendLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] let sendAssignmentList = defaultUsedSlots || [] try { for (let i = 0; i < selectedTracks.length; i++) { let trackInfo = sf.ui.proTools.trackGetByName({ name: selectedTracks[i].normalizedTrackName }) // .insertButtons or .sendButtons .track[buttons].filter(x => x.value.invalidate().value != "unassigned").map(x => x.title.invalidate().value.split(" ")[2]) sendAssignmentList.push(...trackInfo) } } catch (err) { } const firstFreeSend = sendLetters.filter(letter => sendAssignmentList.indexOf(letter) === -1)[0] if (firstFreeSend) { return firstFreeSend } else { if (slotType == "Insert") { alert(`Must have at least one free ${slotType} slot.`) } else if (slotType == "Send") { alert(`Must have at least one free ${slotType} slot, that is the same for selected tracks.`) } throw 0 }; }; /** * @param {string} sendLetter * @param {'Inserts'|'Sends'} slotType */ function getGroup(slotType, sendLetter) { let group sendLetter.toLowerCase().charCodeAt(0) - 97 <= 4 ? group = `${slotType} A-E` : group = `${slotType} F-J` return group } function newTrackSettings(trackName) { const newTrackWin = sf.ui.proTools.windows.whoseTitle.startsWith("New Track").first.elementWaitFor().element; const format = newTrackWin.popupButtons.allItems[2]; const type = newTrackWin.popupButtons.allItems[0]; const timeBase = newTrackWin.popupButtons.allItems[1]; if (format.value.invalidate().value != monoOrStereo) { format.popupMenuSelect({ menuPath: [monoOrStereo] }); } if (type.value.invalidate().value != "Audio Track") { type.popupMenuSelect({ menuPath: ["Audio Track"] }); } if (timeBase.value.invalidate().value != "Samples") { timeBase.popupMenuSelect({ menuPath: ["Samples"] }); } newTrackWin.checkBoxes.whoseTitle.is("Create next to current track").first.checkboxSet({ targetValue: "Enable" }); newTrackWin.textFields.whoseTitle.is("Track Name").first.elementSetTextFieldWithAreaValue({ value: trackName }); newTrackWin.buttons.whoseTitle.is("Create").first.elementClick(); newTrackWin.elementWaitFor({ waitType: "Disappear",}); } /** * @param {'Enable'|'Disable'} targetValue * @param {array} [viewsNames] = [] - If parameter is not used, default is set inside */ function setWindowViews(targetValue, viewsNames) { let views = viewsNames || ["Inserts A-E", "Inserts F-J", "Sends A-E", "Sends F-J"] views.forEach(view => { sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: targetValue }) }) } const getSelectedTrackOut = (trackName) => sf.ui.proTools.trackGetByName({ name: trackName }).track.outputPathButton.title.invalidate().value.split('\n')[1].trim(); let insertSlot; let firstFreeSend; function actions() { // Original Selected Tracks const originalSelectedTracks = sf.ui.proTools.selectedTrackNames // Save first selected track output on variable const firstSelectedOut = getSelectedTrackOut(originalSelectedTracks[0]) // Add 'pt' to new track name const newTrackName = originalSelectedTracks[0] + ' pt'; // Get free insert slot insertSlot = getFirstFreeInsertOrSend("Insert"); // Open Hardware Insert on Source Track sf.ui.proTools.selectedTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`) .first.popupMenuSelect({ menuPath: hardwareInsert, }, `Could not add hardware insert`); // Wait for new Hardware Insert to be Added while (true) { const plugIsOpen = sf.ui.proTools.selectedTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`).first .value.invalidate().value != "unassigned" if (!plugIsOpen) { sf.wait({ intervalMs: 1000 }) } else { break; } } // Get free sends on source track firstFreeSend = getFirstFreeInsertOrSend("Send"); // Assign new send to new track assignToNewTrack(firstFreeSend); // New track setting and wait for track name newTrackSettings(newTrackName); // If new send win is blocking the inserts or sends, move win away moveSendWinOutOfSlots(); // Solo safe new Aux const selectedTracks = sf.ui.proTools.selectedTrackNames const auxTrack = sf.ui.proTools.trackGetByName({ name: selectedTracks[selectedTracks.length - 1] }).track auxTrack.trackSelect() auxTrack.trackScrollToView() // Aux Tracks now default to solo safe status - so this is irrelevant unless you want your aux return to be NOT solo safed. // auxTrack.buttons.whoseTitle.is("Solo").first.mouseClickElement({ isCommand: true }) // set new aux output if (getSelectedTrackOut(auxTrack.normalizedTrackName) != firstSelectedOut) { auxTrack.trackOutputSelect({ outputSelector: items => items.filter(item => item.element.title.value.includes(firstSelectedOut))[0] }) } // Set Track Record Enable if (sf.ui.proTools.selectedTrack.buttons.whoseTitle.is("Track Record Enable").first.value.value !== 'on state') { sf.ui.proTools.selectedTrack.buttons.whoseTitle.is("Track Record Enable").first.elementClick(); } // Set Record Track to Mute sf.ui.proTools.selectedTrack.trackSetMute({ targetValue: "Enable" }); // Set Send to Full Volume sf.ui.proTools.mainTrackOutputWindow.invalidate().textFields.whoseTitle.is("Volume Numerical").first.elementSetTextFieldWithAreaValue({ value: '0.0', useMouseKeyboard: true }) sf.keyboard.press({ keys: 'enter' }) sf.ui.proTools.trackSelectByName({ names: originalSelectedTracks }) } function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); const isActiveInsGroupFEdit = sf.ui.proTools.getMenuItem("View", "Edit Window Views", "Inserts F-J").isMenuChecked const isActiveSendGroupFEdit = sf.ui.proTools.getMenuItem("View", "Edit Window Views", "Sends F-J").isMenuChecked const isEditWin = sf.ui.proTools.focusedWindow.title.value.startsWith("Edit") if (!isEditWin) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Edit"] }) } // Close expanded sends sf.ui.proTools.menuClick({ menuPath: ["View", "Expanded Sends", "None"], targetValue: "Enable" }) setWindowViews("Enable"); try { actions() } catch (err) { throw err } finally { // Go to mix if needed if (!isEditWin) { sf.ui.proTools.menuClick({ menuPath: ["Window", "Mix"] }) } // Close Inserts Views if not needed if (insertSlot.toLowerCase().charCodeAt(0) - 97 <= 4 && (/* !isActiveInsGroupFMix || */ !isActiveInsGroupFEdit)) { // if (!isActiveInsGroupFMix) { setWindowViews("Disable", ["Inserts F-J"]) } if (!isActiveInsGroupFEdit) { setWindowViews("Disable", ["Inserts F-J"]) } } // Close Sends F-J if not needed if (firstFreeSend.toLowerCase().charCodeAt(0) - 97 <= 4 && (/* !isActiveSendGroupFMix || */ !isActiveSendGroupFEdit)) { // if (!isActiveSendGroupFMix) { setWindowViews("Disable", ["Sends F-J"]) } if (!isActiveSendGroupFEdit) { setWindowViews("Disable", ["Sends F-J"]) } } } } main()
- TTom Mochiach @Tom_Mochiach
Im sorry I do not really understand what to do
and you worked so hard on it
still doesn't work here
I have mono and stereo hardwares , can you post one option set so I can see if it works?
because I do not know how exactly to change the script myself.. thank you so muchChad Wahlbrink @Chad2025-01-30 22:37:48.411Z
Hi @Tom_Mochiach,
This only works if you modify the script to match the menu path of the i/o you are trying to address. See if this video helps you with understanding what to do:
- TTom Mochiach @Tom_Mochiach
- TTom Mochiach @Tom_Mochiach
I have a progress here....
will update I a second- TTom Mochiach @Tom_Mochiach
AMAZING ITS ALL WORKING - YOU ARE A GENIUS!!!
Chad Wahlbrink @Chad2025-01-30 23:17:36.541Z
Glad to hear it!
- TTom Mochiach @Tom_Mochiach
on the same topic (almost), I have a problem of latency when using the Chandler summing and I want to record some new instrument
my solution is to make a send from that track that its output goes to the chandler , then when recording, I hear it through 1-2 ,and when listening to what iv just recorded I listen from the new track's send that goes to the summing along with all other tracks
my English is not that great and anyway it is easier to look at I guess
it looks like this:can you automate opening both the brown tracks (with their state of pre fader send, input monitoring and record enable using one command?
and another command to switch mutes between them?or if you have a more elegant solution of course
Thank you