topical media & game development
student-mma-16-Clip.mx
student-mma-16-Clip.mx
[swf]
flex
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="64" height="78">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.controls.Image;
import mx.controls.Label;
import de.popforge.audio.output.Audio;
import de.popforge.audio.output.Sample;
import de.popforge.format.wav.*;
public static var
GREEN:int = 0,
RED:int = 1,
BLUE:int = 2,
YELLOW:int = 3,
STATE_ERROR:int = -1,
STATE_INACTIVE:int = 0,
STATE_LOADING:int = 1,
STATE_IDLE:int = 2,
STATE_PLAYING:int = 3,
TYPE_NOLOOP:int = 0,
TYPE_LOOP:int = 1;
public var color:int;
public var url:String = "";
public var title:String = "";
public var type:int = TYPE_NOLOOP;
public var length:int = 1;
public var lastX:Number; //last steady position (before dragging)
public var lastY:Number;
public var lastParent:String; //parent of clip in last steady position
public var state:int = STATE_INACTIVE;
public var sequencer:student_mma_16_Sequencer;
public var sequencerSlot:int;
private var wav:WavFormat;
private var progressBar:Shape;
private var img:Image;
private var c:int = 0; //clip sample iterator
private var numSamples:int;
private var startSample:uint = 0; //the first buffer sample to add sound to, specified by the sequencer
private var progressTimer:student_mma_16_MyTimer;
private var clipLength:uint; //length of clip in ms
private var progressCount:uint = 0;
private var firstRun:Boolean = true;
private var inited:Boolean = false;
internal var onComplete:Function;
public function init():void {
if(!inited) {
setImage();
setLabel();
createSound(url);
}
else
state = STATE_IDLE;
}
prepare the clip to be launched by the sequencer
public function start(sequencer:student_mma_16_Sequencer):void {
this.sequencer = sequencer;
sequencerSlot = sequencer.getSlot(this);
c = 0;
progressCount = 0;
}
starts the clip launch
internal function launch(startSample:uint = 0):void {
this.startSample = startSample;
if(state == STATE_IDLE) {
state = STATE_PLAYING;
onComplete = onAudioBufferComplete;
firstRun = true;
}
}
private function loadComplete(e:Event):void {
wav = WavFormat.decode(ByteArray(e.target.data));
state = STATE_IDLE;
inited = true;
progressBar.graphics.clear();
clipLength = (60 / student_mma_16_Sequencer.BPM) * 4 * length * 1000;
//make sure the length in samples is correct
if(type == TYPE_NOLOOP) {
numSamples = wav.samples.length;
}
else {
numSamples = Math.ceil(44.1 * clipLength);
if(numSamples > wav.samples.length) {
//add silent samples at the end
Alert.show("adding samples");
for(var i:int = 0; i < numSamples - wav.samples.length; i++) {
wav.samples.push(new Sample());
}
}
}
}
internal function onAudioBufferComplete(buffer: student_mma_16_AudioBuffer): void {
if(state != STATE_PLAYING) return;
if(firstRun) {
//start the progress bar when the audio starts
var timer:Timer = new Timer(Math.floor(startSample / 44.1 + buffer.numSamples / 44.1), 1);
timer.addEventListener(TimerEvent.TIMER, startPlayProgressTimer);
timer.start();
firstRun = false;
}
var samples: Array = buffer.getSamples();
for(var i:int = startSample; i < samples.length; i++) {
samples[i].left = wav.samples[c].left;
samples[i].right = wav.samples[c].right;
c++;
if(c == wav.samples.length) {
if(type == TYPE_NOLOOP) {
stop();
break;
}
c = 0;
}
}
buffer.update();
startSample = 0;
}
public function stop():void {
sequencer.freeSlot(sequencerSlot);
state = STATE_IDLE;
img.alpha = 0.5;
progressTimer.stop();
progressBar.graphics.clear();
}
set clip to inactive
public function remove():void {
if(state == STATE_PLAYING)
stop();
state = student_mma_16_Clip.STATE_INACTIVE;
}
public function setVolume(vol:Number):void {
sequencer.changeSlotVolume(sequencerSlot, vol);
}
private function setImage():void {
var src:String = "student-mma-16-img-final-";
switch(color) {
case RED: src += "loop-red.png"; break;
case BLUE: src += "loop-blue.png"; break;
case YELLOW: src += "loop-yellow.png";break;
default: src += "loop-green.png";
}
img = new Image();
img.source = src;
img.width = 64;
img.height = 78;
img.alpha = 0.5;
this.addChild(img);
}
private function setLabel():void {
var label:Label = new Label();
label.text = title;
label.x = 10;
label.y = 24;
label.styleName = "loopLabel";
label.truncateToFit = false;
label.width = 46;
label.setStyle("color", getColor(color));
this.addChild(label);
}
private function createSound(url:String):void {
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, loadComplete );
loader.addEventListener(IOErrorEvent.IO_ERROR, loadError );
loader.addEventListener(ProgressEvent.PROGRESS, updateProgress);
createProgressBar();
loader.load( new URLRequest(url));
}
public static function getColor(color:int):uint {
switch(color) {
case RED: return 0x7d0000;
case BLUE: return 0x00527d;
case YELLOW: return 0x7c7d00;
default: return 0x007d11;
}
}
private function createProgressBar():void {
progressBar = new Shape();
this.rawChildren.addChild(progressBar);
}
private function startPlayProgressTimer(e:TimerEvent):void {
var reps:int = (type == TYPE_LOOP ? 0 : 10);
progressTimer = new student_mma_16_MyTimer(clipLength / 10, reps, updatePlayProgress);
progressTimer.start();
img.alpha = 1;
}
private function updatePlayProgress():void {
progressCount++;
if(progressCount > 10) progressCount = 1;
var width:int = (progressCount / 10) * 62;
progressBar.graphics.clear();
progressBar.graphics.beginFill(0xFFFFFF);
progressBar.graphics.drawRect(1, 65, width, 12);
}
private function updateProgress(e:ProgressEvent):void {
var width:int = (e.bytesLoaded / e.bytesTotal) * 62;
progressBar.graphics.clear();
progressBar.graphics.beginFill(0xFFFFFF);
progressBar.graphics.drawRect(1, 65, width, 12);
}
private function loadError(e:IOErrorEvent):void {
state = STATE_ERROR;
}
]]>
</mx:Script>
</mx:Canvas>
(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.