This commit is contained in:
Robbbert 2016-02-04 15:56:27 +11:00
commit 9e910e95a8
3 changed files with 217 additions and 4 deletions

View File

@ -88,7 +88,7 @@ end
targetextension ".bc"
if os.getenv("EMSCRIPTEN") then
postbuildcommands {
os.getenv("EMSCRIPTEN") .. "/emcc -O3 -s DISABLE_EXCEPTION_CATCHING=2 -s USE_SDL=2 --memory-init-file 0 -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_MEMORY=268435456 -s EXCEPTION_CATCHING_WHITELIST='[\"__ZN15running_machine17start_all_devicesEv\"]' -s EXPORTED_FUNCTIONS=\"['_main', '_malloc', '__Z14js_get_machinev', '__Z9js_get_uiv', '__Z12js_get_soundv', '__ZN10ui_manager12set_show_fpsEb', '__ZNK10ui_manager8show_fpsEv', '__ZN13sound_manager4muteEbh', '_SDL_PauseAudio']\" $(TARGET) -o " .. _MAKE.esc(MAME_DIR) .. _OPTIONS["target"] .. _OPTIONS["subtarget"] .. ".js --post-js " .. _MAKE.esc(MAME_DIR) .. "src/osd/sdl/emscripten_post.js",
os.getenv("EMSCRIPTEN") .. "/emcc -O3 -s DISABLE_EXCEPTION_CATCHING=2 -s USE_SDL=2 --memory-init-file 0 -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_MEMORY=268435456 -s EXCEPTION_CATCHING_WHITELIST='[\"__ZN15running_machine17start_all_devicesEv\"]' -s EXPORTED_FUNCTIONS=\"['_main', '_malloc', '__Z14js_get_machinev', '__Z9js_get_uiv', '__Z12js_get_soundv', '__ZN10ui_manager12set_show_fpsEb', '__ZNK10ui_manager8show_fpsEv', '__ZN13sound_manager4muteEbh', '_SDL_PauseAudio']\" $(TARGET) -o " .. _MAKE.esc(MAME_DIR) .. _OPTIONS["target"] .. _OPTIONS["subtarget"] .. ".js --pre-js " .. _MAKE.esc(MAME_DIR) .. "src/osd/modules/sound/js_sound.js --post-js " .. _MAKE.esc(MAME_DIR) .. "src/osd/sdl/emscripten_post.js",
}
end

View File

@ -6,7 +6,7 @@
Shim for native JavaScript sound interface implementations (Emscripten only).
*******************************************************************c********/
****************************************************************************/
#include "sound_module.h"
#include "modules/osdmodule.h"
@ -34,14 +34,14 @@ public:
{
EM_ASM_ARGS({
// Forward audio stream update on to JS backend implementation.
jsmess_update_audio_stream($0, $1);
jsmame_update_audio_stream($0, $1);
}, (unsigned int)buffer, samples_this_frame);
}
virtual void set_mastervolume(int attenuation)
{
EM_ASM_ARGS({
// Forward volume update on to JS backend implementation.
jsmess_set_mastervolume($0);
jsmame_set_mastervolume($0);
}, attenuation);
}

View File

