Path: blob/master/libmupen64plus/mupen64plus-audio-bkm/main.c
2 views
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1* Mupen64plus-bkm-audio - main.c *2* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *3* Editet 2013 null_ptr Completely rewritten to suit custom needs *4* Copyright (C) 2007-2009 Richard Goedeken *5* Copyright (C) 2007-2008 Ebenblues *6* Copyright (C) 2003 JttL *7* Copyright (C) 2002 Hacktarux *8* *9* This program is free software; you can redistribute it and/or modify *10* it under the terms of the GNU General Public License as published by *11* the Free Software Foundation; either version 2 of the License, or *12* (at your option) any later version. *13* *14* This program is distributed in the hope that it will be useful, *15* but WITHOUT ANY WARRANTY; without even the implied warranty of *16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *17* GNU General Public License for more details. *18* *19* You should have received a copy of the GNU General Public License *20* along with this program; if not, write to the *21* Free Software Foundation, Inc., *22* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *23* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2425#include <stdio.h>26#include <stdlib.h>27#include <string.h>2829#define M64P_PLUGIN_PROTOTYPES 130#include "m64p_types.h"31#include "m64p_plugin.h"32#include "m64p_common.h"33#include "m64p_config.h"3435#include "main.h"36#include "osal_dynamiclib.h"3738/* This sets default frequency what is used if rom doesn't want to change it.39Probably only game that needs this is Zelda: Ocarina Of Time Master Quest40*NOTICE* We should try to find out why Demos' frequencies are always wrong41They tend to rely on a default frequency, apparently, never the same one ;)*/42#define DEFAULT_FREQUENCY 3360043#define DEFAULT_BUFFER_SIZE 124804445/* number of bytes per sample */46#define N64_SAMPLE_BYTES 44748/* local variables */49static void (*l_DebugCallback)(void *, int, const char *) = NULL;50static void *l_DebugCallContext = NULL;51static int l_PluginInit = 0;5253/* Read header for type definition */54static AUDIO_INFO AudioInfo;55/* Audio frequency, this is usually obtained from the game, but for compatibility we set default value */56static int GameFreq = DEFAULT_FREQUENCY;5758/* Audio buffer */59static char* audioBuffer = NULL;60static size_t bufferBack = 0;61static size_t bufferSize = 0;6263// Prototype of local functions64static void SetSamplingRate(int freq);65static void SetBufferSize(size_t size);6667static int critical_failure = 0;6869/* Global functions */70static void DebugMessage(int level, const char *message, ...)71{72char msgbuf[1024];73va_list args;7475if (l_DebugCallback == NULL)76return;7778va_start(args, message);79vsprintf(msgbuf, message, args);8081(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);8283va_end(args);84}8586#pragma region (De-)Initialization87/* Mupen64Plus plugin functions */88EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,89void (*DebugCallback)(void *, int, const char *))90{91ptr_CoreGetAPIVersions CoreAPIVersionFunc;9293int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;9495if (l_PluginInit)96return M64ERR_ALREADY_INIT;9798/* first thing is to set the callback function for debug info */99l_DebugCallback = DebugCallback;100l_DebugCallContext = Context;101102/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */103CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");104if (CoreAPIVersionFunc == NULL)105{106DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");107return M64ERR_INCOMPATIBLE;108}109110(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);111if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))112{113DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",114VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));115return M64ERR_INCOMPATIBLE;116}117118l_PluginInit = 1;119return M64ERR_SUCCESS;120}121122EXPORT m64p_error CALL PluginShutdown(void)123{124if (!l_PluginInit)125return M64ERR_NOT_INIT;126127/* reset some local variables */128l_DebugCallback = NULL;129l_DebugCallContext = NULL;130131l_PluginInit = 0;132return M64ERR_SUCCESS;133}134135EXPORT int CALL RomOpen(void)136{137if (!l_PluginInit)138return 0;139140SetSamplingRate(GameFreq);141SetBufferSize(DEFAULT_BUFFER_SIZE);142return 1;143}144145EXPORT void CALL RomClosed( void )146{147if (!l_PluginInit)148return;149if (critical_failure == 1)150return;151152// Delete the buffer, as we are done producing sound153if (audioBuffer != NULL)154{155bufferSize = 0;156bufferBack = 0;157free(audioBuffer);158audioBuffer = NULL;159}160}161162EXPORT int CALL InitiateAudio( AUDIO_INFO Audio_Info )163{164if (!l_PluginInit)165return 0;166167AudioInfo = Audio_Info;168return 1;169}170171static void SetBufferSize(size_t size)172{173char* oldBuffer = audioBuffer;174audioBuffer = (char*)malloc(size);175if(audioBuffer != NULL)176{177memcpy(audioBuffer, oldBuffer, min(size, bufferBack));178free(oldBuffer);179}180bufferSize = size;181bufferBack = min(size, bufferBack);182}183#pragma endregion184185#pragma region Pluginversion186EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)187{188/* set version info */189if (PluginType != NULL)190*PluginType = M64PLUGIN_AUDIO;191192if (PluginVersion != NULL)193*PluginVersion = BKM_AUDIO_PLUGIN_VERSION;194195if (APIVersion != NULL)196*APIVersion = AUDIO_PLUGIN_API_VERSION;197198if (PluginNamePtr != NULL)199*PluginNamePtr = "Mupen64Plus BKM Audio Plugin for Bizhawk";200201if (Capabilities != NULL)202{203*Capabilities = 0;204}205206return M64ERR_SUCCESS;207}208#pragma endregion209210#pragma region Handle audio211/* --- Called when sampling rate changes --- */212EXPORT void CALL AiDacrateChanged( int SystemType )213{214int f = GameFreq;215216if (!l_PluginInit)217return;218219if (*AudioInfo.AI_DACRATE_REG == 0)220{221f = DEFAULT_FREQUENCY;222}223else224{225switch (SystemType)226{227case SYSTEM_NTSC:228f = 48681812 / (*AudioInfo.AI_DACRATE_REG + 1);229break;230case SYSTEM_PAL:231f = 49656530 / (*AudioInfo.AI_DACRATE_REG + 1);232break;233case SYSTEM_MPAL:234f = 48628316 / (*AudioInfo.AI_DACRATE_REG + 1);235break;236}237}238SetSamplingRate(f);239}240241/* --- Called when length of n64 audio buffer changes --- */242/* --- i.e. new audio data in buffer --- */243EXPORT void CALL AiLenChanged( void )244{245unsigned int LenReg;246unsigned char *p;247248if (critical_failure == 1)249return;250if (!l_PluginInit)251return;252253LenReg = *AudioInfo.AI_LEN_REG;254p = AudioInfo.RDRAM + (*AudioInfo.AI_DRAM_ADDR_REG & 0xFFFFFF);255256if (bufferBack + LenReg < bufferSize)257{258unsigned int i;259260for ( i = 0 ; i < LenReg ; i += 4 )261{262// Left channel263audioBuffer[ bufferBack + i ] = p[ i + 2 ];264audioBuffer[ bufferBack + i + 1 ] = p[ i + 3 ];265266// Right channel267audioBuffer[ bufferBack + i + 2 ] = p[ i ];268audioBuffer[ bufferBack + i + 3 ] = p[ i + 1 ];269}270bufferBack += i;271272}273else274{275DebugMessage(M64MSG_WARNING, "AiLenChanged(): Audio buffer overflow.");276}277}278279static void SetSamplingRate(int freq)280{281GameFreq = freq; // This is important for the sync282}283#pragma endregion284285#pragma region Unused methods286/* ----------------------------------------------------------------------287* ------------ STUBS. WE DO NOT USE THESE API FUNCTIONS ---------------288* -------- MUPEN EXPECTS THEM AND FAILS IF THEY DON'T EXIST ------------289* ---------------------------------------------------------------------- */290EXPORT void CALL ProcessAList(void)291{292}293294EXPORT void CALL SetSpeedFactor(int percentage)295{296}297298static int VolumeGetUnmutedLevel(void)299{300return 100;301}302303EXPORT void CALL VolumeMute(void)304{305}306307EXPORT void CALL VolumeUp(void)308{309}310311EXPORT void CALL VolumeDown(void)312{313}314315EXPORT int CALL VolumeGetLevel(void)316{317return 100;318}319320EXPORT void CALL VolumeSetLevel(int level)321{322}323324EXPORT const char * CALL VolumeGetString(void)325{326return "100%";327}328/* ----------------------------------------------------------------------329* --------------------------- STUBS END --------------------------------330* ---------------------------------------------------------------------- */331#pragma endregion332333#pragma region Buffer export334/* --- Moves content of audio buffer to destination --- */335EXPORT void CALL ReadAudioBuffer(short* dest)336{337memcpy(dest, audioBuffer, bufferBack);338bufferBack = 0;339}340/* --- Returns number of shorts of internal data --- */341EXPORT int CALL GetBufferSize()342{343return max(bufferBack/2, 0);344}345346/* --- Returns current sampling rate --- */347EXPORT int CALL GetAudioRate()348{349return GameFreq;350}351#pragma endregion352353