Class: Rtmidi::MidiIn

Inherits:
Object
  • Object
show all
Defined in:
lib/rtmidi/midi_in.rb

Defined Under Namespace

Classes: Release

Constant Summary collapse

DEFAULT_CLIENT_NAME =
"Rtmidi Ruby Client"
DEFAULT_PORT_NAME =
"Rtmidi Input"
DEFAULT_QUEUE_SIZE_LIMIT =
1024
POLL_BUFFER_SIZE =
65_536

Instance Method Summary collapse

Constructor Details

#initialize(api: :unspecified, client_name: DEFAULT_CLIENT_NAME, queue_size_limit: DEFAULT_QUEUE_SIZE_LIMIT) ⇒ MidiIn

Returns a new instance of MidiIn.

Raises:



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

def initialize(api: :unspecified, client_name: DEFAULT_CLIENT_NAME, queue_size_limit: DEFAULT_QUEUE_SIZE_LIMIT)
  Native.ensure_loaded!
  queue_limit = integer_for(queue_size_limit, "queue_size_limit")

  @mutex = Mutex.new
  @port_open = false
  @closed = false
  @last_async_error = nil
  @user_error_callback = nil
  @error_callback = nil
  @message_callback = nil

  @handle = Native.rtmidi_in_create(Api.normalize(api), client_name.to_s, queue_limit)
  raise Error, "failed to create RtMidi input device" if @handle.nil? || @handle.null?

  @release = Release.new(@handle)
  ObjectSpace.define_finalizer(self, @release)

  setup_error_callback
  Native.check_error(@handle)
end

Instance Method Details

#cancel_callbackObject



142
143
144
145
146
147
148
149
150
151
# File 'lib/rtmidi/midi_in.rb', line 142

def cancel_callback
  with_device_lock do
    if @message_callback
      Native.rtmidi_in_cancel_callback(@handle)
      Native.check_error(@handle)
      @message_callback = nil
    end
  end
  self
end

#closeObject



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rtmidi/midi_in.rb', line 187

def close
  @mutex.synchronize do
    return if @closed

    begin
      if @message_callback
        Native.rtmidi_in_cancel_callback(@handle)
        Native.check_error(@handle)
        @message_callback = nil
      end

      if @port_open
        Native.rtmidi_close_port(@handle)
        Native.check_error(@handle)
        @port_open = false
      end
    ensure
      @release&.free
      @handle = nil
      @closed = true
    end
  end
  nil
end

#close_portObject



90
91
92
93
94
95
96
97
# File 'lib/rtmidi/midi_in.rb', line 90

def close_port
  with_device_lock do
    Native.rtmidi_close_port(@handle)
    Native.check_error(@handle)
    @port_open = false
  end
  self
end

#closed?Boolean

Returns:

  • (Boolean)


212
213
214
# File 'lib/rtmidi/midi_in.rb', line 212

def closed?
  @mutex.synchronize { @closed }
end

#current_apiObject



103
104
105
106
107
# File 'lib/rtmidi/midi_in.rb', line 103

def current_api
  with_device_lock do
    Api.normalize(Native.rtmidi_in_get_current_api(@handle))
  end
end

#current_api_display_nameObject



113
114
115
# File 'lib/rtmidi/midi_in.rb', line 113

def current_api_display_name
  Rtmidi.api_display_name(current_api)
end

#current_api_nameObject



109
110
111
# File 'lib/rtmidi/midi_in.rb', line 109

def current_api_name
  Rtmidi.api_name(current_api)
end

#get_message(parsed: false) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/rtmidi/midi_in.rb', line 153

def get_message(parsed: false)
  with_device_lock do
    raise InvalidUseError, "get_message cannot be used while callback is set" if @message_callback

    buffer = FFI::MemoryPointer.new(:uint8, POLL_BUFFER_SIZE)
    size_ptr = FFI::MemoryPointer.new(:size_t, 1)
    Native.write_size_t(size_ptr, POLL_BUFFER_SIZE)

    timestamp = Native.rtmidi_in_get_message(@handle, buffer, size_ptr)
    Native.check_error(@handle)

    size = Native.read_size_t(size_ptr)
    return nil if size.zero?

    bytes = buffer.read_array_of_uint8(size)
    [parsed ? Rtmidi::Message.parse(bytes) : bytes, timestamp]
  end
end

#ignore_types(sysex: true, timing: true, active_sensing: true) ⇒ Object



172
173
174
175
176
177
178
# File 'lib/rtmidi/midi_in.rb', line 172

def ignore_types(sysex: true, timing: true, active_sensing: true)
  with_device_lock do
    Native.rtmidi_in_ignore_types(@handle, !!sysex, !!timing, !!active_sensing)
    Native.check_error(@handle)
  end
  self
end

#on_error(&block) ⇒ Object

Raises:

  • (ArgumentError)


180
181
182
183
184
185
# File 'lib/rtmidi/midi_in.rb', line 180

def on_error(&block)
  raise ArgumentError, "block required" unless block

  @mutex.synchronize { @user_error_callback = block }
  self
end

#open_port(number, name: DEFAULT_PORT_NAME) ⇒ Object



71
72
73
74
75
76
77
78
79
# File 'lib/rtmidi/midi_in.rb', line 71

def open_port(number, name: DEFAULT_PORT_NAME)
  with_device_lock do
    index = normalize_port_number(number, port_count_locked)
    Native.rtmidi_open_port(@handle, index, name.to_s)
    Native.check_error(@handle)
    @port_open = true
  end
  self
end

#open_virtual_port(name: "Rtmidi Virtual Input") ⇒ Object



81
82
83
84
85
86
87
88
# File 'lib/rtmidi/midi_in.rb', line 81

def open_virtual_port(name: "Rtmidi Virtual Input")
  with_device_lock do
    Native.rtmidi_open_virtual_port(@handle, name.to_s)
    Native.check_error(@handle)
    @port_open = true
  end
  self
end

#port_countObject



52
53
54
55
56
# File 'lib/rtmidi/midi_in.rb', line 52

def port_count
  with_device_lock do
    port_count_locked
  end
end

#port_name(number) ⇒ Object



58
59
60
61
62
# File 'lib/rtmidi/midi_in.rb', line 58

def port_name(number)
  with_device_lock do
    port_name_locked(normalize_port_number(number, port_count_locked))
  end
end

#port_namesObject



64
65
66
67
68
69
# File 'lib/rtmidi/midi_in.rb', line 64

def port_names
  with_device_lock do
    count = port_count_locked
    Array.new(count) { |index| port_name_locked(index) }
  end
end

#port_open?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/rtmidi/midi_in.rb', line 99

def port_open?
  @mutex.synchronize { @port_open }
end

#set_callback(parsed: false, &block) ⇒ Object Also known as: on_message

Raises:

  • (ArgumentError)


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rtmidi/midi_in.rb', line 117

def set_callback(parsed: false, &block)
  raise ArgumentError, "block required" unless block

  with_device_lock do
    raise InvalidUseError, "callback already set" if @message_callback

    @message_callback = proc do |timestamp, msg_ptr, msg_size, _user_data|
      bytes = if msg_ptr.nil? || msg_ptr.null? || msg_size.to_i <= 0
                []
              else
                msg_ptr.read_array_of_uint8(msg_size.to_i)
              end
      payload = parsed ? Rtmidi::Message.parse(bytes) : bytes
      block.call(payload, timestamp)
    rescue StandardError => e
      @mutex.synchronize { @last_async_error ||= e }
    end

    Native.rtmidi_in_set_callback(@handle, @message_callback, nil)
    Native.check_error(@handle)
  end
  self
end