src/audio/macrom/SDL_romaudio.c
author Sam Lantinga
Mon, 01 Sep 2008 16:04:20 +0000
changeset 2738 79c1bd651f04
parent 2060 866052b01ee5
child 2859 99210400e8b9
permissions -rw-r--r--
Fixed a bunch of compile warnings on Mac OS X
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
icculus@2049
    24
/* This should work on PowerPC and Intel Mac OS X, and Carbonized Mac OS 9. */
icculus@2049
    25
icculus@1133
    26
#if defined(__APPLE__) && defined(__MACH__)
icculus@2049
    27
#  define SDL_MACOS_NAME "Mac OS X"
icculus@1133
    28
#  include <Carbon/Carbon.h>
icculus@1133
    29
#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
icculus@2049
    30
#  define SDL_MACOS_NAME "Mac OS 9"
slouken@0
    31
#  include <Carbon.h>
slouken@0
    32
#else
icculus@2049
    33
#  define SDL_MACOS_NAME "Mac OS 9"
slouken@1895
    34
#  include <Sound.h>            /* SoundManager interface */
slouken@0
    35
#  include <Gestalt.h>
slouken@323
    36
#  include <DriverServices.h>
slouken@0
    37
#endif
slouken@0
    38
icculus@1133
    39
#if !defined(NewSndCallBackUPP) && (UNIVERSAL_INTERFACES_VERSION < 0x0335)
slouken@1895
    40
#if !defined(NewSndCallBackProc)        /* avoid circular redefinition... */
icculus@1133
    41
#define NewSndCallBackUPP NewSndCallBackProc
icculus@1133
    42
#endif
icculus@1135
    43
#if !defined(NewSndCallBackUPP)
icculus@1135
    44
#define NewSndCallBackUPP NewSndCallBackProc
icculus@1135
    45
#endif
icculus@1133
    46
#endif
icculus@1133
    47
slouken@0
    48
#include "SDL_audio.h"
slouken@1361
    49
#include "../SDL_audio_c.h"
slouken@1361
    50
#include "../SDL_sysaudio.h"
slouken@0
    51
#include "SDL_romaudio.h"
slouken@0
    52
slouken@323
    53
#pragma options align=power
slouken@323
    54
slouken@323
    55
static volatile SInt32 audio_is_locked = 0;
slouken@323
    56
static volatile SInt32 need_to_mix = 0;
slouken@0
    57
slouken@1895
    58
static UInt8 *buffer[2];
slouken@0
    59
static volatile UInt32 running = 0;
slouken@0
    60
static CmpSoundHeader header;
slouken@323
    61
static volatile Uint32 fill_me = 0;
slouken@323
    62
icculus@2049
    63
slouken@1895
    64
static void
slouken@1895
    65
mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
slouken@323
    66
{
slouken@1895
    67
    if (!audio->paused) {
slouken@1402
    68
#ifdef __MACOSX__
slouken@348
    69
        SDL_mutexP(audio->mixer_lock);
slouken@348
    70
#endif
slouken@1895
    71
        if (audio->convert.needed) {
slouken@348
    72
            audio->spec.callback(audio->spec.userdata,
slouken@1895
    73
                                 (Uint8 *) audio->convert.buf,
slouken@1895
    74
                                 audio->convert.len);
slouken@348
    75
            SDL_ConvertAudio(&audio->convert);
slouken@1895
    76
            if (audio->convert.len_cvt != audio->spec.size) {
slouken@1895
    77
                /* Uh oh... probably crashes here */ ;
slouken@323
    78
            }
slouken@1336
    79
            SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
slouken@323
    80
        } else {
slouken@1895
    81
            audio->spec.callback(audio->spec.userdata, buffer,
slouken@1895
    82
                                 audio->spec.size);
slouken@323
    83
        }
slouken@1402
    84
#ifdef __MACOSX__
slouken@348
    85
        SDL_mutexV(audio->mixer_lock);
slouken@348
    86
#endif
slouken@323
    87
    }
slouken@323
    88
slouken@1895
    89
    DecrementAtomic((SInt32 *) & need_to_mix);
slouken@323
    90
}
slouken@323
    91
slouken@2738
    92
#ifndef __MACOSX__
slouken@1895
    93
