Add a per rom config to Notaz Audio Plugin
[mupen64plus-pandora.git] / source / notaz_audio / main.c
CommitLineData
a84c12f4 1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - main.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * notaz_audio: (c) notaz, 2010 *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <sys/ioctl.h>
30#include <linux/soundcard.h>
31#include <stdarg.h>
32/*
33#include "../main/winlnxdefs.h"
34
35#include "Audio_1.2.h"
36*/
37#define M64P_PLUGIN_PROTOTYPES 1
38#include "m64p_types.h"
39#include "m64p_plugin.h"
40#include "m64p_common.h"
41#include "m64p_config.h"
468fb36e 42#include "m64p_frontend.h"
a84c12f4 43
44#include "osal_dynamiclib.h"
45
46/* version info */
47#define NOTAZ_AUDIO_PLUGIN_VERSION 0x020000
48#define AUDIO_PLUGIN_API_VERSION 0x020000
49#define CONFIG_API_VERSION 0x020100
50#define CONFIG_PARAM_VERSION 1.00
51
52#define VERSION_PRINTF_SPLIT(x) (((x) >> 16) & 0xffff), (((x) >> 8) & 0xff), ((x) & 0xff)
53
54/* declarations of pointers to Core config functions */
55extern ptr_ConfigListSections ConfigListSections;
56extern ptr_ConfigOpenSection ConfigOpenSection;
57extern ptr_ConfigDeleteSection ConfigDeleteSection;
58extern ptr_ConfigSaveSection ConfigSaveSection;
59extern ptr_ConfigListParameters ConfigListParameters;
60extern ptr_ConfigSaveFile ConfigSaveFile;
61extern ptr_ConfigSetParameter ConfigSetParameter;
62extern ptr_ConfigGetParameter ConfigGetParameter;
63extern ptr_ConfigGetParameterHelp ConfigGetParameterHelp;
64extern ptr_ConfigSetDefaultInt ConfigSetDefaultInt;
65extern ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat;
66extern ptr_ConfigSetDefaultBool ConfigSetDefaultBool;
67extern ptr_ConfigSetDefaultString ConfigSetDefaultString;
68extern ptr_ConfigGetParamInt ConfigGetParamInt;
69extern ptr_ConfigGetParamFloat ConfigGetParamFloat;
70extern ptr_ConfigGetParamBool ConfigGetParamBool;
71extern ptr_ConfigGetParamString ConfigGetParamString;
468fb36e 72extern ptr_CoreDoCommand CoreDoCommand;
a84c12f4 73
74/* definitions of pointers to Core config functions */
75ptr_ConfigOpenSection ConfigOpenSection = NULL;
76ptr_ConfigDeleteSection ConfigDeleteSection = NULL;
77ptr_ConfigSaveSection ConfigSaveSection = NULL;
78ptr_ConfigSetParameter ConfigSetParameter = NULL;
79ptr_ConfigGetParameter ConfigGetParameter = NULL;
80ptr_ConfigGetParameterHelp ConfigGetParameterHelp = NULL;
81ptr_ConfigSetDefaultInt ConfigSetDefaultInt = NULL;
82ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat = NULL;
83ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL;
84ptr_ConfigSetDefaultString ConfigSetDefaultString = NULL;
85ptr_ConfigGetParamInt ConfigGetParamInt = NULL;
86ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
87ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
88ptr_ConfigGetParamString ConfigGetParamString = NULL;
468fb36e 89ptr_CoreDoCommand CoreDoCommand = NULL;
a84c12f4 90
91/* local variables */
92static void (*l_DebugCallback)(void *, int, const char *) = NULL;
93static void *l_DebugCallContext = NULL;
94static int l_PluginInit = 0;
95static int l_PausedForSync = 1; /* Audio is started in paused state after SDL initialization */
96static m64p_handle l_ConfigAudio;
97
98#undef PLUGIN_VERSION
99#define PLUGIN_VERSION "r2"
100
101#define PREFIX "[audio] "
102#define log(f, ...) printf(PREFIX f, ##__VA_ARGS__)
103
104#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
105
106/* comment from jttl_audio:
107 * This sets default frequency what is used if rom doesn't want to change it.
108 * Popably only game that needs this is Zelda: Ocarina Of Time Master Quest
109 * *NOTICE* We should try to find out why Demos' frequencies are always wrong
110 * They tend to rely on a default frequency, apparently, never the same one ;)*/
111#define DEFAULT_FREQUENCY 33600
112
113#define OSS_FRAGMENT_COUNT 5
114
115/* Read header for type definition */
116static AUDIO_INFO audio_info;
117/* Audio frequency, this is usually obtained from the game,
118 * but for compatibility we set default value */
119static int input_freq = DEFAULT_FREQUENCY;
120
121/* config stuff */
122static int minimum_rate = 8000;
123static int pich_percent = 100;
124
125static unsigned int sound_out_buff[48000 * 4]; // ~4 sec, enough?
126static unsigned int sound_silence_buff[48000 / 10];
127
128static int sound_dev = -1;
129static int output_freq;
130static int resample_step;
131static int silence_bytes;
132static int fade_len;
133static int fade_step;
134
135/* rates Pandora supports natively, we'll need to do
136 * less resampling if we stick close to these */
137static const int supported_rates[] = {
138 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
139};
140
141static int init(int freq)
142{
143 static int output_freq_old;
144 int stereo, bits, rate;
145 int bsize, frag;
146 int ret, i;
147
148 input_freq = freq;
149
a84c12f4 150 // find lowest alowed rate that is higher than game's output
151 for (i = 0; i < ARRAY_SIZE(supported_rates); i++) {
152 int rate = supported_rates[i];
153 if (freq <= rate + 100 && rate >= minimum_rate) {
154 output_freq = rate;
155 break;
156 }
157 }
158
159 if (sound_dev >= 0) {
160 if (output_freq == output_freq_old)
161 goto finish;
162 close(sound_dev);
163 }
164
165 sound_dev = open("/dev/dsp", O_WRONLY);
166 if (sound_dev == -1) {
167 perror(PREFIX "open(\"/dev/dsp\")");
168 sound_dev = open("/dev/dsp1", O_WRONLY);
169 if (sound_dev == -1) {
170 perror(PREFIX "open(\"/dev/dsp1\")");
171 return -1;
172 }
173 }
174
175 bsize = output_freq / 20 * 4; // ~50ms
176 for (frag = 0; bsize; bsize >>= 1, frag++)
177 ;
178
179 frag |= OSS_FRAGMENT_COUNT << 16; // fragment count
180 ret = ioctl(sound_dev, SNDCTL_DSP_SETFRAGMENT, &frag);
181 if (ret < 0)
182 perror(PREFIX "SNDCTL_DSP_SETFRAGMENT failed");
183
184 silence_bytes = output_freq / 30 * 4; // ~ 25ms
185 memset(sound_silence_buff, 0, sizeof(sound_silence_buff));
186
187 stereo = 1;
188 bits = 16;
189 rate = output_freq;
190 ret = ioctl(sound_dev, SNDCTL_DSP_STEREO, &stereo);
191 if (ret == 0)
192 ret = ioctl(sound_dev, SNDCTL_DSP_SETFMT, &bits);
193 if (ret == 0)
194 ret = ioctl(sound_dev, SNDCTL_DSP_SPEED, &rate);
195 if (ret < 0)
196 perror(PREFIX "failed to set audio format");
197
198 if (rate != output_freq)
199 log("warning: output rate %d differs from desired %d\n", rate, output_freq);
200
201finish:
202 resample_step = freq * 1024 / output_freq;
203 if (pich_percent != 100)
204 resample_step = resample_step * pich_percent / 100;
205 fade_len = output_freq / 1000;
206 fade_step = 64 * 1024 / fade_len;
207
208 log("(re)started, rates: %d -> %d\n", freq, output_freq);
209
210 return 0;
211}
212
213static unsigned int resample(unsigned int *input, int in_size, unsigned int *output, int out_size)
214{
215 unsigned int i, j, t;
216 int step = resample_step;
217 int count = 0;
218
219 t = input[0];
220 t = (t << 16) | (t >> 16);
221
222 for (i = j = 0; i < out_size / 4;)
223 {
224 output[i++] = t;
225
226 count += step;
227 while (count >= 1024) {
228 count -= 1024;
229 j++;
230 if (j >= in_size / 4)
231 goto out;
232 t = input[j];
233 t = (t << 16) | (t >> 16);
234 }
235 }
236
237out:
238 return i * 4; // number of bytes to output
239}
240
241static void fade(unsigned int *buf, int buf_len, int up)
242{
243 signed short *sb = (void *)buf;
244 int len = fade_len;
245 int step = fade_step;
246 int counter = 0, mult, mult_step;
247 int i;
248
249 if (up) {
250 mult = 0;
251 mult_step = 1;
252 } else {
253 sb += buf_len / 2 - len * 2;
254 if (sb < (signed short *)buf)
255 sb = (void *)buf;
256 mult = 63;
257 mult_step = -1;
258 }
259
260 for (i = 0; i < len; i++) {
261 counter += step;
262 while (counter >= 1024) {
263 counter -= 1024;
264 mult += mult_step;
265 }
266 sb[i * 2] = sb[i * 2] / 64 * mult;
267 sb[i * 2 + 1] = sb[i * 2] / 64 * mult;
268 }
269}
270
271EXPORT void CALL AiDacrateChanged( int SystemType )
272{
273 int f = input_freq;
274 switch (SystemType)
275 {
276 case SYSTEM_NTSC:
277 f = 48681812 / (*audio_info.AI_DACRATE_REG + 1);
278 break;
279 case SYSTEM_PAL:
280 f = 49656530 / (*audio_info.AI_DACRATE_REG + 1);
281 break;
282 case SYSTEM_MPAL:
283 f = 48628316 / (*audio_info.AI_DACRATE_REG + 1);
284 break;
285 }
286 init(f);
287}
288
289EXPORT void CALL AiLenChanged(void)
290{
291 static int had_uflow;
292 unsigned int ret, len, *in, *part2, part2_len;
293 audio_buf_info bi;
294
295 if (sound_dev < 0)
296 return;
297
298 // XXX: what about alignment? len limit? rdram overflow?
299 in = (unsigned int *)(audio_info.RDRAM + (*audio_info.AI_DRAM_ADDR_REG & 0xFFFFFC));
300 len = *audio_info.AI_LEN_REG;
301
302 //log("AiLenChanged: %u\n", len);
303
304 ret = resample(in, len, sound_out_buff, sizeof(sound_out_buff));
305 if (ret >= sizeof(sound_out_buff))
306 log("overflow, in_len=%d\n", len);
307
308 if (had_uflow)
309 fade(sound_out_buff, ret / 2, 1);
310
311 write(sound_dev, sound_out_buff, ret / 2);
312 part2 = sound_out_buff + (ret / 4) / 2;
313 part2_len = ret - ret / 2;
314
315 // try to keep at most 2 free fragments to avoid
316 // hardware underflows that cause crackling on pandora
317 // XXX: for some reason GETOSPACE only works after write?
318 // XXX: .fragments sometimes overflows? ALSA OSS emu bugs?
319 ret = ioctl(sound_dev, SNDCTL_DSP_GETOSPACE, &bi);
320 if (ret == 0 && 2 < bi.fragments && bi.fragments <= OSS_FRAGMENT_COUNT) {
321 fade(part2, part2_len, 0);
322 write(sound_dev, part2, part2_len);
323 write(sound_dev, sound_silence_buff, silence_bytes);
324 if (bi.fragments == 4)
325 write(sound_dev, sound_silence_buff, silence_bytes);
326 had_uflow = 1;
327 }
328 else {
329 write(sound_dev, part2, part2_len);
330 had_uflow = 0;
331 }
332}
333
334/*
335EXPORT DWORD CALL AiReadLength(void)
336{
337 return 0;
338}
339EXPORT void CALL CloseDLL(void)
340{
341 if (sound_dev >= 0)
342 close(sound_dev);
343 sound_dev = -1;
344}
468fb36e 345
a84c12f4 346static char config_file[512];
347
348static void read_config(void)
349{
350 char cfg[512], *p;
351 int val;
352 FILE *f;
353
354 f = fopen(config_file, "r");
355 if (f == NULL) {
356 perror(PREFIX "can't open config");
357 return;
358 }
359
360 while (1) {
361 p = fgets(cfg, sizeof(cfg), f);
362 if (p == NULL)
363 break;
364 if (p[0] == '#')
365 continue;
366
367 if (sscanf(p, "pich_percent = %d", &val) == 1 && 10 <= val && val <= 1000) {
368 pich_percent = val;
369 break;
370 }
371 if (sscanf(p, "minimum_rate = %d", &val) == 1) {
372 minimum_rate = val;
373 break;
374 }
375 }
376 fclose(f);
377}
a84c12f4 378EXPORT void CALL SetConfigDir(char *configDir)
379{
380 snprintf(config_file, sizeof(config_file), "%snotaz_audio.conf", configDir);
381 read_config();
382}
383
384EXPORT void CALL DllTest(HWND hParent)
385{
386}
387
388EXPORT void CALL GetDllInfo(PLUGIN_INFO *PluginInfo)
389{
390 PluginInfo->Version = 0x0101;
391 PluginInfo->Type = PLUGIN_TYPE_AUDIO;
392 strcpy(PluginInfo->Name, "notaz's OSS audio " PLUGIN_VERSION);
393 PluginInfo->NormalMemory = TRUE;
394 PluginInfo->MemoryBswaped = TRUE;
395}
396
397EXPORT void CALL DllAbout(HWND hParent)
398{
399}
400
401EXPORT void CALL DllConfig(HWND hParent)
402{
403 char cmd[512];
404 FILE *f;
405
406 f = fopen(config_file, "r");
407 if (f != NULL)
408 fclose(f);
409 else {
410 f = fopen(config_file, "w");
411 if (f != NULL) {
412 fprintf(f, "# minimum sample rate to use. Higher values sound better on Pandora's DAC.\n");
413 fprintf(f, "minimum_rate = %d\n\n", minimum_rate);
414 fprintf(f, "# sound playback speed compared to normal (10-200%%)\n");
415 fprintf(f, "# this will affect gameplay speed and sound pitch\n");
416 fprintf(f, "pich_percent = %d\n\n", pich_percent);
417 fclose(f);
418 }
419 }
420
421 snprintf(cmd, sizeof(cmd), "mousepad \"%s\"", config_file);
422 system(cmd);
423
424 read_config();
425}
426*/
427EXPORT int CALL InitiateAudio(AUDIO_INFO Audio_Info)
428{
429 if (!l_PluginInit)
430 return 0;
431
432 audio_info = Audio_Info;
433 return 1;
434}
435
436EXPORT int CALL RomOpen(void)
437{
438 if (!l_PluginInit)
439 return 0;
440
468fb36e 441 minimum_rate = ConfigGetParamInt(l_ConfigAudio, "MINIMUM_RATE" );
442 pich_percent = ConfigGetParamInt(l_ConfigAudio, "PITCH_PERCENT" );
443
444 /* get rom crc */
445 char romcrc[50];
446 m64p_rom_header romheader;
447 CoreDoCommand(M64CMD_ROM_GET_HEADER, sizeof(romheader), &romheader); // is that the right way to get rom header and crc ?
448 sprintf((char*)romcrc, "%08x%08x", (unsigned int)romheader.CRC1, (unsigned int)romheader.CRC2);
449
450 /* open NotazAudio.ini if any, and look for the rom crc section to have per rom config */
451 FILE *f;
452 f = fopen("NotazAudio.ini", "r");
453 if (f)
454 {
455 int section = 0;
456 int rightsection = 0;
457 char line[500];
458 while (!feof(f))
459 {
460 fgets(line, 500, f);
461 size_t ln = strlen(line) - 1;
462 if (line[ln] == '\n')
463 line[ln] = '\0';
464 // *TODO* remove unused whitespaces
465 if (line[0] == '/')
466 continue;
467 if (!(strcasecmp(line,"")==0))
468 {
469 if (line[0] == '{') //if a section heading
470 {
471 line[strlen(line)-1]='\0';
472 if (strcasecmp(line+1,romcrc)==0)
473 section = 1; // found !!!
474 else
475 section = 0;
476 } else if (section==1)
477 {
478 if (strncasecmp(line, "MINIMUM_RATE", 12)==0)
479 {
480 minimum_rate = strtol(strchr(line,'=')+1,NULL,10);
481 }
482 else if (strncasecmp(line, "PITCH_PERCENT", 13)==0)
483 {
484 pich_percent = strtol(strchr(line,'=')+1,NULL,10);
485 }
486 }
487 }
488 }
489 fclose(f);
490
491 }
492
a84c12f4 493 /* This function is for compatibility with Mupen64. */
468fb36e 494 output_freq = minimum_rate;
a84c12f4 495 init(input_freq);
496 return 1;
497}
498
499EXPORT void CALL RomClosed(void)
500{
501}
502
503EXPORT void CALL ProcessAList(void)
504{
505}
506
507EXPORT void CALL SetSpeedFactor(int percentage)
508{
509}
510
511EXPORT void CALL VolumeUp(void)
512{
513}
514
515EXPORT void CALL VolumeDown(void)
516{
517}
518
519EXPORT void CALL VolumeMute(void)
520{
521}
522EXPORT int CALL VolumeGetLevel(void)
523{
524 return 255;
525}
526
527EXPORT void CALL VolumeSetLevel(int level)
528{
529}
530
531EXPORT const char * CALL VolumeGetString(void)
532{
533 return "100%%";
534}
535
536/* Global functions */
537static void DebugMessage(int level, const char *message, ...)
538{
539 char msgbuf[1024];
540 va_list args;
541
542 if (l_DebugCallback == NULL)
543 return;
544
545 va_start(args, message);
546 vsprintf(msgbuf, message, args);
547
548 (*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
549
550 va_end(args);
551}
552
553/* Mupen64Plus plugin functions */
554EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
555 void (*DebugCallback)(void *, int, const char *))
556{
557 ptr_CoreGetAPIVersions CoreAPIVersionFunc;
558
559 int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion, bSaveConfig;
560 float fConfigParamsVersion = 0.0f;
561
562 if (l_PluginInit)
563 return M64ERR_ALREADY_INIT;
564
565 /* first thing is to set the callback function for debug info */
566 l_DebugCallback = DebugCallback;
567 l_DebugCallContext = Context;
568
569 /* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
570 CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
571 if (CoreAPIVersionFunc == NULL)
572 {
573 DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
574 return M64ERR_INCOMPATIBLE;
575 }
576
577 (*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
578 if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
579 {
580 DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
581 VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
582 return M64ERR_INCOMPATIBLE;
583 }
584
585 /* Get the core config function pointers from the library handle */
586 ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection");
587 ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection");
588 ConfigSaveSection = (ptr_ConfigSaveSection) osal_dynlib_getproc(CoreLibHandle, "ConfigSaveSection");
589 ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter");
590 ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter");
591 ConfigSetDefaultInt = (ptr_ConfigSetDefaultInt) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultInt");
592 ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat");
593 ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool");
594 ConfigSetDefaultString = (ptr_ConfigSetDefaultString) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultString");
595 ConfigGetParamInt = (ptr_ConfigGetParamInt) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamInt");
596 ConfigGetParamFloat = (ptr_ConfigGetParamFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamFloat");
597 ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool");
598 ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamString");
599
468fb36e 600 CoreDoCommand = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreLibHandle, "CoreDoCommand");
601
a84c12f4 602 if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSetParameter || !ConfigGetParameter ||
603 !ConfigSetDefaultInt || !ConfigSetDefaultFloat || !ConfigSetDefaultBool || !ConfigSetDefaultString ||
468fb36e 604 !ConfigGetParamInt || !ConfigGetParamFloat || !ConfigGetParamBool || !ConfigGetParamString ||
605 !CoreDoCommand )
a84c12f4 606 return M64ERR_INCOMPATIBLE;
607
608 /* ConfigSaveSection was added in Config API v2.1.0 */
609 if (ConfigAPIVersion >= 0x020100 && !ConfigSaveSection)
610 return M64ERR_INCOMPATIBLE;
611
612 /* get a configuration section handle */
613 if (ConfigOpenSection("Audio-Notaz", &l_ConfigAudio) != M64ERR_SUCCESS)
614 {
615 DebugMessage(M64MSG_ERROR, "Couldn't open config section 'Audio-Notaz'");
616 return M64ERR_INPUT_NOT_FOUND;
617 }
618
619 /* check the section version number */
620 bSaveConfig = 0;
621 if (ConfigGetParameter(l_ConfigAudio, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
622 {
623 DebugMessage(M64MSG_WARNING, "No version number in 'Audio-Notaz' config section. Setting defaults.");
624 ConfigDeleteSection("Audio-Notaz");
625 ConfigOpenSection("Audio-Notaz", &l_ConfigAudio);
626 bSaveConfig = 1;
627 }
628 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
629 {
630 DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'Audio-Notaz' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
631 ConfigDeleteSection("Audio-Notaz");
632 ConfigOpenSection("Audio-Notaz", &l_ConfigAudio);
633 bSaveConfig = 1;
634 }
635 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
636 {
637 /* handle upgrades */
638 float fVersion = CONFIG_PARAM_VERSION;
639 ConfigSetParameter(l_ConfigAudio, "Version", M64TYPE_FLOAT, &fVersion);
640 DebugMessage(M64MSG_INFO, "Updating parameter set version in 'Audio-Notaz' config section to %.2f", fVersion);
641 bSaveConfig = 1;
642 }
643
644 /* set the default values for this plugin */
645 ConfigSetDefaultFloat(l_ConfigAudio, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus Notaz Audio Plugin config parameter version number");
646 ConfigSetDefaultInt(l_ConfigAudio, "MINIMUM_RATE", 44100, "Minimum sample rate to use. Higher values sound better on Pandora's DAC.");
647 ConfigSetDefaultInt(l_ConfigAudio, "PITCH_PERCENT", 100, "sound playback speed compared to normal (10-200%%). this will affect gameplay speed and sound pitch");
648
649 if (bSaveConfig && ConfigAPIVersion >= 0x020100)
650 ConfigSaveSection("Audio-SDL");
651
652 l_PluginInit = 1;
653 return M64ERR_SUCCESS;
654}
655
656EXPORT m64p_error CALL PluginShutdown(void)
657{
658 if (!l_PluginInit)
659 return M64ERR_NOT_INIT;
660
661 /* reset some local variables */
662 l_DebugCallback = NULL;
663 l_DebugCallContext = NULL;
664
665 if (sound_dev >= 0)
666 close(sound_dev);
667 sound_dev = -1;
668
669 l_PluginInit = 0;
670 log("Notaz-audio Plugin shutdown\n");
671 return M64ERR_SUCCESS;
672}
673
674
675EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
676{
677 /* set version info */
678 if (PluginType != NULL)
679 *PluginType = M64PLUGIN_AUDIO;
680
681 if (PluginVersion != NULL)
682 *PluginVersion = NOTAZ_AUDIO_PLUGIN_VERSION;
683
684 if (APIVersion != NULL)
685 *APIVersion = AUDIO_PLUGIN_API_VERSION;
686
687 if (PluginNamePtr != NULL)
688 *PluginNamePtr = "Mupen64Plus Notaz Audio Plugin";
689
690 if (Capabilities != NULL)
691 {
692 *Capabilities = 0;
693 }
694
695 return M64ERR_SUCCESS;
696}