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.
Files changed (68) hide show
  1. data/MANUAL +172 -0
  2. data/MANUAL.en +135 -0
  3. data/MANUAL.en.html +150 -0
  4. data/MANUAL.en.rd +144 -0
  5. data/MANUAL.html +201 -0
  6. data/MANUAL.rd +179 -0
  7. data/README +33 -0
  8. data/README.en +33 -0
  9. data/lib/smf.rb +736 -0
  10. data/lib/smf/divert.rb +21 -0
  11. data/lib/smf/io.rb +1278 -0
  12. data/lib/smf/toy/beatmap.rb +73 -0
  13. data/lib/smf/toy/gm.rb +327 -0
  14. data/lib/smf/toy/groove.rb +34 -0
  15. data/lib/smf/toy/macro.rb +282 -0
  16. data/lib/smf/toy/macro/mml.rb +34 -0
  17. data/lib/smf/toy/macro/mml/parser.rb +545 -0
  18. data/lib/smf/toy/macro/mml/parser.ry +239 -0
  19. data/lib/smf/toy/macro/stt.rb +33 -0
  20. data/lib/smf/toy/morse.rb +126 -0
  21. data/lib/smf/toy/quantize.rb +32 -0
  22. data/lib/smf/toy/rmi.rb +29 -0
  23. data/lib/smf/toy/searchsegment.rb +24 -0
  24. data/lib/smf/toy/shuffle.rb +39 -0
  25. data/lib/smf/toy/tempomap.rb +75 -0
  26. data/lib/smf/toy/text.rb +369 -0
  27. data/lib/smf/toy/velcomp.rb +42 -0
  28. data/lib/smf/toy/virtual.rb +118 -0
  29. data/lib/smf/toy/xml.rb +377 -0
  30. data/sample/Makefile +58 -0
  31. data/sample/bwv772.mid +0 -0
  32. data/sample/bwv772.mml +94 -0
  33. data/sample/bwv775.mid +0 -0
  34. data/sample/bwv775.mml +157 -0
  35. data/sample/bwv787.mid +0 -0
  36. data/sample/bwv787.mml +129 -0
  37. data/sample/groove.grv +33 -0
  38. data/sample/groove.rb +45 -0
  39. data/sample/ltvddpd2.mid +0 -0
  40. data/sample/ltvddpd2.stt +60 -0
  41. data/sample/merge.rb +38 -0
  42. data/sample/mml-samp.rb +19 -0
  43. data/sample/mml.rb +36 -0
  44. data/sample/morse-samp.rb +11 -0
  45. data/sample/morse.rb +31 -0
  46. data/sample/play-oss.rb +215 -0
  47. data/sample/play-oss2.rb +253 -0
  48. data/sample/play-oss3.rb +150 -0
  49. data/sample/play-spkr.rb +97 -0
  50. data/sample/play-win.rb +195 -0
  51. data/sample/quantize.rb +41 -0
  52. data/sample/rand1.rb +21 -0
  53. data/sample/rand2.rb +24 -0
  54. data/sample/rmi2smf.rb +26 -0
  55. data/sample/shuffle.rb +43 -0
  56. data/sample/smf2rmi.rb +26 -0
  57. data/sample/smf2smf.rb +26 -0
  58. data/sample/smf2text.rb +27 -0
  59. data/sample/smf2wav.rb +123 -0
  60. data/sample/smf2xml.rb +27 -0
  61. data/sample/split.rb +40 -0
  62. data/sample/stt-samp.rb +19 -0
  63. data/sample/stt.rb +36 -0
  64. data/sample/text2smf.rb +28 -0
  65. data/sample/velcomp.rb +45 -0
  66. data/sample/virtual-samp.rb +19 -0
  67. data/sample/xml2smf.rb +28 -0
  68. metadata +128 -0
@@ -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
@@ -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