diff -Nru sidplay-base-1.0.9/ChangeLog sidplay-base-1.0.9/ChangeLog --- sidplay-base-1.0.9/ChangeLog 2002-09-28 21:44:02.000000000 +0300 +++ sidplay-base-1.0.9/ChangeLog 2008-07-16 20:22:01.000000000 +0300 @@ -1,3 +1,6 @@ +* Wed Jul 16 2008 Tommi Saviranta +- Added ALSA audio driver. + * Sat Sep 28 2002 Michael Schwendt - Added NetBSD port changes. (Garph) - Added libossaudio on Net/OpenBSD. (reported by Christian Weisgerber) diff -Nru sidplay-base-1.0.9/Makefile.am sidplay-base-1.0.9/Makefile.am --- sidplay-base-1.0.9/Makefile.am 2002-09-28 21:44:02.000000000 +0300 +++ sidplay-base-1.0.9/Makefile.am 2008-07-16 20:32:59.000000000 +0300 @@ -11,7 +11,7 @@ bin_PROGRAMS = sidplay sid2wav sidcon sidplay_SOURCES = sidplay.cpp -sidplay_LDADD = audiodrv.o @SIDPLAY_LDFLAGS@ -lsidplay $(LIBAUDIO) +sidplay_LDADD = audiodrv.o @SIDPLAY_LDFLAGS@ -lsidplay $(LIBAUDIO) $(LIBASOUND) sid2wav_SOURCES = sid2wav.cpp sid2wav_LDADD = @SIDPLAY_LDFLAGS@ -lsidplay diff -Nru sidplay-base-1.0.9/audio/alsa/audiodrv.cpp sidplay-base-1.0.9/audio/alsa/audiodrv.cpp --- sidplay-base-1.0.9/audio/alsa/audiodrv.cpp 1970-01-01 02:00:00.000000000 +0200 +++ sidplay-base-1.0.9/audio/alsa/audiodrv.cpp 2008-07-17 02:12:46.000000000 +0300 @@ -0,0 +1,275 @@ +// -------------------------------------------------------------------------- +// ``Advanced Linux Sound Architecture (ALSA)'' specific audio driver interface. +// -------------------------------------------------------------------------- + +#include "audiodrv.h" + +#include + +#define ALSA_DEFAULT "default" + + +audioDriver::audioDriver() +{ + // Reset everything. + alsa = NULL; + errorString = "None"; + frequency = 0; + channels = 0; + precision = 0; + bufShift = 0; +} + + + +bool audioDriver::IsThere() +{ + // Check device availability and write permissions. + snd_pcm_t *handle; + int err; + err = snd_pcm_open(&handle, ALSA_DEFAULT, SND_PCM_STREAM_PLAYBACK, 0); + if (err < 0) { + return false; + } else if (handle != NULL) { + snd_pcm_close(handle); + return true; + } else { + return false; + } +} + + + +bool audioDriver::SetFormat(snd_pcm_t *handle, + snd_pcm_hw_params_t *hw_params, + int inPrecision) +{ + struct precinfo { + snd_pcm_format_t format; + int encoding; + int precision; + int swap; + }; + struct precinfo info[] = { +#if defined(WORDS_BIGENDIAN) + { SND_PCM_FORMAT_S16_BE, SIDEMU_SIGNED_PCM, + SIDEMU_16BIT, false }, + { SND_PCM_FORMAT_U16_BE, SIDEMU_UNSIGNED_PCM, + SIDEMU_16BIT, false }, + { SND_PCM_FORMAT_S16_LE, SIDEMU_SIGNED_PCM, + SIDEMU_16BIT, true }, + { SND_PCM_FORMAT_U16_LE, SIDEMU_UNSIGNED_PCM, + SIDEMU_16BIT, true }, +#else + { SND_PCM_FORMAT_S16_LE, SIDEMU_SIGNED_PCM, + SIDEMU_16BIT, false }, + { SND_PCM_FORMAT_U16_LE, SIDEMU_UNSIGNED_PCM, + SIDEMU_16BIT, false }, + { SND_PCM_FORMAT_S16_BE, SIDEMU_SIGNED_PCM, + SIDEMU_16BIT, true }, + { SND_PCM_FORMAT_U16_BE, SIDEMU_UNSIGNED_PCM, + SIDEMU_16BIT, true }, +#endif + { SND_PCM_FORMAT_S8, SIDEMU_SIGNED_PCM, + SIDEMU_8BIT, false }, + { SND_PCM_FORMAT_U8, SIDEMU_UNSIGNED_PCM, + SIDEMU_8BIT, false } + }; + + switch (inPrecision) { + case SIDEMU_8BIT: + for (int i = 0; i < 2; i++) { + struct precinfo t; + memcpy(&t, &info[i], sizeof(t)); + memcpy(&info[i + 4], &info[i], sizeof(t)); + memcpy(&info[i], &t, sizeof(t)); + } + break; + case SIDEMU_16BIT: + break; + default: + fprintf(stderr, "unsupported precision: %d bits\n", + inPrecision); + return false; + } + + int err; + for (int i = 0; i < 6; i++) { + err = snd_pcm_hw_params_set_format(handle, hw_params, + info[i].format); + if (err < 0) { + continue; + } + + precision = info[i].precision; + encoding = info[i].encoding; + swapEndian = info[i].swap; + bufShift = info[i].precision == SIDEMU_8BIT ? 0 : 1; + return true; + } + + fprintf(stderr, "cannot set sample format: %s\n", snd_strerror(err)); + return false; +} + + + +bool audioDriver::InitAlsa(snd_pcm_t *handle, int inPrecision, + int inFrequency, int inChannels) +{ + snd_pcm_hw_params_t *hw_params; + unsigned int get; + int err; + + err = snd_pcm_hw_params_malloc(&hw_params); + if (err < 0) { + fprintf(stderr, "cannot allocate hardware " + "parameter structure: %s\n", + snd_strerror(err)); + return false; + } + + err = snd_pcm_hw_params_any(handle, hw_params); + if (err < 0) { + fprintf(stderr, "cannot initialize hardware " + "parameter structure: %s\n", + snd_strerror(err)); + snd_pcm_hw_params_free(hw_params); + return false; + } + + err = snd_pcm_hw_params_set_access(handle, hw_params, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (err < 0) { + fprintf(stderr, "cannot set access type: %s\n", + snd_strerror(err)); + snd_pcm_hw_params_free(hw_params); + return false; + } + + /* try to find supported format/precision */ + if (! SetFormat(handle, hw_params, inPrecision)) { + snd_pcm_hw_params_free(hw_params); + return false; + } + + /* use closest frequency */ + get = (unsigned int) inFrequency; + err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &get, 0); + if (err < 0) { + fprintf(stderr, "cannot set sample rate: %s\n", + snd_strerror(err)); + snd_pcm_hw_params_free(hw_params); + return false; + } + if (get != (unsigned int) inFrequency) { + frequency = get; + } + + int chancount; + switch (inChannels) { + case SIDEMU_STEREO: + chancount = 2; + channels = SIDEMU_STEREO; + bufShift++; + break; + case SIDEMU_MONO: + chancount = 1; + channels = SIDEMU_MONO; + break; + default: + fprintf(stderr, "unsupported channel count: %d\n", + inChannels); + snd_pcm_hw_params_free(hw_params); + return false; + } + err = snd_pcm_hw_params_set_channels(handle, hw_params, chancount); + if (err < 0) { + fprintf(stderr, "cannot set channel count: %s\n", + snd_strerror(err)); + snd_pcm_hw_params_free(hw_params); + return false; + } + + err = snd_pcm_hw_params(handle, hw_params); + if (err < 0) { + fprintf(stderr, "cannot set parameters: %s\n", + snd_strerror(err)); + snd_pcm_hw_params_free(hw_params); + return false; + } + + snd_pcm_hw_params_free(hw_params); + + err = snd_pcm_prepare(handle); + if (err < 0) { + fprintf(stderr, "cannot prepare audio interface for use: %s\n", + snd_strerror(err)); + return false; + } + + return true; +} + + + +bool audioDriver::Open(udword inFreq, int inPrecision, int inChannels, + int inFragments, int inFragBase) +{ + bool ret; + int err; + snd_pcm_t *handle; + + /* set wanted values, may be overwritten */ + frequency = inFreq; + precision = inPrecision; + channels = inChannels; + + err = snd_pcm_open(&handle, ALSA_DEFAULT, SND_PCM_STREAM_PLAYBACK, 0); + if (err < 0) { + fprintf(stderr, "cannot open audio device: %s\n", + snd_strerror(err)); + errorString = "ERROR: Could not open audio device."; + return false; + } + + ret = InitAlsa(handle, inPrecision, inFreq, inChannels); + if (ret == false) { + errorString = "ERROR: Could not initialise audio device."; + snd_pcm_close(handle); + return false; + } + + alsa = handle; + blockSize = 4096; + + return true; +} + + + +// Close an opened audio device, free any allocated buffers and +// reset any variables that reflect the current state. +void audioDriver::Close() +{ + if (alsa != NULL) { + snd_pcm_close(alsa); + alsa = NULL; + } +} + + + +void audioDriver::Play(ubyte* pBuffer, int bufferSize) +{ + if (alsa != NULL) { + if (swapEndian) { + for (int n = 0; n < bufferSize; n += 2) { + ubyte tmp = pBuffer[n + 0]; + pBuffer[n + 0] = pBuffer[n + 1]; + pBuffer[n + 1] = tmp; + } + } + snd_pcm_writei(alsa, pBuffer, bufferSize >> bufShift); + } +} diff -Nru sidplay-base-1.0.9/audio/alsa/audiodrv.h sidplay-base-1.0.9/audio/alsa/audiodrv.h --- sidplay-base-1.0.9/audio/alsa/audiodrv.h 1970-01-01 02:00:00.000000000 +0200 +++ sidplay-base-1.0.9/audio/alsa/audiodrv.h 2008-07-17 02:12:50.000000000 +0300 @@ -0,0 +1,102 @@ +// -------------------------------------------------------------------------- +// ``Advanced Linux Sound Architecture (ALSA)'' specific audio driver interface. +// -------------------------------------------------------------------------- + +#ifndef AUDIODRV_H +#define AUDIODRV_H + + +#include + +#include + +class audioDriver +{ + + public: + audioDriver(); + + bool IsThere(); + + bool InitAlsa(snd_pcm_t *handle, int bits, int freq, int chans); + + bool SetFormat(snd_pcm_t *handle, snd_pcm_hw_params_t *hw_params, + int inPrecision); + + bool Open(udword freq, int precision, int channels, + int fragments, int fragBase); + + void Close(); + + void Play(ubyte* buffer, int bufferSize); + + bool Reset() + { + return true; + } + + snd_pcm_t *GetAudioHandle() + { + return alsa; + } + + udword GetFrequency() + { + return frequency; + } + + int GetChannels() + { + return channels; + } + + int GetSamplePrecision() + { + return precision; + } + + int GetSampleEncoding() + { + return encoding; + } + + int GetBlockSize() + { + return blockSize; + } + + int GetFragments() + { + return 0; + } + + int GetFragSizeBase() + { + return 0; + } + + const char *GetErrorString() + { + return errorString; + } + + private: + static const char AUDIODEVICE[]; + snd_pcm_t *alsa; + + const char *errorString; + + int blockSize; + + udword frequency; + + // These are constants/enums from ``libsidplay/include/emucfg.h''. + int encoding; + int precision; + int channels; + int bufShift; + bool swapEndian; +}; + + +#endif // AUDIODRV_H diff -Nru sidplay-base-1.0.9/configure.in sidplay-base-1.0.9/configure.in --- sidplay-base-1.0.9/configure.in 2008-07-16 20:17:26.000000000 +0300 +++ sidplay-base-1.0.9/configure.in 2008-07-16 20:34:30.000000000 +0300 @@ -28,14 +28,26 @@ AC_CHECK_HEADERS(sys/ioctl.h linux/soundcard.h machine/soundcard.h \ soundcard.h sys/audio.h sun/audioio.h sun/dbriio.h sys/audioio.h \ audio.h dmedia/audio.h) +AC_CHECK_HEADER(alsa/asoundlib.h, [HAVE_ALSA=1]) AC_PATH_PROG(CP,cp,cp) dnl NetBSD, OpenBSD AC_CHECK_LIB(ossaudio, main, [LIBAUDIO=-lossaudio AC_SUBST(LIBAUDIO)]) +dnl ALSA +AC_CHECK_LIB(asound, snd_pcm_open, [LIBASOUND=-lasound AC_SUBST(LIBASOUND)]) + +# get sound driver from host, but use alsa if available +audio="$host" +test "$HAVE_ALSA" -a "$LIBASOUND" && audio="alsa" + AC_MSG_CHECKING(which audio driver to install) -case "$host" in +case "$audio" in + alsa) AC_DEFINE(HAVE_LINUX,1) + $CP audio/alsa/* . + AC_MSG_RESULT(alsa) + ;; *linux*) AC_DEFINE(HAVE_LINUX,1) $CP audio/oss/* . AC_MSG_RESULT(oss)