summaryrefslogtreecommitdiff
path: root/dynamicaudio.as
diff options
context:
space:
mode:
Diffstat (limited to 'dynamicaudio.as')
-rw-r--r--dynamicaudio.as80
1 files changed, 80 insertions, 0 deletions
diff --git a/dynamicaudio.as b/dynamicaudio.as
new file mode 100644
index 0000000..45c2ceb
--- /dev/null
+++ b/dynamicaudio.as
@@ -0,0 +1,80 @@
+package {
+ import flash.display.Sprite;
+ import flash.events.SampleDataEvent;
+ import flash.external.ExternalInterface;
+ import flash.media.Sound;
+ import flash.media.SoundChannel;
+
+ public class dynamicaudio extends Sprite {
+ public var bufferSize:Number = 2048; // In samples
+ public var sound:Sound;
+ public var buffer:Array = [];
+ public var channel:SoundChannel;
+ public var writtenSampleCount:Number = 0;
+
+ public function dynamicaudio() {
+ ExternalInterface.addCallback('write', write);
+ ExternalInterface.addCallback('stop', stop);
+ ExternalInterface.addCallback('bufferedDuration', bufferedDuration);
+ this.sound = new Sound();
+ this.sound.addEventListener(
+ SampleDataEvent.SAMPLE_DATA,
+ soundGenerator
+ );
+ this.channel = this.sound.play();
+ }
+
+ // Called from JavaScript to add samples to the buffer
+ // Note we are using a space separated string of samples instead of an
+ // array. Flash's stupid ExternalInterface passes every sample as XML,
+ // which is incredibly expensive to encode/decode
+ public function write(s:String):Number {
+ var multiplier:Number = 1/32768;
+ var alreadyBufferedDuration:Number = (this.writtenSampleCount + this.buffer.length/2) / 44.1;
+ for each (var sample:String in s.split(" ")) {
+ this.buffer.push(Number(sample)*multiplier);
+ }
+ return (this.channel ? alreadyBufferedDuration - this.channel.position : 0);
+ }
+
+ public function bufferedDuration():Number {
+ // duration (in ms) of audio written to Flash so far = (writtenSampleCount * 1000 / sampleRate)
+ // number of ms in Flash's buffer = (writtenSampleCount * 1000 / sampleRate) - this.channel.position
+ // number of ms in our buffer = (this.buffer.length/2 * 1000 / sampleRate)
+ // (/2 because buffer stores stereo data => 2 elements per sample)
+ // for 44100Hz, x * 1000 / sampleRate => x / 44.1
+ return (this.writtenSampleCount + this.buffer.length/2) / 44.1 - this.channel.position;
+ }
+
+ public function stop():void {
+ this.channel.stop();
+ this.buffer = [];
+ this.writtenSampleCount = 0;
+ this.channel = this.sound.play();
+ }
+
+ public function soundGenerator(event:SampleDataEvent):void {
+ var i:int;
+
+ // If we haven't got enough data, write 2048 samples of silence to
+ // both channels, the minimum Flash allows
+ if (this.buffer.length < this.bufferSize*2) {
+ for (i = 0; i < 4096; i++) {
+ event.data.writeFloat(0.0);
+ }
+ this.writtenSampleCount += 2048;
+ return;
+ }
+
+ var count:Number = Math.min(this.buffer.length, 16384);
+
+ for each (var sample:Number in this.buffer.slice(0, count)) {
+ event.data.writeFloat(sample);
+ }
+
+ this.writtenSampleCount += count/2;
+ this.buffer = this.buffer.slice(count, this.buffer.length);
+ }
+ }
+}
+