Using and mapping midi (korg nanokontrol2)

Hey all,

I’m experimenting with an external MIDI device for the first time. When I looked at the cues from my nanoKontrol2, I realized that there was basically a single MIDI event sent by the device, with different indexes for each button/knob/slider.

8e62a2423fbee297ee0a8513243a70f9_sp

Are there any established patterns for working with such events? My go at it is below, any feedback? Had to up my Ruby game a bit. Is a live loop the right way to keep my controller ‘state’ up to date?

class Kontrol
  def initialize
    @slots = []
    8.times do
      @slots.push(KontrolSlot.new)
    end
    @buttons = []
    5.times do
      @buttons.push(KontrolButton.new)
    end
  end
  
  attr_reader :slots, :buttons
end

class KontrolSlot
  def initialize
    @knob = 0
    @slide = 0
    
  end
  attr_accessor :knob
  attr_accessor :slide
end

class KontrolButton
  def initialize
    @pressed = false
    @down = false
  end
  
  attr_reader :down
  
  def push_down
    @down = true
  end
  
  def release
    @down = false
    @pressed = true
  end
  
  # toggle off after checking
  def was_pressed
    was_pressed = @pressed
    @pressed = false
    was_pressed
  end
end

kontrol = Kontrol.new

live_loop :control do
  use_real_time
  control_index, value = sync "/midi:nanokontrol2_slider_knob:1/control_change"
  case control_index
  when 0..7
    slot = kontrol.slots[control_index]
    slot.slide = value
  when 16..23
    slot = kontrol.slots[control_index-16]
    slot.knob = value
  when 41..45
    button = kontrol.buttons[control_index-41]
    if (value > 0)
      button.push_down
    else
      button.release
    end
  end
end

live_loop :synth do
  amp = kontrol.slots[0].slide/127.0 #between 0 and 1
  pan = kontrol.slots[0].knob/63.5 - 1 #between -1 and 1
  note = :d4
  if (kontrol.buttons[0].down)
    note = :e4
  end
  if (kontrol.buttons[1].was_pressed)
    use_synth synth_names[rrand_i(0, 10)]
  end
  play note, amp: amp, pan: pan
  sleep 1
end

Took this a bit further and published to GitHub. Seems I can keep it around and use it as a library. :heart:

eval_file "~/SonicPi/lib/kontrol.rb"

Any suggestions still welcome. Based on other threads I might be using Ruby features that aren’t technically supported in Sonic Pi.

1 Like

One issue I’m seeing with this approach is that my control state (kontrol values) is not being preserved between runs with this approach with live looping.

Hi!

I wrote such code for a different controller. I don’t think you could use it directly (maybe with some modifications), but maybe you find some inspiration. The approach is basically the same: a live loop and sync on the MIDI events to update some general state that can then be looked up and used in different ways. I use get and set a lot for that state, I think it’s the standard way in sonic-pi to share information across threads in a safe way.

I hope it’s useful in some way!

1 Like

Thanks @porras, some great ideas here, I will try to incorporate. Use of get and set to persist values might solve my state persistence issue.

Cheers,
Nick