View unanswered posts | View active topics It is currently Tue Jun 18, 2019 6:44 am



Reply to topic  [ 136 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next
Linux/FreeBSD/Mac OS X etc sound 

Best audio API
SDL 20%  20%  [ 10 ]
AO 20%  20%  [ 10 ]
OpenAL 29%  29%  [ 14 ]
Semi Portable OSS 12%  12%  [ 6 ]
Non Portable ALSA 10%  10%  [ 5 ]
Non Portable CoreAudio 2%  2%  [ 1 ]
Other 6%  6%  [ 3 ]
Total votes : 49

Linux/FreeBSD/Mac OS X etc sound 
Author Message
ZSNES Developer
ZSNES Developer

Joined: Tue Dec 28, 2004 6:47 am
Posts: 6747
Reply with quote
Post 
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.


IIRC, you have to specifically configure that. That's not something ZSNES is supposed to deal with.

_________________
Continuing FF4 Research...


Tue Dec 05, 2006 5:06 pm
Profile
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
Okay, I'm back with a new approach which should hopefully be feasable! :D

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:
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()

Add -lao to the link step, then compile it.

When running ZSNES, you should see something like this:
Code:
Valid Audio Drivers:
null
nas
oss
alsa09
esd
arts

By default I let libao pick what it thinks is best. However look in linux/sdllink.c on line 768 for:
Code:
//driver_id = ao_driver_id("oss");

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.

_________________
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding


Wed Jan 03, 2007 12:56 pm
Profile WWW
Winter Knight
User avatar

Joined: Mon Aug 16, 2004 10:16 pm
Posts: 467
Reply with quote
Post 
It works fine here with ALSA, but I got a few underrun messages with ALSA; it didn't seem to affect ingame sound much, so I'm not too worried.


Wed Jan 03, 2007 3:19 pm
Profile WWW
Rookie
User avatar

Joined: Tue Dec 05, 2006 1:31 pm
Posts: 14
Location: Finland, Rovaniemi
Reply with quote
Post 
How do I add -lao to the link step?


Wed Jan 03, 2007 7:45 pm
Profile WWW
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
Skiessi wrote:
How do I add -lao to the link step?

You edit the Makefile and put -lao next to -lSDL.

_________________
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding


Wed Jan 03, 2007 10:45 pm
Profile WWW
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
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:
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


Fri Jan 05, 2007 11:37 am
Profile WWW
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
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:
Code:
ln -s /var/chroot/sid-ia32/usr/lib/ao/plugins-2/liboss.so /usr/lib/ao/plugins-2/liboss32.so

And repeat for all drivers you have that you want to use.

And without further rambling, the patch:
Code:
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(); }


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.

_________________
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding


Fri Jan 05, 2007 1:58 pm
Profile WWW
Winter Knight
User avatar

Joined: Mon Aug 16, 2004 10:16 pm
Posts: 467
Reply with quote
Post 
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.



Fri Jan 05, 2007 3:54 pm
Profile WWW
New Member

Joined: Sun Jun 18, 2006 7:21 pm
Posts: 3
Reply with quote
Post 
patch doesn't apply cleanly, but works in Linux
in fact I don't see (or hear) any difference


Fri Jan 05, 2007 4:08 pm
Profile
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Aug 17, 2004 5:24 am
Posts: 812
Location: In your garden
Reply with quote
Post 
Patch against SVN, not 1.50.


Fri Jan 05, 2007 7:13 pm
Profile
Rookie

Joined: Fri Dec 22, 2006 10:05 pm
Posts: 14
Reply with quote
Post 
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:
Code:
ALSA: underrun, at least 0ms.


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:
Code:
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


Sat Jan 06, 2007 3:30 am
Profile
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
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


Sat Jan 06, 2007 4:53 pm
Profile WWW
Rookie

Joined: Fri Dec 22, 2006 10:05 pm
Posts: 14
Reply with quote
Post 
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.


Sat Jan 06, 2007 6:31 pm
Profile
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
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.

_________________
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding


Sat Jan 06, 2007 9:35 pm
Profile WWW
Rookie

Joined: Tue Apr 25, 2006 4:30 am
Posts: 11
Reply with quote
Post 
Mednafen's solution, SexyAL, is a thin sound layer continued from Xod's work on FCE Ultra. It works very well, outputting to SDL, OSS, ALSA, and Jack with very low latencies.


Tue Jan 16, 2007 3:54 am
Profile
Lurker
User avatar

Joined: Sun Jan 30, 2005 10:06 pm
Posts: 109
Location: Wouldn't you like to know?
Reply with quote
Post 
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.

_________________
SNES Sprite Animations, made by an Insane Killer Robot.
I'm a computer programmer (in C++) and a future game designer.


Wed Jan 17, 2007 8:55 pm
Profile WWW
ZSNES Developer
ZSNES Developer

Joined: Tue Dec 28, 2004 6:47 am
Posts: 6747
Reply with quote
Post 
The whole point of the libao testing is to see if you are able to rid of static or playback issues. It won't fix notable sound emulation problems of course, but certain things should play back better.

_________________
Continuing FF4 Research...


Wed Jan 17, 2007 9:19 pm
Profile
Lurker
User avatar

Joined: Sun Jan 30, 2005 10:06 pm
Posts: 109
Location: Wouldn't you like to know?
Reply with quote
Post 
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.

_________________
SNES Sprite Animations, made by an Insane Killer Robot.
I'm a computer programmer (in C++) and a future game designer.


Thu Jan 18, 2007 4:08 am
Profile WWW
Rookie

Joined: Fri Dec 22, 2006 10:05 pm
Posts: 14
Reply with quote
Post 
With the newest zsnes version, I still got the delay sound problem with libao and alsa output (it's very little delay). But with oss it's ok.


Thu Jan 25, 2007 6:36 pm
Profile
ZSNES Developer
ZSNES Developer
User avatar

Joined: Tue Jul 27, 2004 10:54 pm
Posts: 3901
Location: Solar powered park bench
Reply with quote
Post 
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


Thu Jan 25, 2007 10:47 pm
Profile WWW
Rookie

Joined: Fri Dec 22, 2006 10:05 pm
Posts: 14
Reply with quote
Post 
I know that, I am happy with oss. I was thinking that maybe you wanted to know about that problem. Anyway, is the alsa problem some kind of bug?


Fri Jan 26, 2007 6:21 pm
Profile
ZSNES Developer
ZSNES Developer

Joined: Tue Dec 28, 2004 6:47 am
Posts: 6747
Reply with quote
Post 
The ALSA issue is usually a result of either bad drivers, or just a bad sound API to work with.

_________________
Continuing FF4 Research...


Fri Jan 26, 2007 6:25 pm
Profile
New Member

Joined: Fri Oct 26, 2007 7:04 am
Posts: 2
Location: Ontario, Canada
Reply with quote
Post 
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.


Fri Oct 26, 2007 7:12 am
Profile WWW
Reply with quote
Post 
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-devel-list/2007-October/msg00136.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)


Sat Nov 17, 2007 7:28 pm
New Member

Joined: Fri Oct 26, 2007 7:04 am
Posts: 2
Location: Ontario, Canada
Reply with quote
Post 
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-devel-list/2007-October/msg00136.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.

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.


Sat Nov 17, 2007 9:06 pm
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 136 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next

Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software.