Class: Rtmidi::MidiOut

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

Defined Under Namespace

Classes: Release

Constant Summary collapse

DEFAULT_CLIENT_NAME =
"Rtmidi Ruby Client"
DEFAULT_PORT_NAME =
"Rtmidi Output"

Instance Method Summary collapse

Constructor Details

#initialize(api: :unspecified, client_name: DEFAULT_CLIENT_NAME) ⇒ MidiOut

Returns a new instance of MidiOut.

Raises:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rtmidi/midi_out.rb', line 28

def initialize(api: :unspecified, client_name: DEFAULT_CLIENT_NAME)
  Native.ensure_loaded!

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

  @handle = Native.rtmidi_out_create(Api.normalize(api), client_name.to_s)
  raise Error, "failed to create RtMidi output 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

#active_sensingObject



218
219
220
# File 'lib/rtmidi/midi_out.rb', line 218

def active_sensing
  send_message(Rtmidi::Message::ActiveSensing.new)
end

#channel_aftertouch(channel, pressure) ⇒ Object



171
172
173
174
175
176
# File 'lib/rtmidi/midi_out.rb', line 171

def channel_aftertouch(channel, pressure)
  send_message([
    status_byte(0xD0, channel),
    data_byte(pressure, "pressure")
  ])
end

#closeObject



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/rtmidi/midi_out.rb', line 244

def close
  @mutex.synchronize do
    return if @closed

    begin
      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



86
87
88
89
90
91
92
93
# File 'lib/rtmidi/midi_out.rb', line 86

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)


263
264
265
# File 'lib/rtmidi/midi_out.rb', line 263

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

#continueObject



210
211
212
# File 'lib/rtmidi/midi_out.rb', line 210

def continue
  send_message(Rtmidi::Message::Continue.new)
end

#control_change(channel, controller, value) ⇒ Object



147
148
149
150
151
152
153
# File 'lib/rtmidi/midi_out.rb', line 147

def control_change(channel, controller, value)
  send_message([
    status_byte(0xB0, channel),
    data_byte(controller, "controller"),
    data_byte(value, "value")
  ])
end

#current_apiObject



99
100
101
102
103
# File 'lib/rtmidi/midi_out.rb', line 99

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

#current_api_display_nameObject



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

def current_api_display_name
  Rtmidi.api_display_name(current_api)
end

#current_api_nameObject



105
106
107
# File 'lib/rtmidi/midi_out.rb', line 105

def current_api_name
  Rtmidi.api_name(current_api)
end

#note_off(channel, note, velocity: 0) ⇒ Object



139
140
141
142
143
144
145
# File 'lib/rtmidi/midi_out.rb', line 139

def note_off(channel, note, velocity: 0)
  send_message([
    status_byte(0x80, channel),
    data_byte(note, "note"),
    data_byte(velocity, "velocity")
  ])
end

#note_on(channel, note, velocity) ⇒ Object



131
132
133
134
135
136
137
# File 'lib/rtmidi/midi_out.rb', line 131

def note_on(channel, note, velocity)
  send_message([
    status_byte(0x90, channel),
    data_byte(note, "note"),
    data_byte(velocity, "velocity")
  ])
end

#nrpn(channel, parameter, value) ⇒ Object



226
227
228
229
230
231
232
233
234
235
# File 'lib/rtmidi/midi_out.rb', line 226

def nrpn(channel, parameter, value)
  parameter_number = normalize_range(parameter, 0, 16_383, "parameter")
  data_value = normalize_range(value, 0, 16_383, "value")

  control_change(channel, 99, (parameter_number >> 7) & 0x7F)
  control_change(channel, 98, parameter_number & 0x7F)
  control_change(channel, 6, (data_value >> 7) & 0x7F)
  control_change(channel, 38, data_value & 0x7F)
  self
end

#on_error(&block) ⇒ Object

Raises:

  • (ArgumentError)


237
238
239
240
241
242
# File 'lib/rtmidi/midi_out.rb', line 237

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



