summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/SDL_audio.c695
-rw-r--r--src/audio/SDL_audio_c.h34
-rw-r--r--src/audio/SDL_audiocvt.c1510
-rw-r--r--src/audio/SDL_audiodev.c179
-rw-r--r--src/audio/SDL_audiodev_c.h26
-rw-r--r--src/audio/SDL_audiomem.h25
-rw-r--r--src/audio/SDL_mixer.c264
-rw-r--r--src/audio/SDL_mixer_MMX.c207
-rw-r--r--src/audio/SDL_mixer_MMX.h17
-rw-r--r--src/audio/SDL_mixer_MMX_VC.c183
-rw-r--r--src/audio/SDL_mixer_MMX_VC.h38
-rw-r--r--src/audio/SDL_mixer_m68k.c211
-rw-r--r--src/audio/SDL_mixer_m68k.h36
-rw-r--r--src/audio/SDL_sysaudio.h184
-rw-r--r--src/audio/SDL_wave.c600
-rw-r--r--src/audio/SDL_wave.h62
-rw-r--r--src/audio/alsa/SDL_alsa_audio.c612
-rw-r--r--src/audio/alsa/SDL_alsa_audio.h48
-rw-r--r--src/audio/arts/SDL_artsaudio.c348
-rw-r--r--src/audio/arts/SDL_artsaudio.h60
-rw-r--r--src/audio/baudio/SDL_beaudio.cc225
-rw-r--r--src/audio/baudio/SDL_beaudio.h39
-rw-r--r--src/audio/bsd/SDL_bsdaudio.c404
-rw-r--r--src/audio/bsd/SDL_bsdaudio.h58
-rw-r--r--src/audio/dart/SDL_dart.c441
-rw-r--r--src/audio/dart/SDL_dart.h63
-rw-r--r--src/audio/dc/SDL_dcaudio.c246
-rw-r--r--src/audio/dc/SDL_dcaudio.h41
-rw-r--r--src/audio/dc/aica.c271
-rw-r--r--src/audio/dc/aica.h40
-rw-r--r--src/audio/disk/SDL_diskaudio.c186
-rw-r--r--src/audio/disk/SDL_diskaudio.h41
-rw-r--r--src/audio/dma/SDL_dmaaudio.c455
-rw-r--r--src/audio/dma/SDL_dmaaudio.h59
-rw-r--r--src/audio/dmedia/SDL_irixaudio.c242
-rw-r--r--src/audio/dmedia/SDL_irixaudio.h45
-rw-r--r--src/audio/dsp/SDL_dspaudio.c340
-rw-r--r--src/audio/dsp/SDL_dspaudio.h53
-rw-r--r--src/audio/dummy/SDL_dummyaudio.c156
-rw-r--r--src/audio/dummy/SDL_dummyaudio.h40
-rw-r--r--src/audio/esd/SDL_esdaudio.c323
-rw-r--r--src/audio/esd/SDL_esdaudio.h57
-rw-r--r--src/audio/macosx/SDL_coreaudio.c291
-rw-r--r--src/audio/macosx/SDL_coreaudio.h45
-rw-r--r--src/audio/macrom/SDL_romaudio.c496
-rw-r--r--src/audio/macrom/SDL_romaudio.h50
-rw-r--r--src/audio/mint/SDL_mintaudio.c215
-rw-r--r--src/audio/mint/SDL_mintaudio.h157
-rw-r--r--src/audio/mint/SDL_mintaudio_dma8.c361
-rw-r--r--src/audio/mint/SDL_mintaudio_dma8.h85
-rw-r--r--src/audio/mint/SDL_mintaudio_gsxb.c436
-rw-r--r--src/audio/mint/SDL_mintaudio_gsxb.h108
-rw-r--r--src/audio/mint/SDL_mintaudio_it.S281
-rw-r--r--src/audio/mint/SDL_mintaudio_mcsn.c404
-rw-r--r--src/audio/mint/SDL_mintaudio_mcsn.h59
-rw-r--r--src/audio/mint/SDL_mintaudio_stfa.c323
-rw-r--r--src/audio/mint/SDL_mintaudio_stfa.h100
-rw-r--r--src/audio/mint/SDL_mintaudio_xbios.c495
-rw-r--r--src/audio/mme/SDL_mmeaudio.c264
-rw-r--r--src/audio/mme/SDL_mmeaudio.h51
-rw-r--r--src/audio/nas/SDL_nasaudio.c423
-rw-r--r--src/audio/nas/SDL_nasaudio.h62
-rw-r--r--src/audio/nds/SDL_ndsaudio.c335
-rw-r--r--src/audio/nds/SDL_ndsaudio.h40
-rw-r--r--src/audio/nds/sound9.c61
-rw-r--r--src/audio/nds/soundcommon.h80
-rw-r--r--src/audio/nto/SDL_nto_audio.c507
-rw-r--r--src/audio/nto/SDL_nto_audio.h68
-rw-r--r--src/audio/paudio/SDL_paudio.c511
-rw-r--r--src/audio/paudio/SDL_paudio.h57
-rw-r--r--src/audio/pulse/SDL_pulseaudio.c534
-rw-r--r--src/audio/pulse/SDL_pulseaudio.h71
-rw-r--r--src/audio/sun/SDL_sunaudio.c432
-rw-r--r--src/audio/sun/SDL_sunaudio.h55
-rw-r--r--src/audio/symbian/SDL_epocaudio.cpp614
-rw-r--r--src/audio/symbian/SDL_epocaudio.h37
-rw-r--r--src/audio/symbian/streamplayer.cpp279
-rw-r--r--src/audio/symbian/streamplayer.h89
-rw-r--r--src/audio/ums/SDL_umsaudio.c547
-rw-r--r--src/audio/ums/SDL_umsaudio.h50
-rw-r--r--src/audio/windib/SDL_dibaudio.c322
-rw-r--r--src/audio/windib/SDL_dibaudio.h49
-rw-r--r--src/audio/windx5/SDL_dx5audio.c705
-rw-r--r--src/audio/windx5/SDL_dx5audio.h55
-rw-r--r--src/audio/windx5/directx.h84
85 files changed, 19452 insertions, 0 deletions
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
new file mode 100644
index 0000000..bdeacdc
--- /dev/null
+++ b/src/audio/SDL_audio.c
@@ -0,0 +1,695 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include "SDL.h"
+#include "SDL_audio_c.h"
+#include "SDL_audiomem.h"
+#include "SDL_sysaudio.h"
+
+#ifdef __OS2__
+/* We'll need the DosSetPriority() API! */
+#define INCL_DOSPROCESS
+#include <os2.h>
+#endif
+
+/* Available audio drivers */
+static AudioBootStrap *bootstrap[] = {
+#if SDL_AUDIO_DRIVER_BSD
+ &BSD_AUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_PULSE
+ &PULSE_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ALSA
+ &ALSA_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_OSS
+ &DSP_bootstrap,
+ &DMA_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_QNXNTO
+ &QNXNTOAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_SUNAUDIO
+ &SUNAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DMEDIA
+ &DMEDIA_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ARTS
+ &ARTS_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_ESD
+ &ESD_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_NAS
+ &NAS_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DSOUND
+ &DSOUND_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_WAVEOUT
+ &WAVEOUT_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_PAUD
+ &Paud_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_BAUDIO
+ &BAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_COREAUDIO
+ &COREAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_SNDMGR
+ &SNDMGR_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_MINT
+ &MINTAUDIO_GSXB_bootstrap,
+ &MINTAUDIO_MCSN_bootstrap,
+ &MINTAUDIO_STFA_bootstrap,
+ &MINTAUDIO_XBIOS_bootstrap,
+ &MINTAUDIO_DMA8_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DISK
+ &DISKAUD_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DUMMY
+ &DUMMYAUD_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DC
+ &DCAUD_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_NDS
+ &NDSAUD_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_MMEAUDIO
+ &MMEAUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_DART
+ &DART_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_EPOCAUDIO
+ &EPOCAudio_bootstrap,
+#endif
+ NULL
+};
+SDL_AudioDevice *current_audio = NULL;
+
+/* Various local functions */
+int SDL_AudioInit(const char *driver_name);
+void SDL_AudioQuit(void);
+
+/* The general mixing thread function */
+int SDLCALL SDL_RunAudio(void *audiop)
+{
+ SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
+ Uint8 *stream;
+ int stream_len;
+ void *udata;
+ void (SDLCALL *fill)(void *userdata,Uint8 *stream, int len);
+ int silence;
+
+ /* Perform any thread setup */
+ if ( audio->ThreadInit ) {
+ audio->ThreadInit(audio);
+ }
+ audio->threadid = SDL_ThreadID();
+
+ /* Set up the mixing function */
+ fill = audio->spec.callback;
+ udata = audio->spec.userdata;
+
+ if ( audio->convert.needed ) {
+ if ( audio->convert.src_format == AUDIO_U8 ) {
+ silence = 0x80;
+ } else {
+ silence = 0;
+ }
+ stream_len = audio->convert.len;
+ } else {
+ silence = audio->spec.silence;
+ stream_len = audio->spec.size;
+ }
+
+#ifdef __OS2__
+ /* Increase the priority of this thread to make sure that
+ the audio will be continuous all the time! */
+#ifdef USE_DOSSETPRIORITY
+ if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO"))
+ {
+#ifdef DEBUG_BUILD
+ printf("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n", SDL_ThreadID());
+#endif
+ DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
+ }
+ else
+ {
+#ifdef DEBUG_BUILD
+ printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
+#endif
+ DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
+ }
+#endif
+#endif
+
+ /* Loop, filling the audio buffers */
+ while ( audio->enabled ) {
+
+ /* Fill the current buffer with sound */
+ if ( audio->convert.needed ) {
+ if ( audio->convert.buf ) {
+ stream = audio->convert.buf;
+ } else {
+ continue;
+ }
+ } else {
+ stream = audio->GetAudioBuf(audio);
+ if ( stream == NULL ) {
+ stream = audio->fake_stream;
+ }
+ }
+
+ SDL_memset(stream, silence, stream_len);
+
+ if ( ! audio->paused ) {
+ SDL_mutexP(audio->mixer_lock);
+ (*fill)(udata, stream, stream_len);
+ SDL_mutexV(audio->mixer_lock);
+ }
+
+ /* Convert the audio if necessary */
+ if ( audio->convert.needed ) {
+ SDL_ConvertAudio(&audio->convert);
+ stream = audio->GetAudioBuf(audio);
+ if ( stream == NULL ) {
+ stream = audio->fake_stream;
+ }
+ SDL_memcpy(stream, audio->convert.buf,
+ audio->convert.len_cvt);
+ }
+
+ /* Ready current buffer for play and change current buffer */
+ if ( stream != audio->fake_stream ) {
+ audio->PlayAudio(audio);
+ }
+
+ /* Wait for an audio buffer to become available */
+ if ( stream == audio->fake_stream ) {
+ SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
+ } else {
+ audio->WaitAudio(audio);
+ }
+ }
+
+ /* Wait for the audio to drain.. */
+ if ( audio->WaitDone ) {
+ audio->WaitDone(audio);
+ }
+
+#ifdef __OS2__
+#ifdef DEBUG_BUILD
+ printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
+#endif
+#endif
+ return(0);
+}
+
+static void SDL_LockAudio_Default(SDL_AudioDevice *audio)
+{
+ if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
+ return;
+ }
+ SDL_mutexP(audio->mixer_lock);
+}
+
+static void SDL_UnlockAudio_Default(SDL_AudioDevice *audio)
+{
+ if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
+ return;
+ }
+ SDL_mutexV(audio->mixer_lock);
+}
+
+static Uint16 SDL_ParseAudioFormat(const char *string)
+{
+ Uint16 format = 0;
+
+ switch (*string) {
+ case 'U':
+ ++string;
+ format |= 0x0000;
+ break;
+ case 'S':
+ ++string;
+ format |= 0x8000;
+ break;
+ default:
+ return 0;
+ }
+ switch (SDL_atoi(string)) {
+ case 8:
+ string += 1;
+ format |= 8;
+ break;
+ case 16:
+ string += 2;
+ format |= 16;
+ if ( SDL_strcmp(string, "LSB") == 0
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+ || SDL_strcmp(string, "SYS") == 0
+#endif
+ ) {
+ format |= 0x0000;
+ }
+ if ( SDL_strcmp(string, "MSB") == 0
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ || SDL_strcmp(string, "SYS") == 0
+#endif
+ ) {
+ format |= 0x1000;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return format;
+}
+
+int SDL_AudioInit(const char *driver_name)
+{
+ SDL_AudioDevice *audio;
+ int i = 0, idx;
+
+ /* Check to make sure we don't overwrite 'current_audio' */
+ if ( current_audio != NULL ) {
+ SDL_AudioQuit();
+ }
+
+ /* Select the proper audio driver */
+ audio = NULL;
+ idx = 0;
+#if SDL_AUDIO_DRIVER_ESD
+ if ( (driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL) ) {
+ /* Ahem, we know that if ESPEAKER is set, user probably wants
+ to use ESD, but don't start it if it's not already running.
+ This probably isn't the place to do this, but... Shh! :)
+ */
+ for ( i=0; bootstrap[i]; ++i ) {
+ if ( SDL_strcasecmp(bootstrap[i]->name, "esd") == 0 ) {
+#ifdef HAVE_PUTENV
+ const char *esd_no_spawn;
+
+ /* Don't start ESD if it's not running */
+ esd_no_spawn = getenv("ESD_NO_SPAWN");
+ if ( esd_no_spawn == NULL ) {
+ putenv("ESD_NO_SPAWN=1");
+ }
+#endif
+ if ( bootstrap[i]->available() ) {
+ audio = bootstrap[i]->create(0);
+ break;
+ }
+#ifdef HAVE_UNSETENV
+ if ( esd_no_spawn == NULL ) {
+ unsetenv("ESD_NO_SPAWN");
+ }
+#endif
+ }
+ }
+ }
+#endif /* SDL_AUDIO_DRIVER_ESD */
+ if ( audio == NULL ) {
+ if ( driver_name != NULL ) {
+#if 0 /* This will be replaced with a better driver selection API */
+ if ( SDL_strrchr(driver_name, ':') != NULL ) {
+ idx = atoi(SDL_strrchr(driver_name, ':')+1);
+ }
+#endif
+ for ( i=0; bootstrap[i]; ++i ) {
+ if (SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0) {
+ if ( bootstrap[i]->available() ) {
+ audio=bootstrap[i]->create(idx);
+ break;
+ }
+ }
+ }
+ } else {
+ for ( i=0; bootstrap[i]; ++i ) {
+ if ( bootstrap[i]->available() ) {
+ audio = bootstrap[i]->create(idx);
+ if ( audio != NULL ) {
+ break;
+ }
+ }
+ }
+ }
+ if ( audio == NULL ) {
+ SDL_SetError("No available audio device");
+#if 0 /* Don't fail SDL_Init() if audio isn't available.
+ SDL_OpenAudio() will handle it at that point. *sigh*
+ */
+ return(-1);
+#endif
+ }
+ }
+ current_audio = audio;
+ if ( current_audio ) {
+ current_audio->name = bootstrap[i]->name;
+ if ( !current_audio->LockAudio && !current_audio->UnlockAudio ) {
+ current_audio->LockAudio = SDL_LockAudio_Default;
+ current_audio->UnlockAudio = SDL_UnlockAudio_Default;
+ }
+ }
+ return(0);
+}
+
+char *SDL_AudioDriverName(char *namebuf, int maxlen)
+{
+ if ( current_audio != NULL ) {
+ SDL_strlcpy(namebuf, current_audio->name, maxlen);
+ return(namebuf);
+ }
+ return(NULL);
+}
+
+int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
+{
+ SDL_AudioDevice *audio;
+ const char *env;
+
+ /* Start up the audio driver, if necessary */
+ if ( ! current_audio ) {
+ if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
+ (current_audio == NULL) ) {
+ return(-1);
+ }
+ }
+ audio = current_audio;
+
+ if (audio->opened) {
+ SDL_SetError("Audio device is already opened");
+ return(-1);
+ }
+
+ /* Verify some parameters */
+ if ( desired->freq == 0 ) {
+ env = SDL_getenv("SDL_AUDIO_FREQUENCY");
+ if ( env ) {
+ desired->freq = SDL_atoi(env);
+ }
+ }
+ if ( desired->freq == 0 ) {
+ /* Pick some default audio frequency */
+ desired->freq = 22050;
+ }
+ if ( desired->format == 0 ) {
+ env = SDL_getenv("SDL_AUDIO_FORMAT");
+ if ( env ) {
+ desired->format = SDL_ParseAudioFormat(env);
+ }
+ }
+ if ( desired->format == 0 ) {
+ /* Pick some default audio format */
+ desired->format = AUDIO_S16;
+ }
+ if ( desired->channels == 0 ) {
+ env = SDL_getenv("SDL_AUDIO_CHANNELS");
+ if ( env ) {
+ desired->channels = (Uint8)SDL_atoi(env);
+ }
+ }
+ if ( desired->channels == 0 ) {
+ /* Pick a default number of channels */
+ desired->channels = 2;
+ }
+ switch ( desired->channels ) {
+ case 1: /* Mono */
+ case 2: /* Stereo */
+ case 4: /* surround */
+ case 6: /* surround with center and lfe */
+ break;
+ default:
+ SDL_SetError("1 (mono) and 2 (stereo) channels supported");
+ return(-1);
+ }
+ if ( desired->samples == 0 ) {
+ env = SDL_getenv("SDL_AUDIO_SAMPLES");
+ if ( env ) {
+ desired->samples = (Uint16)SDL_atoi(env);
+ }
+ }
+ if ( desired->samples == 0 ) {
+ /* Pick a default of ~46 ms at desired frequency */
+ int samples = (desired->freq / 1000) * 46;
+ int power2 = 1;
+ while ( power2 < samples ) {
+ power2 *= 2;
+ }
+ desired->samples = power2;
+ }
+ if ( desired->callback == NULL ) {
+ SDL_SetError("SDL_OpenAudio() passed a NULL callback");
+ return(-1);
+ }
+
+#if SDL_THREADS_DISABLED
+ /* Uses interrupt driven audio, without thread */
+#else
+ /* Create a semaphore for locking the sound buffers */
+ audio->mixer_lock = SDL_CreateMutex();
+ if ( audio->mixer_lock == NULL ) {
+ SDL_SetError("Couldn't create mixer lock");
+ SDL_CloseAudio();
+ return(-1);
+ }
+#endif /* SDL_THREADS_DISABLED */
+
+ /* Calculate the silence and size of the audio specification */
+ SDL_CalculateAudioSpec(desired);
+
+ /* Open the audio subsystem */
+ SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
+ audio->convert.needed = 0;
+ audio->enabled = 1;
+ audio->paused = 1;
+
+ audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
+
+ if ( ! audio->opened ) {
+ SDL_CloseAudio();
+ return(-1);
+ }
+
+ /* If the audio driver changes the buffer size, accept it */
+ if ( audio->spec.samples != desired->samples ) {
+ desired->samples = audio->spec.samples;
+ SDL_CalculateAudioSpec(desired);
+ }
+
+ /* Allocate a fake audio memory buffer */
+ audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
+ if ( audio->fake_stream == NULL ) {
+ SDL_CloseAudio();
+ SDL_OutOfMemory();
+ return(-1);
+ }
+
+ /* See if we need to do any conversion */
+ if ( obtained != NULL ) {
+ SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
+ } else if ( desired->freq != audio->spec.freq ||
+ desired->format != audio->spec.format ||
+ desired->channels != audio->spec.channels ) {
+ /* Build an audio conversion block */
+ if ( SDL_BuildAudioCVT(&audio->convert,
+ desired->format, desired->channels,
+ desired->freq,
+ audio->spec.format, audio->spec.channels,
+ audio->spec.freq) < 0 ) {
+ SDL_CloseAudio();
+ return(-1);
+ }
+ if ( audio->convert.needed ) {
+ audio->convert.len = (int) ( ((double) audio->spec.size) /
+ audio->convert.len_ratio );
+ audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
+ audio->convert.len*audio->convert.len_mult);
+ if ( audio->convert.buf == NULL ) {
+ SDL_CloseAudio();
+ SDL_OutOfMemory();
+ return(-1);
+ }
+ }
+ }
+
+ /* Start the audio thread if necessary */
+ switch (audio->opened) {
+ case 1:
+ /* Start the audio thread */
+#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) && !defined(__SYMBIAN32__)
+#undef SDL_CreateThread
+ audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
+#else
+ audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
+#endif
+ if ( audio->thread == NULL ) {
+ SDL_CloseAudio();
+ SDL_SetError("Couldn't create audio thread");
+ return(-1);
+ }
+ break;
+
+ default:
+ /* The audio is now playing */
+ break;
+ }
+
+ return(0);
+}
+
+SDL_audiostatus SDL_GetAudioStatus(void)
+{
+ SDL_AudioDevice *audio = current_audio;
+ SDL_audiostatus status;
+
+ status = SDL_AUDIO_STOPPED;
+ if ( audio && audio->enabled ) {
+ if ( audio->paused ) {
+ status = SDL_AUDIO_PAUSED;
+ } else {
+ status = SDL_AUDIO_PLAYING;
+ }
+ }
+ return(status);
+}
+
+void SDL_PauseAudio (int pause_on)
+{
+ SDL_AudioDevice *audio = current_audio;
+
+ if ( audio ) {
+ audio->paused = pause_on;
+ }
+}
+
+void SDL_LockAudio (void)
+{
+ SDL_AudioDevice *audio = current_audio;
+
+ /* Obtain a lock on the mixing buffers */
+ if ( audio && audio->LockAudio ) {
+ audio->LockAudio(audio);
+ }
+}
+
+void SDL_UnlockAudio (void)
+{
+ SDL_AudioDevice *audio = current_audio;
+
+ /* Release lock on the mixing buffers */
+ if ( audio && audio->UnlockAudio ) {
+ audio->UnlockAudio(audio);
+ }
+}
+
+void SDL_CloseAudio (void)
+{
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+}
+
+void SDL_AudioQuit(void)
+{
+ SDL_AudioDevice *audio = current_audio;
+
+ if ( audio ) {
+ audio->enabled = 0;
+ if ( audio->thread != NULL ) {
+ SDL_WaitThread(audio->thread, NULL);
+ }
+ if ( audio->mixer_lock != NULL ) {
+ SDL_DestroyMutex(audio->mixer_lock);
+ }
+ if ( audio->fake_stream != NULL ) {
+ SDL_FreeAudioMem(audio->fake_stream);
+ }
+ if ( audio->convert.needed ) {
+ SDL_FreeAudioMem(audio->convert.buf);
+
+ }
+ if ( audio->opened ) {
+ audio->CloseAudio(audio);
+ audio->opened = 0;
+ }
+ /* Free the driver data */
+ audio->free(audio);
+ current_audio = NULL;
+ }
+}
+
+#define NUM_FORMATS 6
+static int format_idx;
+static int format_idx_sub;
+static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
+ { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
+ { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
+ { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
+ { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
+ { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
+ { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
+};
+
+Uint16 SDL_FirstAudioFormat(Uint16 format)
+{
+ for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
+ if ( format_list[format_idx][0] == format ) {
+ break;
+ }
+ }
+ format_idx_sub = 0;
+ return(SDL_NextAudioFormat());
+}
+
+Uint16 SDL_NextAudioFormat(void)
+{
+ if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
+ return(0);
+ }
+ return(format_list[format_idx][format_idx_sub++]);
+}
+
+void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
+{
+ switch (spec->format) {
+ case AUDIO_U8:
+ spec->silence = 0x80;
+ break;
+ default:
+ spec->silence = 0x00;
+ break;
+ }
+ spec->size = (spec->format&0xFF)/8;
+ spec->size *= spec->channels;
+ spec->size *= spec->samples;
+}
diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h
new file mode 100644
index 0000000..3a5c102
--- /dev/null
+++ b/src/audio/SDL_audio_c.h
@@ -0,0 +1,34 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
+
+/* Functions to get a list of "close" audio formats */
+extern Uint16 SDL_FirstAudioFormat(Uint16 format);
+extern Uint16 SDL_NextAudioFormat(void);
+
+/* Function to calculate the size and silence for a SDL_AudioSpec */
+extern void SDL_CalculateAudioSpec(SDL_AudioSpec *spec);
+
+/* The actual mixing thread function */
+extern int SDLCALL SDL_RunAudio(void *audiop);
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
new file mode 100644
index 0000000..5db30b3
--- /dev/null
+++ b/src/audio/SDL_audiocvt.c
@@ -0,0 +1,1510 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Functions for audio drivers to perform runtime conversion of audio format */
+
+#include "SDL_audio.h"
+
+
+/* Effectively mix right and left channels into a single channel */
+void SDLCALL SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Sint32 sample;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to mono\n");
+#endif
+ switch (format&0x8018) {
+
+ case AUDIO_U8: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ sample = src[0] + src[1];
+ *dst = (Uint8)(sample / 2);
+ src += 2;
+ dst += 1;
+ }
+ }
+ break;
+
+ case AUDIO_S8: {
+ Sint8 *src, *dst;
+
+ src = (Sint8 *)cvt->buf;
+ dst = (Sint8 *)cvt->buf;
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ sample = src[0] + src[1];
+ *dst = (Sint8)(sample / 2);
+ src += 2;
+ dst += 1;
+ }
+ }
+ break;
+
+ case AUDIO_U16: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ sample = (Uint16)((src[0]<<8)|src[1])+
+ (Uint16)((src[2]<<8)|src[3]);
+ sample /= 2;
+ dst[1] = (sample&0xFF);
+ sample >>= 8;
+ dst[0] = (sample&0xFF);
+ src += 4;
+ dst += 2;
+ }
+ } else {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ sample = (Uint16)((src[1]<<8)|src[0])+
+ (Uint16)((src[3]<<8)|src[2]);
+ sample /= 2;
+ dst[0] = (sample&0xFF);
+ sample >>= 8;
+ dst[1] = (sample&0xFF);
+ src += 4;
+ dst += 2;
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ sample = (Sint16)((src[0]<<8)|src[1])+
+ (Sint16)((src[2]<<8)|src[3]);
+ sample /= 2;
+ dst[1] = (sample&0xFF);
+ sample >>= 8;
+ dst[0] = (sample&0xFF);
+ src += 4;
+ dst += 2;
+ }
+ } else {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ sample = (Sint16)((src[1]<<8)|src[0])+
+ (Sint16)((src[3]<<8)|src[2]);
+ sample /= 2;
+ dst[0] = (sample&0xFF);
+ sample >>= 8;
+ dst[1] = (sample&0xFF);
+ src += 4;
+ dst += 2;
+ }
+ }
+ }
+ break;
+ }
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Discard top 4 channels */
+void SDLCALL SDL_ConvertStrip(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Sint32 lsample, rsample;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting down to stereo\n");
+#endif
+ switch (format&0x8018) {
+
+ case AUDIO_U8: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ for ( i=cvt->len_cvt/6; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 6;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_S8: {
+ Sint8 *src, *dst;
+
+ src = (Sint8 *)cvt->buf;
+ dst = (Sint8 *)cvt->buf;
+ for ( i=cvt->len_cvt/6; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 6;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_U16: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/12; i; --i ) {
+ lsample = (Uint16)((src[0]<<8)|src[1]);
+ rsample = (Uint16)((src[2]<<8)|src[3]);
+ dst[1] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[0] = (lsample&0xFF);
+ dst[3] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[2] = (rsample&0xFF);
+ src += 12;
+ dst += 4;
+ }
+ } else {
+ for ( i=cvt->len_cvt/12; i; --i ) {
+ lsample = (Uint16)((src[1]<<8)|src[0]);
+ rsample = (Uint16)((src[3]<<8)|src[2]);
+ dst[0] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[1] = (lsample&0xFF);
+ dst[2] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[3] = (rsample&0xFF);
+ src += 12;
+ dst += 4;
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/12; i; --i ) {
+ lsample = (Sint16)((src[0]<<8)|src[1]);
+ rsample = (Sint16)((src[2]<<8)|src[3]);
+ dst[1] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[0] = (lsample&0xFF);
+ dst[3] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[2] = (rsample&0xFF);
+ src += 12;
+ dst += 4;
+ }
+ } else {
+ for ( i=cvt->len_cvt/12; i; --i ) {
+ lsample = (Sint16)((src[1]<<8)|src[0]);
+ rsample = (Sint16)((src[3]<<8)|src[2]);
+ dst[0] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[1] = (lsample&0xFF);
+ dst[2] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[3] = (rsample&0xFF);
+ src += 12;
+ dst += 4;
+ }
+ }
+ }
+ break;
+ }
+ cvt->len_cvt /= 3;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Discard top 2 channels of 6 */
+void SDLCALL SDL_ConvertStrip_2(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Sint32 lsample, rsample;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting 6 down to quad\n");
+#endif
+ switch (format&0x8018) {
+
+ case AUDIO_U8: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 4;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_S8: {
+ Sint8 *src, *dst;
+
+ src = (Sint8 *)cvt->buf;
+ dst = (Sint8 *)cvt->buf;
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 4;
+ dst += 2;
+ }
+ }
+ break;
+
+ case AUDIO_U16: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ lsample = (Uint16)((src[0]<<8)|src[1]);
+ rsample = (Uint16)((src[2]<<8)|src[3]);
+ dst[1] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[0] = (lsample&0xFF);
+ dst[3] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[2] = (rsample&0xFF);
+ src += 8;
+ dst += 4;
+ }
+ } else {
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ lsample = (Uint16)((src[1]<<8)|src[0]);
+ rsample = (Uint16)((src[3]<<8)|src[2]);
+ dst[0] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[1] = (lsample&0xFF);
+ dst[2] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[3] = (rsample&0xFF);
+ src += 8;
+ dst += 4;
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16: {
+ Uint8 *src, *dst;
+
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ lsample = (Sint16)((src[0]<<8)|src[1]);
+ rsample = (Sint16)((src[2]<<8)|src[3]);
+ dst[1] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[0] = (lsample&0xFF);
+ dst[3] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[2] = (rsample&0xFF);
+ src += 8;
+ dst += 4;
+ }
+ } else {
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ lsample = (Sint16)((src[1]<<8)|src[0]);
+ rsample = (Sint16)((src[3]<<8)|src[2]);
+ dst[0] = (lsample&0xFF);
+ lsample >>= 8;
+ dst[1] = (lsample&0xFF);
+ dst[2] = (rsample&0xFF);
+ rsample >>= 8;
+ dst[3] = (rsample&0xFF);
+ src += 8;
+ dst += 4;
+ }
+ }
+ }
+ break;
+ }
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Duplicate a mono channel to both stereo channels */
+void SDLCALL SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to stereo\n");
+#endif
+ if ( (format & 0xFF) == 16 ) {
+ Uint16 *src, *dst;
+
+ src = (Uint16 *)(cvt->buf+cvt->len_cvt);
+ dst = (Uint16 *)(cvt->buf+cvt->len_cvt*2);
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ dst -= 2;
+ src -= 1;
+ dst[0] = src[0];
+ dst[1] = src[0];
+ }
+ } else {
+ Uint8 *src, *dst;
+
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ for ( i=cvt->len_cvt; i; --i ) {
+ dst -= 2;
+ src -= 1;
+ dst[0] = src[0];
+ dst[1] = src[0];
+ }
+ }
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Duplicate a stereo channel to a pseudo-5.1 stream */
+void SDLCALL SDL_ConvertSurround(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting stereo to surround\n");
+#endif
+ switch (format&0x8018) {
+
+ case AUDIO_U8: {
+ Uint8 *src, *dst, lf, rf, ce;
+
+ src = (Uint8 *)(cvt->buf+cvt->len_cvt);
+ dst = (Uint8 *)(cvt->buf+cvt->len_cvt*3);
+ for ( i=cvt->len_cvt; i; --i ) {
+ dst -= 6;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf/2) + (rf/2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ dst[4] = ce;
+ dst[5] = ce;
+ }
+ }
+ break;
+
+ case AUDIO_S8: {
+ Sint8 *src, *dst, lf, rf, ce;
+
+ src = (Sint8 *)cvt->buf+cvt->len_cvt;
+ dst = (Sint8 *)cvt->buf+cvt->len_cvt*3;
+ for ( i=cvt->len_cvt; i; --i ) {
+ dst -= 6;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf/2) + (rf/2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ dst[4] = ce;
+ dst[5] = ce;
+ }
+ }
+ break;
+
+ case AUDIO_U16: {
+ Uint8 *src, *dst;
+ Uint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*3;
+
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 12;
+ src -= 4;
+ lf = (Uint16)((src[0]<<8)|src[1]);
+ rf = (Uint16)((src[2]<<8)|src[3]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf&0xFF);
+ dst[0] = ((lf>>8)&0xFF);
+ dst[3] = (rf&0xFF);
+ dst[2] = ((rf>>8)&0xFF);
+
+ dst[1+4] = (lr&0xFF);
+ dst[0+4] = ((lr>>8)&0xFF);
+ dst[3+4] = (rr&0xFF);
+ dst[2+4] = ((rr>>8)&0xFF);
+
+ dst[1+8] = (ce&0xFF);
+ dst[0+8] = ((ce>>8)&0xFF);
+ dst[3+8] = (ce&0xFF);
+ dst[2+8] = ((ce>>8)&0xFF);
+ }
+ } else {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 12;
+ src -= 4;
+ lf = (Uint16)((src[1]<<8)|src[0]);
+ rf = (Uint16)((src[3]<<8)|src[2]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf&0xFF);
+ dst[1] = ((lf>>8)&0xFF);
+ dst[2] = (rf&0xFF);
+ dst[3] = ((rf>>8)&0xFF);
+
+ dst[0+4] = (lr&0xFF);
+ dst[1+4] = ((lr>>8)&0xFF);
+ dst[2+4] = (rr&0xFF);
+ dst[3+4] = ((rr>>8)&0xFF);
+
+ dst[0+8] = (ce&0xFF);
+ dst[1+8] = ((ce>>8)&0xFF);
+ dst[2+8] = (ce&0xFF);
+ dst[3+8] = ((ce>>8)&0xFF);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16: {
+ Uint8 *src, *dst;
+ Sint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*3;
+
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 12;
+ src -= 4;
+ lf = (Sint16)((src[0]<<8)|src[1]);
+ rf = (Sint16)((src[2]<<8)|src[3]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf&0xFF);
+ dst[0] = ((lf>>8)&0xFF);
+ dst[3] = (rf&0xFF);
+ dst[2] = ((rf>>8)&0xFF);
+
+ dst[1+4] = (lr&0xFF);
+ dst[0+4] = ((lr>>8)&0xFF);
+ dst[3+4] = (rr&0xFF);
+ dst[2+4] = ((rr>>8)&0xFF);
+
+ dst[1+8] = (ce&0xFF);
+ dst[0+8] = ((ce>>8)&0xFF);
+ dst[3+8] = (ce&0xFF);
+ dst[2+8] = ((ce>>8)&0xFF);
+ }
+ } else {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 12;
+ src -= 4;
+ lf = (Sint16)((src[1]<<8)|src[0]);
+ rf = (Sint16)((src[3]<<8)|src[2]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf&0xFF);
+ dst[1] = ((lf>>8)&0xFF);
+ dst[2] = (rf&0xFF);
+ dst[3] = ((rf>>8)&0xFF);
+
+ dst[0+4] = (lr&0xFF);
+ dst[1+4] = ((lr>>8)&0xFF);
+ dst[2+4] = (rr&0xFF);
+ dst[3+4] = ((rr>>8)&0xFF);
+
+ dst[0+8] = (ce&0xFF);
+ dst[1+8] = ((ce>>8)&0xFF);
+ dst[2+8] = (ce&0xFF);
+ dst[3+8] = ((ce>>8)&0xFF);
+ }
+ }
+ }
+ break;
+ }
+ cvt->len_cvt *= 3;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Duplicate a stereo channel to a pseudo-4.0 stream */
+void SDLCALL SDL_ConvertSurround_4(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting stereo to quad\n");
+#endif
+ switch (format&0x8018) {
+
+ case AUDIO_U8: {
+ Uint8 *src, *dst, lf, rf, ce;
+
+ src = (Uint8 *)(cvt->buf+cvt->len_cvt);
+ dst = (Uint8 *)(cvt->buf+cvt->len_cvt*2);
+ for ( i=cvt->len_cvt; i; --i ) {
+ dst -= 4;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf/2) + (rf/2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ }
+ }
+ break;
+
+ case AUDIO_S8: {
+ Sint8 *src, *dst, lf, rf, ce;
+
+ src = (Sint8 *)cvt->buf+cvt->len_cvt;
+ dst = (Sint8 *)cvt->buf+cvt->len_cvt*2;
+ for ( i=cvt->len_cvt; i; --i ) {
+ dst -= 4;
+ src -= 2;
+ lf = src[0];
+ rf = src[1];
+ ce = (lf/2) + (rf/2);
+ dst[0] = lf;
+ dst[1] = rf;
+ dst[2] = lf - ce;
+ dst[3] = rf - ce;
+ }
+ }
+ break;
+
+ case AUDIO_U16: {
+ Uint8 *src, *dst;
+ Uint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 8;
+ src -= 4;
+ lf = (Uint16)((src[0]<<8)|src[1]);
+ rf = (Uint16)((src[2]<<8)|src[3]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf&0xFF);
+ dst[0] = ((lf>>8)&0xFF);
+ dst[3] = (rf&0xFF);
+ dst[2] = ((rf>>8)&0xFF);
+
+ dst[1+4] = (lr&0xFF);
+ dst[0+4] = ((lr>>8)&0xFF);
+ dst[3+4] = (rr&0xFF);
+ dst[2+4] = ((rr>>8)&0xFF);
+ }
+ } else {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 8;
+ src -= 4;
+ lf = (Uint16)((src[1]<<8)|src[0]);
+ rf = (Uint16)((src[3]<<8)|src[2]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf&0xFF);
+ dst[1] = ((lf>>8)&0xFF);
+ dst[2] = (rf&0xFF);
+ dst[3] = ((rf>>8)&0xFF);
+
+ dst[0+4] = (lr&0xFF);
+ dst[1+4] = ((lr>>8)&0xFF);
+ dst[2+4] = (rr&0xFF);
+ dst[3+4] = ((rr>>8)&0xFF);
+ }
+ }
+ }
+ break;
+
+ case AUDIO_S16: {
+ Uint8 *src, *dst;
+ Sint16 lf, rf, ce, lr, rr;
+
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+
+ if ( (format & 0x1000) == 0x1000 ) {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 8;
+ src -= 4;
+ lf = (Sint16)((src[0]<<8)|src[1]);
+ rf = (Sint16)((src[2]<<8)|src[3]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[1] = (lf&0xFF);
+ dst[0] = ((lf>>8)&0xFF);
+ dst[3] = (rf&0xFF);
+ dst[2] = ((rf>>8)&0xFF);
+
+ dst[1+4] = (lr&0xFF);
+ dst[0+4] = ((lr>>8)&0xFF);
+ dst[3+4] = (rr&0xFF);
+ dst[2+4] = ((rr>>8)&0xFF);
+ }
+ } else {
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst -= 8;
+ src -= 4;
+ lf = (Sint16)((src[1]<<8)|src[0]);
+ rf = (Sint16)((src[3]<<8)|src[2]);
+ ce = (lf/2) + (rf/2);
+ rr = lf - ce;
+ lr = rf - ce;
+ dst[0] = (lf&0xFF);
+ dst[1] = ((lf>>8)&0xFF);
+ dst[2] = (rf&0xFF);
+ dst[3] = ((rf>>8)&0xFF);
+
+ dst[0+4] = (lr&0xFF);
+ dst[1+4] = ((lr>>8)&0xFF);
+ dst[2+4] = (rr&0xFF);
+ dst[3+4] = ((rr>>8)&0xFF);
+ }
+ }
+ }
+ break;
+ }
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Convert 8-bit to 16-bit - LSB */
+void SDLCALL SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to 16-bit LSB\n");
+#endif
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ for ( i=cvt->len_cvt; i; --i ) {
+ src -= 1;
+ dst -= 2;
+ dst[1] = *src;
+ dst[0] = 0;
+ }
+ format = ((format & ~0x0008) | AUDIO_U16LSB);
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+/* Convert 8-bit to 16-bit - MSB */
+void SDLCALL SDL_Convert16MSB(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to 16-bit MSB\n");
+#endif
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ for ( i=cvt->len_cvt; i; --i ) {
+ src -= 1;
+ dst -= 2;
+ dst[0] = *src;
+ dst[1] = 0;
+ }
+ format = ((format & ~0x0008) | AUDIO_U16MSB);
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Convert 16-bit to 8-bit */
+void SDLCALL SDL_Convert8(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting to 8-bit\n");
+#endif
+ src = cvt->buf;
+ dst = cvt->buf;
+ if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
+ ++src;
+ }
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ *dst = *src;
+ src += 2;
+ dst += 1;
+ }
+ format = ((format & ~0x9010) | AUDIO_U8);
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Toggle signed/unsigned */
+void SDLCALL SDL_ConvertSign(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *data;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio signedness\n");
+#endif
+ data = cvt->buf;
+ if ( (format & 0xFF) == 16 ) {
+ if ( (format & 0x1000) != 0x1000 ) { /* Little endian */
+ ++data;
+ }
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ *data ^= 0x80;
+ data += 2;
+ }
+ } else {
+ for ( i=cvt->len_cvt; i; --i ) {
+ *data++ ^= 0x80;
+ }
+ }
+ format = (format ^ 0x8000);
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Toggle endianness */
+void SDLCALL SDL_ConvertEndian(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *data, tmp;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio endianness\n");
+#endif
+ data = cvt->buf;
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ tmp = data[0];
+ data[0] = data[1];
+ data[1] = tmp;
+ data += 2;
+ }
+ format = (format ^ 0x1000);
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Convert rate up by multiple of 2 */
+void SDLCALL SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate * 2\n");
+#endif
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt; i; --i ) {
+ src -= 1;
+ dst -= 2;
+ dst[0] = src[0];
+ dst[1] = src[0];
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ src -= 2;
+ dst -= 4;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst[3] = src[1];
+ }
+ break;
+ }
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Convert rate up by multiple of 2, for stereo */
+void SDLCALL SDL_RateMUL2_c2(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate * 2\n");
+#endif
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ src -= 2;
+ dst -= 4;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst[3] = src[1];
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ src -= 4;
+ dst -= 8;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[0];
+ dst[5] = src[1];
+ dst[6] = src[2];
+ dst[7] = src[3];
+ }
+ break;
+ }
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Convert rate up by multiple of 2, for quad */
+void SDLCALL SDL_RateMUL2_c4(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate * 2\n");
+#endif
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ src -= 4;
+ dst -= 8;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[0];
+ dst[5] = src[1];
+ dst[6] = src[2];
+ dst[7] = src[3];
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ src -= 8;
+ dst -= 16;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+ dst[8] = src[0];
+ dst[9] = src[1];
+ dst[10] = src[2];
+ dst[11] = src[3];
+ dst[12] = src[4];
+ dst[13] = src[5];
+ dst[14] = src[6];
+ dst[15] = src[7];
+ }
+ break;
+ }
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Convert rate up by multiple of 2, for 5.1 */
+void SDLCALL SDL_RateMUL2_c6(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate * 2\n");
+#endif
+ src = cvt->buf+cvt->len_cvt;
+ dst = cvt->buf+cvt->len_cvt*2;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/6; i; --i ) {
+ src -= 6;
+ dst -= 12;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[0];
+ dst[7] = src[1];
+ dst[8] = src[2];
+ dst[9] = src[3];
+ dst[10] = src[4];
+ dst[11] = src[5];
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/12; i; --i ) {
+ src -= 12;
+ dst -= 24;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+ dst[8] = src[8];
+ dst[9] = src[9];
+ dst[10] = src[10];
+ dst[11] = src[11];
+ dst[12] = src[0];
+ dst[13] = src[1];
+ dst[14] = src[2];
+ dst[15] = src[3];
+ dst[16] = src[4];
+ dst[17] = src[5];
+ dst[18] = src[6];
+ dst[19] = src[7];
+ dst[20] = src[8];
+ dst[21] = src[9];
+ dst[22] = src[10];
+ dst[23] = src[11];
+ }
+ break;
+ }
+ cvt->len_cvt *= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Convert rate down by multiple of 2 */
+void SDLCALL SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate / 2\n");
+#endif
+ src = cvt->buf;
+ dst = cvt->buf;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/2; i; --i ) {
+ dst[0] = src[0];
+ src += 2;
+ dst += 1;
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 4;
+ dst += 2;
+ }
+ break;
+ }
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Convert rate down by multiple of 2, for stereo */
+void SDLCALL SDL_RateDIV2_c2(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate / 2\n");
+#endif
+ src = cvt->buf;
+ dst = cvt->buf;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/4; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 4;
+ dst += 2;
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ src += 8;
+ dst += 4;
+ }
+ break;
+ }
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+
+/* Convert rate down by multiple of 2, for quad */
+void SDLCALL SDL_RateDIV2_c4(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate / 2\n");
+#endif
+ src = cvt->buf;
+ dst = cvt->buf;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/8; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ src += 8;
+ dst += 4;
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/16; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+ src += 16;
+ dst += 8;
+ }
+ break;
+ }
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Convert rate down by multiple of 2, for 5.1 */
+void SDLCALL SDL_RateDIV2_c6(SDL_AudioCVT *cvt, Uint16 format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate / 2\n");
+#endif
+ src = cvt->buf;
+ dst = cvt->buf;
+ switch (format & 0xFF) {
+ case 8:
+ for ( i=cvt->len_cvt/12; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ src += 12;
+ dst += 6;
+ }
+ break;
+ case 16:
+ for ( i=cvt->len_cvt/24; i; --i ) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+ dst[8] = src[8];
+ dst[9] = src[9];
+ dst[10] = src[10];
+ dst[11] = src[11];
+ src += 24;
+ dst += 12;
+ }
+ break;
+ }
+ cvt->len_cvt /= 2;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+/* Very slow rate conversion routine */
+void SDLCALL SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format)
+{
+ double ipos;
+ int i, clen;
+
+#ifdef DEBUG_CONVERT
+ fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr);
+#endif
+ clen = (int)((double)cvt->len_cvt / cvt->rate_incr);
+ if ( cvt->rate_incr > 1.0 ) {
+ switch (format & 0xFF) {
+ case 8: {
+ Uint8 *output;
+
+ output = cvt->buf;
+ ipos = 0.0;
+ for ( i=clen; i; --i ) {
+ *output = cvt->buf[(int)ipos];
+ ipos += cvt->rate_incr;
+ output += 1;
+ }
+ }
+ break;
+
+ case 16: {
+ Uint16 *output;
+
+ clen &= ~1;
+ output = (Uint16 *)cvt->buf;
+ ipos = 0.0;
+ for ( i=clen/2; i; --i ) {
+ *output=((Uint16 *)cvt->buf)[(int)ipos];
+ ipos += cvt->rate_incr;
+ output += 1;
+ }
+ }
+ break;
+ }
+ } else {
+ switch (format & 0xFF) {
+ case 8: {
+ Uint8 *output;
+
+ output = cvt->buf+clen;
+ ipos = (double)cvt->len_cvt;
+ for ( i=clen; i; --i ) {
+ ipos -= cvt->rate_incr;
+ output -= 1;
+ *output = cvt->buf[(int)ipos];
+ }
+ }
+ break;
+
+ case 16: {
+ Uint16 *output;
+
+ clen &= ~1;
+ output = (Uint16 *)(cvt->buf+clen);
+ ipos = (double)cvt->len_cvt/2;
+ for ( i=clen/2; i; --i ) {
+ ipos -= cvt->rate_incr;
+ output -= 1;
+ *output=((Uint16 *)cvt->buf)[(int)ipos];
+ }
+ }
+ break;
+ }
+ }
+ cvt->len_cvt = clen;
+ if ( cvt->filters[++cvt->filter_index] ) {
+ cvt->filters[cvt->filter_index](cvt, format);
+ }
+}
+
+int SDL_ConvertAudio(SDL_AudioCVT *cvt)
+{
+ /* Make sure there's data to convert */
+ if ( cvt->buf == NULL ) {
+ SDL_SetError("No buffer allocated for conversion");
+ return(-1);
+ }
+ /* Return okay if no conversion is necessary */
+ cvt->len_cvt = cvt->len;
+ if ( cvt->filters[0] == NULL ) {
+ return(0);
+ }
+
+ /* Set up the conversion and go! */
+ cvt->filter_index = 0;
+ cvt->filters[0](cvt, cvt->src_format);
+ return(0);
+}
+
+/* Creates a set of audio filters to convert from one format to another.
+ Returns -1 if the format conversion is not supported, or 1 if the
+ audio filter is set up.
+*/
+
+int SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
+ Uint16 src_format, Uint8 src_channels, int src_rate,
+ Uint16 dst_format, Uint8 dst_channels, int dst_rate)
+{
+/*printf("Build format %04x->%04x, channels %u->%u, rate %d->%d\n",
+ src_format, dst_format, src_channels, dst_channels, src_rate, dst_rate);*/
+ /* Start off with no conversion necessary */
+ cvt->needed = 0;
+ cvt->filter_index = 0;
+ cvt->filters[0] = NULL;
+ cvt->len_mult = 1;
+ cvt->len_ratio = 1.0;
+
+ /* First filter: Endian conversion from src to dst */
+ if ( (src_format & 0x1000) != (dst_format & 0x1000)
+ && ((src_format & 0xff) == 16) && ((dst_format & 0xff) == 16)) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertEndian;
+ }
+
+ /* Second filter: Sign conversion -- signed/unsigned */
+ if ( (src_format & 0x8000) != (dst_format & 0x8000) ) {
+ cvt->filters[cvt->filter_index++] = SDL_ConvertSign;
+ }
+
+ /* Next filter: Convert 16 bit <--> 8 bit PCM */
+ if ( (src_format & 0xFF) != (dst_format & 0xFF) ) {
+ switch (dst_format&0x10FF) {
+ case AUDIO_U8:
+ cvt->filters[cvt->filter_index++] =
+ SDL_Convert8;
+ cvt->len_ratio /= 2;
+ break;
+ case AUDIO_U16LSB:
+ cvt->filters[cvt->filter_index++] =
+ SDL_Convert16LSB;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ break;
+ case AUDIO_U16MSB:
+ cvt->filters[cvt->filter_index++] =
+ SDL_Convert16MSB;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ break;
+ }
+ }
+
+ /* Last filter: Mono/Stereo conversion */
+ if ( src_channels != dst_channels ) {
+ if ( (src_channels == 1) && (dst_channels > 1) ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertStereo;
+ cvt->len_mult *= 2;
+ src_channels = 2;
+ cvt->len_ratio *= 2;
+ }
+ if ( (src_channels == 2) &&
+ (dst_channels == 6) ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertSurround;
+ src_channels = 6;
+ cvt->len_mult *= 3;
+ cvt->len_ratio *= 3;
+ }
+ if ( (src_channels == 2) &&
+ (dst_channels == 4) ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertSurround_4;
+ src_channels = 4;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ }
+ while ( (src_channels*2) <= dst_channels ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertStereo;
+ cvt->len_mult *= 2;
+ src_channels *= 2;
+ cvt->len_ratio *= 2;
+ }
+ if ( (src_channels == 6) &&
+ (dst_channels <= 2) ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertStrip;
+ src_channels = 2;
+ cvt->len_ratio /= 3;
+ }
+ if ( (src_channels == 6) &&
+ (dst_channels == 4) ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertStrip_2;
+ src_channels = 4;
+ cvt->len_ratio /= 2;
+ }
+ /* This assumes that 4 channel audio is in the format:
+ Left {front/back} + Right {front/back}
+ so converting to L/R stereo works properly.
+ */
+ while ( ((src_channels%2) == 0) &&
+ ((src_channels/2) >= dst_channels) ) {
+ cvt->filters[cvt->filter_index++] =
+ SDL_ConvertMono;
+ src_channels /= 2;
+ cvt->len_ratio /= 2;
+ }
+ if ( src_channels != dst_channels ) {
+ /* Uh oh.. */;
+ }
+ }
+
+ /* Do rate conversion */
+ cvt->rate_incr = 0.0;
+ if ( (src_rate/100) != (dst_rate/100) ) {
+ Uint32 hi_rate, lo_rate;
+ int len_mult;
+ double len_ratio;
+ void (SDLCALL *rate_cvt)(SDL_AudioCVT *cvt, Uint16 format);
+
+ if ( src_rate > dst_rate ) {
+ hi_rate = src_rate;
+ lo_rate = dst_rate;
+ switch (src_channels) {
+ case 1: rate_cvt = SDL_RateDIV2; break;
+ case 2: rate_cvt = SDL_RateDIV2_c2; break;
+ case 4: rate_cvt = SDL_RateDIV2_c4; break;
+ case 6: rate_cvt = SDL_RateDIV2_c6; break;
+ default: return -1;
+ }
+ len_mult = 1;
+ len_ratio = 0.5;
+ } else {
+ hi_rate = dst_rate;
+ lo_rate = src_rate;
+ switch (src_channels) {
+ case 1: rate_cvt = SDL_RateMUL2; break;
+ case 2: rate_cvt = SDL_RateMUL2_c2; break;
+ case 4: rate_cvt = SDL_RateMUL2_c4; break;
+ case 6: rate_cvt = SDL_RateMUL2_c6; break;
+ default: return -1;
+ }
+ len_mult = 2;
+ len_ratio = 2.0;
+ }
+ /* If hi_rate = lo_rate*2^x then conversion is easy */
+ while ( ((lo_rate*2)/100) <= (hi_rate/100) ) {
+ cvt->filters[cvt->filter_index++] = rate_cvt;
+ cvt->len_mult *= len_mult;
+ lo_rate *= 2;
+ cvt->len_ratio *= len_ratio;
+ }
+ /* We may need a slow conversion here to finish up */
+ if ( (lo_rate/100) != (hi_rate/100) ) {
+#if 1
+ /* The problem with this is that if the input buffer is
+ say 1K, and the conversion rate is say 1.1, then the
+ output buffer is 1.1K, which may not be an acceptable
+ buffer size for the audio driver (not a power of 2)
+ */
+ /* For now, punt and hope the rate distortion isn't great.
+ */
+#else
+ if ( src_rate < dst_rate ) {
+ cvt->rate_incr = (double)lo_rate/hi_rate;
+ cvt->len_mult *= 2;
+ cvt->len_ratio /= cvt->rate_incr;
+ } else {
+ cvt->rate_incr = (double)hi_rate/lo_rate;
+ cvt->len_ratio *= cvt->rate_incr;
+ }
+ cvt->filters[cvt->filter_index++] = SDL_RateSLOW;
+#endif
+ }
+ }
+
+ /* Set up the filter information */
+ if ( cvt->filter_index != 0 ) {
+ cvt->needed = 1;
+ cvt->src_format = src_format;
+ cvt->dst_format = dst_format;
+ cvt->len = 0;
+ cvt->buf = NULL;
+ cvt->filters[cvt->filter_index] = NULL;
+ }
+ return(cvt->needed);
+}
diff --git a/src/audio/SDL_audiodev.c b/src/audio/SDL_audiodev.c
new file mode 100644
index 0000000..41d882f
--- /dev/null
+++ b/src/audio/SDL_audiodev.c
@@ -0,0 +1,179 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Get the name of the audio device we use for output */
+
+#if SDL_AUDIO_DRIVER_BSD || SDL_AUDIO_DRIVER_OSS || SDL_AUDIO_DRIVER_SUNAUDIO
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "SDL_stdinc.h"
+#include "SDL_audiodev_c.h"
+
+#ifndef _PATH_DEV_DSP
+#if defined(__NETBSD__) || defined(__OPENBSD__)
+#define _PATH_DEV_DSP "/dev/audio"
+#else
+#define _PATH_DEV_DSP "/dev/dsp"
+#endif
+#endif
+#ifndef _PATH_DEV_DSP24
+#define _PATH_DEV_DSP24 "/dev/sound/dsp"
+#endif
+#ifndef _PATH_DEV_AUDIO
+#define _PATH_DEV_AUDIO "/dev/audio"
+#endif
+
+
+int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
+{
+ const char *audiodev;
+ int audio_fd;
+ char audiopath[1024];
+
+ /* Figure out what our audio device is */
+ if ( ((audiodev=SDL_getenv("SDL_PATH_DSP")) == NULL) &&
+ ((audiodev=SDL_getenv("AUDIODEV")) == NULL) ) {
+ if ( classic ) {
+ audiodev = _PATH_DEV_AUDIO;
+ } else {
+ struct stat sb;
+
+ /* Added support for /dev/sound/\* in Linux 2.4 */
+ if ( ((stat("/dev/sound", &sb) == 0) && S_ISDIR(sb.st_mode)) &&
+ ((stat(_PATH_DEV_DSP24, &sb) == 0) && S_ISCHR(sb.st_mode)) ) {
+ audiodev = _PATH_DEV_DSP24;
+ } else {
+ audiodev = _PATH_DEV_DSP;
+ }
+ }
+ }
+ audio_fd = open(audiodev, flags, 0);
+
+ /* If the first open fails, look for other devices */
+ if ( (audio_fd < 0) && (SDL_strlen(audiodev) < (sizeof(audiopath)-3)) ) {
+ int exists, instance;
+ struct stat sb;
+
+ instance = 1;
+ do { /* Don't use errno ENOENT - it may not be thread-safe */
+ SDL_snprintf(audiopath, SDL_arraysize(audiopath),
+ "%s%d", audiodev, instance++);
+ exists = 0;
+ if ( stat(audiopath, &sb) == 0 ) {
+ exists = 1;
+ audio_fd = open(audiopath, flags, 0);
+ }
+ } while ( exists && (audio_fd < 0) );
+ audiodev = audiopath;
+ }
+ if ( path != NULL ) {
+ SDL_strlcpy(path, audiodev, maxlen);
+ path[maxlen-1] = '\0';
+ }
+ return(audio_fd);
+}
+
+#elif SDL_AUDIO_DRIVER_PAUD
+
+/* Get the name of the audio device we use for output */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "SDL_stdinc.h"
+#include "SDL_audiodev_c.h"
+
+#ifndef _PATH_DEV_DSP
+#define _PATH_DEV_DSP "/dev/%caud%c/%c"
+#endif
+
+char devsettings[][3] =
+{
+ { 'p', '0', '1' }, { 'p', '0', '2' }, { 'p', '0', '3' }, { 'p', '0', '4' },
+ { 'p', '1', '1' }, { 'p', '1', '2' }, { 'p', '1', '3' }, { 'p', '1', '4' },
+ { 'p', '2', '1' }, { 'p', '2', '2' }, { 'p', '2', '3' }, { 'p', '2', '4' },
+ { 'p', '3', '1' }, { 'p', '3', '2' }, { 'p', '3', '3' }, { 'p', '3', '4' },
+ { 'b', '0', '1' }, { 'b', '0', '2' }, { 'b', '0', '3' }, { 'b', '0', '4' },
+ { 'b', '1', '1' }, { 'b', '1', '2' }, { 'b', '1', '3' }, { 'b', '1', '4' },
+ { 'b', '2', '1' }, { 'b', '2', '2' }, { 'b', '2', '3' }, { 'b', '2', '4' },
+ { 'b', '3', '1' }, { 'b', '3', '2' }, { 'b', '3', '3' }, { 'b', '3', '4' },
+ { '\0', '\0', '\0' }
+};
+
+static int OpenUserDefinedDevice(char *path, int maxlen, int flags)
+{
+ const char *audiodev;
+ int audio_fd;
+
+ /* Figure out what our audio device is */
+ if ((audiodev=SDL_getenv("SDL_PATH_DSP")) == NULL) {
+ audiodev=SDL_getenv("AUDIODEV");
+ }
+ if ( audiodev == NULL ) {
+ return -1;
+ }
+ audio_fd = open(audiodev, flags, 0);
+ if ( path != NULL ) {
+ SDL_strlcpy(path, audiodev, maxlen);
+ path[maxlen-1] = '\0';
+ }
+ return audio_fd;
+}
+
+int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic)
+{
+ struct stat sb;
+ int audio_fd;
+ char audiopath[1024];
+ int cycle;
+
+ audio_fd = OpenUserDefinedDevice(path,maxlen,flags);
+ if ( audio_fd != -1 ) {
+ return audio_fd;
+ }
+
+ cycle = 0;
+ while( devsettings[cycle][0] != '\0' ) {
+ SDL_snprintf( audiopath, SDL_arraysize(audiopath),
+ _PATH_DEV_DSP,
+ devsettings[cycle][0],
+ devsettings[cycle][1],
+ devsettings[cycle][2]);
+
+ if ( stat(audiopath, &sb) == 0 ) {
+ audio_fd = open(audiopath, flags, 0);
+ if ( audio_fd > 0 ) {
+ if ( path != NULL ) {
+ SDL_strlcpy( path, audiopath, maxlen );
+ }
+ return audio_fd;
+ }
+ }
+ }
+ return -1;
+}
+
+#endif /* Audio driver selection */
diff --git a/src/audio/SDL_audiodev_c.h b/src/audio/SDL_audiodev_c.h
new file mode 100644
index 0000000..d4c0c9c
--- /dev/null
+++ b/src/audio/SDL_audiodev_c.h
@@ -0,0 +1,26 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Open the audio device, storing the pathname in 'path' */
+extern int SDL_OpenAudioPath(char *path, int maxlen, int flags, int classic);
+
diff --git a/src/audio/SDL_audiomem.h b/src/audio/SDL_audiomem.h
new file mode 100644
index 0000000..3b164ab
--- /dev/null
+++ b/src/audio/SDL_audiomem.h
@@ -0,0 +1,25 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#define SDL_AllocAudioMem SDL_malloc
+#define SDL_FreeAudioMem SDL_free
diff --git a/src/audio/SDL_mixer.c b/src/audio/SDL_mixer.c
new file mode 100644
index 0000000..5a1d7ef
--- /dev/null
+++ b/src/audio/SDL_mixer.c
@@ -0,0 +1,264 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* This provides the default mixing callback for the SDL audio routines */
+
+#include "SDL_cpuinfo.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "SDL_sysaudio.h"
+#include "SDL_mixer_MMX.h"
+#include "SDL_mixer_MMX_VC.h"
+#include "SDL_mixer_m68k.h"
+
+/* This table is used to add two sound values together and pin
+ * the value to avoid overflow. (used with permission from ARDI)
+ * Changed to use 0xFE instead of 0xFF for better sound quality.
+ */
+static const Uint8 mix8[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
+ 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
+ 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
+ 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
+ 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
+ 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
+ 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
+ 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
+ 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
+ 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
+ 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
+ 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
+ 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE
+};
+
+/* The volume ranges from 0 - 128 */
+#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME)
+#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
+
+void SDL_MixAudio (Uint8 *dst, const Uint8 *src, Uint32 len, int volume)
+{
+ Uint16 format;
+
+ if ( volume == 0 ) {
+ return;
+ }
+ /* Mix the user-level audio format */
+ if ( current_audio ) {
+ if ( current_audio->convert.needed ) {
+ format = current_audio->convert.src_format;
+ } else {
+ format = current_audio->spec.format;
+ }
+ } else {
+ /* HACK HACK HACK */
+ format = AUDIO_S16;
+ }
+ switch (format) {
+
+ case AUDIO_U8: {
+#if defined(__GNUC__) && defined(__M68000__) && defined(SDL_ASSEMBLY_ROUTINES)
+ SDL_MixAudio_m68k_U8((char*)dst,(char*)src,(unsigned long)len,(long)volume,(char *)mix8);
+#else
+ Uint8 src_sample;
+
+ while ( len-- ) {
+ src_sample = *src;
+ ADJUST_VOLUME_U8(src_sample, volume);
+ *dst = mix8[*dst+src_sample];
+ ++dst;
+ ++src;
+ }
+#endif
+ }
+ break;
+
+ case AUDIO_S8: {
+#if defined(SDL_BUGGY_MMX_MIXERS) /* buggy, so we're disabling them. --ryan. */
+#if defined(__GNUC__) && defined(__i386__) && defined(SDL_ASSEMBLY_ROUTINES)
+ if (SDL_HasMMX())
+ {
+ SDL_MixAudio_MMX_S8((char*)dst,(char*)src,(unsigned int)len,(int)volume);
+ }
+ else
+#elif ((defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)) && defined(SDL_ASSEMBLY_ROUTINES)
+ if (SDL_HasMMX())
+ {
+ SDL_MixAudio_MMX_S8_VC((char*)dst,(char*)src,(unsigned int)len,(int)volume);
+ }
+ else
+#endif
+#endif
+
+#if defined(__GNUC__) && defined(__M68000__) && defined(SDL_ASSEMBLY_ROUTINES)
+ SDL_MixAudio_m68k_S8((char*)dst,(char*)src,(unsigned long)len,(long)volume);
+#else
+ {
+ Sint8 *dst8, *src8;
+ Sint8 src_sample;
+ int dst_sample;
+ const int max_audioval = ((1<<(8-1))-1);
+ const int min_audioval = -(1<<(8-1));
+
+ src8 = (Sint8 *)src;
+ dst8 = (Sint8 *)dst;
+ while ( len-- ) {
+ src_sample = *src8;
+ ADJUST_VOLUME(src_sample, volume);
+ dst_sample = *dst8 + src_sample;
+ if ( dst_sample > max_audioval ) {
+ *dst8 = max_audioval;
+ } else
+ if ( dst_sample < min_audioval ) {
+ *dst8 = min_audioval;
+ } else {
+ *dst8 = dst_sample;
+ }
+ ++dst8;
+ ++src8;
+ }
+ }
+#endif
+ }
+ break;
+
+ case AUDIO_S16LSB: {
+#if defined(SDL_BUGGY_MMX_MIXERS) /* buggy, so we're disabling them. --ryan. */
+#if defined(__GNUC__) && defined(__i386__) && defined(SDL_ASSEMBLY_ROUTINES)
+ if (SDL_HasMMX())
+ {
+ SDL_MixAudio_MMX_S16((char*)dst,(char*)src,(unsigned int)len,(int)volume);
+ }
+ else
+#elif ((defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)) && defined(SDL_ASSEMBLY_ROUTINES)
+ if (SDL_HasMMX())
+ {
+ SDL_MixAudio_MMX_S16_VC((char*)dst,(char*)src,(unsigned int)len,(int)volume);
+ }
+ else
+#endif
+#endif
+
+#if defined(__GNUC__) && defined(__M68000__) && defined(SDL_ASSEMBLY_ROUTINES)
+ SDL_MixAudio_m68k_S16LSB((short*)dst,(short*)src,(unsigned long)len,(long)volume);
+#else
+ {
+ Sint16 src1, src2;
+ int dst_sample;
+ const int max_audioval = ((1<<(16-1))-1);
+ const int min_audioval = -(1<<(16-1));
+
+ len /= 2;
+ while ( len-- ) {
+ src1 = ((src[1])<<8|src[0]);
+ ADJUST_VOLUME(src1, volume);
+ src2 = ((dst[1])<<8|dst[0]);
+ src += 2;
+ dst_sample = src1+src2;
+ if ( dst_sample > max_audioval ) {
+ dst_sample = max_audioval;
+ } else
+ if ( dst_sample < min_audioval ) {
+ dst_sample = min_audioval;
+ }
+ dst[0] = dst_sample&0xFF;
+ dst_sample >>= 8;
+ dst[1] = dst_sample&0xFF;
+ dst += 2;
+ }
+ }
+#endif
+ }
+ break;
+
+ case AUDIO_S16MSB: {
+#if defined(__GNUC__) && defined(__M68000__) && defined(SDL_ASSEMBLY_ROUTINES)
+ SDL_MixAudio_m68k_S16MSB((short*)dst,(short*)src,(unsigned long)len,(long)volume);
+#else
+ Sint16 src1, src2;
+ int dst_sample;
+ const int max_audioval = ((1<<(16-1))-1);
+ const int min_audioval = -(1<<(16-1));
+
+ len /= 2;
+ while ( len-- ) {
+ src1 = ((src[0])<<8|src[1]);
+ ADJUST_VOLUME(src1, volume);
+ src2 = ((dst[0])<<8|dst[1]);
+ src += 2;
+ dst_sample = src1+src2;
+ if ( dst_sample > max_audioval ) {
+ dst_sample = max_audioval;
+ } else
+ if ( dst_sample < min_audioval ) {
+ dst_sample = min_audioval;
+ }
+ dst[1] = dst_sample&0xFF;
+ dst_sample >>= 8;
+ dst[0] = dst_sample&0xFF;
+ dst += 2;
+ }
+#endif
+ }
+ break;
+
+ default: /* If this happens... FIXME! */
+ SDL_SetError("SDL_MixAudio(): unknown audio format");
+ return;
+ }
+}
+
diff --git a/src/audio/SDL_mixer_MMX.c b/src/audio/SDL_mixer_MMX.c
new file mode 100644
index 0000000..10b1ccb
--- /dev/null
+++ b/src/audio/SDL_mixer_MMX.c
@@ -0,0 +1,207 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MMX assembler version of SDL_MixAudio for signed little endian 16 bit samples and signed 8 bit samples
+ Copyright 2002 Stephane Marchesin (stephane.marchesin@wanadoo.fr)
+ This code is licensed under the LGPL (see COPYING for details)
+
+ Assumes buffer size in bytes is a multiple of 16
+ Assumes SDL_MIX_MAXVOLUME = 128
+*/
+
+
+/***********************************************
+* Mixing for 16 bit signed buffers
+***********************************************/
+
+#if defined(SDL_BUGGY_MMX_MIXERS) /* buggy, so we're disabling them. --ryan. */
+#if defined(__GNUC__) && defined(__i386__) && defined(SDL_ASSEMBLY_ROUTINES)
+void SDL_MixAudio_MMX_S16(char* dst,char* src,unsigned int size,int volume)
+{
+ __asm__ __volatile__ (
+
+" movl %3,%%eax\n" /* eax = volume */
+
+" movl %2,%%edx\n" /* edx = size */
+
+" shrl $4,%%edx\n" /* process 16 bytes per iteration = 8 samples */
+
+" jz .endS16\n"
+
+" pxor %%mm0,%%mm0\n"
+
+" movd %%eax,%%mm0\n"
+" movq %%mm0,%%mm1\n"
+" psllq $16,%%mm0\n"
+" por %%mm1,%%mm0\n"
+" psllq $16,%%mm0\n"
+" por %%mm1,%%mm0\n"
+" psllq $16,%%mm0\n"
+" por %%mm1,%%mm0\n" /* mm0 = vol|vol|vol|vol */
+
+".align 8\n"
+" .mixloopS16:\n"
+
+" movq (%1),%%mm1\n" /* mm1 = a|b|c|d */
+
+" movq %%mm1,%%mm2\n" /* mm2 = a|b|c|d */
+
+" movq 8(%1),%%mm4\n" /* mm4 = e|f|g|h */
+
+ /* pré charger le buffer dst dans mm7 */
+" movq (%0),%%mm7\n" /* mm7 = dst[0] */
+
+ /* multiplier par le volume */
+" pmullw %%mm0,%%mm1\n" /* mm1 = l(a*v)|l(b*v)|l(c*v)|l(d*v) */
+
+" pmulhw %%mm0,%%mm2\n" /* mm2 = h(a*v)|h(b*v)|h(c*v)|h(d*v) */
+" movq %%mm4,%%mm5\n" /* mm5 = e|f|g|h */
+
+" pmullw %%mm0,%%mm4\n" /* mm4 = l(e*v)|l(f*v)|l(g*v)|l(h*v) */
+
+" pmulhw %%mm0,%%mm5\n" /* mm5 = h(e*v)|h(f*v)|h(g*v)|h(h*v) */
+" movq %%mm1,%%mm3\n" /* mm3 = l(a*v)|l(b*v)|l(c*v)|l(d*v) */
+
+" punpckhwd %%mm2,%%mm1\n" /* mm1 = a*v|b*v */
+
+" movq %%mm4,%%mm6\n" /* mm6 = l(e*v)|l(f*v)|l(g*v)|l(h*v) */
+" punpcklwd %%mm2,%%mm3\n" /* mm3 = c*v|d*v */
+
+" punpckhwd %%mm5,%%mm4\n" /* mm4 = e*f|f*v */
+
+" punpcklwd %%mm5,%%mm6\n" /* mm6 = g*v|h*v */
+
+ /* pré charger le buffer dst dans mm5 */
+" movq 8(%0),%%mm5\n" /* mm5 = dst[1] */
+
+ /* diviser par 128 */
+" psrad $7,%%mm1\n" /* mm1 = a*v/128|b*v/128 , 128 = SDL_MIX_MAXVOLUME */
+" add $16,%1\n"
+
+" psrad $7,%%mm3\n" /* mm3 = c*v/128|d*v/128 */
+
+" psrad $7,%%mm4\n" /* mm4 = e*v/128|f*v/128 */
+
+ /* mm1 = le sample avec le volume modifié */
+" packssdw %%mm1,%%mm3\n" /* mm3 = s(a*v|b*v|c*v|d*v) */
+
+" psrad $7,%%mm6\n" /* mm6= g*v/128|h*v/128 */
+" paddsw %%mm7,%%mm3\n" /* mm3 = adjust_volume(src)+dst */
+
+ /* mm4 = le sample avec le volume modifié */
+" packssdw %%mm4,%%mm6\n" /* mm6 = s(e*v|f*v|g*v|h*v) */
+" movq %%mm3,(%0)\n"
+
+" paddsw %%mm5,%%mm6\n" /* mm6 = adjust_volume(src)+dst */
+
+" movq %%mm6,8(%0)\n"
+
+" add $16,%0\n"
+
+" dec %%edx\n"
+
+" jnz .mixloopS16\n"
+
+" emms\n"
+
+".endS16:\n"
+ :
+ : "r" (dst), "r"(src),"m"(size),
+ "m"(volume)
+ : "eax","edx","memory"
+ );
+}
+
+
+
+/*////////////////////////////////////////////// */
+/* Mixing for 8 bit signed buffers */
+/*////////////////////////////////////////////// */
+
+void SDL_MixAudio_MMX_S8(char* dst,char* src,unsigned int size,int volume)
+{
+ __asm__ __volatile__ (
+
+" movl %3,%%eax\n" /* eax = volume */
+
+" movd %%eax,%%mm0\n"
+" movq %%mm0,%%mm1\n"
+" psllq $16,%%mm0\n"
+" por %%mm1,%%mm0\n"
+" psllq $16,%%mm0\n"
+" por %%mm1,%%mm0\n"
+" psllq $16,%%mm0\n"
+" por %%mm1,%%mm0\n"
+
+" movl %2,%%edx\n" /* edx = size */
+" shr $3,%%edx\n" /* process 8 bytes per iteration = 8 samples */
+
+" cmp $0,%%edx\n"
+" je .endS8\n"
+
+".align 8\n"
+" .mixloopS8:\n"
+
+" pxor %%mm2,%%mm2\n" /* mm2 = 0 */
+" movq (%1),%%mm1\n" /* mm1 = a|b|c|d|e|f|g|h */
+
+" movq %%mm1,%%mm3\n" /* mm3 = a|b|c|d|e|f|g|h */
+
+ /* on va faire le "sign extension" en faisant un cmp avec 0 qui retourne 1 si <0, 0 si >0 */
+" pcmpgtb %%mm1,%%mm2\n" /* mm2 = 11111111|00000000|00000000.... */
+
+" punpckhbw %%mm2,%%mm1\n" /* mm1 = 0|a|0|b|0|c|0|d */
+
+" punpcklbw %%mm2,%%mm3\n" /* mm3 = 0|e|0|f|0|g|0|h */
+" movq (%0),%%mm2\n" /* mm2 = destination */
+
+" pmullw %%mm0,%%mm1\n" /* mm1 = v*a|v*b|v*c|v*d */
+" add $8,%1\n"
+
+" pmullw %%mm0,%%mm3\n" /* mm3 = v*e|v*f|v*g|v*h */
+" psraw $7,%%mm1\n" /* mm1 = v*a/128|v*b/128|v*c/128|v*d/128 */
+
+" psraw $7,%%mm3\n" /* mm3 = v*e/128|v*f/128|v*g/128|v*h/128 */
+
+" packsswb %%mm1,%%mm3\n" /* mm1 = v*a/128|v*b/128|v*c/128|v*d/128|v*e/128|v*f/128|v*g/128|v*h/128 */
+
+" paddsb %%mm2,%%mm3\n" /* add to destination buffer */
+
+" movq %%mm3,(%0)\n" /* store back to ram */
+" add $8,%0\n"
+
+" dec %%edx\n"
+
+" jnz .mixloopS8\n"
+
+".endS8:\n"
+" emms\n"
+ :
+ : "r" (dst), "r"(src),"m"(size),
+ "m"(volume)
+ : "eax","edx","memory"
+ );
+}
+#endif
+#endif
diff --git a/src/audio/SDL_mixer_MMX.h b/src/audio/SDL_mixer_MMX.h
new file mode 100644
index 0000000..836b259
--- /dev/null
+++ b/src/audio/SDL_mixer_MMX.h
@@ -0,0 +1,17 @@
+/*
+ headers for MMX assembler version of SDL_MixAudio
+ Copyright 2002 Stephane Marchesin (stephane.marchesin@wanadoo.fr)
+ This code is licensed under the LGPL (see COPYING for details)
+
+ Assumes buffer size in bytes is a multiple of 16
+ Assumes SDL_MIX_MAXVOLUME = 128
+*/
+#include "SDL_config.h"
+
+#if defined(SDL_BUGGY_MMX_MIXERS) /* buggy, so we're disabling them. --ryan. */
+#if defined(__GNUC__) && defined(__i386__) && defined(SDL_ASSEMBLY_ROUTINES)
+void SDL_MixAudio_MMX_S16(char* ,char* ,unsigned int ,int );
+void SDL_MixAudio_MMX_S8(char* ,char* ,unsigned int ,int );
+#endif
+#endif
+
diff --git a/src/audio/SDL_mixer_MMX_VC.c b/src/audio/SDL_mixer_MMX_VC.c
new file mode 100644
index 0000000..e9d53c1
--- /dev/null
+++ b/src/audio/SDL_mixer_MMX_VC.c
@@ -0,0 +1,183 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_mixer_MMX_VC.h"
+
+#if defined(SDL_BUGGY_MMX_MIXERS) /* buggy, so we're disabling them. --ryan. */
+#if ((defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)) && defined(SDL_ASSEMBLY_ROUTINES)
+// MMX assembler version of SDL_MixAudio for signed little endian 16 bit samples and signed 8 bit samples
+// Copyright 2002 Stephane Marchesin (stephane.marchesin@wanadoo.fr)
+// Converted to Intel ASM notation by Cth
+// This code is licensed under the LGPL (see COPYING for details)
+//
+// Assumes buffer size in bytes is a multiple of 16
+// Assumes SDL_MIX_MAXVOLUME = 128
+
+
+////////////////////////////////////////////////
+// Mixing for 16 bit signed buffers
+////////////////////////////////////////////////
+
+void SDL_MixAudio_MMX_S16_VC(char* dst,char* src,unsigned int nSize,int volume)
+{
+ __asm
+ {
+
+ push edi
+ push esi
+ push ebx
+
+ mov edi, dst // edi = dst
+ mov esi, src // esi = src
+ mov eax, volume // eax = volume
+ mov ebx, nSize // ebx = size
+ shr ebx, 4 // process 16 bytes per iteration = 8 samples
+ jz endS16
+
+ pxor mm0, mm0
+ movd mm0, eax //%%eax,%%mm0
+ movq mm1, mm0 //%%mm0,%%mm1
+ psllq mm0, 16 //$16,%%mm0
+ por mm0, mm1 //%%mm1,%%mm0
+ psllq mm0, 16 //$16,%%mm0
+ por mm0, mm1 //%%mm1,%%mm0
+ psllq mm0, 16 //$16,%%mm0
+ por mm0, mm1 //%%mm1,%%mm0 // mm0 = vol|vol|vol|vol
+
+ #ifndef __WATCOMC__
+ align 16
+ #endif
+mixloopS16:
+ movq mm1, [esi] //(%%esi),%%mm1\n" // mm1 = a|b|c|d
+ movq mm2, mm1 //%%mm1,%%mm2\n" // mm2 = a|b|c|d
+ movq mm4, [esi + 8] //8(%%esi),%%mm4\n" // mm4 = e|f|g|h
+ // pre charger le buffer dst dans mm7
+ movq mm7, [edi] //(%%edi),%%mm7\n" // mm7 = dst[0]"
+ // multiplier par le volume
+ pmullw mm1, mm0 //%%mm0,%%mm1\n" // mm1 = l(a*v)|l(b*v)|l(c*v)|l(d*v)
+ pmulhw mm2, mm0 //%%mm0,%%mm2\n" // mm2 = h(a*v)|h(b*v)|h(c*v)|h(d*v)
+ movq mm5, mm4 //%%mm4,%%mm5\n" // mm5 = e|f|g|h
+ pmullw mm4, mm0 //%%mm0,%%mm4\n" // mm4 = l(e*v)|l(f*v)|l(g*v)|l(h*v)
+ pmulhw mm5, mm0 //%%mm0,%%mm5\n" // mm5 = h(e*v)|h(f*v)|h(g*v)|h(h*v)
+ movq mm3, mm1 //%%mm1,%%mm3\n" // mm3 = l(a*v)|l(b*v)|l(c*v)|l(d*v)
+ punpckhwd mm1, mm2 //%%mm2,%%mm1\n" // mm1 = a*v|b*v
+ movq mm6, mm4 //%%mm4,%%mm6\n" // mm6 = l(e*v)|l(f*v)|l(g*v)|l(h*v)
+ punpcklwd mm3, mm2 //%%mm2,%%mm3\n" // mm3 = c*v|d*v
+ punpckhwd mm4, mm5 //%%mm5,%%mm4\n" // mm4 = e*f|f*v
+ punpcklwd mm6, mm5 //%%mm5,%%mm6\n" // mm6 = g*v|h*v
+ // pre charger le buffer dst dans mm5
+ movq mm5, [edi + 8] //8(%%edi),%%mm5\n" // mm5 = dst[1]
+ // diviser par 128
+ psrad mm1, 7 //$7,%%mm1\n" // mm1 = a*v/128|b*v/128 , 128 = SDL_MIX_MAXVOLUME
+ add esi, 16 //$16,%%esi\n"
+ psrad mm3, 7 //$7,%%mm3\n" // mm3 = c*v/128|d*v/128
+ psrad mm4, 7 //$7,%%mm4\n" // mm4 = e*v/128|f*v/128
+ // mm1 = le sample avec le volume modifie
+ packssdw mm3, mm1 //%%mm1,%%mm3\n" // mm3 = s(a*v|b*v|c*v|d*v)
+ psrad mm6, 7 //$7,%%mm6\n" // mm6= g*v/128|h*v/128
+ paddsw mm3, mm7 //%%mm7,%%mm3\n" // mm3 = adjust_volume(src)+dst
+ // mm4 = le sample avec le volume modifie
+ packssdw mm6, mm4 //%%mm4,%%mm6\n" // mm6 = s(e*v|f*v|g*v|h*v)
+ movq [edi], mm3 //%%mm3,(%%edi)\n"
+ paddsw mm6, mm5 //%%mm5,%%mm6\n" // mm6 = adjust_volume(src)+dst
+ movq [edi + 8], mm6 //%%mm6,8(%%edi)\n"
+ add edi, 16 //$16,%%edi\n"
+ dec ebx //%%ebx\n"
+ jnz mixloopS16
+
+endS16:
+ emms
+
+ pop ebx
+ pop esi
+ pop edi
+ }
+
+}
+
+////////////////////////////////////////////////
+// Mixing for 8 bit signed buffers
+////////////////////////////////////////////////
+
+void SDL_MixAudio_MMX_S8_VC(char* dst,char* src,unsigned int nSize,int volume)
+{
+ _asm
+ {
+
+ push edi
+ push esi
+ push ebx
+
+ mov edi, dst //movl %0,%%edi // edi = dst
+ mov esi, src //%1,%%esi // esi = src
+ mov eax, volume //%3,%%eax // eax = volume
+
+ movd mm0, eax //%%eax,%%mm0
+ movq mm1, mm0 //%%mm0,%%mm1
+ psllq mm0, 16 //$16,%%mm0
+ por mm0, mm1 //%%mm1,%%mm0
+ psllq mm0, 16 //$16,%%mm0
+ por mm0, mm1 //%%mm1,%%mm0
+ psllq mm0, 16 //$16,%%mm0
+ por mm0, mm1 //%%mm1,%%mm0
+
+ mov ebx, nSize //%2,%%ebx // ebx = size
+ shr ebx, 3 //$3,%%ebx // process 8 bytes per iteration = 8 samples
+ cmp ebx, 0 //$0,%%ebx
+ je endS8
+
+ #ifndef __WATCOMC__
+ align 16
+ #endif
+mixloopS8:
+ pxor mm2, mm2 //%%mm2,%%mm2 // mm2 = 0
+ movq mm1, [esi] //(%%esi),%%mm1 // mm1 = a|b|c|d|e|f|g|h
+ movq mm3, mm1 //%%mm1,%%mm3 // mm3 = a|b|c|d|e|f|g|h
+ // on va faire le "sign extension" en faisant un cmp avec 0 qui retourne 1 si <0, 0 si >0
+ pcmpgtb mm2, mm1 //%%mm1,%%mm2 // mm2 = 11111111|00000000|00000000....
+ punpckhbw mm1, mm2 //%%mm2,%%mm1 // mm1 = 0|a|0|b|0|c|0|d
+ punpcklbw mm3, mm2 //%%mm2,%%mm3 // mm3 = 0|e|0|f|0|g|0|h
+ movq mm2, [edi] //(%%edi),%%mm2 // mm2 = destination
+ pmullw mm1, mm0 //%%mm0,%%mm1 // mm1 = v*a|v*b|v*c|v*d
+ add esi, 8 //$8,%%esi
+ pmullw mm3, mm0 //%%mm0,%%mm3 // mm3 = v*e|v*f|v*g|v*h
+ psraw mm1, 7 //$7,%%mm1 // mm1 = v*a/128|v*b/128|v*c/128|v*d/128
+ psraw mm3, 7 //$7,%%mm3 // mm3 = v*e/128|v*f/128|v*g/128|v*h/128
+ packsswb mm3, mm1 //%%mm1,%%mm3 // mm1 = v*a/128|v*b/128|v*c/128|v*d/128|v*e/128|v*f/128|v*g/128|v*h/128
+ paddsb mm3, mm2 //%%mm2,%%mm3 // add to destination buffer
+ movq [edi], mm3 //%%mm3,(%%edi) // store back to ram
+ add edi, 8 //$8,%%edi
+ dec ebx //%%ebx
+ jnz mixloopS8
+
+endS8:
+ emms
+
+ pop ebx
+ pop esi
+ pop edi
+ }
+}
+
+#endif /* SDL_ASSEMBLY_ROUTINES */
+#endif /* SDL_BUGGY_MMX_MIXERS */
diff --git a/src/audio/SDL_mixer_MMX_VC.h b/src/audio/SDL_mixer_MMX_VC.h
new file mode 100644
index 0000000..7c67a36
--- /dev/null
+++ b/src/audio/SDL_mixer_MMX_VC.h
@@ -0,0 +1,38 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+
+#if defined(SDL_BUGGY_MMX_MIXERS) /* buggy, so we're disabling them. --ryan. */
+#if ((defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)) && defined(SDL_ASSEMBLY_ROUTINES)
+/* headers for MMX assembler version of SDL_MixAudio
+ Copyright 2002 Stephane Marchesin (stephane.marchesin@wanadoo.fr)
+ Converted to Intel ASM notation by Cth
+ This code is licensed under the LGPL (see COPYING for details)
+
+ Assumes buffer size in bytes is a multiple of 16
+ Assumes SDL_MIX_MAXVOLUME = 128
+*/
+void SDL_MixAudio_MMX_S16_VC(char* ,char* ,unsigned int ,int );
+void SDL_MixAudio_MMX_S8_VC(char* ,char* ,unsigned int ,int );
+#endif
+#endif
diff --git a/src/audio/SDL_mixer_m68k.c b/src/audio/SDL_mixer_m68k.c
new file mode 100644
index 0000000..477a6bb
--- /dev/null
+++ b/src/audio/SDL_mixer_m68k.c
@@ -0,0 +1,211 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ m68k assembly mix routines
+
+ Patrice Mandin
+*/
+
+#if defined(__M68000__) && defined(__GNUC__)
+void SDL_MixAudio_m68k_U8(char* dst, char* src, long len, long volume, char* mix8)
+{
+ __asm__ __volatile__ (
+
+ "tstl %2\n"
+" beqs stoploop_u8\n"
+"mixloop_u8:\n"
+
+ /* Mix a sample */
+
+" moveq #0,%%d0\n"
+" moveq #0,%%d1\n"
+
+" moveb %1@+,%%d0\n" /* d0 = *src++ */
+" sub #128,%%d0\n" /* d0 -= 128 */
+" muls %3,%%d0\n" /* d0 *= volume (0<=volume<=128) */
+" moveb %0@,%%d1\n" /* d1 = *dst */
+" asr #7,%%d0\n" /* d0 /= 128 (SDL_MIX_MAXVOLUME) */
+" add #128,%%d0\n" /* d0 += 128 */
+
+" add %%d1,%%d0\n"
+
+" moveb %4@(%%d0:w),%0@+\n"
+
+ /* Loop till done */
+
+" subql #1,%2\n"
+" bhis mixloop_u8\n"
+"stoploop_u8:\n"
+
+ : /* no return value */
+ : /* input */
+ "a"(dst), "a"(src), "d"(len), "d"(volume), "a"(mix8)
+ : /* clobbered registers */
+ "d0", "d1", "cc", "memory"
+ );
+}
+
+void SDL_MixAudio_m68k_S8(char* dst, char* src, long len, long volume)
+{
+ __asm__ __volatile__ (
+
+ "tstl %2\n"
+" beqs stoploop_s8\n"
+" moveq #-128,%%d2\n"
+" moveq #127,%%d3\n"
+"mixloop_s8:\n"
+
+ /* Mix a sample */
+
+" moveq #0,%%d0\n"
+" moveq #0,%%d1\n"
+
+" moveb %1@+,%%d0\n" /* d0 = *src++ */
+" muls %3,%%d0\n" /* d0 *= volume (0<=volume<=128) */
+" moveb %0@,%%d1\n" /* d1 = *dst */
+" asr #7,%%d0\n" /* d0 /= 128 (SDL_MIX_MAXVOLUME) */
+
+" add %%d1,%%d0\n"
+
+" cmp %%d2,%%d0\n"
+" bges lower_limit_s8\n"
+" move %%d2,%%d0\n"
+"lower_limit_s8:\n"
+
+" cmp %%d3,%%d0\n"
+" bles upper_limit_s8\n"
+" move %%d3,%%d0\n"
+"upper_limit_s8:\n"
+" moveb %%d0,%0@+\n"
+
+ /* Loop till done */
+
+" subql #1,%2\n"
+" bhis mixloop_s8\n"
+"stoploop_s8:\n"
+
+ : /* no return value */
+ : /* input */
+ "a"(dst), "a"(src), "d"(len), "d"(volume)
+ : /* clobbered registers */
+ "d0", "d1", "d2", "d3", "cc", "memory"
+ );
+}
+
+void SDL_MixAudio_m68k_S16MSB(short* dst, short* src, long len, long volume)
+{
+ __asm__ __volatile__ (
+
+ "tstl %2\n"
+" beqs stoploop_s16msb\n"
+" movel #-32768,%%d2\n"
+" movel #32767,%%d3\n"
+" lsrl #1,%2\n"
+"mixloop_s16msb:\n"
+
+ /* Mix a sample */
+
+" move %1@+,%%d0\n" /* d0 = *src++ */
+" muls %3,%%d0\n" /* d0 *= volume (0<=volume<=128) */
+" move %0@,%%d1\n" /* d1 = *dst */
+" extl %%d1\n" /* extend d1 to 32 bits */
+" asrl #7,%%d0\n" /* d0 /= 128 (SDL_MIX_MAXVOLUME) */
+
+" addl %%d1,%%d0\n"
+
+" cmpl %%d2,%%d0\n"
+" bges lower_limit_s16msb\n"
+" move %%d2,%%d0\n"
+"lower_limit_s16msb:\n"
+
+" cmpl %%d3,%%d0\n"
+" bles upper_limit_s16msb\n"
+" move %%d3,%%d0\n"
+"upper_limit_s16msb:\n"
+" move %%d0,%0@+\n"
+
+ /* Loop till done */
+
+" subql #1,%2\n"
+" bhis mixloop_s16msb\n"
+"stoploop_s16msb:\n"
+
+ : /* no return value */
+ : /* input */
+ "a"(dst), "a"(src), "d"(len), "d"(volume)
+ : /* clobbered registers */
+ "d0", "d1", "d2", "d3", "cc", "memory"
+ );
+}
+
+void SDL_MixAudio_m68k_S16LSB(short* dst, short* src, long len, long volume)
+{
+ __asm__ __volatile__ (
+
+ "tstl %2\n"
+" beqs stoploop_s16lsb\n"
+" movel #-32768,%%d2\n"
+" movel #32767,%%d3\n"
+" lsrl #1,%2\n"
+"mixloop_s16lsb:\n"
+
+ /* Mix a sample */
+
+" move %1@+,%%d0\n" /* d0 = *src++ */
+" rorw #8,%%d0\n"
+" muls %3,%%d0\n" /* d0 *= volume (0<=volume<=128) */
+" move %0@,%%d1\n" /* d1 = *dst */
+" rorw #8,%%d1\n"
+" extl %%d1\n" /* extend d1 to 32 bits */
+" asrl #7,%%d0\n" /* d0 /= 128 (SDL_MIX_MAXVOLUME) */
+
+" addl %%d1,%%d0\n"
+
+" cmpl %%d2,%%d0\n"
+" bges lower_limit_s16lsb\n"
+" move %%d2,%%d0\n"
+"lower_limit_s16lsb:\n"
+
+" cmpl %%d3,%%d0\n"
+" bles upper_limit_s16lsb\n"
+" move %%d3,%%d0\n"
+"upper_limit_s16lsb:\n"
+" rorw #8,%%d0\n"
+" move %%d0,%0@+\n"
+
+ /* Loop till done */
+
+" subql #1,%2\n"
+" bhis mixloop_s16lsb\n"
+"stoploop_s16lsb:\n"
+
+ : /* no return value */
+ : /* input */
+ "a"(dst), "a"(src), "d"(len), "d"(volume)
+ : /* clobbered registers */
+ "d0", "d1", "d2", "d3", "cc", "memory"
+ );
+}
+#endif
+
diff --git a/src/audio/SDL_mixer_m68k.h b/src/audio/SDL_mixer_m68k.h
new file mode 100644
index 0000000..12b7f35
--- /dev/null
+++ b/src/audio/SDL_mixer_m68k.h
@@ -0,0 +1,36 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ m68k assembly mix routines
+
+ Patrice Mandin
+*/
+
+#if defined(__M68000__) && defined(__GNUC__)
+void SDL_MixAudio_m68k_U8(char* dst,char* src, long len, long volume, char* mix8);
+void SDL_MixAudio_m68k_S8(char* dst,char* src, long len, long volume);
+
+void SDL_MixAudio_m68k_S16MSB(short* dst,short* src, long len, long volume);
+void SDL_MixAudio_m68k_S16LSB(short* dst,short* src, long len, long volume);
+#endif
diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h
new file mode 100644
index 0000000..50cf179
--- /dev/null
+++ b/src/audio/SDL_sysaudio.h
@@ -0,0 +1,184 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is SDL_free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_sysaudio_h
+#define _SDL_sysaudio_h
+
+#include "SDL_mutex.h"
+#include "SDL_thread.h"
+
+/* The SDL audio driver */
+typedef struct SDL_AudioDevice SDL_AudioDevice;
+
+/* Define the SDL audio driver structure */
+#define _THIS SDL_AudioDevice *_this
+#ifndef _STATUS
+#define _STATUS SDL_status *status
+#endif
+struct SDL_AudioDevice {
+ /* * * */
+ /* The name of this audio driver */
+ const char *name;
+
+ /* * * */
+ /* The description of this audio driver */
+ const char *desc;
+
+ /* * * */
+ /* Public driver functions */
+ int (*OpenAudio)(_THIS, SDL_AudioSpec *spec);
+ void (*ThreadInit)(_THIS); /* Called by audio thread at start */
+ void (*WaitAudio)(_THIS);
+ void (*PlayAudio)(_THIS);
+ Uint8 *(*GetAudioBuf)(_THIS);
+ void (*WaitDone)(_THIS);
+ void (*CloseAudio)(_THIS);
+
+ /* * * */
+ /* Lock / Unlock functions added for the Mac port */
+ void (*LockAudio)(_THIS);
+ void (*UnlockAudio)(_THIS);
+
+ /* * * */
+ /* Data common to all devices */
+
+ /* The current audio specification (shared with audio thread) */
+ SDL_AudioSpec spec;
+
+ /* An audio conversion block for audio format emulation */
+ SDL_AudioCVT convert;
+
+ /* Current state flags */
+ int enabled;
+ int paused;
+ int opened;
+
+ /* Fake audio buffer for when the audio hardware is busy */
+ Uint8 *fake_stream;
+
+ /* A semaphore for locking the mixing buffers */
+ SDL_mutex *mixer_lock;
+
+ /* A thread to feed the audio device */
+ SDL_Thread *thread;
+ Uint32 threadid;
+
+ /* * * */
+ /* Data private to this driver */
+ struct SDL_PrivateAudioData *hidden;
+
+ /* * * */
+ /* The function used to dispose of this structure */
+ void (*free)(_THIS);
+};
+#undef _THIS
+
+typedef struct AudioBootStrap {
+ const char *name;
+ const char *desc;
+ int (*available)(void);
+ SDL_AudioDevice *(*create)(int devindex);
+} AudioBootStrap;
+
+#if SDL_AUDIO_DRIVER_BSD
+extern AudioBootStrap BSD_AUDIO_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_PULSE
+extern AudioBootStrap PULSE_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_ALSA
+extern AudioBootStrap ALSA_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_OSS
+extern AudioBootStrap DSP_bootstrap;
+extern AudioBootStrap DMA_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_QNXNTO
+extern AudioBootStrap QNXNTOAUDIO_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_SUNAUDIO
+extern AudioBootStrap SUNAUDIO_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_DMEDIA
+extern AudioBootStrap DMEDIA_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_ARTS
+extern AudioBootStrap ARTS_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_ESD
+extern AudioBootStrap ESD_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_NAS
+extern AudioBootStrap NAS_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_DSOUND
+extern AudioBootStrap DSOUND_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_WAVEOUT
+extern AudioBootStrap WAVEOUT_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_PAUD
+extern AudioBootStrap Paud_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_BAUDIO
+extern AudioBootStrap BAUDIO_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_COREAUDIO
+extern AudioBootStrap COREAUDIO_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_SNDMGR
+extern AudioBootStrap SNDMGR_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_MINT
+extern AudioBootStrap MINTAUDIO_GSXB_bootstrap;
+extern AudioBootStrap MINTAUDIO_MCSN_bootstrap;
+extern AudioBootStrap MINTAUDIO_STFA_bootstrap;
+extern AudioBootStrap MINTAUDIO_XBIOS_bootstrap;
+extern AudioBootStrap MINTAUDIO_DMA8_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_DISK
+extern AudioBootStrap DISKAUD_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_DUMMY
+extern AudioBootStrap DUMMYAUD_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_DC
+extern AudioBootStrap DCAUD_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_NDS
+extern AudioBootStrap NDSAUD_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_MMEAUDIO
+extern AudioBootStrap MMEAUDIO_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_DART
+extern AudioBootStrap DART_bootstrap;
+#endif
+#if SDL_AUDIO_DRIVER_EPOCAUDIO
+extern AudioBootStrap EPOCAudio_bootstrap;
+#endif
+
+/* This is the current audio device */
+extern SDL_AudioDevice *current_audio;
+
+#endif /* _SDL_sysaudio_h */
diff --git a/src/audio/SDL_wave.c b/src/audio/SDL_wave.c
new file mode 100644
index 0000000..a2f1164
--- /dev/null
+++ b/src/audio/SDL_wave.c
@@ -0,0 +1,600 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Microsoft WAVE file loading routines */
+
+#include "SDL_audio.h"
+#include "SDL_wave.h"
+
+
+static int ReadChunk(SDL_RWops *src, Chunk *chunk);
+
+struct MS_ADPCM_decodestate {
+ Uint8 hPredictor;
+ Uint16 iDelta;
+ Sint16 iSamp1;
+ Sint16 iSamp2;
+};
+static struct MS_ADPCM_decoder {
+ WaveFMT wavefmt;
+ Uint16 wSamplesPerBlock;
+ Uint16 wNumCoef;
+ Sint16 aCoeff[7][2];
+ /* * * */
+ struct MS_ADPCM_decodestate state[2];
+} MS_ADPCM_state;
+
+static int InitMS_ADPCM(WaveFMT *format)
+{
+ Uint8 *rogue_feel;
+ Uint16 extra_info;
+ int i;
+
+ /* Set the rogue pointer to the MS_ADPCM specific data */
+ MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
+ MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
+ MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
+ MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
+ MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
+ MS_ADPCM_state.wavefmt.bitspersample =
+ SDL_SwapLE16(format->bitspersample);
+ rogue_feel = (Uint8 *)format+sizeof(*format);
+ if ( sizeof(*format) == 16 ) {
+ extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ }
+ MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ MS_ADPCM_state.wNumCoef = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ if ( MS_ADPCM_state.wNumCoef != 7 ) {
+ SDL_SetError("Unknown set of MS_ADPCM coefficients");
+ return(-1);
+ }
+ for ( i=0; i<MS_ADPCM_state.wNumCoef; ++i ) {
+ MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ }
+ return(0);
+}
+
+static Sint32 MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state,
+ Uint8 nybble, Sint16 *coeff)
+{
+ const Sint32 max_audioval = ((1<<(16-1))-1);
+ const Sint32 min_audioval = -(1<<(16-1));
+ const Sint32 adaptive[] = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+ };
+ Sint32 new_sample, delta;
+
+ new_sample = ((state->iSamp1 * coeff[0]) +
+ (state->iSamp2 * coeff[1]))/256;
+ if ( nybble & 0x08 ) {
+ new_sample += state->iDelta * (nybble-0x10);
+ } else {
+ new_sample += state->iDelta * nybble;
+ }
+ if ( new_sample < min_audioval ) {
+ new_sample = min_audioval;
+ } else
+ if ( new_sample > max_audioval ) {
+ new_sample = max_audioval;
+ }
+ delta = ((Sint32)state->iDelta * adaptive[nybble])/256;
+ if ( delta < 16 ) {
+ delta = 16;
+ }
+ state->iDelta = (Uint16)delta;
+ state->iSamp2 = state->iSamp1;
+ state->iSamp1 = (Sint16)new_sample;
+ return(new_sample);
+}
+
+static int MS_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len)
+{
+ struct MS_ADPCM_decodestate *state[2];
+ Uint8 *freeable, *encoded, *decoded;
+ Sint32 encoded_len, samplesleft;
+ Sint8 nybble, stereo;
+ Sint16 *coeff[2];
+ Sint32 new_sample;
+
+ /* Allocate the proper sized output buffer */
+ encoded_len = *audio_len;
+ encoded = *audio_buf;
+ freeable = *audio_buf;
+ *audio_len = (encoded_len/MS_ADPCM_state.wavefmt.blockalign) *
+ MS_ADPCM_state.wSamplesPerBlock*
+ MS_ADPCM_state.wavefmt.channels*sizeof(Sint16);
+ *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
+ if ( *audio_buf == NULL ) {
+ SDL_Error(SDL_ENOMEM);
+ return(-1);
+ }
+ decoded = *audio_buf;
+
+ /* Get ready... Go! */
+ stereo = (MS_ADPCM_state.wavefmt.channels == 2);
+ state[0] = &MS_ADPCM_state.state[0];
+ state[1] = &MS_ADPCM_state.state[stereo];
+ while ( encoded_len >= MS_ADPCM_state.wavefmt.blockalign ) {
+ /* Grab the initial information for this block */
+ state[0]->hPredictor = *encoded++;
+ if ( stereo ) {
+ state[1]->hPredictor = *encoded++;
+ }
+ state[0]->iDelta = ((encoded[1]<<8)|encoded[0]);
+ encoded += sizeof(Sint16);
+ if ( stereo ) {
+ state[1]->iDelta = ((encoded[1]<<8)|encoded[0]);
+ encoded += sizeof(Sint16);
+ }
+ state[0]->iSamp1 = ((encoded[1]<<8)|encoded[0]);
+ encoded += sizeof(Sint16);
+ if ( stereo ) {
+ state[1]->iSamp1 = ((encoded[1]<<8)|encoded[0]);
+ encoded += sizeof(Sint16);
+ }
+ state[0]->iSamp2 = ((encoded[1]<<8)|encoded[0]);
+ encoded += sizeof(Sint16);
+ if ( stereo ) {
+ state[1]->iSamp2 = ((encoded[1]<<8)|encoded[0]);
+ encoded += sizeof(Sint16);
+ }
+ coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor];
+ coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor];
+
+ /* Store the two initial samples we start with */
+ decoded[0] = state[0]->iSamp2&0xFF;
+ decoded[1] = state[0]->iSamp2>>8;
+ decoded += 2;
+ if ( stereo ) {
+ decoded[0] = state[1]->iSamp2&0xFF;
+ decoded[1] = state[1]->iSamp2>>8;
+ decoded += 2;
+ }
+ decoded[0] = state[0]->iSamp1&0xFF;
+ decoded[1] = state[0]->iSamp1>>8;
+ decoded += 2;
+ if ( stereo ) {
+ decoded[0] = state[1]->iSamp1&0xFF;
+ decoded[1] = state[1]->iSamp1>>8;
+ decoded += 2;
+ }
+
+ /* Decode and store the other samples in this block */
+ samplesleft = (MS_ADPCM_state.wSamplesPerBlock-2)*
+ MS_ADPCM_state.wavefmt.channels;
+ while ( samplesleft > 0 ) {
+ nybble = (*encoded)>>4;
+ new_sample = MS_ADPCM_nibble(state[0],nybble,coeff[0]);
+ decoded[0] = new_sample&0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample&0xFF;
+ decoded += 2;
+
+ nybble = (*encoded)&0x0F;
+ new_sample = MS_ADPCM_nibble(state[1],nybble,coeff[1]);
+ decoded[0] = new_sample&0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample&0xFF;
+ decoded += 2;
+
+ ++encoded;
+ samplesleft -= 2;
+ }
+ encoded_len -= MS_ADPCM_state.wavefmt.blockalign;
+ }
+ SDL_free(freeable);
+ return(0);
+}
+
+struct IMA_ADPCM_decodestate {
+ Sint32 sample;
+ Sint8 index;
+};
+static struct IMA_ADPCM_decoder {
+ WaveFMT wavefmt;
+ Uint16 wSamplesPerBlock;
+ /* * * */
+ struct IMA_ADPCM_decodestate state[2];
+} IMA_ADPCM_state;
+
+static int InitIMA_ADPCM(WaveFMT *format)
+{
+ Uint8 *rogue_feel;
+ Uint16 extra_info;
+
+ /* Set the rogue pointer to the IMA_ADPCM specific data */
+ IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
+ IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
+ IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
+ IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
+ IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
+ IMA_ADPCM_state.wavefmt.bitspersample =
+ SDL_SwapLE16(format->bitspersample);
+ rogue_feel = (Uint8 *)format+sizeof(*format);
+ if ( sizeof(*format) == 16 ) {
+ extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ rogue_feel += sizeof(Uint16);
+ }
+ IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]);
+ return(0);
+}
+
+static Sint32 IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state,Uint8 nybble)
+{
+ const Sint32 max_audioval = ((1<<(16-1))-1);
+ const Sint32 min_audioval = -(1<<(16-1));
+ const int index_table[16] = {
+ -1, -1, -1, -1,
+ 2, 4, 6, 8,
+ -1, -1, -1, -1,
+ 2, 4, 6, 8
+ };
+ const Sint32 step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
+ 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
+ 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
+ 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
+ 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
+ 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
+ 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
+ 22385, 24623, 27086, 29794, 32767
+ };
+ Sint32 delta, step;
+
+ /* Compute difference and new sample value */
+ step = step_table[state->index];
+ delta = step >> 3;
+ if ( nybble & 0x04 ) delta += step;
+ if ( nybble & 0x02 ) delta += (step >> 1);
+ if ( nybble & 0x01 ) delta += (step >> 2);
+ if ( nybble & 0x08 ) delta = -delta;
+ state->sample += delta;
+
+ /* Update index value */
+ state->index += index_table[nybble];
+ if ( state->index > 88 ) {
+ state->index = 88;
+ } else
+ if ( state->index < 0 ) {
+ state->index = 0;
+ }
+
+ /* Clamp output sample */
+ if ( state->sample > max_audioval ) {
+ state->sample = max_audioval;
+ } else
+ if ( state->sample < min_audioval ) {
+ state->sample = min_audioval;
+ }
+ return(state->sample);
+}
+
+/* Fill the decode buffer with a channel block of data (8 samples) */
+static void Fill_IMA_ADPCM_block(Uint8 *decoded, Uint8 *encoded,
+ int channel, int numchannels, struct IMA_ADPCM_decodestate *state)
+{
+ int i;
+ Sint8 nybble;
+ Sint32 new_sample;
+
+ decoded += (channel * 2);
+ for ( i=0; i<4; ++i ) {
+ nybble = (*encoded)&0x0F;
+ new_sample = IMA_ADPCM_nibble(state, nybble);
+ decoded[0] = new_sample&0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample&0xFF;
+ decoded += 2 * numchannels;
+
+ nybble = (*encoded)>>4;
+ new_sample = IMA_ADPCM_nibble(state, nybble);
+ decoded[0] = new_sample&0xFF;
+ new_sample >>= 8;
+ decoded[1] = new_sample&0xFF;
+ decoded += 2 * numchannels;
+
+ ++encoded;
+ }
+}
+
+static int IMA_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len)
+{
+ struct IMA_ADPCM_decodestate *state;
+ Uint8 *freeable, *encoded, *decoded;
+ Sint32 encoded_len, samplesleft;
+ unsigned int c, channels;
+
+ /* Check to make sure we have enough variables in the state array */
+ channels = IMA_ADPCM_state.wavefmt.channels;
+ if ( channels > SDL_arraysize(IMA_ADPCM_state.state) ) {
+ SDL_SetError("IMA ADPCM decoder can only handle %d channels",
+ SDL_arraysize(IMA_ADPCM_state.state));
+ return(-1);
+ }
+ state = IMA_ADPCM_state.state;
+
+ /* Allocate the proper sized output buffer */
+ encoded_len = *audio_len;
+ encoded = *audio_buf;
+ freeable = *audio_buf;
+ *audio_len = (encoded_len/IMA_ADPCM_state.wavefmt.blockalign) *
+ IMA_ADPCM_state.wSamplesPerBlock*
+ IMA_ADPCM_state.wavefmt.channels*sizeof(Sint16);
+ *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
+ if ( *audio_buf == NULL ) {
+ SDL_Error(SDL_ENOMEM);
+ return(-1);
+ }
+ decoded = *audio_buf;
+
+ /* Get ready... Go! */
+ while ( encoded_len >= IMA_ADPCM_state.wavefmt.blockalign ) {
+ /* Grab the initial information for this block */
+ for ( c=0; c<channels; ++c ) {
+ /* Fill the state information for this block */
+ state[c].sample = ((encoded[1]<<8)|encoded[0]);
+ encoded += 2;
+ if ( state[c].sample & 0x8000 ) {
+ state[c].sample -= 0x10000;
+ }
+ state[c].index = *encoded++;
+ /* Reserved byte in buffer header, should be 0 */
+ if ( *encoded++ != 0 ) {
+ /* Uh oh, corrupt data? Buggy code? */;
+ }
+
+ /* Store the initial sample we start with */
+ decoded[0] = (Uint8)(state[c].sample&0xFF);
+ decoded[1] = (Uint8)(state[c].sample>>8);
+ decoded += 2;
+ }
+
+ /* Decode and store the other samples in this block */
+ samplesleft = (IMA_ADPCM_state.wSamplesPerBlock-1)*channels;
+ while ( samplesleft > 0 ) {
+ for ( c=0; c<channels; ++c ) {
+ Fill_IMA_ADPCM_block(decoded, encoded,
+ c, channels, &state[c]);
+ encoded += 4;
+ samplesleft -= 8;
+ }
+ decoded += (channels * 8 * 2);
+ }
+ encoded_len -= IMA_ADPCM_state.wavefmt.blockalign;
+ }
+ SDL_free(freeable);
+ return(0);
+}
+
+SDL_AudioSpec * SDL_LoadWAV_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+ int was_error;
+ Chunk chunk;
+ int lenread;
+ int MS_ADPCM_encoded, IMA_ADPCM_encoded;
+ int samplesize;
+
+ /* WAV magic header */
+ Uint32 RIFFchunk;
+ Uint32 wavelen = 0;
+ Uint32 WAVEmagic;
+ Uint32 headerDiff = 0;
+
+ /* FMT chunk */
+ WaveFMT *format = NULL;
+
+ /* Make sure we are passed a valid data source */
+ was_error = 0;
+ if ( src == NULL ) {
+ was_error = 1;
+ goto done;
+ }
+
+ /* Check the magic header */
+ RIFFchunk = SDL_ReadLE32(src);
+ wavelen = SDL_ReadLE32(src);
+ if ( wavelen == WAVE ) { /* The RIFFchunk has already been read */
+ WAVEmagic = wavelen;
+ wavelen = RIFFchunk;
+ RIFFchunk = RIFF;
+ } else {
+ WAVEmagic = SDL_ReadLE32(src);
+ }
+ if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
+ SDL_SetError("Unrecognized file type (not WAVE)");
+ was_error = 1;
+ goto done;
+ }
+ headerDiff += sizeof(Uint32); /* for WAVE */
+
+ /* Read the audio data format chunk */
+ chunk.data = NULL;
+ do {
+ if ( chunk.data != NULL ) {
+ SDL_free(chunk.data);
+ chunk.data = NULL;
+ }
+ lenread = ReadChunk(src, &chunk);
+ if ( lenread < 0 ) {
+ was_error = 1;
+ goto done;
+ }
+ /* 2 Uint32's for chunk header+len, plus the lenread */
+ headerDiff += lenread + 2 * sizeof(Uint32);
+ } while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
+
+ /* Decode the audio data format */
+ format = (WaveFMT *)chunk.data;
+ if ( chunk.magic != FMT ) {
+ SDL_SetError("Complex WAVE files not supported");
+ was_error = 1;
+ goto done;
+ }
+ MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
+ switch (SDL_SwapLE16(format->encoding)) {
+ case PCM_CODE:
+ /* We can understand this */
+ break;
+ case MS_ADPCM_CODE:
+ /* Try to understand this */
+ if ( InitMS_ADPCM(format) < 0 ) {
+ was_error = 1;
+ goto done;
+ }
+ MS_ADPCM_encoded = 1;
+ break;
+ case IMA_ADPCM_CODE:
+ /* Try to understand this */
+ if ( InitIMA_ADPCM(format) < 0 ) {
+ was_error = 1;
+ goto done;
+ }
+ IMA_ADPCM_encoded = 1;
+ break;
+ case MP3_CODE:
+ SDL_SetError("MPEG Layer 3 data not supported",
+ SDL_SwapLE16(format->encoding));
+ was_error = 1;
+ goto done;
+ default:
+ SDL_SetError("Unknown WAVE data format: 0x%.4x",
+ SDL_SwapLE16(format->encoding));
+ was_error = 1;
+ goto done;
+ }
+ SDL_memset(spec, 0, (sizeof *spec));
+ spec->freq = SDL_SwapLE32(format->frequency);
+ switch (SDL_SwapLE16(format->bitspersample)) {
+ case 4:
+ if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) {
+ spec->format = AUDIO_S16;
+ } else {
+ was_error = 1;
+ }
+ break;
+ case 8:
+ spec->format = AUDIO_U8;
+ break;
+ case 16:
+ spec->format = AUDIO_S16;
+ break;
+ default:
+ was_error = 1;
+ break;
+ }
+ if ( was_error ) {
+ SDL_SetError("Unknown %d-bit PCM data format",
+ SDL_SwapLE16(format->bitspersample));
+ goto done;
+ }
+ spec->channels = (Uint8)SDL_SwapLE16(format->channels);
+ spec->samples = 4096; /* Good default buffer size */
+
+ /* Read the audio data chunk */
+ *audio_buf = NULL;
+ do {
+ if ( *audio_buf != NULL ) {
+ SDL_free(*audio_buf);
+ *audio_buf = NULL;
+ }
+ lenread = ReadChunk(src, &chunk);
+ if ( lenread < 0 ) {
+ was_error = 1;
+ goto done;
+ }
+ *audio_len = lenread;
+ *audio_buf = chunk.data;
+ if(chunk.magic != DATA) headerDiff += lenread + 2 * sizeof(Uint32);
+ } while ( chunk.magic != DATA );
+ headerDiff += 2 * sizeof(Uint32); /* for the data chunk and len */
+
+ if ( MS_ADPCM_encoded ) {
+ if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) {
+ was_error = 1;
+ goto done;
+ }
+ }
+ if ( IMA_ADPCM_encoded ) {
+ if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) {
+ was_error = 1;
+ goto done;
+ }
+ }
+
+ /* Don't return a buffer that isn't a multiple of samplesize */
+ samplesize = ((spec->format & 0xFF)/8)*spec->channels;
+ *audio_len &= ~(samplesize-1);
+
+done:
+ if ( format != NULL ) {
+ SDL_free(format);
+ }
+ if ( src ) {
+ if ( freesrc ) {
+ SDL_RWclose(src);
+ } else {
+ /* seek to the end of the file (given by the RIFF chunk) */
+ SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR);
+ }
+ }
+ if ( was_error ) {
+ spec = NULL;
+ }
+ return(spec);
+}
+
+/* Since the WAV memory is allocated in the shared library, it must also
+ be freed here. (Necessary under Win32, VC++)
+ */
+void SDL_FreeWAV(Uint8 *audio_buf)
+{
+ if ( audio_buf != NULL ) {
+ SDL_free(audio_buf);
+ }
+}
+
+static int ReadChunk(SDL_RWops *src, Chunk *chunk)
+{
+ chunk->magic = SDL_ReadLE32(src);
+ chunk->length = SDL_ReadLE32(src);
+ chunk->data = (Uint8 *)SDL_malloc(chunk->length);
+ if ( chunk->data == NULL ) {
+ SDL_Error(SDL_ENOMEM);
+ return(-1);
+ }
+ if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
+ SDL_Error(SDL_EFREAD);
+ SDL_free(chunk->data);
+ chunk->data = NULL;
+ return(-1);
+ }
+ return(chunk->length);
+}
diff --git a/src/audio/SDL_wave.h b/src/audio/SDL_wave.h
new file mode 100644
index 0000000..b1ba47f
--- /dev/null
+++ b/src/audio/SDL_wave.h
@@ -0,0 +1,62 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is SDL_free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* WAVE files are little-endian */
+
+/*******************************************/
+/* Define values for Microsoft WAVE format */
+/*******************************************/
+#define RIFF 0x46464952 /* "RIFF" */
+#define WAVE 0x45564157 /* "WAVE" */
+#define FACT 0x74636166 /* "fact" */
+#define LIST 0x5453494c /* "LIST" */
+#define FMT 0x20746D66 /* "fmt " */
+#define DATA 0x61746164 /* "data" */
+#define PCM_CODE 0x0001
+#define MS_ADPCM_CODE 0x0002
+#define IMA_ADPCM_CODE 0x0011
+#define MP3_CODE 0x0055
+#define WAVE_MONO 1
+#define WAVE_STEREO 2
+
+/* Normally, these three chunks come consecutively in a WAVE file */
+typedef struct WaveFMT {
+/* Not saved in the chunk we read:
+ Uint32 FMTchunk;
+ Uint32 fmtlen;
+*/
+ Uint16 encoding;
+ Uint16 channels; /* 1 = mono, 2 = stereo */
+ Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
+ Uint32 byterate; /* Average bytes per second */
+ Uint16 blockalign; /* Bytes per sample block */
+ Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
+} WaveFMT;
+
+/* The general chunk found in the WAVE file */
+typedef struct Chunk {
+ Uint32 magic;
+ Uint32 length;
+ Uint8 *data;
+} Chunk;
+
diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c
new file mode 100644
index 0000000..e3ce985
--- /dev/null
+++ b/src/audio/alsa/SDL_alsa_audio.c
@@ -0,0 +1,612 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <sys/types.h>
+#include <signal.h> /* For kill() */
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "SDL_alsa_audio.h"
+
+#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+
+/* The tag name used by ALSA audio */
+#define DRIVER_NAME "alsa"
+
+/* Audio driver functions */
+static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void ALSA_WaitAudio(_THIS);
+static void ALSA_PlayAudio(_THIS);
+static Uint8 *ALSA_GetAudioBuf(_THIS);
+static void ALSA_CloseAudio(_THIS);
+
+#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+
+static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
+static void *alsa_handle = NULL;
+static int alsa_loaded = 0;
+
+static int (*SDL_NAME(snd_pcm_open))(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
+static int (*SDL_NAME(snd_pcm_close))(snd_pcm_t *pcm);
+static snd_pcm_sframes_t (*SDL_NAME(snd_pcm_writei))(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
+static int (*SDL_NAME(snd_pcm_recover))(snd_pcm_t *pcm, int err, int silent);
+static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm);
+static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm);
+static const char *(*SDL_NAME(snd_strerror))(int errnum);
+static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void);
+static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
+static void (*SDL_NAME(snd_pcm_hw_params_copy))(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src);
+static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
+static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
+static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
+static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val);
+static int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
+static int (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
+static int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir);
+static int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
+static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
+static int (*SDL_NAME(snd_pcm_hw_params_set_buffer_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
+static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
+static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+/*
+*/
+static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams);
+static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
+static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
+static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
+static int (*SDL_NAME(snd_pcm_wait))(snd_pcm_t *pcm, int timeout);
+#define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
+#define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+static struct {
+ const char *name;
+ void **func;
+} alsa_functions[] = {
+ { "snd_pcm_open", (void**)(char*)&SDL_NAME(snd_pcm_open) },
+ { "snd_pcm_close", (void**)(char*)&SDL_NAME(snd_pcm_close) },
+ { "snd_pcm_writei", (void**)(char*)&SDL_NAME(snd_pcm_writei) },
+ { "snd_pcm_recover", (void**)(char*)&SDL_NAME(snd_pcm_recover) },
+ { "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) },
+ { "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) },
+ { "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) },
+ { "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) },
+ { "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) },
+ { "snd_pcm_hw_params_copy", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_copy) },
+ { "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) },
+ { "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) },
+ { "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) },
+ { "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) },
+ { "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) },
+ { "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) },
+ { "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) },
+ { "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
+ { "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
+ { "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
+ { "snd_pcm_hw_params_set_buffer_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_buffer_size_near) },
+ { "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) },
+ { "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
+ { "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) },
+ { "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) },
+ { "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
+ { "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
+ { "snd_pcm_wait", (void**)(char*)&SDL_NAME(snd_pcm_wait) },
+};
+
+static void UnloadALSALibrary(void) {
+ if (alsa_loaded) {
+ SDL_UnloadObject(alsa_handle);
+ alsa_handle = NULL;
+ alsa_loaded = 0;
+ }
+}
+
+static int LoadALSALibrary(void) {
+ int i, retval = -1;
+
+ alsa_handle = SDL_LoadObject(alsa_library);
+ if (alsa_handle) {
+ alsa_loaded = 1;
+ retval = 0;
+ for (i = 0; i < SDL_arraysize(alsa_functions); i++) {
+ *alsa_functions[i].func = SDL_LoadFunction(alsa_handle,alsa_functions[i].name);
+ if (!*alsa_functions[i].func) {
+ retval = -1;
+ UnloadALSALibrary();
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void UnloadALSALibrary(void) {
+ return;
+}
+
+static int LoadALSALibrary(void) {
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
+
+static const char *get_audio_device(int channels)
+{
+ const char *device;
+
+ device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
+ if ( device == NULL ) {
+ switch (channels) {
+ case 6:
+ device = "plug:surround51";
+ break;
+ case 4:
+ device = "plug:surround40";
+ break;
+ default:
+ device = "default";
+ break;
+ }
+ }
+ return device;
+}
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int available;
+ int status;
+ snd_pcm_t *handle;
+
+ available = 0;
+ if (LoadALSALibrary() < 0) {
+ return available;
+ }
+ status = SDL_NAME(snd_pcm_open)(&handle, get_audio_device(2), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ if ( status >= 0 ) {
+ available = 1;
+ SDL_NAME(snd_pcm_close)(handle);
+ }
+ UnloadALSALibrary();
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+ UnloadALSALibrary();
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ LoadALSALibrary();
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = ALSA_OpenAudio;
+ this->WaitAudio = ALSA_WaitAudio;
+ this->PlayAudio = ALSA_PlayAudio;
+ this->GetAudioBuf = ALSA_GetAudioBuf;
+ this->CloseAudio = ALSA_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap ALSA_bootstrap = {
+ DRIVER_NAME, "ALSA PCM audio",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void ALSA_WaitAudio(_THIS)
+{
+ /* We're in blocking mode, so there's nothing to do here */
+}
+
+
+/*
+ * http://bugzilla.libsdl.org/show_bug.cgi?id=110
+ * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
+ * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
+ */
+#define SWIZ6(T) \
+ T *ptr = (T *) mixbuf; \
+ const Uint32 count = (this->spec.samples / 6); \
+ Uint32 i; \
+ for (i = 0; i < count; i++, ptr += 6) { \
+ T tmp; \
+ tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
+ tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
+ }
+
+static __inline__ void swizzle_alsa_channels_6_64bit(_THIS) { SWIZ6(Uint64); }
+static __inline__ void swizzle_alsa_channels_6_32bit(_THIS) { SWIZ6(Uint32); }
+static __inline__ void swizzle_alsa_channels_6_16bit(_THIS) { SWIZ6(Uint16); }
+static __inline__ void swizzle_alsa_channels_6_8bit(_THIS) { SWIZ6(Uint8); }
+
+#undef SWIZ6
+
+
+/*
+ * Called right before feeding this->mixbuf to the hardware. Swizzle channels
+ * from Windows/Mac order to the format alsalib will want.
+ */
+static __inline__ void swizzle_alsa_channels(_THIS)
+{
+ if (this->spec.channels == 6) {
+ const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
+ if (fmtsize == 16)
+ swizzle_alsa_channels_6_16bit(this);
+ else if (fmtsize == 8)
+ swizzle_alsa_channels_6_8bit(this);
+ else if (fmtsize == 32)
+ swizzle_alsa_channels_6_32bit(this);
+ else if (fmtsize == 64)
+ swizzle_alsa_channels_6_64bit(this);
+ }
+
+ /* !!! FIXME: update this for 7.1 if needed, later. */
+}
+
+
+static void ALSA_PlayAudio(_THIS)
+{
+ int status;
+ snd_pcm_uframes_t frames_left;
+ const Uint8 *sample_buf = (const Uint8 *) mixbuf;
+ const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) * this->spec.channels;
+
+ swizzle_alsa_channels(this);
+
+ frames_left = ((snd_pcm_uframes_t) this->spec.samples);
+
+ while ( frames_left > 0 && this->enabled ) {
+ /* This works, but needs more testing before going live */
+ /*SDL_NAME(snd_pcm_wait)(pcm_handle, -1);*/
+
+ status = SDL_NAME(snd_pcm_writei)(pcm_handle, sample_buf, frames_left);
+ if ( status < 0 ) {
+ if ( status == -EAGAIN ) {
+ /* Apparently snd_pcm_recover() doesn't handle this case - does it assume snd_pcm_wait() above? */
+ SDL_Delay(1);
+ continue;
+ }
+ status = SDL_NAME(snd_pcm_recover)(pcm_handle, status, 0);
+ if ( status < 0 ) {
+ /* Hmm, not much we can do - abort */
+ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", SDL_NAME(snd_strerror)(status));
+ this->enabled = 0;
+ return;
+ }
+ continue;
+ }
+ sample_buf += status * frame_size;
+ frames_left -= status;
+ }
+}
+
+static Uint8 *ALSA_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void ALSA_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( pcm_handle ) {
+ SDL_NAME(snd_pcm_drain)(pcm_handle);
+ SDL_NAME(snd_pcm_close)(pcm_handle);
+ pcm_handle = NULL;
+ }
+}
+
+static int ALSA_finalize_hardware(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *hwparams, int override)
+{
+ int status;
+ snd_pcm_uframes_t bufsize;
+
+ /* "set" the hardware with the desired parameters */
+ status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ /* Get samples for the actual buffer size */
+ status = SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
+ if ( status < 0 ) {
+ return(-1);
+ }
+ if ( !override && bufsize != spec->samples * 2 ) {
+ return(-1);
+ }
+
+ /* FIXME: Is this safe to do? */
+ spec->samples = bufsize / 2;
+
+ /* This is useful for debugging */
+ if ( getenv("SDL_AUDIO_ALSA_DEBUG") ) {
+ snd_pcm_uframes_t persize = 0;
+ unsigned int periods = 0;
+
+ SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, NULL);
+ SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, NULL);
+
+ fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
+ }
+ return(0);
+}
+
+static int ALSA_set_period_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params, int override)
+{
+ const char *env;
+ int status;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_uframes_t frames;
+ unsigned int periods;
+
+ /* Copy the hardware parameters for this setup */
+ snd_pcm_hw_params_alloca(&hwparams);
+ SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params);
+
+ if ( !override ) {
+ env = getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
+ if ( env ) {
+ override = SDL_atoi(env);
+ if ( override == 0 ) {
+ return(-1);
+ }
+ }
+ }
+
+ frames = spec->samples;
+ status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ periods = 2;
+ status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ return ALSA_finalize_hardware(this, spec, hwparams, override);
+}
+
+static int ALSA_set_buffer_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params, int override)
+{
+ const char *env;
+ int status;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_uframes_t frames;
+
+ /* Copy the hardware parameters for this setup */
+ snd_pcm_hw_params_alloca(&hwparams);
+ SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params);
+
+ if ( !override ) {
+ env = getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
+ if ( env ) {
+ override = SDL_atoi(env);
+ if ( override == 0 ) {
+ return(-1);
+ }
+ }
+ }
+
+ frames = spec->samples * 2;
+ status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames);
+ if ( status < 0 ) {
+ return(-1);
+ }
+
+ return ALSA_finalize_hardware(this, spec, hwparams, override);
+}
+
+static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int status;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_format_t format;
+ unsigned int rate;
+ unsigned int channels;
+ Uint16 test_format;
+
+ /* Open the audio device */
+ /* Name of device should depend on # channels in spec */
+ status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't open audio device: %s", SDL_NAME(snd_strerror)(status));
+ return(-1);
+ }
+
+ /* Figure out what the hardware is capable of */
+ snd_pcm_hw_params_alloca(&hwparams);
+ status = SDL_NAME(snd_pcm_hw_params_any)(pcm_handle, hwparams);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't get hardware config: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+
+ /* SDL only uses interleaved sample output */
+ status = SDL_NAME(snd_pcm_hw_params_set_access)(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't set interleaved access: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+
+ /* Try for a closest match on audio format */
+ status = -1;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ test_format && (status < 0); ) {
+ switch ( test_format ) {
+ case AUDIO_U8:
+ format = SND_PCM_FORMAT_U8;
+ break;
+ case AUDIO_S8:
+ format = SND_PCM_FORMAT_S8;
+ break;
+ case AUDIO_S16LSB:
+ format = SND_PCM_FORMAT_S16_LE;
+ break;
+ case AUDIO_S16MSB:
+ format = SND_PCM_FORMAT_S16_BE;
+ break;
+ case AUDIO_U16LSB:
+ format = SND_PCM_FORMAT_U16_LE;
+ break;
+ case AUDIO_U16MSB:
+ format = SND_PCM_FORMAT_U16_BE;
+ break;
+ default:
+ format = 0;
+ break;
+ }
+ if ( format != 0 ) {
+ status = SDL_NAME(snd_pcm_hw_params_set_format)(pcm_handle, hwparams, format);
+ }
+ if ( status < 0 ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ spec->format = test_format;
+
+ /* Set the number of channels */
+ status = SDL_NAME(snd_pcm_hw_params_set_channels)(pcm_handle, hwparams, spec->channels);
+ channels = spec->channels;
+ if ( status < 0 ) {
+ status = SDL_NAME(snd_pcm_hw_params_get_channels)(hwparams, &channels);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't set audio channels");
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ spec->channels = channels;
+ }
+
+ /* Set the audio rate */
+ rate = spec->freq;
+
+ status = SDL_NAME(snd_pcm_hw_params_set_rate_near)(pcm_handle, hwparams, &rate, NULL);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ spec->freq = rate;
+
+ /* Set the buffer size, in samples */
+ if ( ALSA_set_period_size(this, spec, hwparams, 0) < 0 &&
+ ALSA_set_buffer_size(this, spec, hwparams, 0) < 0 ) {
+ /* Failed to set desired buffer size, do the best you can... */
+ if ( ALSA_set_period_size(this, spec, hwparams, 1) < 0 ) {
+ SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ }
+
+ /* Set the software parameters */
+ snd_pcm_sw_params_alloca(&swparams);
+ status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't get software config: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ status = SDL_NAME(snd_pcm_sw_params_set_start_threshold)(pcm_handle, swparams, 1);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
+ if ( status < 0 ) {
+ SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+ if ( mixbuf == NULL ) {
+ ALSA_CloseAudio(this);
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* Switch to blocking mode for playback */
+ SDL_NAME(snd_pcm_nonblock)(pcm_handle, 0);
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/alsa/SDL_alsa_audio.h b/src/audio/alsa/SDL_alsa_audio.h
new file mode 100644
index 0000000..252f333
--- /dev/null
+++ b/src/audio/alsa/SDL_alsa_audio.h
@@ -0,0 +1,48 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _ALSA_PCM_audio_h
+#define _ALSA_PCM_audio_h
+
+#include <alsa/asoundlib.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The audio device handle */
+ snd_pcm_t *pcm_handle;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+};
+
+/* Old variable names */
+#define pcm_handle (this->hidden->pcm_handle)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+
+#endif /* _ALSA_PCM_audio_h */
diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c
new file mode 100644
index 0000000..44447a2
--- /dev/null
+++ b/src/audio/arts/SDL_artsaudio.c
@@ -0,0 +1,348 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_artsaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+/* The tag name used by artsc audio */
+#define ARTS_DRIVER_NAME "arts"
+
+/* Audio driver functions */
+static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void ARTS_WaitAudio(_THIS);
+static void ARTS_PlayAudio(_THIS);
+static Uint8 *ARTS_GetAudioBuf(_THIS);
+static void ARTS_CloseAudio(_THIS);
+
+#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
+
+static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
+static void *arts_handle = NULL;
+static int arts_loaded = 0;
+
+static int (*SDL_NAME(arts_init))(void);
+static void (*SDL_NAME(arts_free))(void);
+static arts_stream_t (*SDL_NAME(arts_play_stream))(int rate, int bits, int channels, const char *name);
+static int (*SDL_NAME(arts_stream_set))(arts_stream_t s, arts_parameter_t param, int value);
+static int (*SDL_NAME(arts_stream_get))(arts_stream_t s, arts_parameter_t param);
+static int (*SDL_NAME(arts_write))(arts_stream_t s, const void *buffer, int count);
+static void (*SDL_NAME(arts_close_stream))(arts_stream_t s);
+static int (*SDL_NAME(arts_suspended))(void);
+static const char *(*SDL_NAME(arts_error_text))(int errorcode);
+
+static struct {
+ const char *name;
+ void **func;
+} arts_functions[] = {
+ { "arts_init", (void **)&SDL_NAME(arts_init) },
+ { "arts_free", (void **)&SDL_NAME(arts_free) },
+ { "arts_play_stream", (void **)&SDL_NAME(arts_play_stream) },
+ { "arts_stream_set", (void **)&SDL_NAME(arts_stream_set) },
+ { "arts_stream_get", (void **)&SDL_NAME(arts_stream_get) },
+ { "arts_write", (void **)&SDL_NAME(arts_write) },
+ { "arts_close_stream", (void **)&SDL_NAME(arts_close_stream) },
+ { "arts_suspended", (void **)&SDL_NAME(arts_suspended) },
+ { "arts_error_text", (void **)&SDL_NAME(arts_error_text) },
+};
+
+static void UnloadARTSLibrary()
+{
+ if ( arts_loaded ) {
+ SDL_UnloadObject(arts_handle);
+ arts_handle = NULL;
+ arts_loaded = 0;
+ }
+}
+
+static int LoadARTSLibrary(void)
+{
+ int i, retval = -1;
+
+ arts_handle = SDL_LoadObject(arts_library);
+ if ( arts_handle ) {
+ arts_loaded = 1;
+ retval = 0;
+ for ( i=0; i<SDL_arraysize(arts_functions); ++i ) {
+ *arts_functions[i].func = SDL_LoadFunction(arts_handle, arts_functions[i].name);
+ if ( !*arts_functions[i].func ) {
+ retval = -1;
+ UnloadARTSLibrary();
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void UnloadARTSLibrary()
+{
+ return;
+}
+
+static int LoadARTSLibrary(void)
+{
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int available = 0;
+
+ if ( LoadARTSLibrary() < 0 ) {
+ return available;
+ }
+ if ( SDL_NAME(arts_init)() == 0 ) {
+ if ( SDL_NAME(arts_suspended)() ) {
+ /* Play a stream so aRts doesn't crash */
+ arts_stream_t stream2;
+ stream2=SDL_NAME(arts_play_stream)(44100, 16, 2, "SDL");
+ SDL_NAME(arts_write)(stream2, "", 0);
+ SDL_NAME(arts_close_stream)(stream2);
+ available = 1;
+ }
+ SDL_NAME(arts_free)();
+ }
+ UnloadARTSLibrary();
+
+ return available;
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+ UnloadARTSLibrary();
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ LoadARTSLibrary();
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ stream = 0;
+
+ /* Set the function pointers */
+ this->OpenAudio = ARTS_OpenAudio;
+ this->WaitAudio = ARTS_WaitAudio;
+ this->PlayAudio = ARTS_PlayAudio;
+ this->GetAudioBuf = ARTS_GetAudioBuf;
+ this->CloseAudio = ARTS_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap ARTS_bootstrap = {
+ ARTS_DRIVER_NAME, "Analog Realtime Synthesizer",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void ARTS_WaitAudio(_THIS)
+{
+ Sint32 ticks;
+
+ /* Check to see if the thread-parent process is still alive */
+ { static int cnt = 0;
+ /* Note that this only works with thread implementations
+ that use a different process id for each thread.
+ */
+ if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
+ if ( kill(parent, 0) < 0 ) {
+ this->enabled = 0;
+ }
+ }
+ }
+
+ /* Use timer for general audio synchronization */
+ ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
+ if ( ticks > 0 ) {
+ SDL_Delay(ticks);
+ }
+}
+
+static void ARTS_PlayAudio(_THIS)
+{
+ int written;
+
+ /* Write the audio data */
+ written = SDL_NAME(arts_write)(stream, mixbuf, mixlen);
+
+ /* If timer synchronization is enabled, set the next write frame */
+ if ( frame_ticks ) {
+ next_frame += frame_ticks;
+ }
+
+ /* If we couldn't write, assume fatal error for now */
+ if ( written < 0 ) {
+ this->enabled = 0;
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *ARTS_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void ARTS_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( stream ) {
+ SDL_NAME(arts_close_stream)(stream);
+ stream = 0;
+ }
+ SDL_NAME(arts_free)();
+}
+
+static int ARTS_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int bits, frag_spec;
+ Uint16 test_format, format;
+ int error_code;
+
+ /* Reset the timer synchronization flag */
+ frame_ticks = 0.0;
+
+ mixbuf = NULL;
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ bits = 0;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ ! format && test_format; ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch ( test_format ) {
+ case AUDIO_U8:
+ bits = 8;
+ format = 1;
+ break;
+ case AUDIO_S16LSB:
+ bits = 16;
+ format = 1;
+ break;
+ default:
+ format = 0;
+ break;
+ }
+ if ( ! format ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( format == 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ return(-1);
+ }
+ spec->format = test_format;
+
+ error_code = SDL_NAME(arts_init)();
+ if ( error_code != 0 ) {
+ SDL_SetError("Unable to initialize ARTS: %s", SDL_NAME(arts_error_text)(error_code));
+ return(-1);
+ }
+ if ( ! SDL_NAME(arts_suspended)() ) {
+ SDL_SetError("ARTS can not open audio device");
+ return(-1);
+ }
+ stream = SDL_NAME(arts_play_stream)(spec->freq, bits, spec->channels, "SDL");
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Determine the power of two of the fragment size */
+ for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
+ if ( (0x01<<frag_spec) != spec->size ) {
+ SDL_SetError("Fragment size must be a power of two");
+ return(-1);
+ }
+ frag_spec |= 0x00020000; /* two fragments, for low latency */
+
+#ifdef ARTS_P_PACKET_SETTINGS
+ SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SETTINGS, frag_spec);
+#else
+ SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_SIZE, frag_spec&0xffff);
+ SDL_NAME(arts_stream_set)(stream, ARTS_P_PACKET_COUNT, frag_spec>>16);
+#endif
+ spec->size = SDL_NAME(arts_stream_get)(stream, ARTS_P_PACKET_SIZE);
+
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+ if ( mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/arts/SDL_artsaudio.h b/src/audio/arts/SDL_artsaudio.h
new file mode 100644
index 0000000..b5ccf35
--- /dev/null
+++ b/src/audio/arts/SDL_artsaudio.h
@@ -0,0 +1,60 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_artscaudio_h
+#define _SDL_artscaudio_h
+
+#include <artsc.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The stream descriptor for the audio device */
+ arts_stream_t stream;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer, in addition to select() */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+/* Old variable names */
+#define stream (this->hidden->stream)
+#define parent (this->hidden->parent)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+#define frame_ticks (this->hidden->frame_ticks)
+#define next_frame (this->hidden->next_frame)
+
+#endif /* _SDL_artscaudio_h */
+
diff --git a/src/audio/baudio/SDL_beaudio.cc b/src/audio/baudio/SDL_beaudio.cc
new file mode 100644
index 0000000..fc23f01
--- /dev/null
+++ b/src/audio/baudio/SDL_beaudio.cc
@@ -0,0 +1,225 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to the audio stream on BeOS */
+
+#include <SoundPlayer.h>
+
+#include "../../main/beos/SDL_BeApp.h"
+
+extern "C" {
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "../../thread/beos/SDL_systhread_c.h"
+#include "SDL_beaudio.h"
+
+
+/* Audio driver functions */
+static int BE_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void BE_WaitAudio(_THIS);
+static void BE_PlayAudio(_THIS);
+static Uint8 *BE_GetAudioBuf(_THIS);
+static void BE_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *device;
+
+ /* Initialize all variables that we clean on shutdown */
+ device = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( device ) {
+ SDL_memset(device, 0, (sizeof *device));
+ device->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *device->hidden));
+ }
+ if ( (device == NULL) || (device->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( device ) {
+ SDL_free(device);
+ }
+ return(0);
+ }
+ SDL_memset(device->hidden, 0, (sizeof *device->hidden));
+
+ /* Set the function pointers */
+ device->OpenAudio = BE_OpenAudio;
+ device->WaitAudio = BE_WaitAudio;
+ device->PlayAudio = BE_PlayAudio;
+ device->GetAudioBuf = BE_GetAudioBuf;
+ device->CloseAudio = BE_CloseAudio;
+
+ device->free = Audio_DeleteDevice;
+
+ return device;
+}
+
+AudioBootStrap BAUDIO_bootstrap = {
+ "baudio", "BeOS BSoundPlayer",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* The BeOS callback for handling the audio buffer */
+static void FillSound(void *device, void *stream, size_t len,
+ const media_raw_audio_format &format)
+{
+ SDL_AudioDevice *audio = (SDL_AudioDevice *)device;
+
+ /* Silence the buffer, since it's ours */
+ SDL_memset(stream, audio->spec.silence, len);
+
+ /* Only do soemthing if audio is enabled */
+ if ( ! audio->enabled )
+ return;
+
+ if ( ! audio->paused ) {
+ if ( audio->convert.needed ) {
+ SDL_mutexP(audio->mixer_lock);
+ (*audio->spec.callback)(audio->spec.userdata,
+ (Uint8 *)audio->convert.buf,audio->convert.len);
+ SDL_mutexV(audio->mixer_lock);
+ SDL_ConvertAudio(&audio->convert);
+ SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt);
+ } else {
+ SDL_mutexP(audio->mixer_lock);
+ (*audio->spec.callback)(audio->spec.userdata,
+ (Uint8 *)stream, len);
+ SDL_mutexV(audio->mixer_lock);
+ }
+ }
+ return;
+}
+
+/* Dummy functions -- we don't use thread-based audio */
+void BE_WaitAudio(_THIS)
+{
+ return;
+}
+void BE_PlayAudio(_THIS)
+{
+ return;
+}
+Uint8 *BE_GetAudioBuf(_THIS)
+{
+ return(NULL);
+}
+
+void BE_CloseAudio(_THIS)
+{
+ if ( audio_obj ) {
+ audio_obj->Stop();
+ delete audio_obj;
+ audio_obj = NULL;
+ }
+
+ /* Quit the Be Application, if there's nothing left to do */
+ SDL_QuitBeApp();
+}
+
+int BE_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int valid_datatype = 0;
+ media_raw_audio_format format;
+ Uint16 test_format = SDL_FirstAudioFormat(spec->format);
+
+ /* Parse the audio format and fill the Be raw audio format */
+ memset(&format, '\0', sizeof (media_raw_audio_format));
+ format.byte_order = B_MEDIA_LITTLE_ENDIAN;
+ format.frame_rate = (float) spec->freq;
+ format.channel_count = spec->channels; /* !!! FIXME: support > 2? */
+ while ((!valid_datatype) && (test_format)) {
+ valid_datatype = 1;
+ spec->format = test_format;
+ switch (test_format) {
+ case AUDIO_S8:
+ format.format = media_raw_audio_format::B_AUDIO_CHAR;
+ break;
+
+ case AUDIO_U8:
+ format.format = media_raw_audio_format::B_AUDIO_UCHAR;
+ break;
+
+ case AUDIO_S16LSB:
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
+ break;
+
+ case AUDIO_S16MSB:
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
+ format.byte_order = B_MEDIA_BIG_ENDIAN;
+ break;
+
+ default:
+ valid_datatype = 0;
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+ }
+
+ if (!valid_datatype) { /* shouldn't happen, but just in case... */
+ SDL_SetError("Unsupported audio format");
+ return (-1);
+ }
+
+ /* Initialize the Be Application, if it's not already started */
+ if (SDL_InitBeApp() < 0) {
+ return (-1);
+ }
+
+ format.buffer_size = spec->samples;
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Subscribe to the audio stream (creates a new thread) */
+ { sigset_t omask;
+ SDL_MaskSignals(&omask);
+ audio_obj = new BSoundPlayer(&format, "SDL Audio", FillSound,
+ NULL, _this);
+ SDL_UnmaskSignals(&omask);
+ }
+ if ( audio_obj->Start() == B_NO_ERROR ) {
+ audio_obj->SetHasData(true);
+ } else {
+ SDL_SetError("Unable to start Be audio");
+ return(-1);
+ }
+
+ /* We're running! */
+ return(1);
+}
+
+}; /* Extern C */
diff --git a/src/audio/baudio/SDL_beaudio.h b/src/audio/baudio/SDL_beaudio.h
new file mode 100644
index 0000000..8495cb6
--- /dev/null
+++ b/src/audio/baudio/SDL_beaudio.h
@@ -0,0 +1,39 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *_this
+
+struct SDL_PrivateAudioData {
+ BSoundPlayer *audio_obj;
+};
+
+/* Old variable names */
+#define audio_obj (_this->hidden->audio_obj)
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c
new file mode 100644
index 0000000..f5db020
--- /dev/null
+++ b/src/audio/bsd/SDL_bsdaudio.c
@@ -0,0 +1,404 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ * Driver for native OpenBSD/NetBSD audio(4).
+ * vedge@vedge.com.ar.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/audioio.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_bsdaudio.h"
+
+/* The tag name used by NetBSD/OpenBSD audio */
+#ifdef __NetBSD__
+#define BSD_AUDIO_DRIVER_NAME "netbsd"
+#define BSD_AUDIO_DRIVER_DESC "Native NetBSD audio"
+#else
+#define BSD_AUDIO_DRIVER_NAME "openbsd"
+#define BSD_AUDIO_DRIVER_DESC "Native OpenBSD audio"
+#endif
+
+/* Open the audio device for playback, and don't block if busy */
+/* #define USE_BLOCKING_WRITES */
+
+/* Use timer for synchronization */
+/* #define USE_TIMER_SYNC */
+
+/* #define DEBUG_AUDIO */
+/* #define DEBUG_AUDIO_STREAM */
+
+#ifdef USE_BLOCKING_WRITES
+#define OPEN_FLAGS O_WRONLY
+#else
+#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
+#endif
+
+/* Audio driver functions */
+static void OBSD_WaitAudio(_THIS);
+static int OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void OBSD_PlayAudio(_THIS);
+static Uint8 *OBSD_GetAudioBuf(_THIS);
+static void OBSD_CloseAudio(_THIS);
+
+#ifdef DEBUG_AUDIO
+static void OBSD_Status(_THIS);
+#endif
+
+/* Audio driver bootstrap functions */
+
+static int
+Audio_Available(void)
+{
+ int fd;
+ int available;
+
+ available = 0;
+ fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
+ if(fd >= 0) {
+ available = 1;
+ close(fd);
+ }
+ return(available);
+}
+
+static void
+Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice
+*Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice*)SDL_malloc(sizeof(SDL_AudioDevice));
+ if(this) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden =
+ (struct SDL_PrivateAudioData*)SDL_malloc((sizeof *this->hidden));
+ }
+ if((this == NULL) || (this->hidden == NULL)) {
+ SDL_OutOfMemory();
+ if(this) SDL_free(this);
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ audio_fd = -1;
+
+ /* Set the function pointers */
+ this->OpenAudio = OBSD_OpenAudio;
+ this->WaitAudio = OBSD_WaitAudio;
+ this->PlayAudio = OBSD_PlayAudio;
+ this->GetAudioBuf = OBSD_GetAudioBuf;
+ this->CloseAudio = OBSD_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap BSD_AUDIO_bootstrap = {
+ BSD_AUDIO_DRIVER_NAME, BSD_AUDIO_DRIVER_DESC,
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void
+OBSD_WaitAudio(_THIS)
+{
+#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
+ /* See if we need to use timed audio synchronization */
+ if ( frame_ticks ) {
+ /* Use timer for general audio synchronization */
+ Sint32 ticks;
+
+ ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
+ if ( ticks > 0 ) {
+ SDL_Delay(ticks);
+ }
+ } else {
+ /* Use select() for audio synchronization */
+ fd_set fdset;
+ struct timeval timeout;
+
+ FD_ZERO(&fdset);
+ FD_SET(audio_fd, &fdset);
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 0;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Waiting for audio to get ready\n");
+#endif
+ if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
+ const char *message =
+ "Audio timeout - buggy audio driver? (disabled)";
+ /* In general we should never print to the screen,
+ but in this case we have no other way of letting
+ the user know what happened.
+ */
+ fprintf(stderr, "SDL: %s\n", message);
+ this->enabled = 0;
+ /* Don't try to close - may hang */
+ audio_fd = -1;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Done disabling audio\n");
+#endif
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Ready!\n");
+#endif
+ }
+#endif /* !USE_BLOCKING_WRITES */
+}
+
+static void
+OBSD_PlayAudio(_THIS)
+{
+ int written, p=0;
+
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ written = write(audio_fd, &mixbuf[p], mixlen-p);
+ if (written>0)
+ p += written;
+ if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR)
+ {
+ /* Non recoverable error has occurred. It should be reported!!! */
+ perror("audio");
+ break;
+ }
+
+ if ( p < written || ((written < 0) && ((errno == 0) || (errno == EAGAIN))) ) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while ( p < written );
+
+ /* If timer synchronization is enabled, set the next write frame */
+ if ( frame_ticks ) {
+ next_frame += frame_ticks;
+ }
+
+ /* If we couldn't write, assume fatal error for now */
+ if ( written < 0 ) {
+ this->enabled = 0;
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8
+*OBSD_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void
+OBSD_CloseAudio(_THIS)
+{
+ if(mixbuf != NULL) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if(audio_fd >= 0) {
+ close(audio_fd);
+ audio_fd = -1;
+ }
+}
+
+#ifdef DEBUG_AUDIO
+void
+OBSD_Status(_THIS)
+{
+ audio_info_t info;
+
+ if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
+ fprintf(stderr,"AUDIO_GETINFO failed.\n");
+ return;
+ }
+
+ fprintf(stderr,"\n"
+"[play/record info]\n"
+"buffer size : %d bytes\n"
+"sample rate : %i Hz\n"
+"channels : %i\n"
+"precision : %i-bit\n"
+"encoding : 0x%x\n"
+"seek : %i\n"
+"sample count : %i\n"
+"EOF count : %i\n"
+"paused : %s\n"
+"error occured : %s\n"
+"waiting : %s\n"
+"active : %s\n"
+"",
+ info.play.buffer_size,
+ info.play.sample_rate,
+ info.play.channels,
+ info.play.precision,
+ info.play.encoding,
+ info.play.seek,
+ info.play.samples,
+ info.play.eof,
+ info.play.pause ? "yes" : "no",
+ info.play.error ? "yes" : "no",
+ info.play.waiting ? "yes" : "no",
+ info.play.active ? "yes": "no");
+
+ fprintf(stderr,"\n"
+"[audio info]\n"
+"monitor_gain : %i\n"
+"hw block size : %d bytes\n"
+"hi watermark : %i\n"
+"lo watermark : %i\n"
+"audio mode : %s\n"
+"",
+ info.monitor_gain,
+ info.blocksize,
+ info.hiwat, info.lowat,
+ (info.mode == AUMODE_PLAY) ? "PLAY"
+ : (info.mode = AUMODE_RECORD) ? "RECORD"
+ : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL"
+ : "?"));
+}
+#endif /* DEBUG_AUDIO */
+
+static int
+OBSD_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ char audiodev[64];
+ Uint16 format;
+ audio_info_t info;
+
+ AUDIO_INITINFO(&info);
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+#ifdef USE_TIMER_SYNC
+ frame_ticks = 0.0;
+#endif
+
+ /* Open the audio device */
+ audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
+ if(audio_fd < 0) {
+ SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ return(-1);
+ }
+
+ /* Set to play mode */
+ info.mode = AUMODE_PLAY;
+ if(ioctl(audio_fd, AUDIO_SETINFO, &info) < 0) {
+ SDL_SetError("Couldn't put device into play mode");
+ return(-1);
+ }
+
+ mixbuf = NULL;
+ AUDIO_INITINFO(&info);
+ for (format = SDL_FirstAudioFormat(spec->format);
+ format; format = SDL_NextAudioFormat())
+ {
+ switch(format) {
+ case AUDIO_U8:
+ info.play.encoding = AUDIO_ENCODING_ULINEAR;
+ info.play.precision = 8;
+ break;
+ case AUDIO_S8:
+ info.play.encoding = AUDIO_ENCODING_SLINEAR;
+ info.play.precision = 8;
+ break;
+ case AUDIO_S16LSB:
+ info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
+ info.play.precision = 16;
+ break;
+ case AUDIO_S16MSB:
+ info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
+ info.play.precision = 16;
+ break;
+ case AUDIO_U16LSB:
+ info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
+ info.play.precision = 16;
+ break;
+ case AUDIO_U16MSB:
+ info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
+ info.play.precision = 16;
+ break;
+ default:
+ continue;
+ }
+ if (ioctl(audio_fd, AUDIO_SETINFO, &info) == 0)
+ break;
+ }
+
+ if(!format) {
+ SDL_SetError("No supported encoding for 0x%x", spec->format);
+ return(-1);
+ }
+
+ spec->format = format;
+
+ AUDIO_INITINFO(&info);
+ info.play.channels = spec->channels;
+ if (ioctl(audio_fd, AUDIO_SETINFO, &info) == -1)
+ spec->channels = 1;
+ AUDIO_INITINFO(&info);
+ info.play.sample_rate = spec->freq;
+ info.blocksize = spec->size;
+ info.hiwat = 5;
+ info.lowat = 3;
+ (void)ioctl(audio_fd, AUDIO_SETINFO, &info);
+ (void)ioctl(audio_fd, AUDIO_GETINFO, &info);
+ spec->freq = info.play.sample_rate;
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8*)SDL_AllocAudioMem(mixlen);
+ if(mixbuf == NULL) {
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+#ifdef DEBUG_AUDIO
+ OBSD_Status(this);
+#endif
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/bsd/SDL_bsdaudio.h b/src/audio/bsd/SDL_bsdaudio.h
new file mode 100644
index 0000000..3e95809
--- /dev/null
+++ b/src/audio/bsd/SDL_bsdaudio.h
@@ -0,0 +1,58 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_openbsdaudio_h
+#define _SDL_openbsdaudio_h
+
+#include "../SDL_sysaudio.h"
+
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer, in addition to select() */
+ float frame_ticks;
+ float next_frame;
+};
+
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+/* Old variable names */
+#define audio_fd (this->hidden->audio_fd)
+#define parent (this->hidden->parent)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+#define frame_ticks (this->hidden->frame_ticks)
+#define next_frame (this->hidden->next_frame)
+
+#endif /* _SDL_openbsdaudio_h */
diff --git a/src/audio/dart/SDL_dart.c b/src/audio/dart/SDL_dart.c
new file mode 100644
index 0000000..5ebe437
--- /dev/null
+++ b/src/audio/dart/SDL_dart.c
@@ -0,0 +1,441 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_dart.h"
+
+// Buffer states:
+#define BUFFER_EMPTY 0
+#define BUFFER_USED 1
+
+typedef struct _tMixBufferDesc {
+ int iBufferUsage; // BUFFER_EMPTY or BUFFER_USED
+ SDL_AudioDevice *pSDLAudioDevice;
+} tMixBufferDesc, *pMixBufferDesc;
+
+
+//---------------------------------------------------------------------
+// DARTEventFunc
+//
+// This function is called by DART, when an event occures, like end of
+// playback of a buffer, etc...
+//---------------------------------------------------------------------
+LONG APIENTRY DARTEventFunc(ULONG ulStatus,
+ PMCI_MIX_BUFFER pBuffer,
+ ULONG ulFlags)
+{
+ if (ulFlags && MIX_WRITE_COMPLETE)
+ { // Playback of buffer completed!
+
+ // Get pointer to buffer description
+ pMixBufferDesc pBufDesc;
+
+ if (pBuffer)
+ {
+ pBufDesc = (pMixBufferDesc) (*pBuffer).ulUserParm;
+
+ if (pBufDesc)
+ {
+ SDL_AudioDevice *pSDLAudioDevice = pBufDesc->pSDLAudioDevice;
+ // Set the buffer to be empty
+ pBufDesc->iBufferUsage = BUFFER_EMPTY;
+ // And notify DART feeder thread that it will have to work a bit.
+ if (pSDLAudioDevice)
+ DosPostEventSem(pSDLAudioDevice->hidden->hevAudioBufferPlayed);
+ }
+ }
+ }
+ return TRUE;
+}
+
+
+int DART_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ Uint16 test_format = SDL_FirstAudioFormat(spec->format);
+ int valid_datatype = 0;
+ MCI_AMP_OPEN_PARMS AmpOpenParms;
+ MCI_GENERIC_PARMS GenericParms;
+ int iDeviceOrd = 0; // Default device to be used
+ int bOpenShared = 1; // Try opening it shared
+ int iBits = 16; // Default is 16 bits signed
+ int iFreq = 44100; // Default is 44KHz
+ int iChannels = 2; // Default is 2 channels (Stereo)
+ int iNumBufs = 2; // Number of audio buffers: 2
+ int iBufSize;
+ int iOpenMode;
+ int iSilence;
+ int rc;
+
+ // First thing is to try to open a given DART device!
+ SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
+ // pszDeviceType should contain the device type in low word, and device ordinal in high word!
+ AmpOpenParms.pszDeviceType = (PSZ) (MCI_DEVTYPE_AUDIO_AMPMIX | (iDeviceOrd << 16));
+
+ iOpenMode = MCI_WAIT | MCI_OPEN_TYPE_ID;
+ if (bOpenShared) iOpenMode |= MCI_OPEN_SHAREABLE;
+
+ rc = mciSendCommand( 0, MCI_OPEN,
+ iOpenMode,
+ (PVOID) &AmpOpenParms, 0);
+ if (rc!=MCIERR_SUCCESS) // No audio available??
+ return (-1);
+ // Save the device ID we got from DART!
+ // We will use this in the next calls!
+ iDeviceOrd = AmpOpenParms.usDeviceID;
+
+ // Determine the audio parameters from the AudioSpec
+ if (spec->channels > 2)
+ spec->channels = 2; // !!! FIXME: more than stereo support in OS/2?
+
+ while ((!valid_datatype) && (test_format)) {
+ spec->format = test_format;
+ valid_datatype = 1;
+ switch (test_format) {
+ case AUDIO_U8:
+ // Unsigned 8 bit audio data
+ iSilence = 0x80;
+ iBits = 8;
+ break;
+
+ case AUDIO_S16LSB:
+ // Signed 16 bit audio data
+ iSilence = 0x00;
+ iBits = 16;
+ break;
+
+ default:
+ valid_datatype = 0;
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+ }
+
+ if (!valid_datatype) { // shouldn't happen, but just in case...
+ // Close DART, and exit with error code!
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("Unsupported audio format");
+ return (-1);
+ }
+
+ iFreq = spec->freq;
+ iChannels = spec->channels;
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+ iBufSize = spec->size;
+
+ // Now query this device if it supports the given freq/bits/channels!
+ SDL_memset(&(_this->hidden->MixSetupParms), 0, sizeof(MCI_MIXSETUP_PARMS));
+ _this->hidden->MixSetupParms.ulBitsPerSample = iBits;
+ _this->hidden->MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
+ _this->hidden->MixSetupParms.ulSamplesPerSec = iFreq;
+ _this->hidden->MixSetupParms.ulChannels = iChannels;
+ _this->hidden->MixSetupParms.ulFormatMode = MCI_PLAY;
+ _this->hidden->MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
+ _this->hidden->MixSetupParms.pmixEvent = DARTEventFunc;
+ rc = mciSendCommand (iDeviceOrd, MCI_MIXSETUP,
+ MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
+ &(_this->hidden->MixSetupParms), 0);
+ if (rc!=MCIERR_SUCCESS)
+ { // The device cannot handle this format!
+ // Close DART, and exit with error code!
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("Audio device doesn't support requested audio format");
+ return(-1);
+ }
+ // The device can handle this format, so initialize!
+ rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
+ MCI_WAIT | MCI_MIXSETUP_INIT,
+ &(_this->hidden->MixSetupParms), 0);
+ if (rc!=MCIERR_SUCCESS)
+ { // The device could not be opened!
+ // Close DART, and exit with error code!
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("Audio device could not be set up");
+ return(-1);
+ }
+ // Ok, the device is initialized.
+ // Now we should allocate buffers. For this, we need a place where
+ // the buffer descriptors will be:
+ _this->hidden->pMixBuffers = (MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER)*iNumBufs);
+ if (!(_this->hidden->pMixBuffers))
+ { // Not enough memory!
+ // Close DART, and exit with error code!
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("Not enough memory for audio buffer descriptors");
+ return(-1);
+ }
+ // Now that we have the place for buffer list, we can ask DART for the
+ // buffers!
+ _this->hidden->BufferParms.ulNumBuffers = iNumBufs; // Number of buffers
+ _this->hidden->BufferParms.ulBufferSize = iBufSize; // each with this size
+ _this->hidden->BufferParms.pBufList = _this->hidden->pMixBuffers; // getting descriptorts into this list
+ // Allocate buffers!
+ rc = mciSendCommand(iDeviceOrd, MCI_BUFFER,
+ MCI_WAIT | MCI_ALLOCATE_MEMORY,
+ &(_this->hidden->BufferParms), 0);
+ if ((rc!=MCIERR_SUCCESS) || (iNumBufs != _this->hidden->BufferParms.ulNumBuffers) || (_this->hidden->BufferParms.ulBufferSize==0))
+ { // Could not allocate memory!
+ // Close DART, and exit with error code!
+ SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("DART could not allocate buffers");
+ return(-1);
+ }
+ // Ok, we have all the buffers allocated, let's mark them!
+ {
+ int i;
+ for (i=0; i<iNumBufs; i++)
+ {
+ pMixBufferDesc pBufferDesc = (pMixBufferDesc) SDL_malloc(sizeof(tMixBufferDesc));;
+ // Check if this buffer was really allocated by DART
+ if ((!(_this->hidden->pMixBuffers[i].pBuffer)) || (!pBufferDesc))
+ { // Wrong buffer!
+ // Close DART, and exit with error code!
+ // Free buffer descriptions
+ { int j;
+ for (j=0; j<i; j++) SDL_free((void *)(_this->hidden->pMixBuffers[j].ulUserParm));
+ }
+ // and cleanup
+ mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
+ SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("Error at internal buffer check");
+ return(-1);
+ }
+ pBufferDesc->iBufferUsage = BUFFER_EMPTY;
+ pBufferDesc->pSDLAudioDevice = _this;
+
+ _this->hidden->pMixBuffers[i].ulBufferLength = _this->hidden->BufferParms.ulBufferSize;
+ _this->hidden->pMixBuffers[i].ulUserParm = (ULONG) pBufferDesc; // User parameter: Description of buffer
+ _this->hidden->pMixBuffers[i].ulFlags = 0; // Some stuff should be flagged here for DART, like end of
+ // audio data, but as we will continously send
+ // audio data, there will be no end.:)
+ SDL_memset(_this->hidden->pMixBuffers[i].pBuffer, iSilence, iBufSize);
+ }
+ }
+ _this->hidden->iNextFreeBuffer = 0;
+ _this->hidden->iLastPlayedBuf = -1;
+ // Create event semaphore
+ if (DosCreateEventSem(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE)!=NO_ERROR)
+ {
+ // Could not create event semaphore!
+ {
+ int i;
+ for (i=0; i<iNumBufs; i++) SDL_free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
+ }
+ mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
+ SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
+ mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
+ SDL_SetError("Could not create event semaphore");
+ return(-1);
+ }
+
+ // Store the new settings in global variables
+ _this->hidden->iCurrDeviceOrd = iDeviceOrd;
+ _this->hidden->iCurrFreq = iFreq;
+ _this->hidden->iCurrBits = iBits;
+ _this->hidden->iCurrChannels = iChannels;
+ _this->hidden->iCurrNumBufs = iNumBufs;
+ _this->hidden->iCurrBufSize = iBufSize;
+
+ return (0);
+}
+
+
+
+void DART_ThreadInit(_THIS)
+{
+ return;
+}
+
+/* This function waits until it is possible to write a full sound buffer */
+void DART_WaitAudio(_THIS)
+{
+ int i;
+ pMixBufferDesc pBufDesc;
+ ULONG ulPostCount;
+
+ DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
+ // If there is already an empty buffer, then return now!
+ for (i=0; i<_this->hidden->iCurrNumBufs; i++)
+ {
+ pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[i].ulUserParm;
+ if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
+ return;
+ }
+ // If there is no empty buffer, wait for one to be empty!
+ DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // Wait max 1 sec!!! Important!
+ return;
+}
+
+void DART_PlayAudio(_THIS)
+{
+ int iFreeBuf = _this->hidden->iNextFreeBuffer;
+ pMixBufferDesc pBufDesc;
+
+ pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
+ pBufDesc->iBufferUsage = BUFFER_USED;
+ // Send it to DART to be queued
+ _this->hidden->MixSetupParms.pmixWrite(_this->hidden->MixSetupParms.ulMixHandle,
+ &(_this->hidden->pMixBuffers[iFreeBuf]), 1);
+
+ _this->hidden->iLastPlayedBuf = iFreeBuf;
+ iFreeBuf = (iFreeBuf+1) % _this->hidden->iCurrNumBufs;
+ _this->hidden->iNextFreeBuffer = iFreeBuf;
+}
+
+Uint8 *DART_GetAudioBuf(_THIS)
+{
+ int iFreeBuf;
+ Uint8 *pResult;
+ pMixBufferDesc pBufDesc;
+
+ if (_this)
+ {
+ if (_this->hidden)
+ {
+ iFreeBuf = _this->hidden->iNextFreeBuffer;
+ pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
+
+ if (pBufDesc)
+ {
+ if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
+ {
+ pResult = _this->hidden->pMixBuffers[iFreeBuf].pBuffer;
+ return pResult;
+ }
+ } else
+ printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n", pBufDesc);
+ } else
+ printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n", _this->hidden);
+ } else
+ printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
+ return NULL;
+}
+
+void DART_WaitDone(_THIS)
+{
+ pMixBufferDesc pBufDesc;
+ ULONG ulPostCount;
+ APIRET rc;
+
+ pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->iLastPlayedBuf].ulUserParm;
+ rc = NO_ERROR;
+ while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc==NO_ERROR))
+ {
+ DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
+ rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
+ }
+}
+
+void DART_CloseAudio(_THIS)
+{
+ MCI_GENERIC_PARMS GenericParms;
+ int rc;
+
+ // Stop DART playback
+ rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT, &GenericParms, 0);
+ if (rc!=MCIERR_SUCCESS)
+ {
+#ifdef SFX_DEBUG_BUILD
+ printf("Could not stop DART playback!\n");
+ fflush(stdout);
+#endif
+ }
+
+ // Close event semaphore
+ DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
+
+ // Free memory of buffer descriptions
+ {
+ int i;
+ for (i=0; i<_this->hidden->iCurrNumBufs; i++) SDL_free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
+ }
+
+ // Deallocate buffers
+ rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
+
+ // Free bufferlist
+ SDL_free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
+
+ // Close dart
+ rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT, &(GenericParms), 0);
+}
+
+/* Audio driver bootstrap functions */
+
+int Audio_Available(void)
+{
+ return(1);
+}
+
+void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this )
+ {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) )
+ {
+ SDL_OutOfMemory();
+ if ( this )
+ SDL_free(this);
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = DART_OpenAudio;
+ this->ThreadInit = DART_ThreadInit;
+ this->WaitAudio = DART_WaitAudio;
+ this->PlayAudio = DART_PlayAudio;
+ this->GetAudioBuf = DART_GetAudioBuf;
+ this->WaitDone = DART_WaitDone;
+ this->CloseAudio = DART_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DART_bootstrap = {
+ "dart", "OS/2 Direct Audio RouTines (DART)",
+ Audio_Available, Audio_CreateDevice
+};
+
diff --git a/src/audio/dart/SDL_dart.h b/src/audio/dart/SDL_dart.h
new file mode 100644
index 0000000..1f75a35
--- /dev/null
+++ b/src/audio/dart/SDL_dart.h
@@ -0,0 +1,63 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#define INCL_TYPES
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSRESOURCES
+#define INCL_DOSMISC
+#define INCL_DOSERRORS
+
+#define INCL_OS2MM
+#define INCL_MMIOOS2
+#define INCL_MCIOS2
+#include <os2.h>
+#include <os2me.h> // DART stuff and MMIO stuff
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *_this
+
+/* The DirectSound objects */
+struct SDL_PrivateAudioData
+{
+ int iCurrDeviceOrd;
+ int iCurrFreq;
+ int iCurrBits;
+ int iCurrChannels;
+ int iCurrNumBufs;
+ int iCurrBufSize;
+
+ int iLastPlayedBuf;
+ int iNextFreeBuffer;
+
+ MCI_BUFFER_PARMS BufferParms; // Sound buffer parameters
+ MCI_MIX_BUFFER *pMixBuffers; // Sound buffers
+ MCI_MIXSETUP_PARMS MixSetupParms; // Mixer setup parameters
+ HEV hevAudioBufferPlayed; // Event semaphore to indicate that an audio buffer has been played by DART
+};
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/dc/SDL_dcaudio.c b/src/audio/dc/SDL_dcaudio.c
new file mode 100644
index 0000000..8a2c7d2
--- /dev/null
+++ b/src/audio/dc/SDL_dcaudio.c
@@ -0,0 +1,246 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+
+*/
+#include "SDL_config.h"
+
+/* Output dreamcast aica */
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_dcaudio.h"
+
+#include "aica.h"
+#include <dc/spu.h>
+
+/* Audio driver functions */
+static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DCAUD_WaitAudio(_THIS);
+static void DCAUD_PlayAudio(_THIS);
+static Uint8 *DCAUD_GetAudioBuf(_THIS);
+static void DCAUD_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+static int DCAUD_Available(void)
+{
+ return 1;
+}
+
+static void DCAUD_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *DCAUD_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = DCAUD_OpenAudio;
+ this->WaitAudio = DCAUD_WaitAudio;
+ this->PlayAudio = DCAUD_PlayAudio;
+ this->GetAudioBuf = DCAUD_GetAudioBuf;
+ this->CloseAudio = DCAUD_CloseAudio;
+
+ this->free = DCAUD_DeleteDevice;
+
+ spu_init();
+
+ return this;
+}
+
+AudioBootStrap DCAUD_bootstrap = {
+ "dcaudio", "Dreamcast AICA audio",
+ DCAUD_Available, DCAUD_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void DCAUD_WaitAudio(_THIS)
+{
+ if (this->hidden->playing) {
+ /* wait */
+ while(aica_get_pos(0)/this->spec.samples == this->hidden->nextbuf) {
+ thd_pass();
+ }
+ }
+}
+
+#define SPU_RAM_BASE 0xa0800000
+
+static void spu_memload_stereo8(int leftpos,int rightpos,void *src0,size_t size)
+{
+ uint8 *src = src0;
+ uint32 *left = (uint32*)(leftpos +SPU_RAM_BASE);
+ uint32 *right = (uint32*)(rightpos+SPU_RAM_BASE);
+ size = (size+7)/8;
+ while(size--) {
+ unsigned lval,rval;
+ lval = *src++;
+ rval = *src++;
+ lval|= (*src++)<<8;
+ rval|= (*src++)<<8;
+ lval|= (*src++)<<16;
+ rval|= (*src++)<<16;
+ lval|= (*src++)<<24;
+ rval|= (*src++)<<24;
+ g2_write_32(left++,lval);
+ g2_write_32(right++,rval);
+ g2_fifo_wait();
+ }
+}
+
+static void spu_memload_stereo16(int leftpos,int rightpos,void *src0,size_t size)
+{
+ uint16 *src = src0;
+ uint32 *left = (uint32*)(leftpos +SPU_RAM_BASE);
+ uint32 *right = (uint32*)(rightpos+SPU_RAM_BASE);
+ size = (size+7)/8;
+ while(size--) {
+ unsigned lval,rval;
+ lval = *src++;
+ rval = *src++;
+ lval|= (*src++)<<16;
+ rval|= (*src++)<<16;
+ g2_write_32(left++,lval);
+ g2_write_32(right++,rval);
+ g2_fifo_wait();
+ }
+}
+
+static void DCAUD_PlayAudio(_THIS)
+{
+ SDL_AudioSpec *spec = &this->spec;
+ unsigned int offset;
+
+ if (this->hidden->playing) {
+ /* wait */
+ while(aica_get_pos(0)/spec->samples == this->hidden->nextbuf) {
+ thd_pass();
+ }
+ }
+
+ offset = this->hidden->nextbuf*spec->size;
+ this->hidden->nextbuf^=1;
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ if (spec->channels==1) {
+ spu_memload(this->hidden->leftpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
+ } else {
+ offset/=2;
+ if ((this->spec.format&255)==8) {
+ spu_memload_stereo8(this->hidden->leftpos+offset,this->hidden->rightpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
+ } else {
+ spu_memload_stereo16(this->hidden->leftpos+offset,this->hidden->rightpos+offset,this->hidden->mixbuf,this->hidden->mixlen);
+ }
+ }
+
+ if (!this->hidden->playing) {
+ int mode;
+ this->hidden->playing = 1;
+ mode = (spec->format==AUDIO_S8)?SM_8BIT:SM_16BIT;
+ if (spec->channels==1) {
+ aica_play(0,mode,this->hidden->leftpos,0,spec->samples*2,spec->freq,255,128,1);
+ } else {
+ aica_play(0,mode,this->hidden->leftpos ,0,spec->samples*2,spec->freq,255,0,1);
+ aica_play(1,mode,this->hidden->rightpos,0,spec->samples*2,spec->freq,255,255,1);
+ }
+ }
+}
+
+static Uint8 *DCAUD_GetAudioBuf(_THIS)
+{
+ return(this->hidden->mixbuf);
+}
+
+static void DCAUD_CloseAudio(_THIS)
+{
+ aica_stop(0);
+ if (this->spec.channels==2) aica_stop(1);
+ if ( this->hidden->mixbuf != NULL ) {
+ SDL_FreeAudioMem(this->hidden->mixbuf);
+ this->hidden->mixbuf = NULL;
+ }
+}
+
+static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ Uint16 test_format = SDL_FirstAudioFormat(spec->format);
+ int valid_datatype = 0;
+ while ((!valid_datatype) && (test_format)) {
+ spec->format = test_format;
+ switch (test_format) {
+ /* only formats Dreamcast accepts... */
+ case AUDIO_S8:
+ case AUDIO_S16LSB:
+ valid_datatype = 1;
+ break;
+
+ default:
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+ }
+
+ if (!valid_datatype) { /* shouldn't happen, but just in case... */
+ SDL_SetError("Unsupported audio format");
+ return (-1);
+ }
+
+ if (spec->channels > 2)
+ spec->channels = 2; /* no more than stereo on the Dreamcast. */
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = spec->size;
+ this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
+ if ( this->hidden->mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
+ this->hidden->leftpos = 0x11000;
+ this->hidden->rightpos = 0x11000+spec->size;
+ this->hidden->playing = 0;
+ this->hidden->nextbuf = 0;
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/dc/SDL_dcaudio.h b/src/audio/dc/SDL_dcaudio.h
new file mode 100644
index 0000000..4a7c7cd
--- /dev/null
+++ b/src/audio/dc/SDL_dcaudio.h
@@ -0,0 +1,41 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_dcaudio_h
+#define _SDL_dcaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ Uint8 *mixbuf;
+ Uint32 mixlen;
+ int playing;
+ int leftpos,rightpos;
+ int nextbuf;
+};
+
+#endif /* _SDL_dcaudio_h */
diff --git a/src/audio/dc/aica.c b/src/audio/dc/aica.c
new file mode 100644
index 0000000..b6a1c93
--- /dev/null
+++ b/src/audio/dc/aica.c
@@ -0,0 +1,271 @@
+/* This file is part of the Dreamcast function library.
+ * Please see libdream.c for further details.
+ *
+ * (c)2000 Dan Potter
+ * modify BERO
+ */
+#include "aica.h"
+
+#include <arch/irq.h>
+#include <dc/spu.h>
+
+/* #define dc_snd_base ((volatile unsigned char *)0x00800000) */ /* arm side */
+#define dc_snd_base ((volatile unsigned char *)0xa0700000) /* dc side */
+
+/* Some convienence macros */
+#define SNDREGADDR(x) (0xa0700000 + (x))
+#define CHNREGADDR(ch,x) SNDREGADDR(0x80*(ch)+(x))
+
+
+#define SNDREG32(x) (*(volatile unsigned long *)SNDREGADDR(x))
+#define SNDREG8(x) (*(volatile unsigned char *)SNDREGADDR(x))
+#define CHNREG32(ch, x) (*(volatile unsigned long *)CHNREGADDR(ch,x))
+#define CHNREG8(ch, x) (*(volatile unsigned long *)CHNREGADDR(ch,x))
+
+#define G2_LOCK(OLD) \
+ do { \
+ if (!irq_inside_int()) \
+ OLD = irq_disable(); \
+ /* suspend any G2 DMA here... */ \
+ while((*(volatile unsigned int *)0xa05f688c) & 0x20) \
+ ; \
+ } while(0)
+
+#define G2_UNLOCK(OLD) \
+ do { \
+ /* resume any G2 DMA here... */ \
+ if (!irq_inside_int()) \
+ irq_restore(OLD); \
+ } while(0)
+
+
+void aica_init() {
+ int i, j, old = 0;
+
+ /* Initialize AICA channels */
+ G2_LOCK(old);
+ SNDREG32(0x2800) = 0x0000;
+
+ for (i=0; i<64; i++) {
+ for (j=0; j<0x80; j+=4) {
+ if ((j&31)==0) g2_fifo_wait();
+ CHNREG32(i, j) = 0;
+ }
+ g2_fifo_wait();
+ CHNREG32(i,0) = 0x8000;
+ CHNREG32(i,20) = 0x1f;
+ }
+
+ SNDREG32(0x2800) = 0x000f;
+ g2_fifo_wait();
+ G2_UNLOCK(old);
+}
+
+/* Translates a volume from linear form to logarithmic form (required by
+ the AICA chip */
+/* int logs[] = {
+
+0, 40, 50, 58, 63, 68, 73, 77, 80, 83, 86, 89, 92, 94, 97, 99, 101, 103,
+105, 107, 109, 111, 112, 114, 116, 117, 119, 120, 122, 123, 125, 126, 127,
+129, 130, 131, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145,
+146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
+160, 161, 162, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 170, 171,
+172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 180, 180, 181, 182,
+182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 188, 189, 190, 190, 191,
+191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198, 198, 199, 199,
+200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 207,
+208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
+215, 216, 216, 217, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222,
+222, 222, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228,
+228, 229, 229, 230, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234,
+234, 235, 235, 236, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240,
+240, 241, 241, 241, 242, 242, 243, 243, 243, 244, 244, 244, 245, 245, 245,
+246, 246, 247, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251,
+251, 251, 252, 252, 252, 253, 253, 253, 254, 254, 254, 255
+
+}; */
+
+const static unsigned char logs[] = {
+ 0, 15, 22, 27, 31, 35, 39, 42, 45, 47, 50, 52, 55, 57, 59, 61,
+ 63, 65, 67, 69, 71, 73, 74, 76, 78, 79, 81, 82, 84, 85, 87, 88,
+ 90, 91, 92, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106,
+ 108, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 138, 139, 140, 141, 142, 143, 144, 145, 146,
+ 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 156,
+ 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167,
+ 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176,
+ 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185,
+ 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194,
+ 195, 195, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202,
+ 203, 204, 204, 205, 205, 206, 207, 207, 208, 209, 209, 210, 210,
+ 211, 212, 212, 213, 213, 214, 215, 215, 216, 216, 217, 217, 218,
+ 219, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225,
+ 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233,
+ 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240,
+ 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246,
+ 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 254, 255
+};
+
+/* For the moment this is going to have to suffice, until we really
+ figure out what these mean. */
+#define AICA_PAN(x) ((x)==0x80?(0):((x)<0x80?(0x1f):(0x0f)))
+#define AICA_VOL(x) (0xff - logs[128 + (((x) & 0xff) / 2)])
+//#define AICA_VOL(x) (0xff - logs[x&255])
+
+static inline unsigned AICA_FREQ(unsigned freq) {
+ unsigned long freq_lo, freq_base = 5644800;
+ int freq_hi = 7;
+
+ /* Need to convert frequency to floating point format
+ (freq_hi is exponent, freq_lo is mantissa)
+ Formula is ferq = 44100*2^freq_hi*(1+freq_lo/1024) */
+ while (freq < freq_base && freq_hi > -8) {
+ freq_base >>= 1;
+ --freq_hi;
+ }
+ while (freq < freq_base && freq_hi > -8) {
+ freq_base >>= 1;
+ freq_hi--;
+ }
+ freq_lo = (freq<<10) / freq_base;
+ return (freq_hi << 11) | (freq_lo & 1023);
+}
+
+/* Sets up a sound channel completely. This is generally good if you want
+ a quick and dirty way to play notes. If you want a more comprehensive
+ set of routines (more like PC wavetable cards) see below.
+
+ ch is the channel to play on (0 - 63)
+ smpptr is the pointer to the sound data; if you're running off the
+ SH4, then this ought to be (ptr - 0xa0800000); otherwise it's just
+ ptr. Basically, it's an offset into sound ram.
+ mode is one of the mode constants (16 bit, 8 bit, ADPCM)
+ nsamp is the number of samples to play (not number of bytes!)
+ freq is the sampling rate of the sound
+ vol is the volume, 0 to 0xff (0xff is louder)
+ pan is a panning constant -- 0 is left, 128 is center, 255 is right.
+
+ This routine (and the similar ones) owe a lot to Marcus' sound example --
+ I hadn't gotten quite this far into dissecting the individual regs yet. */
+void aica_play(int ch,int mode,unsigned long smpptr,int loopst,int loopend,int freq,int vol,int pan,int loopflag) {
+/* int i;
+*/
+ int val;
+ int old = 0;
+
+ /* Stop the channel (if it's already playing) */
+ aica_stop(ch);
+ /* doesn't seem to be needed, but it's here just in case */
+/*
+ for (i=0; i<256; i++) {
+ asm("nop");
+ asm("nop");
+ asm("nop");
+ asm("nop");
+ }
+*/
+ G2_LOCK(old);
+ /* Envelope setup. The first of these is the loop point,
+ e.g., where the sample starts over when it loops. The second
+ is the loop end. This is the full length of the sample when
+ you are not looping, or the loop end point when you are (though
+ storing more than that is a waste of memory if you're not doing
+ volume enveloping). */
+ CHNREG32(ch, 8) = loopst & 0xffff;
+ CHNREG32(ch, 12) = loopend & 0xffff;
+
+ /* Write resulting values */
+ CHNREG32(ch, 24) = AICA_FREQ(freq);
+
+ /* Set volume, pan, and some other things that we don't know what
+ they do =) */
+ CHNREG32(ch, 36) = AICA_PAN(pan) | (0xf<<8);
+ /* Convert the incoming volume and pan into hardware values */
+ /* Vol starts at zero so we can ramp */
+ vol = AICA_VOL(vol);
+ CHNREG32(ch, 40) = 0x24 | (vol<<8);
+ /* Convert the incoming volume and pan into hardware values */
+ /* Vol starts at zero so we can ramp */
+
+ /* If we supported volume envelopes (which we don't yet) then
+ this value would set that up. The top 4 bits determine the
+ envelope speed. f is the fastest, 1 is the slowest, and 0
+ seems to be an invalid value and does weird things). The
+ default (below) sets it into normal mode (play and terminate/loop).
+ CHNREG32(ch, 16) = 0xf010;
+ */
+ CHNREG32(ch, 16) = 0x1f; /* No volume envelope */
+
+
+ /* Set sample format, buffer address, and looping control. If
+ 0x0200 mask is set on reg 0, the sample loops infinitely. If
+ it's not set, the sample plays once and terminates. We'll
+ also set the bits to start playback here. */
+ CHNREG32(ch, 4) = smpptr & 0xffff;
+ val = 0xc000 | 0x0000 | (mode<<7) | (smpptr >> 16);
+ if (loopflag) val|=0x200;
+
+ CHNREG32(ch, 0) = val;
+
+ G2_UNLOCK(old);
+
+ /* Enable playback */
+ /* CHNREG32(ch, 0) |= 0xc000; */
+ g2_fifo_wait();
+
+#if 0
+ for (i=0xff; i>=vol; i--) {
+ if ((i&7)==0) g2_fifo_wait();
+ CHNREG32(ch, 40) = 0x24 | (i<<8);;
+ }
+
+ g2_fifo_wait();
+#endif
+}
+
+/* Stop the sound on a given channel */
+void aica_stop(int ch) {
+ g2_write_32(CHNREGADDR(ch, 0),(g2_read_32(CHNREGADDR(ch, 0)) & ~0x4000) | 0x8000);
+ g2_fifo_wait();
+}
+
+
+/* The rest of these routines can change the channel in mid-stride so you
+ can do things like vibrato and panning effects. */
+
+/* Set channel volume */
+void aica_vol(int ch,int vol) {
+// g2_write_8(CHNREGADDR(ch, 41),AICA_VOL(vol));
+ g2_write_32(CHNREGADDR(ch, 40),(g2_read_32(CHNREGADDR(ch, 40))&0xffff00ff)|(AICA_VOL(vol)<<8) );
+ g2_fifo_wait();
+}
+
+/* Set channel pan */
+void aica_pan(int ch,int pan) {
+// g2_write_8(CHNREGADDR(ch, 36),AICA_PAN(pan));
+ g2_write_32(CHNREGADDR(ch, 36),(g2_read_32(CHNREGADDR(ch, 36))&0xffffff00)|(AICA_PAN(pan)) );
+ g2_fifo_wait();
+}
+
+/* Set channel frequency */
+void aica_freq(int ch,int freq) {
+ g2_write_32(CHNREGADDR(ch, 24),AICA_FREQ(freq));
+ g2_fifo_wait();
+}
+
+/* Get channel position */
+int aica_get_pos(int ch) {
+#if 1
+ /* Observe channel ch */
+ g2_write_32(SNDREGADDR(0x280c),(g2_read_32(SNDREGADDR(0x280c))&0xffff00ff) | (ch<<8));
+ g2_fifo_wait();
+ /* Update position counters */
+ return g2_read_32(SNDREGADDR(0x2814)) & 0xffff;
+#else
+ /* Observe channel ch */
+ g2_write_8(SNDREGADDR(0x280d),ch);
+ /* Update position counters */
+ return g2_read_32(SNDREGADDR(0x2814)) & 0xffff;
+#endif
+}
diff --git a/src/audio/dc/aica.h b/src/audio/dc/aica.h
new file mode 100644
index 0000000..2bee433
--- /dev/null
+++ b/src/audio/dc/aica.h
@@ -0,0 +1,40 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _AICA_H_
+#define _AICA_H_
+
+#define AICA_MEM 0xa0800000
+
+#define SM_8BIT 1
+#define SM_16BIT 0
+#define SM_ADPCM 2
+
+void aica_play(int ch,int mode,unsigned long smpptr,int looptst,int loopend,int freq,int vol,int pan,int loopflag);
+void aica_stop(int ch);
+void aica_vol(int ch,int vol);
+void aica_pan(int ch,int pan);
+void aica_freq(int ch,int freq);
+int aica_get_pos(int ch);
+
+#endif
diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c
new file mode 100644
index 0000000..fd3595c
--- /dev/null
+++ b/src/audio/disk/SDL_diskaudio.c
@@ -0,0 +1,186 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+
+ This file written by Ryan C. Gordon (icculus@icculus.org)
+*/
+#include "SDL_config.h"
+
+/* Output raw audio data to a file. */
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#include "SDL_rwops.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_diskaudio.h"
+
+/* The tag name used by DISK audio */
+#define DISKAUD_DRIVER_NAME "disk"
+
+/* environment variables and defaults. */
+#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
+#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
+#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
+#define DISKDEFAULT_WRITEDELAY 150
+
+/* Audio driver functions */
+static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DISKAUD_WaitAudio(_THIS);
+static void DISKAUD_PlayAudio(_THIS);
+static Uint8 *DISKAUD_GetAudioBuf(_THIS);
+static void DISKAUD_CloseAudio(_THIS);
+
+static const char *DISKAUD_GetOutputFilename(void)
+{
+ const char *envr = SDL_getenv(DISKENVR_OUTFILE);
+ return((envr != NULL) ? envr : DISKDEFAULT_OUTFILE);
+}
+
+/* Audio driver bootstrap functions */
+static int DISKAUD_Available(void)
+{
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+ if (envr && (SDL_strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) {
+ return(1);
+ }
+ return(0);
+}
+
+static void DISKAUD_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *DISKAUD_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+ const char *envr;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ envr = SDL_getenv(DISKENVR_WRITEDELAY);
+ this->hidden->write_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
+
+ /* Set the function pointers */
+ this->OpenAudio = DISKAUD_OpenAudio;
+ this->WaitAudio = DISKAUD_WaitAudio;
+ this->PlayAudio = DISKAUD_PlayAudio;
+ this->GetAudioBuf = DISKAUD_GetAudioBuf;
+ this->CloseAudio = DISKAUD_CloseAudio;
+
+ this->free = DISKAUD_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DISKAUD_bootstrap = {
+ DISKAUD_DRIVER_NAME, "direct-to-disk audio",
+ DISKAUD_Available, DISKAUD_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void DISKAUD_WaitAudio(_THIS)
+{
+ SDL_Delay(this->hidden->write_delay);
+}
+
+static void DISKAUD_PlayAudio(_THIS)
+{
+ int written;
+
+ /* Write the audio data */
+ written = SDL_RWwrite(this->hidden->output,
+ this->hidden->mixbuf, 1,
+ this->hidden->mixlen);
+
+ /* If we couldn't write, assume fatal error for now */
+ if ( (Uint32)written != this->hidden->mixlen ) {
+ this->enabled = 0;
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *DISKAUD_GetAudioBuf(_THIS)
+{
+ return(this->hidden->mixbuf);
+}
+
+static void DISKAUD_CloseAudio(_THIS)
+{
+ if ( this->hidden->mixbuf != NULL ) {
+ SDL_FreeAudioMem(this->hidden->mixbuf);
+ this->hidden->mixbuf = NULL;
+ }
+ if ( this->hidden->output != NULL ) {
+ SDL_RWclose(this->hidden->output);
+ this->hidden->output = NULL;
+ }
+}
+
+static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ const char *fname = DISKAUD_GetOutputFilename();
+
+ /* Open the audio device */
+ this->hidden->output = SDL_RWFromFile(fname, "wb");
+ if ( this->hidden->output == NULL ) {
+ return(-1);
+ }
+
+#if HAVE_STDIO_H
+ fprintf(stderr, "WARNING: You are using the SDL disk writer"
+ " audio driver!\n Writing to file [%s].\n", fname);
+#endif
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = spec->size;
+ this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
+ if ( this->hidden->mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
+
diff --git a/src/audio/disk/SDL_diskaudio.h b/src/audio/disk/SDL_diskaudio.h
new file mode 100644
index 0000000..76f0607
--- /dev/null
+++ b/src/audio/disk/SDL_diskaudio.h
@@ -0,0 +1,41 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_diskaudio_h
+#define _SDL_diskaudio_h
+
+#include "SDL_rwops.h"
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ SDL_RWops *output;
+ Uint8 *mixbuf;
+ Uint32 mixlen;
+ Uint32 write_delay;
+};
+
+#endif /* _SDL_diskaudio_h */
diff --git a/src/audio/dma/SDL_dmaaudio.c b/src/audio/dma/SDL_dmaaudio.c
new file mode 100644
index 0000000..dbb5a20
--- /dev/null
+++ b/src/audio/dma/SDL_dmaaudio.c
@@ -0,0 +1,455 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <stdio.h>
+#include <string.h> /* For strerror() */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
+/* This is installed on some systems */
+#include <soundcard.h>
+#else
+/* This is recommended by OSS */
+#include <sys/soundcard.h>
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((Uint8 *)-1)
+#endif
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_dmaaudio.h"
+
+/* The tag name used by DMA audio */
+#define DMA_DRIVER_NAME "dma"
+
+/* Open the audio device for playback, and don't block if busy */
+#define OPEN_FLAGS (O_RDWR|O_NONBLOCK)
+
+/* Audio driver functions */
+static int DMA_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DMA_WaitAudio(_THIS);
+static void DMA_PlayAudio(_THIS);
+static Uint8 *DMA_GetAudioBuf(_THIS);
+static void DMA_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int available;
+ int fd;
+
+ available = 0;
+
+ fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
+ if ( fd >= 0 ) {
+ int caps;
+ struct audio_buf_info info;
+
+ if ( (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps) == 0) &&
+ (caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
+ (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == 0) ) {
+ available = 1;
+ }
+ close(fd);
+ }
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ audio_fd = -1;
+
+ /* Set the function pointers */
+ this->OpenAudio = DMA_OpenAudio;
+ this->WaitAudio = DMA_WaitAudio;
+ this->PlayAudio = DMA_PlayAudio;
+ this->GetAudioBuf = DMA_GetAudioBuf;
+ this->CloseAudio = DMA_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DMA_bootstrap = {
+ DMA_DRIVER_NAME, "OSS /dev/dsp DMA audio",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void DMA_WaitAudio(_THIS)
+{
+ fd_set fdset;
+
+ /* Check to see if the thread-parent process is still alive */
+ { static int cnt = 0;
+ /* Note that this only works with thread implementations
+ that use a different process id for each thread.
+ */
+ if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
+ if ( kill(parent, 0) < 0 ) {
+ this->enabled = 0;
+ }
+ }
+ }
+
+ /* See if we need to use timed audio synchronization */
+ if ( frame_ticks ) {
+ /* Use timer for general audio synchronization */
+ Sint32 ticks;
+
+ ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
+ if ( ticks > 0 ) {
+ SDL_Delay(ticks);
+ }
+ } else {
+ /* Use select() for audio synchronization */
+ struct timeval timeout;
+ FD_ZERO(&fdset);
+ FD_SET(audio_fd, &fdset);
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 0;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Waiting for audio to get ready\n");
+#endif
+ if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
+ const char *message =
+#ifdef AUDIO_OSPACE_HACK
+ "Audio timeout - buggy audio driver? (trying ospace)";
+#else
+ "Audio timeout - buggy audio driver? (disabled)";
+#endif
+ /* In general we should never print to the screen,
+ but in this case we have no other way of letting
+ the user know what happened.
+ */
+ fprintf(stderr, "SDL: %s\n", message);
+#ifdef AUDIO_OSPACE_HACK
+ /* We may be able to use GET_OSPACE trick */
+ frame_ticks = (float)(this->spec->samples*1000) /
+ this->spec->freq;
+ next_frame = SDL_GetTicks()+frame_ticks;
+#else
+ this->enabled = 0;
+ /* Don't try to close - may hang */
+ audio_fd = -1;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Done disabling audio\n");
+#endif
+#endif /* AUDIO_OSPACE_HACK */
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Ready!\n");
+#endif
+ }
+}
+
+static void DMA_PlayAudio(_THIS)
+{
+ /* If timer synchronization is enabled, set the next write frame */
+ if ( frame_ticks ) {
+ next_frame += frame_ticks;
+ }
+ return;
+}
+
+static Uint8 *DMA_GetAudioBuf(_THIS)
+{
+ count_info info;
+ int playing;
+ int filling;
+
+ /* Get number of blocks, looping if we're not using select() */
+ do {
+ if ( ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) < 0 ) {
+ /* Uh oh... */
+ this->enabled = 0;
+ return(NULL);
+ }
+ } while ( frame_ticks && (info.blocks < 1) );
+#ifdef DEBUG_AUDIO
+ if ( info.blocks > 1 ) {
+ printf("Warning: audio underflow (%d frags)\n", info.blocks-1);
+ }
+#endif
+ playing = info.ptr / this->spec.size;
+ filling = (playing + 1)%num_buffers;
+ return (dma_buf + (filling * this->spec.size));
+}
+
+static void DMA_CloseAudio(_THIS)
+{
+ if ( dma_buf != NULL ) {
+ munmap(dma_buf, dma_len);
+ dma_buf = NULL;
+ }
+ if ( audio_fd >= 0 ) {
+ close(audio_fd);
+ audio_fd = -1;
+ }
+}
+
+static int DMA_ReopenAudio(_THIS, const char *audiodev, int format, int stereo,
+ SDL_AudioSpec *spec)
+{
+ int frag_spec;
+ int value;
+
+ /* Close and then reopen the audio device */
+ close(audio_fd);
+ audio_fd = open(audiodev, O_RDWR, 0);
+ if ( audio_fd < 0 ) {
+ SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ return(-1);
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Determine the power of two of the fragment size */
+ for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
+ if ( (0x01<<frag_spec) != spec->size ) {
+ SDL_SetError("Fragment size must be a power of two");
+ return(-1);
+ }
+
+ /* Set the audio buffering parameters */
+ if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) {
+ SDL_SetError("Couldn't set audio fragment spec");
+ return(-1);
+ }
+
+ /* Set the audio format */
+ value = format;
+ if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
+ (value != format) ) {
+ SDL_SetError("Couldn't set audio format");
+ return(-1);
+ }
+
+ /* Set mono or stereo audio */
+ value = (spec->channels > 1);
+ if ( (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
+ (value != stereo) ) {
+ SDL_SetError("Couldn't set audio channels");
+ return(-1);
+ }
+
+ /* Set the DSP frequency */
+ value = spec->freq;
+ if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) {
+ SDL_SetError("Couldn't set audio frequency");
+ return(-1);
+ }
+ spec->freq = value;
+
+ /* We successfully re-opened the audio */
+ return(0);
+}
+
+static int DMA_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ char audiodev[1024];
+ int format;
+ int stereo;
+ int value;
+ Uint16 test_format;
+ struct audio_buf_info info;
+
+ /* Reset the timer synchronization flag */
+ frame_ticks = 0.0;
+
+ /* Open the audio device */
+ audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
+ if ( audio_fd < 0 ) {
+ SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ return(-1);
+ }
+ dma_buf = NULL;
+ ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
+
+ /* Get a list of supported hardware formats */
+ if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
+ SDL_SetError("Couldn't get audio format list");
+ return(-1);
+ }
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ ! format && test_format; ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch ( test_format ) {
+ case AUDIO_U8:
+ if ( value & AFMT_U8 ) {
+ format = AFMT_U8;
+ }
+ break;
+ case AUDIO_S8:
+ if ( value & AFMT_S8 ) {
+ format = AFMT_S8;
+ }
+ break;
+ case AUDIO_S16LSB:
+ if ( value & AFMT_S16_LE ) {
+ format = AFMT_S16_LE;
+ }
+ break;
+ case AUDIO_S16MSB:
+ if ( value & AFMT_S16_BE ) {
+ format = AFMT_S16_BE;
+ }
+ break;
+ case AUDIO_U16LSB:
+ if ( value & AFMT_U16_LE ) {
+ format = AFMT_U16_LE;
+ }
+ break;
+ case AUDIO_U16MSB:
+ if ( value & AFMT_U16_BE ) {
+ format = AFMT_U16_BE;
+ }
+ break;
+ default:
+ format = 0;
+ break;
+ }
+ if ( ! format ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( format == 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ return(-1);
+ }
+ spec->format = test_format;
+
+ /* Set the audio format */
+ value = format;
+ if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
+ (value != format) ) {
+ SDL_SetError("Couldn't set audio format");
+ return(-1);
+ }
+
+ /* Set mono or stereo audio (currently only two channels supported) */
+ stereo = (spec->channels > 1);
+ ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
+ if ( stereo ) {
+ spec->channels = 2;
+ } else {
+ spec->channels = 1;
+ }
+
+ /* Because some drivers don't allow setting the buffer size
+ after setting the format, we must re-open the audio device
+ once we know what format and channels are supported
+ */
+ if ( DMA_ReopenAudio(this, audiodev, format, stereo, spec) < 0 ) {
+ /* Error is set by DMA_ReopenAudio() */
+ return(-1);
+ }
+
+ /* Memory map the audio buffer */
+ if ( ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) < 0 ) {
+ SDL_SetError("Couldn't get OSPACE parameters");
+ return(-1);
+ }
+ spec->size = info.fragsize;
+ spec->samples = spec->size / ((spec->format & 0xFF) / 8);
+ spec->samples /= spec->channels;
+ num_buffers = info.fragstotal;
+ dma_len = num_buffers*spec->size;
+ dma_buf = (Uint8 *)mmap(NULL, dma_len, PROT_WRITE, MAP_SHARED,
+ audio_fd, 0);
+ if ( dma_buf == MAP_FAILED ) {
+ SDL_SetError("DMA memory map failed");
+ dma_buf = NULL;
+ return(-1);
+ }
+ SDL_memset(dma_buf, spec->silence, dma_len);
+
+ /* Check to see if we need to use select() workaround */
+ { char *workaround;
+ workaround = SDL_getenv("SDL_DSP_NOSELECT");
+ if ( workaround ) {
+ frame_ticks = (float)(spec->samples*1000)/spec->freq;
+ next_frame = SDL_GetTicks()+frame_ticks;
+ }
+ }
+
+ /* Trigger audio playback */
+ value = 0;
+ ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value);
+ value = PCM_ENABLE_OUTPUT;
+ if ( ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &value) < 0 ) {
+ SDL_SetError("Couldn't trigger audio output");
+ return(-1);
+ }
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/dma/SDL_dmaaudio.h b/src/audio/dma/SDL_dmaaudio.h
new file mode 100644
index 0000000..9874072
--- /dev/null
+++ b/src/audio/dma/SDL_dmaaudio.h
@@ -0,0 +1,59 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_dspaudio_h
+#define _SDL_dspaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *dma_buf;
+ int dma_len;
+ int num_buffers;
+
+ /* Support for audio timing using a timer, in addition to select() */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+/* Old variable names */
+#define audio_fd (this->hidden->audio_fd)
+#define parent (this->hidden->parent)
+#define dma_buf (this->hidden->dma_buf)
+#define dma_len (this->hidden->dma_len)
+#define num_buffers (this->hidden->num_buffers)
+#define frame_ticks (this->hidden->frame_ticks)
+#define next_frame (this->hidden->next_frame)
+
+#endif /* _SDL_dspaudio_h */
diff --git a/src/audio/dmedia/SDL_irixaudio.c b/src/audio/dmedia/SDL_irixaudio.c
new file mode 100644
index 0000000..d17d09b
--- /dev/null
+++ b/src/audio/dmedia/SDL_irixaudio.c
@@ -0,0 +1,242 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer (For IRIX 6.5 and higher) */
+/* patch for IRIX 5 by Georg Schwarz 18/07/2004 */
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "SDL_irixaudio.h"
+
+
+#ifndef AL_RESOURCE /* as a test whether we use the old IRIX audio libraries */
+#define OLD_IRIX_AUDIO
+#define alClosePort(x) ALcloseport(x)
+#define alFreeConfig(x) ALfreeconfig(x)
+#define alGetFillable(x) ALgetfillable(x)
+#define alNewConfig() ALnewconfig()
+#define alOpenPort(x,y,z) ALopenport(x,y,z)
+#define alSetChannels(x,y) ALsetchannels(x,y)
+#define alSetQueueSize(x,y) ALsetqueuesize(x,y)
+#define alSetSampFmt(x,y) ALsetsampfmt(x,y)
+#define alSetWidth(x,y) ALsetwidth(x,y)
+#endif
+
+/* Audio driver functions */
+static int AL_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void AL_WaitAudio(_THIS);
+static void AL_PlayAudio(_THIS);
+static Uint8 *AL_GetAudioBuf(_THIS);
+static void AL_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ return 1;
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = AL_OpenAudio;
+ this->WaitAudio = AL_WaitAudio;
+ this->PlayAudio = AL_PlayAudio;
+ this->GetAudioBuf = AL_GetAudioBuf;
+ this->CloseAudio = AL_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DMEDIA_bootstrap = {
+ "AL", "IRIX DMedia audio",
+ Audio_Available, Audio_CreateDevice
+};
+
+
+void static AL_WaitAudio(_THIS)
+{
+ Sint32 timeleft;
+
+ timeleft = this->spec.samples - alGetFillable(audio_port);
+ if ( timeleft > 0 ) {
+ timeleft /= (this->spec.freq/1000);
+ SDL_Delay((Uint32)timeleft);
+ }
+}
+
+static void AL_PlayAudio(_THIS)
+{
+ /* Write the audio data out */
+ if ( alWriteFrames(audio_port, mixbuf, this->spec.samples) < 0 ) {
+ /* Assume fatal error, for now */
+ this->enabled = 0;
+ }
+}
+
+static Uint8 *AL_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void AL_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( audio_port != NULL ) {
+ alClosePort(audio_port);
+ audio_port = NULL;
+ }
+}
+
+static int AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
+{
+ Uint16 test_format = SDL_FirstAudioFormat(spec->format);
+ long width = 0;
+ long fmt = 0;
+ int valid = 0;
+
+#ifdef OLD_IRIX_AUDIO
+ {
+ long audio_param[2];
+ audio_param[0] = AL_OUTPUT_RATE;
+ audio_param[1] = spec->freq;
+ valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0);
+ }
+#else
+ {
+ ALpv audio_param;
+ audio_param.param = AL_RATE;
+ audio_param.value.i = spec->freq;
+ valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0);
+ }
+#endif
+
+ while ((!valid) && (test_format)) {
+ valid = 1;
+ spec->format = test_format;
+
+ switch (test_format) {
+ case AUDIO_S8:
+ width = AL_SAMPLE_8;
+ fmt = AL_SAMPFMT_TWOSCOMP;
+ break;
+
+ case AUDIO_S16SYS:
+ width = AL_SAMPLE_16;
+ fmt = AL_SAMPFMT_TWOSCOMP;
+ break;
+
+ default:
+ valid = 0;
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+
+ if (valid) {
+ ALconfig audio_config = alNewConfig();
+ valid = 0;
+ if (audio_config) {
+ if (alSetChannels(audio_config, spec->channels) < 0) {
+ if (spec->channels > 2) { /* can't handle > stereo? */
+ spec->channels = 2; /* try again below. */
+ }
+ }
+
+ if ((alSetSampFmt(audio_config, fmt) >= 0) &&
+ ((!width) || (alSetWidth(audio_config, width) >= 0)) &&
+ (alSetQueueSize(audio_config, spec->samples * 2) >= 0) &&
+ (alSetChannels(audio_config, spec->channels) >= 0)) {
+
+ audio_port = alOpenPort("SDL audio", "w", audio_config);
+ if (audio_port == NULL) {
+ /* docs say AL_BAD_CHANNELS happens here, too. */
+ int err = oserror();
+ if (err == AL_BAD_CHANNELS) {
+ spec->channels = 2;
+ alSetChannels(audio_config, spec->channels);
+ audio_port = alOpenPort("SDL audio", "w",
+ audio_config);
+ }
+ }
+
+ if (audio_port != NULL) {
+ valid = 1;
+ }
+ }
+
+ alFreeConfig(audio_config);
+ }
+ }
+ }
+
+ if (!valid) {
+ SDL_SetError("Unsupported audio format");
+ return (-1);
+ }
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size);
+ if (mixbuf == NULL) {
+ SDL_OutOfMemory();
+ return (-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* We're ready to rock and roll. :-) */
+ return (0);
+}
+
diff --git a/src/audio/dmedia/SDL_irixaudio.h b/src/audio/dmedia/SDL_irixaudio.h
new file mode 100644
index 0000000..f8bc43a
--- /dev/null
+++ b/src/audio/dmedia/SDL_irixaudio.h
@@ -0,0 +1,45 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include <dmedia/audio.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The handle for the audio device */
+ ALport audio_port;
+
+ Uint8 *mixbuf; /* The app mixing buffer */
+};
+
+/* Old variable names */
+#define audio_port (this->hidden->audio_port)
+#define mixbuf (this->hidden->mixbuf)
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c
new file mode 100644
index 0000000..c394a59
--- /dev/null
+++ b/src/audio/dsp/SDL_dspaudio.c
@@ -0,0 +1,340 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+
+ Modified in Oct 2004 by Hannu Savolainen
+ hannu@opensound.com
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <stdio.h> /* For perror() */
+#include <string.h> /* For strerror() */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
+/* This is installed on some systems */
+#include <soundcard.h>
+#else
+/* This is recommended by OSS */
+#include <sys/soundcard.h>
+#endif
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_dspaudio.h"
+
+/* The tag name used by DSP audio */
+#define DSP_DRIVER_NAME "dsp"
+
+/* Open the audio device for playback, and don't block if busy */
+#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
+
+/* Audio driver functions */
+static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DSP_WaitAudio(_THIS);
+static void DSP_PlayAudio(_THIS);
+static Uint8 *DSP_GetAudioBuf(_THIS);
+static void DSP_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int fd;
+ int available;
+
+ available = 0;
+ fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
+ if ( fd >= 0 ) {
+ available = 1;
+ close(fd);
+ }
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ audio_fd = -1;
+
+ /* Set the function pointers */
+ this->OpenAudio = DSP_OpenAudio;
+ this->WaitAudio = DSP_WaitAudio;
+ this->PlayAudio = DSP_PlayAudio;
+ this->GetAudioBuf = DSP_GetAudioBuf;
+ this->CloseAudio = DSP_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DSP_bootstrap = {
+ DSP_DRIVER_NAME, "OSS /dev/dsp standard audio",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void DSP_WaitAudio(_THIS)
+{
+ /* Not needed at all since OSS handles waiting automagically */
+}
+
+static void DSP_PlayAudio(_THIS)
+{
+ if (write(audio_fd, mixbuf, mixlen)==-1)
+ {
+ perror("Audio write");
+ this->enabled = 0;
+ }
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
+#endif
+}
+
+static Uint8 *DSP_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void DSP_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( audio_fd >= 0 ) {
+ close(audio_fd);
+ audio_fd = -1;
+ }
+}
+
+static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ char audiodev[1024];
+ int format;
+ int value;
+ int frag_spec;
+ Uint16 test_format;
+
+ /* Make sure fragment size stays a power of 2, or OSS fails. */
+ /* I don't know which of these are actually legal values, though... */
+ if (spec->channels > 8)
+ spec->channels = 8;
+ else if (spec->channels > 4)
+ spec->channels = 4;
+ else if (spec->channels > 2)
+ spec->channels = 2;
+
+ /* Open the audio device */
+ audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
+ if ( audio_fd < 0 ) {
+ SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ return(-1);
+ }
+ mixbuf = NULL;
+
+ /* Make the file descriptor use blocking writes with fcntl() */
+ { long flags;
+ flags = fcntl(audio_fd, F_GETFL);
+ flags &= ~O_NONBLOCK;
+ if ( fcntl(audio_fd, F_SETFL, flags) < 0 ) {
+ SDL_SetError("Couldn't set audio blocking mode");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+ }
+
+ /* Get a list of supported hardware formats */
+ if ( ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0 ) {
+ perror("SNDCTL_DSP_GETFMTS");
+ SDL_SetError("Couldn't get audio format list");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ ! format && test_format; ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch ( test_format ) {
+ case AUDIO_U8:
+ if ( value & AFMT_U8 ) {
+ format = AFMT_U8;
+ }
+ break;
+ case AUDIO_S16LSB:
+ if ( value & AFMT_S16_LE ) {
+ format = AFMT_S16_LE;
+ }
+ break;
+ case AUDIO_S16MSB:
+ if ( value & AFMT_S16_BE ) {
+ format = AFMT_S16_BE;
+ }
+ break;
+#if 0
+/*
+ * These formats are not used by any real life systems so they are not
+ * needed here.
+ */
+ case AUDIO_S8:
+ if ( value & AFMT_S8 ) {
+ format = AFMT_S8;
+ }
+ break;
+ case AUDIO_U16LSB:
+ if ( value & AFMT_U16_LE ) {
+ format = AFMT_U16_LE;
+ }
+ break;
+ case AUDIO_U16MSB:
+ if ( value & AFMT_U16_BE ) {
+ format = AFMT_U16_BE;
+ }
+ break;
+#endif
+ default:
+ format = 0;
+ break;
+ }
+ if ( ! format ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( format == 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+ spec->format = test_format;
+
+ /* Set the audio format */
+ value = format;
+ if ( (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
+ (value != format) ) {
+ perror("SNDCTL_DSP_SETFMT");
+ SDL_SetError("Couldn't set audio format");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+
+ /* Set the number of channels of output */
+ value = spec->channels;
+ if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0 ) {
+ perror("SNDCTL_DSP_CHANNELS");
+ SDL_SetError("Cannot set the number of channels");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+ spec->channels = value;
+
+ /* Set the DSP frequency */
+ value = spec->freq;
+ if ( ioctl(audio_fd, SNDCTL_DSP_SPEED, &value) < 0 ) {
+ perror("SNDCTL_DSP_SPEED");
+ SDL_SetError("Couldn't set audio frequency");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+ spec->freq = value;
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Determine the power of two of the fragment size */
+ for ( frag_spec = 0; (0x01U<<frag_spec) < spec->size; ++frag_spec );
+ if ( (0x01U<<frag_spec) != spec->size ) {
+ SDL_SetError("Fragment size must be a power of two");
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+ frag_spec |= 0x00020000; /* two fragments, for low latency */
+
+ /* Set the audio buffering parameters */
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Requesting %d fragments of size %d\n",
+ (frag_spec >> 16), 1<<(frag_spec&0xFFFF));
+#endif
+ if ( ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0 ) {
+ perror("SNDCTL_DSP_SETFRAGMENT");
+ }
+#ifdef DEBUG_AUDIO
+ { audio_buf_info info;
+ ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
+ fprintf(stderr, "fragments = %d\n", info.fragments);
+ fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
+ fprintf(stderr, "fragsize = %d\n", info.fragsize);
+ fprintf(stderr, "bytes = %d\n", info.bytes);
+ }
+#endif
+
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+ if ( mixbuf == NULL ) {
+ DSP_CloseAudio(this);
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/dsp/SDL_dspaudio.h b/src/audio/dsp/SDL_dspaudio.h
new file mode 100644
index 0000000..26d8d2e
--- /dev/null
+++ b/src/audio/dsp/SDL_dspaudio.h
@@ -0,0 +1,53 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_dspaudio_h
+#define _SDL_dspaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+/* Old variable names */
+#define audio_fd (this->hidden->audio_fd)
+#define parent (this->hidden->parent)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+#define frame_ticks (this->hidden->frame_ticks)
+#define next_frame (this->hidden->next_frame)
+
+#endif /* _SDL_dspaudio_h */
diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c
new file mode 100644
index 0000000..9567d96
--- /dev/null
+++ b/src/audio/dummy/SDL_dummyaudio.c
@@ -0,0 +1,156 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+
+ This file written by Ryan C. Gordon (icculus@icculus.org)
+*/
+#include "SDL_config.h"
+
+/* Output audio to nowhere... */
+
+#include "SDL_rwops.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_dummyaudio.h"
+
+/* The tag name used by DUMMY audio */
+#define DUMMYAUD_DRIVER_NAME "dummy"
+
+/* Audio driver functions */
+static int DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DUMMYAUD_WaitAudio(_THIS);
+static void DUMMYAUD_PlayAudio(_THIS);
+static Uint8 *DUMMYAUD_GetAudioBuf(_THIS);
+static void DUMMYAUD_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+static int DUMMYAUD_Available(void)
+{
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+ if (envr && (SDL_strcmp(envr, DUMMYAUD_DRIVER_NAME) == 0)) {
+ return(1);
+ }
+ return(0);
+}
+
+static void DUMMYAUD_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *DUMMYAUD_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = DUMMYAUD_OpenAudio;
+ this->WaitAudio = DUMMYAUD_WaitAudio;
+ this->PlayAudio = DUMMYAUD_PlayAudio;
+ this->GetAudioBuf = DUMMYAUD_GetAudioBuf;
+ this->CloseAudio = DUMMYAUD_CloseAudio;
+
+ this->free = DUMMYAUD_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DUMMYAUD_bootstrap = {
+ DUMMYAUD_DRIVER_NAME, "SDL dummy audio driver",
+ DUMMYAUD_Available, DUMMYAUD_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void DUMMYAUD_WaitAudio(_THIS)
+{
+ /* Don't block on first calls to simulate initial fragment filling. */
+ if (this->hidden->initial_calls)
+ this->hidden->initial_calls--;
+ else
+ SDL_Delay(this->hidden->write_delay);
+}
+
+static void DUMMYAUD_PlayAudio(_THIS)
+{
+ /* no-op...this is a null driver. */
+}
+
+static Uint8 *DUMMYAUD_GetAudioBuf(_THIS)
+{
+ return(this->hidden->mixbuf);
+}
+
+static void DUMMYAUD_CloseAudio(_THIS)
+{
+ if ( this->hidden->mixbuf != NULL ) {
+ SDL_FreeAudioMem(this->hidden->mixbuf);
+ this->hidden->mixbuf = NULL;
+ }
+}
+
+static int DUMMYAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ float bytes_per_sec = 0.0f;
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = spec->size;
+ this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
+ if ( this->hidden->mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
+
+ bytes_per_sec = (float) (((spec->format & 0xFF) / 8) *
+ spec->channels * spec->freq);
+
+ /*
+ * We try to make this request more audio at the correct rate for
+ * a given audio spec, so timing stays fairly faithful.
+ * Also, we have it not block at all for the first two calls, so
+ * it seems like we're filling two audio fragments right out of the
+ * gate, like other SDL drivers tend to do.
+ */
+ this->hidden->initial_calls = 2;
+ this->hidden->write_delay =
+ (Uint32) ((((float) spec->size) / bytes_per_sec) * 1000.0f);
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
+
diff --git a/src/audio/dummy/SDL_dummyaudio.h b/src/audio/dummy/SDL_dummyaudio.h
new file mode 100644
index 0000000..e233e2a
--- /dev/null
+++ b/src/audio/dummy/SDL_dummyaudio.h
@@ -0,0 +1,40 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_dummyaudio_h
+#define _SDL_dummyaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ Uint8 *mixbuf;
+ Uint32 mixlen;
+ Uint32 write_delay;
+ Uint32 initial_calls;
+};
+
+#endif /* _SDL_dummyaudio_h */
diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c
new file mode 100644
index 0000000..5514baf
--- /dev/null
+++ b/src/audio/esd/SDL_esdaudio.c
@@ -0,0 +1,323 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to an ESD network stream mixing buffer */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <esd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_esdaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+/* The tag name used by ESD audio */
+#define ESD_DRIVER_NAME "esd"
+
+/* Audio driver functions */
+static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void ESD_WaitAudio(_THIS);
+static void ESD_PlayAudio(_THIS);
+static Uint8 *ESD_GetAudioBuf(_THIS);
+static void ESD_CloseAudio(_THIS);
+
+#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
+
+static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
+static void *esd_handle = NULL;
+static int esd_loaded = 0;
+
+static int (*SDL_NAME(esd_open_sound))( const char *host );
+static int (*SDL_NAME(esd_close))( int esd );
+static int (*SDL_NAME(esd_play_stream))( esd_format_t format, int rate,
+ const char *host, const char *name );
+static struct {
+ const char *name;
+ void **func;
+} esd_functions[] = {
+ { "esd_open_sound", (void **)&SDL_NAME(esd_open_sound) },
+ { "esd_close", (void **)&SDL_NAME(esd_close) },
+ { "esd_play_stream", (void **)&SDL_NAME(esd_play_stream) },
+};
+
+static void UnloadESDLibrary()
+{
+ if ( esd_loaded ) {
+ SDL_UnloadObject(esd_handle);
+ esd_handle = NULL;
+ esd_loaded = 0;
+ }
+}
+
+static int LoadESDLibrary(void)
+{
+ int i, retval = -1;
+
+ esd_handle = SDL_LoadObject(esd_library);
+ if ( esd_handle ) {
+ esd_loaded = 1;
+ retval = 0;
+ for ( i=0; i<SDL_arraysize(esd_functions); ++i ) {
+ *esd_functions[i].func = SDL_LoadFunction(esd_handle, esd_functions[i].name);
+ if ( !*esd_functions[i].func ) {
+ retval = -1;
+ UnloadESDLibrary();
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void UnloadESDLibrary()
+{
+ return;
+}
+
+static int LoadESDLibrary(void)
+{
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int connection;
+ int available;
+
+ available = 0;
+ if ( LoadESDLibrary() < 0 ) {
+ return available;
+ }
+ connection = SDL_NAME(esd_open_sound)(NULL);
+ if ( connection >= 0 ) {
+ available = 1;
+ SDL_NAME(esd_close)(connection);
+ }
+ UnloadESDLibrary();
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+ UnloadESDLibrary();
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ LoadESDLibrary();
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ audio_fd = -1;
+
+ /* Set the function pointers */
+ this->OpenAudio = ESD_OpenAudio;
+ this->WaitAudio = ESD_WaitAudio;
+ this->PlayAudio = ESD_PlayAudio;
+ this->GetAudioBuf = ESD_GetAudioBuf;
+ this->CloseAudio = ESD_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap ESD_bootstrap = {
+ ESD_DRIVER_NAME, "Enlightened Sound Daemon",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void ESD_WaitAudio(_THIS)
+{
+ Sint32 ticks;
+
+ /* Check to see if the thread-parent process is still alive */
+ { static int cnt = 0;
+ /* Note that this only works with thread implementations
+ that use a different process id for each thread.
+ */
+ if (parent && (((++cnt)%10) == 0)) { /* Check every 10 loops */
+ if ( kill(parent, 0) < 0 ) {
+ this->enabled = 0;
+ }
+ }
+ }
+
+ /* Use timer for general audio synchronization */
+ ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
+ if ( ticks > 0 ) {
+ SDL_Delay(ticks);
+ }
+}
+
+static void ESD_PlayAudio(_THIS)
+{
+ int written;
+
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ written = write(audio_fd, mixbuf, mixlen);
+ if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while ( (written < 0) &&
+ ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
+
+ /* Set the next write frame */
+ next_frame += frame_ticks;
+
+ /* If we couldn't write, assume fatal error for now */
+ if ( written < 0 ) {
+ this->enabled = 0;
+ }
+}
+
+static Uint8 *ESD_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void ESD_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( audio_fd >= 0 ) {
+ SDL_NAME(esd_close)(audio_fd);
+ audio_fd = -1;
+ }
+}
+
+/* Try to get the name of the program */
+static char *get_progname(void)
+{
+ char *progname = NULL;
+#ifdef __LINUX__
+ FILE *fp;
+ static char temp[BUFSIZ];
+
+ SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
+ fp = fopen(temp, "r");
+ if ( fp != NULL ) {
+ if ( fgets(temp, sizeof(temp)-1, fp) ) {
+ progname = SDL_strrchr(temp, '/');
+ if ( progname == NULL ) {
+ progname = temp;
+ } else {
+ progname = progname+1;
+ }
+ }
+ fclose(fp);
+ }
+#endif
+ return(progname);
+}
+
+static int ESD_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ esd_format_t format;
+
+ /* Convert audio spec to the ESD audio format */
+ format = (ESD_STREAM | ESD_PLAY);
+ switch ( spec->format & 0xFF ) {
+ case 8:
+ format |= ESD_BITS8;
+ break;
+ case 16:
+ format |= ESD_BITS16;
+ break;
+ default:
+ SDL_SetError("Unsupported ESD audio format");
+ return(-1);
+ }
+ if ( spec->channels == 1 ) {
+ format |= ESD_MONO;
+ } else {
+ format |= ESD_STEREO;
+ }
+#if 0
+ spec->samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
+#endif
+
+ /* Open a connection to the ESD audio server */
+ audio_fd = SDL_NAME(esd_play_stream)(format, spec->freq, NULL, get_progname());
+ if ( audio_fd < 0 ) {
+ SDL_SetError("Couldn't open ESD connection");
+ return(-1);
+ }
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+ frame_ticks = (float)(spec->samples*1000)/spec->freq;
+ next_frame = SDL_GetTicks()+frame_ticks;
+
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+ if ( mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/esd/SDL_esdaudio.h b/src/audio/esd/SDL_esdaudio.h
new file mode 100644
index 0000000..9f8d325
--- /dev/null
+++ b/src/audio/esd/SDL_esdaudio.h
@@ -0,0 +1,57 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_esdaudio_h
+#define _SDL_esdaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+/* Old variable names */
+#define audio_fd (this->hidden->audio_fd)
+#define parent (this->hidden->parent)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+#define frame_ticks (this->hidden->frame_ticks)
+#define next_frame (this->hidden->next_frame)
+
+#endif /* _SDL_esdaudio_h */
diff --git a/src/audio/macosx/SDL_coreaudio.c b/src/audio/macosx/SDL_coreaudio.c
new file mode 100644
index 0000000..5842e90
--- /dev/null
+++ b/src/audio/macosx/SDL_coreaudio.c
@@ -0,0 +1,291 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include <CoreAudio/CoreAudio.h>
+#include <CoreServices/CoreServices.h>
+#include <AudioUnit/AudioUnit.h>
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1050
+#include <AudioUnit/AUNTComponent.h>
+#endif
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_coreaudio.h"
+
+
+/* Audio driver functions */
+
+static int Core_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Core_WaitAudio(_THIS);
+static void Core_PlayAudio(_THIS);
+static Uint8 *Core_GetAudioBuf(_THIS);
+static void Core_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Core_OpenAudio;
+ this->WaitAudio = Core_WaitAudio;
+ this->PlayAudio = Core_PlayAudio;
+ this->GetAudioBuf = Core_GetAudioBuf;
+ this->CloseAudio = Core_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap COREAUDIO_bootstrap = {
+ "coreaudio", "Mac OS X CoreAudio",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* The CoreAudio callback */
+static OSStatus audioCallback (void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *)inRefCon;
+ UInt32 remaining, len;
+ AudioBuffer *abuf;
+ void *ptr;
+ UInt32 i;
+
+ /* Only do anything if audio is enabled and not paused */
+ if ( ! this->enabled || this->paused ) {
+ for (i = 0; i < ioData->mNumberBuffers; i++) {
+ abuf = &ioData->mBuffers[i];
+ SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
+ }
+ return 0;
+ }
+
+ /* No SDL conversion should be needed here, ever, since we accept
+ any input format in OpenAudio, and leave the conversion to CoreAudio.
+ */
+ /*
+ assert(!this->convert.needed);
+ assert(this->spec.channels == ioData->mNumberChannels);
+ */
+
+ for (i = 0; i < ioData->mNumberBuffers; i++) {
+ abuf = &ioData->mBuffers[i];
+ remaining = abuf->mDataByteSize;
+ ptr = abuf->mData;
+ while (remaining > 0) {
+ if (bufferOffset >= bufferSize) {
+ /* Generate the data */
+ SDL_memset(buffer, this->spec.silence, bufferSize);
+ SDL_mutexP(this->mixer_lock);
+ (*this->spec.callback)(this->spec.userdata,
+ buffer, bufferSize);
+ SDL_mutexV(this->mixer_lock);
+ bufferOffset = 0;
+ }
+
+ len = bufferSize - bufferOffset;
+ if (len > remaining)
+ len = remaining;
+ SDL_memcpy(ptr, (char *)buffer + bufferOffset, len);
+ ptr = (char *)ptr + len;
+ remaining -= len;
+ bufferOffset += len;
+ }
+ }
+
+ return 0;
+}
+
+/* Dummy functions -- we don't use thread-based audio */
+void Core_WaitAudio(_THIS)
+{
+ return;
+}
+
+void Core_PlayAudio(_THIS)
+{
+ return;
+}
+
+Uint8 *Core_GetAudioBuf(_THIS)
+{
+ return(NULL);
+}
+
+void Core_CloseAudio(_THIS)
+{
+ OSStatus result;
+ struct AURenderCallbackStruct callback;
+
+ /* stop processing the audio unit */
+ result = AudioOutputUnitStop (outputAudioUnit);
+ if (result != noErr) {
+ SDL_SetError("Core_CloseAudio: AudioOutputUnitStop");
+ return;
+ }
+
+ /* Remove the input callback */
+ callback.inputProc = 0;
+ callback.inputProcRefCon = 0;
+ result = AudioUnitSetProperty (outputAudioUnit,
+ kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Input,
+ 0,
+ &callback,
+ sizeof(callback));
+ if (result != noErr) {
+ SDL_SetError("Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)");
+ return;
+ }
+
+ result = CloseComponent(outputAudioUnit);
+ if (result != noErr) {
+ SDL_SetError("Core_CloseAudio: CloseComponent");
+ return;
+ }
+
+ SDL_free(buffer);
+}
+
+#define CHECK_RESULT(msg) \
+ if (result != noErr) { \
+ SDL_SetError("Failed to start CoreAudio: " msg); \
+ return -1; \
+ }
+
+
+int Core_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ OSStatus result = noErr;
+ Component comp;
+ ComponentDescription desc;
+ struct AURenderCallbackStruct callback;
+ AudioStreamBasicDescription requestedDesc;
+
+ /* Setup a AudioStreamBasicDescription with the requested format */
+ requestedDesc.mFormatID = kAudioFormatLinearPCM;
+ requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
+ requestedDesc.mChannelsPerFrame = spec->channels;
+ requestedDesc.mSampleRate = spec->freq;
+
+ requestedDesc.mBitsPerChannel = spec->format & 0xFF;
+ if (spec->format & 0x8000)
+ requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+ if (spec->format & 0x1000)
+ requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
+
+ requestedDesc.mFramesPerPacket = 1;
+ requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
+ requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
+
+
+ /* Locate the default output audio unit */
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+
+ comp = FindNextComponent (NULL, &desc);
+ if (comp == NULL) {
+ SDL_SetError ("Failed to start CoreAudio: FindNextComponent returned NULL");
+ return -1;
+ }
+
+ /* Open & initialize the default output audio unit */
+ result = OpenAComponent (comp, &outputAudioUnit);
+ CHECK_RESULT("OpenAComponent")
+
+ result = AudioUnitInitialize (outputAudioUnit);
+ CHECK_RESULT("AudioUnitInitialize")
+
+ /* Set the input format of the audio unit. */
+ result = AudioUnitSetProperty (outputAudioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 0,
+ &requestedDesc,
+ sizeof (requestedDesc));
+ CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)")
+
+ /* Set the audio callback */
+ callback.inputProc = audioCallback;
+ callback.inputProcRefCon = this;
+ result = AudioUnitSetProperty (outputAudioUnit,
+ kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Input,
+ 0,
+ &callback,
+ sizeof(callback));
+ CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_SetInputCallback)")
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate a sample buffer */
+ bufferOffset = bufferSize = this->spec.size;
+ buffer = SDL_malloc(bufferSize);
+
+ /* Finally, start processing of the audio unit */
+ result = AudioOutputUnitStart (outputAudioUnit);
+ CHECK_RESULT("AudioOutputUnitStart")
+
+
+ /* We're running! */
+ return(1);
+}
diff --git a/src/audio/macosx/SDL_coreaudio.h b/src/audio/macosx/SDL_coreaudio.h
new file mode 100644
index 0000000..cf74856
--- /dev/null
+++ b/src/audio/macosx/SDL_coreaudio.h
@@ -0,0 +1,45 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_coreaudio_h
+#define _SDL_coreaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ AudioUnit outputAudioUnit;
+ void *buffer;
+ UInt32 bufferOffset;
+ UInt32 bufferSize;
+};
+
+/* Old variable names */
+#define outputAudioUnit (this->hidden->outputAudioUnit)
+#define buffer (this->hidden->buffer)
+#define bufferOffset (this->hidden->bufferOffset)
+#define bufferSize (this->hidden->bufferSize)
+
+#endif /* _SDL_coreaudio_h */
diff --git a/src/audio/macrom/SDL_romaudio.c b/src/audio/macrom/SDL_romaudio.c
new file mode 100644
index 0000000..2a29be2
--- /dev/null
+++ b/src/audio/macrom/SDL_romaudio.c
@@ -0,0 +1,496 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <Carbon/Carbon.h>
+#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
+# include <Carbon.h>
+#else
+# include <Sound.h> /* SoundManager interface */
+# include <Gestalt.h>
+# include <DriverServices.h>
+#endif
+
+#if !defined(NewSndCallBackUPP) && (UNIVERSAL_INTERFACES_VERSION < 0x0335)
+#if !defined(NewSndCallBackProc) /* avoid circular redefinition... */
+#define NewSndCallBackUPP NewSndCallBackProc
+#endif
+#if !defined(NewSndCallBackUPP)
+#define NewSndCallBackUPP NewSndCallBackProc
+#endif
+#endif
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_romaudio.h"
+
+/* Audio driver functions */
+
+static void Mac_CloseAudio(_THIS);
+static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Mac_LockAudio(_THIS);
+static void Mac_UnlockAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+
+static int Audio_Available(void)
+{
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Mac_OpenAudio;
+ this->CloseAudio = Mac_CloseAudio;
+ this->LockAudio = Mac_LockAudio;
+ this->UnlockAudio = Mac_UnlockAudio;
+ this->free = Audio_DeleteDevice;
+
+#ifdef __MACOSX__ /* Mac OS X uses threaded audio, so normal thread code is okay */
+ this->LockAudio = NULL;
+ this->UnlockAudio = NULL;
+#endif
+ return this;
+}
+
+AudioBootStrap SNDMGR_bootstrap = {
+ "sndmgr", "MacOS SoundManager 3.0",
+ Audio_Available, Audio_CreateDevice
+};
+
+#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
+/* This works correctly on Mac OS X */
+
+#pragma options align=power
+
+static volatile SInt32 audio_is_locked = 0;
+static volatile SInt32 need_to_mix = 0;
+
+static UInt8 *buffer[2];
+static volatile UInt32 running = 0;
+static CmpSoundHeader header;
+static volatile Uint32 fill_me = 0;
+
+static void mix_buffer(SDL_AudioDevice *audio, UInt8 *buffer)
+{
+ if ( ! audio->paused ) {
+#ifdef __MACOSX__
+ SDL_mutexP(audio->mixer_lock);
+#endif
+ if ( audio->convert.needed ) {
+ audio->spec.callback(audio->spec.userdata,
+ (Uint8 *)audio->convert.buf,audio->convert.len);
+ SDL_ConvertAudio(&audio->convert);
+ if ( audio->convert.len_cvt != audio->spec.size ) {
+ /* Uh oh... probably crashes here */;
+ }
+ SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
+ } else {
+ audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
+ }
+#ifdef __MACOSX__
+ SDL_mutexV(audio->mixer_lock);
+#endif
+ }
+
+ DecrementAtomic((SInt32 *) &need_to_mix);
+}
+
+static void Mac_LockAudio(_THIS)
+{
+ IncrementAtomic((SInt32 *) &audio_is_locked);
+}
+
+static void Mac_UnlockAudio(_THIS)
+{
+ SInt32 oldval;
+
+ oldval = DecrementAtomic((SInt32 *) &audio_is_locked);
+ if ( oldval != 1 ) /* != 1 means audio is still locked. */
+ return;
+
+ /* Did we miss the chance to mix in an interrupt? Do it now. */
+ if ( BitAndAtomic (0xFFFFFFFF, (UInt32 *) &need_to_mix) ) {
+ /*
+ * Note that this could be a problem if you missed an interrupt
+ * while the audio was locked, and get preempted by a second
+ * interrupt here, but that means you locked for way too long anyhow.
+ */
+ mix_buffer (this, buffer[fill_me]);
+ }
+}
+
+static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) {
+ UInt32 play_me;
+ SndCommand cmd;
+ SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo;
+
+ IncrementAtomic((SInt32 *) &need_to_mix);
+
+ fill_me = cmd_passed->param2; /* buffer that has just finished playing, so fill it */
+ play_me = ! fill_me; /* filled buffer to play _now_ */
+
+ if ( ! audio->enabled ) {
+ return;
+ }
+
+ /* queue previously mixed buffer for playback. */
+ header.samplePtr = (Ptr)buffer[play_me];
+ cmd.cmd = bufferCmd;
+ cmd.param1 = 0;
+ cmd.param2 = (long)&header;
+ SndDoCommand (chan, &cmd, 0);
+
+ memset (buffer[fill_me], 0, audio->spec.size);
+
+ /*
+ * if audio device isn't locked, mix the next buffer to be queued in
+ * the memory block that just finished playing.
+ */
+ if ( ! BitAndAtomic(0xFFFFFFFF, (UInt32 *) &audio_is_locked) ) {
+ mix_buffer (audio, buffer[fill_me]);
+ }
+
+ /* set this callback to run again when current buffer drains. */
+ if ( running ) {
+ cmd.cmd = callBackCmd;
+ cmd.param1 = 0;
+ cmd.param2 = play_me;
+
+ SndDoCommand (chan, &cmd, 0);
+ }
+}
+
+static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
+
+ SndCallBackUPP callback;
+ int sample_bits;
+ int i;
+ long initOptions;
+
+ /* Very few conversions are required, but... */
+ switch (spec->format) {
+ case AUDIO_S8:
+ spec->format = AUDIO_U8;
+ break;
+ case AUDIO_U16LSB:
+ spec->format = AUDIO_S16LSB;
+ break;
+ case AUDIO_U16MSB:
+ spec->format = AUDIO_S16MSB;
+ break;
+ }
+ SDL_CalculateAudioSpec(spec);
+
+ /* initialize bufferCmd header */
+ memset (&header, 0, sizeof(header));
+ callback = (SndCallBackUPP) NewSndCallBackUPP (callBackProc);
+ sample_bits = spec->size / spec->samples / spec->channels * 8;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr,
+ "Audio format 0x%x, channels = %d, sample_bits = %d, frequency = %d\n",
+ spec->format, spec->channels, sample_bits, spec->freq);
+#endif /* DEBUG_AUDIO */
+
+ header.numChannels = spec->channels;
+ header.sampleSize = sample_bits;
+ header.sampleRate = spec->freq << 16;
+ header.numFrames = spec->samples;
+ header.encode = cmpSH;
+
+ /* Note that we install the 16bitLittleEndian Converter if needed. */
+ if ( spec->format == 0x8010 ) {
+ header.compressionID = fixedCompression;
+ header.format = k16BitLittleEndianFormat;
+ }
+
+ /* allocate 2 buffers */
+ for (i=0; i<2; i++) {
+ buffer[i] = (UInt8*)malloc (sizeof(UInt8) * spec->size);
+ if (buffer[i] == NULL) {
+ SDL_OutOfMemory();
+ return (-1);
+ }
+ memset (buffer[i], 0, spec->size);
+ }
+
+ /* Create the sound manager channel */
+ channel = (SndChannelPtr)SDL_malloc(sizeof(*channel));
+ if ( channel == NULL ) {
+ SDL_OutOfMemory();
+ return(-1);
+ }
+ if ( spec->channels >= 2 ) {
+ initOptions = initStereo;
+ } else {
+ initOptions = initMono;
+ }
+ channel->userInfo = (long)this;
+ channel->qLength = 128;
+ if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr ) {
+ SDL_SetError("Unable to create audio channel");
+ SDL_free(channel);
+ channel = NULL;
+ return(-1);
+ }
+
+ /* start playback */
+ {
+ SndCommand cmd;
+ cmd.cmd = callBackCmd;
+ cmd.param2 = 0;
+ running = 1;
+ SndDoCommand (channel, &cmd, 0);
+ }
+
+ return 1;
+}
+
+static void Mac_CloseAudio(_THIS) {
+
+ int i;
+
+ running = 0;
+
+ if (channel) {
+ SndDisposeChannel (channel, true);
+ channel = NULL;
+ }
+
+ for ( i=0; i<2; ++i ) {
+ if ( buffer[i] ) {
+ SDL_free(buffer[i]);
+ buffer[i] = NULL;
+ }
+ }
+}
+
+#else /* !TARGET_API_MAC_CARBON && !USE_RYANS_SOUNDCODE */
+
+static void Mac_LockAudio(_THIS)
+{
+ /* no-op. */
+}
+
+static void Mac_UnlockAudio(_THIS)
+{
+ /* no-op. */
+}
+
+
+/* This function is called by Sound Manager when it has exhausted one of
+ the buffers, so we'll zero it to silence and fill it with audio if
+ we're not paused.
+*/
+static pascal
+void sndDoubleBackProc (SndChannelPtr chan, SndDoubleBufferPtr newbuf)
+{
+ SDL_AudioDevice *audio = (SDL_AudioDevice *)newbuf->dbUserInfo[0];
+
+ /* If audio is quitting, don't do anything */
+ if ( ! audio->enabled ) {
+ return;
+ }
+ memset (newbuf->dbSoundData, 0, audio->spec.size);
+ newbuf->dbNumFrames = audio->spec.samples;
+ if ( ! audio->paused ) {
+ if ( audio->convert.needed ) {
+ audio->spec.callback(audio->spec.userdata,
+ (Uint8 *)audio->convert.buf,audio->convert.len);
+ SDL_ConvertAudio(&audio->convert);
+#if 0
+ if ( audio->convert.len_cvt != audio->spec.size ) {
+ /* Uh oh... probably crashes here */;
+ }
+#endif
+ SDL_memcpy(newbuf->dbSoundData, audio->convert.buf,
+ audio->convert.len_cvt);
+ } else {
+ audio->spec.callback(audio->spec.userdata,
+ (Uint8 *)newbuf->dbSoundData, audio->spec.size);
+ }
+ }
+ newbuf->dbFlags |= dbBufferReady;
+}
+
+static int DoubleBufferAudio_Available(void)
+{
+ int available;
+ NumVersion sndversion;
+ long response;
+
+ available = 0;
+ sndversion = SndSoundManagerVersion();
+ if ( sndversion.majorRev >= 3 ) {
+ if ( Gestalt(gestaltSoundAttr, &response) == noErr ) {
+ if ( (response & (1 << gestaltSndPlayDoubleBuffer)) ) {
+ available = 1;
+ }
+ }
+ } else {
+ if ( Gestalt(gestaltSoundAttr, &response) == noErr ) {
+ if ( (response & (1 << gestaltHasASC)) ) {
+ available = 1;
+ }
+ }
+ }
+ return(available);
+}
+
+static void Mac_CloseAudio(_THIS)
+{
+ int i;
+
+ if ( channel != NULL ) {
+ /* Clean up the audio channel */
+ SndDisposeChannel(channel, true);
+ channel = NULL;
+ }
+ for ( i=0; i<2; ++i ) {
+ if ( audio_buf[i] ) {
+ SDL_free(audio_buf[i]);
+ audio_buf[i] = NULL;
+ }
+ }
+}
+
+static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ SndDoubleBufferHeader2 audio_dbh;
+ int i;
+ long initOptions;
+ int sample_bits;
+ SndDoubleBackUPP doubleBackProc;
+
+ /* Check to make sure double-buffered audio is available */
+ if ( ! DoubleBufferAudio_Available() ) {
+ SDL_SetError("Sound manager doesn't support double-buffering");
+ return(-1);
+ }
+
+ /* Very few conversions are required, but... */
+ switch (spec->format) {
+ case AUDIO_S8:
+ spec->format = AUDIO_U8;
+ break;
+ case AUDIO_U16LSB:
+ spec->format = AUDIO_S16LSB;
+ break;
+ case AUDIO_U16MSB:
+ spec->format = AUDIO_S16MSB;
+ break;
+ }
+ SDL_CalculateAudioSpec(spec);
+
+ /* initialize the double-back header */
+ SDL_memset(&audio_dbh, 0, sizeof(audio_dbh));
+ doubleBackProc = NewSndDoubleBackProc (sndDoubleBackProc);
+ sample_bits = spec->size / spec->samples / spec->channels * 8;
+
+ audio_dbh.dbhNumChannels = spec->channels;
+ audio_dbh.dbhSampleSize = sample_bits;
+ audio_dbh.dbhCompressionID = 0;
+ audio_dbh.dbhPacketSize = 0;
+ audio_dbh.dbhSampleRate = spec->freq << 16;
+ audio_dbh.dbhDoubleBack = doubleBackProc;
+ audio_dbh.dbhFormat = 0;
+
+ /* Note that we install the 16bitLittleEndian Converter if needed. */
+ if ( spec->format == 0x8010 ) {
+ audio_dbh.dbhCompressionID = fixedCompression;
+ audio_dbh.dbhFormat = k16BitLittleEndianFormat;
+ }
+
+ /* allocate the 2 double-back buffers */
+ for ( i=0; i<2; ++i ) {
+ audio_buf[i] = SDL_calloc(1, sizeof(SndDoubleBuffer)+spec->size);
+ if ( audio_buf[i] == NULL ) {
+ SDL_OutOfMemory();
+ return(-1);
+ }
+ audio_buf[i]->dbNumFrames = spec->samples;
+ audio_buf[i]->dbFlags = dbBufferReady;
+ audio_buf[i]->dbUserInfo[0] = (long)this;
+ audio_dbh.dbhBufferPtr[i] = audio_buf[i];
+ }
+
+ /* Create the sound manager channel */
+ channel = (SndChannelPtr)SDL_malloc(sizeof(*channel));
+ if ( channel == NULL ) {
+ SDL_OutOfMemory();
+ return(-1);
+ }
+ if ( spec->channels >= 2 ) {
+ initOptions = initStereo;
+ } else {
+ initOptions = initMono;
+ }
+ channel->userInfo = 0;
+ channel->qLength = 128;
+ if ( SndNewChannel(&channel, sampledSynth, initOptions, 0L) != noErr ) {
+ SDL_SetError("Unable to create audio channel");
+ SDL_free(channel);
+ channel = NULL;
+ return(-1);
+ }
+
+ /* Start playback */
+ if ( SndPlayDoubleBuffer(channel, (SndDoubleBufferHeaderPtr)&audio_dbh)
+ != noErr ) {
+ SDL_SetError("Unable to play double buffered audio");
+ return(-1);
+ }
+
+ return 1;
+}
+
+#endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */
+
diff --git a/src/audio/macrom/SDL_romaudio.h b/src/audio/macrom/SDL_romaudio.h
new file mode 100644
index 0000000..2a892f4
--- /dev/null
+++ b/src/audio/macrom/SDL_romaudio.h
@@ -0,0 +1,50 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_romaudio_h
+#define _SDL_romaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* This is Ryan's improved MacOS sound code, with locking support */
+#define USE_RYANS_SOUNDCODE
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* Sound manager audio channel */
+ SndChannelPtr channel;
+#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
+ /* FIXME: Add Ryan's static data here */
+#else
+ /* Double buffering variables */
+ SndDoubleBufferPtr audio_buf[2];
+#endif
+};
+
+/* Old variable names */
+#define channel (this->hidden->channel)
+#define audio_buf (this->hidden->audio_buf)
+
+#endif /* _SDL_romaudio_h */
diff --git a/src/audio/mint/SDL_mintaudio.c b/src/audio/mint/SDL_mintaudio.c
new file mode 100644
index 0000000..221c8eb
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio.c
@@ -0,0 +1,215 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ Audio interrupt variables and callback function
+
+ Patrice Mandin
+*/
+
+#include <unistd.h>
+
+#include <mint/osbind.h>
+#include <mint/falcon.h>
+#include <mint/mintbind.h>
+#include <mint/cookie.h>
+
+#include "SDL_audio.h"
+#include "SDL_mintaudio.h"
+#include "SDL_mintaudio_stfa.h"
+
+/* The audio device */
+
+SDL_AudioDevice *SDL_MintAudio_device;
+Uint8 *SDL_MintAudio_audiobuf[2]; /* Pointers to buffers */
+unsigned long SDL_MintAudio_audiosize; /* Length of audio buffer=spec->size */
+volatile unsigned short SDL_MintAudio_numbuf; /* Buffer to play */
+volatile unsigned short SDL_MintAudio_mutex;
+volatile unsigned long SDL_MintAudio_clocktics;
+cookie_stfa_t *SDL_MintAudio_stfa;
+unsigned short SDL_MintAudio_hasfpu;
+
+/* MiNT thread variables */
+SDL_bool SDL_MintAudio_mint_present;
+SDL_bool SDL_MintAudio_quit_thread;
+SDL_bool SDL_MintAudio_thread_finished;
+long SDL_MintAudio_thread_pid;
+
+/* The callback function, called by each driver whenever needed */
+
+void SDL_MintAudio_Callback(void)
+{
+ Uint8 *buffer;
+ SDL_AudioDevice *audio = SDL_MintAudio_device;
+
+ buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+ SDL_memset(buffer, audio->spec.silence, audio->spec.size);
+
+ if (audio->paused)
+ return;
+
+ if (audio->convert.needed) {
+ int silence;
+
+ if ( audio->convert.src_format == AUDIO_U8 ) {
+ silence = 0x80;
+ } else {
+ silence = 0;
+ }
+ SDL_memset(audio->convert.buf, silence, audio->convert.len);
+ audio->spec.callback(audio->spec.userdata,
+ (Uint8 *)audio->convert.buf,audio->convert.len);
+ SDL_ConvertAudio(&audio->convert);
+ SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
+ } else {
+ audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
+ }
+}
+
+/* Add a new frequency/clock/predivisor to the current list */
+void SDL_MintAudio_AddFrequency(_THIS, Uint32 frequency, Uint32 clock,
+ Uint32 prediv, int gpio_bits)
+{
+ int i, p;
+
+ if (MINTAUDIO_freqcount==MINTAUDIO_maxfreqs) {
+ return;
+ }
+
+ /* Search where to insert the frequency (highest first) */
+ for (p=0; p<MINTAUDIO_freqcount; p++) {
+ if (frequency > MINTAUDIO_frequencies[p].frequency) {
+ break;
+ }
+ }
+
+ /* Put all following ones farer */
+ if (MINTAUDIO_freqcount>0) {
+ for (i=MINTAUDIO_freqcount; i>p; i--) {
+ SDL_memcpy(&MINTAUDIO_frequencies[i], &MINTAUDIO_frequencies[i-1], sizeof(mint_frequency_t));
+ }
+ }
+
+ /* And insert new one */
+ MINTAUDIO_frequencies[p].frequency = frequency;
+ MINTAUDIO_frequencies[p].masterclock = clock;
+ MINTAUDIO_frequencies[p].predivisor = prediv;
+ MINTAUDIO_frequencies[p].gpio_bits = gpio_bits;
+
+ MINTAUDIO_freqcount++;
+}
+
+/* Search for the nearest frequency */
+int SDL_MintAudio_SearchFrequency(_THIS, int desired_freq)
+{
+ int i;
+
+ /* Only 1 freq ? */
+ if (MINTAUDIO_freqcount==1) {
+ return 0;
+ }
+
+ /* Check the array */
+ for (i=0; i<MINTAUDIO_freqcount; i++) {
+ if (desired_freq >= ((MINTAUDIO_frequencies[i].frequency+
+ MINTAUDIO_frequencies[i+1].frequency)>>1)) {
+ return i;
+ }
+ }
+
+ /* Not in the array, give the latest */
+ return MINTAUDIO_freqcount-1;
+}
+
+/* Check if FPU is present */
+void SDL_MintAudio_CheckFpu(void)
+{
+ unsigned long cookie_fpu;
+
+ SDL_MintAudio_hasfpu = 0;
+ if (Getcookie(C__FPU, &cookie_fpu) != C_FOUND) {
+ return;
+ }
+ switch ((cookie_fpu>>16)&0xfffe) {
+ case 2:
+ case 4:
+ case 6:
+ case 8:
+ case 16:
+ SDL_MintAudio_hasfpu = 1;
+ break;
+ }
+}
+
+/* The thread function, used under MiNT with xbios */
+int SDL_MintAudio_Thread(long param)
+{
+ SndBufPtr pointers;
+ SDL_bool buffers_filled[2] = {SDL_FALSE, SDL_FALSE};
+
+ SDL_MintAudio_thread_finished = SDL_FALSE;
+ while (!SDL_MintAudio_quit_thread) {
+ if (Buffptr(&pointers)!=0)
+ continue;
+
+ if (( (unsigned long)pointers.play>=(unsigned long)SDL_MintAudio_audiobuf[0])
+ && ( (unsigned long)pointers.play<=(unsigned long)SDL_MintAudio_audiobuf[1]))
+ {
+ /* DMA is reading buffer #0, setup buffer #1 if not already done */
+ if (!buffers_filled[1]) {
+ SDL_MintAudio_numbuf = 1;
+ SDL_MintAudio_Callback();
+ Setbuffer(0, SDL_MintAudio_audiobuf[1], SDL_MintAudio_audiobuf[1] + SDL_MintAudio_audiosize);
+ buffers_filled[1]=SDL_TRUE;
+ buffers_filled[0]=SDL_FALSE;
+ }
+ } else {
+ /* DMA is reading buffer #1, setup buffer #0 if not already done */
+ if (!buffers_filled[0]) {
+ SDL_MintAudio_numbuf = 0;
+ SDL_MintAudio_Callback();
+ Setbuffer(0, SDL_MintAudio_audiobuf[0], SDL_MintAudio_audiobuf[0] + SDL_MintAudio_audiosize);
+ buffers_filled[0]=SDL_TRUE;
+ buffers_filled[1]=SDL_FALSE;
+ }
+ }
+
+ usleep(100);
+ }
+ SDL_MintAudio_thread_finished = SDL_TRUE;
+ return 0;
+}
+
+void SDL_MintAudio_WaitThread(void)
+{
+ if (!SDL_MintAudio_mint_present)
+ return;
+
+ if (SDL_MintAudio_thread_finished)
+ return;
+
+ SDL_MintAudio_quit_thread = SDL_TRUE;
+ while (!SDL_MintAudio_thread_finished) {
+ Syield();
+ }
+}
diff --git a/src/audio/mint/SDL_mintaudio.h b/src/audio/mint/SDL_mintaudio.h
new file mode 100644
index 0000000..859e7ba
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio.h
@@ -0,0 +1,157 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MiNT audio driver
+
+ Patrice Mandin
+*/
+
+#ifndef _SDL_mintaudio_h
+#define _SDL_mintaudio_h
+
+#include "../SDL_sysaudio.h"
+#include "SDL_mintaudio_stfa.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+/* 16 predivisors with 3 clocks max. */
+#define MINTAUDIO_maxfreqs (16*3)
+
+typedef struct {
+ Uint32 frequency;
+ Uint32 masterclock;
+ Uint32 predivisor;
+ int gpio_bits; /* in case of external clock */
+} mint_frequency_t;
+
+struct SDL_PrivateAudioData {
+ mint_frequency_t frequencies[MINTAUDIO_maxfreqs];
+ int freq_count; /* Number of frequencies in the array */
+ int numfreq; /* Number of selected frequency */
+};
+
+/* Old variable names */
+
+#define MINTAUDIO_frequencies (this->hidden->frequencies)
+#define MINTAUDIO_freqcount (this->hidden->freq_count)
+#define MINTAUDIO_numfreq (this->hidden->numfreq)
+
+/* _MCH cookie (values>>16) */
+enum {
+ MCH_ST=0,
+ MCH_STE,
+ MCH_TT,
+ MCH_F30,
+ MCH_CLONE,
+ MCH_ARANYM
+};
+
+/* Master clocks for replay frequencies */
+#define MASTERCLOCK_STE 8010666 /* Not sure of this one */
+#define MASTERCLOCK_TT 16107953 /* Not sure of this one */
+#define MASTERCLOCK_FALCON1 25175000
+#define MASTERCLOCK_FALCON2 32000000 /* Only usable for DSP56K */
+#define MASTERCLOCK_FALCONEXT -1 /* Clock on DSP56K port, unknown */
+#define MASTERCLOCK_44K 22579200 /* Standard clock for 44.1 Khz */
+#define MASTERCLOCK_48K 24576000 /* Standard clock for 48 Khz */
+
+/* Master clock predivisors */
+#define MASTERPREDIV_STE 160
+#define MASTERPREDIV_TT 320
+#define MASTERPREDIV_FALCON 256
+#define MASTERPREDIV_MILAN 256
+
+/* MFP 68901 interrupt sources */
+#ifndef MFP_PARALLEL
+enum {
+ MFP_PARALLEL=0,
+ MFP_DCD,
+ MFP_CTS,
+ MFP_BITBLT,
+ MFP_TIMERD,
+ MFP_BAUDRATE=MFP_TIMERD,
+ MFP_TIMERC,
+ MFP_200HZ=MFP_TIMERC,
+ MFP_ACIA,
+ MFP_DISK,
+ MFP_TIMERB,
+ MFP_HBLANK=MFP_TIMERB,
+ MFP_TERR,
+ MFP_TBE,
+ MFP_RERR,
+ MFP_RBF,
+ MFP_TIMERA,
+ MFP_DMASOUND=MFP_TIMERA,
+ MFP_RING,
+ MFP_MONODETECT
+};
+#endif
+
+/* Xbtimer() timers */
+#ifndef XB_TIMERA
+enum {
+ XB_TIMERA=0,
+ XB_TIMERB,
+ XB_TIMERC,
+ XB_TIMERD
+};
+#endif
+
+/* Variables */
+extern SDL_AudioDevice *SDL_MintAudio_device;
+extern Uint8 *SDL_MintAudio_audiobuf[2]; /* Pointers to buffers */
+extern unsigned long SDL_MintAudio_audiosize; /* Length of audio buffer=spec->size */
+extern volatile unsigned short SDL_MintAudio_numbuf; /* Buffer to play */
+extern volatile unsigned short SDL_MintAudio_mutex;
+extern cookie_stfa_t *SDL_MintAudio_stfa;
+extern volatile unsigned long SDL_MintAudio_clocktics;
+extern unsigned short SDL_MintAudio_hasfpu; /* To preserve fpu registers if needed */
+
+/* MiNT thread variables */
+extern SDL_bool SDL_MintAudio_mint_present;
+extern SDL_bool SDL_MintAudio_quit_thread;
+extern SDL_bool SDL_MintAudio_thread_finished;
+extern long SDL_MintAudio_thread_pid;
+
+/* Functions */
+void SDL_MintAudio_Callback(void);
+void SDL_MintAudio_AddFrequency(_THIS, Uint32 frequency, Uint32 clock,
+ Uint32 prediv, int gpio_bits);
+int SDL_MintAudio_SearchFrequency(_THIS, int desired_freq);
+void SDL_MintAudio_CheckFpu(void);
+
+/* MiNT thread functions */
+int SDL_MintAudio_Thread(long param);
+void SDL_MintAudio_WaitThread(void);
+
+/* ASM interrupt functions */
+void SDL_MintAudio_GsxbInterrupt(void);
+void SDL_MintAudio_EmptyGsxbInterrupt(void);
+void SDL_MintAudio_XbiosInterruptMeasureClock(void);
+void SDL_MintAudio_XbiosInterrupt(void);
+void SDL_MintAudio_Dma8Interrupt(void);
+void SDL_MintAudio_StfaInterrupt(void);
+
+#endif /* _SDL_mintaudio_h */
diff --git a/src/audio/mint/SDL_mintaudio_dma8.c b/src/audio/mint/SDL_mintaudio_dma8.c
new file mode 100644
index 0000000..94be6a5
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_dma8.c
@@ -0,0 +1,361 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MiNT audio driver
+ using DMA 8bits (hardware access)
+
+ Patrice Mandin
+*/
+
+/* Mint includes */
+#include <mint/osbind.h>
+#include <mint/falcon.h>
+#include <mint/cookie.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+
+#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
+
+#include "SDL_mintaudio.h"
+#include "SDL_mintaudio_dma8.h"
+
+/*--- Defines ---*/
+
+#define MINT_AUDIO_DRIVER_NAME "mint_dma8"
+
+/* Debug print info */
+#define DEBUG_NAME "audio:dma8: "
+#if 0
+#define DEBUG_PRINT(what) \
+ { \
+ printf what; \
+ }
+#else
+#define DEBUG_PRINT(what)
+#endif
+
+/*--- Static variables ---*/
+
+static unsigned long cookie_snd, cookie_mch;
+
+/*--- Audio driver functions ---*/
+
+static void Mint_CloseAudio(_THIS);
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_LockAudio(_THIS);
+static void Mint_UnlockAudio(_THIS);
+
+/* To check/init hardware audio */
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
+
+/*--- Audio driver bootstrap functions ---*/
+
+static int Audio_Available(void)
+{
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+
+ /* Check if user asked a different audio driver */
+ if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
+ DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
+ return 0;
+ }
+
+ /* Cookie _MCH present ? if not, assume ST machine */
+ if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
+ cookie_mch = MCH_ST;
+ }
+
+ /* Cookie _SND present ? if not, assume ST machine */
+ if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
+ cookie_snd = SND_PSG;
+ }
+
+ /* Check if we have 8 bits audio */
+ if ((cookie_snd & SND_8BIT)==0) {
+ DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n"));
+ return(0);
+ }
+
+ /* Check if audio is lockable */
+ if (cookie_snd & SND_16BIT) {
+ if (Locksnd()!=1) {
+ DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
+ return(0);
+ }
+
+ Unlocksnd();
+ }
+
+ DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Mint_OpenAudio;
+ this->CloseAudio = Mint_CloseAudio;
+ this->LockAudio = Mint_LockAudio;
+ this->UnlockAudio = Mint_UnlockAudio;
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
+ MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void Mint_LockAudio(_THIS)
+{
+ void *oldpile;
+
+ /* Stop replay */
+ oldpile=(void *)Super(0);
+ DMAAUDIO_IO.control=0;
+ Super(oldpile);
+}
+
+static void Mint_UnlockAudio(_THIS)
+{
+ void *oldpile;
+
+ /* Restart replay */
+ oldpile=(void *)Super(0);
+ DMAAUDIO_IO.control=3;
+ Super(oldpile);
+}
+
+static void Mint_CloseAudio(_THIS)
+{
+ void *oldpile;
+
+ /* Stop replay */
+ oldpile=(void *)Super(0);
+ DMAAUDIO_IO.control=0;
+ Super(oldpile);
+
+ DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
+
+ /* Disable interrupt */
+ Jdisint(MFP_DMASOUND);
+
+ DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
+
+ /* Wait if currently playing sound */
+ while (SDL_MintAudio_mutex != 0) {
+ }
+
+ DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
+
+ /* Clear buffers */
+ if (SDL_MintAudio_audiobuf[0]) {
+ Mfree(SDL_MintAudio_audiobuf[0]);
+ SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
+ }
+
+ DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
+}
+
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int i, masterprediv, sfreq;
+ unsigned long masterclock;
+
+ DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ if (spec->channels > 2)
+ spec->channels = 2;
+
+ /* Check formats available */
+ spec->format = AUDIO_S8;
+
+ /* Calculate and select the closest frequency */
+ sfreq=0;
+ masterclock=MASTERCLOCK_STE;
+ masterprediv=MASTERPREDIV_STE;
+ switch(cookie_mch>>16) {
+/*
+ case MCH_STE:
+ masterclock=MASTERCLOCK_STE;
+ masterprediv=MASTERPREDIV_STE;
+ break;
+*/
+ case MCH_TT:
+ masterclock=MASTERCLOCK_TT;
+ masterprediv=MASTERPREDIV_TT;
+ break;
+ case MCH_F30:
+ case MCH_ARANYM:
+ masterclock=MASTERCLOCK_FALCON1;
+ masterprediv=MASTERPREDIV_FALCON;
+ sfreq=1;
+ break;
+ }
+
+ MINTAUDIO_freqcount=0;
+ for (i=sfreq;i<4;i++) {
+ SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)),
+ masterclock, i-sfreq, -1);
+ }
+
+#if 1
+ for (i=0; i<MINTAUDIO_freqcount; i++) {
+ DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
+ i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
+ MINTAUDIO_frequencies[i].predivisor
+ ));
+ }
+#endif
+
+ MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
+ spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
+
+ DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ return 0;
+}
+
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
+{
+ void *oldpile;
+ unsigned long buffer;
+ unsigned char mode;
+
+ /* Set replay tracks */
+ if (cookie_snd & SND_16BIT) {
+ Settracks(0,0);
+ Setmontracks(0);
+ }
+
+ oldpile=(void *)Super(0);
+
+ /* Stop currently playing sound */
+ DMAAUDIO_IO.control=0;
+
+ /* Set buffer */
+ buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+ DMAAUDIO_IO.start_high = (buffer>>16) & 255;
+ DMAAUDIO_IO.start_mid = (buffer>>8) & 255;
+ DMAAUDIO_IO.start_low = buffer & 255;
+
+ buffer += SDL_MintAudio_audiosize;
+ DMAAUDIO_IO.end_high = (buffer>>16) & 255;
+ DMAAUDIO_IO.end_mid = (buffer>>8) & 255;
+ DMAAUDIO_IO.end_low = buffer & 255;
+
+ mode = 3-MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
+ if (spec->channels==1) {
+ mode |= 1<<7;
+ }
+ DMAAUDIO_IO.sound_ctrl = mode;
+
+ /* Set interrupt */
+ Jdisint(MFP_DMASOUND);
+ Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
+ Jenabint(MFP_DMASOUND);
+
+ if (cookie_snd & SND_16BIT) {
+ if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
+ }
+ }
+
+ /* Go */
+ DMAAUDIO_IO.control = 3; /* playback + repeat */
+
+ Super(oldpile);
+}
+
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ SDL_MintAudio_device = this;
+
+ /* Check audio capabilities */
+ if (Mint_CheckAudio(this, spec)==-1) {
+ return -1;
+ }
+
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate memory for audio buffers in DMA-able RAM */
+ DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
+
+ SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
+ if (SDL_MintAudio_audiobuf[0]==NULL) {
+ SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
+ return (-1);
+ }
+ SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
+ SDL_MintAudio_numbuf=0;
+ SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
+ SDL_MintAudio_audiosize = spec->size;
+ SDL_MintAudio_mutex = 0;
+
+ DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
+ DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
+
+ SDL_MintAudio_CheckFpu();
+
+ /* Setup audio hardware */
+ Mint_InitAudio(this, spec);
+
+ return(1); /* We don't use threaded audio */
+}
diff --git a/src/audio/mint/SDL_mintaudio_dma8.h b/src/audio/mint/SDL_mintaudio_dma8.h
new file mode 100644
index 0000000..9ae010b
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_dma8.h
@@ -0,0 +1,85 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ DMA 8bits and Falcon Codec audio definitions
+
+ Patrice Mandin, Didier Méquignon
+*/
+
+#ifndef _SDL_mintaudio_dma8_h
+#define _SDL_mintaudio_dma8_h
+
+#define DMAAUDIO_IO_BASE (0xffff8900)
+struct DMAAUDIO_IO_S {
+ unsigned char int_ctrl;
+ unsigned char control;
+
+ unsigned char dummy1;
+ unsigned char start_high;
+ unsigned char dummy2;
+ unsigned char start_mid;
+ unsigned char dummy3;
+ unsigned char start_low;
+
+ unsigned char dummy4;
+ unsigned char cur_high;
+ unsigned char dummy5;
+ unsigned char cur_mid;
+ unsigned char dummy6;
+ unsigned char cur_low;
+
+ unsigned char dummy7;
+ unsigned char end_high;
+ unsigned char dummy8;
+ unsigned char end_mid;
+ unsigned char dummy9;
+ unsigned char end_low;
+
+ unsigned char dummy10[12];
+
+ unsigned char track_ctrl; /* CODEC only */
+ unsigned char sound_ctrl;
+ unsigned short sound_data;
+ unsigned short sound_mask;
+
+ unsigned char dummy11[10];
+
+ unsigned short dev_ctrl;
+ unsigned short dest_ctrl;
+ unsigned short sync_div;
+ unsigned char track_rec;
+ unsigned char adderin_input;
+ unsigned char channel_input;
+ unsigned char channel_amplification;
+ unsigned char channel_reduction;
+
+ unsigned char dummy12[6];
+
+ unsigned char data_direction;
+ unsigned char dummy13;
+ unsigned char dev_data;
+};
+#define DMAAUDIO_IO ((*(volatile struct DMAAUDIO_IO_S *)DMAAUDIO_IO_BASE))
+
+#endif /* _SDL_mintaudio_dma8_h */
diff --git a/src/audio/mint/SDL_mintaudio_gsxb.c b/src/audio/mint/SDL_mintaudio_gsxb.c
new file mode 100644
index 0000000..58ddc9f
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_gsxb.c
@@ -0,0 +1,436 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MiNT audio driver
+ using XBIOS functions (GSXB compatible driver)
+
+ Patrice Mandin
+*/
+
+/* Mint includes */
+#include <mint/osbind.h>
+#include <mint/falcon.h>
+#include <mint/cookie.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+
+#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
+
+#include "SDL_mintaudio.h"
+#include "SDL_mintaudio_gsxb.h"
+
+/*--- Defines ---*/
+
+#define MINT_AUDIO_DRIVER_NAME "mint_gsxb"
+
+/* Debug print info */
+#define DEBUG_NAME "audio:gsxb: "
+#if 0
+#define DEBUG_PRINT(what) \
+ { \
+ printf what; \
+ }
+#else
+#define DEBUG_PRINT(what)
+#endif
+
+/*--- Static variables ---*/
+
+static unsigned long cookie_snd, cookie_gsxb;
+
+/*--- Audio driver functions ---*/
+
+static void Mint_CloseAudio(_THIS);
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_LockAudio(_THIS);
+static void Mint_UnlockAudio(_THIS);
+
+/* To check/init hardware audio */
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
+
+/* GSXB callbacks */
+static void Mint_GsxbInterrupt(void);
+static void Mint_GsxbNullInterrupt(void);
+
+/*--- Audio driver bootstrap functions ---*/
+
+static int Audio_Available(void)
+{
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+
+ /* Check if user asked a different audio driver */
+ if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
+ DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
+ return(0);
+ }
+
+ /* Cookie _SND present ? if not, assume ST machine */
+ if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
+ cookie_snd = SND_PSG;
+ }
+
+ /* Check if we have 16 bits audio */
+ if ((cookie_snd & SND_16BIT)==0) {
+ DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
+ return(0);
+ }
+
+ /* Cookie GSXB present ? */
+ cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
+
+ /* Is it GSXB ? */
+ if (((cookie_snd & SND_GSXB)==0) || (cookie_gsxb==0)) {
+ DEBUG_PRINT((DEBUG_NAME "no GSXB audio\n"));
+ return(0);
+ }
+
+ /* Check if audio is lockable */
+ if (Locksnd()!=1) {
+ DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
+ return(0);
+ }
+
+ Unlocksnd();
+
+ DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Mint_OpenAudio;
+ this->CloseAudio = Mint_CloseAudio;
+ this->LockAudio = Mint_LockAudio;
+ this->UnlockAudio = Mint_UnlockAudio;
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
+ MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void Mint_LockAudio(_THIS)
+{
+ /* Stop replay */
+ Buffoper(0);
+}
+
+static void Mint_UnlockAudio(_THIS)
+{
+ /* Restart replay */
+ Buffoper(SB_PLA_ENA|SB_PLA_RPT);
+}
+
+static void Mint_CloseAudio(_THIS)
+{
+ /* Stop replay */
+ Buffoper(0);
+
+ /* Uninstall interrupt */
+ if (NSetinterrupt(2, SI_NONE, Mint_GsxbNullInterrupt)<0) {
+ DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
+ }
+
+ /* Wait if currently playing sound */
+ while (SDL_MintAudio_mutex != 0) {
+ }
+
+ /* Clear buffers */
+ if (SDL_MintAudio_audiobuf[0]) {
+ Mfree(SDL_MintAudio_audiobuf[0]);
+ SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
+ }
+
+ /* Unlock sound system */
+ Unlocksnd();
+}
+
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
+{
+ long snd_format;
+ int i, resolution, format_signed, format_bigendian;
+ Uint16 test_format = SDL_FirstAudioFormat(spec->format);
+ int valid_datatype = 0;
+
+ resolution = spec->format & 0x00ff;
+ format_signed = ((spec->format & 0x8000)!=0);
+ format_bigendian = ((spec->format & 0x1000)!=0);
+
+ DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ if (spec->channels > 2) {
+ spec->channels = 2; /* no more than stereo! */
+ }
+
+ while ((!valid_datatype) && (test_format)) {
+ /* Check formats available */
+ snd_format = Sndstatus(SND_QUERYFORMATS);
+ spec->format = test_format;
+ resolution = spec->format & 0xff;
+ format_signed = (spec->format & (1<<15));
+ format_bigendian = (spec->format & (1<<12));
+ switch (test_format) {
+ case AUDIO_U8:
+ case AUDIO_S8:
+ if (snd_format & SND_FORMAT8) {
+ valid_datatype = 1;
+ snd_format = Sndstatus(SND_QUERY8BIT);
+ }
+ break;
+
+ case AUDIO_U16LSB:
+ case AUDIO_S16LSB:
+ case AUDIO_U16MSB:
+ case AUDIO_S16MSB:
+ if (snd_format & SND_FORMAT16) {
+ valid_datatype = 1;
+ snd_format = Sndstatus(SND_QUERY16BIT);
+ }
+ break;
+
+ default:
+ test_format = SDL_NextAudioFormat();
+ break;
+ }
+ }
+
+ if (!valid_datatype) {
+ SDL_SetError("Unsupported audio format");
+ return (-1);
+ }
+
+ /* Check signed/unsigned format */
+ if (format_signed) {
+ if (snd_format & SND_FORMATSIGNED) {
+ /* Ok */
+ } else if (snd_format & SND_FORMATUNSIGNED) {
+ /* Give unsigned format */
+ spec->format = spec->format & (~0x8000);
+ }
+ } else {
+ if (snd_format & SND_FORMATUNSIGNED) {
+ /* Ok */
+ } else if (snd_format & SND_FORMATSIGNED) {
+ /* Give signed format */
+ spec->format |= 0x8000;
+ }
+ }
+
+ if (format_bigendian) {
+ if (snd_format & SND_FORMATBIGENDIAN) {
+ /* Ok */
+ } else if (snd_format & SND_FORMATLITTLEENDIAN) {
+ /* Give little endian format */
+ spec->format = spec->format & (~0x1000);
+ }
+ } else {
+ if (snd_format & SND_FORMATLITTLEENDIAN) {
+ /* Ok */
+ } else if (snd_format & SND_FORMATBIGENDIAN) {
+ /* Give big endian format */
+ spec->format |= 0x1000;
+ }
+ }
+
+ /* Calculate and select the closest frequency */
+ MINTAUDIO_freqcount=0;
+ for (i=1;i<4;i++) {
+ SDL_MintAudio_AddFrequency(this,
+ MASTERCLOCK_44K/(MASTERPREDIV_MILAN*(1<<i)), MASTERCLOCK_44K,
+ (1<<i)-1, -1);
+ }
+
+#if 1
+ for (i=0; i<MINTAUDIO_freqcount; i++) {
+ DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
+ i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
+ MINTAUDIO_frequencies[i].predivisor
+ ));
+ }
+#endif
+
+ MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
+ spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
+
+ DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ return 0;
+}
+
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int channels_mode, prediv;
+ void *buffer;
+
+ /* Stop currently playing sound */
+ Buffoper(0);
+
+ /* Set replay tracks */
+ Settracks(0,0);
+ Setmontracks(0);
+
+ /* Select replay format */
+ switch (spec->format & 0xff) {
+ case 8:
+ if (spec->channels==2) {
+ channels_mode=STEREO8;
+ } else {
+ channels_mode=MONO8;
+ }
+ break;
+ case 16:
+ if (spec->channels==2) {
+ channels_mode=STEREO16;
+ } else {
+ channels_mode=MONO16;
+ }
+ break;
+ default:
+ channels_mode=STEREO16;
+ break;
+ }
+ if (Setmode(channels_mode)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
+ }
+
+ prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
+ Devconnect(DMAPLAY, DAC, CLKEXT, prediv, 1);
+
+ /* Set buffer */
+ buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+ if (Setbuffer(0, buffer, buffer + spec->size)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
+ }
+
+ /* Install interrupt */
+ if (NSetinterrupt(2, SI_PLAY, Mint_GsxbInterrupt)<0) {
+ DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
+ }
+
+ /* Go */
+ Buffoper(SB_PLA_ENA|SB_PLA_RPT);
+ DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
+}
+
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ /* Lock sound system */
+ if (Locksnd()!=1) {
+ SDL_SetError("Mint_OpenAudio: Audio system already in use");
+ return(-1);
+ }
+
+ SDL_MintAudio_device = this;
+
+ /* Check audio capabilities */
+ if (Mint_CheckAudio(this, spec)==-1) {
+ return -1;
+ }
+
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate memory for audio buffers in DMA-able RAM */
+ DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
+
+ SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
+ if (SDL_MintAudio_audiobuf[0]==NULL) {
+ SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
+ return (-1);
+ }
+ SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
+ SDL_MintAudio_numbuf=0;
+ SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
+ SDL_MintAudio_audiosize = spec->size;
+ SDL_MintAudio_mutex = 0;
+
+ DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
+ DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
+
+ SDL_MintAudio_CheckFpu();
+
+ /* Setup audio hardware */
+ Mint_InitAudio(this, spec);
+
+ return(1); /* We don't use threaded audio */
+}
+
+static void Mint_GsxbInterrupt(void)
+{
+ Uint8 *newbuf;
+
+ if (SDL_MintAudio_mutex)
+ return;
+
+ SDL_MintAudio_mutex=1;
+
+ SDL_MintAudio_numbuf ^= 1;
+ SDL_MintAudio_Callback();
+ newbuf = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+ Setbuffer(0, newbuf, newbuf + SDL_MintAudio_audiosize);
+
+ SDL_MintAudio_mutex=0;
+}
+
+static void Mint_GsxbNullInterrupt(void)
+{
+}
diff --git a/src/audio/mint/SDL_mintaudio_gsxb.h b/src/audio/mint/SDL_mintaudio_gsxb.h
new file mode 100644
index 0000000..7c38288
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_gsxb.h
@@ -0,0 +1,108 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ * GSXB audio definitions
+ *
+ * Patrice Mandin
+ */
+
+#ifndef _SDL_mintaudio_gsxb_h
+#define _SDL_mintaudio_gsxb_h
+
+#include <mint/falcon.h> /* for trap_14_xxx macros */
+
+/* GSXB Cookie */
+
+#define C_GSXB 0x47535842L
+
+/* Bit 5 in cookie _SND */
+
+#define SND_GSXB (1<<5)
+
+/* NSoundcmd modes */
+
+#define SETRATE 7 /* Set sample rate */
+#define SET8BITFORMAT 8 /* 8 bits format */
+#define SET16BITFORMAT 9 /* 16 bits format */
+#define SET24BITFORMAT 10 /* 24 bits format */
+#define SET32BITFORMAT 11 /* 32 bits format */
+#define LTATTEN_MASTER 12 /* Attenuation */
+#define RTATTEN_MASTER 13
+#define LTATTEN_MICIN 14
+#define RTATTEN_MICIN 15
+#define LTATTEN_FMGEN 16
+#define RTATTEN_FMGEN 17
+#define LTATTEN_LINEIN 18
+#define RTATTEN_LINEIN 19
+#define LTATTEN_CDIN 20
+#define RTATTEN_CDIN 21
+#define LTATTEN_VIDIN 22
+#define RTATTEN_VIDIN 23
+#define LTATTEN_AUXIN 24
+#define RTATTEN_AUXIN 25
+
+/* Setmode modes */
+
+#define MONO16 3
+#define STEREO24 4
+#define STEREO32 5
+#define MONO24 6
+#define MONO32 7
+
+/* Sndstatus modes */
+
+#define SND_QUERYFORMATS 2
+#define SND_QUERYMIXERS 3
+#define SND_QUERYSOURCES 4
+#define SND_QUERYDUPLEX 5
+#define SND_QUERY8BIT 8
+#define SND_QUERY16BIT 9
+#define SND_QUERY24BIT 10
+#define SND_QUERY32BIT 11
+
+#define SND_FORMAT8 (1<<0)
+#define SND_FORMAT16 (1<<1)
+#define SND_FORMAT24 (1<<2)
+#define SND_FORMAT32 (1<<3)
+
+#define SND_FORMATSIGNED (1<<0)
+#define SND_FORMATUNSIGNED (1<<1)
+#define SND_FORMATBIGENDIAN (1<<2)
+#define SND_FORMATLITTLEENDIAN (1<<3)
+
+/* Devconnect prescalers */
+
+#define CLK_44K 1
+#define CLK_22K 3
+#define CLK_11K 7
+
+/* Extra xbios functions */
+
+#define NSoundcmd(mode,data,data2) \
+ (long)trap_14_wwl((short)130,(short)(mode),(short)(data),(long)(data2))
+#define NSetinterrupt(src_inter,cause,inth_addr) \
+ (long)trap_14_wwwl((short)135,(short)(src_inter),(short)(cause), \
+ (long)(inth_addr))
+
+#endif /* _SDL_mintaudio_gsxb_h */
diff --git a/src/audio/mint/SDL_mintaudio_it.S b/src/audio/mint/SDL_mintaudio_it.S
new file mode 100644
index 0000000..f2d36e8
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_it.S
@@ -0,0 +1,281 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+
+/*
+ Audio interrupts
+
+ Patrice Mandin, Didier Méquignon
+ */
+
+ .text
+
+ .globl _SDL_MintAudio_Callback
+
+ .globl _SDL_MintAudio_XbiosInterrupt
+ .globl _SDL_MintAudio_XbiosInterruptMeasureClock
+ .globl _SDL_MintAudio_Dma8Interrupt
+ .globl _SDL_MintAudio_StfaInterrupt
+
+ .globl _SDL_MintAudio_mutex
+ .globl _SDL_MintAudio_audiobuf
+ .globl _SDL_MintAudio_numbuf
+ .globl _SDL_MintAudio_audiosize
+ .globl _SDL_MintAudio_clocktics
+ .globl _SDL_MintAudio_hasfpu
+
+ .globl _SDL_MintAudio_stfa
+
+/*
+ How it works:
+ - Audio is playing buffer #0 (resp. #1)
+ - We must calculate a sample in buffer #1 (resp. #0)
+ so we first call the callback to do it
+ - Then we swap the buffers
+*/
+
+#define savptr 0x4a2
+#define savamt 0x46
+
+/*--- Xbios interrupt vector to measure Falcon external clock ---*/
+
+_SDL_MintAudio_XbiosInterruptMeasureClock: /* 1 mS */
+
+ btst #0,0xFFFF8901:w /* state DMA sound */
+ beqs SDL_MintAudio_EndIntMeasure
+ addql #1,_SDL_MintAudio_clocktics
+SDL_MintAudio_EndIntMeasure:
+ bclr #5,0xFFFFFA0F:w /* Clear service bit */
+ rte
+
+/*--- Xbios interrupt vector ---*/
+
+_SDL_MintAudio_XbiosInterrupt:
+
+ /* Reenable interrupts, so other interrupts can work */
+ movew #0x2300,sr
+
+ /* Clear service bit, so other MFP interrupts can work */
+ bclr #5,0xfffffa0f:w
+
+ /* Check if we are not already running */
+ tstw _SDL_MintAudio_mutex
+ bne SDL_MintAudio_XbiosEnd
+ notw _SDL_MintAudio_mutex
+
+ /* Swap buffers */
+ eorw #1,_SDL_MintAudio_numbuf
+
+ moveml d0-d7/a0-a6,sp@-
+
+ /* Save FPU if needed */
+ tstw _SDL_MintAudio_hasfpu
+ beqs SDL_MintAudio_Xbios_nofpu1
+ .chip 68060
+ fsave sp@-
+ fmoveml fpcr/fpsr/fpiar,sp@-
+ fmovemx fp0-fp7,sp@-
+ .chip 68000
+SDL_MintAudio_Xbios_nofpu1:
+
+ /* Callback */
+ jsr _SDL_MintAudio_Callback
+
+ /* Restore FPU if needed */
+ tstw _SDL_MintAudio_hasfpu
+ beqs SDL_MintAudio_Xbios_nofpu2
+ .chip 68060
+ fmovemx sp@+,fp0-fp7
+ fmoveml sp@+,fpcr/fpsr/fpiar
+ frestore sp@+
+ .chip 68000
+SDL_MintAudio_Xbios_nofpu2:
+
+ /* Reserve space for registers */
+ subl #savamt,savptr
+
+ /* Set new buffer */
+
+ moveq #0,d0
+ movel _SDL_MintAudio_audiosize,d1
+
+ movew _SDL_MintAudio_numbuf,d0
+ lsll #2,d0
+ lea _SDL_MintAudio_audiobuf,a0
+ movel a0@(d0:l),a1
+
+ lea a1@(d1:l),a2
+
+ movel a2,sp@-
+ movel a1,sp@-
+ clrw sp@-
+ movew #131,sp@-
+ trap #14
+ lea sp@(12),sp
+
+ /* Restore registers space */
+ addl #savamt,savptr
+
+ moveml sp@+,d0-d7/a0-a6
+
+ clrw _SDL_MintAudio_mutex
+SDL_MintAudio_XbiosEnd:
+ rte
+
+/*--- DMA 8 bits interrupt vector ---*/
+
+_SDL_MintAudio_Dma8Interrupt:
+
+ /* Reenable interrupts, so other interrupts can work */
+ movew #0x2300,sr
+
+ /* Clear service bit, so other MFP interrupts can work */
+ bclr #5,0xfffffa0f:w
+
+ /* Check if we are not already running */
+ tstw _SDL_MintAudio_mutex
+ bne SDL_MintAudio_Dma8End
+ notw _SDL_MintAudio_mutex
+
+ /* Swap buffers */
+ eorw #1,_SDL_MintAudio_numbuf
+
+ moveml d0-d1/a0-a1,sp@-
+
+ /* Save FPU if needed */
+ tstw _SDL_MintAudio_hasfpu
+ beqs SDL_MintAudio_Dma8_nofpu1
+ .chip 68060
+ fsave sp@-
+ fmoveml fpcr/fpsr/fpiar,sp@-
+ fmovemx fp0-fp7,sp@-
+ .chip 68000
+SDL_MintAudio_Dma8_nofpu1:
+
+ /* Callback */
+ jsr _SDL_MintAudio_Callback
+
+ /* Restore FPU if needed */
+ tstw _SDL_MintAudio_hasfpu
+ beqs SDL_MintAudio_Dma8_nofpu2
+ .chip 68060
+ fmovemx sp@+,fp0-fp7
+ fmoveml sp@+,fpcr/fpsr/fpiar
+ frestore sp@+
+ .chip 68000
+SDL_MintAudio_Dma8_nofpu2:
+
+ /* Set new buffer */
+
+ moveq #0,d0
+
+ movew _SDL_MintAudio_numbuf,d0
+ lslw #2,d0
+ lea _SDL_MintAudio_audiobuf,a0
+ movel a0@(d0:w),d1
+
+ /* Modify DMA addresses */
+ lea 0xffff8900:w,a0
+
+ moveb d1,a0@(0x07) /* Start address */
+ rorl #8,d1
+ moveb d1,a0@(0x05)
+ rorl #8,d1
+ moveb d1,a0@(0x03)
+ swap d1
+
+ addl _SDL_MintAudio_audiosize,d1
+
+ moveb d1,a0@(0x13) /* End address */
+ rorl #8,d1
+ moveb d1,a0@(0x11)
+ rorl #8,d1
+ moveb d1,a0@(0x0f)
+
+ moveml sp@+,d0-d1/a0-a1
+
+ clrw _SDL_MintAudio_mutex
+SDL_MintAudio_Dma8End:
+ rte
+
+/*--- STFA interrupt vector ---*/
+
+STFA_SOUND_START = 6
+STFA_SOUND_END = STFA_SOUND_START+8
+
+_SDL_MintAudio_StfaInterrupt:
+
+ /* Reenable interrupts, so other interrupts can work */
+ movew #0x2300,sr
+
+ /* Check if we are not already running */
+ tstw _SDL_MintAudio_mutex
+ bnes SDL_MintAudio_StfaEnd
+ notw _SDL_MintAudio_mutex
+
+ /* Swap buffers */
+ eorw #1,_SDL_MintAudio_numbuf
+
+ moveml d0-d7/a0-a6,sp@-
+
+ /* Save FPU if needed */
+ tstw _SDL_MintAudio_hasfpu
+ beqs SDL_MintAudio_Stfa_nofpu1
+ .chip 68060
+ fsave sp@-
+ fmoveml fpcr/fpsr/fpiar,sp@-
+ fmovemx fp0-fp7,sp@-
+ .chip 68000
+SDL_MintAudio_Stfa_nofpu1:
+
+ /* Callback */
+ jsr _SDL_MintAudio_Callback
+
+ /* Restore FPU if needed */
+ tstw _SDL_MintAudio_hasfpu
+ beqs SDL_MintAudio_Stfa_nofpu2
+ .chip 68060
+ fmovemx sp@+,fp0-fp7
+ fmoveml sp@+,fpcr/fpsr/fpiar
+ frestore sp@+
+ .chip 68000
+SDL_MintAudio_Stfa_nofpu2:
+
+ /* Set new buffer */
+
+ moveq #0,d0
+ movel _SDL_MintAudio_stfa,a1
+
+ movew _SDL_MintAudio_numbuf,d0
+ lslw #2,d0
+ lea _SDL_MintAudio_audiobuf,a0
+ movel a0@(d0:w),d1
+
+ /* Modify STFA replay buffers */
+ movel d1,a1@(STFA_SOUND_START)
+ addl _SDL_MintAudio_audiosize,d1
+ movel d1,a1@(STFA_SOUND_END)
+
+ moveml sp@+,d0-d7/a0-a6
+
+ clrw _SDL_MintAudio_mutex
+SDL_MintAudio_StfaEnd:
+ rte
diff --git a/src/audio/mint/SDL_mintaudio_mcsn.c b/src/audio/mint/SDL_mintaudio_mcsn.c
new file mode 100644
index 0000000..9376902
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_mcsn.c
@@ -0,0 +1,404 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MiNT audio driver
+ using XBIOS functions (MacSound compatible driver)
+
+ Patrice Mandin
+*/
+
+#include <support.h>
+
+/* Mint includes */
+#include <mint/osbind.h>
+#include <mint/falcon.h>
+#include <mint/cookie.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+
+#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
+
+#include "SDL_mintaudio.h"
+#include "SDL_mintaudio_mcsn.h"
+
+/*--- Defines ---*/
+
+#define MINT_AUDIO_DRIVER_NAME "mint_mcsn"
+
+/* Debug print info */
+#define DEBUG_NAME "audio:mcsn: "
+#if 0
+#define DEBUG_PRINT(what) \
+ { \
+ printf what; \
+ }
+#else
+#define DEBUG_PRINT(what)
+#endif
+
+/*--- Static variables ---*/
+
+static unsigned long cookie_snd, cookie_mch;
+static cookie_mcsn_t *cookie_mcsn;
+
+/*--- Audio driver functions ---*/
+
+static void Mint_CloseAudio(_THIS);
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_LockAudio(_THIS);
+static void Mint_UnlockAudio(_THIS);
+
+/* To check/init hardware audio */
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
+
+/*--- Audio driver bootstrap functions ---*/
+
+static int Audio_Available(void)
+{
+ unsigned long dummy;
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+
+ SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);
+
+ /* We can't use XBIOS in interrupt with Magic, don't know about thread */
+ if (Getcookie(C_MagX, &dummy) == C_FOUND) {
+ return(0);
+ }
+
+ /* Check if user asked a different audio driver */
+ if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
+ DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
+ return(0);
+ }
+
+ /* Cookie _MCH present ? if not, assume ST machine */
+ if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
+ cookie_mch = MCH_ST;
+ }
+
+ /* Cookie _SND present ? if not, assume ST machine */
+ if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
+ cookie_snd = SND_PSG;
+ }
+
+ /* Check if we have 16 bits audio */
+ if ((cookie_snd & SND_16BIT)==0) {
+ DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
+ return(0);
+ }
+
+ /* Cookie MCSN present ? */
+ if (Getcookie(C_McSn, (long *) &cookie_mcsn) != C_FOUND) {
+ DEBUG_PRINT((DEBUG_NAME "no MCSN audio\n"));
+ return(0);
+ }
+
+ /* Check if interrupt at end of replay */
+ if (cookie_mcsn->pint == 0) {
+ DEBUG_PRINT((DEBUG_NAME "no interrupt at end of replay\n"));
+ return(0);
+ }
+
+ /* Check if audio is lockable */
+ if (Locksnd()!=1) {
+ DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
+ return(0);
+ }
+
+ Unlocksnd();
+
+ DEBUG_PRINT((DEBUG_NAME "MCSN audio available!\n"));
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Mint_OpenAudio;
+ this->CloseAudio = Mint_CloseAudio;
+ this->LockAudio = Mint_LockAudio;
+ this->UnlockAudio = Mint_UnlockAudio;
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap MINTAUDIO_MCSN_bootstrap = {
+ MINT_AUDIO_DRIVER_NAME, "MiNT MCSN audio driver",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void Mint_LockAudio(_THIS)
+{
+ /* Stop replay */
+ Buffoper(0);
+}
+
+static void Mint_UnlockAudio(_THIS)
+{
+ /* Restart replay */
+ Buffoper(SB_PLA_ENA|SB_PLA_RPT);
+}
+
+static void Mint_CloseAudio(_THIS)
+{
+ /* Stop replay */
+ SDL_MintAudio_WaitThread();
+ Buffoper(0);
+
+ if (!SDL_MintAudio_mint_present) {
+ /* Uninstall interrupt */
+ Jdisint(MFP_DMASOUND);
+ }
+
+ /* Wait if currently playing sound */
+ while (SDL_MintAudio_mutex != 0) {
+ }
+
+ /* Clear buffers */
+ if (SDL_MintAudio_audiobuf[0]) {
+ Mfree(SDL_MintAudio_audiobuf[0]);
+ SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
+ }
+
+ /* Unlock sound system */
+ Unlocksnd();
+}
+
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int i;
+ unsigned long masterclock, masterprediv;
+
+ DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ if (spec->channels > 2) {
+ spec->channels = 2; /* no more than stereo! */
+ }
+
+ /* Check formats available */
+ MINTAUDIO_freqcount=0;
+ switch(cookie_mcsn->play) {
+ case MCSN_ST:
+ spec->channels=1;
+ spec->format=8; /* FIXME: is it signed or unsigned ? */
+ SDL_MintAudio_AddFrequency(this, 12500, 0, 0, -1);
+ break;
+ case MCSN_TT: /* Also STE, Mega STE */
+ spec->format=AUDIO_S8;
+ masterclock=MASTERCLOCK_STE;
+ masterprediv=MASTERPREDIV_STE;
+ if ((cookie_mch>>16)==MCH_TT) {
+ masterclock=MASTERCLOCK_TT;
+ masterprediv=MASTERPREDIV_TT;
+ }
+ for (i=0; i<4; i++) {
+ SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)),
+ masterclock, 3-i, -1);
+ }
+ break;
+ case MCSN_FALCON: /* Also Mac */
+ for (i=1; i<12; i++) {
+ /* Remove unusable Falcon codec predivisors */
+ if ((i==6) || (i==8) || (i==10)) {
+ continue;
+ }
+ SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)),
+ CLK25M, i+1, -1);
+ }
+ if (cookie_mcsn->res1 != 0) {
+ for (i=1; i<4; i++) {
+ SDL_MintAudio_AddFrequency(this, (cookie_mcsn->res1)/(MASTERPREDIV_FALCON*(1<<i)),
+ CLKEXT, (1<<i)-1, -1);
+ }
+ }
+ spec->format |= 0x8000; /* Audio is always signed */
+ if ((spec->format & 0x00ff)==16) {
+ spec->format |= 0x1000; /* Audio is always big endian */
+ spec->channels=2; /* 16 bits always stereo */
+ }
+ break;
+ }
+
+#if 0
+ for (i=0; i<MINTAUDIO_freqcount; i++) {
+ DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
+ i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
+ MINTAUDIO_frequencies[i].predivisor
+ ));
+ }
+#endif
+
+ MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
+ spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
+
+ DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ return 0;
+}
+
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int channels_mode, prediv, dmaclock;
+ void *buffer;
+
+ /* Stop currently playing sound */
+ SDL_MintAudio_quit_thread = SDL_FALSE;
+ SDL_MintAudio_thread_finished = SDL_TRUE;
+ SDL_MintAudio_WaitThread();
+ Buffoper(0);
+
+ /* Set replay tracks */
+ Settracks(0,0);
+ Setmontracks(0);
+
+ /* Select replay format */
+ channels_mode=STEREO16;
+ switch (spec->format & 0xff) {
+ case 8:
+ if (spec->channels==2) {
+ channels_mode=STEREO8;
+ } else {
+ channels_mode=MONO8;
+ }
+ break;
+ }
+ if (Setmode(channels_mode)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
+ }
+
+ dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock;
+ prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
+ switch(cookie_mcsn->play) {
+ case MCSN_TT:
+ Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, 1);
+ Soundcmd(SETPRESCALE, prediv);
+ DEBUG_PRINT((DEBUG_NAME "STE/TT prescaler selected\n"));
+ break;
+ case MCSN_FALCON:
+ Devconnect(DMAPLAY, DAC, dmaclock, prediv, 1);
+ DEBUG_PRINT((DEBUG_NAME "Falcon prescaler selected\n"));
+ break;
+ }
+
+ /* Set buffer */
+ buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+ if (Setbuffer(0, buffer, buffer + spec->size)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
+ }
+
+ if (SDL_MintAudio_mint_present) {
+ SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0);
+ } else {
+ /* Install interrupt */
+ Jdisint(MFP_DMASOUND);
+ Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);
+ Jenabint(MFP_DMASOUND);
+
+ if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
+ }
+ }
+
+ /* Go */
+ Buffoper(SB_PLA_ENA|SB_PLA_RPT);
+ DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
+}
+
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ /* Lock sound system */
+ if (Locksnd()!=1) {
+ SDL_SetError("Mint_OpenAudio: Audio system already in use");
+ return(-1);
+ }
+
+ SDL_MintAudio_device = this;
+
+ /* Check audio capabilities */
+ if (Mint_CheckAudio(this, spec)==-1) {
+ return -1;
+ }
+
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate memory for audio buffers in DMA-able RAM */
+ DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
+
+ SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
+ if (SDL_MintAudio_audiobuf[0]==NULL) {
+ SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
+ return (-1);
+ }
+ SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
+ SDL_MintAudio_numbuf=0;
+ SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
+ SDL_MintAudio_audiosize = spec->size;
+ SDL_MintAudio_mutex = 0;
+
+ DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
+ DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
+
+ SDL_MintAudio_CheckFpu();
+
+ /* Setup audio hardware */
+ Mint_InitAudio(this, spec);
+
+ return(1); /* We don't use SDL threaded audio */
+}
diff --git a/src/audio/mint/SDL_mintaudio_mcsn.h b/src/audio/mint/SDL_mintaudio_mcsn.h
new file mode 100644
index 0000000..18fd59c
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_mcsn.h
@@ -0,0 +1,59 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MCSN control structure
+
+ Patrice Mandin
+*/
+
+#ifndef _SDL_mintaudio_mcsh_h
+#define _SDL_mintaudio_mcsh_h
+
+typedef struct {
+ unsigned short version; /* Version */
+ unsigned short size; /* Size of structure */
+
+ unsigned short play; /* Replay capability */
+ unsigned short record; /* Record capability */
+ unsigned short dsp; /* DSP56K present */
+ unsigned short pint; /* Interrupt at end of replay */
+ unsigned short rint; /* Interrupt at end of record */
+
+ unsigned long res1; /* Frequency of external clock */
+ unsigned long res2;
+ unsigned long res3;
+ unsigned long res4;
+} cookie_mcsn_t __attribute__((packed));
+
+enum {
+ MCSN_ST=0,
+ MCSN_TT,
+ MCSN_STE=MCSN_TT,
+ MCSN_FALCON,
+ MCSN_MAC=MCSN_FALCON
+};
+
+#define SETSMPFREQ 7 /* Set sample frequency */
+
+#endif /* _SDL_mintaudio_mcsh_h */
diff --git a/src/audio/mint/SDL_mintaudio_stfa.c b/src/audio/mint/SDL_mintaudio_stfa.c
new file mode 100644
index 0000000..6940f80
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_stfa.c
@@ -0,0 +1,323 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MiNT audio driver
+ using XBIOS functions (STFA driver)
+
+ Patrice Mandin
+*/
+
+/* Mint includes */
+#include <mint/osbind.h>
+#include <mint/falcon.h>
+#include <mint/cookie.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+
+#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
+
+#include "SDL_mintaudio.h"
+#include "SDL_mintaudio_stfa.h"
+
+/*--- Defines ---*/
+
+#define MINT_AUDIO_DRIVER_NAME "mint_stfa"
+
+/* Debug print info */
+#define DEBUG_NAME "audio:stfa: "
+#if 0
+#define DEBUG_PRINT(what) \
+ { \
+ printf what; \
+ }
+#else
+#define DEBUG_PRINT(what)
+#endif
+
+/*--- Static variables ---*/
+
+static unsigned long cookie_snd, cookie_mch;
+static cookie_stfa_t *cookie_stfa;
+
+static const int freqs[16]={
+ 4995, 6269, 7493, 8192,
+ 9830, 10971, 12538, 14985,
+ 16384, 19819, 21943, 24576,
+ 30720, 32336, 43885, 49152
+};
+
+/*--- Audio driver functions ---*/
+
+static void Mint_CloseAudio(_THIS);
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_LockAudio(_THIS);
+static void Mint_UnlockAudio(_THIS);
+
+/* To check/init hardware audio */
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
+
+/*--- Audio driver bootstrap functions ---*/
+
+static int Audio_Available(void)
+{
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+
+ /* Check if user asked a different audio driver */
+ if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
+ DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
+ return(0);
+ }
+
+ /* Cookie _MCH present ? if not, assume ST machine */
+ if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
+ cookie_mch = MCH_ST;
+ }
+
+ /* Cookie _SND present ? if not, assume ST machine */
+ if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
+ cookie_snd = SND_PSG;
+ }
+
+ /* Cookie STFA present ? */
+ if (Getcookie(C_STFA, (long *) &cookie_stfa) != C_FOUND) {
+ DEBUG_PRINT((DEBUG_NAME "no STFA audio\n"));
+ return(0);
+ }
+
+ SDL_MintAudio_stfa = cookie_stfa;
+
+ DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Mint_OpenAudio;
+ this->CloseAudio = Mint_CloseAudio;
+ this->LockAudio = Mint_LockAudio;
+ this->UnlockAudio = Mint_UnlockAudio;
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap MINTAUDIO_STFA_bootstrap = {
+ MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void Mint_LockAudio(_THIS)
+{
+ void *oldpile;
+
+ /* Stop replay */
+ oldpile=(void *)Super(0);
+ cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
+ Super(oldpile);
+}
+
+static void Mint_UnlockAudio(_THIS)
+{
+ void *oldpile;
+
+ /* Restart replay */
+ oldpile=(void *)Super(0);
+ cookie_stfa->sound_enable=STFA_PLAY_ENABLE|STFA_PLAY_REPEAT;
+ Super(oldpile);
+}
+
+static void Mint_CloseAudio(_THIS)
+{
+ void *oldpile;
+
+ /* Stop replay */
+ oldpile=(void *)Super(0);
+ cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
+ Super(oldpile);
+
+ /* Wait if currently playing sound */
+ while (SDL_MintAudio_mutex != 0) {
+ }
+
+ /* Clear buffers */
+ if (SDL_MintAudio_audiobuf[0]) {
+ Mfree(SDL_MintAudio_audiobuf[0]);
+ SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
+ }
+}
+
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int i;
+
+ DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ if (spec->channels > 2) {
+ spec->channels = 2; /* no more than stereo! */
+ }
+
+ /* Check formats available */
+ MINTAUDIO_freqcount=0;
+ for (i=0;i<16;i++) {
+ SDL_MintAudio_AddFrequency(this, freqs[i], 0, i, -1);
+ }
+
+#if 1
+ for (i=0; i<MINTAUDIO_freqcount; i++) {
+ DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
+ i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
+ MINTAUDIO_frequencies[i].predivisor
+ ));
+ }
+#endif
+
+ MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
+ spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
+
+ DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ return 0;
+}
+
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
+{
+ void *buffer;
+ void *oldpile;
+
+ buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+
+ oldpile=(void *)Super(0);
+
+ /* Stop replay */
+ cookie_stfa->sound_enable=STFA_PLAY_DISABLE;
+
+ /* Select replay format */
+ cookie_stfa->sound_control = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
+ if ((spec->format & 0xff)==8) {
+ cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
+ } else {
+ cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
+ }
+ if (spec->channels==2) {
+ cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
+ } else {
+ cookie_stfa->sound_control |= STFA_FORMAT_MONO;
+ }
+ if ((spec->format & 0x8000)!=0) {
+ cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
+ } else {
+ cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED;
+ }
+ if ((spec->format & 0x1000)!=0) {
+ cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
+ } else {
+ cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
+ }
+
+ /* Set buffer */
+ cookie_stfa->sound_start = (unsigned long) buffer;
+ cookie_stfa->sound_end = (unsigned long) (buffer + spec->size);
+
+ /* Set interrupt */
+ cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
+
+ /* Restart replay */
+ cookie_stfa->sound_enable=STFA_PLAY_ENABLE|STFA_PLAY_REPEAT;
+
+ Super(oldpile);
+
+ DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
+}
+
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ SDL_MintAudio_device = this;
+
+ /* Check audio capabilities */
+ if (Mint_CheckAudio(this, spec)==-1) {
+ return -1;
+ }
+
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate memory for audio buffers in DMA-able RAM */
+ DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
+
+ SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
+ if (SDL_MintAudio_audiobuf[0]==NULL) {
+ SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
+ return (-1);
+ }
+ SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
+ SDL_MintAudio_numbuf=0;
+ SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
+ SDL_MintAudio_audiosize = spec->size;
+ SDL_MintAudio_mutex = 0;
+
+ DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
+ DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
+
+ SDL_MintAudio_CheckFpu();
+
+ /* Setup audio hardware */
+ Mint_InitAudio(this, spec);
+
+ return(1); /* We don't use threaded audio */
+}
diff --git a/src/audio/mint/SDL_mintaudio_stfa.h b/src/audio/mint/SDL_mintaudio_stfa.h
new file mode 100644
index 0000000..006fa75
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_stfa.h
@@ -0,0 +1,100 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ STFA control structure
+
+ Patrice Mandin
+*/
+
+#ifndef _SDL_mintaudio_stfa_h
+#define _SDL_mintaudio_stfa_h
+
+/*--- Defines ---*/
+
+#define C_STFA 0x53544641L /* Sound treiber für atari (seb/The removers) */
+
+#define STFA_PLAY_ENABLE (1<<0)
+#define STFA_PLAY_DISABLE (0<<0)
+#define STFA_PLAY_REPEAT (1<<1)
+#define STFA_PLAY_SINGLE (0<<1)
+
+#define STFA_FORMAT_SIGNED (1<<15)
+#define STFA_FORMAT_UNSIGNED (0<<15)
+#define STFA_FORMAT_STEREO (1<<14)
+#define STFA_FORMAT_MONO (0<<14)
+#define STFA_FORMAT_16BIT (1<<13)
+#define STFA_FORMAT_8BIT (0<<13)
+#define STFA_FORMAT_LITENDIAN (1<<9)
+#define STFA_FORMAT_BIGENDIAN (0<<9)
+#define STFA_FORMAT_FREQ_MASK 0x0f
+enum {
+ STFA_FORMAT_F4995=0,
+ STFA_FORMAT_F6269,
+ STFA_FORMAT_F7493,
+ STFA_FORMAT_F8192,
+
+ STFA_FORMAT_F9830,
+ STFA_FORMAT_F10971,
+ STFA_FORMAT_F12538,
+ STFA_FORMAT_F14985,
+
+ STFA_FORMAT_F16384,
+ STFA_FORMAT_F19819,
+ STFA_FORMAT_F21943,
+ STFA_FORMAT_F24576,
+
+ STFA_FORMAT_F30720,
+ STFA_FORMAT_F32336,
+ STFA_FORMAT_F43885,
+ STFA_FORMAT_F49152
+};
+
+/*--- Types ---*/
+
+typedef struct {
+ unsigned short sound_enable;
+ unsigned short sound_control;
+ unsigned short sound_output;
+ unsigned long sound_start;
+ unsigned long sound_current;
+ unsigned long sound_end;
+ unsigned short version;
+ void *old_vbl;
+ void *old_timera;
+ unsigned long old_mfp_status;
+ void *new_vbl;
+ void *drivers_list;
+ void *play_stop;
+ unsigned short frequency;
+ void *set_frequency;
+
+ unsigned short frequency_threshold;
+ unsigned short *custom_freq_table;
+ unsigned short stfa_on_off;
+ void *new_drivers_list;
+ unsigned long old_bit_2_of_cookie_snd;
+ void (*stfa_it)(void);
+} cookie_stfa_t __attribute__((packed));
+
+#endif /* _SDL_mintaudio_stfa_h */
diff --git a/src/audio/mint/SDL_mintaudio_xbios.c b/src/audio/mint/SDL_mintaudio_xbios.c
new file mode 100644
index 0000000..0ad6a20
--- /dev/null
+++ b/src/audio/mint/SDL_mintaudio_xbios.c
@@ -0,0 +1,495 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ MiNT audio driver
+ using XBIOS functions (Falcon)
+
+ Patrice Mandin, Didier Méquignon
+*/
+
+#include <unistd.h>
+#include <support.h>
+
+/* Mint includes */
+#include <mint/osbind.h>
+#include <mint/falcon.h>
+#include <mint/cookie.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+
+#include "../../video/ataricommon/SDL_atarimxalloc_c.h"
+
+#include "SDL_mintaudio.h"
+#include "SDL_mintaudio_dma8.h"
+
+/*--- Defines ---*/
+
+#define MINT_AUDIO_DRIVER_NAME "mint_xbios"
+
+/* Debug print info */
+#define DEBUG_NAME "audio:xbios: "
+#if 0
+#define DEBUG_PRINT(what) \
+ { \
+ printf what; \
+ }
+#else
+#define DEBUG_PRINT(what)
+#endif
+
+/*--- Static variables ---*/
+
+static unsigned long cookie_snd;
+
+/*--- Audio driver functions ---*/
+
+static void Mint_CloseAudio(_THIS);
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_LockAudio(_THIS);
+static void Mint_UnlockAudio(_THIS);
+
+/* To check/init hardware audio */
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec);
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec);
+
+/*--- Audio driver bootstrap functions ---*/
+
+static int Audio_Available(void)
+{
+ unsigned long dummy;
+ const char *envr = SDL_getenv("SDL_AUDIODRIVER");
+
+ /*SDL_MintAudio_mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND);*/
+ SDL_MintAudio_mint_present = SDL_FALSE;
+
+ /* We can't use XBIOS in interrupt with Magic, don't know about thread */
+ /*if (Getcookie(C_MagX, &dummy) == C_FOUND) {
+ return(0);
+ }*/
+
+ /* Check if user asked a different audio driver */
+ if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
+ DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
+ return(0);
+ }
+
+ /* Cookie _SND present ? if not, assume ST machine */
+ if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
+ cookie_snd = SND_PSG;
+ }
+
+ /* Check if we have 16 bits audio */
+ if ((cookie_snd & SND_16BIT)==0) {
+ DEBUG_PRINT((DEBUG_NAME "no 16 bits sound\n"));
+ return(0);
+ }
+
+ /* Check if audio is lockable */
+ if (Locksnd()!=1) {
+ DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
+ return(0);
+ }
+
+ Unlocksnd();
+
+ DEBUG_PRINT((DEBUG_NAME "XBIOS audio available!\n"));
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = Mint_OpenAudio;
+ this->CloseAudio = Mint_CloseAudio;
+ this->LockAudio = Mint_LockAudio;
+ this->UnlockAudio = Mint_UnlockAudio;
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap MINTAUDIO_XBIOS_bootstrap = {
+ MINT_AUDIO_DRIVER_NAME, "MiNT XBIOS audio driver",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void Mint_LockAudio(_THIS)
+{
+ /* Stop replay */
+ Buffoper(0);
+}
+
+static void Mint_UnlockAudio(_THIS)
+{
+ /* Restart replay */
+ Buffoper(SB_PLA_ENA|SB_PLA_RPT);
+}
+
+static void Mint_CloseAudio(_THIS)
+{
+ /* Stop replay */
+ SDL_MintAudio_WaitThread();
+ Buffoper(0);
+
+ if (!SDL_MintAudio_mint_present) {
+ /* Uninstall interrupt */
+ Jdisint(MFP_DMASOUND);
+ }
+
+ /* Wait if currently playing sound */
+ while (SDL_MintAudio_mutex != 0) {
+ }
+
+ /* Clear buffers */
+ if (SDL_MintAudio_audiobuf[0]) {
+ Mfree(SDL_MintAudio_audiobuf[0]);
+ SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
+ }
+
+ /* Unlock sound system */
+ Unlocksnd();
+}
+
+/* Falcon XBIOS implementation of Devconnect() is buggy with external clock */
+static void Devconnect2(int src, int dst, int sclk, int pre)
+{
+ static const unsigned short MASK1[3] = { 0, 0x6000, 0 };
+ static const unsigned short MASK2[4] = { 0xFFF0, 0xFF8F, 0xF0FF, 0x0FFF };
+ static const unsigned short INDEX1[4] = { 1, 3, 5, 7 };
+ static const unsigned short INDEX2[4] = { 0, 2, 4, 6 };
+ unsigned short sync_div,dev_ctrl,dest_ctrl;
+ void *oldstack;
+
+ if (dst==0) {
+ return;
+ }
+
+ oldstack=(void *)Super(0);
+
+ dev_ctrl = DMAAUDIO_IO.dev_ctrl;
+ dest_ctrl = DMAAUDIO_IO.dest_ctrl;
+ dev_ctrl &= MASK2[src];
+
+ if (src==ADC) {
+ dev_ctrl |= MASK1[sclk];
+ } else {
+ dev_ctrl |= (INDEX1[sclk] << (src<<4));
+ }
+
+ if (dst & DMAREC) {
+ dest_ctrl &= 0xFFF0;
+ dest_ctrl |= INDEX1[src];
+ }
+
+ if (dst & DSPRECV) {
+ dest_ctrl &= 0xFF8F;
+ dest_ctrl |= (INDEX1[src]<<4);
+ }
+
+ if (dst & EXTOUT) {
+ dest_ctrl &= 0xF0FF;
+ dest_ctrl |= (INDEX1[src]<<8);
+ }
+
+ if (dst & DAC) {
+ dev_ctrl &= 0x0FFF;
+ dev_ctrl |= MASK1[sclk];
+ dest_ctrl &= 0x0FFF;
+ dest_ctrl |= (INDEX2[src]<<12);
+ }
+
+ sync_div = DMAAUDIO_IO.sync_div;
+ if (sclk==CLKEXT) {
+ pre<<=8;
+ sync_div &= 0xF0FF;
+ } else {
+ sync_div &= 0xFFF0;
+ }
+ sync_div |= pre;
+
+ DMAAUDIO_IO.dev_ctrl = dev_ctrl;
+ DMAAUDIO_IO.dest_ctrl = dest_ctrl;
+ DMAAUDIO_IO.sync_div = sync_div;
+
+ Super(oldstack);
+}
+
+static void Mint_CheckExternalClock(_THIS)
+{
+#define SIZE_BUF_CLOCK_MEASURE (44100/10)
+
+ unsigned long cookie_snd;
+ char *buffer;
+ int i, j;
+
+ /* DSP present with its GPIO port ? */
+ if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
+ return;
+ }
+ if ((cookie_snd & SND_DSP)==0) {
+ return;
+ }
+
+ buffer = Atari_SysMalloc(SIZE_BUF_CLOCK_MEASURE, MX_STRAM);
+ if (buffer==NULL) {
+ DEBUG_PRINT((DEBUG_NAME "Not enough memory for the measure\n"));
+ return;
+ }
+ SDL_memset(buffer, 0, SIZE_BUF_CLOCK_MEASURE);
+
+ Buffoper(0);
+ Settracks(0,0);
+ Setmontracks(0);
+ Setmode(MONO8);
+ Jdisint(MFP_TIMERA);
+
+ for (i=0; i<2; i++) {
+ Gpio(GPIO_SET,7); /* DSP port gpio outputs */
+ Gpio(GPIO_WRITE,2+i); /* 22.5792/24.576 MHz for 44.1/48KHz */
+ Devconnect2(DMAPLAY, DAC, CLKEXT, CLK50K); /* Matrix and clock source */
+ Setbuffer(0, buffer, buffer + SIZE_BUF_CLOCK_MEASURE); /* Set buffer */
+ Xbtimer(XB_TIMERA, 5, 38, SDL_MintAudio_XbiosInterruptMeasureClock); /* delay mode timer A, prediv /64, 1KHz */
+ Jenabint(MFP_TIMERA);
+ SDL_MintAudio_clocktics = 0;
+ Buffoper(SB_PLA_ENA);
+ usleep(110000);
+
+ if((Buffoper(-1) & 1)==0) {
+ if (SDL_MintAudio_clocktics) {
+ unsigned long khz;
+
+ khz = ((SIZE_BUF_CLOCK_MEASURE/SDL_MintAudio_clocktics) +1) & 0xFFFFFFFE;
+ DEBUG_PRINT((DEBUG_NAME "measure %d: freq=%lu KHz\n", i+1, khz));
+
+ if(khz==44) {
+ for (j=1; j<4; j++) {
+ SDL_MintAudio_AddFrequency(this, MASTERCLOCK_44K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_44K, (1<<j)-1, 2+i);
+ }
+ } else if (khz==48) {
+ for (j=1; j<4; j++) {
+ SDL_MintAudio_AddFrequency(this, MASTERCLOCK_48K/(MASTERPREDIV_FALCON*(1<<j)), MASTERCLOCK_48K, (1<<j)-1, 2+i);
+ }
+ }
+ } else {
+ DEBUG_PRINT((DEBUG_NAME "No measure\n"));
+ }
+ } else {
+ DEBUG_PRINT((DEBUG_NAME "No SDMA clock\n"));
+ }
+
+ Buffoper(0); /* stop */
+ Jdisint(MFP_TIMERA); /* Uninstall interrupt */
+ }
+
+ Mfree(buffer);
+}
+
+static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int i;
+ Uint32 extclock;
+
+ DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ if (spec->channels > 2) {
+ spec->channels = 2; /* no more than stereo! */
+ }
+
+ spec->format |= 0x8000; /* Audio is always signed */
+ if ((spec->format & 0x00ff)==16) {
+ spec->format |= 0x1000; /* Audio is always big endian */
+ spec->channels=2; /* 16 bits always stereo */
+ }
+
+ MINTAUDIO_freqcount=0;
+
+ /* Add external clocks if present */
+ Mint_CheckExternalClock(this);
+
+ /* Standard clocks */
+ for (i=1;i<12;i++) {
+ /* Remove unusable Falcon codec predivisors */
+ if ((i==6) || (i==8) || (i==10)) {
+ continue;
+ }
+ SDL_MintAudio_AddFrequency(this, MASTERCLOCK_FALCON1/(MASTERPREDIV_FALCON*(i+1)), MASTERCLOCK_FALCON1, i, -1);
+ }
+
+#if 1
+ for (i=0; i<MINTAUDIO_freqcount; i++) {
+ DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
+ i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
+ MINTAUDIO_frequencies[i].predivisor
+ ));
+ }
+#endif
+
+ MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
+ spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
+
+ DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
+ DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
+ DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
+ DEBUG_PRINT(("channels=%d, ", spec->channels));
+ DEBUG_PRINT(("freq=%d\n", spec->freq));
+
+ return 0;
+}
+
+static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int channels_mode, dmaclock, prediv;
+ void *buffer;
+
+ /* Stop currently playing sound */
+ SDL_MintAudio_quit_thread = SDL_FALSE;
+ SDL_MintAudio_thread_finished = SDL_TRUE;
+ SDL_MintAudio_WaitThread();
+ Buffoper(0);
+
+ /* Set replay tracks */
+ Settracks(0,0);
+ Setmontracks(0);
+
+ /* Select replay format */
+ channels_mode=STEREO16;
+ switch (spec->format & 0xff) {
+ case 8:
+ if (spec->channels==2) {
+ channels_mode=STEREO8;
+ } else {
+ channels_mode=MONO8;
+ }
+ break;
+ }
+ if (Setmode(channels_mode)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
+ }
+
+ dmaclock = MINTAUDIO_frequencies[MINTAUDIO_numfreq].masterclock;
+ prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
+ if (MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits != -1) {
+ Gpio(GPIO_SET,7); /* DSP port gpio outputs */
+ Gpio(GPIO_WRITE, MINTAUDIO_frequencies[MINTAUDIO_numfreq].gpio_bits);
+ Devconnect2(DMAPLAY, DAC|EXTOUT, CLKEXT, prediv);
+ } else {
+ Devconnect2(DMAPLAY, DAC, CLK25M, prediv);
+ }
+
+ /* Set buffer */
+ buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
+ if (Setbuffer(0, buffer, buffer + spec->size)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
+ }
+
+ if (SDL_MintAudio_mint_present) {
+ SDL_MintAudio_thread_pid = tfork(SDL_MintAudio_Thread, 0);
+ } else {
+ /* Install interrupt */
+ Jdisint(MFP_DMASOUND);
+ /*Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_XbiosInterrupt);*/
+ Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
+ Jenabint(MFP_DMASOUND);
+
+ if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
+ DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
+ }
+ }
+
+ /* Go */
+ Buffoper(SB_PLA_ENA|SB_PLA_RPT);
+ DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
+}
+
+static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ /* Lock sound system */
+ if (Locksnd()!=1) {
+ SDL_SetError("Mint_OpenAudio: Audio system already in use");
+ return(-1);
+ }
+
+ SDL_MintAudio_device = this;
+
+ /* Check audio capabilities */
+ if (Mint_CheckAudio(this, spec)==-1) {
+ return -1;
+ }
+
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate memory for audio buffers in DMA-able RAM */
+ DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
+
+ SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
+ if (SDL_MintAudio_audiobuf[0]==NULL) {
+ SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
+ return (-1);
+ }
+ SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
+ SDL_MintAudio_numbuf=0;
+ SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
+ SDL_MintAudio_audiosize = spec->size;
+ SDL_MintAudio_mutex = 0;
+
+ DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
+ DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
+
+ SDL_MintAudio_CheckFpu();
+
+ /* Setup audio hardware */
+ Mint_InitAudio(this, spec);
+
+ return(1); /* We don't use SDL threaded audio */
+}
diff --git a/src/audio/mme/SDL_mmeaudio.c b/src/audio/mme/SDL_mmeaudio.c
new file mode 100644
index 0000000..365f5ff
--- /dev/null
+++ b/src/audio/mme/SDL_mmeaudio.c
@@ -0,0 +1,264 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Tru64 UNIX MME support */
+#include <mme_api.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_mmeaudio.h"
+
+static BOOL inUse[NUM_BUFFERS];
+
+/* Audio driver functions */
+static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void MME_WaitAudio(_THIS);
+static Uint8 *MME_GetAudioBuf(_THIS);
+static void MME_PlayAudio(_THIS);
+static void MME_WaitDone(_THIS);
+static void MME_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+static int Audio_Available(void)
+{
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ if ( device ) {
+ if ( device->hidden ) {
+ SDL_free(device->hidden);
+ device->hidden = NULL;
+ }
+ SDL_free(device);
+ device = NULL;
+ }
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+/* Initialize all variables that we clean on shutdown */
+ this = SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ /* Set the function pointers */
+ this->OpenAudio = MME_OpenAudio;
+ this->WaitAudio = MME_WaitAudio;
+ this->PlayAudio = MME_PlayAudio;
+ this->GetAudioBuf = MME_GetAudioBuf;
+ this->WaitDone = MME_WaitDone;
+ this->CloseAudio = MME_CloseAudio;
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap MMEAUDIO_bootstrap = {
+ "waveout", "Tru64 MME WaveOut",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void SetMMerror(char *function, MMRESULT code)
+{
+ int len;
+ char errbuf[MAXERRORLENGTH];
+
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
+ len = SDL_strlen(errbuf);
+ waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
+ SDL_SetError("%s",errbuf);
+}
+
+static void CALLBACK MME_CALLBACK(HWAVEOUT hwo,
+ UINT uMsg,
+ DWORD dwInstance,
+ LPARAM dwParam1,
+ LPARAM dwParam2)
+{
+ WAVEHDR *wp = (WAVEHDR *) dwParam1;
+
+ if ( uMsg == WOM_DONE )
+ inUse[wp->dwUser] = FALSE;
+}
+
+static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ MMRESULT result;
+ int i;
+
+ mixbuf = NULL;
+
+ /* Set basic WAVE format parameters */
+ shm = mmeAllocMem(sizeof(*shm));
+ if ( shm == NULL ) {
+ SDL_SetError("Out of memory: shm");
+ return(-1);
+ }
+ shm->sound = 0;
+ shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
+
+ /* Determine the audio parameters from the AudioSpec */
+ switch ( spec->format & 0xFF ) {
+ case 8:
+ /* Unsigned 8 bit audio data */
+ spec->format = AUDIO_U8;
+ shm->wFmt.wBitsPerSample = 8;
+ break;
+ case 16:
+ /* Signed 16 bit audio data */
+ spec->format = AUDIO_S16;
+ shm->wFmt.wBitsPerSample = 16;
+ break;
+ default:
+ SDL_SetError("Unsupported audio format");
+ return(-1);
+ }
+
+ shm->wFmt.wf.nChannels = spec->channels;
+ shm->wFmt.wf.nSamplesPerSec = spec->freq;
+ shm->wFmt.wf.nBlockAlign =
+ shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
+ shm->wFmt.wf.nAvgBytesPerSec =
+ shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
+
+ /* Check the buffer size -- minimum of 1/4 second (word aligned) */
+ if ( spec->samples < (spec->freq/4) )
+ spec->samples = ((spec->freq/4)+3)&~3;
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Open the audio device */
+ result = waveOutOpen(&(shm->sound),
+ WAVE_MAPPER,
+ &(shm->wFmt.wf),
+ MME_CALLBACK,
+ NULL,
+ (CALLBACK_FUNCTION|WAVE_OPEN_SHAREABLE));
+ if ( result != MMSYSERR_NOERROR ) {
+ SetMMerror("waveOutOpen()", result);
+ return(-1);
+ }
+
+ /* Create the sound buffers */
+ mixbuf = (Uint8 *)mmeAllocBuffer(NUM_BUFFERS * (spec->size));
+ if ( mixbuf == NULL ) {
+ SDL_SetError("Out of memory: mixbuf");
+ return(-1);
+ }
+
+ for (i = 0; i < NUM_BUFFERS; i++) {
+ shm->wHdr[i].lpData = &mixbuf[i * (spec->size)];
+ shm->wHdr[i].dwBufferLength = spec->size;
+ shm->wHdr[i].dwFlags = 0;
+ shm->wHdr[i].dwUser = i;
+ shm->wHdr[i].dwLoops = 0; /* loop control counter */
+ shm->wHdr[i].lpNext = NULL; /* reserved for driver */
+ shm->wHdr[i].reserved = 0;
+ inUse[i] = FALSE;
+ }
+ next_buffer = 0;
+ return 0;
+}
+
+static void MME_WaitAudio(_THIS)
+{
+ while ( inUse[next_buffer] ) {
+ mmeWaitForCallbacks();
+ mmeProcessCallbacks();
+ }
+}
+
+static Uint8 *MME_GetAudioBuf(_THIS)
+{
+ Uint8 *retval;
+
+ inUse[next_buffer] = TRUE;
+ retval = (Uint8 *)(shm->wHdr[next_buffer].lpData);
+ return retval;
+}
+
+static void MME_PlayAudio(_THIS)
+{
+ /* Queue it up */
+ waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
+ next_buffer = (next_buffer+1)%NUM_BUFFERS;
+}
+
+static void MME_WaitDone(_THIS)
+{
+ MMRESULT result;
+ int i;
+
+ if ( shm->sound ) {
+ for (i = 0; i < NUM_BUFFERS; i++)
+ while ( inUse[i] ) {
+ mmeWaitForCallbacks();
+ mmeProcessCallbacks();
+ }
+ result = waveOutReset(shm->sound);
+ if ( result != MMSYSERR_NOERROR )
+ SetMMerror("waveOutReset()", result);
+ mmeProcessCallbacks();
+ }
+}
+
+static void MME_CloseAudio(_THIS)
+{
+ MMRESULT result;
+
+ if ( mixbuf ) {
+ result = mmeFreeBuffer(mixbuf);
+ if (result != MMSYSERR_NOERROR )
+ SetMMerror("mmeFreeBuffer", result);
+ mixbuf = NULL;
+ }
+
+ if ( shm ) {
+ if ( shm->sound ) {
+ result = waveOutClose(shm->sound);
+ if (result != MMSYSERR_NOERROR )
+ SetMMerror("waveOutClose()", result);
+ mmeProcessCallbacks();
+ }
+ result = mmeFreeMem(shm);
+ if (result != MMSYSERR_NOERROR )
+ SetMMerror("mmeFreeMem()", result);
+ shm = NULL;
+ }
+}
+
diff --git a/src/audio/mme/SDL_mmeaudio.h b/src/audio/mme/SDL_mmeaudio.h
new file mode 100644
index 0000000..41f3b30
--- /dev/null
+++ b/src/audio/mme/SDL_mmeaudio.h
@@ -0,0 +1,51 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+#define NUM_BUFFERS 2
+
+struct SharedMem {
+ HWAVEOUT sound;
+ WAVEHDR wHdr[NUM_BUFFERS];
+ PCMWAVEFORMAT wFmt;
+};
+
+struct SDL_PrivateAudioData {
+ Uint8 *mixbuf; /* The raw allocated mixing buffer */
+ struct SharedMem *shm;
+ int next_buffer;
+};
+
+#define shm (this->hidden->shm)
+#define mixbuf (this->hidden->mixbuf)
+#define next_buffer (this->hidden->next_buffer)
+/* Old variable names */
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c
new file mode 100644
index 0000000..677eb17
--- /dev/null
+++ b/src/audio/nas/SDL_nasaudio.c
@@ -0,0 +1,423 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+
+ This driver was written by:
+ Erik Inge Bolsø
+ knan@mo.himolde.no
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_nasaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
+#include "SDL_loadso.h"
+#endif
+
+/* The tag name used by artsc audio */
+#define NAS_DRIVER_NAME "nas"
+
+static struct SDL_PrivateAudioData *this2 = NULL;
+
+static void (*NAS_AuCloseServer) (AuServer *);
+static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
+static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
+static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
+static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
+static void (*NAS_AuSetElements)
+ (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
+static void (*NAS_AuWriteElement)
+ (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
+static AuServer *(*NAS_AuOpenServer)
+ (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
+static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
+ (AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
+
+
+#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
+
+static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
+static void *nas_handle = NULL;
+
+static int
+load_nas_sym(const char *fn, void **addr)
+{
+ *addr = SDL_LoadFunction(nas_handle, fn);
+ if (*addr == NULL) {
+ return 0;
+ }
+ return 1;
+}
+
+/* cast funcs to char* first, to please GCC's strict aliasing rules. */
+#define SDL_NAS_SYM(x) \
+ if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
+#else
+#define SDL_NAS_SYM(x) NAS_##x = x
+#endif
+
+static int
+load_nas_syms(void)
+{
+ SDL_NAS_SYM(AuCloseServer);
+ SDL_NAS_SYM(AuNextEvent);
+ SDL_NAS_SYM(AuDispatchEvent);
+ SDL_NAS_SYM(AuCreateFlow);
+ SDL_NAS_SYM(AuStartFlow);
+ SDL_NAS_SYM(AuSetElements);
+ SDL_NAS_SYM(AuWriteElement);
+ SDL_NAS_SYM(AuOpenServer);
+ SDL_NAS_SYM(AuRegisterEventHandler);
+ return 0;
+}
+
+#undef SDL_NAS_SYM
+
+#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
+
+static void
+UnloadNASLibrary(void)
+{
+ if (nas_handle != NULL) {
+ SDL_UnloadObject(nas_handle);
+ nas_handle = NULL;
+ }
+}
+
+static int
+LoadNASLibrary(void)
+{
+ int retval = 0;
+ if (nas_handle == NULL) {
+ nas_handle = SDL_LoadObject(nas_library);
+ if (nas_handle == NULL) {
+ /* Copy error string so we can use it in a new SDL_SetError(). */
+ char *origerr = SDL_GetError();
+ size_t len = SDL_strlen(origerr) + 1;
+ char *err = (char *) alloca(len);
+ SDL_strlcpy(err, origerr, len);
+ retval = -1;
+ SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
+ nas_library, err);
+ } else {
+ retval = load_nas_syms();
+ if (retval < 0) {
+ UnloadNASLibrary();
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void
+UnloadNASLibrary(void)
+{
+}
+
+static int
+LoadNASLibrary(void)
+{
+ load_nas_syms();
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
+
+
+/* Audio driver functions */
+static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void NAS_WaitAudio(_THIS);
+static void NAS_PlayAudio(_THIS);
+static Uint8 *NAS_GetAudioBuf(_THIS);
+static void NAS_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ if (LoadNASLibrary() == 0) {
+ AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
+ if (!aud) {
+ UnloadNASLibrary();
+ return 0;
+ }
+ NAS_AuCloseServer(aud);
+ UnloadNASLibrary();
+ return 1;
+ }
+ return 0;
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ UnloadNASLibrary();
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ if (LoadNASLibrary() < 0) {
+ return NULL;
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return NULL;
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = NAS_OpenAudio;
+ this->WaitAudio = NAS_WaitAudio;
+ this->PlayAudio = NAS_PlayAudio;
+ this->GetAudioBuf = NAS_GetAudioBuf;
+ this->CloseAudio = NAS_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap NAS_bootstrap = {
+ NAS_DRIVER_NAME, "Network Audio System",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void NAS_WaitAudio(_THIS)
+{
+ while ( this->hidden->buf_free < this->hidden->mixlen ) {
+ AuEvent ev;
+ NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
+ NAS_AuDispatchEvent(this->hidden->aud, &ev);
+ }
+}
+
+static void NAS_PlayAudio(_THIS)
+{
+ while (this->hidden->mixlen > this->hidden->buf_free) { /* We think the buffer is full? Yikes! Ask the server for events,
+ in the hope that some of them is LowWater events telling us more
+ of the buffer is free now than what we think. */
+ AuEvent ev;
+ NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
+ NAS_AuDispatchEvent(this->hidden->aud, &ev);
+ }
+ this->hidden->buf_free -= this->hidden->mixlen;
+
+ /* Write the audio data */
+ NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0, this->hidden->mixlen, this->hidden->mixbuf, AuFalse, NULL);
+
+ this->hidden->written += this->hidden->mixlen;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
+#endif
+}
+
+static Uint8 *NAS_GetAudioBuf(_THIS)
+{
+ return(this->hidden->mixbuf);
+}
+
+static void NAS_CloseAudio(_THIS)
+{
+ if ( this->hidden->mixbuf != NULL ) {
+ SDL_FreeAudioMem(this->hidden->mixbuf);
+ this->hidden->mixbuf = NULL;
+ }
+ if ( this->hidden->aud ) {
+ NAS_AuCloseServer(this->hidden->aud);
+ this->hidden->aud = 0;
+ }
+}
+
+static unsigned char sdlformat_to_auformat(unsigned int fmt)
+{
+ switch (fmt)
+ {
+ case AUDIO_U8:
+ return AuFormatLinearUnsigned8;
+ case AUDIO_S8:
+ return AuFormatLinearSigned8;
+ case AUDIO_U16LSB:
+ return AuFormatLinearUnsigned16LSB;
+ case AUDIO_U16MSB:
+ return AuFormatLinearUnsigned16MSB;
+ case AUDIO_S16LSB:
+ return AuFormatLinearSigned16LSB;
+ case AUDIO_S16MSB:
+ return AuFormatLinearSigned16MSB;
+ }
+ return AuNone;
+}
+
+static AuBool
+event_handler(AuServer* aud, AuEvent* ev, AuEventHandlerRec* hnd)
+{
+ switch (ev->type) {
+ case AuEventTypeElementNotify: {
+ AuElementNotifyEvent* event = (AuElementNotifyEvent *)ev;
+
+ switch (event->kind) {
+ case AuElementNotifyKindLowWater:
+ if (this2->buf_free >= 0) {
+ this2->really += event->num_bytes;
+ gettimeofday(&this2->last_tv, 0);
+ this2->buf_free += event->num_bytes;
+ } else {
+ this2->buf_free = event->num_bytes;
+ }
+ break;
+ case AuElementNotifyKindState:
+ switch (event->cur_state) {
+ case AuStatePause:
+ if (event->reason != AuReasonUser) {
+ if (this2->buf_free >= 0) {
+ this2->really += event->num_bytes;
+ gettimeofday(&this2->last_tv, 0);
+ this2->buf_free += event->num_bytes;
+ } else {
+ this2->buf_free = event->num_bytes;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ return AuTrue;
+}
+
+static AuDeviceID
+find_device(_THIS, int nch)
+{
+ /* These "Au" things are all macros, not functions... */
+ int i;
+ for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
+ if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
+ AuComponentKindPhysicalOutput) &&
+ AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
+ return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
+ }
+ }
+ return AuNone;
+}
+
+static int NAS_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ AuElement elms[3];
+ int buffer_size;
+ Uint16 test_format, format;
+
+ this->hidden->mixbuf = NULL;
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ ! format && test_format; ) {
+ format = sdlformat_to_auformat(test_format);
+
+ if (format == AuNone) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( format == 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ return(-1);
+ }
+ spec->format = test_format;
+
+ this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
+ if (this->hidden->aud == 0)
+ {
+ SDL_SetError("Couldn't open connection to NAS server");
+ return (-1);
+ }
+
+ this->hidden->dev = find_device(this, spec->channels);
+ if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, NULL)))) {
+ NAS_AuCloseServer(this->hidden->aud);
+ this->hidden->aud = 0;
+ SDL_SetError("Couldn't find a fitting playback device on NAS server");
+ return (-1);
+ }
+
+ buffer_size = spec->freq;
+ if (buffer_size < 4096)
+ buffer_size = 4096;
+
+ if (buffer_size > 32768)
+ buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ this2 = this->hidden;
+
+ /* These "Au" things without a NAS_ prefix are macros, not functions... */
+ AuMakeElementImportClient(elms, spec->freq, format, spec->channels, AuTrue,
+ buffer_size, buffer_size / 4, 0, NULL);
+ AuMakeElementExportDevice(elms+1, 0, this->hidden->dev, spec->freq,
+ AuUnlimitedSamples, 0, NULL);
+ NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, NULL);
+ NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow,
+ event_handler, (AuPointer) NULL);
+
+ NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
+
+ /* Allocate mixing buffer */
+ this->hidden->mixlen = spec->size;
+ this->hidden->mixbuf = (Uint8 *)SDL_AllocAudioMem(this->hidden->mixlen);
+ if ( this->hidden->mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ this->hidden->parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
diff --git a/src/audio/nas/SDL_nasaudio.h b/src/audio/nas/SDL_nasaudio.h
new file mode 100644
index 0000000..1cd04f8
--- /dev/null
+++ b/src/audio/nas/SDL_nasaudio.h
@@ -0,0 +1,62 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+
+ This driver was written by:
+ Erik Inge Bolsø
+ knan@mo.himolde.no
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_nasaudio_h
+#define _SDL_nasaudio_h
+
+#ifdef __sgi
+#include <nas/audiolib.h>
+#else
+#include <audio/audiolib.h>
+#endif
+#include <sys/time.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ AuServer* aud;
+ AuFlowID flow;
+ AuDeviceID dev;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ int written;
+ int really;
+ int bps;
+ struct timeval last_tv;
+ int buf_free;
+};
+#endif /* _SDL_nasaudio_h */
+
diff --git a/src/audio/nds/SDL_ndsaudio.c b/src/audio/nds/SDL_ndsaudio.c
new file mode 100644
index 0000000..ad68d8c
--- /dev/null
+++ b/src/audio/nds/SDL_ndsaudio.c
@@ -0,0 +1,335 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+#include <nds.h>
+#include "SDL.h"
+#include "SDL_endian.h"
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "SDL_ndsaudio.h"
+#include "soundcommon.h"
+
+
+/* Audio driver functions */
+static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void NDS_WaitAudio(_THIS);
+static void NDS_PlayAudio(_THIS);
+static Uint8 *NDS_GetAudioBuf(_THIS);
+static void NDS_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+u32 framecounter = 0,soundoffset = 0;
+static SDL_AudioDevice *sdl_nds_audiodevice;
+
+//void SoundMixCallback(void *stream,u32 size)
+//{
+// //printf("SoundMixCallback\n");
+//
+// Uint8 *buffer;
+//
+// buffer = sdl_nds_audiodevice->hidden->mixbuf;
+// memset(buffer, sdl_nds_audiodevice->spec.silence, size);
+//
+// if (!sdl_nds_audiodevice->paused){
+//
+//
+// //if (sdl_nds_audiodevice->convert.needed) {
+// // int silence;
+//
+// // if (sdl_nds_audiodevice->convert.src_format == AUDIO_U8 ) {
+// // silence = 0x80;
+// // } else {
+// // silence = 0;
+// // }
+// // memset(sdl_nds_audiodevice->convert.buf, silence, sdl_nds_audiodevice->convert.len);
+// // sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata,
+// // (Uint8 *)sdl_nds_audiodevice->convert.buf,sdl_nds_audiodevice->convert.len);
+// // SDL_ConvertAudio(&sdl_nds_audiodevice->convert);
+// // memcpy(buffer, sdl_nds_audiodevice->convert.buf, sdl_nds_audiodevice->convert.len_cvt);
+// //} else
+// {
+// sdl_nds_audiodevice->spec.callback(sdl_nds_audiodevice->spec.userdata, buffer, size);
+// //memcpy((Sint16 *)stream,buffer, size);
+// }
+//
+// }
+//
+// if(soundsystem->format == 8)
+// {
+// int i;
+// s32 *buffer32 = (s32 *)buffer;
+// s32 *stream32 = (s32 *)stream;
+// for(i=0;i<size/4;i++){ *stream32++ = buffer32[i] ^ 0x80808080;}
+// //for(i = 0; i < size; i++)
+// // ((s8*)stream)[i]=(buffer[i]^0x80);
+// }
+// else
+// {
+// int i;
+// for(i = 0; i < size; i++){
+// //((short*)stream)[i] =(short)buffer[i] << 8; // sound 8bit ---> buffer 16bit
+// //if (buffer[i] &0x80)
+// //((Sint16*)stream)[i] = 0xff00 | buffer[i];
+// ((Sint16*)stream)[i] = (buffer[i] - 128) << 8;
+//
+// //else
+// // ((Sint16*)stream)[i] = buffer[i];
+// }
+// //register signed char *pSrc =buffer;
+// //register short *pDest =stream;
+// //int x;
+// // for (x=size; x>0; x--)
+// // {
+// // register short temp = (((short)*pSrc)-128)<<8;
+// // pSrc++;
+// // *pDest++ = temp;
+// // }
+//
+// //memcpy((Sint16 *)stream,buffer, size);
+// }
+//}
+
+void SoundMixCallback(void *stream,u32 len)
+{
+ SDL_AudioDevice *audio = (SDL_AudioDevice *)sdl_nds_audiodevice;
+
+ /* Silence the buffer, since it's ours */
+ SDL_memset(stream, audio->spec.silence, len);
+
+ /* Only do soemthing if audio is enabled */
+ if ( ! audio->enabled )
+ return;
+
+ if ( ! audio->paused ) {
+ if ( audio->convert.needed ) {
+ //fprintf(stderr,"converting audio\n");
+ SDL_mutexP(audio->mixer_lock);
+ (*audio->spec.callback)(audio->spec.userdata,
+ (Uint8 *)audio->convert.buf,audio->convert.len);
+ SDL_mutexV(audio->mixer_lock);
+ SDL_ConvertAudio(&audio->convert);
+ SDL_memcpy(stream,audio->convert.buf,audio->convert.len_cvt);
+ } else {
+ SDL_mutexP(audio->mixer_lock);
+ (*audio->spec.callback)(audio->spec.userdata,
+ (Uint8 *)stream, len);
+ SDL_mutexV(audio->mixer_lock);
+ }
+ }
+ return;
+}
+void MixSound(void)
+{
+ int remain;
+
+ if(soundsystem->format == 8)
+ {
+ if((soundsystem->soundcursor + soundsystem->numsamples) > soundsystem->buffersize)
+ {
+ SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->buffersize - soundsystem->soundcursor);
+ remain = soundsystem->numsamples - (soundsystem->buffersize - soundsystem->soundcursor);
+ SoundMixCallback(soundsystem->mixbuffer,remain);
+ }
+ else
+ {
+ SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor],soundsystem->numsamples);
+ }
+ }
+ else
+ {
+ if((soundsystem->soundcursor + soundsystem->numsamples) > (soundsystem->buffersize >> 1))
+ {
+ SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],(soundsystem->buffersize >> 1) - soundsystem->soundcursor);
+ remain = soundsystem->numsamples - ((soundsystem->buffersize >> 1) - soundsystem->soundcursor);
+ SoundMixCallback(soundsystem->mixbuffer,remain);
+ }
+ else
+ {
+ SoundMixCallback(&soundsystem->mixbuffer[soundsystem->soundcursor << 1],soundsystem->numsamples);
+ }
+ }
+}
+
+void InterruptHandler(void)
+{
+ framecounter++;
+}
+void FiFoHandler(void)
+{
+ u32 command;
+ while ( !(REG_IPC_FIFO_CR & (IPC_FIFO_RECV_EMPTY)) )
+ {
+ command = REG_IPC_FIFO_RX;
+
+ switch(command)
+ {
+ case FIFO_NONE:
+ break;
+ case UPDATEON_ARM9:
+ REG_IME = 0;
+ MixSound();
+ REG_IME = 1;
+ SendCommandToArm7(MIXCOMPLETE_ONARM9);
+ break;
+ }
+ }
+}
+
+
+
+
+
+static int Audio_Available(void)
+{
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = NDS_OpenAudio;
+ this->WaitAudio = NDS_WaitAudio;
+ this->PlayAudio = NDS_PlayAudio;
+ this->GetAudioBuf = NDS_GetAudioBuf;
+ this->CloseAudio = NDS_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+//fprintf(stderr,"Audio_CreateDevice\n");
+ return this;
+}
+
+AudioBootStrap NDSAUD_bootstrap = {
+ "nds", "NDS audio",
+ Audio_Available, Audio_CreateDevice
+};
+
+
+void static NDS_WaitAudio(_THIS)
+{
+ //printf("NDS_WaitAudio\n");
+}
+
+static void NDS_PlayAudio(_THIS)
+{
+ //printf("playing audio\n");
+ if (this->paused)
+ return;
+
+}
+
+static Uint8 *NDS_GetAudioBuf(_THIS)
+{
+ return NULL;//(this->hidden->mixbuf);
+}
+
+static void NDS_CloseAudio(_THIS)
+{
+/* if ( this->hidden->mixbuf != NULL ) {
+ SDL_FreeAudioMem(this->hidden->mixbuf);
+ this->hidden->mixbuf = NULL;
+ }*/
+}
+
+static int NDS_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ //printf("NDS_OpenAudio\n");
+ int format = 0;
+ //switch(spec->format&0xff) {
+ //case 8: spec->format = AUDIO_S8;format=8; break;
+ //case 16: spec->format = AUDIO_S16LSB;format=16; break;
+ //default:
+ // SDL_SetError("Unsupported audio format");
+ // return(-1);
+ //}
+ switch (spec->format&~0x1000) {
+ case AUDIO_S8:
+ /* Signed 8-bit audio supported */
+ format=8;
+ break;
+ case AUDIO_U8:
+ spec->format ^= 0x80;format=8;
+ break;
+ case AUDIO_U16:
+ /* Unsigned 16-bit audio unsupported, convert to S16 */
+ spec->format ^=0x8000;format=16;
+ case AUDIO_S16:
+ /* Signed 16-bit audio supported */
+ format=16;
+ break;
+ }
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ //this->hidden->mixlen = spec->size;
+ //this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
+ //if ( this->hidden->mixbuf == NULL ) {
+ // SDL_SetError("Out of Memory");
+ // return(-1);
+ //}
+
+ SDL_NDSAudio_mutex = 0;
+ sdl_nds_audiodevice=this;
+
+ irqInit();
+ irqSet(IRQ_VBLANK,&InterruptHandler);
+ irqSet(IRQ_FIFO_NOT_EMPTY,&FiFoHandler);
+ irqEnable(IRQ_FIFO_NOT_EMPTY);
+
+ REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR | IPC_FIFO_RECV_IRQ;
+
+
+
+ SoundSystemInit(spec->freq,spec->size,0,format);
+ SoundStartMixer();
+
+
+ return(1);
+}
diff --git a/src/audio/nds/SDL_ndsaudio.h b/src/audio/nds/SDL_ndsaudio.h
new file mode 100644
index 0000000..56e0309
--- /dev/null
+++ b/src/audio/nds/SDL_ndsaudio.h
@@ -0,0 +1,40 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ //Uint8 *mixbuf;
+ //Uint32 mixlen;
+};
+unsigned short SDL_NDSAudio_mutex=0;
+
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/nds/sound9.c b/src/audio/nds/sound9.c
new file mode 100644
index 0000000..aa427ae
--- /dev/null
+++ b/src/audio/nds/sound9.c
@@ -0,0 +1,61 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+#include "SDL_stdinc.h"
+
+#include "soundcommon.h"
+
+void SoundSystemInit(u32 rate,u32 buffersize,u8 channel,u8 format)
+{
+ soundsystem->rate = rate;
+
+ if(format == 8)
+ soundsystem->buffersize = buffersize;
+ else if(format == 16)
+ soundsystem->buffersize = buffersize * sizeof(short);
+
+ soundsystem->mixbuffer = (s8*)SDL_malloc(soundsystem->buffersize);
+ //soundsystem->soundbuffer = soundsystem->mixbuffer;
+ soundsystem->format = format;
+ soundsystem->channel = channel;
+ soundsystem->prevtimer = 0;
+ soundsystem->soundcursor = 0;
+ soundsystem->numsamples = 0;
+ soundsystem->period = 0x1000000 / rate;
+ soundsystem->cmd = INIT;
+}
+
+void SoundStartMixer(void)
+{
+ soundsystem->cmd |= MIX;
+}
+
+void SendCommandToArm7(u32 command)
+{
+ while (REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL);
+ if (REG_IPC_FIFO_CR & IPC_FIFO_ERROR)
+ {
+ REG_IPC_FIFO_CR |= IPC_FIFO_SEND_CLEAR;
+ }
+
+ REG_IPC_FIFO_TX = command;
+}
diff --git a/src/audio/nds/soundcommon.h b/src/audio/nds/soundcommon.h
new file mode 100644
index 0000000..81827df
--- /dev/null
+++ b/src/audio/nds/soundcommon.h
@@ -0,0 +1,80 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef __SOUNDCOMMON_H
+#define __SOUNDCOMMON_H
+
+#include <nds.h>
+
+#define CLOCK (1 << 25)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+ NONE = 0,
+ INIT = 1,
+ MIX = 2,
+ MIXING = 4,
+ STOP = 8
+}CommandType;
+
+typedef enum
+{
+ FIFO_NONE = 0,
+ UPDATEON_ARM9 = 1,
+ MIXCOMPLETE_ONARM9 = 2,
+}FifoType;
+
+typedef struct
+{
+ s8 *mixbuffer;//,*soundbuffer;
+ u32 rate;
+ u32 buffersize;
+ u32 cmd;
+ u8 channel,format;
+ u32 soundcursor,numsamples;
+ s32 prevtimer;
+ s16 period;
+}S_SoundSystem;
+
+#define soundsystem ((S_SoundSystem*)((u32)(IPC)+sizeof(TransferRegion)))
+
+#ifdef ARM9
+extern void SoundSystemInit(u32 rate,u32 buffersize,u8 channel,u8 format);
+extern void SoundStartMixer(void);
+extern void SendCommandToArm7(u32 command);
+#else
+extern void SoundVBlankIrq(void);
+extern void SoundSwapAndMix(void);
+extern void SoundSetTimer(int period);
+extern void SoundFifoHandler(void);
+extern void SendCommandToArm9(u32 command);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/audio/nto/SDL_nto_audio.c b/src/audio/nto/SDL_nto_audio.c
new file mode 100644
index 0000000..612787c
--- /dev/null
+++ b/src/audio/nto/SDL_nto_audio.c
@@ -0,0 +1,507 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sched.h>
+#include <sys/select.h>
+#include <sys/neutrino.h>
+#include <sys/asoundlib.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "SDL_nto_audio.h"
+
+/* The tag name used by NTO audio */
+#define DRIVER_NAME "qsa-nto"
+
+/* default channel communication parameters */
+#define DEFAULT_CPARAMS_RATE 22050
+#define DEFAULT_CPARAMS_VOICES 1
+/* FIXME: need to add in the near future flexible logic with frag_size and frags count */
+#define DEFAULT_CPARAMS_FRAG_SIZE 4096
+#define DEFAULT_CPARAMS_FRAGS_MIN 1
+#define DEFAULT_CPARAMS_FRAGS_MAX 1
+
+/* Open the audio device for playback, and don't block if busy */
+#define OPEN_FLAGS SND_PCM_OPEN_PLAYBACK
+
+#define QSA_NO_WORKAROUNDS 0x00000000
+#define QSA_MMAP_WORKAROUND 0x00000001
+
+struct BuggyCards
+{
+ char* cardname;
+ unsigned long bugtype;
+};
+
+#define QSA_WA_CARDS 3
+
+struct BuggyCards buggycards[QSA_WA_CARDS]=
+{
+ {"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
+ {"Vortex 8820", QSA_MMAP_WORKAROUND},
+ {"Vortex 8830", QSA_MMAP_WORKAROUND},
+};
+
+/* Audio driver functions */
+static void NTO_ThreadInit(_THIS);
+static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec);
+static void NTO_WaitAudio(_THIS);
+static void NTO_PlayAudio(_THIS);
+static Uint8* NTO_GetAudioBuf(_THIS);
+static void NTO_CloseAudio(_THIS);
+
+/* card names check to apply the workarounds */
+static int NTO_CheckBuggyCards(_THIS, unsigned long checkfor)
+{
+ char scardname[33];
+ int it;
+
+ if (snd_card_get_name(cardno, scardname, 32)<0)
+ {
+ return 0;
+ }
+
+ for (it=0; it<QSA_WA_CARDS; it++)
+ {
+ if (SDL_strcmp(buggycards[it].cardname, scardname)==0)
+ {
+ if (buggycards[it].bugtype==checkfor)
+ {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void NTO_ThreadInit(_THIS)
+{
+ int status;
+ struct sched_param param;
+
+ /* increasing default 10 priority to 25 to avoid jerky sound */
+ status=SchedGet(0, 0, &param);
+ param.sched_priority=param.sched_curpriority+15;
+ status=SchedSet(0, 0, SCHED_NOCHANGE, &param);
+}
+
+/* PCM transfer channel parameters initialize function */
+static void NTO_InitAudioParams(snd_pcm_channel_params_t* cpars)
+{
+ SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
+
+ cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
+ cpars->mode = SND_PCM_MODE_BLOCK;
+ cpars->start_mode = SND_PCM_START_DATA;
+ cpars->stop_mode = SND_PCM_STOP_STOP;
+ cpars->format.format = SND_PCM_SFMT_S16_LE;
+ cpars->format.interleave = 1;
+ cpars->format.rate = DEFAULT_CPARAMS_RATE;
+ cpars->format.voices = DEFAULT_CPARAMS_VOICES;
+ cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
+ cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
+ cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
+}
+
+static int NTO_AudioAvailable(void)
+{
+ /* See if we can open a nonblocking channel.
+ Return value '1' means we can.
+ Return value '0' means we cannot. */
+
+ int available;
+ int rval;
+ snd_pcm_t* handle;
+
+ available = 0;
+ handle = NULL;
+
+ rval = snd_pcm_open_preferred(&handle, NULL, NULL, OPEN_FLAGS);
+
+ if (rval >= 0)
+ {
+ available = 1;
+
+ if ((rval = snd_pcm_close(handle)) < 0)
+ {
+ SDL_SetError("NTO_AudioAvailable(): snd_pcm_close failed: %s\n", snd_strerror(rval));
+ available = 0;
+ }
+ }
+ else
+ {
+ SDL_SetError("NTO_AudioAvailable(): there are no available audio devices.\n");
+ }
+
+ return (available);
+}
+
+static void NTO_DeleteAudioDevice(SDL_AudioDevice *device)
+{
+ if ((device)&&(device->hidden))
+ {
+ SDL_free(device->hidden);
+ }
+ if (device)
+ {
+ SDL_free(device);
+ }
+}
+
+static SDL_AudioDevice* NTO_CreateAudioDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if (this)
+ {
+ SDL_memset(this, 0, sizeof(SDL_AudioDevice));
+ this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(struct SDL_PrivateAudioData));
+ }
+ if ((this == NULL) || (this->hidden == NULL))
+ {
+ SDL_OutOfMemory();
+ if (this)
+ {
+ SDL_free(this);
+ }
+ return (0);
+ }
+ SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
+ audio_handle = NULL;
+
+ /* Set the function pointers */
+ this->ThreadInit = NTO_ThreadInit;
+ this->OpenAudio = NTO_OpenAudio;
+ this->WaitAudio = NTO_WaitAudio;
+ this->PlayAudio = NTO_PlayAudio;
+ this->GetAudioBuf = NTO_GetAudioBuf;
+ this->CloseAudio = NTO_CloseAudio;
+
+ this->free = NTO_DeleteAudioDevice;
+
+ return this;
+}
+
+AudioBootStrap QNXNTOAUDIO_bootstrap =
+{
+ DRIVER_NAME, "QNX6 QSA-NTO Audio",
+ NTO_AudioAvailable,
+ NTO_CreateAudioDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void NTO_WaitAudio(_THIS)
+{
+ fd_set wfds;
+ int selectret;
+
+ FD_ZERO(&wfds);
+ FD_SET(audio_fd, &wfds);
+
+ do {
+ selectret=select(audio_fd + 1, NULL, &wfds, NULL, NULL);
+ switch (selectret)
+ {
+ case -1:
+ case 0: SDL_SetError("NTO_WaitAudio(): select() failed: %s\n", strerror(errno));
+ return;
+ default: if (FD_ISSET(audio_fd, &wfds))
+ {
+ return;
+ }
+ break;
+ }
+ } while(1);
+}
+
+static void NTO_PlayAudio(_THIS)
+{
+ int written, rval;
+ int towrite;
+ void* pcmbuffer;
+
+ if (!this->enabled)
+ {
+ return;
+ }
+
+ towrite = this->spec.size;
+ pcmbuffer = pcm_buf;
+
+ /* Write the audio data, checking for EAGAIN (buffer full) and underrun */
+ do {
+ written = snd_pcm_plugin_write(audio_handle, pcm_buf, towrite);
+ if (written != towrite)
+ {
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+ {
+ /* Let a little CPU time go by and try to write again */
+ SDL_Delay(1);
+ /* if we wrote some data */
+ towrite -= written;
+ pcmbuffer += written * this->spec.channels;
+ continue;
+ }
+ else
+ {
+ if ((errno == EINVAL) || (errno == EIO))
+ {
+ SDL_memset(&cstatus, 0, sizeof(cstatus));
+ cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if ((rval = snd_pcm_plugin_status(audio_handle, &cstatus)) < 0)
+ {
+ SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_status failed: %s\n", snd_strerror(rval));
+ return;
+ }
+ if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY))
+ {
+ if ((rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
+ {
+ SDL_SetError("NTO_PlayAudio(): snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval));
+ return;
+ }
+ }
+ continue;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* we wrote all remaining data */
+ towrite -= written;
+ pcmbuffer += written * this->spec.channels;
+ }
+ } while ((towrite > 0) && (this->enabled));
+
+ /* If we couldn't write, assume fatal error for now */
+ if (towrite != 0)
+ {
+ this->enabled = 0;
+ }
+
+ return;
+}
+
+static Uint8* NTO_GetAudioBuf(_THIS)
+{
+ return pcm_buf;
+}
+
+static void NTO_CloseAudio(_THIS)
+{
+ int rval;
+
+ this->enabled = 0;
+
+ if (audio_handle != NULL)
+ {
+ if ((rval = snd_pcm_plugin_flush(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
+ {
+ SDL_SetError("NTO_CloseAudio(): snd_pcm_plugin_flush failed: %s\n", snd_strerror(rval));
+ return;
+ }
+ if ((rval = snd_pcm_close(audio_handle)) < 0)
+ {
+ SDL_SetError("NTO_CloseAudio(): snd_pcm_close failed: %s\n",snd_strerror(rval));
+ return;
+ }
+ audio_handle = NULL;
+ }
+}
+
+static int NTO_OpenAudio(_THIS, SDL_AudioSpec* spec)
+{
+ int rval;
+ int format;
+ Uint16 test_format;
+ int found;
+
+ audio_handle = NULL;
+ this->enabled = 0;
+
+ if (pcm_buf != NULL)
+ {
+ SDL_FreeAudioMem(pcm_buf);
+ pcm_buf = NULL;
+ }
+
+ /* initialize channel transfer parameters to default */
+ NTO_InitAudioParams(&cparams);
+
+ /* Open the audio device */
+ rval = snd_pcm_open_preferred(&audio_handle, &cardno, &deviceno, OPEN_FLAGS);
+ if (rval < 0)
+ {
+ SDL_SetError("NTO_OpenAudio(): snd_pcm_open failed: %s\n", snd_strerror(rval));
+ return (-1);
+ }
+
+ if (!NTO_CheckBuggyCards(this, QSA_MMAP_WORKAROUND))
+ {
+ /* enable count status parameter */
+ if ((rval = snd_pcm_plugin_set_disable(audio_handle, PLUGIN_DISABLE_MMAP)) < 0)
+ {
+ SDL_SetError("snd_pcm_plugin_set_disable failed: %s\n", snd_strerror(rval));
+ return (-1);
+ }
+ }
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ /* can't use format as SND_PCM_SFMT_U8 = 0 in nto */
+ found = 0;
+
+ for (test_format=SDL_FirstAudioFormat(spec->format); !found ;)
+ {
+ /* if match found set format to equivalent ALSA format */
+ switch (test_format)
+ {
+ case AUDIO_U8:
+ format = SND_PCM_SFMT_U8;
+ found = 1;
+ break;
+ case AUDIO_S8:
+ format = SND_PCM_SFMT_S8;
+ found = 1;
+ break;
+ case AUDIO_S16LSB:
+ format = SND_PCM_SFMT_S16_LE;
+ found = 1;
+ break;
+ case AUDIO_S16MSB:
+ format = SND_PCM_SFMT_S16_BE;
+ found = 1;
+ break;
+ case AUDIO_U16LSB:
+ format = SND_PCM_SFMT_U16_LE;
+ found = 1;
+ break;
+ case AUDIO_U16MSB:
+ format = SND_PCM_SFMT_U16_BE;
+ found = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (!found)
+ {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+
+ /* assumes test_format not 0 on success */
+ if (test_format == 0)
+ {
+ SDL_SetError("NTO_OpenAudio(): Couldn't find any hardware audio formats");
+ return (-1);
+ }
+
+ spec->format = test_format;
+
+ /* Set the audio format */
+ cparams.format.format = format;
+
+ /* Set mono or stereo audio (currently only two channels supported) */
+ cparams.format.voices = spec->channels;
+
+ /* Set rate */
+ cparams.format.rate = spec->freq;
+
+ /* Setup the transfer parameters according to cparams */
+ rval = snd_pcm_plugin_params(audio_handle, &cparams);
+ if (rval < 0)
+ {
+ SDL_SetError("NTO_OpenAudio(): snd_pcm_channel_params failed: %s\n", snd_strerror(rval));
+ return (-1);
+ }
+
+ /* Make sure channel is setup right one last time */
+ SDL_memset(&csetup, 0x00, sizeof(csetup));
+ csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
+ if (snd_pcm_plugin_setup(audio_handle, &csetup) < 0)
+ {
+ SDL_SetError("NTO_OpenAudio(): Unable to setup playback channel\n");
+ return -1;
+ }
+
+
+ /* Calculate the final parameters for this audio specification */
+ SDL_CalculateAudioSpec(spec);
+
+ pcm_len = spec->size;
+
+ if (pcm_len==0)
+ {
+ pcm_len = csetup.buf.block.frag_size * spec->channels * (snd_pcm_format_width(format)/8);
+ }
+
+ /* Allocate memory to the audio buffer and initialize with silence (Note that
+ buffer size must be a multiple of fragment size, so find closest multiple)
+ */
+ pcm_buf = (Uint8*)SDL_AllocAudioMem(pcm_len);
+ if (pcm_buf == NULL)
+ {
+ SDL_SetError("NTO_OpenAudio(): pcm buffer allocation failed\n");
+ return (-1);
+ }
+ SDL_memset(pcm_buf, spec->silence, pcm_len);
+
+ /* get the file descriptor */
+ if ((audio_fd = snd_pcm_file_descriptor(audio_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
+ {
+ SDL_SetError("NTO_OpenAudio(): snd_pcm_file_descriptor failed with error code: %s\n", snd_strerror(rval));
+ return (-1);
+ }
+
+ /* Trigger audio playback */
+ rval = snd_pcm_plugin_prepare(audio_handle, SND_PCM_CHANNEL_PLAYBACK);
+ if (rval < 0)
+ {
+ SDL_SetError("snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rval));
+ return (-1);
+ }
+
+ this->enabled = 1;
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+ /* We're really ready to rock and roll. :-) */
+ return (0);
+}
diff --git a/src/audio/nto/SDL_nto_audio.h b/src/audio/nto/SDL_nto_audio.h
new file mode 100644
index 0000000..cae9225
--- /dev/null
+++ b/src/audio/nto/SDL_nto_audio.h
@@ -0,0 +1,68 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef __SDL_NTO_AUDIO_H__
+#define __SDL_NTO_AUDIO_H__
+
+#include <sys/asoundlib.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* The audio device handle */
+ int cardno;
+ int deviceno;
+ snd_pcm_t* audio_handle;
+
+ /* The audio file descriptor */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8* pcm_buf;
+ Uint32 pcm_len;
+
+ /* QSA parameters */
+ snd_pcm_channel_status_t cstatus;
+ snd_pcm_channel_params_t cparams;
+ snd_pcm_channel_setup_t csetup;
+};
+
+#define cardno (this->hidden->cardno)
+#define deviceno (this->hidden->deviceno)
+#define audio_handle (this->hidden->audio_handle)
+#define audio_fd (this->hidden->audio_fd)
+#define parent (this->hidden->parent)
+#define pcm_buf (this->hidden->pcm_buf)
+#define pcm_len (this->hidden->pcm_len)
+#define cstatus (this->hidden->cstatus)
+#define cparams (this->hidden->cparams)
+#define csetup (this->hidden->csetup)
+
+#endif /* __SDL_NTO_AUDIO_H__ */
diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c
new file mode 100644
index 0000000..6795e1e
--- /dev/null
+++ b/src/audio/paudio/SDL_paudio.c
@@ -0,0 +1,511 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Carsten Griwodz
+ griff@kom.tu-darmstadt.de
+
+ based on linux/SDL_dspaudio.c by Sam Lantinga
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_paudio.h"
+
+#define DEBUG_AUDIO 1
+
+/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
+ * I guess nobody ever uses audio... Shame over AIX header files. */
+#include <sys/machine.h>
+#undef BIG_ENDIAN
+#include <sys/audio.h>
+
+/* The tag name used by paud audio */
+#define Paud_DRIVER_NAME "paud"
+
+/* Open the audio device for playback, and don't block if busy */
+/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
+#define OPEN_FLAGS O_WRONLY
+
+/* Audio driver functions */
+static int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void Paud_WaitAudio(_THIS);
+static void Paud_PlayAudio(_THIS);
+static Uint8 *Paud_GetAudioBuf(_THIS);
+static void Paud_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int fd;
+ int available;
+
+ available = 0;
+ fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
+ if ( fd >= 0 ) {
+ available = 1;
+ close(fd);
+ }
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ audio_fd = -1;
+
+ /* Set the function pointers */
+ this->OpenAudio = Paud_OpenAudio;
+ this->WaitAudio = Paud_WaitAudio;
+ this->PlayAudio = Paud_PlayAudio;
+ this->GetAudioBuf = Paud_GetAudioBuf;
+ this->CloseAudio = Paud_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap Paud_bootstrap = {
+ Paud_DRIVER_NAME, "AIX Paudio",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void Paud_WaitAudio(_THIS)
+{
+ fd_set fdset;
+
+ /* See if we need to use timed audio synchronization */
+ if ( frame_ticks ) {
+ /* Use timer for general audio synchronization */
+ Sint32 ticks;
+
+ ticks = ((Sint32)(next_frame - SDL_GetTicks()))-FUDGE_TICKS;
+ if ( ticks > 0 ) {
+ SDL_Delay(ticks);
+ }
+ } else {
+ audio_buffer paud_bufinfo;
+
+ /* Use select() for audio synchronization */
+ struct timeval timeout;
+ FD_ZERO(&fdset);
+ FD_SET(audio_fd, &fdset);
+
+ if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Couldn't get audio buffer information\n");
+#endif
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 0;
+ } else {
+ long ms_in_buf = paud_bufinfo.write_buf_time;
+ timeout.tv_sec = ms_in_buf/1000;
+ ms_in_buf = ms_in_buf - timeout.tv_sec*1000;
+ timeout.tv_usec = ms_in_buf*1000;
+#ifdef DEBUG_AUDIO
+ fprintf( stderr,
+ "Waiting for write_buf_time=%ld,%ld\n",
+ timeout.tv_sec,
+ timeout.tv_usec );
+#endif
+ }
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Waiting for audio to get ready\n");
+#endif
+ if ( select(audio_fd+1, NULL, &fdset, NULL, &timeout) <= 0 ) {
+ const char *message = "Audio timeout - buggy audio driver? (disabled)";
+ /*
+ * In general we should never print to the screen,
+ * but in this case we have no other way of letting
+ * the user know what happened.
+ */
+ fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message);
+ this->enabled = 0;
+ /* Don't try to close - may hang */
+ audio_fd = -1;
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Done disabling audio\n");
+#endif
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Ready!\n");
+#endif
+ }
+}
+
+static void Paud_PlayAudio(_THIS)
+{
+ int written;
+
+ /* Write the audio data, checking for EAGAIN on broken audio drivers */
+ do {
+ written = write(audio_fd, mixbuf, mixlen);
+ if ( (written < 0) && ((errno == 0) || (errno == EAGAIN)) ) {
+ SDL_Delay(1); /* Let a little CPU time go by */
+ }
+ } while ( (written < 0) &&
+ ((errno == 0) || (errno == EAGAIN) || (errno == EINTR)) );
+
+ /* If timer synchronization is enabled, set the next write frame */
+ if ( frame_ticks ) {
+ next_frame += frame_ticks;
+ }
+
+ /* If we couldn't write, assume fatal error for now */
+ if ( written < 0 ) {
+ this->enabled = 0;
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
+}
+
+static Uint8 *Paud_GetAudioBuf(_THIS)
+{
+ return mixbuf;
+}
+
+static void Paud_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( audio_fd >= 0 ) {
+ close(audio_fd);
+ audio_fd = -1;
+ }
+}
+
+static int Paud_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ char audiodev[1024];
+ int format;
+ int bytes_per_sample;
+ Uint16 test_format;
+ audio_init paud_init;
+ audio_buffer paud_bufinfo;
+ audio_status paud_status;
+ audio_control paud_control;
+ audio_change paud_change;
+
+ /* Reset the timer synchronization flag */
+ frame_ticks = 0.0;
+
+ /* Open the audio device */
+ audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
+ if ( audio_fd < 0 ) {
+ SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ return -1;
+ }
+
+ /*
+ * We can't set the buffer size - just ask the device for the maximum
+ * that we can have.
+ */
+ if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 ) {
+ SDL_SetError("Couldn't get audio buffer information");
+ return -1;
+ }
+
+ mixbuf = NULL;
+
+ if ( spec->channels > 1 )
+ spec->channels = 2;
+ else
+ spec->channels = 1;
+
+ /*
+ * Fields in the audio_init structure:
+ *
+ * Ignored by us:
+ *
+ * paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
+ * paud.slot_number; * slot number of the adapter
+ * paud.device_id; * adapter identification number
+ *
+ * Input:
+ *
+ * paud.srate; * the sampling rate in Hz
+ * paud.bits_per_sample; * 8, 16, 32, ...
+ * paud.bsize; * block size for this rate
+ * paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
+ * paud.channels; * 1=mono, 2=stereo
+ * paud.flags; * FIXED - fixed length data
+ * * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
+ * * TWOS_COMPLEMENT - 2's complement data
+ * * SIGNED - signed? comment seems wrong in sys/audio.h
+ * * BIG_ENDIAN
+ * paud.operation; * PLAY, RECORD
+ *
+ * Output:
+ *
+ * paud.flags; * PITCH - pitch is supported
+ * * INPUT - input is supported
+ * * OUTPUT - output is supported
+ * * MONITOR - monitor is supported
+ * * VOLUME - volume is supported
+ * * VOLUME_DELAY - volume delay is supported
+ * * BALANCE - balance is supported
+ * * BALANCE_DELAY - balance delay is supported
+ * * TREBLE - treble control is supported
+ * * BASS - bass control is supported
+ * * BESTFIT_PROVIDED - best fit returned
+ * * LOAD_CODE - DSP load needed
+ * paud.rc; * NO_PLAY - DSP code can't do play requests
+ * * NO_RECORD - DSP code can't do record requests
+ * * INVALID_REQUEST - request was invalid
+ * * CONFLICT - conflict with open's flags
+ * * OVERLOADED - out of DSP MIPS or memory
+ * paud.position_resolution; * smallest increment for position
+ */
+
+ paud_init.srate = spec->freq;
+ paud_init.mode = PCM;
+ paud_init.operation = PLAY;
+ paud_init.channels = spec->channels;
+
+ /* Try for a closest match on audio format */
+ format = 0;
+ for ( test_format = SDL_FirstAudioFormat(spec->format);
+ ! format && test_format; ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch ( test_format ) {
+ case AUDIO_U8:
+ bytes_per_sample = 1;
+ paud_init.bits_per_sample = 8;
+ paud_init.flags = TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_S8:
+ bytes_per_sample = 1;
+ paud_init.bits_per_sample = 8;
+ paud_init.flags = SIGNED |
+ TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_S16LSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = SIGNED |
+ TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_S16MSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = BIG_ENDIAN |
+ SIGNED |
+ TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_U16LSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ case AUDIO_U16MSB:
+ bytes_per_sample = 2;
+ paud_init.bits_per_sample = 16;
+ paud_init.flags = BIG_ENDIAN |
+ TWOS_COMPLEMENT | FIXED;
+ format = 1;
+ break;
+ default:
+ break;
+ }
+ if ( ! format ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ if ( format == 0 ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Couldn't find any hardware audio formats\n");
+#endif
+ SDL_SetError("Couldn't find any hardware audio formats");
+ return -1;
+ }
+ spec->format = test_format;
+
+ /*
+ * We know the buffer size and the max number of subsequent writes
+ * that can be pending. If more than one can pend, allow the application
+ * to do something like double buffering between our write buffer and
+ * the device's own buffer that we are filling with write() anyway.
+ *
+ * We calculate spec->samples like this because SDL_CalculateAudioSpec()
+ * will give put paud_bufinfo.write_buf_cap (or paud_bufinfo.write_buf_cap/2)
+ * into spec->size in return.
+ */
+ if ( paud_bufinfo.request_buf_cap == 1 )
+ {
+ spec->samples = paud_bufinfo.write_buf_cap
+ / bytes_per_sample
+ / spec->channels;
+ }
+ else
+ {
+ spec->samples = paud_bufinfo.write_buf_cap
+ / bytes_per_sample
+ / spec->channels
+ / 2;
+ }
+ paud_init.bsize = bytes_per_sample * spec->channels;
+
+ SDL_CalculateAudioSpec(spec);
+
+ /*
+ * The AIX paud device init can't modify the values of the audio_init
+ * structure that we pass to it. So we don't need any recalculation
+ * of this stuff and no reinit call as in linux dsp and dma code.
+ *
+ * /dev/paud supports all of the encoding formats, so we don't need
+ * to do anything like reopening the device, either.
+ */
+ if ( ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0 ) {
+ switch ( paud_init.rc )
+ {
+ case 1 :
+ SDL_SetError("Couldn't set audio format: DSP can't do play requests");
+ return -1;
+ break;
+ case 2 :
+ SDL_SetError("Couldn't set audio format: DSP can't do record requests");
+ return -1;
+ break;
+ case 4 :
+ SDL_SetError("Couldn't set audio format: request was invalid");
+ return -1;
+ break;
+ case 5 :
+ SDL_SetError("Couldn't set audio format: conflict with open's flags");
+ return -1;
+ break;
+ case 6 :
+ SDL_SetError("Couldn't set audio format: out of DSP MIPS or memory");
+ return -1;
+ break;
+ default :
+ SDL_SetError("Couldn't set audio format: not documented in sys/audio.h");
+ return -1;
+ break;
+ }
+ }
+
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+ if ( mixbuf == NULL ) {
+ return -1;
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /*
+ * Set some paramters: full volume, first speaker that we can find.
+ * Ignore the other settings for now.
+ */
+ paud_change.input = AUDIO_IGNORE; /* the new input source */
+ paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
+ paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
+ paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
+ paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
+ paud_change.balance = 0x3fffffff; /* the new balance */
+ paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
+ paud_change.treble = AUDIO_IGNORE; /* the new treble state */
+ paud_change.bass = AUDIO_IGNORE; /* the new bass state */
+ paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
+
+ paud_control.ioctl_request = AUDIO_CHANGE;
+ paud_control.request_info = (char*)&paud_change;
+ if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Can't change audio display settings\n" );
+#endif
+ }
+
+ /*
+ * Tell the device to expect data. Actual start will wait for
+ * the first write() call.
+ */
+ paud_control.ioctl_request = AUDIO_START;
+ paud_control.position = 0;
+ if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Can't start audio play\n" );
+#endif
+ SDL_SetError("Can't start audio play");
+ return -1;
+ }
+
+ /* Check to see if we need to use select() workaround */
+ { char *workaround;
+ workaround = SDL_getenv("SDL_DSP_NOSELECT");
+ if ( workaround ) {
+ frame_ticks = (float)(spec->samples*1000)/spec->freq;
+ next_frame = SDL_GetTicks()+frame_ticks;
+ }
+ }
+
+ /* Get the parent process id (we're the parent of the audio thread) */
+ parent = getpid();
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
diff --git a/src/audio/paudio/SDL_paudio.h b/src/audio/paudio/SDL_paudio.h
new file mode 100644
index 0000000..6e10bbb
--- /dev/null
+++ b/src/audio/paudio/SDL_paudio.h
@@ -0,0 +1,57 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_paudaudio_h
+#define _SDL_paudaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ /* The parent process id, to detect when application quits */
+ pid_t parent;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+
+ /* Support for audio timing using a timer, in addition to select() */
+ float frame_ticks;
+ float next_frame;
+};
+#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
+
+/* Old variable names */
+#define audio_fd (this->hidden->audio_fd)
+#define parent (this->hidden->parent)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+#define frame_ticks (this->hidden->frame_ticks)
+#define next_frame (this->hidden->next_frame)
+
+#endif /* _SDL_paudaudio_h */
diff --git a/src/audio/pulse/SDL_pulseaudio.c b/src/audio/pulse/SDL_pulseaudio.c
new file mode 100644
index 0000000..21e51cd
--- /dev/null
+++ b/src/audio/pulse/SDL_pulseaudio.c
@@ -0,0 +1,534 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Stéphan Kochen
+ stephan@kochen.nl
+
+ Based on parts of the ALSA and ESounD output drivers.
+*/
+#include "SDL_config.h"
+
+/* Allow access to an PulseAudio network stream mixing buffer */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <pulse/pulseaudio.h>
+#include <pulse/simple.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_pulseaudio.h"
+
+#ifdef SDL_AUDIO_DRIVER_PULSE_DYNAMIC
+#include "SDL_name.h"
+#include "SDL_loadso.h"
+#else
+#define SDL_NAME(X) X
+#endif
+
+/* The tag name used by the driver */
+#define PULSE_DRIVER_NAME "pulse"
+
+/* Audio driver functions */
+static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void PULSE_WaitAudio(_THIS);
+static void PULSE_PlayAudio(_THIS);
+static Uint8 *PULSE_GetAudioBuf(_THIS);
+static void PULSE_CloseAudio(_THIS);
+static void PULSE_WaitDone(_THIS);
+
+#ifdef SDL_AUDIO_DRIVER_PULSE_DYNAMIC
+
+static const char *pulse_library = SDL_AUDIO_DRIVER_PULSE_DYNAMIC;
+static void *pulse_handle = NULL;
+static int pulse_loaded = 0;
+
+static pa_simple* (*SDL_NAME(pa_simple_new))(
+ const char *server,
+ const char *name,
+ pa_stream_direction_t dir,
+ const char *dev,
+ const char *stream_name,
+ const pa_sample_spec *ss,
+ const pa_channel_map *map,
+ const pa_buffer_attr *attr,
+ int *error
+);
+static void (*SDL_NAME(pa_simple_free))(pa_simple *s);
+
+static pa_channel_map* (*SDL_NAME(pa_channel_map_init_auto))(
+ pa_channel_map *m,
+ unsigned channels,
+ pa_channel_map_def_t def
+);
+
+pa_mainloop * (*SDL_NAME(pa_mainloop_new))(void);
+pa_mainloop_api * (*SDL_NAME(pa_mainloop_get_api))(pa_mainloop *m);
+int (*SDL_NAME(pa_mainloop_iterate))(pa_mainloop *m, int block, int *retval);
+void (*SDL_NAME(pa_mainloop_free))(pa_mainloop *m);
+
+pa_operation_state_t (*SDL_NAME(pa_operation_get_state))(pa_operation *o);
+void (*SDL_NAME(pa_operation_cancel))(pa_operation *o);
+void (*SDL_NAME(pa_operation_unref))(pa_operation *o);
+
+pa_context * (*SDL_NAME(pa_context_new))(
+ pa_mainloop_api *m, const char *name);
+int (*SDL_NAME(pa_context_connect))(
+ pa_context *c, const char *server,
+ pa_context_flags_t flags, const pa_spawn_api *api);
+pa_context_state_t (*SDL_NAME(pa_context_get_state))(pa_context *c);
+void (*SDL_NAME(pa_context_disconnect))(pa_context *c);
+void (*SDL_NAME(pa_context_unref))(pa_context *c);
+
+pa_stream * (*SDL_NAME(pa_stream_new))(pa_context *c,
+ const char *name, const pa_sample_spec *ss, const pa_channel_map *map);
+int (*SDL_NAME(pa_stream_connect_playback))(pa_stream *s, const char *dev,
+ const pa_buffer_attr *attr, pa_stream_flags_t flags,
+ pa_cvolume *volume, pa_stream *sync_stream);
+pa_stream_state_t (*SDL_NAME(pa_stream_get_state))(pa_stream *s);
+size_t (*SDL_NAME(pa_stream_writable_size))(pa_stream *s);
+int (*SDL_NAME(pa_stream_write))(pa_stream *s, const void *data, size_t nbytes,
+ pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek);
+pa_operation * (*SDL_NAME(pa_stream_drain))(pa_stream *s,
+ pa_stream_success_cb_t cb, void *userdata);
+int (*SDL_NAME(pa_stream_disconnect))(pa_stream *s);
+void (*SDL_NAME(pa_stream_unref))(pa_stream *s);
+
+static struct {
+ const char *name;
+ void **func;
+} pulse_functions[] = {
+ { "pa_simple_new",
+ (void **)&SDL_NAME(pa_simple_new) },
+ { "pa_simple_free",
+ (void **)&SDL_NAME(pa_simple_free) },
+ { "pa_channel_map_init_auto",
+ (void **)&SDL_NAME(pa_channel_map_init_auto) },
+ { "pa_mainloop_new",
+ (void **)&SDL_NAME(pa_mainloop_new) },
+ { "pa_mainloop_get_api",
+ (void **)&SDL_NAME(pa_mainloop_get_api) },
+ { "pa_mainloop_iterate",
+ (void **)&SDL_NAME(pa_mainloop_iterate) },
+ { "pa_mainloop_free",
+ (void **)&SDL_NAME(pa_mainloop_free) },
+ { "pa_operation_get_state",
+ (void **)&SDL_NAME(pa_operation_get_state) },
+ { "pa_operation_cancel",
+ (void **)&SDL_NAME(pa_operation_cancel) },
+ { "pa_operation_unref",
+ (void **)&SDL_NAME(pa_operation_unref) },
+ { "pa_context_new",
+ (void **)&SDL_NAME(pa_context_new) },
+ { "pa_context_connect",
+ (void **)&SDL_NAME(pa_context_connect) },
+ { "pa_context_get_state",
+ (void **)&SDL_NAME(pa_context_get_state) },
+ { "pa_context_disconnect",
+ (void **)&SDL_NAME(pa_context_disconnect) },
+ { "pa_context_unref",
+ (void **)&SDL_NAME(pa_context_unref) },
+ { "pa_stream_new",
+ (void **)&SDL_NAME(pa_stream_new) },
+ { "pa_stream_connect_playback",
+ (void **)&SDL_NAME(pa_stream_connect_playback) },
+ { "pa_stream_get_state",
+ (void **)&SDL_NAME(pa_stream_get_state) },
+ { "pa_stream_writable_size",
+ (void **)&SDL_NAME(pa_stream_writable_size) },
+ { "pa_stream_write",
+ (void **)&SDL_NAME(pa_stream_write) },
+ { "pa_stream_drain",
+ (void **)&SDL_NAME(pa_stream_drain) },
+ { "pa_stream_disconnect",
+ (void **)&SDL_NAME(pa_stream_disconnect) },
+ { "pa_stream_unref",
+ (void **)&SDL_NAME(pa_stream_unref) },
+};
+
+static void UnloadPulseLibrary()
+{
+ if ( pulse_loaded ) {
+ SDL_UnloadObject(pulse_handle);
+ pulse_handle = NULL;
+ pulse_loaded = 0;
+ }
+}
+
+static int LoadPulseLibrary(void)
+{
+ int i, retval = -1;
+
+ pulse_handle = SDL_LoadObject(pulse_library);
+ if ( pulse_handle ) {
+ pulse_loaded = 1;
+ retval = 0;
+ for ( i=0; i<SDL_arraysize(pulse_functions); ++i ) {
+ *pulse_functions[i].func = SDL_LoadFunction(pulse_handle, pulse_functions[i].name);
+ if ( !*pulse_functions[i].func ) {
+ retval = -1;
+ UnloadPulseLibrary();
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+#else
+
+static void UnloadPulseLibrary()
+{
+ return;
+}
+
+static int LoadPulseLibrary(void)
+{
+ return 0;
+}
+
+#endif /* SDL_AUDIO_DRIVER_PULSE_DYNAMIC */
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ pa_sample_spec paspec;
+ pa_simple *connection;
+ int available;
+
+ available = 0;
+ if ( LoadPulseLibrary() < 0 ) {
+ return available;
+ }
+
+ /* Connect with a dummy format. */
+ paspec.format = PA_SAMPLE_U8;
+ paspec.rate = 11025;
+ paspec.channels = 1;
+ connection = SDL_NAME(pa_simple_new)(
+ NULL, /* server */
+ "Test stream", /* application name */
+ PA_STREAM_PLAYBACK, /* playback mode */
+ NULL, /* device on the server */
+ "Simple DirectMedia Layer", /* stream description */
+ &paspec, /* sample format spec */
+ NULL, /* channel map */
+ NULL, /* buffering attributes */
+ NULL /* error code */
+ );
+ if ( connection != NULL ) {
+ available = 1;
+ SDL_NAME(pa_simple_free)(connection);
+ }
+
+ UnloadPulseLibrary();
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+ UnloadPulseLibrary();
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ LoadPulseLibrary();
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = PULSE_OpenAudio;
+ this->WaitAudio = PULSE_WaitAudio;
+ this->PlayAudio = PULSE_PlayAudio;
+ this->GetAudioBuf = PULSE_GetAudioBuf;
+ this->CloseAudio = PULSE_CloseAudio;
+ this->WaitDone = PULSE_WaitDone;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap PULSE_bootstrap = {
+ PULSE_DRIVER_NAME, "PulseAudio",
+ Audio_Available, Audio_CreateDevice
+};
+
+/* This function waits until it is possible to write a full sound buffer */
+static void PULSE_WaitAudio(_THIS)
+{
+ int size;
+ while(1) {
+ if (SDL_NAME(pa_context_get_state)(context) != PA_CONTEXT_READY ||
+ SDL_NAME(pa_stream_get_state)(stream) != PA_STREAM_READY ||
+ SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
+ this->enabled = 0;
+ return;
+ }
+ size = SDL_NAME(pa_stream_writable_size)(stream);
+ if (size >= mixlen)
+ return;
+ }
+}
+
+static void PULSE_PlayAudio(_THIS)
+{
+ /* Write the audio data */
+ if (SDL_NAME(pa_stream_write)(stream, mixbuf, mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0)
+ this->enabled = 0;
+}
+
+static Uint8 *PULSE_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+static void PULSE_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( stream != NULL ) {
+ SDL_NAME(pa_stream_disconnect)(stream);
+ SDL_NAME(pa_stream_unref)(stream);
+ stream = NULL;
+ }
+ if (context != NULL) {
+ SDL_NAME(pa_context_disconnect)(context);
+ SDL_NAME(pa_context_unref)(context);
+ context = NULL;
+ }
+ if (mainloop != NULL) {
+ SDL_NAME(pa_mainloop_free)(mainloop);
+ mainloop = NULL;
+ }
+}
+
+/* Try to get the name of the program */
+static char *get_progname(void)
+{
+#ifdef __LINUX__
+ char *progname = NULL;
+ FILE *fp;
+ static char temp[BUFSIZ];
+
+ SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
+ fp = fopen(temp, "r");
+ if ( fp != NULL ) {
+ if ( fgets(temp, sizeof(temp)-1, fp) ) {
+ progname = SDL_strrchr(temp, '/');
+ if ( progname == NULL ) {
+ progname = temp;
+ } else {
+ progname = progname+1;
+ }
+ }
+ fclose(fp);
+ }
+ return(progname);
+#elif defined(__NetBSD__)
+ return getprogname();
+#else
+ return("unknown");
+#endif
+}
+
+static void stream_drain_complete(pa_stream *s, int success, void *userdata) {
+}
+
+static void PULSE_WaitDone(_THIS)
+{
+ pa_operation *o;
+
+ o = SDL_NAME(pa_stream_drain)(stream, stream_drain_complete, NULL);
+ if (!o)
+ return;
+
+ while (SDL_NAME(pa_operation_get_state)(o) != PA_OPERATION_DONE) {
+ if (SDL_NAME(pa_context_get_state)(context) != PA_CONTEXT_READY ||
+ SDL_NAME(pa_stream_get_state)(stream) != PA_STREAM_READY ||
+ SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
+ SDL_NAME(pa_operation_cancel)(o);
+ break;
+ }
+ }
+ SDL_NAME(pa_operation_unref)(o);
+}
+
+static int PULSE_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ int state;
+ Uint16 test_format;
+ pa_sample_spec paspec;
+ pa_buffer_attr paattr;
+ pa_channel_map pacmap;
+ pa_stream_flags_t flags = 0;
+
+ paspec.format = PA_SAMPLE_INVALID;
+ for ( test_format = SDL_FirstAudioFormat(spec->format); test_format; ) {
+ switch ( test_format ) {
+ case AUDIO_U8:
+ paspec.format = PA_SAMPLE_U8;
+ break;
+ case AUDIO_S16LSB:
+ paspec.format = PA_SAMPLE_S16LE;
+ break;
+ case AUDIO_S16MSB:
+ paspec.format = PA_SAMPLE_S16BE;
+ break;
+ }
+ if ( paspec.format != PA_SAMPLE_INVALID )
+ break;
+ }
+ if (paspec.format == PA_SAMPLE_INVALID ) {
+ SDL_SetError("Couldn't find any suitable audio formats");
+ return(-1);
+ }
+ spec->format = test_format;
+
+ paspec.channels = spec->channels;
+ paspec.rate = spec->freq;
+
+ /* Calculate the final parameters for this audio specification */
+#ifdef PA_STREAM_ADJUST_LATENCY
+ spec->samples /= 2; /* Mix in smaller chunck to avoid underruns */
+#endif
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ mixlen = spec->size;
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen);
+ if ( mixbuf == NULL ) {
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* Reduced prebuffering compared to the defaults. */
+#ifdef PA_STREAM_ADJUST_LATENCY
+ paattr.tlength = mixlen * 4; /* 2x original requested bufsize */
+ paattr.prebuf = -1;
+ paattr.maxlength = -1;
+ paattr.minreq = mixlen; /* -1 can lead to pa_stream_writable_size()
+ >= mixlen never becoming true */
+ flags = PA_STREAM_ADJUST_LATENCY;
+#else
+ paattr.tlength = mixlen*2;
+ paattr.prebuf = mixlen*2;
+ paattr.maxlength = mixlen*2;
+ paattr.minreq = mixlen;
+#endif
+
+ /* The SDL ALSA output hints us that we use Windows' channel mapping */
+ /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
+ SDL_NAME(pa_channel_map_init_auto)(
+ &pacmap, spec->channels, PA_CHANNEL_MAP_WAVEEX);
+
+ /* Set up a new main loop */
+ if (!(mainloop = SDL_NAME(pa_mainloop_new)())) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("pa_mainloop_new() failed");
+ return(-1);
+ }
+
+ mainloop_api = SDL_NAME(pa_mainloop_get_api)(mainloop);
+ if (!(context = SDL_NAME(pa_context_new)(mainloop_api, get_progname()))) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("pa_context_new() failed");
+ return(-1);
+ }
+
+ /* Connect to the PulseAudio server */
+ if (SDL_NAME(pa_context_connect)(context, NULL, 0, NULL) < 0) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("Could not setup connection to PulseAudio");
+ return(-1);
+ }
+
+ do {
+ if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("pa_mainloop_iterate() failed");
+ return(-1);
+ }
+ state = SDL_NAME(pa_context_get_state)(context);
+ if (!PA_CONTEXT_IS_GOOD(state)) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("Could not connect to PulseAudio");
+ return(-1);
+ }
+ } while (state != PA_CONTEXT_READY);
+
+ stream = SDL_NAME(pa_stream_new)(
+ context,
+ "Simple DirectMedia Layer", /* stream description */
+ &paspec, /* sample format spec */
+ &pacmap /* channel map */
+ );
+ if ( stream == NULL ) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("Could not setup PulseAudio stream");
+ return(-1);
+ }
+
+ if (SDL_NAME(pa_stream_connect_playback)(stream, NULL, &paattr, flags,
+ NULL, NULL) < 0) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("Could not connect PulseAudio stream");
+ return(-1);
+ }
+
+ do {
+ if (SDL_NAME(pa_mainloop_iterate)(mainloop, 1, NULL) < 0) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("pa_mainloop_iterate() failed");
+ return(-1);
+ }
+ state = SDL_NAME(pa_stream_get_state)(stream);
+ if (!PA_STREAM_IS_GOOD(state)) {
+ PULSE_CloseAudio(this);
+ SDL_SetError("Could not create to PulseAudio stream");
+ return(-1);
+ }
+ } while (state != PA_STREAM_READY);
+
+ return(0);
+}
diff --git a/src/audio/pulse/SDL_pulseaudio.h b/src/audio/pulse/SDL_pulseaudio.h
new file mode 100644
index 0000000..27d27c6
--- /dev/null
+++ b/src/audio/pulse/SDL_pulseaudio.h
@@ -0,0 +1,71 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Stéphan Kochen
+ stephan@kochen.nl
+
+ Based on parts of the ALSA and ESounD output drivers.
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_pulseaudio_h
+#define _SDL_pulseaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ pa_mainloop *mainloop;
+ pa_mainloop_api *mainloop_api;
+ pa_context *context;
+ pa_stream *stream;
+
+ /* Raw mixing buffer */
+ Uint8 *mixbuf;
+ int mixlen;
+};
+
+#if (PA_API_VERSION < 12)
+/** Return non-zero if the passed state is one of the connected states */
+static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {
+ return
+ x == PA_CONTEXT_CONNECTING ||
+ x == PA_CONTEXT_AUTHORIZING ||
+ x == PA_CONTEXT_SETTING_NAME ||
+ x == PA_CONTEXT_READY;
+}
+/** Return non-zero if the passed state is one of the connected states */
+static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) {
+ return
+ x == PA_STREAM_CREATING ||
+ x == PA_STREAM_READY;
+}
+#endif /* pulseaudio <= 0.9.10 */
+
+/* Old variable names */
+#define mainloop (this->hidden->mainloop)
+#define mainloop_api (this->hidden->mainloop_api)
+#define context (this->hidden->context)
+#define stream (this->hidden->stream)
+#define mixbuf (this->hidden->mixbuf)
+#define mixlen (this->hidden->mixlen)
+
+#endif /* _SDL_pulseaudio_h */
+
diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c
new file mode 100644
index 0000000..4a57c68
--- /dev/null
+++ b/src/audio/sun/SDL_sunaudio.c
@@ -0,0 +1,432 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <fcntl.h>
+#include <errno.h>
+#ifdef __NETBSD__
+#include <sys/ioctl.h>
+#include <sys/audioio.h>
+#endif
+#ifdef __SVR4
+#include <sys/audioio.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+#include <unistd.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audiomem.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_sunaudio.h"
+
+/* Open the audio device for playback, and don't block if busy */
+#define OPEN_FLAGS (O_WRONLY|O_NONBLOCK)
+
+/* Audio driver functions */
+static int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DSP_WaitAudio(_THIS);
+static void DSP_PlayAudio(_THIS);
+static Uint8 *DSP_GetAudioBuf(_THIS);
+static void DSP_CloseAudio(_THIS);
+
+static Uint8 snd2au(int sample);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ int fd;
+ int available;
+
+ available = 0;
+ fd = SDL_OpenAudioPath(NULL, 0, OPEN_FLAGS, 1);
+ if ( fd >= 0 ) {
+ available = 1;
+ close(fd);
+ }
+ return(available);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+ audio_fd = -1;
+
+ /* Set the function pointers */
+ this->OpenAudio = DSP_OpenAudio;
+ this->WaitAudio = DSP_WaitAudio;
+ this->PlayAudio = DSP_PlayAudio;
+ this->GetAudioBuf = DSP_GetAudioBuf;
+ this->CloseAudio = DSP_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap SUNAUDIO_bootstrap = {
+ "audio", "UNIX /dev/audio interface",
+ Audio_Available, Audio_CreateDevice
+};
+
+#ifdef DEBUG_AUDIO
+void CheckUnderflow(_THIS)
+{
+#ifdef AUDIO_GETINFO
+ audio_info_t info;
+ int left;
+
+ ioctl(audio_fd, AUDIO_GETINFO, &info);
+ left = (written - info.play.samples);
+ if ( written && (left == 0) ) {
+ fprintf(stderr, "audio underflow!\n");
+ }
+#endif
+}
+#endif
+
+void DSP_WaitAudio(_THIS)
+{
+#ifdef AUDIO_GETINFO
+#define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */
+ audio_info_t info;
+ Sint32 left;
+
+ ioctl(audio_fd, AUDIO_GETINFO, &info);
+ left = (written - info.play.samples);
+ if ( left > fragsize ) {
+ Sint32 sleepy;
+
+ sleepy = ((left - fragsize)/frequency);
+ sleepy -= SLEEP_FUDGE;
+ if ( sleepy > 0 ) {
+ SDL_Delay(sleepy);
+ }
+ }
+#else
+ fd_set fdset;
+
+ FD_ZERO(&fdset);
+ FD_SET(audio_fd, &fdset);
+ select(audio_fd+1, NULL, &fdset, NULL, NULL);
+#endif
+}
+
+void DSP_PlayAudio(_THIS)
+{
+ /* Write the audio data */
+ if ( ulaw_only ) {
+ /* Assuming that this->spec.freq >= 8000 Hz */
+ int accum, incr, pos;
+ Uint8 *aubuf;
+
+ accum = 0;
+ incr = this->spec.freq/8;
+ aubuf = ulaw_buf;
+ switch (audio_fmt & 0xFF) {
+ case 8: {
+ Uint8 *sndbuf;
+
+ sndbuf = mixbuf;
+ for ( pos=0; pos < fragsize; ++pos ) {
+ *aubuf = snd2au((0x80-*sndbuf)*64);
+ accum += incr;
+ while ( accum > 0 ) {
+ accum -= 1000;
+ sndbuf += 1;
+ }
+ aubuf += 1;
+ }
+ }
+ break;
+ case 16: {
+ Sint16 *sndbuf;
+
+ sndbuf = (Sint16 *)mixbuf;
+ for ( pos=0; pos < fragsize; ++pos ) {
+ *aubuf = snd2au(*sndbuf/4);
+ accum += incr;
+ while ( accum > 0 ) {
+ accum -= 1000;
+ sndbuf += 1;
+ }
+ aubuf += 1;
+ }
+ }
+ break;
+ }
+#ifdef DEBUG_AUDIO
+ CheckUnderflow(this);
+#endif
+ if ( write(audio_fd, ulaw_buf, fragsize) < 0 ) {
+ /* Assume fatal error, for now */
+ this->enabled = 0;
+ }
+ written += fragsize;
+ } else {
+#ifdef DEBUG_AUDIO
+ CheckUnderflow(this);
+#endif
+ if ( write(audio_fd, mixbuf, this->spec.size) < 0 ) {
+ /* Assume fatal error, for now */
+ this->enabled = 0;
+ }
+ written += fragsize;
+ }
+}
+
+Uint8 *DSP_GetAudioBuf(_THIS)
+{
+ return(mixbuf);
+}
+
+void DSP_CloseAudio(_THIS)
+{
+ if ( mixbuf != NULL ) {
+ SDL_FreeAudioMem(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( ulaw_buf != NULL ) {
+ SDL_free(ulaw_buf);
+ ulaw_buf = NULL;
+ }
+ close(audio_fd);
+}
+
+int DSP_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ char audiodev[1024];
+#ifdef AUDIO_SETINFO
+ int enc;
+#endif
+ int desired_freq = spec->freq;
+
+ /* Initialize our freeable variables, in case we fail*/
+ audio_fd = -1;
+ mixbuf = NULL;
+ ulaw_buf = NULL;
+
+ /* Determine the audio parameters from the AudioSpec */
+ switch ( spec->format & 0xFF ) {
+
+ case 8: { /* Unsigned 8 bit audio data */
+ spec->format = AUDIO_U8;
+#ifdef AUDIO_SETINFO
+ enc = AUDIO_ENCODING_LINEAR8;
+#endif
+ }
+ break;
+
+ case 16: { /* Signed 16 bit audio data */
+ spec->format = AUDIO_S16SYS;
+#ifdef AUDIO_SETINFO
+ enc = AUDIO_ENCODING_LINEAR;
+#endif
+ }
+ break;
+
+ default: {
+ SDL_SetError("Unsupported audio format");
+ return(-1);
+ }
+ }
+ audio_fmt = spec->format;
+
+ /* Open the audio device */
+ audio_fd = SDL_OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 1);
+ if ( audio_fd < 0 ) {
+ SDL_SetError("Couldn't open %s: %s", audiodev,
+ strerror(errno));
+ return(-1);
+ }
+
+ ulaw_only = 0; /* modern Suns do support linear audio */
+#ifdef AUDIO_SETINFO
+ for(;;) {
+ audio_info_t info;
+ AUDIO_INITINFO(&info); /* init all fields to "no change" */
+
+ /* Try to set the requested settings */
+ info.play.sample_rate = spec->freq;
+ info.play.channels = spec->channels;
+ info.play.precision = (enc == AUDIO_ENCODING_ULAW)
+ ? 8 : spec->format & 0xff;
+ info.play.encoding = enc;
+ if( ioctl(audio_fd, AUDIO_SETINFO, &info) == 0 ) {
+
+ /* Check to be sure we got what we wanted */
+ if(ioctl(audio_fd, AUDIO_GETINFO, &info) < 0) {
+ SDL_SetError("Error getting audio parameters: %s",
+ strerror(errno));
+ return -1;
+ }
+ if(info.play.encoding == enc
+ && info.play.precision == (spec->format & 0xff)
+ && info.play.channels == spec->channels) {
+ /* Yow! All seems to be well! */
+ spec->freq = info.play.sample_rate;
+ break;
+ }
+ }
+
+ switch(enc) {
+ case AUDIO_ENCODING_LINEAR8:
+ /* unsigned 8bit apparently not supported here */
+ enc = AUDIO_ENCODING_LINEAR;
+ spec->format = AUDIO_S16SYS;
+ break; /* try again */
+
+ case AUDIO_ENCODING_LINEAR:
+ /* linear 16bit didn't work either, resort to µ-law */
+ enc = AUDIO_ENCODING_ULAW;
+ spec->channels = 1;
+ spec->freq = 8000;
+ spec->format = AUDIO_U8;
+ ulaw_only = 1;
+ break;
+
+ default:
+ /* oh well... */
+ SDL_SetError("Error setting audio parameters: %s",
+ strerror(errno));
+ return -1;
+ }
+ }
+#endif /* AUDIO_SETINFO */
+ written = 0;
+
+ /* We can actually convert on-the-fly to U-Law */
+ if ( ulaw_only ) {
+ spec->freq = desired_freq;
+ fragsize = (spec->samples*1000)/(spec->freq/8);
+ frequency = 8;
+ ulaw_buf = (Uint8 *)SDL_malloc(fragsize);
+ if ( ulaw_buf == NULL ) {
+ SDL_OutOfMemory();
+ return(-1);
+ }
+ spec->channels = 1;
+ } else {
+ fragsize = spec->samples;
+ frequency = spec->freq/1000;
+ }
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Audio device %s U-Law only\n",
+ ulaw_only ? "is" : "is not");
+ fprintf(stderr, "format=0x%x chan=%d freq=%d\n",
+ spec->format, spec->channels, spec->freq);
+#endif
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Allocate mixing buffer */
+ mixbuf = (Uint8 *)SDL_AllocAudioMem(spec->size);
+ if ( mixbuf == NULL ) {
+ SDL_OutOfMemory();
+ return(-1);
+ }
+ SDL_memset(mixbuf, spec->silence, spec->size);
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
+
+/************************************************************************/
+/* This function (snd2au()) copyrighted: */
+/************************************************************************/
+/* Copyright 1989 by Rich Gopstein and Harris Corporation */
+/* */
+/* Permission to use, copy, modify, and distribute this software */
+/* and its documentation for any purpose and without fee is */
+/* hereby granted, provided that the above copyright notice */
+/* appears in all copies and that both that copyright notice and */
+/* this permission notice appear in supporting documentation, and */
+/* that the name of Rich Gopstein and Harris Corporation not be */
+/* used in advertising or publicity pertaining to distribution */
+/* of the software without specific, written prior permission. */
+/* Rich Gopstein and Harris Corporation make no representations */
+/* about the suitability of this software for any purpose. It */
+/* provided "as is" without express or implied warranty. */
+/************************************************************************/
+
+static Uint8 snd2au(int sample)
+{
+
+ int mask;
+
+ if (sample < 0) {
+ sample = -sample;
+ mask = 0x7f;
+ } else {
+ mask = 0xff;
+ }
+
+ if (sample < 32) {
+ sample = 0xF0 | (15 - sample / 2);
+ } else if (sample < 96) {
+ sample = 0xE0 | (15 - (sample - 32) / 4);
+ } else if (sample < 224) {
+ sample = 0xD0 | (15 - (sample - 96) / 8);
+ } else if (sample < 480) {
+ sample = 0xC0 | (15 - (sample - 224) / 16);
+ } else if (sample < 992) {
+ sample = 0xB0 | (15 - (sample - 480) / 32);
+ } else if (sample < 2016) {
+ sample = 0xA0 | (15 - (sample - 992) / 64);
+ } else if (sample < 4064) {
+ sample = 0x90 | (15 - (sample - 2016) / 128);
+ } else if (sample < 8160) {
+ sample = 0x80 | (15 - (sample - 4064) / 256);
+ } else {
+ sample = 0x80;
+ }
+ return (mask & sample);
+}
diff --git a/src/audio/sun/SDL_sunaudio.h b/src/audio/sun/SDL_sunaudio.h
new file mode 100644
index 0000000..480bd4e
--- /dev/null
+++ b/src/audio/sun/SDL_sunaudio.h
@@ -0,0 +1,55 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData {
+ /* The file descriptor for the audio device */
+ int audio_fd;
+
+ Uint16 audio_fmt; /* The app audio format */
+ Uint8 *mixbuf; /* The app mixing buffer */
+ int ulaw_only; /* Flag -- does hardware only output U-law? */
+ Uint8 *ulaw_buf; /* The U-law mixing buffer */
+ Sint32 written; /* The number of samples written */
+ int fragsize; /* The audio fragment size in samples */
+ int frequency; /* The audio frequency in KHz */
+};
+
+/* Old variable names */
+#define audio_fd (this->hidden->audio_fd)
+#define audio_fmt (this->hidden->audio_fmt)
+#define mixbuf (this->hidden->mixbuf)
+#define ulaw_only (this->hidden->ulaw_only)
+#define ulaw_buf (this->hidden->ulaw_buf)
+#define written (this->hidden->written)
+#define fragsize (this->hidden->fragsize)
+#define frequency (this->hidden->frequency)
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/symbian/SDL_epocaudio.cpp b/src/audio/symbian/SDL_epocaudio.cpp
new file mode 100644
index 0000000..304083a
--- /dev/null
+++ b/src/audio/symbian/SDL_epocaudio.cpp
@@ -0,0 +1,614 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@devolution.com
+*/
+
+/*
+ SDL_epocaudio.cpp
+ Epoc based SDL audio driver implementation
+
+ Markus Mertama
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id: SDL_epocaudio.c,v 0.0.0.0 2001/06/19 17:19:56 hercules Exp $";
+#endif
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include "epoc_sdl.h"
+
+#include <e32hal.h>
+
+
+extern "C" {
+#include "SDL_audio.h"
+#include "SDL_error.h"
+#include "SDL_audiomem.h"
+#include "SDL_audio_c.h"
+#include "SDL_timer.h"
+#include "SDL_audiodev_c.h"
+}
+
+#include "SDL_epocaudio.h"
+
+#include "streamplayer.h"
+
+
+//#define DEBUG_AUDIO
+
+
+/* Audio driver functions */
+
+static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec);
+static void EPOC_WaitAudio(SDL_AudioDevice *thisdevice);
+static void EPOC_PlayAudio(SDL_AudioDevice *thisdevice);
+static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice *thisdevice);
+static void EPOC_CloseAudio(SDL_AudioDevice *thisdevice);
+static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice);
+
+static int Audio_Available(void);
+static SDL_AudioDevice *Audio_CreateDevice(int devindex);
+static void Audio_DeleteDevice(SDL_AudioDevice *device);
+
+
+//void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len);
+
+#ifdef __WINS__
+#define DODUMP
+#endif
+
+#ifdef DODUMP
+NONSHARABLE_CLASS(TDump)
+ {
+ public:
+ TInt Open();
+ void Close();
+ void Dump(const TDesC8& aDes);
+ private:
+ RFile iFile;
+ RFs iFs;
+ };
+
+TInt TDump::Open()
+ {
+ TInt err = iFs.Connect();
+ if(err == KErrNone)
+ {
+#ifdef __WINS__
+_LIT(target, "C:\\sdlau.raw");
+#else
+_LIT(target, "E:\\sdlau.raw");
+#endif
+ err = iFile.Replace(iFs, target, EFileWrite);
+ }
+ return err;
+ }
+void TDump::Close()
+ {
+ iFile.Close();
+ iFs.Close();
+ }
+void TDump::Dump(const TDesC8& aDes)
+ {
+ iFile.Write(aDes);
+ }
+#endif
+
+
+NONSHARABLE_CLASS(CSimpleWait) : public CTimer
+ {
+ public:
+ void Wait(TTimeIntervalMicroSeconds32 aWait);
+ static CSimpleWait* NewL();
+ private:
+ CSimpleWait();
+ void RunL();
+ };
+
+
+CSimpleWait* CSimpleWait::NewL()
+ {
+ CSimpleWait* wait = new (ELeave) CSimpleWait();
+ CleanupStack::PushL(wait);
+ wait->ConstructL();
+ CleanupStack::Pop();
+ return wait;
+ }
+
+void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait)
+ {
+ After(aWait);
+ CActiveScheduler::Start();
+ }
+
+CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CSimpleWait::RunL()
+ {
+ CActiveScheduler::Stop();
+ }
+
+const TInt KAudioBuffers(2);
+
+
+NONSHARABLE_CLASS(CEpocAudio) : public CBase, public MStreamObs, public MStreamProvider
+ {
+ public:
+ static void* NewL(TInt BufferSize, TInt aFill);
+ inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
+
+ static void Free(SDL_AudioDevice* thisdevice);
+
+ void Wait();
+ void Play();
+ // void SetBuffer(const TDesC8& aBuffer);
+ void ThreadInitL(TAny* aDevice);
+ void Open(TInt iRate, TInt iChannels, TUint32 aType, TInt aBytes);
+ ~CEpocAudio();
+ TUint8* Buffer();
+ TBool SetPause(TBool aPause);
+ #ifdef DODUMP
+ void Dump(const TDesC8& aBuf) {iDump.Dump(aBuf);}
+ #endif
+ private:
+ CEpocAudio(TInt aBufferSize);
+ void Complete(TInt aState, TInt aError);
+ TPtrC8 Data();
+ void ConstructL(TInt aFill);
+ private:
+ TInt iBufferSize;
+ CStreamPlayer* iPlayer;
+ TInt iBufferRate;
+ TInt iRate;
+ TInt iChannels;
+ TUint32 iType;
+ TInt iPosition;
+ TThreadId iTid;
+ TUint8* iAudioPtr;
+ TUint8* iBuffer;
+ // TTimeIntervalMicroSeconds iStart;
+ TTime iStart;
+ TInt iTune;
+ CSimpleWait* iWait;
+ #ifdef DODUMP
+ TDump iDump;
+ #endif
+ };
+
+inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice)
+ {
+ return *static_cast<CEpocAudio*>((void*)thisdevice->hidden);
+ }
+
+/*
+
+TBool EndSc(TAny*)
+ {
+ CActiveScheduler::Stop();
+ }
+
+LOCAL_C void CleanScL()
+ {
+ CIdle* d = CIdle::NewLC(CActive:::EPriorityIdle);
+ d->Start(TCallBack(EndSc));
+ CActiveScheduler::Start();
+
+ }
+*/
+
+void CEpocAudio::Free(SDL_AudioDevice* thisdevice)
+ {
+ CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden);
+ if(ea)
+ {
+ ASSERT(ea->iTid == RThread().Id());
+ delete ea;
+ thisdevice->hidden = NULL;
+
+ CActiveScheduler* as = CActiveScheduler::Current();
+ ASSERT(as->StackDepth() == 0);
+ delete as;
+ CActiveScheduler::Install(NULL);
+ }
+ ASSERT(thisdevice->hidden == NULL);
+ }
+
+CEpocAudio::CEpocAudio(TInt aBufferSize) : iBufferSize(aBufferSize), iPosition(-1)
+ {
+ }
+
+void* CEpocAudio::NewL(TInt aBufferSize, TInt aFill)
+ {
+ CEpocAudio* eAudioLib = new (ELeave) CEpocAudio(aBufferSize);
+ CleanupStack::PushL(eAudioLib);
+ eAudioLib->ConstructL(aFill);
+ CleanupStack::Pop();
+ return eAudioLib;
+ }
+
+void CEpocAudio::ConstructL(TInt aFill)
+ {
+ iBuffer = (TUint8*) User::AllocL(KAudioBuffers * iBufferSize);
+ memset(iBuffer, aFill, KAudioBuffers * iBufferSize);
+ iAudioPtr = iBuffer;
+ }
+
+
+TBool CEpocAudio::SetPause(TBool aPause)
+ {
+ if(aPause && iPosition >= 0)
+ {
+ iPosition = -1;
+ if(iPlayer != NULL)
+ iPlayer->Stop();
+ }
+ if(!aPause && iPosition < 0)
+ {
+ iPosition = 0;
+ if(iPlayer != NULL)
+ iPlayer->Start();
+ }
+ return iPosition < 0;
+ }
+
+void CEpocAudio::ThreadInitL(TAny* aDevice)
+ {
+ iTid = RThread().Id();
+ CActiveScheduler* as = new (ELeave) CActiveScheduler();
+ CActiveScheduler::Install(as);
+
+ EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice));
+
+ iWait = CSimpleWait::NewL();
+
+ iPlayer = new (ELeave) CStreamPlayer(*this, *this);
+ iPlayer->ConstructL();
+ iPlayer->OpenStream(iRate, iChannels, iType);
+
+ #ifdef DODUMP
+ User::LeaveIfError(iDump.Open());
+ #endif
+ }
+
+
+
+TUint8* CEpocAudio::Buffer()
+ {
+ iStart.UniversalTime();
+// iStart = iPlayer->Position();
+ return iAudioPtr;
+
+ }
+
+CEpocAudio::~CEpocAudio()
+ {
+ if(iWait != NULL)
+ iWait->Cancel();
+ delete iWait;
+ if(iPlayer != NULL)
+ iPlayer->Close();
+ delete iPlayer;
+ delete iBuffer;
+ }
+
+void CEpocAudio::Complete(TInt aState, TInt aError)
+ {
+ if(aState == MStreamObs::EClose)
+ {
+ }
+ if(iPlayer->Closed())
+ return;
+ switch(aError)
+ {
+ case KErrUnderflow:
+ case KErrInUse:
+ iPlayer->Start();
+ break;
+ case KErrAbort:
+ iPlayer->Open();
+ }
+ }
+
+
+void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len)
+ {
+#ifdef DODUMP
+ const TPtrC8 buf((TUint8*)data, len);
+ CEpocAudio::Current(thisdevice).Dump(buf);
+#endif
+ }
+
+const TInt KClip(256);
+
+TPtrC8 CEpocAudio::Data()
+ {
+ if(iPosition < 0)
+ return KNullDesC8();
+
+ TPtrC8 data(iAudioPtr + iPosition, KClip);
+
+#ifdef DODUMP
+ iDump.Dump(data);
+#endif
+
+ iPosition += KClip;
+ if(iPosition >= iBufferSize)
+ {
+
+/* if(iAudioPtr == iBuffer)
+ iAudioPtr = iBuffer + iBufferSize;
+ else
+ iAudioPtr = iBuffer;
+*/
+ iAudioPtr += iBufferSize;
+
+ if((iAudioPtr - iBuffer) >= KAudioBuffers * iBufferSize)
+ iAudioPtr = iBuffer;
+
+ iPosition = -1;
+ if(iWait->IsActive())
+ {
+ iWait->Cancel();
+ CActiveScheduler::Stop();
+ }
+ }
+ return data;
+ }
+
+
+
+
+void CEpocAudio::Play()
+ {
+ iPosition = 0;
+ }
+
+void CEpocAudio::Wait()
+ {
+ if(iPosition >= 0 /*&& iPlayer->Playing()*/)
+ {
+ const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000);
+ const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2);
+ iWait->After(specTime);
+
+ CActiveScheduler::Start();
+ TTime end;
+ end.UniversalTime();
+ const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart);
+
+
+// const TTimeIntervalMicroSeconds end = iPlayer->Position();
+
+
+
+
+ const TInt diff = specTime - delta.Int64();
+
+ if(diff > 0 && diff < 200000)
+ {
+ User::After(diff);
+ }
+
+ }
+ else
+ {
+ User::After(10000);
+// iWait->Wait(10000); //just give some time...
+ }
+ }
+
+void CEpocAudio::Open(TInt aRate, TInt aChannels, TUint32 aType, TInt aBytes)
+ {
+ iRate = aRate;
+ iChannels = aChannels;
+ iType = aType;
+ iBufferRate = iRate * iChannels * aBytes; //1/x
+ }
+
+
+/* Audio driver bootstrap functions */
+
+AudioBootStrap EPOCAudio_bootstrap = {
+ "epoc\0\0\0",
+ "EPOC streaming audio\0\0\0",
+ Audio_Available,
+ Audio_CreateDevice
+};
+
+
+static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/)
+{
+ SDL_AudioDevice *thisdevice;
+
+ /* Initialize all variables that we clean on shutdown */
+ thisdevice = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
+ if ( thisdevice ) {
+ memset(thisdevice, 0, (sizeof *thisdevice));
+ thisdevice->hidden = NULL; /*(struct SDL_PrivateAudioData *)
+ malloc((sizeof thisdevice->hidden)); */
+ }
+ if ( (thisdevice == NULL) /*|| (thisdevice->hidden == NULL) */) {
+ SDL_OutOfMemory();
+ if ( thisdevice ) {
+ free(thisdevice);
+ }
+ return(0);
+ }
+// memset(thisdevice->hidden, 0, (sizeof *thisdevice->hidden));
+
+ /* Set the function pointers */
+ thisdevice->OpenAudio = EPOC_OpenAudio;
+ thisdevice->WaitAudio = EPOC_WaitAudio;
+ thisdevice->PlayAudio = EPOC_PlayAudio;
+ thisdevice->GetAudioBuf = EPOC_GetAudioBuf;
+ thisdevice->CloseAudio = EPOC_CloseAudio;
+ thisdevice->ThreadInit = EPOC_ThreadInit;
+ thisdevice->free = Audio_DeleteDevice;
+
+ return thisdevice;
+}
+
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+ {
+ //free(device->hidden);
+ free(device);
+ }
+
+static int Audio_Available(void)
+{
+ return(1); // Audio stream modules should be always there!
+}
+
+
+static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec)
+{
+ SDL_TRACE("SDL:EPOC_OpenAudio");
+
+
+ TUint32 type = KMMFFourCCCodePCM16;
+ TInt bytes = 2;
+
+ switch(spec->format)
+ {
+ case AUDIO_U16LSB:
+ type = KMMFFourCCCodePCMU16;
+ break;
+ case AUDIO_S16LSB:
+ type = KMMFFourCCCodePCM16;
+ break;
+ case AUDIO_U16MSB:
+ type = KMMFFourCCCodePCMU16B;
+ break;
+ case AUDIO_S16MSB:
+ type = KMMFFourCCCodePCM16B;
+ break;
+ //8 bit not supported!
+ case AUDIO_U8:
+ case AUDIO_S8:
+ default:
+ spec->format = AUDIO_S16LSB;
+ };
+
+
+
+ if(spec->channels > 2)
+ spec->channels = 2;
+
+ spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq);
+
+
+ /* Allocate mixing buffer */
+ const TInt buflen = spec->size;// * bytes * spec->channels;
+// audiobuf = NULL;
+
+ TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence)));
+ if(err != KErrNone)
+ return -1;
+
+ CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes);
+
+ CEpocAudio::Current(thisdevice).SetPause(ETrue);
+
+ // isSDLAudioPaused = 1;
+
+ thisdevice->enabled = 0; /* enable only after audio engine has been initialized!*/
+
+ /* We're ready to rock and roll. :-) */
+ return(0);
+}
+
+
+static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice)
+ {
+#ifdef DEBUG_AUDIO
+ SDL_TRACE("Close audio\n");
+#endif
+
+ CEpocAudio::Free(thisdevice);
+ }
+
+
+static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice)
+ {
+ SDL_TRACE("SDL:EPOC_ThreadInit");
+ CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice);
+ RThread().SetPriority(EPriorityMore);
+ thisdevice->enabled = 1;
+ }
+
+/* This function waits until it is possible to write a full sound buffer */
+static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice)
+{
+#ifdef DEBUG_AUDIO
+ SDL_TRACE1("wait %d audio\n", CEpocAudio::AudioLib().StreamPlayer(KSfxChannel).SyncTime());
+ TInt tics = User::TickCount();
+#endif
+
+ CEpocAudio::Current(thisdevice).Wait();
+
+#ifdef DEBUG_AUDIO
+ TInt ntics = User::TickCount() - tics;
+ SDL_TRACE1("audio waited %d\n", ntics);
+ SDL_TRACE1("audio at %d\n", tics);
+#endif
+}
+
+
+
+static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice)
+ {
+ if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED))
+ SDL_Delay(500); //hold on the busy loop
+ else
+ CEpocAudio::Current(thisdevice).Play();
+
+#ifdef DEBUG_AUDIO
+ SDL_TRACE("buffer has audio data\n");
+#endif
+
+
+#ifdef DEBUG_AUDIO
+ SDL_TRACE1("Wrote %d bytes of audio data\n", buflen);
+#endif
+}
+
+static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice)
+ {
+ return CEpocAudio::Current(thisdevice).Buffer();
+ }
+
+
+
diff --git a/src/audio/symbian/SDL_epocaudio.h b/src/audio/symbian/SDL_epocaudio.h
new file mode 100644
index 0000000..7be79d1
--- /dev/null
+++ b/src/audio/symbian/SDL_epocaudio.h
@@ -0,0 +1,37 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@devolution.com
+*/
+
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id: SDL_epocaudio.h,v 1.1.2.2 2001/02/10 07:20:03 hercules Exp $";
+#endif
+
+#ifndef _SDL_EPOCAUDIO_H
+#define _SDL_EPOCAUDIO_H
+
+extern "C" {
+#include "SDL_sysaudio.h"
+}
+
+
+#endif /* _SDL_EPOCAUDIO_H */
diff --git a/src/audio/symbian/streamplayer.cpp b/src/audio/symbian/streamplayer.cpp
new file mode 100644
index 0000000..dd733a1
--- /dev/null
+++ b/src/audio/symbian/streamplayer.cpp
@@ -0,0 +1,279 @@
+#include "streamplayer.h"
+#include<mda/common/audio.h>
+
+
+
+const TInt KMaxVolume(256);
+
+LOCAL_C TInt GetSampleRate(TInt aRate)
+ {
+ switch(aRate)
+ {
+ case 8000: return TMdaAudioDataSettings::ESampleRate8000Hz;
+ case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
+ case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
+ case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
+ case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
+ case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
+ case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
+ case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
+ case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
+ case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
+ case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
+ }
+ return KErrNotFound;
+ }
+
+LOCAL_C TInt GetChannels(TInt aChannels)
+ {
+ switch(aChannels)
+ {
+ case 1: return TMdaAudioDataSettings::EChannelsMono;
+ case 2: return TMdaAudioDataSettings::EChannelsStereo;
+ }
+ return KErrNotFound;
+ }
+
+TInt CStreamPlayer::ClosestSupportedRate(TInt aRate)
+ {
+ if(aRate > 96000)
+ return 96000;
+ TInt rate = aRate;
+ while(GetSampleRate(rate) == KErrNotFound)
+ {
+ ++rate;
+ }
+ return rate;
+ }
+
+CStreamPlayer::CStreamPlayer(MStreamProvider& aProvider, MStreamObs& aObs) :
+ iProvider(aProvider), iObs(aObs), iVolume(KMaxVolume)
+ {
+ }
+
+CStreamPlayer::~CStreamPlayer()
+ {
+ iState |= EDied;
+ if(iState & EInited)
+ Close();
+ User::After(100000); //wait buffer to be flushed
+ ASSERT(iPtr.Length() == 0);
+ delete iStream;
+ }
+
+
+void CStreamPlayer::ConstructL()
+ {
+ iStream = CMdaAudioOutputStream::NewL(*this, EMdaPriorityMax);
+ iSilence.SetMax();
+ iSilence.FillZ();
+ }
+
+
+TInt CStreamPlayer::OpenStream(TInt aRate, TInt aChannels, TUint32 aType)
+ {
+ Close();
+
+ iType = aType;
+
+ iRate = GetSampleRate(aRate);
+ if(iRate == KErrNotFound)
+ return KErrNotSupported;
+
+ iChannels = GetChannels(aChannels);
+ if(iChannels == KErrNotFound)
+ return KErrNotSupported;
+
+ Open();
+
+ return KErrNone;
+ }
+
+
+TInt CStreamPlayer::MaxVolume() const
+ {
+ return KMaxVolume;
+ }
+
+void CStreamPlayer::SetVolume(TInt aNew)
+ {
+
+ const TInt maxi = MaxVolume();
+ if(aNew > maxi)
+ return;
+ if(aNew < 0)
+ return;
+
+ iVolume = aNew;
+
+ iState |= EVolumeChange;
+ }
+
+ TInt CStreamPlayer::Volume() const
+ {
+ return iVolume;
+ }
+
+void CStreamPlayer::Open()
+ {
+ TMdaAudioDataSettings audioSettings;
+ audioSettings.Query();
+ audioSettings.iCaps = TMdaAudioDataSettings::ERealTime |
+ TMdaAudioDataSettings::ESampleRateFixed;
+ audioSettings.iSampleRate = iRate;
+ audioSettings.iChannels = iChannels;
+ audioSettings.iFlags = TMdaAudioDataSettings::ENoNetworkRouting;
+ audioSettings.iVolume = 0;
+
+ iState &= ~EStopped;
+ iStream->Open(&audioSettings);
+ }
+
+void CStreamPlayer::Stop()
+ {
+ if(iState & (EStarted | EInited))
+ {
+ Close();
+ iState |= EStopped;
+ }
+ }
+
+void CStreamPlayer::Start()
+ {
+ if(iPtr.Length() == 0)
+ {
+ iState |= EStarted;
+ if(iState & EInited)
+ {
+ Request();
+ }
+ else if(iState & EStopped)
+ {
+ Open();
+ }
+ }
+ }
+
+void CStreamPlayer::Close()
+ {
+ iState &= ~EInited;
+ iStream->Stop();
+ iState &= ~EStarted;
+ }
+
+void CStreamPlayer::Request()
+ {
+ if(iState & EInited)
+ {
+ iPtr.Set(KNullDesC8);
+
+ if(iState & EVolumeChange)
+ {
+ const TReal newVol = iVolume;
+ const TReal newMax = MaxVolume();
+ const TInt maxVol = iStream->MaxVolume();
+ const TReal max = static_cast<TReal>(maxVol);
+ const TReal newvolume = (newVol * max) / newMax;
+ const TInt vol = static_cast<TReal>(newvolume);
+ iStream->SetVolume(vol);
+ iState &= ~EVolumeChange;
+ }
+
+ if(iState & EStarted)
+ {
+ iPtr.Set(iProvider.Data());
+ }
+ if(iPtr.Length() == 0)
+ {
+ iPtr.Set(iSilence);
+ }
+ TRAPD(err, iStream->WriteL(iPtr));
+ if(err != KErrNone)
+ {
+ iObs.Complete(MStreamObs::EWrite, err);
+ }
+ /* else
+ {
+ iProvider.Written(iPtr.Length());
+ }*/
+ }
+ }
+
+
+void CStreamPlayer::SetCapsL()
+ {
+ iStream->SetDataTypeL(iType);
+ iStream->SetAudioPropertiesL(iRate, iChannels);
+ }
+
+void CStreamPlayer::MaoscOpenComplete(TInt aError)
+ {
+ if(aError == KErrNone)
+ {
+ TRAPD(err, SetCapsL());
+ if(err == KErrNone)
+ {
+ iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceTime);
+ iState |= EInited;
+
+
+ SetVolume(Volume());
+
+ if(iState & EStarted)
+ {
+ Request();
+ }
+
+ }
+ aError = err;
+ }
+ if(!(iState & EDied))
+ iObs.Complete(MStreamObs::EInit, aError);
+ }
+
+void CStreamPlayer::MaoscBufferCopied(TInt aError, const TDesC8& /*aBuffer*/)
+ {
+ iPtr.Set(KNullDesC8);
+ if(aError == KErrNone)
+ {
+ if(iState & EInited)
+ Request();
+ else
+ iStream->Stop();
+ }
+ else if(!(iState & EDied))
+ iObs.Complete(MStreamObs::EPlay, aError);
+ }
+
+void CStreamPlayer::MaoscPlayComplete(TInt aError)
+ {
+ iPtr.Set(KNullDesC8);
+ iState &= ~EStarted;
+ if(!(iState & EDied))
+ iObs.Complete(MStreamObs::EClose, aError);
+ }
+
+TBool CStreamPlayer::Playing() const
+ {
+ return (iState & EInited) && (iState & EStarted);
+ }
+
+TBool CStreamPlayer::Closed() const
+ {
+ return !(iState & EInited) && !(iState & EDied);
+ }
+
+ /*
+void CStreamPlayer::Request()
+ {
+ SetActive();
+ TRequestStatus* s = &iStatus;
+ User::RequestComplete(s, KErrNone);
+ }
+ // iTimer.After(0);
+ */
+
+
+
+
+
diff --git a/src/audio/symbian/streamplayer.h b/src/audio/symbian/streamplayer.h
new file mode 100644
index 0000000..8c6e74f
--- /dev/null
+++ b/src/audio/symbian/streamplayer.h
@@ -0,0 +1,89 @@
+#ifndef STREAMPLAYER_H
+#define STREAMPLAYER_H
+
+#include<MdaAudioOutputStream.h>
+
+const TInt KSilenceBuffer = 256;
+
+class MStreamObs
+ {
+ public:
+ enum
+ {
+ EInit,
+ EPlay,
+ EWrite,
+ EClose,
+ };
+ virtual void Complete(TInt aState, TInt aError) = 0;
+ };
+
+class MStreamProvider
+ {
+ public:
+ virtual TPtrC8 Data() = 0;
+ };
+
+NONSHARABLE_CLASS(CStreamPlayer) : public CBase, public MMdaAudioOutputStreamCallback
+ {
+ public:
+ CStreamPlayer(MStreamProvider& aProvider, MStreamObs& aObs);
+ ~CStreamPlayer();
+ void ConstructL();
+
+ static TInt ClosestSupportedRate(TInt aRate);
+
+ TInt OpenStream(TInt aRate, TInt aChannels, TUint32 aType = KMMFFourCCCodePCM16);
+
+ void SetVolume(TInt aNew);
+ TInt Volume() const;
+ TInt MaxVolume() const;
+
+ void Stop();
+ void Start();
+ void Open();
+ void Close();
+
+ TBool Playing() const;
+ TBool Closed() const;
+
+ private:
+
+ void MaoscOpenComplete(TInt aError) ;
+ void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
+ void MaoscPlayComplete(TInt aError);
+
+ private:
+ void Request();
+ void SetCapsL();
+
+ private:
+ MStreamProvider& iProvider;
+ MStreamObs& iObs;
+ TInt iVolume;
+
+ CMdaAudioOutputStream* iStream;
+
+ TInt iRate;
+ TInt iChannels;
+ TUint32 iType;
+
+ enum
+ {
+ ENone = 0,
+ EInited = 0x1,
+ EStarted = 0x2,
+ EStopped = 0x4,
+ EVolumeChange = 0x8,
+ EDied = 0x10
+ };
+
+ TInt iState;
+ TBuf8<KSilenceBuffer> iSilence;
+ TPtrC8 iPtr;
+
+ };
+
+
+#endif
+
diff --git a/src/audio/ums/SDL_umsaudio.c b/src/audio/ums/SDL_umsaudio.c
new file mode 100644
index 0000000..0b11441
--- /dev/null
+++ b/src/audio/ums/SDL_umsaudio.c
@@ -0,0 +1,547 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Carsten Griwodz
+ griff@kom.tu-darmstadt.de
+
+ based on linux/SDL_dspaudio.c by Sam Lantinga
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_audiodev_c.h"
+#include "SDL_umsaudio.h"
+
+/* The tag name used by UMS audio */
+#define UMS_DRIVER_NAME "ums"
+
+#define DEBUG_AUDIO 1
+
+/* Audio driver functions */
+static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void UMS_PlayAudio(_THIS);
+static Uint8 *UMS_GetAudioBuf(_THIS);
+static void UMS_CloseAudio(_THIS);
+
+static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode, long flags);
+static UMSAudioDevice_ReturnCode UADClose(_THIS);
+static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits);
+static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits);
+static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate);
+static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order);
+static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt);
+static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt);
+static UMSAudioDevice_ReturnCode UADInitialize(_THIS);
+static UMSAudioDevice_ReturnCode UADStart(_THIS);
+static UMSAudioDevice_ReturnCode UADStop(_THIS);
+static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt );
+static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long* buff_size );
+static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long* buff_size );
+static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long* buff_size );
+static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes, long* bytes_ret );
+static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume );
+static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance );
+static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels );
+static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block );
+static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output, long* left_gain, long* right_gain);
+static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer* buff, long samples, long* samples_written);
+
+/* Audio driver bootstrap functions */
+static int Audio_Available(void)
+{
+ return 1;
+}
+
+static void Audio_DeleteDevice(_THIS)
+{
+ if(this->hidden->playbuf._buffer) SDL_free(this->hidden->playbuf._buffer);
+ if(this->hidden->fillbuf._buffer) SDL_free(this->hidden->fillbuf._buffer);
+ _somFree( this->hidden->umsdev );
+ SDL_free(this->hidden);
+ SDL_free(this);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /*
+ * Allocate and initialize management storage and private management
+ * storage for this SDL-using library.
+ */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Creating UMS Audio device\n");
+#endif
+
+ /*
+ * Calls for UMS env initialization and audio object construction.
+ */
+ this->hidden->ev = somGetGlobalEnvironment();
+ this->hidden->umsdev = UMSAudioDeviceNew();
+
+ /*
+ * Set the function pointers.
+ */
+ this->OpenAudio = UMS_OpenAudio;
+ this->WaitAudio = NULL; /* we do blocking output */
+ this->PlayAudio = UMS_PlayAudio;
+ this->GetAudioBuf = UMS_GetAudioBuf;
+ this->CloseAudio = UMS_CloseAudio;
+ this->free = Audio_DeleteDevice;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "done\n");
+#endif
+ return this;
+}
+
+AudioBootStrap UMS_bootstrap = {
+ UMS_DRIVER_NAME, "AIX UMS audio",
+ Audio_Available, Audio_CreateDevice
+};
+
+static Uint8 *UMS_GetAudioBuf(_THIS)
+{
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "enter UMS_GetAudioBuf\n");
+#endif
+ return this->hidden->fillbuf._buffer;
+/*
+ long bufSize;
+ UMSAudioDevice_ReturnCode rc;
+
+ rc = UADSetTimeFormat(this, UMSAudioTypes_Bytes );
+ rc = UADWriteBuffSize(this, bufSize );
+*/
+}
+
+static void UMS_CloseAudio(_THIS)
+{
+ UMSAudioDevice_ReturnCode rc;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "enter UMS_CloseAudio\n");
+#endif
+ rc = UADPlayRemainingData(this, TRUE);
+ rc = UADStop(this);
+ rc = UADClose(this);
+}
+
+static void UMS_PlayAudio(_THIS)
+{
+ UMSAudioDevice_ReturnCode rc;
+ long samplesToWrite;
+ long samplesWritten;
+ UMSAudioTypes_Buffer swpbuf;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "enter UMS_PlayAudio\n");
+#endif
+ samplesToWrite = this->hidden->playbuf._length/this->hidden->bytesPerSample;
+ do
+ {
+ rc = UADWrite(this, &this->hidden->playbuf,
+ samplesToWrite,
+ &samplesWritten );
+ samplesToWrite -= samplesWritten;
+
+ /* rc values: UMSAudioDevice_Success
+ * UMSAudioDevice_Failure
+ * UMSAudioDevice_Preempted
+ * UMSAudioDevice_Interrupted
+ * UMSAudioDevice_DeviceError
+ */
+ if ( rc == UMSAudioDevice_DeviceError ) {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Returning from PlayAudio with devices error\n");
+#endif
+ return;
+ }
+ }
+ while(samplesToWrite>0);
+
+ SDL_LockAudio();
+ SDL_memcpy( &swpbuf, &this->hidden->playbuf, sizeof(UMSAudioTypes_Buffer) );
+ SDL_memcpy( &this->hidden->playbuf, &this->hidden->fillbuf, sizeof(UMSAudioTypes_Buffer) );
+ SDL_memcpy( &this->hidden->fillbuf, &swpbuf, sizeof(UMSAudioTypes_Buffer) );
+ SDL_UnlockAudio();
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Wrote audio data and swapped buffer\n");
+#endif
+}
+
+#if 0
+// /* Set the DSP frequency */
+// value = spec->freq;
+// if ( ioctl(this->hidden->audio_fd, SOUND_PCM_WRITE_RATE, &value) < 0 ) {
+// SDL_SetError("Couldn't set audio frequency");
+// return(-1);
+// }
+// spec->freq = value;
+#endif
+
+static int UMS_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ char* audiodev = "/dev/paud0";
+ long lgain;
+ long rgain;
+ long outRate;
+ long outBufSize;
+ long bitsPerSample;
+ long samplesPerSec;
+ long success;
+ Uint16 test_format;
+ int frag_spec;
+ UMSAudioDevice_ReturnCode rc;
+
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "enter UMS_OpenAudio\n");
+#endif
+ rc = UADOpen(this, audiodev,"PLAY", UMSAudioDevice_BlockingIO);
+ if ( rc != UMSAudioDevice_Success ) {
+ SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
+ return -1;
+ }
+
+ rc = UADSetAudioFormatType(this, "PCM");
+
+ success = 0;
+ test_format = SDL_FirstAudioFormat(spec->format);
+ do
+ {
+#ifdef DEBUG_AUDIO
+ fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
+#endif
+ switch ( test_format )
+ {
+ case AUDIO_U8:
+/* from the mac code: better ? */
+/* sample_bits = spec->size / spec->samples / spec->channels * 8; */
+ success = 1;
+ bitsPerSample = 8;
+ rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
+ rc = UADSetByteOrder(this, "MSB"); /* irrelevant */
+ rc = UADSetNumberFormat(this, "UNSIGNED");
+ break;
+ case AUDIO_S8:
+ success = 1;
+ bitsPerSample = 8;
+ rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
+ rc = UADSetByteOrder(this, "MSB"); /* irrelevant */
+ rc = UADSetNumberFormat(this, "SIGNED");
+ break;
+ case AUDIO_S16LSB:
+ success = 1;
+ bitsPerSample = 16;
+ rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
+ rc = UADSetByteOrder(this, "LSB");
+ rc = UADSetNumberFormat(this, "SIGNED");
+ break;
+ case AUDIO_S16MSB:
+ success = 1;
+ bitsPerSample = 16;
+ rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
+ rc = UADSetByteOrder(this, "MSB");
+ rc = UADSetNumberFormat(this, "SIGNED");
+ break;
+ case AUDIO_U16LSB:
+ success = 1;
+ bitsPerSample = 16;
+ rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
+ rc = UADSetByteOrder(this, "LSB");
+ rc = UADSetNumberFormat(this, "UNSIGNED");
+ break;
+ case AUDIO_U16MSB:
+ success = 1;
+ bitsPerSample = 16;
+ rc = UADSetSampleRate(this, spec->freq << 16, &outRate );
+ rc = UADSetByteOrder(this, "MSB");
+ rc = UADSetNumberFormat(this, "UNSIGNED");
+ break;
+ default:
+ break;
+ }
+ if ( ! success ) {
+ test_format = SDL_NextAudioFormat();
+ }
+ }
+ while ( ! success && test_format );
+
+ if ( success == 0 ) {
+ SDL_SetError("Couldn't find any hardware audio formats");
+ return -1;
+ }
+
+ spec->format = test_format;
+
+ for ( frag_spec = 0; (0x01<<frag_spec) < spec->size; ++frag_spec );
+ if ( (0x01<<frag_spec) != spec->size ) {
+ SDL_SetError("Fragment size must be a power of two");
+ return -1;
+ }
+ if ( frag_spec > 2048 ) frag_spec = 2048;
+
+ this->hidden->bytesPerSample = (bitsPerSample / 8) * spec->channels;
+ samplesPerSec = this->hidden->bytesPerSample * outRate;
+
+ this->hidden->playbuf._length = 0;
+ this->hidden->playbuf._maximum = spec->size;
+ this->hidden->playbuf._buffer = (unsigned char*)SDL_malloc(spec->size);
+ this->hidden->fillbuf._length = 0;
+ this->hidden->fillbuf._maximum = spec->size;
+ this->hidden->fillbuf._buffer = (unsigned char*)SDL_malloc(spec->size);
+
+ rc = UADSetBitsPerSample(this, bitsPerSample );
+ rc = UADSetDMABufferSize(this, frag_spec, &outBufSize );
+ rc = UADSetChannels(this, spec->channels); /* functions reduces to mono or stereo */
+
+ lgain = 100; /*maximum left input gain*/
+ rgain = 100; /*maimum right input gain*/
+ rc = UADEnableOutput(this, "LINE_OUT",&lgain,&rgain);
+ rc = UADInitialize(this);
+ rc = UADStart(this);
+ rc = UADSetVolume(this, 100);
+ rc = UADSetBalance(this, 0);
+
+ /* We're ready to rock and roll. :-) */
+ return 0;
+}
+
+
+static UMSAudioDevice_ReturnCode UADGetBitsPerSample(_THIS, long* bits)
+{
+ return UMSAudioDevice_get_bits_per_sample( this->hidden->umsdev,
+ this->hidden->ev,
+ bits );
+}
+
+static UMSAudioDevice_ReturnCode UADSetBitsPerSample(_THIS, long bits)
+{
+ return UMSAudioDevice_set_bits_per_sample( this->hidden->umsdev,
+ this->hidden->ev,
+ bits );
+}
+
+static UMSAudioDevice_ReturnCode UADSetSampleRate(_THIS, long rate, long* set_rate)
+{
+ /* from the mac code: sample rate = spec->freq << 16; */
+ return UMSAudioDevice_set_sample_rate( this->hidden->umsdev,
+ this->hidden->ev,
+ rate,
+ set_rate );
+}
+
+static UMSAudioDevice_ReturnCode UADSetByteOrder(_THIS, string byte_order)
+{
+ return UMSAudioDevice_set_byte_order( this->hidden->umsdev,
+ this->hidden->ev,
+ byte_order );
+}
+
+static UMSAudioDevice_ReturnCode UADSetAudioFormatType(_THIS, string fmt)
+{
+ /* possible PCM, A_LAW or MU_LAW */
+ return UMSAudioDevice_set_audio_format_type( this->hidden->umsdev,
+ this->hidden->ev,
+ fmt );
+}
+
+static UMSAudioDevice_ReturnCode UADSetNumberFormat(_THIS, string fmt)
+{
+ /* possible SIGNED, UNSIGNED, or TWOS_COMPLEMENT */
+ return UMSAudioDevice_set_number_format( this->hidden->umsdev,
+ this->hidden->ev,
+ fmt );
+}
+
+static UMSAudioDevice_ReturnCode UADInitialize(_THIS)
+{
+ return UMSAudioDevice_initialize( this->hidden->umsdev,
+ this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADStart(_THIS)
+{
+ return UMSAudioDevice_start( this->hidden->umsdev,
+ this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADSetTimeFormat(_THIS, UMSAudioTypes_TimeFormat fmt )
+{
+ /*
+ * Switches the time format to the new format, immediately.
+ * possible UMSAudioTypes_Msecs, UMSAudioTypes_Bytes or UMSAudioTypes_Samples
+ */
+ return UMSAudioDevice_set_time_format( this->hidden->umsdev,
+ this->hidden->ev,
+ fmt );
+}
+
+static UMSAudioDevice_ReturnCode UADWriteBuffSize(_THIS, long* buff_size )
+{
+ /*
+ * returns write buffer size in the current time format
+ */
+ return UMSAudioDevice_write_buff_size( this->hidden->umsdev,
+ this->hidden->ev,
+ buff_size );
+}
+
+static UMSAudioDevice_ReturnCode UADWriteBuffRemain(_THIS, long* buff_size )
+{
+ /*
+ * returns amount of available space in the write buffer
+ * in the current time format
+ */
+ return UMSAudioDevice_write_buff_remain( this->hidden->umsdev,
+ this->hidden->ev,
+ buff_size );
+}
+
+static UMSAudioDevice_ReturnCode UADWriteBuffUsed(_THIS, long* buff_size )
+{
+ /*
+ * returns amount of filled space in the write buffer
+ * in the current time format
+ */
+ return UMSAudioDevice_write_buff_used( this->hidden->umsdev,
+ this->hidden->ev,
+ buff_size );
+}
+
+static UMSAudioDevice_ReturnCode UADSetDMABufferSize(_THIS, long bytes, long* bytes_ret )
+{
+ /*
+ * Request a new DMA buffer size, maximum requested size 2048.
+ * Takes effect with next initialize() call.
+ * Devices may or may not support DMA.
+ */
+ return UMSAudioDevice_set_DMA_buffer_size( this->hidden->umsdev,
+ this->hidden->ev,
+ bytes,
+ bytes_ret );
+}
+
+static UMSAudioDevice_ReturnCode UADSetVolume(_THIS, long volume )
+{
+ /*
+ * Set the volume.
+ * Takes effect immediately.
+ */
+ return UMSAudioDevice_set_volume( this->hidden->umsdev,
+ this->hidden->ev,
+ volume );
+}
+
+static UMSAudioDevice_ReturnCode UADSetBalance(_THIS, long balance )
+{
+ /*
+ * Set the balance.
+ * Takes effect immediately.
+ */
+ return UMSAudioDevice_set_balance( this->hidden->umsdev,
+ this->hidden->ev,
+ balance );
+}
+
+static UMSAudioDevice_ReturnCode UADSetChannels(_THIS, long channels )
+{
+ /*
+ * Set mono or stereo.
+ * Takes effect with next initialize() call.
+ */
+ if ( channels != 1 ) channels = 2;
+ return UMSAudioDevice_set_number_of_channels( this->hidden->umsdev,
+ this->hidden->ev,
+ channels );
+}
+
+static UMSAudioDevice_ReturnCode UADOpen(_THIS, string device, string mode, long flags)
+{
+ return UMSAudioDevice_open( this->hidden->umsdev,
+ this->hidden->ev,
+ device,
+ mode,
+ flags );
+}
+
+static UMSAudioDevice_ReturnCode UADWrite(_THIS, UMSAudioTypes_Buffer* buff,
+ long samples,
+ long* samples_written)
+{
+ return UMSAudioDevice_write( this->hidden->umsdev,
+ this->hidden->ev,
+ buff,
+ samples,
+ samples_written );
+}
+
+static UMSAudioDevice_ReturnCode UADPlayRemainingData(_THIS, boolean block )
+{
+ return UMSAudioDevice_play_remaining_data( this->hidden->umsdev,
+ this->hidden->ev,
+ block);
+}
+
+static UMSAudioDevice_ReturnCode UADStop(_THIS)
+{
+ return UMSAudioDevice_stop( this->hidden->umsdev,
+ this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADClose(_THIS)
+{
+ return UMSAudioDevice_close( this->hidden->umsdev,
+ this->hidden->ev );
+}
+
+static UMSAudioDevice_ReturnCode UADEnableOutput(_THIS, string output, long* left_gain, long* right_gain)
+{
+ return UMSAudioDevice_enable_output( this->hidden->umsdev,
+ this->hidden->ev,
+ output,
+ left_gain,
+ right_gain );
+}
+
diff --git a/src/audio/ums/SDL_umsaudio.h b/src/audio/ums/SDL_umsaudio.h
new file mode 100644
index 0000000..cb52737
--- /dev/null
+++ b/src/audio/ums/SDL_umsaudio.h
@@ -0,0 +1,50 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Carsten Griwodz
+ griff@kom.tu-darmstadt.de
+
+ based on linux/SDL_dspaudio.h by Sam Lantinga
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_UMSaudio_h
+#define _SDL_UMSaudio_h
+
+#include <UMS/UMSAudioDevice.h>
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+struct SDL_PrivateAudioData
+{
+ /* Pointer to the (open) UMS audio device */
+ Environment* ev;
+ UMSAudioDevice umsdev;
+
+ /* Raw mixing buffer */
+ UMSAudioTypes_Buffer playbuf;
+ UMSAudioTypes_Buffer fillbuf;
+
+ long bytesPerSample;
+};
+
+#endif /* _SDL_UMSaudio_h */
+
diff --git a/src/audio/windib/SDL_dibaudio.c b/src/audio/windib/SDL_dibaudio.c
new file mode 100644
index 0000000..1e63271
--- /dev/null
+++ b/src/audio/windib/SDL_dibaudio.c
@@ -0,0 +1,322 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_dibaudio.h"
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+#include "win_ce_semaphore.h"
+#endif
+
+
+/* Audio driver functions */
+static int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DIB_ThreadInit(_THIS);
+static void DIB_WaitAudio(_THIS);
+static Uint8 *DIB_GetAudioBuf(_THIS);
+static void DIB_PlayAudio(_THIS);
+static void DIB_WaitDone(_THIS);
+static void DIB_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ return(1);
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = DIB_OpenAudio;
+ this->ThreadInit = DIB_ThreadInit;
+ this->WaitAudio = DIB_WaitAudio;
+ this->PlayAudio = DIB_PlayAudio;
+ this->GetAudioBuf = DIB_GetAudioBuf;
+ this->WaitDone = DIB_WaitDone;
+ this->CloseAudio = DIB_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap WAVEOUT_bootstrap = {
+ "waveout", "Win95/98/NT/2000 WaveOut",
+ Audio_Available, Audio_CreateDevice
+};
+
+
+/* The Win32 callback for filling the WAVE device */
+static void CALLBACK FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ SDL_AudioDevice *this = (SDL_AudioDevice *)dwInstance;
+
+ /* Only service "buffer done playing" messages */
+ if ( uMsg != WOM_DONE )
+ return;
+
+ /* Signal that we are done playing a buffer */
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ ReleaseSemaphoreCE(audio_sem, 1, NULL);
+#else
+ ReleaseSemaphore(audio_sem, 1, NULL);
+#endif
+}
+
+static void SetMMerror(char *function, MMRESULT code)
+{
+ size_t len;
+ char errbuf[MAXERRORLENGTH];
+#ifdef _WIN32_WCE
+ wchar_t werrbuf[MAXERRORLENGTH];
+#endif
+
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
+ len = SDL_strlen(errbuf);
+
+#ifdef _WIN32_WCE
+ /* UNICODE version */
+ waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH-len);
+ WideCharToMultiByte(CP_ACP,0,werrbuf,-1,errbuf+len,MAXERRORLENGTH-len,NULL,NULL);
+#else
+ waveOutGetErrorText(code, errbuf+len, (UINT)(MAXERRORLENGTH-len));
+#endif
+
+ SDL_SetError("%s",errbuf);
+}
+
+/* Set high priority for the audio thread */
+static void DIB_ThreadInit(_THIS)
+{
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+}
+
+void DIB_WaitAudio(_THIS)
+{
+ /* Wait for an audio chunk to finish */
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ WaitForSemaphoreCE(audio_sem, INFINITE);
+#else
+ WaitForSingleObject(audio_sem, INFINITE);
+#endif
+}
+
+Uint8 *DIB_GetAudioBuf(_THIS)
+{
+ Uint8 *retval;
+
+ retval = (Uint8 *)(wavebuf[next_buffer].lpData);
+ return retval;
+}
+
+void DIB_PlayAudio(_THIS)
+{
+ /* Queue it up */
+ waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
+ next_buffer = (next_buffer+1)%NUM_BUFFERS;
+}
+
+void DIB_WaitDone(_THIS)
+{
+ int i, left;
+
+ do {
+ left = NUM_BUFFERS;
+ for ( i=0; i<NUM_BUFFERS; ++i ) {
+ if ( wavebuf[i].dwFlags & WHDR_DONE ) {
+ --left;
+ }
+ }
+ if ( left > 0 ) {
+ SDL_Delay(100);
+ }
+ } while ( left > 0 );
+}
+
+void DIB_CloseAudio(_THIS)
+{
+ int i;
+
+ /* Close up audio */
+ if ( audio_sem ) {
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ CloseSynchHandle(audio_sem);
+#else
+ CloseHandle(audio_sem);
+#endif
+ }
+ if ( sound ) {
+ waveOutClose(sound);
+ }
+
+ /* Clean up mixing buffers */
+ for ( i=0; i<NUM_BUFFERS; ++i ) {
+ if ( wavebuf[i].dwUser != 0xFFFF ) {
+ waveOutUnprepareHeader(sound, &wavebuf[i],
+ sizeof(wavebuf[i]));
+ wavebuf[i].dwUser = 0xFFFF;
+ }
+ }
+ /* Free raw mixing buffer */
+ if ( mixbuf != NULL ) {
+ SDL_free(mixbuf);
+ mixbuf = NULL;
+ }
+}
+
+int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ MMRESULT result;
+ int i;
+ WAVEFORMATEX waveformat;
+
+ /* Initialize the wavebuf structures for closing */
+ sound = NULL;
+ audio_sem = NULL;
+ for ( i = 0; i < NUM_BUFFERS; ++i )
+ wavebuf[i].dwUser = 0xFFFF;
+ mixbuf = NULL;
+
+ /* Set basic WAVE format parameters */
+ SDL_memset(&waveformat, 0, sizeof(waveformat));
+ waveformat.wFormatTag = WAVE_FORMAT_PCM;
+
+ /* Determine the audio parameters from the AudioSpec */
+ switch ( spec->format & 0xFF ) {
+ case 8:
+ /* Unsigned 8 bit audio data */
+ spec->format = AUDIO_U8;
+ waveformat.wBitsPerSample = 8;
+ break;
+ case 16:
+ /* Signed 16 bit audio data */
+ spec->format = AUDIO_S16;
+ waveformat.wBitsPerSample = 16;
+ break;
+ default:
+ SDL_SetError("Unsupported audio format");
+ return(-1);
+ }
+ waveformat.nChannels = spec->channels;
+ waveformat.nSamplesPerSec = spec->freq;
+ waveformat.nBlockAlign =
+ waveformat.nChannels * (waveformat.wBitsPerSample/8);
+ waveformat.nAvgBytesPerSec =
+ waveformat.nSamplesPerSec * waveformat.nBlockAlign;
+
+ /* Check the buffer size -- minimum of 1/4 second (word aligned) */
+ if ( spec->samples < (spec->freq/4) )
+ spec->samples = ((spec->freq/4)+3)&~3;
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Open the audio device */
+ result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
+ (DWORD_PTR)FillSound, (DWORD_PTR)this, CALLBACK_FUNCTION);
+ if ( result != MMSYSERR_NOERROR ) {
+ SetMMerror("waveOutOpen()", result);
+ return(-1);
+ }
+
+#ifdef SOUND_DEBUG
+ /* Check the sound device we retrieved */
+ {
+ WAVEOUTCAPS caps;
+
+ result = waveOutGetDevCaps((UINT)sound, &caps, sizeof(caps));
+ if ( result != MMSYSERR_NOERROR ) {
+ SetMMerror("waveOutGetDevCaps()", result);
+ return(-1);
+ }
+ printf("Audio device: %s\n", caps.szPname);
+ }
+#endif
+
+ /* Create the audio buffer semaphore */
+#if defined(_WIN32_WCE) && (_WIN32_WCE < 300)
+ audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
+#else
+ audio_sem = CreateSemaphore(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
+#endif
+ if ( audio_sem == NULL ) {
+ SDL_SetError("Couldn't create semaphore");
+ return(-1);
+ }
+
+ /* Create the sound buffers */
+ mixbuf = (Uint8 *)SDL_malloc(NUM_BUFFERS*spec->size);
+ if ( mixbuf == NULL ) {
+ SDL_SetError("Out of memory");
+ return(-1);
+ }
+ for ( i = 0; i < NUM_BUFFERS; ++i ) {
+ SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
+ wavebuf[i].lpData = (LPSTR) &mixbuf[i*spec->size];
+ wavebuf[i].dwBufferLength = spec->size;
+ wavebuf[i].dwFlags = WHDR_DONE;
+ result = waveOutPrepareHeader(sound, &wavebuf[i],
+ sizeof(wavebuf[i]));
+ if ( result != MMSYSERR_NOERROR ) {
+ SetMMerror("waveOutPrepareHeader()", result);
+ return(-1);
+ }
+ }
+
+ /* Ready to go! */
+ next_buffer = 0;
+ return(0);
+}
diff --git a/src/audio/windib/SDL_dibaudio.h b/src/audio/windib/SDL_dibaudio.h
new file mode 100644
index 0000000..1e6036d
--- /dev/null
+++ b/src/audio/windib/SDL_dibaudio.h
@@ -0,0 +1,49 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+#define NUM_BUFFERS 2 /* -- Don't lower this! */
+
+struct SDL_PrivateAudioData {
+ HWAVEOUT sound;
+ HANDLE audio_sem;
+ Uint8 *mixbuf; /* The raw allocated mixing buffer */
+ WAVEHDR wavebuf[NUM_BUFFERS]; /* Wave audio fragments */
+ int next_buffer;
+};
+
+/* Old variable names */
+#define sound (this->hidden->sound)
+#define audio_sem (this->hidden->audio_sem)
+#define mixbuf (this->hidden->mixbuf)
+#define wavebuf (this->hidden->wavebuf)
+#define next_buffer (this->hidden->next_buffer)
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/windx5/SDL_dx5audio.c b/src/audio/windx5/SDL_dx5audio.c
new file mode 100644
index 0000000..6998c49
--- /dev/null
+++ b/src/audio/windx5/SDL_dx5audio.c
@@ -0,0 +1,705 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* Allow access to a raw mixing buffer */
+
+#include "SDL_timer.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "SDL_dx5audio.h"
+
+/* Define this if you want to use DirectX 6 DirectSoundNotify interface */
+//#define USE_POSITION_NOTIFY
+
+/* DirectX function pointers for audio */
+HRESULT (WINAPI *DSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
+
+/* Audio driver functions */
+static int DX5_OpenAudio(_THIS, SDL_AudioSpec *spec);
+static void DX5_ThreadInit(_THIS);
+static void DX5_WaitAudio_BusyWait(_THIS);
+#ifdef USE_POSITION_NOTIFY
+static void DX6_WaitAudio_EventWait(_THIS);
+#endif
+static void DX5_PlayAudio(_THIS);
+static Uint8 *DX5_GetAudioBuf(_THIS);
+static void DX5_WaitDone(_THIS);
+static void DX5_CloseAudio(_THIS);
+
+/* Audio driver bootstrap functions */
+
+static int Audio_Available(void)
+{
+ HINSTANCE DSoundDLL;
+ int dsound_ok;
+
+ /* Version check DSOUND.DLL (Is DirectX okay?) */
+ dsound_ok = 0;
+ DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
+ if ( DSoundDLL != NULL ) {
+ /* We just use basic DirectSound, we're okay */
+ /* Yay! */
+ /* Unfortunately, the sound drivers on NT have
+ higher latencies than the audio buffers used
+ by many SDL applications, so there are gaps
+ in the audio - it sounds terrible. Punt for now.
+ */
+ OSVERSIONINFO ver;
+ ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ GetVersionEx(&ver);
+ switch (ver.dwPlatformId) {
+ case VER_PLATFORM_WIN32_NT:
+ if ( ver.dwMajorVersion > 4 ) {
+ /* Win2K */
+ dsound_ok = 1;
+ } else {
+ /* WinNT */
+ dsound_ok = 0;
+ }
+ break;
+ default:
+ /* Win95 or Win98 */
+ dsound_ok = 1;
+ break;
+ }
+ /* Now check for DirectX 5 or better - otherwise
+ * we will fail later in DX5_OpenAudio without a chance
+ * to fall back to the DIB driver. */
+ if (dsound_ok) {
+ /* DirectSoundCaptureCreate was added in DX5 */
+ if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate")))
+ dsound_ok = 0;
+
+ }
+ /* Clean up.. */
+ FreeLibrary(DSoundDLL);
+ }
+ return(dsound_ok);
+}
+
+/* Functions for loading the DirectX functions dynamically */
+static HINSTANCE DSoundDLL = NULL;
+
+static void DX5_Unload(void)
+{
+ if ( DSoundDLL != NULL ) {
+ FreeLibrary(DSoundDLL);
+ DSoundCreate = NULL;
+ DSoundDLL = NULL;
+ }
+}
+static int DX5_Load(void)
+{
+ int status;
+
+ DX5_Unload();
+ DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
+ if ( DSoundDLL != NULL ) {
+ DSoundCreate = (void *)GetProcAddress(DSoundDLL,
+ TEXT("DirectSoundCreate"));
+ }
+ if ( DSoundDLL && DSoundCreate ) {
+ status = 0;
+ } else {
+ DX5_Unload();
+ status = -1;
+ }
+ return status;
+}
+
+static void Audio_DeleteDevice(SDL_AudioDevice *device)
+{
+ DX5_Unload();
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_AudioDevice *Audio_CreateDevice(int devindex)
+{
+ SDL_AudioDevice *this;
+
+ /* Load DirectX */
+ if ( DX5_Load() < 0 ) {
+ return(NULL);
+ }
+
+ /* Initialize all variables that we clean on shutdown */
+ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
+ if ( this ) {
+ SDL_memset(this, 0, (sizeof *this));
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ }
+ if ( (this == NULL) || (this->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( this ) {
+ SDL_free(this);
+ }
+ return(0);
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ /* Set the function pointers */
+ this->OpenAudio = DX5_OpenAudio;
+ this->ThreadInit = DX5_ThreadInit;
+ this->WaitAudio = DX5_WaitAudio_BusyWait;
+ this->PlayAudio = DX5_PlayAudio;
+ this->GetAudioBuf = DX5_GetAudioBuf;
+ this->WaitDone = DX5_WaitDone;
+ this->CloseAudio = DX5_CloseAudio;
+
+ this->free = Audio_DeleteDevice;
+
+ return this;
+}
+
+AudioBootStrap DSOUND_bootstrap = {
+ "dsound", "Win95/98/2000 DirectSound",
+ Audio_Available, Audio_CreateDevice
+};
+
+static void SetDSerror(const char *function, int code)
+{
+ static const char *error;
+ static char errbuf[1024];
+
+ errbuf[0] = 0;
+ switch (code) {
+ case E_NOINTERFACE:
+ error =
+ "Unsupported interface\n-- Is DirectX 5.0 or later installed?";
+ break;
+ case DSERR_ALLOCATED:
+ error = "Audio device in use";
+ break;
+ case DSERR_BADFORMAT:
+ error = "Unsupported audio format";
+ break;
+ case DSERR_BUFFERLOST:
+ error = "Mixing buffer was lost";
+ break;
+ case DSERR_CONTROLUNAVAIL:
+ error = "Control requested is not available";
+ break;
+ case DSERR_INVALIDCALL:
+ error = "Invalid call for the current state";
+ break;
+ case DSERR_INVALIDPARAM:
+ error = "Invalid parameter";
+ break;
+ case DSERR_NODRIVER:
+ error = "No audio device found";
+ break;
+ case DSERR_OUTOFMEMORY:
+ error = "Out of memory";
+ break;
+ case DSERR_PRIOLEVELNEEDED:
+ error = "Caller doesn't have priority";
+ break;
+ case DSERR_UNSUPPORTED:
+ error = "Function not supported";
+ break;
+ default:
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf),
+ "%s: Unknown DirectSound error: 0x%x",
+ function, code);
+ break;
+ }
+ if ( ! errbuf[0] ) {
+ SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error);
+ }
+ SDL_SetError("%s", errbuf);
+ return;
+}
+
+/* DirectSound needs to be associated with a window */
+static HWND mainwin = NULL;
+/* */
+void DX5_SoundFocus(HWND hwnd)
+{
+ mainwin = hwnd;
+}
+
+static void DX5_ThreadInit(_THIS)
+{
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+}
+
+static void DX5_WaitAudio_BusyWait(_THIS)
+{
+ DWORD status;
+ DWORD cursor, junk;
+ HRESULT result;
+
+ /* Semi-busy wait, since we have no way of getting play notification
+ on a primary mixing buffer located in hardware (DirectX 5.0)
+ */
+ result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
+ if ( result != DS_OK ) {
+ if ( result == DSERR_BUFFERLOST ) {
+ IDirectSoundBuffer_Restore(mixbuf);
+ }
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound GetCurrentPosition", result);
+#endif
+ return;
+ }
+
+ while ( (cursor/mixlen) == lastchunk ) {
+ /* FIXME: find out how much time is left and sleep that long */
+ SDL_Delay(1);
+
+ /* Try to restore a lost sound buffer */
+ IDirectSoundBuffer_GetStatus(mixbuf, &status);
+ if ( (status&DSBSTATUS_BUFFERLOST) ) {
+ IDirectSoundBuffer_Restore(mixbuf);
+ IDirectSoundBuffer_GetStatus(mixbuf, &status);
+ if ( (status&DSBSTATUS_BUFFERLOST) ) {
+ break;
+ }
+ }
+ if ( ! (status&DSBSTATUS_PLAYING) ) {
+ result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
+ if ( result == DS_OK ) {
+ continue;
+ }
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound Play", result);
+#endif
+ return;
+ }
+
+ /* Find out where we are playing */
+ result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
+ &junk, &cursor);
+ if ( result != DS_OK ) {
+ SetDSerror("DirectSound GetCurrentPosition", result);
+ return;
+ }
+ }
+}
+
+#ifdef USE_POSITION_NOTIFY
+static void DX6_WaitAudio_EventWait(_THIS)
+{
+ DWORD status;
+ HRESULT result;
+
+ /* Try to restore a lost sound buffer */
+ IDirectSoundBuffer_GetStatus(mixbuf, &status);
+ if ( (status&DSBSTATUS_BUFFERLOST) ) {
+ IDirectSoundBuffer_Restore(mixbuf);
+ IDirectSoundBuffer_GetStatus(mixbuf, &status);
+ if ( (status&DSBSTATUS_BUFFERLOST) ) {
+ return;
+ }
+ }
+ if ( ! (status&DSBSTATUS_PLAYING) ) {
+ result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
+ if ( result != DS_OK ) {
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound Play", result);
+#endif
+ return;
+ }
+ }
+ WaitForSingleObject(audio_event, INFINITE);
+}
+#endif /* USE_POSITION_NOTIFY */
+
+static void DX5_PlayAudio(_THIS)
+{
+ /* Unlock the buffer, allowing it to play */
+ if ( locked_buf ) {
+ IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0);
+ }
+
+}
+
+static Uint8 *DX5_GetAudioBuf(_THIS)
+{
+ DWORD cursor, junk;
+ HRESULT result;
+ DWORD rawlen;
+
+ /* Figure out which blocks to fill next */
+ locked_buf = NULL;
+ result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
+ if ( result == DSERR_BUFFERLOST ) {
+ IDirectSoundBuffer_Restore(mixbuf);
+ result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
+ &junk, &cursor);
+ }
+ if ( result != DS_OK ) {
+ SetDSerror("DirectSound GetCurrentPosition", result);
+ return(NULL);
+ }
+ cursor /= mixlen;
+#ifdef DEBUG_SOUND
+ /* Detect audio dropouts */
+ { DWORD spot = cursor;
+ if ( spot < lastchunk ) {
+ spot += NUM_BUFFERS;
+ }
+ if ( spot > lastchunk+1 ) {
+ fprintf(stderr, "Audio dropout, missed %d fragments\n",
+ (spot - (lastchunk+1)));
+ }
+ }
+#endif
+ lastchunk = cursor;
+ cursor = (cursor+1)%NUM_BUFFERS;
+ cursor *= mixlen;
+
+ /* Lock the audio buffer */
+ result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
+ (LPVOID *)&locked_buf, &rawlen, NULL, &junk, 0);
+ if ( result == DSERR_BUFFERLOST ) {
+ IDirectSoundBuffer_Restore(mixbuf);
+ result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
+ (LPVOID *)&locked_buf, &rawlen, NULL, &junk, 0);
+ }
+ if ( result != DS_OK ) {
+ SetDSerror("DirectSound Lock", result);
+ return(NULL);
+ }
+ return(locked_buf);
+}
+
+static void DX5_WaitDone(_THIS)
+{
+ Uint8 *stream;
+
+ /* Wait for the playing chunk to finish */
+ stream = this->GetAudioBuf(this);
+ if ( stream != NULL ) {
+ SDL_memset(stream, silence, mixlen);
+ this->PlayAudio(this);
+ }
+ this->WaitAudio(this);
+
+ /* Stop the looping sound buffer */
+ IDirectSoundBuffer_Stop(mixbuf);
+}
+
+static void DX5_CloseAudio(_THIS)
+{
+ if ( sound != NULL ) {
+ if ( mixbuf != NULL ) {
+ /* Clean up the audio buffer */
+ IDirectSoundBuffer_Release(mixbuf);
+ mixbuf = NULL;
+ }
+ if ( audio_event != NULL ) {
+ CloseHandle(audio_event);
+ audio_event = NULL;
+ }
+ IDirectSound_Release(sound);
+ sound = NULL;
+ }
+}
+
+#ifdef USE_PRIMARY_BUFFER
+/* This function tries to create a primary audio buffer, and returns the
+ number of audio chunks available in the created buffer.
+*/
+static int CreatePrimary(LPDIRECTSOUND sndObj, HWND focus,
+ LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize)
+{
+ HRESULT result;
+ DSBUFFERDESC format;
+ DSBCAPS caps;
+ int numchunks;
+
+ /* Try to set primary mixing privileges */
+ result = IDirectSound_SetCooperativeLevel(sndObj, focus,
+ DSSCL_WRITEPRIMARY);
+ if ( result != DS_OK ) {
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound SetCooperativeLevel", result);
+#endif
+ return(-1);
+ }
+
+ /* Try to create the primary buffer */
+ SDL_memset(&format, 0, sizeof(format));
+ format.dwSize = sizeof(format);
+ format.dwFlags=(DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2);
+ format.dwFlags |= DSBCAPS_STICKYFOCUS;
+#ifdef USE_POSITION_NOTIFY
+ format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
+#endif
+ result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
+ if ( result != DS_OK ) {
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound CreateSoundBuffer", result);
+#endif
+ return(-1);
+ }
+
+ /* Check the size of the fragment buffer */
+ SDL_memset(&caps, 0, sizeof(caps));
+ caps.dwSize = sizeof(caps);
+ result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps);
+ if ( result != DS_OK ) {
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound GetCaps", result);
+#endif
+ IDirectSoundBuffer_Release(*sndbuf);
+ return(-1);
+ }
+ if ( (chunksize > caps.dwBufferBytes) ||
+ ((caps.dwBufferBytes%chunksize) != 0) ) {
+ /* The primary buffer size is not a multiple of 'chunksize'
+ -- this hopefully doesn't happen when 'chunksize' is a
+ power of 2.
+ */
+ IDirectSoundBuffer_Release(*sndbuf);
+ SDL_SetError(
+"Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
+ caps.dwBufferBytes, chunksize);
+ return(-1);
+ }
+ numchunks = (caps.dwBufferBytes/chunksize);
+
+ /* Set the primary audio format */
+ result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
+ if ( result != DS_OK ) {
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound SetFormat", result);
+#endif
+ IDirectSoundBuffer_Release(*sndbuf);
+ return(-1);
+ }
+ return(numchunks);
+}
+#endif /* USE_PRIMARY_BUFFER */
+
+/* This function tries to create a secondary audio buffer, and returns the
+ number of audio chunks available in the created buffer.
+*/
+static int CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
+ LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize)
+{
+ const int numchunks = 8;
+ HRESULT result;
+ DSBUFFERDESC format;
+ LPVOID pvAudioPtr1, pvAudioPtr2;
+ DWORD dwAudioBytes1, dwAudioBytes2;
+
+ /* Try to set primary mixing privileges */
+ if ( focus ) {
+ result = IDirectSound_SetCooperativeLevel(sndObj,
+ focus, DSSCL_PRIORITY);
+ } else {
+ result = IDirectSound_SetCooperativeLevel(sndObj,
+ GetDesktopWindow(), DSSCL_NORMAL);
+ }
+ if ( result != DS_OK ) {
+#ifdef DEBUG_SOUND
+ SetDSerror("DirectSound SetCooperativeLevel", result);
+#endif
+ return(-1);
+ }
+
+ /* Try to create the secondary buffer */
+ SDL_memset(&format, 0, sizeof(format));
+ format.dwSize = sizeof(format);
+ format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
+#ifdef USE_POSITION_NOTIFY
+ format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
+#endif
+ if ( ! focus ) {
+ format.dwFlags |= DSBCAPS_GLOBALFOCUS;
+ } else {
+ format.dwFlags |= DSBCAPS_STICKYFOCUS;
+ }
+ format.dwBufferBytes = numchunks*chunksize;
+ if ( (format.dwBufferBytes < DSBSIZE_MIN) ||
+ (format.dwBufferBytes > DSBSIZE_MAX) ) {
+ SDL_SetError("Sound buffer size must be between %d and %d",
+ DSBSIZE_MIN/numchunks, DSBSIZE_MAX/numchunks);
+ return(-1);
+ }
+ format.dwReserved = 0;
+ format.lpwfxFormat = wavefmt;
+ result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
+ if ( result != DS_OK ) {
+ SetDSerror("DirectSound CreateSoundBuffer", result);
+ return(-1);
+ }
+ IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
+
+ /* Silence the initial audio buffer */
+ result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
+ (LPVOID *)&pvAudioPtr1, &dwAudioBytes1,
+ (LPVOID *)&pvAudioPtr2, &dwAudioBytes2,
+ DSBLOCK_ENTIREBUFFER);
+ if ( result == DS_OK ) {
+ if ( wavefmt->wBitsPerSample == 8 ) {
+ SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
+ } else {
+ SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
+ }
+ IDirectSoundBuffer_Unlock(*sndbuf,
+ (LPVOID)pvAudioPtr1, dwAudioBytes1,
+ (LPVOID)pvAudioPtr2, dwAudioBytes2);
+ }
+
+ /* We're ready to go */
+ return(numchunks);
+}
+
+/* This function tries to set position notify events on the mixing buffer */
+#ifdef USE_POSITION_NOTIFY
+static int CreateAudioEvent(_THIS)
+{
+ LPDIRECTSOUNDNOTIFY notify;
+ DSBPOSITIONNOTIFY *notify_positions;
+ int i, retval;
+ HRESULT result;
+
+ /* Default to fail on exit */
+ retval = -1;
+ notify = NULL;
+
+ /* Query for the interface */
+ result = IDirectSoundBuffer_QueryInterface(mixbuf,
+ &IID_IDirectSoundNotify, (void *)&notify);
+ if ( result != DS_OK ) {
+ goto done;
+ }
+
+ /* Allocate the notify structures */
+ notify_positions = (DSBPOSITIONNOTIFY *)SDL_malloc(NUM_BUFFERS*
+ sizeof(*notify_positions));
+ if ( notify_positions == NULL ) {
+ goto done;
+ }
+
+ /* Create the notify event */
+ audio_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if ( audio_event == NULL ) {
+ goto done;
+ }
+
+ /* Set up the notify structures */
+ for ( i=0; i<NUM_BUFFERS; ++i ) {
+ notify_positions[i].dwOffset = i*mixlen;
+ notify_positions[i].hEventNotify = audio_event;
+ }
+ result = IDirectSoundNotify_SetNotificationPositions(notify,
+ NUM_BUFFERS, notify_positions);
+ if ( result == DS_OK ) {
+ retval = 0;
+ }
+done:
+ if ( notify != NULL ) {
+ IDirectSoundNotify_Release(notify);
+ }
+ return(retval);
+}
+#endif /* USE_POSITION_NOTIFY */
+
+static int DX5_OpenAudio(_THIS, SDL_AudioSpec *spec)
+{
+ HRESULT result;
+ WAVEFORMATEX waveformat;
+
+ /* Set basic WAVE format parameters */
+ SDL_memset(&waveformat, 0, sizeof(waveformat));
+ waveformat.wFormatTag = WAVE_FORMAT_PCM;
+
+ /* Determine the audio parameters from the AudioSpec */
+ switch ( spec->format & 0xFF ) {
+ case 8:
+ /* Unsigned 8 bit audio data */
+ spec->format = AUDIO_U8;
+ silence = 0x80;
+ waveformat.wBitsPerSample = 8;
+ break;
+ case 16:
+ /* Signed 16 bit audio data */
+ spec->format = AUDIO_S16;
+ silence = 0x00;
+ waveformat.wBitsPerSample = 16;
+ break;
+ default:
+ SDL_SetError("Unsupported audio format");
+ return(-1);
+ }
+ waveformat.nChannels = spec->channels;
+ waveformat.nSamplesPerSec = spec->freq;
+ waveformat.nBlockAlign =
+ waveformat.nChannels * (waveformat.wBitsPerSample/8);
+ waveformat.nAvgBytesPerSec =
+ waveformat.nSamplesPerSec * waveformat.nBlockAlign;
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(spec);
+
+ /* Open the audio device */
+ result = DSoundCreate(NULL, &sound, NULL);
+ if ( result != DS_OK ) {
+ SetDSerror("DirectSoundCreate", result);
+ return(-1);
+ }
+
+ /* Create the audio buffer to which we write */
+ NUM_BUFFERS = -1;
+#ifdef USE_PRIMARY_BUFFER
+ if ( mainwin ) {
+ NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf,
+ &waveformat, spec->size);
+ }
+#endif /* USE_PRIMARY_BUFFER */
+ if ( NUM_BUFFERS < 0 ) {
+ NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf,
+ &waveformat, spec->size);
+ if ( NUM_BUFFERS < 0 ) {
+ return(-1);
+ }
+#ifdef DEBUG_SOUND
+ fprintf(stderr, "Using secondary audio buffer\n");
+#endif
+ }
+#ifdef DEBUG_SOUND
+ else
+ fprintf(stderr, "Using primary audio buffer\n");
+#endif
+
+ /* The buffer will auto-start playing in DX5_WaitAudio() */
+ lastchunk = 0;
+ mixlen = spec->size;
+
+#ifdef USE_POSITION_NOTIFY
+ /* See if we can use DirectX 6 event notification */
+ if ( CreateAudioEvent(this) == 0 ) {
+ this->WaitAudio = DX6_WaitAudio_EventWait;
+ } else {
+ this->WaitAudio = DX5_WaitAudio_BusyWait;
+ }
+#endif
+ return(0);
+}
+
diff --git a/src/audio/windx5/SDL_dx5audio.h b/src/audio/windx5/SDL_dx5audio.h
new file mode 100644
index 0000000..797b304
--- /dev/null
+++ b/src/audio/windx5/SDL_dx5audio.h
@@ -0,0 +1,55 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_lowaudio_h
+#define _SDL_lowaudio_h
+
+#include "directx.h"
+
+#include "../SDL_sysaudio.h"
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_AudioDevice *this
+
+/* The DirectSound objects */
+struct SDL_PrivateAudioData {
+ LPDIRECTSOUND sound;
+ LPDIRECTSOUNDBUFFER mixbuf;
+ int NUM_BUFFERS;
+ int mixlen, silence;
+ DWORD lastchunk;
+ Uint8 *locked_buf;
+ HANDLE audio_event;
+};
+
+/* Old variable names */
+#define sound (this->hidden->sound)
+#define mixbuf (this->hidden->mixbuf)
+#define NUM_BUFFERS (this->hidden->NUM_BUFFERS)
+#define mixlen (this->hidden->mixlen)
+#define silence (this->hidden->silence)
+#define lastchunk (this->hidden->lastchunk)
+#define locked_buf (this->hidden->locked_buf)
+#define audio_event (this->hidden->audio_event)
+
+#endif /* _SDL_lowaudio_h */
diff --git a/src/audio/windx5/directx.h b/src/audio/windx5/directx.h
new file mode 100644
index 0000000..d14d6c6
--- /dev/null
+++ b/src/audio/windx5/directx.h
@@ -0,0 +1,84 @@
+
+#ifndef _directx_h
+#define _directx_h
+
+/* Include all of the DirectX 5.0 headers and adds any necessary tweaks */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#ifndef WIN32
+#define WIN32
+#endif
+#undef WINNT
+
+/* Far pointers don't exist in 32-bit code */
+#ifndef FAR
+#define FAR
+#endif
+
+/* Error codes not yet included in Win32 API header files */
+#ifndef MAKE_HRESULT
+#define MAKE_HRESULT(sev,fac,code) \
+ ((HRESULT)(((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))))
+#endif
+
+#ifndef S_OK
+#define S_OK (HRESULT)0x00000000L
+#endif
+
+#ifndef SUCCEEDED
+#define SUCCEEDED(x) ((HRESULT)(x) >= 0)
+#endif
+#ifndef FAILED
+#define FAILED(x) ((HRESULT)(x)<0)
+#endif
+
+#ifndef E_FAIL
+#define E_FAIL (HRESULT)0x80000008L
+#endif
+#ifndef E_NOINTERFACE
+#define E_NOINTERFACE (HRESULT)0x80004002L
+#endif
+#ifndef E_OUTOFMEMORY
+#define E_OUTOFMEMORY (HRESULT)0x8007000EL
+#endif
+#ifndef E_INVALIDARG
+#define E_INVALIDARG (HRESULT)0x80070057L
+#endif
+#ifndef E_NOTIMPL
+#define E_NOTIMPL (HRESULT)0x80004001L
+#endif
+#ifndef REGDB_E_CLASSNOTREG
+#define REGDB_E_CLASSNOTREG (HRESULT)0x80040154L
+#endif
+
+/* Severity codes */
+#ifndef SEVERITY_ERROR
+#define SEVERITY_ERROR 1
+#endif
+
+/* Error facility codes */
+#ifndef FACILITY_WIN32
+#define FACILITY_WIN32 7
+#endif
+
+#ifndef FIELD_OFFSET
+#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
+#endif
+
+/* DirectX headers (if it isn't included, I haven't tested it yet)
+ */
+/* We need these defines to mark what version of DirectX API we use */
+#define DIRECTDRAW_VERSION 0x0700
+#define DIRECTSOUND_VERSION 0x0500
+#define DIRECTINPUT_VERSION 0x0500
+
+#ifdef __GNUC__
+#define NONAMELESSUNION
+#endif
+#include <ddraw.h>
+#include <dsound.h>
+#include <dinput.h>
+
+#endif /* _directx_h */