Skip to content

Commit

Permalink
Adding files.
Browse files Browse the repository at this point in the history
Just wanted to clear out my account due to account snoopers.
  • Loading branch information
taisel committed Jul 12, 2015
0 parents commit 6d0916f
Show file tree
Hide file tree
Showing 7 changed files with 924 additions and 0 deletions.
53 changes: 53 additions & 0 deletions README.md
@@ -0,0 +1,53 @@
<h1>XAudioJS</h1>
<h3>A minimal cross-browser API for writing PCM audio samples:</h3>
<p>This simple JavaScript library abstracts the push-for-audio API of Mozilla Audio, the MediaStream API in experimental Firefox Nightlies, and the passive callback API of Web Audio.
This library introduces an abstraction layer that provides a push-for-audio and a callback API in one. We even provide a flash fallback to bring us to a total of 4 APIs supported.</p>
<br>
<b>This software is hereby placed in the public domain for anyone to use.</b>
<br>
<h3>How To Initialize:</h3>
<dl>
<dt>new XAudioServer(int channels, double sampleRate, int bufferLow, int bufferHigh, function underRunCallback, double volume, function failureCallback);</dt>
<dd>Make sure only one instance of XAudioServer is running at any time.</dd>
<dd>bufferLow MUST be less than bufferHigh.</dd>
<dd>bufferHigh sets the internal FIFO buffer length for all APIs except the Mozilla Audio Data API. Overfill on FIFO causes the oldest samples to be dropped first.</dd>
<dd>
<h4>Array underRunCallback (int samplesRequested)</h4>
<blockquote>
Arguments: Passed the number of samples that are needed to replenish the internal audio buffer back to bufferLow.<br><br>
Functionality: JS developer set callback that can pass back any number of samples to replenish the audio buffer with.<br><br>
Return: Array of samples to be passed into the underlying audio buffer. MUST be divisible by number of channels used (Whole frames required.). The return array length DOES NOT NEED to be of length samplesRequested.
</blockquote>
</dd>
<dd>volume is the output volume.</dd>
<dd>
<h4>void failureCallback (void)</h4>
<blockquote>
Functionality: JS developers set this callback to handle no audio support being available from the browser.
</blockquote>
</dd>
</dl>
<h3>Function Reference:</h3>
<dl>
<dt>void writeAudio (Array buffer)</dt>
<dd>Arguments: Pass an array of audio samples that is divisible by the number of audio channels utilized (buffer % channels == 0).</dd>
<dd>Functionality: Passes the audio samples directly into the underlying audio subsystem, <b>and can call the specified sample buffer under-run callback as needed (Does the equivalent of executeCallback in addition to the forced sample input.)<b>.</dd>
<dd>Return: void (None).</dd>
<dt>void writeAudioNoCallback (Array buffer)</dt>
<dd>Arguments: Pass an array of audio samples that is divisible by the number of audio channels utilized (buffer % channels == 0).</dd>
<dd>Functionality: Passes the audio samples directly into the underlying audio subsystem.</dd>
<dd>Return: void (None).</dd>
<dt>int remainingBuffer (void)</dt>
<dd>Arguments: void (None).</dd>
<dd>Functionality: Returns the number of samples left in the audio system before running out of playable samples.</dd>
<dd>Return (On valid): int samples_remaining (<b>CAN BE NEGATIVE<b>)</dd>
<dd>Return (On invalid): null</dd>
<dt>void executeCallback (void)</dt>
<dd>Arguments: void (None).</dd>
<dd>Functionality: Executes the audio sample under-run callback if the samples remaining is below the set buffer low limit.</dd>
<dd>Return: void (None).</dd>
<dt>void changeVolume (double)</dt>
<dd>Arguments: double float between 0 and 1 specifying the volume.</dd>
<dd>Functionality: Changes the volume. Will affect samples in buffer, so has a low-latency effect (Use this to do a fast-mute).</dd>
<dd>Return: void (None).</dd>
</dl>
86 changes: 86 additions & 0 deletions XAudioJS.as
@@ -0,0 +1,86 @@
package {
import flash.media.Sound;
import flash.events.SampleDataEvent;
import flash.display.Sprite;
import flash.external.ExternalInterface;
public class XAudioJS extends Sprite {
public var sound:Sound = null;
public var channelBuffer:Vector.<Number> = new Vector.<Number>(8192, true);
public var channels:int = 0;
public var volume:Number = 0;
public var samplesFound:int = 0;
public function XAudioJS() {
ExternalInterface.addCallback('initialize', initialize);
ExternalInterface.addCallback('changeVolume', changeVolume);
}
//Initialization function for the flash backend of XAudioJS:
public function initialize(channels:Number, newVolume:Number):void {
//Initialize the new settings:
this.channels = (int(channels) == 2) ? 2 : 1;
this.changeVolume(newVolume);
this.checkForSound();
}
//Volume changing function for the flash backend of XAudioJS:
public function changeVolume(newVolume:Number):void {
//Set the new volume:
this.volume = Math.min(Math.max(newVolume, 0), 1);
}
//Calls the JavaScript function responsible for the polyfill:
public function requestSamples():Boolean {
//Call the javascript callback function:
var buffer:String = ExternalInterface.call("XAudioJSFlashAudioEvent");
//If we received an appropriate response:
if (buffer !== null) {
if ((buffer.length % this.channels) == 0) { //Outsmart bad programmers from messing us up. :/
var channelSample:Number = 0;
this.samplesFound = Math.min(buffer.length, 4096 * this.channels);
for (var index:int = 0; index < this.samplesFound; ++index) {
//Get the unsigned 15-bit encoded sample value at +0x3000 offset:
channelSample = buffer.charCodeAt(index);
//Range-check the sample frame value and convert it:
this.channelBuffer[index] = (channelSample >= 0x3000 && channelSample < 0xAFFF) ? (this.volume * (((channelSample - 0x3000) / 0x3FFF) - 1)) : 0;
}
return true;
}
}
return false;
}
//Check to make sure the audio stream is enabled:
public function checkForSound():void {
if (this.sound == null) {
this.sound = new Sound();
this.sound.addEventListener(
SampleDataEvent.SAMPLE_DATA,
soundCallback
);
this.sound.play();
}
}
//Flash Audio Refill Callback
public function soundCallback(e:SampleDataEvent):void {
var index:int = 0;
if (this.requestSamples()) {
if (this.channels == 2) {
//Stereo:
while (index < this.samplesFound) {
e.data.writeFloat(this.channelBuffer[index++]);
e.data.writeFloat(this.channelBuffer[index++]);
}
index >>= 1;
}
else {
//Mono:
while (index < this.samplesFound) {
e.data.writeFloat(this.channelBuffer[index]);
e.data.writeFloat(this.channelBuffer[index++]);
}
}
}
//Write some silence if not enough samples are found:
while (++index <= 2048) {
e.data.writeFloat(0);
e.data.writeFloat(0);
}
}
}
}
Binary file added XAudioJS.swf
Binary file not shown.

0 comments on commit 6d0916f

Please sign in to comment.