[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.
#if defined(__QNX__)
static const float rate_control_delta = 0.000;
#elif defined(EMSCRIPTEN)
static const float rate_control_delta = 0.002;
#else
static const float rate_control_delta = 0.005;
#endif

View File

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

View File

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

View File

@ -1,160 +1,158 @@
//"use strict";
var LibraryRWebAudio = {
$RA__deps: ['$Browser'],
$RA: {
SCRIPTNODE_BUFFER: 1024,
$RA__deps: ['$Browser'],
$RA: {
BUFFER_SIZE: 256,
context: null,
leftBuffer: null,
rightBuffer: null,
blank: null,
scriptNode: null,
bufferNode: null,
start: 0,
end: 0,
size: 0,
lastWrite: 0,
nonblock: false,
npot: function(n) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;
return n;
},
context: null,
buffers: [],
numBuffers: 0,
bufIndex: 0,
bufOffset: 0,
startTime: 0,
nonblock: false,
process: function(e) {
var left = e.outputBuffer.getChannelData(0);
var right = e.outputBuffer.getChannelData(1);
var samples1 = RA.size;
var samples2 = 0;
samples1 = e.outputBuffer.length > samples1 ? samples1 : e.outputBuffer.length;
setStartTime: function() {
if (RA.context.currentTime) {
RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000;
if (RA.startTime === 0) throw 'startTime is 0';
Module["resumeMainLoop"]();
} else window['setTimeout'](RA.setStartTime, 0);
},
if (samples1 + RA.start > RA.leftBuffer.length) {
samples2 = samples1 + RA.start - RA.leftBuffer.length;
samples1 = samples1 - samples2;
getCurrentPerfTime: function() {
if (RA.startTime) return (window['performance']['now']() - RA.startTime) / 1000;
else throw 'getCurrentPerfTime() called before start time set';
},
process: function(queueBuffers) {
var currentTime = RA.getCurrentPerfTime();
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--;
}
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;
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);
}
},
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.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) {
var fill = RA.fillBuffer(buf, samples);
samples -= fill;
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();
}
}
var remaining = e.outputBuffer.length - (samples1 + samples2);
return count * 8;
},
if (samples1) {
left.set(RA.leftBuffer.subarray(RA.start, RA.start + samples1), 0);
right.set(RA.rightBuffer.subarray(RA.start, RA.start + samples1), 0);
}
RWebAudioStop: function() {
RA.bufIndex = 0;
RA.bufOffset = 0;
return true;
},
if (samples2) {
left.set(RA.leftBuffer.subarray(0, samples2), samples1);
right.set(RA.rightBuffer.subarray(0, samples2), samples1);
}
RWebAudioStart: function() {
return true;
},
/*if (remaining) {
left.set(RA.blank.subarray(0, remaining), samples1 + samples2);
right.set(RA.blank.subarray(0, remaining), samples1 + samples2);
}*/
RWebAudioSetNonblockState: function(state) {
RA.nonblock = state;
},
RA.start = (RA.start + samples1 + samples2) % RA.leftBuffer.length;
RA.size -= samples1 + samples2;
}
},
RWebAudioSampleRate: function() {
return RA.context.sampleRate;
},
RWebAudioFree: function() {
RA.bufIndex = 0;
RA.bufOffset = 0;
return;
},
RWebAudioInit: function(latency) {
var ac = window['AudioContext'] || window['webkitAudioContext'];
var bufferSize;
RWebAudioBufferSize: function() {
return RA.numBuffers * RA.BUFFER_SIZE + RA.BUFFER_SIZE;
},
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) {
var samples = size / 8;
var free = RA.leftBuffer.length - RA.size;
if (free < samples)
RA.start = (RA.start + free) % RA.leftBuffer.length;
for (var i = 0; i < samples; i++) {
RA.leftBuffer[RA.end] = {{{ makeGetValue('buf', 'i * 8', 'float') }}};
RA.rightBuffer[RA.end] = {{{ makeGetValue('buf', 'i * 8 + 4', 'float') }}};
RA.end = (RA.end + 1) % RA.leftBuffer.length;
}
RA.lastWrite = size;
RA.size += samples;
return size;
},
RWebAudioStop: function() {
RA.scriptNode.onaudioprocess = null;
return true;
},
RWebAudioStart: function() {
RA.scriptNode.onaudioprocess = RA.process;
return true;
},
RWebAudioSetNonblockState: function(state) {
RA.nonblock = state;
},
RWebAudioFree: function() {
RA.scriptNode.onaudioprocess = null;
RA.start = RA.end = RA.size = RA.lastWrite = 0;
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() {
return RA.leftBuffer.length / 2;
},
RWebAudioEnoughSpace__deps: ['RWebAudioWriteAvail'],
RWebAudioEnoughSpace: function() {
var guess = RA.lastWrite;
var available = _RWebAudioWriteAvail();
if (RA.nonblock) return true;
if (!guess) return true;
return (guess < available) ? 1 : 0;
}
RWebAudioWriteAvail: function() {
RA.process();
return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8;
}
};
autoAddDeps(LibraryRWebAudio, '$RA');

View File

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