smf 0.15.12
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.
- data/MANUAL +172 -0
- data/MANUAL.en +135 -0
- data/MANUAL.en.html +150 -0
- data/MANUAL.en.rd +144 -0
- data/MANUAL.html +201 -0
- data/MANUAL.rd +179 -0
- data/README +33 -0
- data/README.en +33 -0
- data/lib/smf.rb +736 -0
- data/lib/smf/divert.rb +21 -0
- data/lib/smf/io.rb +1278 -0
- data/lib/smf/toy/beatmap.rb +73 -0
- data/lib/smf/toy/gm.rb +327 -0
- data/lib/smf/toy/groove.rb +34 -0
- data/lib/smf/toy/macro.rb +282 -0
- data/lib/smf/toy/macro/mml.rb +34 -0
- data/lib/smf/toy/macro/mml/parser.rb +545 -0
- data/lib/smf/toy/macro/mml/parser.ry +239 -0
- data/lib/smf/toy/macro/stt.rb +33 -0
- data/lib/smf/toy/morse.rb +126 -0
- data/lib/smf/toy/quantize.rb +32 -0
- data/lib/smf/toy/rmi.rb +29 -0
- data/lib/smf/toy/searchsegment.rb +24 -0
- data/lib/smf/toy/shuffle.rb +39 -0
- data/lib/smf/toy/tempomap.rb +75 -0
- data/lib/smf/toy/text.rb +369 -0
- data/lib/smf/toy/velcomp.rb +42 -0
- data/lib/smf/toy/virtual.rb +118 -0
- data/lib/smf/toy/xml.rb +377 -0
- data/sample/Makefile +58 -0
- data/sample/bwv772.mid +0 -0
- data/sample/bwv772.mml +94 -0
- data/sample/bwv775.mid +0 -0
- data/sample/bwv775.mml +157 -0
- data/sample/bwv787.mid +0 -0
- data/sample/bwv787.mml +129 -0
- data/sample/groove.grv +33 -0
- data/sample/groove.rb +45 -0
- data/sample/ltvddpd2.mid +0 -0
- data/sample/ltvddpd2.stt +60 -0
- data/sample/merge.rb +38 -0
- data/sample/mml-samp.rb +19 -0
- data/sample/mml.rb +36 -0
- data/sample/morse-samp.rb +11 -0
- data/sample/morse.rb +31 -0
- data/sample/play-oss.rb +215 -0
- data/sample/play-oss2.rb +253 -0
- data/sample/play-oss3.rb +150 -0
- data/sample/play-spkr.rb +97 -0
- data/sample/play-win.rb +195 -0
- data/sample/quantize.rb +41 -0
- data/sample/rand1.rb +21 -0
- data/sample/rand2.rb +24 -0
- data/sample/rmi2smf.rb +26 -0
- data/sample/shuffle.rb +43 -0
- data/sample/smf2rmi.rb +26 -0
- data/sample/smf2smf.rb +26 -0
- data/sample/smf2text.rb +27 -0
- data/sample/smf2wav.rb +123 -0
- data/sample/smf2xml.rb +27 -0
- data/sample/split.rb +40 -0
- data/sample/stt-samp.rb +19 -0
- data/sample/stt.rb +36 -0
- data/sample/text2smf.rb +28 -0
- data/sample/velcomp.rb +45 -0
- data/sample/virtual-samp.rb +19 -0
- data/sample/xml2smf.rb +28 -0
- metadata +128 -0
data/lib/smf/divert.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# divert.rb: Written by Tadayoshi Funaba 2000, 2001
|
2
|
+
# $Id: divert.rb,v 1.3 2001-04-01 19:47:51+09 tadf Exp $
|
3
|
+
|
4
|
+
module SMF
|
5
|
+
|
6
|
+
class Track
|
7
|
+
|
8
|
+
def divert(sq)
|
9
|
+
each do |ev|
|
10
|
+
n = yield ev
|
11
|
+
if n
|
12
|
+
sq[n] ||= Track.new
|
13
|
+
sq[n] << ev
|
14
|
+
end
|
15
|
+
end
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/smf/io.rb
ADDED
@@ -0,0 +1,1278 @@
|
|
1
|
+
# io.rb: Written by Tadayoshi Funaba 1998-2008
|
2
|
+
# $Id: io.rb,v 1.9 2008-11-12 19:24:09+09 tadf Exp $
|
3
|
+
|
4
|
+
module SMF
|
5
|
+
|
6
|
+
class Sequence
|
7
|
+
|
8
|
+
class ReadError < StandardError; end
|
9
|
+
|
10
|
+
class RS
|
11
|
+
|
12
|
+
class PO
|
13
|
+
|
14
|
+
def self.u2s(u, w) u -= 2**w if u > 2**(w-1)-1; u end
|
15
|
+
|
16
|
+
def initialize(str) @str, @index = str, 0 end
|
17
|
+
def rem() @str.length - @index end
|
18
|
+
def eof? () rem <= 0 end
|
19
|
+
def skip(n) @index += n end
|
20
|
+
|
21
|
+
def getn(n)
|
22
|
+
raise EOFError if rem < n
|
23
|
+
s = @str[@index, n]
|
24
|
+
skip(n)
|
25
|
+
s
|
26
|
+
end
|
27
|
+
|
28
|
+
unless String === '0'[0]
|
29
|
+
|
30
|
+
def getc
|
31
|
+
raise EOFError if rem < 1
|
32
|
+
c = @str[@index]
|
33
|
+
skip(1)
|
34
|
+
c
|
35
|
+
end
|
36
|
+
|
37
|
+
else
|
38
|
+
|
39
|
+
def getc
|
40
|
+
raise EOFError if rem < 1
|
41
|
+
c = @str[@index].ord
|
42
|
+
skip(1)
|
43
|
+
c
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def getl
|
49
|
+
v = 0
|
50
|
+
begin
|
51
|
+
v <<= 7
|
52
|
+
c = getc
|
53
|
+
v |= c & 0x7f
|
54
|
+
end until (c & 0x80).zero?
|
55
|
+
v
|
56
|
+
end
|
57
|
+
|
58
|
+
def geti(n)
|
59
|
+
u = 0
|
60
|
+
n.times do
|
61
|
+
u <<= 8
|
62
|
+
c = getc
|
63
|
+
u |= c
|
64
|
+
end
|
65
|
+
u
|
66
|
+
end
|
67
|
+
|
68
|
+
def geti16() geti(2) end
|
69
|
+
def geti24() geti(3) end
|
70
|
+
def geti32() geti(4) end
|
71
|
+
|
72
|
+
def to_s() @str.dup end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize(s, cb) @s, @cb = s, cb end
|
77
|
+
|
78
|
+
def read_header(s)
|
79
|
+
rs = RS::PO.new(s)
|
80
|
+
format = rs.geti16
|
81
|
+
ntrks = rs.geti16
|
82
|
+
div1 = rs.getc
|
83
|
+
div2 = rs.getc
|
84
|
+
if (div1 & 0x80) == 0
|
85
|
+
tc = nil
|
86
|
+
division = div1 << 8 | div2
|
87
|
+
else
|
88
|
+
tc = 0x100 - div1
|
89
|
+
division = div2
|
90
|
+
end
|
91
|
+
@cb.header(format, ntrks, division, tc)
|
92
|
+
end
|
93
|
+
|
94
|
+
def read_meta(type, data)
|
95
|
+
case type
|
96
|
+
when 0x0
|
97
|
+
rs = RS::PO.new(data)
|
98
|
+
num = rs.geti16
|
99
|
+
@cb.sequencenumber(num)
|
100
|
+
when 0x1..0xf
|
101
|
+
case type
|
102
|
+
when 0x1; @cb.generalpurposetext(data)
|
103
|
+
when 0x2; @cb.copyrightnotice(data)
|
104
|
+
when 0x3; @cb.trackname(data)
|
105
|
+
when 0x4; @cb.instrumentname(data)
|
106
|
+
when 0x5; @cb.lyric(data)
|
107
|
+
when 0x6; @cb.marker(data)
|
108
|
+
when 0x7; @cb.cuepoint(data)
|
109
|
+
when 0x8; @cb.programname(data)
|
110
|
+
when 0x9; @cb.devicename(data)
|
111
|
+
when 0xa; @cb.text0a(data)
|
112
|
+
when 0xb; @cb.text0b(data)
|
113
|
+
when 0xc; @cb.text0c(data)
|
114
|
+
when 0xd; @cb.text0d(data)
|
115
|
+
when 0xe; @cb.text0e(data)
|
116
|
+
when 0xf; @cb.text0f(data)
|
117
|
+
end
|
118
|
+
when 0x20
|
119
|
+
rs = RS::PO.new(data)
|
120
|
+
ch = rs.getc
|
121
|
+
@cb.channelprefix(ch)
|
122
|
+
when 0x21
|
123
|
+
rs = RS::PO.new(data)
|
124
|
+
num = rs.getc
|
125
|
+
@cb.midiport(num)
|
126
|
+
when 0x2f
|
127
|
+
@cb.endoftrack
|
128
|
+
when 0x51
|
129
|
+
rs = RS::PO.new(data)
|
130
|
+
tempo = rs.geti24
|
131
|
+
@cb.settempo(tempo)
|
132
|
+
when 0x54
|
133
|
+
rs = RS::PO.new(data)
|
134
|
+
hr = rs.getc
|
135
|
+
tc = [24, 25, 29, 30][(hr >> 5) & 0x3]
|
136
|
+
hr &= 0x1f
|
137
|
+
mn = rs.getc
|
138
|
+
se = rs.getc
|
139
|
+
fr = rs.getc
|
140
|
+
ff = rs.getc
|
141
|
+
@cb.smpteoffset(hr, mn, se, fr, ff, tc)
|
142
|
+
when 0x58
|
143
|
+
rs = RS::PO.new(data)
|
144
|
+
nn = rs.getc
|
145
|
+
dd = rs.getc
|
146
|
+
cc = rs.getc
|
147
|
+
bb = rs.getc
|
148
|
+
@cb.timesignature(nn, dd, cc, bb)
|
149
|
+
when 0x59
|
150
|
+
rs = RS::PO.new(data)
|
151
|
+
sf = rs.getc
|
152
|
+
mi = rs.getc
|
153
|
+
sf = RS::PO.u2s(sf, 8)
|
154
|
+
@cb.keysignature(sf, mi)
|
155
|
+
when 0x7f
|
156
|
+
@cb.sequencerspecific(data)
|
157
|
+
else
|
158
|
+
@cb.unknownmeta(type, data)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def read_track(s)
|
163
|
+
@cb.track_start
|
164
|
+
rs = RS::PO.new(s)
|
165
|
+
running = 0
|
166
|
+
until rs.eof?
|
167
|
+
@cb.delta(rs.getl)
|
168
|
+
stat = rs.getc
|
169
|
+
if (stat & 0x80) == 0
|
170
|
+
rs.skip(-1)
|
171
|
+
stat = running
|
172
|
+
else
|
173
|
+
case stat
|
174
|
+
when 0x80..0xef; running = stat
|
175
|
+
when 0xf0..0xf7; running = 0
|
176
|
+
end
|
177
|
+
end
|
178
|
+
case stat
|
179
|
+
when 0x80..0x8f
|
180
|
+
@cb.noteoff(stat & 0xf, rs.getc, rs.getc)
|
181
|
+
when 0x90..0x9f
|
182
|
+
@cb.noteon(stat & 0xf, rs.getc, rs.getc)
|
183
|
+
when 0xa0..0xaf
|
184
|
+
@cb.polyphonickeypressure(stat & 0xf, rs.getc, rs.getc)
|
185
|
+
when 0xb0..0xbf
|
186
|
+
n = rs.getc
|
187
|
+
v = rs.getc
|
188
|
+
if n < 0x78
|
189
|
+
@cb.controlchange(stat & 0xf, n, v)
|
190
|
+
else
|
191
|
+
case n
|
192
|
+
when 0x78; @cb.allsoundoff(stat & 0xf)
|
193
|
+
when 0x79; @cb.resetallcontrollers(stat & 0xf)
|
194
|
+
when 0x7a; @cb.localcontrol(stat & 0xf, v)
|
195
|
+
when 0x7b; @cb.allnotesoff(stat & 0xf)
|
196
|
+
when 0x7c; @cb.omnioff(stat & 0xf)
|
197
|
+
when 0x7d; @cb.omnion(stat & 0xf)
|
198
|
+
when 0x7e; @cb.monomode(stat & 0xf, v)
|
199
|
+
when 0x7f; @cb.polymode(stat & 0xf)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
when 0xc0..0xcf
|
203
|
+
@cb.programchange(stat & 0xf, rs.getc)
|
204
|
+
when 0xd0..0xdf
|
205
|
+
@cb.channelpressure(stat & 0xf, rs.getc)
|
206
|
+
when 0xe0..0xef
|
207
|
+
lsb = rs.getc
|
208
|
+
msb = rs.getc
|
209
|
+
val = (lsb | msb << 7) - 0x2000
|
210
|
+
@cb.pitchbendchange(stat & 0xf, val)
|
211
|
+
when 0xf0, 0xf7
|
212
|
+
len = rs.getl
|
213
|
+
data = rs.getn(len)
|
214
|
+
if stat == 0xf0
|
215
|
+
@cb.exclusivef0(data)
|
216
|
+
else
|
217
|
+
@cb.exclusivef7(data)
|
218
|
+
end
|
219
|
+
when 0xff
|
220
|
+
type = rs.getc
|
221
|
+
len = rs.getl
|
222
|
+
data = rs.getn(len)
|
223
|
+
read_meta(type, data)
|
224
|
+
else
|
225
|
+
until rs.eof?
|
226
|
+
unless (rs.getc & 0x80) == 0
|
227
|
+
rs.skip(-1)
|
228
|
+
break
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
@cb.track_end
|
234
|
+
end
|
235
|
+
|
236
|
+
private :read_header, :read_meta, :read_track
|
237
|
+
|
238
|
+
def get_from_macbin
|
239
|
+
begin
|
240
|
+
if @s[0, 1] == "\000" && @s[74,1] == "\000" &&
|
241
|
+
@s[82,1] == "\000" && @s[65,4] == 'Midi'
|
242
|
+
@s[128,@s[83,4].unpack('N')[0]]
|
243
|
+
end
|
244
|
+
rescue
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def get_from_rmid
|
249
|
+
begin
|
250
|
+
if @s[0,4] == 'RIFF' && @s[8,4] == 'RMID'
|
251
|
+
@s[20,@s[16,4].unpack('V')[0]]
|
252
|
+
end
|
253
|
+
rescue
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
private :get_from_macbin, :get_from_rmid
|
258
|
+
|
259
|
+
def read
|
260
|
+
begin
|
261
|
+
rs = RS::PO.new(get_from_macbin || get_from_rmid || @s)
|
262
|
+
ckid = rs.getn(4)
|
263
|
+
unless ckid == 'MThd'
|
264
|
+
@cb.error('not an SMF')
|
265
|
+
end
|
266
|
+
rs.skip(-4)
|
267
|
+
until rs.eof?
|
268
|
+
ckid = rs.getn(4)
|
269
|
+
leng = rs.geti32
|
270
|
+
body = rs.getn(leng)
|
271
|
+
case ckid
|
272
|
+
when 'MThd'
|
273
|
+
read_header(body)
|
274
|
+
when 'MTrk'
|
275
|
+
read_track(body)
|
276
|
+
else
|
277
|
+
@cb.unknownchunk(ckid, body)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
rescue EOFError
|
281
|
+
@cb.error('unexpected EOF')
|
282
|
+
end
|
283
|
+
@cb.result
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
class WS
|
289
|
+
|
290
|
+
class PO
|
291
|
+
|
292
|
+
def self.s2u(s, w) s += 2**w if s < 0; s end
|
293
|
+
|
294
|
+
# def initialize() @str = '' end
|
295
|
+
def initialize() @arr = [] end
|
296
|
+
|
297
|
+
# def puts(s) @str << s end
|
298
|
+
# def putc(c) @str << c end
|
299
|
+
|
300
|
+
unless String === '0'[0]
|
301
|
+
|
302
|
+
def puts(s) @arr << s end
|
303
|
+
def putc(c) @arr << c.chr end
|
304
|
+
|
305
|
+
def putl(v)
|
306
|
+
s = ''
|
307
|
+
begin
|
308
|
+
s << (v & 0x7f | 0x80)
|
309
|
+
v >>= 7
|
310
|
+
end until v.zero?
|
311
|
+
s[0] &= 0x7f
|
312
|
+
s.reverse!
|
313
|
+
puts(s)
|
314
|
+
end
|
315
|
+
|
316
|
+
else
|
317
|
+
|
318
|
+
def puts(s) @arr << s.dup.force_encoding('ascii-8bit') end
|
319
|
+
def putc(c) @arr << c.chr.force_encoding('ascii-8bit') end
|
320
|
+
|
321
|
+
def putl(v)
|
322
|
+
s = ''.force_encoding('ascii-8bit')
|
323
|
+
begin
|
324
|
+
s << (v & 0x7f | 0x80)
|
325
|
+
v >>= 7
|
326
|
+
end until v.zero?
|
327
|
+
s[0] = (s.ord & 0x7f).chr
|
328
|
+
s.reverse!
|
329
|
+
puts(s)
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
def puti(n, u)
|
335
|
+
n.times do |i|
|
336
|
+
putc((u >> (n - i - 1) * 8) & 0xff)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def puti16(u) puti(2, u) end
|
341
|
+
def puti24(u) puti(3, u) end
|
342
|
+
def puti32(u) puti(4, u) end
|
343
|
+
|
344
|
+
# def to_s() @str.dup end
|
345
|
+
def to_s() @arr.join end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
def initialize(o, cb) @o, @cb = o, cb end
|
350
|
+
|
351
|
+
def read_meta(ev)
|
352
|
+
case ev
|
353
|
+
when SequenceNumber
|
354
|
+
@cb.sequencenumber(ev.num)
|
355
|
+
when Text
|
356
|
+
case ev
|
357
|
+
when GeneralPurposeText; @cb.generalpurposetext(ev.text)
|
358
|
+
when CopyrightNotice; @cb.copyrightnotice(ev.text)
|
359
|
+
when TrackName; @cb.trackname(ev.text)
|
360
|
+
when InstrumentName; @cb.instrumentname(ev.text)
|
361
|
+
when Lyric; @cb.lyric(ev.text)
|
362
|
+
when Marker; @cb.marker(ev.text)
|
363
|
+
when CuePoint; @cb.cuepoint(ev.text)
|
364
|
+
when ProgramName; @cb.programname(ev.text)
|
365
|
+
when DeviceName; @cb.devicename(ev.text)
|
366
|
+
when Text0A; @cb.text0a(ev.text)
|
367
|
+
when Text0B; @cb.text0b(ev.text)
|
368
|
+
when Text0C; @cb.text0c(ev.text)
|
369
|
+
when Text0D; @cb.text0d(ev.text)
|
370
|
+
when Text0E; @cb.text0e(ev.text)
|
371
|
+
when Text0F; @cb.text0f(ev.text)
|
372
|
+
end
|
373
|
+
when ChannelPrefix
|
374
|
+
@cb.channelprefix(ev.ch)
|
375
|
+
when MIDIPort
|
376
|
+
@cb.midiport(ev.num)
|
377
|
+
when EndOfTrack
|
378
|
+
@cb.endoftrack
|
379
|
+
when SetTempo
|
380
|
+
@cb.settempo(ev.tempo)
|
381
|
+
when SMPTEOffset
|
382
|
+
@cb.smpteoffset(ev.hr, ev.mn, ev.se, ev.fr, ev.ff, ev.tc)
|
383
|
+
when TimeSignature
|
384
|
+
@cb.timesignature(ev.nn, ev.dd, ev.cc, ev.bb)
|
385
|
+
when KeySignature
|
386
|
+
@cb.keysignature(ev.sf, ev.mi)
|
387
|
+
when SequencerSpecific
|
388
|
+
@cb.sequencerspecific(ev.data)
|
389
|
+
else
|
390
|
+
@cb.unknownmeta(ev.type, ev.data)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def read_track(tr)
|
395
|
+
@cb.track_start
|
396
|
+
offset = 0
|
397
|
+
tr.each do |ev|
|
398
|
+
@cb.delta(ev.offset - offset)
|
399
|
+
case ev
|
400
|
+
when NoteOff
|
401
|
+
if ev.fake?
|
402
|
+
@cb.noteon(ev.ch, ev.note, 0)
|
403
|
+
else
|
404
|
+
@cb.noteoff(ev.ch, ev.note, ev.vel)
|
405
|
+
end
|
406
|
+
when NoteOn
|
407
|
+
@cb.noteon(ev.ch, ev.note, ev.vel)
|
408
|
+
when PolyphonicKeyPressure
|
409
|
+
@cb.polyphonickeypressure(ev.ch, ev.note, ev.val)
|
410
|
+
when ControlChange
|
411
|
+
@cb.controlchange(ev.ch, ev.num, ev.val)
|
412
|
+
when ProgramChange
|
413
|
+
@cb.programchange(ev.ch, ev.num)
|
414
|
+
when ChannelPressure
|
415
|
+
@cb.channelpressure(ev.ch, ev.val)
|
416
|
+
when PitchBendChange
|
417
|
+
@cb.pitchbendchange(ev.ch, ev.val)
|
418
|
+
when AllSoundOff
|
419
|
+
@cb.allsoundoff(ev.ch)
|
420
|
+
when ResetAllControllers
|
421
|
+
@cb.resetallcontrollers(ev.ch)
|
422
|
+
when LocalControl
|
423
|
+
@cb.localcontrol(ev.ch, ev.val)
|
424
|
+
when AllNotesOff
|
425
|
+
@cb.allnotesoff(ev.ch)
|
426
|
+
when OmniOff
|
427
|
+
@cb.omnioff(ev.ch)
|
428
|
+
when OmniOn
|
429
|
+
@cb.omnion(ev.ch)
|
430
|
+
when MonoMode
|
431
|
+
@cb.monomode(ev.ch, ev.val)
|
432
|
+
when PolyMode
|
433
|
+
@cb.polymode(ev.ch)
|
434
|
+
when ExclusiveF0
|
435
|
+
@cb.exclusivef0(ev.data)
|
436
|
+
when ExclusiveF7
|
437
|
+
@cb.exclusivef7(ev.data)
|
438
|
+
when Meta
|
439
|
+
read_meta(ev)
|
440
|
+
end
|
441
|
+
offset = ev.offset
|
442
|
+
end
|
443
|
+
@cb.track_end
|
444
|
+
end
|
445
|
+
|
446
|
+
private :read_meta, :read_track
|
447
|
+
|
448
|
+
def read
|
449
|
+
@cb.header(@o.format, @o.ntrks, @o.division, @o.tc)
|
450
|
+
@o.each do |ck|
|
451
|
+
case ck
|
452
|
+
when Track
|
453
|
+
read_track(ck)
|
454
|
+
else
|
455
|
+
@cb.unknownchunk(ck.ckid, ck.body)
|
456
|
+
end
|
457
|
+
end
|
458
|
+
@cb.result
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|
462
|
+
|
463
|
+
class XSCallback
|
464
|
+
|
465
|
+
def header(format, ntrks, division, tc) end
|
466
|
+
|
467
|
+
def track_start() end
|
468
|
+
def track_end() end
|
469
|
+
|
470
|
+
def unknownchunk(ckid, body) end
|
471
|
+
def delta(delta) end
|
472
|
+
|
473
|
+
def noteoff(ch, note, vel) end
|
474
|
+
def noteon(ch, note, vel) end
|
475
|
+
def polyphonickeypressure(ch, note, val) end
|
476
|
+
def controlchange(ch, num, val) end
|
477
|
+
def programchange(ch, num) end
|
478
|
+
def channelpressure(ch, val) end
|
479
|
+
def pitchbendchange(ch, val) end
|
480
|
+
|
481
|
+
def allsoundoff(ch) end
|
482
|
+
def resetallcontrollers(ch) end
|
483
|
+
def localcontrol(ch, val) end
|
484
|
+
def allnotesoff(ch) end
|
485
|
+
def omnioff(ch) end
|
486
|
+
def omnion(ch) end
|
487
|
+
def monomode(ch, val) end
|
488
|
+
def polymode(ch) end
|
489
|
+
|
490
|
+
def exclusivef0(data) end
|
491
|
+
def exclusivef7(data) end
|
492
|
+
|
493
|
+
def sequencenumber(num) end
|
494
|
+
|
495
|
+
def generalpurposetext(text) end
|
496
|
+
def copyrightnotice(text) end
|
497
|
+
def trackname(text) end
|
498
|
+
def instrumentname(text) end
|
499
|
+
def lyric(text) end
|
500
|
+
def marker(text) end
|
501
|
+
def cuepoint(text) end
|
502
|
+
def programname(text) end
|
503
|
+
def devicename(text) end
|
504
|
+
def text0a(text) end
|
505
|
+
def text0b(text) end
|
506
|
+
def text0c(text) end
|
507
|
+
def text0d(text) end
|
508
|
+
def text0e(text) end
|
509
|
+
def text0f(text) end
|
510
|
+
|
511
|
+
def channelprefix(ch) end
|
512
|
+
def midiport(num) end
|
513
|
+
def endoftrack() end
|
514
|
+
def settempo(tempo) end
|
515
|
+
def smpteoffset(hr, mn, se, fr, ff, tc) end
|
516
|
+
def timesignature(nn, dd, cc, bb) end
|
517
|
+
def keysignature(sf, mi) end
|
518
|
+
def sequencerspecific(data) end
|
519
|
+
|
520
|
+
def unknownmeta(type, data) end
|
521
|
+
|
522
|
+
def result() end
|
523
|
+
|
524
|
+
def error(mesg) end
|
525
|
+
def warn(mesg) end
|
526
|
+
|
527
|
+
end
|
528
|
+
|
529
|
+
module Checker
|
530
|
+
|
531
|
+
def cr(n, v, e, w=nil)
|
532
|
+
unless e === v
|
533
|
+
error("#{n}: out of range")
|
534
|
+
return
|
535
|
+
end
|
536
|
+
if w
|
537
|
+
unless w === v
|
538
|
+
warn("#{n}: out of range")
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
private :cr
|
544
|
+
|
545
|
+
def header(format, ntrks, division, tc)
|
546
|
+
cr('header/format', format, (0..2**16-1), (0..2))
|
547
|
+
if format == 0
|
548
|
+
cr('header/ntrks', ntrks, (0..2**16-1), (1..1))
|
549
|
+
else
|
550
|
+
cr('header/ntrks', ntrks, (0..2**16-1), (1..2**16-1))
|
551
|
+
end
|
552
|
+
unless tc
|
553
|
+
cr('header/division', division, (1..2**15-1))
|
554
|
+
else
|
555
|
+
cr('header/division', division, (1..2**8-1))
|
556
|
+
cr('header/tc', tc, (0..2**7))
|
557
|
+
unless [24, 25, 29, 30].include? tc
|
558
|
+
warn('header/tc: invalid format')
|
559
|
+
end
|
560
|
+
end
|
561
|
+
super
|
562
|
+
end
|
563
|
+
|
564
|
+
def chunk_body(body)
|
565
|
+
unless body.length <= 2**32-1
|
566
|
+
error('chunk size: too large')
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
private :chunk_body
|
571
|
+
|
572
|
+
def delta(delta)
|
573
|
+
cr('delta', delta, (0..2**28-1))
|
574
|
+
super
|
575
|
+
end
|
576
|
+
|
577
|
+
def noteoff(ch, note, vel)
|
578
|
+
cr('noteoff/ch', ch, (0..2**4-1))
|
579
|
+
cr('noteoff/note', note, (0..2**7-1))
|
580
|
+
cr('noteoff/vel', vel, (0..2**7-1))
|
581
|
+
super
|
582
|
+
end
|
583
|
+
|
584
|
+
def noteon(ch, note, vel)
|
585
|
+
cr('noteon/ch', ch, (0..2**4-1))
|
586
|
+
cr('noteon/note', note, (0..2**7-1))
|
587
|
+
cr('noteon/vel', vel, (0..2**7-1))
|
588
|
+
super
|
589
|
+
end
|
590
|
+
|
591
|
+
def polyphonickeypressure(ch, note, val)
|
592
|
+
cr('polyphonickeypressure/ch', ch, (0..2**4-1))
|
593
|
+
cr('polyphonickeypressure/note', note, (0..2**7-1))
|
594
|
+
cr('polyphonickeypressure/val', val, (0..2**7-1))
|
595
|
+
super
|
596
|
+
end
|
597
|
+
|
598
|
+
def controlchange(ch, num, val)
|
599
|
+
cr('controlchange/ch', ch, (0..2**4-1))
|
600
|
+
cr('controlchange/num', num, (0..0x77))
|
601
|
+
cr('controlchange/val', val, (0..2**7-1))
|
602
|
+
super
|
603
|
+
end
|
604
|
+
|
605
|
+
def programchange(ch, num)
|
606
|
+
cr('programchange/ch', ch, (0..2**4-1))
|
607
|
+
cr('programchange/num', num, (0..2**7-1))
|
608
|
+
super
|
609
|
+
end
|
610
|
+
|
611
|
+
def channelpressure(ch, val)
|
612
|
+
cr('channelpressure/ch', ch, (0..2**4-1))
|
613
|
+
cr('channelpressure/val', val, (0..2**7-1))
|
614
|
+
super
|
615
|
+
end
|
616
|
+
|
617
|
+
def pitchbendchange(ch, val)
|
618
|
+
cr('pitchbendchange/ch', ch, (0..2**4-1))
|
619
|
+
cr('pitchbendchange/val', val, (-2**13..2**13-1))
|
620
|
+
super
|
621
|
+
end
|
622
|
+
|
623
|
+
def no_channelmodemessage(ch, num, val)
|
624
|
+
cr('channelmodemessage/ch', ch, (0..2**4-1))
|
625
|
+
cr('channelmodemessage/num', num, (0x78..0x7f))
|
626
|
+
unless num == 0x7e
|
627
|
+
cr('channelmodemessage/val', val, (0..2**7-1))
|
628
|
+
else
|
629
|
+
cr('channelmodemessage/val', val, (0..2**7-1), (0..16))
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
private :no_channelmodemessage
|
634
|
+
|
635
|
+
def allsoundoff(ch) no_channelmodemessage(ch, 0x78, 0); super end
|
636
|
+
def resetallcontrollers(ch) no_channelmodemessage(ch, 0x79, 0); super end
|
637
|
+
def localcontrol(ch, val) no_channelmodemessage(ch, 0x7a, val); super end
|
638
|
+
def allnotesoff(ch) no_channelmodemessage(ch, 0x7b, 0); super end
|
639
|
+
def omnioff(ch) no_channelmodemessage(ch, 0x7c, 0); super end
|
640
|
+
def omnion(ch) no_channelmodemessage(ch, 0x7d, 0); super end
|
641
|
+
def monomode(ch, val) no_channelmodemessage(ch, 0x7e, val); super end
|
642
|
+
def polymode(ch) no_channelmodemessage(ch, 0x7f, 0); super end
|
643
|
+
|
644
|
+
def exclusivef0(data)
|
645
|
+
cr('exclusive size', data.length, (0..2**28-1), (1..2**28-1))
|
646
|
+
super
|
647
|
+
end
|
648
|
+
|
649
|
+
def exclusivef7(data)
|
650
|
+
cr('exclusive size', data.length, (0..2**28-1), (1..2**28-1))
|
651
|
+
super
|
652
|
+
end
|
653
|
+
|
654
|
+
def sequencenumber(num)
|
655
|
+
cr('sequencenumber/num', num, (0..2**16-1))
|
656
|
+
super
|
657
|
+
end
|
658
|
+
|
659
|
+
def no_text(type, text)
|
660
|
+
cr('text size', text.length, (0..2**28-1), (1..2**28-1))
|
661
|
+
end
|
662
|
+
|
663
|
+
private :no_text
|
664
|
+
|
665
|
+
def generalpurposetext(text) no_text(0x1, text); super end
|
666
|
+
def copyrightnotice(text) no_text(0x2, text); super end
|
667
|
+
def trackname(text) no_text(0x3, text); super end
|
668
|
+
def instrumentname(text) no_text(0x4, text); super end
|
669
|
+
def lyric(text) no_text(0x5, text); super end
|
670
|
+
def marker(text) no_text(0x6, text); super end
|
671
|
+
def cuepoint(text) no_text(0x7, text); super end
|
672
|
+
def programname(text) no_text(0x8, text); super end
|
673
|
+
def devicename(text) no_text(0x9, text); super end
|
674
|
+
def text0a(text) no_text(0xa, text); super end
|
675
|
+
def text0b(text) no_text(0xb, text); super end
|
676
|
+
def text0c(text) no_text(0xc, text); super end
|
677
|
+
def text0d(text) no_text(0xd, text); super end
|
678
|
+
def text0e(text) no_text(0xe, text); super end
|
679
|
+
def text0f(text) no_text(0xf, text); super end
|
680
|
+
|
681
|
+
def channelprefix(ch)
|
682
|
+
cr('channelprefix/ch', ch, (0..2**8-1), (0..2**4-1))
|
683
|
+
super
|
684
|
+
end
|
685
|
+
|
686
|
+
def midiport(num)
|
687
|
+
cr('midiport/num', num, (0..2**8-1))
|
688
|
+
super
|
689
|
+
end
|
690
|
+
|
691
|
+
def settempo(tempo)
|
692
|
+
cr('settempo/tempo', tempo, (1..2**24-1))
|
693
|
+
super
|
694
|
+
end
|
695
|
+
|
696
|
+
def smpteoffset(hr, mn, se, fr, ff, tc)
|
697
|
+
cr('smpteoffset/hr', hr, (0..2**8-1), (1..23))
|
698
|
+
cr('smpteoffset/mn', mn, (0..2**8-1), (1..59))
|
699
|
+
cr('smpteoffset/se', se, (0..2**8-1), (1..59))
|
700
|
+
cr('smpteoffset/fr', fr, (0..2**8-1), (1..29))
|
701
|
+
cr('smpteoffset/ff', ff, (0..2**8-1), (1..99))
|
702
|
+
cr('smpteoffset/tc', tc, (0..2**8-1))
|
703
|
+
unless [24, 25, 29, 30].include? tc
|
704
|
+
warn('smpteoffset/tc: invalid format')
|
705
|
+
end
|
706
|
+
super
|
707
|
+
end
|
708
|
+
|
709
|
+
def timesignature(nn, dd, cc, bb)
|
710
|
+
cr('timesignature/nn', nn, (1..2**8-1))
|
711
|
+
cr('timesignature/dd', dd, (0..2**8-1))
|
712
|
+
cr('timesignature/cc', cc, (1..2**8-1))
|
713
|
+
cr('timesignature/bb', bb, (1..2**8-1))
|
714
|
+
super
|
715
|
+
end
|
716
|
+
|
717
|
+
def keysignature(sf, mi)
|
718
|
+
cr('keysignature/sf', sf, (-2**7..2**7-1))
|
719
|
+
cr('keysignature/mi', mi, (0..1))
|
720
|
+
super
|
721
|
+
end
|
722
|
+
|
723
|
+
def sequencerspecific(data)
|
724
|
+
unless data.length <= 2**28-1
|
725
|
+
error('sequencerspecific: too large')
|
726
|
+
end
|
727
|
+
super
|
728
|
+
end
|
729
|
+
|
730
|
+
def unknownmeta(type, data)
|
731
|
+
unless data.length <= 2**28-1
|
732
|
+
error('unknownmeta: too large')
|
733
|
+
end
|
734
|
+
super
|
735
|
+
end
|
736
|
+
|
737
|
+
end
|
738
|
+
|
739
|
+
class Decode < XSCallback
|
740
|
+
|
741
|
+
# include Checker
|
742
|
+
|
743
|
+
def header(format, ntrks, division, tc)
|
744
|
+
@sq = Sequence.new(format, division, tc)
|
745
|
+
end
|
746
|
+
|
747
|
+
def track_start
|
748
|
+
@sq << (@tr = Track.new)
|
749
|
+
@offset = 0
|
750
|
+
end
|
751
|
+
|
752
|
+
def delta(delta) @offset += delta end
|
753
|
+
|
754
|
+
def noteoff(ch, note, vel)
|
755
|
+
@tr << NoteOff.new(@offset, ch, note, vel)
|
756
|
+
end
|
757
|
+
|
758
|
+
def noteon(ch, note, vel)
|
759
|
+
if vel == 0
|
760
|
+
@tr << NoteOff.new(@offset, ch, note, nil)
|
761
|
+
else
|
762
|
+
@tr << NoteOn.new(@offset, ch, note, vel)
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
def polyphonickeypressure(ch, note, val)
|
767
|
+
@tr << PolyphonicKeyPressure.new(@offset, ch, note, val)
|
768
|
+
end
|
769
|
+
|
770
|
+
def controlchange(ch, num, val)
|
771
|
+
@tr << ControlChange.new(@offset, ch, num, val)
|
772
|
+
end
|
773
|
+
|
774
|
+
def programchange(ch, num)
|
775
|
+
@tr << ProgramChange.new(@offset, ch, num)
|
776
|
+
end
|
777
|
+
|
778
|
+
def channelpressure(ch, val)
|
779
|
+
@tr << ChannelPressure.new(@offset, ch, val)
|
780
|
+
end
|
781
|
+
|
782
|
+
def pitchbendchange(ch, val)
|
783
|
+
@tr << PitchBendChange.new(@offset, ch, val)
|
784
|
+
end
|
785
|
+
|
786
|
+
def allsoundoff(ch)
|
787
|
+
@tr << AllSoundOff.new(@offset, ch)
|
788
|
+
end
|
789
|
+
|
790
|
+
def resetallcontrollers(ch)
|
791
|
+
@tr << ResetAllControllers.new(@offset, ch)
|
792
|
+
end
|
793
|
+
|
794
|
+
def localcontrol(ch, val)
|
795
|
+
@tr << LocalControl.new(@offset, ch, val)
|
796
|
+
end
|
797
|
+
|
798
|
+
def allnotesoff(ch)
|
799
|
+
@tr << AllNotesOff.new(@offset, ch)
|
800
|
+
end
|
801
|
+
|
802
|
+
def omnioff(ch)
|
803
|
+
@tr << OmniOff.new(@offset, ch)
|
804
|
+
end
|
805
|
+
|
806
|
+
def omnion(ch)
|
807
|
+
@tr << OmniOn.new(@offset, ch)
|
808
|
+
end
|
809
|
+
|
810
|
+
def monomode(ch, val)
|
811
|
+
@tr << MonoMode.new(@offset, ch, val)
|
812
|
+
end
|
813
|
+
|
814
|
+
def polymode(ch)
|
815
|
+
@tr << PolyMode.new(@offset, ch)
|
816
|
+
end
|
817
|
+
|
818
|
+
def exclusivef0(data)
|
819
|
+
@tr << ExclusiveF0.new(@offset, data)
|
820
|
+
end
|
821
|
+
|
822
|
+
def exclusivef7(data)
|
823
|
+
@tr << ExclusiveF7.new(@offset, data)
|
824
|
+
end
|
825
|
+
|
826
|
+
def sequencenumber(num)
|
827
|
+
@tr << SequenceNumber.new(@offset, num)
|
828
|
+
end
|
829
|
+
|
830
|
+
def generalpurposetext(text)
|
831
|
+
@tr << GeneralPurposeText.new(@offset, text)
|
832
|
+
end
|
833
|
+
|
834
|
+
def copyrightnotice(text)
|
835
|
+
@tr << CopyrightNotice.new(@offset, text)
|
836
|
+
end
|
837
|
+
|
838
|
+
def trackname(text)
|
839
|
+
@tr << TrackName.new(@offset, text)
|
840
|
+
end
|
841
|
+
|
842
|
+
def instrumentname(text)
|
843
|
+
@tr << InstrumentName.new(@offset, text)
|
844
|
+
end
|
845
|
+
|
846
|
+
def lyric(text)
|
847
|
+
@tr << Lyric.new(@offset, text)
|
848
|
+
end
|
849
|
+
|
850
|
+
def marker(text)
|
851
|
+
@tr << Marker.new(@offset, text)
|
852
|
+
end
|
853
|
+
|
854
|
+
def cuepoint(text)
|
855
|
+
@tr << CuePoint.new(@offset, text)
|
856
|
+
end
|
857
|
+
|
858
|
+
def programname(text)
|
859
|
+
@tr << ProgramName.new(@offset, text)
|
860
|
+
end
|
861
|
+
|
862
|
+
def devicename(text)
|
863
|
+
@tr << DeviceName.new(@offset, text)
|
864
|
+
end
|
865
|
+
|
866
|
+
def text0a(text)
|
867
|
+
@tr << Text0A.new(@offset, text)
|
868
|
+
end
|
869
|
+
|
870
|
+
def text0b(text)
|
871
|
+
@tr << Text0B.new(@offset, text)
|
872
|
+
end
|
873
|
+
|
874
|
+
def text0c(text)
|
875
|
+
@tr << Text0C.new(@offset, text)
|
876
|
+
end
|
877
|
+
|
878
|
+
def text0d(text)
|
879
|
+
@tr << Text0D.new(@offset, text)
|
880
|
+
end
|
881
|
+
|
882
|
+
def text0e(text)
|
883
|
+
@tr << Text0E.new(@offset, text)
|
884
|
+
end
|
885
|
+
|
886
|
+
def text0f(text)
|
887
|
+
@tr << Text0F.new(@offset, text)
|
888
|
+
end
|
889
|
+
|
890
|
+
def channelprefix(ch)
|
891
|
+
@tr << ChannelPrefix.new(@offset, ch)
|
892
|
+
end
|
893
|
+
|
894
|
+
def midiport(num)
|
895
|
+
@tr << MIDIPort.new(@offset, num)
|
896
|
+
end
|
897
|
+
|
898
|
+
def endoftrack
|
899
|
+
@tr << EndOfTrack.new(@offset)
|
900
|
+
end
|
901
|
+
|
902
|
+
def settempo(tempo)
|
903
|
+
@tr << SetTempo.new(@offset, tempo)
|
904
|
+
end
|
905
|
+
|
906
|
+
def smpteoffset(hr, mn, se, fr, ff, tc)
|
907
|
+
@tr << SMPTEOffset.new(@offset, hr, mn, se, fr, ff, tc)
|
908
|
+
end
|
909
|
+
|
910
|
+
def timesignature(nn, dd, cc, bb)
|
911
|
+
@tr << TimeSignature.new(@offset, nn, dd, cc, bb)
|
912
|
+
end
|
913
|
+
|
914
|
+
def keysignature(sf, mi)
|
915
|
+
@tr << KeySignature.new(@offset, sf, mi)
|
916
|
+
end
|
917
|
+
|
918
|
+
def sequencerspecific(data)
|
919
|
+
@tr << SequencerSpecific.new(@offset, data)
|
920
|
+
end
|
921
|
+
|
922
|
+
def result() @sq end
|
923
|
+
|
924
|
+
def error(mesg) raise ReadError, mesg end
|
925
|
+
|
926
|
+
end
|
927
|
+
|
928
|
+
class Encode < XSCallback
|
929
|
+
|
930
|
+
# include Checker
|
931
|
+
|
932
|
+
@@replace_noteoff = false
|
933
|
+
|
934
|
+
def header(format, ntrks, division, tc)
|
935
|
+
@ws = WS::PO.new
|
936
|
+
@ws.puts('MThd')
|
937
|
+
@ws.puti32(6)
|
938
|
+
@ws.puti16(format)
|
939
|
+
@ws.puti16(ntrks)
|
940
|
+
if tc
|
941
|
+
div1 = 0x100 - tc
|
942
|
+
div2 = division
|
943
|
+
else
|
944
|
+
div1 = division >> 8
|
945
|
+
div2 = division & 0xff
|
946
|
+
end
|
947
|
+
@ws.putc(div1)
|
948
|
+
@ws.putc(div2)
|
949
|
+
end
|
950
|
+
|
951
|
+
def track_start
|
952
|
+
@ev = WS::PO.new
|
953
|
+
@running = 0
|
954
|
+
@cieot = false
|
955
|
+
end
|
956
|
+
|
957
|
+
def chunk_body(body) end
|
958
|
+
|
959
|
+
private :chunk_body
|
960
|
+
|
961
|
+
def track_end
|
962
|
+
@ws.puts('MTrk')
|
963
|
+
unless @cieot
|
964
|
+
delta(0)
|
965
|
+
endoftrack
|
966
|
+
end
|
967
|
+
ev = @ev.to_s
|
968
|
+
chunk_body(ev)
|
969
|
+
@ws.puti32(ev.length)
|
970
|
+
@ws.puts(ev)
|
971
|
+
end
|
972
|
+
|
973
|
+
def unknownchunk(ckid, body)
|
974
|
+
@ws.puts(ckid)
|
975
|
+
chunk_body(ev)
|
976
|
+
@ws.puti32(body.length)
|
977
|
+
@ws.puts(body)
|
978
|
+
end
|
979
|
+
|
980
|
+
def de
|
981
|
+
@ev.putl(@delta)
|
982
|
+
end
|
983
|
+
|
984
|
+
def sb(stat)
|
985
|
+
@ev.putc(stat) unless stat == @running
|
986
|
+
case stat
|
987
|
+
when 0x80..0xef; @running = stat
|
988
|
+
when 0xf0..0xf7; @running = 0
|
989
|
+
end
|
990
|
+
end
|
991
|
+
|
992
|
+
def db(data)
|
993
|
+
@ev.putc(data & 0x7f)
|
994
|
+
end
|
995
|
+
|
996
|
+
private :de, :sb, :db
|
997
|
+
|
998
|
+
def delta(delta) @delta = delta end
|
999
|
+
|
1000
|
+
def noteoff(ch, note, vel)
|
1001
|
+
de
|
1002
|
+
if @@replace_noteoff
|
1003
|
+
sb(ch | 0x90)
|
1004
|
+
db(note)
|
1005
|
+
db(0)
|
1006
|
+
else
|
1007
|
+
sb(ch | 0x80)
|
1008
|
+
db(note)
|
1009
|
+
db(vel)
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def noteon(ch, note, vel)
|
1014
|
+
de
|
1015
|
+
sb(ch | 0x90)
|
1016
|
+
db(note)
|
1017
|
+
db(vel)
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
def polyphonickeypressure(ch, note, val)
|
1021
|
+
de
|
1022
|
+
sb(ch | 0xa0)
|
1023
|
+
db(note)
|
1024
|
+
db(val)
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
def controlchange(ch, num, val)
|
1028
|
+
de
|
1029
|
+
sb(ch | 0xb0)
|
1030
|
+
db(num)
|
1031
|
+
db(val)
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def programchange(ch, num)
|
1035
|
+
de
|
1036
|
+
sb(ch | 0xc0)
|
1037
|
+
db(num)
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
def channelpressure(ch, val)
|
1041
|
+
de
|
1042
|
+
sb(ch | 0xd0)
|
1043
|
+
db(val)
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
def pitchbendchange(ch, val)
|
1047
|
+
de
|
1048
|
+
sb(ch | 0xe0)
|
1049
|
+
val += 0x2000
|
1050
|
+
lsb = val & 0x7f
|
1051
|
+
msb = (val >> 7) & 0x7f
|
1052
|
+
db(lsb)
|
1053
|
+
db(msb)
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
def channelmodemessage(ch, num, val)
|
1057
|
+
de
|
1058
|
+
sb(ch | 0xb0)
|
1059
|
+
db(num)
|
1060
|
+
db(val)
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
private :channelmodemessage
|
1064
|
+
|
1065
|
+
def allsoundoff(ch) channelmodemessage(ch, 0x78, 0) end
|
1066
|
+
def resetallcontrollers(ch) channelmodemessage(ch, 0x79, 0) end
|
1067
|
+
def localcontrol(ch, val) channelmodemessage(ch, 0x7a, val) end
|
1068
|
+
def allnotesoff(ch) channelmodemessage(ch, 0x7b, 0) end
|
1069
|
+
def omnioff(ch) channelmodemessage(ch, 0x7c, 0) end
|
1070
|
+
def omnion(ch) channelmodemessage(ch, 0x7d, 0) end
|
1071
|
+
def monomode(ch, val) channelmodemessage(ch, 0x7e, val) end
|
1072
|
+
def polymode(ch) channelmodemessage(ch, 0x7f, 0) end
|
1073
|
+
|
1074
|
+
def exclusivef0(data)
|
1075
|
+
de
|
1076
|
+
@ev.putc(0xf0)
|
1077
|
+
@ev.putl(data.length)
|
1078
|
+
@ev.puts(data)
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
def exclusivef7(data)
|
1082
|
+
de
|
1083
|
+
@ev.putc(0xf7)
|
1084
|
+
@ev.putl(data.length)
|
1085
|
+
@ev.puts(data)
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
def sequencenumber(num)
|
1089
|
+
de
|
1090
|
+
@ev.putc(0xff)
|
1091
|
+
@ev.putc(0x0)
|
1092
|
+
@ev.putl(2)
|
1093
|
+
@ev.puti16(num)
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
def text(type, text)
|
1097
|
+
de
|
1098
|
+
@ev.putc(0xff)
|
1099
|
+
@ev.putc(type)
|
1100
|
+
@ev.putl(text.length)
|
1101
|
+
@ev.puts(text)
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
private :text
|
1105
|
+
|
1106
|
+
def generalpurposetext(text) text(0x1, text) end
|
1107
|
+
def copyrightnotice(text) text(0x2, text) end
|
1108
|
+
def trackname(text) text(0x3, text) end
|
1109
|
+
def instrumentname(text) text(0x4, text) end
|
1110
|
+
def lyric(text) text(0x5, text) end
|
1111
|
+
def marker(text) text(0x6, text) end
|
1112
|
+
def cuepoint(text) text(0x7, text) end
|
1113
|
+
def programname(text) text(0x8, text) end
|
1114
|
+
def devicename(text) text(0x9, text) end
|
1115
|
+
def text0a(text) text(0xa, text) end
|
1116
|
+
def text0b(text) text(0xb, text) end
|
1117
|
+
def text0c(text) text(0xc, text) end
|
1118
|
+
def text0d(text) text(0xd, text) end
|
1119
|
+
def text0e(text) text(0xe, text) end
|
1120
|
+
def text0f(text) text(0xf, text) end
|
1121
|
+
|
1122
|
+
def channelprefix(ch)
|
1123
|
+
de
|
1124
|
+
@ev.putc(0xff)
|
1125
|
+
@ev.putc(0x20)
|
1126
|
+
@ev.putl(1)
|
1127
|
+
@ev.putc(ch)
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
def midiport(num)
|
1131
|
+
de
|
1132
|
+
@ev.putc(0xff)
|
1133
|
+
@ev.putc(0x21)
|
1134
|
+
@ev.putl(1)
|
1135
|
+
@ev.putc(num)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
def endoftrack
|
1139
|
+
de
|
1140
|
+
@ev.putc(0xff)
|
1141
|
+
@ev.putc(0x2f)
|
1142
|
+
@ev.putl(0)
|
1143
|
+
@cieot = true
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
def settempo(tempo)
|
1147
|
+
de
|
1148
|
+
@ev.putc(0xff)
|
1149
|
+
@ev.putc(0x51)
|
1150
|
+
@ev.putl(3)
|
1151
|
+
@ev.puti24(tempo)
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def smpteoffset(hr, mn, se, fr, ff, tc)
|
1155
|
+
unless [24, 25, 29, 30].include? tc
|
1156
|
+
warn('smpteoffset/tc: invalid format')
|
1157
|
+
end
|
1158
|
+
de
|
1159
|
+
@ev.putc(0xff)
|
1160
|
+
@ev.putc(0x54)
|
1161
|
+
@ev.putl(5)
|
1162
|
+
hr |= ({24=>0, 25=>1, 29=>2, 30=>3}[tc] || 0) << 5
|
1163
|
+
@ev.putc(hr)
|
1164
|
+
@ev.putc(mn)
|
1165
|
+
@ev.putc(se)
|
1166
|
+
@ev.putc(fr)
|
1167
|
+
@ev.putc(ff)
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
def timesignature(nn, dd, cc, bb)
|
1171
|
+
de
|
1172
|
+
@ev.putc(0xff)
|
1173
|
+
@ev.putc(0x58)
|
1174
|
+
@ev.putl(4)
|
1175
|
+
@ev.putc(nn)
|
1176
|
+
@ev.putc(dd)
|
1177
|
+
@ev.putc(cc)
|
1178
|
+
@ev.putc(bb)
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
def keysignature(sf, mi)
|
1182
|
+
sf = WS::PO.s2u(sf, 8)
|
1183
|
+
de
|
1184
|
+
@ev.putc(0xff)
|
1185
|
+
@ev.putc(0x59)
|
1186
|
+
@ev.putl(2)
|
1187
|
+
@ev.putc(sf)
|
1188
|
+
@ev.putc(mi)
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
def sequencerspecific(data)
|
1192
|
+
de
|
1193
|
+
@ev.putc(0xff)
|
1194
|
+
@ev.putc(0x7f)
|
1195
|
+
@ev.putl(data.length)
|
1196
|
+
@ev.puts(data)
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
def unknownmeta(type, data)
|
1200
|
+
de
|
1201
|
+
@ev.putc(0xff)
|
1202
|
+
@ev.putc(type)
|
1203
|
+
@ev.putl(data.length)
|
1204
|
+
@ev.puts(data)
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
def result() @ws.to_s end
|
1208
|
+
|
1209
|
+
def error(mesg) raise ReadError, mesg end
|
1210
|
+
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
class << self
|
1214
|
+
|
1215
|
+
unless String === '0'[0]
|
1216
|
+
|
1217
|
+
def decode(s)
|
1218
|
+
self::RS.new(s, self::Decode.new).read
|
1219
|
+
end
|
1220
|
+
|
1221
|
+
else
|
1222
|
+
|
1223
|
+
def decode(s)
|
1224
|
+
s = s.dup.force_encoding('ascii-8bit')
|
1225
|
+
self::RS.new(s, self::Decode.new).read
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
def read(io)
|
1231
|
+
decode(io.binmode.read)
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
def decoceio(io)
|
1235
|
+
warn('decodeio is deprecated; use read') if $VERBOSE
|
1236
|
+
read(io)
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
def load(fn)
|
1240
|
+
open(fn) do |io|
|
1241
|
+
read(io)
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
def decodefile(fn)
|
1246
|
+
warn('decodefile is deprecated; use load') if $VERBOSE
|
1247
|
+
load(fn)
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
def encode
|
1253
|
+
self.class::WS.new(self, self.class::Encode.new).read
|
1254
|
+
end
|
1255
|
+
|
1256
|
+
def write(io)
|
1257
|
+
io.binmode.write(encode)
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
def encodeio(io)
|
1261
|
+
warn('encodeio is deprecated; use write') if $VERBOSE
|
1262
|
+
write(io)
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
def save(fn)
|
1266
|
+
open(fn, 'w') do |io|
|
1267
|
+
write(io)
|
1268
|
+
end
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
def encodefile(fn)
|
1272
|
+
warn('encodefile is deprecated; use save') if $VERBOSE
|
1273
|
+
save(fn)
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
end
|