No internet connection
  1. Home
  2. How to
  3. Ableton Live

Macros to select and arm a range of tracks in Ableton Live 12.2 Session View

By wolaud @wolaud
    2025-05-28 19:52:07.367Z

    Hello,

    Having a bit of trouble setting up some macros that I think should be easy enough:

    I'd like to create macros that selects a range of tracks and then toggles arm recording on/off. I tried using the "UI Click" to select the first track, then "Keyboard Shift Modifier" to simulate holding Shift, then another UI Click to select the last track, then "Toggle Arm Track" - this gave me mixed results, arming only the first track for recording (and then throwing errors when I tried to unarm the track).

    So in the case below I tried to click "Mix 1," then hold shift, then click "Mix 5," then toggle arm track.

    Any help would be appreciated!

    Solved in post #2, click to view
    • 9 replies
    1. Chad Wahlbrink @Chad2025-05-28 22:41:44.469Z

      Hi, @wolaud,

      Thanks for another great question!

      Selecting multiple tracks is tricky for Ableton. In its UI and the API for the control surface we have set up, Ableton only recognizes 1 track as the "selected track." We can set the selected track with something like this:

      // Track to Select
      let trackToSelect = 'MIX 1';
      
      // Filter for Track to Select
      let track = sf.app.abletonLive.song.visibleTracks.find(t => t.name.value === trackToSelect);
      
      // Set Selected Track
      sf.app.abletonLive.song.view.selectedTrack.setValue({ value: track });
      
      

      However, that only works for one track at a time. I want to explore this more and find other solutions for selecting multiple tracks.

      The other option currently available is to use mouse simulation. However, as you noted, results vary with that approach.

      An alternate approach would be to use a script like the one below to set multiple tracks to arm. This technically happens sequentially, but it's speedy, so it may be helpful enough for your use case.

      You can name the tracks in the array defined in line 6 below.

      
      // Bail out if Ableton is not running
      if (!sf.ui.abletonLive.isRunning) throw `Ableton Live is not running`;
      
      // Track Names
      let tracks = ['MIX 1', 'MIX 2', 'MIX 3', 'MIX 4', 'MIX 5']
      
      // Arm Each Track in `tracks`
      tracks.forEach((track) => {
          sf.app.abletonLive.song.tracks.find(tr => tr.name.stringValue == track).arm.setValue({ value: true });
      });
      
      Reply1 LikeSolution
      1. Wwolaud @wolaud
          2025-05-29 03:41:12.299Z

          Yep this seems to work great.

          I modified it a bit so it toggles on/off depending on the existing state of the track:

          // Bail out if Ableton is not running
          if (!sf.ui.abletonLive.isRunning) throw `Ableton Live is not running`;
          
          // Track Names
          let tracks = ['MIX 1', 'MIX 2', 'MIX 3', 'MIX 4', 'MIX 5'];
          
          // Toggle arm state for each track
          tracks.forEach((trackName) => {
              let track = sf.app.abletonLive.song.tracks.find(tr => tr.name.stringValue === trackName);
          
              if (track && track.arm) {
                  let currentArmState = track.arm.value;
                  track.arm.setValue({ value: !currentArmState });
              }
          });
          

          Building on this, here's another question: Would it be possible to add to this script and have it only arm tracks that have an incoming audio signal? For example in the above list let's say "Mix 1" and Mix 4" have incoming audio on their respective "Audio From" sources — could soundflow read incoming audio signals (let's say above a certain threshold) and choose to arm only 1 and 4?

          1. Wwolaud @wolaud
              2025-05-29 22:31:56.473Z

              Okay, slight tweak: If we were using this to arm one specific track as follows:

              // Bail out if Ableton is not running
              if (!sf.ui.abletonLive.isRunning) throw `Ableton Live is not running`;
              
              // Track Names
              let tracks = ['MIX 1']
              
              // Arm Each Track in `tracks`
              tracks.forEach((track) => {
                  sf.app.abletonLive.song.tracks.find(tr => tr.name.stringValue == track).arm.setValue({ value: true });
              });
              

              How could we update this script to move focus in the session to the first empty clip slot for that track? Or to record a new clip?

              1. Chad Wahlbrink @Chad2025-05-31 21:02:16.054Z

                For this idea, I think you would use this type of method for recording to the next available clip:

                // Record to next free slot - 16 stands for 16 beats. 4 measures in 4/4.
                sf.app.abletonLive.song.triggerSessionRecord({ recordLength: 16.0 });
                

                So full script for that would be this:

                
                // Bail out if Ableton is not running
                if (!sf.ui.abletonLive.isRunning) throw `Ableton Live is not running`;
                
                sf.app.abletonLive.song.invalidate();
                
                // Track Names
                let tracks = ['MIX 1']
                
                // Arm Each Track in `tracks`
                tracks.forEach((trackName) => {
                
                    // Track to Arm
                    let trackToArm = sf.app.abletonLive.song.tracks.find(tr => tr.name.stringValue == trackName);
                
                    // Set Arm to True
                    trackToArm.arm.setValue({ value: true });
                
                    // Record to next free slot 
                    sf.app.abletonLive.song.triggerSessionRecord({ recordLength: 16.0 });
                
                });
                
                1. Wwolaud @wolaud
                    2025-06-02 03:14:13.178Z

                    Thanks for getting back to me Chad.

                    When I try running this script it automatically launches clip recording for all currently armed tracks. (I'm using non-exclusive track arming so I can monitor multiple tracks simultaneously, but I don't necessarily record clips for EVERY armed track.

                    Would it be possible to have it only create a new session recording for the designated track ('MIX 1')? Or to have it select the first empty clip slot on that track after arming? (In that case I would then record by simply hitting enter or using a second "record clip" macro.)

                    1. Chad Wahlbrink @Chad2025-06-11 14:21:22.896Z

                      Hi, @wolaud,

                      Thanks for your patience with my replies! I am finally back in the studio and home for the rest of the summer.

                      Okay, you are right, that triggerSessionRecord() doesn't seem specific enough for your use case.

                      I think this version should be helpful for getting you on the right track:

                      
                      // Bail out if Ableton is not running
                      if (!sf.ui.abletonLive.isRunning) throw `Ableton Live is not running`;
                      
                      sf.app.abletonLive.song.invalidate();
                      
                      // Track Names
                      let tracks = ['MIX 1']
                      
                      // Arm Each Track in `tracks`
                      tracks.forEach((trackName) => {
                          try {
                              // Track to Arm
                              let trackToArm = sf.app.abletonLive.song.tracks.find(tr => tr.name.stringValue == trackName);
                      
                              // Set Arm to True
                              trackToArm.arm.setValue({ value: true });
                      
                              // Record to next free slot
                              trackToArm.clipSlots.invalidate().find(clipslot => clipslot.hasClip.boolValue === false).fire()
                          } catch (err){
                              throw `Failed to Arm Track.`
                          }
                      
                      });
                      

                      The primary change being in line 20:

                       trackToArm.clipSlots.invalidate().find(clipslot => clipslot.hasClip.boolValue === false).fire()
                      

                      I'd probably have to see an example Live Set to know how you plan to use this workflow, but this seems to find the next free slot and only record on the named track.

                2. In reply towolaud:
                  Chad Wahlbrink @Chad2025-05-31 20:25:08.495Z

                  Hi @wolaud,

                  Sorry for the delay in responding to these ideas! I've been traveling this week, so I've been in and out a bit.

                  For this first idea, we can read the input level of a track, but only if that track is armed. So to accomplish what you are after, we can arm the track briefly, read the level, and then disarm it if the level is below a certain level.

                  This is how we would do this:

                  
                  // Bail out if Ableton is not running
                  if (!sf.ui.abletonLive.isRunning) throw `Ableton Live is not running`;
                  
                  // Track Names
                  let tracks = ['MIX 1', 'MIX 2', 'MIX 3']
                  
                  // Arm Each Track in `tracks`
                  tracks.forEach((trackName) => {
                      let trackToArm = sf.app.abletonLive.song.tracks.find(tr => tr.name.stringValue == trackName);
                  
                      // This version will toggle - you could change the value in line 15 to "True" if you want to always enable
                      if (trackToArm && trackToArm.arm) {
                          let currentArmState = trackToArm.arm.value;
                          trackToArm.arm.setValue({ value: !currentArmState });
                      }
                  
                      // If the Input Meter Level is less than 10% off full scale, disarm the track; 
                      if (trackToArm.inputMeterLevel.invalidate().floatValue <= 0.1) {
                          trackToArm.arm.setValue({ value: false });
                      }
                  });
                  
                  1. Wwolaud @wolaud
                      2025-06-02 03:21:15.315Z

                      All good on the delay, happy to have some new things to try!

                      Trying out this method I am finding it a bit wonky currently. I tried tweaking the float value a bit but still find it a bit inconsistent — it seems to catch some tracks with incoming audio and not others. Will keep testing and see what I come up with.

                      1. Chad Wahlbrink @Chad2025-06-11 19:36:22.715Z

                        I'm curious where you ended up with this one! This would be one that I'd like to discuss on a call to understand your specific Live Set and use case.