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

Revision 447, 8.6 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
4    public class MTrack {
5        private var m_bpm:Number;     // beat per minute
6        private var m_spt:Number;     // samples per tick
7        private var m_ch:MChannel;            // channel (instrument)
8        private var m_needle:Number           // delta time
9        private var m_volume:int;             // default volume    (max:127)
10        private var m_gate:Number;            // default gate time (max:1.0)
11        private var m_events:Array;           //
12        private var m_pointer:int;            // current event no.
13        private var m_delta:int;
14        private var m_isEnd:int;
15        private var m_globalTick:uint;
16        private var m_signalCnt:int;
17        public  var m_signalInterval:int;
18       
19        public function MTrack() {
20            m_isEnd              = 0;
21            m_ch                 = new MChannel();
22            m_needle             = 0.0;
23            playTempo(120);
24            m_volume             = 100;
25            m_gate               = 15/16;
26            m_events             = new Array();
27            m_pointer = 0;
28            m_delta = 0;
29            m_globalTick = 0;
30            m_signalInterval = 96/4; // (quater note = 96ticks)
31            m_signalCnt = 0;
32        }
33
34        public function onAudioBufferComplete(samples:Array, signal:MSignal = null):void {
35            var startCnt:int = m_signalCnt;
36            if (signal != null) signal.reset();
37            var sLen:int = samples.length;
38            // first signal
39            if (m_globalTick == 0 && signal != null) {
40                signal.add(0, 0, 0);
41            }
42            for (var i:int = 0; i < sLen;) {
43                // exec events
44                var exec:int = 0;
45                var eLen:int = m_events.length;
46                var e:MEvent;
47                var delta:Number;
48                do {
49                    exec = 0;
50                    if (m_pointer < eLen) {
51                        e = m_events[m_pointer];
52                        delta = e.getDelta() * m_spt;
53                        if (m_needle >= delta) {
54                            //trace(m_pointer+"/global:"+(int)(m_globalTick/m_spt)+"/status:"+e.getStatus()+"/delta:"+delta+"-"+e.getDelta()+"/noteNo:"+e.getNoteNo());
55                            exec = 1;
56                            switch(e.getStatus()) {
57                            case MStatus.NOTE_ON:
58                                m_ch.noteOn(MEvent.getFrequency(e.getNoteNo()), e.getVelocity());
59                                break;
60                            case MStatus.NOTE_OFF:
61                                m_ch.noteOff();
62                                break;
63                            case MStatus.NOTE:
64                                m_ch.setFrequency(MEvent.getFrequency(e.getNoteNo()));
65                                break;
66                            case MStatus.VOLUME:
67                                break;
68                            case MStatus.TEMPO:
69                                playTempo(e.getTempo());
70                                break;
71                            case MStatus.FORM:
72                                m_ch.setForm(e.getForm());
73                                break;
74                            case MStatus.ENVELOPE_AD:
75                                m_ch.setEnvelopeAD(e.getEnvelopeA(), e.getEnvelopeD());
76                                break;
77                            case MStatus.ENVELOPE_SR:
78                                m_ch.setEnvelopeSR(e.getEnvelopeS(), e.getEnvelopeR());
79                                break;
80                            case MStatus.NOISE_FREQ:
81                                m_ch.setNoiseFreq(e.getNoiseFreq());
82                                break;
83                            case MStatus.PWM:
84                                m_ch.setPWM(e.getPWM());
85                                break;
86                            case MStatus.EOT:
87                                m_ch.noteOff();
88                                m_isEnd = 1;
89                                break;
90                            case MStatus.NOP:
91                                break;
92                            default:
93                                break;
94                            }
95                            m_needle -= delta;
96                            m_pointer++;
97                        }
98                    }
99                } while(exec);
100
101                // create a short wave
102                var di:int;
103                if (m_pointer < eLen) {
104                    e = m_events[m_pointer];
105                    delta = e.getDelta() * m_spt;
106                    di = Math.ceil(delta - m_needle);
107                    if (i + di >= sLen) di = sLen - i;
108                    m_needle += di;
109                    m_ch.getSamples(samples, i, di);
110                    i += di;
111                }
112                else {
113                    break;
114                }
115
116                // periodic signal
117                if (signal != null) {
118                    m_signalCnt += di;
119                    var intervalSample:int = int(m_signalInterval * m_spt);
120                    while (m_signalCnt >= intervalSample) {
121                        m_globalTick += m_signalInterval;
122                        signal.add(int((intervalSample - startCnt) * (1000.0/44100.0)), m_globalTick, 0);
123                        m_signalCnt -= intervalSample;
124                        startCnt = 0;
125                    }
126                }
127            }
128            if (signal != null) signal.terminate();
129        }
130
131        public function seek(delta:int):void {
132            m_delta += delta;
133        }
134
135        public function recDelta(e:MEvent):void {
136            e.setDelta(m_delta);
137            m_delta = 0;
138        }
139
140        public function recNote(noteNo:int, len:int, vel:int, keyon:int = 1, keyoff:int = 1):void {
141            var e0:MEvent = new MEvent();
142            if (keyon) {
143                e0.setNoteOn(noteNo, vel);
144            }
145            else {
146                e0.setNote(noteNo);
147            }
148            recDelta(e0);
149            m_events.push(e0);
150            var e1:MEvent = new MEvent();
151            if (keyoff) {
152                var gate:int = (int)(len * m_gate);
153                seek(gate);
154                e1.setNoteOff(noteNo, vel);
155                recDelta(e1);
156                m_events.push(e1);
157                seek(len - gate);
158            }
159            else {
160                seek(len);
161            }
162        }
163
164        public function recRest(len:int):void {
165            seek(len);
166        }
167
168        public function recVolume(vol:int):void {
169            var e:MEvent = new MEvent();
170            recDelta(e);
171            e.setVolume(vol);
172            m_events.push(e);
173        }
174
175        public function recTempo(tempo:Number):void {
176            var e:MEvent = new MEvent();
177            recDelta(e);
178            e.setTempo(tempo);
179            m_events.push(e);
180        }
181
182        public function recEOT():void {
183            var e:MEvent = new MEvent();
184            recDelta(e);
185            e.setEOT();
186            m_events.push(e);
187        }
188
189        public function recGate(gate:Number):void {
190            m_gate = gate;
191        }
192
193        public function recForm(form:int):void {
194            var e:MEvent = new MEvent();
195            recDelta(e);
196            e.setForm(form);
197            m_events.push(e);
198        }
199
200        public function recEnvelope(attack:int, decay:int, sustain:int, release:int):void {
201            var e:MEvent = new MEvent();
202            recDelta(e);
203            e.setEnvelopeAD(attack, decay);
204            m_events.push(e);
205            e = new MEvent();
206            e.setEnvelopeSR(sustain, release);
207            m_events.push(e);
208        }
209
210        public function recNoiseFreq(freq:int):void {
211            var e:MEvent = new MEvent();
212            recDelta(e);
213            e.setNoiseFreq(freq);
214            m_events.push(e);
215        }
216
217        public function recPWM(pwm:int):void {
218            var e:MEvent = new MEvent();
219            recDelta(e);
220            e.setPWM(pwm);
221            m_events.push(e);
222        }
223
224        public function isEnd():int {
225            return m_isEnd;
226        }
227
228        private function playTempo(bpm:Number):void {
229            m_bpm = bpm;
230            var tps:Number = m_bpm * 96.0 / 60.0; // ticks per second (quater note = 96ticks)
231            m_spt = 44100.0 / tps;              // samples per tick
232            //trace("spt:"+m_spt)
233        }
234    }
235}
Note: See TracBrowser for help on using the browser.