mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
381 lines
9.1 KiB
C
381 lines
9.1 KiB
C
#ifdef USE_GTK
|
|
#include <gtk/gtk.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/soundcard.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <sys/time.h>
|
|
#include <semaphore.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#include "../main/winlnxdefs.h"
|
|
#include "Audio_#1.1.h"
|
|
|
|
static AUDIO_INFO AudioInfo;
|
|
static int dsp;
|
|
static int frequency;
|
|
static char configdir[PATH_MAX] = {0};
|
|
|
|
EXPORT void CALL
|
|
AiDacrateChanged( int SystemType )
|
|
{
|
|
int f;
|
|
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;
|
|
}
|
|
if (ioctl(dsp, SNDCTL_DSP_SPEED, &f) == -1)
|
|
printf("error initializing frequency:%x\n", f);
|
|
frequency = f;
|
|
}
|
|
|
|
void sync()
|
|
{
|
|
static long long limit = 0;
|
|
double secPerByte = (1/(double)frequency)/4.0;
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
//printf("new tv = %d\n", tv.tv_usec);
|
|
if (limit && (tv.tv_sec*1000000+tv.tv_usec) < limit)
|
|
{
|
|
usleep(limit-(tv.tv_sec*1000000+tv.tv_usec));
|
|
}
|
|
//else printf("not sleep\n");
|
|
gettimeofday(&tv, NULL);
|
|
limit = tv.tv_sec*1000000+tv.tv_usec + (int)(*AudioInfo.AI_LEN_REG*secPerByte*1000000);
|
|
//printf("limit:%d\n", (int)(*AudioInfo.AI_LEN_REG*secPerByte*1000000)-100000);
|
|
//printf("f=%d, %lf\n", frequency, secPerByte);
|
|
}
|
|
|
|
static pthread_t my_thread/*, my_thread2*/;
|
|
static short *buf[2] = {NULL, NULL};
|
|
static int buf_size[2] = {0, 0};
|
|
static int cur_buf = 0;
|
|
static sem_t sem, sem2/*, semt, semt2*/;
|
|
static int closed = 0;
|
|
|
|
static void *sound_thread(void *emp)
|
|
{
|
|
while (!closed)
|
|
{
|
|
sem_wait(&sem);
|
|
write(dsp, buf[cur_buf], *AudioInfo.AI_LEN_REG);
|
|
sem_post(&sem2);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*static void *timing_thread(void *emp)
|
|
{
|
|
//double secPerByte;
|
|
while (!closed)
|
|
{
|
|
sem_wait(&semt);
|
|
//secPerByte = (1/(double)frequency)/4.0;
|
|
//usleep((int)(*AudioInfo.AI_LEN_REG*secPerByte*1000000));
|
|
usleep((long long)((long long)*AudioInfo.AI_LEN_REG*1000000LL/((long long)frequency*4LL)));
|
|
sem_post(&semt2);
|
|
}
|
|
return 0;
|
|
}*/
|
|
|
|
EXPORT void CALL
|
|
AiLenChanged( void )
|
|
{
|
|
int i;
|
|
short *p = (short*)(AudioInfo.RDRAM +
|
|
(*AudioInfo.AI_DRAM_ADDR_REG & 0xFFFFFF));
|
|
if (buf_size[1-cur_buf] < *AudioInfo.AI_LEN_REG)
|
|
{
|
|
buf_size[1-cur_buf] = *AudioInfo.AI_LEN_REG;
|
|
if (buf[1-cur_buf] != NULL) free(buf[1-cur_buf]);
|
|
buf[1-cur_buf] = (short*)malloc(buf_size[1-cur_buf]*sizeof(char));
|
|
}
|
|
for (i=0; i<(buf_size[1-cur_buf]/4); i++)
|
|
{
|
|
buf[1-cur_buf][i*2+0] = p[i*2+1];
|
|
buf[1-cur_buf][i*2+1] = p[i*2+0];
|
|
}
|
|
//pthread_join(my_thread, NULL);
|
|
cur_buf = 1 - cur_buf;
|
|
//pthread_create(&my_thread, NULL, sound_thread, NULL);
|
|
sem_post(&sem);
|
|
sem_wait(&sem2);
|
|
//sem_post(&semt);
|
|
//sem_wait(&semt2);
|
|
//sync();
|
|
/*{
|
|
static int sample_count = 0;
|
|
count_info info;
|
|
while (info.bytes<sample_count)
|
|
{
|
|
if (ioctl(dsp, SNDCTL_DSP_GETOPTR, &info) == -1)
|
|
printf("error getting sample count\n");
|
|
// printf("i:%d<%d\n", info.bytes, sample_count);
|
|
}
|
|
sample_count += *AudioInfo.AI_LEN_REG;
|
|
}*/
|
|
}
|
|
|
|
EXPORT DWORD CALL
|
|
AiReadLength( void )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
EXPORT void CALL
|
|
CloseDLL( void )
|
|
{
|
|
}
|
|
|
|
EXPORT void CALL
|
|
DllAbout( HWND hParent )
|
|
{
|
|
#ifdef USE_GTK
|
|
char tMsg[256];
|
|
GtkWidget *dialog, *label, *okay_button;
|
|
|
|
dialog = gtk_dialog_new();
|
|
sprintf(tMsg,"Mupen64 Audio Plugin v0.2 by Hacktarux");
|
|
label = gtk_label_new(tMsg);
|
|
okay_button = gtk_button_new_with_label("OK");
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(okay_button), "clicked",
|
|
GTK_SIGNAL_FUNC(gtk_widget_destroy),
|
|
GTK_OBJECT(dialog));
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
|
|
okay_button);
|
|
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
|
|
label);
|
|
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
|
|
gtk_widget_show_all(dialog);
|
|
#else
|
|
char tMsg[256];
|
|
sprintf(tMsg,"Mupen64 Audio Plugin v0.2 by Hacktarux");
|
|
fprintf(stderr, "About\n%s\n", tMsg);
|
|
#endif
|
|
}
|
|
|
|
static void GetPluginDir(char *Directory)
|
|
{
|
|
if(strlen(configdir) > 0)
|
|
{
|
|
strncpy(Directory, configdir, PATH_MAX);
|
|
// make sure there's a trailing '/'
|
|
if(Directory[strlen(Directory)-1] != '/')
|
|
strncat(Directory, "/", PATH_MAX - strlen(Directory));
|
|
}
|
|
else
|
|
{
|
|
int n = readlink("/proc/self/exe", Directory, PATH_MAX);
|
|
if (n == -1)
|
|
strcpy(Directory, "./");
|
|
else
|
|
{
|
|
Directory[n] = '\0';
|
|
while(Directory[strlen(Directory)-1] != '/')
|
|
Directory[strlen(Directory)-1] = '\0';
|
|
}
|
|
strcat(Directory, "plugins/");
|
|
}
|
|
}
|
|
|
|
#ifdef USE_GTK
|
|
typedef struct
|
|
{
|
|
GtkWidget *dialog;
|
|
GtkObject *adj;
|
|
} ConfigDialog;
|
|
|
|
static void okButtonCallback(GtkWidget *widget, void *data)
|
|
{
|
|
ConfigDialog *configDialog = (ConfigDialog*)data;
|
|
|
|
int val = (int)(GTK_ADJUSTMENT(configDialog->adj)->value);
|
|
char path[PATH_MAX];
|
|
FILE *f;
|
|
|
|
GetPluginDir(path);
|
|
strncat(path, "mupen64_sound.cfg", PATH_MAX - strlen(path));
|
|
f = fopen(path, "wb");
|
|
fprintf(f, "%d\n", val);
|
|
fclose(f);
|
|
|
|
gtk_widget_hide(configDialog->dialog);
|
|
}
|
|
|
|
static ConfigDialog *CreateConfigDialog()
|
|
{
|
|
ConfigDialog *configDialog = malloc(sizeof(ConfigDialog));
|
|
GtkWidget *dialog;
|
|
GtkWidget *okButton;
|
|
GtkWidget *cancelButton;
|
|
GtkWidget *hScale;
|
|
GtkWidget *frame;
|
|
GtkObject *adj;
|
|
|
|
dialog = gtk_dialog_new();
|
|
gtk_window_set_title(GTK_WINDOW(dialog), "Mupen64 sound plugin configuration");
|
|
|
|
okButton = gtk_button_new_with_label("OK");
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), okButton);
|
|
|
|
cancelButton = gtk_button_new_with_label("Cancel");
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), cancelButton);
|
|
|
|
frame = gtk_frame_new("Buffer size");
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame);
|
|
|
|
adj = gtk_adjustment_new(0x10, 0x2, 0x32, 1, 1, 1);
|
|
|
|
hScale = gtk_hscale_new(GTK_ADJUSTMENT(adj));
|
|
gtk_scale_set_digits(GTK_SCALE(hScale), 0);
|
|
gtk_container_add(GTK_CONTAINER(frame), hScale);
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(dialog), "delete-event",
|
|
GTK_SIGNAL_FUNC(gtk_widget_hide_on_delete),
|
|
GTK_OBJECT(dialog));
|
|
gtk_signal_connect(GTK_OBJECT(okButton), "clicked",
|
|
GTK_SIGNAL_FUNC(okButtonCallback),
|
|
(void*)configDialog);
|
|
gtk_signal_connect_object(GTK_OBJECT(cancelButton), "clicked",
|
|
GTK_SIGNAL_FUNC(gtk_widget_hide),
|
|
GTK_OBJECT(dialog));
|
|
|
|
configDialog->dialog = dialog;
|
|
configDialog->adj = adj;
|
|
return configDialog;
|
|
}
|
|
#endif
|
|
|
|
EXPORT void CALL
|
|
DllConfig ( HWND hParent )
|
|
{
|
|
#ifdef USE_GTK
|
|
static ConfigDialog *configDialog = NULL;
|
|
if (configDialog == NULL) configDialog = CreateConfigDialog();
|
|
|
|
{
|
|
char path[PATH_MAX];
|
|
FILE *f;
|
|
int val;
|
|
|
|
GetPluginDir(path);
|
|
strncat(path, "mupen64_sound.cfg", PATH_MAX - strlen(path));
|
|
f = fopen(path, "rb");
|
|
if (f)
|
|
{
|
|
fscanf(f, "%d", &val);
|
|
fclose(f);
|
|
gtk_adjustment_set_value(GTK_ADJUSTMENT(configDialog->adj), val);
|
|
}
|
|
}
|
|
|
|
gtk_widget_show_all(configDialog->dialog);
|
|
#endif
|
|
}
|
|
|
|
EXPORT void CALL
|
|
DllTest ( HWND hParent )
|
|
{
|
|
}
|
|
|
|
EXPORT void CALL
|
|
GetDllInfo( PLUGIN_INFO * PluginInfo )
|
|
{
|
|
PluginInfo->Version = 0x0101;
|
|
PluginInfo->Type = PLUGIN_TYPE_AUDIO;
|
|
sprintf(PluginInfo->Name,"mupen64 audio plugin");
|
|
PluginInfo->NormalMemory = TRUE;
|
|
PluginInfo->MemoryBswaped = TRUE;
|
|
}
|
|
|
|
EXPORT BOOL CALL
|
|
InitiateAudio( AUDIO_INFO Audio_Info )
|
|
{
|
|
AudioInfo = Audio_Info;
|
|
return TRUE;
|
|
}
|
|
|
|
EXPORT void CALL RomOpen()
|
|
{
|
|
int channel=1, format, f;
|
|
int val = 0x20010;
|
|
char path[PATH_MAX];
|
|
FILE *file;
|
|
|
|
GetPluginDir(path);
|
|
strcat(path, "mupen64_sound.cfg");
|
|
file = fopen(path, "rb");
|
|
if (file)
|
|
{
|
|
fscanf(file, "%d", &val);
|
|
fclose(file);
|
|
val = 0x20000 | val;
|
|
}
|
|
dsp = open("/dev/dsp", O_WRONLY);
|
|
if (dsp == -1) printf("error opening /dev/dsp\n");
|
|
if (ioctl(dsp, SNDCTL_DSP_RESET) == -1)
|
|
printf("error resetting sound card\n");
|
|
f = 0x20010;
|
|
if (ioctl(dsp, SNDCTL_DSP_SETFRAGMENT, &val) == -1)
|
|
printf("error setting fragment size\n");
|
|
if (ioctl(dsp, SNDCTL_DSP_STEREO, &channel) == -1)
|
|
printf("error setting stereo mode\n");
|
|
if (!channel)
|
|
printf("error setting stereo mode\n");
|
|
format = AFMT_S16_LE;
|
|
if (ioctl(dsp, SNDCTL_DSP_SAMPLESIZE, &format) == -1)
|
|
printf("error initializing format\n");
|
|
f = 32000;
|
|
if (ioctl(dsp, SNDCTL_DSP_SPEED, &f) == -1)
|
|
printf("error initializing frequency:%d\n", f);
|
|
sem_init(&sem, 0, 0);
|
|
sem_init(&sem2,0, 1);
|
|
//sem_init(&semt,0, 0);
|
|
//sem_init(&semt2,0,1);
|
|
closed = 0;
|
|
pthread_create(&my_thread, NULL, sound_thread, NULL);
|
|
//pthread_create(&my_thread2,NULL, timing_thread,NULL);
|
|
}
|
|
|
|
EXPORT void CALL
|
|
RomClosed( void )
|
|
{
|
|
|
|
ioctl(dsp, SNDCTL_DSP_SYNC);
|
|
closed = 1;
|
|
sem_post(&sem);
|
|
sem_post(&sem);
|
|
//sem_post(&semt);
|
|
//sem_post(&semt);
|
|
pthread_join(my_thread, NULL);
|
|
//pthread_join(my_thread2,NULL);
|
|
close(dsp);
|
|
}
|
|
|
|
EXPORT void CALL
|
|
SetConfigDir( char *configDir )
|
|
{
|
|
strncpy(configdir, configDir, PATH_MAX);
|
|
}
|
|
|
|
EXPORT void CALL
|
|
ProcessAlist( void )
|
|
{
|
|
}
|