2006-07-23 03:47:20 +00:00
|
|
|
/* FCE Ultra - NES/Famicom Emulator
|
|
|
|
*
|
|
|
|
* Copyright notice for this file:
|
|
|
|
* Copyright (C) 2002 Xodnizel
|
|
|
|
*
|
|
|
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "sdl.h"
|
|
|
|
|
|
|
|
#ifdef USE_SEXYAL
|
|
|
|
|
|
|
|
#include "../sexyal/sexyal.h"
|
|
|
|
|
|
|
|
static SexyAL *Interface;
|
|
|
|
static SexyAL_device *Output;
|
|
|
|
static SexyAL_format format;
|
|
|
|
static SexyAL_buffering buffering;
|
|
|
|
|
|
|
|
uint32 GetMaxSound(void)
|
|
|
|
{
|
|
|
|
return(buffering.totalsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 GetWriteSound(void)
|
|
|
|
{
|
|
|
|
return(Output->CanWrite(Output));
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteSound(int32 *Buffer, int Count)
|
|
|
|
{
|
|
|
|
//printf("%d\n",Output->CanWrite(Output));
|
|
|
|
Output->Write(Output, Buffer, Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
int InitSound(FCEUGI *gi)
|
|
|
|
{
|
|
|
|
if(!_sound) return(0);
|
|
|
|
|
|
|
|
memset(&format,0,sizeof(format));
|
|
|
|
memset(&buffering,0,sizeof(buffering));
|
|
|
|
|
|
|
|
FCEUI_SetSoundVolume(soundvol);
|
|
|
|
FCEUI_SetSoundQuality(soundq);
|
|
|
|
|
|
|
|
Interface=SexyAL_Init(0);
|
|
|
|
|
|
|
|
format.sampformat=SEXYAL_FMT_PCMS32S16;
|
|
|
|
format.channels=gi->soundchan?gi->soundchan:1;
|
|
|
|
format.rate=gi->soundrate?gi->soundrate:soundrate;
|
|
|
|
buffering.fragcount=buffering.fragsize=0;
|
|
|
|
buffering.ms=soundbufsize;
|
|
|
|
|
|
|
|
FCEUI_printf("\nInitializing sound...");
|
|
|
|
if(!(Output=Interface->Open(Interface,SEXYAL_ID_UNUSED,&format,&buffering)))
|
|
|
|
{
|
|
|
|
FCEUD_PrintError("Error opening a sound device.");
|
|
|
|
Interface->Destroy(Interface);
|
|
|
|
Interface=0;
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(soundq && format.rate!=48000 && format.rate!=44100 && format.rate!=96000)
|
|
|
|
{
|
|
|
|
FCEUD_PrintError("Set sound playback rate neither 44100, 48000, nor 96000, but needs to be when in high-quality sound mode.");
|
|
|
|
KillSound();
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(format.rate<8192 || format.rate > 96000)
|
|
|
|
{
|
|
|
|
FCEUD_PrintError("Set rate is out of range [8192-96000]");
|
|
|
|
KillSound();
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
FCEUI_printf("\n Bits: %u\n Rate: %u\n Channels: %u\n Byte order: CPU %s\n Buffer size: %u sample frames(%f ms)\n",(format.sampformat>>4)*8,format.rate,format.channels,format.byteorder?"Reversed":"Native",buffering.totalsize,(double)buffering.totalsize*1000/format.rate);
|
|
|
|
|
|
|
|
format.sampformat=SEXYAL_FMT_PCMS32S16;
|
|
|
|
format.channels=gi->soundchan?gi->soundchan:1;
|
|
|
|
format.byteorder=0;
|
|
|
|
|
|
|
|
//format.rate=gi->soundrate?gi->soundrate:soundrate;
|
|
|
|
|
|
|
|
Output->SetConvert(Output,&format);
|
|
|
|
|
|
|
|
FCEUI_Sound(format.rate);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SilenceSound(int n)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int KillSound(void)
|
|
|
|
{
|
|
|
|
FCEUI_Sound(0);
|
|
|
|
if(Output)
|
|
|
|
Output->Close(Output);
|
|
|
|
if(Interface)
|
|
|
|
Interface->Destroy(Interface);
|
|
|
|
Interface=0;
|
|
|
|
if(!Output) return(0);
|
|
|
|
Output=0;
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif USE_JACKACK /* Use JACK Audio Connection Kit */
|
|
|
|
|
|
|
|
#include <jack/jack.h>
|
|
|
|
#include <jack/ringbuffer.h>
|
|
|
|
|
|
|
|
static jack_port_t *output_port = NULL;
|
|
|
|
static jack_client_t *client = NULL;
|
|
|
|
static jack_ringbuffer_t *tmpbuf = NULL;
|
|
|
|
static unsigned int BufferSize;
|
|
|
|
|
|
|
|
static int process(jack_nframes_t nframes, void *arg)
|
|
|
|
{
|
|
|
|
jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer(output_port, nframes);
|
|
|
|
size_t canread;
|
|
|
|
|
|
|
|
canread = jack_ringbuffer_read_space(tmpbuf) / sizeof(jack_default_audio_sample_t);
|
|
|
|
|
|
|
|
if(canread > nframes)
|
|
|
|
canread = nframes;
|
|
|
|
|
|
|
|
jack_ringbuffer_read(tmpbuf, out,canread * sizeof(jack_default_audio_sample_t));
|
|
|
|
nframes -= canread;
|
|
|
|
|
|
|
|
if(nframes) /* Buffer underflow. Hmm. */
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 GetMaxSound(void)
|
|
|
|
{
|
|
|
|
return(BufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 GetWriteSound(void)
|
|
|
|
{
|
|
|
|
return(jack_readbuffer_write_space / sizeof(jack_default_audio_sample_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void DeadSound(void *arg)
|
|
|
|
{
|
|
|
|
puts("AGH! Sound server hates us! Let's go on a rampage.");
|
|
|
|
}
|
|
|
|
|
|
|
|
int InitSound(FCEUGI *gi)
|
|
|
|
{
|
|
|
|
const char **ports;
|
|
|
|
|
|
|
|
client = jack_client_new("FCE Ultra");
|
|
|
|
|
|
|
|
jack_set_process_callback(client, process, 0);
|
|
|
|
jack_on_shutdown(client, DeadSound, 0);
|
|
|
|
|
|
|
|
printf("%ld\n",jack_get_sample_rate(client));
|
|
|
|
|
|
|
|
output_port = jack_port_register(client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
|
|
|
|
|
|
|
BufferSize = soundbufsize * soundrate / 1000;
|
|
|
|
|
|
|
|
tmpbuf = jack_ringbuffer_create(BufferSize * sizeof(jack_default_audio_sample_t));
|
|
|
|
|
|
|
|
jack_activate(client);
|
|
|
|
|
|
|
|
|
|
|
|
ports = jack_get_ports(client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
|
|
|
|
jack_connect(client, jack_port_name(output_port), ports[0]);
|
|
|
|
free(ports);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteSound(int32 *buf, int Count)
|
|
|
|
{
|
|
|
|
jack_default_audio_sample_t jbuf[Count];
|
|
|
|
int x;
|
|
|
|
|
|
|
|
for(x=0;x<Count;x++,buf++)
|
|
|
|
jbuf[x] = *buf;
|
|
|
|
|
|
|
|
jack_ringbuffer_write(tmpbuf, jbuf, sizeof(jack_default_audio_sample_t) * Count);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SilenceSound(int n)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int KillSound(void)
|
|
|
|
{
|
|
|
|
if(tmpbuf)
|
|
|
|
{
|
|
|
|
jack_ringbuffer_free(tmpbuf);
|
|
|
|
tmpbuf = NULL;
|
|
|
|
}
|
|
|
|
if(client)
|
|
|
|
{
|
|
|
|
jack_client_close(client);
|
|
|
|
client = NULL;
|
|
|
|
}
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* So we'll use SDL's evil sound support. Ok. */
|
|
|
|
static volatile int *Buffer = 0;
|
|
|
|
static unsigned int BufferSize;
|
|
|
|
static unsigned int BufferRead;
|
|
|
|
static unsigned int BufferWrite;
|
|
|
|
static volatile unsigned int BufferIn;
|
|
|
|
|
|
|
|
static void fillaudio(void *udata, uint8 *stream, int len)
|
|
|
|
{
|
|
|
|
int16 *tmps = (int16*)stream;
|
|
|
|
len >>= 1;
|
|
|
|
|
|
|
|
while(len)
|
|
|
|
{
|
|
|
|
int16 sample = 0;
|
|
|
|
if(BufferIn)
|
|
|
|
{
|
|
|
|
sample = Buffer[BufferRead];
|
|
|
|
BufferRead = (BufferRead + 1) % BufferSize;
|
|
|
|
BufferIn--;
|
|
|
|
}
|
|
|
|
else sample = 0;
|
|
|
|
|
|
|
|
*tmps = sample;
|
|
|
|
tmps++;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int InitSound(FCEUGI *gi)
|
|
|
|
{
|
|
|
|
SDL_AudioSpec spec;
|
|
|
|
if(!_sound) return(0);
|
|
|
|
|
|
|
|
memset(&spec,0,sizeof(spec));
|
|
|
|
if(SDL_InitSubSystem(SDL_INIT_AUDIO)<0)
|
|
|
|
{
|
|
|
|
puts(SDL_GetError());
|
|
|
|
KillSound();
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
spec.freq = soundrate;
|
|
|
|
spec.format = AUDIO_S16SYS;
|
|
|
|
spec.channels = 1;
|
|
|
|
spec.samples = 256;
|
|
|
|
spec.callback = fillaudio;
|
|
|
|
spec.userdata = 0;
|
|
|
|
|
|
|
|
BufferSize = soundbufsize * soundrate / 1000;
|
|
|
|
|
|
|
|
BufferSize -= spec.samples * 2; /* SDL uses at least double-buffering, so
|
|
|
|
multiply by 2. */
|
|
|
|
|
|
|
|
if(BufferSize < spec.samples) BufferSize = spec.samples;
|
|
|
|
|
2006-07-28 03:26:59 +00:00
|
|
|
Buffer = (int *)malloc(sizeof(int) * BufferSize);
|
2006-07-23 03:47:20 +00:00
|
|
|
BufferRead = BufferWrite = BufferIn = 0;
|
|
|
|
|
|
|
|
//printf("SDL Size: %d, Internal size: %d\n",spec.samples,BufferSize);
|
|
|
|
|
|
|
|
if(SDL_OpenAudio(&spec,0)<0)
|
|
|
|
{
|
|
|
|
puts(SDL_GetError());
|
|
|
|
KillSound();
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
SDL_PauseAudio(0);
|
|
|
|
FCEUI_Sound(soundrate);
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32 GetMaxSound(void)
|
|
|
|
{
|
|
|
|
return(BufferSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 GetWriteSound(void)
|
|
|
|
{
|
|
|
|
return(BufferSize - BufferIn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteSound(int32 *buf, int Count)
|
|
|
|
{
|
|
|
|
while(Count)
|
|
|
|
{
|
|
|
|
while(BufferIn == BufferSize) SDL_Delay(1);
|
|
|
|
Buffer[BufferWrite] = *buf;
|
|
|
|
Count--;
|
|
|
|
BufferWrite = (BufferWrite + 1) % BufferSize;
|
|
|
|
BufferIn++;
|
|
|
|
buf++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SilenceSound(int n)
|
|
|
|
{
|
|
|
|
SDL_PauseAudio(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
int KillSound(void)
|
|
|
|
{
|
|
|
|
FCEUI_Sound(0);
|
|
|
|
SDL_CloseAudio();
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
|
|
|
if(Buffer)
|
|
|
|
{
|
2006-07-28 03:26:59 +00:00
|
|
|
free((void *)Buffer);
|
2006-07-23 03:47:20 +00:00
|
|
|
Buffer = 0;
|
|
|
|
}
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static int mute=0;
|
|
|
|
static int soundvolume=100;
|
|
|
|
void FCEUD_SoundVolumeAdjust(int n)
|
|
|
|
{
|
|
|
|
switch(n)
|
|
|
|
{
|
|
|
|
case -1: soundvolume-=10; if(soundvolume<0) soundvolume=0; break;
|
|
|
|
case 0: soundvolume=100; break;
|
|
|
|
case 1: soundvolume+=10; if(soundvolume>150) soundvolume=150; break;
|
|
|
|
}
|
|
|
|
mute=0;
|
|
|
|
FCEUI_SetSoundVolume(soundvolume);
|
|
|
|
FCEU_DispMessage("Sound volume %d.", soundvolume);
|
|
|
|
}
|
|
|
|
void FCEUD_SoundToggle(void)
|
|
|
|
{
|
|
|
|
if(mute)
|
|
|
|
{
|
|
|
|
mute=0;
|
|
|
|
FCEUI_SetSoundVolume(soundvolume);
|
|
|
|
FCEU_DispMessage("Sound mute off.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mute=1;
|
|
|
|
FCEUI_SetSoundVolume(0);
|
|
|
|
FCEU_DispMessage("Sound mute on.");
|
|
|
|
}
|
|
|
|
}
|