Hi
Can you guys recommend a plugin (linux native preferably) for midi velocity curve correction?
I’m only aware of Robin’s “Midi Velocity Adjust” but as far as I understand it only lets you adjust Min and Max velocity values - nothing in between.
Ok, so maybe it could be done via lua script? Something like:
if incoming midi velocity is in the range of 60-80 then convert it to 70
if incoming midi velocity is in the range of 80-100 then convert it to 90
etc
etc
Could it be easily done? If so I would be really grateful for any hints how to write it.
The “Midi Velocity Adjust” does linear interpolation of the values in the target-range for example to 32…68 (no offset) the mapping would be as depicted below (x-axis is input velocity, y-axis output):
It does however not offer control over the the curve and certainly not a piecewise function, but yes, you can do that with a Lua script: save the following to your config GNU/Linux: ~/.config/ardour5/scripts/mscale.lua
and edit the function map_velocity
as needed.
ardour {
["type"] = "dsp",
name = "MIDI Velcocity Hack",
category = "Example", -- "Utility"
license = "MIT",
author = "Ardour Lua Task Force",
description = [[An Example Midi Filter for prototyping.]]
}
function dsp_ioconfig ()
return { { midi_in = 1, midi_out = 1, audio_in = 0, audio_out = 0}, }
end
function dsp_run (_, _, n_samples)
local cnt = 1;
function tx_midi (time, data)
midiout[cnt] = {}
midiout[cnt]["time"] = time;
midiout[cnt]["data"] = data;
cnt = cnt + 1;
end
function map_velocity (v)
if v < 50 then
return 1 -- min velocity for a note-on event is 1
elseif v < 70 then -- 50 .. 69
return 50
elseif v < 90 then -- 70 ..89
return 80
else -- 90 .. 127
return 90 + math.floor (25 * ((v - 90) / 37)) -- maps linearly to 90..115
end
end
-- for each incoming midi event
for _,b in pairs (midiin) do
local t = b["time"] -- t = [ 1 .. n_samples ]
local d = b["data"] -- get midi-event bytes
local event_type
if #d == 0 then event_type = -1 else event_type = d[1] >> 4 end
if (#d == 3 and event_type == 9) then -- note on
d[3] = map_velocity (d[3])
tx_midi (t, d)
else -- pass thru all other events unmodified
tx_midi (t, d)
end
end
end
It is based on two existing script that may also provide further insights
Yes! Ardour Lua Task Force to the rescue again
Thank you so much Robin!
For a simple “rounding”, the MIDI Transform tool can be enough, with something like:
Set [Velocity] to [this note's] [velocity]
/ [exactly] 20
* [exactly] 20
+ [exactly] 10
This will map [0 - 20[ to 10, [20 - 40[ to 30 etc…
PS. I do recall seeing a plugin that allows to draw curves, exponential mappings and such, similar to pianoteq’s built-in, but I was not able to find it anymore. In case someone happens stumbles upon this, I’d be interested as well.
Nice trick, I didn’t know that one. Thank you!
Maybe at one point I’ll be tricked into writing a “gamma” lua dsp plugin with an inline UI…
I’ve made a quick hack base on @x42 's example code and implemented midi velocity curve correction, briefly tested, seems worked.
Can you please give some hints about how to make the velocity curve configurable?
Note that I’m not a pro coder, and know little about Ardour. Just started using Ardour a week ago.
ardour {
["type"] = "dsp",
name = "MIDI Velcocity Curve",
category = "Utility",
license = "MIT",
author = "Ardour Lua Task Force",
description = [[Midi Filter for Velocity Curve.]]
}
function dsp_ioconfig ()
return { { midi_in = 1, midi_out = 1, audio_in = 0, audio_out = 0}, }
end
function dsp_run (_, _, n_samples)
local cnt = 1;
function tx_midi (time, data)
midiout[cnt] = {}
midiout[cnt]["time"] = time;
midiout[cnt]["data"] = data;
cnt = cnt + 1;
end
local mapx = {10, 95, 105, 116, 127}
local mapy = {0, 105, 116, 123, 127}
function map_velocity (v)
local i = v // (127 // (#mapx - 1)) + 1
while true do
if i <= 0 then
return mapy[1]
end
if v >= mapx[i] then
if i >= #mapx then
return mapy[i]
end
if v < mapx[i+1] then
return mapy[i] + math.floor((v - mapx[i]) * (mapy[i+1] - mapy[i]) / (mapx[i+1] - mapx[i]))
else
i = i + 1
end
else
i = i - 1
end
end
end
-- for each incoming midi event
for _,b in pairs (midiin) do
local t = b["time"] -- t = [ 1 .. n_samples ]
local d = b["data"] -- get midi-event bytes
local event_type
if #d == 0 then event_type = -1 else event_type = d[1] >> 4 end
if (#d == 3 and event_type == 9) then -- note on
d[3] = map_velocity (d[3])
tx_midi (t, d)
else -- pass thru all other events unmodified
tx_midi (t, d)
end
end
end
Hi guys !
I’m such a big fan of Ardour !
Had the same need and fell into this nice post !
I got inspired and improved the code above to implement linear, exponential and logarithmic curves with customized slope. I know it could be improved but I thought it would be nice to share it to the community !
EDIT : I improved the plugin by adding a note filter so that the curves would only apply to specific notes. And I finally created a Github repository for this script. See here : https://github.com/remyzerems/MIDI-Velocity-Curve
ardour {
["type"] = "dsp",
name = "MIDI Velocity Curve",
category = "Utility",
license = "MIT",
author = "Ardour Lua Task Force",
description = [[Midi Filter for Velocity Curve.]]
}
function dsp_ioconfig ()
return { { midi_in = 1, midi_out = 1, audio_in = 0, audio_out = 0}, }
end
function dsp_params ()
return
{
{ ["type"] = "input", name = "Curve", min = 0, max = 2, default = 0, enum = true, scalepoints =
{
["Linear"] = 0,
["Logarithmic"] = 1,
["Exponential"] = 2,
}
},
{ ["type"] = "input", name = "Slope", min = 0.001, max = 10, default = 1, unit="" }
}
end
function dsp_run (_, _, n_samples)
local cnt = 1;
function tx_midi (time, data)
midiout[cnt] = {}
midiout[cnt]["time"] = time;
midiout[cnt]["data"] = data;
cnt = cnt + 1;
end
function check_limits(v)
if v < 1 then
v = 1
elseif v > 127 then
v = 127
end
return math.floor (v)
end
function linear_curve(v, slope)
return check_limits ( slope*v )
end
function log_curve (v, slope)
return check_limits ( 127*math.log(slope*v)/math.log(slope*127) )
end
function exp_curve (v, slope)
return check_limits ( 127*(math.exp(slope*v/127)-1)/(math.exp(slope)-1) )
end
function map_velocity (v)
local ctrl = CtrlPorts:array ()
local slope = ctrl[2]
if ctrl[1] == 1 then
return log_curve (v, slope)
elseif ctrl[1] == 2 then
return exp_curve (v, slope)
else
return linear_curve (v, slope)
end
end
-- for each incoming midi event
for _,b in pairs (midiin) do
local t = b["time"] -- t = [ 1 .. n_samples ]
local d = b["data"] -- get midi-event bytes
local event_type
if #d == 0 then event_type = -1 else event_type = d[1] >> 4 end
if (#d == 3 and event_type == 9) then -- note on
d[3] = map_velocity (d[3])
tx_midi (t, d)
else -- pass thru all other events unmodified
tx_midi (t, d)
end
end
end
@x42 Is the InserPizHere MidiCurve for velocity or any CC (he has MidiPitchBendCurve too), many of their plugins are ported to Linux (the no-GUI plugins) but Juce-gui plugins don’t.
The code is on google yet: