[EMSCRIPTEN] more audio fixes, revert to busywait method

This commit is contained in:
ToadKing 2013-09-02 21:29:40 -04:00
parent 04be8cbee2
commit 336e1eeb51
5 changed files with 143 additions and 153 deletions

View File

@ -338,8 +338,6 @@ static const bool rate_control = false;
// Rate control delta. Defines how much rate_control is allowed to adjust input rate. // Rate control delta. Defines how much rate_control is allowed to adjust input rate.
#if defined(__QNX__) #if defined(__QNX__)
static const float rate_control_delta = 0.000; static const float rate_control_delta = 0.000;
#elif defined(EMSCRIPTEN)
static const float rate_control_delta = 0.002;
#else #else
static const float rate_control_delta = 0.005; static const float rate_control_delta = 0.005;
#endif #endif

View File

@ -28,8 +28,8 @@ static void *ra_init(const char *device, unsigned rate, unsigned latency)
(void)device; (void)device;
(void)rate; (void)rate;
void *data = RWebAudioInit(latency); void *data = RWebAudioInit(latency);
if (data)
g_settings.audio.out_rate = RWebAudioSampleRate(); g_settings.audio.out_rate = RWebAudioSampleRate();
RARCH_LOG("audio out rate: %u\n", g_settings.audio.out_rate);
return data; return data;
} }

View File

@ -26,4 +26,3 @@ void RWebAudioSetNonblockState(bool state);
void RWebAudioFree(void); void RWebAudioFree(void);
size_t RWebAudioWriteAvail(void); size_t RWebAudioWriteAvail(void);
size_t RWebAudioBufferSize(void); size_t RWebAudioBufferSize(void);
int RWebAudioEnoughSpace(void);

View File

@ -3,122 +3,135 @@
var LibraryRWebAudio = { var LibraryRWebAudio = {
$RA__deps: ['$Browser'], $RA__deps: ['$Browser'],
$RA: { $RA: {
SCRIPTNODE_BUFFER: 1024, BUFFER_SIZE: 256,
context: null, context: null,
leftBuffer: null, buffers: [],
rightBuffer: null, numBuffers: 0,
blank: null, bufIndex: 0,
scriptNode: null, bufOffset: 0,
bufferNode: null, startTime: 0,
start: 0,
end: 0,
size: 0,
lastWrite: 0,
nonblock: false, nonblock: false,
npot: function(n) { setStartTime: function() {
n--; if (RA.context.currentTime) {
n |= n >> 1; RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000;
n |= n >> 2; if (RA.startTime === 0) throw 'startTime is 0';
n |= n >> 4; Module["resumeMainLoop"]();
n |= n >> 8; } else window['setTimeout'](RA.setStartTime, 0);
n |= n >> 16;
n++;
return n;
}, },
process: function(e) { getCurrentPerfTime: function() {
var left = e.outputBuffer.getChannelData(0); if (RA.startTime) return (window['performance']['now']() - RA.startTime) / 1000;
var right = e.outputBuffer.getChannelData(1); else throw 'getCurrentPerfTime() called before start time set';
var samples1 = RA.size; },
var samples2 = 0;
samples1 = e.outputBuffer.length > samples1 ? samples1 : e.outputBuffer.length;
if (samples1 + RA.start > RA.leftBuffer.length) { process: function(queueBuffers) {
samples2 = samples1 + RA.start - RA.leftBuffer.length; var currentTime = RA.getCurrentPerfTime();
samples1 = samples1 - samples2; for (var i = 0; i < RA.bufIndex; i++) {
if (RA.buffers[i].endTime < currentTime) {
var buf = RA.buffers.splice(i, 1);
RA.buffers[RA.numBuffers - 1] = buf[0];
i--;
RA.bufIndex--;
}
}
},
fillBuffer: function(buf, samples) {
var count = 0;
var leftBuffer = RA.buffers[RA.bufIndex].getChannelData(0);
var 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--;
} }
var remaining = e.outputBuffer.length - (samples1 + samples2); return count;
},
if (samples1) { queueAudio: function() {
left.set(RA.leftBuffer.subarray(RA.start, RA.start + samples1), 0); var index = RA.bufIndex;
right.set(RA.rightBuffer.subarray(RA.start, RA.start + samples1), 0);
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;
var 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 - 1);
} }
},
if (samples2) { RWebAudioInit: function(latency) {
left.set(RA.leftBuffer.subarray(0, samples2), samples1); var ac = window['AudioContext'] || window['webkitAudioContext'];
right.set(RA.rightBuffer.subarray(0, samples2), samples1);
}
/*if (remaining) { if (!ac) return 0;
left.set(RA.blank.subarray(0, remaining), samples1 + samples2);
right.set(RA.blank.subarray(0, remaining), samples1 + samples2);
}*/
RA.start = (RA.start + samples1 + samples2) % RA.leftBuffer.length; RA.context = new ac();
RA.size -= samples1 + samples2;
} 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.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() { RWebAudioSampleRate: function() {
return RA.context.sampleRate; return RA.context.sampleRate;
}, },
RWebAudioInit: function(latency) {
var ac = window['AudioContext'] || window['webkitAudioContext'];
var bufferSize;
if (!ac) return 0;
RA.context = new ac();
// account for script processor overhead
latency -= 32;
// because we have to guess on how many samples the core will send when
// returning early, we double the buffer size to account for times when it
// sends more than we expect it to without losing samples
bufferSize = RA.npot(RA.context.sampleRate * latency / 1000) * 2;
RA.leftBuffer = new Float32Array(bufferSize);
RA.rightBuffer = new Float32Array(bufferSize);
RA.blank = new Float32Array(RA.SCRIPTNODE_BUFFER);
RA.bufferNode = RA.context.createBufferSource();
RA.bufferNode.buffer = RA.context.createBuffer(2, RA.SCRIPTNODE_BUFFER, RA.context.sampleRate);
RA.bufferNode.loop = true;
RA.scriptNode = RA.context.createScriptProcessor(RA.SCRIPTNODE_BUFFER, 2, 2);
RA.scriptNode.onaudioprocess = RA.process;
RA.bufferNode.connect(RA.scriptNode);
RA.scriptNode.connect(RA.context.destination);
RA.bufferNode.start(0);
RA.start = RA.end = RA.size = 0;
RA.nonblock = false;
return 1;
},
RWebAudioWrite: function (buf, size) { RWebAudioWrite: function (buf, size) {
RA.process();
var samples = size / 8; var samples = size / 8;
var free = RA.leftBuffer.length - RA.size; var count = 0;
if (free < samples)
RA.start = (RA.start + free) % RA.leftBuffer.length;
for (var i = 0; i < samples; i++) { while (samples) {
RA.leftBuffer[RA.end] = {{{ makeGetValue('buf', 'i * 8', 'float') }}}; var fill = RA.fillBuffer(buf, samples);
RA.rightBuffer[RA.end] = {{{ makeGetValue('buf', 'i * 8 + 4', 'float') }}}; samples -= fill;
RA.end = (RA.end + 1) % RA.leftBuffer.length; count += fill;
buf += fill * 8;
if (RA.bufOffset === RA.BUFFER_SIZE) {
if (RA.bufIndex === RA.numBuffers - 1) {
if (RA.nonblock) break;
else RA.block();
}
RA.queueAudio();
}
} }
RA.lastWrite = size; return count * 8;
RA.size += samples;
return size;
}, },
RWebAudioStop: function() { RWebAudioStop: function() {
RA.scriptNode.onaudioprocess = null; RA.bufIndex = 0;
RA.bufOffset = 0;
return true; return true;
}, },
RWebAudioStart: function() { RWebAudioStart: function() {
RA.scriptNode.onaudioprocess = RA.process;
return true; return true;
}, },
@ -127,33 +140,18 @@ var LibraryRWebAudio = {
}, },
RWebAudioFree: function() { RWebAudioFree: function() {
RA.scriptNode.onaudioprocess = null; RA.bufIndex = 0;
RA.start = RA.end = RA.size = RA.lastWrite = 0; RA.bufOffset = 0;
return; return;
}, },
RWebAudioWriteAvail: function() {
var free = (RA.leftBuffer.length / 2) - RA.size;
// 4 byte samples, 2 channels
free *= 8;
if (free < 0)
return 0;
else
return free;
},
RWebAudioBufferSize: function() { RWebAudioBufferSize: function() {
return RA.leftBuffer.length / 2; return RA.numBuffers * RA.BUFFER_SIZE + RA.BUFFER_SIZE;
}, },
RWebAudioEnoughSpace__deps: ['RWebAudioWriteAvail'], RWebAudioWriteAvail: function() {
RWebAudioEnoughSpace: function() { RA.process();
var guess = RA.lastWrite; return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8;
var available = _RWebAudioWriteAvail();
if (RA.nonblock) return true;
if (!guess) return true;
return (guess < available) ? 1 : 0;
} }
}; };

View File

@ -56,11 +56,6 @@ static void endloop(void)
static void mainloop(void) static void mainloop(void)
{ {
if (!RWebAudioEnoughSpace())
{
return;
}
if (g_extern.system.shutdown) if (g_extern.system.shutdown)
{ {
endloop(); endloop();