SHOW:
|
|
- or go back to the newest paste.
1 | #!/usr/bin/gawk -f | |
2 | # nokia2beeps.tcl - Play an RTTL ringtone file as beeps | |
3 | # Usage: ./nokia2beeps.tcl ringtone_file | |
4 | ||
5 | #TODO: imelody | |
6 | #TODO: chord | |
7 | ||
8 | BEGIN { | |
9 | - | #http://www.phy.mtu.edu/~suits/notefreqs.html |
9 | + | |
10 | default_octave = 4 | |
11 | default_beat = 63 | |
12 | base_time = 200000 | |
13 | loop = 3 | |
14 | # option_qwerty_midi = 0 | |
15 | # option_adjust_octave = 1 | |
16 | ||
17 | # http://www.phy.mtu.edu/~suits/notefreqs.html | |
18 | split("\ | |
19 | C0 16.35 C#0 17.32 Db0 17.32 D0 18.35 D#0 19.45 Eb0 19.45 \ | |
20 | E0 20.60 F0 21.83 F#0 23.12 Gb0 23.12 G0 24.50 G#0 25.96 \ | |
21 | Ab0 25.96 A0 27.50 A#0 29.14 Bb0 29.14 B0 30.87 C1 32.70 \ | |
22 | C#1 34.65 Db1 34.65 D1 36.71 D#1 38.89 Eb1 38.89 E1 41.20 \ | |
23 | F1 43.65 F#1 46.25 Gb1 46.25 G1 49.00 G#1 51.91 Ab1 51.91 \ | |
24 | A1 55.00 A#1 58.27 Bb1 58.27 B1 61.74 C2 65.41 C#2 69.30 \ | |
25 | Db2 69.30 D2 73.42 D#2 77.78 Eb2 77.78 E2 82.41 F2 87.31 \ | |
26 | F#2 92.50 Gb2 92.50 G2 98.00 G#2 103.83 Ab2 103.83 A2 110.00 \ | |
27 | A#2 116.54 Bb2 116.54 B2 123.47 C3 130.81 C#3 138.59 Db3 138.59 \ | |
28 | D3 146.83 D#3 155.56 Eb3 155.56 E3 164.81 F3 174.61 F#3 185.00 \ | |
29 | Gb3 185.00 G3 196.00 G#3 207.65 Ab3 207.65 A3 220.00 A#3 233.08 \ | |
30 | Bb3 233.08 B3 246.94 C4 261.63 C#4 277.18 Db4 277.18 D4 293.66 \ | |
31 | D#4 311.13 Eb4 311.13 E4 329.63 F4 349.23 F#4 369.99 Gb4 369.99 \ | |
32 | G4 392.00 G#4 415.30 Ab4 415.30 A4 440.00 A#4 466.16 Bb4 466.16 \ | |
33 | B4 493.88 C5 523.25 C#5 554.37 Db5 554.37 D5 587.33 D#5 622.25 \ | |
34 | Eb5 622.25 E5 659.26 F5 698.46 F#5 739.99 Gb5 739.99 G5 783.99 \ | |
35 | G#5 830.61 Ab5 830.61 A5 880.00 A#5 932.33 Bb5 932.33 B5 987.77 \ | |
36 | C6 1046.50 C#6 1108.73 Db6 1108.73 D6 1174.66 D#6 1244.51 Eb6 1244.51 \ | |
37 | E6 1318.51 F6 1396.91 F#6 1479.98 Gb6 1479.98 G6 1567.98 G#6 1661.22 \ | |
38 | Ab6 1661.22 A6 1760.00 A#6 1864.66 Bb6 1864.66 B6 1975.53 C7 2093.00 \ | |
39 | C#7 2217.46 Db7 2217.46 D7 2349.32 D#7 2489.02 Eb7 2489.02 E7 2637.02 \ | |
40 | F7 2793.83 F#7 2959.96 Gb7 2959.96 G7 3135.96 G#7 3322.44 Ab7 3322.44 \ | |
41 | A7 3520.00 A#7 3729.31 Bb7 3729.31 B7 3951.07 C8 4186.01 C#8 4434.92 \ | |
42 | - | function nokia2scale(note, octave) { |
42 | + | |
43 | F#8 5919.91 Gb8 5919.91 G8 6271.93 G#8 6644.88 Ab8 6644.88 A8 7040.00 \ | |
44 | A#8 7458.62 Bb8 7458.62 B8 7902.13", arr) | |
45 | for (i = 1; i <= length(arr); i += 2) | |
46 | scale[arr[i]] = arr[i + 1] | |
47 | delete arr | |
48 | } | |
49 | ||
50 | function nokia2scale(note, octave) | |
51 | { | |
52 | - | octave += trans_octave |
52 | + | |
53 | gsub(/[rR-]/, "P", note) | |
54 | match(note, /[a-gA-GpP#].*/) | |
55 | note = toupper(substr(note, RSTART, RLENGTH)) | |
56 | - | function nokia2length(note, duration, dotted) { |
56 | + | |
57 | if (match(note, /[0-8]$/)) { | |
58 | octave = substr(note, length(note), 1) | |
59 | note = substr(note, 1, length(note) - 1) | |
60 | } | |
61 | if (option_adjust_octave) | |
62 | octave += trans_octave | |
63 | return (note ~ /P/) ? note : note octave | |
64 | } | |
65 | ||
66 | function nokia2length(note, duration, dotted) | |
67 | - | function trim(str) { gsub(/^[ \t]+/, "", str); gsub(/[ \t]+$/, "", str); return str } |
67 | + | |
68 | match(note, /^(0.|)[0-9]+/) | |
69 | - | function playnote(note) { |
69 | + | |
70 | if (duration == "") | |
71 | duration = default_duration | |
72 | - | printf "%s ", (qwerty) ? keymap(note) : note |
72 | + | |
73 | - | if (quiet) return |
73 | + | |
74 | if (dotted) duration /= (1.5 * dotted) | |
75 | return base_time / default_beat / duration | |
76 | } | |
77 | ||
78 | function playnote(note) | |
79 | { | |
80 | note = trim(note) | |
81 | if (note == "") return | |
82 | if (!quiet) | |
83 | printf "%s ", option_qwerty_midi ? keymap(note) : note | |
84 | delay = nokia2length(note) | |
85 | note = nokia2scale(note) | |
86 | - | function playRTTL(str, arr, value, i, first) { |
86 | + | |
87 | - | first = 1 |
87 | + | |
88 | - | while (match(str, /([dob])=([0-9]+)/, arr) > 0) { |
88 | + | |
89 | - | if (first) { |
89 | + | |
90 | - | first = 0 |
90 | + | |
91 | - | print substr(str, 1, RSTART-2) #title |
91 | + | |
92 | } | |
93 | ||
94 | function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s } | |
95 | function after(delay) { system("sleep " delay/1000) } | |
96 | ||
97 | function playRTTL( str, arr, value, i, title, r) | |
98 | { | |
99 | str = gensub(/\(Tempo=([0-9]+)\)/, "b=\\1", 1, $0) | |
100 | while (match(str, /([dob])[ \t]*=[ \t]*([0-9]+)/, arr) > 0) { | |
101 | if (title == "") | |
102 | title = substr(str, 1, arr[1, "start"] - 1) | |
103 | if (title ~ /:$/) title = substr(title, 1, length(title) - 1) | |
104 | - | get_octave_range(str) |
104 | + | |
105 | switch (arr[1]) { | |
106 | case "d": default_duration = value; break | |
107 | case "o": default_octave = value; break | |
108 | case "b": default_beat = value; break | |
109 | } | |
110 | str = substr(str, arr[2, "start"] + arr[2, "length"] + 1) | |
111 | - | for (i = 1; i <= length(arr); i++) |
111 | + | |
112 | - | playnote(arr[i]) |
112 | + | print title |
113 | - | print "done.\n" |
113 | + | |
114 | ||
115 | trans_octave = 0 | |
116 | - | function test_nokia_composer(str) { |
116 | + | |
117 | - | return min_octave < 3 && max_octave - min_octave < 4 || str ~ /-/ |
117 | + | |
118 | str = gensub(/#([a-gA-G])/, "\\1#", "g", str) | |
119 | } | |
120 | - | function get_octave_range(str, arr, i, o) { |
120 | + | |
121 | quiet = 0 | |
122 | for (r = 1; r <= loop; ) { | |
123 | split(str, arr, /[ ,]/) | |
124 | for (i = 1; i <= length(arr); i++) | |
125 | playnote(arr[i]) | |
126 | - | if (match(arr[i], /[0-9]$/)) |
126 | + | if (r == 1) print "" |
127 | - | o = substr(arr[i], RSTART, 1) |
127 | + | r++ |
128 | - | if (o+0 < min_octave) min_octave = o |
128 | + | if (r > 1 && r <= loop) { |
129 | - | if (o+0 > max_octave) max_octave = o |
129 | + | quiet = 1 #suppress output |
130 | printf "\rrepeat " r-1 | |
131 | after(nokia2length("R")) | |
132 | } | |
133 | - | #http://outputchannel.com/monophonic-ringtone-synthesizer/ |
133 | + | |
134 | - | function keymap(note, key_map) { |
134 | + | print "\ndone." |
135 | - | key_map = "Cl A C#l W Dl S D#l E El D Fl F F#l T Gl G G#l YAl H A#l U Bl J Cu K C#u O Du L D#u P Eu ; Eu [ Fu ' F#u ] Gu \\" |
135 | + | |
136 | - | if (note ~ /[-pP]/) return "" |
136 | + | |
137 | # http://nokia.nigelcoldwell.co.uk | |
138 | function test_nokia_composer(str, arr, i, n, o) | |
139 | { | |
140 | # get octaves range (global for keymap) | |
141 | min_octave = 10; max_octave = -1 | |
142 | split(str, arr, /[ ,]/) | |
143 | - | if (match(key_map, note)) |
143 | + | |
144 | - | return tolower(substr(key_map, RSTART+RLENGTH+1, 1)) |
144 | + | |
145 | if (arr[i] ~ /[-pP]/) continue | |
146 | if (match(arr[i], /[0-4]$/)) | |
147 | o = substr(arr[i], RSTART, 1)+0 | |
148 | - | #http://www.phoneringsong.com/nokia_composer_tones/ |
148 | + | if (o < min_octave) min_octave = o |
149 | if (o > max_octave) max_octave = o | |
150 | - | result, arr, i, pitch, score, duration, octave, dot) |
150 | + | |
151 | return str ~ /-/ || min_octave < 3 && max_octave - min_octave < 4 | |
152 | - | if (match(str, /( [0-9#*] )|(P&H)/)) { |
152 | + | |
153 | - | result = substr(str, 1, RSTART-1) ":" |
153 | + | |
154 | - | str = substr(str, RSTART) |
154 | + | # http://outputchannel.com/monophonic-ringtone-synthesizer/ |
155 | function keymap(note, str) | |
156 | - | if (match(str, /Tempo = ([0-9]+)/, arr)) { |
156 | + | |
157 | - | default_beat = arr[1] |
157 | + | str = "Cl A C#l W Dl S D#l E El D Fl F F#l T Gl G G#l Y " \ |
158 | - | str = substr(str, arr[1, "start"] + arr[1, "length"] + 1) |
158 | + | "Al H A#l U Bl J Cu K C#u O Du L D#u P Eu ; Eu [ Fu ' F#u ] Gu \\" |
159 | if (note ~ /[-pP]/) return "." | |
160 | - | result = result "b=" default_beat |
160 | + | |
161 | match(note, /[a-gA-GpP#].*/) | |
162 | - | if (sony_ericsson) { |
162 | + | |
163 | - | gsub("0", "@", str) |
163 | + | |
164 | - | gsub("*", "0", str) |
164 | + | |
165 | - | gsub("@", "*", str) |
165 | + | |
166 | if (match(str, note)) | |
167 | return substr(str, RSTART+RLENGTH+1, 1) | |
168 | return "?" note "?" | |
169 | } | |
170 | ||
171 | # http://www.phoneringsong.com/nokia_composer_tones/ | |
172 | function keypress2composer(str, | |
173 | result, score, duration, octave, dot, pitch, arr, i, n) | |
174 | { | |
175 | score = ""; duration = 4; octave = 1; dot = "" | |
176 | split("cdefgab", pitch, ""); pitch[0] = "-" | |
177 | match(str, "( [0-9#*] )|(P&H)") | |
178 | result = substr(str, 1, RSTART - 1) | |
179 | n = split(substr(str, RSTART), arr) | |
180 | - | case /*/: |
180 | + | for (i = 1; i <= n; i++) { |
181 | - | if (sony_ericsson) octave = ++octave % 4 |
181 | + | if (sony_ericsson) { |
182 | - | else octave = ++octave % 3 |
182 | + | sub("0", "@", arr[i]) |
183 | sub("*", "0", arr[i]) | |
184 | sub("@", "*", arr[i]) | |
185 | - | if (i < length(arr) && arr[i+1] !~ /[0-7]/) |
185 | + | |
186 | - | continue |
186 | + | |
187 | - | result = result " " sprintf("%s%s%s", |
187 | + | |
188 | - | duration dot, score, (score ~ /-/) ? "" : octave) |
188 | + | |
189 | - | score = ""; duration = 4; dot = "" |
189 | + | |
190 | break | |
191 | case /#/: score = "#" score; break | |
192 | case /8/: duration *= 2; break | |
193 | case /9/: duration /= 2; break | |
194 | - | /^#/ { print; next } |
194 | + | case /[*]/: |
195 | if (sony_ericsson) | |
196 | - | NF > 0 { |
196 | + | octave = octave++ % 4 + 1 |
197 | - | gsub(/[\r\n]/, "") |
197 | + | else |
198 | - | if (data == "" || data ~ /,$/) { |
198 | + | octave = octave++ % 3 + 1 |
199 | - | data = data $0 |
199 | + | |
200 | - | if (data ~ /,$/) |
200 | + | |
201 | - | next |
201 | + | if (i == n || arr[i + 1] ~ /[0-7]/) { |
202 | result = result " " duration dot score | |
203 | - | data = $0 |
203 | + | if (score !~ /r/) result = result octave |
204 | score = ""; duration = 4; dot = "" | |
205 | - | if (data ~ / [0-9#*] /) { |
205 | + | |
206 | - | if (data ~ /P&H/) |
206 | + | |
207 | - | sony_ericsson = 0 |
207 | + | |
208 | - | data = keypress2composer(data) |
208 | + | |
209 | ||
210 | - | playRTTL(data) |
210 | + | /^#/ || !NF { print; next } |
211 | /,$/ { buf = buf $0 " " } | |
212 | ||
213 | { | |
214 | ||
215 | #if (FNR == 1 && is_imelody()) { | |
216 | # read whole data | |
217 | # play | |
218 | # nextfile | |
219 | #} | |
220 | ||
221 | if (buf) $0 = buf $0 " " | |
222 | if (/ [0-9#*] /) | |
223 | $0 = keypress2composer($0) | |
224 | if (/[ドレミファソラシ]/) | |
225 | $0 = chakumero_conv($0) | |
226 | playRTTL($0) | |
227 | if (buf) buf = "" | |
228 | } | |
229 | ||
230 | # http://www.pluto.dti.ne.jp/~imasa/melody.html | |
231 | # "テンポ=6(126)1:ドH1 2:シ1 3:ドH1 4:シ1 5:ドH1 6:-3 7:ドH1 8:シ1 9:ドH1 10:シ1 11:ドH1 12:-3 13:ドH1 14:シ1 15:ドH1 16:シ1 17:ドH1 18:-1 19:ミH1 20:-1 21:ソ6 22:ラ1 23:ソ1 24:ラ1 25:ソ1 26:ラ1 27:-3 28:ラ1 29:ソ1 30:ラ1 31:ソ1 32:ラ1 33:-3 34:ラ1 35:ソ1 36:ラ1 37:ソ1 38:ラ1 39:-1 40:ドH1 41:-1 42:ミ6 43:レ1 44:-1 45:レ1 46:ミ1 47:ファ1 48:-3 49:ファ1 50:-1 51:ファ1 52:ソ1 53:ラ1 54:-3 55:ソ1 56:-1 57:ソ1 58:ラ1 59:シ1 60:-1 61:ドH1 62:-1 63:レH6" | |
232 | # "テンポ=7(138)1:ド1 2:ドH1 3:シ1 4:ドH1 5:ミH1 6:ドH1 7:シ1 8:ドH1 9:ド1 10:ドH1 11:ラ#1 12:ドH1 13:ミH1 14:ドH1 15:ラ#1 16:ドH1 17:ド1 18:ドH1 19:ラ1 20:ドH1 21:ミH1 22:ドH1 23:ラ1 24:ドH1 25:ド1 26:ドH1 27:ソ#1 28:ドH1 29:ミH1 30:ドH1 31:ソ#1 32:ドH1" | |
233 | # "テンポ=6(126)1:ソL1 2:-1 3:ド1 4:ミ1 5:ソ1 6:ラ1 7:ソ1 8:ミ1 9:ファ1 10:-1 11:ファ1 12:-1 13:レ4 14:ソL1 15:-1 16:シL1 17:レ1 18:ファ1 19:ラ1 20:ソ1 21:ファ1 22:ミ1 23:-1 24:レ1 25:-1 26:ソ4 27:ソL1 28:-1 29:ド1 30:ミ1 31:ソ1 32:ラ1 33:ソ1 34:ミ1 35:ファ1 36:-1 37:ファ1 38:-1 39:レ4 40:シL1 41:レ1 42:ファ1 43:ラ1 44:ソ1 45:-1 46:シL1 47:-1 48:ド1 49:-1 50:ド1 51:-1 52:ド1 53:-3" | |
234 | ||
235 | # http://www.geocities.co.jp/HeartLand-Namiki/8944/onpu.html | |
236 | # "テンポ4(108)レ5/ファ#1/ソ4/-1/レ3/ミ3/レ2/ミ2/シL1/シL5/-4/-1/ド2/シL2/ラL1/シL2/ラL1/ソL2/ソL3/-1/ソL2/ファ#L2/ソL2/ミ4/レ2/ミ1/レ2/-1/レ5/ファ#1/ソ4/-1/レ3/ミ3/ファ#2/ソ2/レ1/レ5/-4/-1/ド2/シL2/ラL1/シL2/ラL1/ソL2/ソL3/-1/ソL2/レ2/ミ2/レ5/-4/-2/ミ2/ミ2/レ1/ミ3/シL1/シL2/-2/-1/ラL1/シL1/ド1/ラL2/シL1/ド1/シL2/ラL1/ソL2/-4/ソL2/ラL2/シL2/ラL4/シL2/ド2/シL4/ソL2/ソL6/-4" | |
237 | # "テンポ3(96)レ2/ミ2/ラ↓2/ラ↓5/休2/ミ2/レ2/ミ2/ソ↓2/ソ↓5/休4/ラ↓2/シ↓2/ド2/ミ5/休2/ミ2/レ2/ミ5/レ1/ミ5/休2/レ2/ミ2/ラ↓2/ラ↓5/ミ2/ミ2/レ2/ミ2/ソ↓2/ソ↓5/ミ2/休2/ラ↓2/シ↓2/ド2/ミ4/ミ4/ミ2/レ5/ミ1/レ1/ミ5/休2/ミ2/レ2/ド2/ラ↓4/ラ↓4/ラ↓2/レ2/休2/レ2/レ4/レ2/シ↓2/シ↓1/シ↓1/ラ↓7/休4" | |
238 | # "テンポ7(138)レ#2/レ2/レ#2/レ2/レ#4/レ2/レ#4/レ2/レ#2/レ2/レ#4/休2/ラ#↓2/ラ#↓4/レ#2/レ#5/ソ2/ソ5/ラ#2/ラ#4/ソ4/レ#7/休4/ド2/ラ#↓2/ド4/レ4/ラ#↓4/ド4/レ4/レ#4/ド4/レ4/レ#4/ファ6/休2/レ#2/レ2/レ#2/レ2/レ#4/レ2/レ#4/レ2/レ#2/レ2/レ#4/休2/ラ#↓2/ラ#↓4/レ#2/レ#5/ソ2/ソ5/ラ#2/ラ#4/ソ4/レ#7/休4/ド2/ラ#↓2/ド4/レ4/ラ#↓4/ド4/レ2/レ#0/休4/休4/休4" | |
239 | ||
240 | # http://hasu.jp/cmelo/index.html | |
241 | # "テンポ144 ラ2・ シ4 ラ8 ラ4 シ8 ド△4 ド△8 ド△4 レ△8 ミ△4・ ●4・ ラ4 ラ8 ラ4 ソ8 ソ4 ソ8 ラ4 ソ8 ミ4 ソ2・ ●2 ラ4 ラ8 ラ4 ラ8 シ4 シ8 ラ4 シ8 ド△4 ド△8 ド△4 レ△8 ミ△4・ ●4・ ラ4 ラ8 ラ4 ラ8 ソ4 ソ8 ラ4 シ8 ド△全 ●2" | |
242 | # "テンポ144 ファ2・ ソ4 ファ8 ファ4 ファ8 ミ4 ミ8 ミ4 ファ8 ソ4・ ●4・ ファ4 ファ8 ファ4 ファ8 ソ4 ソ8 ソ4 ファ8 ファ4 ミ2・ ●2 ファ4 ファ8 ファ4 ファ8 ソ4 ソ8 ファ4 ファ8 ミ4 ミ8 ミ4 ファ8 ソ4・ ●4・ ファ4 ファ8 ファ4 ファ8 ソ4 ソ8 ソ4 ソ8 ソ全 ●2" | |
243 | # "テンポ144 ファ▽2・ ソ▽2・ ラ▽4・ シ▽4・ ド4・ ソ4・ ファ2・ ソ▽2・ ド2・ ラ4・ ソ4・ ファ2・ ソ▽2・ ラ▽4・ シ▽4・ ド4・ ソ4 ファ#8 ファ2・ ソ▽2・ ド全 ド8 シ▽4 ラ▽#8" | |
244 | ||
245 | function chakumero_conv(str, | |
246 | arr, i, j,note, octave, beat, tr_s, tr_d, score, duration, tie_s) | |
247 | { gsub("\"", "", str) | |
248 | octave = 4; beat = 63 | |
249 | if (match(str, /[0-9]{2,3}/)) | |
250 | beat = substr(str, RSTART, RLENGTH) | |
251 | str = substr(str, RSTART+RLENGTH+1) | |
252 | ||
253 | split("ド|c|レ|d|ミ|e|ファ|f|ソ|g|ラ|a|シ|b|#|#|-|p|休|p|●|p|・|.", tr_s, "|") | |
254 | split("9|12|8|6|7|2.|6|2|5|4.|4|4|3|8.|2|8|1|16|0|1|16|16|8|8|4|4|2|2|全|1", tr_d, "|") | |
255 | ||
256 | split(str, arr, "[ /]") | |
257 | for (i = 1; i <= length(arr); i++) { | |
258 | if (match(arr[i], /:/)) | |
259 | arr[i] = substr(arr[i], RSTART+1) | |
260 | for (j = 1; j <= length(tr_s); j += 2) | |
261 | sub(tr_s[j], tr_s[j+1], arr[i]) | |
262 | for (j = 1; j <= length(tr_d); j += 2) | |
263 | if (sub(tr_d[j], tr_d[j+1], arr[i])) | |
264 | break | |
265 | if (match(arr[i], /[.0-9]+$/)) { | |
266 | score = substr(arr[i], 1, RSTART-1) | |
267 | duration = substr(arr[i], RSTART) | |
268 | } | |
269 | sub("\\^", tie_s, score); tie_s = score | |
270 | if (score ~ /[HL↑↓△▽]/) { | |
271 | score = gensub(/([△▽])#/, "#\\1", 1, score) | |
272 | sub(/[H↑△]/, octave+1, score) | |
273 | sub(/[L↓▽]/, octave-1, score) | |
274 | } | |
275 | note = duration score | |
276 | str = (i == 1) ? note : str "," note | |
277 | } | |
278 | return sprintf("o=%d,b=%d:%s", octave, beat, str) | |
279 | } |