I’m trying to set a minimum time on my MIDI notes. (i.e, if MIDI Note Off comes less than X ms after the corresponding Note On, delay the Note Off until X ms have passed)
Some comments on other forums suggest using a trace gate for this purpose.
Do we have any kind of open source Ardour plugin that can do this?
I’m running on a Linux ARM architecture (Raspberry Pi 5), so I need it to be open source and not just freeware, since a Windows download is not suitable for my purposes.
I don’t know an existing plugin, the closest is perhaps “MIDI Sostenuto” from x42 MIDI Filter Collection (Raspbian packages it as x42-plugins):
MIDI Sostenuto: This filter delays note-off messages by a given time, emulating a piano sostenuto pedal. When the pedal is released, note-off messages that are queued will be sent immediately. The delay-time can be changed dynamically, changes do affects note-off messages that are still queued.
It would not be too hard to add a trace gate filter to the MIDI filter set to enforce a minimum note duration.
–
If it does not have to be in realtime, but editing already recorded MIDI on the timeline, you can could use a Lua Script to do this.
Select the MIDI region(s) in the editor that you want to change.
Ardour Menu > Window > Scripting
Copy/Paste the script below there
optionally change required min. note length (line 16, 17)
Press “Run”
local sel = Editor:get_selection ()
-- iterate over all selected regions
for r in sel.regions:regionlist ():iter () do
local mr = r:to_midiregion ()
if mr:isnil () then goto continue end
-- get MIDI Model
local mm = mr:midi_source(0):model ()
-- Prepare Undo command
local midi_command = mm:new_note_diff_command ("MIDI Note Duration")
-- Iterate over all notes of the MIDI region
for note in ARDOUR.LuaAPI.note_list (mm):iter () do
-- len is in Temporal::Beats
local old_len = note:length ()
-- pick one of the following ..
local new_len = old_len:round_up_to_beat ();
--local new_len = Temporal.Beats (0, math.max (old_len:to_ticks (), 1920 / 4)) -- 16th note
--print (old_len, new_len)
if new_len ~= old_len then
local new_note = ARDOUR.LuaAPI.new_noteptr (note:channel (), note:time (), new_len, note:note (), note:velocity ())
midi_command:remove (note)
midi_command:add (new_note)
end
end
mm:apply_command (Session, midi_command)
::continue::
end
I’m using it for live performance, so it does have to be in realtime.
“add a trace gate filter to the MIDI filter set” - sounds like something I could contribute to the project.
What kind of features should it have? Basic operation would be to drop all Note Off messages, and every Note On triggers a series of On/Off/On/Off messages. Timing would be similar to the “MIDI Delayline”, I think. I’ll have to study it to figure out what “Plugin Host” and “Control Port” mean for timing source.
My application is slightly different from a standard trace gate - I wouldn’t mind if my Note Off messages weren’t just dropped. If anything, I’d like a plugin to generate a delayed Note Off message, then another plugin to drop the first Note Off message and forward the second, so I get behavior like the commented out new_len calculation in your LUA script.
Somebody will probably want the thing to loop, too.
I think the suggestion from the other forum had a typo. They probably meant that you should try a “Trance gate” effect. This was made popular in 90’s Trance music.
That is not a MIDI effect, but a sidechain technique:
You use a rhythmic pattern for example using a snare sample (disable routing to master so you don’t hear it in the mix). Then use that pattern to trigger a gate plugin on a seperate track that contains a sustained synth or vocal sound.
Long-time lurker here, jumping to point to my own collection of plugins, that I did not expect to make public just yet (still lacking documentation, no UI yet, and so on), but if I understand correctly your use-case I think this is covered by my MIDI “Gate” plugin. It takes all incoming NoteOn, replace NoteOff with the desired delay (could be set in seconds, minimum 1ms, or in a ratio of the bar duration as advertised by the transport).
Through DPF there are releases for many platforms, ARM included. Look for “ObtuseGate”. I quickly tested on ardour (8.4 installed at the moment), it seems that the inline controls for integers params are a buggy for LV2 and VST2 versions, prefer the VST3 one (I’ll investigate that later).
The typo is mine. I meant “Trance Gate”, but misunderstood the effect. I looked at Kiloheart’s Trance Gate and saw the ADSR controls, but also saw the pattern effect and misunderstood it. I do want the MIDI effect, not the sidechain effect.
But I loaded ACE Expander and must admit that I don’t understand it. What is being graphed in it, for example? Is it decibels vs time somehow?
That’s a nice collection of plugins, that I didn’t know about!
I’m running Ubuntu 24, so I tried apt install dpf-plugins-vst3, and got a bunch of new plugins, but ObtuseGate was not included. I’ll probably have to try building from source.
Sorry, I should have been more specific; DPF is a framework to help develop plugins accross various formats and platforms at the same time. Obtuse is not packaged for any distribution, but you don’t have to compile yourself, you can download it from the github release page and copy to your plugins folder Releases · QualyaIO/obtuse.DPF · GitHub
An expander is like a compressor but instead of attenuating sounds above a a certain threshold it attenuates sounds below it.
It’s similar to a gate (exactly like a gate if you set the Ratio to 100) but you can control how much leakage you want below the threshold.
In this example everything below -15dB gets reduced by a factor of 2.6
Your Gate plugin is real close to what I want. I do want the notes to sustain if I hold the keys down; I’m not sure if that’s best done with a separate plugin or an option on yours.
The Gate plugin pegs the NoteOn velocity at 127, no matter what velocity I strike the key with. Looking at the source code, that’s clearly not what’s intended. Unless you know why it’s doing that, I’ll look into it a little bit more and try to figure it out.
The noteOn() function relays the velocity correctly, but the call to sendNoteOn() in process() uses 127 for the velocity. But I need to study the code more to understand it better.
I’ll have a look at preserving velocity if this is useful to you, however having the gate hold further while the note is held is not on my todo list, as this is not my intended use-case, and it would add in complexity (e.g. what to do if there is never a NoteOff event?).
…and I implemented keeping the velocity, check the latest release.
I tried to think of an easy way for you to also have notes to sustain, best so far would be run in parallel input and plugin output (track with flexible I/O, edit the pin connections of the plugin, add a MIDI out, connect to input), discard one of the noteOn, merge (e.g. MIDI join from FalkTX and carla package?)… and then find a way to discard the first noteOff event (if the note is held longer than gate then discard gate, run until note is released; if the note is short lived, discard the note release, wait until the end of the gate)