| 1 | package 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 | }
|
|---|