Commit b9548234 authored by Sam Lantinga's avatar Sam Lantinga

The audio lock and unlock functions are now a part of the driver.

The MacOS audio locking has been implemented, courtesy of Ryan Gordon

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40324
parent a55059b4
...@@ -30,6 +30,7 @@ static char rcsid = ...@@ -30,6 +30,7 @@ static char rcsid =
#else #else
# include <Sound.h> /* SoundManager interface */ # include <Sound.h> /* SoundManager interface */
# include <Gestalt.h> # include <Gestalt.h>
# include <DriverServices.h>
#endif #endif
#include <stdlib.h> #include <stdlib.h>
...@@ -46,6 +47,8 @@ static char rcsid = ...@@ -46,6 +47,8 @@ static char rcsid =
static void Mac_CloseAudio(_THIS); static void Mac_CloseAudio(_THIS);
static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec); static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void Mac_LockAudio(_THIS);
static void Mac_UnlockAudio(_THIS);
/* Audio driver bootstrap functions */ /* Audio driver bootstrap functions */
...@@ -84,6 +87,8 @@ static SDL_AudioDevice *Audio_CreateDevice(int devindex) ...@@ -84,6 +87,8 @@ static SDL_AudioDevice *Audio_CreateDevice(int devindex)
/* Set the function pointers */ /* Set the function pointers */
this->OpenAudio = Mac_OpenAudio; this->OpenAudio = Mac_OpenAudio;
this->CloseAudio = Mac_CloseAudio; this->CloseAudio = Mac_CloseAudio;
this->LockAudio = Mac_LockAudio;
this->UnlockAudio = Mac_UnlockAudio;
this->free = Audio_DeleteDevice; this->free = Audio_DeleteDevice;
return this; return this;
...@@ -94,18 +99,71 @@ AudioBootStrap SNDMGR_bootstrap = { ...@@ -94,18 +99,71 @@ AudioBootStrap SNDMGR_bootstrap = {
Audio_Available, Audio_CreateDevice 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 UInt8 *buffer[2];
static volatile UInt32 running = 0; static volatile UInt32 running = 0;
static CmpSoundHeader header; 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 ) { static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) {
UInt32 play_me;
UInt32 fill_me, play_me;
SndCommand cmd; SndCommand cmd;
SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo; 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 */ fill_me = cmd_passed->param2; /* buffer that has just finished playing, so fill it */
play_me = ! fill_me; /* filled buffer to play _now_ */ play_me = ! fill_me; /* filled buffer to play _now_ */
...@@ -113,55 +171,31 @@ static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) { ...@@ -113,55 +171,31 @@ static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) {
return; return;
} }
/* queue previously mixed buffer for playback. */
header.samplePtr = (Ptr)buffer[play_me]; header.samplePtr = (Ptr)buffer[play_me];
cmd.cmd = bufferCmd; cmd.cmd = bufferCmd;
cmd.param1 = 0; cmd.param1 = 0;
cmd.param2 = (long)&header; cmd.param2 = (long)&header;
SndDoCommand (chan, &cmd, 0); SndDoCommand (chan, &cmd, 0);
memset (buffer[fill_me], 0, audio->spec.size); 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.cmd = callBackCmd;
cmd.param1 = 0; cmd.param1 = 0;
cmd.param2 = play_me; cmd.param2 = play_me;
SndDoCommand (chan, &cmd, 0); SndDoCommand (chan, &cmd, 0);
} }
} }
static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) { static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
...@@ -170,7 +204,7 @@ static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) { ...@@ -170,7 +204,7 @@ static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
int sample_bits; int sample_bits;
int i; int i;
long initOptions; long initOptions;
/* Very few conversions are required, but... */ /* Very few conversions are required, but... */
switch (spec->format) { switch (spec->format) {
case AUDIO_S8: case AUDIO_S8:
...@@ -231,8 +265,7 @@ static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) { ...@@ -231,8 +265,7 @@ static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
} }
channel->userInfo = (long)this; channel->userInfo = (long)this;
channel->qLength = 128; channel->qLength = 128;
if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr ) {
noErr ) {
SDL_SetError("Unable to create audio channel"); SDL_SetError("Unable to create audio channel");
free(channel); free(channel);
channel = NULL; channel = NULL;
...@@ -270,7 +303,18 @@ static void Mac_CloseAudio(_THIS) { ...@@ -270,7 +303,18 @@ static void Mac_CloseAudio(_THIS) {
} }
} }
#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 /* 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 the buffers, so we'll zero it to silence and fill it with audio if
...@@ -336,14 +380,6 @@ static void Mac_CloseAudio(_THIS) ...@@ -336,14 +380,6 @@ static void Mac_CloseAudio(_THIS)
int i; int i;
if ( channel != NULL ) { 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 */ /* Clean up the audio channel */
SndDisposeChannel(channel, true); SndDisposeChannel(channel, true);
channel = NULL; channel = NULL;
...@@ -446,6 +482,5 @@ static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) ...@@ -446,6 +482,5 @@ static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec)
return 1; return 1;
} }
#endif /* TARGET_API_MAC_CARBON */ #endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */
...@@ -30,16 +30,21 @@ static char rcsid = ...@@ -30,16 +30,21 @@ static char rcsid =
#include "SDL_sysaudio.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 */ /* Hidden "this" pointer for the video functions */
#define _THIS SDL_AudioDevice *this #define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData { struct SDL_PrivateAudioData {
/* Sound manager audio channel */ /* Sound manager audio channel */
SndChannelPtr 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 */ /* Double buffering variables */
SndDoubleBufferPtr audio_buf[2]; SndDoubleBufferPtr audio_buf[2];
#endif #endif
}; };
/* Old variable names */ /* Old variable names */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment