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.



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_usedObject

Returns the value of attribute channels_used.



19
20
21
# File 'lib/midilib/track.rb', line 19

def channels_used
  @channels_used
end

#eventsObject

Returns the value of attribute events.



19
20
21
# File 'lib/midilib/track.rb', line 19

def events
  @events
end

#sequenceObject (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

#instrumentObject



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

#nameObject

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_type == 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_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.



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