static void
icculus@2049
    94
SNDMGR_LockDevice(_THIS)
slouken@323
    95
{
slouken@1895
    96
    IncrementAtomic((SInt32 *) & audio_is_locked);
slouken@323
    97
}
slouken@323
    98
slouken@1895
    99
static void
icculus@2049
   100
SNDMGR_UnlockDevice(_THIS)
slouken@323
   101
{
slouken@323
   102
    SInt32 oldval;
slouken@1895
   103
slouken@1895
   104
    oldval = DecrementAtomic((SInt32 *) & audio_is_locked);
slouken@1895
   105
    if (oldval != 1)            /* != 1 means audio is still locked. */
slouken@323
   106
        return;
slouken@323
   107
slouken@323
   108
    /* Did we miss the chance to mix in an interrupt? Do it now. */
slouken@1895
   109
    if (BitAndAtomic(0xFFFFFFFF, (UInt32 *) & need_to_mix)) {
slouken@323
   110
        /*
slouken@323
   111
         * Note that this could be a problem if you missed an interrupt
slouken@323
   112
         *  while the audio was locked, and get preempted by a second
slouken@323
   113
         *  interrupt here, but that means you locked for way too long anyhow.
slouken@323
   114
         */
slouken@1895
   115
        mix_buffer(this, buffer[fill_me]);
slouken@323
   116
    }
slouken@323
   117
}
slouken@2738
   118
#endif // __MACOSX__
slouken@0
   119
slouken@1895
   120
static void
slouken@1895
   121
callBackProc(SndChannel * chan, SndCommand * cmd_passed)
slouken@1895
   122
{
slouken@1895
   123
    UInt32 play_me;
slouken@1895
   124
    SndCommand cmd;
slouken@1895
   125
    SDL_AudioDevice *audio = (SDL_AudioDevice *) chan->userInfo;
slouken@323
   126
slouken@1895
   127
    IncrementAtomic((SInt32 *) & need_to_mix);
slouken@323
   128
slouken@1895
   129
    fill_me = cmd_passed->param2;       /* buffer that has just finished playing, so fill it */
slouken@1895
   130
    play_me = !fill_me;         /* filled buffer to play _now_ */
slouken@1895
   131
slouken@1895
   132
    if (!audio->enabled) {
slouken@1895
   133
        return;
slouken@1895
   134
    }
slouken@0
   135
slouken@1895
   136
    /* queue previously mixed buffer for playback. */
slouken@1895
   137
    header.samplePtr = (Ptr) buffer[play_me];
slouken@1895
   138
    cmd.cmd = bufferCmd;
slouken@1895
   139
    cmd.param1 = 0;
slouken@1895
   140
    cmd.param2 = (long) &header;
slouken@1895
   141
    SndDoCommand(chan, &cmd, 0);
slouken@47
   142
icculus@2049
   143
    SDL_memset(buffer[fill_me], 0, audio->spec.size);
slouken@47
   144
slouken@1895
   145
    /*
slouken@1895
   146
     * if audio device isn't locked, mix the next buffer to be queued in
slouken@1895
   147
     *  the memory block that just finished playing.
slouken@1895
   148
     */
slouken@1895
   149
    if (!BitAndAtomic(0xFFFFFFFF, (UInt32 *) & audio_is_locked)) {
slouken@1895
   150
        mix_buffer(audio, buffer[fill_me]);
slouken@1895
   151
    }
slouken@323
   152
slouken@1895
   153
    /* set this callback to run again when current buffer drains. */
slouken@1895
   154
    if (running) {
slouken@1895
   155
        cmd.cmd = callBackCmd;
slouken@1895
   156
        cmd.param1 = 0;
slouken@1895
   157
        cmd.param2 = play_me;
slouken@1895
   158
slouken@1895
   159
        SndDoCommand(chan, &cmd, 0);
slouken@1895
   160
    }
slouken@0
   161
}
slouken@0
   162
icculus@2054
   163
static void
icculus@2054
   164
