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/info.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module MIDI
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
VERSION_MAJOR = 2
|
4
|
+
VERSION_MINOR = 0
|
5
|
+
VERSION_TWEAK = 5
|
6
|
+
Version = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_TWEAK}"
|
7
|
+
Copyright = 'Copyright (c) 2003-2015 by Jim Menard <jim@jimmenard.com>'
|
8
8
|
|
9
9
|
end
|
data/lib/midilib/io/midifile.rb
CHANGED
@@ -12,51 +12,51 @@ end
|
|
12
12
|
|
13
13
|
module MIDI
|
14
14
|
|
15
|
-
module IO
|
16
|
-
|
17
|
-
# A MIDIFile parses a MIDI file and calls methods when it sees MIDI events.
|
18
|
-
# Most of the methods are stubs. To do anything interesting with the events,
|
19
|
-
# override these methods (those between the "The rest of these are NOPs by
|
20
|
-
# default" and "End of NOPs" comments).
|
21
|
-
#
|
22
|
-
# See SeqReader for a subclass that uses these methods to create Event
|
23
|
-
# objects.
|
24
|
-
class MIDIFile
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
15
|
+
module IO
|
16
|
+
|
17
|
+
# A MIDIFile parses a MIDI file and calls methods when it sees MIDI events.
|
18
|
+
# Most of the methods are stubs. To do anything interesting with the events,
|
19
|
+
# override these methods (those between the "The rest of these are NOPs by
|
20
|
+
# default" and "End of NOPs" comments).
|
21
|
+
#
|
22
|
+
# See SeqReader for a subclass that uses these methods to create Event
|
23
|
+
# objects.
|
24
|
+
class MIDIFile
|
25
|
+
|
26
|
+
MThd_BYTE_ARRAY = [77, 84, 104, 100] # "MThd"
|
27
|
+
MTrk_BYTE_ARRAY = [77, 84, 114, 107] # "MTrk"
|
28
|
+
|
29
|
+
# This array is indexed by the high half of a status byte. Its
|
30
|
+
# value is either the number of bytes needed (1 or 2) for a channel
|
31
|
+
# message, or 0 if it's not a channel message.
|
32
|
+
NUM_DATA_BYTES = [
|
33
33
|
0, 0, 0, 0, 0, 0, 0, 0, # 0x00 - 0x70
|
34
34
|
2, 2, 2, 2, 1, 1, 2, 0 # 0x80 - 0xf0
|
35
|
-
|
35
|
+
]
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
attr_accessor :curr_ticks # Current time, from delta-time in MIDI file
|
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
40
|
|
41
|
-
|
42
|
-
|
41
|
+
attr_accessor :no_merge # true means continued sysex are not collapsed
|
42
|
+
attr_accessor :skip_init # true if initial garbage should be skipped
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
# Raw data info
|
45
|
+
attr_accessor :raw_time_stamp_data
|
46
|
+
attr_accessor :raw_var_num_data
|
47
|
+
attr_accessor :raw_data
|
48
48
|
|
49
|
-
|
49
|
+
def initialize
|
50
50
|
@no_merge = false
|
51
51
|
@skip_init = true
|
52
52
|
@io = nil
|
53
53
|
@bytes_to_be_read = 0
|
54
54
|
@msg_buf = nil
|
55
|
-
|
55
|
+
end
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
# The only public method. Each MIDI event in the file causes a
|
58
|
+
# method to be called.
|
59
|
+
def read_from(io)
|
60
60
|
error('must specify non-nil input stream') if io.nil?
|
61
61
|
@io = io
|
62
62
|
|
@@ -64,130 +64,129 @@ class MIDIFile
|
|
64
64
|
error('No tracks!') if ntrks <= 0
|
65
65
|
|
66
66
|
ntrks.times { read_track() }
|
67
|
-
|
67
|
+
end
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
# This default getc implementation tries to read a single byte
|
70
|
+
# from io and returns it as an integer.
|
71
|
+
def getc
|
72
|
+
@bytes_to_be_read -= 1
|
73
|
+
@io.readbyte()
|
74
|
+
end
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
# Return the next +n+ bytes from @io as an array.
|
77
|
+
def get_bytes(n)
|
78
78
|
buf = []
|
79
79
|
n.times { buf << getc() }
|
80
80
|
buf
|
81
|
-
|
81
|
+
end
|
82
82
|
|
83
|
-
|
84
|
-
|
83
|
+
# The default error handler.
|
84
|
+
def error(str)
|
85
85
|
loc = @io.tell() - 1
|
86
86
|
raise "#{self.class.name} error at byte #{loc} (0x#{'%02x' % loc}): #{str}"
|
87
|
-
|
87
|
+
end
|
88
88
|
|
89
|
-
# The rest of these are NOPs by default.
|
89
|
+
# The rest of these are NOPs by default.
|
90
90
|
|
91
|
-
|
92
|
-
|
93
|
-
|
91
|
+
# MIDI header.
|
92
|
+
def header(format, ntrks, division)
|
93
|
+
end
|
94
94
|
|
95
|
-
|
96
|
-
|
95
|
+
def start_track(bytes_to_be_read)
|
96
|
+
end
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
def end_track()
|
99
|
+
end
|
100
100
|
|
101
|
-
|
102
|
-
|
101
|
+
def note_on(chan, note, vel)
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
|
104
|
+
def note_off(chan, note, vel)
|
105
|
+
end
|
106
106
|
|
107
|
-
|
108
|
-
|
107
|
+
def pressure(chan, note, press)
|
108
|
+
end
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
def controller(chan, control, value)
|
111
|
+
end
|
112
112
|
|
113
|
-
|
114
|
-
|
113
|
+
def pitch_bend(chan, msb, lsb)
|
114
|
+
end
|
115
115
|
|
116
|
-
|
117
|
-
|
116
|
+
def program(chan, program)
|
117
|
+
end
|
118
118
|
|
119
|
-
|
120
|
-
|
119
|
+
def chan_pressure(chan, press)
|
120
|
+
end
|
121
121
|
|
122
|
-
|
123
|
-
|
122
|
+
def sysex(msg)
|
123
|
+
end
|
124
124
|
|
125
|
-
|
126
|
-
|
125
|
+
def meta_misc(type, msg)
|
126
|
+
end
|
127
127
|
|
128
|
-
|
129
|
-
|
128
|
+
def sequencer_specific(type, msg)
|
129
|
+
end
|
130
130
|
|
131
|
-
|
132
|
-
|
131
|
+
def sequence_number(num)
|
132
|
+
end
|
133
133
|
|
134
|
-
|
135
|
-
|
134
|
+
def text(type, msg)
|
135
|
+
end
|
136
136
|
|
137
|
-
|
138
|
-
|
137
|
+
def eot()
|
138
|
+
end
|
139
139
|
|
140
|
-
|
141
|
-
|
140
|
+
def time_signature(numer, denom, clocks, qnotes)
|
141
|
+
end
|
142
142
|
|
143
|
-
|
144
|
-
|
143
|
+
def smpte(hour, min, sec, frame, fract)
|
144
|
+
end
|
145
145
|
|
146
|
-
|
147
|
-
|
146
|
+
def tempo(microsecs)
|
147
|
+
end
|
148
148
|
|
149
|
-
|
150
|
-
|
149
|
+
def key_signature(sharpflat, is_minor)
|
150
|
+
end
|
151
151
|
|
152
|
-
|
153
|
-
|
152
|
+
def arbitrary(msg)
|
153
|
+
end
|
154
154
|
|
155
|
-
# End of NOPs.
|
155
|
+
# End of NOPs.
|
156
156
|
|
157
157
|
|
158
|
-
|
159
|
-
|
160
|
-
|
158
|
+
# Read through 'MThd' or 'MTrk' header string. If skip is true, attempt
|
159
|
+
# to skip initial trash. If there is an error, #error is called.
|
160
|
+
def read_mt_header_string(bytes, skip)
|
161
161
|
b = []
|
162
162
|
bytes_to_read = 4
|
163
163
|
while true
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
end
|
164
|
+
data = get_bytes(bytes_to_read)
|
165
|
+
b += data
|
166
|
+
if b.length < 4
|
167
|
+
error("unexpected EOF while trying to read header string #{s}")
|
168
|
+
end
|
169
|
+
|
170
|
+
# See if we found the bytes we're looking for
|
171
|
+
return if b == bytes
|
172
|
+
|
173
|
+
if skip # Try again with the next char
|
174
|
+
i = b[1..-1].index(bytes[0])
|
175
|
+
if i.nil?
|
176
|
+
b = []
|
177
|
+
bytes_to_read = 4
|
178
|
+
else
|
179
|
+
b = b[i..-1]
|
180
|
+
bytes_to_read = 4 - i
|
181
|
+
end
|
182
|
+
else
|
183
|
+
error("header string #{bytes.collect{|b| b.chr}.join} not found")
|
184
|
+
end
|
186
185
|
end
|
187
|
-
|
186
|
+
end
|
188
187
|
|
189
|
-
|
190
|
-
|
188
|
+
# Read a header chunk.
|
189
|
+
def read_header
|
191
190
|
@bytes_to_be_read = 0
|
192
191
|
read_mt_header_string(MThd_BYTE_ARRAY, @skip_init) # "MThd"
|
193
192
|
|
@@ -200,15 +199,15 @@ class MIDIFile
|
|
200
199
|
|
201
200
|
# Flush any extra stuff, in case the length of the header is not 6
|
202
201
|
if @bytes_to_be_read > 0
|
203
|
-
|
204
|
-
|
202
|
+
get_bytes(@bytes_to_be_read)
|
203
|
+
@bytes_to_be_read = 0
|
205
204
|
end
|
206
205
|
|
207
206
|
return ntrks
|
208
|
-
|
207
|
+
end
|
209
208
|
|
210
|
-
|
211
|
-
|
209
|
+
# Read a track chunk.
|
210
|
+
def read_track
|
212
211
|
c = c1 = type = needed = 0
|
213
212
|
sysex_continue = false # True if last msg was unfinished
|
214
213
|
running = false # True when running status used
|
@@ -223,80 +222,80 @@ class MIDIFile
|
|
223
222
|
start_track()
|
224
223
|
|
225
224
|
while @bytes_to_be_read > 0
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
225
|
+
@curr_ticks = read_var_len() # Delta time
|
226
|
+
@ticks_so_far += @curr_ticks
|
227
|
+
|
228
|
+
# Copy raw var num data into raw time stamp data
|
229
|
+
@raw_time_stamp_data = @raw_var_num_data.dup()
|
230
|
+
|
231
|
+
c = getc() # Read first byte
|
232
|
+
|
233
|
+
if sysex_continue && c != EOX
|
234
|
+
error("didn't find expected continuation of a sysex")
|
235
|
+
end
|
236
|
+
|
237
|
+
if (c & 0x80).zero? # Running status?
|
238
|
+
error('unexpected running status') if status.zero?
|
239
|
+
running = true
|
240
|
+
else
|
241
|
+
status = c
|
242
|
+
running = false
|
243
|
+
end
|
244
|
+
|
245
|
+
needed = NUM_DATA_BYTES[(status >> 4) & 0x0f]
|
246
|
+
|
247
|
+
if needed.nonzero? # i.e., is it a channel message?
|
248
|
+
c1 = running ? c : (getc() & 0x7f)
|
249
|
+
|
250
|
+
# The "& 0x7f" here may seem unnecessary, but I've seen
|
251
|
+
# "bad" MIDI files that had, for example, volume bytes
|
252
|
+
# with the upper bit set. This code should not harm
|
253
|
+
# proper data.
|
254
|
+
chan_message(running, status, c1,
|
255
|
+
(needed > 1) ? (getc() & 0x7f) : 0)
|
256
|
+
next
|
257
|
+
end
|
258
|
+
|
259
|
+
case c
|
260
|
+
when META_EVENT # Meta event
|
261
|
+
type = getc()
|
262
|
+
msg_init()
|
263
|
+
msg_read(read_var_len())
|
264
|
+
meta_event(type)
|
265
|
+
when SYSEX # Start of system exclusive
|
266
|
+
msg_init()
|
267
|
+
msg_add(SYSEX)
|
268
|
+
c = msg_read(read_var_len())
|
269
|
+
|
270
|
+
if c == EOX || !@no_merge
|
271
|
+
handle_sysex(msg())
|
272
|
+
else
|
273
|
+
sysex_continue = true
|
274
|
+
end
|
275
|
+
when EOX # Sysex continuation or arbitrary stuff
|
276
|
+
msg_init() if !sysex_continue
|
277
|
+
c = msg_read(read_var_len())
|
278
|
+
|
279
|
+
if !sysex_continue
|
280
|
+
handle_arbitrary(msg())
|
281
|
+
elsif c == EOX
|
282
|
+
handle_sysex(msg())
|
283
|
+
sysex_continue = false
|
284
|
+
end
|
285
|
+
else
|
286
|
+
bad_byte(c)
|
287
|
+
end
|
289
288
|
end
|
290
289
|
end_track()
|
291
|
-
|
290
|
+
end
|
292
291
|
|
293
|
-
|
294
|
-
|
292
|
+
# Handle an unexpected byte.
|
293
|
+
def bad_byte(c)
|
295
294
|
error(sprintf("unexpected byte: 0x%02x", c))
|
296
|
-
|
295
|
+
end
|
297
296
|
|
298
|
-
|
299
|
-
|
297
|
+
# Handle a meta event.
|
298
|
+
def meta_event(type)
|
300
299
|
m = msg() # Copy of internal message buffer
|
301
300
|
|
302
301
|
# Create raw data array
|
@@ -309,30 +308,30 @@ class MIDIFile
|
|
309
308
|
|
310
309
|
case type
|
311
310
|
when META_SEQ_NUM
|
312
|
-
|
311
|
+
sequence_number((m[0] << 8) + m[1])
|
313
312
|
when META_TEXT, META_COPYRIGHT, META_SEQ_NAME, META_INSTRUMENT,
|
314
|
-
|
315
|
-
|
316
|
-
|
313
|
+
META_LYRIC, META_MARKER, META_CUE, 0x08, 0x09, 0x0a,
|
314
|
+
0x0b, 0x0c, 0x0d, 0x0e, 0x0f
|
315
|
+
text(type, m)
|
317
316
|
when META_TRACK_END
|
318
|
-
|
317
|
+
eot()
|
319
318
|
when META_SET_TEMPO
|
320
|
-
|
319
|
+
tempo((m[0] << 16) + (m[1] << 8) + m[2])
|
321
320
|
when META_SMPTE
|
322
|
-
|
321
|
+
smpte(m[0], m[1], m[2], m[3], m[4])
|
323
322
|
when META_TIME_SIG
|
324
|
-
|
323
|
+
time_signature(m[0], m[1], m[2], m[3])
|
325
324
|
when META_KEY_SIG
|
326
|
-
|
325
|
+
key_signature(m[0], m[1] == 0 ? false : true)
|
327
326
|
when META_SEQ_SPECIF
|
328
|
-
|
327
|
+
sequencer_specific(type, m)
|
329
328
|
else
|
330
|
-
|
329
|
+
meta_misc(type, m)
|
331
330
|
end
|
332
|
-
|
331
|
+
end
|
333
332
|
|
334
|
-
|
335
|
-
|
333
|
+
# Handle a channel message (note on, note off, etc.)
|
334
|
+
def chan_message(running, status, c1, c2)
|
336
335
|
@raw_data = []
|
337
336
|
@raw_data << status unless running
|
338
337
|
@raw_data << c1
|
@@ -342,126 +341,126 @@ class MIDIFile
|
|
342
341
|
|
343
342
|
case (status & 0xf0)
|
344
343
|
when NOTE_OFF
|
345
|
-
|
344
|
+
note_off(chan, c1, c2)
|
346
345
|
when NOTE_ON
|
347
|
-
|
346
|
+
note_on(chan, c1, c2)
|
348
347
|
when POLY_PRESSURE
|
349
|
-
|
348
|
+
pressure(chan, c1, c2)
|
350
349
|
when CONTROLLER
|
351
|
-
|
350
|
+
controller(chan, c1, c2)
|
352
351
|
when PITCH_BEND
|
353
|
-
|
352
|
+
pitch_bend(chan, c1, c2)
|
354
353
|
when PROGRAM_CHANGE
|
355
|
-
|
354
|
+
program(chan, c1)
|
356
355
|
when CHANNEL_PRESSURE
|
357
|
-
|
356
|
+
chan_pressure(chan, c1)
|
358
357
|
else
|
359
|
-
|
358
|
+
error("illegal chan message 0x#{'%02x' % (status & 0xf0)}\n")
|
360
359
|
end
|
361
|
-
|
360
|
+
end
|
362
361
|
|
363
|
-
|
364
|
-
|
362
|
+
# Copy message into raw data array, then call sysex().
|
363
|
+
def handle_sysex(msg)
|
365
364
|
@raw_data = msg.dup()
|
366
365
|
sysex(msg)
|
367
|
-
|
366
|
+
end
|
368
367
|
|
369
|
-
|
370
|
-
|
368
|
+
# Copy message into raw data array, then call arbitrary().
|
369
|
+
def handle_arbitrary(msg)
|
371
370
|
@raw_data = msg.dup()
|
372
371
|
arbitrary(msg)
|
373
|
-
|
372
|
+
end
|
374
373
|
|
375
|
-
|
376
|
-
|
374
|
+
# Read and return a sixteen bit value.
|
375
|
+
def read16
|
377
376
|
val = (getc() << 8) + getc()
|
378
377
|
val = -(val & 0x7fff) if (val & 0x8000).nonzero?
|
379
378
|
return val
|
380
|
-
|
379
|
+
end
|
381
380
|
|
382
|
-
|
383
|
-
|
381
|
+
# Read and return a 32-bit value.
|
382
|
+
def read32
|
384
383
|
val = (getc() << 24) + (getc() << 16) + (getc() << 8) +
|
385
|
-
|
384
|
+
getc()
|
386
385
|
val = -(val & 0x7fffffff) if (val & 0x80000000).nonzero?
|
387
386
|
return val
|
388
|
-
|
387
|
+
end
|
389
388
|
|
390
|
-
|
391
|
-
|
389
|
+
# Read a varlen value.
|
390
|
+
def read_var_len
|
392
391
|
@raw_var_num_data = []
|
393
392
|
c = getc()
|
394
393
|
@raw_var_num_data << c
|
395
394
|
val = c
|
396
395
|
if (val & 0x80).nonzero?
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
396
|
+
val &= 0x7f
|
397
|
+
while true
|
398
|
+
c = getc()
|
399
|
+
@raw_var_num_data << c
|
400
|
+
val = (val << 7) + (c & 0x7f)
|
401
|
+
break if (c & 0x80).zero?
|
402
|
+
end
|
404
403
|
end
|
405
404
|
return val
|
406
|
-
|
405
|
+
end
|
407
406
|
|
408
|
-
|
409
|
-
|
407
|
+
# Write a sixteen-bit value.
|
408
|
+
def write16(val)
|
410
409
|
val = (-val) | 0x8000 if val < 0
|
411
410
|
putc((val >> 8) & 0xff)
|
412
411
|
putc(val & 0xff)
|
413
|
-
|
412
|
+
end
|
414
413
|
|
415
|
-
|
416
|
-
|
414
|
+
# Write a 32-bit value.
|
415
|
+
def write32(val)
|
417
416
|
val = (-val) | 0x80000000 if val < 0
|
418
417
|
putc((val >> 24) & 0xff)
|
419
418
|
putc((val >> 16) & 0xff)
|
420
419
|
putc((val >> 8) & 0xff)
|
421
420
|
putc(val & 0xff)
|
422
|
-
|
421
|
+
end
|
423
422
|
|
424
|
-
|
425
|
-
|
423
|
+
# Write a variable length value.
|
424
|
+
def write_var_len(val)
|
426
425
|
if val.zero?
|
427
|
-
|
428
|
-
|
426
|
+
putc(0)
|
427
|
+
return
|
429
428
|
end
|
430
429
|
|
431
430
|
buf = []
|
432
431
|
|
433
432
|
buf << (val & 0x7f)
|
434
433
|
while (value >>= 7) > 0
|
435
|
-
|
434
|
+
buf << (val & 0x7f) | 0x80
|
436
435
|
end
|
437
436
|
|
438
|
-
buf.reverse.each { |
|
439
|
-
|
437
|
+
buf.reverse.each { |b| putc(b) }
|
438
|
+
end
|
440
439
|
|
441
|
-
|
442
|
-
|
440
|
+
# Add a byte to the current message buffer.
|
441
|
+
def msg_add(c)
|
443
442
|
@msg_buf << c
|
444
|
-
|
443
|
+
end
|
445
444
|
|
446
|
-
|
447
|
-
|
448
|
-
|
445
|
+
# Read and add a number of bytes to the message buffer. Return
|
446
|
+
# the last byte (so we can see if it's an EOX or not).
|
447
|
+
def msg_read(n_bytes)
|
449
448
|
@msg_buf += get_bytes(n_bytes)
|
450
449
|
@msg_buf.flatten!
|
451
450
|
return @msg_buf[-1]
|
452
|
-
|
451
|
+
end
|
453
452
|
|
454
|
-
|
455
|
-
|
453
|
+
# Initialize the internal message buffer.
|
454
|
+
def msg_init
|
456
455
|
@msg_buf = []
|
457
|
-
|
456
|
+
end
|
458
457
|
|
459
|
-
|
460
|
-
|
458
|
+
# Return a copy of the internal message buffer.
|
459
|
+
def msg
|
461
460
|
return @msg_buf.dup()
|
462
|
-
|
461
|
+
end
|
463
462
|
|
464
|
-
end
|
463
|
+
end
|
465
464
|
|
466
|
-
end
|
465
|
+
end
|
467
466
|
end
|