aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnthony Pesch <anthony@usamp.com>2013-05-02 14:05:50 -0700
committerAnthony Pesch <inolen@gmail.com>2013-07-30 17:45:32 -0700
commitc237c138428baacf6a55dd0cf30a5ea0d98bb743 (patch)
treeedfc0aa378e507096a975e9c6ebcec0faac326d1 /src
parent6fd2313192352995c36d1097e18f591dc65d81d1 (diff)
First pass at buffer queueing
Diffstat (limited to 'src')
-rw-r--r--src/library_openal.js572
1 files changed, 440 insertions, 132 deletions
diff --git a/src/library_openal.js b/src/library_openal.js
index 6a97fce7..c628bfd2 100644
--- a/src/library_openal.js
+++ b/src/library_openal.js
@@ -5,6 +5,8 @@ var LibraryOpenAL = {
$AL: {
contexts: [],
currentContext: null,
+ QUEUE_INTERVAL: 25,
+ QUEUE_LOOKAHEAD: 100
},
alcProcessContext: function(context) {},
@@ -39,6 +41,7 @@ var LibraryOpenAL = {
alcDestroyContext: function(context) {
// Stop playback, etc
+ clearInterval(context.interval);
},
alcCloseDevice: function(device) {
@@ -54,6 +57,7 @@ var LibraryOpenAL = {
}
},
+ alcCreateContext__deps: ['updateSources'],
alcCreateContext: function(device, attrList) {
if (device != 1) {
return 0;
@@ -76,18 +80,131 @@ var LibraryOpenAL = {
}
if (ctx) {
- AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []});
+ var context = {
+ ctx: ctx,
+ err: 0,
+ src: [],
+ buf: [],
+ interval: setInterval(function () { _updateSources(context); }, AL.QUEUE_INTERVAL)
+ };
+ AL.contexts.push(context);
return AL.contexts.length;
} else {
return 0;
}
},
+ updateSources__deps: ['updateSource'],
+ updateSources: function (context) {
+ for (var i = 0; i < context.src.length; i++) {
+ _updateSource(context.src[i]);
+ }
+ },
+
+ updateSource__deps: ['setSourceState'],
+ updateSource: function (src) {
+ if (src.state !== 0x1012 /* AL_PLAYING */) {
+ return;
+ }
+
+ var currentTime = AL.currentContext.ctx.currentTime;
+ var startTime = src.bufferPosition;
+
+ for (var i = src.buffersPlayed; i < src.queue.length; i++) {
+ var entry = src.queue[i];
+
+ var startOffset = startTime - currentTime;
+ var endTime = startTime + entry.buffer.duration;
+
+ // Clean up old buffers.
+ if (currentTime >= endTime) {
+ // Update our location in the queue.
+ src.bufferPosition = endTime;
+ src.buffersPlayed = i + 1;
+
+ // Stop / restart the source when we hit the end.
+ if (src.buffersPlayed >= src.queue.length) {
+ if (src.loop) {
+ _setSourceState(src, 0x1012 /* AL_PLAYING */);
+ } else {
+ _setSourceState(src, 0x1014 /* AL_STOPPED */);
+ }
+ }
+ }
+ // Process all buffers that'll be played before the next tick.
+ else if (startOffset < (AL.QUEUE_LOOKAHEAD / 1000) && !entry.src) {
+ // If the offset is positive, we need to delay playing the sound that amount.
+ var when = Math.max(startOffset, 0);
+ // If the offset is negative, we need to play immediately, offset by its absolute value (print warning?).
+ var offset = Math.abs(Math.min(startOffset, 0));
+
+ entry.src = AL.currentContext.ctx.createBufferSource();
+ entry.src.buffer = entry.buffer;
+ entry.src.connect(src.gain);
+ entry.src.start(when, offset);
+
+ // console.log('playing buffer (' + i + ', ' + entry.buffer.duration.toFixed(4) + ')\t(startTime: ' + startTime.toFixed(4) + ')\t(currentTime: ' + currentTime.toFixed(4) + ')\t(when: ' + when.toFixed(4) + ') ' + ')\t(offset: ' + offset.toFixed(4) + ') ');
+ }
+
+ startTime = endTime;
+ }
+ },
+
+ setSourceState__deps: ['updateSource', 'stopSourceQueue'],
+ setSourceState: function (src, state) {
+ if (state === 0x1012 /* AL_PLAYING */) {
+ if (src.state !== 0x1013 /* AL_PAUSED */) {
+ src.state = 0x1012 /* AL_PLAYING */;
+ // Reset our position.
+ src.bufferPosition = AL.currentContext.ctx.currentTime;
+ src.buffersPlayed = 0;
+ } else {
+ src.state = 0x1012 /* AL_PLAYING */;
+ // Use the current offset from src.bufferPosition to resume at the correct point.
+ src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
+ }
+ _stopSourceQueue(src);
+ _updateSource(src);
+ } else if (state === 0x1013 /* AL_PAUSED */) {
+ if (src.state === 0x1012 /* AL_PLAYING */) {
+ src.state = 0x1013 /* AL_PAUSED */;
+ // Store off the current offset to restore with on resume.
+ src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition;
+ _stopSourceQueue(src);
+ }
+ } else if (state === 0x1014 /* AL_STOPPED */) {
+ if (src.state !== 0x1011 /* AL_INITIAL */) {
+ src.state = 0x1014 /* AL_STOPPED */;
+ src.buffersPlayed = src.queue.length;
+ _stopSourceQueue(src);
+ }
+ } else if (state == 0x1011 /* AL_INITIAL */) {
+ if (src.state !== 0x1011 /* AL_INITIAL */) {
+ src.state = 0x1011 /* AL_INITIAL */;
+ src.bufferPosition = 0;
+ src.buffersPlayed = 0;
+ }
+ }
+ },
+
+ stopSourceQueue: function (src) {
+ for (var i = 0; i < src.queue.length; i++) {
+ var entry = src.queue[i];
+ if (entry.src) {
+ entry.src.stop(0);
+ entry.src = null;
+ }
+ }
+ },
+
alGetError: function() {
if (!AL.currentContext) {
return 0xA004 /* AL_INVALID_OPERATION */;
} else {
- return AL.currentContext.err;
+ // Reset error on get.
+ var err = AL.currentContext.err;
+ AL.currentContext.err = 0 /* AL_NO_ERROR */;
+ return err;
}
},
@@ -97,12 +214,12 @@ var LibraryOpenAL = {
return _alGetError();
},
- alDeleteSources: function(count, sources)
- {
+ alDeleteSources: function(count, sources) {
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alDeleteSources called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
@@ -116,189 +233,298 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGenSources called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
var gain = AL.currentContext.ctx.createGain();
- var panner = AL.currentContext.ctx.createPanner();
- panner.panningModel = "equalpower";
- panner.distanceModel = "linear";
- panner.rolloffFactor = 0.3;
- gain.connect(panner);
- panner.connect(AL.currentContext.ctx.destination);
+ gain.connect(AL.currentContext.ctx.destination);
AL.currentContext.src.push({
+ state: 0x1011 /* AL_INITIAL */,
+ queue: [],
loop: false,
- buffer: null,
+ get refDistance() {
+ return this._refDistance || 1;
+ },
+ set refDistance(val) {
+ this._refDistance = val;
+ if (this.panner) this.panner.refDistance = val;
+ },
+ get maxDistance() {
+ return this._maxDistance || 10000;
+ },
+ set maxDistance(val) {
+ this._maxDistance = val;
+ if (this.panner) this.panner.maxDistance = val;
+ },
+ get rolloffFactor() {
+ return this._rolloffFactor || 1;
+ },
+ set rolloffFactor(val) {
+ this._rolloffFactor = val;
+ if (this.panner) this.panner.rolloffFactor = val;
+ },
+ get position() {
+ return this._position || [0, 0, 0];
+ },
+ set position(val) {
+ this._position = val;
+ if (this.panner) this.panner.setPosition(val[0], val[1], val[2]);
+ },
+ get velocity() {
+ return this._velocity || [0, 0, 0];
+ },
+ set velocity(val) {
+ this._velocity = val;
+ if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]);
+ },
gain: gain,
- panner: panner,
- paused: false,
- playTime: -1,
- pausedTime: 0
+ panner: null,
+ buffersPlayed: 0,
+ bufferPosition: 0
});
{{{ makeSetValue('sources', 'i*4', 'AL.currentContext.src.length', 'i32') }}};
}
},
+ alSourcei__deps: ['updateSource'],
alSourcei: function(source, param, value) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcei called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourcei called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
case 0x1007 /* AL_LOOPING */:
- AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */);
+ src.loop = (value === 1 /* AL_TRUE */);
break;
case 0x1009 /* AL_BUFFER */:
+ var buffer = AL.currentContext.buf[value - 1];
if (value == 0) {
- AL.currentContext.src[source - 1].buffer = null;
+ src.queue = [];
} else {
- AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf;
+ src.queue = [{ buffer: buffer }];
+ }
+ _updateSource(src);
+ break;
+ case 0x202 /* AL_SOURCE_RELATIVE */:
+ if (value === 1 /* AL_TRUE */) {
+ if (src.panner) {
+ src.panner = null;
+
+ // Disconnect from the panner.
+ src.gain.disconnect();
+
+ src.gain.connect(AL.currentContext.ctx.destination);
+ }
+ } else if (value === 0 /* AL_FALSE */) {
+ if (!src.panner) {
+ var panner = src.panner = AL.currentContext.ctx.createPanner();
+ panner.panningModel = "equalpower";
+ panner.distanceModel = "linear";
+ panner.refDistance = src.refDistance;
+ panner.maxDistance = src.maxDistance;
+ panner.rolloffFactor = src.rolloffFactor;
+ panner.setPosition(src.position[0], src.position[1], src.position[2]);
+ panner.setVelocity(src.velocity[0], src.velocity[1], src.velocity[2]);
+ panner.connect(AL.currentContext.ctx.destination);
+
+ // Disconnect from the default source.
+ src.gain.disconnect();
+
+ src.gain.connect(panner);
+ }
+ } else {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
}
break;
default:
#if OPENAL_DEBUG
console.log("alSourcei with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
alSourcef: function(source, param, value) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcef called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourcef called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
- case 0x100A /* AL_GAIN */:
- if (AL.currentContext.src[source - 1]) {
- AL.currentContext.src[source - 1].gain.gain.value = value;
- }
- break;
case 0x1003 /* AL_PITCH */:
#if OPENAL_DEBUG
- console.log("alSourcef was called with AL_PITCH, but Web Audio does not support static pitch changes");
+ console.log("alSourcef was called with 0x1003 /* AL_PITCH */, but Web Audio does not support static pitch changes");
#endif
break;
+ case 0x100A /* AL_GAIN */:
+ src.gain.gain.value = value;
+ break;
+ // case 0x100D /* AL_MIN_GAIN */:
+ // break;
+ // case 0x100E /* AL_MAX_GAIN */:
+ // break;
+ case 0x1023 /* AL_MAX_DISTANCE */:
+ src.maxDistance = value;
+ break;
+ case 0x1021 /* AL_ROLLOFF_FACTOR */:
+ src.rolloffFactor = value;
+ break;
+ // case 0x1022 /* AL_CONE_OUTER_GAIN */:
+ // break;
+ // case 0x1001 /* AL_CONE_INNER_ANGLE */:
+ // break;
+ // case 0x1002 /* AL_CONE_OUTER_ANGLE */:
+ // break;
+ case 0x1020 /* AL_REFERENCE_DISTANCE */:
+ src.refDistance = value;
+ break;
default:
#if OPENAL_DEBUG
console.log("alSourcef with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
- alSourcefv: function(source, param, value) {
+ alSource3f: function(source, param, v1, v2, v3) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
- console.error("alSourcefv called without a valid context");
+ console.error("alSource3f called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
- console.error("alSourcefv called with an invalid source");
+ console.error("alSource3f called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
case 0x1004 /* AL_POSITION */:
- AL.currentContext.src[source - 1].panner.setPosition(
- {{{ makeGetValue('value', '0', 'float') }}},
- {{{ makeGetValue('value', '4', 'float') }}},
- {{{ makeGetValue('value', '8', 'float') }}}
- );
+ src.position = [v1, v2, v3];
break;
case 0x1006 /* AL_VELOCITY */:
- AL.currentContext.src[source - 1].panner.setVelocity(
- {{{ makeGetValue('value', '0', 'float') }}},
- {{{ makeGetValue('value', '4', 'float') }}},
- {{{ makeGetValue('value', '8', 'float') }}}
- );
+ src.velocity = [v1, v2, v3];
break;
default:
#if OPENAL_DEBUG
- console.log("alSourcefv with param " + param + " not implemented yet");
+ console.log("alSource3f with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
+ alSourcefv: function(source, param, value) {
+ _alSource3f(source, param,
+ {{{ makeGetValue('value', '0', 'float') }}},
+ {{{ makeGetValue('value', '4', 'float') }}},
+ {{{ makeGetValue('value', '8', 'float') }}});
+ },
+
+ alSourceQueueBuffers__deps: ["updateSource"],
alSourceQueueBuffers: function(source, count, buffers) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called with an invalid source");
#endif
- return;
- }
- if (count != 1) {
-#if OPENAL_DEBUG
- console.error("Queuing multiple buffers using alSourceQueueBuffers is not supported yet");
-#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
for (var i = 0; i < count; ++i) {
- var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
- if (buffer > AL.currentContext.buf.length) {
+ var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
+ if (bufferIdx > AL.currentContext.buf.length) {
#if OPENAL_DEBUG
console.error("alSourceQueueBuffers called with an invalid buffer");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf;
}
+
+ for (var i = 0; i < count; ++i) {
+ var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
+ var buffer = AL.currentContext.buf[bufferIdx - 1];
+ src.queue.push({ buffer: buffer, src: null });
+ }
+
+ _updateSource(src);
},
- alSourceUnqueueBuffers: function(source, count, buffers)
- {
+ alSourceUnqueueBuffers: function(source, count, buffers) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourceUnqueueBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourceUnqueueBuffers called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- if (count != 1) {
-#if OPENAL_DEBUG
- console.error("Queuing multiple buffers using alSourceUnqueueBuffers is not supported yet");
-#endif
+
+ if (count > src.buffersPlayed) {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
return;
}
- for (var i = 0; i < count; ++i) {
- var buffer = AL.currentContext.src[source - 1].buffer;
- for (var j = 0; j < AL.currentContext.buf.length; ++j) {
- if (buffer == AL.currentContext.buf[j].buf) {
+
+ for (var i = 0; i < count; i++) {
+ var entry = src.queue.shift();
+ // Write the buffers index out to the return list.
+ for (var j = 0; j < AL.currentContext.buf.length; j++) {
+ var b = AL.currentContext.buf[j];
+ if (b && b == entry.buffer) {
{{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}};
- AL.currentContext.src[source - 1].buffer = null;
+ src.buffer = null;
break;
}
}
+ src.buffersPlayed--;
}
},
@@ -308,21 +534,43 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alDeleteBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
+ if (count > AL.currentContext.buf.length) {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
+ return;
+ }
+
for (var i = 0; i < count; ++i) {
var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1;
- if (bufferIdx < AL.currentContext.buf.length && AL.currentContext.buf[bufferIdx]) {
- var buffer = AL.currentContext.buf[bufferIdx].buf;
- for (var j = 0; j < AL.currentContext.src.length; ++j) {
- if (buffer == AL.currentContext.src[j].buffer) {
- AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
+
+ // Make sure the buffer index is valid.
+ if (bufferIdx >= AL.currentContext.buf.length || !AL.currentContext.buf[bufferIdx]) {
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
+ return;
+ }
+
+ // Make sure the buffer is no longer in use.
+ var buffer = AL.currentContext.buf[bufferIdx];
+ for (var j = 0; j < AL.currentContext.src.length; ++j) {
+ var src = AL.currentContext.src[j];
+ if (!src) {
+ continue;
+ }
+ for (var k = 0; k < src.queue.length; k++) {
+ if (buffer === src.queue[k].buffer) {
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
}
- delete AL.currentContext.buf[bufferIdx];
}
}
+
+ for (var i = 0; i < count; ++i) {
+ var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1;
+ delete AL.currentContext.buf[bufferIdx];
+ }
},
alGenBuffers: function(count, buffers) {
@@ -330,10 +578,11 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alGenBuffers called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
for (var i = 0; i < count; ++i) {
- AL.currentContext.buf.push({buf: null});
+ AL.currentContext.buf.push(null);
{{{ makeSetValue('buffers', 'i*4', 'AL.currentContext.buf.length', 'i32') }}};
}
},
@@ -343,6 +592,7 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alBufferData called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
if (buffer > AL.currentContext.buf.length) {
@@ -375,16 +625,21 @@ var LibraryOpenAL = {
#endif
return;
}
- AL.currentContext.buf[buffer - 1].buf = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq);
+ try {
+ AL.currentContext.buf[buffer - 1] = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq);
+ } catch (e) {
+ AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */;
+ return;
+ }
var buf = new Array(channels);
for (var i = 0; i < channels; ++i) {
- buf[i] = AL.currentContext.buf[buffer - 1].buf.getChannelData(i);
+ buf[i] = AL.currentContext.buf[buffer - 1].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*channels+j', 'i8') }}};
+ var val = {{{ makeGetValue('data', 'i*channels+j', 'i8') }}} & 0xff; // unsigned
buf[j][i] = -1.0 + val * (2/256);
break;
case 2:
@@ -396,110 +651,99 @@ var LibraryOpenAL = {
}
},
- alSourcePlay__deps: ["alSourceStop"],
+ alSourcePlay__deps: ['setSourceState'],
alSourcePlay: function(source) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcePlay called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourcePlay called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- var offset = 0;
- if ("src" in AL.currentContext.src[source - 1] &&
- AL.currentContext.src[source - 1]["src"].buffer ==
- AL.currentContext.src[source - 1].buffer) {
- if (AL.currentContext.src[source - 1].paused) {
- // So now we have to resume playback, remember the offset here.
- offset = AL.currentContext.src[source - 1].pausedTime -
- AL.currentContext.src[source - 1].playTime;
- } else {
- // If the source is already playing, we need to resume from beginning.
- // We do that by stopping the current source and replaying it.
- _alSourceStop(source);
- }
- }
- var src = AL.currentContext.ctx.createBufferSource();
- src.loop = AL.currentContext.src[source - 1].loop;
- src.buffer = AL.currentContext.src[source - 1].buffer;
- src.connect(AL.currentContext.src[source - 1].gain);
- src.start(0, offset);
- AL.currentContext.src[source - 1].playTime = AL.currentContext.ctx.currentTime;
- AL.currentContext.src[source - 1].paused = false;
- AL.currentContext.src[source - 1]['src'] = src;
+ _setSourceState(src, 0x1012 /* AL_PLAYING */);
},
+ alSourceStop__deps: ['setSourceState'],
alSourceStop: function(source) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourceStop called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourceStop called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- if (AL.currentContext.src[source - 1] && "src" in AL.currentContext.src[source - 1]) {
- AL.currentContext.src[source - 1]["src"].stop(0);
- delete AL.currentContext.src[source - 1]["src"];
- }
+ _setSourceState(src, 0x1014 /* AL_STOPPED */);
},
+ alSourcePause__deps: ['setSourceState'],
alSourcePause: function(source) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alSourcePause called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alSourcePause called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
- if ("src" in AL.currentContext.src[source - 1] &&
- !AL.currentContext.src[source - 1].paused) {
- AL.currentContext.src[source - 1].paused = true;
- AL.currentContext.src[source - 1].pausedTime = AL.currentContext.ctx.currentTime;
- AL.currentContext.src[source - 1]["src"].stop(0);
- delete AL.currentContext.src[source - 1].src;
- }
+ _setSourceState(src, 0x1013 /* AL_PAUSED */);
},
alGetSourcei: function(source, param, value) {
+ var src;
if (!AL.currentContext) {
#if OPENAL_DEBUG
console.error("alGetSourcei called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
- if (source > AL.currentContext.src.length) {
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
#if OPENAL_DEBUG
console.error("alGetSourcei called with an invalid source");
#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
return;
}
switch (param) {
case 0x202 /* AL_SOURCE_RELATIVE */:
- // Always return 1
- {{{ makeSetValue('value', '0', '1', 'i32') }}};
+ {{{ makeSetValue('value', '0', 'src.panner ? 1 : 0', 'i32') }}};
break;
case 0x1009 /* AL_BUFFER */:
- if (AL.currentContext.src[source - 1].buffer == null) {
+ if (!src.queue.length) {
{{{ makeSetValue('value', '0', '0', 'i32') }}};
} else {
- var buf = AL.currentContext.src[source - 1].buffer;
+ // Find the first unprocessed buffer.
+ var buffer = src.queue[src.buffersPlayed].buffer;
+ // Return its index.
for (var i = 0; i < AL.currentContext.buf.length; ++i) {
- if (buf == AL.currentContext.buf[i].buf) {
+ if (buffer == AL.currentContext.buf[i]) {
{{{ makeSetValue('value', '0', 'i+1', 'i32') }}};
return;
}
@@ -508,32 +752,80 @@ var LibraryOpenAL = {
}
break;
case 0x1010 /* AL_SOURCE_STATE */:
- if ("src" in AL.currentContext.src[source - 1]) {
- {{{ makeSetValue('value', '0', '0x1012', 'i32') }}} /* AL_PLAYING */;
- } else if (AL.currentContext.src[source - 1].paused) {
- {{{ makeSetValue('value', '0', '0x1013', 'i32') }}} /* AL_PAUSED */;
- } else if (AL.currentContext.src[source - 1].playTime == -1) {
- {{{ makeSetValue('value', '0', '0x1011', 'i32') }}} /* AL_INITIAL */;
- } else {
- {{{ makeSetValue('value', '0', '0x1014', 'i32') }}} /* AL_STOPPED */;
- }
+ {{{ makeSetValue('value', '0', 'src.state', 'i32') }}};
break;
case 0x1015 /* AL_BUFFERS_QUEUED */:
- if (AL.currentContext.src[source - 1].buffer) {
- {{{ makeSetValue('value', '0', '1', 'i32') }}}
- } else {
+ {{{ makeSetValue('value', '0', 'src.queue.length', 'i32') }}}
+ break;
+ case 0x1016 /* AL_BUFFERS_PROCESSED */:
+ if (src.loop) {
{{{ makeSetValue('value', '0', '0', 'i32') }}}
+ } else {
+ {{{ makeSetValue('value', '0', 'src.buffersPlayed', 'i32') }}}
}
break;
- case 0x1016 /* AL_BUFFERS_PROCESSED */:
- // Always return 1
- {{{ makeSetValue('value', '0', '1', 'i32') }}}
+ default:
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
+ break;
+ }
+ },
+
+ alGetSourcef: function(source, param, value) {
+ var src;
+ if (!AL.currentContext) {
+#if OPENAL_DEBUG
+ console.error("alGetSourcef called without a valid context");
+#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
+ return;
+ }
+ if (source > AL.currentContext.src.length ||
+ !(src = AL.currentContext.src[source - 1])) {
+#if OPENAL_DEBUG
+ console.error("alGetSourcef called with an invalid source");
+#endif
+ AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */;
+ return;
+ }
+ switch (param) {
+ // case 0x1003 /* AL_PITCH */:
+ // break;
+ case 0x100A /* AL_GAIN */:
+ {{{ makeSetValue('value', '0', 'src.gain.gain.value', 'float') }}}
+ break;
+ // case 0x100D /* AL_MIN_GAIN */:
+ // break;
+ // case 0x100E /* AL_MAX_GAIN */:
+ // break;
+ case 0x1023 /* AL_MAX_DISTANCE */:
+ {{{ makeSetValue('value', '0', 'src.maxDistance', 'float') }}}
+ break;
+ case 0x1021 /* AL_ROLLOFF_FACTOR */:
+ {{{ makeSetValue('value', '0', 'src.rolloffFactor', 'float') }}}
+ break;
+ // case 0x1022 /* AL_CONE_OUTER_GAIN */:
+ // break;
+ // case 0x1001 /* AL_CONE_INNER_ANGLE */:
+ // break;
+ // case 0x1002 /* AL_CONE_OUTER_ANGLE */:
+ // break;
+ case 0x1020 /* AL_REFERENCE_DISTANCE */:
+ {{{ makeSetValue('value', '0', 'src.refDistance', 'float') }}}
+ break;
+ // case 0x1024 /* AL_SEC_OFFSET */:
+ // break;
+ // case 0x1025 /* AL_SAMPLE_OFFSET */:
+ // break;
+ // case 0x1026 /* AL_BYTE_OFFSET */:
+ // break;
+ default:
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
alDistanceModel: function(model) {
- if (model != 0 /* AL_NONE */) {
+ if (model !== 0 /* AL_NONE */) {
#if OPENAL_DEBUG
console.log("Only alDistanceModel(AL_NONE) is currently supported");
#endif
@@ -545,6 +837,7 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.error("alListenerfv called without a valid context");
#endif
+ AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */;
return;
}
switch (param) {
@@ -576,6 +869,7 @@ var LibraryOpenAL = {
#if OPENAL_DEBUG
console.log("alListenerfv with param " + param + " not implemented yet");
#endif
+ AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */;
break;
}
},
@@ -588,13 +882,27 @@ var LibraryOpenAL = {
return 0;
},
+ alGetString: function (param) {
+ return allocate(intArrayFromString('NA'), 'i8', ALLOC_NORMAL);
+ },
+
alGetProcAddress: function(fname) {
return 0;
},
+ alcGetString: function (param) {
+ return allocate(intArrayFromString('NA'), 'i8', ALLOC_NORMAL);
+ },
+
alcGetProcAddress: function(device, fname) {
return 0;
},
+
+ alDopplerFactor: function(value) {
+ },
+
+ alDopplerVelocity: function(value) {
+ }
};
autoAddDeps(LibraryOpenAL, '$AL');