smf 0.15.12

Sign up to get free protection for your applications and to get access to all the features.
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,195 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # play-win.rb: Written by Tadayoshi Funaba 2005,2006
4
+ # $Id: play-win.rb,v 1.4 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf'
7
+ require 'smf/toy/tempomap'
8
+ require 'Win32API'
9
+ require 'gopt'
10
+ include SMF
11
+
12
+ module SMF
13
+
14
+ class Kernel32 < Win32API
15
+
16
+ def initialize(proc, import, export)
17
+ super('kernel32', proc, import, export)
18
+ end
19
+
20
+ end
21
+
22
+ class WinMM < Win32API
23
+
24
+ def initialize(proc, import, export)
25
+ super('winmm', proc, import, export)
26
+ end
27
+
28
+ end
29
+
30
+ module WinBase
31
+
32
+ NORMAL_PRIORITY_CLASS = 0x00000020
33
+ IDEL_PRIORITY_CLASS = 0x00000040
34
+ HIGH_PRIORITY_CLASS = 0x00000080
35
+ REALTIME_PRIORITY_CLASS = 0x00000100
36
+
37
+ @@GetCurrentProcess = Kernel32.new('GetCurrentProcess', %w(), 'l')
38
+ @@SetPriorityClass = Kernel32.new('SetPriorityClass', %w(l l), 'l')
39
+
40
+ def setpriorityclass(prc=NORMAL_PRIORITY_CLASS)
41
+ prh = @@GetCurrentProcess.call
42
+ @@SetPriorityClass.call(prh, prc)
43
+ end
44
+
45
+ module_function :setpriorityclass
46
+
47
+ end
48
+
49
+ class DevMidiOut
50
+
51
+ @@GetNumDevs = WinMM.new('midiOutGetNumDevs', %w(), 'l')
52
+ @@GetDevCaps = WinMM.new('midiOutGetDevCaps', %w(l p l), 'l')
53
+ @@Open = WinMM.new('midiOutOpen', %w(p l l l l), 'l')
54
+ @@Reset = WinMM.new('midiOutReset', %w(l), 'l')
55
+ @@Close = WinMM.new('midiOutClose', %w(l), 'l')
56
+ @@ShortMsg = WinMM.new('midiOutShortMsg', %w(l l), 'l')
57
+ @@LongMsg = WinMM.new('midiOutLongMsg', %w(l p l), 'l')
58
+ @@PrepareHeader = WinMM.new('midiOutPrepareHeader', %w(l p l), 'l')
59
+ @@UnprepareHeader = WinMM.new('midiOutUnprepareHeader', %w(l p l), 'l')
60
+
61
+ def self.getnumdev() @@GetNumDevs.call end
62
+
63
+ def self.getdevcaps(did)
64
+ caps = "\000" * 52
65
+ @@GetDevCaps.call(did, caps, caps.size)
66
+ caps.unpack('S2LZ32S4L')
67
+ end
68
+
69
+ def initialize(did)
70
+ mo = "\000" * 4
71
+ @@Open.call(mo, did, 0, 0, 0)
72
+ @mo = mo.unpack('L')[0]
73
+ end
74
+
75
+ def reset() @@Reset.call(@mo) end
76
+ def close() @@Close.call(@mo) end
77
+ def shortmsg(msg) @@ShortMsg.call(@mo, msg) end
78
+
79
+ def longmsg(msg)
80
+ moh = [msg, msg.size, 0, 0, 0, 0, 0, 0, ''].pack('PL7A32')
81
+ @@PrepareHeader.call(@mo, moh, moh.size)
82
+ @@LongMsg.call(@mo, moh, moh.size)
83
+ @@UnprepareHeader.call(@mo, moh, moh.size)
84
+ end
85
+
86
+ end
87
+
88
+ class Sequence
89
+
90
+ class Timer
91
+
92
+ def initialize() @start = Time.now end
93
+ def elapse() Time.now - @start end
94
+
95
+ end
96
+
97
+ class Play < XSCallback
98
+
99
+ def initialize(tm, num) @tm, @num = tm, num end
100
+
101
+ def header(format, ntrks, division, tc)
102
+ WinBase.setpriorityclass(WinBase::HIGH_PRIORITY_CLASS)
103
+ ndev = DevMidiOut.getnumdev
104
+ puts(DevMidiOut.getdevcaps(@num)[3]) if $VERBOSE
105
+ unless @num < ndev
106
+ raise 'device not available'
107
+ end
108
+ @mo = DevMidiOut.new(@num)
109
+ end
110
+
111
+ def track_start() @offset = 0 end
112
+
113
+ def delta(delta)
114
+ @timer ||= Timer.new
115
+ if delta.nonzero?
116
+ @offset += delta
117
+ e = @tm.offset2elapse(@offset) - @timer.elapse
118
+ if e > 0
119
+ sleep(e.to_f)
120
+ end
121
+ end
122
+ end
123
+
124
+ def midimsg(sb, db1, db2=0)
125
+ @mo.shortmsg(sb | (db1 << 8) | (db2 << 16))
126
+ end
127
+
128
+ private :midimsg
129
+
130
+ def noteoff(ch, note, vel) midimsg(ch | 0x80, note, vel) end
131
+ def noteon(ch, note, vel) midimsg(ch | 0x90, note, vel) end
132
+
133
+ def polyphonickeypressure(ch, note, val)
134
+ midimsg(ch | 0xa0, note, val)
135
+ end
136
+
137
+ def controlchange(ch, num, val) midimsg(ch | 0xb0, num, val) end
138
+ def programchange(ch, num) midimsg(ch | 0xc0, num) end
139
+ def channelpressure(ch, val) midimsg(ch | 0xd0, val) end
140
+
141
+ def pitchbendchange(ch, val)
142
+ val += 0x2000
143
+ lsb = val & 0x7f
144
+ msb = (val >> 7) & 0x7f
145
+ midimsg(ch | 0xe0, lsb, msb)
146
+ end
147
+
148
+ def channelmodemessage(ch, num, val) controlchange(ch, num, val) end
149
+
150
+ private :channelmodemessage
151
+
152
+ def allsoundoff(ch) channelmodemessage(ch, 0x78, 0) end
153
+ def resetallcontrollers(ch) channelmodemessage(ch, 0x79, 0) end
154
+ def localcontrol(ch, val) channelmodemessage(ch, 0x7a, val) end
155
+ def allnotesoff(ch) channelmodemessage(ch, 0x7b, 0) end
156
+ def omnioff(ch) channelmodemessage(ch, 0x7c, 0) end
157
+ def omnion(ch) channelmodemessage(ch, 0x7d, 0) end
158
+ def monomode(ch, val) channelmodemessage(ch, 0x7e, val) end
159
+ def polymode(ch) channelmodemessage(ch, 0x7f, 0) end
160
+
161
+ def exclusivefx(data) @mo.longmsg(data) end
162
+
163
+ private :exclusivefx
164
+
165
+ def exclusivef0(data) exclusivefx("\xf0" + data) end
166
+ def exclusivef7(data) exclusivefx(data) end
167
+
168
+ def result() @mo.close end
169
+
170
+ end
171
+
172
+ def play(num=0)
173
+ j = join
174
+ tm = TempoMap.new(j)
175
+ WS.new(j, Play.new(tm, num)).read
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+
182
+ def usage
183
+ warn 'usage: play-win [-d num] [input]'
184
+ exit 1
185
+ end
186
+
187
+ usage unless opt = Gopt.gopt('d:')
188
+ usage unless $*.size >= 0 && $*.size <= 1
189
+ file = $*.shift
190
+ file = nil if file == '-'
191
+
192
+ num = (opt[:d] || '0').to_i
193
+
194
+ sq = unless file then Sequence.read($stdin) else Sequence.load(file) end
195
+ sq.play(num)
@@ -0,0 +1,41 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # quantize.rb: Written by Tadayoshi Funaba 1999-2006
4
+ # $Id: quantize.rb,v 1.10 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf'
7
+ require 'smf/toy/quantize'
8
+ require 'gopt'
9
+ include SMF
10
+
11
+ def usage
12
+ warn 'usage: quantize [-o output] [-u n/d] [input]'
13
+ exit 1
14
+ end
15
+
16
+ usage unless opt = Gopt.gopt('o:u:')
17
+ usage unless $*.size >= 0 && $*.size <= 1
18
+
19
+ ifile = $*.shift
20
+ ifile = nil if ifile == '-'
21
+
22
+ ofile = opt[:o] if opt[:o]
23
+ ofile ||= File.basename(ifile, '.mid') + '-quantize.mid' if ifile
24
+ ofile = nil if ofile == '-'
25
+
26
+ n, d = (opt[:u] || '1/32').split('/')
27
+ unit = n.to_f / (d || '1').to_f
28
+
29
+ sq = unless ifile then Sequence.read($stdin) else Sequence.load(ifile) end
30
+ qu = Quantize.new(sq.division, unit)
31
+
32
+ sq.each do |tr|
33
+ tr.pop
34
+ tr.each do |ev|
35
+ case ev
36
+ when NoteOn
37
+ qu.quantize(ev)
38
+ end
39
+ end
40
+ end
41
+ unless ofile then sq.write($stdout) else sq.save(ofile) end
@@ -0,0 +1,21 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'smf'
4
+ include SMF
5
+
6
+ sq = Sequence.new
7
+ tr = Track.new
8
+ sq << tr
9
+ tr << SequenceName.new(0, 'rand1')
10
+ srand
11
+ for ch in 0..7
12
+ offset = 0
13
+ for i in 0..127
14
+ note = rand(128)
15
+ vel = rand(127) + 1
16
+ tr << NoteOn .new(offset, ch, note, vel)
17
+ offset += rand(128)
18
+ tr << NoteOff.new(offset, ch, note, 64)
19
+ end
20
+ end
21
+ sq.save('rand1.mid')
@@ -0,0 +1,24 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'smf'
4
+ include SMF
5
+
6
+ class Array; def rand() self[Kernel.rand(self.size)] end end
7
+
8
+ sq = Sequence.new
9
+ tr = Track.new
10
+ sq << tr
11
+ tr << SequenceName.new(0, 'rand2')
12
+ srand
13
+ for ch in 0..2
14
+ offset = 0
15
+ for i in 0..127
16
+ note = [0, 2, 4, 5, 7, 9, 10].rand
17
+ note += (rand(1) + 4 + ch) * 12
18
+ vel = rand(127) + 1
19
+ tr << NoteOn. new(offset, ch, note, vel)
20
+ offset += [12, 24, 48, 96, 192, 384].rand
21
+ tr << NoteOff.new(offset, ch, note, 64)
22
+ end
23
+ end
24
+ sq.save('rand2.mid')
@@ -0,0 +1,26 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # rmi2smf.rb: Written by Tadayoshi Funaba 2001-2006
4
+ # $Id: rmi2smf.rb,v 1.5 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf/toy/rmi'
7
+ require 'gopt'
8
+
9
+ def usage
10
+ warn 'usage: rmi2smf [-o output] [input]'
11
+ exit 1
12
+ end
13
+
14
+ usage unless opt = Gopt.gopt('o:')
15
+ usage unless $*.size >= 0 && $*.size <= 1
16
+
17
+ ifile = $*.shift
18
+ ifile = nil if ifile == '-'
19
+
20
+ ofile = opt[:o] if opt[:o]
21
+ ofile ||= File.basename(ifile, '.rmi') + '.mid' if ifile
22
+ ofile = nil if ofile == '-'
23
+
24
+ i = (unless ifile then $stdin else open(ifile) end).binmode.read
25
+ o = SMF::RMI::rmi2smf(i)
26
+ (unless ofile then $stdout else open(ofile, 'w') end).binmode.write(o)
@@ -0,0 +1,43 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # shuffle.rb: Written by Tadayoshi Funaba 2005,2006
4
+ # $Id: shuffle.rb,v 1.3 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf'
7
+ require 'smf/toy/shuffle'
8
+ require 'gopt'
9
+ include SMF
10
+
11
+ def usage
12
+ warn 'usage: shuffle [-o output] [-u n/d] [-a amount] [input]'
13
+ exit 1
14
+ end
15
+
16
+ usage unless opt = Gopt.gopt('o:u:a:')
17
+ usage unless $*.size >= 0 && $*.size <= 1
18
+
19
+ ifile = $*.shift
20
+ ifile = nil if ifile == '-'
21
+
22
+ ofile = opt[:o] if opt[:o]
23
+ ofile ||= File.basename(ifile, '.mid') + '-shuffle.mid' if ifile
24
+ ofile = nil if ofile == '-'
25
+
26
+ n, d = (opt[:u] || '1/8').split('/')
27
+ unit = n.to_f / (d || '1').to_f
28
+ amount = (opt[:a] || '0.5').to_f
29
+
30
+ sq = unless ifile then Sequence.read($stdin) else Sequence.load(ifile) end
31
+ sh = Shuffle.new(sq.division, unit)
32
+ sh.amount = amount
33
+
34
+ sq.each do |tr|
35
+ tr.pop
36
+ tr.each do |ev|
37
+ case ev
38
+ when NoteOff, NoteOn
39
+ sh.shuffle(ev)
40
+ end
41
+ end
42
+ end
43
+ unless ofile then sq.write($stdout) else sq.save(ofile) end
@@ -0,0 +1,26 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # smf2rmi.rb: Written by Tadayoshi Funaba 2001-2006
4
+ # $Id: smf2rmi.rb,v 1.6 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf/toy/rmi'
7
+ require 'gopt'
8
+
9
+ def usage
10
+ warn 'usage: smf2rmi [-o output] [input]'
11
+ exit 1
12
+ end
13
+
14
+ usage unless opt = Gopt.gopt('o:')
15
+ usage unless $*.size >= 0 && $*.size <= 1
16
+
17
+ ifile = $*.shift
18
+ ifile = nil if ifile == '-'
19
+
20
+ ofile = opt[:o] if opt[:o]
21
+ ofile ||= File.basename(ifile, '.mid') + '.rmi' if ifile
22
+ ofile = nil if ofile == '-'
23
+
24
+ i = (unless ifile then $stdin else open(ifile) end).binmode.read
25
+ o = SMF::RMI::smf2rmi(i)
26
+ (unless ofile then $stdout else open(ofile, 'w') end).binmode.write(o)
@@ -0,0 +1,26 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # smf2smf.rb: Written by Tadayoshi Funaba 1999-2006
4
+ # $Id: smf2smf.rb,v 1.8 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf'
7
+ require 'gopt'
8
+ include SMF
9
+
10
+ def usage
11
+ warn 'usage: smf2smf [-o output] [input]'
12
+ exit 1
13
+ end
14
+
15
+ usage unless opt = Gopt.gopt('o:')
16
+ usage unless $*.size >= 0 && $*.size <= 1
17
+
18
+ ifile = $*.shift
19
+ ifile = nil if ifile == '-'
20
+
21
+ ofile = opt[:o] if opt[:o]
22
+ ofile ||= File.basename(ifile, '.mid') + '-smf2smf.mid' if ifile
23
+ ofile = nil if ofile == '-'
24
+
25
+ sq = unless ifile then Sequence.read($stdin) else Sequence.load(ifile) end
26
+ unless ofile then sq.write($stdout) else sq.save(ofile) end
@@ -0,0 +1,27 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # smf2text.rb: Written by Tadayoshi Funaba 1999-2006
4
+ # $Id: smf2text.rb,v 1.14 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf'
7
+ require 'smf/toy/text'
8
+ require 'gopt'
9
+ include SMF
10
+
11
+ def usage
12
+ warn 'usage: smf2text [-o output] [input]'
13
+ exit 1
14
+ end
15
+
16
+ usage unless opt = Gopt.gopt('o:')
17
+ usage unless $*.size >= 0 && $*.size <= 1
18
+
19
+ ifile = $*.shift
20
+ ifile = nil if ifile == '-'
21
+
22
+ ofile = opt[:o] if opt[:o]
23
+ ofile ||= File.basename(ifile, '.mid') + '.txt' if ifile
24
+ ofile = nil if ofile == '-'
25
+
26
+ sq = unless ifile then Sequence.read($stdin) else Sequence.load(ifile) end
27
+ unless ofile then sq.write_text($stdout) else sq.save_text(ofile) end
@@ -0,0 +1,123 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # smf2wav.rb: Written by Tadayoshi Funaba 1999-2006
4
+ # $Id: smf2wav.rb,v 1.20 2006-11-10 21:57:06+09 tadf Exp $
5
+
6
+ require 'smf'
7
+ require 'smf/toy/tempomap'
8
+ require 'gopt'
9
+ include SMF
10
+
11
+ module SMF
12
+
13
+ class Wave
14
+
15
+ def initialize(rate=8000)
16
+ @rate = rate
17
+ @wave = []
18
+ end
19
+
20
+ def sin(start, stop, freq, amp)
21
+ (start..stop).each do |i|
22
+ r = amp * Math.sin(2 * Math::PI * freq * (i.to_f / @rate))
23
+ @wave[i] ||= 0.0
24
+ @wave[i] += r
25
+ end
26
+ end
27
+
28
+ def dump
29
+ out = [ 'RIFF', @wave.length + 36, 'WAVE', 'fmt', 16, 1, 1, @rate, @rate,
30
+ 1, 8, 'data', @wave.length].pack('A4 V A4 A4 V v v V V v v A4 V')
31
+ @wave.collect!{|x| x || 0.0}
32
+ peak = @wave.max
33
+ @wave.each_with_index do |x, i|
34
+ @wave[i] = 128 + (127 * x / peak).round
35
+ end
36
+ out << @wave.pack('C*')
37
+ out
38
+ end
39
+
40
+ end
41
+
42
+ class Sequence
43
+
44
+ class EncodeWav < XSCallback
45
+
46
+ FREQ = []
47
+ (0..127).each do |n|
48
+ FREQ << 440 * 2**((n-69.0)/12)
49
+ end
50
+
51
+ def initialize(tm)
52
+ @tm = tm
53
+ @rate = 8000
54
+ @wave = Wave.new(@rate)
55
+ end
56
+
57
+ def track_start
58
+ @offset = 0
59
+ @noteon = []
60
+ end
61
+
62
+ def delta(delta) @offset += delta end
63
+
64
+ def noteoff(ch, note, vel)
65
+ return if ch == 9 # GM perc.
66
+ val = (@noteon[ch] || {}).delete(note)
67
+ if val
68
+ start, vel = val
69
+ @wave.sin(pos(start), pos(@offset), FREQ[note], vel)
70
+ end
71
+ end
72
+
73
+ def noteon(ch, note, vel)
74
+ return if ch == 9 # GM perc.
75
+ @noteon[ch] ||= {}
76
+ @noteon[ch][note] ||= [@offset, vel]
77
+ end
78
+
79
+ def pos(offset)
80
+ e = @tm.offset2elapse(offset)
81
+ (e * @rate).round
82
+ end
83
+
84
+ def result() @wave.dump end
85
+
86
+ end
87
+
88
+ def encode_wav
89
+ tm = TempoMap.new(self)
90
+ self.class::WS.new(self, self.class::EncodeWav.new(tm)).read
91
+ end
92
+
93
+ def write_wav(io)
94
+ io.binmode.write(encode_wav)
95
+ end
96
+
97
+ def save_wav(fn)
98
+ open(fn, 'w') do |io|
99
+ write_wav(io)
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
107
+ def usage
108
+ warn 'usage: smf2wav [-o output] [input]'
109
+ exit 1
110
+ end
111
+
112
+ usage unless opt = Gopt.gopt('o:')
113
+ usage unless $*.size >= 0 && $*.size <= 1
114
+
115
+ ifile = $*.shift
116
+ ifile = nil if ifile == '-'
117
+
118
+ ofile = opt[:o] if opt[:o]
119
+ ofile ||= File.basename(ifile, '.mid') + '.wav' if ifile
120
+ ofile = nil if ofile == '-'
121
+
122
+ sq = unless ifile then Sequence.read($stdin) else Sequence.load(ifile) end
123
+ unless ofile then sq.write_wav($stdout) else sq.save_wav(ofile) end