mirror of
https://github.com/CTCaer/RetroArch.git
synced 2024-12-13 22:08:34 +00:00
[EMSCRIPTEN] more audio fixes, revert to busywait method
This commit is contained in:
parent
04be8cbee2
commit
336e1eeb51
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -26,4 +26,3 @@ void RWebAudioSetNonblockState(bool state);
|
||||
void RWebAudioFree(void);
|
||||
size_t RWebAudioWriteAvail(void);
|
||||
size_t RWebAudioBufferSize(void);
|
||||
int RWebAudioEnoughSpace(void);
|
||||
|
@ -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');
|
||||
|
@ -56,11 +56,6 @@ static void endloop(void)
|
||||
|
||||
static void mainloop(void)
|
||||
{
|
||||
if (!RWebAudioEnoughSpace())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_extern.system.shutdown)
|
||||
{
|
||||
endloop();
|
||||
|
Loading…
Reference in New Issue
Block a user