src/audio/macrom/SDL_romaudio.c
author Holmes Futrell <hfutrell@umail.ucsb.edu>
Mon, 18 Aug 2008 19:39:08 +0000
branchgsoc2008_iphone
changeset 2467 058e1f140ff3
parent 2060 866052b01ee5
child 2738 79c1bd651f04
permissions -rw-r--r--
Fixed problem where creating the view passed NULL as the context for setting current context ... needed to actually pass the context.
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@1895
    92
static void
icculus@2049
    93
SNDMGR_LockDevice(_THIS)
slouken@323
    94
{
slouken@1895
    95
    IncrementAtomic((SInt32 *) & audio_is_locked);
slouken@323
    96
}
slouken@323
    97
slouken@1895
    98
static void
icculus@2049
    99
SNDMGR_UnlockDevice(_THIS)
slouken@323
   100
{
slouken@323
   101
    SInt32 oldval;
slouken@1895
   102
slouken@1895
   103
    oldval = DecrementAtomic((SInt32 *) & audio_is_locked);
slouken@1895
   104
    if (oldval != 1)            /* != 1 means audio is still locked. */
slouken@323
   105
        return;
slouken@323
   106
slouken@323
   107
    /* Did we miss the chance to mix in an interrupt? Do it now. */
slouken@1895
   108
    if (BitAndAtomic(0xFFFFFFFF, (UInt32 *) & need_to_mix)) {
slouken@323
   109
        /*
slouken@323
   110
         * Note that this could be a problem if you missed an interrupt
slouken@323
   111
         *  while the audio was locked, and get preempted by a second
slouken@323
   112
         *  interrupt here, but that means you locked for way too long anyhow.
slouken@323
   113
         */
slouken@1895
   114
        mix_buffer(this, buffer[fill_me]);
slouken@323
   115
    }
slouken@323
   116
}
slouken@0
   117
slouken@1895
   118
static void
slouken@1895
   119
callBackProc(SndChannel * chan, SndCommand * cmd_passed)
slouken@1895
   120
{
slouken@1895
   121
    UInt32 play_me;
slouken@1895
   122
    SndCommand cmd;
slouken@1895
   123
    SDL_AudioDevice *audio = (SDL_AudioDevice *) chan->userInfo;
slouken@323
   124
slouken@1895
   125
    IncrementAtomic((SInt32 *) & need_to_mix);
slouken@323
   126
slouken@1895
   127
    fill_me = cmd_passed->param2;       /* buffer that has just finished playing, so fill it */
slouken@1895
   128
    play_me = !fill_me;         /* filled buffer to play _now_ */
slouken@0
   129
slouken@1895
   130
    if (!audio->enabled) {
slouken@1895
   131
        return;
slouken@1895
   132
    }
slouken@47
   133
slouken@1895
   134
    /* queue previously mixed buffer for playback. */
slouken@1895
   135
    header.samplePtr = (Ptr) buffer[play_me];
slouken@1895
   136
    cmd.cmd = bufferCmd;
slouken@1895
   137
    cmd.param1 = 0;
slouken@1895
   138
    cmd.param2 = (long) &header;
slouken@1895
   139
    SndDoCommand(chan, &cmd, 0);
slouken@47
   140
icculus@2049
   141
    SDL_memset(buffer[fill_me], 0, audio->spec.size);
slouken@323
   142
slouken@1895
   143
    /*
slouken@1895
   144
     * if audio device isn't locked, mix the next buffer to be queued in
slouken@1895
   145
     *  the memory block that just finished playing.
slouken@1895
   146
     */
slouken@1895
   147
    if (!BitAndAtomic(0xFFFFFFFF, (UInt32 *) & audio_is_locked)) {
slouken@1895
   148
        mix_buffer(audio, buffer[fill_me]);
slouken@1895
   149
    }
slouken@1895
   150
slouken@1895
   151
    /* set this callback to run again when current buffer drains. */
slouken@1895
   152
    if (running) {
slouken@1895
   153
        cmd.cmd = callBackCmd;
slouken@1895
   154
        cmd.param1 = 0;
slouken@1895
   155
        cmd.param2 = play_me;
slouken@1895
   156
slouken@1895
   157
        SndDoCommand(chan, &cmd, 0);
slouken@1895
   158
    }
slouken@0
   159
}
slouken@0
   160
