IIRC, you have to specifically configure that. That's not something ZSNES is supposed to deal with.Skiessi wrote:And remember the people with multiple soundcards, there must be the ability to choose the output card. I haven't heard anything with this SDL driver.
Linux/FreeBSD/Mac OS X etc sound
Moderator: ZSNES Mods
-
- ZSNES Developer
- Posts: 6747
- Joined: Tue Dec 28, 2004 6:47 am
Continuing [url=http://slickproductions.org/forum/index.php?board=13.0]FF4[/url] Research...
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
Okay, I'm back with a new approach which should hopefully be feasable! 
Now I'm using libao, which can wrap to oss, alsa, arts, esd, nas, openal, sdl, directsound and a bunch of other things for all sorts of OSS including Solaris and Mac OS X specific audio libraries.
First you will need the libao development and shared libraries.
Then apply this patch to SVN:
Add -lao to the link step, then compile it.
When running ZSNES, you should see something like this:
By default I let libao pick what it thinks is best. However look in linux/sdllink.c on line 768 for:
Uncomment it out, and change oss to any of the valid ones listed that you want to try. I don't get audio from some of them, and your list will probably differ from mine.
Let me know if with this, one of the modes give you good audio.
If people are happy with this, I will clean this code up (it is extremely messy, doesn't unload properly, no easy use selectable interface), and commit it.
Please let me know how this works for you and which OSS and sound system you used. Detailed results are appreciated.

Now I'm using libao, which can wrap to oss, alsa, arts, esd, nas, openal, sdl, directsound and a bunch of other things for all sorts of OSS including Solaris and Mac OS X specific audio libraries.
First you will need the libao development and shared libraries.
Then apply this patch to SVN:
Code: Select all
Index: linux/sdllink.c
===================================================================
--- linux/sdllink.c (revision 4229)
+++ linux/sdllink.c (working copy)
@@ -23,6 +23,8 @@
#include "sw_draw.h"
#include "gl_draw.h"
+#include <ao/ao.h>
+
#include <SDL_thread.h>
#include <sys/time.h>
@@ -52,7 +54,7 @@
typedef enum vidstate_e { vid_null, vid_none, vid_soft, vid_gl } vidstate_t;
// SOUND RELATED VARIABLES
-SDL_AudioSpec audiospec;
+//SDL_AudioSpec audiospec;
int SoundEnabled = 1;
BYTE PrevStereoSound;
DWORD PrevSoundQuality;
@@ -725,8 +727,126 @@
}
}
+typedef unsigned long long uint64;
+#define SAMPLE_NTSC_HI_SCALE 995ULL
+#define SAMPLE_NTSC_LO 59649ULL
+#define SAMPLE_PAL_HI_SCALE 1ULL
+#define SAMPLE_PAL_LO 50ULL
+uint64 sample_hi;
+uint64 sample_lo;
+uint64 sample_balance;
+
+static const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
+#define RATE freqtab[SoundQuality]
+
+static ao_device *device;
+
int InitSound(void)
{
+ if (!SoundEnabled)
+ {
+ return FALSE;
+ }
+
+ PrevSoundQuality = SoundQuality;
+ PrevStereoSound = StereoSound;
+
+ ao_initialize();
+
+ int driver_count;
+ ao_info **driver_info = ao_driver_info_list(&driver_count);
+ puts("Valid Audio Drivers:");
+ while (driver_count--)
+ {
+ if (driver_info[driver_count]->type == AO_TYPE_LIVE)
+ {
+ puts(driver_info[driver_count]->short_name);
+ }
+ }
+
+ int driver_id = ao_default_driver_id();
+ //driver_id = ao_driver_id("oss");
+
+ ao_sample_format driver_format;
+ driver_format.bits = 16;
+ driver_format.channels = StereoSound+1;
+ driver_format.rate = freqtab[SoundQuality = ((SoundQuality > 6) ? 1 : SoundQuality)];
+ driver_format.byte_format = AO_FMT_LITTLE;
+
+ device = ao_open_live(driver_id, &driver_format, 0);
+ if (device)
+ {
+ printf("Audio Opened.\nChannels: %u Rate: %u\n", driver_format.channels, driver_format.rate);
+ }
+ else
+ {
+ puts("Audio Open Failed");
+ }
+
+ if (romispal)
+ {
+ sample_hi = SAMPLE_PAL_HI_SCALE*RATE;
+ sample_lo = SAMPLE_PAL_LO;
+ }
+ else
+ {
+ sample_hi = SAMPLE_NTSC_HI_SCALE*RATE;
+ sample_lo = SAMPLE_NTSC_LO;
+ }
+ sample_balance = sample_hi;
+
+ return TRUE;
+}
+
+short stemp[1280];
+void WriteSamples(unsigned int samples)
+{
+ //extern unsigned char soundon, DSPDisable;
+ extern unsigned int BufferSizeB, BufferSizeW;
+ void ProcessSoundBuffer();
+ extern int DSPBuffer[1280];
+
+ int *d = 0;
+ short *p = 0;
+
+ if (samples > 1280)
+ {
+ WriteSamples(1280);
+ samples -= 1280;
+ }
+
+ //printf("samples %d\n", samples);
+
+ BufferSizeB = samples;
+ BufferSizeW = samples<<1;
+
+ asm_call(ProcessSoundBuffer);
+
+ d = DSPBuffer;
+ p = stemp;
+
+ for (; d < DSPBuffer+samples; d++, p++)
+ {
+ if ((unsigned int)(*d + 0x8000) <= 0xFFFF) { *p = *d; continue; }
+ if (*d > 0x7FFF) { *p = 0x7FFF; }
+ else { *p = 0x8000; }
+ }
+
+ ao_play(device, (char *)stemp, samples*2);
+}
+
+void WriteAudio()
+{
+ unsigned int samples = (unsigned int)((sample_balance/sample_lo) << StereoSound);
+ sample_balance %= sample_lo;
+ sample_balance += sample_hi;
+
+ WriteSamples(samples);
+}
+
+/*
+int InitSound(void)
+{
SDL_AudioSpec wanted;
const int samptab[7] = { 1, 1, 2, 4, 2, 4, 4 };
const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
@@ -776,11 +896,12 @@
SDL_PauseAudio(0);
Buffer_len = (audiospec.size * 2);
- Buffer_len = (Buffer_len + 255) & ~255; /* Align to SPCSize */
+ Buffer_len = (Buffer_len + 255) & ~255; // Align to SPCSize
Buffer = malloc(Buffer_len);
return TRUE;
}
+*/
int ReInitSound(void)
{
@@ -1199,6 +1320,7 @@
}
}
+/*
//Why in the world did someone make this use signed values??? -Nach
void UpdateSound(void *userdata, Uint8 * stream, int len)
{
@@ -1225,6 +1347,7 @@
Buffer_fill -= len;
}
}
+*/
void sem_sleep(void)
{
@@ -1275,7 +1398,7 @@
void UpdateVFrame(void)
{
- extern unsigned char DSPDisable;
+ //extern unsigned char DSPDisable;
extern unsigned int BufferSizeB, BufferSizeW;
//Quick fix for GUI CPU usage
@@ -1284,11 +1407,12 @@
CheckTimers();
Main_Proc();
- /* Process sound */
+/*
+ // Process sound
BufferSizeB = 256;
BufferSizeW = BufferSizeB+BufferSizeB;
- /* take care of the things we left behind last time */
+ // take care of the things we left behind last time
SDL_LockAudio();
while (Buffer_fill < Buffer_len)
{
@@ -1317,6 +1441,7 @@
if (Buffer_tail >= Buffer_len) { Buffer_tail = 0; }
}
SDL_UnlockAudio();
+ */
}
void clearwin()
@@ -1344,6 +1469,11 @@
else
#endif
sw_drawwin();
+
+ if (!GUIOn2 && !GUIOn && !EMUPause)
+ {
+ WriteAudio();
+ }
}
void UnloadSDL()
When running ZSNES, you should see something like this:
Code: Select all
Valid Audio Drivers:
null
nas
oss
alsa09
esd
arts
Code: Select all
//driver_id = ao_driver_id("oss");
Let me know if with this, one of the modes give you good audio.
If people are happy with this, I will clean this code up (it is extremely messy, doesn't unload properly, no easy use selectable interface), and commit it.
Please let me know how this works for you and which OSS and sound system you used. Detailed results are appreciated.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
You edit the Makefile and put -lao next to -lSDL.Skiessi wrote:How do I add -lao to the link step?
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
Okay take 2, now I have the audio threaded, this should fix fast forward and some occasional lag issues. I notice with this my CPU usage dropped way down. Also some unloading is done.
Code: Select all
Index: Makefile.in
===================================================================
--- Makefile.in (revision 4270)
+++ Makefile.in (working copy)
@@ -99,7 +99,7 @@
default: main
all: main tools
main: makefile.dep $(Z_OBJS)
- @ZC@ -o @ZSNESEXE@ $(Z_OBJS) @ZCFLAGS@ @LDFLAGS@
+ @ZC@ -o @ZSNESEXE@ $(Z_OBJS) @ZCFLAGS@ @LDFLAGS@ -lao
rm -f version.o
$(PSR): parsegen.cpp
Index: linux/sdllink.c
===================================================================
--- linux/sdllink.c (revision 4270)
+++ linux/sdllink.c (working copy)
@@ -23,8 +23,10 @@
#include "sw_draw.h"
#include "gl_draw.h"
+#include <ao/ao.h>
+
#include <SDL_thread.h>
-
+#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <dirent.h>
@@ -52,15 +54,15 @@
typedef enum vidstate_e { vid_null, vid_none, vid_soft, vid_gl } vidstate_t;
// SOUND RELATED VARIABLES
-SDL_AudioSpec audiospec;
+//SDL_AudioSpec audiospec;
int SoundEnabled = 1;
BYTE PrevStereoSound;
DWORD PrevSoundQuality;
Uint8 *Buffer = NULL;
-int Buffer_len = 0, Buffer_fill = 0;
-int Buffer_head = 0, Buffer_tail = 0;
+//int Buffer_len = 0, Buffer_fill = 0;
+//int Buffer_head = 0, Buffer_tail = 0;
-extern int DSPBuffer[];
+//extern int DSPBuffer[];
/* VIDEO VARIABLES */
SDL_Surface *surface;
@@ -725,63 +727,156 @@
}
}
-int InitSound(void)
+typedef unsigned long long uint64;
+#define SAMPLE_NTSC_HI_SCALE 995ULL
+#define SAMPLE_NTSC_LO 59649ULL
+#define SAMPLE_PAL_HI_SCALE 1ULL
+#define SAMPLE_PAL_LO 50ULL
+uint64 sample_hi;
+uint64 sample_lo;
+uint64 sample_balance;
+
+static const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
+#define RATE freqtab[SoundQuality]
+
+static ao_device *device;
+
+void WriteSamples(unsigned int samples)
{
- SDL_AudioSpec wanted;
- const int samptab[7] = { 1, 1, 2, 4, 2, 4, 4 };
- const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
+ extern unsigned int BufferSizeB, BufferSizeW;
+ extern int DSPBuffer[1280];
+ void ProcessSoundBuffer();
+ short stemp[1280];
- SDL_CloseAudio();
+ int *d = 0;
+ short *p = 0;
+ if (samples > 1280)
+ {
+ WriteSamples(1280);
+ samples -= 1280;
+ }
+
+ //printf("samples %d\n", samples);
+
+ BufferSizeB = samples;
+ BufferSizeW = samples<<1;
+
+ asm_call(ProcessSoundBuffer);
+
+ d = DSPBuffer;
+ p = stemp;
+
+ for (; d < DSPBuffer+samples; d++, p++)
+ {
+ if ((unsigned int)(*d + 0x8000) <= 0xFFFF) { *p = *d; continue; }
+ if (*d > 0x7FFF) { *p = 0x7FFF; }
+ else { *p = 0x8000; }
+ }
+
+ ao_play(device, (char *)stemp, samples*2);
+}
+
+static unsigned int samples_waiting = 0;
+
+void *AudioThread(void *useless)
+{
+ for (;;)
+ {
+ if (samples_waiting)
+ {
+ int samples = samples_waiting;
+ samples_waiting = 0;
+ WriteSamples(samples);
+ }
+ else
+ {
+ usleep(20);
+ }
+ }
+ return(0);
+}
+
+pthread_t audio_thread;
+
+int InitSound(void)
+{
if (!SoundEnabled)
{
return FALSE;
}
- if (Buffer)
- free(Buffer);
- Buffer = NULL;
- Buffer_len = 0;
-
PrevSoundQuality = SoundQuality;
PrevStereoSound = StereoSound;
- if (SoundQuality > 6)
- SoundQuality = 1;
- wanted.freq = freqtab[SoundQuality];
+ ao_initialize();
- if (StereoSound)
+ int driver_count;
+ ao_info **driver_info = ao_driver_info_list(&driver_count);
+ puts("Valid Audio Drivers:");
+ while (driver_count--)
{
- wanted.channels = 2;
+ if (driver_info[driver_count]->type == AO_TYPE_LIVE)
+ {
+ puts(driver_info[driver_count]->short_name);
+ }
}
+
+ int driver_id = ao_default_driver_id();
+ //driver_id = ao_driver_id("oss");
+
+ ao_sample_format driver_format;
+ driver_format.bits = 16;
+ driver_format.channels = StereoSound+1;
+ driver_format.rate = freqtab[SoundQuality = ((SoundQuality > 6) ? 1 : SoundQuality)];
+ driver_format.byte_format = AO_FMT_LITTLE;
+
+ if (device)
+ {
+ ao_close(device);
+ }
else
{
- wanted.channels = 1;
+ pthread_create(&audio_thread, 0, AudioThread, 0);
}
- wanted.samples = samptab[SoundQuality] * 128 * wanted.channels;
+ device = ao_open_live(driver_id, &driver_format, 0);
+ if (device)
+ {
+ printf("Audio Opened.\nChannels: %u Rate: %u\n", driver_format.channels, driver_format.rate);
+ }
+ else
+ {
+ puts("Audio Open Failed");
+ }
- wanted.format = AUDIO_S16LSB;
- wanted.userdata = NULL;
- wanted.callback = UpdateSound;
-
- if (SDL_OpenAudio(&wanted, &audiospec) < 0)
+ if (romispal)
{
- fprintf(stderr, "Sound init failed!\n");
- fprintf(stderr, "freq: %d, channels: %d, samples: %d\n",
- wanted.freq, wanted.channels, wanted.samples);
- SoundEnabled = 0;
- return FALSE;
+ sample_hi = SAMPLE_PAL_HI_SCALE*RATE;
+ sample_lo = SAMPLE_PAL_LO;
}
- SDL_PauseAudio(0);
+ else
+ {
+ sample_hi = SAMPLE_NTSC_HI_SCALE*RATE;
+ sample_lo = SAMPLE_NTSC_LO;
+ }
+ sample_balance = sample_hi;
- Buffer_len = (audiospec.size * 2);
- Buffer_len = (Buffer_len + 255) & ~255; /* Align to SPCSize */
- Buffer = malloc(Buffer_len);
-
return TRUE;
}
+void WriteAudio()
+{
+ unsigned int samples = (unsigned int)((sample_balance/sample_lo) << StereoSound);
+ sample_balance %= sample_lo;
+ sample_balance += sample_hi;
+
+ if (!samples_waiting)
+ {
+ samples_waiting = samples;
+ }
+}
+
int ReInitSound(void)
{
return InitSound();
@@ -1199,6 +1294,7 @@
}
}
+/*
//Why in the world did someone make this use signed values??? -Nach
void UpdateSound(void *userdata, Uint8 * stream, int len)
{
@@ -1225,6 +1321,7 @@
Buffer_fill -= len;
}
}
+*/
void sem_sleep(void)
{
@@ -1275,7 +1372,7 @@
void UpdateVFrame(void)
{
- extern unsigned char DSPDisable;
+ //extern unsigned char DSPDisable;
extern unsigned int BufferSizeB, BufferSizeW;
//Quick fix for GUI CPU usage
@@ -1284,11 +1381,19 @@
CheckTimers();
Main_Proc();
- /* Process sound */
+/*
+ if (!GUIOn2 && !GUIOn && !EMUPause)
+ {
+ WriteAudio();
+ }
+*/
+
+/*
+ // Process sound
BufferSizeB = 256;
BufferSizeW = BufferSizeB+BufferSizeB;
- /* take care of the things we left behind last time */
+ // take care of the things we left behind last time
SDL_LockAudio();
while (Buffer_fill < Buffer_len)
{
@@ -1317,6 +1422,7 @@
if (Buffer_tail >= Buffer_len) { Buffer_tail = 0; }
}
SDL_UnlockAudio();
+ */
}
void clearwin()
@@ -1344,10 +1450,18 @@
else
#endif
sw_drawwin();
+
+ if (!GUIOn2 && !GUIOn && !EMUPause)
+ {
+ WriteAudio();
+ }
+
}
void UnloadSDL()
{
+ if (device) { ao_close(device); }
+ ao_shutdown();
sem_sleep_die(); // Shutdown semaphore
if (Buffer) { free(Buffer); }
if (sdl_state == vid_soft) { sw_end(); }
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
3rd times the charm! Apply against latest SVN.
Should now work for all sorts of cases, fast fowarding is fast, CPU usage is low, command line loading, NTSC and PAL. You can see driver list with zsnes --help, you can select which driver to use via command line or config file, stuff is unloaded right.
Make sure you have libao and libao-dev installed. Please play with the various available sound drivers.
Please post results you're having with the various drivers, list your CPU, RAM, OS, and Sound Card.
If you're using 64 bit, you'll need libao 32 bit drivers installed. I notice for me, that I have my 32 bit drivers going in /var/chroot/sid-ia32/usr/lib/, with 64 bit drivers in /usr/lib. Now I'm not sure if you can edit a config file somewhere, but my libao seems to be hardcoded to find it's drivers in /lib/ao/plugins-2/. To get around this problem, I symlinked everything in /var/chroot/sid-ia32/usr/lib/ao/plugins-2/ into /usr/lib/ao/plugins-2/.
For example:
And repeat for all drivers you have that you want to use.
And without further rambling, the patch:
I'd appreciate if those who knows pthreads well can contribute advice or perhaps code on how to sync the audio better. It works fine for me, but if I tax down my CPU, the audio gets crackly, probably since one thread no longer stays in sync with the other.
Should now work for all sorts of cases, fast fowarding is fast, CPU usage is low, command line loading, NTSC and PAL. You can see driver list with zsnes --help, you can select which driver to use via command line or config file, stuff is unloaded right.
Make sure you have libao and libao-dev installed. Please play with the various available sound drivers.
Please post results you're having with the various drivers, list your CPU, RAM, OS, and Sound Card.
If you're using 64 bit, you'll need libao 32 bit drivers installed. I notice for me, that I have my 32 bit drivers going in /var/chroot/sid-ia32/usr/lib/, with 64 bit drivers in /usr/lib. Now I'm not sure if you can edit a config file somewhere, but my libao seems to be hardcoded to find it's drivers in /lib/ao/plugins-2/. To get around this problem, I symlinked everything in /var/chroot/sid-ia32/usr/lib/ao/plugins-2/ into /usr/lib/ao/plugins-2/.
For example:
Code: Select all
ln -s /var/chroot/sid-ia32/usr/lib/ao/plugins-2/liboss.so /usr/lib/ao/plugins-2/liboss32.so
And without further rambling, the patch:
Code: Select all
Index: zloader.c
===================================================================
--- zloader.c (revision 4274)
+++ zloader.c (working copy)
@@ -21,6 +21,7 @@
#ifdef __UNIXSDL__
#include "gblhdr.h"
+#include <ao/ao.h>
#else
#define _POSIX_
#include <stdio.h>
@@ -73,6 +74,11 @@
{
size_t lines_out = 0;
bool tty = isatty(fileno(stdout));
+#ifdef __UNIXSDL__
+ int driver_count;
+ ao_info **driver_info;
+ char line[75];
+#endif
put_line("Usage : zsnes [-d,-f #, ... ] <filename.sfc>");
put_line(" Eg : zsnes -s -r 2 game.sfc");
@@ -97,6 +103,20 @@
#ifdef __WIN32__
put_line(" -6 # Force a user-specified refresh rate for fullscreen modes [50..180]");
#endif
+#ifdef __UNIXSDL__
+ put_line(" -ad <> Select Audio Driver :");
+ snprintf(line, sizeof(line), "%22s = automatically select", "auto");
+ driver_info = ao_driver_info_list(&driver_count);
+ put_line(line);
+ while (driver_count--)
+ {
+ if (driver_info[driver_count]->type == AO_TYPE_LIVE)
+ {
+ snprintf(line, sizeof(line), "%22s = %s", driver_info[driver_count]->short_name, driver_info[driver_count]->name);
+ put_line(line);
+ }
+ }
+#endif
#ifdef __MSDOS__
put_line(" -8 Force 8-bit sound");
put_line(" -c Enable full/wide screen (when available)");
@@ -714,6 +734,22 @@
DSPDisable = 1;
}
+ #ifdef __UNIXSDL__
+ else if (tolower(argv[i][1]) == 'a' && tolower(argv[i][2]) == 'd') //Disable sound DSP emulation
+ {
+ i++;
+ if (!strcmp(argv[i], "auto") || (ao_driver_id(argv[i]) >= 0))
+ {
+ strcpy(libAoDriver, argv[i]);
+ }
+ else
+ {
+ puts("Audio driver selection invalid.");
+ exit(1);
+ }
+ }
+ #endif
+
else if (tolower(argv[i][1]) == 'd' && tolower(argv[i][2]) == 's') //Disable sound output
{
soundon = 0;
@@ -899,6 +935,9 @@
{
if (init_paths(*zargv))
{
+ #ifdef __UNIXSDL__
+ ao_initialize();
+ #endif
handle_params(zargc, zargv);
atexit(ZCleanup);
Index: Makefile.in
===================================================================
--- Makefile.in (revision 4274)
+++ Makefile.in (working copy)
@@ -99,7 +99,7 @@
default: main
all: main tools
main: makefile.dep $(Z_OBJS)
- @ZC@ -o @ZSNESEXE@ $(Z_OBJS) @ZCFLAGS@ @LDFLAGS@
+ @ZC@ -o @ZSNESEXE@ $(Z_OBJS) @ZCFLAGS@ @LDFLAGS@ -lao
rm -f version.o
$(PSR): parsegen.cpp
Index: initc.c
===================================================================
--- initc.c (revision 4274)
+++ initc.c (working copy)
@@ -2139,6 +2139,10 @@
void SetupROM()
{
+ #ifdef __UNIXSDL__
+ void init_sample_control();
+ #endif
+
static bool CLforce = false;
unsigned char *ROM = (unsigned char *)romdata;
@@ -2175,6 +2179,10 @@
romispal = ((!BSEnable) && (ROM[infoloc+CountryOffset] > 1) && (ROM[infoloc+CountryOffset] < 0xD));
}
+ #ifdef __UNIXSDL__
+ init_sample_control();
+ #endif
+
if (romispal)
{
totlines = 314;
Index: linux/sdllink.c
===================================================================
--- linux/sdllink.c (revision 4274)
+++ linux/sdllink.c (working copy)
@@ -23,8 +23,10 @@
#include "sw_draw.h"
#include "gl_draw.h"
+#include <ao/ao.h>
+
#include <SDL_thread.h>
-
+#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <dirent.h>
@@ -53,16 +55,10 @@
typedef enum vidstate_e { vid_null, vid_none, vid_soft, vid_gl } vidstate_t;
// SOUND RELATED VARIABLES
-SDL_AudioSpec audiospec;
int SoundEnabled = 1;
BYTE PrevStereoSound;
DWORD PrevSoundQuality;
-Uint8 *Buffer = NULL;
-int Buffer_len = 0, Buffer_fill = 0;
-int Buffer_head = 0, Buffer_tail = 0;
-extern int DSPBuffer[];
-
/* VIDEO VARIABLES */
SDL_Surface *surface;
int SurfaceLocking = 0;
@@ -726,63 +722,158 @@
}
}
+#define SAMPLE_NTSC_HI_SCALE 995ULL
+#define SAMPLE_NTSC_LO 59649ULL
+#define SAMPLE_PAL_HI_SCALE 1ULL
+#define SAMPLE_PAL_LO 50ULL
+static const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
+#define RATE freqtab[SoundQuality]
+
+struct
+{
+ unsigned long long hi;
+ unsigned long long lo;
+ unsigned long long balance;
+} sample_control;
+
+void init_sample_control()
+{
+ if (romispal)
+ {
+ sample_control.hi = SAMPLE_PAL_HI_SCALE*RATE;
+ sample_control.lo = SAMPLE_PAL_LO;
+ }
+ else
+ {
+ sample_control.hi = SAMPLE_NTSC_HI_SCALE*RATE;
+ sample_control.lo = SAMPLE_NTSC_LO;
+ }
+ sample_control.balance = sample_control.hi;
+}
+
+static ao_device *device;
+
+void WriteSamples(unsigned int samples)
+{
+ extern unsigned int BufferSizeB, BufferSizeW;
+ extern int DSPBuffer[1280];
+ void ProcessSoundBuffer();
+ short stemp[1280];
+
+ int *d = 0;
+ short *p = 0;
+
+ if (samples > 1280)
+ {
+ WriteSamples(1280);
+ samples -= 1280;
+ }
+
+ //printf("samples %d\n", samples);
+
+ BufferSizeB = samples;
+ BufferSizeW = samples<<1;
+
+ asm_call(ProcessSoundBuffer);
+
+ d = DSPBuffer;
+ p = stemp;
+
+ for (; d < DSPBuffer+samples; d++, p++)
+ {
+ if ((unsigned int)(*d + 0x8000) <= 0xFFFF) { *p = *d; continue; }
+ if (*d > 0x7FFF) { *p = 0x7FFF; }
+ else { *p = 0x8000; }
+ }
+
+ ao_play(device, (char *)stemp, samples*2);
+}
+
+static unsigned int samples_waiting = 0;
+
+void *AudioThread(void *useless)
+{
+ for (;;)
+ {
+ if (samples_waiting)
+ {
+ int samples = samples_waiting;
+ samples_waiting = 0;
+ WriteSamples(samples);
+ }
+ else
+ {
+ usleep(20);
+ }
+ }
+ return(0);
+}
+
+pthread_t audio_thread;
+
int InitSound(void)
{
- SDL_AudioSpec wanted;
- const int samptab[7] = { 1, 1, 2, 4, 2, 4, 4 };
- const int freqtab[7] = { 8000, 11025, 22050, 44100, 16000, 32000, 48000 };
+ int driver_id;
- SDL_CloseAudio();
-
if (!SoundEnabled)
{
return FALSE;
}
- if (Buffer)
- free(Buffer);
- Buffer = NULL;
- Buffer_len = 0;
-
PrevSoundQuality = SoundQuality;
PrevStereoSound = StereoSound;
- if (SoundQuality > 6)
- SoundQuality = 1;
- wanted.freq = freqtab[SoundQuality];
+ driver_id = ao_driver_id(libAoDriver);
+ if (driver_id < 0) { driver_id = ao_default_driver_id(); }
- if (StereoSound)
+ ao_sample_format driver_format;
+ driver_format.bits = 16;
+ driver_format.channels = StereoSound+1;
+ driver_format.rate = freqtab[SoundQuality = ((SoundQuality > 6) ? 1 : SoundQuality)];
+ driver_format.byte_format = AO_FMT_LITTLE;
+
+ if (device)
{
- wanted.channels = 2;
+ ao_close(device);
}
else
{
- wanted.channels = 1;
+ pthread_create(&audio_thread, 0, AudioThread, 0);
+ init_sample_control();
}
- wanted.samples = samptab[SoundQuality] * 128 * wanted.channels;
+ //ao_option driver_options = { "buf_size", "32768", 0 };
- wanted.format = AUDIO_S16LSB;
- wanted.userdata = NULL;
- wanted.callback = UpdateSound;
-
- if (SDL_OpenAudio(&wanted, &audiospec) < 0)
+ device = ao_open_live(driver_id, &driver_format, 0);
+ if (device)
{
- fprintf(stderr, "Sound init failed!\n");
- fprintf(stderr, "freq: %d, channels: %d, samples: %d\n",
- wanted.freq, wanted.channels, wanted.samples);
- SoundEnabled = 0;
- return FALSE;
+ ao_info *di = ao_driver_info(driver_id);
+ printf("\nAudio Opened.\nDriver: %s\nChannels: %u\nRate: %u\n\n", di->name, driver_format.channels, driver_format.rate);
}
- SDL_PauseAudio(0);
+ else
+ {
+ puts("Audio Open Failed");
+ }
- Buffer_len = (audiospec.size * 2);
- Buffer_len = (Buffer_len + 255) & ~255; /* Align to SPCSize */
- Buffer = malloc(Buffer_len);
-
return TRUE;
}
+void WriteAudio()
+{
+ unsigned int samples = 0;
+ if (sample_control.lo)
+ {
+ samples = (unsigned int)((sample_control.balance/sample_control.lo) << StereoSound);
+ sample_control.balance %= sample_control.lo;
+ sample_control.balance += sample_control.hi;
+ }
+
+ if (!samples_waiting)
+ {
+ samples_waiting = samples;
+ }
+}
+
int ReInitSound(void)
{
return InitSound();
@@ -1200,33 +1291,6 @@
}
}
-//Why in the world did someone make this use signed values??? -Nach
-void UpdateSound(void *userdata, Uint8 * stream, int len)
-{
- int left = Buffer_len - Buffer_head;
-
- if (left < 0)
- {
- return;
- }
-
- if (left <= len)
- {
- memcpy(stream, &Buffer[Buffer_head], left);
- stream += left;
- len -= left;
- Buffer_head = 0;
- Buffer_fill -= left;
- }
-
- if (len)
- {
- memcpy(stream, &Buffer[Buffer_head], len);
- Buffer_head += len;
- Buffer_fill -= len;
- }
-}
-
void sem_sleep(void)
{
end = update_ticks_pc - (sem_GetTicks() - start) - .2f;
@@ -1276,48 +1340,11 @@
void UpdateVFrame(void)
{
- extern unsigned char DSPDisable;
- extern unsigned int BufferSizeB, BufferSizeW;
-
//Quick fix for GUI CPU usage
if (GUIOn || GUIOn2 || EMUPause) { usleep(6000); }
CheckTimers();
Main_Proc();
-
- /* Process sound */
- BufferSizeB = 256;
- BufferSizeW = BufferSizeB+BufferSizeB;
-
- /* take care of the things we left behind last time */
- SDL_LockAudio();
- while (Buffer_fill < Buffer_len)
- {
- short *ptr = (short*)&Buffer[Buffer_tail];
-
- if (soundon && !DSPDisable) { asm_call(ProcessSoundBuffer); }
-
- if (T36HZEnabled)
- {
- memset(ptr, 0, BufferSizeW);
- }
- else
- {
- int *d = DSPBuffer;
- int *end_d = DSPBuffer+BufferSizeB;
- for (; d < end_d; d++, ptr++)
- {
- if ((unsigned) (*d + 0x8000) <= 0xFFFF) { *ptr = *d; continue; }
- if (*d > 0x7FFF) { *ptr = 0x7FFF; }
- else { *d = 0x8000; }
- }
- }
-
- Buffer_fill += BufferSizeW;
- Buffer_tail += BufferSizeW;
- if (Buffer_tail >= Buffer_len) { Buffer_tail = 0; }
- }
- SDL_UnlockAudio();
}
void clearwin()
@@ -1336,6 +1363,8 @@
void drawscreenwin(void)
{
+ extern bool RawDumpInProgress;
+
/* Just in case - DDOI */
if (sdl_state == vid_none) return;
@@ -1345,12 +1374,19 @@
else
#endif
sw_drawwin();
+
+ if (!GUIOn2 && !GUIOn && !EMUPause && !RawDumpInProgress)
+ {
+ WriteAudio();
+ }
+
}
void UnloadSDL()
{
+ if (device) { ao_close(device); }
+ ao_shutdown();
sem_sleep_die(); // Shutdown semaphore
- if (Buffer) { free(Buffer); }
if (sdl_state == vid_soft) { sw_end(); }
#ifdef __OPENGL__
else if (sdl_state == vid_gl) { gl_end(); }
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
Dunno what all you did, but loading savestates results in a permanent 0/60 fps with that patch. [It seems to be due to a state for a specific game., however; saving/loading a state in Chrono Trigger works fine.]
Last edited by Aerdan on Fri Jan 05, 2007 4:29 pm, edited 1 time in total.
Thanks for the patch, I was testing it, so far with chrono trigger, and I get the best results with oss, with alsa from time to time the sound becomes crappy but just temporarly.
With oss from time to time the sound gets cut, but not so often. It's just a small cut.
Another thing is that when I was using it with Alsa i got this message more than once:
Also I tested the patch with contra III and the problems I mentioned above don't appear at all, however using alsa I noticed a very small delay of sound, not so noticeable, but just comparing with oss...
And when using oss I always get this at the beginning:
Specs:
Ubuntu Edgy (AMD64)
CPU: Amd64 x2 3800+
1 GB RAM
Soundcard: Nvidia Ck804 chip: Realtek ACL850 rev 0
Using libao 0.8.6-4
With oss from time to time the sound gets cut, but not so often. It's just a small cut.
Another thing is that when I was using it with Alsa i got this message more than once:
Code: Select all
ALSA: underrun, at least 0ms.
And when using oss I always get this at the beginning:
Code: Select all
ALSA lib ../../../src/pcm/pcm_dmix.c:862:(snd_pcm_dmix_open) unable to open slave
Specs:
Ubuntu Edgy (AMD64)
CPU: Amd64 x2 3800+
1 GB RAM
Soundcard: Nvidia Ck804 chip: Realtek ACL850 rev 0
Using libao 0.8.6-4
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
Oh, also mention if you think it sounds better than the SDL we were using.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
Well, you can forget about what I said before, now I don't get that cut problems with oss or the crappy sound with alsa, (I think I installed some libraries today so now that problems don't happen).
The only thing that is still there, is that with alsa there is some delay time, by the way, I am using alsa 1.0.11
As for which one sounds better, if the old sdl or the new one, I cannot hear a difference, maybe you can tell me a better way to compare them, or some game that is good to compare with.
EDIT:
With Chrono Trigger I cannot hear a difference, but I just tried with Top Gear, and the music sounds really better with libao.
The only thing that is still there, is that with alsa there is some delay time, by the way, I am using alsa 1.0.11
As for which one sounds better, if the old sdl or the new one, I cannot hear a difference, maybe you can tell me a better way to compare them, or some game that is good to compare with.
EDIT:
With Chrono Trigger I cannot hear a difference, but I just tried with Top Gear, and the music sounds really better with libao.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
Okay, forget using any patches, libao is now in SVN. It's usage is optional, you can still select SDL output.
I also fixed two bugs with the SDL sound code in the process.
I also fixed two bugs with the SDL sound code in the process.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
-
- Rookie
- Posts: 11
- Joined: Tue Apr 25, 2006 4:30 am
-
- Lurker
- Posts: 109
- Joined: Sun Jan 30, 2005 10:06 pm
- Location: Wouldn't you like to know?
- Contact:
Nach asked me to test the new libao options under FreeBSD (I'm using 6.2-RC1 right now, which probably isn't too different from 6.2-RELEASE), and I couldn't hear much difference between using oss or sdl. I could not test arts because I have that disabled (it takes over my entire sound card so nothing else can use it, so I don't use it). I only tested it with Chrono Trigger while inside one of the huts in 65,000,000 B.C., though, so I'm not sure how accurate the test would've been. If there's a better game or place in CT to test, I'll try that instead.
[url=http://www.cyberbotx.com/]SNES Sprite Animations[/url], made by an Insane Killer Robot.
I'm a computer programmer (in C++) and a future game designer.
I'm a computer programmer (in C++) and a future game designer.
-
- ZSNES Developer
- Posts: 6747
- Joined: Tue Dec 28, 2004 6:47 am
-
- Lurker
- Posts: 109
- Joined: Sun Jan 30, 2005 10:06 pm
- Location: Wouldn't you like to know?
- Contact:
Ah. Well in that case, I didn't detect any noticable difference in staticness between older versions and current ones with libao. As for playback, I've noticed it still depends on how overloaded my CPU is. Both before and after libao, the sound gets a bit choppy when it hits a CPU lag bubble. So I think for myself, it seems mostly the same.
[url=http://www.cyberbotx.com/]SNES Sprite Animations[/url], made by an Insane Killer Robot.
I'm a computer programmer (in C++) and a future game designer.
I'm a computer programmer (in C++) and a future game designer.
-
- ZSNES Developer
- Posts: 3904
- Joined: Tue Jul 27, 2004 10:54 pm
- Location: Solar powered park bench
- Contact:
ALSA sucks. If OSS works good for you than be happy. Fee free to try the other drivers too.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
_____________
Insane Coding
-
- ZSNES Developer
- Posts: 6747
- Joined: Tue Dec 28, 2004 6:47 am
A few things to keep in mind:
1. As I understand it, hardware mixing is actually worse than properly-done software mixing (dmix doesn't count) for modern systems because the system has to poll the buffers on the hardware mixer rather than just pushing in the completed stream. (And apparently the polling has a bigger performance penalty than just doing the mixing in the CPU)
3. Apparently OSS 4.x (GPLed and with an ALSA compatibility layer) does software mixing properly. (It has an in-kernel software mixer called vmix)
Oh, and dmix default settings will often still cause crackling when using ZSNES 1.51 with Intel HDA audio. I'll let you guys know when I figure out the proper /etc/asound.conf to fix it.
1. As I understand it, hardware mixing is actually worse than properly-done software mixing (dmix doesn't count) for modern systems because the system has to poll the buffers on the hardware mixer rather than just pushing in the completed stream. (And apparently the polling has a bigger performance penalty than just doing the mixing in the CPU)
3. Apparently OSS 4.x (GPLed and with an ALSA compatibility layer) does software mixing properly. (It has an in-kernel software mixer called vmix)
Oh, and dmix default settings will often still cause crackling when using ZSNES 1.51 with Intel HDA audio. I'll let you guys know when I figure out the proper /etc/asound.conf to fix it.
PulseAudio is the future..
i use fedora 8 and 1.51 works like a dream.. it has wrappers for most systems and works like a dream.. SDL is very nice and will be nice in the future.. so do stuff through SDL.. and PA will do the rest..
read this for a nice explanation about PulseAudio and see how it works and what it do.. it's a discussion about making PA the soundserver for gnome.. and a main developer comes in to explain what PA is about.. very nice read.. you dont need to read the rest of the mails..
http://mail.gnome.org/archives/desktop- ... 00136.html
i think it's best to keep it to SDL since it's very portable and only get's more and more accepted and the development in it is ace.. lots of commercial stuff use it.. (and it support pulseaudio directly if you want)
i use fedora 8 and 1.51 works like a dream.. it has wrappers for most systems and works like a dream.. SDL is very nice and will be nice in the future.. so do stuff through SDL.. and PA will do the rest..
read this for a nice explanation about PulseAudio and see how it works and what it do.. it's a discussion about making PA the soundserver for gnome.. and a main developer comes in to explain what PA is about.. very nice read.. you dont need to read the rest of the mails..
http://mail.gnome.org/archives/desktop- ... 00136.html
i think it's best to keep it to SDL since it's very portable and only get's more and more accepted and the development in it is ace.. lots of commercial stuff use it.. (and it support pulseaudio directly if you want)
PulseAudio is a sound server. Many people (myself included) prefer to avoid sound servers.bsund wrote:PulseAudio is the future..
i use fedora 8 and 1.51 works like a dream.. it has wrappers for most systems and works like a dream.. SDL is very nice and will be nice in the future.. so do stuff through SDL.. and PA will do the rest..
read this for a nice explanation about PulseAudio and see how it works and what it do.. it's a discussion about making PA the soundserver for gnome.. and a main developer comes in to explain what PA is about.. very nice read.. you dont need to read the rest of the mails..
http://mail.gnome.org/archives/desktop- ... 00136.html
i think it's best to keep it to SDL since it's very portable and only get's more and more accepted and the development in it is ace.. lots of commercial stuff use it.. (and it support pulseaudio directly if you want)
As for using SDL audio, I believe the devs said that it was the main reason for the timing problems that I remember so well in earlier Linux ZSNES releases... but don't quote me on that.