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,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