Try to improve audio playback on mobile

This commit is contained in:
Maximilian Mader 2019-06-08 19:10:23 +02:00
parent 7550707562
commit f9c932b737
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
5 changed files with 145 additions and 36 deletions

View File

@ -58,7 +58,7 @@ endif
CFLAGS += -Werror -Wall -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES CFLAGS += -Werror -Wall -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
# CFLAGS += -DGB_INTERNAL=1 # get access to internal APIs # CFLAGS += -DGB_INTERNAL=1 # get access to internal APIs
CFLAGS += -I$(CORE_DIR) CFLAGS += -I$(CORE_DIR)
CFLAGS += -s WASM=1 -s USE_SDL=2 --preload-file $(BOOTROMS_DIR)@/BootROMs -s "EXTRA_EXPORTED_RUNTIME_METHODS=['FS']" CFLAGS += -s WASM=1 -s USE_SDL=2 --preload-file $(BOOTROMS_DIR)@/BootROMs -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap', 'getValue', 'AsciiToString', 'FS']"
# CFLAGS += -Wcast-align -Wover-aligned -s SAFE_HEAP=1 -s WARN_UNALIGNED=1 # CFLAGS += -Wcast-align -Wover-aligned -s SAFE_HEAP=1 -s WARN_UNALIGNED=1
WASM_LDFLAGS := WASM_LDFLAGS :=

View File

