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

Revision 38797, 22.7 kB (checked in by tekisuke, 2 years ago)

@aloerinさんの代理コミット。
#USING POLYによるポリフォニック(複数発音)指定が追加されました。
その他、#TITLE, #COMMENT, #ARTIST, #CODINGなど各種情報を埋め込めるようになりました。

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:IChannel;        // 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                private var m_polyFound:Boolean;
26                private var m_chordBegin:uint;
27                private var m_chordEnd:uint;
28                private var m_chordMode:Boolean;
29
30        public function MTrack() {
31            m_isEnd              = 0;
32            m_ch                 = new MChannel();
33            m_needle             = 0.0;
34                        m_polyFound                      = false;
35            playTempo(DEFAULT_BPM);
36            m_volume             = 100;
37            recGate(15.0/16.0);
38            recGate2(0);
39            m_events             = new Array();
40            m_pointer = 0;
41            m_delta = 0;
42            m_globalTick = 0;
43            m_signalInterval = 96/4; // (quater note = 96ticks)
44            m_signalCnt = 0;
45            m_lfoWidth = 0.0;
46            m_totalMSec = 0;
47                        m_chordBegin = 0;
48                        m_chordEnd = 0;
49                        m_chordMode = false;
50        }
51
52        public function getNumEvents():int {
53            return m_events.length;
54        }
55
56        public function onSampleData(samples:Vector.<Number>, start:int, end:int, signal:MSignal = null):void {
57            if (isEnd()) return;
58            var startCnt:int = m_signalCnt;
59            if (signal != null) signal.reset();
60            // first signal
61            if (m_globalTick == 0 && signal != null) {
62                signal.add(0, 0, 0);
63            }
64            for (var i:int = start; i < end;) {
65                // exec events
66                var exec:int = 0;
67                var eLen:int = m_events.length;
68                var e:MEvent;
69                var delta:Number;
70                do {
71                    exec = 0;
72                    if (m_pointer < eLen) {
73                        e = m_events[m_pointer];
74                        delta = e.getDelta() * m_spt;
75                        if (m_needle >= delta) {
76                            //trace(m_pointer+"/global:"+(int)(m_globalTick/m_spt)+"/status:"+e.getStatus()+"/delta:"+delta+"-"+e.getDelta()+"/noteNo:"+e.getNoteNo());
77                            exec = 1;
78                            switch(e.getStatus()) {
79                            case MStatus.NOTE_ON:
80                                m_ch.noteOn(e.getNoteNo(), e.getVelocity());
81                                break;
82                            case MStatus.NOTE_OFF:
83                                m_ch.noteOff(e.getNoteNo());
84                                break;
85                            case MStatus.NOTE:
86                                m_ch.setNoteNo(e.getNoteNo());
87                                break;
88                            case MStatus.VOLUME:
89                                break;
90                            case MStatus.TEMPO:
91                                playTempo(e.getTempo());
92                                break;
93                            case MStatus.FORM:
94                                m_ch.setForm(e.getForm(), e.getSubForm());
95                                break;
96                            case MStatus.ENVELOPE1_ATK:
97                                m_ch.setEnvelope1Atk(e.getEnvelopeA());
98                                break;
99                            case MStatus.ENVELOPE1_ADD:
100                                m_ch.setEnvelope1Point(e.getEnvelopeT(), e.getEnvelopeL());
101                                break;
102                            case MStatus.ENVELOPE1_REL:
103                                m_ch.setEnvelope1Rel(e.getEnvelopeR());
104                                break;
105                            case MStatus.ENVELOPE2_ATK:
106                                m_ch.setEnvelope2Atk(e.getEnvelopeA());
107                                break;
108                            case MStatus.ENVELOPE2_ADD:
109                                m_ch.setEnvelope2Point(e.getEnvelopeT(), e.getEnvelopeL());
110                                break;
111                            case MStatus.ENVELOPE2_REL:
112                                m_ch.setEnvelope2Rel(e.getEnvelopeR());
113                                break;
114                            case MStatus.NOISE_FREQ:
115                                m_ch.setNoiseFreq(e.getNoiseFreq());
116                                break;
117                            case MStatus.PWM:
118                                m_ch.setPWM(e.getPWM());
119                                break;
120                            case MStatus.PAN:
121                                m_ch.setPan(e.getPan());
122                                break;
123                            case MStatus.FORMANT:
124                                m_ch.setFormant(e.getVowel());
125                                break;
126                            case MStatus.DETUNE:
127                                m_ch.setDetune(e.getDetune());
128                                break;
129                            case MStatus.LFO_FMSF:
130                                m_ch.setLFOFMSF(e.getLFOForm(), e.getLFOSubForm());
131                                break;
132                            case MStatus.LFO_DPWD:
133                                m_lfoWidth = e.getLFOWidth() * m_spt;
134                                m_ch.setLFODPWD(e.getLFODepth(), 44100.0 / m_lfoWidth);
135                                break;
136                            case MStatus.LFO_DLTM:
137                                m_ch.setLFODLTM(e.getLFODelay() * m_spt, e.getLFOTime() * m_lfoWidth);
138                                break;
139                            case MStatus.LFO_TARGET:
140                                m_ch.setLFOTarget(e.getLFOTarget());
141                                break;
142                            case MStatus.LPF_SWTAMT:
143                                m_ch.setLpfSwtAmt(e.getLPFSwt(), e.getLPFAmt());
144                                break;
145                            case MStatus.LPF_FRQRES:
146                                m_ch.setLpfFrqRes(e.getLPFFrq(), e.getLPFRes());
147                                break;
148                            case MStatus.VOL_MODE:
149                                m_ch.setVolMode(e.getVolMode());
150                                break;
151                            case MStatus.INPUT:
152                                m_ch.setInput(e.getInputSens(), e.getInputPipe());
153                                break;
154                            case MStatus.OUTPUT:
155                                m_ch.setOutput(e.getOutputMode(), e.getOutputPipe());
156                                break;
157                            case MStatus.EXPRESSION:
158                                m_ch.setExpression(e.getExpression());
159                                break;
160                            case MStatus.RINGMODULATE:
161                                m_ch.setRing(e.getRingSens(), e.getRingInput());
162                                break;
163                            case MStatus.SYNC:
164                                m_ch.setSync(e.getSyncMode(), e.getSyncPipe());
165                                break;
166                                                        case MStatus.PORTAMENTO:
167                                                                m_ch.setPortamento(e.getPorDepth() * 100, e.getPorLen() * m_spt);
168                                                                break;
169                                                        case MStatus.MIDIPORT:
170                                                                m_ch.setMidiPort(e.getMidiPort());
171                                                                break;
172                                                        case MStatus.MIDIPORTRATE:
173                                                                var rate:Number = e.getMidiPortRate();
174                                                                m_ch.setMidiPortRate((8 - (rate * 7.99 / 128)) / rate);
175                                                                break;
176                                                        case MStatus.BASENOTE:
177                                                                m_ch.setPortBase(e.getPortBase() * 100);
178                                                                break;
179                                                        case MStatus.POLY:
180                                                                m_ch.setVoiceLimit(e.getVoiceCount());
181                                                                break;
182                                                        case MStatus.SOUND_OFF:
183                                                                m_ch.setSoundOff();
184                                                                break;
185                                                        case MStatus.RESET_ALL:
186                                                                m_ch.reset();
187                                                                break;                                                         
188                            case MStatus.CLOSE:
189                                m_ch.close();
190                                break;
191                            case MStatus.EOT:
192                                m_isEnd = 1;
193                                break;
194                            case MStatus.NOP:
195                                break;
196                            default:
197                                break;
198                            }
199                            m_needle -= delta;
200                            m_pointer++;
201                        }
202                    }
203                } while(exec);
204
205                // create a short wave
206                var di:int;
207                if (m_pointer < eLen) {
208                    e = m_events[m_pointer];
209                    delta = e.getDelta() * m_spt;
210                    di = Math.ceil(delta - m_needle);
211                    if (i + di >= end) di = end - i;
212                    m_needle += di;
213                    if (signal == null) m_ch.getSamples(samples, end, i, di);
214                    i += di;
215                }
216                else {
217                    break;
218                }
219
220                // periodic signal
221                if (signal != null) {
222                    m_signalCnt += di;
223                    var intervalSample:int = int(m_signalInterval * m_spt);
224                    while (m_signalCnt >= intervalSample) {
225                        m_globalTick += m_signalInterval;
226                        signal.add(int((intervalSample - startCnt) * (1000.0/44100.0)), m_globalTick, 0);
227                        m_signalCnt -= intervalSample;
228                        startCnt = 0;
229                    }
230                }
231            }
232            if (signal != null) signal.terminate();
233        }
234
235        public function seek(delta:int):void {
236            m_delta += delta;
237            m_globalTick += delta;
238                        m_chordEnd = Math.max(m_chordEnd, m_globalTick);
239        }
240               
241                public function seekChordStart():void {
242            m_globalTick = m_chordBegin;
243                }
244
245        public function recDelta(e:MEvent):void {
246            e.setDelta(m_delta);
247            m_delta = 0;
248        }
249
250        public function recNote(noteNo:int, len:int, vel:int, keyon:int = 1, keyoff:int = 1):void {
251            var e0:MEvent = makeEvent();
252            if (keyon) {
253                e0.setNoteOn(noteNo, vel);
254            }
255            else {
256                e0.setNote(noteNo);
257            }
258            pushEvent(e0);
259            if (keyoff) {
260                var gate:int;
261                gate = (int)(len * m_gate) - m_gate2;
262                if (gate <= 0) gate = 0;
263                seek(gate);
264                                recNoteOff(noteNo, vel);
265                seek(len - gate);
266                                if (m_chordMode) {
267                                        seekChordStart();
268                                }
269            }
270            else {
271                seek(len);
272            }
273        }
274               
275                public function recNoteOff(noteNo:int, vel:int):void {
276                        var e:MEvent = makeEvent();
277                        e.setNoteOff(noteNo, vel);
278                        pushEvent(e);
279                }
280
281        public function recRest(len:int):void {
282            seek(len);
283                        if (m_chordMode) {
284                                m_chordBegin += len;
285                        }
286        }
287               
288                public function recChordStart():void {
289                        if (m_chordMode == false) {
290                                m_chordMode = true;
291                                m_chordBegin = m_globalTick;
292                        }
293                }
294               
295                public function recChordEnd():void {
296                        if (m_chordMode) {
297                                if (m_events.length > 0) {
298                                        m_delta = m_chordEnd - m_events[m_events.length-1].getTick();
299                                }
300                                else {
301                                        m_delta = 0;
302                                }
303                                m_globalTick = m_chordEnd;
304                                m_chordMode = false;
305                        }
306                }
307               
308        public function recRestMSec(msec:int):void {
309            var len:int = msec * 44100 / (m_spt * 1000);
310            seek(len);
311        }
312
313        public function recVolume(vol:int):void {
314            var e:MEvent = makeEvent();
315            e.setVolume(vol);
316            pushEvent(e);
317        }
318
319        protected function recGlobal(globalTick:uint, e:MEvent):void {
320            var n:int = m_events.length;
321            var preGlobalTick:uint = 0;
322            var tmpArr:Array = new Array();
323            for(var i:int; i < n; i++) {
324                var en:MEvent = m_events[i];
325                var nextTick:uint = preGlobalTick + en.getDelta();
326                if (nextTick > globalTick || (nextTick == globalTick && en.getStatus() != MStatus.TEMPO)) {
327                    en.setDelta(nextTick - globalTick);
328                    e.setDelta(globalTick - preGlobalTick);
329                    m_events.splice(i, 0, e);
330                    //trace("e(TEMPO"+e.getTempo()+") delta="+(globalTick-preGlobalTick));
331                    return;
332                }
333                preGlobalTick = nextTick;
334            }
335            e.setDelta(globalTick-preGlobalTick);
336            m_events.push(e);
337            //trace("e(TEMPO"+e.getTempo()+") delta="+(globalTick-preGlobalTick));
338        }
339               
340                // 新規イベントインスタンスを得る
341                protected function makeEvent():MEvent {
342                        var e:MEvent = new MEvent(m_globalTick);
343                        e.setDelta(m_delta);
344                        m_delta = 0;
345                        return e;
346                }
347               
348                // イベントを適切に追加する
349                protected function pushEvent(e:MEvent):void {
350                        if (m_chordMode == false) {
351                                m_events.push(e);
352                        }
353                        else {
354                                insertEvent(e);
355                        }
356                }
357               
358                // 挿入先に同時間のイベントがあった場合、その後に挿入する
359        protected function insertEvent(e:MEvent):void {
360            var n:int = m_events.length;
361            var preGlobalTick:uint = 0;
362                        var globalTick:uint = e.getTick();
363            var tmpArr:Array = new Array();
364            for(var i:int; i < n; i++) {
365                var en:MEvent = m_events[i];
366                var nextTick:uint = preGlobalTick + en.getDelta();
367                if (nextTick > globalTick) {
368                    en.setDelta(nextTick - globalTick);
369                    e.setDelta(globalTick - preGlobalTick);
370                    m_events.splice(i, 0, e);
371                    return;
372                }
373                preGlobalTick = nextTick;
374            }
375            e.setDelta(globalTick-preGlobalTick);
376            m_events.push(e);
377        }               
378
379        public function recTempo(globalTick:uint, tempo:Number):void {
380            var e:MEvent = new MEvent(globalTick); // makeEvent()は使用してはならない
381            e.setTempo(tempo);
382            insertEvent(e);
383        }
384
385        public function recEOT():void {
386            var e:MEvent = makeEvent();
387            e.setEOT();
388            pushEvent(e);
389        }
390
391        public function recGate(gate:Number):void {
392            m_gate = gate;
393        }
394
395        public function recGate2(gate2:int):void {
396            if (gate2 < 0) gate2 = 0;
397            m_gate2 = gate2;
398        }
399
400        public function recForm(form:int, sub:int):void {
401            var e:MEvent = makeEvent();
402            e.setForm(form, sub);
403            pushEvent(e);
404        }
405
406        public function recEnvelope(env:int, attack:int, times:Vector.<int>, levels:Vector.<int>, release:int):void {
407            var e:MEvent = makeEvent();
408            if (env == 1) e.setEnvelope1Atk(attack); else e.setEnvelope2Atk(attack);
409            pushEvent(e);
410            for(var i:int = 0, pts:int = times.length; i < pts; i++){
411                e = makeEvent();
412                        if (env == 1) e.setEnvelope1Point(times[i], levels[i]); else e.setEnvelope2Point(times[i], levels[i]);
413                pushEvent(e);
414            }
415            e = makeEvent();
416            if (env == 1) e.setEnvelope1Rel(release); else e.setEnvelope2Rel(release);
417            pushEvent(e);
418        }
419
420        public function recNoiseFreq(freq:int):void {
421            var e:MEvent = makeEvent();
422            e.setNoiseFreq(freq);
423            pushEvent(e);
424        }
425
426        public function recPWM(pwm:int):void {
427            var e:MEvent = makeEvent();
428            e.setPWM(pwm);
429            pushEvent(e);
430        }
431
432        public function recPan(pan:int):void {
433            var e:MEvent = makeEvent();
434            e.setPan(pan);
435            pushEvent(e);
436        }
437
438        public function recFormant(vowel:int):void {
439            var e:MEvent = makeEvent();
440            e.setFormant(vowel);
441            pushEvent(e);
442        }
443
444        public function recDetune(d:int):void {
445            var e:MEvent = makeEvent();
446            e.setDetune(d);
447            pushEvent(e);
448        }
449
450        public function recLFO(depth:int, width:int, form:int, subform:int, delay:int, time:int, target:int):void {
451            var e:MEvent = makeEvent();
452            e.setLFOFMSF(form, subform);
453            pushEvent(e);
454            e = makeEvent();
455            e.setLFODPWD(depth, width);
456            pushEvent(e);
457            e = makeEvent();
458            e.setLFODLTM(delay, time);
459            pushEvent(e);
460            e = makeEvent();
461            e.setLFOTarget(target);
462            pushEvent(e);
463        }
464
465        public function recLPF(swt:int, amt:int, frq:int, res:int):void {
466            var e:MEvent = makeEvent();
467            e.setLPFSWTAMT(swt, amt);
468            pushEvent(e);
469            e = makeEvent();
470            e.setLPFFRQRES(frq, res);
471            pushEvent(e);
472        }
473
474        public function recVolMode(m:int): void {
475            var e:MEvent = makeEvent();
476            e.setVolMode(m);
477            pushEvent(e);
478        }
479
480        public function recInput(sens:int, pipe:int):void {
481            var e:MEvent = makeEvent();
482            e.setInput(sens, pipe);
483            pushEvent(e);
484        }
485
486        public function recOutput(mode:int, pipe:int):void {
487            var e:MEvent = makeEvent();
488            e.setOutput(mode, pipe);
489            pushEvent(e);
490        }
491
492        public function recExpression(ex:int):void {
493            var e:MEvent = makeEvent();
494            e.setExpression(ex);
495            pushEvent(e);
496        }
497       
498        public function recRing(sens:int, pipe:int):void {
499                var e:MEvent = makeEvent();
500                e.setRing(sens, pipe);
501                pushEvent(e);
502        }
503       
504        public function recSync(mode:int, pipe:int):void {
505                var e:MEvent = makeEvent();
506                e.setSync(mode, pipe);
507                pushEvent(e);
508        }
509
510        public function recClose():void {
511            var e:MEvent = makeEvent();
512            e.setClose();
513            pushEvent(e);
514        }
515
516                public function recPortamento(depth:int, len:int):void {
517            var e:MEvent = makeEvent();
518            e.setPortamento(depth, len);
519            pushEvent(e);
520                }
521               
522                public function recMidiPort(mode:int):void {
523                        var e:MEvent = makeEvent();
524                        e.setMidiPort(mode);
525                        pushEvent(e);
526                }
527               
528                public function recMidiPortRate(rate:int):void {
529                        var e:MEvent = makeEvent();
530                        e.setMidiPortRate(rate);
531                        pushEvent(e);
532                }
533
534                public function recPortBase(base:int):void {
535                        var e:MEvent = makeEvent();
536                        e.setPortBase(base);
537                        pushEvent(e);
538                }
539               
540                public function recPoly(voiceCount:int):void {
541                        var e:MEvent = makeEvent();
542                        e.setPoly(voiceCount);
543                        pushEvent(e);
544                        m_polyFound = true;
545                }
546
547        public function isEnd():int {
548            return m_isEnd;
549        }
550
551        public function getRecGlobalTick():uint {
552            return m_globalTick;
553        }
554
555        public function seekTop():void {
556            m_globalTick = 0;
557        }
558
559        public function conduct(trackArr:Array):void {
560            var ni:int = m_events.length;
561            var nj:int = trackArr.length;
562            var globalTick:uint = 0;
563            var globalSample:uint = 0;
564            var spt:Number = calcSpt(DEFAULT_BPM);
565            var i:int, j:int;
566            var e:MEvent;
567            for(i = 0; i < ni; i++) {
568                e = m_events[i];
569                globalTick += e.getDelta();
570                globalSample += e.getDelta() * spt;
571                switch(e.getStatus()) {
572                case MStatus.TEMPO:
573                    spt = calcSpt(e.getTempo());
574                    for (j = FIRST_TRACK; j < nj; j++) {
575                        trackArr[j].recTempo(globalTick, e.getTempo());
576                    }
577                    break;
578                default:
579                    break;
580                }
581            }
582            var maxGlobalTick:int = 0;
583            for (j = FIRST_TRACK; j < nj; j++) {
584                if (maxGlobalTick < trackArr[j].getRecGlobalTick()) maxGlobalTick = trackArr[j].getRecGlobalTick();
585            }
586            e = makeEvent();
587            e.setClose();
588            recGlobal(maxGlobalTick, e);
589            globalSample += (maxGlobalTick - globalTick) * spt;
590
591            recRestMSec(3000);
592            recEOT();
593            globalSample += 3 * 44100;
594
595            m_totalMSec = globalSample*1000/44100;
596        }
597        // calc number of samples per tick
598        private function calcSpt(bpm:Number):Number {
599            var tps:Number = bpm * 96.0 / 60.0; // ticks per second (quater note = 96ticks)
600            return 44100.0 / tps;              // samples per tick
601        }
602        // set tempo
603        private function playTempo(bpm:Number):void {
604            m_bpm = bpm;
605            m_spt = calcSpt(bpm);
606            //trace("spt:"+m_spt)
607        }
608        public function getTotalMSec():uint {
609            return m_totalMSec;
610        }
611        public function getTotalTimeStr():String {
612            var sec:int = Math.ceil(Number(m_totalMSec) / 1000);
613            var smin:String = "0" + int(sec / 60);
614            var ssec:String = "0" + (sec % 60);
615            return smin.substr(smin.length-2, 2) + ":" + ssec.substr(ssec.length-2, 2);
616        }
617               
618        // 発声数取得
619        public function getVoiceCount():int {
620            return m_ch.getVoiceCount();
621        }
622               
623        // モノモードへ移行 (再生開始前に行うこと)
624        public function usingMono():void {
625            m_ch = new MChannel();
626        }
627               
628        // ポリモードへ移行 (再生開始前に行うこと)
629        public function usingPoly(maxVoice:int):void {
630            m_ch = new MPolyChannel(maxVoice);
631        }               
632               
633                // ポリ命令を1回でも使ったか?
634                public function findPoly():Boolean {
635                        return m_polyFound;
636                }
637    }
638}
Note: See TracBrowser for help on using the browser.