//"use strict"; var LibraryRWebAudio = { $RA__deps: ['$Browser', 'usleep'], $RA: { BUFFER_SIZE: 2048, context: null, buffers: [], numBuffers: 0, bufIndex: 0, bufOffset: 0, startTime: 0, nonblock: false, currentTimeWorkaround: false, setStartTime: function() { if (RA.context.currentTime) { RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000; Module["resumeMainLoop"](); } else window['setTimeout'](RA.setStartTime, 0); }, getCurrentPerfTime: function() { if (RA.startTime) return (window['performance']['now']() - RA.startTime) / 1000; else return 0; }, process: function(queueBuffers) { var currentTime = RA.getCurrentPerfTime(); for (var i = 0; i < RA.bufIndex; i++) { if (RA.buffers[i].endTime !== 0 && RA.buffers[i].endTime < currentTime) { RA.buffers[i].endTime = 0; var buf = RA.buffers.splice(i, 1); RA.buffers[RA.numBuffers - 1] = buf[0]; i--; RA.bufIndex--; } } }, fillBuffer: function(buf, samples) { var count = 0; const leftBuffer = RA.buffers[RA.bufIndex].getChannelData(0); const rightBuffer = RA.buffers[RA.bufIndex].getChannelData(1); while (samples && RA.bufOffset !== RA.BUFFER_SIZE) { leftBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8', 'float') }}}; rightBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8 + 4', 'float') }}}; RA.bufOffset++; count++; samples--; } return count; }, queueAudio: function() { var index = RA.bufIndex; var startTime; if (RA.bufIndex) startTime = RA.buffers[RA.bufIndex - 1].endTime; else startTime = RA.context.currentTime; RA.buffers[index].endTime = startTime + RA.buffers[index].duration; const bufferSource = RA.context.createBufferSource(); bufferSource.buffer = RA.buffers[index]; bufferSource.connect(RA.context.destination); bufferSource.start(startTime); RA.bufIndex++; RA.bufOffset = 0; }, block: function() { do { RA.process(); } while (RA.bufIndex === RA.numBuffers); } }, RWebAudioInit: function(latency) { var ac = window['AudioContext'] || window['webkitAudioContext']; if (!ac) return 0; RA.context = new ac(); RA.numBuffers = ((latency * RA.context.sampleRate) / (1000 * RA.BUFFER_SIZE))|0; if (RA.numBuffers < 2) RA.numBuffers = 2; for (var i = 0; i < RA.numBuffers; i++) { RA.buffers[i] = RA.context.createBuffer(2, RA.BUFFER_SIZE, RA.context.sampleRate); RA.buffers[i].endTime = 0 } RA.nonblock = false; RA.startTime = 0; // chrome hack to get currentTime running RA.context.createGain(); window['setTimeout'](RA.setStartTime, 0); Module["pauseMainLoop"](); return 1; }, RWebAudioSampleRate: function() { return RA.context.sampleRate; }, RWebAudioWrite: function (buf, size) { RA.process(); var samples = size / 8; var count = 0; while (samples) { if (RA.bufIndex === RA.numBuffers) { if (RA.nonblock) break; else RA.block(); } var fill = RA.fillBuffer(buf, samples); samples -= fill; count += fill; buf += fill * 8; if (RA.bufOffset === RA.BUFFER_SIZE) { RA.queueAudio(); } } return count * 8; }, RWebAudioStop: function() { RA.bufIndex = 0; RA.bufOffset = 0; return true; }, RWebAudioStart: function() { return true; }, RWebAudioSetNonblockState: function(state) { RA.nonblock = state; }, RWebAudioFree: function() { RA.bufIndex = 0; RA.bufOffset = 0; }, RWebAudioBufferSize: function() { return RA.numBuffers * RA.BUFFER_SIZE * 8; }, RWebAudioWriteAvail: function() { RA.process(); return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8; }, RWebAudioRecalibrateTime: function() { if (RA.startTime) { RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000; } } }; autoAddDeps(LibraryRWebAudio, '$RA'); mergeInto(LibraryManager.library, LibraryRWebAudio);