diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 2 | ||||
-rw-r--r-- | src/library.js | 141 | ||||
-rw-r--r-- | src/library_gl.js | 2 | ||||
-rw-r--r-- | src/library_jansson.js | 2 | ||||
-rw-r--r-- | src/library_openal.js | 596 | ||||
-rw-r--r-- | src/library_sdl.js | 168 | ||||
-rw-r--r-- | src/postamble.js | 94 | ||||
-rw-r--r-- | src/preamble.js | 73 | ||||
-rw-r--r-- | src/settings.js | 1655 |
9 files changed, 1616 insertions, 1117 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index b1f0b585..1a752305 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -338,7 +338,7 @@ function analyzer(data, sidePass) { if (subItem != item && (!(subItem.intertype in UNUNFOLDABLE) || (subItem.intertype == 'value' && isNumber(subItem.ident) && isIllegalType(subItem.type)))) { if (item.intertype == 'phi') { - assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue', 'We can only unfold illegal constants in phis'); + assert(subItem.intertype == 'value' || subItem.intertype == 'structvalue' || subItem.intertype in PARSABLE_LLVM_FUNCTIONS, 'We can only unfold some expressions in phis'); // we must handle this in the phi itself, if we unfold normally it will not be pushed back with the phi } else { var tempIdent = '$$etemp$' + (tempId++); diff --git a/src/library.js b/src/library.js index f7c7a3ba..85d1d13f 100644 --- a/src/library.js +++ b/src/library.js @@ -29,7 +29,8 @@ LibraryManager.library = { _impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)', $FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'], - $FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' + + $FS__postset: 'FS.staticInit();' + + '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' + '__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' + '__ATEXIT__.push({ func: function() { FS.quit() } });' + // export some names through closure @@ -223,7 +224,6 @@ LibraryManager.library = { // set to true and the object is a symbolic link, it will be returned as is // instead of being resolved. Links embedded in the path are still resolved. findObject: function(path, dontResolveLastLink) { - FS.ensureRoot(); var ret = FS.analyzePath(path, dontResolveLastLink); if (ret.exists) { return ret.object; @@ -509,8 +509,7 @@ LibraryManager.library = { if (!success) ___setErrNo(ERRNO_CODES.EIO); return success; }, - ensureRoot: function() { - if (FS.root) return; + staticInit: function () { // The main file system tree. All the contents are inside this. FS.root = { read: true, @@ -521,6 +520,11 @@ LibraryManager.library = { inodeNumber: 1, contents: {} }; + // Create the temporary folder, if not already created + try { + FS.createFolder('/', 'tmp', true, true); + } catch(e) {} + FS.createFolder('/', 'dev', true, true); }, // Initializes the filesystems with stdin/stdout/stderr devices, given // optional handlers. @@ -529,8 +533,6 @@ LibraryManager.library = { assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); FS.init.initialized = true; - FS.ensureRoot(); - // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here input = input || Module['stdin']; output = output || Module['stdout']; @@ -583,21 +585,15 @@ LibraryManager.library = { if (!error.printer) error.printer = Module['printErr']; if (!error.buffer) error.buffer = []; - // Create the temporary folder, if not already created - try { - FS.createFolder('/', 'tmp', true, true); - } catch(e) {} - // Create the I/O devices. - var devFolder = FS.createFolder('/', 'dev', true, true); - var stdin = FS.createDevice(devFolder, 'stdin', input); + var stdin = FS.createDevice('/dev', 'stdin', input); stdin.isTerminal = !stdinOverridden; - var stdout = FS.createDevice(devFolder, 'stdout', null, output); + var stdout = FS.createDevice('/dev', 'stdout', null, output); stdout.isTerminal = !stdoutOverridden; - var stderr = FS.createDevice(devFolder, 'stderr', null, error); + var stderr = FS.createDevice('/dev', 'stderr', null, error); stderr.isTerminal = !stderrOverridden; - FS.createDevice(devFolder, 'tty', input, output); - FS.createDevice(devFolder, 'null', function(){}, function(){}); + FS.createDevice('/dev', 'tty', input, output); + FS.createDevice('/dev', 'null', function(){}, function(){}); // Create default streams. FS.streams[1] = { @@ -1165,7 +1161,7 @@ LibraryManager.library = { ['i32', 'f_namemax']]), statvfs__deps: ['$FS', '__statvfs_struct_layout'], statvfs: function(path, buf) { - // http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html + // http://pubs.opengroup.org/onlinepubs/009695399/functions/statvfs.html // int statvfs(const char *restrict path, struct statvfs *restrict buf); var offsets = ___statvfs_struct_layout; // NOTE: None of the constants here are true. We're just returning safe and @@ -1417,6 +1413,16 @@ LibraryManager.library = { }, // ========================================================================== + // sys/file.h + // ========================================================================== + + flock: function(fd, operation) { + // int flock(int fd, int operation); + // Pretend to succeed + return 0; + }, + + // ========================================================================== // poll.h // ========================================================================== @@ -2133,20 +2139,7 @@ LibraryManager.library = { _exit: function(status) { // void _exit(int status); // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html - - function ExitStatus() { - this.name = "ExitStatus"; - this.message = "Program terminated with exit(" + status + ")"; - this.status = status; - Module.print('Exit Status: ' + status); - }; - ExitStatus.prototype = new Error(); - ExitStatus.prototype.constructor = ExitStatus; - - exitRuntime(); - ABORT = true; - - throw new ExitStatus(); + Module['exit'](status); }, fork__deps: ['__setErrNo', '$ERRNO_CODES'], fork: function() { @@ -3653,29 +3646,19 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.EAGAIN); return -1; }, - fscanf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', - '_scanString', 'fgetc', 'fseek', 'ftell'], + fscanf__deps: ['$FS', '_scanString', 'fgetc', 'ungetc'], fscanf: function(stream, format, varargs) { // int fscanf(FILE *restrict stream, const char *restrict format, ... ); // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html if (FS.streams[stream]) { - var i = _ftell(stream), SEEK_SET = 0; - // if the stream does not support seeking backwards (e.g. stdin), buffer it here - var buffer = [], bufferIndex = 0; + var buffer = []; var get = function() { - if (bufferIndex < buffer.length) { - return buffer[bufferIndex++]; - } - i++; - bufferIndex++; var c = _fgetc(stream); buffer.push(c); return c; }; var unget = function() { - if (_fseek(stream, --i, SEEK_SET) !== 0) { - bufferIndex--; - } + _ungetc(buffer.pop(), stream); }; return __scanString(format, get, unget, varargs); } else { @@ -3876,6 +3859,20 @@ LibraryManager.library = { // TODO: Implement mremap. + mprotect: function(addr, len, prot) { + // int mprotect(void *addr, size_t len, int prot); + // http://pubs.opengroup.org/onlinepubs/7908799/xsh/mprotect.html + // Pretend to succeed + return 0; + }, + + msync: function(addr, len, flags) { + // int msync(void *addr, size_t len, int flags); + // http://pubs.opengroup.org/onlinepubs/009696799/functions/msync.html + // Pretend to succeed + return 0; + }, + // ========================================================================== // stdlib.h // ========================================================================== @@ -3939,13 +3936,16 @@ LibraryManager.library = { __cxa_atexit: 'atexit', abort: function() { - ABORT = true; - throw 'abort() at ' + (new Error().stack); + Module['abort'](); }, bsearch: function(key, base, num, size, compar) { var cmp = function(x, y) { - return Runtime.dynCall('iii', compar, [x, y]) +#if ASM_JS + return Module['dynCall_iii'](compar, x, y); +#else + return FUNCTION_TABLE[compar](x, y); +#endif }; var left = 0; var right = num; @@ -3955,7 +3955,6 @@ LibraryManager.library = { mid = (left + right) >>> 1; addr = base + (mid * size); test = cmp(key, addr); - if (test < 0) { right = mid; } else if (test > 0) { @@ -4175,13 +4174,14 @@ LibraryManager.library = { if (num == 0 || size == 0) return; // forward calls to the JavaScript sort method // first, sort the items logically - var comparator = function(x, y) { - return Runtime.dynCall('iii', cmp, [x, y]); - } var keys = []; for (var i = 0; i < num; i++) keys.push(i); keys.sort(function(a, b) { - return comparator(base+a*size, base+b*size); +#if ASM_JS + return Module['dynCall_iii'](cmp, base+a*size, base+b*size); +#else + return FUNCTION_TABLE[cmp](base+a*size, base+b*size); +#endif }); // apply the sort var temp = _malloc(num*size); @@ -4459,6 +4459,13 @@ LibraryManager.library = { llvm_memmove_p0i8_p0i8_i32: 'memmove', llvm_memmove_p0i8_p0i8_i64: 'memmove', + bcopy__deps: ['memmove'], + bcopy: function(src, dest, num) { + // void bcopy(const void *s1, void *s2, size_t n); + // http://pubs.opengroup.org/onlinepubs/009695399/functions/bcopy.html + _memmove(dest, src, num); + }, + memset__inline: function(ptr, value, num, align) { return makeSetValues(ptr, 0, value, 'null', num, align); }, @@ -4947,7 +4954,17 @@ LibraryManager.library = { (chr >= {{{ charCode('{') }}} && chr <= {{{ charCode('~') }}}); }, isspace: function(chr) { - return chr in { 32: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0 }; + switch(chr) { + case 32: + case 9: + case 10: + case 11: + case 12: + case 13: + return true; + default: + return false; + }; }, isblank: function(chr) { return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}}; @@ -6161,9 +6178,14 @@ LibraryManager.library = { {{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getUTCDay()', 'i32') }}} {{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', '0', 'i32') }}} {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', '0', 'i32') }}} - - var start = new Date(date.getFullYear(), 0, 1); - var yday = Math.round((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); + var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC + start.setUTCDate(1); + start.setUTCMonth(0); + start.setUTCHours(0); + start.setUTCMinutes(0); + start.setUTCSeconds(0); + start.setUTCMilliseconds(0); + var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}} var timezone = "GMT"; @@ -6174,7 +6196,6 @@ LibraryManager.library = { return tmPtr; }, - timegm__deps: ['mktime'], timegm: function(tmPtr) { _tzset(); @@ -7823,7 +7844,7 @@ LibraryManager.library = { inet_pton__deps: ['__setErrNo', '$ERRNO_CODES', 'inet_addr'], inet_pton: function(af, src, dst) { // int af, const char *src, void *dst - if ((af ^ {{{ cDefine("AF_INET") }}}) !== 0) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); return -1; } + if ((af ^ {{{ cDefine('AF_INET') }}}) !== 0) { ___setErrNo(ERRNO_CODES.EAFNOSUPPORT); return -1; } var ret = _inet_addr(src); if (ret == -1 || isNaN(ret)) return 0; setValue(dst, ret, 'i32'); @@ -7911,7 +7932,7 @@ LibraryManager.library = { var aliasesBuf = _malloc(4); setValue(aliasesBuf, 0, 'i8*'); setValue(ret+___hostent_struct_layout.h_aliases, aliasesBuf, 'i8**'); - setValue(ret+___hostent_struct_layout.h_addrtype, {{{ cDefine("AF_INET") }}}, 'i32'); + setValue(ret+___hostent_struct_layout.h_addrtype, {{{ cDefine('AF_INET') }}}, 'i32'); setValue(ret+___hostent_struct_layout.h_length, 4, 'i32'); var addrListBuf = _malloc(12); setValue(addrListBuf, addrListBuf+8, 'i32*'); diff --git a/src/library_gl.js b/src/library_gl.js index d0f1a692..54b2f956 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -1318,7 +1318,7 @@ var LibraryGL = { GLEmulation.fogColor = new Float32Array(4); // Add some emulation workarounds - Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work'); + Module.printErr('WARNING: using emscripten GL emulation. This is a collection of limited workarounds, do not expect it to work. (If you do not want this, build with -s DISABLE_GL_EMULATION=1)'); #if GL_UNSAFE_OPTS == 0 Module.printErr('WARNING: using emscripten GL emulation unsafe opts. If weirdness happens, try -s GL_UNSAFE_OPTS=0'); #endif diff --git a/src/library_jansson.js b/src/library_jansson.js index 93f239fc..da8c5aa8 100644 --- a/src/library_jansson.js +++ b/src/library_jansson.js @@ -79,7 +79,7 @@ var LibraryJansson = { load: function(string, flags, error) { // This is potentially a security problem. // TODO: Make sure everything is properly escaped - var json_obj = eval('(' + string + ')'); + var json_obj = JSON.parse(string); if (json_obj != null) { // The context is an array storing all child nodes. diff --git a/src/library_openal.js b/src/library_openal.js index 6a97fce7..d2516559 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -5,6 +5,8 @@ var LibraryOpenAL = { $AL: { contexts: [], currentContext: null, + QUEUE_INTERVAL: 25, + QUEUE_LOOKAHEAD: 100 }, alcProcessContext: function(context) {}, @@ -39,6 +41,7 @@ var LibraryOpenAL = { alcDestroyContext: function(context) { // Stop playback, etc + clearInterval(context.interval); }, alcCloseDevice: function(device) { @@ -54,6 +57,7 @@ var LibraryOpenAL = { } }, + alcCreateContext__deps: ['updateSources'], alcCreateContext: function(device, attrList) { if (device != 1) { return 0; @@ -76,18 +80,152 @@ var LibraryOpenAL = { } if (ctx) { - AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []}); + var context = { + ctx: ctx, + err: 0, + src: [], + buf: [], + interval: setInterval(function () { _updateSources(context); }, AL.QUEUE_INTERVAL) + }; + AL.contexts.push(context); return AL.contexts.length; } else { return 0; } }, + updateSources__deps: ['updateSource'], + updateSources: function (context) { + for (var i = 0; i < context.src.length; i++) { + _updateSource(context.src[i]); + } + }, + + updateSource__deps: ['setSourceState'], + updateSource: function (src) { +#if OPENAL_DEBUG + var idx = AL.currentContext.src.indexOf(src); +#endif + if (src.state !== 0x1012 /* AL_PLAYING */) { + return; + } + + var currentTime = AL.currentContext.ctx.currentTime; + var startTime = src.bufferPosition; + + for (var i = src.buffersPlayed; i < src.queue.length; i++) { + var entry = src.queue[i]; + + var startOffset = startTime - currentTime; + var endTime = startTime + entry.buffer.duration; + + // Clean up old buffers. + if (currentTime >= endTime) { + // Update our location in the queue. + src.bufferPosition = endTime; + src.buffersPlayed = i + 1; + + // Stop / restart the source when we hit the end. + if (src.buffersPlayed >= src.queue.length) { + if (src.loop) { + _setSourceState(src, 0x1012 /* AL_PLAYING */); + } else { + _setSourceState(src, 0x1014 /* AL_STOPPED */); + } + } + } + // Process all buffers that'll be played before the next tick. + else if (startOffset < (AL.QUEUE_LOOKAHEAD / 1000) && !entry.src) { + // If the start offset is negative, we need to offset the actual buffer. + var offset = Math.abs(Math.min(startOffset, 0)); + + entry.src = AL.currentContext.ctx.createBufferSource(); + entry.src.buffer = entry.buffer; + entry.src.connect(src.gain); + entry.src.start(startTime, offset); + +#if OPENAL_DEBUG + console.log('updateSource queuing buffer ' + i + ' for source ' + idx + ' at ' + startTime + ' (offset by ' + offset + ')'); +#endif + } + + startTime = endTime; + } + }, + + setSourceState__deps: ['updateSource', 'stopSourceQueue'], + setSourceState: function (src, state) { +#if OPENAL_DEBUG + var idx = AL.currentContext.src.indexOf(src); +#endif + if (state === 0x1012 /* AL_PLAYING */) { + if (src.state !== 0x1013 /* AL_PAUSED */) { + src.state = 0x1012 /* AL_PLAYING */; + // Reset our position. + src.bufferPosition = AL.currentContext.ctx.currentTime; + src.buffersPlayed = 0; +#if OPENAL_DEBUG + console.log('setSourceState resetting and playing source ' + idx); +#endif + } else { + src.state = 0x1012 /* AL_PLAYING */; + // Use the current offset from src.bufferPosition to resume at the correct point. + src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition; +#if OPENAL_DEBUG + console.log('setSourceState resuming source ' + idx + ' at ' + src.bufferPosition.toFixed(4)); +#endif + } + _stopSourceQueue(src); + _updateSource(src); + } else if (state === 0x1013 /* AL_PAUSED */) { + if (src.state === 0x1012 /* AL_PLAYING */) { + src.state = 0x1013 /* AL_PAUSED */; + // Store off the current offset to restore with on resume. + src.bufferPosition = AL.currentContext.ctx.currentTime - src.bufferPosition; + _stopSourceQueue(src); +#if OPENAL_DEBUG + console.log('setSourceState pausing source ' + idx + ' at ' + src.bufferPosition.toFixed(4)); +#endif + } + } else if (state === 0x1014 /* AL_STOPPED */) { + if (src.state !== 0x1011 /* AL_INITIAL */) { + src.state = 0x1014 /* AL_STOPPED */; + src.buffersPlayed = src.queue.length; + _stopSourceQueue(src); +#if OPENAL_DEBUG + console.log('setSourceState stopping source ' + idx); +#endif + } + } else if (state == 0x1011 /* AL_INITIAL */) { + if (src.state !== 0x1011 /* AL_INITIAL */) { + src.state = 0x1011 /* AL_INITIAL */; + src.bufferPosition = 0; + src.buffersPlayed = 0; +#if OPENAL_DEBUG + console.log('setSourceState initializing source ' + idx); +#endif + } + } + }, + + stopSourceQueue: function (src) { + for (var i = 0; i < src.queue.length; i++) { + var entry = src.queue[i]; + if (entry.src) { + entry.src.stop(0); + entry.src = null; + } + } + }, + alGetError: function() { if (!AL.currentContext) { return 0xA004 /* AL_INVALID_OPERATION */; } else { - return AL.currentContext.err; + // Reset error on get. + var err = AL.currentContext.err; + AL.currentContext.err = 0 /* AL_NO_ERROR */; + return err; } }, @@ -97,12 +235,12 @@ var LibraryOpenAL = { return _alGetError(); }, - alDeleteSources: function(count, sources) - { + alDeleteSources: function(count, sources) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alDeleteSources called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { @@ -116,57 +254,126 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGenSources called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { var gain = AL.currentContext.ctx.createGain(); - var panner = AL.currentContext.ctx.createPanner(); - panner.panningModel = "equalpower"; - panner.distanceModel = "linear"; - panner.rolloffFactor = 0.3; - gain.connect(panner); - panner.connect(AL.currentContext.ctx.destination); + gain.connect(AL.currentContext.ctx.destination); AL.currentContext.src.push({ + state: 0x1011 /* AL_INITIAL */, + queue: [], loop: false, - buffer: null, + get refDistance() { + return this._refDistance || 1; + }, + set refDistance(val) { + this._refDistance = val; + if (this.panner) this.panner.refDistance = val; + }, + get maxDistance() { + return this._maxDistance || 10000; + }, + set maxDistance(val) { + this._maxDistance = val; + if (this.panner) this.panner.maxDistance = val; + }, + get rolloffFactor() { + return this._rolloffFactor || 1; + }, + set rolloffFactor(val) { + this._rolloffFactor = val; + if (this.panner) this.panner.rolloffFactor = val; + }, + get position() { + return this._position || [0, 0, 0]; + }, + set position(val) { + this._position = val; + if (this.panner) this.panner.setPosition(val[0], val[1], val[2]); + }, + get velocity() { + return this._velocity || [0, 0, 0]; + }, + set velocity(val) { + this._velocity = val; + if (this.panner) this.panner.setVelocity(val[0], val[1], val[2]); + }, gain: gain, - panner: panner, - paused: false, - playTime: -1, - pausedTime: 0 + panner: null, + buffersPlayed: 0, + bufferPosition: 0 }); {{{ makeSetValue('sources', 'i*4', 'AL.currentContext.src.length', 'i32') }}}; } }, + alSourcei__deps: ['updateSource'], alSourcei: function(source, param, value) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourcei called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourcei called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } switch (param) { case 0x1007 /* AL_LOOPING */: - AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */); + src.loop = (value === 1 /* AL_TRUE */); break; case 0x1009 /* AL_BUFFER */: + var buffer = AL.currentContext.buf[value - 1]; if (value == 0) { - AL.currentContext.src[source - 1].buffer = null; + src.queue = []; + } else { + src.queue = [{ buffer: buffer }]; + } + _updateSource(src); + break; + case 0x202 /* AL_SOURCE_RELATIVE */: + if (value === 1 /* AL_TRUE */) { + if (src.panner) { + src.panner = null; + + // Disconnect from the panner. + src.gain.disconnect(); + + src.gain.connect(AL.currentContext.ctx.destination); + } + } else if (value === 0 /* AL_FALSE */) { + if (!src.panner) { + var panner = src.panner = AL.currentContext.ctx.createPanner(); + panner.panningModel = "equalpower"; + panner.distanceModel = "linear"; + panner.refDistance = src.refDistance; + panner.maxDistance = src.maxDistance; + panner.rolloffFactor = src.rolloffFactor; + panner.setPosition(src.position[0], src.position[1], src.position[2]); + panner.setVelocity(src.velocity[0], src.velocity[1], src.velocity[2]); + panner.connect(AL.currentContext.ctx.destination); + + // Disconnect from the default source. + src.gain.disconnect(); + + src.gain.connect(panner); + } } else { - AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf; + AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */; } break; default: #if OPENAL_DEBUG console.log("alSourcei with param " + param + " not implemented yet"); #endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; } }, @@ -176,130 +383,168 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alSourcef called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourcef called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } switch (param) { - case 0x100A /* AL_GAIN */: - if (AL.currentContext.src[source - 1]) { - AL.currentContext.src[source - 1].gain.gain.value = value; - } - break; case 0x1003 /* AL_PITCH */: #if OPENAL_DEBUG - console.log("alSourcef was called with AL_PITCH, but Web Audio does not support static pitch changes"); + console.log("alSourcef was called with 0x1003 /* AL_PITCH */, but Web Audio does not support static pitch changes"); #endif break; + case 0x100A /* AL_GAIN */: + src.gain.gain.value = value; + break; + // case 0x100D /* AL_MIN_GAIN */: + // break; + // case 0x100E /* AL_MAX_GAIN */: + // break; + case 0x1023 /* AL_MAX_DISTANCE */: + src.maxDistance = value; + break; + case 0x1021 /* AL_ROLLOFF_FACTOR */: + src.rolloffFactor = value; + break; + // case 0x1022 /* AL_CONE_OUTER_GAIN */: + // break; + // case 0x1001 /* AL_CONE_INNER_ANGLE */: + // break; + // case 0x1002 /* AL_CONE_OUTER_ANGLE */: + // break; + case 0x1020 /* AL_REFERENCE_DISTANCE */: + src.refDistance = value; + break; default: #if OPENAL_DEBUG console.log("alSourcef with param " + param + " not implemented yet"); #endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; } }, - alSourcefv: function(source, param, value) { + alSource3f: function(source, param, v1, v2, v3) { if (!AL.currentContext) { #if OPENAL_DEBUG - console.error("alSourcefv called without a valid context"); + console.error("alSource3f called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG - console.error("alSourcefv called with an invalid source"); + console.error("alSource3f called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } switch (param) { case 0x1004 /* AL_POSITION */: - AL.currentContext.src[source - 1].panner.setPosition( - {{{ makeGetValue('value', '0', 'float') }}}, - {{{ makeGetValue('value', '4', 'float') }}}, - {{{ makeGetValue('value', '8', 'float') }}} - ); + src.position = [v1, v2, v3]; break; case 0x1006 /* AL_VELOCITY */: - AL.currentContext.src[source - 1].panner.setVelocity( - {{{ makeGetValue('value', '0', 'float') }}}, - {{{ makeGetValue('value', '4', 'float') }}}, - {{{ makeGetValue('value', '8', 'float') }}} - ); + src.velocity = [v1, v2, v3]; break; default: #if OPENAL_DEBUG - console.log("alSourcefv with param " + param + " not implemented yet"); + console.log("alSource3f with param " + param + " not implemented yet"); #endif + AL.currentContext.err = 0xA002 /* AL_INVALID_ENUM */; break; } }, + alSourcefv__deps: ['alSource3f'], + alSourcefv: function(source, param, value) { + _alSource3f(source, param, + {{{ makeGetValue('value', '0', 'float') }}}, + {{{ makeGetValue('value', '4', 'float') }}}, + {{{ makeGetValue('value', '8', 'float') }}}); + }, + + alSourceQueueBuffers__deps: ["updateSource"], alSourceQueueBuffers: function(source, count, buffers) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid source"); #endif - return; - } - if (count != 1) { -#if OPENAL_DEBUG - console.error("Queuing multiple buffers using alSourceQueueBuffers is not supported yet"); -#endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } for (var i = 0; i < count; ++i) { - var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; - if (buffer > AL.currentContext.buf.length) { + var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; + if (bufferIdx > AL.currentContext.buf.length) { #if OPENAL_DEBUG console.error("alSourceQueueBuffers called with an invalid buffer"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } - AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf; } + + for (var i = 0; i < count; ++i) { + var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; + var buffer = AL.currentContext.buf[bufferIdx - 1]; + src.queue.push({ buffer: buffer, src: null }); + } + + _updateSource(src); }, - alSourceUnqueueBuffers: function(source, count, buffers) - { + alSourceUnqueueBuffers__deps: ["updateSource"], + alSourceUnqueueBuffers: function(source, count, buffers) { if (!AL.currentContext) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } - if (source > AL.currentContext.src.length) { + var src = AL.currentContext.src[source - 1]; + if (!src) { #if OPENAL_DEBUG console.error("alSourceUnqueueBuffers called with an invalid source"); #endif + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; return; } - if (count != 1) { -#if OPENAL_DEBUG - console.error("Queuing multiple buffers using alSourceUnqueueBuffers is not supported yet"); -#endif + + if (count > src.buffersPlayed) { + AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */; return; } - for (var i = 0; i < count; ++i) { - var buffer = AL.currentContext.src[source - 1].buffer; - for (var j = 0; j < AL.currentContext.buf.length; ++j) { - if (buffer == AL.currentContext.buf[j].buf) { + + for (var i = 0; i < count; i++) { + var entry = src.queue.shift(); + // Write the buffers index out to the return list. + for (var j = 0; j < AL.currentContext.buf.length; j++) { + var b = AL.currentContext.buf[j]; + if (b && b == entry.buffer) { {{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}}; - AL.currentContext.src[source - 1].buffer = null; break; } } + src.buffersPlayed--; } + + _updateSource(src); }, alDeleteBuffers: function(count, buffers) @@ -308,21 +553,43 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alDeleteBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; + return; + } + if (count > AL.currentContext.buf.length) { + AL.currentContext.err = 0xA003 /* AL_INVALID_VALUE */; return; } + for (var i = 0; i < count; ++i) { var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1; - if (bufferIdx < AL.currentContext.buf.length && AL.currentContext.buf[bufferIdx]) { - var buffer = AL.currentContext.buf[bufferIdx].buf; - for (var j = 0; j < AL.currentContext.src.length; ++j) { - if (buffer == AL.currentContext.src[j].buffer) { - AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; + + // Make sure the buffer index is valid. + if (bufferIdx >= AL.currentContext.buf.length || !AL.currentContext.buf[bufferIdx]) { + AL.currentContext.err = 0xA001 /* AL_INVALID_NAME */; + return; + } + + // Make sure the buffer is no longer in use. + var buffer = AL.currentContext.buf[bufferIdx]; + for (var j = 0; j < AL.currentContext.src.length; ++j) { + var src = AL.currentContext.src[j]; + if (!src) { + continue; + } + for (var k = 0; k < src.queue.length; k++) { + if (buffer === src.queue[k].buffer) { + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } } - delete AL.currentContext.buf[bufferIdx]; } } + + for (var i = 0; i < count; ++i) { + var bufferIdx = {{{ makeGetValue('buffers', 'i*4', 'i32') }}} - 1; + delete AL.currentContext.buf[bufferIdx]; + } }, alGenBuffers: function(count, buffers) { @@ -330,10 +597,11 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alGenBuffers called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; return; } for (var i = 0; i < count; ++i) { - AL.currentContext.buf.push({buf: null}); + AL.currentContext.buf.push(null); {{{ makeSetValue('buffers', 'i*4', 'AL.currentContext.buf.length', 'i32') }}}; } }, @@ -343,6 +611,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG console.error("alBufferData called without a valid context"); #endif + AL.currentContext.err = 0xA004 /* AL_INVALID_OPER |