Midi_messages2

Re-writing my old midi-event listener. Still using external command aseqdump, but separated the reader and the parser into separate fibers.

Right now only tested on one controller (keystation 49es).. but will make it work with oxygen 25, KORG padKONTROL and Zoom R16.

I will add on event subscription via wisper.

require 'open3'

CLIENT = 'Keystation 49es'

symbolize = ->(str) { str.tr(' ', '_').downcase.to_sym }
hashify   = ->(str) { str.split(',').map { it.split(' ') }
  .map {|k,v| [k.to_sym, v.to_i] }.to_h }


midi = Fiber.new { 
  port = `aseqdump -l`.lines(chomp: true)
    .select { it.include?(CLIENT) }[0]
    .then { it[/(\d+:\d+)/] ? $1 : abort('No such client') }

  wr, rd = Open3.popen2("aseqdump -p #{port}"); wr.close

  while line = rd.gets.chomp; Fiber.yield line end
}


parse = Fiber.new { 
  loop {
    if /(?<event>\w+ \w+).*?\d+, (?<data>.*)$/ =~ midi.resume
      Fiber.yield [symbolize[event], hashify[data]]
    end
  }
}


loop { p parse.resume }

Made some additions…

require 'wisper'
require 'open3'

CLIENT = 'Keystation 49es'
# CLIENT = 'R16'

symbolize = ->(str) { str.tr(' ', '_').downcase.to_sym }
hashify   = ->(str) { str.split(',').map { it.split(' ') }
  .map {|k,v| [k.to_sym, v.to_i] }.to_h }


midi = Fiber.new { 
  port = `aseqdump -l`.lines(chomp: true)
    .select { it.include?(CLIENT) }[0]
    .then { it[/(\d+:\d+)/] ? $1 : abort('No such client') }

  wr, rd = Open3.popen2("aseqdump -p #{port}"); wr.close

  while line = rd.gets.chomp; Fiber.yield line end
}


parse = Fiber.new { 
  include Wisper::Publisher
  
  loop {
    if /(?<event>\w+ \w+).*?(?<channel>\d+), (?<data>.*)$/ =~ midi.resume
      publish(symbolize[event], hashify["channel #{channel}," + data])
    end
  }
}



# output all events and data
# class Lizten
#   def note_on(msg)        = ( p msg )
#   def note_off(msg)       = ( p msg )
#   def control_change(msg) = ( p msg )
#   def pitch_bend(msg)     = ( p msg )
# end

# Wisper.subscribe(Lizten.new)

# output note-name
class Notename
  def append(data)
    p %w(C C♯/D♭ D D♯/E♭ E F F♯/G♭ G G♯/A♭ A A♯/B♭ B)[data[:note] % 12]
  end
end

Wisper.subscribe(Notename.new, on: [:note_on, :note_off], with: :append )



loop { parse.resume }