Hi There!
I'm running into a problem with the script below.
//memory original window
let originalWin = sf.ui.proTools.focusedWindow.title.value.split(":").slice(0, 1).join(":")
/**
* @param {array} path - menu full path
* @param {'Enable'|'Disable'} targetValue
*/
function menuClick(path, targetValue) {
sf.ui.proTools.menuClick({ menuPath: path, targetValue: targetValue });
}
// Make sure track lis is visible
sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Track List"], targetValue: "Enable" })
// Get all items from track list
const trackList = sf.ui.proTools.trackListItems
// Get all selected tracks
const selectedTracks = sf.ui.proTools.selectedTrackNames
// Scroll first track to view
const indexOfFirstSelected = trackList.findIndex(x => x.normalizedTrackName == selectedTracks[0])
trackList[indexOfFirstSelected].children.whoseRole.is("AXCell").allItems[1].buttons.first.mouseClickElement({ isControl: true, isShift: true })
// Select original selection
sf.ui.proTools.trackSelectByName({ names: selectedTracks });
/**
* @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
}
})
}
}
function getFirstFreeSend() {
const selectedTracks = sf.ui.proTools.selectedTrackHeaders
const sendLetters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
let sendAssignmentList = []
for (let i = 0; i < selectedTracks.length; i++) {
let trackInfo = sf.ui.proTools.trackGetByName({ name: selectedTracks[i].normalizedTrackName })
.track.sendButtons.filter(x => x.value.invalidate().value != "unassigned").map(x => x.title.invalidate().value.split(" ")[2])
sendAssignmentList.push(...trackInfo)
}
const firstFreeSend = sendLetters.filter(letter => sendAssignmentList.indexOf(letter) === -1)[0]
if (firstFreeSend) {
return firstFreeSend
} else {
alert("Must have at least one free send, that is the same for all tracks.")
throw 0
};
};
/**
* @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() {
const newTrackWin = sf.ui.proTools.windows.whoseTitle.is("New Track").first.elementWaitFor().element
const format = newTrackWin.popupButtons.whoseTitle.is("Stereo").first
const type = newTrackWin.popupButtons.whoseTitle.is("Aux Input").first
const timeBase = newTrackWin.popupButtons.whoseTitle.is("Samples").first
if (format.value.invalidate().value != "Stereo") { format.popupMenuSelect({ menuPath: ["Stereo"] }); }
if (type.value.invalidate().value != "Aux Input") { type.popupMenuSelect({ menuPath: ["Aux Input"] }); }
if (timeBase.value.invalidate().value != "Samples") { timeBase.popupMenuSelect({ menuPath: ["Samples"] }); }
newTrackWin.checkBoxes.whoseTitle.is("Create next to current track").first.checkboxSet({ targetValue: "Enable" });
// Wait to name track and press ok
newTrackWin.elementWaitFor({ waitType: "Disappear", timeout: -1 })
sf.ui.proTools.invalidate()
}
// function setWindowViews() {
// const views = ["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: "Enable" })
// sf.ui.proTools.menuClick({ menuPath: ["View", "Mix Window Views", view], targetValue: "Enable" })
// })
// }
/**
* @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 })
// sf.ui.proTools.menuClick({ menuPath: ["View", "Mix Window Views", view], targetValue: targetValue })
})
}
// function closeWindowViews(views) {
// views.forEach(view => {
// sf.ui.proTools.menuClick({ menuPath: ["View", "Edit Window Views", view], targetValue: "Disable" })
// sf.ui.proTools.menuClick({ menuPath: ["View", "Mix Window Views", view], targetValue: "Disable" })
// })
// }
const getSelectedTrackOut = (trackName) => sf.ui.proTools.trackGetByName({ name: trackName }).track.outputPathButton.title.invalidate().value.split('\n')[1].trim();
let insertSlot
let firstFreeSend
function actions() {
const originalSelectedTracks = sf.ui.proTools.selectedTrackNames
// Save first selected track output on variable
const firstSelectedOut = getSelectedTrackOut(originalSelectedTracks[0])
// Get free sends
firstFreeSend = getFirstFreeInsertOrSend("Send")
// Assign new send to new track
assignToNewTrack(firstFreeSend)
// New track setting and wait for track name
newTrackSettings()
// If new send win is blocking the inserts or sends, move win away
moveSendWinOutOfSlots()
// Expand created send
sf.ui.proTools.menuClick({ menuPath: ["View", "Expanded Sends", `Send ${firstFreeSend}`], targetValue: "Enable" })
// 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()
auxTrack.buttons.whoseTitle.is("Solo").first.mouseClickElement({ isCommand: true })
sf.ui.proTools.colorsSelect({
colorNumber: 20,
});
// set new aux output
if (getSelectedTrackOut(auxTrack.normalizedTrackName) != firstSelectedOut) {
auxTrack.trackOutputSelect({ outputSelector: items => items.filter(item => item.path[1] === firstSelectedOut)[0] })
}
// Get free insert slot after A
insertSlot = getFirstFreeInsertOrSend("Insert", ["A"])
///Wait
sf.wait({
intervalMs: 100,
});
// Open search...
auxTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
.buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`)
.first.popupMenuSelect({
menuPath: ["search..."],
});
// Wait to open new plug
while (true) {
const plugIsOpen = auxTrack.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;
}
}
sf.ui.proTools.trackSelectByName({ names: originalSelectedTracks })
}
function main() {
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.invalidate();
// const isActiveInsGroupFMix = sf.ui.proTools.getMenuItem("View", "Mix Window Views", "Inserts F-J").isMenuChecked
const isActiveInsGroupFEdit = sf.ui.proTools.getMenuItem("View", "Edit Window Views", "Inserts F-J").isMenuChecked
// const isActiveSendGroupFMix = sf.ui.proTools.getMenuItem("View", "Mix Window Views", "Sends 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 expand created 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"]) }
}
}
}
//show original window
sf.ui.proTools.menuClick({ menuPath: ["Window", originalWin] });
main()
When running this script, if the output of the first selected track is mono, the following error will occur.
: Logging error in action (01) PopupMenuSelectAction: No menu item was returned by menuSelector callback
Logging error in action (01) TrackSelectOutputAction: Could not select output menu item:''
It seems it will stop at the command to select "search ..." from the Insert menu of the newly created AUX track.
It works well when the output of the first selected track is stereo.
If anyone can help me figure out what's causing this, I'd appreciate it!
- Christian Scheuer @chrscheuer2021-10-03 18:48:17.222Z
Hi Masayoshi,
This indicates that the callback function for
outputSelector
doesn't return any item.auxTrack.trackOutputSelect({ outputSelector: items => items.filter(item => item.path[1] === firstSelectedOut)[0] })
If you need more help with this, I'd recommend that you log the values of
items
and offirstSelectedOut
. This will help you figure out why there's a mismatch there. Most likely, the comparison doesn't properly take into account how PT formats the value of outputs here.If you want even better help, try to isolate the issue into a short script that others can run. It's often much more easy to help with short scripts vs. something very complex :)
samuel henriques @samuel_henriques
Hey Masayoshi,
I'm sorry you are having trouble with this code, I think its all mine. I'll have some time tomorrow to figure out the problem.
Thank you Christian, I hope I can figure this out.
samuel henriques @samuel_henriques
Got it, Christian was correct, the callback was wrong. Hope it's better now.
Updated on the original thread:
Create New Track from Send Menu on Selected Tracks Script Help #post-6- MMasayoshi Sugai @Masayoshi_Sugai
It worked perfectly!
Thank you Samuel !!!