Class: MIDI::Track
Overview
A Track is a list of events.
When you modify the events
array, make sure to call recalc_times so each Event gets its time_from_start
recalculated.
A Track also holds a bitmask that specifies the channels used by the track. This bitmask is set when the track is read from the MIDI file by an IO::SeqReader but is not kept up to date by any other methods.
Constant Summary collapse
- UNNAMED =
'Unnamed'
Instance Attribute Summary collapse
-
#channels_used ⇒ Object
Returns the value of attribute channels_used.
-
#events ⇒ Object
Returns the value of attribute events.
-
#sequence ⇒ Object
readonly
Returns the value of attribute sequence.
Instance Method Summary collapse
-
#each(&block) ⇒ Object
Iterate over events.
-
#initialize(sequence) ⇒ Track
constructor
A new instance of Track.
- #instrument ⇒ Object
- #instrument=(str_or_bytes) ⇒ Object
-
#merge(event_list) ⇒ Object
Merges an array of events into our event list.
-
#merge_event_lists(list1, list2) ⇒ Object
Merges two event arrays together.
-
#name ⇒ Object
Return track name.
-
#name=(name) ⇒ Object
Set track name.
-
#quantize(length_or_note) ⇒ Object
Quantize every event.
-
#recalc_delta_from_times(starting_at = 0, list = @events) ⇒ Object
(also: #sort)
The opposite of recalc_times: recalculates delta_time for each event from each event’s time_from_start.
-
#recalc_times(starting_at = 0, list = @events) ⇒ Object
Recalculate start times for all events in
list
from starting_at to end.
Constructor Details
#initialize(sequence) ⇒ Track
Returns a new instance of Track.
22 23 24 25 26 27 28 29 30 |
# File 'lib/midilib/track.rb', line 22 def initialize(sequence) @sequence = sequence @events = [] # Bitmask of all channels used. Set when track is read in from # a MIDI file. @channels_used = 0 @instrument = nil end |
Instance Attribute Details
#channels_used ⇒ Object
Returns the value of attribute channels_used.
19 20 21 |
# File 'lib/midilib/track.rb', line 19 def channels_used @channels_used end |
#events ⇒ Object
Returns the value of attribute events.
19 20 21 |
# File 'lib/midilib/track.rb', line 19 def events @events end |
#sequence ⇒ Object (readonly)
Returns the value of attribute sequence.
20 21 22 |
# File 'lib/midilib/track.rb', line 20 def sequence @sequence end |
Instance Method Details
#each(&block) ⇒ Object
Iterate over events.
125 126 127 |
# File 'lib/midilib/track.rb', line 125 def each(&block) # :yields: event @events.each(&block) end |
#instrument ⇒ Object
49 50 51 |
# File 'lib/midilib/track.rb', line 49 def instrument MetaEvent.bytes_as_str(@instrument) end |
#instrument=(str_or_bytes) ⇒ Object
53 54 55 56 57 58 59 60 |
# File 'lib/midilib/track.rb', line 53 def instrument=(str_or_bytes) @instrument = case str_or_bytes when String MetaEvent.str_as_bytes(str_or_bytes) else str_or_bytes end end |
#merge(event_list) ⇒ Object
Merges an array of events into our event list. After merging, the events’ time_from_start values are correct so you don’t need to worry about calling recalc_times.
65 66 67 |
# File 'lib/midilib/track.rb', line 65 def merge(event_list) @events = merge_event_lists(@events, event_list) end |
#merge_event_lists(list1, list2) ⇒ Object
Merges two event arrays together. Does not modify this track.
70 71 72 73 74 75 76 |
# File 'lib/midilib/track.rb', line 70 def merge_event_lists(list1, list2) recalc_times(0, list1) recalc_times(0, list2) list = list1 + list2 recalc_delta_from_times(0, list) list end |
#name ⇒ Object
Return track name. If there is no name, return UNNAMED.
33 34 35 36 |
# File 'lib/midilib/track.rb', line 33 def name event = @events.detect { |e| e.is_a?(MetaEvent) && e. == META_SEQ_NAME } event ? event.data_as_str : UNNAMED end |
#name=(name) ⇒ Object
Set track name. Replaces or creates a name meta-event.
39 40 41 42 43 44 45 46 47 |
# File 'lib/midilib/track.rb', line 39 def name=(name) event = @events.detect { |e| e.is_a?(MetaEvent) && e. == META_SEQ_NAME } if event event.data = name else event = MetaEvent.new(META_SEQ_NAME, name, 0) @events[0, 0] = event end end |
#quantize(length_or_note) ⇒ Object
Quantize every event. length_or_note is either a length (1 = quarter, 0.25 = sixteenth, 4 = whole note) or a note name (“sixteenth”, “32nd”, “8th triplet”, “dotted quarter”).
Since each event’s time_from_start is modified, we call recalc_delta_from_times after each event quantizes itself.
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/midilib/track.rb', line 84 def quantize(length_or_note) delta = case length_or_note when String @sequence.note_to_delta(length_or_note) else @sequence.length_to_delta(length_or_note.to_i) end @events.each { |event| event.quantize_to(delta) } recalc_delta_from_times end |
#recalc_delta_from_times(starting_at = 0, list = @events) ⇒ Object Also known as: sort
The opposite of recalc_times: recalculates delta_time for each event from each event’s time_from_start. This is useful, for example, when merging two event lists. As a side-effect, elements from starting_at are sorted by time_from_start.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/midilib/track.rb', line 109 def recalc_delta_from_times(starting_at = 0, list = @events) prev_time_from_start = 0 # We need to sort the sublist. sublist.sort! does not do what we want. # We call mergesort instead of Array.sort because sort is not stable # (it can mix up the order of events that have the same start time). # See http://wiki.github.com/adamjmurray/cosy/midilib-notes for details. list[starting_at..-1] = mergesort(list[starting_at..-1]) do |e1, e2| e1.time_from_start <=> e2.time_from_start end list[starting_at..-1].each do |e| e.delta_time = e.time_from_start - prev_time_from_start prev_time_from_start = e.time_from_start end end |
#recalc_times(starting_at = 0, list = @events) ⇒ Object
Recalculate start times for all events in list
from starting_at to end.
97 98 99 100 101 102 103 |
# File 'lib/midilib/track.rb', line 97 def recalc_times(starting_at = 0, list = @events) t = starting_at == 0 ? 0 : list[starting_at - 1].time_from_start list[starting_at..-1].each do |e| t += e.delta_time e.time_from_start = t end end |