smf 0.15.12
Sign up to get free protection for your applications and to get access to all the features.
- 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/sample/play-oss2.rb
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# play-oss2.rb: Written by Tadayoshi Funaba 1999-2006
|
4
|
+
# $Id: play-oss2.rb,v 1.4 2006-11-10 21:57:06+09 tadf Exp $
|
5
|
+
|
6
|
+
require 'smf'
|
7
|
+
require 'gopt'
|
8
|
+
include SMF
|
9
|
+
|
10
|
+
module SMF
|
11
|
+
|
12
|
+
class DevSeq < File
|
13
|
+
|
14
|
+
def putbuf(s)
|
15
|
+
@buf ||= ''
|
16
|
+
if @buf.size > 4096
|
17
|
+
dumpbuf
|
18
|
+
end
|
19
|
+
@buf << s
|
20
|
+
end
|
21
|
+
|
22
|
+
def dumpbuf
|
23
|
+
syswrite(@buf)
|
24
|
+
@buf = ''
|
25
|
+
end
|
26
|
+
|
27
|
+
EV_TIMING = 0x81
|
28
|
+
|
29
|
+
def timer_event(ev, parm)
|
30
|
+
putbuf([EV_TIMING, ev, 0, 0, parm].pack('C4I'))
|
31
|
+
end
|
32
|
+
|
33
|
+
private :timer_event
|
34
|
+
|
35
|
+
TMR_START = 4
|
36
|
+
TMR_STOP = 3
|
37
|
+
TMR_WAIT_ABS = 2
|
38
|
+
TMR_TEMPO = 6
|
39
|
+
TMR_TIMESIG = 11
|
40
|
+
|
41
|
+
def start_timer() timer_event(TMR_START, 0) end
|
42
|
+
def stop_timer() timer_event(TMR_STOP, 0) end
|
43
|
+
def wait_time(ticks) timer_event(TMR_WAIT_ABS, ticks) end
|
44
|
+
def settempo(value) timer_event(TMR_TEMPO, value) end
|
45
|
+
def timesignature(sig) timer_event(TMR_TIMESIG, sig) end
|
46
|
+
|
47
|
+
EV_CHN_COMMON = 0x92
|
48
|
+
EV_CHN_VOICE = 0x93
|
49
|
+
EV_SYSEX = 0x94
|
50
|
+
|
51
|
+
def chn_voice(dev, event, chn, note, parm)
|
52
|
+
putbuf([EV_CHN_VOICE, dev, event, chn, note, parm, 0, 0].pack('C8'))
|
53
|
+
end
|
54
|
+
|
55
|
+
def chn_common(dev, event, chn, p1, p2, w14)
|
56
|
+
putbuf([EV_CHN_COMMON, dev, event, chn, p1, p2, w14].pack('C6s'))
|
57
|
+
end
|
58
|
+
|
59
|
+
def sysex(dev, buf, len)
|
60
|
+
buf2 = buf
|
61
|
+
if len < 6
|
62
|
+
buf2 = buf2 + "\xff" * 6
|
63
|
+
end
|
64
|
+
putbuf([EV_SYSEX, dev].pack('C2') + buf2[0,6])
|
65
|
+
end
|
66
|
+
|
67
|
+
private :chn_voice, :chn_common
|
68
|
+
|
69
|
+
MIDI_NOTEOFF = 0x80
|
70
|
+
MIDI_NOTEON = 0x90
|
71
|
+
MIDI_KEY_PRESSURE = 0xa0
|
72
|
+
MIDI_CTL_CHANGE = 0xb0
|
73
|
+
MIDI_PGM_CHANGE = 0xc0
|
74
|
+
MIDI_CHN_PRESSURE = 0xd0
|
75
|
+
MIDI_PITCH_BEND = 0xe0
|
76
|
+
|
77
|
+
def noteoff(dev, ch, note, vel)
|
78
|
+
chn_voice(dev, MIDI_NOTEOFF, ch, note, vel)
|
79
|
+
end
|
80
|
+
|
81
|
+
def noteon(dev, ch, note, vel)
|
82
|
+
chn_voice(dev, MIDI_NOTEON, ch, note, vel)
|
83
|
+
end
|
84
|
+
|
85
|
+
def polyphonickeypressure(dev, ch, note, val)
|
86
|
+
chn_voice(dev, MIDI_KEY_PRESSURE, ch, note, val)
|
87
|
+
end
|
88
|
+
|
89
|
+
def controlchange(dev, ch, num, val)
|
90
|
+
chn_common(dev, MIDI_CTL_CHANGE, ch, num, 0, val)
|
91
|
+
end
|
92
|
+
|
93
|
+
def programchange(dev, ch, num)
|
94
|
+
chn_common(dev, MIDI_PGM_CHANGE, ch, num, 0, 0)
|
95
|
+
end
|
96
|
+
|
97
|
+
def channelpressure(dev, ch, val)
|
98
|
+
chn_common(dev, MIDI_CHN_PRESSURE, ch, val, 0, 0)
|
99
|
+
end
|
100
|
+
|
101
|
+
def pitchbendchange(dev, ch, val)
|
102
|
+
chn_common(dev, MIDI_PITCH_BEND, ch, 0, 0, val)
|
103
|
+
end
|
104
|
+
|
105
|
+
case RUBY_PLATFORM
|
106
|
+
when /freebsd/
|
107
|
+
SNDCTL_SEQ_NRSYNTHS = 0x4004510a
|
108
|
+
SNDCTL_SYNTH_INFO = 0xc08c5102
|
109
|
+
SNDCTL_TMR_TIMEBASE = 0xc0045401
|
110
|
+
SNDCTL_TMR_TEMPO = 0xc0045405
|
111
|
+
when /linux/
|
112
|
+
SNDCTL_SEQ_NRSYNTHS = 0x8004510a
|
113
|
+
SNDCTL_SYNTH_INFO = 0xc08c5102
|
114
|
+
SNDCTL_TMR_TIMEBASE = 0xc0045401
|
115
|
+
SNDCTL_TMR_TEMPO = 0xc0045405
|
116
|
+
else
|
117
|
+
raise 'unknown system'
|
118
|
+
end
|
119
|
+
|
120
|
+
def nrsynths
|
121
|
+
n = [0].pack('i')
|
122
|
+
ioctl(SNDCTL_SEQ_NRSYNTHS, n)
|
123
|
+
n.unpack('i')[0]
|
124
|
+
end
|
125
|
+
|
126
|
+
def synth_info(dev)
|
127
|
+
templ = 'A30x2i7Lix76'
|
128
|
+
a = [0] * 28
|
129
|
+
a[0] = ''
|
130
|
+
a[1] = dev
|
131
|
+
n = a.pack(templ)
|
132
|
+
ioctl(SNDCTL_SYNTH_INFO, n)
|
133
|
+
n.unpack(templ)
|
134
|
+
end
|
135
|
+
|
136
|
+
def timebase(div)
|
137
|
+
n = [div].pack('i')
|
138
|
+
ioctl(SNDCTL_TMR_TIMEBASE, n)
|
139
|
+
n.unpack('i')[0]
|
140
|
+
end
|
141
|
+
|
142
|
+
def tempo(tempo)
|
143
|
+
n = [tempo].pack('i')
|
144
|
+
ioctl(SNDCTL_TMR_TEMPO, n)
|
145
|
+
n.unpack('i')[0]
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
class Sequence
|
151
|
+
|
152
|
+
class Play < XSCallback
|
153
|
+
|
154
|
+
def initialize(num) @num = num end
|
155
|
+
|
156
|
+
def header(format, ntrks, division, tc)
|
157
|
+
@sq = DevSeq.open('/dev/sequencer2', 'w')
|
158
|
+
puts(@sq.synth_info(@num)[0]) if $VERBOSE
|
159
|
+
unless @num < @sq.nrsynths
|
160
|
+
raise 'device not available'
|
161
|
+
end
|
162
|
+
@sq.timebase(division)
|
163
|
+
@sq.tempo(120)
|
164
|
+
end
|
165
|
+
|
166
|
+
def track_start() @offset = 0 end
|
167
|
+
|
168
|
+
def delta(delta)
|
169
|
+
@start_timer ||= (@sq.start_timer; true)
|
170
|
+
prev = @offset
|
171
|
+
@offset += delta
|
172
|
+
if @offset > prev
|
173
|
+
@sq.wait_time(@offset)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def noteoff(ch, note, vel) @sq.noteoff(@num, ch, note, vel) end
|
178
|
+
def noteon(ch, note, vel) @sq.noteon(@num, ch, note, vel) end
|
179
|
+
|
180
|
+
def polyphonickeypressure(ch, note, val)
|
181
|
+
@sq.polyphonickeypressure(@num, ch, note, val)
|
182
|
+
end
|
183
|
+
|
184
|
+
def controlchange(ch, num, val) @sq.controlchange(@num, ch, num, val) end
|
185
|
+
def programchange(ch, num) @sq.programchange(@num, ch, num) end
|
186
|
+
def channelpressure(ch, val) @sq.channelpressure(@num, ch, val) end
|
187
|
+
|
188
|
+
def pitchbendchange(ch, val)
|
189
|
+
val += 0x2000
|
190
|
+
@sq.pitchbendchange(@num, ch, val)
|
191
|
+
end
|
192
|
+
|
193
|
+
def channelmodemessage(ch, num, val) controlchange(ch, num, val) end
|
194
|
+
|
195
|
+
private :channelmodemessage
|
196
|
+
|
197
|
+
def allsoundoff(ch) channelmodemessage(ch, 0x78, 0) end
|
198
|
+
def resetallcontrollers(ch) channelmodemessage(ch, 0x79, 0) end
|
199
|
+
def localcontrol(ch, val) channelmodemessage(ch, 0x7a, val) end
|
200
|
+
def allnotesoff(ch) channelmodemessage(ch, 0x7b, 0) end
|
201
|
+
def omnioff(ch) channelmodemessage(ch, 0x7c, 0) end
|
202
|
+
def omnion(ch) channelmodemessage(ch, 0x7d, 0) end
|
203
|
+
def monomode(ch, val) channelmodemessage(ch, 0x7e, val) end
|
204
|
+
def polymode(ch) channelmodemessage(ch, 0x7f, 0) end
|
205
|
+
|
206
|
+
def exclusivefx(data)
|
207
|
+
i = 0
|
208
|
+
while i < data.size
|
209
|
+
len = data.size - i
|
210
|
+
len = 6 if len > 6
|
211
|
+
@sq.sysex(@num, data[i,6], len)
|
212
|
+
i += 6
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
private :exclusivefx
|
217
|
+
|
218
|
+
def exclusivef0(data) exclusivefx("\xf0" + data) end
|
219
|
+
def exclusivef7(data) exclusivefx(data) end
|
220
|
+
def settempo(tempo) @sq.settempo(60000000 / tempo) end
|
221
|
+
|
222
|
+
def timesignature(nn, dd, cc, bb)
|
223
|
+
@sq.timesignature(nn << 24 | dd << 16 | cc << 8 | bb)
|
224
|
+
end
|
225
|
+
|
226
|
+
def result
|
227
|
+
@sq.dumpbuf
|
228
|
+
@sq.stop_timer
|
229
|
+
@sq.close
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
def play(num=0) WS.new(join, Play.new(num)).read end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
def usage
|
241
|
+
warn 'usage: play-oss2 [-d num] [input]'
|
242
|
+
exit 1
|
243
|
+
end
|
244
|
+
|
245
|
+
usage unless opt = Gopt.gopt('d:')
|
246
|
+
usage unless $*.size >= 0 && $*.size <= 1
|
247
|
+
file = $*.shift
|
248
|
+
file = nil if file == '-'
|
249
|
+
|
250
|
+
num = (opt[:d] || '0').to_i
|
251
|
+
|
252
|
+
sq = unless file then Sequence.read($stdin) else Sequence.load(file) end
|
253
|
+
sq.play(num)
|
data/sample/play-oss3.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# play-oss3.rb: Written by Tadayoshi Funaba 1999-2006
|
4
|
+
# $Id: play-oss3.rb,v 1.4 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 Sequence
|
14
|
+
|
15
|
+
class Timer
|
16
|
+
|
17
|
+
def initialize() @start = Time.now end
|
18
|
+
def elapse() Time.now - @start end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class Play < XSCallback
|
23
|
+
|
24
|
+
def initialize(tm, num) @tm, @num = tm, num end
|
25
|
+
|
26
|
+
def header(format, ntrks, division, tc)
|
27
|
+
@mo = open("/dev/midi%02d" % @num, 'w')
|
28
|
+
end
|
29
|
+
|
30
|
+
def track_start() @offset = 0 end
|
31
|
+
|
32
|
+
def delta(delta)
|
33
|
+
@timer ||= Timer.new
|
34
|
+
if delta.nonzero?
|
35
|
+
@offset += delta
|
36
|
+
e = @tm.offset2elapse(@offset) - @timer.elapse
|
37
|
+
if e > 0
|
38
|
+
sleep(e.to_f)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def noteoff(ch, note, vel)
|
44
|
+
@mo.putc(ch | 0x80)
|
45
|
+
@mo.putc(note)
|
46
|
+
@mo.putc(vel)
|
47
|
+
@mo.flush
|
48
|
+
end
|
49
|
+
|
50
|
+
def noteon(ch, note, vel)
|
51
|
+
@mo.putc(ch | 0x90)
|
52
|
+
@mo.putc(note)
|
53
|
+
@mo.putc(vel)
|
54
|
+
@mo.flush
|
55
|
+
end
|
56
|
+
|
57
|
+
def polyphonickeypressure(ch, note, val)
|
58
|
+
@mo.putc(ch | 0xa0)
|
59
|
+
@mo.putc(note)
|
60
|
+
@mo.putc(val)
|
61
|
+
@mo.flush
|
62
|
+
end
|
63
|
+
|
64
|
+
def controlchange(ch, num, val)
|
65
|
+
@mo.putc(ch | 0xb0)
|
66
|
+
@mo.putc(num)
|
67
|
+
@mo.putc(val)
|
68
|
+
@mo.flush
|
69
|
+
end
|
70
|
+
|
71
|
+
def programchange(ch, num)
|
72
|
+
@mo.putc(ch | 0xc0)
|
73
|
+
@mo.putc(num)
|
74
|
+
@mo.flush
|
75
|
+
end
|
76
|
+
|
77
|
+
def channelpressure(ch, val)
|
78
|
+
@mo.putc(ch | 0xd0)
|
79
|
+
@mo.putc(val)
|
80
|
+
@mo.flush
|
81
|
+
end
|
82
|
+
|
83
|
+
def pitchbendchange(ch, val)
|
84
|
+
@mo.putc(ch | 0xe0)
|
85
|
+
val += 0x2000
|
86
|
+
lsb = val & 0x7f
|
87
|
+
msb = (val >> 7) & 0x7f
|
88
|
+
@mo.putc(lsb)
|
89
|
+
@mo.putc(msb)
|
90
|
+
@mo.flush
|
91
|
+
end
|
92
|
+
|
93
|
+
def channelmodemessage(ch, num, val) controlchange(ch, num, val) end
|
94
|
+
|
95
|
+
private :channelmodemessage
|
96
|
+
|
97
|
+
def allsoundoff(ch) channelmodemessage(ch, 0x78, 0) end
|
98
|
+
def resetallcontrollers(ch) channelmodemessage(ch, 0x79, 0) end
|
99
|
+
def localcontrol(ch, val) channelmodemessage(ch, 0x7a, val) end
|
100
|
+
def allnotesoff(ch) channelmodemessage(ch, 0x7b, 0) end
|
101
|
+
def omnioff(ch) channelmodemessage(ch, 0x7c, 0) end
|
102
|
+
def omnion(ch) channelmodemessage(ch, 0x7d, 0) end
|
103
|
+
def monomode(ch, val) channelmodemessage(ch, 0x7e, val) end
|
104
|
+
def polymode(ch) channelmodemessage(ch, 0x7f, 0) end
|
105
|
+
|
106
|
+
def exclusivefx(data)
|
107
|
+
data.each_byte do |x|
|
108
|
+
@mo.putc(x)
|
109
|
+
end
|
110
|
+
@mo.flush
|
111
|
+
end
|
112
|
+
|
113
|
+
private :exclusivefx
|
114
|
+
|
115
|
+
def exclusivef0(data)
|
116
|
+
@mo.putc(0xf0)
|
117
|
+
exclusivefx(data)
|
118
|
+
@mo.flush
|
119
|
+
end
|
120
|
+
|
121
|
+
def exclusivef7(data) exclusivefx(data) end
|
122
|
+
|
123
|
+
def result() @mo.close end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
def play(num=0)
|
128
|
+
j = join
|
129
|
+
tm = TempoMap.new(j)
|
130
|
+
WS.new(j, Play.new(tm, num)).read
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
def usage
|
138
|
+
warn 'usage: play-oss3 [-d num] [input]'
|
139
|
+
exit 1
|
140
|
+
end
|
141
|
+
|
142
|
+
usage unless opt = Gopt.gopt('d:')
|
143
|
+
usage unless $*.size >= 0 && $*.size <= 1
|
144
|
+
file = $*.shift
|
145
|
+
file = nil if file == '-'
|
146
|
+
|
147
|
+
num = (opt[:d] || '0').to_i
|
148
|
+
|
149
|
+
sq = unless file then Sequence.read($stdin) else Sequence.load(file) end
|
150
|
+
sq.play(num)
|
data/sample/play-spkr.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
# play-spkr.rb: Written by Tadayoshi Funaba 2005,2006
|
4
|
+
# $Id: play-spkr.rb,v 1.4 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 DevSpkr < File
|
14
|
+
|
15
|
+
case RUBY_PLATFORM
|
16
|
+
when /freebsd/
|
17
|
+
SPKRTONE = 0x80085301
|
18
|
+
else
|
19
|
+
raise 'unknown system'
|
20
|
+
end
|
21
|
+
|
22
|
+
def emit_tone(freq, duration)
|
23
|
+
ioctl(SPKRTONE, [freq, duration].pack('i*'))
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class Sequence
|
29
|
+
|
30
|
+
class PlaySpkr < XSCallback
|
31
|
+
|
32
|
+
FREQ = []
|
33
|
+
(0..127).each do |n|
|
34
|
+
FREQ << 440 * 2**((n-69.0)/12)
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(tm) @tm = tm end
|
38
|
+
|
39
|
+
def header(format, ntrks, division, tc)
|
40
|
+
@sp = DevSpkr.open('/dev/speaker', 'w')
|
41
|
+
end
|
42
|
+
|
43
|
+
def track_start
|
44
|
+
@loffset = 0
|
45
|
+
@offset = 0
|
46
|
+
@noteon = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def delta(delta) @offset += delta end
|
50
|
+
|
51
|
+
def noteoff(ch, note, vel)
|
52
|
+
return if ch == 9 # GM perc.
|
53
|
+
if @noteon && @noteon[0] == note
|
54
|
+
start = @noteon[1]
|
55
|
+
@noteon = nil
|
56
|
+
if start > @loffset
|
57
|
+
s = @tm.offset2elapse(@loffset)
|
58
|
+
e = @tm.offset2elapse(start)
|
59
|
+
@sp.emit_tone(0, ((e - s) * 100).round)
|
60
|
+
end
|
61
|
+
s = @tm.offset2elapse(start)
|
62
|
+
e = @tm.offset2elapse(@offset)
|
63
|
+
@sp.emit_tone(FREQ[note], ((e - s) * 100).round)
|
64
|
+
@loffset = @offset
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def noteon(ch, note, vel)
|
69
|
+
return if ch == 9 # GM perc.
|
70
|
+
@noteon ||= [note, @offset]
|
71
|
+
end
|
72
|
+
|
73
|
+
def result() @sp.close end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def play
|
78
|
+
j = join
|
79
|
+
tm = TempoMap.new(j)
|
80
|
+
WS.new(j, PlaySpkr.new(tm)).read
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def usage
|
88
|
+
warn 'usage: play-spkr [input]'
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
|
92
|
+
usage unless $*.size >= 0 && $*.size <= 1
|
93
|
+
file = $*.shift
|
94
|
+
file = nil if file == '-'
|
95
|
+
|
96
|
+
sq = unless file then Sequence.read($stdin) else Sequence.load(file) end
|
97
|
+
sq.play
|