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
@@ -0,0 +1,239 @@
|
|
1
|
+
# parser.ry: Written by Tadayoshi Funaba 1999-2005,2008
|
2
|
+
# $Id: parser.ry,v 1.3 2008-02-16 16:56:21+09 tadf Exp $
|
3
|
+
|
4
|
+
class SMF::MMLParser
|
5
|
+
|
6
|
+
prechigh
|
7
|
+
nonassoc UMINUS
|
8
|
+
left '*' '/'
|
9
|
+
left '+' '-'
|
10
|
+
preclow
|
11
|
+
|
12
|
+
rule
|
13
|
+
|
14
|
+
prog : list { result = val[0] } ;
|
15
|
+
|
16
|
+
list : { result = [:list, []] }
|
17
|
+
| list stmt { val[0][1] << val[1]; result = val[0] }
|
18
|
+
;
|
19
|
+
|
20
|
+
stmt : expr { result = [:stmt, val[0]] }
|
21
|
+
| expr '&' { result = [:stmt, val[0], val[1]] }
|
22
|
+
;
|
23
|
+
|
24
|
+
expr : step { result = [:step, val[0]] }
|
25
|
+
| note | text | asgn
|
26
|
+
| '{' list '}' { result = val[1] }
|
27
|
+
;
|
28
|
+
|
29
|
+
note : NOTE { result = [:note, val[0]] } ;
|
30
|
+
text : TEXT { result = [:text, val[0]] } ;
|
31
|
+
|
32
|
+
asgn : VAR AOP num
|
33
|
+
{ result = [:asgn, val[0], val[1], val[2]] }
|
34
|
+
| VAR AOP num ',' num
|
35
|
+
{ result = [:asgn, val[0], val[1], val[2], val[4]] }
|
36
|
+
;
|
37
|
+
|
38
|
+
step : step '+' step { result = [:add, val[0], val[2]] }
|
39
|
+
| step '-' step { result = [:sub, val[0], val[2]] }
|
40
|
+
| step '*' num { result = [:mul, val[0], val[2]] }
|
41
|
+
| step '/' num { result = [:div, val[0], val[2]] }
|
42
|
+
| '(' step ')' { result = val[1] }
|
43
|
+
| STEP { result = [:imm, val[0]] }
|
44
|
+
;
|
45
|
+
|
46
|
+
num : num '+' num { result = [:add, val[0], val[2]] }
|
47
|
+
| num '-' num { result = [:sub, val[0], val[2]] }
|
48
|
+
| num '*' num { result = [:mul, val[0], val[2]] }
|
49
|
+
| num '/' num { result = [:div, val[0], val[2]] }
|
50
|
+
| '-' num = UMINUS { result = [:negate, val[1]] }
|
51
|
+
| '(' num ')' { result = val[1] }
|
52
|
+
| NUM { result = [:imm, val[0]] }
|
53
|
+
;
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
---- header ----
|
58
|
+
|
59
|
+
require 'smf'
|
60
|
+
require 'smf/toy/macro'
|
61
|
+
require 'rational'
|
62
|
+
|
63
|
+
class SemanticError < StandardError; end
|
64
|
+
|
65
|
+
---- inner ----
|
66
|
+
|
67
|
+
STEPTAB = { 'w'=>1.to_r/1, 'h'=>1.to_r/2,
|
68
|
+
'q'=>1.to_r/4, 'i'=>1.to_r/8,
|
69
|
+
's'=>1.to_r/16,'z'=>1.to_r/32,
|
70
|
+
'u'=>1.to_r/1920 }
|
71
|
+
|
72
|
+
NOTETAB = { 'a'=>9, 'b'=>11, 'c'=>0, 'd'=>2, 'e'=>4, 'f'=>5, 'g'=>7 }
|
73
|
+
|
74
|
+
def lineno() @co end
|
75
|
+
|
76
|
+
def parse(str)
|
77
|
+
@co = 1
|
78
|
+
@str = str
|
79
|
+
do_parse
|
80
|
+
end
|
81
|
+
|
82
|
+
def next_token
|
83
|
+
loop do
|
84
|
+
@str = @str.sub(/\A([\s\v]+)/, '')
|
85
|
+
if $1
|
86
|
+
@co += $1.count("\n")
|
87
|
+
end
|
88
|
+
@str = @str.sub(%r|\A(//.*)$|, '')
|
89
|
+
break unless $1
|
90
|
+
end
|
91
|
+
return [false, false] if @str.size == 0
|
92
|
+
|
93
|
+
if /\A([whqiszu])\b(\.+)?/i =~ @str
|
94
|
+
@str = $'
|
95
|
+
n = STEPTAB[$1.downcase]
|
96
|
+
i = if $2 then $2.size else 0 end
|
97
|
+
p = 1
|
98
|
+
i.times do |j|
|
99
|
+
p += Rational(1, 2 ** (j + 1))
|
100
|
+
end
|
101
|
+
s = n * p
|
102
|
+
return [:STEP, s]
|
103
|
+
end
|
104
|
+
|
105
|
+
if /\Ar\b/i =~ @str
|
106
|
+
@str = $'
|
107
|
+
return [:NOTE, nil]
|
108
|
+
end
|
109
|
+
|
110
|
+
if /\A([abcdefg])\b([$%#]+)?([,']+)?/i =~ @str
|
111
|
+
@str = $'
|
112
|
+
na = NOTETAB[$1.downcase]
|
113
|
+
if $2
|
114
|
+
s1 = 0
|
115
|
+
s1 -= $2.count('$')
|
116
|
+
s1 += $2.count('#')
|
117
|
+
end
|
118
|
+
if $3
|
119
|
+
s12 = 0
|
120
|
+
s12 -= $3.count(",") * 12
|
121
|
+
s12 += $3.count("'") * 12
|
122
|
+
end
|
123
|
+
return [:NOTE, [na, s1, s12]]
|
124
|
+
end
|
125
|
+
|
126
|
+
if /\A"/ =~ @str
|
127
|
+
@str = $'
|
128
|
+
s = '"'
|
129
|
+
until /\A"/ =~ @str
|
130
|
+
case @str
|
131
|
+
when /\A(\\.|.)/m; s << $1
|
132
|
+
end
|
133
|
+
@co += $1.count("\n")
|
134
|
+
@str = $'
|
135
|
+
end
|
136
|
+
s << '"'
|
137
|
+
@str = $'
|
138
|
+
return [:TEXT, eval(s)]
|
139
|
+
end
|
140
|
+
|
141
|
+
if /\A([a-z][a-z0-9]*)/i =~ @str
|
142
|
+
@str = $'
|
143
|
+
return [:VAR, $1]
|
144
|
+
end
|
145
|
+
|
146
|
+
if %r|\A([-+*/]?=)| =~ @str
|
147
|
+
@str = $'
|
148
|
+
return [:AOP, $1[0]]
|
149
|
+
end
|
150
|
+
|
151
|
+
if /\A(\d+)/ =~ @str
|
152
|
+
@str = $'
|
153
|
+
return [:NUM, Rational($1.to_i)]
|
154
|
+
end
|
155
|
+
|
156
|
+
if /\A(.)/ =~ @str
|
157
|
+
@str = $'
|
158
|
+
return [$1, $1]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
---- footer ----
|
163
|
+
|
164
|
+
module SMF
|
165
|
+
|
166
|
+
class MMLEvaluator
|
167
|
+
|
168
|
+
def initialize(de) @de = de end
|
169
|
+
|
170
|
+
def evaluate(st)
|
171
|
+
case st[0]
|
172
|
+
when :list
|
173
|
+
@de.push
|
174
|
+
st[1].each do |st2|
|
175
|
+
evaluate(st2)
|
176
|
+
end
|
177
|
+
of = @de[:of]
|
178
|
+
@de.pop
|
179
|
+
@de[:of] = of
|
180
|
+
@de.snap
|
181
|
+
when :stmt
|
182
|
+
of = @de[:of]
|
183
|
+
evaluate(st[1])
|
184
|
+
if st[2]
|
185
|
+
@de[:of] = of
|
186
|
+
end
|
187
|
+
when :step
|
188
|
+
@de[:le] = evaluate(st[1])
|
189
|
+
when :add
|
190
|
+
return evaluate(st[1]) + evaluate(st[2])
|
191
|
+
when :sub
|
192
|
+
return evaluate(st[1]) - evaluate(st[2])
|
193
|
+
when :mul
|
194
|
+
return evaluate(st[1]) * evaluate(st[2])
|
195
|
+
when :div
|
196
|
+
return evaluate(st[1]) / evaluate(st[2])
|
197
|
+
when :negate
|
198
|
+
return - evaluate(st[1])
|
199
|
+
when :imm
|
200
|
+
return st[1]
|
201
|
+
when :note
|
202
|
+
@de[:_no] = st[1]
|
203
|
+
@de.snap
|
204
|
+
@de[:_no] = nil
|
205
|
+
@de[:of] += @de[:le]
|
206
|
+
when :text
|
207
|
+
@de[:_tx] = st[1]
|
208
|
+
@de.snap
|
209
|
+
@de[:_tx] = nil
|
210
|
+
when :asgn
|
211
|
+
va = st[1]
|
212
|
+
op = st[2]
|
213
|
+
ob = evaluate(st[3])
|
214
|
+
if st[4]
|
215
|
+
ob2 = evaluate(st[4])
|
216
|
+
ob = [ob, ob2]
|
217
|
+
end
|
218
|
+
va = va.intern
|
219
|
+
v = @de[va]
|
220
|
+
case op
|
221
|
+
when ?+; v += ob
|
222
|
+
when ?-; v -= ob
|
223
|
+
when ?*; v *= ob
|
224
|
+
when ?/; v /= ob
|
225
|
+
when ?=; v = ob
|
226
|
+
end
|
227
|
+
if va == :ke
|
228
|
+
@de[:_ke] = v
|
229
|
+
@de.snap
|
230
|
+
@de[:_ke] = nil
|
231
|
+
end
|
232
|
+
@de[va] = v
|
233
|
+
@de.snap
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# stt.rb: Written by Tadayoshi Funaba 2005
|
2
|
+
# $Id: stt.rb,v 1.2 2005-07-17 17:08:20+09 tadf Exp $
|
3
|
+
|
4
|
+
$KCODE = 'e'
|
5
|
+
|
6
|
+
require 'smf/toy/macro/mml'
|
7
|
+
require 'kconv'
|
8
|
+
require 'jcode'
|
9
|
+
|
10
|
+
module SMF
|
11
|
+
|
12
|
+
class STT < MML
|
13
|
+
|
14
|
+
NOTETAB = { '��'=>'a', '��' =>'b', '��'=>'c', '��'=>'d',
|
15
|
+
'��'=>'e', '�ե�'=>'f', '��'=>'g', '��'=>'r' }
|
16
|
+
|
17
|
+
def << (s)
|
18
|
+
s2 = s.toeuc.
|
19
|
+
gsub(/(��|��|��|��|��|�ե�|��|��)([$%#�����]+)?([,'����]+)?(��+)?/) do
|
20
|
+
n, s, o, x = $1, $2, $3, $4
|
21
|
+
no = NOTETAB[n]
|
22
|
+
no += s.tr('�����', '$%#') if s
|
23
|
+
no += o.tr('����', ",'") if o
|
24
|
+
le = 1
|
25
|
+
le += x.jsize if x
|
26
|
+
format('{le*=%d %s}', le, no)
|
27
|
+
end
|
28
|
+
super(s2)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# morse.rb: Written by Tadayoshi Funaba 2005,2006
|
2
|
+
# $Id: morse.rb,v 1.4 2006-11-10 21:58:21+09 tadf Exp $
|
3
|
+
|
4
|
+
require 'smf'
|
5
|
+
require 'smf/toy/gm'
|
6
|
+
|
7
|
+
module SMF
|
8
|
+
|
9
|
+
class Morse
|
10
|
+
|
11
|
+
PLAIN = {
|
12
|
+
# '!' => 'exclamation mark',
|
13
|
+
# '"' => 'quotation mark',
|
14
|
+
'#' => 'number sign',
|
15
|
+
# '$' => 'dollar sign',
|
16
|
+
'%' => 'percent sign',
|
17
|
+
# '&' => 'ampersand',
|
18
|
+
# "'" => 'apostrophe',
|
19
|
+
# '(' => 'left parenthesis',
|
20
|
+
# ')' => 'right parenthesis',
|
21
|
+
'*' => 'asterisk',
|
22
|
+
'+' => 'plus sign',
|
23
|
+
# ',' => 'comma',
|
24
|
+
# '-' => 'hyphen', # -minus
|
25
|
+
# '.' => 'full stop',
|
26
|
+
# '/' => 'solidus',
|
27
|
+
# ':' => 'colon',
|
28
|
+
# ';' => 'semicolon',
|
29
|
+
'<' => 'less than sign',
|
30
|
+
# '=' => 'equals sign',
|
31
|
+
'>' => 'greater than sign',
|
32
|
+
# '?' => 'question mark',
|
33
|
+
# '@' => 'commercial at',
|
34
|
+
'[' => 'left square bracket',
|
35
|
+
'\\' => 'reverse solidus',
|
36
|
+
']' => 'right square bracket',
|
37
|
+
'^' => 'circumflex accent',
|
38
|
+
# '_' => 'low line',
|
39
|
+
'`' => 'grave accent',
|
40
|
+
'{' => 'left curly bracket',
|
41
|
+
'|' => 'vertical line',
|
42
|
+
'}' => 'right curly bracket',
|
43
|
+
'~' => 'tilde'
|
44
|
+
}
|
45
|
+
|
46
|
+
CODE = {
|
47
|
+
?! => '-.-.--', ?" => '.-..-.', ?$ => '...-..-',
|
48
|
+
?& => '. ...', ?' => '.----.', ?( => '-.--.-', # '
|
49
|
+
?) => '-.--.-', ?* => '-..-', ?+ => '.-.-.',
|
50
|
+
?, => '--..--', ?- => '-....-', ?. => '.-.-.-',
|
51
|
+
?/ => '-..-.',
|
52
|
+
|
53
|
+
?0 => '-----', ?1 => '.----', ?2 => '..---',
|
54
|
+
?3 => '...--', ?4 => '....-', ?5 => '.....',
|
55
|
+
?6 => '-....', ?7 => '--...', ?8 => '---..',
|
56
|
+
?9 => '----.',
|
57
|
+
|
58
|
+
?: => '---...', ?; => '-.-.-', ?= => '-...-',
|
59
|
+
?? => '..--..', ?@ => '.--.-.',
|
60
|
+
|
61
|
+
?a => '.-', ?b => '-...', ?c => '-.-.',
|
62
|
+
?d => '-..', ?e => '.', ?f => '..-.',
|
63
|
+
?g => '--.', ?h => '....', ?i => '..',
|
64
|
+
?j => '.---', ?k => '-.-', ?l => '.-..',
|
65
|
+
?m => '--', ?n => '-.', ?o => '---',
|
66
|
+
?p => '.--.', ?q => '--.-', ?r => '.-.',
|
67
|
+
?s => '...', ?t => '-', ?u => '..-',
|
68
|
+
?v => '...-', ?w => '.--', ?x => '-..-',
|
69
|
+
?y => '-.--', ?z => '--..',
|
70
|
+
|
71
|
+
?_ => '..--.-'
|
72
|
+
}
|
73
|
+
|
74
|
+
def initialize(sq, te=120)
|
75
|
+
@sq = sq << Track.new
|
76
|
+
@te = te
|
77
|
+
@mesg = []
|
78
|
+
end
|
79
|
+
|
80
|
+
def << (s) @mesg << s end
|
81
|
+
|
82
|
+
def plain(s)
|
83
|
+
s = s.dup
|
84
|
+
PLAIN.each_pair{|k, v| s.gsub!(k, ' %s ' % v)}
|
85
|
+
s
|
86
|
+
end
|
87
|
+
|
88
|
+
def encode(s)
|
89
|
+
s.downcase.scan(/\S+/).collect {|w|
|
90
|
+
w.scan(/./).collect{|c|
|
91
|
+
(CODE[c[0]] || '').scan(/./).join("\s")
|
92
|
+
}.join("\s"*3)
|
93
|
+
}.join("\s"*7) + "\s"*15
|
94
|
+
end
|
95
|
+
|
96
|
+
private :plain, :encode
|
97
|
+
|
98
|
+
def generate
|
99
|
+
of = 0
|
100
|
+
@sq[0] << SetTempo.new(of, 60000000 / 240)
|
101
|
+
@sq[0] << GMSystemOn.new(of)
|
102
|
+
of += @sq.division / 2
|
103
|
+
@sq[0] << ProgramChange.new(of, 0, 81)
|
104
|
+
of += @sq.division / 2
|
105
|
+
@sq[0] << SetTempo.new(of, 60000000 / @te)
|
106
|
+
@mesg.each do |s|
|
107
|
+
@sq[0] << Marker.new(of, s)
|
108
|
+
encode(plain(s)).each_byte do |c|
|
109
|
+
case c
|
110
|
+
when ?.; le = (@sq.division / 8) * 1
|
111
|
+
when ?-; le = (@sq.division / 8) * 3
|
112
|
+
else; le = (@sq.division / 8) * 1
|
113
|
+
end
|
114
|
+
if c == ?. || c == ?-
|
115
|
+
@sq[0] << NoteOn .new(of, 0, 69, 96)
|
116
|
+
@sq[0] << NoteOff.new(of + le, 0, 69, 64)
|
117
|
+
end
|
118
|
+
of += le
|
119
|
+
end
|
120
|
+
end
|
121
|
+
@sq[0] << EndOfTrack.new(of)
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# quantize.rb: Written by Tadayoshi Funaba 1999-2005
|
2
|
+
# $Id: quantize.rb,v 1.1 2005-07-09 07:36:31+09 tadf Exp $
|
3
|
+
|
4
|
+
module SMF
|
5
|
+
|
6
|
+
class Quantize
|
7
|
+
|
8
|
+
def initialize(div, unit=1.0/8)
|
9
|
+
@unit = unit * div * 4
|
10
|
+
self.min = 0.0
|
11
|
+
self.max = 1.0
|
12
|
+
self.rand = 0.0
|
13
|
+
end
|
14
|
+
|
15
|
+
def min=(v) @min = @unit * v end
|
16
|
+
def max=(v) @max = @unit * v end
|
17
|
+
def rand=(v) @rand = @unit * v end
|
18
|
+
|
19
|
+
def quantize(ev)
|
20
|
+
offset = (ev.offset + @unit / 2) / @unit * @unit
|
21
|
+
if @rand != 0
|
22
|
+
offset += rand(@rand) - @rand / 2
|
23
|
+
end
|
24
|
+
offset = offset.round
|
25
|
+
if (@min..@max) === (ev.offset - offset).abs
|
26
|
+
ev.offset = offset
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/smf/toy/rmi.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# rmi.rb: Written by Tadayoshi Funaba 2001-2005
|
2
|
+
# $Id: rmi.rb,v 1.1 2005-07-09 07:36:31+09 tadf Exp $
|
3
|
+
|
4
|
+
module SMF
|
5
|
+
|
6
|
+
module RMI
|
7
|
+
|
8
|
+
def smf2rmi(s)
|
9
|
+
pad = s.size % 2
|
10
|
+
o = 'RIFF'
|
11
|
+
o << [12 + s.size + pad].pack('V')
|
12
|
+
o << 'RMID'
|
13
|
+
o << 'data'
|
14
|
+
o << [s.size].pack('V')
|
15
|
+
o << s
|
16
|
+
pad.times do o << "\000" end
|
17
|
+
o
|
18
|
+
end
|
19
|
+
|
20
|
+
def rmi2smf(s)
|
21
|
+
x, = s[16,4].unpack('V')
|
22
|
+
s[20,x]
|
23
|
+
end
|
24
|
+
|
25
|
+
module_function :smf2rmi, :rmi2smf
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|