src/audio/macrom/SDL_romaudio.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. Audio_Available
  2. Audio_DeleteDevice
  3. Audio_CreateDevice
  4. callBackProc
  5. Mac_OpenAudio
  6. Mac_CloseAudio
  7. sndDoubleBackProc
  8. DoubleBufferAudio_Available
  9. Mac_CloseAudio
  10. Mac_OpenAudio

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_romaudio.c,v 1.1.2.5 2001/02/10 19:28:06 hercules Exp $";
  26 #endif
  27 
  28 #if TARGET_API_MAC_CARBON
  29 #  include <Carbon.h>
  30 #else
  31 #  include <Sound.h> /* SoundManager interface */
  32 #  include <Gestalt.h>
  33 #endif
  34 
  35 #include <stdlib.h>
  36 #include <stdio.h>
  37 
  38 #include "SDL_endian.h"
  39 #include "SDL_audio.h"
  40 #include "SDL_audio_c.h"
  41 #include "SDL_audiomem.h"
  42 #include "SDL_sysaudio.h"
  43 #include "SDL_romaudio.h"
  44 
  45 /* Audio driver functions */
  46 
  47 static void Mac_CloseAudio(_THIS);
  48 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec);
  49 
  50 /* Audio driver bootstrap functions */
  51 
  52 
  53 static int Audio_Available(void)
     /* [<][>][^][v][top][bottom][index][help] */
  54 {
  55     return(1);
  56 }
  57 
  58 static void Audio_DeleteDevice(SDL_AudioDevice *device)
     /* [<][>][^][v][top][bottom][index][help] */
  59 {
  60     free(device->hidden);
  61     free(device);
  62 }
  63 
  64 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66     SDL_AudioDevice *this;
  67 
  68     /* Initialize all variables that we clean on shutdown */
  69     this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  70     if ( this ) {
  71         memset(this, 0, (sizeof *this));
  72         this->hidden = (struct SDL_PrivateAudioData *)
  73                 malloc((sizeof *this->hidden));
  74     }
  75     if ( (this == NULL) || (this->hidden == NULL) ) {
  76         SDL_OutOfMemory();
  77         if ( this ) {
  78             free(this);
  79         }
  80         return(0);
  81     }
  82     memset(this->hidden, 0, (sizeof *this->hidden));
  83 
  84     /* Set the function pointers */
  85     this->OpenAudio   = Mac_OpenAudio;
  86     this->CloseAudio  = Mac_CloseAudio;
  87     this->free        = Audio_DeleteDevice;
  88 
  89     return this;
  90 }
  91 
  92 AudioBootStrap SNDMGR_bootstrap = {
  93         "sndmgr", "MacOS SoundManager 3.0",
  94         Audio_Available, Audio_CreateDevice
  95 };
  96 
  97 #if TARGET_API_MAC_CARBON
  98 
  99 static UInt8  *buffer[2];
 100 static volatile UInt32 running = 0;
 101 static CmpSoundHeader header;
 102 
 103 static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) {
     /* [<][>][^][v][top][bottom][index][help] */
 104    
 105    UInt32 fill_me, play_me;
 106    SndCommand cmd; 
 107    SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo;
 108  
 109    fill_me = cmd_passed->param2;  /* buffer that has just finished playing,
 110 so fill it */      
 111    play_me = ! fill_me;           /* filled buffer to play _now_ */
 112 
 113    if ( ! audio->enabled ) {
 114       return;
 115    }
 116    
 117    header.samplePtr = (Ptr)buffer[play_me];
 118    
 119    cmd.cmd = bufferCmd;
 120    cmd.param1 = 0; 
 121    cmd.param2 = (long)&header;
 122    
 123     SndDoCommand (chan, &cmd, 0);
 124    
 125    memset (buffer[fill_me], 0, audio->spec.size);
 126    
 127    if ( ! audio->paused ) {
 128         if ( audio->convert.needed ) {
 129             audio->spec.callback(audio->spec.userdata,
 130                 (Uint8 *)audio->convert.buf,audio->convert.len);
 131                SDL_ConvertAudio(&audio->convert);
 132 #if 0
 133             if ( audio->convert.len_cvt != audio->spec.size ) {
 134                 /* Uh oh... probably crashes here; */
 135             }
 136 #endif
 137             memcpy(buffer[fill_me], audio->convert.buf,
 138                             audio->convert.len_cvt);
 139         } else {
 140             audio->spec.callback(audio->spec.userdata,
 141                 (Uint8 *)buffer[fill_me], audio->spec.size);
 142         }
 143     }
 144     
 145     if ( running ) {
 146          
 147       cmd.cmd = callBackCmd;
 148       cmd.param1 = 0;
 149       cmd.param2 = play_me;
 150    
 151       SndDoCommand (chan, &cmd, 0);
 152    }
 153 }
 154 
 155 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
     /* [<][>][^][v][top][bottom][index][help] */
 156 
 157    SndCallBackUPP callback;
 158    int sample_bits;
 159    int i;
 160    long initOptions;
 161    
 162    /* Very few conversions are required, but... */
 163     switch (spec->format) {
 164         case AUDIO_S8:
 165         spec->format = AUDIO_U8;
 166         break;
 167         case AUDIO_U16LSB:
 168         spec->format = AUDIO_S16LSB;
 169         break;
 170         case AUDIO_U16MSB:
 171         spec->format = AUDIO_S16MSB;
 172         break;
 173     }
 174     SDL_CalculateAudioSpec(spec);
 175     
 176     /* initialize bufferCmd header */
 177     memset (&header, 0, sizeof(header));
 178     callback = NewSndCallBackUPP (callBackProc);
 179     sample_bits = spec->size / spec->samples / spec->channels * 8;
 180 
 181 #ifdef DEBUG_AUDIO
 182     fprintf(stderr,
 183         "Audio format 0x%x, channels = %d, sample_bits = %d, frequency = %d\n",
 184         spec->format, spec->channels, sample_bits, spec->freq);
 185 #endif /* DEBUG_AUDIO */
 186     
 187     header.numChannels = spec->channels;
 188     header.sampleSize  = sample_bits;
 189     header.sampleRate  = spec->freq << 16;
 190     header.numFrames   = spec->samples;
 191     header.encode      = cmpSH;
 192     
 193     /* Note that we install the 16bitLittleEndian Converter if needed. */
 194     if ( spec->format == 0x8010 ) {
 195         header.compressionID = fixedCompression;
 196         header.format = k16BitLittleEndianFormat;
 197     }
 198     
 199     /* allocate 2 buffers */
 200     for (i=0; i<2; i++) {
 201        buffer[i] = (UInt8*)malloc (sizeof(UInt8) * spec->size);
 202       if (buffer[i] == NULL) {
 203          SDL_OutOfMemory();
 204          return (-1);
 205       }
 206      memset (buffer[i], 0, spec->size);
 207    }
 208    
 209    /* Create the sound manager channel */
 210     channel = (SndChannelPtr)malloc(sizeof(*channel));
 211     if ( channel == NULL ) {
 212         SDL_OutOfMemory();
 213         return(-1);
 214     }
 215     if ( spec->channels >= 2 ) {
 216         initOptions = initStereo;
 217     } else {
 218         initOptions = initMono;
 219     }
 220     channel->userInfo = (long)this;
 221     channel->qLength = 128;
 222     if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) !=
 223 noErr ) {
 224         SDL_SetError("Unable to create audio channel");
 225         free(channel);
 226         channel = NULL;
 227         return(-1);
 228     }
 229    
 230    /* start playback */
 231    {
 232       SndCommand cmd;
 233       cmd.cmd = callBackCmd;
 234       cmd.param2 = 0;
 235       running = 1;
 236       SndDoCommand (channel, &cmd, 0);
 237    }
 238    
 239    return 1;
 240 }
 241 
 242 static void Mac_CloseAudio(_THIS) {
     /* [<][>][^][v][top][bottom][index][help] */
 243    
 244    int i;
 245    
 246    running = 0;
 247    
 248    if (channel) {
 249       SndDisposeChannel (channel, true);
 250       channel = NULL;
 251    }
 252    
 253     for ( i=0; i<2; ++i ) {
 254         if ( buffer[i] ) {
 255             free(buffer[i]);
 256             buffer[i] = NULL;
 257         }
 258     }
 259 }
 260 
 261 #else /* !TARGET_API_MAC_CARBON */
 262 
 263 /* This function is called by Sound Manager when it has exhausted one of
 264    the buffers, so we'll zero it to silence and fill it with audio if
 265    we're not paused.
 266 */
 267 static pascal
 268 void sndDoubleBackProc (SndChannelPtr chan, SndDoubleBufferPtr newbuf)
     /* [<][>][^][v][top][bottom][index][help] */
 269 {
 270     SDL_AudioDevice *audio = (SDL_AudioDevice *)newbuf->dbUserInfo[0];
 271 
 272     /* If audio is quitting, don't do anything */
 273     if ( ! audio->enabled ) {
 274         return;
 275     }
 276     memset (newbuf->dbSoundData, 0, audio->spec.size);
 277     newbuf->dbNumFrames = audio->spec.samples;
 278     if ( ! audio->paused ) {
 279         if ( audio->convert.needed ) {
 280             audio->spec.callback(audio->spec.userdata,
 281                 (Uint8 *)audio->convert.buf,audio->convert.len);
 282             SDL_ConvertAudio(&audio->convert);
 283 #if 0
 284             if ( audio->convert.len_cvt != audio->spec.size ) {
 285                 /* Uh oh... probably crashes here */;
 286             }
 287 #endif
 288             memcpy(newbuf->dbSoundData, audio->convert.buf,
 289                             audio->convert.len_cvt);
 290         } else {
 291             audio->spec.callback(audio->spec.userdata,
 292                 (Uint8 *)newbuf->dbSoundData, audio->spec.size);
 293         }
 294     }
 295     newbuf->dbFlags    |= dbBufferReady;
 296 }
 297 
 298 static int DoubleBufferAudio_Available(void)
     /* [<][>][^][v][top][bottom][index][help] */
 299 {
 300     int available;
 301     NumVersion sndversion;
 302     long response;
 303 
 304     available = 0;
 305     sndversion = SndSoundManagerVersion();
 306     if ( sndversion.majorRev >= 3 ) {
 307         if ( Gestalt(gestaltSoundAttr, &response) == noErr ) {
 308             if ( (response & (1 << gestaltSndPlayDoubleBuffer)) ) {
 309                 available = 1;
 310             }
 311         }
 312     } else {
 313         if ( Gestalt(gestaltSoundAttr, &response) == noErr ) {
 314             if ( (response & (1 << gestaltHasASC)) ) {
 315                 available = 1;
 316             }
 317         }
 318     }
 319     return(available);
 320 }
 321 
 322 static void Mac_CloseAudio(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 323 {
 324     int i;
 325 
 326     if ( channel != NULL ) {
 327 #if 0
 328         SCStatus status;
 329 
 330         /* Wait for audio to complete */
 331         do {
 332             SndChannelStatus(channel, sizeof(status), &status);
 333         } while ( status.scChannelBusy );
 334 #endif
 335         /* Clean up the audio channel */
 336         SndDisposeChannel(channel, true);
 337         channel = NULL;
 338     }
 339     for ( i=0; i<2; ++i ) {
 340         if ( audio_buf[i] ) {
 341             free(audio_buf[i]);
 342             audio_buf[i] = NULL;
 343         }
 344     }
 345 }
 346 
 347 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec)
     /* [<][>][^][v][top][bottom][index][help] */
 348 {
 349     SndDoubleBufferHeader2 audio_dbh;
 350     int i;
 351     long initOptions;
 352     int sample_bits;
 353     SndDoubleBackUPP doubleBackProc;
 354 
 355     /* Check to make sure double-buffered audio is available */
 356     if ( ! DoubleBufferAudio_Available() ) {
 357         SDL_SetError("Sound manager doesn't support double-buffering");
 358         return(-1);
 359     }
 360 
 361     /* Very few conversions are required, but... */
 362     switch (spec->format) {
 363         case AUDIO_S8:
 364         spec->format = AUDIO_U8;
 365         break;
 366         case AUDIO_U16LSB:
 367         spec->format = AUDIO_S16LSB;
 368         break;
 369         case AUDIO_U16MSB:
 370         spec->format = AUDIO_S16MSB;
 371         break;
 372     }
 373     SDL_CalculateAudioSpec(spec);
 374 
 375     /* initialize the double-back header */
 376     memset(&audio_dbh, 0, sizeof(audio_dbh));
 377     doubleBackProc = NewSndDoubleBackProc (sndDoubleBackProc);
 378     sample_bits = spec->size / spec->samples / spec->channels * 8;
 379     
 380     audio_dbh.dbhNumChannels = spec->channels;
 381     audio_dbh.dbhSampleSize    = sample_bits;
 382     audio_dbh.dbhCompressionID = 0;
 383     audio_dbh.dbhPacketSize    = 0;
 384     audio_dbh.dbhSampleRate    = spec->freq << 16;
 385     audio_dbh.dbhDoubleBack    = doubleBackProc;
 386     audio_dbh.dbhFormat    = 0;
 387 
 388     /* Note that we install the 16bitLittleEndian Converter if needed. */
 389     if ( spec->format == 0x8010 ) {
 390         audio_dbh.dbhCompressionID = fixedCompression;
 391         audio_dbh.dbhFormat = k16BitLittleEndianFormat;
 392     }
 393 
 394     /* allocate the 2 double-back buffers */
 395     for ( i=0; i<2; ++i ) {
 396         audio_buf[i] = calloc(1, sizeof(SndDoubleBuffer)+spec->size);
 397         if ( audio_buf[i] == NULL ) {
 398             SDL_OutOfMemory();
 399             return(-1);
 400         }
 401         audio_buf[i]->dbNumFrames = spec->samples;
 402         audio_buf[i]->dbFlags = dbBufferReady;
 403         audio_buf[i]->dbUserInfo[0] = (long)this;
 404         audio_dbh.dbhBufferPtr[i] = audio_buf[i];
 405     }
 406 
 407     /* Create the sound manager channel */
 408     channel = (SndChannelPtr)malloc(sizeof(*channel));
 409     if ( channel == NULL ) {
 410         SDL_OutOfMemory();
 411         return(-1);
 412     }
 413     if ( spec->channels >= 2 ) {
 414         initOptions = initStereo;
 415     } else {
 416         initOptions = initMono;
 417     }
 418     channel->userInfo = 0;
 419     channel->qLength = 128;
 420     if ( SndNewChannel(&channel, sampledSynth, initOptions, 0L) != noErr ) {
 421         SDL_SetError("Unable to create audio channel");
 422         free(channel);
 423         channel = NULL;
 424         return(-1);
 425     }
 426  
 427     /* Start playback */
 428     if ( SndPlayDoubleBuffer(channel, (SndDoubleBufferHeaderPtr)&audio_dbh)
 429                                 != noErr ) {
 430         SDL_SetError("Unable to play double buffered audio");
 431         return(-1);
 432     }
 433     
 434     return 1;
 435 }
 436 
 437 #endif /* TARGET_API_MAC_CARBON */
 438 
 439 

/* [<][>][^][v][top][bottom][index][help] */