| 1 |
//---------------------------------------------------------------------------------------------------- |
|---|
| 2 |
// SiON driver |
|---|
| 3 |
// Copyright (c) 2008 keim All rights reserved. |
|---|
| 4 |
// Distributed under BSD-style license (see org.si.license.txt). |
|---|
| 5 |
//---------------------------------------------------------------------------------------------------- |
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
package org.si.sion { |
|---|
| 9 |
import flash.errors.*; |
|---|
| 10 |
import flash.events.*; |
|---|
| 11 |
import flash.media.*; |
|---|
| 12 |
import flash.display.Sprite; |
|---|
| 13 |
import flash.utils.getTimer; |
|---|
| 14 |
import flash.utils.ByteArray; |
|---|
| 15 |
import org.si.utils.SLLint; |
|---|
| 16 |
import org.si.utils.SLLNumber; |
|---|
| 17 |
import org.si.sion.events.*; |
|---|
| 18 |
import org.si.sion.sequencer.base._sion_sequencer_internal; |
|---|
| 19 |
import org.si.sion.sequencer.base.MMLSequence; |
|---|
| 20 |
import org.si.sion.sequencer.base.MMLEvent; |
|---|
| 21 |
import org.si.sion.sequencer.SiMMLSequencer; |
|---|
| 22 |
import org.si.sion.sequencer.SiMMLTrack; |
|---|
| 23 |
import org.si.sion.sequencer.SiMMLEnvelopTable; |
|---|
| 24 |
import org.si.sion.sequencer.SiMMLTable; |
|---|
| 25 |
import org.si.sion.sequencer.SiMMLVoice; |
|---|
| 26 |
import org.si.sion.module.ISiOPMWaveInterface; |
|---|
| 27 |
import org.si.sion.module.SiOPMTable; |
|---|
| 28 |
import org.si.sion.module.SiOPMModule; |
|---|
| 29 |
import org.si.sion.module.SiOPMChannelParam; |
|---|
| 30 |
import org.si.sion.module.SiOPMWaveTable; |
|---|
| 31 |
import org.si.sion.module.SiOPMWavePCMTable; |
|---|
| 32 |
import org.si.sion.module.SiOPMWavePCMData; |
|---|
| 33 |
import org.si.sion.module.SiOPMWaveSamplerTable; |
|---|
| 34 |
import org.si.sion.module.SiOPMWaveSamplerData; |
|---|
| 35 |
import org.si.sion.effector.SiEffectModule; |
|---|
| 36 |
import org.si.sion.effector.SiEffectBase; |
|---|
| 37 |
import org.si.sion.utils.soundloader.SoundLoader; |
|---|
| 38 |
import org.si.sion.utils.SiONUtil; |
|---|
| 39 |
import org.si.sion.utils.Fader; |
|---|
| 40 |
import org.si.sion.namespaces._sion_internal; |
|---|
| 41 |
|
|---|
| 42 |
|
|---|
| 43 |
// Dispatching events |
|---|
| 44 |
/** @eventType org.si.sion.events.SiONEvent.QUEUE_PROGRESS */ |
|---|
| 45 |
[Event(name="queueProgress", type="org.si.sion.events.SiONEvent")] |
|---|
| 46 |
/** @eventType org.si.sion.events.SiONEvent.QUEUE_COMPLETE */ |
|---|
| 47 |
[Event(name="queueComplete", type="org.si.sion.events.SiONEvent")] |
|---|
| 48 |
/** @eventType org.si.sion.events.SiONEvent.QUEUE_CANCEL */ |
|---|
| 49 |
[Event(name="queueCancel", type="org.si.sion.events.SiONEvent")] |
|---|
| 50 |
/** @eventType org.si.sion.events.SiONEvent.STREAM */ |
|---|
| 51 |
[Event(name="stream", type="org.si.sion.events.SiONEvent")] |
|---|
| 52 |
/** @eventType org.si.sion.events.SiONEvent.STREAM_START */ |
|---|
| 53 |
[Event(name="streamStart", type="org.si.sion.events.SiONEvent")] |
|---|
| 54 |
/** @eventType org.si.sion.events.SiONEvent.STREAM_STOP */ |
|---|
| 55 |
[Event(name="streamStop", type="org.si.sion.events.SiONEvent")] |
|---|
| 56 |
/** @eventType org.si.sion.events.SiONEvent.FINISH_SEQUENCE */ |
|---|
| 57 |
[Event(name="finishSequence", type="org.si.sion.events.SiONEvent")] |
|---|
| 58 |
/** @eventType org.si.sion.events.SiONEvent.FADE_PROGRESS */ |
|---|
| 59 |
[Event(name="fadeProgress", type="org.si.sion.events.SiONEvent")] |
|---|
| 60 |
/** @eventType org.si.sion.events.SiONEvent.FADE_IN_COMPLETE */ |
|---|
| 61 |
[Event(name="fadeInComplete", type="org.si.sion.events.SiONEvent")] |
|---|
| 62 |
/** @eventType org.si.sion.events.SiONEvent.FADE_OUT_COMPLETE */ |
|---|
| 63 |
[Event(name="fadeOutComplete", type="org.si.sion.events.SiONEvent")] |
|---|
| 64 |
/** @eventType org.si.sion.events.SiONTrackEvent.NOTE_ON_STREAM */ |
|---|
| 65 |
[Event(name="noteOnStream", type="org.si.sion.events.SiONTrackEvent")] |
|---|
| 66 |
/** @eventType org.si.sion.events.SiONTrackEvent.NOTE_OFF_STREAM */ |
|---|
| 67 |
[Event(name="noteOffStream", type="org.si.sion.events.SiONTrackEvent")] |
|---|
| 68 |
/** @eventType org.si.sion.events.SiONTrackEvent.NOTE_ON_FRAME */ |
|---|
| 69 |
[Event(name="noteOnFrame", type="org.si.sion.events.SiONTrackEvent")] |
|---|
| 70 |
/** @eventType org.si.sion.events.SiONTrackEvent.NOTE_OFF_FRAME */ |
|---|
| 71 |
[Event(name="noteOffFrame", type="org.si.sion.events.SiONTrackEvent")] |
|---|
| 72 |
/** @eventType org.si.sion.events.SiONTrackEvent.BEAT */ |
|---|
| 73 |
[Event(name="beat", type="org.si.sion.events.SiONTrackEvent")] |
|---|
| 74 |
/** @eventType org.si.sion.events.SiONTrackEvent.CHANGE_BPM */ |
|---|
| 75 |
[Event(name="changeBPM", type="org.si.sion.events.SiONTrackEvent")] |
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 |
/** SiONDriver class provides the driver of SiON's digital signal processor emulator. SiON's all basic operations are provided as SiONDriver's properties, methods and events. You can create only one SiONDriver instance in one SWF file, and the error appears when you try to create plural SiONDrivers.<br/> |
|---|
| 79 |
* @see SiONData |
|---|
| 80 |
* @see SiONVoice |
|---|
| 81 |
* @see org.si.sion.events.SiONEvent |
|---|
| 82 |
* @see org.si.sion.events.SiONTrackEvent |
|---|
| 83 |
* @see org.si.sion.module.SiOPMModule |
|---|
| 84 |
* @see org.si.sion.sequencer.SiMMLSequencer |
|---|
| 85 |
* @see org.si.sion.effector.SiEffectModule |
|---|
| 86 |
@example 1) The simplest sample. Create new instance and call play with MML string.<br/> |
|---|
| 87 |
<listing version="3.0"> |
|---|
| 88 |
// create driver instance. |
|---|
| 89 |
var driver:SiONDriver = new SiONDriver(); |
|---|
| 90 |
// call play() with mml string whenever you want to play sound. |
|---|
| 91 |
driver.play("t100 l8 [ ccggaag4 ffeeddc4 | [ggffeed4]2 ]2"); |
|---|
| 92 |
</listing> |
|---|
| 93 |
*/ |
|---|
| 94 |
public class SiONDriver extends Sprite implements ISiOPMWaveInterface |
|---|
| 95 |
{ |
|---|
| 96 |
// namespace |
|---|
| 97 |
//---------------------------------------- |
|---|
| 98 |
use namespace _sion_internal; |
|---|
| 99 |
|
|---|
| 100 |
|
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
// constants |
|---|
| 104 |
//---------------------------------------- |
|---|
| 105 |
/** version number */ |
|---|
| 106 |
static public const VERSION:String = "0.6.4.1"; |
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 |
/** note-on exception mode "ignore", SiON does not consider about track ID's conflict in noteOn() method (default). */ |
|---|
| 110 |
static public const NEM_IGNORE:int = 0; |
|---|
| 111 |
/** note-on exception mode "reject", Reject new note when the track IDs are conflicted. */ |
|---|
| 112 |
static public const NEM_REJECT:int = 1; |
|---|
| 113 |
/** note-on exception mode "overwrite", Overwrite current note when the track IDs are conflicted. */ |
|---|
| 114 |
static public const NEM_OVERWRITE:int = 2; |
|---|
| 115 |
/** note-on exception mode "shift", Shift the sound timing to next quantize when the track IDs are conflicted. */ |
|---|
| 116 |
static public const NEM_SHIFT:int = 3; |
|---|
| 117 |
|
|---|
| 118 |
static private const NEM_MAX:int = 4; |
|---|
| 119 |
|
|---|
| 120 |
|
|---|
| 121 |
// event listener type |
|---|
| 122 |
private const NO_LISTEN:int = 0; |
|---|
| 123 |
private const LISTEN_QUEUE:int = 1; |
|---|
| 124 |
private const LISTEN_PROCESS:int = 2; |
|---|
| 125 |
|
|---|
| 126 |
// time avaraging sample count |
|---|
| 127 |
private const TIME_AVARAGING_COUNT:int = 8; |
|---|
| 128 |
|
|---|
| 129 |
|
|---|
| 130 |
|
|---|
| 131 |
|
|---|
| 132 |
// valiables |
|---|
| 133 |
//---------------------------------------- |
|---|
| 134 |
/** SiOPM digital signal processor module instance. */ |
|---|
| 135 |
public var module:SiOPMModule; |
|---|
| 136 |
|
|---|
| 137 |
/** Effector module instance. */ |
|---|
| 138 |
public var effector:SiEffectModule; |
|---|
| 139 |
|
|---|
| 140 |
/** Sequencer module instance. */ |
|---|
| 141 |
public var sequencer:SiMMLSequencer; |
|---|
| 142 |
|
|---|
| 143 |
|
|---|
| 144 |
// private: |
|---|
| 145 |
//----- general |
|---|
| 146 |
private var _data:SiONData; // data to compile or process |
|---|
| 147 |
private var _tempData:SiONData; // temporary data |
|---|
| 148 |
private var _mmlString:String; // mml string of previous compiling |
|---|
| 149 |
//----- sound related |
|---|
| 150 |
private var _sound:Sound; // sound stream instance |
|---|
| 151 |
private var _soundChannel:SoundChannel; // sound channel instance |
|---|
| 152 |
private var _soundTransform:SoundTransform; // sound transform |
|---|
| 153 |
private var _fader:Fader; // sound fader |
|---|
| 154 |
//----- SiOPM DSP module related |
|---|
| 155 |
private var _channelCount:int; // module output channels (1 or 2) |
|---|
| 156 |
private var _sampleRate:Number; // module output frequency ratio (44100 or 22050) |
|---|
| 157 |
private var _bitRate:int; // module output bitrate |
|---|
| 158 |
private var _bufferLength:int; // module and streaming buffer size (8192, 4096 or 2048) |
|---|
| 159 |
private var _debugMode:Boolean; // true; throw Error, false; throw ErrorEvent |
|---|
| 160 |
private var _dispatchStreamEvent:Boolean; // dispatch steam event |
|---|
| 161 |
private var _dispatchFadingEvent:Boolean; // dispatch fading event |
|---|
| 162 |
private var _inStreaming:Boolean; // in streaming |
|---|
| 163 |
private var _preserveStop:Boolean; // preserve stop after streaming |
|---|
| 164 |
private var _suspendStreaming:Boolean; // suspend streaming |
|---|
| 165 |
private var _suspendWhileLoading:Boolean; // suspend starting steam while loading |
|---|
| 166 |
private var _loadingSoundList:Array; // loading sound list |
|---|
| 167 |
private var _isFinishSeqDispatched:Boolean; // FINISH_SEQUENCE event already dispacthed |
|---|
| 168 |
//----- operation related |
|---|
| 169 |
private var _autoStop:Boolean; // auto stop when the sequence finished |
|---|
| 170 |
private var _noteOnExceptionMode:int; // track id exception mode |
|---|
| 171 |
private var _isPaused:Boolean; // flag to pause |
|---|
| 172 |
private var _position:Number; // start position [ms] |
|---|
| 173 |
private var _masterVolume:Number; // master volume |
|---|
| 174 |
private var _faderVolume:Number; // fader volume |
|---|
| 175 |
//----- background sound |
|---|
| 176 |
private var _backgroundSound:Sound; // background Sound |
|---|
| 177 |
private var _backgroundLevel:Number; // background Sound mixing level |
|---|
| 178 |
private var _backgroundBuffer:ByteArray; // buffer for background Sound |
|---|
| 179 |
private var _backgroundLoop:Boolean; // looping flag of background Sound |
|---|
| 180 |
//----- queue |
|---|
| 181 |
private var _queueInterval:int; // interupting interval to execute queued jobs |
|---|
| 182 |
private var _queueLength:int; // queue length to execute |
|---|
| 183 |
private var _jobProgress:Number; // progression of current job |
|---|
| 184 |
private var _currentJob:int; // current job 0=no job, 1=compile, 2=render |
|---|
| 185 |
private var _jobQueue:Vector.<SiONDriverJob> = null; // compiling/rendering jobs queue |
|---|
| 186 |
private var _trackEventQueue:Vector.<SiONTrackEvent>; // SiONTrackEvents queue |
|---|
| 187 |
//----- timer interruption |
|---|
| 188 |
private var _timerSequence:MMLSequence; // global sequence |
|---|
| 189 |
private var _timerIntervalEvent:MMLEvent; // MMLEvent.GLOBAL_WAIT event |
|---|
| 190 |
private var _timerCallback:Function; // callback function |
|---|
| 191 |
//----- rendering |
|---|
| 192 |
private var _renderBuffer:Vector.<Number>; // rendering buffer |
|---|
| 193 |
private var _renderBufferChannelCount:int; // rendering buffer channel count |
|---|
| 194 |
private var _renderBufferIndex:int; // rendering buffer writing index |
|---|
| 195 |
private var _renderBufferSizeMax:int; // maximum value of rendering buffer size |
|---|
| 196 |
//----- timers |
|---|
| 197 |
private var _timeCompile:int; // previous compiling time. |
|---|
| 198 |
private var _timeRender:int; // previous rendering time. |
|---|
| 199 |
private var _timeProcess:int; // averge processing time in 1sec. |
|---|
| 200 |
private var _timeProcessTotal:int; // total processing time in last 8 bufferings. |
|---|
| 201 |
private var _timeProcessData:SLLint; // processing time data of last 8 bufferings. |
|---|
| 202 |
private var _timeProcessAveRatio:Number;// number to averaging _timeProcessTotal |
|---|
| 203 |
private var _timePrevStream:int; // previous streaming time. |
|---|
| 204 |
private var _latency:Number; // streaming latency [ms] |
|---|
| 205 |
private var _prevFrameTime:int; // previous frame time |
|---|
| 206 |
private var _frameRate:int; // frame rate |
|---|
| 207 |
//----- listeners management |
|---|
| 208 |
private var _eventListenerPrior:int; // event listeners priority |
|---|
| 209 |
private var _listenEvent:int; // current lintening event |
|---|
| 210 |
|
|---|
| 211 |
// mutex instance |
|---|
| 212 |
static private var _mutex:SiONDriver = null; // unique instance |
|---|
| 213 |
|
|---|
| 214 |
|
|---|
| 215 |
|
|---|
| 216 |
|
|---|
| 217 |
// properties |
|---|
| 218 |
//---------------------------------------- |
|---|
| 219 |
/** Instance of unique SiONDriver. null when new SiONDriver is not created yet. */ |
|---|
| 220 |
static public function get mutex() : SiONDriver { return _mutex; } |
|---|
| 221 |
|
|---|
| 222 |
|
|---|
| 223 |
// data |
|---|
| 224 |
/** MML string (this property is only available during compiling). */ |
|---|
| 225 |
public function get mmlString() : String { return _mmlString; } |
|---|
| 226 |
|
|---|
| 227 |
/** Data to compile, render and process. */ |
|---|
| 228 |
public function get data() : SiONData { return _data; } |
|---|
| 229 |
|
|---|
| 230 |
/** flash.media.Sound instance to stream SiON's sound. */ |
|---|
| 231 |
public function get sound() : Sound { return _sound; } |
|---|
| 232 |
|
|---|
| 233 |
/** flash.media.SoundChannel instance of SiON's sound stream (this property is only available during streaming). */ |
|---|
| 234 |
public function get soundChannel() : SoundChannel { return _soundChannel; } |
|---|
| 235 |
|
|---|
| 236 |
/** Fader to control fade-in/out. You can check activity by "fader.isActive". */ |
|---|
| 237 |
public function get fader() : Fader { return _fader; } |
|---|
| 238 |
|
|---|
| 239 |
|
|---|
| 240 |
// paramteters |
|---|
| 241 |
/** The number of sound tracks (this property is only available during streaming). */ |
|---|
| 242 |
public function get trackCount() : int { return sequencer.tracks.length; } |
|---|
| 243 |
|
|---|
| 244 |
/** Streaming buffer length. */ |
|---|
| 245 |
public function get bufferLength() : int { return _bufferLength; } |
|---|
| 246 |
/** Sample rate (44100 is only available in current version). */ |
|---|
| 247 |
public function get sampleRate() : Number { return _sampleRate; } |
|---|
| 248 |
/** bit rate, the value of 0 means the wave is represented as float value[-1 - +1]. */ |
|---|
| 249 |
public function get bitRate() : Number { return _bitRate; } |
|---|
| 250 |
|
|---|
| 251 |
/** Sound volume. */ |
|---|
| 252 |
public function get volume() : Number { return _masterVolume; } |
|---|
| 253 |
public function set volume(v:Number) : void { |
|---|
| 254 |
_masterVolume = v; |
|---|
| 255 |
_soundTransform.volume = _masterVolume * _faderVolume; |
|---|
| 256 |
if (_soundChannel) _soundChannel.soundTransform = _soundTransform; |
|---|
| 257 |
} |
|---|
| 258 |
|
|---|
| 259 |
/** Sound panning. */ |
|---|
| 260 |
public function get pan() : Number { return _soundTransform.pan; } |
|---|
| 261 |
public function set pan(p:Number) : void { |
|---|
| 262 |
_soundTransform.pan = p; |
|---|
| 263 |
if (_soundChannel) _soundChannel.soundTransform = _soundTransform; |
|---|
| 264 |
} |
|---|
| 265 |
|
|---|
| 266 |
|
|---|
| 267 |
// measured times |
|---|
| 268 |
/** previous compiling time [ms]. */ |
|---|
| 269 |
public function get compileTime() : int { return _timeCompile; } |
|---|
| 270 |
|
|---|
| 271 |
/** previous rendering time [ms]. */ |
|---|
| 272 |
public function get renderTime() : int { return _timeRender; } |
|---|
| 273 |
|
|---|
| 274 |
/** average processing time in 1sec [ms]. */ |
|---|
| 275 |
public function get processTime() : int { return _timeProcess; } |
|---|
| 276 |
|
|---|
| 277 |
/** progression of current compiling/rendering (0=start -> 1=finish). */ |
|---|
| 278 |
public function get jobProgress() : Number { return _jobProgress; } |
|---|
| 279 |
|
|---|
| 280 |
/** progression of all queued jobs (0=start -> 1=finish). */ |
|---|
| 281 |
public function get jobQueueProgress() : Number { |
|---|
| 282 |
if (_queueLength == 0) return 1; |
|---|
| 283 |
return (_queueLength - _jobQueue.length - 1 + _jobProgress) / _queueLength; |
|---|
| 284 |
} |
|---|
| 285 |
|
|---|
| 286 |
/** compiling/rendering jobs queue length. */ |
|---|
| 287 |
public function get jobQueueLength() : int { return _jobQueue.length; } |
|---|
| 288 |
|
|---|
| 289 |
/** streaming latency [ms]. */ |
|---|
| 290 |
public function get latency() : Number { return _latency; } |
|---|
| 291 |
|
|---|
| 292 |
|
|---|
| 293 |
// flags |
|---|
| 294 |
/** Is job executing ? */ |
|---|
| 295 |
public function get isJobExecuting() : Boolean { return (_jobProgress>0 && _jobProgress<1); } |
|---|
| 296 |
|
|---|
| 297 |
/** Is streaming ? */ |
|---|
| 298 |
public function get isPlaying() : Boolean { return (_soundChannel != null); } |
|---|
| 299 |
|
|---|
| 300 |
/** Is paused ? */ |
|---|
| 301 |
public function get isPaused() : Boolean { return _isPaused; } |
|---|
| 302 |
|
|---|
| 303 |
|
|---|
| 304 |
// operation |
|---|
| 305 |
/** Get playing position[ms] of current data, or Set initial position of playing data. @default 0 */ |
|---|
| 306 |
public function get position() : Number { |
|---|
| 307 |
return sequencer.processedSampleCount * 1000 / _sampleRate; |
|---|
| 308 |
} |
|---|
| 309 |
public function set position(pos:Number) : void { |
|---|
| 310 |
_position = pos; |
|---|
| 311 |
if (sequencer.isReadyToProcess) { |
|---|
| 312 |
sequencer._resetAllTracks(); |
|---|
| 313 |
sequencer.dummyProcess(_position * _sampleRate * 0.001); |
|---|
| 314 |
} |
|---|
| 315 |
} |
|---|
| 316 |
|
|---|
| 317 |
/** The maximum limit of sound tracks. @default 128 */ |
|---|
| 318 |
public function get maxTrackCount() : int { return sequencer._maxTrackCount; } |
|---|
| 319 |
public function set maxTrackCount(max:int) : void { sequencer._maxTrackCount = max; } |
|---|
| 320 |
|
|---|
| 321 |
/** Beat par minute value of SiON's play. @default 120 */ |
|---|
| 322 |
public function get bpm() : Number { |
|---|
| 323 |
return (sequencer.isReadyToProcess) ? sequencer.bpm : sequencer.setting.defaultBPM; |
|---|
| 324 |
} |
|---|
| 325 |
public function set bpm(t:Number) : void { |
|---|
| 326 |
sequencer.setting.defaultBPM = t; |
|---|
| 327 |
if (sequencer.isReadyToProcess) { |
|---|
| 328 |
if (!sequencer.isEnableChangeBPM) throw errorCannotChangeBPM(); |
|---|
| 329 |
sequencer.bpm = t; |
|---|
| 330 |
} |
|---|
| 331 |
} |
|---|
| 332 |
|
|---|
| 333 |
/** Auto stop when the sequence finished or fade-outed. @default false */ |
|---|
| 334 |
public function get autoStop() : Boolean { return _autoStop; } |
|---|
| 335 |
public function set autoStop(mode:Boolean) : void { _autoStop = mode; } |
|---|
| 336 |
|
|---|
| 337 |
/** pause while loading sound @default true */ |
|---|
| 338 |
public function get pauseWhileLoading() : Boolean { return _suspendWhileLoading; } |
|---|
| 339 |
public function set pauseWhileLoading(b:Boolean) : void { _suspendWhileLoading = b; } |
|---|
| 340 |
|
|---|
| 341 |
/** Debug mode, true; throw Error / false; throw ErrorEvent when error appears inside. @default false */ |
|---|
| 342 |
public function get debugMode() : Boolean { return _debugMode; } |
|---|
| 343 |
public function set debugMode(mode:Boolean) : void { _debugMode = mode; } |
|---|
| 344 |
|
|---|
| 345 |
/** Note on exception mode, this mode is refered when the noteOn() sound's track IDs are conflicted at the same moment. This value have to be SiONDriver.NEM_*. @default NEM_IGNORE. |
|---|
| 346 |
* @see #NEM_IGNORE |
|---|
| 347 |
* @see #NEM_REJECT |
|---|
| 348 |
* @see #NEM_OVERWRITE |
|---|
| 349 |
* @see #NEM_SHIFT |
|---|
| 350 |
*/ |
|---|
| 351 |
public function get noteOnExceptionMode() : int { return _noteOnExceptionMode; } |
|---|
| 352 |
public function set noteOnExceptionMode(mode:int) : void { _noteOnExceptionMode = (0<mode && mode<NEM_MAX) ? mode : 0; } |
|---|
| 353 |
|
|---|
| 354 |
|
|---|
| 355 |
|
|---|
| 356 |
|
|---|
| 357 |
// constructor |
|---|
| 358 |
//---------------------------------------- |
|---|
| 359 |
/** Create driver to manage the synthesizer, sequencer and effector. Only one SiONDriver instance can be created. |
|---|
| 360 |
* @param bufferLength Buffer size of sound stream. The value of 8192, 4096 or 2048 is available. |
|---|
| 361 |
* @param channel Channel count. 1(monoral) or 2(stereo) is available. |
|---|
| 362 |
* @param sampleRate Sampling ratio of wave. 44100 is only available in current version. |
|---|
| 363 |
* @param bitRate Bit ratio of wave. 0 means float value [-1 to 1]. |
|---|
| 364 |
*/ |
|---|
| 365 |
function SiONDriver(bufferLength:int=2048, channelCount:int=2, sampleRate:int=44100, bitRate:int=0) |
|---|
| 366 |
{ |
|---|
| 367 |
// check mutex |
|---|
| 368 |
if (_mutex != null) throw errorPluralDrivers(); |
|---|
| 369 |
|
|---|
| 370 |
// check parameters |
|---|
| 371 |
if (bufferLength != 2048 && bufferLength != 4096 && bufferLength != 8192) throw errorParamNotAvailable("stream buffer", bufferLength); |
|---|
| 372 |
if (channelCount != 1 && channelCount != 2) throw errorParamNotAvailable("channel count", channelCount); |
|---|
| 373 |
if (sampleRate != 44100) throw errorParamNotAvailable("sampling rate", sampleRate); |
|---|
| 374 |
|
|---|
| 375 |
// initialize tables |
|---|
| 376 |
var dummy:*; |
|---|
| 377 |
dummy = SiOPMTable.instance; //initialize(3580000, 1789772.5, 44100) sampleRate; |
|---|
| 378 |
dummy = SiMMLTable.instance; //initialize(); |
|---|
| 379 |
|
|---|
| 380 |
// allocation |
|---|
| 381 |
_jobQueue = new Vector.<SiONDriverJob>(); |
|---|
| 382 |
module = new SiOPMModule(); |
|---|
| 383 |
effector = new SiEffectModule(module); |
|---|
| 384 |
sequencer = new SiMMLSequencer(module, _callbackEventTriggerOn, _callbackEventTriggerOff, _callbackTempoChanged); |
|---|
| 385 |
_sound = new Sound(); |
|---|
| 386 |
_soundTransform = new SoundTransform(); |
|---|
| 387 |
_fader = new Fader(); |
|---|
| 388 |
_timerSequence = new MMLSequence(); |
|---|
| 389 |
_loadingSoundList = []; |
|---|
| 390 |
|
|---|
| 391 |
// initialize |
|---|
| 392 |
_tempData = null; |
|---|
| 393 |
_channelCount = channelCount; |
|---|
| 394 |
_sampleRate = sampleRate; // sampleRate; 44100 is only in current version. |
|---|
| 395 |
_bitRate = bitRate; |
|---|
| 396 |
_bufferLength = bufferLength; |
|---|
| 397 |
_listenEvent = NO_LISTEN; |
|---|
| 398 |
_dispatchStreamEvent = false; |
|---|
| 399 |
_dispatchFadingEvent = false; |
|---|
| 400 |
_preserveStop = false; |
|---|
| 401 |
_inStreaming = false; |
|---|
| 402 |
_suspendStreaming = false; |
|---|
| 403 |
_suspendWhileLoading = true; |
|---|
| 404 |
_autoStop = false; |
|---|
| 405 |
_noteOnExceptionMode = NEM_IGNORE; |
|---|
| 406 |
_debugMode = false; |
|---|
| 407 |
_isFinishSeqDispatched = false; |
|---|
| 408 |
_timerCallback = null; |
|---|
| 409 |
_timerSequence.initialize(); |
|---|
| 410 |
_timerSequence.appendNewEvent(MMLEvent.REPEAT_ALL, 0); |
|---|
| 411 |
_timerSequence.appendNewEvent(MMLEvent.TIMER, 0); |
|---|
| 412 |
_timerIntervalEvent = _timerSequence.appendNewEvent(MMLEvent.GLOBAL_WAIT, 0, 0); |
|---|
| 413 |
|
|---|
| 414 |
_backgroundSound = null; |
|---|
| 415 |
_backgroundLevel = 1; |
|---|
| 416 |
_backgroundBuffer = null; |
|---|
| 417 |
_backgroundLoop = false; |
|---|
| 418 |
|
|---|
| 419 |
_position = 0; |
|---|
| 420 |
_masterVolume = 1; |
|---|
| 421 |
_faderVolume = 1; |
|---|
| 422 |
_soundTransform.pan = 0; |
|---|
| 423 |
_soundTransform.volume = _masterVolume * _faderVolume; |
|---|
| 424 |
|
|---|
| 425 |
_eventListenerPrior = 1; |
|---|
| 426 |
_trackEventQueue = new Vector.<SiONTrackEvent>(); |
|---|
| 427 |
|
|---|
| 428 |
_queueInterval = 500; |
|---|
| 429 |
_jobProgress = 0; |
|---|
| 430 |
_currentJob = 0; |
|---|
| 431 |
_queueLength = 0; |
|---|
| 432 |
|
|---|
| 433 |
_timeCompile = 0; |
|---|
| 434 |
_timeProcessTotal = 0; |
|---|
| 435 |
_timeProcessData = SLLint.allocRing(TIME_AVARAGING_COUNT); |
|---|
| 436 |
_timeProcessAveRatio = _sampleRate / (_bufferLength * TIME_AVARAGING_COUNT); |
|---|
| 437 |
_timePrevStream = 0; |
|---|
| 438 |
_latency = 0; |
|---|
| 439 |
_prevFrameTime = 0; |
|---|
| 440 |
_frameRate = 1; |
|---|
| 441 |
|
|---|
| 442 |
_mmlString = null; |
|---|
| 443 |
_data = null; |
|---|
| 444 |
_soundChannel = null; |
|---|
| 445 |
|
|---|
| 446 |
// register sound streaming function |
|---|
| 447 |
_sound.addEventListener("sampleData", _streaming); |
|---|
| 448 |
|
|---|
| 449 |
// set mutex |
|---|
| 450 |
_mutex = this; |
|---|
| 451 |
} |
|---|
| 452 |
|
|---|
| 453 |
|
|---|
| 454 |
|
|---|
| 455 |
|
|---|
| 456 |
// interfaces for data preparation |
|---|
| 457 |
//---------------------------------------- |
|---|
| 458 |
/** Compile MML string to SiONData. |
|---|
| 459 |
* @param mml MML string to compile. |
|---|
| 460 |
* @param data SiONData to compile. The SiONDriver creates new SiONData instance when this argument is null. |
|---|
| 461 |
* @return Compiled data. |
|---|
| 462 |
*/ |
|---|
| 463 |
public function compile(mml:String, data:SiONData=null) : SiONData |
|---|
| 464 |
{ |
|---|
| 465 |
try { |
|---|
| 466 |
// stop sound |
|---|
| 467 |
stop(); |
|---|
| 468 |
|
|---|
| 469 |
// compile immediately |
|---|
| 470 |
var t:int = getTimer(); |
|---|
| 471 |
_prepareCompile(mml, data); |
|---|
| 472 |
_jobProgress = sequencer.compile(0); |
|---|
| 473 |
_timeCompile = getTimer() - t; |
|---|
| 474 |
_mmlString = null; |
|---|
| 475 |
} catch(e:Error) { |
|---|
| 476 |
// error |
|---|
| 477 |
if (_debugMode) throw e; |
|---|
| 478 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 479 |
} |
|---|
| 480 |
|
|---|
| 481 |
return _data; |
|---|
| 482 |
} |
|---|
| 483 |
|
|---|
| 484 |
|
|---|
| 485 |
/** Push queue job to compile MML string. Start compiling after calling startQueue.<br/> |
|---|
| 486 |
* @param mml MML string to compile. |
|---|
| 487 |
* @param data SiONData to compile. |
|---|
| 488 |
* @return Queue length. |
|---|
| 489 |
* @see #startQueue() |
|---|
| 490 |
*/ |
|---|
| 491 |
public function compileQueue(mml:String, data:SiONData) : int |
|---|
| 492 |
{ |
|---|
| 493 |
if (mml == null || data == null) return _jobQueue.length; |
|---|
| 494 |
return _jobQueue.push(new SiONDriverJob(mml, null, data, 2, false)); |
|---|
| 495 |
} |
|---|
| 496 |
|
|---|
| 497 |
|
|---|
| 498 |
|
|---|
| 499 |
|
|---|
| 500 |
// interfaces for sound rendering |
|---|
| 501 |
//---------------------------------------- |
|---|
| 502 |
/** Render wave data from MML string or SiONData. This method may take long time, please consider the using renderQueue() instead. |
|---|
| 503 |
* @param data SiONData or mml String to play. |
|---|
| 504 |
* @param renderBuffer Rendering target. null to create new buffer. The length of this argument limits the rendering length (except for 0). |
|---|
| 505 |
* @param renderBufferChannelCount Channel count of renderBuffer. 2 for stereo and 1 for monoral. |
|---|
| 506 |
* @param resetEffector reset all effectors before play data. |
|---|
| 507 |
* @return rendered wave data as Vector.<Number>. |
|---|
| 508 |
*/ |
|---|
| 509 |
public function render(data:*, renderBuffer:Vector.<Number>=null, renderBufferChannelCount:int=2, resetEffector:Boolean=true) : Vector.<Number> |
|---|
| 510 |
{ |
|---|
| 511 |
try { |
|---|
| 512 |
// stop sound |
|---|
| 513 |
stop(); |
|---|
| 514 |
|
|---|
| 515 |
// rendering immediately |
|---|
| 516 |
var t:int = getTimer(); |
|---|
| 517 |
_prepareRender(data, renderBuffer, renderBufferChannelCount, resetEffector); |
|---|
| 518 |
while(true) { if (_rendering()) break; } |
|---|
| 519 |
_timeRender = getTimer() - t; |
|---|
| 520 |
} catch (e:Error) { |
|---|
| 521 |
// error |
|---|
| 522 |
_removeAllEventListners(); |
|---|
| 523 |
if (_debugMode) throw e; |
|---|
| 524 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 525 |
} |
|---|
| 526 |
|
|---|
| 527 |
return _renderBuffer; |
|---|
| 528 |
} |
|---|
| 529 |
|
|---|
| 530 |
|
|---|
| 531 |
/** Push queue job to render sound. Start rendering after calling startQueue.<br/> |
|---|
| 532 |
* @param data SiONData or mml String to render. |
|---|
| 533 |
* @param renderBuffer Rendering target. The length of renderBuffer limits rendering length except for 0. |
|---|
| 534 |
* @param renderBufferChannelCount Channel count of renderBuffer. 2 for stereo and 1 for monoral. |
|---|
| 535 |
* @return Queue length. |
|---|
| 536 |
* @see #startQueue() |
|---|
| 537 |
*/ |
|---|
| 538 |
public function renderQueue(data:*, renderBuffer:Vector.<Number>, renderBufferChannelCount:int=2, resetEffector:Boolean=false) : int |
|---|
| 539 |
{ |
|---|
| 540 |
if (data == null || renderBuffer == null) return _jobQueue.length; |
|---|
| 541 |
|
|---|
| 542 |
if (data is String) { |
|---|
| 543 |
var compiled:SiONData = new SiONData(); |
|---|
| 544 |
_jobQueue.push(new SiONDriverJob(data as String, null, compiled, 2, false)); |
|---|
| 545 |
return _jobQueue.push(new SiONDriverJob(null, renderBuffer, compiled, renderBufferChannelCount, resetEffector)); |
|---|
| 546 |
} else |
|---|
| 547 |
if (data is SiONData) { |
|---|
| 548 |
return _jobQueue.push(new SiONDriverJob(null, renderBuffer, data as SiONData, renderBufferChannelCount, resetEffector)); |
|---|
| 549 |
} |
|---|
| 550 |
|
|---|
| 551 |
var e:Error = errorDataIncorrect(); |
|---|
| 552 |
if (_debugMode) throw e; |
|---|
| 553 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 554 |
return _jobQueue.length; |
|---|
| 555 |
} |
|---|
| 556 |
|
|---|
| 557 |
|
|---|
| 558 |
|
|---|
| 559 |
|
|---|
| 560 |
// interfaces for jobs queue |
|---|
| 561 |
//---------------------------------------- |
|---|
| 562 |
/** Execute all elements queued by compileQueue() and renderQueue(). |
|---|
| 563 |
* After calling this function, the SiONEvent.QUEUE_PROGRESS, SiONEvent.QUEUE_COMPLETE and ErrorEvent.ERROR events will be dispatched.<br/> |
|---|
| 564 |
* The SiONEvent.QUEUE_PROGRESS is dispatched when it's executing queued job.<br/> |
|---|
| 565 |
* The SiONEvent.QUEUE_COMPLETE is dispatched when finish all queued jobs.<br/> |
|---|
| 566 |
* The ErrorEvent.ERROR is dispatched when some error appears during the compile.<br/> |
|---|
| 567 |
* @param interval Interupting interval |
|---|
| 568 |
* @return Queue length. |
|---|
| 569 |
* @see #compileQueue() |
|---|
| 570 |
* @see #renderQueue() |
|---|
| 571 |
*/ |
|---|
| 572 |
public function startQueue(interval:int=500) : int |
|---|
| 573 |
{ |
|---|
| 574 |
try { |
|---|
| 575 |
stop(); |
|---|
| 576 |
_queueLength = _jobQueue.length; |
|---|
| 577 |
if (_jobQueue.length > 0) { |
|---|
| 578 |
_queueInterval = interval; |
|---|
| 579 |
_executeNextJob(); |
|---|
| 580 |
_queue_addAllEventListners(); |
|---|
| 581 |
} |
|---|
| 582 |
} catch (e:Error) { |
|---|
| 583 |
// error |
|---|
| 584 |
_removeAllEventListners(); |
|---|
| 585 |
_cancelAllJobs(); |
|---|
| 586 |
if (_debugMode) throw e; |
|---|
| 587 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 588 |
} |
|---|
| 589 |
return _queueLength; |
|---|
| 590 |
} |
|---|
| 591 |
|
|---|
| 592 |
|
|---|
| 593 |
/** Listen loading status of flash.media.Sound instance. |
|---|
| 594 |
* When SiONDriver.pauseWhileLoading is true, SiONDriver starts streaming after all Sound instances passed by this function are loaded. |
|---|
| 595 |
* @param sound Sound or SoundLoader instance to listern |
|---|
| 596 |
* @param prior listening priority |
|---|
| 597 |
* @see #pauseWhileLoading() |
|---|
| 598 |
* @see #clearLoadingSoundList() |
|---|
| 599 |
*/ |
|---|
| 600 |
public function listenSoundLoadingStatus(sound:*, prior:int=-99999) : void |
|---|
| 601 |
{ |
|---|
| 602 |
if (!sound is Sound && !sound is SoundLoader) throw errorCannotListenLoading(); |
|---|
| 603 |
if (_loadingSoundList.indexOf(sound) != -1) return; |
|---|
| 604 |
if (sound is Sound) { |
|---|
| 605 |
if (sound.bytesTotal == 0 || sound.bytesLoaded != sound.bytesTotal) { |
|---|
| 606 |
_loadingSoundList.push(sound); |
|---|
| 607 |
sound.addEventListener(Event.COMPLETE, _onSoundEvent, false, prior); |
|---|
| 608 |
sound.addEventListener(IOErrorEvent.IO_ERROR, _onSoundEvent, false, prior); |
|---|
| 609 |
} |
|---|
| 610 |
} else { // sound is SoundLoader |
|---|
| 611 |
if (sound.loadingFileCount > 0) { |
|---|
| 612 |
_loadingSoundList.push(sound); |
|---|
| 613 |
sound.addEventListener(Event.COMPLETE, _onSoundEvent, false, prior); |
|---|
| 614 |
sound.addEventListener(ErrorEvent.ERROR, _onSoundEvent, false, prior); |
|---|
| 615 |
} |
|---|
| 616 |
} |
|---|
| 617 |
} |
|---|
| 618 |
|
|---|
| 619 |
|
|---|
| 620 |
/** Clear all listening sound list registerd by SiONDriver.listenLoadingStatus(). |
|---|
| 621 |
*/ |
|---|
| 622 |
public function clearSoundLoadingList() : void |
|---|
| 623 |
{ |
|---|
| 624 |
_loadingSoundList.length = 0; |
|---|
| 625 |
} |
|---|
| 626 |
|
|---|
| 627 |
|
|---|
| 628 |
/** Set Sound Reference Table refered from #SAMPLER and #PCMWAVE commands. |
|---|
| 629 |
*/ |
|---|
| 630 |
public function setSoudReferenceTable(soundReferenceTable:* = null) : void |
|---|
| 631 |
{ |
|---|
| 632 |
SiOPMTable.instance.soundReference = soundReferenceTable || {}; |
|---|
| 633 |
} |
|---|
| 634 |
|
|---|
| 635 |
|
|---|
| 636 |
|
|---|
| 637 |
// interfaces for sound streaming |
|---|
| 638 |
//---------------------------------------- |
|---|
| 639 |
/** Play SiONData or MML string. |
|---|
| 640 |
* @param data SiONData or mml String to play. You can pass null when resume after pause or streaming without any data. |
|---|
| 641 |
* @param resetEffector reset all effectors before play data. |
|---|
| 642 |
* @return SoundChannel instance to play data. This instance is same as soundChannel property. |
|---|
| 643 |
* @see #soundChannel |
|---|
| 644 |
*/ |
|---|
| 645 |
public function play(data:*=null, resetEffector:Boolean=true) : SoundChannel |
|---|
| 646 |
{ |
|---|
| 647 |
try { |
|---|
| 648 |
if (_isPaused) { |
|---|
| 649 |
_isPaused = false; |
|---|
| 650 |
} else { |
|---|
| 651 |
// stop sound |
|---|
| 652 |
stop(); |
|---|
| 653 |
|
|---|
| 654 |
// preparation |
|---|
| 655 |
_prepareProcess(data, resetEffector); |
|---|
| 656 |
|
|---|
| 657 |
// initialize |
|---|
| 658 |
_timeProcessTotal = 0; |
|---|
| 659 |
for (var i:int=0; i<TIME_AVARAGING_COUNT; i++) { |
|---|
| 660 |
_timeProcessData.i = 0; |
|---|
| 661 |
_timeProcessData = _timeProcessData.next; |
|---|
| 662 |
} |
|---|
| 663 |
_isPaused = false; |
|---|
| 664 |
_isFinishSeqDispatched = (data == null); |
|---|
| 665 |
|
|---|
| 666 |
// start streaming |
|---|
| 667 |
_suspendStreaming = true; |
|---|
| 668 |
_soundChannel = _sound.play(); |
|---|
| 669 |
_soundChannel.soundTransform = _soundTransform; |
|---|
| 670 |
_process_addAllEventListners(); |
|---|
| 671 |
} |
|---|
| 672 |
} catch(e:Error) { |
|---|
| 673 |
// error |
|---|
| 674 |
if (_debugMode) throw e; |
|---|
| 675 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 676 |
} |
|---|
| 677 |
|
|---|
| 678 |
return _soundChannel; |
|---|
| 679 |
} |
|---|
| 680 |
|
|---|
| 681 |
|
|---|
| 682 |
/** Stop sound. */ |
|---|
| 683 |
public function stop() : void |
|---|
| 684 |
{ |
|---|
| 685 |
if (_soundChannel) { |
|---|
| 686 |
if (_inStreaming) { |
|---|
| 687 |
_preserveStop = true; |
|---|
| 688 |
} else { |
|---|
| 689 |
_removeAllEventListners(); |
|---|
| 690 |
_preserveStop = false; |
|---|
| 691 |
_soundChannel.stop(); |
|---|
| 692 |
_soundChannel = null; |
|---|
| 693 |
_latency = 0; |
|---|
| 694 |
_fader.stop(); |
|---|
| 695 |
_faderVolume = 1; |
|---|
| 696 |
_isPaused = false; |
|---|
| 697 |
_soundTransform.volume = _masterVolume; |
|---|
| 698 |
sequencer._sion_internal::_stopSequence(); |
|---|
| 699 |
|
|---|
| 700 |
// dispatch streaming stop event |
|---|
| 701 |
dispatchEvent(new SiONEvent(SiONEvent.STREAM_STOP, this)); |
|---|
| 702 |
} |
|---|
| 703 |
} |
|---|
| 704 |
} |
|---|
| 705 |
|
|---|
| 706 |
|
|---|
| 707 |
/** Reset signal processor. The effector and sequencer will not reset. If you want to all of effectors and sequencers, call SiONDriver.stop(). */ |
|---|
| 708 |
public function reset() : void |
|---|
| 709 |
{ |
|---|
| 710 |
sequencer._resetAllTracks(); |
|---|
| 711 |
} |
|---|
| 712 |
|
|---|
| 713 |
|
|---|
| 714 |
/** Pause sound. You can resume it by play() without any arguments. */ |
|---|
| 715 |
public function pause() : void |
|---|
| 716 |
{ |
|---|
| 717 |
_isPaused = true; |
|---|
| 718 |
} |
|---|
| 719 |
|
|---|
| 720 |
|
|---|
| 721 |
/** Play Sound as a background. This function should be called before play(). |
|---|
| 722 |
* @param sound Sound instance to play background. |
|---|
| 723 |
* @param mixLevel Mixing level (0-1). |
|---|
| 724 |
*/ |
|---|
| 725 |
public function setBackgroundSound(sound:Sound, mixLevel:Number=1, isLooping:Boolean=false) : void |
|---|
| 726 |
{ |
|---|
| 727 |
_backgroundSound = sound; |
|---|
| 728 |
_backgroundLevel = mixLevel; |
|---|
| 729 |
_backgroundLoop = isLooping; |
|---|
| 730 |
if (_backgroundBuffer == null) { |
|---|
| 731 |
_backgroundBuffer = new ByteArray(); |
|---|
| 732 |
_backgroundBuffer.length = _bufferLength * 8; |
|---|
| 733 |
} |
|---|
| 734 |
} |
|---|
| 735 |
|
|---|
| 736 |
|
|---|
| 737 |
/** Stop background sound. */ |
|---|
| 738 |
public function stopBackgroundSound() : void |
|---|
| 739 |
{ |
|---|
| 740 |
_backgroundSound = null; |
|---|
| 741 |
} |
|---|
| 742 |
|
|---|
| 743 |
|
|---|
| 744 |
/** Fade in. |
|---|
| 745 |
* @param term Fading time [second]. |
|---|
| 746 |
*/ |
|---|
| 747 |
public function fadeIn(term:Number) : void |
|---|
| 748 |
{ |
|---|
| 749 |
_fader.setFade(_fadeVolume, 0, 1, term * _sampleRate / _bufferLength); |
|---|
| 750 |
_dispatchFadingEvent = (hasEventListener(SiONEvent.FADE_PROGRESS)); |
|---|
| 751 |
} |
|---|
| 752 |
|
|---|
| 753 |
|
|---|
| 754 |
/** Fade out. |
|---|
| 755 |
* @param term Fading time [second]. |
|---|
| 756 |
*/ |
|---|
| 757 |
public function fadeOut(term:Number) : void |
|---|
| 758 |
{ |
|---|
| 759 |
_fader.setFade(_fadeVolume, 1, 0, term * _sampleRate / _bufferLength); |
|---|
| 760 |
_dispatchFadingEvent = (hasEventListener(SiONEvent.FADE_PROGRESS)); |
|---|
| 761 |
} |
|---|
| 762 |
|
|---|
| 763 |
|
|---|
| 764 |
/** Set timer interruption. |
|---|
| 765 |
* @param length16th Interupting interval in 16th beat. |
|---|
| 766 |
* @param callback Callback function. the Type is function():void. |
|---|
| 767 |
*/ |
|---|
| 768 |
public function setTimerInterruption(length16th:Number=1, callback:Function=null) : void |
|---|
| 769 |
{ |
|---|
| 770 |
_timerIntervalEvent.length = length16th * sequencer.setting.resolution * 0.0625; |
|---|
| 771 |
_timerCallback = (length16th > 0) ? callback : null; |
|---|
| 772 |
} |
|---|
| 773 |
|
|---|
| 774 |
|
|---|
| 775 |
/** Set callback interval of SiONTrackEvent.BEAT. |
|---|
| 776 |
* @param length16th Interval in 16th beat. 2^n is only available(1,2,4,8,16....). |
|---|
| 777 |
*/ |
|---|
| 778 |
public function setBeatCallbackInterval(length16th:Number=1) : void |
|---|
| 779 |
{ |
|---|
| 780 |
var filter:int = 1; |
|---|
| 781 |
while (length16th > 1.5) { |
|---|
| 782 |
filter <<= 1; |
|---|
| 783 |
length16th *= 0.5 |
|---|
| 784 |
} |
|---|
| 785 |
sequencer._setBeatCallbackFilter(filter - 1); |
|---|
| 786 |
} |
|---|
| 787 |
|
|---|
| 788 |
|
|---|
| 789 |
/** Force dispatch stream event. The SiONEvent.STREAM is dispatched only when the event listener is set BEFORE calling play(). You can let SiONDriver to dispatch SiONEvent.STREAM event by this function. |
|---|
| 790 |
* @param dispatch Set true to force dispatching. Or set false to not dispatching if there are no listeners. |
|---|
| 791 |
*/ |
|---|
| 792 |
_sion_internal function forceDispatchStreamEvent(dispatch:Boolean=true) : void |
|---|
| 793 |
{ |
|---|
| 794 |
_dispatchStreamEvent = dispatch || (hasEventListener(SiONEvent.STREAM)); |
|---|
| 795 |
} |
|---|
| 796 |
|
|---|
| 797 |
|
|---|
| 798 |
|
|---|
| 799 |
// Interface for public data registration |
|---|
| 800 |
//---------------------------------------- |
|---|
| 801 |
/** Set wave table data refered by %4. |
|---|
| 802 |
* @param index wave table number. |
|---|
| 803 |
* @param table wave shape vector ranges in -1 to 1. |
|---|
| 804 |
*/ |
|---|
| 805 |
public function setWaveTable(index:int, table:Vector.<Number>) : SiOPMWaveTable |
|---|
| 806 |
{ |
|---|
| 807 |
var len:int, bits:int=-1; |
|---|
| 808 |
for (len=table.length; len>0; len>>=1) bits++; |
|---|
| 809 |
if (bits<2) return null; |
|---|
| 810 |
var waveTable:Vector.<int> = SiONUtil.logTransVector(table, 1, null); |
|---|
| 811 |
waveTable.length = 1<<bits; |
|---|
| 812 |
return SiOPMTable._instance.registerWaveTable(index, waveTable); |
|---|
| 813 |
} |
|---|
| 814 |
|
|---|
| 815 |
|
|---|
| 816 |
/** Set PCM wave data rederd by %7. |
|---|
| 817 |
* @param index PCM data number. |
|---|
| 818 |
* @param data wave data, Sound, Vector.<Number> or Vector.<int> is available. The Sound instance is extracted internally, the maximum length to extract is SiOPMWavePCMData.maxSampleLengthFromSound[samples]. |
|---|
| 819 |
* @param samplingNote Sampling wave's original note number, this allows decimal number |
|---|
| 820 |
* @param keyRangeFrom Assigning key range starts from (not implemented in current version) |
|---|
| 821 |
* @param keyRangeTo Assigning key range ends at (not implemented in current version) |
|---|
| 822 |
* @param srcChannelCount channel count of source data, 1 for monoral, 2 for stereo. |
|---|
| 823 |
* @param channelCount channel count of this data, 1 for monoral, 2 for stereo, 0 sets same with srcChannelCount. |
|---|
| 824 |
* @see #org.si.sion.module.SiOPMWavePCMData.maxSampleLengthFromSound |
|---|
| 825 |
* @see #render() |
|---|
| 826 |
*/ |
|---|
| 827 |
public function setPCMWave(index:int, data:*, samplingNote:Number=68, keyRangeFrom:int=0, keyRangeTo:int=127, srcChannelCount:int=2, channelCount:int=0) : SiOPMWavePCMData |
|---|
| 828 |
{ |
|---|
| 829 |
var pcmVoice:SiMMLVoice = SiOPMTable._instance._getGlobalPCMVoice(index & (SiOPMTable.PCM_DATA_MAX-1)); |
|---|
| 830 |
var pcmTable:SiOPMWavePCMTable = pcmVoice.waveData as SiOPMWavePCMTable; |
|---|
| 831 |
return pcmTable.setSample(new SiOPMWavePCMData(data, int(samplingNote*64), srcChannelCount, channelCount), keyRangeFrom, keyRangeTo); |
|---|
| 832 |
} |
|---|
| 833 |
|
|---|
| 834 |
|
|---|
| 835 |
/** Set sampler wave data refered by %10. |
|---|
| 836 |
* @param index note number. 0-127 for bank0, 128-255 for bank1. |
|---|
| 837 |
* @param data wave data, Sound, Vector.<Number> or Vector.<int> is available. The Sound is extracted when the length is shorter than SiOPMWaveSamplerData.extractThreshold[msec]. |
|---|
| 838 |
* @param ignoreNoteOff True to set ignoring note off. |
|---|
| 839 |
* @param pan pan of this sample [-64 - 64]. |
|---|
| 840 |
* @param srcChannelCount channel count of source data, 1 for monoral, 2 for stereo. |
|---|
| 841 |
* @param channelCount channel count of this data, 1 for monoral, 2 for stereo, 0 sets same with srcChannelCount. |
|---|
| 842 |
* @return created data instance |
|---|
| 843 |
* @see #org.si.sion.module.SiOPMWaveSamplerData.extractThreshold |
|---|
| 844 |
* @see #render() |
|---|
| 845 |
*/ |
|---|
| 846 |
public function setSamplerWave(index:int, data:*, ignoreNoteOff:Boolean=false, pan:int=0, srcChannelCount:int=2, channelCount:int=0) : SiOPMWaveSamplerData |
|---|
| 847 |
{ |
|---|
| 848 |
return SiOPMTable._instance.registerSamplerData(index, data, ignoreNoteOff, pan, srcChannelCount, channelCount); |
|---|
| 849 |
} |
|---|
| 850 |
|
|---|
| 851 |
|
|---|
| 852 |
/** Set pcm voice |
|---|
| 853 |
* @param index PCM data number. |
|---|
| 854 |
* @param voice pcm voice to set, ussualy from SiONSoundFont |
|---|
| 855 |
* @see SiONSoundFont |
|---|
| 856 |
*/ |
|---|
| 857 |
public function setPCMVoice(index:int, voice:SiONVoice) : void |
|---|
| 858 |
{ |
|---|
| 859 |
SiOPMTable._instance._setGlobalPCMVoice(index & (SiOPMTable.PCM_DATA_MAX-1), voice); |
|---|
| 860 |
} |
|---|
| 861 |
|
|---|
| 862 |
|
|---|
| 863 |
/** Set sampler table |
|---|
| 864 |
* @param bank bank number |
|---|
| 865 |
* @param table sampler table class, ussualy from SiONSoundFont |
|---|
| 866 |
* @see SiONSoundFont |
|---|
| 867 |
*/ |
|---|
| 868 |
public function setSamplerTable(bank:int, table:SiOPMWaveSamplerTable) : void |
|---|
| 869 |
{ |
|---|
| 870 |
SiOPMTable._instance.samplerTables[bank & (SiOPMTable.SAMPLER_TABLE_MAX-1)] = table; |
|---|
| 871 |
} |
|---|
| 872 |
|
|---|
| 873 |
|
|---|
| 874 |
/** [NOT RECOMMENDED] This function is for a compatibility with previous versions, please use setPCMWave instead of this function. @see #setPCMWave(). */ |
|---|
| 875 |
public function setPCMData(index:int, data:Vector.<Number>, samplingOctave:int=5, keyRangeFrom:int=0, keyRangeTo:int=127, isSourceDataStereo:Boolean=false) : SiOPMWavePCMData |
|---|
| 876 |
{ |
|---|
| 877 |
return setPCMWave(index, data, samplingOctave*12+8, keyRangeFrom, keyRangeTo, (isSourceDataStereo)?2:1); |
|---|
| 878 |
} |
|---|
| 879 |
|
|---|
| 880 |
|
|---|
| 881 |
/** [NOT RECOMMENDED] This function is for a compatibility with previous versions, please use setPCMWave instead of this function. @see #setPCMWave(). */ |
|---|
| 882 |
public function setPCMSound(index:int, sound:Sound, samplingOctave:int=5, keyRangeFrom:int=0, keyRangeTo:int=127) : SiOPMWavePCMData |
|---|
| 883 |
{ |
|---|
| 884 |
return setPCMWave(index, sound, samplingOctave*12+8, keyRangeFrom, keyRangeTo, 1, 0); |
|---|
| 885 |
} |
|---|
| 886 |
|
|---|
| 887 |
|
|---|
| 888 |
/** [NOT RECOMMENDED] This function is for a compatibility with previous versions, please use setSamplerWave instead of this function. @see #setSamplerWave(). */ |
|---|
| 889 |
public function setSamplerData(index:int, data:Vector.<Number>, ignoreNoteOff:Boolean=false, channelCount:int=1) : SiOPMWaveSamplerData |
|---|
| 890 |
{ |
|---|
| 891 |
return setSamplerWave(index, data, ignoreNoteOff, 0, channelCount); |
|---|
| 892 |
} |
|---|
| 893 |
|
|---|
| 894 |
|
|---|
| 895 |
/** [NOT RECOMMENDED] This function is for a compatibility with previous versions, please use setSamplerWave instead of this function. @see #setSamplerWave(). */ |
|---|
| 896 |
public function setSamplerSound(index:int, sound:Sound, ignoreNoteOff:Boolean=false, channelCount:int=2) : SiOPMWaveSamplerData |
|---|
| 897 |
{ |
|---|
| 898 |
return setSamplerWave(index, sound, ignoreNoteOff, 0, channelCount); |
|---|
| 899 |
} |
|---|
| 900 |
|
|---|
| 901 |
|
|---|
| 902 |
/** Set envelop table data refered by @@,na,np,nt,nf,_@@,_na,_np,_nt and _nf. |
|---|
| 903 |
* @param index envelop table number. |
|---|
| 904 |
* @param table envelop table vector. |
|---|
| 905 |
* @param loopPoint returning point index of looping. -1 sets no loop. |
|---|
| 906 |
*/ |
|---|
| 907 |
public function setEnvelopTable(index:int, table:Vector.<int>, loopPoint:int=-1) : void |
|---|
| 908 |
{ |
|---|
| 909 |
SiMMLTable.registerMasterEnvelopTable(index, new SiMMLEnvelopTable(table, loopPoint)); |
|---|
| 910 |
} |
|---|
| 911 |
|
|---|
| 912 |
|
|---|
| 913 |
/** Set wave table data refered by %6. |
|---|
| 914 |
* @param index wave table number. |
|---|
| 915 |
* @param voice voice to register. |
|---|
| 916 |
*/ |
|---|
| 917 |
public function setVoice(index:int, voice:SiONVoice) : void |
|---|
| 918 |
{ |
|---|
| 919 |
if (!voice._isSuitableForFMVoice) throw errorNotGoodFMVoice(); |
|---|
| 920 |
SiMMLTable.registerMasterVoice(index, voice); |
|---|
| 921 |
} |
|---|
| 922 |
|
|---|
| 923 |
|
|---|
| 924 |
/** Clear all of WaveTables, FM Voices, EnvelopTables, Sampler waves and PCM waves. |
|---|
| 925 |
* @see #setWaveTable() |
|---|
| 926 |
* @see #setVoice() |
|---|
| 927 |
* @see #setEnvelopTable() |
|---|
| 928 |
* @see #setSamplerWave() |
|---|
| 929 |
* @see #setPCMWave() |
|---|
| 930 |
*/ |
|---|
| 931 |
public function clearAllUserTables() : void |
|---|
| 932 |
{ |
|---|
| 933 |
SiOPMTable.instance.resetAllUserTables(); |
|---|
| 934 |
SiMMLTable.instance.resetAllUserTables(); |
|---|
| 935 |
} |
|---|
| 936 |
|
|---|
| 937 |
|
|---|
| 938 |
|
|---|
| 939 |
|
|---|
| 940 |
// Interface for intaractivity |
|---|
| 941 |
//---------------------------------------- |
|---|
| 942 |
/** Play sound registered in sampler table (registered by setSamplerData()), same as noteOn(note, new SiONVoice(10), ...). |
|---|
| 943 |
* @param sampleNumber sample number [0-127]. |
|---|
| 944 |
* @param length note length in 16th beat. 0 sets no note off, this means you should call noteOff(). |
|---|
| 945 |
* @param delay note on delay units in 16th beat. |
|---|
| 946 |
* @param quant quantize in 16th beat. 0 sets no quantization. 4 sets quantization by 4th beat. |
|---|
| 947 |
* @param trackID new tracks id (0-65535). |
|---|
| 948 |
* @param isDisposable use disposable track. The disposable track will free automatically when finished rendering. |
|---|
| 949 |
* This means you should not keep a dieposable track in your code perpetually. |
|---|
| 950 |
* If you want to keep track, set this argument false. And after using, SiMMLTrack::setDisposal() to disposed by system.<br/> |
|---|
| 951 |
* [REMARKS] Not disposable track is kept perpetually in the system while streaming, this may causes critical performance loss. |
|---|
| 952 |
* @return SiMMLTrack to play the note. |
|---|
| 953 |
*/ |
|---|
| 954 |
public function playSound(sampleNumber:int, |
|---|
| 955 |
length:Number = 0, |
|---|
| 956 |
delay:Number = 0, |
|---|
| 957 |
quant:Number = 0, |
|---|
| 958 |
trackID:int = 0, |
|---|
| 959 |
isDisposable:Boolean = true) : SiMMLTrack |
|---|
| 960 |
{ |
|---|
| 961 |
var internalTrackID:int = (trackID & SiMMLTrack.TRACK_ID_FILTER) | SiMMLTrack.DRIVER_NOTE, |
|---|
| 962 |
mmlTrack:SiMMLTrack = null, |
|---|
| 963 |
delaySamples:Number = sequencer.calcSampleDelay(0, delay, quant); |
|---|
| 964 |
|
|---|
| 965 |
// check track id exception |
|---|
| 966 |
if (_noteOnExceptionMode != NEM_IGNORE) { |
|---|
| 967 |
// find a track sounds at same timing |
|---|
| 968 |
mmlTrack = sequencer._findActiveTrack(internalTrackID, delaySamples); |
|---|
| 969 |
if (_noteOnExceptionMode == NEM_REJECT && mmlTrack != null) return null; // reject |
|---|
| 970 |
else if (_noteOnExceptionMode == NEM_SHIFT) { // shift timing |
|---|
| 971 |
var step:int = sequencer.calcSampleLength(quant); |
|---|
| 972 |
while (mmlTrack) { |
|---|
| 973 |
delaySamples += step; |
|---|
| 974 |
mmlTrack = sequencer._findActiveTrack(internalTrackID, delaySamples); |
|---|
| 975 |
} |
|---|
| 976 |
} |
|---|
| 977 |
} |
|---|
| 978 |
|
|---|
| 979 |
mmlTrack = mmlTrack || sequencer._newControlableTrack(internalTrackID, isDisposable); |
|---|
| 980 |
if (mmlTrack) { |
|---|
| 981 |
mmlTrack.setChannelModuleType(10, 0); |
|---|
| 982 |
mmlTrack.keyOn(sampleNumber, length * sequencer.setting.resolution * 0.0625, delaySamples); |
|---|
| 983 |
} |
|---|
| 984 |
return mmlTrack; |
|---|
| 985 |
} |
|---|
| 986 |
|
|---|
| 987 |
|
|---|
| 988 |
/** Note on. This function only is available after play(). The NOTE_ON_STREAM event is dispatched inside. |
|---|
| 989 |
* @param note note number [0-127]. |
|---|
| 990 |
* @param voice SiONVoice to play note. You can specify null, but it sets only a default square wave. |
|---|
| 991 |
* @param length note length in 16th beat. 0 sets no note off, this means you should call noteOff(). |
|---|
| 992 |
* @param delay note on delay units in 16th beat. |
|---|
| 993 |
* @param quant quantize in 16th beat. 0 sets no quantization. 4 sets quantization by 4th beat. |
|---|
| 994 |
* @param trackID new tracks id (0-65535). |
|---|
| 995 |
* @param isDisposable use disposable track. The disposable track will free automatically when finished rendering. |
|---|
| 996 |
* This means you should not keep a dieposable track in your code perpetually. |
|---|
| 997 |
* If you want to keep track, set this argument false. And after using, call SiMMLTrack::setDisposal() to disposed by system.<br/> |
|---|
| 998 |
* [REMARKS] Not disposable track is kept in the system perpetually while streaming, this may causes critical performance loss. |
|---|
| 999 |
* @return SiMMLTrack to play the note. |
|---|
| 1000 |
*/ |
|---|
| 1001 |
public function noteOn(note:int, |
|---|
| 1002 |
voice:SiONVoice = null, |
|---|
| 1003 |
length:Number = 0, |
|---|
| 1004 |
delay:Number = 0, |
|---|
| 1005 |
quant:Number = 0, |
|---|
| 1006 |
trackID:int = 0, |
|---|
| 1007 |
isDisposable:Boolean = true) : SiMMLTrack |
|---|
| 1008 |
{ |
|---|
| 1009 |
var internalTrackID:int = (trackID & SiMMLTrack.TRACK_ID_FILTER) | SiMMLTrack.DRIVER_NOTE, |
|---|
| 1010 |
mmlTrack:SiMMLTrack = null, |
|---|
| 1011 |
delaySamples:Number = sequencer.calcSampleDelay(0, delay, quant); |
|---|
| 1012 |
|
|---|
| 1013 |
// check track id exception |
|---|
| 1014 |
if (_noteOnExceptionMode != NEM_IGNORE) { |
|---|
| 1015 |
// find a track sounds at same timing |
|---|
| 1016 |
mmlTrack = sequencer._findActiveTrack(internalTrackID, delaySamples); |
|---|
| 1017 |
if (_noteOnExceptionMode == NEM_REJECT && mmlTrack != null) return null; // reject |
|---|
| 1018 |
else if (_noteOnExceptionMode == NEM_SHIFT) { // shift timing |
|---|
| 1019 |
var step:int = sequencer.calcSampleLength(quant); |
|---|
| 1020 |
while (mmlTrack) { |
|---|
| 1021 |
delaySamples += step; |
|---|
| 1022 |
mmlTrack = sequencer._findActiveTrack(internalTrackID, delaySamples); |
|---|
| 1023 |
} |
|---|
| 1024 |
} |
|---|
| 1025 |
} |
|---|
| 1026 |
|
|---|
| 1027 |
mmlTrack = mmlTrack || sequencer._newControlableTrack(internalTrackID, isDisposable); |
|---|
| 1028 |
if (mmlTrack) { |
|---|
| 1029 |
if (voice) voice.updateTrackVoice(mmlTrack); |
|---|
| 1030 |
mmlTrack.keyOn(note, length * sequencer.setting.resolution * 0.0625, delaySamples); |
|---|
| 1031 |
} |
|---|
| 1032 |
return mmlTrack; |
|---|
| 1033 |
} |
|---|
| 1034 |
|
|---|
| 1035 |
|
|---|
| 1036 |
/** Note off. This function only is available after play(). The NOTE_OFF_STREAM event is dispatched inside. |
|---|
| 1037 |
* @param note note number [-1-127]. The value of -1 ignores note number. |
|---|
| 1038 |
* @param trackID track id to note off. |
|---|
| 1039 |
* @param delay note off delay units in 16th beat. |
|---|
| 1040 |
* @param quant quantize in 16th beat. 0 sets no quantization. 4 sets quantization by 4th beat. |
|---|
| 1041 |
* @param stopImmediately stop sound with reseting channel's process |
|---|
| 1042 |
* @return All SiMMLTracks switched key off. |
|---|
| 1043 |
*/ |
|---|
| 1044 |
public function noteOff(note:int, trackID:int=0, delay:Number=0, quant:Number=0, stopImmediately:Boolean=false) : Vector.<SiMMLTrack> |
|---|
| 1045 |
{ |
|---|
| 1046 |
var internalTrackID:int = (trackID & SiMMLTrack.TRACK_ID_FILTER) | SiMMLTrack.DRIVER_NOTE, |
|---|
| 1047 |
delaySamples:int = sequencer.calcSampleDelay(0, delay, quant), n:int, |
|---|
| 1048 |
tracks:Vector.<SiMMLTrack> = new Vector.<SiMMLTrack>(); |
|---|
| 1049 |
for each (var mmlTrack:SiMMLTrack in sequencer.tracks) { |
|---|
| 1050 |
if (mmlTrack._sion_sequencer_internal::_internalTrackID == internalTrackID) { |
|---|
| 1051 |
if (note == -1 || (note == mmlTrack.note && mmlTrack.channel.isNoteOn)) { |
|---|
| 1052 |
mmlTrack.keyOff(delaySamples, stopImmediately); |
|---|
| 1053 |
tracks.push(mmlTrack); |
|---|
| 1054 |
} else if (mmlTrack.executor.noteWaitingFor == note) { |
|---|
| 1055 |
// if this track is waiting for starting sound ... |
|---|
| 1056 |
mmlTrack.keyOn(note, 1, delaySamples); |
|---|
| 1057 |
tracks.push(mmlTrack); |
|---|
| 1058 |
} |
|---|
| 1059 |
} |
|---|
| 1060 |
} |
|---|
| 1061 |
return tracks; |
|---|
| 1062 |
} |
|---|
| 1063 |
|
|---|
| 1064 |
|
|---|
| 1065 |
/** Play sequences with synchronizing. This function only is available after play(). |
|---|
| 1066 |
* @param data The SiONData including sequences. This data is used only for sequences. The system ignores wave, envelop and voice data. |
|---|
| 1067 |
* @param voice SiONVoice to play sequence. The voice setting in the sequence has priority. |
|---|
| 1068 |
* @param length note length in 16th beat. 0 sets no note off, this means you should call noteOff(). |
|---|
| 1069 |
* @param delay note on delay units in 16th beat. |
|---|
| 1070 |
* @param quant quantize in 16th beat. 0 sets no quantization. 4 sets quantization by 4th beat. |
|---|
| 1071 |
* @param trackID new tracks id (0-65535). |
|---|
| 1072 |
* @param isDisposable use disposable track. The disposable track will free automatically when finished rendering. |
|---|
| 1073 |
* This means you should not keep a dieposable track in your code perpetually. |
|---|
| 1074 |
* If you want to keep track, set this argument false. And after using, call SiMMLTrack::setDisposal() to disposed by system.<br/> |
|---|
| 1075 |
* [REMARKS] Not disposable track is kept in the system perpetually while streaming, this may causes critical performance loss. |
|---|
| 1076 |
* @return list of SiMMLTracks to play sequence. |
|---|
| 1077 |
*/ |
|---|
| 1078 |
public function sequenceOn(data:SiONData, |
|---|
| 1079 |
voice:SiONVoice = null, |
|---|
| 1080 |
length:Number = 0, |
|---|
| 1081 |
delay:Number = 0, |
|---|
| 1082 |
quant:Number = 1, |
|---|
| 1083 |
trackID:int = 0, |
|---|
| 1084 |
isDisposable:Boolean = true) : Vector.<SiMMLTrack> |
|---|
| 1085 |
{ |
|---|
| 1086 |
var internalTrackID:int = (trackID & SiMMLTrack.TRACK_ID_FILTER) | SiMMLTrack.DRIVER_SEQUENCE, |
|---|
| 1087 |
mmlTrack:SiMMLTrack, |
|---|
| 1088 |
tracks:Vector.<SiMMLTrack> = new Vector.<SiMMLTrack>(), |
|---|
| 1089 |
seq:MMLSequence = data.sequenceGroup.headSequence, |
|---|
| 1090 |
delaySamples:int = sequencer.calcSampleDelay(0, delay, quant), |
|---|
| 1091 |
lengthSamples:int = sequencer.calcSampleLength(length); |
|---|
| 1092 |
|
|---|
| 1093 |
// create new sequence tracks |
|---|
| 1094 |
while (seq) { |
|---|
| 1095 |
if (seq.isActive) { |
|---|
| 1096 |
mmlTrack = sequencer._newControlableTrack(internalTrackID, isDisposable); |
|---|
| 1097 |
mmlTrack.sequenceOn(seq, lengthSamples, delaySamples); |
|---|
| 1098 |
if (voice) voice.updateTrackVoice(mmlTrack); |
|---|
| 1099 |
tracks.push(mmlTrack); |
|---|
| 1100 |
} |
|---|
| 1101 |
seq = seq.nextSequence; |
|---|
| 1102 |
} |
|---|
| 1103 |
return tracks; |
|---|
| 1104 |
} |
|---|
| 1105 |
|
|---|
| 1106 |
|
|---|
| 1107 |
/** Stop the sequences with synchronizing. This function only is available after play(). |
|---|
| 1108 |
* @param trackID tracks id to stop. |
|---|
| 1109 |
* @param delay sequence off delay units in 16th beat. |
|---|
| 1110 |
* @param quant quantize in 16th beat. 0 sets no quantization. 4 sets quantization by 4th beat. |
|---|
| 1111 |
* @param stopWithReset stop sound with reseting channel's process |
|---|
| 1112 |
* @return list of SiMMLTracks stopped to play sequence. |
|---|
| 1113 |
*/ |
|---|
| 1114 |
public function sequenceOff(trackID:int, delay:Number=0, quant:Number=1, stopWithReset:Boolean=false) : Vector.<SiMMLTrack> |
|---|
| 1115 |
{ |
|---|
| 1116 |
var internalTrackID:int = (trackID & SiMMLTrack.TRACK_ID_FILTER) | SiMMLTrack.DRIVER_SEQUENCE, |
|---|
| 1117 |
delaySamples:int = sequencer.calcSampleDelay(0, delay, quant), stoppedTrack:SiMMLTrack = null, |
|---|
| 1118 |
tracks:Vector.<SiMMLTrack> = new Vector.<SiMMLTrack>(); |
|---|
| 1119 |
for each (var mmlTrack:SiMMLTrack in sequencer.tracks) { |
|---|
| 1120 |
if (mmlTrack._sion_sequencer_internal::_internalTrackID == internalTrackID) { |
|---|
| 1121 |
mmlTrack.sequenceOff(delaySamples, stopWithReset); |
|---|
| 1122 |
tracks.push(mmlTrack); |
|---|
| 1123 |
} |
|---|
| 1124 |
} |
|---|
| 1125 |
return tracks; |
|---|
| 1126 |
} |
|---|
| 1127 |
|
|---|
| 1128 |
|
|---|
| 1129 |
/** Create new user controlable track. This function only is available after play(). |
|---|
| 1130 |
* @trackID new user controlable track's ID. |
|---|
| 1131 |
* @return new user controlable track. This track is NOT disposable. |
|---|
| 1132 |
*/ |
|---|
| 1133 |
public function newUserControlableTrack(trackID:int=0) : SiMMLTrack |
|---|
| 1134 |
{ |
|---|
| 1135 |
var internalTrackID:int = (trackID & SiMMLTrack.TRACK_ID_FILTER) | SiMMLTrack.USER_CONTROLLED; |
|---|
| 1136 |
return sequencer._newControlableTrack(internalTrackID, false); |
|---|
| 1137 |
} |
|---|
| 1138 |
|
|---|
| 1139 |
|
|---|
| 1140 |
|
|---|
| 1141 |
|
|---|
| 1142 |
//==================================================================================================== |
|---|
| 1143 |
// Internal uses |
|---|
| 1144 |
//==================================================================================================== |
|---|
| 1145 |
// callback for event trigger |
|---|
| 1146 |
//---------------------------------------- |
|---|
| 1147 |
// call back when sound streaming |
|---|
| 1148 |
private function _callbackEventTriggerOn(track:SiMMLTrack) : Boolean |
|---|
| 1149 |
{ |
|---|
| 1150 |
return _publishEventTrigger(track, track.eventTriggerTypeOn, SiONTrackEvent.NOTE_ON_FRAME, SiONTrackEvent.NOTE_ON_STREAM); |
|---|
| 1151 |
} |
|---|
| 1152 |
|
|---|
| 1153 |
// call back when sound streaming |
|---|
| 1154 |
private function _callbackEventTriggerOff(track:SiMMLTrack) : Boolean |
|---|
| 1155 |
{ |
|---|
| 1156 |
return _publishEventTrigger(track, track.eventTriggerTypeOff, SiONTrackEvent.NOTE_OFF_FRAME, SiONTrackEvent.NOTE_OFF_STREAM); |
|---|
| 1157 |
} |
|---|
| 1158 |
|
|---|
| 1159 |
// publish event trigger |
|---|
| 1160 |
private function _publishEventTrigger(track:SiMMLTrack, type:int, frameEvent:String, streamEvent:String) : Boolean |
|---|
| 1161 |
{ |
|---|
| 1162 |
var event:SiONTrackEvent; |
|---|
| 1163 |
if (type & 1) { // frame event. dispatch later |
|---|
| 1164 |
event = new SiONTrackEvent(frameEvent, this, track); |
|---|
| 1165 |
_trackEventQueue.push(event); |
|---|
| 1166 |
} |
|---|
| 1167 |
if (type & 2) { // sound event. dispatch immediately |
|---|
| 1168 |
event = new SiONTrackEvent(streamEvent, this, track); |
|---|
| 1169 |
dispatchEvent(event); |
|---|
| 1170 |
return !(event.isDefaultPrevented()); |
|---|
| 1171 |
} |
|---|
| 1172 |
return true; |
|---|
| 1173 |
} |
|---|
| 1174 |
|
|---|
| 1175 |
// call back when tempo changed |
|---|
| 1176 |
private function _callbackTempoChanged(bufferIndex:int) : void |
|---|
| 1177 |
{ |
|---|
| 1178 |
var event:SiONTrackEvent = new SiONTrackEvent(SiONTrackEvent.CHANGE_BPM, this, null, bufferIndex); |
|---|
| 1179 |
_trackEventQueue.push(event); |
|---|
| 1180 |
} |
|---|
| 1181 |
|
|---|
| 1182 |
// call back on beat |
|---|
| 1183 |
private function _callbackBeat(bufferIndex:int, beatCounter:int) : void |
|---|
| 1184 |
{ |
|---|
| 1185 |
var event:SiONTrackEvent = new SiONTrackEvent(SiONTrackEvent.BEAT, this, null, bufferIndex, 0, beatCounter); |
|---|
| 1186 |
_trackEventQueue.push(event); |
|---|
| 1187 |
} |
|---|
| 1188 |
|
|---|
| 1189 |
|
|---|
| 1190 |
|
|---|
| 1191 |
|
|---|
| 1192 |
// operate event listener |
|---|
| 1193 |
//---------------------------------------- |
|---|
| 1194 |
// add all event listners |
|---|
| 1195 |
private function _queue_addAllEventListners() : void |
|---|
| 1196 |
{ |
|---|
| 1197 |
if (_listenEvent != NO_LISTEN) throw errorDriverBusy(LISTEN_QUEUE); |
|---|
| 1198 |
addEventListener(Event.ENTER_FRAME, _queue_onEnterFrame, false, _eventListenerPrior); |
|---|
| 1199 |
_listenEvent = LISTEN_QUEUE; |
|---|
| 1200 |
} |
|---|
| 1201 |
|
|---|
| 1202 |
|
|---|
| 1203 |
// add all event listners |
|---|
| 1204 |
private function _process_addAllEventListners() : void |
|---|
| 1205 |
{ |
|---|
| 1206 |
if (_listenEvent != NO_LISTEN) throw errorDriverBusy(LISTEN_PROCESS); |
|---|
| 1207 |
addEventListener(Event.ENTER_FRAME, _process_onEnterFrame, false, _eventListenerPrior); |
|---|
| 1208 |
if (hasEventListener(SiONTrackEvent.BEAT)) sequencer._setBeatCallback(_callbackBeat); |
|---|
| 1209 |
else sequencer._setBeatCallback(null); |
|---|
| 1210 |
_dispatchStreamEvent = (hasEventListener(SiONEvent.STREAM)); |
|---|
| 1211 |
_prevFrameTime = getTimer(); |
|---|
| 1212 |
_listenEvent = LISTEN_PROCESS; |
|---|
| 1213 |
} |
|---|
| 1214 |
|
|---|
| 1215 |
|
|---|
| 1216 |
// remove all event listners |
|---|
| 1217 |
private function _removeAllEventListners() : void |
|---|
| 1218 |
{ |
|---|
| 1219 |
switch (_listenEvent) { |
|---|
| 1220 |
case LISTEN_QUEUE: |
|---|
| 1221 |
removeEventListener(Event.ENTER_FRAME, _queue_onEnterFrame); |
|---|
| 1222 |
break; |
|---|
| 1223 |
case LISTEN_PROCESS: |
|---|
| 1224 |
removeEventListener(Event.ENTER_FRAME, _process_onEnterFrame); |
|---|
| 1225 |
sequencer._setBeatCallback(null); |
|---|
| 1226 |
_dispatchStreamEvent = false; |
|---|
| 1227 |
break; |
|---|
| 1228 |
} |
|---|
| 1229 |
_listenEvent = NO_LISTEN; |
|---|
| 1230 |
} |
|---|
| 1231 |
|
|---|
| 1232 |
|
|---|
| 1233 |
// handler for Sound COMPLETE/IO_ERROR Event |
|---|
| 1234 |
private function _onSoundEvent(e:Event) : void |
|---|
| 1235 |
{ |
|---|
| 1236 |
if (e.target is Sound) { |
|---|
| 1237 |
e.target.removeEventListener(Event.COMPLETE, _onSoundEvent); |
|---|
| 1238 |
e.target.removeEventListener(IOErrorEvent.IO_ERROR, _onSoundEvent); |
|---|
| 1239 |
} else { // e.target is SoundLoader |
|---|
| 1240 |
e.target.removeEventListener(Event.COMPLETE, _onSoundEvent); |
|---|
| 1241 |
e.target.removeEventListener(ErrorEvent.ERROR, _onSoundEvent); |
|---|
| 1242 |
} |
|---|
| 1243 |
var i:int = _loadingSoundList.indexOf(e.target); |
|---|
| 1244 |
if (i != -1) _loadingSoundList.splice(i, 1); |
|---|
| 1245 |
} |
|---|
| 1246 |
|
|---|
| 1247 |
|
|---|
| 1248 |
|
|---|
| 1249 |
|
|---|
| 1250 |
// parse |
|---|
| 1251 |
//---------------------------------------- |
|---|
| 1252 |
// parse system command on SiONDriver |
|---|
| 1253 |
private function _parseSystemCommand(systemCommands:Array) : Boolean |
|---|
| 1254 |
{ |
|---|
| 1255 |
var id:int, wcol:uint, effectSet:Boolean = false; |
|---|
| 1256 |
for each (var cmd:* in systemCommands) { |
|---|
| 1257 |
switch(cmd.command){ |
|---|
| 1258 |
case "#EFFECT": |
|---|
| 1259 |
effectSet = true; |
|---|
| 1260 |
effector.parseMML(cmd.number, cmd.content, cmd.postfix); |
|---|
| 1261 |
break; |
|---|
| 1262 |
case "#WAVCOLOR": |
|---|
| 1263 |
case "#WAVC": |
|---|
| 1264 |
wcol = parseInt(cmd.content, 16); |
|---|
| 1265 |
setWaveTable(cmd.number, SiONUtil.waveColor(wcol)); |
|---|
| 1266 |
break; |
|---|
| 1267 |
} |
|---|
| 1268 |
} |
|---|
| 1269 |
return effectSet; |
|---|
| 1270 |
} |
|---|
| 1271 |
|
|---|
| 1272 |
|
|---|
| 1273 |
|
|---|
| 1274 |
|
|---|
| 1275 |
// jobs queue |
|---|
| 1276 |
//---------------------------------------- |
|---|
| 1277 |
// cancel |
|---|
| 1278 |
private function _cancelAllJobs() : void |
|---|
| 1279 |
{ |
|---|
| 1280 |
_data = null; |
|---|
| 1281 |
_mmlString = null; |
|---|
| 1282 |
_currentJob = 0; |
|---|
| 1283 |
_jobProgress = 0; |
|---|
| 1284 |
_jobQueue.length = 0; |
|---|
| 1285 |
_queueLength = 0; |
|---|
| 1286 |
_removeAllEventListners(); |
|---|
| 1287 |
dispatchEvent(new SiONEvent(SiONEvent.QUEUE_CANCEL, this, null)); |
|---|
| 1288 |
} |
|---|
| 1289 |
|
|---|
| 1290 |
|
|---|
| 1291 |
// next job |
|---|
| 1292 |
private function _executeNextJob() : Boolean |
|---|
| 1293 |
{ |
|---|
| 1294 |
_data = null; |
|---|
| 1295 |
_mmlString = null; |
|---|
| 1296 |
_currentJob = 0; |
|---|
| 1297 |
if (_jobQueue.length == 0) { |
|---|
| 1298 |
_queueLength = 0; |
|---|
| 1299 |
_removeAllEventListners(); |
|---|
| 1300 |
dispatchEvent(new SiONEvent(SiONEvent.QUEUE_COMPLETE, this, null)); |
|---|
| 1301 |
return true; |
|---|
| 1302 |
} |
|---|
| 1303 |
|
|---|
| 1304 |
var queue:SiONDriverJob = _jobQueue.shift(); |
|---|
| 1305 |
if (queue.mml) _prepareCompile(queue.mml, queue.data); |
|---|
| 1306 |
else _prepareRender(queue.data, queue.buffer, queue.channelCount, queue.resetEffector); |
|---|
| 1307 |
return false; |
|---|
| 1308 |
} |
|---|
| 1309 |
|
|---|
| 1310 |
|
|---|
| 1311 |
// on enterFrame |
|---|
| 1312 |
private function _queue_onEnterFrame(e:Event) : void |
|---|
| 1313 |
{ |
|---|
| 1314 |
try { |
|---|
| 1315 |
var event:SiONEvent, t:int = getTimer(); |
|---|
| 1316 |
|
|---|
| 1317 |
switch (_currentJob) { |
|---|
| 1318 |
case 1: // compile |
|---|
| 1319 |
_jobProgress = sequencer.compile(_queueInterval); |
|---|
| 1320 |
_timeCompile += getTimer() - t; |
|---|
| 1321 |
break; |
|---|
| 1322 |
case 2: // render |
|---|
| 1323 |
_jobProgress += (1 - _jobProgress) * 0.5; |
|---|
| 1324 |
while (getTimer() - t <= _queueInterval) { |
|---|
| 1325 |
if (_rendering()) { |
|---|
| 1326 |
_jobProgress = 1; |
|---|
| 1327 |
break; |
|---|
| 1328 |
} |
|---|
| 1329 |
} |
|---|
| 1330 |
_timeRender += getTimer() - t; |
|---|
| 1331 |
break; |
|---|
| 1332 |
} |
|---|
| 1333 |
|
|---|
| 1334 |
// finish job |
|---|
| 1335 |
if (_jobProgress == 1) { |
|---|
| 1336 |
// finish all jobs |
|---|
| 1337 |
if (_executeNextJob()) return; |
|---|
| 1338 |
} |
|---|
| 1339 |
|
|---|
| 1340 |
// progress |
|---|
| 1341 |
event = new SiONEvent(SiONEvent.QUEUE_PROGRESS, this, null, true); |
|---|
| 1342 |
dispatchEvent(event); |
|---|
| 1343 |
if (event.isDefaultPrevented()) _cancelAllJobs(); // canceled |
|---|
| 1344 |
} catch (e:Error) { |
|---|
| 1345 |
// error |
|---|
| 1346 |
_removeAllEventListners(); |
|---|
| 1347 |
_cancelAllJobs(); |
|---|
| 1348 |
if (_debugMode) throw e; |
|---|
| 1349 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 1350 |
} |
|---|
| 1351 |
} |
|---|
| 1352 |
|
|---|
| 1353 |
|
|---|
| 1354 |
|
|---|
| 1355 |
|
|---|
| 1356 |
// compile |
|---|
| 1357 |
//---------------------------------------- |
|---|
| 1358 |
// prepare to compile |
|---|
| 1359 |
private function _prepareCompile(mml:String, data:SiONData) : void |
|---|
| 1360 |
{ |
|---|
| 1361 |
if (data) data.clear(); |
|---|
| 1362 |
_data = data || new SiONData(); |
|---|
| 1363 |
_mmlString = mml; |
|---|
| 1364 |
sequencer.prepareCompile(_data, _mmlString); |
|---|
| 1365 |
_jobProgress = 0.01; |
|---|
| 1366 |
_timeCompile = 0; |
|---|
| 1367 |
_currentJob = 1; |
|---|
| 1368 |
} |
|---|
| 1369 |
|
|---|
| 1370 |
|
|---|
| 1371 |
|
|---|
| 1372 |
|
|---|
| 1373 |
// render |
|---|
| 1374 |
//---------------------------------------- |
|---|
| 1375 |
// prepare for rendering |
|---|
| 1376 |
private function _prepareRender(data:*, renderBuffer:Vector.<Number>, renderBufferChannelCount:int, resetEffector:Boolean) : void |
|---|
| 1377 |
{ |
|---|
| 1378 |
// same preparation as streaming |
|---|
| 1379 |
_prepareProcess(data, resetEffector); |
|---|
| 1380 |
|
|---|
| 1381 |
// prepare rendering buffer |
|---|
| 1382 |
_renderBuffer = renderBuffer || new Vector.<Number>(); |
|---|
| 1383 |
_renderBufferChannelCount = (renderBufferChannelCount==2) ? 2 : 1; |
|---|
| 1384 |
_renderBufferSizeMax = _renderBuffer.length; |
|---|
| 1385 |
_renderBufferIndex = 0; |
|---|
| 1386 |
|
|---|
| 1387 |
// initialize parameters |
|---|
| 1388 |
_jobProgress = 0.01; |
|---|
| 1389 |
_timeRender = 0; |
|---|
| 1390 |
_currentJob = 2; |
|---|
| 1391 |
} |
|---|
| 1392 |
|
|---|
| 1393 |
|
|---|
| 1394 |
// rendering @return true when finished rendering. |
|---|
| 1395 |
private function _rendering() : Boolean |
|---|
| 1396 |
{ |
|---|
| 1397 |
var i:int, j:int, imax:int, extention:int, |
|---|
| 1398 |
output:Vector.<Number> = module.output, |
|---|
| 1399 |
finished:Boolean = false; |
|---|
| 1400 |
|
|---|
| 1401 |
// processing |
|---|
| 1402 |
module._beginProcess(); |
|---|
| 1403 |
effector._beginProcess(); |
|---|
| 1404 |
sequencer._process(); |
|---|
| 1405 |
effector._endProcess(); |
|---|
| 1406 |
module._endProcess(); |
|---|
| 1407 |
|
|---|
| 1408 |
// limit rendering length |
|---|
| 1409 |
imax = _bufferLength<<1; |
|---|
| 1410 |
extention = _bufferLength<<(_renderBufferChannelCount-1); |
|---|
| 1411 |
if (_renderBufferSizeMax != 0 && _renderBufferSizeMax < _renderBufferIndex+extention) { |
|---|
| 1412 |
extention = _renderBufferSizeMax - _renderBufferIndex; |
|---|
| 1413 |
finished = true; |
|---|
| 1414 |
} |
|---|
| 1415 |
|
|---|
| 1416 |
// extend buffer |
|---|
| 1417 |
if (_renderBuffer.length < _renderBufferIndex+extention) { |
|---|
| 1418 |
_renderBuffer.length = _renderBufferIndex+extention; |
|---|
| 1419 |
} |
|---|
| 1420 |
|
|---|
| 1421 |
// copy output |
|---|
| 1422 |
if (_renderBufferChannelCount==2) { |
|---|
| 1423 |
for (i=0, j=_renderBufferIndex; i<imax; i++, j++) { |
|---|
| 1424 |
_renderBuffer[j] = output[i]; |
|---|
| 1425 |
} |
|---|
| 1426 |
} else { |
|---|
| 1427 |
for (i=0, j=_renderBufferIndex; i<imax; i+=2, j++) { |
|---|
| 1428 |
_renderBuffer[j] = output[i]; |
|---|
| 1429 |
} |
|---|
| 1430 |
} |
|---|
| 1431 |
|
|---|
| 1432 |
// incerement index |
|---|
| 1433 |
_renderBufferIndex += extention; |
|---|
| 1434 |
|
|---|
| 1435 |
return (finished || (_renderBufferSizeMax==0 && sequencer.isFinished)); |
|---|
| 1436 |
} |
|---|
| 1437 |
|
|---|
| 1438 |
|
|---|
| 1439 |
|
|---|
| 1440 |
|
|---|
| 1441 |
// process |
|---|
| 1442 |
//---------------------------------------- |
|---|
| 1443 |
// prepare for processing |
|---|
| 1444 |
private function _prepareProcess(data:*, resetEffector:Boolean) : void |
|---|
| 1445 |
{ |
|---|
| 1446 |
if (data is String) { |
|---|
| 1447 |
// compile mml and play |
|---|
| 1448 |
_tempData = _tempData || new SiONData(); |
|---|
| 1449 |
_data = compile(data as String, _tempData); |
|---|
| 1450 |
} else { |
|---|
| 1451 |
// type check and play |
|---|
| 1452 |
if (!(data == null || data is SiONData)) throw errorDataIncorrect(); |
|---|
| 1453 |
_data = data; |
|---|
| 1454 |
} |
|---|
| 1455 |
|
|---|
| 1456 |
// THESE FUNCTIONS ORDER IS VERY IMPORTANT !! |
|---|
| 1457 |
module.initialize(_channelCount, _bitRate, _bufferLength); // initialize DSP |
|---|
| 1458 |
module.reset(); // reset all channels |
|---|
| 1459 |
if (resetEffector) effector.initialize(); // initialize (or reset) effectors |
|---|
| 1460 |
else effector._reset(); |
|---|
| 1461 |
sequencer._prepareProcess(_data, _sampleRate, _bufferLength); // set sequencer tracks (should be called after module.reset()) |
|---|
| 1462 |
if (_data) _parseSystemCommand(_data.systemCommands); // parse #EFFECT command (should be called after effector._reset()) |
|---|
| 1463 |
effector._prepareProcess(); // set effector connections |
|---|
| 1464 |
_trackEventQueue.length = 0; // clear event que |
|---|
| 1465 |
|
|---|
| 1466 |
// set position |
|---|
| 1467 |
if (_data && _position > 0) { |
|---|
| 1468 |
sequencer.dummyProcess(_position * _sampleRate * 0.001); |
|---|
| 1469 |
} |
|---|
| 1470 |
|
|---|
| 1471 |
// set timer interruption |
|---|
| 1472 |
if (_timerCallback != null) { |
|---|
| 1473 |
sequencer.setGlobalSequence(_timerSequence); // set timer interruption |
|---|
| 1474 |
sequencer._setTimerCallback(_timerCallback); |
|---|
| 1475 |
} |
|---|
| 1476 |
} |
|---|
| 1477 |
|
|---|
| 1478 |
|
|---|
| 1479 |
// on enterFrame |
|---|
| 1480 |
private function _process_onEnterFrame(e:Event) : void |
|---|
| 1481 |
{ |
|---|
| 1482 |
// frame rate |
|---|
| 1483 |
var t:int = getTimer(); |
|---|
| 1484 |
_frameRate = t - _prevFrameTime; |
|---|
| 1485 |
_prevFrameTime = t; |
|---|
| 1486 |
|
|---|
| 1487 |
// _suspendStreaming = true when first streaming |
|---|
| 1488 |
if (_suspendStreaming) { |
|---|
| 1489 |
_onSuspendStream(); |
|---|
| 1490 |
} else { |
|---|
| 1491 |
// preserve stop |
|---|
| 1492 |
if (_preserveStop) stop(); |
|---|
| 1493 |
|
|---|
| 1494 |
// frame trigger |
|---|
| 1495 |
if (_trackEventQueue.length > 0) { |
|---|
| 1496 |
_trackEventQueue = _trackEventQueue.filter(_trackEventQueueFilter); |
|---|
| 1497 |
} |
|---|
| 1498 |
} |
|---|
| 1499 |
} |
|---|
| 1500 |
|
|---|
| 1501 |
|
|---|
| 1502 |
// _trackEventQueue filter |
|---|
| 1503 |
private function _trackEventQueueFilter(e:SiONTrackEvent, i:int, v:Vector.<SiONTrackEvent>) : Boolean { |
|---|
| 1504 |
if (e._decrementTimer(_frameRate)) { |
|---|
| 1505 |
dispatchEvent(e); |
|---|
| 1506 |
return false; |
|---|
| 1507 |
} |
|---|
| 1508 |
return true; |
|---|
| 1509 |
} |
|---|
| 1510 |
|
|---|
| 1511 |
|
|---|
| 1512 |
// suspend starting stream |
|---|
| 1513 |
private function _onSuspendStream() : void { |
|---|
| 1514 |
// reset suspending |
|---|
| 1515 |
_suspendStreaming = _suspendWhileLoading && (_loadingSoundList.length > 0); |
|---|
| 1516 |
|
|---|
| 1517 |
if (!_suspendStreaming) { |
|---|
| 1518 |
// dispatch streaming start event |
|---|
| 1519 |
var event:SiONEvent = new SiONEvent(SiONEvent.STREAM_START, this, null, true); |
|---|
| 1520 |
dispatchEvent(event); |
|---|
| 1521 |
if (event.isDefaultPrevented()) stop(); // canceled |
|---|
| 1522 |
} |
|---|
| 1523 |
} |
|---|
| 1524 |
|
|---|
| 1525 |
|
|---|
| 1526 |
// on sampleData |
|---|
| 1527 |
private function _streaming(e:SampleDataEvent) : void |
|---|
| 1528 |
{ |
|---|
| 1529 |
var buffer:ByteArray = e.data, extracted:int, |
|---|
| 1530 |
output:Vector.<Number> = module.output, |
|---|
| 1531 |
imax:int, i:int, event:SiONEvent; |
|---|
| 1532 |
|
|---|
| 1533 |
// calculate latency (0.022675736961451247 = 1/44.1) |
|---|
| 1534 |
if (_soundChannel) { |
|---|
| 1535 |
_latency = e.position * 0.022675736961451247 - _soundChannel.position; |
|---|
| 1536 |
} |
|---|
| 1537 |
|
|---|
| 1538 |
try { |
|---|
| 1539 |
// set streaming flag |
|---|
| 1540 |
_inStreaming = true; |
|---|
| 1541 |
|
|---|
| 1542 |
if (_isPaused || _suspendStreaming) { |
|---|
| 1543 |
// fill silence |
|---|
| 1544 |
_fillzero(e.data); |
|---|
| 1545 |
} else { |
|---|
| 1546 |
// process starting time |
|---|
| 1547 |
var t:int = getTimer(); |
|---|
| 1548 |
|
|---|
| 1549 |
// processing |
|---|
| 1550 |
module._beginProcess(); |
|---|
| 1551 |
effector._beginProcess(); |
|---|
| 1552 |
sequencer._process(); |
|---|
| 1553 |
effector._endProcess(); |
|---|
| 1554 |
module._endProcess(); |
|---|
| 1555 |
|
|---|
| 1556 |
// calculate the average of processing time |
|---|
| 1557 |
_timePrevStream = t; |
|---|
| 1558 |
_timeProcessTotal -= _timeProcessData.i; |
|---|
| 1559 |
_timeProcessData.i = getTimer() - t; |
|---|
| 1560 |
_timeProcessTotal += _timeProcessData.i; |
|---|
| 1561 |
_timeProcessData = _timeProcessData.next; |
|---|
| 1562 |
_timeProcess = _timeProcessTotal * _timeProcessAveRatio; |
|---|
| 1563 |
|
|---|
| 1564 |
// write samples |
|---|
| 1565 |
imax = output.length; |
|---|
| 1566 |
if (_backgroundSound) { |
|---|
| 1567 |
// w/ background sound |
|---|
| 1568 |
_backgroundBuffer.length = 0; |
|---|
| 1569 |
extracted = _backgroundSound.extract(_backgroundBuffer, _bufferLength); |
|---|
| 1570 |
if (_backgroundLoop) { |
|---|
| 1571 |
while (extracted < _bufferLength) { |
|---|
| 1572 |
extracted += _backgroundSound.extract(_backgroundBuffer, _bufferLength-extracted, 0); |
|---|
| 1573 |
} |
|---|
| 1574 |
} |
|---|
| 1575 |
if (extracted == _bufferLength) { |
|---|
| 1576 |
for (i=0; i<imax; i++) buffer.writeFloat(output[i]+_backgroundBuffer.readFloat()*_backgroundLevel); |
|---|
| 1577 |
} else { |
|---|
| 1578 |
for (i=0; i<extracted; i++) buffer.writeFloat(output[i]+_backgroundBuffer.readFloat()*_backgroundLevel); |
|---|
| 1579 |
for (; i<imax; i++) buffer.writeFloat(output[i]); |
|---|
| 1580 |
} |
|---|
| 1581 |
} else { |
|---|
| 1582 |
// w/o background sound |
|---|
| 1583 |
for (i=0; i<imax; i++) buffer.writeFloat(output[i]); |
|---|
| 1584 |
} |
|---|
| 1585 |
|
|---|
| 1586 |
// dispatch streaming event |
|---|
| 1587 |
if (_dispatchStreamEvent) { |
|---|
| 1588 |
event = new SiONEvent(SiONEvent.STREAM, this, buffer, true); |
|---|
| 1589 |
dispatchEvent(event); |
|---|
| 1590 |
if (event.isDefaultPrevented()) stop(); // canceled |
|---|
| 1591 |
} |
|---|
| 1592 |
|
|---|
| 1593 |
// dispatch finishSequence event |
|---|
| 1594 |
if (!_isFinishSeqDispatched && sequencer.isSequenceFinished) { |
|---|
| 1595 |
dispatchEvent(new SiONEvent(SiONEvent.FINISH_SEQUENCE, this)); |
|---|
| 1596 |
_isFinishSeqDispatched = true; |
|---|
| 1597 |
} |
|---|
| 1598 |
|
|---|
| 1599 |
// fading |
|---|
| 1600 |
if (_fader.execute()) { |
|---|
| 1601 |
var eventType:String = (_fader.isIncrement) ? SiONEvent.FADE_IN_COMPLETE : SiONEvent.FADE_OUT_COMPLETE; |
|---|
| 1602 |
dispatchEvent(new SiONEvent(eventType, this, buffer)); |
|---|
| 1603 |
if (_autoStop && !_fader.isIncrement) stop(); |
|---|
| 1604 |
} else { |
|---|
| 1605 |
// auto stop |
|---|
| 1606 |
if (_autoStop && sequencer.isFinished) stop(); |
|---|
| 1607 |
} |
|---|
| 1608 |
} |
|---|
| 1609 |
|
|---|
| 1610 |
// reset streaming flag |
|---|
| 1611 |
_inStreaming = false; |
|---|
| 1612 |
|
|---|
| 1613 |
} catch (e:Error) { |
|---|
| 1614 |
// error |
|---|
| 1615 |
_removeAllEventListners(); |
|---|
| 1616 |
if (_debugMode) throw e; |
|---|
| 1617 |
else dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, e.message)); |
|---|
| 1618 |
} |
|---|
| 1619 |
} |
|---|
| 1620 |
|
|---|
| 1621 |
|
|---|
| 1622 |
// fill zero |
|---|
| 1623 |
private function _fillzero(buffer:ByteArray) : void { |
|---|
| 1624 |
var i:int, imax:int = _bufferLength; |
|---|
| 1625 |
for (i=0; i<imax; i++) { |
|---|
| 1626 |
buffer.writeFloat(0); |
|---|
| 1627 |
buffer.writeFloat(0); |
|---|
| 1628 |
} |
|---|
| 1629 |
} |
|---|
| 1630 |
|
|---|
| 1631 |
|
|---|
| 1632 |
|
|---|
| 1633 |
|
|---|
| 1634 |
// operations |
|---|
| 1635 |
//---------------------------------------- |
|---|
| 1636 |
// volume fading |
|---|
| 1637 |
private function _fadeVolume(v:Number) : void { |
|---|
| 1638 |
_faderVolume = v; |
|---|
| 1639 |
_soundTransform.volume = _masterVolume * _faderVolume; |
|---|
| 1640 |
if (_soundChannel) _soundChannel.soundTransform = _soundTransform; |
|---|
| 1641 |
if (_dispatchFadingEvent) { |
|---|
| 1642 |
var event:SiONEvent = new SiONEvent(SiONEvent.FADE_PROGRESS, this, null, true); |
|---|
| 1643 |
dispatchEvent(event); |
|---|
| 1644 |
if (event.isDefaultPrevented()) _fader.stop(); // canceled |
|---|
| 1645 |
} |
|---|
| 1646 |
} |
|---|
| 1647 |
|
|---|
| 1648 |
|
|---|
| 1649 |
|
|---|
| 1650 |
|
|---|
| 1651 |
// errors |
|---|
| 1652 |
//---------------------------------------- |
|---|
| 1653 |
private function errorPluralDrivers() : Error { |
|---|
| 1654 |
return new Error("SiONDriver error; Cannot create pulral SiONDrivers."); |
|---|
| 1655 |
} |
|---|
| 1656 |
|
|---|
| 1657 |
|
|---|
| 1658 |
private function errorParamNotAvailable(param:String, num:Number) : Error { |
|---|
| 1659 |
return new Error("SiONDriver error; Parameter not available. " + param + String(num)); |
|---|
| 1660 |
} |
|---|
| 1661 |
|
|---|
| 1662 |
|
|---|
| 1663 |
private function errorDataIncorrect() : Error { |
|---|
| 1664 |
return new Error("SiONDriver error; data incorrect in play() or render()."); |
|---|
| 1665 |
} |
|---|
| 1666 |
|
|---|
| 1667 |
|
|---|
| 1668 |
private function errorDriverBusy(execID:int) : Error { |
|---|
| 1669 |
var states:Array = ["???", "compiling", "streaming", "rendering"]; |
|---|
| 1670 |
return new Error("SiONDriver error: Driver busy. Call " + states[execID] + " while " + states[_listenEvent] + "."); |
|---|
| 1671 |
} |
|---|
| 1672 |
|
|---|
| 1673 |
|
|---|
| 1674 |
private function errorCannotChangeBPM() : Error { |
|---|
| 1675 |
return new Error("SiONDriver error: Cannot change bpm while rendering (SiONTrackEvent.NOTE_*_STREAM)."); |
|---|
| 1676 |
} |
|---|
| 1677 |
|
|---|
| 1678 |
|
|---|
| 1679 |
private function errorNotGoodFMVoice() : Error { |
|---|
| 1680 |
return new Error("SiONDriver error; Cannot register the voice."); |
|---|
| 1681 |
} |
|---|
| 1682 |
|
|---|
| 1683 |
private function errorCannotListenLoading() : Error { |
|---|
| 1684 |
return new Error("SiONDriver error; the class not available for listenSoundLoadingStatus"); |
|---|
| 1685 |
} |
|---|
| 1686 |
} |
|---|
| 1687 |
} |
|---|
| 1688 |
|
|---|
| 1689 |
|
|---|
| 1690 |
|
|---|
| 1691 |
|
|---|
| 1692 |
import org.si.sion.SiONData; |
|---|
| 1693 |
|
|---|
| 1694 |
class SiONDriverJob |
|---|
| 1695 |
{ |
|---|
| 1696 |
public var mml:String; |
|---|
| 1697 |
public var buffer:Vector.<Number>; |
|---|
| 1698 |
public var data:SiONData; |
|---|
| 1699 |
public var channelCount:int; |
|---|
| 1700 |
public var resetEffector:Boolean; |
|---|
| 1701 |
|
|---|
| 1702 |
function SiONDriverJob(mml_:String, buffer_:Vector.<Number>, data_:SiONData, channelCount_:int, resetEffector_:Boolean) |
|---|
| 1703 |
{ |
|---|
| 1704 |
mml = mml_; |
|---|
| 1705 |
buffer = buffer_; |
|---|
| 1706 |
data = data_ || new SiONData(); |
|---|
| 1707 |
channelCount = channelCount_; |
|---|
| 1708 |
resetEffector = resetEffector_; |
|---|
| 1709 |
} |
|---|
| 1710 |
} |
|---|
| 1711 |
|
|---|
| 1712 |
|
|---|