aboutsummaryrefslogtreecommitdiffstats
path: root/distrib/sdl-1.2.15/src/audio/macrom/SDL_romaudio.c
diff options
context:
space:
mode:
Diffstat (limited to 'distrib/sdl-1.2.15/src/audio/macrom/SDL_romaudio.c')
-rw-r--r--distrib/sdl-1.2.15/src/audio/macrom/SDL_romaudio.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/distrib/sdl-1.2.15/src/audio/macrom/SDL_romaudio.c b/distrib/sdl-1.2.15/src/audio/macrom/SDL_romaudio.c
new file mode 100644
index 0000000..1b3d49e
--- /dev/null
+++ b/distrib/sdl-1.2.15/src/audio/macrom/SDL_romaudio.c
@@ -0,0 +1,496 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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 */
+