@ -0,0 +1,213 @@
// license:BSD-3-Clause
// copyright-holders:Grant Galitz, Katelyn Gadd
/***************************************************************************
JSMAME web audio backend v0.3
Original by katelyn gadd - kg at luminance dot org ; @antumbral on twitter
Substantial changes by taisel
***************************************************************************/
var jsmame_web_audio = (function () {
var context = null;
var gain_node = null;
var eventNode = null;
var sampleScale = 32766;
var inputBuffer = new Float32Array(44100);
var bufferSize = 44100;
var start = 0;
var rear = 0;
var watchDogDateLast = null;
var watchDogTimerEvent = null;
function lazy_init () {
//Make
if (context) {
//Return if already created:
return;
}
if (typeof AudioContext != "undefined") {
//Standard context creation:
context = new AudioContext();
}
else if (typeof webkitAudioContext != "undefined") {
//Older webkit context creation:
context = new webkitAudioContext();
}
else {
//API not found!
return;
}
//Generate a volume control node:
gain_node = context.createGain();
//Set initial volume to 1:
gain_node.gain.value = 1.0;
//Connect volume node to output:
gain_node.connect(context.destination);
//Initialize the streaming event:
init_event();
};
function init_event() {
//Generate a streaming node point:
if (typeof context.createScriptProcessor == "function") {
//Current standard compliant way:
eventNode = context.createScriptProcessor(4096, 0, 2);
}
else {
//Deprecated way:
eventNode = context.createJavaScriptNode(4096, 0, 2);
}
//Make our tick function the audio callback function:
eventNode.onaudioprocess = tick;
//Connect stream to volume control node:
eventNode.connect(gain_node);
//WORKAROUND FOR FIREFOX BUG:
initializeWatchDogForFirefoxBug();
};
function initializeWatchDogForFirefoxBug() {
//TODO: decide if we want to user agent sniff firefox here,
//since Google Chrome doesn't need this:
watchDogDateLast = (new Date()).getTime();
if (watchDogTimerEvent === null) {
watchDogTimerEvent = setInterval(function () {
var timeDiff = (new Date()).getTime() - watchDogDateLast;
if (timeDiff > 500) {
disconnect_old_event();
init_event();
}
}, 500);
}
};
function disconnect_old_event() {
//Disconnect from audio graph:
eventNode.disconnect();
//IIRC there was a firefox bug that did not GC this event when nulling the node itself:
eventNode.onaudioprocess = null;
//Null the glitched/unused node:
eventNode = null;
};
function set_mastervolume (
// even though it's 'attenuation' the value is negative, so...
attenuation_in_decibels
) {
lazy_init();
if (!context) return;
// http://stackoverflow.com/questions/22604500/web-audio-api-working-with-decibels
// seemingly incorrect/broken. figures. welcome to Web Audio
// var gain_web_audio = 1.0 - Math.pow(10, 10 / attenuation_in_decibels);
// HACK: Max attenuation in JSMESS appears to be 32.
// Hit ' then left/right arrow to test.
// FIXME: This is linear instead of log10 scale.
var gain_web_audio = 1.0 + (+attenuation_in_decibels / +32);
if (gain_web_audio < +0)
gain_web_audio = +0;
else if (gain_web_audio > +1)
gain_web_audio = +1;
gain_node.gain.value = gain_web_audio;
};
function update_audio_stream (
pBuffer, // pointer into emscripten heap. int16 samples
samples_this_frame // int. number of samples at pBuffer address.
) {
lazy_init();
if (!context) return;
for (
var i = 0,
l = samples_this_frame | 0;
i < l;
i++
) {
var offset =
// divide by sizeof(INT16) since pBuffer is offset
// in bytes
((pBuffer / 2) | 0) +
((i * 2) | 0);
var left_sample = HEAP16[offset];
var right_sample = HEAP16[(offset + 1) | 0];
// normalize from signed int16 to signed float
var left_sample_float = left_sample / sampleScale;
var right_sample_float = right_sample / sampleScale;
inputBuffer[rear++] = left_sample_float;
inputBuffer[rear++] = right_sample_float;
if (rear == bufferSize) {
rear = 0;
}
if (start == rear) {
start += 2;
if (start == bufferSize) {
start = 0;
}
}
}
};
function tick (event) {
//Find all output channels:
for (var bufferCount = 0, buffers = []; bufferCount < 2; ++bufferCount) {
buffers[bufferCount] = event.outputBuffer.getChannelData(bufferCount);
}
//Copy samples from the input buffer to the Web Audio API:
for (var index = 0; index < 4096 && start != rear; ++index) {
buffers[0][index] = inputBuffer[start++];
buffers[1][index] = inputBuffer[start++];
if (start == bufferSize) {
start = 0;
}
}
//Pad with silence if we're underrunning:
while (index < 4096) {
buffers[0][index] = 0;
buffers[1][index++] = 0;
}
//Deep inside the bowels of vendors bugs,
//we're using watchdog for a firefox bug,
//where the user agent decides to stop firing events
//if the user agent lags out due to system load.
//Don't even ask....
watchDogDateLast = (new Date()).getTime();
}
function get_context() {
return context;
};
function sample_count() {
//TODO get someone to call this from the emulator,
//so the emulator can do proper audio buffering by
//knowing how many samples are left:
if (!context) {
//Use impossible value as an error code:
return -1;
}
var count = rear - start;
if (start > rear) {
count += bufferSize;
}
return count;
}
return {
set_mastervolume: set_mastervolume,
update_audio_stream: update_audio_stream,
get_context: get_context,
sample_count: sample_count
};
})();
window.jsmame_set_mastervolume = jsmame_web_audio.set_mastervolume;
window.jsmame_update_audio_stream = jsmame_web_audio.update_audio_stream;
window.jsmame_sample_count = jsmame_web_audio.sample_count;