root/lang/actionscript/flmml/trunk/src/com/txt_nifty/sketch/flmml/MTrack.as @ 14833

Revision 14833, 14.4 kB (checked in by tekisuke, 5 years ago)

lang/actionscript/flmml/: 終了処理を再修正。処理の仕方を思い出しました・・・。

Line 
1package com.txt_nifty.sketch.flmml {
2    import de.popforge.audio.output.*;
3
4    public class MTrack {
5        public static const TEMPO_TRACK:int = 0;
6        public static const FIRST_TRACK:int = 1;
7        private var m_bpm:Number;         // beat per minute
8        private var m_spt:Number;         // samples per tick
9        private var m_ch:MChannel;        // channel (instrument)
10        private var m_needle:Number       // delta time
11        private var m_volume:int;         // default volume    (max:127)
12        private var m_gate:Number;        // default gate time (max:1.0)
13        private var m_events:Array;       //
14        private var m_pointer:int;        // current event no.
15        private var m_delta:int;
16        private var m_isEnd:int;
17        private var m_globalTick:uint;
18        private var m_signalCnt:int;
19        private var m_lfoWidth:Number;
20        public  var m_signalInterval:int;
21
22        public function MTrack() {
23            m_isEnd              = 0;
24            m_ch                 = new MChannel();
25            m_needle             = 0.0;
26            playTempo(120);
27            m_volume             = 100;
28            m_gate               = 15/16;
29            m_events             = new Array();
30            m_pointer = 0;
31            m_delta = 0;
32            m_globalTick = 0;
33            m_signalInterval = 96/4; // (quater note = 96ticks)
34            m_signalCnt = 0;
35            m_lfoWidth = 0.0;
36        }
37
38        public function getNumEvents():int {
39            return m_events.length;
40        }
41
42        public function onAudioBufferComplete(samples:Array, signal:MSignal = null):void {
43            var startCnt:int = m_signalCnt;
44            if (signal != null) signal.reset();
45            var sLen:int = samples.length;
46            // first signal
47            if (m_globalTick == 0 && signal != null) {
48                signal.add(0, 0, 0);
49            }
50            for (var i:int = 0; i < sLen;) {
51                // exec events
52                var exec:int = 0;
53                var eLen:int = m_events.length;
54                var e:MEvent;
55                var delta:Number;
56                do {
57                    exec = 0;
58                    if (m_pointer < eLen) {
59                        e = m_events[m_pointer];
60                        delta = e.getDelta() * m_spt;
61                        if (m_needle >= delta) {
62                            //trace(m_pointer+"/global:"+(int)(m_globalTick/m_spt)+"/status:"+e.getStatus()+"/delta:"+delta+"-"+e.getDelta()+"/noteNo:"+e.getNoteNo());
63                            exec = 1;
64                            switch(e.getStatus()) {
65                            case MStatus.NOTE_ON:
66                                m_ch.noteOn(e.getNoteNo(), e.getVelocity());
67                                break;
68                            case MStatus.NOTE_OFF:
69                                m_ch.noteOff();
70                                break;
71                            case MStatus.NOTE:
72                                m_ch.setNoteNo(e.getNoteNo());
73                                break;
74                            case MStatus.VOLUME:
75                                break;
76                            case MStatus.TEMPO:
77                                playTempo(e.getTempo());
78                                break;
79                            case MStatus.FORM:
80                                m_ch.setForm(e.getForm());
81                                break;
82                            case MStatus.ENVELOPE1_AD:
83                                m_ch.setEnvelope1AD(e.getEnvelopeA(), e.getEnvelopeD());
84                                break;
85                            case MStatus.ENVELOPE1_SR:
86                                m_ch.setEnvelope1SR(e.getEnvelopeS(), e.getEnvelopeR());
87                                break;
88                            case MStatus.ENVELOPE2_AD:
89                                m_ch.setEnvelope2AD(e.getEnvelopeA(), e.getEnvelopeD());
90                                break;
91                            case MStatus.ENVELOPE2_SR:
92                                m_ch.setEnvelope2SR(e.getEnvelopeS(), e.getEnvelopeR());
93                                break;
94                            case MStatus.NOISE_FREQ:
95                                m_ch.setNoiseFreq(e.getNoiseFreq());
96                                break;
97                            case MStatus.PWM:
98                                m_ch.setPWM(e.getPWM());
99                                break;
100                            case MStatus.PAN:
101                                m_ch.setPan(e.getPan());
102                                break;
103                            case MStatus.FORMANT:
104                                m_ch.setFormant(e.getVowel());
105                                break;
106                            case MStatus.DETUNE:
107                                m_ch.setDetune(e.getDetune());
108                                break;
109                            case MStatus.LFO_DPCN:
110                                m_ch.setLFODPCN(e.getLFODepth(), e.getLFOConnect());
111                                break;
112                            case MStatus.LFO_WDFM:
113                                m_lfoWidth = e.getLFOWidth() * m_spt;
114                                m_ch.setLFOWDFM(44010.0 / m_lfoWidth, e.getLFOForm());
115                                break;
116                            case MStatus.LFO_DLTM:
117                                m_ch.setLFODLTM(e.getLFODelay() * m_spt, e.getLFOTime() * m_lfoWidth);
118                                break;
119                            case MStatus.LPF_SWTAMT:
120                                m_ch.setLpfSwtAmt(e.getLPFSwt(), e.getLPFAmt());
121                                break;
122                            case MStatus.LPF_FRQRES:
123                                m_ch.setLpfFrqRes(e.getLPFFrq(), e.getLPFRes());
124                                break;
125                            case MStatus.CLOSE:
126                                m_ch.close();
127                                break;
128                            case MStatus.EOT:
129                                m_isEnd = 1;
130                                break;
131                            case MStatus.NOP:
132                                break;
133                            default:
134                                break;
135                            }
136                            m_needle -= delta;
137                            m_pointer++;
138                        }
139                    }
140                } while(exec);
141
142                // create a short wave
143                var di:int;
144                if (m_pointer < eLen) {
145                    e = m_events[m_pointer];
146                    delta = e.getDelta() * m_spt;
147                    di = Math.ceil(delta - m_needle);
148                    if (i + di >= sLen) di = sLen - i;
149                    m_needle += di;
150                    if (signal == null) m_ch.getSamples(samples, i, di);
151                    i += di;
152                }
153                else {
154                    break;
155                }
156
157                // periodic signal
158                if (signal != null) {
159                    m_signalCnt += di;
160                    var intervalSample:int = int(m_signalInterval * m_spt);
161                    while (m_signalCnt >= intervalSample) {
162                        m_globalTick += m_signalInterval;
163                        signal.add(int((intervalSample - startCnt) * (1000.0/44100.0)), m_globalTick, 0);
164                        m_signalCnt -= intervalSample;
165                        startCnt = 0;
166                    }
167                }
168            }
169            if (signal != null) signal.terminate();
170        }
171
172        public function seek(delta:int):void {
173            m_delta += delta;
174            m_globalTick += delta;
175        }
176
177        public function recDelta(e:MEvent):void {
178            e.setDelta(m_delta);
179            m_delta = 0;
180        }
181
182        public function recNote(noteNo:int, len:int, vel:int, keyon:int = 1, keyoff:int = 1):void {
183            var e0:MEvent = new MEvent();
184            if (keyon) {
185                e0.setNoteOn(noteNo, vel);
186            }
187            else {
188                e0.setNote(noteNo);
189            }
190            recDelta(e0);
191            m_events.push(e0);
192            var e1:MEvent = new MEvent();
193            if (keyoff) {
194                var gate:int = (int)(len * m_gate);
195                seek(gate);
196                e1.setNoteOff(noteNo, vel);
197                recDelta(e1);
198                m_events.push(e1);
199                seek(len - gate);
200            }
201            else {
202                seek(len);
203            }
204        }
205
206        public function recRest(len:int):void {
207            seek(len);
208        }
209
210        public function recVolume(vol:int):void {
211            var e:MEvent = new MEvent();
212            recDelta(e);
213            e.setVolume(vol);
214            m_events.push(e);
215        }
216
217        protected function recGlobal(globalTick:uint, e:MEvent):void {
218            var n:int = m_events.length;
219            var preGlobalTick:uint = 0;
220            var tmpArr:Array = new Array();
221            for(var i:int; i < n; i++) {
222                var en:MEvent = m_events[i];
223                var nextTick:uint = preGlobalTick + en.getDelta();
224                if (nextTick >= globalTick) {
225                    en.setDelta(nextTick - globalTick);
226                    e.setDelta(globalTick - preGlobalTick);
227                    m_events.splice(i, 0, e);
228                    //trace("e(TEMPO"+e.getTempo()+") delta="+(globalTick-preGlobalTick));
229                    return;
230                }
231                preGlobalTick = nextTick;
232            }
233            e.setDelta(globalTick-preGlobalTick);
234            m_events.push(e);
235            //trace("e(TEMPO"+e.getTempo()+") delta="+(globalTick-preGlobalTick));
236        }
237
238        public function recTempo(globalTick:uint, tempo:Number):void {
239            var e:MEvent = new MEvent();
240            recDelta(e);
241            e.setTempo(tempo);
242            recGlobal(globalTick, e);
243        }
244
245        public function recEOT():void {
246            var e:MEvent = new MEvent();
247            recDelta(e);
248            e.setEOT();
249            m_events.push(e);
250        }
251
252        public function recGate(gate:Number):void {
253            m_gate = gate;
254        }
255
256        public function recForm(form:int):void {
257            var e:MEvent = new MEvent();
258            recDelta(e);
259            e.setForm(form);
260            m_events.push(e);
261        }
262
263        public function recEnvelope(env:int, attack:int, decay:int, sustain:int, release:int):void {
264            var e:MEvent = new MEvent();
265            recDelta(e);
266            if (env == 1) e.setEnvelope1AD(attack, decay); else e.setEnvelope2AD(attack, decay);
267            m_events.push(e);
268            e = new MEvent();
269            if (env == 1) e.setEnvelope1SR(sustain, release); else e.setEnvelope2SR(sustain, release);
270            m_events.push(e);
271        }
272
273        public function recNoiseFreq(freq:int):void {
274            var e:MEvent = new MEvent();
275            recDelta(e);
276            e.setNoiseFreq(freq);
277            m_events.push(e);
278        }
279
280        public function recPWM(pwm:int):void {
281            var e:MEvent = new MEvent();
282            recDelta(e);
283            e.setPWM(pwm);
284            m_events.push(e);
285        }
286
287        public function recPan(pan:int):void {
288            var e:MEvent = new MEvent();
289            recDelta(e);
290            e.setPan(pan);
291            m_events.push(e);
292        }
293
294        public function recFormant(vowel:int):void {
295            var e:MEvent = new MEvent();
296            recDelta(e);
297            e.setFormant(vowel);
298            m_events.push(e);
299        }
300
301        public function recDetune(d:int):void {
302            var e:MEvent = new MEvent();
303            recDelta(e);
304            e.setDetune(d);
305            m_events.push(e);
306        }
307
308        public function recLFO(depth:int, width:int, form:int, delay:int, time:int):void {
309            var e:MEvent = new MEvent();
310            recDelta(e);
311            e.setLFODPCN(depth, 0);
312            m_events.push(e);
313            e = new MEvent();
314            e.setLFOWDFM(width, form);
315            m_events.push(e);
316            e = new MEvent();
317            e.setLFODLTM(delay, time);
318            m_events.push(e);
319        }
320
321        public function recLPF(swt:int, amt:int, frq:int, res:int):void {
322            var e:MEvent = new MEvent();
323            recDelta(e);
324            e.setLPFSWTAMT(swt, amt);
325            m_events.push(e);
326            e = new MEvent();
327            e.setLPFFRQRES(frq, res);
328            m_events.push(e);
329        }
330
331        public function recClose():void {
332            var e:MEvent = new MEvent();
333            recDelta(e);
334            e.setClose();
335            m_events.push(e);
336        }
337
338        public function isEnd():int {
339            return m_isEnd;
340        }
341
342        public function getRecGlobalTick():uint {
343            return m_globalTick;
344        }
345
346        public function seekTop():void {
347            m_globalTick = 0;
348        }
349
350        public function conduct(trackArr:Array):void {
351            var ni:int = m_events.length;
352            var nj:int = trackArr.length;
353            var globalTick:uint = 0;
354            var i:int, j:int;
355            var e:MEvent;
356            for(i; i < ni; i++) {
357                e = m_events[i];
358                globalTick += e.getDelta();
359                switch(e.getStatus()) {
360                case MStatus.TEMPO:
361                    for (j = FIRST_TRACK; j < nj; j++) {
362                        trackArr[j].recTempo(globalTick, e.getTempo());
363                    }
364                    break;
365                default:
366                    break;
367                }
368            }
369            var maxGlobalTick:int = 0;
370            for (j = FIRST_TRACK; j < nj; j++) {
371                if (maxGlobalTick < trackArr[j].getRecGlobalTick()) maxGlobalTick = trackArr[j].getRecGlobalTick();
372            }
373            e = new MEvent();
374            e.setEOT();
375            recGlobal(maxGlobalTick, e);
376        }
377
378        private function playTempo(bpm:Number):void {
379            m_bpm = bpm;
380            var tps:Number = m_bpm * 96.0 / 60.0; // ticks per second (quater note = 96ticks)
381            m_spt = 44100.0 / tps;              // samples per tick
382            //trace("spt:"+m_spt)
383        }
384    }
385}
Note: See TracBrowser for help on using the browser.