The audio lock and unlock functions are now a part of the driver.
authorSam Lantinga <slouken@libsdl.org>
Sat, 30 Mar 2002 20:03:27 +0000
changeset 323 b7e8038e40ae
parent 322 fd93a09655e3
child 324 f25f666d609a
The audio lock and unlock functions are now a part of the driver. The MacOS audio locking has been implemented, courtesy of Ryan Gordon
src/audio/macrom/SDL_romaudio.c
src/audio/macrom/SDL_romaudio.h
--- a/src/audio/macrom/SDL_romaudio.c	Sat Mar 30 19:48:56 2002 +0000
+++ b/src/audio/macrom/SDL_romaudio.c	Sat Mar 30 20:03:27 2002 +0000
@@ -30,6 +30,7 @@
 #else
 #  include <Sound.h> /* SoundManager interface */
 #  include <Gestalt.h>
+#  include <DriverServices.h>
 #endif
 
 #include <stdlib.h>
@@ -46,6 +47,8 @@
 
 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 */
 
@@ -84,6 +87,8 @@
     /* Set the function pointers */
     this->OpenAudio   = Mac_OpenAudio;
     this->CloseAudio  = Mac_CloseAudio;
+    this->LockAudio   = Mac_LockAudio;
+    this->UnlockAudio = Mac_UnlockAudio;
     this->free        = Audio_DeleteDevice;
 
     return this;
@@ -94,18 +99,71 @@
 	Audio_Available, Audio_CreateDevice
 };
 
-#if TARGET_API_MAC_CARBON
+#if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
+/* FIXME: Does this work correctly on MacOS X as well? */
+
+#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 ) {
+        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
+            memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
+        } else {
+            audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
+        }
+    }
+
+    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, &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 fill_me, play_me;
+   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_ */
 
@@ -113,55 +171,31 @@
       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);
 
-   SndDoCommand (chan, &cmd, 0);
-   
    memset (buffer[fill_me], 0, audio->spec.size);
-   
-   if ( ! audio->paused ) {
-        if ( audio->convert.needed ) {
-            #if MACOSX
-                SDL_mutexP(audio->mixer_lock);
-            #endif
-                audio->spec.callback(audio->spec.userdata,
-                    (Uint8 *)audio->convert.buf,audio->convert.len);
-            #if MACOSX
-                SDL_mutexV(audio->mixer_lock);
-            #endif 
-               SDL_ConvertAudio(&audio->convert);
-#if 0
-            if ( audio->convert.len_cvt != audio->spec.size ) {
-                /* Uh oh... probably crashes here; */
-            }
-#endif
-            memcpy(buffer[fill_me], audio->convert.buf,
-                            audio->convert.len_cvt);
-        } else {
-            #if MACOSX
-                SDL_mutexP(audio->mixer_lock);
-            #endif
-            audio->spec.callback(audio->spec.userdata,
-                (Uint8 *)buffer[fill_me], audio->spec.size);
-            #if MACOSX
-                SDL_mutexV(audio->mixer_lock);
-            #endif
-        }
-    }
 
-    if ( running ) {
-         
+   /*
+    * if audio device isn't locked, mix the next buffer to be queued in
+    *  the memory block that just finished playing.
+    */
+   if ( ! BitAndAtomic(0xFFFFFFFF, &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) {
@@ -170,7 +204,7 @@
    int sample_bits;
    int i;
    long initOptions;
-   
+      
    /* Very few conversions are required, but... */
     switch (spec->format) {
         case AUDIO_S8:
@@ -231,8 +265,7 @@
     }
     channel->userInfo = (long)this;
     channel->qLength = 128;
-    if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) !=
-noErr ) {
+    if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr ) {
         SDL_SetError("Unable to create audio channel");
         free(channel);
         channel = NULL;
@@ -270,7 +303,18 @@
     }
 }
 
-#else /* !TARGET_API_MAC_CARBON */
+#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
@@ -336,14 +380,6 @@
     int i;
 
     if ( channel != NULL ) {
-#if 0
-        SCStatus status;
-
-        /* Wait for audio to complete */
-        do {
-            SndChannelStatus(channel, sizeof(status), &status);
-        } while ( status.scChannelBusy );
-#endif
         /* Clean up the audio channel */
         SndDisposeChannel(channel, true);
         channel = NULL;
@@ -446,6 +482,5 @@
     return 1;
 }
 
-#endif /* TARGET_API_MAC_CARBON */
+#endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */
 
-
--- a/src/audio/macrom/SDL_romaudio.h	Sat Mar 30 19:48:56 2002 +0000
+++ b/src/audio/macrom/SDL_romaudio.h	Sat Mar 30 20:03:27 2002 +0000
@@ -30,16 +30,21 @@
 
 #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 ! TARGET_API_MAC_CARBON
+#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
+#endif
 };
 
 /* Old variable names */