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

Revision 38691, 20.2 kB (checked in by tekisuke, 3 years ago)

ゆみさんの代理コミット

音長のtickカウントでの指定(%)
音長のみのタイ(&)
MML風ポルタメント(*)
MIDI風ポルタメント(@U)
連符({})

Line 
1package com.txt_nifty.sketch.flmml {
2    import __AS3__.vec.Vector;
3        import flash.errors.MemoryError;
4
5    public class MTrack {
6        public static const TEMPO_TRACK:int = 0;
7        public static const FIRST_TRACK:int = 1;
8        public static const DEFAULT_BPM:int = 120;
9        private var m_bpm:Number;         // beat per minute
10        private var m_spt:Number;         // samples per tick
11        private var m_ch:MChannel;        // channel (instrument)
12        private var m_needle:Number       // delta time
13        private var m_volume:int;         // default volume    (max:127)
14        private var m_gate:Number;        // default gate time (max:1.0)
15        private var m_gate2:int;          // gate time 2
16        private var m_events:Array;       //
17        private var m_pointer:int;        // current event no.
18        private var m_delta:int;
19        private var m_isEnd:int;
20        private var m_globalTick:uint;
21        private var m_signalCnt:int;
22        private var m_lfoWidth:Number;
23        private var m_totalMSec:uint;
24        public  var m_signalInterval:int;
25
26        public function MTrack() {
27            m_isEnd              = 0;
28            m_ch                 = new MChannel();
29            m_needle             = 0.0;
30            playTempo(DEFAULT_BPM);
31            m_volume             = 100;
32            recGate(15/16);
33            recGate2(0);
34            m_events             = new Array();
35            m_pointer = 0;
36            m_delta = 0;
37            m_globalTick = 0;
38            m_signalInterval = 96/4; // (quater note = 96ticks)
39            m_signalCnt = 0;
40            m_lfoWidth = 0.0;
41            m_totalMSec = 0;
42        }
43
44        public function getNumEvents():int {
45            return m_events.length;
46        }
47
48        public function onSampleData(samples:Vector.<Number>, start:int, end:int, signal:MSignal = null):void {
49            if (isEnd()) return;
50            var startCnt:int = m_signalCnt;
51            if (signal != null) signal.reset();
52            // first signal
53            if (m_globalTick == 0 && signal != null) {
54                signal.add(0, 0, 0);
55            }
56            for (var i:int = start; i < end;) {
57                // exec events
58                var exec:int = 0;
59                var eLen:int = m_events.length;
60                var e:MEvent;
61                var delta:Number;
62                do {
63                    exec = 0;
64                    if (m_pointer < eLen) {
65                        e = m_events[m_pointer];
66                        delta = e.getDelta() * m_spt;
67                        if (m_needle >= delta) {
68                            //trace(m_pointer+"/global:"+(int)(m_globalTick/m_spt)+"/status:"+e.getStatus()+"/delta:"+delta+"-"+e.getDelta()+"/noteNo:"+e.getNoteNo());
69                            exec = 1;
70                            switch(e.getStatus()) {
71                            case MStatus.NOTE_ON:
72                                m_ch.noteOn(e.getNoteNo(), e.getVelocity());
73                                break;
74                            case MStatus.NOTE_OFF:
75                                m_ch.noteOff();
76                                break;
77                            case MStatus.NOTE:
78                                m_ch.setNoteNo(e.getNoteNo());
79                                break;
80                            case MStatus.VOLUME:
81                                break;
82                            case MStatus.TEMPO:
83                                playTempo(e.getTempo());
84                                break;
85                            case MStatus.FORM:
86                                m_ch.setForm(e.getForm(), e.getSubForm());
87                                break;
88                            case MStatus.ENVELOPE1_ATK:
89                                m_ch.setEnvelope1Atk(e.getEnvelopeA());
90                                break;
91                            case MStatus.ENVELOPE1_ADD:
92                                m_ch.setEnvelope1Point(e.getEnvelopeT(), e.getEnvelopeL());
93                                break;
94                            case MStatus.ENVELOPE1_REL:
95                                m_ch.setEnvelope1Rel(e.getEnvelopeR());
96                                break;
97                            case MStatus.ENVELOPE2_ATK:
98                                m_ch.setEnvelope2Atk(e.getEnvelopeA());
99                                break;
100                            case MStatus.ENVELOPE2_ADD:
101                                m_ch.setEnvelope2Point(e.getEnvelopeT(), e.getEnvelopeL());
102                                break;
103                            case MStatus.ENVELOPE2_REL:
104                                m_ch.setEnvelope2Rel(e.getEnvelopeR());
105                                break;
106                            case MStatus.NOISE_FREQ:
107                                m_ch.setNoiseFreq(e.getNoiseFreq());
108                                break;
109                            case MStatus.PWM:
110                                m_ch.setPWM(e.getPWM());
111                                break;
112                            case MStatus.PAN:
113                                m_ch.setPan(e.getPan());
114                                break;
115                            case MStatus.FORMANT:
116                                m_ch.setFormant(e.getVowel());
117                                break;
118                            case MStatus.DETUNE:
119                                m_ch.setDetune(e.getDetune());
120                                break;
121                            case MStatus.LFO_FMSF:
122                                m_ch.setLFOFMSF(e.getLFOForm(), e.getLFOSubForm());
123                                break;
124                            case MStatus.LFO_DPWD:
125                                m_lfoWidth = e.getLFOWidth() * m_spt;
126                                m_ch.setLFODPWD(e.getLFODepth(), 44100.0 / m_lfoWidth);
127                                break;
128                            case MStatus.LFO_DLTM:
129                                m_ch.setLFODLTM(e.getLFODelay() * m_spt, e.getLFOTime() * m_lfoWidth);
130                                break;
131                            case MStatus.LFO_TARGET:
132                                m_ch.setLFOTarget(e.getLFOTarget());
133                                break;
134                            case MStatus.LPF_SWTAMT:
135                                m_ch.setLpfSwtAmt(e.getLPFSwt(), e.getLPFAmt());
136                                break;
137                            case MStatus.LPF_FRQRES:
138                                m_ch.setLpfFrqRes(e.getLPFFrq(), e.getLPFRes());
139                                break;
140                            case MStatus.VOL_MODE:
141                                m_ch.setVolMode(e.getVolMode());
142                                break;
143                            case MStatus.INPUT:
144                                m_ch.setInput(e.getInputSens(), e.getInputPipe());
145                                break;
146                            case MStatus.OUTPUT:
147                                m_ch.setOutput(e.getOutputMode(), e.getOutputPipe());
148                                break;
149                            case MStatus.EXPRESSION:
150                                m_ch.setExpression(e.getExpression());
151                                break;
152                            case MStatus.RINGMODULATE:
153                                m_ch.setRing(e.getRingSens(), e.getRingInput());
154                                break;
155                            case MStatus.SYNC:
156                                m_ch.setSync(e.getSyncMode(), e.getSyncPipe());
157                                break;
158                                                        case MStatus.PORTAMENTO:
159                                                                m_ch.setPortamento(e.getPorDepth() * 100, e.getPorLen() * m_spt);
160                                                                break;
161                                                        case MStatus.MIDIPORT:
162                                                                m_ch.setMidiPort(e.getMidiPort());
163                                                                break;
164                                                        case MStatus.MIDIPORTRATE:
165                                                                var rate:Number = e.getMidiPortRate();
166                                                                m_ch.setMidiPortRate((8 - (rate * 7.99 / 128)) / rate);
167                                                                break;
168                                                        case MStatus.BASENOTE:
169                                                                m_ch.setPortBase(e.getPortBase() * 100);
170                                                                break;
171                            case MStatus.CLOSE:
172                                m_ch.close();
173                                break;
174                            case MStatus.EOT:
175                                m_isEnd = 1;
176                                break;
177                            case MStatus.NOP:
178                                break;
179                            default:
180                                break;
181                            }
182                            m_needle -= delta;
183                            m_pointer++;
184                        }
185                    }
186                } while(exec);
187
188                // create a short wave
189                var di:int;
190                if (m_pointer < eLen) {
191                    e = m_events[m_pointer];
192                    delta = e.getDelta() * m_spt;
193                    di = Math.ceil(delta - m_needle);
194                    if (i + di >= end) di = end - i;
195                    m_needle += di;
196                    if (signal == null) m_ch.getSamples(samples, end, i, di);
197                    i += di;
198                }
199                else {
200                    break;
201                }
202
203                // periodic signal
204                if (signal != null) {
205                    m_signalCnt += di;
206                    var intervalSample:int = int(m_signalInterval * m_spt);
207                    while (m_signalCnt >= intervalSample) {
208                        m_globalTick += m_signalInterval;
209                        signal.add(int((intervalSample - startCnt) * (1000.0/44100.0)), m_globalTick, 0);
210                        m_signalCnt -= intervalSample;
211                        startCnt = 0;
212                    }
213                }
214            }
215            if (signal != null) signal.terminate();
216        }
217
218        public function seek(delta:int):void {
219            m_delta += delta;
220            m_globalTick += delta;
221        }
222
223        public function recDelta(e:MEvent):void {
224            e.setDelta(m_delta);
225            m_delta = 0;
226        }
227
228        public function recNote(noteNo:int, len:int, vel:int, keyon:int = 1, keyoff:int = 1):void {
229            var e0:MEvent = new MEvent();
230            if (keyon) {
231                e0.setNoteOn(noteNo, vel);
232            }
233            else {
234                e0.setNote(noteNo);
235            }
236            recDelta(e0);
237            m_events.push(e0);
238            var e1:MEvent = new MEvent();
239            if (keyoff) {
240                var gate:int;
241                gate = (int)(len * m_gate) - m_gate2;
242                if (gate <= 0) gate = 0;
243                seek(gate);
244                e1.setNoteOff(noteNo, vel);
245                recDelta(e1);
246                m_events.push(e1);
247                seek(len - gate);
248            }
249            else {
250                seek(len);
251            }
252        }
253
254        public function recRest(len:int):void {
255            seek(len);
256        }
257        public function recRestMSec(msec:int):void {
258            var len:int = msec * 44100 / (m_spt * 1000);
259            seek(len);
260        }
261
262        public function recVolume(vol:int):void {
263            var e:MEvent = new MEvent();
264            recDelta(e);
265            e.setVolume(vol);
266            m_events.push(e);
267        }
268
269        protected function recGlobal(globalTick:uint, e:MEvent):void {
270            var n:int = m_events.length;
271            var preGlobalTick:uint = 0;
272            var tmpArr:Array = new Array();
273            for(var i:int; i < n; i++) {
274                var en:MEvent = m_events[i];
275                var nextTick:uint = preGlobalTick + en.getDelta();
276                if (nextTick > globalTick || (nextTick == globalTick && en.getStatus() != MStatus.TEMPO)) {
277                    en.setDelta(nextTick - globalTick);
278                    e.setDelta(globalTick - preGlobalTick);
279                    m_events.splice(i, 0, e);
280                    //trace("e(TEMPO"+e.getTempo()+") delta="+(globalTick-preGlobalTick));
281                    return;
282                }
283                preGlobalTick = nextTick;
284            }
285            e.setDelta(globalTick-preGlobalTick);
286            m_events.push(e);
287            //trace("e(TEMPO"+e.getTempo()+") delta="+(globalTick-preGlobalTick));
288        }
289
290        public function recTempo(globalTick:uint, tempo:Number):void {
291            var e:MEvent = new MEvent();
292            recDelta(e);
293            e.setTempo(tempo);
294            recGlobal(globalTick, e);
295        }
296
297        public function recEOT():void {
298            var e:MEvent = new MEvent();
299            recDelta(e);
300            e.setEOT();
301            m_events.push(e);
302        }
303
304        public function recGate(gate:Number):void {
305            m_gate = gate;
306        }
307
308        public function recGate2(gate2:int):void {
309            if (gate2 < 0) gate2 = 0;
310            m_gate2 = gate2;
311        }
312
313        public function recForm(form:int, sub:int):void {
314            var e:MEvent = new MEvent();
315            recDelta(e);
316            e.setForm(form, sub);
317            m_events.push(e);
318        }
319
320        public function recEnvelope(env:int, attack:int, times:Vector.<int>, levels:Vector.<int>, release:int):void {
321            var e:MEvent = new MEvent();
322            recDelta(e);
323            if (env == 1) e.setEnvelope1Atk(attack); else e.setEnvelope2Atk(attack);
324            m_events.push(e);
325            for(var i:int = 0, pts:int = times.length; i < pts; i++){
326                e = new MEvent();
327                        if (env == 1) e.setEnvelope1Point(times[i], levels[i]); else e.setEnvelope2Point(times[i], levels[i]);
328                m_events.push(e);
329            }
330            e = new MEvent();
331            if (env == 1) e.setEnvelope1Rel(release); else e.setEnvelope2Rel(release);
332            m_events.push(e);
333        }
334
335        public function recNoiseFreq(freq:int):void {
336            var e:MEvent = new MEvent();
337            recDelta(e);
338            e.setNoiseFreq(freq);
339            m_events.push(e);
340        }
341
342        public function recPWM(pwm:int):void {
343            var e:MEvent = new MEvent();
344            recDelta(e);
345            e.setPWM(pwm);
346            m_events.push(e);
347        }
348
349        public function recPan(pan:int):void {
350            var e:MEvent = new MEvent();
351            recDelta(e);
352            e.setPan(pan);
353            m_events.push(e);
354        }
355
356        public function recFormant(vowel:int):void {
357            var e:MEvent = new MEvent();
358            recDelta(e);
359            e.setFormant(vowel);
360            m_events.push(e);
361        }
362
363        public function recDetune(d:int):void {
364            var e:MEvent = new MEvent();
365            recDelta(e);
366            e.setDetune(d);
367            m_events.push(e);
368        }
369
370        public function recLFO(depth:int, width:int, form:int, subform:int, delay:int, time:int, target:int):void {
371            var e:MEvent = new MEvent();
372            recDelta(e);
373            e.setLFOFMSF(form, subform);
374            m_events.push(e);
375            e = new MEvent();
376            e.setLFODPWD(depth, width);
377            m_events.push(e);
378            e = new MEvent();
379            e.setLFODLTM(delay, time);
380            m_events.push(e);
381            e = new MEvent();
382            e.setLFOTarget(target);
383            m_events.push(e);
384        }
385
386        public function recLPF(swt:int, amt:int, frq:int, res:int):void {
387            var e:MEvent = new MEvent();
388            recDelta(e);
389            e.setLPFSWTAMT(swt, amt);
390            m_events.push(e);
391            e = new MEvent();
392            e.setLPFFRQRES(frq, res);
393            m_events.push(e);
394        }
395
396        public function recVolMode(m:int): void {
397            var e:MEvent = new MEvent();
398            recDelta(e);
399            e.setVolMode(m);
400            m_events.push(e);
401        }
402
403        public function recInput(sens:int, pipe:int):void {
404            var e:MEvent = new MEvent();
405            recDelta(e);
406            e.setInput(sens, pipe);
407            m_events.push(e);
408        }
409
410        public function recOutput(mode:int, pipe:int):void {
411            var e:MEvent = new MEvent();
412            recDelta(e);
413            e.setOutput(mode, pipe);
414            m_events.push(e);
415        }
416
417        public function recExpression(ex:int):void {
418            var e:MEvent = new MEvent();
419            recDelta(e);
420            e.setExpression(ex);
421            m_events.push(e);
422        }
423       
424        public function recRing(sens:int, pipe:int):void {
425                var e:MEvent = new MEvent();
426                recDelta(e);
427                e.setRing(sens, pipe);
428                m_events.push(e);
429        }
430       
431        public function recSync(mode:int, pipe:int):void {
432                var e:MEvent = new MEvent();
433                recDelta(e);
434                e.setSync(mode, pipe);
435                m_events.push(e);
436        }
437
438        public function recClose():void {
439            var e:MEvent = new MEvent();
440            recDelta(e);
441            e.setClose();
442            m_events.push(e);
443        }
444
445                public function recPortamento(depth:int, len:int):void {
446            var e:MEvent = new MEvent();
447            recDelta(e);
448            e.setPortamento(depth, len);
449            m_events.push(e);
450                }
451               
452                public function recMidiPort(mode:int):void {
453                        var e:MEvent = new MEvent();
454                        recDelta(e);
455                        e.setMidiPort(mode);
456                        m_events.push(e);
457                }
458               
459                public function recMidiPortRate(rate:int):void {
460                        var e:MEvent = new MEvent();
461                        recDelta(e);
462                        e.setMidiPortRate(rate);
463                        m_events.push(e);
464                }
465
466                public function recPortBase(base:int):void {
467                        var e:MEvent = new MEvent();
468                        recDelta(e);
469                        e.setPortBase(base);
470                        m_events.push(e);
471                }
472
473        public function isEnd():int {
474            return m_isEnd;
475        }
476
477        public function getRecGlobalTick():uint {
478            return m_globalTick;
479        }
480
481        public function seekTop():void {
482            m_globalTick = 0;
483        }
484
485        public function conduct(trackArr:Array):void {
486            var ni:int = m_events.length;
487            var nj:int = trackArr.length;
488            var globalTick:uint = 0;
489            var globalSample:uint = 0;
490            var spt:Number = calcSpt(DEFAULT_BPM);
491            var i:int, j:int;
492            var e:MEvent;
493            for(i; i < ni; i++) {
494                e = m_events[i];
495                globalTick += e.getDelta();
496                globalSample += e.getDelta() * spt;
497                switch(e.getStatus()) {
498                case MStatus.TEMPO:
499                    spt = calcSpt(e.getTempo());
500                    for (j = FIRST_TRACK; j < nj; j++) {
501                        trackArr[j].recTempo(globalTick, e.getTempo());
502                    }
503                    break;
504                default:
505                    break;
506                }
507            }
508            var maxGlobalTick:int = 0;
509            for (j = FIRST_TRACK; j < nj; j++) {
510                if (maxGlobalTick < trackArr[j].getRecGlobalTick()) maxGlobalTick = trackArr[j].getRecGlobalTick();
511            }
512            e = new MEvent();
513            e.setClose();
514            recGlobal(maxGlobalTick, e);
515            globalSample += (maxGlobalTick - globalTick) * spt;
516
517            recRestMSec(3000);
518            recEOT();
519            globalSample += 3 * 44100;
520
521            m_totalMSec = globalSample*1000/44100;
522        }
523        // calc number of samples per tick
524        private function calcSpt(bpm:Number):Number {
525            var tps:Number = bpm * 96.0 / 60.0; // ticks per second (quater note = 96ticks)
526            return 44100.0 / tps;              // samples per tick
527        }
528        // set tempo
529        private function playTempo(bpm:Number):void {
530            m_bpm = bpm;
531            m_spt = calcSpt(bpm);
532            //trace("spt:"+m_spt)
533        }
534        public function getTotalMSec():uint {
535            return m_totalMSec;
536        }
537        public function getTotalTimeStr():String {
538            var sec:int = Math.ceil(Number(m_totalMSec) / 1000);
539            var smin:String = "0" + int(sec / 60);
540            var ssec:String = "0" + (sec % 60);
541            return smin.substr(smin.length-2, 2) + ":" + ssec.substr(ssec.length-2, 2);
542        }
543    }
544}
Note: See TracBrowser for help on using the browser.