icculus@2054
   161
static void
icculus@2054
   162
SNDMGR_CloseDevice(_THIS)
icculus@2054
   163
{
icculus@2054
   164
    running = 0;
icculus@2054
   165
icculus@2054
   166
    if (this->hidden != NULL) {
icculus@2054
   167
        if (this->hidden->channel) {
icculus@2054
   168
            SndDisposeChannel(this->hidden->channel, true);
icculus@2054
   169
            this->hidden->channel = NULL;
icculus@2054
   170
        }
icculus@2054
   171
icculus@2054
   172
        SDL_free(buffer[0]);
icculus@2054
   173
        SDL_free(buffer[1]);
icculus@2054
   174
        buffer[0] = buffer[1] = NULL;
icculus@2054
   175
icculus@2054
   176
        SDL_free(this->hidden);
icculus@2054
   177
        this->hidden = NULL;
icculus@2054
   178
    }
icculus@2054
   179
}
icculus@2054
   180
slouken@1895
   181
static int
icculus@2049
   182
SNDMGR_OpenDevice(_THIS, const char *devname, int iscapture)
slouken@1895
   183
{
icculus@2049
   184
    SDL_AudioSpec *spec = &this->spec;
icculus@2049
   185
    SndChannelPtr channel = NULL;
slouken@1895
   186
    SndCallBackUPP callback;
slouken@1895
   187
    int sample_bits;
slouken@1895
   188
    int i;
slouken@1895
   189
    long initOptions;
slouken@1895
   190
icculus@2049
   191
    /* Initialize all variables that we clean on shutdown */
icculus@2049
   192
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   193
        SDL_malloc((sizeof *this->hidden));
icculus@2049
   194
    if (this->hidden == NULL) {
icculus@2049
   195
        SDL_OutOfMemory();
icculus@2049
   196
        return 0;
icculus@2049
   197
    }
icculus@2049
   198
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
icculus@2049
   199
icculus@2049
   200
    /* !!! FIXME: iterate through format matrix... */
slouken@1895
   201
    /* Very few conversions are required, but... */
slouken@0
   202
    switch (spec->format) {
slouken@1895
   203
    case AUDIO_S8:
slouken@0
   204
        spec->format = AUDIO_U8;
slouken@0
   205
        break;
slouken@1895
   206
    case AUDIO_U16LSB:
slouken@0
   207
        spec->format = AUDIO_S16LSB;
slouken@0
   208
        break;
slouken@1895
   209
    case AUDIO_U16MSB:
slouken@0
   210
        spec->format = AUDIO_S16MSB;
slouken@0
   211
        break;
icculus@2004
   212
    case AUDIO_F32LSB:
icculus@2004
   213
        spec->format = AUDIO_F32MSB;
icculus@2004
   214
        break;
slouken@0
   215
    }
icculus@2049
   216
    SDL_CalculateAudioSpec(&this->spec);
slouken@1895
   217
slouken@0
   218
    /* initialize bufferCmd header */
icculus@2049
   219
    SDL_memset(&header, 0, sizeof(header));
slouken@1895
   220
    callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
slouken@0
   221
    sample_bits = spec->size / spec->samples / spec->channels * 8;
slouken@0
   222
slouken@0
   223
#ifdef DEBUG_AUDIO
slouken@0
   224
    fprintf(stderr,
slouken@1895
   225
            "Audio format 0x%x, channels = %d, sample_bits = %d, frequency = %d\n",
slouken@1895
   226
            spec->format, spec->channels, sample_bits, spec->freq);
slouken@0
   227
#endif /* DEBUG_AUDIO */
slouken@1895
   228
slouken@0
   229
    header.numChannels = spec->channels;
slouken@1895
   230
    header.sampleSize = sample_bits;
slouken@1895
   231
    header.sampleRate = spec->freq << 16;
slouken@1895
   232
    header.numFrames = spec->samples;
slouken@1895
   233
    header.encode = cmpSH;
slouken@1895
   234
slouken@0
   235
    /* Note that we install the 16bitLittleEndian Converter if needed. */
icculus@2004
   236
    if (spec->format == AUDIO_S16LSB) {
slouken@0
   237
        header.compressionID = fixedCompression;
slouken@0
   238
        header.format = k16BitLittleEndianFormat;
icculus@2004
   239
    } else if (spec->format == AUDIO_S32MSB) {
icculus@2004
   240
        header.compressionID = fixedCompression;
icculus@2004
   241
        header.format = k32BitFormat;
icculus@2004
   242
    } else if (spec->format == AUDIO_S32LSB) {
icculus@2004
   243
        header.compressionID = fixedCompression;
icculus@2004
   244
        header.format = k32BitLittleEndianFormat;
icculus@2004
   245
    } else if (spec->format == AUDIO_F32MSB) {
icculus@2004
   246
        header.compressionID = fixedCompression;
icculus@2004
   247
        header.format = kFloat32Format;
slouken@0
   248
    }
slouken@1895
   249
slouken@0
   250
    /* allocate 2 buffers */
slouken@1895
   251
    for (i = 0; i < 2; i++) {
icculus@2049
   252
        buffer[i] = (UInt8 *) SDL_malloc(sizeof(UInt8) * spec->size);
slouken@1895
   253
        if (buffer[i] == NULL) {
icculus@2049
   254
            SNDMGR_CloseDevice(this);
slouken@1895
   255
            SDL_OutOfMemory();
icculus@2049
   256
            return 0;
slouken@1895
   257
        }
icculus@2049
   258
        SDL_memset(buffer[i], 0, spec->size);
slouken@1895
   259
    }
slouken@1895
   260
slouken@1895
   261
    /* Create the sound manager channel */
slouken@1895
   262
    channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
slouken@1895
   263
    if (channel == NULL) {
icculus@2049
   264
        SNDMGR_CloseDevice(this);
slouken@0
   265
        SDL_OutOfMemory();
icculus@2049
   266
        return 0;
slouken@0
   267
    }
icculus@2049
   268
    this->hidden->channel = channel;
slouken@1895
   269
    if (spec->channels >= 2) {
slouken@0
   270
        initOptions = initStereo;
slouken@0
   271
    } else {
slouken@0
   272
        initOptions = initMono;
slouken@0
   273
    }
slouken@1895
   274
    channel->userInfo = (long) this;
slouken@0
   275
    channel->qLength = 128;
slouken@1895
   276
    if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
icculus@2049
   277
        SNDMGR_CloseDevice(this);
slouken@0
   278
        SDL_SetError("Unable to create audio channel");
icculus@2049
   279
        return 0;
slouken@0
   280
    }
