Class: MTK::IO::UniMIDIInput

Inherits:
MIDIInput show all
Defined in:
lib/mtk/io/unimidi_input.rb

Overview

Note:

This class is optional and only available if you require ‘mtk/midi/unimidi_input’. It depends on the ‘unimidi’ gem.

Provides realtime MIDI input for MRI/YARV Ruby via the unimidi gem.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from MIDIInput

available_input_types, find_by_name, input_types_by_device, #name, open

Constructor Details

#initialize(input_device, options = {}) ⇒ UniMIDIInput

Returns a new instance of UniMIDIInput.



25
26
27
28
# File 'lib/mtk/io/unimidi_input.rb', line 25

def initialize(input_device, options={})
  super
  @open_time = Time.now.to_f
end

Instance Attribute Details

#deviceObject (readonly)

Returns the value of attribute device.



23
24
25
# File 'lib/mtk/io/unimidi_input.rb', line 23

def device
  @device
end

#recordingObject (readonly)

Returns the value of attribute recording.



23
24
25
# File 'lib/mtk/io/unimidi_input.rb', line 23

def recording
  @recording
end

#threadObject (readonly)

Returns the value of attribute thread.



23
24
25
# File 'lib/mtk/io/unimidi_input.rb', line 23

def thread
  @thread
end

Class Method Details

.devicesObject



14
15
16
# File 'lib/mtk/io/unimidi_input.rb', line 14

def self.devices
  @devices ||= ::UniMIDI::Input.all.reject{|d| d.name.strip.empty? }
end

.devices_by_nameObject



18
19
20
# File 'lib/mtk/io/unimidi_input.rb', line 18

def self.devices_by_name
  @devices_by_name ||= devices.each_with_object( Hash.new ){|device,hash| hash[device.name] = device }
end

Instance Method Details

#record(options = {}) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/mtk/io/unimidi_input.rb', line 30

def record(options={})
  @recording = [] unless options[:append] and @recording
  monitor = options[:monitor]

  stop
  @thread = Thread.new do
    @start_time = Time.now.to_f
    loop do
      @device.gets.each do |data|
        puts data if monitor
        record_raw_data data
      end
      sleep 0.001
    end
  end

  time_limit = options[:time_limit]
  if time_limit
    puts "Blocking current thread for #{time_limit} seconds to record MIDI input."
    @thread.join(time_limit)
  end
end

#stopObject



53
54
55
# File 'lib/mtk/io/unimidi_input.rb', line 53

def stop
  Thread.kill @thread if @thread
end

#to_timeline(options = {}) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/mtk/io/unimidi_input.rb', line 57

def to_timeline(options={})
  return nil if not @recording

  bpm = options.fetch :bmp, 120
  beats_per_second = bpm.to_f/60
  timeline = MTK::Events::Timeline.new
  note_ons = {}
  start = nil

  @recording.each do |message, time|
    start ||= time
    time -= start
    time /= beats_per_second

    if message.is_a? MTK::Events::Event
      timeline.add time,message unless message.type == :unknown
    else
      message_type = message.type
      message_type = :note_off if message_type == :note_on and message.velocity == 0
      # TODO: this will need to be made more robust when we support off velocities

      case message_type
      when :note_on
        pitch = message.pitch
        note_ons[pitch] = [message,time]

      when :note_off
        pitch = message.pitch
        if note_ons.has_key? pitch
          note_on, start_time = note_ons.delete(pitch)
          duration = time - start_time
          note = MTK::Events::Note.from_midi pitch, note_on.velocity, duration
          timeline.add time,note
        end
      end
    end
  end

  timeline.quantize! options[:quantize] if options.key? :quantize
  timeline.shift_to! options[:shift_to] if options.key? :shift_to

  timeline
end