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.



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

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.



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

def channels_used
  @channels_used
end

#eventsObject

Returns the value of attribute events.



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

def events
  @events
end

#sequenceObject (readonly)

Returns the value of attribute sequence.



63
64
65
# File 'lib/midilib/track.rb', line 63

def sequence
  @sequence
end

Instance Method Details

#eachObject

Iterate over events.



171
172
173
# File 'lib/midilib/track.rb', line 171

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

#instrumentObject



95
96
97
# File 'lib/midilib/track.rb', line 95

def instrument
	MetaEvent.bytes_as_str(@instrument)
end

#instrument=(str_or_bytes) ⇒ Object



99
100
101
102
103
104
105
106
# File 'lib/midilib/track.rb', line 99

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.



111
112
113
# File 'lib/midilib/track.rb', line 111

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.



116
117
118
119
120
121
122
# File 'lib/midilib/track.rb', line 116

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.



75
76
77
78
79
80
# File 'lib/midilib/track.rb', line 75

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

#name=(name) ⇒ Object

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



83
84
85
86
87
88
89
90
91
92
93
# File 'lib/midilib/track.rb', line 83

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.



130
131
132
133
134
135
136
137
138
139
# File 'lib/midilib/track.rb', line 130

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.



155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/midilib/track.rb', line 155

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] = list[starting_at .. -1].mergesort { | e1, e2 |
 e1.time_from_start <=> e2.time_from_start
	}
	list[starting_at .. -1].each { | e |
 e.delta_time = e.time_from_start - prev_time_from_start
 prev_time_from_start = e.time_from_start
	}
end

#recalc_times(starting_at = 0, list = @events) ⇒ Object

Recalculate start times for all events in list from starting_at to end.



143
144
145
146
147
148
149
# File 'lib/midilib/track.rb', line 143

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 { | e |
 t += e.delta_time
 e.time_from_start = t
	}
end