67
68
69
70
71
72
73
74
75
# File 'lib/rtmidi/midi_out.rb', line 67

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 Output") ⇒ Object



77
78
79
80
81
82
83
84
# File 'lib/rtmidi/midi_out.rb', line 77

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

#pitch_bend(channel, value) ⇒ Object



162
163
164
165
166
167
168
169
# File 'lib/rtmidi/midi_out.rb', line 162

def pitch_bend(channel, value)
  bend = normalize_range(value, 0, 16_383, "value")
  send_message([
    status_byte(0xE0, channel),
    bend & 0x7F,
    (bend >> 7) & 0x7F
  ])
end

#poly_aftertouch(channel, note, pressure) ⇒ Object



178
179
180
181
182
183
184
# File 'lib/rtmidi/midi_out.rb', line 178

def poly_aftertouch(channel, note, pressure)
  send_message([
    status_byte(0xA0, channel),
    data_byte(note, "note"),
    data_byte(pressure, "pressure")
  ])
end

#port_countObject



48
49
50
51
52
# File 'lib/rtmidi/midi_out.rb', line 48

def port_count
  with_device_lock do
    port_count_locked
  end
end

#port_name(number) ⇒ Object



54
55
56
57
58
# File 'lib/rtmidi/midi_out.rb', line 54

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

#port_namesObject



60
61
62
63
64
65
# File 'lib/rtmidi/midi_out.rb', line 60

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)


95
96
97
# File 'lib/rtmidi/midi_out.rb', line 95

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

#program_change(channel, program) ⇒ Object



155
156
157
158
159
160
# File 'lib/rtmidi/midi_out.rb', line 155

def program_change(channel, program)
  send_message([
    status_byte(0xC0, channel),
    data_byte(program, "program")
  ])
end

#send_message(message) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rtmidi/midi_out.rb', line 113

def send_message(message)
  bytes = normalize_message(message)

  with_device_lock do
    raise InvalidUseError, "port is not open" unless @port_open

    buffer = FFI::MemoryPointer.new(:uint8, bytes.length)
    buffer.write_array_of_uint8(bytes)
    Native.rtmidi_out_send_message(@handle, buffer, bytes.length)
    Native.check_error(@handle)
  end
  self
end

#song_position_pointer(position) ⇒ Object



190
191
192
# File 'lib/rtmidi/midi_out.rb', line 190

def song_position_pointer(position)
  send_message(Rtmidi::Message::SongPositionPointer.new(position: position))
end

#song_select(song) ⇒ Object



194
195
196
# File 'lib/rtmidi/midi_out.rb', line 194

def song_select(song)
  send_message(Rtmidi::Message::SongSelect.new(song: song))
end

#startObject



206
207
208
# File 'lib/rtmidi/midi_out.rb', line 206

def start
  send_message(Rtmidi::Message::Start.new)
end

#stopObject



214
215
216
# File 'lib/rtmidi/midi_out.rb', line 214

def stop
  send_message(Rtmidi::Message::Stop.new)
end

#sysex(data) ⇒ Object



127
128
129
# File 'lib/rtmidi/midi_out.rb', line 127

def sysex(data)
  send_message(Rtmidi::Message::SysEx.new(data: data))
end

#system_resetObject



222
223
224
# File 'lib/rtmidi/midi_out.rb', line 222

def system_reset
  send_message(Rtmidi::Message::SystemReset.new)
end

#time_code_quarter_frame(message_type, value) ⇒ Object



186
187
188
# File 'lib/rtmidi/midi_out.rb', line 186

def time_code_quarter_frame(message_type, value)
  send_message(Rtmidi::Message::TimeCodeQuarterFrame.new(message_type: message_type, value: value))
end

#timing_clockObject



202
203
204
# File 'lib/rtmidi/midi_out.rb', line 202

def timing_clock
  send_message(Rtmidi::Message::TimingClock.new)
end

#tune_requestObject



198
199
200
# File 'lib/rtmidi/midi_out.rb', line 198

def tune_request
  send_message(Rtmidi::Message::TuneRequest.new)
end