RetroArch/emscripten/library_rwebaudio.js
2015-07-27 00:08:25 +02:00

177 lines
4.8 KiB
JavaScript

"use strict";
var LibraryRWebAudio = {
$RA__deps: ['$Browser', 'usleep'],
$RA: {
BUFFER_SIZE: 256,
context: null,
buffers: [],
numBuffers: 0,
bufIndex: 0,
bufOffset: 0,
startTime: 0,
performance: null,
nonblock: false,
performanceSupported: false,
setStartTime: function() {
RA.performance = window['performance'] || window['webkitPerformance'] || window['msPerformance'] || window['mozPerformance'];
if (RA.performance) {
RA.performanceSupported = true;
} else {
RA.performanceSupported = false;
}
if (RA.context.currentTime) {
var now = RA.performanceSupported ? RA.performance.now() : Date.now();
RA.startTime = now - RA.context.currentTime * 1000;
Module["resumeMainLoop"];
} else {
window.setTimeout(RA.setStartTime, 0);
}
},
getCurrentPerfTime: function() {
if (true === RA.performanceSupported) {
return (RA.performance.now() - RA.startTime) / 1000;
} else {
return (Date.now() - RA.startTime) / 1000;
}
},
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) {
Module.pauseMainLoop();
if (!RA.context) {
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();
RA.setStartTime();
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();
}
}
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;
return;
},
RWebAudioBufferSize: function() {
return RA.numBuffers * RA.BUFFER_SIZE + RA.BUFFER_SIZE;
},
RWebAudioWriteAvail: function() {
RA.process();
return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8;
}
};
autoAddDeps(LibraryRWebAudio, '$RA');
mergeInto(LibraryManager.library, LibraryRWebAudio);