SNDMGR_CloseDevice(_THIS)
icculus@2054
   165
{
icculus@2054
   166
    running = 0;
icculus@2054
   167
icculus@2054
   168
    if (this->hidden != NULL) {
icculus@2054
   169
        if (this->hidden->channel) {
icculus@2054
   170
            SndDisposeChannel(this->hidden->channel, true);
icculus@2054
   171
            this->hidden->channel = NULL;
icculus@2054
   172
        }
icculus@2054
   173
icculus@2054
   174
        SDL_free(buffer[0]);
icculus@2054
   175
        SDL_free(buffer[1]);
icculus@2054
   176
        buffer[0] = buffer[1] = NULL;
icculus@2054
   177
icculus@2054
   178
        SDL_free(this->hidden);
icculus@2054
   179
        this->hidden = NULL;
icculus@2054
   180
    }
icculus@2054
   181
}
icculus@2054
   182
slouken@1895
   183
static int
icculus@2049
   184
SNDMGR_OpenDevice(_THIS, const char *devname, int iscapture)
slouken@1895
   185
{
icculus@2049
   186
    SDL_AudioSpec *spec = &this->spec;
icculus@2049
   187
    SndChannelPtr channel = NULL;
slouken@1895
   188
    SndCallBackUPP callback;
slouken@1895
   189
    int sample_bits;
slouken@1895
   190
    int i;
slouken@1895
   191
    long initOptions;
slouken@1895
   192
icculus@2049
   193
    /* Initialize all variables that we clean on shutdown */
icculus@2049
   194
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   195
        SDL_malloc((sizeof *this->hidden));
icculus@2049
   196
    if (this->hidden == NULL) {
icculus@2049
   197
        SDL_OutOfMemory();
icculus@2049
   198
        return 0;
icculus@2049
   199
    }
icculus@2049
   200
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
icculus@2049
   201
icculus@2049
   202
    /* !!! FIXME: iterate through format matrix... */
slouken@1895
   203
    /* Very few conversions are required, but... */
slouken@0
   204
    switch (spec->format) {
slouken@1895
   205
    case AUDIO_S8:
slouken@0
   206
        spec->format = AUDIO_U8;
slouken@0
   207
        break;
slouken@1895
   208
    case AUDIO_U16LSB:
slouken@0
   209
        spec->format = AUDIO_S16LSB;
slouken@0
   210
        break;
slouken@1895
   211
    case AUDIO_U16MSB:
slouken@0
   212
        spec->format = AUDIO_S16MSB;
slouken@0
   213
        break;
icculus@2004
   214
    case AUDIO_F32LSB:
icculus@2004
   215
        spec->format = AUDIO_F32MSB;
icculus@2004
   216
        break;
slouken@0
   217
    }
icculus@2049
   218
    SDL_CalculateAudioSpec(&this->spec);
slouken@1895
   219
slouken@0
   220
    /* initialize bufferCmd header */
icculus@2049
   221
    SDL_memset(&header, 0, sizeof(header));
slouken@1895
   222
    callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
slouken@0
   223
    sample_bits = spec->size / spec->samples / spec->channels * 8;
slouken@0
   224
slouken@0
   225
#ifdef DEBUG_AUDIO
slouken@0
   226
    fprintf(stderr,
slouken@1895
   227
            "Audio format 0x%x, channels = %d, sample_bits = %d, frequency = %d\n",
slouken@1895
   228
            spec->format, spec->channels, sample_bits, spec->freq);
slouken@0
   229
#endif /* DEBUG_AUDIO */
slouken@1895
   230
slouken@0
   231
    header.numChannels = spec->channels;
slouken@1895
   232
    header.sampleSize = sample_bits;
slouken@1895
   233
    header.sampleRate = spec->freq << 16;
slouken@1895
   234
    header.numFrames = spec->samples;
slouken@1895
   235
    header.encode = cmpSH;
slouken@1895
   236
slouken@0
   237
    /* Note that we install the 16bitLittleEndian Converter if needed. */
icculus@2004
   238
    if (spec->format == AUDIO_S16LSB) {
slouken@0
   239
        header.compressionID = fixedCompression;
slouken@0
   240
        header.format = k16BitLittleEndianFormat;
icculus@2004
   241
    } else if (spec->format == AUDIO_S32MSB) {
icculus@2004
   242
        header.compressionID = fixedCompression;
icculus@2004
   243
        header.format = k32BitFormat;
icculus@2004
   244
    } else if (spec->format == AUDIO_S32LSB) {
icculus@2004
   245
        header.compressionID = fixedCompression;
icculus@2004
   246
        header.format = k32BitLittleEndianFormat;
icculus@2004
   247
    } else if (spec->format == AUDIO_F32MSB) {
icculus@2004
   248
        header.compressionID = fixedCompression;
icculus@2004
   249
        header.format = kFloat32Format;
slouken@0
   250
    }
slouken@1895
   251
slouken@0
   252
    /* allocate 2 buffers */
slouken@1895
   253
    for (i = 0; i < 2; i++) {
icculus@2049
   254
        buffer[i] = (UInt8 *) SDL_malloc(sizeof(UInt8) * spec->size);
slouken@1895
   255
        if (buffer[i] == NULL) {
icculus@2049
   256
            SNDMGR_CloseDevice(this);
slouken@1895
   257
            SDL_OutOfMemory();
icculus@2049
   258
            return 0;
slouken@1895
   259
        }
icculus@2049
   260
        SDL_memset(buffer[i], 0, spec->size);
slouken@1895
   261
    }
slouken@1895
   262
slouken@1895
   263
    /* Create the sound manager channel */
slouken@1895
   264
    channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
slouken@1895
   265
    if (channel == NULL) {
icculus@2049
   266
        SNDMGR_CloseDevice(this);
slouken@0
   267
        SDL_OutOfMemory();
icculus@2049
   268
        return 0;
slouken@0
   269
    }
icculus@2049
   270
    this->hidden->channel = channel;
slouken@1895
   271
    if (spec->channels >= 2) {
slouken@0
   272
        initOptions = initStereo;
slouken@0
   273
    } else {
slouken@0
   274
        initOptions = initMono;
slouken@0
   275
    }
slouken@1895
   276
    channel->userInfo = (long) this;
slouken@0
   277
    channel->qLength = 128;
slouken@1895
   278
    if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
icculus@2049
   279
        SNDMGR_CloseDevice(this);
slouken@0
   280
        SDL_SetError("Unable to create audio channel");
icculus@2049
   281
        return 0;
slouken@0
   282
    }
