Skip to content

Instantly share code, notes, and snippets.

@kerrishotts
Last active March 14, 2021 20:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kerrishotts/9a760852216f6a300d58b9bc005458b1 to your computer and use it in GitHub Desktop.
Save kerrishotts/9a760852216f6a300d58b9bc005458b1 to your computer and use it in GitHub Desktop.
Pitch-based Velocity Mapper for Logic Pro X / Mainstage

Pitch-based velocity transform plugin for Logic Pro X / Mainstage Midi FX Scripter plugin.

Original Python code and discussion at http://forum.pianoworld.com/ubbthreads.php/topics/3092415/re-realtime-pitch-based-velocity-filter-transformed-the-nu1x.html#Post3092415

Converted to JavaScript and enhanced by Kerri Shotts based on ideas in the above thread.


Parameters

  • Transform: additive | multiplicative (default)
    • Controls if the adjustment is added or multiplied with the original velocity.
  • Scaling Factor (add): Default 10
    • Scaling for additive transform.
  • Scaling Factor (mul): Default 0.2
    • Scaling for multiplicative transform.
  • Log Level: None | Normal (default) | Silly
    • Controls how much logging is performed in the Scripter window.
  • Transform NoteOff: unchecked (default) | checked
    • If checked, NoteOff velocities are transformed using the same algorithm as NoteOn velocities.
  • Lower Velocity Bound: 0 (default) - 127
    • If the transformed velocity goes below the specified value, it will be clipped to the specified value.
  • Higher Velocity Bound: 0 - 127 (default)
    • If the transformed velocity goes above this value, it will be clipped to the value.
  • Midpoint: 0 - 100% (50% default)
    • Controls the midpoint for the calculations. 50% is the middle of the Piano.
  • Equation: Linear (default) | S-Curve | Sine Curve
    • Controls the equation utilized, which determines the shape of the transform curve.
    • Linear is a linear transformation (from top left to bottom right).
    • S-Curve is a curved transformation (from top left to bottom right), focused around the midpoint. S-Curve Slope controls the degree of the transformation around the split.
    • Sine Curve is a curved transformation focused around the midpoint.
  • Offset: -127 - 127 (default: 0)
    • Controls the offset of the equation from the midpoint.
  • S-Curve Slope: 0.1 - 2048 (default: 248.208)
    • Controls the degree of the slope for the S-Curve equation. Lower numbers are more severe, approaching a "switch"-like appearance (on/off) instead of a smooth curve.
// BASED ON http://forum.pianoworld.com/ubbthreads.php/topics/3092415/re-realtime-pitch-based-velocity-filter-transformed-the-nu1x.html#Post3092415
// Converted to JavaScript and Logic Pro X Scripter by Kerri Shotts
const TRANSFORM_MODE = {
ADD: "additive",
MUL: "multiplicative"
};
const LOG_LEVEL = {
NONE: 0,
NORMAL: 1,
SILLY: 2
};
const EQUATIONS = {
LINEAR: "Linear",
SCURVE: "S-Curve",
SINCRV: "Sine Curve"
};
var PluginParameters = [
{
name:"Transform", type: "menu",
valueStrings: Object.values(TRANSFORM_MODE),
defaultValue: 1
},
{
name:"Scaling Factor (Add)", type: "lin", defaultValue: 10,
minValue: -127, maxValue: 127, numberOfSteps: 254
},
{
name:"Scaling Factor (Mul)", type: "lin", defaultValue: 0.2,
minValue: -1, maxValue: 1, numberOfSteps: 200
},
{
name:"Log Level", type: "menu",
valueStrings: Object.keys(LOG_LEVEL),
defaultValue: LOG_LEVEL.NONE
},
{
name:"Transform NoteOff", type: "checkbox",
defaultValue: 0
},
{
name:"Lower Velocity Bound", type: "lin", defaultValue: 0,
minValue: 0, maxValue: 127, numberOfSteps: 127
},
{
name:"Higher Velocity Bound", type: "lin", defaultValue: 127,
minValue: 0, maxValue: 127, numberOfSteps: 127
},
{
name:"Midpoint", type: "lin", defaultValue: 50,
minValue: 0, maxValue: 100, numberOfSteps: 100,
unit: "%"
},
{
name:"Equation", type: "menu",
valueStrings: Object.values(EQUATIONS),
defaultValue: 0
},
{
name:"Offset", type: "lin", defaultValue: 0,
minValue: -87, maxValue: 87, numberOfSteps: 174
},
{
name:"S-Curve Slope", type: "lin", defaultValue: 256,
minValue: 0.01, maxValue: 2048, numberOfSteps: 10240
}
];
let options = {};
function ParameterChanged(param, value) {
options = {
scaleFactorAdd : GetParameter("Scaling Factor (Add)"),
scaleFactorMult : GetParameter("Scaling Factor (Mul)"),
transformMode : Object.entries(TRANSFORM_MODE)[GetParameter("Transform")][1],
logLevel : GetParameter("Log Level"),
transformNoteOff : GetParameter("Transform NoteOff"),
lowerVelBound : GetParameter("Lower Velocity Bound"),
higherVelBound : GetParameter("Higher Velocity Bound"),
midpoint : 87 * ((GetParameter("Midpoint"))/100),
equation : Object.entries(EQUATIONS)[GetParameter("Equation")][1],
offset : GetParameter("Offset"),
sCurveSlope : GetParameter("S-Curve Slope"),
};
}
function HandleMIDI(event)
{
const { scaleFactorAdd, scaleFactorMult, transformMode, logLevel,
transformNoteOff, lowerVelBound, higherVelBound, midpoint,
equation, offset, sCurveSlope } = options;
if (logLevel >= LOG_LEVEL.SILLY)
event.trace();
if (event instanceof NoteOn || (transformNoteOff && event instanceof NoteOff)) {
const which = event instanceof NoteOn ? "on" : "off";
const p = (event.pitch - 21) - midpoint;
const pN = (p-offset)/87;
const pP = (p+offset)/(87/Math.PI);
const origVel = event.velocity;
let adjust = 1;
switch (equation) {
case EQUATIONS.LINEAR:
adjust = (-2 * pN);
break;
case EQUATIONS.SCURVE:
adjust = -1 * ((p - offset) / (Math.sqrt(sCurveSlope + (p - offset)**2)));
break;
case EQUATIONS.SINCRV:
adjust = -1 * Math.sin(pP);
break;
}
let newVel = transformMode === TRANSFORM_MODE.MUL
? Math.floor(origVel * (1.0 + (scaleFactorMult * adjust)))
: Math.floor(origVel + (scaleFactorAdd * adjust));
if (newVel<lowerVelBound) newVel = lowerVelBound;
if (newVel>higherVelBound) newVel = higherVelBound;
event.velocity = newVel;
if (logLevel >= LOG_LEVEL.NORMAL)
Trace(`[${MIDI.noteName(event.pitch)} ${which}]`.padEnd(9, " ") + ` nn:${Math.round(adjust*10000)/10000}`.padEnd(12, " ") + ` ov:${origVel} nv:${newVel}`);
}
event.send();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment