midilib 2.0.4 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.rdoc +9 -4
- data/Rakefile +2 -6
- data/examples/from_scratch.rb +3 -5
- data/examples/measures_mbt.rb +4 -4
- data/examples/print_program_changes.rb +9 -9
- data/examples/reader2text.rb +188 -188
- data/examples/seq2text.rb +17 -17
- data/examples/split.rb +19 -19
- data/examples/strings.rb +14 -14
- data/examples/transpose.rb +31 -31
- data/html/IO.html +65 -169
- data/html/MIDI.html +138 -256
- data/html/MIDI/ActiveSense.html +89 -178
- data/html/MIDI/ChannelEvent.html +95 -183
- data/html/MIDI/ChannelPressure.html +105 -190
- data/html/MIDI/Clock.html +89 -178
- data/html/MIDI/Continue.html +89 -178
- data/html/MIDI/Controller.html +107 -192
- data/html/MIDI/Event.html +138 -222
- data/html/MIDI/IO.html +45 -157
- data/html/MIDI/IO/MIDIFile.html +596 -568
- data/html/MIDI/IO/SeqReader.html +272 -314
- data/html/MIDI/IO/SeqWriter.html +229 -305
- data/html/MIDI/KeySig.html +129 -211
- data/html/MIDI/MIDI.html +45 -154
- data/html/MIDI/MIDI/MIDI.html +45 -154
- data/html/MIDI/MIDI/MIDI/Array.html +87 -185
- data/html/MIDI/Marker.html +71 -170
- data/html/MIDI/Measure.html +95 -190
- data/html/MIDI/Measures.html +103 -193
- data/html/MIDI/MetaEvent.html +180 -253
- data/html/MIDI/NoteEvent.html +118 -204
- data/html/MIDI/NoteOff.html +95 -183
- data/html/MIDI/NoteOn.html +95 -183
- data/html/MIDI/PitchBend.html +106 -191
- data/html/MIDI/PolyPressure.html +106 -189
- data/html/MIDI/ProgramChange.html +105 -190
- data/html/MIDI/Realtime.html +98 -184
- data/html/MIDI/Sequence.html +246 -311
- data/html/MIDI/SongPointer.html +106 -191
- data/html/MIDI/SongSelect.html +105 -190
- data/html/MIDI/Start.html +89 -178
- data/html/MIDI/Stop.html +89 -178
- data/html/MIDI/SystemCommon.html +71 -170
- data/html/MIDI/SystemExclusive.html +108 -193
- data/html/MIDI/SystemReset.html +89 -178
- data/html/MIDI/Tempo.html +135 -213
- data/html/MIDI/TimeSig.html +135 -214
- data/html/MIDI/Track.html +217 -291
- data/html/MIDI/TuneRequest.html +98 -184
- data/html/MIDI/Utils.html +89 -189
- data/html/README_rdoc.html +237 -257
- data/html/TODO_rdoc.html +64 -139
- data/html/created.rid +14 -14
- data/html/css/fonts.css +167 -0
- data/html/{rdoc.css → css/rdoc.css} +265 -218
- data/html/fonts/Lato-Light.ttf +0 -0
- data/html/fonts/Lato-LightItalic.ttf +0 -0
- data/html/fonts/Lato-Regular.ttf +0 -0
- data/html/fonts/Lato-RegularItalic.ttf +0 -0
- data/html/fonts/SourceCodePro-Bold.ttf +0 -0
- data/html/fonts/SourceCodePro-Regular.ttf +0 -0
- data/html/images/add.png +0 -0
- data/html/images/arrow_up.png +0 -0
- data/html/images/delete.png +0 -0
- data/html/images/tag_blue.png +0 -0
- data/html/index.html +187 -169
- data/html/js/darkfish.js +41 -33
- data/html/js/jquery.js +4 -18
- data/html/js/navigation.js.gz +0 -0
- data/html/js/search.js +20 -5
- data/html/js/search_index.js +1 -1
- data/html/js/search_index.js.gz +0 -0
- data/html/js/searcher.js.gz +0 -0
- data/html/table_of_contents.html +1111 -498
- data/install.rb +43 -32
- data/lib/midilib/consts.rb +407 -407
- data/lib/midilib/event.rb +295 -294
- data/lib/midilib/info.rb +5 -5
- data/lib/midilib/io/midifile.rb +266 -267
- data/lib/midilib/io/seqreader.rb +106 -106
- data/lib/midilib/io/seqwriter.rb +59 -60
- data/lib/midilib/measure.rb +69 -69
- data/lib/midilib/sequence.rb +68 -70
- data/lib/midilib/track.rb +96 -102
- data/lib/midilib/utils.rb +15 -15
- data/test/event_equality.rb +50 -50
- data/test/test_event.rb +120 -122
- data/test/test_io.rb +35 -48
- data/test/test_sequence.rb +60 -60
- data/test/test_track.rb +154 -154
- data/test/test_varlen.rb +23 -25
- metadata +65 -57
data/lib/midilib/event.rb
CHANGED
@@ -3,8 +3,9 @@ require 'midilib/utils'
|
|
3
3
|
|
4
4
|
module MIDI
|
5
5
|
|
6
|
-
# The abstract superclass of all MIDI events.
|
7
|
-
class Event
|
6
|
+
# The abstract superclass of all MIDI events.
|
7
|
+
class Event
|
8
|
+
|
8
9
|
# Modifying delta_time does not affect time_from_start. You need to call
|
9
10
|
# the event's track's +recalc_time+ method.
|
10
11
|
attr_accessor :delta_time
|
@@ -28,9 +29,9 @@ class Event
|
|
28
29
|
attr_accessor :print_channel_numbers_from_one
|
29
30
|
|
30
31
|
def initialize(status = 0, delta_time = 0)
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
@status = status
|
33
|
+
@delta_time = delta_time
|
34
|
+
@time_from_start = 0 # maintained by tracks
|
34
35
|
end
|
35
36
|
protected :initialize
|
36
37
|
|
@@ -38,7 +39,7 @@ class Event
|
|
38
39
|
# MIDI stream. In MIDI::EVENT this raises a "subclass responsibility"
|
39
40
|
# exception.
|
40
41
|
def data_as_bytes
|
41
|
-
|
42
|
+
raise "subclass responsibility"
|
42
43
|
end
|
43
44
|
|
44
45
|
# Quantize this event's time_from_start by moving it to the nearest
|
@@ -46,64 +47,64 @@ class Event
|
|
46
47
|
# modify the event's delta_time, though MIDI::Track#quantize calls
|
47
48
|
# recalc_delta_from_times after it asks each event to quantize itself.
|
48
49
|
def quantize_to(boundary)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
diff = @time_from_start % boundary
|
51
|
+
@time_from_start -= diff
|
52
|
+
if diff >= boundary / 2
|
53
|
+
@time_from_start += boundary
|
54
|
+
end
|
54
55
|
end
|
55
56
|
|
56
57
|
# For sorting. Uses @time_from_start, which is maintained by this event's
|
57
58
|
# track. I'm not sure this is necessary, since each track has to
|
58
59
|
# maintain its events' time-from-start values anyway.
|
59
60
|
def <=>(an_event)
|
60
|
-
|
61
|
+
return @time_from_start <=> an_event.time_from_start
|
61
62
|
end
|
62
63
|
|
63
64
|
# Returns +val+ as a decimal or hex string, depending upon the value of
|
64
65
|
# @print_decimal_numbers.
|
65
66
|
def number_to_s(val)
|
66
|
-
|
67
|
+
return @print_decimal_numbers ? val.to_s : ('%02x' % val)
|
67
68
|
end
|
68
69
|
|
69
70
|
# Returns +val+ as a decimal or hex string, depending upon the value of
|
70
71
|
# @print_decimal_numbers.
|
71
72
|
def channel_to_s(val)
|
72
|
-
|
73
|
-
|
73
|
+
val += 1 if @print_channel_numbers_from_one
|
74
|
+
return number_to_s(val)
|
74
75
|
end
|
75
76
|
|
76
77
|
def to_s
|
77
|
-
|
78
|
+
"#{@delta_time}: "
|
78
79
|
end
|
79
|
-
end
|
80
|
+
end
|
80
81
|
|
81
|
-
# The abstract superclass of all channel events (events that have a MIDI
|
82
|
-
# channel, like notes and program changes).
|
83
|
-
class ChannelEvent < Event
|
82
|
+
# The abstract superclass of all channel events (events that have a MIDI
|
83
|
+
# channel, like notes and program changes).
|
84
|
+
class ChannelEvent < Event
|
84
85
|
# MIDI channel, 0-15.
|
85
86
|
attr_accessor :channel
|
86
87
|
|
87
88
|
def initialize(status, channel, delta_time)
|
88
|
-
|
89
|
-
|
89
|
+
super(status, delta_time)
|
90
|
+
@channel = channel
|
90
91
|
end
|
91
92
|
protected :initialize
|
92
93
|
|
93
94
|
def to_s
|
94
|
-
|
95
|
+
return super << "ch #{channel_to_s(@channel)} "
|
95
96
|
end
|
96
97
|
|
97
|
-
end
|
98
|
+
end
|
98
99
|
|
99
|
-
# The abstract superclass of all note on, and note off, and polyphonic
|
100
|
-
# pressure events.
|
101
|
-
class NoteEvent < ChannelEvent
|
100
|
+
# The abstract superclass of all note on, and note off, and polyphonic
|
101
|
+
# pressure events.
|
102
|
+
class NoteEvent < ChannelEvent
|
102
103
|
attr_accessor :note, :velocity
|
103
104
|
def initialize(status, channel, note, velocity, delta_time)
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
super(status, channel, delta_time)
|
106
|
+
@note = note
|
107
|
+
@velocity = velocity
|
107
108
|
end
|
108
109
|
protected :initialize
|
109
110
|
|
@@ -111,528 +112,528 @@ class NoteEvent < ChannelEvent
|
|
111
112
|
|
112
113
|
# Returns note name as a pitch/octave string like "C4" or "F#6".
|
113
114
|
def pch_oct(val=@note)
|
114
|
-
|
115
|
-
|
116
|
-
|
115
|
+
pch = val % 12
|
116
|
+
oct = (val / 12) - 1
|
117
|
+
"#{PITCHES[pch]}#{oct}"
|
117
118
|
end
|
118
119
|
|
119
120
|
# If @print_note_names is true, returns pch_oct(val) else returns value
|
120
121
|
# as a number using number_to_s.
|
121
122
|
def note_to_s
|
122
|
-
|
123
|
+
return @print_note_names ? pch_oct(@note) : number_to_s(@note)
|
123
124
|
end
|
124
125
|
|
125
126
|
def data_as_bytes
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
127
|
+
data = []
|
128
|
+
data << (@status + @channel)
|
129
|
+
data << @note
|
130
|
+
data << @velocity
|
130
131
|
end
|
131
|
-
end
|
132
|
+
end
|
132
133
|
|
133
|
-
class NoteOn < NoteEvent
|
134
|
+
class NoteOn < NoteEvent
|
134
135
|
attr_accessor :off
|
135
136
|
def initialize(channel = 0, note = 64, velocity = 64, delta_time = 0)
|
136
|
-
|
137
|
+
super(NOTE_ON, channel, note, velocity, delta_time)
|
137
138
|
end
|
138
139
|
|
139
140
|
def to_s
|
140
|
-
|
141
|
-
|
141
|
+
return super <<
|
142
|
+
"on #{note_to_s} #{number_to_s(@velocity)}"
|
142
143
|
end
|
143
|
-
end
|
144
|
+
end
|
144
145
|
|
145
|
-
# Old class name for compatability
|
146
|
-
NoteOnEvent = NoteOn
|
146
|
+
# Old class name for compatability
|
147
|
+
NoteOnEvent = NoteOn
|
147
148
|
|
148
|
-
class NoteOff < NoteEvent
|
149
|
+
class NoteOff < NoteEvent
|
149
150
|
attr_accessor :on
|
150
151
|
def initialize(channel = 0, note = 64, velocity = 64, delta_time = 0)
|
151
|
-
|
152
|
+
super(NOTE_OFF, channel, note, velocity, delta_time)
|
152
153
|
end
|
153
154
|
|
154
155
|
def to_s
|
155
|
-
|
156
|
-
|
156
|
+
return super <<
|
157
|
+
"off #{note_to_s} #{number_to_s(@velocity)}"
|
157
158
|
end
|
158
|
-
end
|
159
|
+
end
|
159
160
|
|
160
|
-
# Old class name for compatability
|
161
|
-
NoteOffEvent = NoteOff
|
161
|
+
# Old class name for compatability
|
162
|
+
NoteOffEvent = NoteOff
|
162
163
|
|
163
|
-
class PolyPressure < NoteEvent
|
164
|
+
class PolyPressure < NoteEvent
|
164
165
|
def initialize(channel = 0, note = 64, value = 0, delta_time = 0)
|
165
|
-
|
166
|
+
super(POLY_PRESSURE, channel, note, value, delta_time)
|
166
167
|
end
|
167
168
|
|
168
169
|
def pressure
|
169
|
-
|
170
|
+
return @velocity
|
170
171
|
end
|
171
172
|
def pressure=(val)
|
172
|
-
|
173
|
+
@velocity = val
|
173
174
|
end
|
174
175
|
def to_s
|
175
|
-
|
176
|
-
|
176
|
+
return super <<
|
177
|
+
"poly press #{channel_to_s(@channel)} #{note_to_s} #{number_to_s(@velocity)}"
|
177
178
|
end
|
178
|
-
end
|
179
|
+
end
|
179
180
|
|
180
|
-
class Controller < ChannelEvent
|
181
|
+
class Controller < ChannelEvent
|
181
182
|
attr_accessor :controller, :value
|
182
183
|
|
183
184
|
def initialize(channel = 0, controller = 0, value = 0, delta_time = 0)
|
184
|
-
|
185
|
-
|
186
|
-
|
185
|
+
super(CONTROLLER, channel, delta_time)
|
186
|
+
@controller = controller
|
187
|
+
@value = value
|
187
188
|
end
|
188
189
|
|
189
190
|
def data_as_bytes
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
191
|
+
data = []
|
192
|
+
data << (@status + @channel)
|
193
|
+
data << @controller
|
194
|
+
data << @value
|
194
195
|
end
|
195
196
|
|
196
197
|
def to_s
|
197
|
-
|
198
|
+
return super << "cntl #{number_to_s(@controller)} #{number_to_s(@value)}"
|
198
199
|
end
|
199
|
-
end
|
200
|
+
end
|
200
201
|
|
201
|
-
class ProgramChange < ChannelEvent
|
202
|
+
class ProgramChange < ChannelEvent
|
202
203
|
attr_accessor :program
|
203
204
|
|
204
205
|
def initialize(channel = 0, program = 0, delta_time = 0)
|
205
|
-
|
206
|
-
|
206
|
+
super(PROGRAM_CHANGE, channel, delta_time)
|
207
|
+
@program = program
|
207
208
|
end
|
208
209
|
|
209
210
|
def data_as_bytes
|
210
|
-
|
211
|
-
|
212
|
-
|
211
|
+
data = []
|
212
|
+
data << (@status + @channel)
|
213
|
+
data << @program
|
213
214
|
end
|
214
215
|
|
215
216
|
def to_s
|
216
|
-
|
217
|
+
return super << "prog #{number_to_s(@program)}"
|
217
218
|
end
|
218
|
-
end
|
219
|
+
end
|
219
220
|
|
220
|
-
class ChannelPressure < ChannelEvent
|
221
|
+
class ChannelPressure < ChannelEvent
|
221
222
|
attr_accessor :pressure
|
222
223
|
|
223
224
|
def initialize(channel = 0, pressure = 0, delta_time = 0)
|
224
|
-
|
225
|
-
|
225
|
+
super(CHANNEL_PRESSURE, channel, delta_time)
|
226
|
+
@pressure = pressure
|
226
227
|
end
|
227
228
|
|
228
229
|
def data_as_bytes
|
229
|
-
|
230
|
-
|
231
|
-
|
230
|
+
data = []
|
231
|
+
data << (@status + @channel)
|
232
|
+
data << @pressure
|
232
233
|
end
|
233
234
|
|
234
235
|
def to_s
|
235
|
-
|
236
|
+
return super << "chan press #{number_to_s(@pressure)}"
|
236
237
|
end
|
237
|
-
end
|
238
|
+
end
|
238
239
|
|
239
|
-
class PitchBend < ChannelEvent
|
240
|
+
class PitchBend < ChannelEvent
|
240
241
|
attr_accessor :value
|
241
242
|
|
242
243
|
def initialize(channel = 0, value = 0, delta_time = 0)
|
243
|
-
|
244
|
-
|
244
|
+
super(PITCH_BEND, channel, delta_time)
|
245
|
+
@value = value
|
245
246
|
end
|
246
247
|
|
247
248
|
def data_as_bytes
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
249
|
+
data = []
|
250
|
+
data << (@status + @channel)
|
251
|
+
data << (@value & 0x7f) # lsb
|
252
|
+
data << ((@value >> 7) & 0x7f) # msb
|
252
253
|
end
|
253
254
|
|
254
255
|
def to_s
|
255
|
-
|
256
|
+
return super << "pb #{number_to_s(@value)}"
|
256
257
|
end
|
257
|
-
end
|
258
|
+
end
|
258
259
|
|
259
|
-
class SystemCommon < Event
|
260
|
+
class SystemCommon < Event
|
260
261
|
def initialize(status, delta_time)
|
261
|
-
|
262
|
+
super(status, delta_time)
|
262
263
|
end
|
263
|
-
end
|
264
|
+
end
|
264
265
|
|
265
|
-
class SystemExclusive < SystemCommon
|
266
|
+
class SystemExclusive < SystemCommon
|
266
267
|
attr_accessor :data
|
267
268
|
|
268
269
|
def initialize(data, delta_time = 0)
|
269
|
-
|
270
|
-
|
270
|
+
super(SYSEX, delta_time)
|
271
|
+
@data = data
|
271
272
|
end
|
272
273
|
|
273
274
|
def data_as_bytes
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
275
|
+
data = []
|
276
|
+
data << @status
|
277
|
+
data << Utils.as_var_len(@data.length)
|
278
|
+
data << @data
|
279
|
+
data << EOX
|
280
|
+
data.flatten
|
280
281
|
end
|
281
282
|
|
282
283
|
def to_s
|
283
|
-
|
284
|
+
return super << "sys ex"
|
284
285
|
end
|
285
|
-
end
|
286
|
+
end
|
286
287
|
|
287
|
-
class SongPointer < SystemCommon
|
288
|
+
class SongPointer < SystemCommon
|
288
289
|
attr_accessor :pointer
|
289
290
|
|
290
291
|
def initialize(pointer = 0, delta_time = 0)
|
291
|
-
|
292
|
-
|
292
|
+
super(SONG_POINTER, delta_time)
|
293
|
+
@pointer = pointer
|
293
294
|
end
|
294
295
|
|
295
296
|
def data_as_bytes
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
297
|
+
data = []
|
298
|
+
data << @status
|
299
|
+
data << ((@pointer >> 8) & 0xff)
|
300
|
+
data << (@pointer & 0xff)
|
300
301
|
end
|
301
302
|
|
302
303
|
def to_s
|
303
|
-
|
304
|
+
return super << "song ptr #{number_to_s(@pointer)}"
|
304
305
|
end
|
305
|
-
end
|
306
|
+
end
|
306
307
|
|
307
|
-
class SongSelect < SystemCommon
|
308
|
+
class SongSelect < SystemCommon
|
308
309
|
attr_accessor :song
|
309
310
|
|
310
311
|
def initialize(song = 0, delta_time = 0)
|
311
|
-
|
312
|
-
|
312
|
+
super(SONG_SELECT, delta_time)
|
313
|
+
@song = song
|
313
314
|
end
|
314
315
|
|
315
316
|
def data_as_bytes
|
316
|
-
|
317
|
-
|
318
|
-
|
317
|
+
data = []
|
318
|
+
data << @status
|
319
|
+
data << @song
|
319
320
|
end
|
320
321
|
|
321
322
|
def to_s
|
322
|
-
|
323
|
+
return super << "song sel #{number_to_s(@song)}"
|
323
324
|
end
|
324
|
-
end
|
325
|
+
end
|
325
326
|
|
326
|
-
class TuneRequest < SystemCommon
|
327
|
+
class TuneRequest < SystemCommon
|
327
328
|
def initialize(delta_time = 0)
|
328
|
-
|
329
|
+
super(TUNE_REQUEST, delta_time)
|
329
330
|
end
|
330
331
|
|
331
332
|
def data_as_bytes
|
332
|
-
|
333
|
-
|
333
|
+
data = []
|
334
|
+
data << @status
|
334
335
|
end
|
335
336
|
|
336
337
|
def to_s
|
337
|
-
|
338
|
+
return super << "tune req"
|
338
339
|
end
|
339
|
-
end
|
340
|
+
end
|
340
341
|
|
341
|
-
class Realtime < Event
|
342
|
+
class Realtime < Event
|
342
343
|
def initialize(status, delta_time)
|
343
|
-
|
344
|
+
super(status, delta_time)
|
344
345
|
end
|
345
346
|
|
346
347
|
def data_as_bytes
|
347
|
-
|
348
|
-
|
348
|
+
data = []
|
349
|
+
data << @status
|
349
350
|
end
|
350
351
|
|
351
352
|
def to_s
|
352
|
-
|
353
|
+
return super << "realtime #{number_to_s(@status)}"
|
353
354
|
end
|
354
|
-
end
|
355
|
+
end
|
355
356
|
|
356
|
-
class Clock < Realtime
|
357
|
+
class Clock < Realtime
|
357
358
|
def initialize(delta_time = 0)
|
358
|
-
|
359
|
+
super(CLOCK, delta_time)
|
359
360
|
end
|
360
361
|
|
361
362
|
def to_s
|
362
|
-
|
363
|
+
return super << "clock"
|
363
364
|
end
|
364
|
-
end
|
365
|
+
end
|
365
366
|
|
366
|
-
class Start < Realtime
|
367
|
+
class Start < Realtime
|
367
368
|
def initialize(delta_time = 0)
|
368
|
-
|
369
|
+
super(START, delta_time)
|
369
370
|
end
|
370
371
|
def to_s
|
371
|
-
|
372
|
+
return super << "start"
|
372
373
|
end
|
373
|
-
end
|
374
|
+
end
|
374
375
|
|
375
|
-
class Continue < Realtime
|
376
|
+
class Continue < Realtime
|
376
377
|
def initialize(delta_time = 0)
|
377
|
-
|
378
|
+
super(CONTINUE, delta_time)
|
378
379
|
end
|
379
380
|
def to_s
|
380
|
-
|
381
|
+
return super << "continue"
|
381
382
|
end
|
382
|
-
end
|
383
|
+
end
|
383
384
|
|
384
|
-
class Stop < Realtime
|
385
|
+
class Stop < Realtime
|
385
386
|
def initialize(delta_time = 0)
|
386
|
-
|
387
|
+
super(STOP, delta_time)
|
387
388
|
end
|
388
389
|
def to_s
|
389
|
-
|
390
|
+
return super << "stop"
|
390
391
|
end
|
391
|
-
end
|
392
|
+
end
|
392
393
|
|
393
|
-
class ActiveSense < Realtime
|
394
|
+
class ActiveSense < Realtime
|
394
395
|
def initialize(delta_time = 0)
|
395
|
-
|
396
|
+
super(ACTIVE_SENSE, delta_time)
|
396
397
|
end
|
397
398
|
def to_s
|
398
|
-
|
399
|
+
return super << "act sens"
|
399
400
|
end
|
400
|
-
end
|
401
|
+
end
|
401
402
|
|
402
|
-
class SystemReset < Realtime
|
403
|
+
class SystemReset < Realtime
|
403
404
|
def initialize(delta_time = 0)
|
404
|
-
|
405
|
+
super(SYSTEM_RESET, delta_time)
|
405
406
|
end
|
406
407
|
def to_s
|
407
|
-
|
408
|
+
return super << "sys reset"
|
408
409
|
end
|
409
|
-
end
|
410
|
+
end
|
410
411
|
|
411
|
-
class MetaEvent < Event
|
412
|
+
class MetaEvent < Event
|
412
413
|
attr_reader :meta_type
|
413
414
|
attr_reader :data
|
414
415
|
|
415
416
|
def self.bytes_as_str(bytes)
|
416
|
-
|
417
|
+
bytes ? bytes.collect { |byte| byte.chr }.join : nil
|
417
418
|
end
|
418
419
|
|
419
420
|
if RUBY_VERSION >= '1.9'
|
420
|
-
|
421
|
-
|
422
|
-
|
421
|
+
def self.str_as_bytes(str)
|
422
|
+
str.split(//).collect { |chr| chr.ord }
|
423
|
+
end
|
423
424
|
else
|
424
|
-
|
425
|
-
|
426
|
-
|
425
|
+
def self.str_as_bytes(str)
|
426
|
+
str.split(//).collect { |chr| chr[0] }
|
427
|
+
end
|
427
428
|
end
|
428
429
|
|
429
430
|
def initialize(meta_type, data = nil, delta_time = 0)
|
430
|
-
|
431
|
-
|
432
|
-
|
431
|
+
super(META_EVENT, delta_time)
|
432
|
+
@meta_type = meta_type
|
433
|
+
self.data=(data)
|
433
434
|
end
|
434
435
|
|
435
436
|
def data_as_bytes
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
437
|
+
data = []
|
438
|
+
data << @status
|
439
|
+
data << @meta_type
|
440
|
+
data << (@data ? Utils.as_var_len(@data.length) : 0)
|
441
|
+
data << @data if @data
|
442
|
+
data.flatten
|
442
443
|
end
|
443
444
|
|
444
445
|
def data_as_str
|
445
|
-
|
446
|
+
MetaEvent.bytes_as_str(@data)
|
446
447
|
end
|
447
448
|
|
448
449
|
# Stores bytes. If data is a string, splits it into an array of bytes.
|
449
450
|
def data=(data)
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
451
|
+
case data
|
452
|
+
when String
|
453
|
+
@data = MetaEvent.str_as_bytes(data)
|
454
|
+
else
|
455
|
+
@data = data
|
456
|
+
end
|
456
457
|
end
|
457
458
|
|
458
459
|
def to_s
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
class Marker < MetaEvent
|
460
|
+
str = super()
|
461
|
+
str << "meta #{number_to_s(@meta_type)} "
|
462
|
+
# I know, I know...this isn't OO.
|
463
|
+
case @meta_type
|
464
|
+
when META_SEQ_NUM
|
465
|
+
str << "sequence number"
|
466
|
+
when META_TEXT
|
467
|
+
str << "text: #{data_as_str}"
|
468
|
+
when META_COPYRIGHT
|
469
|
+
str << "copyright: #{data_as_str}"
|
470
|
+
when META_SEQ_NAME
|
471
|
+
str << "sequence or track name: #{data_as_str}"
|
472
|
+
when META_INSTRUMENT
|
473
|
+
str << "instrument name: #{data_as_str}"
|
474
|
+
when META_LYRIC
|
475
|
+
str << "lyric: #{data_as_str}"
|
476
|
+
when META_MARKER
|
477
|
+
str << "marker: #{data_as_str}"
|
478
|
+
when META_CUE
|
479
|
+
str << "cue point: #{@data}"
|
480
|
+
when META_TRACK_END
|
481
|
+
str << "track end"
|
482
|
+
when META_SMPTE
|
483
|
+
str << "smpte"
|
484
|
+
when META_TIME_SIG
|
485
|
+
str << "time signature"
|
486
|
+
when META_KEY_SIG
|
487
|
+
str << "key signature"
|
488
|
+
when META_SEQ_SPECIF
|
489
|
+
str << "sequence specific"
|
490
|
+
else
|
491
|
+
# Some other possible @meta_type values are handled by subclasses.
|
492
|
+
str << "(other)"
|
493
|
+
end
|
494
|
+
return str
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
class Marker < MetaEvent
|
498
499
|
def initialize(msg, delta_time = 0)
|
499
|
-
|
500
|
+
super(META_MARKER, msg, delta_time)
|
500
501
|
end
|
501
|
-
end
|
502
|
+
end
|
502
503
|
|
503
|
-
class Tempo < MetaEvent
|
504
|
+
class Tempo < MetaEvent
|
504
505
|
|
505
506
|
MICROSECS_PER_MINUTE = 1_000_000 * 60
|
506
507
|
|
507
508
|
# Translates beats per minute to microseconds per quarter note (beat).
|
508
509
|
def Tempo.bpm_to_mpq(bpm)
|
509
|
-
|
510
|
+
return MICROSECS_PER_MINUTE / bpm
|
510
511
|
end
|
511
512
|
|
512
513
|
# Translates microseconds per quarter note (beat) to beats per minute.
|
513
514
|
def Tempo.mpq_to_bpm(mpq)
|
514
|
-
|
515
|
+
return MICROSECS_PER_MINUTE.to_f / mpq.to_f
|
515
516
|
end
|
516
517
|
|
517
518
|
def initialize(msecs_per_qnote, delta_time = 0)
|
518
|
-
|
519
|
+
super(META_SET_TEMPO, msecs_per_qnote, delta_time)
|
519
520
|
end
|
520
521
|
|
521
522
|
def tempo
|
522
|
-
|
523
|
+
return @data
|
523
524
|
end
|
524
525
|
|
525
526
|
def tempo=(val)
|
526
|
-
|
527
|
+
@data = val
|
527
528
|
end
|
528
529
|
|
529
530
|
def data_as_bytes
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
531
|
+
data = []
|
532
|
+
data << @status
|
533
|
+
data << @meta_type
|
534
|
+
data << 3
|
535
|
+
data << ((@data >> 16) & 0xff)
|
536
|
+
data << ((@data >> 8) & 0xff)
|
537
|
+
data << (@data & 0xff)
|
537
538
|
end
|
538
539
|
|
539
540
|
def to_s
|
540
|
-
|
541
|
+
"tempo #{@data} msecs per qnote (#{Tempo.mpq_to_bpm(@data)} bpm)"
|
541
542
|
end
|
542
|
-
end
|
543
|
+
end
|
544
|
+
|
545
|
+
# Container for time signature events
|
546
|
+
class TimeSig < MetaEvent
|
543
547
|
|
544
|
-
# Container for time signature events
|
545
|
-
class TimeSig < MetaEvent
|
546
|
-
|
547
548
|
# Constructor
|
548
549
|
def initialize(numer, denom, clocks, qnotes, delta_time = 0)
|
549
|
-
|
550
|
+
super(META_TIME_SIG, [numer, denom, clocks, qnotes], delta_time)
|
550
551
|
end
|
551
|
-
|
552
|
+
|
552
553
|
# Returns the complete event as stored in the sequence
|
553
554
|
def data_as_bytes
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
555
|
+
data = []
|
556
|
+
data << @status
|
557
|
+
data << @meta_type
|
558
|
+
data << 4
|
559
|
+
data << @data[0]
|
560
|
+
data << @data[1]
|
561
|
+
data << @data[2]
|
562
|
+
data << @data[3]
|
562
563
|
end
|
563
564
|
|
564
|
-
# Calculates the duration (in ticks) for a full measure
|
565
|
-
def measure_duration(ppqn)
|
566
|
-
|
565
|
+
# Calculates the duration (in ticks) for a full measure
|
566
|
+
def measure_duration(ppqn)
|
567
|
+
(4 * ppqn * @data[0]) / (2**@data[1])
|
567
568
|
end
|
568
|
-
|
569
|
+
|
569
570
|
# Returns the numerator (the top digit) for the time signature
|
570
571
|
def numerator
|
571
|
-
|
572
|
+
@data[0]
|
572
573
|
end
|
573
|
-
|
574
|
+
|
574
575
|
# Returns the denominator of the time signature. Use it as a power of 2
|
575
576
|
# to get the displayed (lower-part) digit of the time signature.
|
576
577
|
def denominator
|
577
|
-
|
578
|
+
@data[1]
|
578
579
|
end
|
579
|
-
|
580
|
+
|
580
581
|
# Returns the metronome tick duration for the time signature. On
|
581
582
|
# each quarter note, there's 24 ticks.
|
582
583
|
def metronome_ticks
|
583
|
-
|
584
|
+
@data[2]
|
584
585
|
end
|
585
|
-
|
586
|
+
|
586
587
|
# Returns the time signature for the event as a string.
|
587
588
|
# Example: "time sig 3/4"
|
588
589
|
def to_s
|
589
|
-
|
590
|
+
"time sig #{@data[0]}/#{2**@data[1]}"
|
590
591
|
end
|
591
|
-
end
|
592
|
+
end
|
593
|
+
|
594
|
+
# Container for key signature events
|
595
|
+
class KeySig < MetaEvent
|
592
596
|
|
593
|
-
# Container for key signature events
|
594
|
-
class KeySig < MetaEvent
|
595
|
-
|
596
597
|
# Constructor
|
597
598
|
def initialize(sharpflat, is_minor, delta_time = 0)
|
598
|
-
|
599
|
+
super(META_KEY_SIG, [sharpflat, is_minor], delta_time)
|
599
600
|
end
|
600
|
-
|
601
|
+
|
601
602
|
# Returns the complete event as stored in the sequence
|
602
603
|
def data_as_bytes
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
end
|
610
|
-
|
604
|
+
data = []
|
605
|
+
data << @status
|
606
|
+
data << @meta_type
|
607
|
+
data << 2
|
608
|
+
data << @data[0]
|
609
|
+
data << (@data[1] ? 1 : 0)
|
610
|
+
end
|
611
|
+
|
611
612
|
# Returns true if it's a minor key, false if major key
|
612
613
|
def minor_key?
|
613
|
-
|
614
|
+
@data[1]
|
614
615
|
end
|
615
|
-
|
616
|
+
|
616
617
|
# Returns true if it's a major key, false if minor key
|
617
618
|
def major_key?
|
618
|
-
|
619
|
+
!@data[1]
|
619
620
|
end
|
620
|
-
|
621
|
+
|
621
622
|
# Returns the number of sharps/flats in the key sig. Negative for flats.
|
622
623
|
def sharpflat
|
623
|
-
|
624
|
+
@data[0] > 7 ? @data[0] - 256 : @data[0]
|
624
625
|
end
|
625
|
-
|
626
|
+
|
626
627
|
# Returns the key signature as a text string.
|
627
628
|
# Example: "key sig A flat major"
|
628
629
|
def to_s
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
end
|
636
|
-
end
|
630
|
+
majorkeys = ['C flat', 'G flat', 'D flat', 'A flat', 'E flat', 'B flat', 'F',
|
631
|
+
'C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#']
|
632
|
+
minorkeys = ['a flat', 'e flat', 'b flat', 'f', 'c', 'g', 'd',
|
633
|
+
'a', 'e', 'b', 'f#', 'c#', 'g#', 'd#', 'a#']
|
634
|
+
minor_key? ? "key sig #{minorkeys[sharpflat + 7]} minor" :
|
635
|
+
"key sig #{majorkeys[sharpflat + 7]} major"
|
636
|
+
end
|
637
|
+
end
|
637
638
|
|
638
639
|
end
|