mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-30 19:50:24 +00:00
0256156a6b
fixes audio getting stuck in an always fast state
170 lines
4.5 KiB
JavaScript
170 lines
4.5 KiB
JavaScript
//"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);
|