slouken@1895
   283
slouken@1895
   284
    /* start playback */
slouken@1895
   285
    {
slouken@1895
   286
        SndCommand cmd;
slouken@1895
   287
        cmd.cmd = callBackCmd;
slouken@1895
   288
        cmd.param2 = 0;
slouken@1895
   289
        running = 1;
slouken@1895
   290
        SndDoCommand(channel, &cmd, 0);
slouken@1895
   291
    }
slouken@1895
   292
slouken@1895
   293
    return 1;
slouken@0
   294
}
slouken@0
   295
slouken@1895
   296
static int
slouken@2060
   297
SNDMGR_Init(SDL_AudioDriverImpl * impl)
slouken@0
   298
{
icculus@2049
   299
    /* Set the function pointers */
icculus@2049
   300
    impl->OpenDevice = SNDMGR_OpenDevice;
icculus@2049
   301
    impl->CloseDevice = SNDMGR_CloseDevice;
icculus@2049
   302
    impl->ProvidesOwnCallbackThread = 1;
icculus@2049
   303
    impl->OnlyHasDefaultOutputDevice = 1;
slouken@0
   304
icculus@2049
   305
/* Mac OS X uses threaded audio, so normal thread code is okay */
icculus@2049
   306
#ifndef __MACOSX__
icculus@2049
   307
    impl->LockDevice = SNDMGR_LockDevice;
icculus@2049
   308
    impl->UnlockDevice = SNDMGR_UnlockDevice;
icculus@2049
   309
    impl->SkipMixerLock = 1;
icculus@2049
   310
#endif
slouken@1895
   311
slouken@0
   312
    return 1;
slouken@0
   313
}
slouken@0
   314
icculus@2049
   315
AudioBootStrap SNDMGR_bootstrap = {
icculus@2049
   316
    "sndmgr", SDL_MACOS_NAME " SoundManager", SNDMGR_Init, 0
icculus@2049
   317
};
icculus@2049
   318
slouken@1895
   319
/* vi: set ts=4 sw=4 expandtab: */