@ -98,6 +98,34 @@
const progressElement = document.querySelector('#progress'); const progressElement = document.querySelector('#progress');
var Module = { var Module = {
get_models: function () {
const ptr = Module._get_models_string_pointer();
const ptr_size = Module._get_models_string_pointer_size();
const size = Module._get_models_string_size() - ptr_size; // last element is a end marker
const models = [];
for (let i = 0; i < size; i += ptr_size) {
const key = AsciiToString(getValue(ptr + i, '*'));
models.push(key.replace(/^MODEL_/, ''));
}
return models
},
get_sgb_revisions: function () {
const ptr = Module._get_sgb_revisions_string_pointer();
const ptr_size = Module._get_sgb_revisions_string_pointer_size();
const size = Module._get_sgb_revisions_string_size() - ptr_size; // last element is a end marker
const revisions = [];
for (let i = 0; i < size; i += ptr_size) {
const key = AsciiToString(getValue(ptr + i, '*'));
revisions.push(key.replace(/^SGB_/, ''));
}
return revisions
},
sync_fs: function () { sync_fs: function () {
console.log("Syncing file system ..."); console.log("Syncing file system ...");

View File

@ -80,11 +80,15 @@ int save_battery(GB_gameboy_t *gb, const char *path) {
unsigned query_sample_rate_of_audiocontexts() { unsigned query_sample_rate_of_audiocontexts() {
return EM_ASM_INT({ return EM_ASM_INT({
if (!Module.SDL2 || !Module.SDL2.audioContext) {
const AudioContext = window.AudioContext || window.webkitAudioContext; const AudioContext = window.AudioContext || window.webkitAudioContext;
const ctx = new AudioContext(); const ctx = new AudioContext();
const sr = ctx.sampleRate; const sr = ctx.sampleRate;
ctx.close(); ctx.close();
return sr; return sr;
}
return Module.SDL2.audioContext.sampleRate;
}); });
} }
@ -217,7 +221,7 @@ void init_gb() {
} }
int EMSCRIPTEN_KEEPALIVE init() { int EMSCRIPTEN_KEEPALIVE init() {
#define str(x) #x #define str(x) #x
#define xstr(x) str(x) #define xstr(x) str(x)
pixel_format = (SDL_PixelFormat *) malloc(sizeof(SDL_PixelFormat)); pixel_format = (SDL_PixelFormat *) malloc(sizeof(SDL_PixelFormat));
@ -292,7 +296,7 @@ int EMSCRIPTEN_KEEPALIVE init() {
want_aspec.freq = audio_sample_rate; want_aspec.freq = audio_sample_rate;
want_aspec.format = AUDIO_S16SYS; want_aspec.format = AUDIO_S16SYS;
want_aspec.channels = 2; want_aspec.channels = 2;
want_aspec.samples = 512; want_aspec.samples = 2048;
want_aspec.callback = audio_callback; want_aspec.callback = audio_callback;
want_aspec.userdata = &gb; want_aspec.userdata = &gb;
@ -302,27 +306,51 @@ int EMSCRIPTEN_KEEPALIVE init() {
fprintf(stderr, "Failed to open audio: %s", SDL_GetError()); fprintf(stderr, "Failed to open audio: %s", SDL_GetError());
} }
EM_ASM({ fprintf(stderr, "WANT:\nfreq: %d\nchannels: %d\nsilence: %d\nsamples: %d\nsize: %d\nformat: %d\n", want_aspec.freq, want_aspec.channels, want_aspec.silence, want_aspec.samples, want_aspec.size, want_aspec.format);
var AudioContext = window.AudioContext || window.webkitAudioContext; fprintf(stderr, "HAVE:\nfreq: %d\nchannels: %d\nsilence: %d\nsamples: %d\nsize: %d\nformat: %d\n", have_aspec.freq, have_aspec.channels, have_aspec.silence, have_aspec.samples, have_aspec.size, have_aspec.format);
var ctx = new AudioContext();
// unlock audio for iOS EM_ASM({
if (ctx && ctx.currentTime == 0) { function audio_workaround(e) {
var buffer = ctx.createBuffer(1, 1, 22050); if (!Module.SDL2 || !Module.SDL2.audioContext || !Module.SDL2.audioContext.resume) return;
var source = ctx.createBufferSource();
source.buffer = buffer; console.log('Applying audio workarounds...');
source.connect(ctx.destination);
source.start(0); if (Module.SDL2.audioContext.state == 'suspended') {
Module.SDL2.audioContext.resume();
} }
// Google audio enable work-around: if (Module.SDL2.audioContext.state == 'running') {
// https://github.com/emscripten-ports/SDL2/issues/57 document.removeEventListener('touchstart', audio_workaround);
try { document.removeEventListener('click', audio_workaround);
if (!Module.SDL2 || !ctx || !ctx.resume) return; document.removeEventListener('keydown', audio_workaround);
ctx.resume();
} catch (err) {}
ctx.close(); if (Module.canvas) {
Module.canvas.removeEventListener('touchstart', audio_workaround);
Module.canvas.removeEventListener('click', audio_workaround);
Module.canvas.removeEventListener('keydown', audio_workaround);
}
}
else if (Module.SDL2.audioContext && Module.SDL2.audioContext.currentTime == 0) {
// unlock audio for iOS
let buffer = Module.SDL2.audioContext.createBuffer(1, 1, 22050);
let source = Module.SDL2.audioContext.createBufferSource();
source.buffer = buffer;
source.connect(Module.SDL2.audioContext.destination);
source.start(0);
}
}
document.addEventListener('touchstart', audio_workaround);
document.addEventListener('click', audio_workaround);
document.addEventListener('keydown', audio_workaround);
if (Module.canvas) {
Module.canvas.addEventListener('touchstart', audio_workaround);
Module.canvas.addEventListener('click', audio_workaround);
Module.canvas.addEventListener('keydown', audio_workaround);
}
audio_workaround();
}); });
init_gb(); init_gb();
@ -332,7 +360,11 @@ int EMSCRIPTEN_KEEPALIVE init() {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
int EMSCRIPTEN_KEEPALIVE load_rom(char* filename, char* battery_save_path) { int EMSCRIPTEN_KEEPALIVE load_boot_rom_from_file(char* filename) {
return GB_load_boot_rom(&gb, filename);
}
int EMSCRIPTEN_KEEPALIVE load_rom_from_file(char* filename, char* battery_save_path) {
int result = GB_load_rom(&gb, filename); int result = GB_load_rom(&gb, filename);
if (result == 0) { if (result == 0) {

View File

@ -1,6 +1,9 @@
#ifndef main_h #ifndef main_h
#define main_h #define main_h
#define str(x) #x
#define xstr(x) str(x)
#define VIDEO_WIDTH 160 #define VIDEO_WIDTH 160
#define VIDEO_HEIGHT 144 #define VIDEO_HEIGHT 144
#define VIDEO_PIXELS (VIDEO_WIDTH * VIDEO_HEIGHT) #define VIDEO_PIXELS (VIDEO_WIDTH * VIDEO_HEIGHT)
@ -9,6 +12,22 @@
#define SGB_VIDEO_HEIGHT 224 #define SGB_VIDEO_HEIGHT 224
#define SGB_VIDEO_PIXELS (SGB_VIDEO_WIDTH * SGB_VIDEO_HEIGHT) #define SGB_VIDEO_PIXELS (SGB_VIDEO_WIDTH * SGB_VIDEO_HEIGHT)
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
#define MODELS(MODEL) \
MODEL(MODEL_DMG) \
MODEL(MODEL_CGB) \
MODEL(MODEL_AGB) \
MODEL(MODEL_SGB) \
MODEL(MODEL_MAX)
#define SGB_REVISIONS(REVISION) \
REVISION(SGB_NTSC) \
REVISION(SGB_PAL) \
REVISION(SGB_2) \
REVISION(SGB_MAX)
typedef enum { typedef enum {
JOYPAD_AXISES_X, JOYPAD_AXISES_X,
JOYPAD_AXISES_Y, JOYPAD_AXISES_Y,
@ -24,11 +43,7 @@ typedef struct {
char filter[32]; char filter[32];
enum { enum {
MODEL_DMG, MODELS(GENERATE_ENUM)
MODEL_CGB,
MODEL_AGB,
MODEL_SGB,
MODEL_MAX,
} model; } model;
/* v0.11 */ /* v0.11 */
@ -39,11 +54,42 @@ typedef struct {
/* v0.12 */ /* v0.12 */
enum { enum {
SGB_NTSC, SGB_REVISIONS(GENERATE_ENUM)
SGB_PAL,
SGB_2,
SGB_MAX
} sgb_revision; } sgb_revision;
} configuration_t; } configuration_t;
// TODO: There must be a better way to not duplicate this data on the JavaScript side
static const char *MODELS_STRING[] = {
MODELS(GENERATE_STRING)
};
static const char *SGB_REVISIONS_STRING[] = {
SGB_REVISIONS(GENERATE_STRING)
};
static const char** EMSCRIPTEN_KEEPALIVE get_models_string_pointer() {
return MODELS_STRING;
}
static const size_t EMSCRIPTEN_KEEPALIVE get_models_string_pointer_size() {
return sizeof(*MODELS_STRING);
}
static const size_t EMSCRIPTEN_KEEPALIVE get_models_string_size() {
return sizeof(MODELS_STRING);
}
static const char** EMSCRIPTEN_KEEPALIVE get_sgb_revisions_string_pointer() {
return SGB_REVISIONS_STRING;
}
static const size_t EMSCRIPTEN_KEEPALIVE get_sgb_revisions_string_pointer_size() {
return sizeof(*SGB_REVISIONS_STRING);
}
static const size_t EMSCRIPTEN_KEEPALIVE get_sgb_revisions_string_size() {
return sizeof(SGB_REVISIONS_STRING);
}
#endif /* main_h */ #endif /* main_h */

View File

@ -50,7 +50,7 @@ const loadRomFromMemory = (name, data) => {
const rom_path = allocate(intArrayFromString(`/rom/${name}`), 'i8', ALLOC_NORMAL); const rom_path = allocate(intArrayFromString(`/rom/${name}`), 'i8', ALLOC_NORMAL);
const battery_path = allocate(intArrayFromString(`/persist/${battery_name}`), 'i8', ALLOC_NORMAL); const battery_path = allocate(intArrayFromString(`/persist/${battery_name}`), 'i8', ALLOC_NORMAL);
Module._load_rom(rom_path, battery_path); Module._load_rom_from_file(rom_path, battery_path);
// The ROM has been read into memory, we can unlink the file now // The ROM has been read into memory, we can unlink the file now
FS.unlink(`/rom/${name}`) FS.unlink(`/rom/${name}`)
@ -123,6 +123,9 @@ document.getElementById('file').addEventListener('change', e => {
}, false); }, false);
Module.onRuntimeInitialized = _ => { Module.onRuntimeInitialized = _ => {
console.log(Module.get_models());
console.log(Module.get_sgb_revisions());
FS.mkdir('/persist'); FS.mkdir('/persist');
FS.mount(IDBFS, { }, '/persist'); FS.mount(IDBFS, { }, '/persist');