No internet connection
  1. Home
  2. Ideas
  3. Logic

Midi Velocity Up & Down and pre determined values

By Justin Krol @Justin_Krol
    2024-09-09 16:49:59.767Z

    Hey @Kitch!

    I've got another idea that I've been exploring but can't really find an elegant solution to. Maybe there's already something that can help with this? I've tried a couple of ideas but have kept hitting roadblocks.

    I'd love to be able to select a note in the piano roll with my mouse while simultaneously clicking a stream deck button to either raise or lower the velocity. Going further, it would be great to have pre-determined level values of increse and decrease (like +10, -10).

    As far as I can tell, there might be a way to do this with the step editor via midi control, but that defeats the whole idea of having a quick way to punch up the velocity while editing in the piano roll without having to manual slide it with the mouse or opening the velocity automation lane.

    Thanks!

    • 5 replies
    1. Kitch Membery @Kitch2024-09-09 17:10:56.872Z

      Hi @Justin_Krol,

      I'll take a look this week and see if it's something that we can achieve, I can see the benefits!

      Thanks for the request.

      1. S
        In reply toJustin_Krol:
        SoundFlow Bot @soundflowbot
          2024-09-09 19:10:33.904Z

          This issue is now tracked internally by SoundFlow as SF-1441

          1. In reply toJustin_Krol:
            Kitch Membery @Kitch2024-11-14 19:08:05.666Z

            Hi @Justin_Krol,

            I did some research into this and unfortunately hit a roadblock.

            When multiple notes of different velocities are selected, the velocity slider value only displays the lowest velocity of all selected notes.

            However, if your use case is for single MIDI notes or MIDI notes with the same velocity values, this script will do the trick.

            const logic = sf.ui.logic;
            
            // Bail out if Logic Pro is not running
            if (!logic.isRunning) throw `Logic Pro is not running`;
            
            logic.invalidate();
            logic.appActivate();
            
            const pianoRollGroup = logic.mainWindow.groups.whoseDescription.is("Piano Roll").first;
            const pianoRoll = pianoRollGroup.groups.whoseDescription.is("Piano Roll").allItems[1];
            const pianoRollInspector = pianoRoll.splitGroups.first.splitGroups.allItems[1].children.whoseRole.is("AXUnknown").whoseDescription.is("Inspector").first;
            const velocityGroup = pianoRollInspector.scrollAreas.first.groups.find(g => g.children.whoseRole.is("AXStaticText").whoseValue.is("Velocity").first.exists);
            
            const [_, velocityValueText, velocitySliderElement] = velocityGroup.children.map(e => e);
            
            const velocitySlider = velocitySliderElement.children.whoseRole.is("AXValueIndicator").first;
            
            if (!velocitySlider) throw `Could not find the Velocity slider`;
            
            const getCurrentVelocity = () => Number(velocityValueText.value.invalidate().value);
            
            // Increments the Slider by 1
            const incrementSmall = () => velocitySlider.value.value = "1";
            // Increments the Slider by 5
            const incrementLarge = () => velocitySliderElement.elementClick({ actionName: "AXIncrement" });
            
            // Decrements the Slider by 1
            const decrementSmall = () => velocitySlider.value.value = "-1";
            // Decrements the Slider by 5
            const decrementLarge = () => velocitySliderElement.elementClick({ actionName: "AXDecrement" });
            
            /**
             * Adjusts the velocity in the Piano Roll.
             *
             * @param {Object} options - The adjustment options.
             * @param {number} [options.targetVelocity] - The specific velocity to set (must be between 1 and 127).
             * @param {number} [options.adjustBy] - The amount to increase or decrease the current velocity.
             * @throws Will throw an error if targetVelocity is provided and is out of range (1-127).
             */
            function adjustVelocity({ targetVelocity, adjustBy } = {}) {
                if (targetVelocity != null) {
                    if (targetVelocity < 1 || targetVelocity > 127) {
                        log("Set/Adjust Velocity", `Target Velocity must be between 1 and 127`);
                        throw 0
                    }
                } else if (adjustBy != null) {
                    // Calculate the target based on current velocity and adjustBy
                    targetVelocity = Math.max(1, Math.min(127, getCurrentVelocity() + adjustBy));
                } else if(targetVelocity === undefined && adjustBy === undefined){
                    log("Set/Adjust Velocity", `This preset must have either a "Target Velocity" or "Increment By" property value`);
                    throw 0
                }
            
                // Adjust to reach target velocity
                while (getCurrentVelocity() !== targetVelocity) {
                    const currentVelocity = getCurrentVelocity();
                    const delta = Math.abs(currentVelocity - targetVelocity);
            
                    if (currentVelocity > targetVelocity) { // Decrement
                        if (delta >= 5) {
                            decrementLarge();
                        } else {
                            for (let i = 0; i < delta; i++) decrementSmall();
                        }
                    } else { // Increment
                        if (delta >= 5) {
                            incrementLarge();
                        } else {
                            for (let i = 0; i < delta; i++) incrementSmall();
                        }
                    }
            
                    sf.engine.checkForCancellation();
                }
            }
            

            Here are some example use cases for the function call.

            // Set a target velocity value between 1-127
            adjustVelocity({ targetVelocity:60 });
            
            // Increment the note velocity by 10
            adjustVelocity({ adjustBy:10 });
            
            // Decrement the note velocity by 10
            adjustVelocity({ adjustBy:-10 });
            
            1. In reply toJustin_Krol:
              Kitch Membery @Kitch2024-11-14 19:13:37.392Z

              You could also turn this into a Command Template...

              const { targetVelocity, adjustBy } = event.props;
              
              const logic = sf.ui.logic;
              
              // Bail out if Logic Pro is not running
              if (!logic.isRunning) throw `Logic Pro is not running`;
              
              logic.invalidate();
              logic.appActivate();
              
              const pianoRollGroup = logic.mainWindow.groups.whoseDescription.is("Piano Roll").first;
              const pianoRoll = pianoRollGroup.groups.whoseDescription.is("Piano Roll").allItems[1];
              const pianoRollInspector = pianoRoll.splitGroups.first.splitGroups.allItems[1].children.whoseRole.is("AXUnknown").whoseDescription.is("Inspector").first;
              const velocityGroup = pianoRollInspector.scrollAreas.first.groups.find(g => g.children.whoseRole.is("AXStaticText").whoseValue.is("Velocity").first.exists);
              
              const [_, velocityValueText, velocitySliderElement] = velocityGroup.children.map(e => e);
              
              const velocitySlider = velocitySliderElement.children.whoseRole.is("AXValueIndicator").first;
              
              if (!velocitySlider) throw `Could not find the Velocity slider`;
              
              const getCurrentVelocity = () => Number(velocityValueText.value.invalidate().value);
              
              // Increments the Slider by 1
              const incrementSmall = () => velocitySlider.value.value = "1";
              // Increments the Slider by 5
              const incrementLarge = () => velocitySliderElement.elementClick({ actionName: "AXIncrement" });
              
              // Decrements the Slider by 1
              const decrementSmall = () => velocitySlider.value.value = "-1";
              // Decrements the Slider by 5
              const decrementLarge = () => velocitySliderElement.elementClick({ actionName: "AXDecrement" });
              
              /**
               * Adjusts the velocity in the Piano Roll.
               *
               * @param {Object} options - The adjustment options.
               * @param {number} [options.targetVelocity] - The specific velocity to set (must be between 1 and 127).
               * @param {number} [options.adjustBy] - The amount to increase or decrease the current velocity.
               * @throws Will throw an error if targetVelocity is provided and is out of range (1-127).
               */
              function adjustVelocity({ targetVelocity, adjustBy } = {}) {
                  if (targetVelocity != null) {
                      if (targetVelocity < 1 || targetVelocity > 127) {
                          log("Set/Adjust Velocity", `Target Velocity must be between 1 and 127`);
                          throw 0
                      }
                  } else if (adjustBy != null) {
                      // Calculate the target based on current velocity and adjustBy
                      targetVelocity = Math.max(1, Math.min(127, getCurrentVelocity() + adjustBy));
                  } else if(targetVelocity === undefined && adjustBy === undefined){
                      log("Set/Adjust Velocity", `This preset must have either a "Target Velocity" or "Increment By" property value`);
                      throw 0
                  }
              
                  // Adjust to reach target velocity
                  while (getCurrentVelocity() !== targetVelocity) {
                      const currentVelocity = getCurrentVelocity();
                      const delta = Math.abs(currentVelocity - targetVelocity);
              
                      if (currentVelocity > targetVelocity) { // Decrement
                          if (delta >= 5) {
                              decrementLarge();
                          } else {
                              for (let i = 0; i < delta; i++) decrementSmall();
                          }
                      } else { // Increment
                          if (delta >= 5) {
                              incrementLarge();
                          } else {
                              for (let i = 0; i < delta; i++) incrementSmall();
                          }
                      }
              
                      sf.engine.checkForCancellation();
                  }
              }
              
              adjustVelocity({ targetVelocity, adjustBy });
              

              With template properties set up like this...

              With presets like this...

              1. S
                In reply toJustin_Krol:
                SoundFlow Bot @soundflowbot
                  2024-11-15 12:02:02.348Z

                  The linked internal issue SF-1441 has been marked as Done