Try to improve audio playback on mobile
This commit is contained in:
parent
7550707562
commit
f9c932b737
@ -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 :=
|
||||||
|
|
||||||
|
@ -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 ...");
|
||||||
|
|
||||||
|
70
wasm/main.c
70
wasm/main.c
@ -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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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) {
|
||||||
|
64
wasm/main.h
64
wasm/main.h
@ -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 */
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user