var LibraryOpenAL = {
$AL__deps: ['$MainLoop'],
$AL: {
QUEUE_INTERVAL: 25,
QUEUE_LOOKAHEAD: 100.0 / 1000.0,
DEVICE_NAME: 'Emscripten OpenAL',
CAPTURE_DEVICE_NAME: 'Emscripten OpenAL capture',
ALC_EXTENSIONS: {
'ALC_SOFT_pause_device': true,
'ALC_SOFT_HRTF': true
},
AL_EXTENSIONS: {
'AL_EXT_float32': true,
'AL_SOFT_loop_points': true,
'AL_SOFT_source_length': true,
'AL_EXT_source_distance_model': true,
'AL_SOFT_source_spatialize': true
},
_alcErr: 0,
get alcErr() {
return this._alcErr;
},
set alcErr(val) {
if (this._alcErr === {{{ cDefs.ALC_NO_ERROR }}} || val === {{{ cDefs.ALC_NO_ERROR }}}) {
this._alcErr = val;
}
},
deviceRefCounts: {},
alcStringCache: {},
paused: false,
stringCache: {},
contexts: {},
currentCtx: null,
buffers: {
'0': {
id: 0,
refCount: 0,
audioBuf: null,
frequency: 0,
bytesPerSample: 2,
channels: 1,
length: 0
}
},
paramArray: [],
_nextId: 1,
newId: () => AL.freeIds.length > 0 ? AL.freeIds.pop() : AL._nextId++,
freeIds: [],
scheduleContextAudio: (ctx) => {
if (MainLoop.timingMode === {{{ cDefs.EM_TIMING_RAF }}} && document['visibilityState'] != 'visible') {
return;
}
for (var i in ctx.sources) {
AL.scheduleSourceAudio(ctx.sources[i]);
}
},
scheduleSourceAudio: (src, lookahead) => {
if (MainLoop.timingMode === {{{ cDefs.EM_TIMING_RAF }}} && document['visibilityState'] != 'visible') {
return;
}
if (src.state !== {{{ cDefs.AL_PLAYING }}}) {
return;
}
var currentTime = AL.updateSourceTime(src);
var startTime = src.bufStartTime;
var startOffset = src.bufOffset;
var bufCursor = src.bufsProcessed;
for (var i = 0; i < src.audioQueue.length; i++) {
var audioSrc = src.audioQueue[i];
startTime = audioSrc._startTime + audioSrc._duration;
startOffset = 0.0;
bufCursor += audioSrc._skipCount + 1;
}
if (!lookahead) {
lookahead = AL.QUEUE_LOOKAHEAD;
}
var lookaheadTime = currentTime + lookahead;
var skipCount = 0;
while (startTime < lookaheadTime) {
if (bufCursor >= src.bufQueue.length) {
if (src.looping) {
bufCursor %= src.bufQueue.length;
} else {
break;
}
}
var buf = src.bufQueue[bufCursor % src.bufQueue.length];
if (buf.length === 0) {
skipCount++;
if (skipCount === src.bufQueue.length) {
break;
}
} else {
var audioSrc = src.context.audioCtx.createBufferSource();
audioSrc.buffer = buf.audioBuf;
audioSrc.playbackRate.value = src.playbackRate;
if (buf.audioBuf._loopStart || buf.audioBuf._loopEnd) {
audioSrc.loopStart = buf.audioBuf._loopStart;
audioSrc.loopEnd = buf.audioBuf._loopEnd;
}
var duration = 0.0;
if (src.type === {{{ cDefs.AL_STATIC }}} && src.looping) {
duration = Number.POSITIVE_INFINITY;
audioSrc.loop = true;
if (buf.audioBuf._loopStart) {
audioSrc.loopStart = buf.audioBuf._loopStart;
}
if (buf.audioBuf._loopEnd) {
audioSrc.loopEnd = buf.audioBuf._loopEnd;
}
} else {
duration = (buf.audioBuf.duration - startOffset) / src.playbackRate;
}
audioSrc._startOffset = startOffset;
audioSrc._duration = duration;
audioSrc._skipCount = skipCount;
skipCount = 0;
audioSrc.connect(src.gain);
if (typeof audioSrc.start != 'undefined') {
startTime = Math.max(startTime, src.context.audioCtx.currentTime);
audioSrc.start(startTime, startOffset);
} else if (typeof audioSrc.noteOn != 'undefined') {
startTime = Math.max(startTime, src.context.audioCtx.currentTime);
audioSrc.noteOn(startTime);
#if OPENAL_DEBUG
if (offset > 0.0) {
warnOnce('The current browser does not support AudioBufferSourceNode.start(when, offset); method, so cannot play back audio with an offset '+startOffset+' secs! Audio glitches will occur!');
}
#endif
}
#if OPENAL_DEBUG
else {
warnOnce('Unable to start AudioBufferSourceNode playback! Not supported by the browser?');
}
dbg(`scheduleSourceAudio() queuing buffer ${buf.id} for source ${src.id} at ${startTime} (offset by ${startOffset})`);
#endif
audioSrc._startTime = startTime;
src.audioQueue.push(audioSrc);
startTime += duration;
}
startOffset = 0.0;
bufCursor++;
}
},
updateSourceTime: (src) => {
var currentTime = src.context.audioCtx.currentTime;
if (src.state !== {{{ cDefs.AL_PLAYING }}}) {
return currentTime;
}
if (!isFinite(src.bufStartTime)) {
src.bufStartTime = currentTime - src.bufOffset / src.playbackRate;
src.bufOffset = 0.0;
}
var nextStartTime = 0.0;
while (src.audioQueue.length) {
var audioSrc = src.audioQueue[0];
src.bufsProcessed += audioSrc._skipCount;
nextStartTime = audioSrc._startTime + audioSrc._duration;
if (currentTime < nextStartTime) {
break;
}
src.audioQueue.shift();
src.bufStartTime = nextStartTime;
src.bufOffset = 0.0;
src.bufsProcessed++;
}
if (src.bufsProcessed >= src.bufQueue.length && !src.looping) {
AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}});
} else if (src.type === {{{ cDefs.AL_STATIC }}} && src.looping) {
var buf = src.bufQueue[0];
if (buf.length === 0) {
src.bufOffset = 0.0;
} else {
var delta = (currentTime - src.bufStartTime) * src.playbackRate;
var loopStart = buf.audioBuf._loopStart || 0.0;
var loopEnd = buf.audioBuf._loopEnd || buf.audioBuf.duration;
if (loopEnd <= loopStart) {
loopEnd = buf.audioBuf.duration;
}
if (delta < loopEnd) {
src.bufOffset = delta;
} else {
src.bufOffset = loopStart + (delta - loopStart) % (loopEnd - loopStart);
}
}
} else if (src.audioQueue[0]) {
src.bufOffset = (currentTime - src.audioQueue[0]._startTime) * src.playbackRate;
} else {
if (src.type !== {{{ cDefs.AL_STATIC }}} && src.looping) {
var srcDuration = AL.sourceDuration(src) / src.playbackRate;
if (srcDuration > 0.0) {
src.bufStartTime += Math.floor((currentTime - src.bufStartTime) / srcDuration) * srcDuration;
}
}
for (var i = 0; i < src.bufQueue.length; i++) {
if (src.bufsProcessed >= src.bufQueue.length) {
if (src.looping) {
src.bufsProcessed %= src.bufQueue.length;
} else {
AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}});
break;
}
}
var buf = src.bufQueue[src.bufsProcessed];
if (buf.length > 0) {
nextStartTime = src.bufStartTime + buf.audioBuf.duration / src.playbackRate;
if (currentTime < nextStartTime) {
src.bufOffset = (currentTime - src.bufStartTime) * src.playbackRate;
break;
}
src.bufStartTime = nextStartTime;
}
src.bufOffset = 0.0;
src.bufsProcessed++;
}
}
return currentTime;
},
cancelPendingSourceAudio: (src) => {
AL.updateSourceTime(src);
for (var i = 1; i < src.audioQueue.length; i++) {
var audioSrc = src.audioQueue[i];
audioSrc.stop();
}
if (src.audioQueue.length > 1) {
src.audioQueue.length = 1;
}
},
stopSourceAudio: (src) => {
for (var i = 0; i < src.audioQueue.length; i++) {
src.audioQueue[i].stop();
}
src.audioQueue.length = 0;
},
setSourceState: (src, state) => {
if (state === {{{ cDefs.AL_PLAYING }}}) {
if (src.state === {{{ cDefs.AL_PLAYING }}} || src.state == {{{ cDefs.AL_STOPPED }}}) {
src.bufsProcessed = 0;
src.bufOffset = 0.0;
#if OPENAL_DEBUG
dbg(`setSourceState() resetting and playing source ${src.id}`);
#endif
} else {
#if OPENAL_DEBUG
dbg(`setSourceState() playing source ${src.id} at ${src.bufOffset}`);
#endif
}
AL.stopSourceAudio(src);
src.state = {{{ cDefs.AL_PLAYING }}};
src.bufStartTime = Number.NEGATIVE_INFINITY;
AL.scheduleSourceAudio(src);
} else if (state === {{{ cDefs.AL_PAUSED }}}) {
if (src.state === {{{ cDefs.AL_PLAYING }}}) {
AL.updateSourceTime(src);
AL.stopSourceAudio(src);
src.state = {{{ cDefs.AL_PAUSED }}};
#if OPENAL_DEBUG
dbg(`setSourceState() pausing source ${src.id} at ${src.bufOffset}`);
#endif
}
} else if (state === {{{ cDefs.AL_STOPPED }}}) {
if (src.state !== {{{ cDefs.AL_INITIAL }}}) {
src.state = {{{ cDefs.AL_STOPPED }}};
src.bufsProcessed = src.bufQueue.length;
src.bufStartTime = Number.NEGATIVE_INFINITY;
src.bufOffset = 0.0;
AL.stopSourceAudio(src);
#if OPENAL_DEBUG
dbg(`setSourceState() stopping source ${src.id}`);
#endif
}
} else if (state === {{{ cDefs.AL_INITIAL }}}) {
if (src.state !== {{{ cDefs.AL_INITIAL }}}) {
src.state = {{{ cDefs.AL_INITIAL }}};
src.bufsProcessed = 0;
src.bufStartTime = Number.NEGATIVE_INFINITY;
src.bufOffset = 0.0;
AL.stopSourceAudio(src);
#if OPENAL_DEBUG
dbg(`setSourceState() initializing source ${src.id}`);
#endif
}
}
},
initSourcePanner: (src) => {
if (src.type === 0x1030 ) {
return;
}
var templateBuf = AL.buffers[0];
for (var i = 0; i < src.bufQueue.length; i++) {
if (src.bufQueue[i].id !== 0) {
templateBuf = src.bufQueue[i];
break;
}
}
if (src.spatialize === {{{ cDefs.AL_TRUE }}} || (src.spatialize === 2 && templateBuf.channels === 1)) {
if (src.panner) {
return;
}
src.panner = src.context.audioCtx.createPanner();
AL.updateSourceGlobal(src);
AL.updateSourceSpace(src);
src.panner.connect(src.context.gain);
src.gain.disconnect();
src.gain.connect(src.panner);
} else {
if (!src.panner) {
return;
}
src.panner.disconnect();
src.gain.disconnect();
src.gain.connect(src.context.gain);
src.panner = null;
}
},
updateContextGlobal: (ctx) => {
for (var i in ctx.sources) {
AL.updateSourceGlobal(ctx.sources[i]);
}
},
updateSourceGlobal: (src) => {
var panner = src.panner;
if (!panner) {
return;
}
panner.refDistance = src.refDistance;
panner.maxDistance = src.maxDistance;
panner.rolloffFactor = src.rolloffFactor;
panner.panningModel = src.context.hrtf ? 'HRTF' : 'equalpower';
var distanceModel = src.context.sourceDistanceModel ? src.distanceModel : src.context.distanceModel;
switch (distanceModel) {
case {{{ cDefs.AL_NONE }}}:
panner.distanceModel = 'inverse';
panner.refDistance = 3.40282e38 ;
break;
case 0xd001 :
case 0xd002 :
panner.distanceModel = 'inverse';
break;
case 0xd003 :
case 0xd004 :
panner.distanceModel = 'linear';
break;
case 0xd005 :
case 0xd006 :
panner.distanceModel = 'exponential';
break;
}
},
updateListenerSpace: (ctx) => {
var listener = ctx.audioCtx.listener;
if (listener.positionX) {
listener.positionX.value = ctx.listener.position[0];
listener.positionY.value = ctx.listener.position[1];
listener.positionZ.value = ctx.listener.position[2];
} else {
#if OPENAL_DEBUG
warnOnce('Listener position attributes are not present, falling back to setPosition()');
#endif
listener.setPosition(ctx.listener.position[0], ctx.listener.position[1], ctx.listener.position[2]);
}
if (listener.forwardX) {
listener.forwardX.value = ctx.listener.direction[0];
listener.forwardY.value = ctx.listener.direction[1];
listener.forwardZ.value = ctx.listener.direction[2];
listener.upX.value = ctx.listener.up[0];
listener.upY.value = ctx.listener.up[1];
listener.upZ.value = ctx.listener.up[2];
} else {
#if OPENAL_DEBUG
warnOnce('Listener orientation attributes are not present, falling back to setOrientation()');
#endif
listener.setOrientation(
ctx.listener.direction[0], ctx.listener.direction[1], ctx.listener.direction[2],
ctx.listener.up[0], ctx.listener.up[1], ctx.listener.up[2]);
}
for (var i in ctx.sources) {
AL.updateSourceSpace(ctx.sources[i]);
}
},
updateSourceSpace: (src) => {
if (!src.panner) {
return;
}
var panner = src.panner;
var posX = src.position[0];
var posY = src.position[1];
var posZ = src.position[2];
var dirX = src.direction[0];
var dirY = src.direction[1];
var dirZ = src.direction[2];
var listener = src.context.listener;
var lPosX = listener.position[0];
var lPosY = listener.position[1];
var lPosZ = listener.position[2];
if (src.relative) {
var lBackX = -listener.direction[0];
var lBackY = -listener.direction[1];
var lBackZ = -listener.direction[2];
var lUpX = listener.up[0];
var lUpY = listener.up[1];
var lUpZ = listener.up[2];
var inverseMagnitude = (x, y, z) => {
var length = Math.sqrt(x * x + y * y + z * z);
if (length < Number.EPSILON) {
return 0.0;
}
return 1.0 / length;
};
var invMag = inverseMagnitude(lBackX, lBackY, lBackZ);
lBackX *= invMag;
lBackY *= invMag;
lBackZ *= invMag;
invMag = inverseMagnitude(lUpX, lUpY, lUpZ);
lUpX *= invMag;
lUpY *= invMag;
lUpZ *= invMag;
var lRightX = (lUpY * lBackZ - lUpZ * lBackY);
var lRightY = (lUpZ * lBackX - lUpX * lBackZ);
var lRightZ = (lUpX * lBackY - lUpY * lBackX);
invMag = inverseMagnitude(lRightX, lRightY, lRightZ);
lRightX *= invMag;
lRightY *= invMag;
lRightZ *= invMag;
lUpX = (lBackY * lRightZ - lBackZ * lRightY);
lUpY = (lBackZ * lRightX - lBackX * lRightZ);
lUpZ = (lBackX * lRightY - lBackY * lRightX);
var oldX = dirX;
var oldY = dirY;
var oldZ = dirZ;
dirX = oldX * lRightX + oldY * lUpX + oldZ * lBackX;
dirY = oldX * lRightY + oldY * lUpY + oldZ * lBackY;
dirZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ;
oldX = posX;
oldY = posY;
oldZ = posZ;
posX = oldX * lRightX + oldY * lUpX + oldZ * lBackX;
posY = oldX * lRightY + oldY * lUpY + oldZ * lBackY;
posZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ;
posX += lPosX;
posY += lPosY;
posZ += lPosZ;
}
if (panner.positionX) {
if (posX != panner.positionX.value) panner.positionX.value = posX;
if (posY != panner.positionY.value) panner.positionY.value = posY;
if (posZ != panner.positionZ.value) panner.positionZ.value = posZ;
} else {
#if OPENAL_DEBUG
warnOnce('Panner position attributes are not present, falling back to setPosition()');
#endif
panner.setPosition(posX, posY, posZ);
}
if (panner.orientationX) {
if (dirX != panner.orientationX.value) panner.orientationX.value = dirX;
if (dirY != panner.orientationY.value) panner.orientationY.value = dirY;
if (dirZ != panner.orientationZ.value) panner.orientationZ.value = dirZ;
} else {
#if OPENAL_DEBUG
warnOnce('Panner orientation attributes are not present, falling back to setOrientation()');
#endif
panner.setOrientation(dirX, dirY, dirZ);
}
var oldShift = src.dopplerShift;
var velX = src.velocity[0];
var velY = src.velocity[1];
var velZ = src.velocity[2];
var lVelX = listener.velocity[0];
var lVelY = listener.velocity[1];
var lVelZ = listener.velocity[2];
if (posX === lPosX && posY === lPosY && posZ === lPosZ
|| velX === lVelX && velY === lVelY && velZ === lVelZ)
{
src.dopplerShift = 1.0;
} else {
var speedOfSound = src.context.speedOfSound;
var dopplerFactor = src.context.dopplerFactor;
var slX = lPosX - posX;
var slY = lPosY - posY;
var slZ = lPosZ - posZ;
var magSl = Math.sqrt(slX * slX + slY * slY + slZ * slZ);
var vls = (slX * lVelX + slY * lVelY + slZ * lVelZ) / magSl;
var vss = (slX * velX + slY * velY + slZ * velZ) / magSl;
vls = Math.min(vls, speedOfSound / dopplerFactor);
vss = Math.min(vss, speedOfSound / dopplerFactor);
src.dopplerShift = (speedOfSound - dopplerFactor * vls) / (speedOfSound - dopplerFactor * vss);
}
if (src.dopplerShift !== oldShift) {
AL.updateSourceRate(src);
}
},
updateSourceRate: (src) => {
if (src.state === {{{ cDefs.AL_PLAYING }}}) {
AL.cancelPendingSourceAudio(src);
var audioSrc = src.audioQueue[0];
if (!audioSrc) {
return;
}
var duration;
if (src.type === {{{ cDefs.AL_STATIC }}} && src.looping) {
duration = Number.POSITIVE_INFINITY;
} else {
duration = (audioSrc.buffer.duration - audioSrc._startOffset) / src.playbackRate;
}
audioSrc._duration = duration;
audioSrc.playbackRate.value = src.playbackRate;
AL.scheduleSourceAudio(src);
}
},
sourceDuration: (src) => {
var length = 0.0;
for (var i = 0; i < src.bufQueue.length; i++) {
var audioBuf = src.bufQueue[i].audioBuf;
length += audioBuf ? audioBuf.duration : 0.0;
}
return length;
},
sourceTell: (src) => {
AL.updateSourceTime(src);
var offset = 0.0;
for (var i = 0; i < src.bufsProcessed; i++) {
if (src.bufQueue[i].audioBuf) {
offset += src.bufQueue[i].audioBuf.duration;
}
}
offset += src.bufOffset;
return offset;
},
sourceSeek: (src, offset) => {
var playing = src.state == {{{ cDefs.AL_PLAYING }}};
if (playing) {
AL.setSourceState(src, {{{ cDefs.AL_INITIAL }}});
}
if (src.bufQueue[src.bufsProcessed].audioBuf !== null) {
src.bufsProcessed = 0;
while (offset > src.bufQueue[src.bufsProcessed].audioBuf.duration) {
offset -= src.bufQueue[src.bufsProcessed].audioBuf.duration;
src.bufsProcessed++;
}
src.bufOffset = offset;
}
if (playing) {
AL.setSourceState(src, {{{ cDefs.AL_PLAYING }}});
}
},
getGlobalParam: (funcname, param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return null;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
return AL.currentCtx.dopplerFactor;
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
return AL.currentCtx.speedOfSound;
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
return AL.currentCtx.distanceModel;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param} is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return null;
}
},
setGlobalParam: (funcname, param, value) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
if (!Number.isFinite(value) || value < 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.currentCtx.dopplerFactor = value;
AL.updateListenerSpace(AL.currentCtx);
break;
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
if (!Number.isFinite(value) || value <= 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.currentCtx.speedOfSound = value;
AL.updateListenerSpace(AL.currentCtx);
break;
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
switch (value) {
case {{{ cDefs.AL_NONE }}}:
case 0xd001 :
case 0xd002 :
case 0xd003 :
case 0xd004 :
case 0xd005 :
case 0xd006 :
AL.currentCtx.distanceModel = value;
AL.updateContextGlobal(AL.currentCtx);
break;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
break;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
getListenerParam: (funcname, param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return null;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
return AL.currentCtx.listener.position;
case {{{ cDefs.AL_VELOCITY }}}:
return AL.currentCtx.listener.velocity;
case {{{ cDefs.AL_ORIENTATION }}}:
return AL.currentCtx.listener.direction.concat(AL.currentCtx.listener.up);
case {{{ cDefs.AL_GAIN }}}:
return AL.currentCtx.gain.gain.value;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return null;
}
},
setListenerParam: (funcname, param, value) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return;
}
if (value === null) {
#if OPENAL_DEBUG
dbg(`${funcname}(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
var listener = AL.currentCtx.listener;
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_POSITION value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
listener.position[0] = value[0];
listener.position[1] = value[1];
listener.position[2] = value[2];
AL.updateListenerSpace(AL.currentCtx);
break;
case {{{ cDefs.AL_VELOCITY }}}:
if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_VELOCITY value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
listener.velocity[0] = value[0];
listener.velocity[1] = value[1];
listener.velocity[2] = value[2];
AL.updateListenerSpace(AL.currentCtx);
break;
case {{{ cDefs.AL_GAIN }}}:
if (!Number.isFinite(value) || value < 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_GAIN value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.currentCtx.gain.gain.value = value;
break;
case {{{ cDefs.AL_ORIENTATION }}}:
if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])
|| !Number.isFinite(value[3]) || !Number.isFinite(value[4]) || !Number.isFinite(value[5])
) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_ORIENTATION value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
listener.direction[0] = value[0];
listener.direction[1] = value[1];
listener.direction[2] = value[2];
listener.up[0] = value[3];
listener.up[1] = value[4];
listener.up[2] = value[5];
AL.updateListenerSpace(AL.currentCtx);
break;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
getBufferParam: (funcname, bufferId, param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return;
}
var buf = AL.buffers[bufferId];
if (!buf || bufferId === 0) {
#if OPENAL_DEBUG
dbg(`${funcname}() called with an invalid buffer`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
switch (param) {
case 0x2001 :
return buf.frequency;
case 0x2002 :
return buf.bytesPerSample * 8;
case 0x2003 :
return buf.channels;
case 0x2004 :
return buf.length * buf.bytesPerSample * buf.channels;
case 0x2015 :
if (buf.length === 0) {
return [0, 0];
}
return [
(buf.audioBuf._loopStart || 0.0) * buf.frequency,
(buf.audioBuf._loopEnd || buf.length) * buf.frequency
];
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return null;
}
},
setBufferParam: (funcname, bufferId, param, value) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return;
}
var buf = AL.buffers[bufferId];
if (!buf || bufferId === 0) {
#if OPENAL_DEBUG
dbg(`${funcname}() called with an invalid buffer`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
if (value === null) {
#if OPENAL_DEBUG
dbg(`${funcname}(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
switch (param) {
case 0x2004 :
if (value !== 0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_SIZE value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
break;
case 0x2015 :
if (value[0] < 0 || value[0] > buf.length || value[1] < 0 || value[1] > buf.Length || value[0] >= value[1]) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_LOOP_POINTS_SOFT value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
if (buf.refCount > 0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_LOOP_POINTS_SOFT set on bound buffer`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}};
return;
}
if (buf.audioBuf) {
buf.audioBuf._loopStart = value[0] / buf.frequency;
buf.audioBuf._loopEnd = value[1] / buf.frequency;
}
break;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)}' is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
getSourceParam: (funcname, sourceId, param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return null;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg(`${funcname}() called with an invalid source`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return null;
}
switch (param) {
case 0x202 :
return src.relative;
case 0x1001 :
return src.coneInnerAngle;
case 0x1002 :
return src.coneOuterAngle;
case 0x1003 :
return src.pitch;
case {{{ cDefs.AL_POSITION }}}:
return src.position;
case {{{ cDefs.AL_DIRECTION }}}:
return src.direction;
case {{{ cDefs.AL_VELOCITY }}}:
return src.velocity;
case 0x1007 :
return src.looping;
case 0x1009 :
if (src.type === {{{ cDefs.AL_STATIC }}}) {
return src.bufQueue[0].id;
}
return 0;
case {{{ cDefs.AL_GAIN }}}:
return src.gain.gain.value;
case 0x100D :
return src.minGain;
case 0x100E :
return src.maxGain;
case 0x1010 :
return src.state;
case 0x1015 :
if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) {
return 0;
}
return src.bufQueue.length;
case 0x1016 :
if ((src.bufQueue.length === 1 && src.bufQueue[0].id === 0) || src.looping) {
return 0;
}
return src.bufsProcessed;
case 0x1020 :
return src.refDistance;
case 0x1021 :
return src.rolloffFactor;
case 0x1022 :
return src.coneOuterGain;
case 0x1023 :
return src.maxDistance;
case 0x1024 :
return AL.sourceTell(src);
case 0x1025 :
var offset = AL.sourceTell(src);
if (offset > 0.0) {
offset *= src.bufQueue[0].frequency;
}
return offset;
case 0x1026 :
var offset = AL.sourceTell(src);
if (offset > 0.0) {
offset *= src.bufQueue[0].frequency * src.bufQueue[0].bytesPerSample;
}
return offset;
case 0x1027 :
return src.type;
case 0x1214 :
return src.spatialize;
case 0x2009 :
var length = 0;
var bytesPerFrame = 0;
for (var i = 0; i < src.bufQueue.length; i++) {
length += src.bufQueue[i].length;
if (src.bufQueue[i].id !== 0) {
bytesPerFrame = src.bufQueue[i].bytesPerSample * src.bufQueue[i].channels;
}
}
return length * bytesPerFrame;
case 0x200A :
var length = 0;
for (var i = 0; i < src.bufQueue.length; i++) {
length += src.bufQueue[i].length;
}
return length;
case 0x200B :
return AL.sourceDuration(src);
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
return src.distanceModel;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)}' is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return null;
}
},
setSourceParam: (funcname, sourceId, param, value) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg(`${funcname}() called without a valid context`);
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourcef() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
if (value === null) {
#if OPENAL_DEBUG
dbg(`${funcname}(): param ${ptrToString(param)}' has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
switch (param) {
case 0x202 :
if (value === {{{ cDefs.AL_TRUE }}}) {
src.relative = true;
AL.updateSourceSpace(src);
} else if (value === {{{ cDefs.AL_FALSE }}}) {
src.relative = false;
AL.updateSourceSpace(src);
} else {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_SOURCE_RELATIVE value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
break;
case 0x1001 :
if (!Number.isFinite(value)) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_CONE_INNER_ANGLE value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.coneInnerAngle = value;
if (src.panner) {
src.panner.coneInnerAngle = value % 360.0;
}
break;
case 0x1002 :
if (!Number.isFinite(value)) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_CONE_OUTER_ANGLE value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.coneOuterAngle = value;
if (src.panner) {
src.panner.coneOuterAngle = value % 360.0;
}
break;
case 0x1003 :
if (!Number.isFinite(value) || value <= 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_PITCH value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
if (src.pitch === value) {
break;
}
src.pitch = value;
AL.updateSourceRate(src);
break;
case {{{ cDefs.AL_POSITION }}}:
if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_POSITION value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.position[0] = value[0];
src.position[1] = value[1];
src.position[2] = value[2];
AL.updateSourceSpace(src);
break;
case {{{ cDefs.AL_DIRECTION }}}:
if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_DIRECTION value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.direction[0] = value[0];
src.direction[1] = value[1];
src.direction[2] = value[2];
AL.updateSourceSpace(src);
break;
case {{{ cDefs.AL_VELOCITY }}}:
if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_VELOCITY value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.velocity[0] = value[0];
src.velocity[1] = value[1];
src.velocity[2] = value[2];
AL.updateSourceSpace(src);
break;
case 0x1007 :
if (value === {{{ cDefs.AL_TRUE }}}) {
src.looping = true;
AL.updateSourceTime(src);
if (src.type === {{{ cDefs.AL_STATIC }}} && src.audioQueue.length > 0) {
var audioSrc = src.audioQueue[0];
audioSrc.loop = true;
audioSrc._duration = Number.POSITIVE_INFINITY;
}
} else if (value === {{{ cDefs.AL_FALSE }}}) {
src.looping = false;
var currentTime = AL.updateSourceTime(src);
if (src.type === {{{ cDefs.AL_STATIC }}} && src.audioQueue.length > 0) {
var audioSrc = src.audioQueue[0];
audioSrc.loop = false;
audioSrc._duration = src.bufQueue[0].audioBuf.duration / src.playbackRate;
audioSrc._startTime = currentTime - src.bufOffset / src.playbackRate;
}
} else {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_LOOPING value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
break;
case 0x1009 :
if (src.state === {{{ cDefs.AL_PLAYING }}} || src.state === {{{ cDefs.AL_PAUSED }}}) {
#if OPENAL_DEBUG
dbg(`${funcname}(AL_BUFFER) called while source is playing or paused`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}};
return;
}
if (value === 0) {
for (var i in src.bufQueue) {
src.bufQueue[i].refCount--;
}
src.bufQueue.length = 1;
src.bufQueue[0] = AL.buffers[0];
src.bufsProcessed = 0;
src.type = 0x1030 ;
} else {
var buf = AL.buffers[value];
if (!buf) {
#if OPENAL_DEBUG
dbg('alSourcei(AL_BUFFER) called with an invalid buffer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
for (var i in src.bufQueue) {
src.bufQueue[i].refCount--;
}
src.bufQueue.length = 0;
buf.refCount++;
src.bufQueue = [buf];
src.bufsProcessed = 0;
src.type = {{{ cDefs.AL_STATIC }}};
}
AL.initSourcePanner(src);
AL.scheduleSourceAudio(src);
break;
case {{{ cDefs.AL_GAIN }}}:
if (!Number.isFinite(value) || value < 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_GAIN value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.gain.gain.value = value;
break;
case 0x100D :
if (!Number.isFinite(value) || value < 0.0 || value > Math.min(src.maxGain, 1.0)) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_MIN_GAIN value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
warnOnce('AL_MIN_GAIN is not currently supported');
#endif
src.minGain = value;
break;
case 0x100E :
if (!Number.isFinite(value) || value < Math.max(0.0, src.minGain) || value > 1.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_MAX_GAIN value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
warnOnce('AL_MAX_GAIN is not currently supported');
#endif
src.maxGain = value;
break;
case 0x1020 :
if (!Number.isFinite(value) || value < 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_REFERENCE_DISTANCE value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.refDistance = value;
if (src.panner) {
src.panner.refDistance = value;
}
break;
case 0x1021 :
if (!Number.isFinite(value) || value < 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_ROLLOFF_FACTOR value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.rolloffFactor = value;
if (src.panner) {
src.panner.rolloffFactor = value;
}
break;
case 0x1022 :
if (!Number.isFinite(value) || value < 0.0 || value > 1.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_CORE_OUTER_GAIN value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.coneOuterGain = value;
if (src.panner) {
src.panner.coneOuterGain = value;
}
break;
case 0x1023 :
if (!Number.isFinite(value) || value < 0.0) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_MAX_DISTANCE value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.maxDistance = value;
if (src.panner) {
src.panner.maxDistance = value;
}
break;
case 0x1024 :
if (value < 0.0 || value > AL.sourceDuration(src)) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_SEC_OFFSET value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.sourceSeek(src, value);
break;
case 0x1025 :
var srcLen = AL.sourceDuration(src);
if (srcLen > 0.0) {
var frequency;
for (var bufId in src.bufQueue) {
if (bufId) {
frequency = src.bufQueue[bufId].frequency;
break;
}
}
value /= frequency;
}
if (value < 0.0 || value > srcLen) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_SAMPLE_OFFSET value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.sourceSeek(src, value);
break;
case 0x1026 :
var srcLen = AL.sourceDuration(src);
if (srcLen > 0.0) {
var bytesPerSec;
for (var bufId in src.bufQueue) {
if (bufId) {
var buf = src.bufQueue[bufId];
bytesPerSec = buf.frequency * buf.bytesPerSample * buf.channels;
break;
}
}
value /= bytesPerSec;
}
if (value < 0.0 || value > srcLen) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_BYTE_OFFSET value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.sourceSeek(src, value);
break;
case 0x1214 :
if (value !== {{{ cDefs.AL_FALSE }}} && value !== {{{ cDefs.AL_TRUE }}} && value !== 2 ) {
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_SOURCE_SPATIALIZE_SOFT value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
src.spatialize = value;
AL.initSourcePanner(src);
break;
case 0x2009 :
case 0x200A :
case 0x200B :
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_*_LENGTH_SOFT is read only`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}};
break;
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
switch (value) {
case {{{ cDefs.AL_NONE }}}:
case 0xd001 :
case 0xd002 :
case 0xd003 :
case 0xd004 :
case 0xd005 :
case 0xd006 :
src.distanceModel = value;
if (AL.currentCtx.sourceDistanceModel) {
AL.updateContextGlobal(AL.currentCtx);
}
break;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param AL_DISTANCE_MODEL value ${value} is out of range`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
break;
default:
#if OPENAL_DEBUG
dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
captures: {},
sharedCaptureAudioCtx: null,
requireValidCaptureDevice: (deviceId, funcname) => {
if (deviceId === 0) {
#if OPENAL_DEBUG
dbg(`${funcname}() on a NULL device is an error`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return null;
}
var c = AL.captures[deviceId];
if (!c) {
#if OPENAL_DEBUG
dbg(`${funcname}() on an invalid device`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return null;
}
var err = c.mediaStreamError;
if (err) {
#if OPENAL_DEBUG
switch (err.name) {
case 'PermissionDeniedError':
dbg(`${funcname}() but the user denied access to the device`);
break;
case 'NotFoundError':
dbg(`${funcname}() but no capture device was found`);
break;
default:
dbg(`${funcname}() but a MediaStreamError was encountered: ${err}`);
break;
}
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return null;
}
return c;
}
},
alcCaptureOpenDevice__deps: ['$autoResumeAudioContext'],
alcCaptureOpenDevice__proxy: 'sync',
alcCaptureOpenDevice: (pDeviceName, requestedSampleRate, format, bufferFrameCapacity) => {
var resolvedDeviceName = AL.CAPTURE_DEVICE_NAME;
if (pDeviceName !== 0) {
resolvedDeviceName = UTF8ToString(pDeviceName);
if (resolvedDeviceName !== AL.CAPTURE_DEVICE_NAME) {
#if OPENAL_DEBUG
dbg(`alcCaptureOpenDevice() with invalid device name '${resolvedDeviceName}'`);
#endif
AL.alcErr = 0xA005 ;
return 0;
}
}
if (bufferFrameCapacity < 0) {
#if OPENAL_DEBUG
dbg('alcCaptureOpenDevice() with negative bufferSize');
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return 0;
}
navigator.getUserMedia = navigator.getUserMedia
|| navigator.webkitGetUserMedia
|| navigator.mozGetUserMedia
|| navigator.msGetUserMedia;
var has_getUserMedia = navigator.getUserMedia
|| (navigator.mediaDevices
&& navigator.mediaDevices.getUserMedia);
if (!has_getUserMedia) {
#if OPENAL_DEBUG
dbg('alcCaptureOpenDevice() cannot capture audio, because your browser lacks a `getUserMedia()` implementation');
#endif
AL.alcErr = 0xA005 ;
return 0;
}
var AudioContext = window.AudioContext || window.webkitAudioContext;
if (!AL.sharedCaptureAudioCtx) {
try {
AL.sharedCaptureAudioCtx = new AudioContext();
} catch(e) {
#if OPENAL_DEBUG
dbg(`alcCaptureOpenDevice() could not create the shared capture AudioContext: ${e}`);
#endif
AL.alcErr = 0xA005 ;
return 0;
}
}
autoResumeAudioContext(AL.sharedCaptureAudioCtx);
var outputChannelCount;
switch (format) {
case 0x10010:
case 0x1101:
case 0x1100:
outputChannelCount = 1;
break;
case 0x10011:
case 0x1103:
case 0x1102:
outputChannelCount = 2;
break;
default:
#if OPENAL_DEBUG
dbg(`alcCaptureOpenDevice() with unsupported format ${format}`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return 0;
}
function newF32Array(cap) { return new Float32Array(cap);}
function newI16Array(cap) { return new Int16Array(cap); }
function newU8Array(cap) { return new Uint8Array(cap); }
var requestedSampleType;
var newSampleArray;
switch (format) {
case 0x10010:
case 0x10011:
requestedSampleType = 'f32';
newSampleArray = newF32Array;
break;
case 0x1101:
case 0x1103:
requestedSampleType = 'i16';
newSampleArray = newI16Array;
break;
case 0x1100:
case 0x1102:
requestedSampleType = 'u8';
newSampleArray = newU8Array;
break;
}
var buffers = [];
try {
for (var chan=0; chan < outputChannelCount; ++chan) {
buffers[chan] = newSampleArray(bufferFrameCapacity);
}
} catch(e) {
#if OPENAL_DEBUG
dbg(`alcCaptureOpenDevice() failed to allocate internal buffers (is bufferSize low enough?): ${e}`);
#endif
AL.alcErr = 0xA005 ;
return 0;
}
var newCapture = {
audioCtx: AL.sharedCaptureAudioCtx,
deviceName: resolvedDeviceName,
requestedSampleRate,
requestedSampleType,
outputChannelCount,
inputChannelCount: null,
mediaStreamError: null,
mediaStreamSourceNode: null,
mediaStream: null,
mergerNode: null,
splitterNode: null,
scriptProcessorNode: null,
isCapturing: false,
buffers,
get bufferFrameCapacity() {
return buffers[0].length;
},
capturePlayhead: 0,
captureReadhead: 0,
capturedFrameCount: 0
};
var onError = (mediaStreamError) => {
newCapture.mediaStreamError = mediaStreamError;
#if OPENAL_DEBUG
dbg(`navigator.getUserMedia() errored with: ${mediaStreamError}`);
#endif
};
var onSuccess = (mediaStream) => {
newCapture.mediaStreamSourceNode = newCapture.audioCtx.createMediaStreamSource(mediaStream);
newCapture.mediaStream = mediaStream;
var inputChannelCount = 1;
switch (newCapture.mediaStreamSourceNode.channelCountMode) {
case 'max':
inputChannelCount = outputChannelCount;
break;
case 'clamped-max':
inputChannelCount = Math.min(outputChannelCount, newCapture.mediaStreamSourceNode.channelCount);
break;
case 'explicit':
inputChannelCount = newCapture.mediaStreamSourceNode.channelCount;
break;
}
newCapture.inputChannelCount = inputChannelCount;
#if OPENAL_DEBUG
if (inputChannelCount > 2 || outputChannelCount > 2) {
dbg('The number of input or output channels is too high, capture might not work as expected!');
}
#endif
var processorFrameCount = 512;
newCapture.scriptProcessorNode = newCapture.audioCtx.createScriptProcessor(
processorFrameCount, inputChannelCount, outputChannelCount
);
if (inputChannelCount > outputChannelCount) {
newCapture.mergerNode = newCapture.audioCtx.createChannelMerger(inputChannelCount);
newCapture.mediaStreamSourceNode.connect(newCapture.mergerNode);
newCapture.mergerNode.connect(newCapture.scriptProcessorNode);
} else if (inputChannelCount < outputChannelCount) {
newCapture.splitterNode = newCapture.audioCtx.createChannelSplitter(outputChannelCount);
newCapture.mediaStreamSourceNode.connect(newCapture.splitterNode);
newCapture.splitterNode.connect(newCapture.scriptProcessorNode);
} else {
newCapture.mediaStreamSourceNode.connect(newCapture.scriptProcessorNode);
}
newCapture.scriptProcessorNode.connect(newCapture.audioCtx.destination);
newCapture.scriptProcessorNode.onaudioprocess = (audioProcessingEvent) => {
if (!newCapture.isCapturing) {
return;
}
var c = newCapture;
var srcBuf = audioProcessingEvent.inputBuffer;
switch (format) {
case 0x10010:
var channel0 = srcBuf.getChannelData(0);
for (var i = 0 ; i < srcBuf.length; ++i) {
var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity;
c.buffers[0][wi] = channel0[i];
}
break;
case 0x10011:
var channel0 = srcBuf.getChannelData(0);
var channel1 = srcBuf.getChannelData(1);
for (var i = 0 ; i < srcBuf.length; ++i) {
var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity;
c.buffers[0][wi] = channel0[i];
c.buffers[1][wi] = channel1[i];
}
break;
case 0x1101:
var channel0 = srcBuf.getChannelData(0);
for (var i = 0 ; i < srcBuf.length; ++i) {
var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity;
c.buffers[0][wi] = channel0[i] * 32767;
}
break;
case 0x1103:
var channel0 = srcBuf.getChannelData(0);
var channel1 = srcBuf.getChannelData(1);
for (var i = 0 ; i < srcBuf.length; ++i) {
var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity;
c.buffers[0][wi] = channel0[i] * 32767;
c.buffers[1][wi] = channel1[i] * 32767;
}
break;
case 0x1100:
var channel0 = srcBuf.getChannelData(0);
for (var i = 0 ; i < srcBuf.length; ++i) {
var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity;
c.buffers[0][wi] = (channel0[i] + 1.0) * 127;
}
break;
case 0x1102:
var channel0 = srcBuf.getChannelData(0);
var channel1 = srcBuf.getChannelData(1);
for (var i = 0 ; i < srcBuf.length; ++i) {
var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity;
c.buffers[0][wi] = (channel0[i] + 1.0) * 127;
c.buffers[1][wi] = (channel1[i] + 1.0) * 127;
}
break;
}
c.capturePlayhead += srcBuf.length;
c.capturePlayhead %= c.bufferFrameCapacity;
c.capturedFrameCount += srcBuf.length;
c.capturedFrameCount = Math.min(c.capturedFrameCount, c.bufferFrameCapacity);
};
};
if (navigator.mediaDevices?.getUserMedia) {
navigator.mediaDevices
.getUserMedia({audio: true})
.then(onSuccess)
.catch(onError);
} else {
navigator.getUserMedia({audio: true}, onSuccess, onError);
}
var id = AL.newId();
AL.captures[id] = newCapture;
return id;
},
alcCaptureCloseDevice__proxy: 'sync',
alcCaptureCloseDevice: (deviceId) => {
var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureCloseDevice');
if (!c) return false;
delete AL.captures[deviceId];
AL.freeIds.push(deviceId);
c.mediaStreamSourceNode?.disconnect();
c.mergerNode?.disconnect();
c.splitterNode?.disconnect();
c.scriptProcessorNode?.disconnect();
if (c.mediaStream) {
c.mediaStream.getTracks().forEach((track) => track.stop());
}
delete c.buffers;
c.capturedFrameCount = 0;
c.isCapturing = false;
return true;
},
alcCaptureStart__proxy: 'sync',
alcCaptureStart: (deviceId) => {
var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStart');
if (!c) return;
if (c.isCapturing) {
#if OPENAL_DEBUG
dbg('Redundant call to alcCaptureStart()');
#endif
return;
}
c.isCapturing = true;
c.capturedFrameCount = 0;
c.capturePlayhead = 0;
},
alcCaptureStop__proxy: 'sync',
alcCaptureStop: (deviceId) => {
var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStop');
if (!c) return;
#if OPENAL_DEBUG
if (!c.isCapturing) {
dbg('Redundant call to alcCaptureStop()');
}
#endif
c.isCapturing = false;
},
alcCaptureSamples__proxy: 'sync',
alcCaptureSamples: (deviceId, pFrames, requestedFrameCount) => {
var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureSamples');
if (!c) return;
var dstfreq = c.requestedSampleRate;
var srcfreq = c.audioCtx.sampleRate;
var fratio = srcfreq / dstfreq;
if (requestedFrameCount < 0
|| requestedFrameCount > (c.capturedFrameCount / fratio))
{
#if OPENAL_DEBUG
dbg('alcCaptureSamples() with invalid bufferSize');
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return;
}
function setF32Sample(i, sample) {
{{{ makeSetValue('pFrames', '4*i', 'sample', 'float') }}};
}
function setI16Sample(i, sample) {
{{{ makeSetValue('pFrames', '2*i', 'sample', 'i16') }}};
}
function setU8Sample(i, sample) {
{{{ makeSetValue('pFrames', 'i', 'sample', 'i8') }}};
}
var setSample;
switch (c.requestedSampleType) {
case 'f32': setSample = setF32Sample; break;
case 'i16': setSample = setI16Sample; break;
case 'u8' : setSample = setU8Sample ; break;
default:
#if OPENAL_DEBUG
dbg(`Internal error: Unknown sample type '${c.requestedSampleType}'`);
#endif
return;
}
if (Math.floor(fratio) == fratio) {
for (var i = 0, frame_i = 0; frame_i < requestedFrameCount; ++frame_i) {
for (var chan = 0; chan < c.buffers.length; ++chan, ++i) {
setSample(i, c.buffers[chan][c.captureReadhead]);
}
c.captureReadhead = (fratio + c.captureReadhead) % c.bufferFrameCapacity;
}
} else {
for (var i = 0, frame_i = 0; frame_i < requestedFrameCount; ++frame_i) {
var lefti = Math.floor(c.captureReadhead);
var righti = Math.ceil(c.captureReadhead);
var d = c.captureReadhead - lefti;
for (var chan = 0; chan < c.buffers.length; ++chan, ++i) {
var lefts = c.buffers[chan][lefti];
var rights = c.buffers[chan][righti];
setSample(i, (1 - d) * lefts + d * rights);
}
c.captureReadhead = (c.captureReadhead + fratio) % c.bufferFrameCapacity;
}
}
c.capturedFrameCount = 0;
},
alcOpenDevice__proxy: 'sync',
alcOpenDevice: (pDeviceName) => {
if (pDeviceName) {
var name = UTF8ToString(pDeviceName);
if (name !== AL.DEVICE_NAME) {
return 0;
}
}
if (typeof AudioContext != 'undefined' || typeof webkitAudioContext != 'undefined') {
var deviceId = AL.newId();
AL.deviceRefCounts[deviceId] = 0;
return deviceId;
}
return 0;
},
alcCloseDevice__proxy: 'sync',
alcCloseDevice: (deviceId) => {
if (!(deviceId in AL.deviceRefCounts) || AL.deviceRefCounts[deviceId] > 0) {
return {{{ cDefs.ALC_FALSE }}};
}
delete AL.deviceRefCounts[deviceId];
AL.freeIds.push(deviceId);
return {{{ cDefs.ALC_TRUE }}};
},
alcCreateContext__deps: ['$autoResumeAudioContext'],
alcCreateContext__proxy: 'sync',
alcCreateContext: (deviceId, pAttrList) => {
if (!(deviceId in AL.deviceRefCounts)) {
#if OPENAL_DEBUG
dbg('alcCreateContext() called with an invalid device');
#endif
AL.alcErr = 0xA001;
return 0;
}
var options = null;
var attrs = [];
var hrtf = null;
pAttrList >>= 2;
if (pAttrList) {
var attr = 0;
var val = 0;
while (true) {
attr = HEAP32[pAttrList++];
attrs.push(attr);
if (attr === 0) {
break;
}
val = HEAP32[pAttrList++];
attrs.push(val);
switch (attr) {
case 0x1007 :
if (!options) {
options = {};
}
options.sampleRate = val;
break;
case 0x1010 :
case 0x1011 :
break
case 0x1992 :
switch (val) {
case {{{ cDefs.ALC_FALSE }}}:
hrtf = false;
break;
case {{{ cDefs.ALC_TRUE }}}:
hrtf = true;
break;
case 2 :
break;
default:
#if OPENAL_DEBUG
dbg(`Unsupported ALC_HRTF_SOFT mode ${val}`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return 0;
}
break;
case 0x1996 :
if (val !== 0) {
#if OPENAL_DEBUG
dbg(`Invalid ALC_HRTF_ID_SOFT index ${val}`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return 0;
}
break;
default:
#if OPENAL_DEBUG
dbg(`Unsupported context attribute ${ptrToString(attr)}`);
#endif
AL.alcErr = 0xA004;
return 0;
}
}
}
var AudioContext = window.AudioContext || window.webkitAudioContext;
var ac = null;
try {
if (options) {
ac = new AudioContext(options);
} else {
ac = new AudioContext();
}
} catch (e) {
if (e.name === 'NotSupportedError') {
#if OPENAL_DEBUG
dbg('Invalid or unsupported options');
#endif
AL.alcErr = 0xA004;
} else {
AL.alcErr = 0xA001;
}
return 0;
}
autoResumeAudioContext(ac);
if (typeof ac.createGain == 'undefined') {
ac.createGain = ac.createGainNode;
}
var gain = ac.createGain();
gain.connect(ac.destination);
var ctx = {
deviceId,
id: AL.newId(),
attrs,
audioCtx: ac,
listener: {
position: [0.0, 0.0, 0.0],
velocity: [0.0, 0.0, 0.0],
direction: [0.0, 0.0, 0.0],
up: [0.0, 0.0, 0.0]
},
sources: [],
interval: setInterval(() => AL.scheduleContextAudio(ctx), AL.QUEUE_INTERVAL),
gain,
distanceModel: 0xd002 ,
speedOfSound: 343.3,
dopplerFactor: 1.0,
sourceDistanceModel: false,
hrtf: hrtf || false,
_err: 0,
get err() {
return this._err;
},
set err(val) {
if (this._err === {{{ cDefs.AL_NO_ERROR }}} || val === {{{ cDefs.AL_NO_ERROR }}}) {
this._err = val;
}
}
};
AL.deviceRefCounts[deviceId]++;
AL.contexts[ctx.id] = ctx;
if (hrtf !== null) {
for (var ctxId in AL.contexts) {
var c = AL.contexts[ctxId];
if (c.deviceId === deviceId) {
c.hrtf = hrtf;
AL.updateContextGlobal(c);
}
}
}
return ctx.id;
},
alcDestroyContext__proxy: 'sync',
alcDestroyContext: (contextId) => {
var ctx = AL.contexts[contextId];
if (AL.currentCtx === ctx) {
#if OPENAL_DEBUG
dbg('alcDestroyContext() called with an invalid context');
#endif
AL.alcErr = 0xA002 ;
return;
}
if (AL.contexts[contextId].interval) {
clearInterval(AL.contexts[contextId].interval);
}
AL.deviceRefCounts[ctx.deviceId]--;
delete AL.contexts[contextId];
AL.freeIds.push(contextId);
},
alcGetError__proxy: 'sync',
alcGetError: (deviceId) => {
var err = AL.alcErr;
AL.alcErr = {{{ cDefs.ALC_NO_ERROR }}};
return err;
},
alcGetCurrentContext__proxy: 'sync',
alcGetCurrentContext: () => {
if (AL.currentCtx !== null) {
return AL.currentCtx.id;
}
return 0;
},
alcMakeContextCurrent__proxy: 'sync',
alcMakeContextCurrent: (contextId) => {
if (contextId === 0) {
AL.currentCtx = null;
} else {
AL.currentCtx = AL.contexts[contextId];
}
return {{{ cDefs.ALC_TRUE }}};
},
alcGetContextsDevice__proxy: 'sync',
alcGetContextsDevice: (contextId) => {
if (contextId in AL.contexts) {
return AL.contexts[contextId].deviceId;
}
return 0;
},
alcProcessContext: (contextId) => {},
alcSuspendContext: (contextId) => {},
alcIsExtensionPresent__proxy: 'sync',
alcIsExtensionPresent: (deviceId, pExtName) => {
var name = UTF8ToString(pExtName);
return AL.ALC_EXTENSIONS[name] ? 1 : 0;
},
alcGetEnumValue__proxy: 'sync',
alcGetEnumValue: (deviceId, pEnumName) => {
if (deviceId !== 0 && !(deviceId in AL.deviceRefCounts)) {
#if OPENAL_DEBUG
dbg('alcGetEnumValue() called with an invalid device');
#endif
return 0;
} else if (!pEnumName) {
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return 0;
}
var name = UTF8ToString(pEnumName);
switch (name) {
case 'ALC_NO_ERROR': return 0;
case 'ALC_INVALID_DEVICE': return 0xA001;
case 'ALC_INVALID_CONTEXT': return 0xA002;
case 'ALC_INVALID_ENUM': return 0xA003;
case 'ALC_INVALID_VALUE': return 0xA004;
case 'ALC_OUT_OF_MEMORY': return 0xA005;
case 'ALC_MAJOR_VERSION': return 0x1000;
case 'ALC_MINOR_VERSION': return 0x1001;
case 'ALC_ATTRIBUTES_SIZE': return 0x1002;
case 'ALC_ALL_ATTRIBUTES': return 0x1003;
case 'ALC_DEFAULT_DEVICE_SPECIFIER': return 0x1004;
case 'ALC_DEVICE_SPECIFIER': return 0x1005;
case 'ALC_EXTENSIONS': return 0x1006;
case 'ALC_FREQUENCY': return 0x1007;
case 'ALC_REFRESH': return 0x1008;
case 'ALC_SYNC': return 0x1009;
case 'ALC_MONO_SOURCES': return 0x1010;
case 'ALC_STEREO_SOURCES': return 0x1011;
case 'ALC_CAPTURE_DEVICE_SPECIFIER': return 0x310;
case 'ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER': return 0x311;
case 'ALC_CAPTURE_SAMPLES': return 0x312;
case 'ALC_HRTF_SOFT': return 0x1992;
case 'ALC_HRTF_ID_SOFT': return 0x1996;
case 'ALC_DONT_CARE_SOFT': return 0x0002;
case 'ALC_HRTF_STATUS_SOFT': return 0x1993;
case 'ALC_NUM_HRTF_SPECIFIERS_SOFT': return 0x1994;
case 'ALC_HRTF_SPECIFIER_SOFT': return 0x1995;
case 'ALC_HRTF_DISABLED_SOFT': return 0x0000;
case 'ALC_HRTF_ENABLED_SOFT': return 0x0001;
case 'ALC_HRTF_DENIED_SOFT': return 0x0002;
case 'ALC_HRTF_REQUIRED_SOFT': return 0x0003;
case 'ALC_HRTF_HEADPHONES_DETECTED_SOFT': return 0x0004;
case 'ALC_HRTF_UNSUPPORTED_FORMAT_SOFT': return 0x0005;
default:
#if OPENAL_DEBUG
dbg(`No value for `${pEnumName}` is known by alcGetEnumValue()`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return {{{ cDefs.AL_NONE }}};
}
},
alcGetString__proxy: 'sync',
alcGetString__deps: ['$stringToNewUTF8'],
alcGetString: (deviceId, param) => {
if (AL.alcStringCache[param]) {
return AL.alcStringCache[param];
}
var ret;
switch (param) {
case {{{ cDefs.ALC_NO_ERROR }}}:
ret = 'No Error';
break;
case {{{ cDefs.ALC_INVALID_DEVICE }}}:
ret = 'Invalid Device';
break;
case 0xA002 :
ret = 'Invalid Context';
break;
case {{{ cDefs.ALC_INVALID_ENUM }}}:
ret = 'Invalid Enum';
break;
case {{{ cDefs.ALC_INVALID_VALUE }}}:
ret = 'Invalid Value';
break;
case 0xA005 :
ret = 'Out of Memory';
break;
case 0x1004 :
if (typeof AudioContext != 'undefined' ||
typeof webkitAudioContext != 'undefined') {
ret = AL.DEVICE_NAME;
} else {
return 0;
}
break;
case 0x1005 :
if (typeof AudioContext != 'undefined' ||
typeof webkitAudioContext != 'undefined') {
ret = AL.DEVICE_NAME + '\0';
} else {
ret = '\0';
}
break;
case 0x311 :
ret = AL.CAPTURE_DEVICE_NAME;
break;
case 0x310 :
if (deviceId === 0) {
ret = AL.CAPTURE_DEVICE_NAME + '\0';
} else {
var c = AL.requireValidCaptureDevice(deviceId, 'alcGetString');
if (!c) {
return 0;
}
ret = c.deviceName;
}
break;
case 0x1006 :
if (!deviceId) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return 0;
}
ret = Object.keys(AL.ALC_EXTENSIONS).join(' ')
break;
default:
AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}};
return 0;
}
ret = stringToNewUTF8(ret);
AL.alcStringCache[param] = ret;
return ret;
},
alcGetIntegerv__proxy: 'sync',
alcGetIntegerv: (deviceId, param, size, pValues) => {
if (size === 0 || !pValues) {
return;
}
switch (param) {
case 0x1000 :
{{{ makeSetValue('pValues', '0', '1', 'i32') }}};
break;
case 0x1001 :
{{{ makeSetValue('pValues', '0', '1', 'i32') }}};
break;
case 0x1002 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (!AL.currentCtx) {
AL.alcErr = 0xA002 ;
return;
}
{{{ makeSetValue('pValues', '0', 'AL.currentCtx.attrs.length', 'i32') }}};
break;
case 0x1003 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (!AL.currentCtx) {
AL.alcErr = 0xA002 ;
return;
}
for (var i = 0; i < AL.currentCtx.attrs.length; i++) {
{{{ makeSetValue('pValues', 'i*4', 'AL.currentCtx.attrs[i]', 'i32') }}};
}
break;
case 0x1007 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (!AL.currentCtx) {
AL.alcErr = 0xA002 ;
return;
}
{{{ makeSetValue('pValues', '0', 'AL.currentCtx.audioCtx.sampleRate', 'i32') }}};
break;
case 0x1010 :
case 0x1011 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (!AL.currentCtx) {
AL.alcErr = 0xA002 ;
return;
}
{{{ makeSetValue('pValues', '0', '0x7FFFFFFF', 'i32') }}};
break;
case 0x1992 :
case 0x1993 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
var hrtfStatus = 0 ;
for (var ctxId in AL.contexts) {
var ctx = AL.contexts[ctxId];
if (ctx.deviceId === deviceId) {
hrtfStatus = ctx.hrtf ? 1 : 0 ;
}
}
{{{ makeSetValue('pValues', '0', 'hrtfStatus', 'i32') }}};
break;
case 0x1994 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
{{{ makeSetValue('pValues', '0', '1', 'i32') }}};
break;
case 0x20003 :
if (!(deviceId in AL.deviceRefCounts)) {
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (!AL.currentCtx) {
AL.alcErr = 0xA002 ;
return;
}
{{{ makeSetValue('pValues', '0', '1', 'i32') }}};
case 0x312 :
var c = AL.requireValidCaptureDevice(deviceId, 'alcGetIntegerv');
if (!c) {
return;
}
var n = c.capturedFrameCount;
var dstfreq = c.requestedSampleRate;
var srcfreq = c.audioCtx.sampleRate;
var nsamples = Math.floor(n * (dstfreq/srcfreq));
{{{ makeSetValue('pValues', '0', 'nsamples', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alcGetIntegerv() with param ${ptrToString(param)} not implemented yet`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}};
return;
}
},
emscripten_alcDevicePauseSOFT__proxy: 'sync',
emscripten_alcDevicePauseSOFT__sig: 'vi',
emscripten_alcDevicePauseSOFT: (deviceId) => {
if (!(deviceId in AL.deviceRefCounts)) {
#if OPENAL_DEBUG
dbg('alcDevicePauseSOFT() called with an invalid device');
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (AL.paused) {
return;
}
AL.paused = true;
for (var ctxId in AL.contexts) {
var ctx = AL.contexts[ctxId];
if (ctx.deviceId !== deviceId) {
continue;
}
ctx.audioCtx.suspend();
clearInterval(ctx.interval);
ctx.interval = null;
}
},
emscripten_alcDeviceResumeSOFT__proxy: 'sync',
emscripten_alcDeviceResumeSOFT__sig: 'vi',
emscripten_alcDeviceResumeSOFT: (deviceId) => {
if (!(deviceId in AL.deviceRefCounts)) {
#if OPENAL_DEBUG
dbg('alcDeviceResumeSOFT() called with an invalid device');
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return;
}
if (!AL.paused) {
return;
}
AL.paused = false;
for (var ctxId in AL.contexts) {
var ctx = AL.contexts[ctxId];
if (ctx.deviceId !== deviceId) {
continue;
}
ctx.interval = setInterval(() => AL.scheduleContextAudio(ctx), AL.QUEUE_INTERVAL);
ctx.audioCtx.resume();
}
},
emscripten_alcGetStringiSOFT__proxy: 'sync',
emscripten_alcGetStringiSOFT__sig: 'iiii',
emscripten_alcGetStringiSOFT__deps: ['alcGetString', '$stringToNewUTF8'],
emscripten_alcGetStringiSOFT: (deviceId, param, index) => {
if (!(deviceId in AL.deviceRefCounts)) {
#if OPENAL_DEBUG
dbg('alcGetStringiSOFT() called with an invalid device');
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return 0;
}
if (AL.alcStringCache[param]) {
return AL.alcStringCache[param];
}
var ret;
switch (param) {
case 0x1995 :
if (index === 0) {
ret = 'Web Audio HRTF';
} else {
#if OPENAL_DEBUG
dbg(`alcGetStringiSOFT() with param ALC_HRTF_SPECIFIER_SOFT index ${index} is out of range`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}};
return 0;
}
break;
default:
if (index !== 0) {
#if OPENAL_DEBUG
dbg(`alcGetStringiSOFT() with param ${ptrToString(param)} not implemented yet`);
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}};
return 0;
}
return _alcGetString(deviceId, param);
}
ret = stringToNewUTF8(ret);
AL.alcStringCache[param] = ret;
return ret;
},
emscripten_alcResetDeviceSOFT__proxy: 'sync',
emscripten_alcResetDeviceSOFT__sig: 'iii',
emscripten_alcResetDeviceSOFT: (deviceId, pAttrList) => {
if (!(deviceId in AL.deviceRefCounts)) {
#if OPENAL_DEBUG
dbg('alcResetDeviceSOFT() called with an invalid device');
#endif
AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}};
return {{{ cDefs.ALC_FALSE }}};
}
var hrtf = null;
pAttrList >>= 2;
if (pAttrList) {
var attr = 0;
var val = 0;
while (true) {
attr = HEAP32[pAttrList++];
if (attr === 0) {
break;
}
val = HEAP32[pAttrList++];
switch (attr) {
case 0x1992 :
if (val === {{{ cDefs.ALC_TRUE }}}) {
hrtf = true;
} else if (val === {{{ cDefs.ALC_FALSE }}}) {
hrtf = false;
}
break;
}
}
}
if (hrtf !== null) {
for (var ctxId in AL.contexts) {
var ctx = AL.contexts[ctxId];
if (ctx.deviceId === deviceId) {
ctx.hrtf = hrtf;
AL.updateContextGlobal(ctx);
}
}
}
return {{{ cDefs.ALC_TRUE }}};
},
alGenBuffers__proxy: 'sync',
alGenBuffers: (count, pBufferIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alGenBuffers() called without a valid context');
#endif
return;
}
for (var i = 0; i < count; ++i) {
var buf = {
deviceId: AL.currentCtx.deviceId,
id: AL.newId(),
refCount: 0,
audioBuf: null,
frequency: 0,
bytesPerSample: 2,
channels: 1,
length: 0,
};
AL.deviceRefCounts[buf.deviceId]++;
AL.buffers[buf.id] = buf;
{{{ makeSetValue('pBufferIds', 'i*4', 'buf.id', 'i32') }}};
}
},
alDeleteBuffers__proxy: 'sync',
alDeleteBuffers: (count, pBufferIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alDeleteBuffers() called without a valid context');
#endif
return;
}
for (var i = 0; i < count; ++i) {
var bufId = {{{ makeGetValue('pBufferIds', 'i*4', 'i32') }}};
if (bufId === 0) {
continue;
}
if (!AL.buffers[bufId]) {
#if OPENAL_DEBUG
dbg('alDeleteBuffers() called with an invalid buffer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
if (AL.buffers[bufId].refCount) {
#if OPENAL_DEBUG
dbg('alDeleteBuffers() called with a used buffer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}};
return;
}
}
for (var i = 0; i < count; ++i) {
var bufId = {{{ makeGetValue('pBufferIds', 'i*4', 'i32') }}};
if (bufId === 0) {
continue;
}
AL.deviceRefCounts[AL.buffers[bufId].deviceId]--;
delete AL.buffers[bufId];
AL.freeIds.push(bufId);
}
},
alGenSources__proxy: 'sync',
alGenSources: (count, pSourceIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alGenSources() called without a valid context');
#endif
return;
}
for (var i = 0; i < count; ++i) {
var gain = AL.currentCtx.audioCtx.createGain();
gain.connect(AL.currentCtx.gain);
var src = {
context: AL.currentCtx,
id: AL.newId(),
type: 0x1030 ,
state: {{{ cDefs.AL_INITIAL }}},
bufQueue: [AL.buffers[0]],
audioQueue: [],
looping: false,
pitch: 1.0,
dopplerShift: 1.0,
gain,
minGain: 0.0,
maxGain: 1.0,
panner: null,
bufsProcessed: 0,
bufStartTime: Number.NEGATIVE_INFINITY,
bufOffset: 0.0,
relative: false,
refDistance: 1.0,
maxDistance: 3.40282e38 ,
rolloffFactor: 1.0,
position: [0.0, 0.0, 0.0],
velocity: [0.0, 0.0, 0.0],
direction: [0.0, 0.0, 0.0],
coneOuterGain: 0.0,
coneInnerAngle: 360.0,
coneOuterAngle: 360.0,
distanceModel: 0xd002 ,
spatialize: 2 ,
get playbackRate() {
return this.pitch * this.dopplerShift;
}
};
AL.currentCtx.sources[src.id] = src;
{{{ makeSetValue('pSourceIds', 'i*4', 'src.id', 'i32') }}};
}
},
alDeleteSources__deps: ['alSourcei'],
alDeleteSources__proxy: 'sync',
alDeleteSources: (count, pSourceIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alDeleteSources() called without a valid context');
#endif
return;
}
for (var i = 0; i < count; ++i) {
var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}};
if (!AL.currentCtx.sources[srcId]) {
#if OPENAL_DEBUG
dbg('alDeleteSources() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
}
for (var i = 0; i < count; ++i) {
var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}};
AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_STOPPED }}});
_alSourcei(srcId, 0x1009 , 0);
delete AL.currentCtx.sources[srcId];
AL.freeIds.push(srcId);
}
},
alGetError__proxy: 'sync',
alGetError: () => {
if (!AL.currentCtx) {
return {{{ cDefs.AL_INVALID_OPERATION }}};
}
var err = AL.currentCtx.err;
AL.currentCtx.err = {{{ cDefs.AL_NO_ERROR }}};
return err;
},
alIsExtensionPresent__proxy: 'sync',
alIsExtensionPresent: (pExtName) => {
var name = UTF8ToString(pExtName);
return AL.AL_EXTENSIONS[name] ? 1 : 0;
},
alGetEnumValue__proxy: 'sync',
alGetEnumValue: (pEnumName) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alGetEnumValue() called without a valid context');
#endif
return 0;
}
if (!pEnumName) {
#if OPENAL_DEBUG
dbg('alGetEnumValue() called with null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return {{{ cDefs.AL_NONE }}};
}
var name = UTF8ToString(pEnumName);
switch (name) {
case 'AL_BITS': return 0x2002;
case 'AL_BUFFER': return 0x1009;
case 'AL_BUFFERS_PROCESSED': return 0x1016;
case 'AL_BUFFERS_QUEUED': return 0x1015;
case 'AL_BYTE_OFFSET': return 0x1026;
case 'AL_CHANNELS': return 0x2003;
case 'AL_CONE_INNER_ANGLE': return 0x1001;
case 'AL_CONE_OUTER_ANGLE': return 0x1002;
case 'AL_CONE_OUTER_GAIN': return 0x1022;
case 'AL_DIRECTION': return 0x1005;
case 'AL_DISTANCE_MODEL': return 0xD000;
case 'AL_DOPPLER_FACTOR': return 0xC000;
case 'AL_DOPPLER_VELOCITY': return 0xC001;
case 'AL_EXPONENT_DISTANCE': return 0xD005;
case 'AL_EXPONENT_DISTANCE_CLAMPED': return 0xD006;
case 'AL_EXTENSIONS': return 0xB004;
case 'AL_FORMAT_MONO16': return 0x1101;
case 'AL_FORMAT_MONO8': return 0x1100;
case 'AL_FORMAT_STEREO16': return 0x1103;
case 'AL_FORMAT_STEREO8': return 0x1102;
case 'AL_FREQUENCY': return 0x2001;
case 'AL_GAIN': return 0x100A;
case 'AL_INITIAL': return 0x1011;
case 'AL_INVALID': return -1;
case 'AL_ILLEGAL_ENUM':
case 'AL_INVALID_ENUM': return 0xA002;
case 'AL_INVALID_NAME': return 0xA001;
case 'AL_ILLEGAL_COMMAND':
case 'AL_INVALID_OPERATION': return 0xA004;
case 'AL_INVALID_VALUE': return 0xA003;
case 'AL_INVERSE_DISTANCE': return 0xD001;
case 'AL_INVERSE_DISTANCE_CLAMPED': return 0xD002;
case 'AL_LINEAR_DISTANCE': return 0xD003;
case 'AL_LINEAR_DISTANCE_CLAMPED': return 0xD004;
case 'AL_LOOPING': return 0x1007;
case 'AL_MAX_DISTANCE': return 0x1023;
case 'AL_MAX_GAIN': return 0x100E;
case 'AL_MIN_GAIN': return 0x100D;
case 'AL_NONE': return 0;
case 'AL_NO_ERROR': return 0;
case 'AL_ORIENTATION': return 0x100F;
case 'AL_OUT_OF_MEMORY': return 0xA005;
case 'AL_PAUSED': return 0x1013;
case 'AL_PENDING': return 0x2011;
case 'AL_PITCH': return 0x1003;
case 'AL_PLAYING': return 0x1012;
case 'AL_POSITION': return 0x1004;
case 'AL_PROCESSED': return 0x2012;
case 'AL_REFERENCE_DISTANCE': return 0x1020;
case 'AL_RENDERER': return 0xB003;
case 'AL_ROLLOFF_FACTOR': return 0x1021;
case 'AL_SAMPLE_OFFSET': return 0x1025;
case 'AL_SEC_OFFSET': return 0x1024;
case 'AL_SIZE': return 0x2004;
case 'AL_SOURCE_RELATIVE': return 0x202;
case 'AL_SOURCE_STATE': return 0x1010;
case 'AL_SOURCE_TYPE': return 0x1027;
case 'AL_SPEED_OF_SOUND': return 0xC003;
case 'AL_STATIC': return 0x1028;
case 'AL_STOPPED': return 0x1014;
case 'AL_STREAMING': return 0x1029;
case 'AL_UNDETERMINED': return 0x1030;
case 'AL_UNUSED': return 0x2010;
case 'AL_VELOCITY': return 0x1006;
case 'AL_VENDOR': return 0xB001;
case 'AL_VERSION': return 0xB002;
case 'AL_AUTO_SOFT': return 0x0002;
case 'AL_SOURCE_DISTANCE_MODEL': return 0x200;
case 'AL_SOURCE_SPATIALIZE_SOFT': return 0x1214;
case 'AL_LOOP_POINTS_SOFT': return 0x2015;
case 'AL_BYTE_LENGTH_SOFT': return 0x2009;
case 'AL_SAMPLE_LENGTH_SOFT': return 0x200A;
case 'AL_SEC_LENGTH_SOFT': return 0x200B;
case 'AL_FORMAT_MONO_FLOAT32': return 0x10010;
case 'AL_FORMAT_STEREO_FLOAT32': return 0x10011;
default:
#if OPENAL_DEBUG
dbg(`No value for `${name}` is known by alGetEnumValue()`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return 0;
}
},
alGetString__proxy: 'sync',
alGetString__deps: ['$stringToNewUTF8'],
alGetString: (param) => {
if (AL.stringCache[param]) {
return AL.stringCache[param];
}
var ret;
switch (param) {
case {{{ cDefs.AL_NO_ERROR }}}:
ret = 'No Error';
break;
case {{{ cDefs.AL_INVALID_NAME }}}:
ret = 'Invalid Name';
break;
case {{{ cDefs.AL_INVALID_ENUM }}}:
ret = 'Invalid Enum';
break;
case {{{ cDefs.AL_INVALID_VALUE }}}:
ret = 'Invalid Value';
break;
case {{{ cDefs.AL_INVALID_OPERATION }}}:
ret = 'Invalid Operation';
break;
case 0xA005 :
ret = 'Out of Memory';
break;
case 0xB001 :
ret = 'Emscripten';
break;
case 0xB002 :
ret = '1.1';
break;
case 0xB003 :
ret = 'WebAudio';
break;
case 0xB004 :
ret = Object.keys(AL.AL_EXTENSIONS).join(' ');
break;
default:
if (AL.currentCtx) {
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
} else {
#if OPENAL_DEBUG
dbg('alGetString() called without a valid context');
#endif
}
return 0;
}
ret = stringToNewUTF8(ret);
AL.stringCache[param] = ret;
return ret;
},
alEnable__proxy: 'sync',
alEnable: (param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alEnable() called without a valid context');
#endif
return;
}
switch (param) {
case 0x200 :
AL.currentCtx.sourceDistanceModel = true;
AL.updateContextGlobal(AL.currentCtx);
break;
default:
#if OPENAL_DEBUG
dbg(`alEnable() with param ${ptrToString(param)} not implemented yet`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alDisable__proxy: 'sync',
alDisable: (param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alDisable() called without a valid context');
#endif
return;
}
switch (param) {
case 0x200 :
AL.currentCtx.sourceDistanceModel = false;
AL.updateContextGlobal(AL.currentCtx);
break;
default:
#if OPENAL_DEBUG
dbg(`alDisable() with param ${ptrToString(param)} not implemented yet`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alIsEnabled__proxy: 'sync',
alIsEnabled: (param) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alIsEnabled() called without a valid context');
#endif
return 0;
}
switch (param) {
case 0x200 :
return AL.currentCtx.sourceDistanceModel ? {{{ cDefs.AL_FALSE }}} : {{{ cDefs.AL_TRUE }}};
default:
#if OPENAL_DEBUG
dbg(`alIsEnabled() with param ${ptrToString(param)} not implemented yet`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return 0;
}
},
alGetDouble__proxy: 'sync',
alGetDouble: (param) => {
var val = AL.getGlobalParam('alGetDouble', param);
if (val === null) {
return 0.0;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
return val;
default:
#if OPENAL_DEBUG
dbg(`alGetDouble(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return 0.0;
}
},
alGetDoublev__proxy: 'sync',
alGetDoublev: (param, pValues) => {
var val = AL.getGlobalParam('alGetDoublev', param);
if (val === null || !pValues) {
return;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
{{{ makeSetValue('pValues', '0', 'val', 'double') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetDoublev(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetFloat__proxy: 'sync',
alGetFloat: (param) => {
var val = AL.getGlobalParam('alGetFloat', param);
if (val === null) {
return 0.0;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
return val;
default:
#if OPENAL_DEBUG
dbg(`alGetFloat(): param ${ptrToString(param)} has wrong signature`);
#endif
return 0.0;
}
},
alGetFloatv__proxy: 'sync',
alGetFloatv: (param, pValues) => {
var val = AL.getGlobalParam('alGetFloatv', param);
if (val === null || !pValues) {
return;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
{{{ makeSetValue('pValues', '0', 'val', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetFloatv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetInteger__proxy: 'sync',
alGetInteger: (param) => {
var val = AL.getGlobalParam('alGetInteger', param);
if (val === null) {
return 0;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
return val;
default:
#if OPENAL_DEBUG
dbg(`alGetInteger(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return 0;
}
},
alGetIntegerv__proxy: 'sync',
alGetIntegerv: (param, pValues) => {
var val = AL.getGlobalParam('alGetIntegerv', param);
if (val === null || !pValues) {
return;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
{{{ makeSetValue('pValues', '0', 'val', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetIntegerv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetBoolean__proxy: 'sync',
alGetBoolean: (param) => {
var val = AL.getGlobalParam('alGetBoolean', param);
if (val === null) {
return {{{ cDefs.AL_FALSE }}};
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
return val !== 0 ? {{{ cDefs.AL_TRUE }}} : {{{ cDefs.AL_FALSE }}};
default:
#if OPENAL_DEBUG
dbg(`alGetBoolean(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return {{{ cDefs.AL_FALSE }}};
}
},
alGetBooleanv__proxy: 'sync',
alGetBooleanv: (param, pValues) => {
var val = AL.getGlobalParam('alGetBooleanv', param);
if (val === null || !pValues) {
return;
}
switch (param) {
case {{{ cDefs.AL_DOPPLER_FACTOR }}}:
case {{{ cDefs.AL_SPEED_OF_SOUND }}}:
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
{{{ makeSetValue('pValues', '0', 'val', 'i8') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetBooleanv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alDistanceModel__proxy: 'sync',
alDistanceModel: (model) => {
AL.setGlobalParam('alDistanceModel', {{{ cDefs.AL_DISTANCE_MODEL }}}, model);
},
alSpeedOfSound__proxy: 'sync',
alSpeedOfSound: (value) => {
AL.setGlobalParam('alSpeedOfSound', {{{ cDefs.AL_SPEED_OF_SOUND }}}, value);
},
alDopplerFactor__proxy: 'sync',
alDopplerFactor: (value) => {
AL.setGlobalParam('alDopplerFactor', {{{ cDefs.AL_DOPPLER_FACTOR }}}, value);
},
alDopplerVelocity__proxy: 'sync',
alDopplerVelocity: (value) => {
warnOnce('alDopplerVelocity() is deprecated, and only kept for compatibility with OpenAL 1.0. Use alSpeedOfSound() instead.');
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alDopplerVelocity() called without a valid context');
#endif
return;
}
if (value <= 0) {
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
},
alGetListenerf__proxy: 'sync',
alGetListenerf: (param, pValue) => {
var val = AL.getListenerParam('alGetListenerf', param);
if (val === null) {
return;
}
if (!pValue) {
#if OPENAL_DEBUG
dbg('alGetListenerf() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_GAIN }}}:
{{{ makeSetValue('pValue', '0', 'val', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetListenerf(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetListener3f__proxy: 'sync',
alGetListener3f: (param, pValue0, pValue1, pValue2) => {
var val = AL.getListenerParam('alGetListener3f', param);
if (val === null) {
return;
}
if (!pValue0 || !pValue1 || !pValue2) {
#if OPENAL_DEBUG
dbg('alGetListener3f() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValue0', '0', 'val[0]', 'float') }}};
{{{ makeSetValue('pValue1', '0', 'val[1]', 'float') }}};
{{{ makeSetValue('pValue2', '0', 'val[2]', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetListener3f(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetListenerfv__proxy: 'sync',
alGetListenerfv: (param, pValues) => {
var val = AL.getListenerParam('alGetListenerfv', param);
if (val === null) {
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alGetListenerfv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'float') }}};
{{{ makeSetValue('pValues', '8', 'val[2]', 'float') }}};
break;
case {{{ cDefs.AL_ORIENTATION }}}:
{{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'float') }}};
{{{ makeSetValue('pValues', '8', 'val[2]', 'float') }}};
{{{ makeSetValue('pValues', '12', 'val[3]', 'float') }}};
{{{ makeSetValue('pValues', '16', 'val[4]', 'float') }}};
{{{ makeSetValue('pValues', '20', 'val[5]', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetListenerfv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetListeneri__proxy: 'sync',
alGetListeneri: (param, pValue) => {
var val = AL.getListenerParam('alGetListeneri', param);
if (val === null) {
return;
}
if (!pValue) {
#if OPENAL_DEBUG
dbg('alGetListeneri() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
dbg(`alGetListeneri(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
},
alGetListener3i__proxy: 'sync',
alGetListener3i: (param, pValue0, pValue1, pValue2) => {
var val = AL.getListenerParam('alGetListener3i', param);
if (val === null) {
return;
}
if (!pValue0 || !pValue1 || !pValue2) {
#if OPENAL_DEBUG
dbg('alGetListener3i() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValue0', '0', 'val[0]', 'i32') }}};
{{{ makeSetValue('pValue1', '0', 'val[1]', 'i32') }}};
{{{ makeSetValue('pValue2', '0', 'val[2]', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetListener3i(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetListeneriv__proxy: 'sync',
alGetListeneriv: (param, pValues) => {
var val = AL.getListenerParam('alGetListeneriv', param);
if (val === null) {
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alGetListeneriv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}};
{{{ makeSetValue('pValues', '8', 'val[2]', 'i32') }}};
break;
case {{{ cDefs.AL_ORIENTATION }}}:
{{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}};
{{{ makeSetValue('pValues', '8', 'val[2]', 'i32') }}};
{{{ makeSetValue('pValues', '12', 'val[3]', 'i32') }}};
{{{ makeSetValue('pValues', '16', 'val[4]', 'i32') }}};
{{{ makeSetValue('pValues', '20', 'val[5]', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetListeneriv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alListenerf__proxy: 'sync',
alListenerf: (param, value) => {
switch (param) {
case {{{ cDefs.AL_GAIN }}}:
AL.setListenerParam('alListenerf', param, value);
break;
default:
AL.setListenerParam('alListenerf', param, null);
break;
}
},
alListener3f__proxy: 'sync',
alListener3f: (param, value0, value1, value2) => {
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = value0;
AL.paramArray[1] = value1;
AL.paramArray[2] = value2;
AL.setListenerParam('alListener3f', param, AL.paramArray);
break;
default:
AL.setListenerParam('alListener3f', param, null);
break;
}
},
alListenerfv__proxy: 'sync',
alListenerfv: (param, pValues) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alListenerfv() called without a valid context');
#endif
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alListenerfv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'float') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'float') }}};
AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'float') }}};
AL.setListenerParam('alListenerfv', param, AL.paramArray);
break;
case {{{ cDefs.AL_ORIENTATION }}}:
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'float') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'float') }}};
AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'float') }}};
AL.paramArray[3] = {{{ makeGetValue('pValues', '12', 'float') }}};
AL.paramArray[4] = {{{ makeGetValue('pValues', '16', 'float') }}};
AL.paramArray[5] = {{{ makeGetValue('pValues', '20', 'float') }}};
AL.setListenerParam('alListenerfv', param, AL.paramArray);
break;
default:
AL.setListenerParam('alListenerfv', param, null);
break;
}
},
alListeneri__proxy: 'sync',
alListeneri: (param, value) => {
AL.setListenerParam('alListeneri', param, null);
},
alListener3i__proxy: 'sync',
alListener3i: (param, value0, value1, value2) => {
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = value0;
AL.paramArray[1] = value1;
AL.paramArray[2] = value2;
AL.setListenerParam('alListener3i', param, AL.paramArray);
break;
default:
AL.setListenerParam('alListener3i', param, null);
break;
}
},
alListeneriv__proxy: 'sync',
alListeneriv: (param, pValues) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alListeneriv() called without a valid context');
#endif
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alListeneriv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}};
AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'i32') }}};
AL.setListenerParam('alListeneriv', param, AL.paramArray);
break;
case {{{ cDefs.AL_ORIENTATION }}}:
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}};
AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'i32') }}};
AL.paramArray[3] = {{{ makeGetValue('pValues', '12', 'i32') }}};
AL.paramArray[4] = {{{ makeGetValue('pValues', '16', 'i32') }}};
AL.paramArray[5] = {{{ makeGetValue('pValues', '20', 'i32') }}};
AL.setListenerParam('alListeneriv', param, AL.paramArray);
break;
default:
AL.setListenerParam('alListeneriv', param, null);
break;
}
},
alIsBuffer__proxy: 'sync',
alIsBuffer: (bufferId) => {
if (!AL.currentCtx) {
return false;
}
if (bufferId > AL.buffers.length) {
return false;
}
if (!AL.buffers[bufferId]) {
return false;
}
return true;
},
alBufferData__proxy: 'sync',
alBufferData: (bufferId, format, pData, size, freq) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alBufferData() called without a valid context');
#endif
return;
}
var buf = AL.buffers[bufferId];
if (!buf) {
#if OPENAL_DEBUG
dbg('alBufferData() called with an invalid buffer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
if (freq <= 0) {
#if OPENAL_DEBUG
dbg('alBufferData() called with an invalid frequency');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
var audioBuf = null;
try {
switch (format) {
case 0x1100 :
if (size > 0) {
audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size, freq);
var channel0 = audioBuf.getChannelData(0);
for (var i = 0; i < size; ++i) {
channel0[i] = HEAPU8[pData++] * 0.0078125 - 1.0;
}
}
buf.bytesPerSample = 1;
buf.channels = 1;
buf.length = size;
break;
case 0x1101 :
if (size > 0) {
audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size >> 1, freq);
var channel0 = audioBuf.getChannelData(0);
pData >>= 1;
for (var i = 0; i < size >> 1; ++i) {
channel0[i] = HEAP16[pData++] * 0.000030517578125 ;
}
}
buf.bytesPerSample = 2;
buf.channels = 1;
buf.length = size >> 1;
break;
case 0x1102 :
if (size > 0) {
audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 1, freq);
var channel0 = audioBuf.getChannelData(0);
var channel1 = audioBuf.getChannelData(1);
for (var i = 0; i < size >> 1; ++i) {
channel0[i] = HEAPU8[pData++] * 0.0078125 - 1.0;
channel1[i] = HEAPU8[pData++] * 0.0078125 - 1.0;
}
}
buf.bytesPerSample = 1;
buf.channels = 2;
buf.length = size >> 1;
break;
case 0x1103 :
if (size > 0) {
audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 2, freq);
var channel0 = audioBuf.getChannelData(0);
var channel1 = audioBuf.getChannelData(1);
pData >>= 1;
for (var i = 0; i < size >> 2; ++i) {
channel0[i] = HEAP16[pData++] * 0.000030517578125 ;
channel1[i] = HEAP16[pData++] * 0.000030517578125 ;
}
}
buf.bytesPerSample = 2;
buf.channels = 2;
buf.length = size >> 2;
break;
case 0x10010 :
if (size > 0) {
audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size >> 2, freq);
var channel0 = audioBuf.getChannelData(0);
pData >>= 2;
for (var i = 0; i < size >> 2; ++i) {
channel0[i] = HEAPF32[pData++];
}
}
buf.bytesPerSample = 4;
buf.channels = 1;
buf.length = size >> 2;
break;
case 0x10011 :
if (size > 0) {
audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 3, freq);
var channel0 = audioBuf.getChannelData(0);
var channel1 = audioBuf.getChannelData(1);
pData >>= 2;
for (var i = 0; i < size >> 3; ++i) {
channel0[i] = HEAPF32[pData++];
channel1[i] = HEAPF32[pData++];
}
}
buf.bytesPerSample = 4;
buf.channels = 2;
buf.length = size >> 3;
break;
default:
#if OPENAL_DEBUG
dbg(`alBufferData() called with invalid format ${format}`;
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
buf.frequency = freq;
buf.audioBuf = audioBuf;
} catch (e) {
#if OPENAL_DEBUG
dbg(`alBufferData() upload failed with an exception ${e}`;
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
},
alGetBufferf__proxy: 'sync',
alGetBufferf: (bufferId, param, pValue) => {
var val = AL.getBufferParam('alGetBufferf', bufferId, param);
if (val === null) {
return;
}
if (!pValue) {
#if OPENAL_DEBUG
dbg('alGetBufferf() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
dbg(`alGetBufferf(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
},
alGetBuffer3f__proxy: 'sync',
alGetBuffer3f: (bufferId, param, pValue0, pValue1, pValue2) => {
var val = AL.getBufferParam('alGetBuffer3f', bufferId, param);
if (val === null) {
return;
}
if (!pValue0 || !pValue1 || !pValue2) {
#if OPENAL_DEBUG
dbg('alGetBuffer3f() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
dbg(`alGetBuffer3f(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
},
alGetBufferfv__proxy: 'sync',
alGetBufferfv: (bufferId, param, pValues) => {
var val = AL.getBufferParam('alGetBufferfv', bufferId, param);
if (val === null) {
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alGetBufferfv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
dbg(`alGetBufferfv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
},
alGetBufferi__proxy: 'sync',
alGetBufferi: (bufferId, param, pValue) => {
var val = AL.getBufferParam('alGetBufferi', bufferId, param);
if (val === null) {
return;
}
if (!pValue) {
#if OPENAL_DEBUG
dbg('alGetBufferi() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x2001 :
case 0x2002 :
case 0x2003 :
case 0x2004 :
{{{ makeSetValue('pValue', '0', 'val', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetBufferi(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetBuffer3i__proxy: 'sync',
alGetBuffer3i: (bufferId, param, pValue0, pValue1, pValue2) => {
var val = AL.getBufferParam('alGetBuffer3i', bufferId, param);
if (val === null) {
return;
}
if (!pValue0 || !pValue1 || !pValue2) {
#if OPENAL_DEBUG
dbg('alGetBuffer3i() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
#if OPENAL_DEBUG
dbg(`alGetBuffer3i(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
},
alGetBufferiv__proxy: 'sync',
alGetBufferiv: (bufferId, param, pValues) => {
var val = AL.getBufferParam('alGetBufferiv', bufferId, param);
if (val === null) {
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alGetBufferiv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x2001 :
case 0x2002 :
case 0x2003 :
case 0x2004 :
{{{ makeSetValue('pValues', '0', 'val', 'i32') }}};
break;
case 0x2015 :
{{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetBufferiv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alBufferf__proxy: 'sync',
alBufferf: (bufferId, param, value) => {
AL.setBufferParam('alBufferf', bufferId, param, null);
},
alBuffer3f__proxy: 'sync',
alBuffer3f: (bufferId, param, value0, value1, value2) => {
AL.setBufferParam('alBuffer3f', bufferId, param, null);
},
alBufferfv__proxy: 'sync',
alBufferfv: (bufferId, param, pValues) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alBufferfv() called without a valid context');
#endif
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alBufferfv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
AL.setBufferParam('alBufferfv', bufferId, param, null);
},
alBufferi__proxy: 'sync',
alBufferi: (bufferId, param, value) => {
AL.setBufferParam('alBufferi', bufferId, param, null);
},
alBuffer3i__proxy: 'sync',
alBuffer3i: (bufferId, param, value0, value1, value2) => {
AL.setBufferParam('alBuffer3i', bufferId, param, null);
},
alBufferiv__proxy: 'sync',
alBufferiv: (bufferId, param, pValues) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alBufferiv() called without a valid context');
#endif
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alBufferiv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x2015 :
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}};
AL.setBufferParam('alBufferiv', bufferId, param, AL.paramArray);
break;
default:
AL.setBufferParam('alBufferiv', bufferId, param, null);
break;
}
},
alIsSource__proxy: 'sync',
alIsSource: (sourceId) => {
if (!AL.currentCtx) {
return false;
}
if (!AL.currentCtx.sources[sourceId]) {
return false;
}
return true;
},
alSourceQueueBuffers__proxy: 'sync',
alSourceQueueBuffers: (sourceId, count, pBufferIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceQueueBuffers() called without a valid context');
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourceQueueBuffers() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
if (src.type === {{{ cDefs.AL_STATIC }}}) {
#if OPENAL_DEBUG
dbg('alSourceQueueBuffers() called while a static buffer is bound');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}};
return;
}
if (count === 0) {
return;
}
var templateBuf = AL.buffers[0];
for (var buf of src.bufQueue) {
if (buf.id !== 0) {
templateBuf = buf;
break;
}
}
for (var i = 0; i < count; ++i) {
var bufId = {{{ makeGetValue('pBufferIds', 'i*4', 'i32') }}};
var buf = AL.buffers[bufId];
if (!buf) {
#if OPENAL_DEBUG
dbg('alSourceQueueBuffers() called with an invalid buffer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
if (templateBuf.id !== 0 && (
buf.frequency !== templateBuf.frequency
|| buf.bytesPerSample !== templateBuf.bytesPerSample
|| buf.channels !== templateBuf.channels)
) {
#if OPENAL_DEBUG
dbg('alSourceQueueBuffers() called with a buffer of different format');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}};
}
}
if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) {
src.bufQueue.length = 0;
}
src.type = 0x1029 ;
for (var i = 0; i < count; ++i) {
var bufId = {{{ makeGetValue('pBufferIds', 'i*4', 'i32') }}};
var buf = AL.buffers[bufId];
buf.refCount++;
src.bufQueue.push(buf);
}
if (src.looping) {
AL.cancelPendingSourceAudio(src);
}
AL.initSourcePanner(src);
AL.scheduleSourceAudio(src);
},
alSourceUnqueueBuffers__proxy: 'sync',
alSourceUnqueueBuffers: (sourceId, count, pBufferIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceUnqueueBuffers() called without a valid context');
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourceUnqueueBuffers() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
if (count > (src.bufQueue.length === 1 && src.bufQueue[0].id === 0 ? 0 : src.bufsProcessed)) {
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
if (count === 0) {
return;
}
for (var i = 0; i < count; i++) {
var buf = src.bufQueue.shift();
buf.refCount--;
{{{ makeSetValue('pBufferIds', 'i*4', 'buf.id', 'i32') }}};
src.bufsProcessed--;
}
if (src.bufQueue.length === 0) {
src.bufQueue.push(AL.buffers[0]);
}
AL.initSourcePanner(src);
AL.scheduleSourceAudio(src);
},
alSourcePlay__proxy: 'sync',
alSourcePlay: (sourceId) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourcePlay() called without a valid context');
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourcePlay() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
AL.setSourceState(src, {{{ cDefs.AL_PLAYING }}});
},
alSourcePlayv__proxy: 'sync',
alSourcePlayv: (count, pSourceIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourcePlayv() called without a valid context');
#endif
return;
}
if (!pSourceIds) {
#if OPENAL_DEBUG
dbg('alSourcePlayv() called with null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
}
for (var i = 0; i < count; ++i) {
if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) {
#if OPENAL_DEBUG
dbg('alSourcePlayv() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
}
for (var i = 0; i < count; ++i) {
var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}};
AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_PLAYING }}});
}
},
alSourceStop__proxy: 'sync',
alSourceStop: (sourceId) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceStop() called without a valid context');
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourceStop() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}});
},
alSourceStopv__proxy: 'sync',
alSourceStopv: (count, pSourceIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceStopv() called without a valid context');
#endif
return;
}
if (!pSourceIds) {
#if OPENAL_DEBUG
dbg('alSourceStopv() called with null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
}
for (var i = 0; i < count; ++i) {
if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) {
#if OPENAL_DEBUG
dbg('alSourceStopv() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
}
for (var i = 0; i < count; ++i) {
var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}};
AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_STOPPED }}});
}
},
alSourceRewind__proxy: 'sync',
alSourceRewind: (sourceId) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceRewind() called without a valid context');
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourceRewind() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}});
AL.setSourceState(src, {{{ cDefs.AL_INITIAL }}});
},
alSourceRewindv__proxy: 'sync',
alSourceRewindv: (count, pSourceIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceRewindv() called without a valid context');
#endif
return;
}
if (!pSourceIds) {
#if OPENAL_DEBUG
dbg('alSourceRewindv() called with null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
}
for (var i = 0; i < count; ++i) {
if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) {
#if OPENAL_DEBUG
dbg('alSourceRewindv() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
}
for (var i = 0; i < count; ++i) {
var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}};
AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_INITIAL }}});
}
},
alSourcePause__proxy: 'sync',
alSourcePause: (sourceId) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourcePause() called without a valid context');
#endif
return;
}
var src = AL.currentCtx.sources[sourceId];
if (!src) {
#if OPENAL_DEBUG
dbg('alSourcePause() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
AL.setSourceState(src, {{{ cDefs.AL_PAUSED }}});
},
alSourcePausev__proxy: 'sync',
alSourcePausev: (count, pSourceIds) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourcePausev() called without a valid context');
#endif
return;
}
if (!pSourceIds) {
#if OPENAL_DEBUG
dbg('alSourcePausev() called with null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
}
for (var i = 0; i < count; ++i) {
if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) {
#if OPENAL_DEBUG
dbg('alSourcePausev() called with an invalid source');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}};
return;
}
}
for (var i = 0; i < count; ++i) {
var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}};
AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_PAUSED }}});
}
},
alGetSourcef__proxy: 'sync',
alGetSourcef: (sourceId, param, pValue) => {
var val = AL.getSourceParam('alGetSourcef', sourceId, param);
if (val === null) {
return;
}
if (!pValue) {
#if OPENAL_DEBUG
dbg('alGetSourcef() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x1001 :
case 0x1002 :
case 0x1003 :
case {{{ cDefs.AL_GAIN }}}:
case 0x100D :
case 0x100E :
case 0x1020 :
case 0x1021 :
case 0x1022 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x200B :
{{{ makeSetValue('pValue', '0', 'val', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetSourcef(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetSource3f__proxy: 'sync',
alGetSource3f: (sourceId, param, pValue0, pValue1, pValue2) => {
var val = AL.getSourceParam('alGetSource3f', sourceId, param);
if (val === null) {
return;
}
if (!pValue0 || !pValue1 || !pValue2) {
#if OPENAL_DEBUG
dbg('alGetSource3f() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValue0', '0', 'val[0]', 'float') }}};
{{{ makeSetValue('pValue1', '0', 'val[1]', 'float') }}};
{{{ makeSetValue('pValue2', '0', 'val[2]', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetSource3f(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetSourcefv__proxy: 'sync',
alGetSourcefv: (sourceId, param, pValues) => {
var val = AL.getSourceParam('alGetSourcefv', sourceId, param);
if (val === null) {
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alGetSourcefv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x1001 :
case 0x1002 :
case 0x1003 :
case {{{ cDefs.AL_GAIN }}}:
case 0x100D :
case 0x100E :
case 0x1020 :
case 0x1021 :
case 0x1022 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x200B :
{{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}};
break;
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'float') }}};
{{{ makeSetValue('pValues', '8', 'val[2]', 'float') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetSourcefv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetSourcei__proxy: 'sync',
alGetSourcei: (sourceId, param, pValue) => {
var val = AL.getSourceParam('alGetSourcei', sourceId, param);
if (val === null) {
return;
}
if (!pValue) {
#if OPENAL_DEBUG
dbg('alGetSourcei() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x202 :
case 0x1001 :
case 0x1002 :
case 0x1007 :
case 0x1009 :
case 0x1010 :
case 0x1015 :
case 0x1016 :
case 0x1020 :
case 0x1021 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x1027 :
case 0x1214 :
case 0x2009 :
case 0x200A :
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
{{{ makeSetValue('pValue', '0', 'val', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetSourcei(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetSource3i__proxy: 'sync',
alGetSource3i: (sourceId, param, pValue0, pValue1, pValue2) => {
var val = AL.getSourceParam('alGetSource3i', sourceId, param);
if (val === null) {
return;
}
if (!pValue0 || !pValue1 || !pValue2) {
#if OPENAL_DEBUG
dbg('alGetSource3i() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValue0', '0', 'val[0]', 'i32') }}};
{{{ makeSetValue('pValue1', '0', 'val[1]', 'i32') }}};
{{{ makeSetValue('pValue2', '0', 'val[2]', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetSource3i(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alGetSourceiv__proxy: 'sync',
alGetSourceiv: (sourceId, param, pValues) => {
var val = AL.getSourceParam('alGetSourceiv', sourceId, param);
if (val === null) {
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alGetSourceiv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x202 :
case 0x1001 :
case 0x1002 :
case 0x1007 :
case 0x1009 :
case 0x1010 :
case 0x1015 :
case 0x1016 :
case 0x1020 :
case 0x1021 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x1027 :
case 0x1214 :
case 0x2009 :
case 0x200A :
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
{{{ makeSetValue('pValues', '0', 'val', 'i32') }}};
break;
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
{{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}};
{{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}};
{{{ makeSetValue('pValues', '8', 'val[2]', 'i32') }}};
break;
default:
#if OPENAL_DEBUG
dbg(`alGetSourceiv(): param ${ptrToString(param)} has wrong signature`);
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}};
return;
}
},
alSourcef__proxy: 'sync',
alSourcef: (sourceId, param, value) => {
switch (param) {
case 0x1001 :
case 0x1002 :
case 0x1003 :
case {{{ cDefs.AL_GAIN }}}:
case 0x100D :
case 0x100E :
case 0x1020 :
case 0x1021 :
case 0x1022 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x200B :
AL.setSourceParam('alSourcef', sourceId, param, value);
break;
default:
AL.setSourceParam('alSourcef', sourceId, param, null);
break;
}
},
alSource3f__proxy: 'sync',
alSource3f: (sourceId, param, value0, value1, value2) => {
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = value0;
AL.paramArray[1] = value1;
AL.paramArray[2] = value2;
AL.setSourceParam('alSource3f', sourceId, param, AL.paramArray);
break;
default:
AL.setSourceParam('alSource3f', sourceId, param, null);
break;
}
},
alSourcefv__proxy: 'sync',
alSourcefv: (sourceId, param, pValues) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourcefv() called without a valid context');
#endif
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alSourcefv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x1001 :
case 0x1002 :
case 0x1003 :
case {{{ cDefs.AL_GAIN }}}:
case 0x100D :
case 0x100E :
case 0x1020 :
case 0x1021 :
case 0x1022 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x200B :
var val = {{{ makeGetValue('pValues', '0', 'float') }}};
AL.setSourceParam('alSourcefv', sourceId, param, val);
break;
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'float') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'float') }}};
AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'float') }}};
AL.setSourceParam('alSourcefv', sourceId, param, AL.paramArray);
break;
default:
AL.setSourceParam('alSourcefv', sourceId, param, null);
break;
}
},
alSourcei__proxy: 'sync',
alSourcei: (sourceId, param, value) => {
switch (param) {
case 0x202 :
case 0x1001 :
case 0x1002 :
case 0x1007 :
case 0x1009 :
case 0x1020 :
case 0x1021 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x1214 :
case 0x2009 :
case 0x200A :
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
AL.setSourceParam('alSourcei', sourceId, param, value);
break;
default:
AL.setSourceParam('alSourcei', sourceId, param, null);
break;
}
},
alSource3i__proxy: 'sync',
alSource3i: (sourceId, param, value0, value1, value2) => {
switch (param) {
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = value0;
AL.paramArray[1] = value1;
AL.paramArray[2] = value2;
AL.setSourceParam('alSource3i', sourceId, param, AL.paramArray);
break;
default:
AL.setSourceParam('alSource3i', sourceId, param, null);
break;
}
},
alSourceiv__proxy: 'sync',
alSourceiv: (sourceId, param, pValues) => {
if (!AL.currentCtx) {
#if OPENAL_DEBUG
dbg('alSourceiv() called without a valid context');
#endif
return;
}
if (!pValues) {
#if OPENAL_DEBUG
dbg('alSourceiv() called with a null pointer');
#endif
AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}};
return;
}
switch (param) {
case 0x202 :
case 0x1001 :
case 0x1002 :
case 0x1007 :
case 0x1009 :
case 0x1020 :
case 0x1021 :
case 0x1023 :
case 0x1024 :
case 0x1025 :
case 0x1026 :
case 0x1214 :
case 0x2009 :
case 0x200A :
case {{{ cDefs.AL_DISTANCE_MODEL }}}:
var val = {{{ makeGetValue('pValues', '0', 'i32') }}};
AL.setSourceParam('alSourceiv', sourceId, param, val);
break;
case {{{ cDefs.AL_POSITION }}}:
case {{{ cDefs.AL_DIRECTION }}}:
case {{{ cDefs.AL_VELOCITY }}}:
AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}};
AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}};
AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'i32') }}};
AL.setSourceParam('alSourceiv', sourceId, param, AL.paramArray);
break;
default:
AL.setSourceParam('alSourceiv', sourceId, param, null);
break;
}
}
};
autoAddDeps(LibraryOpenAL, '$AL');
addToLibrary(LibraryOpenAL);