Class: Musa::MIDIVoices::MIDIVoices

Inherits:
Object
  • Object
show all
Defined in:
lib/musa-dsl/midi/midi-voices.rb

Overview

Note:

All durations are expressed as Rational numbers representing bars.

Note:

MIDI channels are zero-indexed (0-15), not 1-16.

High level helpers to drive one or more MIDI channels from a Sequencer::Sequencer.

A voice represents the state of a given MIDI channel (active notes, controllers, sustain pedal, etc.). MIDIVoices ties the life‑cycle of those voices to the sequencer clock so that note durations, waits and callbacks stay in the musical timeline even when running in fast-forward or quantized sessions.

Typical usage:

Examples:

Basic setup and playback

require 'musa-dsl'
require 'midi-communications'

clock     = Musa::Clock::TimerClock.new bpm: 120
transport = Musa::Transport::Transport.new clock
output    = MIDICommunications::Output.all.first

voices = Musa::MIDIVoices::MIDIVoices.new(
  sequencer: transport.sequencer,
  output:    output,
  channels:  [0, 1] # also accepts ranges such as 0..7
)

voices.voices.first.note pitch: 64, velocity: 90, duration: 1r / 4

Playing chords

voice = voices.voices.first
voice.note pitch: [60, 64, 67], velocity: 90, duration: 1r

Using note controls with callbacks

voice = voices.voices.first
note_ctrl = voice.note pitch: 60, duration: nil  # indefinite
note_ctrl.on_stop { puts "Note ended!" }
# ... later:
note_ctrl.note_off

Fast-forward for silent catch-up

voices.fast_forward = true
# ... replay past events ...
voices.fast_forward = false  # resumes audible output

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sequencer:, output:, channels:, do_log: nil) ⇒ void

Builds the voice container for one or many MIDI channels.

Parameters:

  • sequencer (Musa::Sequencer::Sequencer)

    sequencer that schedules waits and callbacks.

  • output (#puts, nil)

    anything responding to puts that accepts MIDIEvents::Events (typically a MIDICommunications output).

  • channels (Array<Numeric>, Range, Numeric)

    list of MIDI channels to control. Ranges are expanded automatically.

  • do_log (Boolean) (defaults to: nil)

    enables info level logs per emitted message.



115
116
117
118
119
120
121
122
123
124
# File 'lib/musa-dsl/midi/midi-voices.rb', line 115

def initialize(sequencer:, output:, channels:, do_log: nil)
  do_log ||= false

  @sequencer = sequencer
  @output = output
  @channels = channels.arrayfy.explode_ranges
  @do_log = do_log

  reset
end

Instance Attribute Details

#do_logBoolean

Returns whether verbose logging is enabled.

Returns:

  • (Boolean)

    whether verbose logging is enabled.



105
106
107
# File 'lib/musa-dsl/midi/midi-voices.rb', line 105

def do_log
  @do_log
end

#voicesArray<MIDIVoice> (readonly)

Returns read-only list of per-channel voices.

Returns:



135
136
137
# File 'lib/musa-dsl/midi/midi-voices.rb', line 135

def voices
  @voices
end

Instance Method Details

#fast_forward=(enabled) ⇒ void

This method returns an undefined value.

Enables or disables the fast-forward mode on every voice.

When enabled, notes are registered internally but their MIDI messages are not emitted, allowing the sequencer to catch up silently (e.g. when loading a snapshot).

Parameters:

  • enabled (Boolean)

    true to enable fast-forward, false to disable.



145
146
147
# File 'lib/musa-dsl/midi/midi-voices.rb', line 145

def fast_forward=(enabled)
  @voices.each { |voice| voice.fast_forward = enabled }
end

#panic(reset: nil) ⇒ void

This method returns an undefined value.

Sends all-notes-off on every channel and (optionally) a MIDI reset.

Parameters:

  • reset (Boolean) (defaults to: nil)

    whether to emit an FF SystemRealtime (panic) message.



153
154
155
156
157
158
159
# File 'lib/musa-dsl/midi/midi-voices.rb', line 153

def panic(reset: nil)
  reset ||= false

  @voices.each(&:all_notes_off)

  @output.puts MIDIEvents::SystemRealtime.new(0xff) if reset
end

#resetvoid

This method returns an undefined value.

Resets the collection recreating every Musa::MIDIVoices::MIDIVoice. Useful when the MIDI output has changed or after a panic.



130
131
132
# File 'lib/musa-dsl/midi/midi-voices.rb', line 130

def reset
  @voices = @channels.collect { |channel| MIDIVoice.new(sequencer: @sequencer, output: @output, channel: channel, do_log: @do_log) }.freeze
end