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,42 @@
1
+ # velcomp.rb: Written by Tadayoshi Funaba 2005,2006,2008
2
+ # $Id: velcomp.rb,v 1.3 2008-02-16 16:56:21+09 tadf Exp $
3
+
4
+ require 'gsl'
5
+
6
+ module SMF
7
+
8
+ class VelComp
9
+
10
+ def initialize
11
+ self.gain = 0
12
+ self.thresh = 80
13
+ self.ratio = 0.9
14
+ end
15
+
16
+ def init
17
+ max = @thresh + (127 - @thresh) * @ratio
18
+ @x = GSL::Vector.alloc(0, @thresh, 127)
19
+ @y = GSL::Vector.alloc(0, @thresh, max)
20
+ @interp = GSL::Interp.alloc('linear', 3)
21
+ end
22
+
23
+ private :init
24
+
25
+ def gain=(v) @gain = v end
26
+ def thresh=(v) @thresh = v; @interp = nil end
27
+ def ratio=(v) @ratio = v; @interp = nil end
28
+
29
+ def velcomp(ev)
30
+ init unless @interp
31
+ v = ev.vel + @gain
32
+ v = 127 if v > 127
33
+ v = 1 if v < 1
34
+ v2 = @interp.eval(@x, @y, v)
35
+ v2 = 127 if v > 127
36
+ v2 = 1 if v < 1
37
+ ev.vel = v2.round
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,118 @@
1
+ # virtual.rb: Written by Tadayoshi Funaba 2005,2006
2
+ # $Id: virtual.rb,v 1.3 2006-11-10 21:58:21+09 tadf Exp $
3
+
4
+ module SMF
5
+
6
+ class Sequence
7
+
8
+ def to_virtual
9
+ v = VirtualSequence.new(format, division, tc)
10
+ each do |tr|
11
+ v << tr.to_virtual
12
+ end
13
+ v
14
+ end
15
+
16
+ end
17
+
18
+ class Track
19
+
20
+ def to_virtual
21
+ v = VirtualTrack.new
22
+ xs = []
23
+ each do |ev|
24
+ case ev
25
+ when NoteOn
26
+ xs.push(ev)
27
+ when NoteOff
28
+ on = nil
29
+ i = 0
30
+ xs.each_with_index do |x, i|
31
+ if x.ch == ev.ch && x.note == ev.note
32
+ on = x
33
+ break
34
+ end
35
+ end
36
+ if on
37
+ v << VirtualNote.new(on.offset, on.ch, on.note,
38
+ on.vel, ev.vel, ev.offset - on.offset)
39
+ xs.delete_at(i)
40
+ end
41
+ else
42
+ v << ev
43
+ end
44
+ end
45
+ v
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
52
+ module SMF
53
+
54
+ class VirtualSequence < Sequence
55
+
56
+ class RS < Sequence::RS; end
57
+ class WS < Sequence::WS
58
+
59
+ def initialize(o, cb) super(o.to_real, cb) end
60
+
61
+ end
62
+
63
+ class Decode < Sequence::Decode
64
+
65
+ def result() super().to_virtual end
66
+
67
+ end
68
+
69
+ class Encode < Sequence::Encode; end
70
+
71
+ def initialize(format, division, tc)
72
+ super(format, division, tc)
73
+ end
74
+
75
+ def to_real
76
+ r = Sequence.new(format, division, tc)
77
+ each do |tr|
78
+ r << tr.to_real
79
+ end
80
+ r
81
+ end
82
+
83
+ end
84
+
85
+ class VirtualTrack < Track
86
+
87
+ def initialize()
88
+ super()
89
+ end
90
+
91
+ def to_real
92
+ r = Track.new
93
+ each do |ev|
94
+ case ev
95
+ when VirtualNote
96
+ r << NoteOn.new(ev.offset, ev.ch, ev.note, ev.vel)
97
+ r << NoteOff.new(ev.offset + ev.length, ev.ch, ev.note, ev.offvel)
98
+ else
99
+ r << ev
100
+ end
101
+ end
102
+ r
103
+ end
104
+
105
+ end
106
+
107
+ class VirtualNote < VoiceMessage
108
+
109
+ def initialize(offset, ch, note, vel, offvel, length)
110
+ super(offset, ch)
111
+ @note, @vel, @offvel, @length = note, vel, offvel, length
112
+ end
113
+
114
+ attr_accessor :note, :vel, :offvel, :length
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,377 @@
1
+ # xml.rb: Written by Tadayoshi Funaba 2004-2007
2
+ # $Id: xml.rb,v 1.4 2007-12-26 20:33:25+09 tadf Exp $
3
+
4
+ require 'rexml/document'
5
+ require 'rexml/streamlistener'
6
+
7
+ begin require 'rexml/formatters/pretty'; rescue LoadError; end
8
+
9
+ module SMF
10
+
11
+ class Sequence
12
+
13
+ class RSXML
14
+
15
+ def initialize(s, cb) @s, @cb = s, cb end
16
+
17
+ include REXML::StreamListener
18
+
19
+ def get_params(attrs, keys)
20
+ attrs.values_at(*keys).collect{|x| x.to_i}
21
+ end
22
+
23
+ def get_text(attrs, key)
24
+ s = attrs[key]
25
+ eval('"%s"' % s)
26
+ end
27
+
28
+ def tag_start(name, attrs)
29
+ if attrs['offset']
30
+ offset = attrs['offset'].to_i
31
+ @cb.delta(offset - @loffset)
32
+ @loffset = offset
33
+ end
34
+ case name
35
+ when /\AMThd\z/i
36
+ f, n, d, s = get_params(attrs, %w(format ntrks division tc))
37
+ s = nil if attrs['tc']
38
+ @cb.header(f, n, d, s)
39
+ when /\AMTrk\z/i
40
+ @loffset = 0
41
+ @cb.track_start
42
+ when /\ANoteOff\z/i
43
+ @cb.noteoff(*get_params(attrs, %w(ch note vel)))
44
+ when /\ANoteOn\z/i
45
+ @cb.noteon(*get_params(attrs, %w(ch note vel)))
46
+ when /\APolyphonicKeyPressure\z/i
47
+ @cb.polyphonickeypressure(*get_params(attrs, %w(ch note val)))
48
+ when /\AControlChange\z/i
49
+ @cb.controlchange(*get_params(attrs, %w(ch num val)))
50
+ when /\AProgramChange\z/i
51
+ @cb.programchange(*get_params(attrs, %w(ch num)))
52
+ when /\AChannelPressure\z/i
53
+ @cb.channelpressure(*get_params(attrs, %w(ch val)))
54
+ when /\APitchBendChange\z/i
55
+ @cb.pitchbendchange(*get_params(attrs, %w(ch val)))
56
+ when /\AAllSoundOff\z/i
57
+ ch, = get_params(attrs, %w(ch))
58
+ @cb.allsoundoff(ch)
59
+ when /\AResetAllControllers\z/i
60
+ ch, = get_params(attrs, %w(ch))
61
+ @cb.resetallcontrollers(ch)
62
+ when /\ALocalControl\z/i
63
+ ch, val, = get_params(attrs, %w(ch, val))
64
+ @cb.localcontrol(ch, val)
65
+ when /\AAllNotesOff\z/i
66
+ ch, = get_params(attrs, %w(ch))
67
+ @cb.allnotesoff(ch)
68
+ when /\AOmniOff\z/i
69
+ ch, = get_params(attrs, %w(ch))
70
+ @cb.omnioff(ch)
71
+ when /\AOmniOn\z/i
72
+ ch, = get_params(attrs, %w(ch))
73
+ @cb.omnion(ch)
74
+ when /\AMonoMode\z/i
75
+ ch, val, = get_params(attrs, %w(ch val))
76
+ @cb.monomode(ch, val)
77
+ when /\APolyMode\z/i
78
+ ch, = get_params(attrs, %w(ch))
79
+ @cb.polymode(ch)
80
+ when /\AExclusiveF0\z/i
81
+ @cb.exclusivef0(get_text(attrs, 'data'))
82
+ when /\AExclusiveF7\z/i
83
+ @cb.exclusivef7(get_text(attrs, 'data'))
84
+ when /\ASequenceNumber\z/i
85
+ @cb.sequencenumber(*get_params(attrs, %w(num)))
86
+ when /\A(GeneralPurposeText|Text01)\z/i
87
+ @cb.generalpurposetext(get_text(attrs, 'text'))
88
+ when /\A(CopyrightNotice|Text02)\z/i
89
+ @cb.copyrightnotice(get_text(attrs, 'text'))
90
+ when /\A(TrackName|SequenceName|Text03)\z/i
91
+ @cb.trackname(get_text(attrs, 'text'))
92
+ when /\A(InstrumentName|Text04)\z/i
93
+ @cb.instrumentname(get_text(attrs, 'text'))
94
+ when /\A(Lyric|Text05)\z/i
95
+ @cb.lyric(get_text(attrs, 'text'))
96
+ when /\A(Marker|Text06)\z/i
97
+ @cb.marker(get_text(attrs, 'text'))
98
+ when /\A(CuePoint|Text07)\z/i
99
+ @cb.cuepoint(get_text(attrs, 'text'))
100
+ when /\A(ProgramName|Text08)\z/i
101
+ @cb.programname(get_text(attrs, 'text'))
102
+ when /\A(DeviceName|Text09)\z/i
103
+ @cb.devicename(get_text(attrs, 'text'))
104
+ when /\AText0([A-F])\z/i
105
+ case $1
106
+ when 'A'; @cb.text0a(get_text(attrs, 'text'))
107
+ when 'B'; @cb.text0b(get_text(attrs, 'text'))
108
+ when 'C'; @cb.text0c(get_text(attrs, 'text'))
109
+ when 'D'; @cb.text0d(get_text(attrs, 'text'))
110
+ when 'E'; @cb.text0e(get_text(attrs, 'text'))
111
+ when 'F'; @cb.text0f(get_text(attrs, 'text'))
112
+ end
113
+ when /\AChannelPrefix\z/i
114
+ @cb.channelprefix(*get_params(attrs, %w(ch)))
115
+ when /\AMIDIPort\z/i
116
+ @cb.midiport(*get_params(attrs, %w(num)))
117
+ when /\AEndOfTrack\z/i
118
+ @cb.endoftrack()
119
+ when /\ASetTempo\z/i
120
+ @cb.settempo(*get_params(attrs, %w(tempo)))
121
+ when /\ASMPTEOffset\z/i
122
+ @cb.smpteoffset(*get_params(attrs, %w(hr mn se fr ff tc)))
123
+ when /\ATimeSignature\z/i
124
+ @cb.timesignature(*get_params(attrs, %w(nn dd cc bb)))
125
+ when /\AKeySignature\z/i
126
+ @cb.keysignature(*get_params(attrs, %w(sf mi)))
127
+ when /\ASequencerSpecific\z/i
128
+ @cb.sequencerspecific(get_text(attrs, 'data'))
129
+ else
130
+ @cb.error('unknown event: ' + name)
131
+ end
132
+ end
133
+
134
+ def read
135
+ REXML::Document.parse_stream(@s, self)
136
+ @cb.result
137
+ end
138
+
139
+ end
140
+
141
+ class << self
142
+
143
+ def decode_xml(s)
144
+ self::RSXML.new(s, self::Decode.new).read
145
+ end
146
+
147
+ def read_xml(io)
148
+ decode_xml(io.binmode.read)
149
+ end
150
+
151
+ def load_xml(fn)
152
+ open(fn) do |io|
153
+ read_xml(io)
154
+ end
155
+ end
156
+
157
+ end
158
+
159
+ class EncodeXML < XSCallback
160
+
161
+ def header(format, ntrks, division, tc)
162
+ @doc = REXML::Document.new
163
+ @doc << REXML::XMLDecl.new
164
+ @docsq = REXML::Element.new('MThd', @doc)
165
+ @docsq.attributes['format'] = format.to_s
166
+ @docsq.attributes['division'] = division.to_s
167
+ @docsq.attributes['tc'] = tc.to_s
168
+ end
169
+
170
+ def track_start()
171
+ @offset = 0
172
+ @doctr = REXML::Element.new('MTrk', @docsq)
173
+ end
174
+
175
+ def delta(delta) @offset += delta end
176
+
177
+ def noteoff(ch, note, vel)
178
+ e = REXML::Element.new('NoteOff', @doctr)
179
+ e.attributes['offset'] = @offset.to_s
180
+ e.attributes['ch'] = ch.to_s
181
+ e.attributes['note'] = note.to_s
182
+ e.attributes['vel'] = vel.to_s
183
+ end
184
+
185
+ def noteon(ch, note, vel)
186
+ e = REXML::Element.new('NoteOn', @doctr)
187
+ e.attributes['offset'] = @offset.to_s
188
+ e.attributes['ch'] = ch.to_s
189
+ e.attributes['note'] = note.to_s
190
+ e.attributes['vel'] = vel.to_s
191
+ end
192
+
193
+ def polyphonickeypressure(ch, note, val)
194
+ e = REXML::Element.new('PolyphonicKeyPressure', @doctr)
195
+ e.attributes['offset'] = @offset.to_s
196
+ e.attributes['ch'] = ch.to_s
197
+ e.attributes['note'] = note.to_s
198
+ e.attributes['val'] = val.to_s
199
+ end
200
+
201
+ def controlchange(ch, num, val)
202
+ e = REXML::Element.new('ControlChange', @doctr)
203
+ e.attributes['offset'] = @offset.to_s
204
+ e.attributes['ch'] = ch.to_s
205
+ e.attributes['num'] = num.to_s
206
+ e.attributes['val'] = val.to_s
207
+ end
208
+
209
+ def programchange(ch, num)
210
+ e = REXML::Element.new('ProgramChange', @doctr)
211
+ e.attributes['offset'] = @offset.to_s
212
+ e.attributes['ch'] = ch.to_s
213
+ e.attributes['num'] = num.to_s
214
+ end
215
+
216
+ def channelpressure(ch, val)
217
+ e = REXML::Element.new('ChannelPressure', @doctr)
218
+ e.attributes['offset'] = @offset.to_s
219
+ e.attributes['ch'] = ch.to_s
220
+ e.attributes['val'] = val.to_s
221
+ end
222
+
223
+ def pitchbendchange(ch, val)
224
+ e = REXML::Element.new('PitchBendChange', @doctr)
225
+ e.attributes['offset'] = @offset.to_s
226
+ e.attributes['ch'] = ch.to_s
227
+ e.attributes['val'] = val.to_s
228
+ end
229
+
230
+ def channelmodemessage(name, ch, val=nil)
231
+ e = REXML::Element.new(name, @doctr)
232
+ e.attributes['offset'] = @offset.to_s
233
+ e.attributes['ch'] = ch.to_s
234
+ e.attributes['val'] = val.to_s if val
235
+ end
236
+
237
+ private :channelmodemessage
238
+
239
+ def allsoundoff(ch) channelmodemessage('AllSoundOff', ch) end
240
+ def resetallcontrollers(ch) channelmodemessage('ResetAllControllers', ch) end
241
+ def localcontrol(ch, val) channelmodemessage('LocalControl', ch, val) end
242
+ def allnotesoff(ch) channelmodemessage('AllNotesOff', ch) end
243
+ def omnioff(ch) channelmodemessage('OmniOff', ch) end
244
+ def omnion(ch) channelmodemessage('OmniOn', ch) end
245
+ def monomode(ch, val) channelmodemessage('MonoMode', ch, val) end
246
+ def polymode(ch) channelmodemessage('PolyMode', ch) end
247
+
248
+ def put_binary(name, data)
249
+ e = REXML::Element.new(name, @doctr)
250
+ e.attributes['offset'] = @offset.to_s
251
+ s = ''
252
+ data.each_byte do |c|
253
+ s << format('\\%03o', c)
254
+ end
255
+ e.attributes['data'] = s
256
+ end
257
+
258
+ private :put_binary
259
+
260
+ def exclusivef0(data) put_binary('ExclusiveF0', data) end
261
+ def exclusivef7(data) put_binary('ExclusiveF7', data) end
262
+
263
+ def sequencenumber(num)
264
+ e = REXML::Element.new('SequenceNumber', @doctr)
265
+ e.attributes['offset'] = @offset.to_s
266
+ e.attributes['num'] = num.to_s
267
+ end
268
+
269
+ def text(name, text)
270
+ e = REXML::Element.new(name, @doctr)
271
+ e.attributes['offset'] = @offset.to_s
272
+ e.attributes['text'] = text.dump[1..-2]
273
+ end
274
+
275
+ private :text
276
+
277
+ def generalpurposetext(text) text('GeneralPurposeText', text) end
278
+ def copyrightnotice(text) text('CopyrightNotice', text) end
279
+ def trackname(text) text('TrackName', text) end
280
+ def instrumentname(text) text('InstrumentName', text) end
281
+ def lyric(text) text('Lyric', text) end
282
+ def marker(text) text('Marker', text) end
283
+ def cuepoint(text) text('CuePoint', text) end
284
+ def programname(text) text('ProgramName', text) end
285
+ def devicename(text) text('DeviceName', text) end
286
+ def text0a(text) text('Text0A', text) end
287
+ def text0b(text) text('Text0B', text) end
288
+ def text0c(text) text('Text0C', text) end
289
+ def text0d(text) text('Text0D', text) end
290
+ def text0e(text) text('Text0E', text) end
291
+ def text0f(text) text('Text0F', text) end
292
+
293
+ def channelprefix(ch)
294
+ e = REXML::Element.new('ChannelPrefix', @doctr)
295
+ e.attributes['offset'] = @offset.to_s
296
+ e.attributes['ch'] = ch.to_s
297
+ end
298
+
299
+ def midiport(num)
300
+ e = REXML::Element.new('MIDIPort', @doctr)
301
+ e.attributes['offset'] = @offset.to_s
302
+ e.attributes['num'] = num.to_s
303
+ end
304
+
305
+ def endoftrack
306
+ e = REXML::Element.new('EndOfTrack', @doctr)
307
+ e.attributes['offset'] = @offset.to_s
308
+ end
309
+
310
+ def settempo(tempo)
311
+ e = REXML::Element.new('SetTempo', @doctr)
312
+ e.attributes['offset'] = @offset.to_s
313
+ e.attributes['tempo'] = tempo.to_s
314
+ end
315
+
316
+ def smpteoffset(hr, mn, se, fr, ff, tc)
317
+ e = REXML::Element.new('SMPTEOffset', @doctr)
318
+ e.attributes['offset'] = @offset.to_s
319
+ e.attributes['hr'] = hr.to_s
320
+ e.attributes['mn'] = mn.to_s
321
+ e.attributes['se'] = se.to_s
322
+ e.attributes['fr'] = fr.to_s
323
+ e.attributes['ff'] = ff.to_s
324
+ e.attributes['tc'] = tc.to_s
325
+ end
326
+
327
+ def timesignature(nn, dd, cc, bb)
328
+ e = REXML::Element.new('TimeSignature', @doctr)
329
+ e.attributes['offset'] = @offset.to_s
330
+ e.attributes['nn'] = nn.to_s
331
+ e.attributes['dd'] = dd.to_s
332
+ e.attributes['cc'] = cc.to_s
333
+ e.attributes['bb'] = bb.to_s
334
+ end
335
+
336
+ def keysignature(sf, mi)
337
+ e = REXML::Element.new('KeySignature', @doctr)
338
+ e.attributes['offset'] = @offset.to_s
339
+ e.attributes['sf'] = sf.to_s
340
+ e.attributes['mi'] = mi.to_s
341
+ end
342
+
343
+ def sequencerspecific(data) put_binary('SequencerSpecific', data) end
344
+
345
+ unless defined? REXML::Formatters::Pretty
346
+
347
+ def result() @doc.to_s(0) end
348
+
349
+ else
350
+
351
+ def result
352
+ f = REXML::Formatters::Pretty.new(2)
353
+ f.write(@doc, r = "")
354
+ r
355
+ end
356
+
357
+ end
358
+
359
+ end
360
+
361
+ def encode_xml
362
+ self.class::WS.new(self, self.class::EncodeXML.new).read
363
+ end
364
+
365
+ def write_xml(io)
366
+ io.write(encode_xml)
367
+ end
368
+
369
+ def save_xml(fn)
370
+ open(fn, 'w') do |io|
371
+ write_xml(io)
372
+ end
373
+ end
374
+
375
+ end
376
+
377
+ end