No internet connection
  1. Home
  2. How to

Create New Stereo Send From Selected Track (First available send-intelligent)

By Jordan Oorebeek @Jordan_Oorebeek
    2024-02-16 02:03:41.945Z

    Hey SF users!

    I've seen a few scripts around that create mono sends intelligently from a track's sends menu but there is no option on those scripts/presets to create a stereo send. I've tried modifying the existing scripts but have had no luck. Does anyone know how to make a script that would:

    1. Find first available send on a selected track(s)
    2. Create a new send (with the option to choose mono or stereo as well as name the new send)

    The concept shouldn't be too different from the "add an insert to first available" so I'm hoping its fairly simple to do.

    Any help would be really appreciate and I think it would be really useful for a lot of Pro Tools users.

    Thanks in advance!
    JO

    • 15 replies

    There are 15 replies. Estimated reading time: 59 minutes

    1. Chad Wahlbrink @Chad2024-02-16 15:29:58.900Z2024-02-16 17:06:11.775Z

      Hey @Jordan_Oorebeek!

      I saw you asking about this on these other thread:

      
      let monoOrStereo = 'Mono'
      
      ///////////////////////////////////////
      
      /**
      * @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.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 != "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()
      }
      
      /**
       * @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() {
      
          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()
      
          // 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] })
          }
      
          // Use if you want to automatically search for a plugin
      
          // Get free insert slot after A
          insertSlot = getFirstFreeInsertOrSend("Insert", ["A"])
      
          /* 
          // 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 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();
      
      1. In reply toJordan_Oorebeek:
        Chad Wahlbrink @Chad2024-02-16 15:39:49.335Z2024-02-16 17:04:36.254Z

        @Jordan_Oorebeek, this version will allow you to define a plug-in path at the top of the script if you want to be able to always have it open a specific plug-in.

        
        let pluginPath = ['multichannel plug-in', 'SoundToys', 'EchoBoy (stereo)']
        let monoOrStereo = 'Stereo'
        
        ///////////////////////////////////////
        
        /**
        * @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.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 != "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()
        }
        
        /**
         * @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() {
        
            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()
        
            // 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] })
            }
        
            // Get free insert slot after A
            insertSlot = getFirstFreeInsertOrSend("Insert", ["A"])
        
            // Open Plugin
            auxTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
                .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`)
                .first.popupMenuSelect({
                    menuPath: pluginPath,
                });
        
            // 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 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()
        
        
        1. JJordan Oorebeek @Jordan_Oorebeek
            2024-02-16 16:57:04.763Z

            Thank you so much! Works perfectly! Is there a way to make it so it will automatically do a stereo send? The reason being is I'm attempting to mix without a screen and am hoping to be able to run this and have it auto create the send. Without being able to "see" whether it's mono or stereo and just knowing its going to be set as a mono send command or Stereo send command would be awesome! I'm getting really picky with that though. I'm already thrilled that this script above works.

            1. Chad Wahlbrink @Chad2024-02-16 17:08:12.636Z

              @Jordan_Oorebeek, sure thing!

              I have updated both scripts

              You can declare whether you want a mono or stereo send by changing the following at the top of each script:

              let monoOrStereo = 'Stereo'
              

              OR

              let monoOrStereo = 'Mono'
              
              1. JJordan Oorebeek @Jordan_Oorebeek
                  2024-02-16 17:36:00.133Z

                  You rock. Thank you so much! Love this.

              2. In reply toChad:
                KKaey Music @Kaey_Music
                  2024-12-11 19:41:24.549Z

                  This is SOOO helpful. Thanks @Chad

                • T
                  In reply toJordan_Oorebeek:
                  Tom Mochiach @Tom_Mochiach
                    2025-01-28 09:59:32.692Z

                    I GET THIS

                    1. T
                      In reply toJordan_Oorebeek:
                      Tom Mochiach @Tom_Mochiach
                        2025-01-30 19:11:27.404Z

                        oh great it actually works!!!
                        can you add an option to add a hardware insert on the track you are sending from, and that the new track would be an audio track?
                        I want to actually add an outboard and record it on the new track so a record enabled track would also be great

                        1. Chad Wahlbrink @Chad2025-01-30 20:14:01.487Z

                          Hi @Tom_Mochiach, I can take a look at that option!

                          Can you let me know which version of the script above you are using? You can link to the version you'd like me to tweak by clicking the link at the bottom of the posted reply:

                          Thanks,
                          Chad

                          1. TTom Mochiach @Tom_Mochiach
                              2025-01-30 20:23:14.529Z2025-01-30 20:28:30.036Z

                              I did succeed in making it an audio track so here is the script - yes please if you may take it from there-

                              
                              let pluginPath = ['multichannel plug-in', 'SoundToys', 'EchoBoy (stereo)']
                              let monoOrStereo = 'Stereo'
                              
                              ///////////////////////////////////////
                              
                              /**
                              * @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.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" });
                              
                                  //  Wait to name track and press ok
                                  newTrackWin.elementWaitFor({ waitType: "Disappear", timeout: -1 })
                                  sf.ui.proTools.invalidate()
                              }
                              
                              /**
                               * @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() {
                              
                                  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()
                              
                                  // 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] })
                                  }
                              
                                  // Get free insert slot after A
                                  insertSlot = getFirstFreeInsertOrSend("Insert", ["A"])
                              
                                  // Open Plugin
                                  auxTrack.groups.whoseTitle.is(getGroup("Inserts", insertSlot)).first
                                      .buttons.whoseTitle.is(`Insert Assignment ${insertSlot}`)
                                      .first.popupMenuSelect({
                                          menuPath: pluginPath,
                                      });
                              
                                  // 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 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()
                              
                              
                              1. Chad Wahlbrink @Chad2025-01-30 20:52:43.078Z2025-01-30 22:11:49.574Z

                                Nice, @Tom_Mochiach,

                                Below is a new version.

                                You'll need to replace the pluginPath in line 2 with the path of your desired HW. If you'd prefer to search for a piece of hardware each time, I can try to adapt this.

                                let pluginPath = ['i/o', 'H3000 HW (Stereo)']
                                

                                Also, just a note that you used ''' instead of ``` when you quoted the code. In order to post a script to the forum, you need to use the back ticks (`). In this instance, I just edited your post to format it.

                                View this tutorial on sharing code on the forum: How to quote code in the SoundFlow forum.

                                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()
                                
                                1. Chad Wahlbrink @Chad2025-01-30 21:07:38.557Z

                                  Realizing now I didn't do what you asked! Working on it.

                                  1. TTom Mochiach @Tom_Mochiach
                                      2025-01-30 21:11:39.064Z

                                      Thank you so much- while on that I was thinking that naming the new track with the same name of the original plus, maybe, "pt" for printed (like pro tools does with committed trucks), will be great. then we can skip the stage of naming the track or give it a width or kind (aux audio etc.)

                                      1. Chad Wahlbrink @Chad2025-01-30 21:43:29.764Z

                                        Okay! I updated the script above.
                                        Create New Stereo Send From Selected Track (First available send-intelligent) #post-12

                                        It will now:

                                        • Add a Hardware Insert to the Source Track
                                        • Create a New Aux Print Track using the Track Name + "pt"
                                        • The new Aux is record enabled and muted to prevent doubling up while monitoring
                                        • The send level is set to "0.0" so you can print at "100%"

                                        If I'm missing anything or misunderstanding, please let me know.

                                        Here's a quick video:

                            • T
                              In reply toJordan_Oorebeek:
                              Tom Mochiach @Tom_Mochiach
                                2025-01-30 21:54:19.637Z

                                I get this