aboutsummaryrefslogtreecommitdiff
path: root/src/library_openal.js
diff options
context:
space:
mode:
authorEhsan Akhgari <ehsan.akhgari@gmail.com>2013-03-13 13:50:37 -0400
committerAlon Zakai <alonzakai@gmail.com>2013-03-15 11:53:15 -0700
commit412a497665b629619c59752a0d88255ba49d1432 (patch)
treecf4099ed7985150343104d5a9ebab9baf41ede34 /src/library_openal.js
parent46e1c03ff0a15ef12fccae5fa699f012c331a6ab (diff)
Initial implementation of some of the OpenAL APIs
Diffstat (limited to 'src/library_openal.js')
-rw-r--r--src/library_openal.js204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/library_openal.js b/src/library_openal.js
new file mode 100644
index 00000000..2abc04eb
--- /dev/null
+++ b/src/library_openal.js
@@ -0,0 +1,204 @@
+//"use strict";
+
+var LibraryOpenAL = {
+ $AL__deps: ['$Browser'],
+ $AL: {
+ contexts: [],
+ currentContext: null,
+
+ structs: {
+ Rect: Runtime.generateStructInfo([
+ ['i32', 'x'], ['i32', 'y'], ['i32', 'w'], ['i32', 'h'],
+ ])
+ },
+ },
+
+ alcProcessContext: function(context) {},
+ alcSuspendContext: function(context) {},
+
+ alcMakeContextCurrent: function(context) {
+ if (context == 0) {
+ AL.currentContext = null;
+ } else {
+ AL.currentContext = AL.contexts[context];
+ }
+ },
+
+ alcDestroyContext: function(context) {
+ // Stop playback, etc
+ },
+
+ alcCloseDevice: function(device) {
+ // Stop playback, etc
+ },
+
+ alcOpenDevice: function(deviceName) {
+ if (typeof(AudioContext) == "function" ||
+ typeof(webkitAudioContext) == "function") {
+ return 1; // non-null pointer -- we just simulate one device
+ } else {
+ return 0;
+ }
+ },
+
+ alcCreateContext: function(device, attrList) {
+ if (device != 1) {
+ return 0;
+ }
+
+ if (attrList) {
+ console.log("The attrList argument of alcCreateContext is not supported yet");
+ return 0;
+ }
+
+ var ctx;
+ try {
+ ctx = new AudioContext();
+ } catch (e) {
+ try {
+ ctx = new webkitAudioContext();
+ } catch (e) {}
+ }
+
+ if (ctx) {
+ AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []});
+ return AL.contexts.length - 1;
+ } else {
+ return 0;
+ }
+ },
+
+ alGetError: function() {
+ if (!AL.currentContext) {
+ return 0xA004 /* AL_INVALID_OPERATION */;
+ } else {
+ return AL.currentContext.err;
+ }
+ },
+
+ alGenSources: function(count, sources) {
+ if (!AL.currentContext) {
+ console.error("alGenSources called without a valid context");
+ return;
+ }
+ for (var i = 0; i < count; ++i) {
+ var src = AL.currentContext.ctx.createBufferSource();
+ var gain = AL.currentContext.ctx.createGain();
+ src.connect(gain);
+ gain.connect(AL.currentContext.destination);
+ AL.currentContext.src.push({src: src, gain: gain});
+ {{{ makeSetValue('sources', 'i', 'AL.currentContext.src.length - 1', 'i32') }}};
+ }
+ },
+
+ alSourcei: function(source, param, value) {
+ if (!AL.currentContext) {
+ console.error("alSourcei called without a valid context");
+ return;
+ }
+ if (source >= AL.currentContext.src.length) {
+ console.error("alSourcei called with an invalid source");
+ return;
+ }
+ switch (param) {
+ case 0x1007 /* AL_LOOPING */:
+ AL.currentContext.src[source - 1].src.loop = (value != 0 /* AL_FALSE */);
+ break;
+ case 0x1009 /* AL_BUFFER */:
+ AL.currentContext.src[source - 1].src.buffer = AL.currentContext.buf[value].buf;
+ break;
+ default:
+ console.log("alSourcei with param " + param + " not implemented yet");
+ break;
+ }
+
+ alGenBuffers: function(count, buffers) {
+ if (!AL.currentContext) {
+ console.error("alGenBuffers called without a valid context");
+ return;
+ }
+ for (var i = 0; i < count; ++i) {
+ AL.currentContext.buf.push({buf: null});
+ {{{ makeSetValue('buffers', 'i', 'AL.currentContext.buf.length - 1', 'i32') }}};
+ }
+ },
+
+ alBufferData: function(buffer, format, data, size, freq) {
+ if (!AL.currentContext) {
+ console.error("alBufferData called without a valid context");
+ return;
+ }
+ if (buffer >= AL.currentContext.buf.length) {
+ console.error("alBufferData called with an invalid buffer");
+ return;
+ }
+ var channels, bytes;
+ switch (format) {
+ case 0x1100 /* AL_FORMAT_MONO8 */:
+ bytes = 1;
+ case 0x1101 /* AL_FORMAT_MONO16 */:
+ bytes = 2;
+ channels = 1;
+ break;
+ case 0x1102 /* AL_FORMAT_STEREO8 */:
+ bytes = 1;
+ case 0x1103 /* AL_FORMAT_STEREO16 */:
+ bytes = 2;
+ channels = 2;
+ break;
+ default:
+ console.error("alBufferData called with invalid format " + format);
+ return;
+ }
+ AL.currentContext.buf[buffer].buf = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq);
+ var data = new Array(channels);
+ for (var i = 0; i < channels; ++i) {
+ data[i] = AL.currentContext.buf[buffer].buf.getChannelData(i);
+ }
+ for (var i = 0; i < size / (bytes * channels); ++i) {
+ for (var j = 0; j < channels; ++j) {
+ switch (bytes) {
+ case 1:
+ var val = {{{ makeGetValue('data', 'i+j', 'i8') }}};
+ data[j][i] = -1.0 + val * (2/256);
+ break;
+ case 2:
+ var val = {{{ makeGetValue('data', 'i+j', 'i16') }}};
+ data[j][i] = -1.0 + (val + -32768) * (2/65536);
+ break;
+ }
+ }
+ }
+ },
+
+ alDistanceModel: function(model) {
+ if (model != 0 /* AL_NONE */) {
+ console.log("Only alDistanceModel(AL_NONE) is currently supported");
+ }
+ },
+
+ alListenerfv: function(param, values) {
+ console.log("alListenerfv is not supported yet");
+ },
+
+ alIsExtensionPresent: function(extName) {
+ return 0;
+ },
+
+ alcIsExtensionPresent: function(device, extName) {
+ return 0;
+ },
+
+ alGetProcAddress: function(fname) {
+ return 0;
+ },
+
+ alcGetProcAddress: function(device, fname) {
+ return 0;
+ },
+
+};
+
+autoAddDeps(LibraryOpenAL, '$AL');
+mergeInto(LibraryManager.library, LibraryOpenAL);
+