class MIDI::Sequence

A MIDI::Sequence contains MIDI::Track objects.

Constants

DEFAULT_TEMPO
NOTE_TO_LENGTH
UNNAMED

Attributes

clocks[RW]
denom[RW]
format[RW]

The MIDI file format (0, 1, or 2)

numer[RW]
ppqn[RW]

Pulses (i.e. clocks) Per Quarter Note resolution for the sequence

qnotes[RW]
reader_class[RW]

The class to use for reading MIDI from a stream. The default is MIDI::IO::SeqReader. You can change this at any time.

tracks[RW]

Array with all tracks for the sequence

writer_class[RW]

The class to use for writeing MIDI from a stream. The default is MIDI::IO::SeqWriter. You can change this at any time.

Public Class Methods

new() click to toggle source
# File lib/midilib/sequence.rb, line 43
def initialize
  @tracks = []
  @ppqn = 480

  # Time signature
  @numer = 4 # Numer + denom = 4/4 time default
  @denom = 2
  @clocks = 24 # Bug fix  Nov 11, 2007 - this is not the same as ppqn!
  @qnotes = 8

  @reader_class = IO::SeqReader
  @writer_class = IO::SeqWriter
end

Public Instance Methods

beats_per_minute() click to toggle source

Returns the song tempo in beats per minute.

# File lib/midilib/sequence.rb, line 66
def beats_per_minute
  return DEFAULT_TEMPO if @tracks.nil? || @tracks.empty?

  event = @tracks.first.events.detect { |e| e.is_a?(MIDI::Tempo) }
  event ? Tempo.mpq_to_bpm(event.tempo) : DEFAULT_TEMPO
end
Also aliased as: bpm, tempo
bpm()
Alias for: beats_per_minute
each() { |track| ... } click to toggle source

Iterates over the tracks.

# File lib/midilib/sequence.rb, line 154
def each(&block) # :yields: track
  @tracks.each(&block)
end
get_measures() click to toggle source

Returns a Measures object, which is an array container for all measures in the sequence

# File lib/midilib/sequence.rb, line 160
def get_measures
  # Collect time sig events and scan for last event time
  time_sigs = []
  max_pos = 0
  @tracks.each do |t|
    t.each do |e|
      time_sigs << e if e.is_a?(MIDI::TimeSig)
      max_pos = e.time_from_start if e.time_from_start > max_pos
    end
  end
  time_sigs.sort { |x, y| x.time_from_start <=> y.time_from_start }

  # Add a "fake" time sig event at the very last position of the sequence,
  # just to make sure the whole sequence is calculated.
  t = MIDI::TimeSig.new(4, 2, 24, 8, 0)
  t.time_from_start = max_pos
  time_sigs << t

  # Default to 4/4
  measure_length = @ppqn * 4
  oldnumer = 4
  olddenom = 2
  oldbeats = 24

  measures = MIDI::Measures.new(max_pos, @ppqn)
  curr_pos = 0
  curr_meas_no = 1
  time_sigs.each do |te|
    meas_count = (te.time_from_start - curr_pos) / measure_length
    meas_count += 1 if (te.time_from_start - curr_pos) % measure_length > 0
    1.upto(meas_count) do |i|
      measures << MIDI::Measure.new(curr_meas_no, curr_pos, measure_length,
                                    oldnumer, olddenom, oldbeats)
      curr_meas_no += 1
      curr_pos += measure_length
    end
    oldnumer = te.numerator
    olddenom = te.denominator
    oldbeats = te.metronome_ticks
    measure_length = te.measure_duration(@ppqn)
  end
  measures
end
length_to_delta(length) click to toggle source

Translates length (a multiple of a quarter note) into a delta time. For example, 1 is a quarter note, 1.0/32.0 is a 32nd note, 1.5 is a dotted quarter, etc. Be aware when using division; 1/32 is zero due to integer mathematics and rounding. Use floating-point numbers like 1.0 and 32.0. This method always returns an integer by calling ‘.round` on the floating-point result.

See also note_to_delta and note_to_length.

# File lib/midilib/sequence.rb, line 122
def length_to_delta(length)
  (@ppqn * length).round
end
name() click to toggle source

Returns the name of the first track (track zero). If there are no tracks, returns UNNAMED.

# File lib/midilib/sequence.rb, line 128
def name
  return UNNAMED if @tracks.empty?

  @tracks.first.name
end
name=(name) click to toggle source

Hands the name to the first track. Does nothing if there are no tracks.

# File lib/midilib/sequence.rb, line 135
def name=(name)
  return if @tracks.empty?

  @tracks.first.name = name
end
note_to_delta(name) click to toggle source

Given a note length name like “whole”, “dotted quarter”, or “8th triplet”, return the length of that note in quarter notes as a delta time.

# File lib/midilib/sequence.rb, line 85
def note_to_delta(name)
  length_to_delta(note_to_length(name))
end
note_to_length(name) click to toggle source

Given a note length name like “whole”, “dotted quarter”, or “8th triplet”, return the length of that note in quarter notes as a floating-point number, suitable for use as an argument to length_to_delta.

Legal names are any value in NOTE_TO_LENGTH, optionally prefixed by “dotted_” and/or suffixed by “_triplet”. So, for example, “dotted_quarter_triplet” returns the length of a dotted quarter-note triplet and “32nd” returns 1/32.

# File lib/midilib/sequence.rb, line 98
def note_to_length(name)
  name.strip!
  name =~ /^(dotted)?(.*?)(triplet)?$/
  dotted = Regexp.last_match(1)
  note_name = Regexp.last_match(2)
  triplet = Regexp.last_match(3)
  note_name.strip!
  mult = 1.0
  mult = 1.5 if dotted
  mult /= 3.0 if triplet
  len = NOTE_TO_LENGTH[note_name]
  raise "Sequence.note_to_length: \"#{note_name}\" not understood in \"#{name}\"" unless len

  len * mult
end
pulses_to_seconds(pulses) click to toggle source

Pulses (also called ticks) are the units of delta times and event time_from_start values. This method converts a number of pulses to a float value that is a time in seconds.

# File lib/midilib/sequence.rb, line 78
def pulses_to_seconds(pulses)
  (pulses.to_f / @ppqn.to_f / beats_per_minute) * 60.0
end
read(io) { |track, num_tracks, index| ... } click to toggle source

Reads a MIDI stream.

# File lib/midilib/sequence.rb, line 142
def read(io, &block) # :yields: track, num_tracks, index
  reader = @reader_class.new(self, &block)
  reader.read_from(io)
end
tempo()
Alias for: beats_per_minute
time_signature(numer, denom, clocks, qnotes) click to toggle source

Sets the time signature.

# File lib/midilib/sequence.rb, line 58
def time_signature(numer, denom, clocks, qnotes)
  @numer = numer
  @denom = denom
  @clocks = clocks
  @qnotes = qnotes
end
write(io, midi_format = 1) { |track, num_tracks, index| ... } click to toggle source

Writes to a MIDI stream. midi_format defaults to 1.

# File lib/midilib/sequence.rb, line 148
def write(io, midi_format = 1, &block) # :yields: track, num_tracks, index
  writer = @writer_class.new(self, midi_format, &block)
  writer.write_to(io)
end