Class: Musa::MIDIVoices::MIDIVoice Private
- Defined in:
- lib/musa-dsl/midi/midi-voices.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Individual MIDI channel voice with sequencer-synchronized note management.
Manages the state of a single MIDI channel including active notes, controller values, and sustain pedal. All note scheduling is tied to the sequencer clock, ensuring proper timing in fast-forward mode or during quantized playback.
Supports indefinite notes (manual note-off), automatic note-off scheduling, callbacks on note stop, and fast-forward mode for silent state updates.
Instance Attribute Summary collapse
-
#active_pitches ⇒ Array<Hash>
readonly
private
Metadata for each of the 128 MIDI pitches.
-
#channel ⇒ Integer
readonly
private
MIDI channel number (0-15).
-
#do_log ⇒ Boolean
private
Whether this voice logs every emitted message.
-
#name ⇒ String?
private
Optional name used in log messages.
-
#output ⇒ #puts?
readonly
private
MIDI destination.
-
#sequencer ⇒ Musa::Sequencer::Sequencer
readonly
private
Sequencer driving this voice.
-
#tick_duration ⇒ Rational
readonly
private
Duration (in bars) of a sequencer tick; used to schedule note offs.
Instance Method Summary collapse
-
#all_notes_off ⇒ void
private
Sends immediate note-off messages for all active pitches and an all-notes-off message on this channel and resets internal state.
-
#controller ⇒ ControllersControl
private
MIDI CC manager for this voice.
-
#fast_forward=(enabled) ⇒ void
private
Turns fast-forward on/off for this voice.
-
#fast_forward? ⇒ Boolean
private
True when in fast-forward mode (notes registered but not emitted).
- #initialize(sequencer:, output:, channel:, name: nil, do_log: nil) ⇒ void constructor private
-
#log(msg) ⇒ void
private
Logs a message tagging the current voice.
-
#note(pitchvalue = nil, pitch: nil, velocity: nil, duration: nil, duration_offset: nil, note_duration: nil, velocity_off: nil) ⇒ NoteControl?
private
Plays one or several MIDI notes.
-
#sustain_pedal ⇒ Integer?
private
Current sustain pedal value.
-
#sustain_pedal=(value) ⇒ Object
private
Sets the sustain pedal state.
-
#to_s ⇒ String
private
Human-readable voice description.
Constructor Details
#initialize(sequencer:, output:, channel:, name: nil, do_log: nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 207 def initialize(sequencer:, output:, channel:, name: nil, do_log: nil) do_log ||= false @sequencer = sequencer @output = output @channel = channel @name = name @do_log = do_log @tick_duration = Rational(1, @sequencer.) @controllers_control = ControllersControl.new(@output, @channel) @active_pitches = [] fill_active_pitches @active_pitches @sequencer.logger.warn 'voice without output' unless @output self end |
Instance Attribute Details
#active_pitches ⇒ Array<Hash> (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns metadata for each of the 128 MIDI pitches. Mainly used internally.
196 197 198 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 196 def active_pitches @active_pitches end |
#channel ⇒ Integer (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns MIDI channel number (0-15).
193 194 195 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 193 def channel @channel end |
#do_log ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns whether this voice logs every emitted message.
184 185 186 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 184 def do_log @do_log end |
#name ⇒ String?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns optional name used in log messages.
181 182 183 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 181 def name @name end |
#output ⇒ #puts? (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns MIDI destination. When nil the voice becomes silent.
190 191 192 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 190 def output @output end |
#sequencer ⇒ Musa::Sequencer::Sequencer (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns sequencer driving this voice.
187 188 189 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 187 def sequencer @sequencer end |
#tick_duration ⇒ Rational (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns duration (in bars) of a sequencer tick; used to schedule note offs.
199 200 201 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 199 def tick_duration @tick_duration end |
Instance Method Details
#all_notes_off ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Sends immediate note-off messages for all active pitches and an all-notes-off message on this channel and resets internal state.
295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 295 def all_notes_off @output.puts MIDIEvents::ChannelMessage.new(0xb, @channel, 0x7b, 0) @active_pitches.each_with_index do |pitch_status, pitch| next if @fast_forward || pitch_status[:note_controls].empty? msg = MIDIEvents::NoteOff.new(@channel, pitch, 0) @output&.puts msg end @active_pitches.clear fill_active_pitches @active_pitches end |
#controller ⇒ ControllersControl
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns MIDI CC manager for this voice.
276 277 278 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 276 def controller @controllers_control end |
#fast_forward=(enabled) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Turns fast-forward on/off for this voice.
When disabling it, pending notes that were held silently are sent again so the synth is in sync with the sequencer state.
235 236 237 238 239 240 241 242 243 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 235 def fast_forward=(enabled) if @fast_forward && !enabled (0..127).each do |pitch| @output.puts MIDIEvents::NoteOn.new(@channel, pitch, @active_pitches[pitch][:velocity]) unless @active_pitches[pitch][:note_controls].empty? end end @fast_forward = enabled end |
#fast_forward? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns true when in fast-forward mode (notes registered but not emitted).
246 247 248 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 246 def fast_forward? @fast_forward end |
#log(msg) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Logs a message tagging the current voice.
313 314 315 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 313 def log(msg) @sequencer.logger.info('MIDIVoice') { "voice #{name || @channel}: #{msg}" } if @do_log end |
#note(pitchvalue = nil, pitch: nil, velocity: nil, duration: nil, duration_offset: nil, note_duration: nil, velocity_off: nil) ⇒ NoteControl?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Plays one or several MIDI notes.
260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 260 def note(pitchvalue = nil, pitch: nil, velocity: nil, duration: nil, duration_offset: nil, note_duration: nil, velocity_off: nil) pitch ||= pitchvalue if pitch velocity ||= 63 duration_offset ||= -@tick_duration note_duration ||= [0, duration + duration_offset].max velocity_off ||= 63 NoteControl.new(self, pitch: pitch, velocity: velocity, duration: note_duration, velocity_off: velocity_off).note_on end end |
#sustain_pedal ⇒ Integer?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns current sustain pedal value.
288 289 290 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 288 def sustain_pedal @controllers_control[:sustain_pedal] end |
#sustain_pedal=(value) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Sets the sustain pedal state.
283 284 285 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 283 def sustain_pedal=(value) @controllers_control[:sustain_pedal] = value end |
#to_s ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns human-readable voice description.
318 319 320 |
# File 'lib/musa-dsl/midi/midi-voices.rb', line 318 def to_s "voice #{@name} output: #{@output} channel: #{@channel}" end |