Skip to content

Commit

Permalink
Introduce the m64p_audio_backend structure.
Browse files Browse the repository at this point in the history
  • Loading branch information
bsmiles32 committed Mar 7, 2015
1 parent b07829d commit 9830461
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 55 deletions.
34 changes: 34 additions & 0 deletions doc/emuwiki-api-doc/Mupen64Plus-v2.0-headers.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
6 changes: 5 additions & 1 deletion projects/VisualStudio2013/mupen64plus-core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ItemGroup>
<ClCompile Include="..\..\src\ai\ai_controller.c" />
<ClCompile Include="..\..\src\api\callbacks.c" />
<ClCompile Include="..\..\src\api\audio_backend.c" />
<ClCompile Include="..\..\src\api\common.c" />
<ClCompile Include="..\..\src\api\config.c" />
<ClCompile Include="..\..\src\api\debugger.c" />
Expand Down Expand Up @@ -70,6 +71,7 @@
<ClCompile Include="..\..\src\pi\flashram.c" />
<ClCompile Include="..\..\src\pi\pi_controller.c" />
<ClCompile Include="..\..\src\pi\sram.c" />
<ClCompile Include="..\..\src\plugin\audio_backend_compat.c" />
<ClCompile Include="..\..\src\plugin\dummy_audio.c" />
<ClCompile Include="..\..\src\plugin\dummy_input.c" />
<ClCompile Include="..\..\src\plugin\dummy_rsp.c" />
Expand Down Expand Up @@ -285,6 +287,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ai\ai_controller.h" />
<ClInclude Include="..\..\src\api\audio_backend.h" />
<ClInclude Include="..\..\src\api\callbacks.h" />
<ClInclude Include="..\..\src\api\config.h" />
<ClInclude Include="..\..\src\api\debugger.h" />
Expand Down Expand Up @@ -335,6 +338,7 @@
<ClInclude Include="..\..\src\pi\flashram.h" />
<ClInclude Include="..\..\src\pi\pi_controller.h" />
<ClInclude Include="..\..\src\pi\sram.h" />
<ClInclude Include="..\..\src\plugin\audio_backend_compat.h" />
<ClInclude Include="..\..\src\plugin\dummy_audio.h" />
<ClInclude Include="..\..\src\plugin\dummy_input.h" />
<ClInclude Include="..\..\src\plugin\dummy_rsp.h" />
Expand Down Expand Up @@ -647,4 +651,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
3 changes: 2 additions & 1 deletion projects/unix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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 \
Expand Down
18 changes: 4 additions & 14 deletions src/ai/ai_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 3 additions & 6 deletions src/ai/ai_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#ifndef M64P_AI_AI_CONTROLLER_H
#define M64P_AI_AI_CONTROLLER_H

#include "api/m64p_types.h"

#include <stddef.h>
#include <stdint.h>

Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down
36 changes: 36 additions & 0 deletions src/api/audio_backend.c
Original file line number Diff line number Diff line change
@@ -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);
}
38 changes: 38 additions & 0 deletions src/api/audio_backend.h
Original file line number Diff line number Diff line change
@@ -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 <stddef.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);
void push_audio_samples(struct m64p_audio_backend* backend, const void* buffer, size_t size);

#endif /* M64P_API_AUDIO_BACKEND_H */
37 changes: 37 additions & 0 deletions src/api/m64p_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#if !defined(M64P_TYPES_H)
#define M64P_TYPES_H

#include <stddef.h>

/* ----------------------------------------- */
/* Platform-specific stuff */
/* ----------------------------------------- */
Expand Down Expand Up @@ -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 */

6 changes: 2 additions & 4 deletions src/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 *
* *
Expand All @@ -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 <stddef.h>
#include <stdint.h>

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
};
Loading

0 comments on commit 9830461

Please sign in to comment.