MIDI keyboard with gated synths

I have been working a bit on Robin’s keyboard driver. I had a lot of fun with it, but found 2 points for improvement: There is a certain likelihood for a »runaway synth«, i. e. a synth that keeps playing, because the note_off is missed, or to be precise, not properly recorded for timing issues. Also, emulating a gated synth by controling it down to amp: 0 somehow doesn’t feel right.

»Gated« means that the synth has a gated envelope and a gate: option to control it. A gated synth is started with the gate open and sustained until the gate is set to 0 (with control), which will induce the release phase.

So, here’s a different sketch (but read the notes below …):

# Polyphonic midi input program with sustained notes
# Ben Marx, February 2023
# based Robin Newman's programme, November 2017:
# https://in-thread.sonic-pi.net/t/polyphonic-gated-synth-for-sonic-pi-3-works-on-a-pi3/452
# https://gist.github.com/rbnpi/ebedd26d61180230db891ccbd9d74971

use_debug false

load_synthdef "<PATH_TO_THE_GATED_SYNTHDEFS>/sonic-pi-winwood_lead_gated.scsyndef"

set :synth, 'sonic-pi-winwood_lead_gated'

if get[:ns].nil? then
  
  set :ns, []#array to store note playing references
 
  helper = {}
  128.times do |i|
    helper[i]= nil
  end

  set :ns, helper
end

ns = {}
# Deep copy; time state elements are immutable
get(:ns).each{|key, value| ns[key] = value}

white_key_scale = scale(0, :major, num_octaves: 12)
current_scale = scale(12, :major, num_octaves: 12)

with_fx :reverb, room: 0.8,mix: 0.6 do #add some reverb
  
  live_loop :midi_note_on do
    use_real_time
    note, on = sync "/midi:mpk_mini_3_mpk_mini_3_midi_1_*/note_on"
    white_key_index = white_key_scale.to_a.index(note)
    unless white_key_index.nil?
      note = current_scale[white_key_index]
      vn=(on.to_f/128)+3
      use_synth get(:synth)
      x = play note, amp: vn #start playing note
      ns[note] = x #store reference to note in ns array
      set :ns, ns
    end
  end # live loop :midi_note_on
  
  live_loop :midi_note_off do
    use_real_time
    note, on = sync "/midi:mpk_mini_3_mpk_mini_3_midi_1_*/note_off"
    white_key_index = white_key_scale.to_a.index(note)
    unless white_key_index.nil?
      note = current_scale[white_key_index]
      begin
        control ns[note], gate: 0
      rescue
        puts 'Could not kill synth.'
      end
      ns[note] = nil
      set :ns, ns
    end
  end # live loop :midi_note_off
  
  live_loop :pitch_bend do #get current pitchbend value adjusted in range -12 to +12 (octave)
    b = sync "/midi:mpk_mini_3_mpk_mini_3_midi_1_*/pitch_bend" #change to match your controller
    
    ns.each do |note, sth|
      unless sth.nil?
        control sth, note: note + (b[0]-8192).to_f/8192*24
      end
    end
  end # live loop pitch_bend
end #reverb

Some notes, I think important:

  • Vary rarely, this may be liable to »runaway synths«, i. e. synths that are not stored in the ns var and hence can never get killed, unless you Alt-S (stop all runs).
  • Unlike in Robins solution, runaway synths will not run for 100 beats, but forever. The probability, I think, is now lower, but you sure get one if you Alt-R (re-run) while a key is held. There is a workaround, though, particularly for live performances: Just run this in a Sonic Pi of its own, so that stopping will only affect this Sonic Pi instance, while others continue running. I think using several SP in parallel should be supported on most (all?) operating systems.
  • You need real gated synths, i. e. standard synths that SP comes along with, won’t do. Using them will end up in cacophony, as they will never terminate.
  • Gated synths are non-standard in SP. One of the basic requirements for the standard synths is for them to be self-terminating. Some of them (and I hope more in future) can be found here, at current just the piano (which admittedly benefits little from this approach, for its plucked nature), the tonewheel organ, and the Winwood lead synth. In order to use them, copy them somewhere on your file system where SP can access them and use them as described in the code above.
  • You may have noticed the white_key_scale thingy in the code. This has nothing to do with the synths as such, but rather with me being a piano keyboard noob. This construction just maps any (note) key to C major, so I can play anything with the white keys only, and it always sound right. I have never understood, why one would squeeze some black keys between the white keys anyway.