m64p: Created a new audio plugin that saves the samples in a buffer for bizhawk to retrieve. Also added some miscellaneous svn:ignores
N64: Hooked up the new audio plugin, but it doesn't sound exactly right.
This commit is contained in:
parent
160de71206
commit
7f7b9eac1f
|
@ -36,8 +36,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|||
public int BufferHeight { get { return 480; } }
|
||||
public int BackgroundColor { get { return 0; } }
|
||||
|
||||
short[] m64pAudioBuffer;
|
||||
public ISoundProvider SoundProvider { get { return this; } }
|
||||
public void GetSamples(short[] samples) { }
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
if (m64pAudioBuffer.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < samples.Length / 2; i++)
|
||||
{
|
||||
samples[i * 2] = m64pAudioBuffer[(int)((((double)m64pAudioBuffer.Length / 2) / (double)(samples.Length / 2)) * i) * 2];
|
||||
samples[i * 2 + 1] = m64pAudioBuffer[(int)((((double)m64pAudioBuffer.Length / 2) / (double)(samples.Length / 2)) * i) * 2 + 1]; ;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void DiscardSamples() { }
|
||||
public int MaxVolume { get; set; }
|
||||
public ISyncSoundProvider SyncSoundProvider { get { return null; } }
|
||||
|
@ -202,12 +213,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|||
private delegate void ReadScreen2(byte[] framebuffer, ref int width, ref int height, int buffer);
|
||||
ReadScreen2 GFXReadScreen2;
|
||||
|
||||
// Audio plugin specific
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate int GetBufferSize();
|
||||
GetBufferSize AudGetBufferSize;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void ReadAudioBuffer(short[] dest);
|
||||
ReadAudioBuffer AudReadAudioBuffer;
|
||||
|
||||
// This has the same calling pattern for all the plugins
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate m64p_error PluginStartup(IntPtr CoreHandle, string Context, DebugCallback DebugCallback);
|
||||
|
||||
PluginStartup GfxPluginStartup;
|
||||
PluginStartup RspPluginStartup;
|
||||
PluginStartup AudPluginStartup;
|
||||
|
||||
public delegate void DebugCallback(IntPtr Context, int level, string Message);
|
||||
|
||||
|
@ -227,12 +248,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|||
VICallback m64pVICallback;
|
||||
public void FrameComplete()
|
||||
{
|
||||
int m64pAudioBufferSize = AudGetBufferSize();
|
||||
m64pAudioBuffer = new short[m64pAudioBufferSize];
|
||||
if (m64pAudioBufferSize > 0)
|
||||
{
|
||||
AudReadAudioBuffer(m64pAudioBuffer);
|
||||
}
|
||||
m64pFrameComplete = true;
|
||||
}
|
||||
|
||||
IntPtr CoreDll;
|
||||
IntPtr GfxDll;
|
||||
IntPtr RspDll;
|
||||
IntPtr AudDll;
|
||||
|
||||
Thread m64pEmulator;
|
||||
|
||||
|
@ -248,6 +276,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|||
CoreDll = LoadLibrary("mupen64plus.dll");
|
||||
GfxDll = LoadLibrary("mupen64plus-video-rice.dll");
|
||||
RspDll = LoadLibrary("mupen64plus-rsp-hle.dll");
|
||||
AudDll = LoadLibrary("mupen64plus-audio-bkm.dll");
|
||||
|
||||
m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreStartup"), typeof(CoreStartup));
|
||||
m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(GetProcAddress(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray));
|
||||
|
@ -260,6 +289,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|||
GfxPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "PluginStartup"), typeof(PluginStartup));
|
||||
GFXReadScreen2 = (ReadScreen2)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2));
|
||||
|
||||
AudPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "PluginStartup"), typeof(PluginStartup));
|
||||
AudGetBufferSize = (GetBufferSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetBufferSize"), typeof(GetBufferSize));
|
||||
AudReadAudioBuffer = (ReadAudioBuffer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "ReadAudioBuffer"), typeof(ReadAudioBuffer));
|
||||
|
||||
RspPluginStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(GetProcAddress(RspDll, "PluginStartup"), typeof(PluginStartup));
|
||||
|
||||
// Set up the core
|
||||
|
@ -271,7 +304,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.N64
|
|||
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_GFX, GfxDll);
|
||||
|
||||
// Set up a null audio plugin
|
||||
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO, IntPtr.Zero);
|
||||
result = AudPluginStartup(CoreDll, "Audio", (IntPtr foo, int level, string Message) => { Console.WriteLine(Message); });
|
||||
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_AUDIO, AudDll);
|
||||
|
||||
// Set up a null input plugin
|
||||
result = m64pCoreAttachPlugin(m64p_plugin_type.M64PLUGIN_INPUT, IntPtr.Zero);
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,748 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-sdl-audio - main.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2007-2009 Richard Goedeken *
|
||||
* Copyright (C) 2007-2008 Ebenblues *
|
||||
* Copyright (C) 2003 JttL *
|
||||
* Copyright (C) 2002 Hacktarux *
|
||||
* *
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_SRC
|
||||
#include <samplerate.h>
|
||||
#endif
|
||||
#ifdef USE_SPEEX
|
||||
#include <speex/speex_resampler.h>
|
||||
#endif
|
||||
|
||||
#define M64P_PLUGIN_PROTOTYPES 1
|
||||
#include "m64p_types.h"
|
||||
#include "m64p_plugin.h"
|
||||
#include "m64p_common.h"
|
||||
#include "m64p_config.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "osal_dynamiclib.h"
|
||||
|
||||
/* Default start-time size of primary buffer (in equivalent output samples).
|
||||
This is the buffer where audio is loaded after it's extracted from n64's memory.
|
||||
This value must be larger than PRIMARY_BUFFER_TARGET */
|
||||
#define PRIMARY_BUFFER_SIZE 16384
|
||||
|
||||
/* this is the buffer fullness level (in equivalent output samples) which is targeted
|
||||
for the primary audio buffer (by inserting delays) each time data is received from
|
||||
the running N64 program. This value must be larger than the SECONDARY_BUFFER_SIZE.
|
||||
Decreasing this value will reduce audio latency but requires a faster PC to avoid
|
||||
choppiness. Increasing this will increase audio latency but reduce the chance of
|
||||
drop-outs. The default value 10240 gives a 232ms maximum A/V delay at 44.1khz */
|
||||
#define PRIMARY_BUFFER_TARGET 10240
|
||||
|
||||
/* Size of secondary buffer, in output samples. This is the requested size of SDL's
|
||||
hardware buffer, and the size of the mix buffer for doing SDL volume control. The
|
||||
SDL documentation states that this should be a power of two between 512 and 8192. */
|
||||
#define SECONDARY_BUFFER_SIZE 2048
|
||||
|
||||
/* This sets default frequency what is used if rom doesn't want to change it.
|
||||
Probably only game that needs this is Zelda: Ocarina Of Time Master Quest
|
||||
*NOTICE* We should try to find out why Demos' frequencies are always wrong
|
||||
They tend to rely on a default frequency, apparently, never the same one ;)*/
|
||||
#define DEFAULT_FREQUENCY 33600
|
||||
|
||||
/* number of bytes per sample */
|
||||
#define N64_SAMPLE_BYTES 4
|
||||
#define SDL_SAMPLE_BYTES 4
|
||||
|
||||
/* volume mixer types */
|
||||
#define VOLUME_TYPE_SDL 1
|
||||
#define VOLUME_TYPE_OSS 2
|
||||
|
||||
/* local variables */
|
||||
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
|
||||
static void *l_DebugCallContext = NULL;
|
||||
static int l_PluginInit = 0;
|
||||
static m64p_handle l_ConfigAudio;
|
||||
|
||||
enum resampler_type {
|
||||
RESAMPLER_TRIVIAL,
|
||||
#ifdef USE_SRC
|
||||
RESAMPLER_SRC,
|
||||
#endif
|
||||
#ifdef USE_SPEEX
|
||||
RESAMPLER_SPEEX,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Read header for type definition */
|
||||
static AUDIO_INFO AudioInfo;
|
||||
/* Pointer to the primary audio buffer */
|
||||
static unsigned char *primaryBuffer = NULL;
|
||||
static unsigned char *mixBuffer = NULL;
|
||||
static unsigned int primaryBufferBytes = 0;
|
||||
/* Position in buffer array where next audio chunk should be placed */
|
||||
static unsigned int buffer_pos = 0;
|
||||
/* Audio frequency, this is usually obtained from the game, but for compatibility we set default value */
|
||||
static int GameFreq = DEFAULT_FREQUENCY;
|
||||
/* timestamp for the last time that our audio callback was called */
|
||||
static unsigned int last_callback_ticks = 0;
|
||||
/* SpeedFactor is used to increase/decrease game playback speed */
|
||||
static unsigned int speed_factor = 100;
|
||||
// If this is true then left and right channels are swapped */
|
||||
static int SwapChannels = 0;
|
||||
// Size of Primary audio buffer in equivalent output samples
|
||||
static unsigned int PrimaryBufferSize = PRIMARY_BUFFER_SIZE;
|
||||
// Fullness level target for Primary audio buffer, in equivalent output samples
|
||||
static unsigned int PrimaryBufferTarget = PRIMARY_BUFFER_TARGET;
|
||||
// Size of Secondary audio buffer in output samples
|
||||
static unsigned int SecondaryBufferSize = SECONDARY_BUFFER_SIZE;
|
||||
// Resample type
|
||||
static enum resampler_type Resample = RESAMPLER_TRIVIAL;
|
||||
// Resampler specific quality
|
||||
static int ResampleQuality = 3;
|
||||
// volume to scale the audio by, range of 0..100
|
||||
// if muted, this holds the volume when not muted
|
||||
static int VolPercent = 80;
|
||||
// how much percent to increment/decrement volume by
|
||||
static int VolDelta = 5;
|
||||
// Muted or not
|
||||
static int VolIsMuted = 0;
|
||||
//which type of volume control to use
|
||||
static int VolumeControlType = VOLUME_TYPE_SDL;
|
||||
|
||||
static int OutputFreq;
|
||||
|
||||
// Prototype of local functions
|
||||
static void InitializeAudio(int freq);
|
||||
static void ReadConfig(void);
|
||||
static void InitializeSDL(void);
|
||||
|
||||
static int critical_failure = 0;
|
||||
|
||||
/* definitions of pointers to Core config functions */
|
||||
ptr_ConfigOpenSection ConfigOpenSection = NULL;
|
||||
ptr_ConfigDeleteSection ConfigDeleteSection = NULL;
|
||||
ptr_ConfigSaveSection ConfigSaveSection = NULL;
|
||||
ptr_ConfigSetParameter ConfigSetParameter = NULL;
|
||||
ptr_ConfigGetParameter ConfigGetParameter = NULL;
|
||||
ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
|
||||
ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
|
||||
ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
|
||||
ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
|
||||
ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
|
||||
ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
|
||||
ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
|
||||
ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
|
||||
ptr_ConfigGetParamString ConfigGetParamString = NULL;
|
||||
|
||||
/* Global functions */
|
||||
static void DebugMessage(int level, const char *message, ...)
|
||||
{
|
||||
char msgbuf[1024];
|
||||
va_list args;
|
||||
|
||||
if (l_DebugCallback == NULL)
|
||||
return;
|
||||
|
||||
va_start(args, message);
|
||||
vsprintf(msgbuf, message, args);
|
||||
|
||||
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Mupen64Plus plugin functions */
|
||||
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
|
||||
void (*DebugCallback)(void *, int, const char *))
|
||||
{
|
||||
ptr_CoreGetAPIVersions CoreAPIVersionFunc;
|
||||
|
||||
int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion, bSaveConfig;
|
||||
float fConfigParamsVersion = 0.0f;
|
||||
|
||||
if (l_PluginInit)
|
||||
return M64ERR_ALREADY_INIT;
|
||||
|
||||
/* first thing is to set the callback function for debug info */
|
||||
l_DebugCallback = DebugCallback;
|
||||
l_DebugCallContext = Context;
|
||||
|
||||
/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
|
||||
CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
|
||||
if (CoreAPIVersionFunc == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
|
||||
return M64ERR_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
|
||||
if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
|
||||
VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
|
||||
return M64ERR_INCOMPATIBLE;
|
||||
}
|
||||
|
||||
/* Get the core config function pointers from the library handle */
|
||||
ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
|
||||
ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection");
|
||||
ConfigSaveSection = (ptr_ConfigSaveSection) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveSection");
|
||||
ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
|
||||
ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
|
||||
ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
|
||||
ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
|
||||
ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
|
||||
ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
|
||||
ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
|
||||
ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
|
||||
ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
|
||||
ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
|
||||
|
||||
if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSetParameter || !ConfigGetParameter ||
|
||||
!ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
|
||||
!ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString)
|
||||
return M64ERR_INCOMPATIBLE;
|
||||
|
||||
/* ConfigSaveSection was added in Config API v2.1.0 */
|
||||
if (ConfigAPIVersion >= 0x020100 && !ConfigSaveSection)
|
||||
return M64ERR_INCOMPATIBLE;
|
||||
|
||||
/* get a configuration section handle */
|
||||
if (ConfigOpenSection("Audio-SDL", &l_ConfigAudio) != M64ERR_SUCCESS)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Couldn't open config section 'Audio-SDL'");
|
||||
return M64ERR_INPUT_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* check the section version number */
|
||||
bSaveConfig = 0;
|
||||
if (ConfigGetParameter(l_ConfigAudio, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "No version number in 'Audio-SDL' config section. Setting defaults.");
|
||||
ConfigDeleteSection("Audio-SDL");
|
||||
ConfigOpenSection("Audio-SDL", &l_ConfigAudio);
|
||||
bSaveConfig = 1;
|
||||
}
|
||||
else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Audio-SDL' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
|
||||
ConfigDeleteSection("Audio-SDL");
|
||||
ConfigOpenSection("Audio-SDL", &l_ConfigAudio);
|
||||
bSaveConfig = 1;
|
||||
}
|
||||
else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
|
||||
{
|
||||
/* handle upgrades */
|
||||
float fVersion = CONFIG_PARAM_VERSION;
|
||||
ConfigSetParameter(l_ConfigAudio, "Version", M64TYPE_FLOAT, &fVersion);
|
||||
DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Audio-SDL' config section to %.2f", fVersion);
|
||||
bSaveConfig = 1;
|
||||
}
|
||||
|
||||
/* set the default values for this plugin */
|
||||
ConfigSetDefaultFloat(l_ConfigAudio, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus SDL Audio Plugin config parameter version number");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "DEFAULT_FREQUENCY", DEFAULT_FREQUENCY, "Frequency which is used if rom doesn't want to change it");
|
||||
ConfigSetDefaultBool(l_ConfigAudio, "SWAP_CHANNELS", 0, "Swaps left and right channels");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "PRIMARY_BUFFER_SIZE", PRIMARY_BUFFER_SIZE, "Size of primary buffer in output samples. This is where audio is loaded after it's extracted from n64's memory.");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "PRIMARY_BUFFER_TARGET", PRIMARY_BUFFER_TARGET, "Fullness level target for Primary audio buffer, in equivalent output samples");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "SECONDARY_BUFFER_SIZE", SECONDARY_BUFFER_SIZE, "Size of secondary buffer in output samples. This is SDL's hardware buffer.");
|
||||
ConfigSetDefaultString(l_ConfigAudio, "RESAMPLE", "trivial", "Audio resampling algorithm. src-sinc-best-quality, src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold, src-linear, speex-fixed-{10-0}, trivial");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "VOLUME_CONTROL_TYPE", VOLUME_TYPE_SDL, "Volume control type: 1 = SDL (only affects Mupen64Plus output) 2 = OSS mixer (adjusts master PC volume)");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "VOLUME_ADJUST", 5, "Percentage change each time the volume is increased or decreased");
|
||||
ConfigSetDefaultInt(l_ConfigAudio, "VOLUME_DEFAULT", 80, "Default volume when a game is started. Only used if VOLUME_CONTROL_TYPE is 1");
|
||||
|
||||
if (bSaveConfig && ConfigAPIVersion >= 0x020100)
|
||||
ConfigSaveSection("Audio-SDL");
|
||||
|
||||
l_PluginInit = 1;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT m64p_error CALL PluginShutdown(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return M64ERR_NOT_INIT;
|
||||
|
||||
/* reset some local variables */
|
||||
l_DebugCallback = NULL;
|
||||
l_DebugCallContext = NULL;
|
||||
|
||||
l_PluginInit = 0;
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
|
||||
{
|
||||
/* set version info */
|
||||
if (PluginType != NULL)
|
||||
*PluginType = M64PLUGIN_AUDIO;
|
||||
|
||||
if (PluginVersion != NULL)
|
||||
*PluginVersion = SDL_AUDIO_PLUGIN_VERSION;
|
||||
|
||||
if (APIVersion != NULL)
|
||||
*APIVersion = AUDIO_PLUGIN_API_VERSION;
|
||||
|
||||
if (PluginNamePtr != NULL)
|
||||
*PluginNamePtr = "Mupen64Plus SDL Audio Plugin";
|
||||
|
||||
if (Capabilities != NULL)
|
||||
{
|
||||
*Capabilities = 0;
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/* ----------- Audio Functions ------------- */
|
||||
EXPORT void CALL AiDacrateChanged( int SystemType )
|
||||
{
|
||||
int f = GameFreq;
|
||||
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
switch (SystemType)
|
||||
{
|
||||
case SYSTEM_NTSC:
|
||||
f = 48681812 / (*AudioInfo.AI_DACRATE_REG + 1);
|
||||
break;
|
||||
case SYSTEM_PAL:
|
||||
f = 49656530 / (*AudioInfo.AI_DACRATE_REG + 1);
|
||||
break;
|
||||
case SYSTEM_MPAL:
|
||||
f = 48628316 / (*AudioInfo.AI_DACRATE_REG + 1);
|
||||
break;
|
||||
}
|
||||
InitializeAudio(f);
|
||||
}
|
||||
|
||||
|
||||
EXPORT void CALL AiLenChanged( void )
|
||||
{
|
||||
unsigned int LenReg;
|
||||
unsigned char *p;
|
||||
|
||||
if (critical_failure == 1)
|
||||
return;
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
LenReg = *AudioInfo.AI_LEN_REG;
|
||||
p = AudioInfo.RDRAM + (*AudioInfo.AI_DRAM_ADDR_REG & 0xFFFFFF);
|
||||
|
||||
if (buffer_pos + LenReg < primaryBufferBytes)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for ( i = 0 ; i < LenReg ; i += 4 )
|
||||
{
|
||||
|
||||
if(SwapChannels == 0)
|
||||
{
|
||||
// Left channel
|
||||
primaryBuffer[ buffer_pos + i ] = p[ i + 2 ];
|
||||
primaryBuffer[ buffer_pos + i + 1 ] = p[ i + 3 ];
|
||||
|
||||
// Right channel
|
||||
primaryBuffer[ buffer_pos + i + 2 ] = p[ i ];
|
||||
primaryBuffer[ buffer_pos + i + 3 ] = p[ i + 1 ];
|
||||
} else {
|
||||
// Left channel
|
||||
primaryBuffer[ buffer_pos + i ] = p[ i ];
|
||||
primaryBuffer[ buffer_pos + i + 1 ] = p[ i + 1 ];
|
||||
|
||||
// Right channel
|
||||
primaryBuffer[ buffer_pos + i + 2 ] = p[ i + 2];
|
||||
primaryBuffer[ buffer_pos + i + 3 ] = p[ i + 3 ];
|
||||
}
|
||||
}
|
||||
buffer_pos += i;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "AiLenChanged(): Audio buffer overflow.");
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT int CALL InitiateAudio( AUDIO_INFO Audio_Info )
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return 0;
|
||||
|
||||
|
||||
AudioInfo = Audio_Info;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int underrun_count = 0;
|
||||
|
||||
#ifdef USE_SRC
|
||||
static float *_src = NULL;
|
||||
static unsigned int _src_len = 0;
|
||||
static float *_dest = NULL;
|
||||
static unsigned int _dest_len = 0;
|
||||
static int error;
|
||||
static SRC_STATE *src_state;
|
||||
static SRC_DATA src_data;
|
||||
#endif
|
||||
#ifdef USE_SPEEX
|
||||
SpeexResamplerState* spx_state = NULL;
|
||||
static int error;
|
||||
#endif
|
||||
|
||||
EXPORT int CALL RomOpen(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return 0;
|
||||
|
||||
ReadConfig();
|
||||
InitializeAudio(GameFreq);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void CreatePrimaryBuffer(void)
|
||||
{
|
||||
unsigned int newPrimaryBytes = (unsigned int) ((long long) PrimaryBufferSize * GameFreq * speed_factor /
|
||||
(OutputFreq * 100)) * N64_SAMPLE_BYTES;
|
||||
if (primaryBuffer == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_VERBOSE, "Allocating memory for audio buffer: %i bytes.", newPrimaryBytes);
|
||||
primaryBuffer = (unsigned char*) malloc(newPrimaryBytes);
|
||||
memset(primaryBuffer, 0, newPrimaryBytes);
|
||||
primaryBufferBytes = newPrimaryBytes;
|
||||
}
|
||||
else if (newPrimaryBytes > primaryBufferBytes) /* primary buffer only grows; there's no point in shrinking it */
|
||||
{
|
||||
unsigned char *newPrimaryBuffer = (unsigned char*) malloc(newPrimaryBytes);
|
||||
unsigned char *oldPrimaryBuffer = primaryBuffer;
|
||||
memcpy(newPrimaryBuffer, oldPrimaryBuffer, primaryBufferBytes);
|
||||
memset(newPrimaryBuffer + primaryBufferBytes, 0, newPrimaryBytes - primaryBufferBytes);
|
||||
primaryBuffer = newPrimaryBuffer;
|
||||
primaryBufferBytes = newPrimaryBytes;
|
||||
free(oldPrimaryBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void InitializeAudio(int freq)
|
||||
{
|
||||
GameFreq = freq; // This is important for the sync
|
||||
|
||||
if(freq < 11025) OutputFreq = 11025;
|
||||
else if(freq < 22050) OutputFreq = 22050;
|
||||
else OutputFreq = 44100;
|
||||
|
||||
OutputFreq = 11025;
|
||||
|
||||
/* reload these because they gets re-assigned from SDL data below, and InitializeAudio can be called more than once */
|
||||
PrimaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_SIZE");
|
||||
PrimaryBufferTarget = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_TARGET");
|
||||
SecondaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "SECONDARY_BUFFER_SIZE");
|
||||
|
||||
if (PrimaryBufferTarget < SecondaryBufferSize)
|
||||
PrimaryBufferTarget = SecondaryBufferSize;
|
||||
if (PrimaryBufferSize < PrimaryBufferTarget)
|
||||
PrimaryBufferSize = PrimaryBufferTarget;
|
||||
if (PrimaryBufferSize < SecondaryBufferSize * 2)
|
||||
PrimaryBufferSize = SecondaryBufferSize * 2;
|
||||
CreatePrimaryBuffer();
|
||||
if (mixBuffer != NULL)
|
||||
free(mixBuffer);
|
||||
mixBuffer = (unsigned char*) malloc(SecondaryBufferSize * SDL_SAMPLE_BYTES);
|
||||
}
|
||||
EXPORT void CALL RomClosed( void )
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
if (critical_failure == 1)
|
||||
return;
|
||||
|
||||
// Delete the buffer, as we are done producing sound
|
||||
if (primaryBuffer != NULL)
|
||||
{
|
||||
primaryBufferBytes = 0;
|
||||
free(primaryBuffer);
|
||||
primaryBuffer = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EXPORT void CALL ProcessAList(void)
|
||||
{
|
||||
}
|
||||
|
||||
EXPORT void CALL SetSpeedFactor(int percentage)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
if (percentage >= 10 && percentage <= 300)
|
||||
speed_factor = percentage;
|
||||
// we need a different size primary buffer to store the N64 samples when the speed changes
|
||||
CreatePrimaryBuffer();
|
||||
}
|
||||
|
||||
static void ReadConfig(void)
|
||||
{
|
||||
const char *resampler_id;
|
||||
|
||||
/* read the configuration values into our static variables */
|
||||
GameFreq = ConfigGetParamInt(l_ConfigAudio, "DEFAULT_FREQUENCY");
|
||||
SwapChannels = ConfigGetParamBool(l_ConfigAudio, "SWAP_CHANNELS");
|
||||
PrimaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_SIZE");
|
||||
PrimaryBufferTarget = ConfigGetParamInt(l_ConfigAudio, "PRIMARY_BUFFER_TARGET");
|
||||
SecondaryBufferSize = ConfigGetParamInt(l_ConfigAudio, "SECONDARY_BUFFER_SIZE");
|
||||
resampler_id = ConfigGetParamString(l_ConfigAudio, "RESAMPLE");
|
||||
VolumeControlType = ConfigGetParamInt(l_ConfigAudio, "VOLUME_CONTROL_TYPE");
|
||||
VolDelta = ConfigGetParamInt(l_ConfigAudio, "VOLUME_ADJUST");
|
||||
VolPercent = ConfigGetParamInt(l_ConfigAudio, "VOLUME_DEFAULT");
|
||||
|
||||
if (!resampler_id) {
|
||||
Resample = RESAMPLER_TRIVIAL;
|
||||
DebugMessage(M64MSG_WARNING, "Could not find RESAMPLE configuration; use trivial resampler");
|
||||
return;
|
||||
}
|
||||
if (strcmp(resampler_id, "trivial") == 0) {
|
||||
Resample = RESAMPLER_TRIVIAL;
|
||||
return;
|
||||
}
|
||||
#ifdef USE_SPEEX
|
||||
if (strncmp(resampler_id, "speex-fixed-", strlen("speex-fixed-")) == 0) {
|
||||
int i;
|
||||
static const char *speex_quality[] = {
|
||||
"speex-fixed-0",
|
||||
"speex-fixed-1",
|
||||
"speex-fixed-2",
|
||||
"speex-fixed-3",
|
||||
"speex-fixed-4",
|
||||
"speex-fixed-5",
|
||||
"speex-fixed-6",
|
||||
"speex-fixed-7",
|
||||
"speex-fixed-8",
|
||||
"speex-fixed-9",
|
||||
"speex-fixed-10",
|
||||
};
|
||||
Resample = RESAMPLER_SPEEX;
|
||||
for (i = 0; i < sizeof(speex_quality) / sizeof(*speex_quality); i++) {
|
||||
if (strcmp(speex_quality[i], resampler_id) == 0) {
|
||||
ResampleQuality = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
DebugMessage(M64MSG_WARNING, "Unknown RESAMPLE configuration %s; use speex-fixed-4 resampler", resampler_id);
|
||||
ResampleQuality = 4;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SRC
|
||||
if (strncmp(resampler_id, "src-", strlen("src-")) == 0) {
|
||||
Resample = RESAMPLER_SRC;
|
||||
if (strcmp(resampler_id, "src-sinc-best-quality") == 0) {
|
||||
ResampleQuality = SRC_SINC_BEST_QUALITY;
|
||||
return;
|
||||
}
|
||||
if (strcmp(resampler_id, "src-sinc-medium-quality") == 0) {
|
||||
ResampleQuality = SRC_SINC_MEDIUM_QUALITY;
|
||||
return;
|
||||
}
|
||||
if (strcmp(resampler_id, "src-sinc-fastest") == 0) {
|
||||
ResampleQuality = SRC_SINC_FASTEST;
|
||||
return;
|
||||
}
|
||||
if (strcmp(resampler_id, "src-zero-order-hold") == 0) {
|
||||
ResampleQuality = SRC_ZERO_ORDER_HOLD;
|
||||
return;
|
||||
}
|
||||
if (strcmp(resampler_id, "src-linear") == 0) {
|
||||
ResampleQuality = SRC_LINEAR;
|
||||
return;
|
||||
}
|
||||
DebugMessage(M64MSG_WARNING, "Unknown RESAMPLE configuration %s; use src-sinc-medium-quality resampler", resampler_id);
|
||||
ResampleQuality = SRC_SINC_MEDIUM_QUALITY;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
DebugMessage(M64MSG_WARNING, "Unknown RESAMPLE configuration %s; use trivial resampler", resampler_id);
|
||||
Resample = RESAMPLER_TRIVIAL;
|
||||
}
|
||||
|
||||
// Returns the most recent ummuted volume level.
|
||||
static int VolumeGetUnmutedLevel(void)
|
||||
{
|
||||
#if defined(HAS_OSS_SUPPORT)
|
||||
// reload volume if we're using OSS
|
||||
if (!VolIsMuted && VolumeControlType == VOLUME_TYPE_OSS)
|
||||
{
|
||||
return volGet();
|
||||
}
|
||||
#endif
|
||||
|
||||
return VolPercent;
|
||||
}
|
||||
|
||||
EXPORT void CALL VolumeMute(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
// Store the volume level in order to restore it later
|
||||
if (!VolIsMuted)
|
||||
VolPercent = VolumeGetUnmutedLevel();
|
||||
|
||||
// Toogle mute
|
||||
VolIsMuted = !VolIsMuted;
|
||||
}
|
||||
|
||||
EXPORT void CALL VolumeUp(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
VolumeSetLevel(VolumeGetUnmutedLevel() + VolDelta);
|
||||
}
|
||||
|
||||
EXPORT void CALL VolumeDown(void)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
VolumeSetLevel(VolumeGetUnmutedLevel() - VolDelta);
|
||||
}
|
||||
|
||||
EXPORT int CALL VolumeGetLevel(void)
|
||||
{
|
||||
return VolIsMuted ? 0 : VolumeGetUnmutedLevel();
|
||||
}
|
||||
|
||||
EXPORT void CALL VolumeSetLevel(int level)
|
||||
{
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
//if muted, unmute first
|
||||
VolIsMuted = 0;
|
||||
|
||||
// adjust volume
|
||||
VolPercent = level;
|
||||
if (VolPercent < 0)
|
||||
VolPercent = 0;
|
||||
else if (VolPercent > 100)
|
||||
VolPercent = 100;
|
||||
|
||||
}
|
||||
|
||||
EXPORT const char * CALL VolumeGetString(void)
|
||||
{
|
||||
static char VolumeString[32];
|
||||
|
||||
if (VolIsMuted)
|
||||
{
|
||||
strcpy(VolumeString, "Mute");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(VolumeString, "%i%%", VolPercent);
|
||||
}
|
||||
|
||||
return VolumeString;
|
||||
}
|
||||
|
||||
static int resample(unsigned char *input, int input_avail, int oldsamplerate, unsigned char *output, int output_needed, int newsamplerate)
|
||||
{
|
||||
int *psrc = (int*)input;
|
||||
int *pdest = (int*)output;
|
||||
int i = 0, j = 0;
|
||||
|
||||
// RESAMPLE == TRIVIAL
|
||||
if (newsamplerate >= oldsamplerate)
|
||||
{
|
||||
int sldf = oldsamplerate;
|
||||
int const2 = 2*sldf;
|
||||
int dldf = newsamplerate;
|
||||
int const1 = const2 - 2*dldf;
|
||||
int criteria = const2 - dldf;
|
||||
for (i = 0; i < output_needed/4; i++)
|
||||
{
|
||||
pdest[i] = psrc[j];
|
||||
if(criteria >= 0)
|
||||
{
|
||||
++j;
|
||||
criteria += const1;
|
||||
}
|
||||
else criteria += const2;
|
||||
}
|
||||
return j * 4; //number of bytes consumed
|
||||
}
|
||||
// newsamplerate < oldsamplerate, this only happens when speed_factor > 1
|
||||
for (i = 0; i < output_needed/4; i++)
|
||||
{
|
||||
j = i * oldsamplerate / newsamplerate;
|
||||
pdest[i] = psrc[j];
|
||||
}
|
||||
return j * 4; //number of bytes consumed
|
||||
}
|
||||
|
||||
EXPORT void CALL my_audio_callback(unsigned char *stream, int len)
|
||||
{
|
||||
int oldsamplerate, newsamplerate;
|
||||
|
||||
if (!l_PluginInit)
|
||||
return;
|
||||
|
||||
newsamplerate = OutputFreq * 100 / speed_factor;
|
||||
oldsamplerate = GameFreq;
|
||||
|
||||
if (buffer_pos > (unsigned int) (len * oldsamplerate) / newsamplerate)
|
||||
{
|
||||
int input_used;
|
||||
{
|
||||
input_used = resample(primaryBuffer, buffer_pos, oldsamplerate, stream, len, newsamplerate);
|
||||
}
|
||||
memmove(primaryBuffer, &primaryBuffer[input_used], buffer_pos - input_used);
|
||||
buffer_pos -= input_used;
|
||||
DebugMessage(M64MSG_VERBOSE, "my_audio_callback: used %i samples",
|
||||
len / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int SamplesNeeded = (len * oldsamplerate) / (newsamplerate * 4);
|
||||
unsigned int SamplesPresent = buffer_pos / N64_SAMPLE_BYTES;
|
||||
underrun_count++;
|
||||
DebugMessage(M64MSG_VERBOSE, "Buffer underflow (%i). %i samples present, %i needed",
|
||||
underrun_count, SamplesPresent, SamplesNeeded);
|
||||
memset(stream , 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT void CALL ReadAudioBuffer(short* dest)
|
||||
{
|
||||
int i;
|
||||
short * src = (short*)primaryBuffer;
|
||||
for (i = 0; i < buffer_pos/2; i++)
|
||||
{
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
buffer_pos = 0;
|
||||
}
|
||||
|
||||
EXPORT int CALL GetBufferSize()
|
||||
{
|
||||
return buffer_pos/2;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - main.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2008-2012 Tillin9, Richard42 *
|
||||
* *
|
||||
* 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. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* version info */
|
||||
#define SDL_AUDIO_PLUGIN_VERSION 0x016305
|
||||
#define AUDIO_PLUGIN_API_VERSION 0x020000
|
||||
#define CONFIG_API_VERSION 0x020100
|
||||
#define CONFIG_PARAM_VERSION 1.00
|
||||
|
||||
#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)
|
||||
|
||||
/* declarations of pointers to Core config functions */
|
||||
extern ptr_ConfigListSections ConfigListSections;
|
||||
extern ptr_ConfigOpenSection ConfigOpenSection;
|
||||
extern ptr_ConfigDeleteSection ConfigDeleteSection;
|
||||
extern ptr_ConfigSaveSection ConfigSaveSection;
|
||||
extern ptr_ConfigListParameters ConfigListParameters;
|
||||
extern ptr_ConfigSaveFile ConfigSaveFile;
|
||||
extern ptr_ConfigSetParameter ConfigSetParameter;
|
||||
extern ptr_ConfigGetParameter ConfigGetParameter;
|
||||
extern ptr_ConfigGetParameterHelp ConfigGetParameterHelp;
|
||||
extern ptr_ConfigSetDefaultInt ConfigSetDefaultInt;
|
||||
extern ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat;
|
||||
extern ptr_ConfigSetDefaultBool ConfigSetDefaultBool;
|
||||
extern ptr_ConfigSetDefaultString ConfigSetDefaultString;
|
||||
extern ptr_ConfigGetParamInt ConfigGetParamInt;
|
||||
extern ptr_ConfigGetParamFloat ConfigGetParamFloat;
|
||||
extern ptr_ConfigGetParamBool ConfigGetParamBool;
|
||||
extern ptr_ConfigGetParamString ConfigGetParamString;
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B6F20769-1385-4C0F-91A9-26F47AD1E78F}</ProjectGuid>
|
||||
<RootNamespace>mupen64plusaudiobkm</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v100</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>
|
||||
</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\mupen64plus-core\src\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y $(OutDir)$(TargetName)$(TargetExt) $(TargetDir)..\..\..\..\..\BizHawk.MultiClient\output\dll\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\main.c" />
|
||||
<ClCompile Include="..\osal_dynamiclib_win32.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\main.h" />
|
||||
<ClInclude Include="..\osal_dynamiclib.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,30 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-core - osal/dynamiclib.h *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* *
|
||||
* 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. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#if !defined(OSAL_DYNAMICLIB_H)
|
||||
#define OSAL_DYNAMICLIB_H
|
||||
|
||||
#include "m64p_types.h"
|
||||
|
||||
void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName);
|
||||
|
||||
#endif /* #define OSAL_DYNAMICLIB_H */
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-core - osal/dynamiclib_unix.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* *
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "m64p_types.h"
|
||||
#include "osal_dynamiclib.h"
|
||||
|
||||
void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
|
||||
{
|
||||
if (pccProcedureName == NULL)
|
||||
return NULL;
|
||||
|
||||
return dlsym(LibHandle, pccProcedureName);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus-ui-console - osal_dynamiclib_win32.c *
|
||||
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
|
||||
* Copyright (C) 2009 Richard Goedeken *
|
||||
* *
|
||||
* 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 <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "m64p_types.h"
|
||||
#include "osal_dynamiclib.h"
|
||||
|
||||
m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath)
|
||||
{
|
||||
if (pLibHandle == NULL || pccLibraryPath == NULL)
|
||||
return M64ERR_INPUT_ASSERT;
|
||||
|
||||
*pLibHandle = LoadLibrary(pccLibraryPath);
|
||||
|
||||
if (*pLibHandle == NULL)
|
||||
{
|
||||
char *pchErrMsg;
|
||||
DWORD dwErr = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
|
||||
fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg);
|
||||
LocalFree(pchErrMsg);
|
||||
return M64ERR_INPUT_NOT_FOUND;
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName)
|
||||
{
|
||||
if (pccProcedureName == NULL)
|
||||
return NULL;
|
||||
|
||||
return GetProcAddress(LibHandle, pccProcedureName);
|
||||
}
|
||||
|
||||
m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle)
|
||||
{
|
||||
int rval = FreeLibrary(LibHandle);
|
||||
|
||||
if (rval == 0)
|
||||
{
|
||||
char *pchErrMsg;
|
||||
DWORD dwErr = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL);
|
||||
fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg);
|
||||
LocalFree(pchErrMsg);
|
||||
return M64ERR_INTERNAL;
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
|
@ -14,6 +14,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-audio-sdl", "..
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-video-glide64mk2", "..\..\..\mupen64plus-video-glide64mk2\projects\msvc10\mupen64plus-video-glide64mk2.vcxproj", "{A4D13408-A794-4199-8FC7-4A9A32505005}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mupen64plus-audio-bkm", "..\..\..\mupen64plus-audio-bkm\mupen64plus-audio-bkm\mupen64plus-audio-bkm.vcxproj", "{B6F20769-1385-4C0F-91A9-26F47AD1E78F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -48,6 +50,10 @@ Global
|
|||
{A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.Build.0 = Release|Win32
|
||||
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B6F20769-1385-4C0F-91A9-26F47AD1E78F}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
Loading…
Reference in New Issue