class AlsaRawMIDI::Input
Input
device class
Attributes
Public Class Methods
All available inputs @return [Array<Input>]
# File lib/alsa-rawmidi/input.rb, line 97 def self.all Device.all_by_type[:input] end
The first input available @return [Input]
# File lib/alsa-rawmidi/input.rb, line 85 def self.first Device.first(:input) end
The last input available @return [Input]
# File lib/alsa-rawmidi/input.rb, line 91 def self.last Device.last(:input) end
Public Instance Methods
Close this input @return [Boolean]
# File lib/alsa-rawmidi/input.rb, line 72 def close if @enabled Thread.kill(@listener) API::Device.close(@resource) @enabled = false true else false end end
Enable this the input for use; yields @param [Hash] options @param [Proc] block @return [Input] self
# File lib/alsa-rawmidi/input.rb, line 50 def enable(options = {}, &block) unless @enabled @start_time = Time.now.to_f @resource = API::Input.open(@system_id) @enabled = true initialize_buffer spawn_listener end if block_given? begin yield(self) ensure close end end self end
An array of MIDI event hashes as such: [
{ :data => [144, 60, 100], :timestamp => 1024 }, { :data => [128, 60, 100], :timestamp => 1100 }, { :data => [144, 40, 120], :timestamp => 1200 }
]
The data is an array of numeric bytes The timestamp is the number of millis since this input was enabled
@return [Array<Hash>]
# File lib/alsa-rawmidi/input.rb, line 22 def gets loop until enqueued_messages? msgs = enqueued_messages @pointer = @buffer.length msgs end
Like Input#gets
but returns message data as string of hex digits as such:
[ { :data => "904060", :timestamp => 904 }, { :data => "804060", :timestamp => 1150 }, { :data => "90447F", :timestamp => 1300 } ]
@return [Array<Hash>]
# File lib/alsa-rawmidi/input.rb, line 38 def gets_s msgs = gets msgs.each { |m| m[:data] = numeric_bytes_to_hex_string(m[:data]) } msgs end
Private Instance Methods
The messages enqueued in the buffer @return [Array<Hash>]
# File lib/alsa-rawmidi/input.rb, line 135 def enqueued_messages @buffer.slice(@pointer, @buffer.length - @pointer) end
Are there messages enqueued? @return [Boolean]
# File lib/alsa-rawmidi/input.rb, line 141 def enqueued_messages? @pointer < @buffer.length end
A message paired with timestamp @param [String] hexstring @param [Float] timestamp @return [Hash]
# File lib/alsa-rawmidi/input.rb, line 126 def get_message_formatted(hexstring, timestamp) { :data => hex_string_to_numeric_bytes(hexstring), :timestamp => timestamp } end
Convert a hex string to an array of numeric bytes eg “904040” -> [0x90, 0x40, 0x40] @param [String] string @return [Array<Integer>]
# File lib/alsa-rawmidi/input.rb, line 175 def hex_string_to_numeric_bytes(string) string = string.dup bytes = [] until string.length.zero? string_byte = string.slice!(0, 2) bytes << string_byte.hex end bytes end
Initialize the input buffer @return [Array]
# File lib/alsa-rawmidi/input.rb, line 105 def initialize_buffer @pointer = 0 @buffer = [] def @buffer.clear super @pointer = 0 end @buffer end
A timestamp for the current time @return [Float]
# File lib/alsa-rawmidi/input.rb, line 117 def now time = Time.now.to_f - @start_time time * 1000 end
Convert an array of numeric bytes to a hex string eg [0x90, 0x40, 0x40] -> “904040” @param [Array<Integer>] bytes @return [String]
# File lib/alsa-rawmidi/input.rb, line 188 def numeric_bytes_to_hex_string(bytes) string_bytes = bytes.map do |byte| string_byte = byte.to_s(16).upcase string_byte = "0#{string_byte}" if byte < 16 string_byte end string_bytes.join end
Collect messages from the system buffer @return [Array<String>, nil]
# File lib/alsa-rawmidi/input.rb, line 168 def populate_buffer(messages) @buffer << get_message_formatted(messages, now) unless messages.nil? end
Launch a background thread that collects messages and holds them for the next call to gets* @return [Thread]
# File lib/alsa-rawmidi/input.rb, line 148 def spawn_listener interval = 1.0/1000 @listener = Thread.new do begin loop do while (messages = API::Input.poll(@resource)).nil? sleep(interval) end populate_buffer(messages) unless messages.nil? end rescue Exception => exception Thread.main.raise(exception) end end @listener.abort_on_exception = true @listener end