slouken@1895
   281
slouken@1895
   282
    /* start playback */
slouken@1895
   283
    {
slouken@1895
   284
        SndCommand cmd;
slouken@1895
   285
        cmd.cmd = callBackCmd;
slouken@1895
   286
        cmd.param2 = 0;
slouken@1895
   287
        running = 1;
slouken@1895
   288
        SndDoCommand(channel, &cmd, 0);
slouken@1895
   289
    }
slouken@1895
   290
slouken@1895
   291
    return 1;
slouken@0
   292
}
slouken@0
   293
slouken@1895
   294
static int
slouken@2060
   295
SNDMGR_Init(SDL_AudioDriverImpl * impl)
slouken@0
   296
{
icculus@2049
   297
    /* Set the function pointers */
icculus@2049
   298
    impl->OpenDevice = SNDMGR_OpenDevice;
icculus@2049
   299
    impl->CloseDevice = SNDMGR_CloseDevice;
icculus@2049
   300
    impl->ProvidesOwnCallbackThread = 1;
icculus@2049
   301
    impl->OnlyHasDefaultOutputDevice = 1;
slouken@0
   302
icculus@2049
   303
/* Mac OS X uses threaded audio, so normal thread code is okay */
icculus@2049
   304
#ifndef __MACOSX__
icculus@2049
   305
    impl->LockDevice = SNDMGR_LockDevice;
icculus@2049
   306
    impl->UnlockDevice = SNDMGR_UnlockDevice;
icculus@2049
   307
    impl->SkipMixerLock = 1;
icculus@2049
   308
#endif
slouken@1895
   309
slouken@0
   310
    return 1;
slouken@0
   311
}
slouken@0
   312
icculus@2049
   313
AudioBootStrap SNDMGR_bootstrap = {
icculus@2049
   314
    "sndmgr", SDL_MACOS_NAME " SoundManager", SNDMGR_Init, 0
icculus@2049
   315
};
icculus@2049
   316
slouken@1895
   317
/* vi: set ts=4 sw=4 expandtab: */