Class: MIDI::Track

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/midilib/track.rb

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

Instance Method Summary collapse

Constructor Details

#initialize(sequence) ⇒ Track

Returns a new instance of Track.


63
64
65
66
67
68
69
70
# File 'lib/midilib/track.rb', line 63

def initialize(sequence)
  @sequence = sequence
  @events = Array.new()

  # Bitmask of all channels used. Set when track is read in from
  # a MIDI file.
  @channels_used = 0
end

Instance Attribute Details

#channels_usedObject

Returns the value of attribute channels_used


60
61
62
# File 'lib/midilib/track.rb', line 60

def channels_used
  @channels_used
end

#eventsObject

Returns the value of attribute events


60
61
62
# File 'lib/midilib/track.rb', line 60

def events
  @events
end

#sequenceObject (readonly)

Returns the value of attribute sequence


61
62
63
# File 'lib/midilib/track.rb', line 61

def sequence
  @sequence
end

Instance Method Details

#eachObject

Iterate over events.


165
166
167
# File 'lib/midilib/track.rb', line 165

def each			# :yields: event
  @events.each { |event| yield event }
end

#instrumentObject


89
90
91
# File 'lib/midilib/track.rb', line 89

def instrument
  MetaEvent.bytes_as_str(@instrument)
end

#instrument=(str_or_bytes) ⇒ Object


93
94
95
96
97
98
99
100
# File 'lib/midilib/track.rb', line 93

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.


105
106
107
# File 'lib/midilib/track.rb', line 105

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.


110
111
112
113
114
115
116
# File 'lib/midilib/track.rb', line 110

def merge_event_lists(list1, list2)
  recalc_times(0, list1)
  recalc_times(0, list2)
  list = list1 + list2
  recalc_delta_from_times(0, list)
  return list
end

#nameObject

Return track name. If there is no name, return UNNAMED.


73
74
75
76
# File 'lib/midilib/track.rb', line 73

def name
  event = @events.detect { |e| e.kind_of?(MetaEvent) && e.meta_type == META_SEQ_NAME }
  event ? event.data_as_str : UNNAMED
end

#name=(name) ⇒ Object

Set track name. Replaces or creates a name meta-event.


79
80
81
82
83
84
85
86
87
# File 'lib/midilib/track.rb', line 79

def name=(name)
  event = @events.detect { |e| e.kind_of?(MetaEvent) && e.meta_type == 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.


124
125
126
127
128
129
130
131
132
133
# File 'lib/midilib/track.rb', line 124

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.


149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/midilib/track.rb', line 149

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] = MIDI::Array.new(list[starting_at .. -1]).mergesort 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.


137
138
139
140
141
142
143
# File 'lib/midilib/track.rb', line 137

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