root/lang/actionscript/flmml/trunk/src/com/txt_nifty/sketch/flmml/MSequencer.as @ 27528

Revision 27173, 10.1 kB (checked in by tekisuke, 4 years ago)

lang/actionscript/flmml/: ダブルバッファリングが安定した!と思う。

Line 
1package com.txt_nifty.sketch.flmml {
2    import flash.events.EventDispatcher;
3    import flash.events.SampleDataEvent;
4    import flash.events.Event;
5    import flash.events.TimerEvent;
6    import flash.media.Sound;
7    import flash.media.SoundChannel;
8    import flash.media.SoundMixer;
9    import flash.media.SoundTransform;
10    import flash.utils.*;
11    import __AS3__.vec.Vector;
12
13    public class MSequencer extends EventDispatcher {
14        public var onSignal:Function = null;
15        public static const BUFFER_SIZE:int         = 8192;
16        public static const RATE44100:int           = 44100;
17
18        protected static const STATUS_STOP:int      = 0;
19        protected static const STATUS_PAUSE:int     = 1;
20        protected static const STATUS_BUFFERING:int = 2;
21        protected static const STATUS_PLAY:int      = 3;
22        protected static const STATUS_LAST:int      = 4;
23        protected static const STEP_NONE:int     = 0;
24        protected static const STEP_PRE:int      = 1;
25        protected static const STEP_TRACK:int    = 2;
26        protected static const STEP_POST:int     = 3;
27        protected static const STEP_COMPLETE:int = 4;
28        protected var m_sound:Sound;
29        protected var m_soundChannel:SoundChannel;
30        protected var m_soundTransform:SoundTransform;
31        protected var m_buffer:Vector.<Vector.<Number>>;
32        protected var m_playSide:int;
33        protected var m_playSize:int;
34        protected var m_step:int;
35        protected var m_processTrack:int;
36        protected var m_processOffset:int;
37        protected var m_output:Boolean;
38        protected var m_trackArr:Array;
39        protected var m_signalArr:Array;
40        protected var m_signalPtr:int;
41        protected var m_globalTick:uint;
42        protected var m_status:int;
43        protected var m_signalInterval:int;
44        protected var m_stopTimer:Timer;
45        protected var m_buffTimer:Timer;
46        protected var m_procTimer:Timer;
47        protected var m_multiple:int;
48
49        public function MSequencer(multiple:int = 32) {
50            m_multiple = multiple;
51            m_output = false;
52            MChannel.boot(MSequencer.BUFFER_SIZE * m_multiple);
53            MOscillator.boot();
54            MEnvelope.boot();
55            m_trackArr = new Array();
56            m_signalArr = new Array(3);
57            for(var i:int = 0; i < m_signalArr.length; i++) {
58                m_signalArr[i] = new MSignal(i);
59                m_signalArr[i].setFunction(onSignalHandler);
60            }
61            m_signalPtr = 0;
62            m_buffer = new Vector.<Vector.<Number>>(2);
63            m_buffer.fixed = true;
64            m_buffer[0] = new Vector.<Number>(MSequencer.BUFFER_SIZE * m_multiple * 2); // * 2 stereo
65            m_buffer[0].fixed = true;
66            m_buffer[1] = new Vector.<Number>(MSequencer.BUFFER_SIZE * m_multiple * 2); //
67            m_buffer[1].fixed = true;
68            m_playSide = 1;
69            m_playSize = 0;
70            m_step = STEP_NONE;
71            m_sound = new Sound();
72            m_soundChannel = new SoundChannel();
73            m_soundTransform = new SoundTransform();
74            setMasterVolume(100);
75            m_signalInterval = 96;
76            stop();
77            m_sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
78        }
79
80        public function play():void {
81            if (m_status != STATUS_PAUSE) {
82                stop();
83                m_globalTick = 0;
84                for (var i:int = 0; i < m_trackArr.length; i++) {
85                    m_trackArr[i].seekTop();
86                }
87            }
88            m_status = STATUS_BUFFERING;
89            processStart();
90        }
91
92        public function stop():void {
93            m_stopTimer = new Timer(0, 1);
94            m_stopTimer.addEventListener(TimerEvent.TIMER, onStopReq);
95            m_buffTimer = new Timer(0, 1);
96            m_buffTimer.addEventListener(TimerEvent.TIMER, onBufferingReq);
97            m_procTimer = new Timer(2, 1);
98            m_procTimer.addEventListener(TimerEvent.TIMER_COMPLETE, processAll);
99            if (m_soundChannel) m_soundChannel.stop();
100            m_status = STATUS_STOP;
101        }
102
103        public function pause():void {
104            if (m_soundChannel) m_soundChannel.stop();
105            m_status = STATUS_PAUSE;
106        }
107
108        public function setMasterVolume(vol:int):void {
109            m_soundTransform.volume = vol * (1.0 / 127.0);
110            SoundMixer.soundTransform = m_soundTransform;
111        }
112
113        public function isPlaying():Boolean {
114            return (m_status > STATUS_PAUSE);
115        }
116
117        public function isPaused():Boolean {
118            return (m_status == STATUS_PAUSE);
119        }
120
121        public function disconnectAll():void {
122            while(m_trackArr.pop());
123            m_status = STATUS_STOP;
124        }
125
126        public function connect(track:MTrack):void {
127            track.m_signalInterval = m_signalInterval;
128            m_trackArr.push(track);
129        }
130
131        public function getGlobalTick():uint {
132            return m_globalTick;
133        }
134
135        public function setSignalInterval(interval:int):void {
136            m_signalInterval = interval;
137        }
138
139        protected function onSignalHandler(globalTick:uint, event:int):void {
140            m_globalTick = globalTick;
141            if (onSignal != null) onSignal(globalTick, event);
142        }
143
144        private function reqStop():void {
145            m_stopTimer.start();
146        }
147        private function onStopReq(e:Event):void {
148            stop();
149            dispatchEvent(new MMLEvent(MMLEvent.COMPLETE));
150        }
151        private function reqBuffering():void {
152            //trace("reqBf");
153            m_buffTimer.start();
154        }
155        private function onBufferingReq(e:Event):void {
156            pause();
157            m_status = STATUS_BUFFERING;
158        }
159
160        private function processStart():void {
161            m_step = STEP_PRE;
162            m_processOffset = 0;
163            m_procTimer.start();
164        }
165        private function processAll(e:Event):void {
166            var sLen:int = MSequencer.BUFFER_SIZE * m_multiple;
167            var bLen:int = MSequencer.BUFFER_SIZE * 4;
168            if (bLen > sLen) bLen = sLen;
169            var nLen:int = m_trackArr.length;
170            var i:int;
171            var buffer:Vector.<Number> = m_buffer[1 - m_playSide];
172            switch(m_step) {
173            case STEP_PRE:
174                if (m_output) {
175                    //trace("pro1");
176                    m_procTimer.start();
177                    return;
178                }
179                for(i = sLen * 2 - 1; i >= 0; i--) {
180                    buffer[i] = 0.0;
181                }
182                if (nLen > 0) {
183                    var track:MTrack = m_trackArr[MTrack.TEMPO_TRACK];
184                    track.onSampleData(buffer, 0, sLen, m_signalArr[m_signalPtr]);
185                }
186                m_processTrack = MTrack.FIRST_TRACK;
187                m_processOffset = 0;
188                m_step++;
189                m_procTimer.start();
190                break;
191            case STEP_TRACK:
192                if (m_output) {
193                    //trace("pro2");
194                    m_procTimer.start();
195                    return;
196                }
197                if (m_processTrack >= nLen) m_step++;
198                else {
199                    m_trackArr[m_processTrack].onSampleData(buffer, m_processOffset, m_processOffset + bLen);
200                    m_processOffset += bLen;
201                    if (m_processOffset >= sLen) {
202                        m_processTrack++;
203                        m_processOffset = 0;
204                        if (m_status == STATUS_BUFFERING) {
205                            dispatchEvent(new MMLEvent(MMLEvent.BUFFERING, false, false, 0, 0, (m_processTrack+1) * 100 / (nLen+1)));
206                        }
207                    }
208                }
209                m_procTimer.start();
210                break;
211            case STEP_POST:
212                m_step = STEP_COMPLETE;
213                if (m_status == STATUS_BUFFERING) {
214                    m_status = STATUS_PLAY;
215                    m_playSide = 1 - m_playSide;
216                    m_playSize = 0;
217                    processStart();
218                    m_soundChannel = m_sound.play();
219                    //trace("play");
220                }
221                break;
222            default:
223                break;
224            }
225        }
226
227        private function onSampleData(e:SampleDataEvent):void {
228            m_output = true;
229            if (m_playSize >= m_multiple) {
230                if (m_step == STEP_COMPLETE) {
231                    m_playSide = 1 - m_playSide;
232                    m_playSize = 0;
233                    processStart();
234                }
235                else {
236                    m_output = false;
237                    reqBuffering();
238                    return;
239                }
240                if (m_status == STATUS_LAST) {
241                    m_output = false;
242                    reqStop();
243                    return;
244                }
245                else if (m_status == STATUS_PLAY) {
246                    var n:int = 0;
247                    for (i = 0; i < m_trackArr.length; i++) {
248                        if (m_trackArr[i].isEnd()) n++;
249                    }
250                    if (n >= m_trackArr.length) {
251                        m_status = STATUS_LAST;
252                    }
253                }
254            }
255            var buffer:Vector.<Number> = m_buffer[m_playSide];
256            var base:int = (BUFFER_SIZE * m_playSize) * 2;
257            var i:int;
258            for(i = 0; i < BUFFER_SIZE; i++) {
259                e.data.writeFloat(buffer[base+i+i]);
260                e.data.writeFloat(buffer[base+i+i+1]);
261            }
262            m_playSize++;
263            //m_signalArr[(m_signalPtr + m_signalArr.length-1) % m_signalArr.length].start();
264            m_signalPtr = (++m_signalPtr) % m_signalArr.length;
265            m_output = false;
266        }
267        public function createPipes(num:int):void {
268            MChannel.createPipes(num);
269        }
270    }
271}
Note: See TracBrowser for help on using the browser.