Class: MIDI::Sequence
- Inherits:
-
Object
- Object
- MIDI::Sequence
- Includes:
- Enumerable
- Defined in:
- lib/midilib/sequence.rb
Overview
A MIDI::Sequence contains MIDI::Track objects.
Constant Summary collapse
- UNNAMED =
'Unnamed Sequence'
- DEFAULT_TEMPO =
120
- NOTE_TO_LENGTH =
{ 'whole' => 4.0, 'half' => 2.0, 'quarter' => 1.0, 'eighth' => 0.5, '8th' => 0.5, 'sixteenth' => 0.25, '16th' => 0.25, 'thirty second' => 0.125, 'thirtysecond' => 0.125, '32nd' => 0.125, 'sixty fourth' => 0.0625, 'sixtyfourth' => 0.0625, '64th' => 0.0625 }
Instance Attribute Summary collapse
-
#clocks ⇒ Object
Returns the value of attribute clocks.
-
#denom ⇒ Object
Returns the value of attribute denom.
-
#format ⇒ Object
The MIDI file format (0, 1, or 2).
-
#numer ⇒ Object
Returns the value of attribute numer.
-
#ppqn ⇒ Object
Pulses (i.e. clocks) Per Quarter Note resolution for the sequence.
-
#qnotes ⇒ Object
Returns the value of attribute qnotes.
-
#reader_class ⇒ Object
The class to use for reading MIDI from a stream.
-
#tracks ⇒ Object
Array with all tracks for the sequence.
-
#writer_class ⇒ Object
The class to use for writeing MIDI from a stream.
Instance Method Summary collapse
-
#beats_per_minute ⇒ Object
(also: #bpm, #tempo)
Returns the song tempo in beats per minute.
-
#each ⇒ Object
Iterates over the tracks.
-
#get_measures ⇒ Object
Returns a Measures object, which is an array container for all measures in the sequence.
-
#initialize ⇒ Sequence
constructor
A new instance of Sequence.
-
#length_to_delta(length) ⇒ Object
Translates
length
(a multiple of a quarter note) into a delta time. -
#name ⇒ Object
Returns the name of the first track (track zero).
-
#name=(name) ⇒ Object
Hands the name to the first track.
-
#note_to_delta(name) ⇒ Object
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.
-
#note_to_length(name) ⇒ Object
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.
-
#read(io, proc = nil) ⇒ Object
Reads a MIDI stream.
-
#time_signature(numer, denom, clocks, qnotes) ⇒ Object
Sets the time signature.
-
#write(io, proc = nil) ⇒ Object
Writes to a MIDI stream.
Constructor Details
#initialize ⇒ Sequence
Returns a new instance of Sequence.
45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/midilib/sequence.rb', line 45 def initialize @tracks = Array.new() @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 |
Instance Attribute Details
#clocks ⇒ Object
Returns the value of attribute clocks.
37 38 39 |
# File 'lib/midilib/sequence.rb', line 37 def clocks @clocks end |
#denom ⇒ Object
Returns the value of attribute denom.
37 38 39 |
# File 'lib/midilib/sequence.rb', line 37 def denom @denom end |
#format ⇒ Object
The MIDI file format (0, 1, or 2)
36 37 38 |
# File 'lib/midilib/sequence.rb', line 36 def format @format end |
#numer ⇒ Object
Returns the value of attribute numer.
37 38 39 |
# File 'lib/midilib/sequence.rb', line 37 def numer @numer end |
#ppqn ⇒ Object
Pulses (i.e. clocks) Per Quarter Note resolution for the sequence
34 35 36 |
# File 'lib/midilib/sequence.rb', line 34 def ppqn @ppqn end |
#qnotes ⇒ Object
Returns the value of attribute qnotes.
37 38 39 |
# File 'lib/midilib/sequence.rb', line 37 def qnotes @qnotes end |
#reader_class ⇒ Object
The class to use for reading MIDI from a stream. The default is MIDI::IO::SeqReader. You can change this at any time.
40 41 42 |
# File 'lib/midilib/sequence.rb', line 40 def reader_class @reader_class end |
#tracks ⇒ Object
Array with all tracks for the sequence
32 33 34 |
# File 'lib/midilib/sequence.rb', line 32 def tracks @tracks end |
#writer_class ⇒ Object
The class to use for writeing MIDI from a stream. The default is MIDI::IO::SeqWriter. You can change this at any time.
43 44 45 |
# File 'lib/midilib/sequence.rb', line 43 def writer_class @writer_class end |
Instance Method Details
#beats_per_minute ⇒ Object Also known as: bpm, tempo
Returns the song tempo in beats per minute.
68 69 70 71 72 73 74 |
# File 'lib/midilib/sequence.rb', line 68 def beats_per_minute return DEFAULT_TEMPO if @tracks.nil? || @tracks.empty? event = @tracks.first.events.detect { | e | e.kind_of?(MIDI::Tempo) } return event ? (Tempo.mpq_to_bpm(event.tempo)) : DEFAULT_TEMPO end |
#each ⇒ Object
Iterates over the tracks.
144 145 146 |
# File 'lib/midilib/sequence.rb', line 144 def each # :yields: track @tracks.each { | track | yield track } end |
#get_measures ⇒ Object
Returns a Measures object, which is an array container for all measures in the sequence
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/midilib/sequence.rb', line 150 def get_measures # Collect time sig events and scan for last event time time_sigs = [] max_pos = 0 @tracks.each { |t| t.each { |e| time_sigs << e if e.kind_of?(MIDI::TimeSig) max_pos = e.time_from_start if e.time_from_start > max_pos } } 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, olddenom, oldbeats = 4, 2, 24 measures = MIDI::Measures.new(max_pos, @ppqn) curr_pos = 0 curr_meas_no = 1 time_sigs.each { |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) { |i| measures << MIDI::Measure.new(curr_meas_no, curr_pos, measure_length, oldnumer, olddenom, oldbeats) curr_meas_no += 1 curr_pos += measure_length } oldnumer, olddenom, oldbeats = te.numerator, te.denominator, te.metronome_ticks measure_length = te.measure_duration(@ppqn) } measures end |
#length_to_delta(length) ⇒ Object
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.
See also note_to_delta and note_to_length.
114 115 116 |
# File 'lib/midilib/sequence.rb', line 114 def length_to_delta(length) return (@ppqn * length).to_i end |
#name ⇒ Object
Returns the name of the first track (track zero). If there are no tracks, returns UNNAMED.
120 121 122 123 |
# File 'lib/midilib/sequence.rb', line 120 def name return UNNAMED if @tracks.empty? return @tracks.first.name() end |
#name=(name) ⇒ Object
Hands the name to the first track. Does nothing if there are no tracks.
126 127 128 129 |
# File 'lib/midilib/sequence.rb', line 126 def name=(name) return if @tracks.empty? @tracks.first.name = name end |
#note_to_delta(name) ⇒ Object
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.
81 82 83 |
# File 'lib/midilib/sequence.rb', line 81 def note_to_delta(name) return length_to_delta(note_to_length(name)) end |
#note_to_length(name) ⇒ Object
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.
94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/midilib/sequence.rb', line 94 def note_to_length(name) name.strip! name =~ /^(dotted)?(.*?)(triplet)?$/ dotted, note_name, triplet = $1, $2, $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 return len * mult end |
#read(io, proc = nil) ⇒ Object
Reads a MIDI stream.
132 133 134 135 |
# File 'lib/midilib/sequence.rb', line 132 def read(io, proc = nil) # :yields: track, num_tracks, index reader = @reader_class.new(self, block_given?() ? Proc.new() : proc) reader.read_from(io) end |
#time_signature(numer, denom, clocks, qnotes) ⇒ Object
Sets the time signature.
60 61 62 63 64 65 |
# File 'lib/midilib/sequence.rb', line 60 def time_signature(numer, denom, clocks, qnotes) @numer = numer @denom = denom @clocks = clocks @qnotes = qnotes end |
#write(io, proc = nil) ⇒ Object
Writes to a MIDI stream.
138 139 140 141 |
# File 'lib/midilib/sequence.rb', line 138 def write(io, proc = nil) # :yields: track, num_tracks, index writer = @writer_class.new(self, block_given?() ? Proc.new() : proc) writer.write_to(io) end |