Class: Deftones::Music::Midi
- Inherits:
-
Object
- Object
- Deftones::Music::Midi
- Defined in:
- lib/deftones/music/midi.rb
Defined Under Namespace
Classes: OutputSession
Instance Attribute Summary collapse
-
#transport ⇒ Object
readonly
Returns the value of attribute transport.
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Class Method Summary collapse
- .available? ⇒ Boolean
- .control_change(controller, value, channel: 1, device: nil) ⇒ Object
- .find_device(devices, name) ⇒ Object private
- .find_input(name = nil) ⇒ Object
- .find_output(name = nil) ⇒ Object
- .input_devices ⇒ Object
- .load_backend! ⇒ Object private
- .matches_device_id?(device, selector) ⇒ Boolean private
- .message_data(message) ⇒ Object private
- .normalize_channel(channel) ⇒ Object private
- .normalize_data_byte(value) ⇒ Object private
- .normalize_note(note) ⇒ Object private
- .note_off(note, velocity: 0, channel: 1, device: nil) ⇒ Object
- .note_on(note, velocity: 100, channel: 1, device: nil) ⇒ Object
- .open_device(device, *args, &block) ⇒ Object private
- .open_input(name = nil, *args, &block) ⇒ Object
- .open_output(name = nil, *args, &block) ⇒ Object
- .open_output_session(name = nil, *args) ⇒ Object
- .output_devices ⇒ Object
- .parse(value) ⇒ Object
- .receive(name = nil, *args) ⇒ Object
- .send_message(message, device: nil) ⇒ Object
- .status_byte(base, channel) ⇒ Object private
- .sync_transport(message, transport: Deftones.transport) ⇒ Object
- .trigger_from_message(message, target:, time: nil, velocity_scale: 127.0) ⇒ Object
- .trigger_release(target, note, time) ⇒ Object private
Instance Method Summary collapse
- #dispose ⇒ Object
- #disposed? ⇒ Boolean
- #from_type(type) ⇒ Object
- #harmonize(intervals) ⇒ Object
-
#initialize(value, transport: Deftones.transport) ⇒ Midi
constructor
A new instance of Midi.
- #quantize(subdiv, percent = 1.0) ⇒ Object
- #to_bars_beats_sixteenths ⇒ Object
- #to_frequency ⇒ Object
- #to_i ⇒ Object
- #to_milliseconds ⇒ Object
- #to_notation ⇒ Object
- #to_note ⇒ Object
- #to_s ⇒ Object (also: #toString)
- #to_samples(sample_rate = Deftones.context.sample_rate) ⇒ Object
- #to_seconds ⇒ Object
- #to_ticks ⇒ Object
- #transpose(interval) ⇒ Object
- #value_of ⇒ Object
Constructor Details
Instance Attribute Details
#transport ⇒ Object (readonly)
Returns the value of attribute transport.
6 7 8 |
# File 'lib/deftones/music/midi.rb', line 6 def transport @transport end |
#value ⇒ Object (readonly)
Returns the value of attribute value.
6 7 8 |
# File 'lib/deftones/music/midi.rb', line 6 def value @value end |
Class Method Details
.available? ⇒ Boolean
101 102 103 104 |
# File 'lib/deftones/music/midi.rb', line 101 def available? load_backend! !!defined?(UniMIDI) end |
.control_change(controller, value, channel: 1, device: nil) ⇒ Object
165 166 167 168 169 170 |
# File 'lib/deftones/music/midi.rb', line 165 def control_change(controller, value, channel: 1, device: nil) ( [status_byte(0xB0, channel), normalize_data_byte(controller), normalize_data_byte(value)], device: device ) end |
.find_device(devices, name) ⇒ Object (private)
226 227 228 229 230 231 232 233 234 235 |
# File 'lib/deftones/music/midi.rb', line 226 def find_device(devices, name) return devices.first if name.nil? matched_by_id = devices.find { |device| matches_device_id?(device, name) } return matched_by_id if matched_by_id return devices[name] if name.is_a?(Integer) && name >= 0 && name < devices.length matcher = name.is_a?(Regexp) ? name : Regexp.new(Regexp.escape(name.to_s), Regexp::IGNORECASE) devices.find { |device| device.respond_to?(:name) && device.name.to_s.match?(matcher) } end |
.find_input(name = nil) ⇒ Object
118 119 120 |
# File 'lib/deftones/music/midi.rb', line 118 def find_input(name = nil) find_device(input_devices, name) end |
.find_output(name = nil) ⇒ Object
122 123 124 |
# File 'lib/deftones/music/midi.rb', line 122 def find_output(name = nil) find_device(output_devices, name) end |
.input_devices ⇒ Object
106 107 108 109 110 |
# File 'lib/deftones/music/midi.rb', line 106 def input_devices return [] unless available? UniMIDI::Input.all end |
.load_backend! ⇒ Object (private)
212 213 214 215 216 217 218 219 |
# File 'lib/deftones/music/midi.rb', line 212 def load_backend! return true if defined?(UniMIDI) require "unimidi" true rescue LoadError false end |
.matches_device_id?(device, selector) ⇒ Boolean (private)
237 238 239 240 241 242 243 244 245 246 |
# File 'lib/deftones/music/midi.rb', line 237 def matches_device_id?(device, selector) return false if selector.is_a?(Regexp) candidates = [] candidates << device.id if device.respond_to?(:id) candidates << device.device_id if device.respond_to?(:device_id) candidates << device.index if device.respond_to?(:index) candidates << device.device_index if device.respond_to?(:device_index) candidates.compact.any? { |candidate| candidate.to_s == selector.to_s } end |
.message_data(message) ⇒ Object (private)
221 222 223 224 |
# File 'lib/deftones/music/midi.rb', line 221 def () data = .is_a?(Hash) ? .fetch(:data, ) : Array(data).map(&:to_i) end |
.normalize_channel(channel) ⇒ Object (private)
280 281 282 283 284 285 |
# File 'lib/deftones/music/midi.rb', line 280 def normalize_channel(channel) integer = channel.to_i raise ArgumentError, "MIDI channel must be between 1 and 16" unless (1..16).cover?(integer) integer - 1 end |
.normalize_data_byte(value) ⇒ Object (private)
266 267 268 |
# File 'lib/deftones/music/midi.rb', line 266 def normalize_data_byte(value) value.to_i.clamp(0, 127) end |
.normalize_note(note) ⇒ Object (private)
262 263 264 |
# File 'lib/deftones/music/midi.rb', line 262 def normalize_note(note) normalize_data_byte(parse(note)) end |
.note_off(note, velocity: 0, channel: 1, device: nil) ⇒ Object
161 162 163 |
# File 'lib/deftones/music/midi.rb', line 161 def note_off(note, velocity: 0, channel: 1, device: nil) ([status_byte(0x80, channel), normalize_note(note), normalize_data_byte(velocity)], device: device) end |
.note_on(note, velocity: 100, channel: 1, device: nil) ⇒ Object
157 158 159 |
# File 'lib/deftones/music/midi.rb', line 157 def note_on(note, velocity: 100, channel: 1, device: nil) ([status_byte(0x90, channel), normalize_note(note), normalize_data_byte(velocity)], device: device) end |
.open_device(device, *args, &block) ⇒ Object (private)
248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/deftones/music/midi.rb', line 248 def open_device(device, *args, &block) raise Deftones::MissingMidiBackendError, "MIDI support is unavailable. Install the unimidi gem to enable MIDI I/O." unless available? raise ArgumentError, "No matching MIDI device found" unless device return device.open(*args) unless block device.open(*args) begin block.call(device) ensure device.close if device.respond_to?(:close) end end |
.open_input(name = nil, *args, &block) ⇒ Object
126 127 128 |
# File 'lib/deftones/music/midi.rb', line 126 def open_input(name = nil, *args, &block) open_device(find_input(name), *args, &block) end |
.open_output(name = nil, *args, &block) ⇒ Object
130 131 132 |
# File 'lib/deftones/music/midi.rb', line 130 def open_output(name = nil, *args, &block) open_device(find_output(name), *args, &block) end |
.open_output_session(name = nil, *args) ⇒ Object
134 135 136 137 138 139 140 141 142 143 |
# File 'lib/deftones/music/midi.rb', line 134 def open_output_session(name = nil, *args) session = OutputSession.new(open_output(name, *args)) return session unless block_given? begin yield session ensure session.close end end |
.output_devices ⇒ Object
112 113 114 115 116 |
# File 'lib/deftones/music/midi.rb', line 112 def output_devices return [] unless available? UniMIDI::Output.all end |
.parse(value) ⇒ Object
95 96 97 98 99 |
# File 'lib/deftones/music/midi.rb', line 95 def parse(value) return value.to_i if value.is_a?(Numeric) Note.to_midi(value) end |
.receive(name = nil, *args) ⇒ Object
145 146 147 148 149 |
# File 'lib/deftones/music/midi.rb', line 145 def receive(name = nil, *args) open_input(name) do |input| input.gets(*args) end end |
.send_message(message, device: nil) ⇒ Object
151 152 153 154 155 |
# File 'lib/deftones/music/midi.rb', line 151 def (, device: nil) open_output(device) do |output| output.puts() end end |
.status_byte(base, channel) ⇒ Object (private)
270 271 272 |
# File 'lib/deftones/music/midi.rb', line 270 def status_byte(base, channel) base + normalize_channel(channel) end |
.sync_transport(message, transport: Deftones.transport) ⇒ Object
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/deftones/music/midi.rb', line 172 def sync_transport(, transport: Deftones.transport) status = ().first.to_i case status when 0xF8 transport.ticks = transport.ticks + (transport.ppq / 24.0) :clock when 0xFA transport.ticks = 0 transport.start(0) :start when 0xFB transport.start(transport.seconds) :continue when 0xFC transport.stop :stop else :ignored end end |
.trigger_from_message(message, target:, time: nil, velocity_scale: 127.0) ⇒ Object
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/deftones/music/midi.rb', line 193 def (, target:, time: nil, velocity_scale: 127.0) data = () status = data.first.to_i command = status & 0xF0 return :ignored unless [0x80, 0x90].include?(command) note = Note.from_midi(normalize_data_byte(data[1])) velocity = normalize_data_byte(data[2]) / [velocity_scale.to_f, 1.0].max if command == 0x90 && velocity.positive? target.trigger_attack(note, time, velocity) :note_on else trigger_release(target, note, time) :note_off end end |
.trigger_release(target, note, time) ⇒ Object (private)
274 275 276 277 278 |
# File 'lib/deftones/music/midi.rb', line 274 def trigger_release(target, note, time) target.trigger_release(note, time) rescue ArgumentError target.trigger_release(time) end |
Instance Method Details
#dispose ⇒ Object
71 72 73 74 |
# File 'lib/deftones/music/midi.rb', line 71 def dispose @disposed = true self end |
#disposed? ⇒ Boolean
76 77 78 |
# File 'lib/deftones/music/midi.rb', line 76 def disposed? @disposed end |
#from_type(type) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/deftones/music/midi.rb', line 59 def from_type(type) @value = if type.respond_to?(:to_midi) type.to_midi elsif type.respond_to?(:value_of) type.value_of else type end self end |
#harmonize(intervals) ⇒ Object
50 51 52 |
# File 'lib/deftones/music/midi.rb', line 50 def harmonize(intervals) Array(intervals).map { |interval| transpose(interval) } end |
#quantize(subdiv, percent = 1.0) ⇒ Object
54 55 56 57 |
# File 'lib/deftones/music/midi.rb', line 54 def quantize(subdiv, percent = 1.0) quantized_seconds = UnitHelpers.quantize_seconds(to_seconds, subdiv, transport: transport, percent: percent) Note.to_midi(Note.from_frequency(1.0 / [quantized_seconds, 1.0e-6].max)) end |
#to_bars_beats_sixteenths ⇒ Object
30 31 32 |
# File 'lib/deftones/music/midi.rb', line 30 def transport.seconds_to_position(to_seconds) end |
#to_frequency ⇒ Object
18 19 20 |
# File 'lib/deftones/music/midi.rb', line 18 def to_frequency Note.to_frequency(to_note) end |
#to_i ⇒ Object
14 15 16 |
# File 'lib/deftones/music/midi.rb', line 14 def to_i self.class.parse(value) end |
#to_milliseconds ⇒ Object
34 35 36 |
# File 'lib/deftones/music/midi.rb', line 34 def to_milliseconds to_seconds * 1000.0 end |
#to_notation ⇒ Object
42 43 44 |
# File 'lib/deftones/music/midi.rb', line 42 def to_notation UnitHelpers.closest_notation(to_seconds, transport: transport) end |
#to_note ⇒ Object
86 87 88 |
# File 'lib/deftones/music/midi.rb', line 86 def to_note Note.from_midi(to_i) end |
#to_s ⇒ Object Also known as: toString
80 81 82 |
# File 'lib/deftones/music/midi.rb', line 80 def to_s value.to_s end |
#to_samples(sample_rate = Deftones.context.sample_rate) ⇒ Object
38 39 40 |
# File 'lib/deftones/music/midi.rb', line 38 def to_samples(sample_rate = Deftones.context.sample_rate) UnitHelpers.samples_for_seconds(to_seconds, sample_rate) end |
#to_seconds ⇒ Object
22 23 24 |
# File 'lib/deftones/music/midi.rb', line 22 def to_seconds 1.0 / to_frequency end |
#to_ticks ⇒ Object
26 27 28 |
# File 'lib/deftones/music/midi.rb', line 26 def to_ticks transport.seconds_to_ticks(to_seconds) end |
#transpose(interval) ⇒ Object
46 47 48 |
# File 'lib/deftones/music/midi.rb', line 46 def transpose(interval) self.class.new(to_i + interval.to_i, transport: transport) end |
#value_of ⇒ Object
90 91 92 |
# File 'lib/deftones/music/midi.rb', line 90 def value_of to_i end |