Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-audio-bkm/main.c
2 views
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* Mupen64plus-bkm-audio - main.c *
3
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4
* Editet 2013 null_ptr Completely rewritten to suit custom needs *
5
* Copyright (C) 2007-2009 Richard Goedeken *
6
* Copyright (C) 2007-2008 Ebenblues *
7
* Copyright (C) 2003 JttL *
8
* Copyright (C) 2002 Hacktarux *
9
* *
10
* This program is free software; you can redistribute it and/or modify *
11
* it under the terms of the GNU General Public License as published by *
12
* the Free Software Foundation; either version 2 of the License, or *
13
* (at your option) any later version. *
14
* *
15
* This program is distributed in the hope that it will be useful, *
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18
* GNU General Public License for more details. *
19
* *
20
* You should have received a copy of the GNU General Public License *
21
* along with this program; if not, write to the *
22
* Free Software Foundation, Inc., *
23
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
30
#define M64P_PLUGIN_PROTOTYPES 1
31
#include "m64p_types.h"
32
#include "m64p_plugin.h"
33
#include "m64p_common.h"
34
#include "m64p_config.h"
35
36
#include "main.h"
37
#include "osal_dynamiclib.h"
38
39
/* This sets default frequency what is used if rom doesn't want to change it.
40
Probably only game that needs this is Zelda: Ocarina Of Time Master Quest
41
*NOTICE* We should try to find out why Demos' frequencies are always wrong
42
They tend to rely on a default frequency, apparently, never the same one ;)*/
43
#define DEFAULT_FREQUENCY 33600
44
#define DEFAULT_BUFFER_SIZE 12480
45
46
/* number of bytes per sample */
47
#define N64_SAMPLE_BYTES 4
48
49
/* local variables */
50
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
51
static void *l_DebugCallContext = NULL;
52
static int l_PluginInit = 0;
53
54
/* Read header for type definition */
55
static AUDIO_INFO AudioInfo;
56
/* Audio frequency, this is usually obtained from the game, but for compatibility we set default value */
57
static int GameFreq = DEFAULT_FREQUENCY;
58
59
/* Audio buffer */
60
static char* audioBuffer = NULL;
61
static size_t bufferBack = 0;
62
static size_t bufferSize = 0;
63
64
// Prototype of local functions
65
static void SetSamplingRate(int freq);
66
static void SetBufferSize(size_t size);
67
68
static int critical_failure = 0;
69
70
/* Global functions */
71
static void DebugMessage(int level, const char *message, ...)
72
{
73
char msgbuf[1024];
74
va_list args;
75
76
if (l_DebugCallback == NULL)
77
return;
78
79
va_start(args, message);
80
vsprintf(msgbuf, message, args);
81
82
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
83
84
va_end(args);
85
}
86
87
#pragma region (De-)Initialization
88
/* Mupen64Plus plugin functions */
89
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
90
void (*DebugCallback)(void *, int, const char *))
91
{
92
ptr_CoreGetAPIVersions CoreAPIVersionFunc;
93
94
int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
95
96
if (l_PluginInit)
97
return M64ERR_ALREADY_INIT;
98
99
/* first thing is to set the callback function for debug info */
100
l_DebugCallback = DebugCallback;
101
l_DebugCallContext = Context;
102
103
/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
104
CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
105
if (CoreAPIVersionFunc == NULL)
106
{
107
DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
108
return M64ERR_INCOMPATIBLE;
109
}
110
111
(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
112
if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
113
{
114
DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
115
VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
116
return M64ERR_INCOMPATIBLE;
117
}
118
119
l_PluginInit = 1;
120
return M64ERR_SUCCESS;
121
}
122
123
EXPORT m64p_error CALL PluginShutdown(void)
124
{
125
if (!l_PluginInit)
126
return M64ERR_NOT_INIT;
127
128
/* reset some local variables */
129
l_DebugCallback = NULL;
130
l_DebugCallContext = NULL;
131
132
l_PluginInit = 0;
133
return M64ERR_SUCCESS;
134
}
135
136
EXPORT int CALL RomOpen(void)
137
{
138
if (!l_PluginInit)
139
return 0;
140
141
SetSamplingRate(GameFreq);
142
SetBufferSize(DEFAULT_BUFFER_SIZE);
143
return 1;
144
}
145
146
EXPORT void CALL RomClosed( void )
147
{
148
if (!l_PluginInit)
149
return;
150
if (critical_failure == 1)
151
return;
152
153
// Delete the buffer, as we are done producing sound
154
if (audioBuffer != NULL)
155
{
156
bufferSize = 0;
157
bufferBack = 0;
158
free(audioBuffer);
159
audioBuffer = NULL;
160
}
161
}
162
163
EXPORT int CALL InitiateAudio( AUDIO_INFO Audio_Info )
164
{
165
if (!l_PluginInit)
166
return 0;
167
168
AudioInfo = Audio_Info;
169
return 1;
170
}
171
172
static void SetBufferSize(size_t size)
173
{
174
char* oldBuffer = audioBuffer;
175
audioBuffer = (char*)malloc(size);
176
if(audioBuffer != NULL)
177
{
178
memcpy(audioBuffer, oldBuffer, min(size, bufferBack));
179
free(oldBuffer);
180
}
181
bufferSize = size;
182
bufferBack = min(size, bufferBack);
183
}
184
#pragma endregion
185
186
#pragma region Pluginversion
187
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
188
{
189
/* set version info */
190
if (PluginType != NULL)
191
*PluginType = M64PLUGIN_AUDIO;
192
193
if (PluginVersion != NULL)
194
*PluginVersion = BKM_AUDIO_PLUGIN_VERSION;
195
196
if (APIVersion != NULL)
197
*APIVersion = AUDIO_PLUGIN_API_VERSION;
198
199
if (PluginNamePtr != NULL)
200
*PluginNamePtr = "Mupen64Plus BKM Audio Plugin for Bizhawk";
201
202
if (Capabilities != NULL)
203
{
204
*Capabilities = 0;
205
}
206
207
return M64ERR_SUCCESS;
208
}
209
#pragma endregion
210
211
#pragma region Handle audio
212
/* --- Called when sampling rate changes --- */
213
EXPORT void CALL AiDacrateChanged( int SystemType )
214
{
215
int f = GameFreq;
216
217
if (!l_PluginInit)
218
return;
219
220
if (*AudioInfo.AI_DACRATE_REG == 0)
221
{
222
f = DEFAULT_FREQUENCY;
223
}
224
else
225
{
226
switch (SystemType)
227
{
228
case SYSTEM_NTSC:
229
f = 48681812 / (*AudioInfo.AI_DACRATE_REG + 1);
230
break;
231
case SYSTEM_PAL:
232
f = 49656530 / (*AudioInfo.AI_DACRATE_REG + 1);
233
break;
234
case SYSTEM_MPAL:
235
f = 48628316 / (*AudioInfo.AI_DACRATE_REG + 1);
236
break;
237
}
238
}
239
SetSamplingRate(f);
240
}
241
242
/* --- Called when length of n64 audio buffer changes --- */
243
/* --- i.e. new audio data in buffer --- */
244
EXPORT void CALL AiLenChanged( void )
245
{
246
unsigned int LenReg;
247
unsigned char *p;
248
249
if (critical_failure == 1)
250
return;
251
if (!l_PluginInit)
252
return;
253
254
LenReg = *AudioInfo.AI_LEN_REG;
255
p = AudioInfo.RDRAM + (*AudioInfo.AI_DRAM_ADDR_REG & 0xFFFFFF);
256
257
if (bufferBack + LenReg < bufferSize)
258
{
259
unsigned int i;
260
261
for ( i = 0 ; i < LenReg ; i += 4 )
262
{
263
// Left channel
264
audioBuffer[ bufferBack + i ] = p[ i + 2 ];
265
audioBuffer[ bufferBack + i + 1 ] = p[ i + 3 ];
266
267
// Right channel
268
audioBuffer[ bufferBack + i + 2 ] = p[ i ];
269
audioBuffer[ bufferBack + i + 3 ] = p[ i + 1 ];
270
}
271
bufferBack += i;
272
273
}
274
else
275
{
276
DebugMessage(M64MSG_WARNING, "AiLenChanged(): Audio buffer overflow.");
277
}
278
}
279
280
static void SetSamplingRate(int freq)
281
{
282
GameFreq = freq; // This is important for the sync
283
}
284
#pragma endregion
285
286
#pragma region Unused methods
287
/* ----------------------------------------------------------------------
288
* ------------ STUBS. WE DO NOT USE THESE API FUNCTIONS ---------------
289
* -------- MUPEN EXPECTS THEM AND FAILS IF THEY DON'T EXIST ------------
290
* ---------------------------------------------------------------------- */
291
EXPORT void CALL ProcessAList(void)
292
{
293
}
294
295
EXPORT void CALL SetSpeedFactor(int percentage)
296
{
297
}
298
299
static int VolumeGetUnmutedLevel(void)
300
{
301
return 100;
302
}
303
304
EXPORT void CALL VolumeMute(void)
305
{
306
}
307
308
EXPORT void CALL VolumeUp(void)
309
{
310
}
311
312
EXPORT void CALL VolumeDown(void)
313
{
314
}
315
316
EXPORT int CALL VolumeGetLevel(void)
317
{
318
return 100;
319
}
320
321
EXPORT void CALL VolumeSetLevel(int level)
322
{
323
}
324
325
EXPORT const char * CALL VolumeGetString(void)
326
{
327
return "100%";
328
}
329
/* ----------------------------------------------------------------------
330
* --------------------------- STUBS END --------------------------------
331
* ---------------------------------------------------------------------- */
332
#pragma endregion
333
334
#pragma region Buffer export
335
/* --- Moves content of audio buffer to destination --- */
336
EXPORT void CALL ReadAudioBuffer(short* dest)
337
{
338
memcpy(dest, audioBuffer, bufferBack);
339
bufferBack = 0;
340
}
341
/* --- Returns number of shorts of internal data --- */
342
EXPORT int CALL GetBufferSize()
343
{
344
return max(bufferBack/2, 0);
345
}
346
347
/* --- Returns current sampling rate --- */
348
EXPORT int CALL GetAudioRate()
349
{
350
return GameFreq;
351
}
352
#pragma endregion
353