From 98304612143101bfed7778ac387a70bf0b1a47d1 Mon Sep 17 00:00:00 2001 From: Bobby Smiles Date: Sat, 7 Mar 2015 10:20:05 +0100 Subject: [PATCH] Introduce the m64p_audio_backend structure. --- .../Mupen64Plus-v2.0-headers.mediawiki | 34 +++++++++++ .../VisualStudio2013/mupen64plus-core.vcxproj | 6 +- projects/unix/Makefile | 3 +- src/ai/ai_controller.c | 18 ++---- src/ai/ai_controller.h | 9 +-- src/api/audio_backend.c | 36 ++++++++++++ src/api/audio_backend.h | 38 ++++++++++++ src/api/m64p_types.h | 37 ++++++++++++ src/main/main.c | 6 +- ..._audio_plugin.c => audio_backend_compat.c} | 58 +++++++++++-------- ..._audio_plugin.h => audio_backend_compat.h} | 12 ++-- 11 files changed, 202 insertions(+), 55 deletions(-) create mode 100644 src/api/audio_backend.c create mode 100644 src/api/audio_backend.h rename src/plugin/{emulate_speaker_via_audio_plugin.c => audio_backend_compat.c} (51%) rename src/plugin/{emulate_speaker_via_audio_plugin.h => audio_backend_compat.h} (79%) diff --git a/doc/emuwiki-api-doc/Mupen64Plus-v2.0-headers.mediawiki b/doc/emuwiki-api-doc/Mupen64Plus-v2.0-headers.mediawiki index 139075b08..6d24bb678 100644 --- a/doc/emuwiki-api-doc/Mupen64Plus-v2.0-headers.mediawiki +++ b/doc/emuwiki-api-doc/Mupen64Plus-v2.0-headers.mediawiki @@ -337,3 +337,37 @@ m64p_error (*VidExtFuncResizeWindow)(int, int); } m64p_video_extension_functions; + /* ------------------------------------------ */ + /* Structures and Types for Audio Backend API */ + /* ------------------------------------------ */ + + /* Audio backend object + * + * user_data is a pointer which will be passed as the first argument of audio backend functions. + * Frontend writers are free to use it as they please. + * + * set_audio_format function allows the audio backend to be notified of the format of incoming samples. + * 2nd parameter frequency is the sample rate of incoming samples. + * 3rd parameter bits is the sample resolution (usually 16 bits) + * + * This function should be called by the core at least one time before any call to "push_audio_samples". + * Audio backends are expected to handle gracefully eventual changes of audio format + * even after this "initial" setup. Though in practice, very few games, if any, + * changes the audio format after the initial setup. + * + * push_audio_samples function notifies the audio backend of new samples ready to be played. + * 2nd parameter buffer is a pointer to the beginning of the incoming samples. + * 3rd parameter size is the size in bytes of the buffer. + * + * Samples are in stereo interleaved format (LR LR LR ...) and their resolution (bits per channel) + * is specified by prior calls of set_audio_format. + * Audio backends are expected not to block during the servicing of this function. + * We invite audio backends writers to buffer (and maybe resample) the incoming samples + * and return control to the core as soon as possible. + */ + struct m64p_audio_backend + { + void* user_data; + void (*set_audio_format)(void*, unsigned int, unsigned int); + void (*push_audio_samples)(void*, const void*, size_t); + }; diff --git a/projects/VisualStudio2013/mupen64plus-core.vcxproj b/projects/VisualStudio2013/mupen64plus-core.vcxproj index 273b82f53..916fdfae5 100644 --- a/projects/VisualStudio2013/mupen64plus-core.vcxproj +++ b/projects/VisualStudio2013/mupen64plus-core.vcxproj @@ -21,6 +21,7 @@ + @@ -70,6 +71,7 @@ + @@ -285,6 +287,7 @@ + @@ -335,6 +338,7 @@ + @@ -647,4 +651,4 @@ - \ No newline at end of file + diff --git a/projects/unix/Makefile b/projects/unix/Makefile index 56a30a3f4..ee499f1fe 100644 --- a/projects/unix/Makefile +++ b/projects/unix/Makefile @@ -413,6 +413,7 @@ OBJDIR = _obj$(POSTFIX) # list of required source files for compilation SOURCE = \ $(SRCDIR)/ai/ai_controller.c \ + $(SRCDIR)/api/audio_backend.c \ $(SRCDIR)/api/callbacks.c \ $(SRCDIR)/api/common.c \ $(SRCDIR)/api/config.c \ @@ -439,7 +440,7 @@ SOURCE = \ $(SRCDIR)/pi/pi_controller.c \ $(SRCDIR)/pi/sram.c \ $(SRCDIR)/plugin/emulate_game_controller_via_input_plugin.c \ - $(SRCDIR)/plugin/emulate_speaker_via_audio_plugin.c \ + $(SRCDIR)/plugin/audio_backend_compat.c \ $(SRCDIR)/plugin/get_time_using_C_localtime.c \ $(SRCDIR)/plugin/rumble_via_input_plugin.c \ $(SRCDIR)/plugin/plugin.c \ diff --git a/src/ai/ai_controller.c b/src/ai/ai_controller.c index aef3eb06f..fdb1d4bfb 100644 --- a/src/ai/ai_controller.c +++ b/src/ai/ai_controller.c @@ -21,6 +21,7 @@ #include "ai_controller.h" +#include "api/audio_backend.h" #include "main/rom.h" #include "memory/memory.h" #include "r4300/r4300_core.h" @@ -81,13 +82,13 @@ static void do_dma(struct ai_controller* ai, const struct ai_dma* dma) ? 16 : 1 + ai->regs[AI_BITRATE_REG]; - set_audio_format(ai, frequency, bits); + set_audio_format(&ai->backend, frequency, bits); ai->samples_format_changed = 0; } - /* push audio samples to external sink */ - push_audio_samples(ai, &ai->ri->rdram.dram[dma->address/4], dma->length); + /* push audio samples to audio backend */ + push_audio_samples(&ai->backend, &ai->ri->rdram.dram[dma->address/4], dma->length); /* schedule end of dma event */ update_count(); @@ -134,17 +135,6 @@ static void fifo_pop(struct ai_controller* ai) } -void set_audio_format(struct ai_controller* ai, unsigned int frequency, unsigned int bits) -{ - ai->set_audio_format(ai->user_data, frequency, bits); -} - -void push_audio_samples(struct ai_controller* ai, const void* buffer, size_t size) -{ - ai->push_audio_samples(ai->user_data, buffer, size); -} - - void connect_ai(struct ai_controller* ai, struct r4300_core* r4300, struct ri_controller* ri, diff --git a/src/ai/ai_controller.h b/src/ai/ai_controller.h index 7ce27802f..ff789bbfd 100644 --- a/src/ai/ai_controller.h +++ b/src/ai/ai_controller.h @@ -22,6 +22,8 @@ #ifndef M64P_AI_AI_CONTROLLER_H #define M64P_AI_AI_CONTROLLER_H +#include "api/m64p_types.h" + #include #include @@ -53,10 +55,7 @@ struct ai_controller struct ai_dma fifo[2]; unsigned int samples_format_changed; - /* external speaker output */ - void* user_data; - void (*set_audio_format)(void*,unsigned int, unsigned int); - void (*push_audio_samples)(void*,const void*,size_t); + struct m64p_audio_backend backend; struct r4300_core* r4300; struct ri_controller* ri; @@ -68,8 +67,6 @@ static uint32_t ai_reg(uint32_t address) return (address & 0xffff) >> 2; } -void set_audio_format(struct ai_controller* ai, unsigned int frequency, unsigned int bits); -void push_audio_samples(struct ai_controller* ai, const void* buffer, size_t size); void connect_ai(struct ai_controller* ai, struct r4300_core* r4300, diff --git a/src/api/audio_backend.c b/src/api/audio_backend.c new file mode 100644 index 000000000..d5b3c31e1 --- /dev/null +++ b/src/api/audio_backend.c @@ -0,0 +1,36 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - audio_backend.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2015 Bobby Smiles * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "audio_backend.h" + +#include "api/m64p_types.h" + + +/* Thin wrappers to ease usage of backend callbacks - used by ai_controller.c */ +void set_audio_format(struct m64p_audio_backend* backend, unsigned int frequency, unsigned int bits) +{ + backend->set_audio_format(backend->user_data, frequency, bits); +} + +void push_audio_samples(struct m64p_audio_backend* backend, const void* buffer, size_t size) +{ + backend->push_audio_samples(backend->user_data, buffer, size); +} diff --git a/src/api/audio_backend.h b/src/api/audio_backend.h new file mode 100644 index 000000000..23df37e5c --- /dev/null +++ b/src/api/audio_backend.h @@ -0,0 +1,38 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus - audio_backend.h * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2015 Bobby Smiles * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This file contains the definitions for the audio backend functions which + * will be called from other Core modules. + */ + +#if !defined(M64P_API_AUDIO_BACKEND_H) +#define M64P_API_AUDIO_BACKEND_H + +#include "m64p_types.h" + +#include + + +/* Thin wrappers to ease usage of backend callbacks - used by ai_controller.c */ +void set_audio_format(struct m64p_audio_backend* backend, unsigned int frequency, unsigned int bits); +void push_audio_samples(struct m64p_audio_backend* backend, const void* buffer, size_t size); + +#endif /* M64P_API_AUDIO_BACKEND_H */ diff --git a/src/api/m64p_types.h b/src/api/m64p_types.h index a8efd3578..03688f838 100644 --- a/src/api/m64p_types.h +++ b/src/api/m64p_types.h @@ -23,6 +23,8 @@ #if !defined(M64P_TYPES_H) #define M64P_TYPES_H +#include + /* ----------------------------------------- */ /* Platform-specific stuff */ /* ----------------------------------------- */ @@ -362,5 +364,40 @@ typedef struct { m64p_error (*VidExtFuncResizeWindow)(int, int); } m64p_video_extension_functions; +/* ------------------------------------------ */ +/* Structures and Types for Audio Backend API */ +/* ------------------------------------------ */ + +/* Audio backend object + * + * user_data is a pointer which will be passed as the first argument of audio backend functions. + * Frontend writers are free to use it as they please. + * + * set_audio_format function allows the audio backend to be notified of the format of incoming samples. + * 2nd parameter frequency is the sample rate of incoming samples. + * 3rd parameter bits is the sample resolution (usually 16 bits) + * + * This function should be called by the core at least one time before any call to "push_audio_samples". + * Audio backends are expected to handle gracefully eventual changes of audio format + * even after this "initial" setup. Though in practice, very few games, if any, + * changes the audio format after the initial setup. + * + * push_audio_samples function notifies the audio backend of new samples ready to be played. + * 2nd parameter buffer is a pointer to the beginning of the incoming samples. + * 3rd parameter size is the size in bytes of the buffer. + * + * Samples are in stereo interleaved format (LR LR LR ...) and their resolution (bits per channel) + * is specified by prior calls of set_audio_format. + * Audio backends are expected not to block during the servicing of this function. + * We invite audio backends writers to buffer (and maybe resample) the incoming samples + * and return control to the core as soon as possible. + */ +struct m64p_audio_backend +{ + void* user_data; + void (*set_audio_format)(void*, unsigned int, unsigned int); + void (*push_audio_samples)(void*, const void*, size_t); +}; + #endif /* define M64P_TYPES_H */ diff --git a/src/main/main.c b/src/main/main.c index 45a604640..813ffdb07 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -62,8 +62,8 @@ #include "osd/screenshot.h" #include "pi/pi_controller.h" #include "plugin/plugin.h" +#include "plugin/audio_backend_compat.h" #include "plugin/emulate_game_controller_via_input_plugin.h" -#include "plugin/emulate_speaker_via_audio_plugin.h" #include "plugin/get_time_using_C_localtime.h" #include "plugin/rumble_via_input_plugin.h" #include "r4300/r4300.h" @@ -929,9 +929,7 @@ m64p_error main_run(void) gfx.setRenderingCallback(video_plugin_render_callback); /* connect external audio sink to AI component */ - g_ai.user_data = &g_ai; - g_ai.set_audio_format = set_audio_format_via_audio_plugin; - g_ai.push_audio_samples = push_audio_samples_via_audio_plugin; + memcpy(&g_ai.backend, &AUDIO_BACKEND_COMPAT, sizeof(struct m64p_audio_backend)); /* connect external time source to AF_RTC component */ g_si.pif.af_rtc.user_data = NULL; diff --git a/src/plugin/emulate_speaker_via_audio_plugin.c b/src/plugin/audio_backend_compat.c similarity index 51% rename from src/plugin/emulate_speaker_via_audio_plugin.c rename to src/plugin/audio_backend_compat.c index 06db42dc3..07646722a 100644 --- a/src/plugin/emulate_speaker_via_audio_plugin.c +++ b/src/plugin/audio_backend_compat.c @@ -1,5 +1,5 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Mupen64plus - emulate_speaker_via_audio_plugin.c * + * Mupen64plus - audio_backend_compat.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2014 Bobby Smiles * * * @@ -19,44 +19,56 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "emulate_speaker_via_audio_plugin.h" +#include "audio_backend_compat.h" +#include "api/m64p_types.h" #include "ai/ai_controller.h" +#include "main/main.h" #include "main/rom.h" #include "plugin/plugin.h" -#include "ri/ri_controller.h" +#include #include -void set_audio_format_via_audio_plugin(void* user_data, unsigned int frequency, unsigned int bits) + +/* A fully compliant implementation is not really possible with just the zilmar spec. + * We assume bits == 16 (assumption compatible with audio-sdl plugin implementation) + */ +static void set_audio_format_via_audio_plugin(void* user_data, unsigned int frequency, unsigned int bits) { - /* not really implementable with just the zilmar spec. - * Try a best effort approach - */ - struct ai_controller* ai = (struct ai_controller*)user_data; - uint32_t saved_ai_dacrate = ai->regs[AI_DACRATE_REG]; - - ai->regs[AI_DACRATE_REG] = ROM_PARAMS.aidacrate / frequency - 1; + /* save registers values */ + uint32_t saved_ai_dacrate = g_ai.regs[AI_DACRATE_REG]; + /* notify plugin of the new frequency (can't do the same for bits) */ + g_ai.regs[AI_DACRATE_REG] = (ROM_PARAMS.aidacrate / frequency) - 1; audio.aiDacrateChanged(ROM_PARAMS.systemtype); - ai->regs[AI_DACRATE_REG] = saved_ai_dacrate; + /* restore original registers values */ + g_ai.regs[AI_DACRATE_REG] = saved_ai_dacrate; } -void push_audio_samples_via_audio_plugin(void* user_data, const void* buffer, size_t size) +/* Abuse core & audio plugin implementation details to obtain the desired effect. */ +static void push_audio_samples_via_audio_plugin(void* user_data, const void* buffer, size_t size) { - /* abuse core & audio plugin implementation to approximate desired effect */ - struct ai_controller* ai = (struct ai_controller*)user_data; - uint32_t saved_ai_length = ai->regs[AI_LEN_REG]; - uint32_t saved_ai_dram = ai->regs[AI_DRAM_ADDR_REG]; - - /* exploit the fact that buffer points in g_rdram to retreive dram_addr_reg value */ - ai->regs[AI_DRAM_ADDR_REG] = (uint8_t*)buffer - (uint8_t*)ai->ri->rdram.dram; - ai->regs[AI_LEN_REG] = size; + /* save registers values */ + uint32_t saved_ai_length = g_ai.regs[AI_LEN_REG]; + uint32_t saved_ai_dram = g_ai.regs[AI_DRAM_ADDR_REG]; + /* notify plugin of new samples to play. + * Exploit the fact that buffer points in g_rdram to retreive dram_addr_reg value */ + g_ai.regs[AI_DRAM_ADDR_REG] = (uint8_t*)buffer - (uint8_t*)g_rdram; + g_ai.regs[AI_LEN_REG] = size; audio.aiLenChanged(); - ai->regs[AI_LEN_REG] = saved_ai_length; - ai->regs[AI_DRAM_ADDR_REG] = saved_ai_dram; + /* restore original registers vlaues */ + g_ai.regs[AI_LEN_REG] = saved_ai_length; + g_ai.regs[AI_DRAM_ADDR_REG] = saved_ai_dram; } + +const struct m64p_audio_backend AUDIO_BACKEND_COMPAT = +{ + NULL, + set_audio_format_via_audio_plugin, + push_audio_samples_via_audio_plugin +}; diff --git a/src/plugin/emulate_speaker_via_audio_plugin.h b/src/plugin/audio_backend_compat.h similarity index 79% rename from src/plugin/emulate_speaker_via_audio_plugin.h rename to src/plugin/audio_backend_compat.h index 5156ecd06..45e6ef1ea 100644 --- a/src/plugin/emulate_speaker_via_audio_plugin.h +++ b/src/plugin/audio_backend_compat.h @@ -1,5 +1,5 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Mupen64plus - emulate_speaker_via_audio_plugin.h * + * Mupen64plus - audio_backend_compat.h * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2014 Bobby Smiles * * * @@ -19,12 +19,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef M64P_PLUGIN_EMULATE_SPEAKER_VIA_AUDIO_PLUGIN_H -#define M64P_PLUGIN_EMULATE_SPEAKER_VIA_AUDIO_PLUGIN_H +#ifndef M64P_PLUGIN_AUDIO_BACKEND_COMPAT_H +#define M64P_PLUGIN_AUDIO_BACKEND_COMPAT_H -#include +#include "api/m64p_types.h" -void set_audio_format_via_audio_plugin(void* user_data, unsigned int frequency, unsigned int bits); -void push_audio_samples_via_audio_plugin(void* user_data, const void* buffer, size_t size); +/* Audio backend compatible with m64p audio plugins */ +extern const struct m64p_audio_backend AUDIO_BACKEND_COMPAT; #endif