midilib 2.0.5 → 3.0.1
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 +5 -5
- data/ChangeLog +2 -1
- data/Credits +39 -2
- data/README.rdoc +5 -6
- data/Rakefile +36 -49
- data/TODO.rdoc +13 -2
- data/examples/from_scratch.rb +1 -1
- data/examples/measures_mbt.rb +11 -11
- data/examples/print_program_changes.rb +2 -2
- data/examples/reader2text.rb +47 -47
- data/examples/seq2text.rb +1 -1
- data/examples/split.rb +4 -3
- data/examples/strings.rb +4 -4
- data/examples/transpose.rb +19 -20
- data/install.rb +21 -13
- data/lib/midilib/consts.rb +237 -239
- data/lib/midilib/event.rb +128 -100
- data/lib/midilib/info.rb +3 -5
- data/lib/midilib/io/midifile.rb +155 -182
- data/lib/midilib/io/seqreader.rb +80 -85
- data/lib/midilib/io/seqwriter.rb +93 -88
- data/lib/midilib/measure.rb +78 -80
- data/lib/midilib/mergesort.rb +39 -0
- data/lib/midilib/sequence.rb +40 -32
- data/lib/midilib/track.rb +16 -57
- data/lib/midilib/utils.rb +4 -7
- data/lib/midilib.rb +5 -5
- data/test/event_equality.rb +28 -30
- data/test/test_event.rb +9 -11
- data/test/test_io.rb +83 -3
- data/test/test_mergesort.rb +37 -0
- data/test/test_midifile.rb +6 -19
- data/test/test_sequence.rb +5 -4
- data/test/test_track.rb +9 -38
- data/test/test_varlen.rb +1 -3
- metadata +8 -95
- data/html/IO.html +0 -155
- data/html/MIDI/ActiveSense.html +0 -206
- data/html/MIDI/ChannelEvent.html +0 -231
- data/html/MIDI/ChannelPressure.html +0 -265
- data/html/MIDI/Clock.html +0 -206
- data/html/MIDI/Continue.html +0 -206
- data/html/MIDI/Controller.html +0 -280
- data/html/MIDI/Event.html +0 -489
- data/html/MIDI/IO/MIDIFile.html +0 -2024
- data/html/MIDI/IO/SeqReader.html +0 -904
- data/html/MIDI/IO/SeqWriter.html +0 -572
- data/html/MIDI/IO.html +0 -95
- data/html/MIDI/KeySig.html +0 -353
- data/html/MIDI/MIDI/MIDI/Array.html +0 -255
- data/html/MIDI/MIDI/MIDI.html +0 -95
- data/html/MIDI/MIDI.html +0 -95
- data/html/MIDI/Marker.html +0 -158
- data/html/MIDI/Measure.html +0 -328
- data/html/MIDI/Measures.html +0 -285
- data/html/MIDI/MetaEvent.html +0 -461
- data/html/MIDI/NoteEvent.html +0 -331
- data/html/MIDI/NoteOff.html +0 -228
- data/html/MIDI/NoteOn.html +0 -228
- data/html/MIDI/PitchBend.html +0 -266
- data/html/MIDI/PolyPressure.html +0 -277
- data/html/MIDI/ProgramChange.html +0 -265
- data/html/MIDI/Realtime.html +0 -242
- data/html/MIDI/Sequence.html +0 -896
- data/html/MIDI/SongPointer.html +0 -266
- data/html/MIDI/SongSelect.html +0 -265
- data/html/MIDI/Start.html +0 -206
- data/html/MIDI/Stop.html +0 -206
- data/html/MIDI/SystemCommon.html +0 -158
- data/html/MIDI/SystemExclusive.html +0 -268
- data/html/MIDI/SystemReset.html +0 -206
- data/html/MIDI/Tempo.html +0 -396
- data/html/MIDI/TimeSig.html +0 -388
- data/html/MIDI/Track.html +0 -695
- data/html/MIDI/TuneRequest.html +0 -242
- data/html/MIDI/Utils.html +0 -220
- data/html/MIDI.html +0 -547
- data/html/README_rdoc.html +0 -731
- data/html/TODO_rdoc.html +0 -125
- data/html/created.rid +0 -14
- data/html/css/fonts.css +0 -167
- data/html/css/rdoc.css +0 -590
- 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/brick.png +0 -0
- data/html/images/brick_link.png +0 -0
- data/html/images/bug.png +0 -0
- data/html/images/bullet_black.png +0 -0
- data/html/images/bullet_toggle_minus.png +0 -0
- data/html/images/bullet_toggle_plus.png +0 -0
- data/html/images/date.png +0 -0
- data/html/images/delete.png +0 -0
- data/html/images/find.png +0 -0
- data/html/images/loadingAnimation.gif +0 -0
- data/html/images/macFFBgHack.png +0 -0
- data/html/images/package.png +0 -0
- data/html/images/page_green.png +0 -0
- data/html/images/page_white_text.png +0 -0
- data/html/images/page_white_width.png +0 -0
- data/html/images/plugin.png +0 -0
- data/html/images/ruby.png +0 -0
- data/html/images/tag_blue.png +0 -0
- data/html/images/tag_green.png +0 -0
- data/html/images/transparent.png +0 -0
- data/html/images/wrench.png +0 -0
- data/html/images/wrench_orange.png +0 -0
- data/html/images/zoom.png +0 -0
- data/html/index.html +0 -768
- data/html/js/darkfish.js +0 -161
- data/html/js/jquery.js +0 -4
- data/html/js/navigation.js +0 -142
- data/html/js/navigation.js.gz +0 -0
- data/html/js/search.js +0 -109
- data/html/js/search_index.js +0 -1
- data/html/js/search_index.js.gz +0 -0
- data/html/js/searcher.js +0 -228
- data/html/js/searcher.js.gz +0 -0
- data/html/table_of_contents.html +0 -1265
data/lib/midilib/io/midifile.rb
CHANGED
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if RUBY_VERSION < '1.9'
|
|
4
|
-
class IO
|
|
5
|
-
def readbyte
|
|
6
|
-
c = getc()
|
|
7
|
-
raise 'unexpected EOF' unless c
|
|
8
|
-
c
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
1
|
+
require_relative '../consts'
|
|
12
2
|
|
|
13
3
|
module MIDI
|
|
14
|
-
|
|
15
4
|
module IO
|
|
16
|
-
|
|
17
5
|
# A MIDIFile parses a MIDI file and calls methods when it sees MIDI events.
|
|
18
6
|
# Most of the methods are stubs. To do anything interesting with the events,
|
|
19
7
|
# override these methods (those between the "The rest of these are NOPs by
|
|
@@ -22,7 +10,6 @@ module MIDI
|
|
|
22
10
|
# See SeqReader for a subclass that uses these methods to create Event
|
|
23
11
|
# objects.
|
|
24
12
|
class MIDIFile
|
|
25
|
-
|
|
26
13
|
MThd_BYTE_ARRAY = [77, 84, 104, 100] # "MThd"
|
|
27
14
|
MTrk_BYTE_ARRAY = [77, 84, 114, 107] # "MTrk"
|
|
28
15
|
|
|
@@ -30,60 +17,53 @@ module MIDI
|
|
|
30
17
|
# value is either the number of bytes needed (1 or 2) for a channel
|
|
31
18
|
# message, or 0 if it's not a channel message.
|
|
32
19
|
NUM_DATA_BYTES = [
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
0, 0, 0, 0, 0, 0, 0, 0, # 0x00 - 0x70
|
|
21
|
+
2, 2, 2, 2, 1, 1, 2, 0 # 0x80 - 0xf0
|
|
35
22
|
]
|
|
36
23
|
|
|
37
|
-
attr_accessor
|
|
38
|
-
attr_accessor :ticks_so_far # Number of delta-time ticks so far
|
|
39
|
-
attr_accessor :bytes_to_be_read # Counts number of bytes expected
|
|
40
|
-
|
|
41
|
-
attr_accessor :no_merge # true means continued sysex are not collapsed
|
|
42
|
-
attr_accessor :skip_init # true if initial garbage should be skipped
|
|
24
|
+
attr_accessor :curr_ticks, :ticks_so_far, :bytes_to_be_read, :no_merge, :skip_init, :raw_var_num_data, :raw_data # Current time, from delta-time in MIDI file # Number of delta-time ticks so far # Counts number of bytes expected # true means continued sysex are not collapsed # true if initial garbage should be skipped
|
|
43
25
|
|
|
44
26
|
# Raw data info
|
|
45
|
-
attr_accessor
|
|
46
|
-
attr_accessor :raw_var_num_data
|
|
47
|
-
attr_accessor :raw_data
|
|
27
|
+
attr_accessor :raw_time_stamp_data
|
|
48
28
|
|
|
49
29
|
def initialize
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
30
|
+
@no_merge = false
|
|
31
|
+
@skip_init = true
|
|
32
|
+
@io = nil
|
|
33
|
+
@bytes_to_be_read = 0
|
|
34
|
+
@msg_buf = nil
|
|
55
35
|
end
|
|
56
36
|
|
|
57
37
|
# The only public method. Each MIDI event in the file causes a
|
|
58
38
|
# method to be called.
|
|
59
39
|
def read_from(io)
|
|
60
|
-
|
|
61
|
-
|
|
40
|
+
error('must specify non-nil input stream') if io.nil?
|
|
41
|
+
@io = io
|
|
62
42
|
|
|
63
|
-
|
|
64
|
-
|
|
43
|
+
ntrks = read_header
|
|
44
|
+
error('No tracks!') if ntrks <= 0
|
|
65
45
|
|
|
66
|
-
|
|
46
|
+
ntrks.times { read_track }
|
|
67
47
|
end
|
|
68
48
|
|
|
69
49
|
# This default getc implementation tries to read a single byte
|
|
70
50
|
# from io and returns it as an integer.
|
|
71
51
|
def getc
|
|
72
52
|
@bytes_to_be_read -= 1
|
|
73
|
-
@io.readbyte
|
|
53
|
+
@io.readbyte
|
|
74
54
|
end
|
|
75
55
|
|
|
76
56
|
# Return the next +n+ bytes from @io as an array.
|
|
77
57
|
def get_bytes(n)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
58
|
+
buf = []
|
|
59
|
+
n.times { buf << getc }
|
|
60
|
+
buf
|
|
81
61
|
end
|
|
82
62
|
|
|
83
63
|
# The default error handler.
|
|
84
64
|
def error(str)
|
|
85
|
-
|
|
86
|
-
|
|
65
|
+
loc = @io.tell - 1
|
|
66
|
+
raise "#{self.class.name} error at byte #{loc} (0x#{'%02x' % loc}): #{str}"
|
|
87
67
|
end
|
|
88
68
|
|
|
89
69
|
# The rest of these are NOPs by default.
|
|
@@ -95,7 +75,7 @@ module MIDI
|
|
|
95
75
|
def start_track(bytes_to_be_read)
|
|
96
76
|
end
|
|
97
77
|
|
|
98
|
-
def end_track
|
|
78
|
+
def end_track
|
|
99
79
|
end
|
|
100
80
|
|
|
101
81
|
def note_on(chan, note, vel)
|
|
@@ -134,7 +114,7 @@ module MIDI
|
|
|
134
114
|
def text(type, msg)
|
|
135
115
|
end
|
|
136
116
|
|
|
137
|
-
def eot
|
|
117
|
+
def eot
|
|
138
118
|
end
|
|
139
119
|
|
|
140
120
|
def time_signature(numer, denom, clocks, qnotes)
|
|
@@ -154,23 +134,20 @@ module MIDI
|
|
|
154
134
|
|
|
155
135
|
# End of NOPs.
|
|
156
136
|
|
|
157
|
-
|
|
158
137
|
# Read through 'MThd' or 'MTrk' header string. If skip is true, attempt
|
|
159
138
|
# to skip initial trash. If there is an error, #error is called.
|
|
160
139
|
def read_mt_header_string(bytes, skip)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
140
|
+
b = []
|
|
141
|
+
bytes_to_read = 4
|
|
142
|
+
while true
|
|
164
143
|
data = get_bytes(bytes_to_read)
|
|
165
144
|
b += data
|
|
166
|
-
if b.length < 4
|
|
167
|
-
error("unexpected EOF while trying to read header string #{s}")
|
|
168
|
-
end
|
|
145
|
+
error("unexpected EOF while trying to read header string #{s}") if b.length < 4
|
|
169
146
|
|
|
170
147
|
# See if we found the bytes we're looking for
|
|
171
148
|
return if b == bytes
|
|
172
149
|
|
|
173
|
-
if skip
|
|
150
|
+
if skip # Try again with the next char
|
|
174
151
|
i = b[1..-1].index(bytes[0])
|
|
175
152
|
if i.nil?
|
|
176
153
|
b = []
|
|
@@ -180,59 +157,57 @@ module MIDI
|
|
|
180
157
|
bytes_to_read = 4 - i
|
|
181
158
|
end
|
|
182
159
|
else
|
|
183
|
-
error("header string #{bytes.collect{|b| b.chr}.join} not found")
|
|
160
|
+
error("header string #{bytes.collect { |b| b.chr }.join} not found")
|
|
184
161
|
end
|
|
185
|
-
|
|
162
|
+
end
|
|
186
163
|
end
|
|
187
164
|
|
|
188
165
|
# Read a header chunk.
|
|
189
166
|
def read_header
|
|
190
|
-
|
|
191
|
-
|
|
167
|
+
@bytes_to_be_read = 0
|
|
168
|
+
read_mt_header_string(MThd_BYTE_ARRAY, @skip_init) # "MThd"
|
|
192
169
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
170
|
+
@bytes_to_be_read = read32
|
|
171
|
+
format = read16
|
|
172
|
+
ntrks = read16
|
|
173
|
+
division = read16
|
|
197
174
|
|
|
198
|
-
|
|
175
|
+
header(format, ntrks, division)
|
|
199
176
|
|
|
200
|
-
|
|
201
|
-
|
|
177
|
+
# Flush any extra stuff, in case the length of the header is not 6
|
|
178
|
+
if @bytes_to_be_read > 0
|
|
202
179
|
get_bytes(@bytes_to_be_read)
|
|
203
180
|
@bytes_to_be_read = 0
|
|
204
|
-
|
|
181
|
+
end
|
|
205
182
|
|
|
206
|
-
|
|
183
|
+
ntrks
|
|
207
184
|
end
|
|
208
185
|
|
|
209
186
|
# Read a track chunk.
|
|
210
187
|
def read_track
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
188
|
+
c = c1 = type = needed = 0
|
|
189
|
+
sysex_continue = false # True if last msg was unfinished
|
|
190
|
+
running = false # True when running status used
|
|
191
|
+
status = 0 # (Possibly running) status byte
|
|
215
192
|
|
|
216
|
-
|
|
217
|
-
|
|
193
|
+
@bytes_to_be_read = 0
|
|
194
|
+
read_mt_header_string(MTrk_BYTE_ARRAY, false)
|
|
218
195
|
|
|
219
|
-
|
|
220
|
-
|
|
196
|
+
@bytes_to_be_read = read32
|
|
197
|
+
@curr_ticks = @ticks_so_far = 0
|
|
221
198
|
|
|
222
|
-
|
|
199
|
+
start_track
|
|
223
200
|
|
|
224
|
-
|
|
225
|
-
@curr_ticks = read_var_len
|
|
201
|
+
while @bytes_to_be_read > 0
|
|
202
|
+
@curr_ticks = read_var_len # Delta time
|
|
226
203
|
@ticks_so_far += @curr_ticks
|
|
227
204
|
|
|
228
205
|
# Copy raw var num data into raw time stamp data
|
|
229
|
-
@raw_time_stamp_data = @raw_var_num_data.dup
|
|
206
|
+
@raw_time_stamp_data = @raw_var_num_data.dup
|
|
230
207
|
|
|
231
|
-
c = getc
|
|
208
|
+
c = getc # Read first byte
|
|
232
209
|
|
|
233
|
-
if sysex_continue && c != EOX
|
|
234
|
-
error("didn't find expected continuation of a sysex")
|
|
235
|
-
end
|
|
210
|
+
error("didn't find expected continuation of a sysex") if sysex_continue && c != EOX
|
|
236
211
|
|
|
237
212
|
if (c & 0x80).zero? # Running status?
|
|
238
213
|
error('unexpected running status') if status.zero?
|
|
@@ -244,223 +219,221 @@ module MIDI
|
|
|
244
219
|
|
|
245
220
|
needed = NUM_DATA_BYTES[(status >> 4) & 0x0f]
|
|
246
221
|
|
|
247
|
-
if needed.nonzero?
|
|
248
|
-
c1 = running ? c : (getc
|
|
222
|
+
if needed.nonzero? # i.e., is it a channel message?
|
|
223
|
+
c1 = running ? c : (getc & 0x7f)
|
|
249
224
|
|
|
250
225
|
# The "& 0x7f" here may seem unnecessary, but I've seen
|
|
251
226
|
# "bad" MIDI files that had, for example, volume bytes
|
|
252
227
|
# with the upper bit set. This code should not harm
|
|
253
228
|
# proper data.
|
|
254
229
|
chan_message(running, status, c1,
|
|
255
|
-
|
|
230
|
+
needed > 1 ? (getc & 0x7f) : 0)
|
|
256
231
|
next
|
|
257
232
|
end
|
|
258
233
|
|
|
259
234
|
case c
|
|
260
|
-
when META_EVENT
|
|
261
|
-
type = getc
|
|
262
|
-
msg_init
|
|
263
|
-
msg_read(read_var_len
|
|
235
|
+
when META_EVENT # Meta event
|
|
236
|
+
type = getc
|
|
237
|
+
msg_init
|
|
238
|
+
msg_read(read_var_len)
|
|
264
239
|
meta_event(type)
|
|
265
|
-
when SYSEX
|
|
266
|
-
msg_init
|
|
240
|
+
when SYSEX # Start of system exclusive
|
|
241
|
+
msg_init
|
|
267
242
|
msg_add(SYSEX)
|
|
268
|
-
c = msg_read(read_var_len
|
|
243
|
+
c = msg_read(read_var_len)
|
|
269
244
|
|
|
270
245
|
if c == EOX || !@no_merge
|
|
271
|
-
handle_sysex(msg
|
|
246
|
+
handle_sysex(msg)
|
|
272
247
|
else
|
|
273
248
|
sysex_continue = true
|
|
274
249
|
end
|
|
275
|
-
when EOX
|
|
276
|
-
msg_init
|
|
277
|
-
c = msg_read(read_var_len
|
|
250
|
+
when EOX # Sysex continuation or arbitrary stuff
|
|
251
|
+
msg_init unless sysex_continue
|
|
252
|
+
c = msg_read(read_var_len)
|
|
278
253
|
|
|
279
254
|
if !sysex_continue
|
|
280
|
-
handle_arbitrary(msg
|
|
255
|
+
handle_arbitrary(msg)
|
|
281
256
|
elsif c == EOX
|
|
282
|
-
handle_sysex(msg
|
|
257
|
+
handle_sysex(msg)
|
|
283
258
|
sysex_continue = false
|
|
284
259
|
end
|
|
285
260
|
else
|
|
286
261
|
bad_byte(c)
|
|
287
262
|
end
|
|
288
|
-
|
|
289
|
-
|
|
263
|
+
end
|
|
264
|
+
end_track
|
|
290
265
|
end
|
|
291
266
|
|
|
292
267
|
# Handle an unexpected byte.
|
|
293
268
|
def bad_byte(c)
|
|
294
|
-
|
|
269
|
+
error(format('unexpected byte: 0x%02x', c))
|
|
295
270
|
end
|
|
296
271
|
|
|
297
272
|
# Handle a meta event.
|
|
298
273
|
def meta_event(type)
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
274
|
+
m = msg # Copy of internal message buffer
|
|
275
|
+
|
|
276
|
+
# Create raw data array
|
|
277
|
+
@raw_data = []
|
|
278
|
+
@raw_data << META_EVENT
|
|
279
|
+
@raw_data << type
|
|
280
|
+
@raw_data << @raw_var_num_data
|
|
281
|
+
@raw_data << m
|
|
282
|
+
@raw_data.flatten!
|
|
283
|
+
|
|
284
|
+
case type
|
|
285
|
+
when META_SEQ_NUM
|
|
311
286
|
sequence_number((m[0] << 8) + m[1])
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
287
|
+
when META_TEXT, META_COPYRIGHT, META_SEQ_NAME, META_INSTRUMENT,
|
|
288
|
+
META_LYRIC, META_MARKER, META_CUE, 0x08, 0x09, 0x0a,
|
|
289
|
+
0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
|
315
290
|
text(type, m)
|
|
316
|
-
|
|
317
|
-
eot
|
|
318
|
-
|
|
291
|
+
when META_TRACK_END
|
|
292
|
+
eot
|
|
293
|
+
when META_SET_TEMPO
|
|
319
294
|
tempo((m[0] << 16) + (m[1] << 8) + m[2])
|
|
320
|
-
|
|
295
|
+
when META_SMPTE
|
|
321
296
|
smpte(m[0], m[1], m[2], m[3], m[4])
|
|
322
|
-
|
|
297
|
+
when META_TIME_SIG
|
|
323
298
|
time_signature(m[0], m[1], m[2], m[3])
|
|
324
|
-
|
|
325
|
-
key_signature(m[0], m[1] == 0
|
|
326
|
-
|
|
299
|
+
when META_KEY_SIG
|
|
300
|
+
key_signature(m[0], !(m[1] == 0))
|
|
301
|
+
when META_SEQ_SPECIF
|
|
327
302
|
sequencer_specific(type, m)
|
|
328
|
-
|
|
303
|
+
else
|
|
329
304
|
meta_misc(type, m)
|
|
330
|
-
|
|
305
|
+
end
|
|
331
306
|
end
|
|
332
307
|
|
|
333
308
|
# Handle a channel message (note on, note off, etc.)
|
|
334
309
|
def chan_message(running, status, c1, c2)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
310
|
+
@raw_data = []
|
|
311
|
+
@raw_data << status unless running
|
|
312
|
+
@raw_data << c1
|
|
313
|
+
@raw_data << c2
|
|
339
314
|
|
|
340
|
-
|
|
315
|
+
chan = status & 0x0f
|
|
341
316
|
|
|
342
|
-
|
|
343
|
-
|
|
317
|
+
case (status & 0xf0)
|
|
318
|
+
when NOTE_OFF
|
|
344
319
|
note_off(chan, c1, c2)
|
|
345
|
-
|
|
320
|
+
when NOTE_ON
|
|
346
321
|
note_on(chan, c1, c2)
|
|
347
|
-
|
|
322
|
+
when POLY_PRESSURE
|
|
348
323
|
pressure(chan, c1, c2)
|
|
349
|
-
|
|
324
|
+
when CONTROLLER
|
|
350
325
|
controller(chan, c1, c2)
|
|
351
|
-
|
|
326
|
+
when PITCH_BEND
|
|
352
327
|
pitch_bend(chan, c1, c2)
|
|
353
|
-
|
|
328
|
+
when PROGRAM_CHANGE
|
|
354
329
|
program(chan, c1)
|
|
355
|
-
|
|
330
|
+
when CHANNEL_PRESSURE
|
|
356
331
|
chan_pressure(chan, c1)
|
|
357
|
-
|
|
358
|
-
error("illegal chan message 0x#{'%02x'
|
|
359
|
-
|
|
332
|
+
else
|
|
333
|
+
error("illegal chan message 0x#{format('%02x', (status & 0xf0))}\n")
|
|
334
|
+
end
|
|
360
335
|
end
|
|
361
336
|
|
|
362
337
|
# Copy message into raw data array, then call sysex().
|
|
363
338
|
def handle_sysex(msg)
|
|
364
|
-
|
|
365
|
-
|
|
339
|
+
@raw_data = msg.dup
|
|
340
|
+
sysex(msg)
|
|
366
341
|
end
|
|
367
342
|
|
|
368
343
|
# Copy message into raw data array, then call arbitrary().
|
|
369
344
|
def handle_arbitrary(msg)
|
|
370
|
-
|
|
371
|
-
|
|
345
|
+
@raw_data = msg.dup
|
|
346
|
+
arbitrary(msg)
|
|
372
347
|
end
|
|
373
348
|
|
|
374
349
|
# Read and return a sixteen bit value.
|
|
375
350
|
def read16
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
351
|
+
val = (getc << 8) + getc
|
|
352
|
+
val = -(val & 0x7fff) if (val & 0x8000).nonzero?
|
|
353
|
+
val
|
|
379
354
|
end
|
|
380
355
|
|
|
381
356
|
# Read and return a 32-bit value.
|
|
382
357
|
def read32
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
358
|
+
val = (getc << 24) + (getc << 16) + (getc << 8) +
|
|
359
|
+
getc
|
|
360
|
+
val = -(val & 0x7fffffff) if (val & 0x80000000).nonzero?
|
|
361
|
+
val
|
|
387
362
|
end
|
|
388
363
|
|
|
389
364
|
# Read a varlen value.
|
|
390
365
|
def read_var_len
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
366
|
+
@raw_var_num_data = []
|
|
367
|
+
c = getc
|
|
368
|
+
@raw_var_num_data << c
|
|
369
|
+
val = c
|
|
370
|
+
if (val & 0x80).nonzero?
|
|
396
371
|
val &= 0x7f
|
|
397
372
|
while true
|
|
398
|
-
c = getc
|
|
373
|
+
c = getc
|
|
399
374
|
@raw_var_num_data << c
|
|
400
375
|
val = (val << 7) + (c & 0x7f)
|
|
401
376
|
break if (c & 0x80).zero?
|
|
402
377
|
end
|
|
403
|
-
|
|
404
|
-
|
|
378
|
+
end
|
|
379
|
+
val
|
|
405
380
|
end
|
|
406
381
|
|
|
407
382
|
# Write a sixteen-bit value.
|
|
408
383
|
def write16(val)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
384
|
+
val = (-val) | 0x8000 if val < 0
|
|
385
|
+
putc((val >> 8) & 0xff)
|
|
386
|
+
putc(val & 0xff)
|
|
412
387
|
end
|
|
413
388
|
|
|
414
389
|
# Write a 32-bit value.
|
|
415
390
|
def write32(val)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
391
|
+
val = (-val) | 0x80000000 if val < 0
|
|
392
|
+
putc((val >> 24) & 0xff)
|
|
393
|
+
putc((val >> 16) & 0xff)
|
|
394
|
+
putc((val >> 8) & 0xff)
|
|
395
|
+
putc(val & 0xff)
|
|
421
396
|
end
|
|
422
397
|
|
|
423
398
|
# Write a variable length value.
|
|
424
399
|
def write_var_len(val)
|
|
425
|
-
|
|
400
|
+
if val.zero?
|
|
426
401
|
putc(0)
|
|
427
402
|
return
|
|
428
|
-
|
|
403
|
+
end
|
|
429
404
|
|
|
430
|
-
|
|
405
|
+
buf = []
|
|
431
406
|
|
|
432
|
-
|
|
433
|
-
|
|
407
|
+
buf << (val & 0x7f)
|
|
408
|
+
while (value >>= 7) > 0
|
|
434
409
|
buf << (val & 0x7f) | 0x80
|
|
435
|
-
|
|
410
|
+
end
|
|
436
411
|
|
|
437
|
-
|
|
412
|
+
buf.reverse.each { |b| putc(b) }
|
|
438
413
|
end
|
|
439
414
|
|
|
440
415
|
# Add a byte to the current message buffer.
|
|
441
416
|
def msg_add(c)
|
|
442
|
-
|
|
417
|
+
@msg_buf << c
|
|
443
418
|
end
|
|
444
419
|
|
|
445
420
|
# Read and add a number of bytes to the message buffer. Return
|
|
446
421
|
# the last byte (so we can see if it's an EOX or not).
|
|
447
422
|
def msg_read(n_bytes)
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
423
|
+
@msg_buf += get_bytes(n_bytes)
|
|
424
|
+
@msg_buf.flatten!
|
|
425
|
+
@msg_buf[-1]
|
|
451
426
|
end
|
|
452
427
|
|
|
453
428
|
# Initialize the internal message buffer.
|
|
454
429
|
def msg_init
|
|
455
|
-
|
|
430
|
+
@msg_buf = []
|
|
456
431
|
end
|
|
457
432
|
|
|
458
433
|
# Return a copy of the internal message buffer.
|
|
459
434
|
def msg
|
|
460
|
-
|
|
435
|
+
@msg_buf.dup
|
|
461
436
|
end
|
|
462
|
-
|
|
463
437
|
end
|
|
464
|
-
|
|
465
438
|
end
|
|
466
439
|
end
|