topical media & game development

talk show tell print

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;
                          
                          //isInit = true;
                          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.