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