topical media & game development
student-mma-16-Sequencer.ax
student-mma-16-Sequencer.ax
[swf]
flex
package
{
import de.popforge.audio.output.Audio;
import de.popforge.audio.output.SoundFactory;
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.utils.ByteArray;
public class @ax-student-mma-16-Sequencer
{
public static var
NUM_SLOTS:int = 31,
BPM:int = 125;
public var onInit:Function;
private var buffers:Array;
private var slots:Array; //containts the clips or null for empty slot, parallel to buffers
private var launchQueue:Array; //contains clips that are waiting to be launched
private var numReady:int = 0;
private var numBarSamples:uint; //number of samples that fit in 1 bar
private var samplesLeft:int; //number of samples left to next bar
private var sync: Sound; //buffer sync (sync buffer playback)
private var syncChannel: SoundChannel;
private var syncBuf:student_mma_16_AudioBuffer; //the buffer used for bar syncing
public function @ax-student-mma-16-Sequencer() {
init();
}
public function init():void {
buffers = new Array(NUM_SLOTS);
slots = new Array(NUM_SLOTS);
launchQueue = new Array(NUM_SLOTS);
for(var i:int = 0; i < NUM_SLOTS; i++) {
buffers[i] = new student_mma_16_AudioBuffer(4, Audio.STEREO, Audio.BIT16, Audio.RATE44100);
//buffers[i].onInit = onBufferInit;
}
syncBuf = buffers[0];
syncBuf.onComplete = syncBufComplete;
numBarSamples = (Math.ceil(44100 * (60 / BPM)) * 4);
samplesLeft = numBarSamples;
//-- create silent bytes for sync sound
var syncSamples: ByteArray = new ByteArray();
syncSamples.length = ( buffers[0].numSamples - 1 ) << 1;
SoundFactory.fromByteArray( syncSamples, 1, Audio.BIT16, Audio.RATE44100, onGenerateSyncSound );
}
private function onGenerateSyncSound( sound: Sound ): void
{
//silent sync sound created, start sync and buffers
sync = sound;
//
if( sync != null )
{
syncChannel = sync.play( 0, 1 );
syncChannel.addEventListener( Event.SOUND_COMPLETE, onSyncComplete, false, 10 );
for(var i:int = 0; i < NUM_SLOTS; i++) {
buffers[i].start();
}
}
if(onInit != null)
onInit();
}
private function onSyncComplete( event: Event ): void
{
if( syncChannel != null )
syncChannel.stop();
syncChannel = sync.play( 0, 1 );
syncChannel.addEventListener( Event.SOUND_COMPLETE, onSyncComplete, false, 10 );
for(var i:int = 0; i < NUM_SLOTS; i++) {
buffers[i].onSyncComplete();
if(slots[i] != null && slots[i].onComplete != null)
slots[i].onComplete(buffers[i]);
}
syncBufComplete();
}
private function syncBufComplete():void {
samplesLeft -= syncBuf.numSamples;
//samplesLeft < 0 (already launched, do nothing)
//samplesLeft >= syncBuf.numSamples (not nearing end of bar yet, do nothing)
//samplesLeft < syncBuf.numSamples (next buffer will contain new bar: launch clips!)
if(samplesLeft < syncBuf.numSamples) {
//new bar in next buffer: launch clips in queue
for each(var clip:student_mma_16_Clip in launchQueue) {
clip.launch(samplesLeft);
}
launchQueue = new Array(NUM_SLOTS);
// Alert.show("bar at next buf after " + samplesLeft + " samples");
samplesLeft += numBarSamples;
}
}
get a slot in the sequencer
returns: slot number or 0 if no slots are available
public function getSlot(clip:student_mma_16_Clip):int {
for(var i:int = 1; i < NUM_SLOTS; i++) {
if(slots[i] == null) {
slots[i] = clip;
launchQueue.push(clip);
return i;
}
}
return 0;
}
free a slot when done using it
public function freeSlot(slotNumber:int):void {
slots[slotNumber] = null;
buffers[slotNumber].onComplete = null;
}
public function changeSlotVolume(slotNumber:int, volume:Number):void {
if(buffers[slotNumber] == null) return;
buffers[slotNumber].changeVolume(volume);
}
}
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.