root/lang/javascript/jsmml/trunk/vendor/flmml/com/txt_nifty/sketch/flmml/MML.as @ 447

Revision 447, 7.8 kB (checked in by secondlife, 6 years ago)

lang/javascript/jsmml: release 1.0.0, include flmml source.

Line 
1package com.txt_nifty.sketch.flmml {
2        import de.popforge.audio.output.*;
3        import flash.events.EventDispatcher;
4
5        public class MML extends EventDispatcher {
6                protected var m_sequencer:MSequencer;
7                protected var m_tracks:Array;
8                protected var m_string:String;
9                protected var m_trackNo:int;
10                protected var m_octave:int;
11                protected var m_velocity:int;           // default velocity
12                protected var m_length:int;                     // default length
13                protected var m_tempo:int;
14                protected var m_letter:int;
15                protected var m_keyoff:int;
16                protected var m_gate:int;
17                protected var m_maxGate:int;
18                protected var m_form:int;
19
20                public function MML() {
21                        m_sequencer = new MSequencer();
22                }
23
24                public function set onSignal(func:Function):void {
25                        // ex) function func(globalTick:uint, event:int):void {}
26                        m_sequencer.onSignal = func;
27                }
28
29                public function setSignalInterval(interval:int):void {
30                        m_sequencer.setSignalInterval(interval);
31                }
32
33                protected function len2tick(len:int):int {
34                        if (len == 0) len = m_length;
35                        return 384/len;
36                }
37               
38                protected function note(noteNo:int):void {
39                        //trace("note"+noteNo);
40                        noteNo += getKeySig();
41                        var len:int;
42                        len = getUInt(m_length);
43                        var tick:int = len2tick(len);
44                        tick = getDot(tick);
45                        var keyon:int = (m_keyoff == 0) ? 0 : 1;
46                        m_keyoff = 1;
47                        if (getChar() == '&') {
48                                m_letter++;
49                                m_keyoff = 0;
50                        }
51                        m_tracks[m_trackNo].recNote(noteNo + m_octave*12, tick, m_velocity, keyon, m_keyoff);
52                }
53
54                protected function rest():void {
55                        //trace("rest");
56                        var len:int;
57                        len = getUInt(m_length);
58                        var tick:int = len2tick(len);
59                        tick = getDot(tick);
60                        m_tracks[m_trackNo].recRest(tick);
61                }
62               
63                protected function atmark():void {
64                        var c:String = getChar();
65                        var o:int = 1, a:int = 0, d:int = 64, s:int = 32, r:int = 0;
66                        switch(c) {
67                        case 'e':
68                                m_letter++;
69                                o = getUInt(o);
70                                if (getChar() == ',') m_letter++;
71                                a = getUInt(a);
72                                if (getChar() == ',') m_letter++;
73                                d = getUInt(d);
74                                if (getChar() == ',') m_letter++;
75                                s = getUInt(s);
76                                if (getChar() == ',') m_letter++;
77                                r = getUInt(r);
78                                //trace("A"+a+",D"+d+",S"+s+",R"+r);
79                                m_tracks[m_trackNo].recEnvelope(a, d, s, r);
80                                break;
81            case 'n':
82                m_letter++;
83                o = getUInt(0);
84                if (o < 0 || o > 127) o = 0;
85                m_tracks[m_trackNo].recNoiseFreq(o);
86                break;
87            case 'w':
88                m_letter++;
89                o = getUInt(50);
90                if (o < 1) o = 1;
91                if (o > 99) o = 99;
92                m_tracks[m_trackNo].recPWM(o);
93                break;
94                        default:
95                                m_form = getUInt(m_form);
96                                m_tracks[m_trackNo].recForm(m_form);
97                                break;
98                        }
99                }
100
101                protected function firstLetter():void {
102                        var c:String = getCharNext();
103                        var i:int;
104                        switch(c) {
105                        case "c": note(0);      break;
106                        case "d": note(2);      break;
107                        case "e": note(4);      break;
108                        case "f": note(5);      break;
109                        case "g": note(7);      break;
110                        case "a": note(9);      break;
111                        case "b": note(11); break;
112                        case "r": rest(); break;
113                        case "o":
114                                m_octave = getUInt(m_octave);
115                                if (m_octave < -2) m_octave = -2;
116                                if (m_octave >  8) m_octave =  8;
117                                break;
118                        case "v":
119                                m_velocity = getUInt(m_velocity) * 8 + 7;
120                                if (m_velocity > 127) m_velocity = 127;
121                                break;
122                        case "l":
123                                m_length = getUInt(m_length);
124                                if (m_length == 0) m_length = 4;
125                                break;
126                        case "t":
127                                m_tempo = getUInt(m_tempo);
128                                if (m_tempo == 0) m_tempo = 1;
129                                m_tracks[m_trackNo].recTempo(m_tempo);
130                                break;
131                        case "q":
132                                m_gate = getUInt(m_gate);
133                                m_tracks[m_trackNo].recGate(m_gate / m_maxGate);
134                                break;
135                        case "<" :
136                                m_octave++;
137                                break;
138                        case ">":
139                                m_octave--;
140                                break;
141                        case ';':
142                                //trace("nexttrack");
143                                m_tracks[++m_trackNo] = createTrack();
144                                m_sequencer.connect(m_tracks[m_trackNo]);
145                                break;
146                        case '@':
147                                atmark();
148                                break;
149                        default:
150                                break;
151                        }
152                }
153
154                protected function getCharNext():String {
155                        var c:String = '';
156                        do {
157                                c = m_string.charAt(m_letter++);
158                        } while (c == ' ' && m_letter < m_string.length);
159                        return c;
160                }
161
162                protected function getChar():String {
163                        var l:int = m_letter;
164                        var c:String = '';
165                        do {
166                                c = m_string.charAt(l++);
167                        } while (c == ' ' && l < m_string.length);
168                        return c;
169                }
170
171                protected function getKeySig():int {
172                        var k:int = 0;
173                        var f:int = 1;
174                        while(f) {
175                                var c:String = getChar();
176                                switch(c) {
177                                case "+": case "#": k++; m_letter++; break;
178                                case "-":                       k--; m_letter++; break;
179                                default: f = 0; break;
180                                }
181                        }
182                        return k;
183                }
184
185                protected function getUInt(def:int):int {
186                        var ret:int = 0;
187                        var l:int = m_letter;
188                        var f:int = 1;
189                        while(f) {
190                                var c:String = getChar();
191                                switch(c) {
192                                case '0': ret = ret * 10 + 0; m_letter++; break;
193                                case '1': ret = ret * 10 + 1; m_letter++; break;
194                                case '2': ret = ret * 10 + 2; m_letter++; break;
195                                case '3': ret = ret * 10 + 3; m_letter++; break;
196                                case '4': ret = ret * 10 + 4; m_letter++; break;
197                                case '5': ret = ret * 10 + 5; m_letter++; break;
198                                case '6': ret = ret * 10 + 6; m_letter++; break;
199                                case '7': ret = ret * 10 + 7; m_letter++; break;
200                                case '8': ret = ret * 10 + 8; m_letter++; break;
201                                case '9': ret = ret * 10 + 9; m_letter++; break;
202                                default: f = 0; break;
203                                }
204                        }
205                        return (m_letter == l) ? def : ret;
206                }
207
208                protected function getDot(tick:int):int {
209                        var c:String = getChar();
210                        while(c == '.') {
211                                m_letter++;
212                                tick *= 1.5;
213                                c = getChar();
214                        }
215                        return tick;
216                }
217
218                public function createTrack():MTrack {
219                        return new MTrack();
220                }
221               
222                protected function process():void {
223                        m_letter = 0;
224                        while(m_letter < m_string.length) {
225                                firstLetter();
226                        }
227                }
228
229                protected function preProcess(str:String):void {
230                        m_string = str.toLowerCase();
231                        m_letter = 0;
232                        var repeat:Array = new Array();
233                        var origin:Array = new Array();
234                        var start:Array = new Array();
235                        var last:Array = new Array();
236                        var nest:int = -1;
237                        while(m_letter < m_string.length) {
238                                var c:String = getCharNext();
239                                switch(c) {
240                                case '/':
241                                        if (getChar() == ':') {
242                                                m_letter++;
243                                                origin[++nest] = m_letter - 2;
244                                                repeat[nest] = getUInt(2);
245                                                start[nest] = m_letter;
246                                                last[nest] = -1;
247                                        }
248                                        else {
249                                                last[nest] = m_letter - 1;
250                                                m_string = m_string.substring(0, m_letter-1) + m_string.substring(m_letter);
251                                        }
252                                        break;
253                                case ':':
254                                        if (getChar() == '/' && nest >= 0) {
255                                                m_letter++;
256                                                var contents:String = m_string.substring(start[nest], m_letter - 2);
257                                                var newstr:String = m_string.substring(0, origin[nest]);
258                                                for (var i:int = 0; i < repeat[nest]; i++) {
259                                                        if (i < repeat[nest]-1 || last[nest] < 0) newstr += contents;
260                                                        else newstr += m_string.substring(start[nest], last[nest]);
261                                                }
262                                                newstr += m_string.substring(m_letter);
263                                                m_string = newstr;
264                                                nest--;
265                                        }
266                                        break;
267                                default:
268                                        break;
269                                }
270                        }
271                }
272
273                public function play(str:String):void {
274                        m_sequencer.disconnectAll();
275                        m_tracks = new Array();
276                        m_tracks[0] = createTrack();
277                        m_sequencer.connect(m_tracks[0]);
278
279                        m_trackNo = 0;
280                        m_octave = 4;
281                        m_velocity = 100;
282                        m_length = 4;
283                        m_tempo  = 120;
284                        m_keyoff = 1;
285                        m_gate = 15;
286                        m_maxGate = 16;
287                        m_form = MOscillator.PULSE;
288
289                        preProcess(str);
290                        process();
291
292                        // add ends of tracks
293                        for(var i:int = 0; i < m_tracks.length; i++) {
294                                m_tracks[i].recRest(384);
295                                m_tracks[i].recEOT();
296                        }
297                        // play start
298                        m_sequencer.play();
299                }
300
301                public function getGlobalTick():uint {
302                        return m_sequencer.getGlobalTick();
303                }
304
305                public function isPlaying():Boolean {
306                        return m_sequencer.isPlaying();
307                }
308        }
309}
Note: See TracBrowser for help on using the browser.