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