Mercurial > sdl-ios-xcode
diff src/audio/macrom/SDL_romaudio.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | 45b1c4303f87 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audio/macrom/SDL_romaudio.c Thu Apr 26 16:45:43 2001 +0000 @@ -0,0 +1,439 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 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$"; +#endif + +#if TARGET_API_MAC_CARBON +# include <Carbon.h> +#else +# include <Sound.h> /* SoundManager interface */ +# include <Gestalt.h> +#endif + +#include <stdlib.h> +#include <stdio.h> + +#include "SDL_endian.h" +#include "SDL_audio.h" +#include "SDL_audio_c.h" +#include "SDL_audiomem.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); + +/* Audio driver bootstrap functions */ + + +static int Audio_Available(void) +{ + return(1); +} + +static void Audio_DeleteDevice(SDL_AudioDevice *device) +{ + free(device->hidden); + free(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 ) { + memset(this, 0, (sizeof *this)); + this->hidden = (struct SDL_PrivateAudioData *) + malloc((sizeof *this->hidden)); + } + if ( (this == NULL) || (this->hidden == NULL) ) { + SDL_OutOfMemory(); + if ( this ) { + free(this); + } + return(0); + } + memset(this->hidden, 0, (sizeof *this->hidden)); + + /* Set the function pointers */ + this->OpenAudio = Mac_OpenAudio; + this->CloseAudio = Mac_CloseAudio; + this->free = Audio_DeleteDevice; + + return this; +} + +AudioBootStrap SNDMGR_bootstrap = { + "sndmgr", "MacOS SoundManager 3.0", + Audio_Available, Audio_CreateDevice +}; + +#if TARGET_API_MAC_CARBON + +static UInt8 *buffer[2]; +static volatile UInt32 running = 0; +static CmpSoundHeader header; + +static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) { + + UInt32 fill_me, play_me; + SndCommand cmd; + SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo; + + 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; + } + + 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->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[fill_me], audio->convert.buf, + audio->convert.len_cvt); + } else { + audio->spec.callback(audio->spec.userdata, + (Uint8 *)buffer[fill_me], audio->spec.size); + } + } + + 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 = 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)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"); + 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] ) { + free(buffer[i]); + buffer[i] = NULL; + } + } +} + +#else /* !TARGET_API_MAC_CARBON */ + +/* 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 + 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 ) { +#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; + } + for ( i=0; i<2; ++i ) { + if ( audio_buf[i] ) { + 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 */ + 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] = 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)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"); + 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 */ + +