diff -uNr uae-0.8.22-org/configure.in uae-0.8.22/configure.in --- uae-0.8.22-org/configure.in 2004-09-11 20:16:30.151434416 +0300 +++ uae-0.8.22/configure.in 2004-09-11 20:16:41.469713776 +0300 @@ -230,7 +230,8 @@ AC_ARG_WITH(svgalib,[ --with-svgalib Use SVGAlib for graphics output],[WANT_SVGALIB=$withval],[]) AC_ARG_WITH(sdl,[ --with-sdl Use SDL library for low-level functions],[WANT_SDL=$withval],[]) AC_ARG_WITH(sdl-sound,[ --with-sdl-sound Use SDL library for sound],[WANT_SDLSND=$withval],[]) -AC_ARG_WITH(sdl-gfx,[ --with-sdl-gfx Use SDL library for graphics],[WANT_SDLGFX=$withval],[]) +AC_ARG_WITH(sdl-gfx,[ --with-sdl-gfx Use SDL library for graphics],[WANT_SDLGFX=$withval],[]) +AC_ARG_WITH(alsa,[ --with-alsa Use ALSA library for sound],[WANT_ALSA=$withval],[]) AC_ARG_WITH(asciiart,[ --with-asciiart Use ncurses ascii art for graphics output],[WANT_ASCIIART=$withval],[]) AC_ARG_ENABLE(dga,[ --enable-dga X11 version: Use the DGA extension],[WANT_DGA=$enableval],[]) AC_ARG_ENABLE(vidmode,[ --enable-vidmode X11 version: Use the XF86VidMode extension],[WANT_VIDMODE=$enableval],[]) @@ -256,6 +257,10 @@ fi fi +if [[ "x$WANT_ALSA" = "xyes" ]]; then + LIBS="$LIBS -lasound" +fi + if [[ "x$WANT_DGA" = "xyes" ]]; then if [[ "x$WANT_SVGALIB" = "xyes" -o "x$WANT_ASCIIART" = "xyes" -o "x$WANT_SDLGFX" = "xyes" ]]; then echo "You can't enable DGA for SVGAlib, SDL and ncurses targets!" @@ -853,6 +858,10 @@ SOUNDDEP=sd-sdl USE_SOUND=yes NEED_THREAD_SUPPORT=yes +else if [[ "x$WANT_ALSA" = "xyes" ]]; then + AC_MSG_RESULT(ALSA) + SOUNDDEP=sd-alsa + USE_SOUND=yes else if [[ "x$HAVE_USS_SOUND" = "xyes" ]]; then AC_MSG_RESULT(USS) SOUNDDEP=sd-uss @@ -910,6 +919,7 @@ fi fi fi +fi if [[ "x$NEED_THREAD_SUPPORT" = "xyes" ]]; then if [[ "x$USE_THREADS" != "xyes" ]]; then diff -uNr uae-0.8.22-org/src/sd-alsa/sound.c uae-0.8.22/src/sd-alsa/sound.c --- uae-0.8.22-org/src/sd-alsa/sound.c 1970-01-01 02:00:00.000000000 +0200 +++ uae-0.8.22/src/sd-alsa/sound.c 2004-09-11 20:17:00.390837328 +0300 @@ -0,0 +1,188 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Support for Linux/ALSA sound + * + * Copyright 1997 Bernd Schmidt + * Copyright 2004 Heikki Orsila + * + * BUGS: certainly + * TODO: + * - if setup_sound() fails, there may still be hope to get the + * sound device, but we totally give up.. see sd-uss. + */ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "config.h" +#include "options.h" +#include "memory.h" +#include "events.h" +#include "custom.h" +#include "gensound.h" +#include "sounddep/sound.h" + +#include + +int sound_fd; +static int have_sound = 0; +static unsigned long formats; + +uae_u16 sndbuffer[44100]; +uae_u16 *sndbufpt; +int sndbufsize; + +snd_pcm_t *alsa_playback_handle = 0; +int alsa_to_frames_divisor = 4; + +void close_sound (void) +{ + if (alsa_playback_handle) { + snd_pcm_close (alsa_playback_handle); + alsa_playback_handle = 0; + } +} + +static int open_sound(void) +{ + return snd_pcm_open (&alsa_playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0); +} + +/* Try to determine whether sound is available. This is only for GUI purposes. */ +int setup_sound (void) +{ + int err; + sound_available = 0; + if ((err = open_sound()) < 0) { + /* TODO: if the pcm was busy, we should the same as sd-uss does. + tell the caller that sound is available. in any other + condition we should just return 0. */ + fprintf (stderr, "cannot open audio device (%s)\n", snd_strerror (err)); + return 0; + } + snd_pcm_close (alsa_playback_handle); + alsa_playback_handle = 0; + sound_available = 1; + return 1; +} + +int init_sound (void) +{ + int tmp; + int rate; + int dspbits; + int alsamode; + int channels; + int err; + snd_pcm_hw_params_t *hw_params; + snd_pcm_uframes_t buffer_frames; + + dspbits = currprefs.sound_bits; + channels = currprefs.stereo ? 2 : 1; + rate = currprefs.sound_freq; + + have_sound = 0; + alsa_playback_handle = 0; + if ((err = open_sound()) < 0) { + fprintf (stderr, "cannot open audio device (%s)\n", snd_strerror (err)); + goto nosound; + } + + if (currprefs.sound_maxbsiz < 128 || currprefs.sound_maxbsiz > 16384) { + fprintf (stderr, "Sound buffer size %d out of range.\n", currprefs.sound_maxbsiz); + currprefs.sound_maxbsiz = 8192; + } + sndbufsize = currprefs.sound_maxbsiz; + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { + fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", + snd_strerror (err)); + goto nosound; + } + + if ((err = snd_pcm_hw_params_any (alsa_playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", + snd_strerror (err)); + goto nosound; + } + + if ((err = snd_pcm_hw_params_set_access (alsa_playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf (stderr, "cannot set access type (%s)\n", + snd_strerror (err)); + goto nosound; + } + + switch (dspbits) { + case 8: + alsamode = SND_PCM_FORMAT_U8; + break; + case 16: + alsamode = SND_PCM_FORMAT_S16; + break; + default: + fprintf(stderr, "%d bit samples not supported with uae's alsa\n", dspbits); + goto nosound; + } + + if ((err = snd_pcm_hw_params_set_format (alsa_playback_handle, hw_params, alsamode)) < 0) { + fprintf (stderr, "cannot set sample format (%s)\n", + snd_strerror (err)); + goto nosound; + } + + if ((err = snd_pcm_hw_params_set_channels (alsa_playback_handle, hw_params, channels)) < 0) { + fprintf (stderr, "cannot set channel count (%s)\n", + snd_strerror (err)); + goto nosound; + } + + if ((err = snd_pcm_hw_params_set_rate_near (alsa_playback_handle, hw_params, &rate, 0)) < 0) { + fprintf (stderr, "cannot set sample rate (%s)\n", + snd_strerror (err)); + goto nosound; + } + + alsa_to_frames_divisor = channels * dspbits / 8; + buffer_frames = sndbufsize / alsa_to_frames_divisor; + if ((err = snd_pcm_hw_params_set_period_size_near(alsa_playback_handle, hw_params, &buffer_frames, 0)) < 0) { + fprintf (stderr, "cannot set period size near (%s)\n", snd_strerror (err)); + goto nosound; + } + + if ((err = snd_pcm_hw_params (alsa_playback_handle, hw_params)) < 0) { + fprintf (stderr, "cannot set parameters (%s)\n", + snd_strerror (err)); + goto nosound; + } + + snd_pcm_hw_params_free (hw_params); + + if ((err = snd_pcm_prepare (alsa_playback_handle)) < 0) { + fprintf (stderr, "cannot prepare audio interface for use (%s)\n", + snd_strerror (err)); + goto nosound; + } + + scaled_sample_evtime = (unsigned long) MAXHPOS_PAL * MAXVPOS_PAL * VBLANK_HZ_PAL * CYCLE_UNIT / rate; + scaled_sample_evtime_ok = 1; + + if (dspbits == 16) { + init_sound_table16 (); + sample_handler = currprefs.stereo ? sample16s_handler : sample16_handler; + } else { + init_sound_table8 (); + sample_handler = currprefs.stereo ? sample8s_handler : sample8_handler; + } + have_sound = 1; + sound_available = 1; + printf ("Sound driver found and configured for %d bits at %d Hz, buffer is %d bytes\n", dspbits, rate, sndbufsize); + + sndbufpt = sndbuffer; + return 1; + + nosound: + have_sound = 0; + close_sound(); + return 0; +} diff -uNr uae-0.8.22-org/src/sd-alsa/sound.h uae-0.8.22/src/sd-alsa/sound.h --- uae-0.8.22-org/src/sd-alsa/sound.h 1970-01-01 02:00:00.000000000 +0200 +++ uae-0.8.22/src/sd-alsa/sound.h 2004-09-11 20:16:41.470713624 +0300 @@ -0,0 +1,84 @@ + /* + * UAE - The Un*x Amiga Emulator + * + * Support for Linux/ALSA sound + * + * Copyright 1997 Bernd Schmidt + * Copyright 2004 Heikki Orsila + */ + +#include + +extern int sound_fd; +extern uae_u16 sndbuffer[]; +extern uae_u16 *sndbufpt; +extern int sndbufsize; +extern snd_pcm_t *alsa_playback_handle; +extern int alsa_to_frames_divisor; + +/* alsa_xrun_recovery() function is copied from ALSA manual. why the hell did + they make ALSA this hard?! i bet 95% of ALSA programmers would like a + simpler way to do error handling.. let the 5% use tricky APIs. +*/ +static int alsa_xrun_recovery(snd_pcm_t *handle, int err) +{ + if (err == -EPIPE) { + /* under-run */ + err = snd_pcm_prepare(handle); + if (err < 0) + fprintf(stderr, "uae: no recovery with alsa from underrun, prepare failed: %s\n", snd_strerror(err)); + return 0; + } else if (err == -ESTRPIPE) { + while ((err = snd_pcm_resume(handle)) == -EAGAIN) { + /* wait until the suspend flag is released */ + fprintf(stderr, "uae: sleeping for alsa.\n"); + sleep(1); + } + if (err < 0) { + err = snd_pcm_prepare(handle); + if (err < 0) + fprintf(stderr, "uae: no recovery with alsa from suspend, prepare failed: %s\n", snd_strerror(err)); + } + return 0; + } + return err; +} + +static void check_sound_buffers (void) +{ + if ((char *)sndbufpt - (char *)sndbuffer >= sndbufsize) { + int frames = sndbufsize / alsa_to_frames_divisor; + char *buf = (char *) sndbuffer; + int ret; + while (frames > 0) { + ret = snd_pcm_writei(alsa_playback_handle, buf, frames); + if (ret < 0) { + if (ret == -EAGAIN || ret == -EINTR) + continue; + if (alsa_xrun_recovery(alsa_playback_handle, ret) < 0) { + fprintf(stderr, "uae: write error with alsa: %s\n", snd_strerror(ret)); + exit(-1); + } + continue; + } + frames -= ret; + buf += ret * alsa_to_frames_divisor; + } + sndbufpt = sndbuffer; + } +} + +#define PUT_SOUND_BYTE(b) do { *(uae_u8 *)sndbufpt = b; sndbufpt = (uae_u16 *)(((uae_u8 *)sndbufpt) + 1); } while (0) +#define PUT_SOUND_WORD(b) do { *(uae_u16 *)sndbufpt = b; sndbufpt = (uae_u16 *)(((uae_u8 *)sndbufpt) + 2); } while (0) +#define PUT_SOUND_BYTE_LEFT(b) PUT_SOUND_BYTE(b) +#define PUT_SOUND_WORD_LEFT(b) PUT_SOUND_WORD(b) +#define PUT_SOUND_BYTE_RIGHT(b) PUT_SOUND_BYTE(b) +#define PUT_SOUND_WORD_RIGHT(b) PUT_SOUND_WORD(b) +#define SOUND16_BASE_VAL 0 +#define SOUND8_BASE_VAL 128 + +#define DEFAULT_SOUND_MAXB 8192 +#define DEFAULT_SOUND_MINB 8192 +#define DEFAULT_SOUND_BITS 16 +#define DEFAULT_SOUND_FREQ 44100 +#define HAVE_STEREO_SUPPORT