src/audio/SDL_audio.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 24 Aug 2006 12:10:46 +0000
changeset 1982 3b4ce57c6215
parent 1978 542c78b6fb12
child 1993 7a3889fc9e5d
permissions -rw-r--r--
First shot at new audio data types (int32 and float32).

Notable changes:
- Converters between types are autogenerated. Instead of making multiple
passes over the data with seperate filters for endianess, size, signedness,
etc, converting between data types is always one specialized filter. This
simplifies SDL_BuildAudioCVT(), which otherwise had a million edge cases
with the new types, and makes the actually conversions more CPU cache
friendly. Left a stub for adding specific optimized versions of these
routines (SSE/MMX/Altivec, assembler, etc)
- Autogenerated converters are built by SDL/src/audio/sdlgenaudiocvt.pl. This
does not need to be run unless tweaking the code, and thus doesn't need
integration into the build system.
- Went through all the drivers and tried to weed out all the "Uint16"
references that are better specified with the new SDL_AudioFormat typedef.
- Cleaned out a bunch of hardcoded bitwise magic numbers and replaced them
with new SDL_AUDIO_* macros.
- Added initial float32 and int32 support code. Theoretically, existing
drivers will push these through converters to get the data they want to
feed to the hardware.

Still TODO:
- Optimize and debug new converters.
- Update the CoreAudio backend to accept float32 data directly.
- Other backends, too?
- SDL_LoadWAV() needs to be updated to support int32 and float32 .wav files
(both of which exist and can be generated by 'sox' for testing purposes).
- Update the mixer to handle new datatypes.
- Optionally update SDL_sound and SDL_mixer, etc.
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
slouken@0
    24
/* Allow access to a raw mixing buffer */
slouken@0
    25
slouken@0
    26
#include "SDL.h"
slouken@0
    27
#include "SDL_audio_c.h"
slouken@0
    28
#include "SDL_audiomem.h"
slouken@0
    29
#include "SDL_sysaudio.h"
slouken@0
    30
icculus@1190
    31
#ifdef __OS2__
slouken@1487
    32
/* We'll need the DosSetPriority() API! */
icculus@1190
    33
#define INCL_DOSPROCESS
icculus@1190
    34
#include <os2.h>
icculus@1190
    35
#endif
icculus@1190
    36
slouken@0
    37
/* Available audio drivers */
slouken@0
    38
static AudioBootStrap *bootstrap[] = {
slouken@1567
    39
#if SDL_AUDIO_DRIVER_BSD
slouken@1895
    40
    &BSD_AUDIO_bootstrap,
slouken@94
    41
#endif
slouken@1361
    42
#if SDL_AUDIO_DRIVER_OSS
slouken@1895
    43
    &DSP_bootstrap,
slouken@1895
    44
    &DMA_bootstrap,
slouken@0
    45
#endif
slouken@1361
    46
#if SDL_AUDIO_DRIVER_ALSA
slouken@1895
    47
    &ALSA_bootstrap,
slouken@0
    48
#endif
slouken@1361
    49
#if SDL_AUDIO_DRIVER_QNXNTO
slouken@1895
    50
    &QNXNTOAUDIO_bootstrap,
slouken@663
    51
#endif
slouken@1361
    52
#if SDL_AUDIO_DRIVER_SUNAUDIO
slouken@1895
    53
    &SUNAUDIO_bootstrap,
slouken@148
    54
#endif
slouken@1361
    55
#if SDL_AUDIO_DRIVER_DMEDIA
slouken@1895
    56
    &DMEDIA_bootstrap,
slouken@35
    57
#endif
slouken@1361
    58
#if SDL_AUDIO_DRIVER_ARTS
slouken@1895
    59
    &ARTS_bootstrap,
slouken@0
    60
#endif
slouken@1361
    61
#if SDL_AUDIO_DRIVER_ESD
slouken@1895
    62
    &ESD_bootstrap,
slouken@0
    63
#endif
slouken@1361
    64
#if SDL_AUDIO_DRIVER_NAS
slouken@1895
    65
    &NAS_bootstrap,
slouken@0
    66
#endif
slouken@1361
    67
#if SDL_AUDIO_DRIVER_DSOUND
slouken@1895
    68
    &DSOUND_bootstrap,
slouken@0
    69
#endif
slouken@1361
    70
#if SDL_AUDIO_DRIVER_WAVEOUT
slouken@1895
    71
    &WAVEOUT_bootstrap,
slouken@0
    72
#endif
slouken@1361
    73
#if SDL_AUDIO_DRIVER_PAUD
slouken@1895
    74
    &Paud_bootstrap,
slouken@1361
    75
#endif
slouken@1361
    76
#if SDL_AUDIO_DRIVER_BAUDIO
slouken@1895
    77
    &BAUDIO_bootstrap,
slouken@0
    78
#endif
slouken@1361
    79
#if SDL_AUDIO_DRIVER_COREAUDIO
slouken@1895
    80
    &COREAUDIO_bootstrap,
slouken@935
    81
#endif
slouken@1361
    82
#if SDL_AUDIO_DRIVER_SNDMGR
slouken@1895
    83
    &SNDMGR_bootstrap,
slouken@0
    84
#endif
slouken@1361
    85
#if SDL_AUDIO_DRIVER_AHI
slouken@1895
    86
    &AHI_bootstrap,
slouken@21
    87
#endif
slouken@1361
    88
#if SDL_AUDIO_DRIVER_MINT
slouken@1895
    89
    &MINTAUDIO_GSXB_bootstrap,
slouken@1895
    90
    &MINTAUDIO_MCSN_bootstrap,
slouken@1895
    91
    &MINTAUDIO_STFA_bootstrap,
slouken@1895
    92
    &MINTAUDIO_XBIOS_bootstrap,
slouken@1895
    93
    &MINTAUDIO_DMA8_bootstrap,
slouken@398
    94
#endif
slouken@1361
    95
#if SDL_AUDIO_DRIVER_DISK
slouken@1895
    96
    &DISKAUD_bootstrap,
slouken@68
    97
#endif
icculus@1532
    98
#if SDL_AUDIO_DRIVER_DUMMY
slouken@1895
    99
    &DUMMYAUD_bootstrap,
icculus@1532
   100
#endif
slouken@1361
   101
#if SDL_AUDIO_DRIVER_DC
slouken@1895
   102
    &DCAUD_bootstrap,
slouken@509
   103
#endif
slouken@1361
   104
#if SDL_AUDIO_DRIVER_MMEAUDIO
slouken@1895
   105
    &MMEAUDIO_bootstrap,
slouken@1361
   106
#endif
slouken@1361
   107
#if SDL_AUDIO_DRIVER_DART
slouken@1895
   108
    &DART_bootstrap,
icculus@1190
   109
#endif
slouken@1895
   110
    NULL
slouken@0
   111
};
slouken@0
   112
SDL_AudioDevice *current_audio = NULL;
slouken@0
   113
slouken@0
   114
/* Various local functions */
slouken@0
   115
int SDL_AudioInit(const char *driver_name);
slouken@0
   116
void SDL_AudioQuit(void);
slouken@0
   117
slouken@1402
   118
#if SDL_AUDIO_DRIVER_AHI
slouken@21
   119
static int audio_configured = 0;
slouken@21
   120
#endif
slouken@0
   121
slouken@0
   122
/* The general mixing thread function */
slouken@1895
   123
int SDLCALL
slouken@1895
   124
SDL_RunAudio(void *audiop)
slouken@0
   125
{
slouken@1895
   126
    SDL_AudioDevice *audio = (SDL_AudioDevice *) audiop;
slouken@1895
   127
    Uint8 *stream;
slouken@1895
   128
    int stream_len;
slouken@1895
   129
    void *udata;
slouken@1895
   130
    void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len);
slouken@1895
   131
    int silence;
slouken@1402
   132
#if SDL_AUDIO_DRIVER_AHI
slouken@1895
   133
    int started = 0;
slouken@21
   134
slouken@21
   135
/* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
slouken@21
   136
slouken@1895
   137
    D(bug("Task audio started audio struct:<%lx>...\n", audiop));
slouken@21
   138
slouken@1895
   139
    D(bug("Before Openaudio..."));
slouken@1895
   140
    if (audio->OpenAudio(audio, &audio->spec) == -1) {
slouken@1895
   141
        D(bug("Open audio failed...\n"));
slouken@1895
   142
        return (-1);
slouken@1895
   143
    }
slouken@1895
   144
    D(bug("OpenAudio...OK\n"));
slouken@21
   145
#endif
slouken@0
   146
slouken@1895
   147
    /* Perform any thread setup */
slouken@1895
   148
    if (audio->ThreadInit) {
slouken@1895
   149
        audio->ThreadInit(audio);
slouken@1895
   150
    }
slouken@1895
   151
    audio->threadid = SDL_ThreadID();
slouken@0
   152
slouken@1895
   153
    /* Set up the mixing function */
slouken@1895
   154
    fill = audio->spec.callback;
slouken@1895
   155
    udata = audio->spec.userdata;
slouken@21
   156
slouken@1402
   157
#if SDL_AUDIO_DRIVER_AHI
slouken@1895
   158
    audio_configured = 1;
slouken@21
   159
slouken@1895
   160
    D(bug("Audio configured... Checking for conversion\n"));
slouken@1895
   161
    SDL_mutexP(audio->mixer_lock);
slouken@1895
   162
    D(bug("Semaphore obtained...\n"));
slouken@21
   163
#endif
slouken@21
   164
slouken@1895
   165
    if (audio->convert.needed) {
slouken@1895
   166
        if (audio->convert.src_format == AUDIO_U8) {
slouken@1895
   167
            silence = 0x80;
slouken@1895
   168
        } else {
slouken@1895
   169
            silence = 0;
slouken@1895
   170
        }
slouken@1895
   171
        stream_len = audio->convert.len;
slouken@1895
   172
    } else {
slouken@1895
   173
        silence = audio->spec.silence;
slouken@1895
   174
        stream_len = audio->spec.size;
slouken@1895
   175
    }
icculus@1561
   176
slouken@1402
   177
#if SDL_AUDIO_DRIVER_AHI
slouken@1895
   178
    SDL_mutexV(audio->mixer_lock);
slouken@1895
   179
    D(bug("Entering audio loop...\n"));
slouken@21
   180
#endif
slouken@21
   181
icculus@1190
   182
#ifdef __OS2__
slouken@1895
   183
    /* Increase the priority of this thread to make sure that
slouken@1895
   184
       the audio will be continuous all the time! */
icculus@1190
   185
#ifdef USE_DOSSETPRIORITY
slouken@1895
   186
    if (SDL_getenv("SDL_USE_TIMECRITICAL_AUDIO")) {
icculus@1190
   187
#ifdef DEBUG_BUILD
slouken@1895
   188
        printf
slouken@1895
   189
            ("[SDL_RunAudio] : Setting priority to TimeCritical+0! (TID%d)\n",
slouken@1895
   190
             SDL_ThreadID());
icculus@1190
   191
#endif
slouken@1895
   192
        DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
slouken@1895
   193
    } else {
slouken@1442
   194
#ifdef DEBUG_BUILD
slouken@1895
   195
        printf
slouken@1895
   196
            ("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n",
slouken@1895
   197
             SDL_ThreadID());
slouken@1442
   198
#endif
slouken@1895
   199
        DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
slouken@1895
   200
    }
icculus@1190
   201
#endif
icculus@1190
   202
#endif
slouken@21
   203
slouken@1895
   204
    /* Loop, filling the audio buffers */
slouken@1895
   205
    while (audio->enabled) {
slouken@0
   206
slouken@1895
   207
        /* Fill the current buffer with sound */
slouken@1895
   208
        if (audio->convert.needed) {
slouken@1895
   209
            if (audio->convert.buf) {
slouken@1895
   210
                stream = audio->convert.buf;
slouken@1895
   211
            } else {
slouken@1895
   212
                continue;
slouken@1895
   213
            }
slouken@1895
   214
        } else {
slouken@1895
   215
            stream = audio->GetAudioBuf(audio);
slouken@1895
   216
            if (stream == NULL) {
slouken@1895
   217
                stream = audio->fake_stream;
slouken@1895
   218
            }
slouken@1895
   219
        }
slouken@1895
   220
        SDL_memset(stream, silence, stream_len);
slouken@0
   221
slouken@1895
   222
        if (!audio->paused) {
slouken@1895
   223
            SDL_mutexP(audio->mixer_lock);
slouken@1895
   224
            (*fill) (udata, stream, stream_len);
slouken@1895
   225
            SDL_mutexV(audio->mixer_lock);
slouken@1895
   226
        }
slouken@0
   227
slouken@1895
   228
        /* Convert the audio if necessary */
slouken@1895
   229
        if (audio->convert.needed) {
slouken@1895
   230
            SDL_ConvertAudio(&audio->convert);
slouken@1895
   231
            stream = audio->GetAudioBuf(audio);
slouken@1895
   232
            if (stream == NULL) {
slouken@1895
   233
                stream = audio->fake_stream;
slouken@1895
   234
            }
slouken@1895
   235
            SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
slouken@1895
   236
        }
slouken@0
   237
slouken@1895
   238
        /* Ready current buffer for play and change current buffer */
slouken@1895
   239
        if (stream != audio->fake_stream) {
slouken@1895
   240
            audio->PlayAudio(audio);
slouken@1895
   241
        }
slouken@1562
   242
slouken@1895
   243
        /* Wait for an audio buffer to become available */
slouken@1895
   244
        if (stream == audio->fake_stream) {
slouken@1895
   245
            SDL_Delay((audio->spec.samples * 1000) / audio->spec.freq);
slouken@1895
   246
        } else {
slouken@1895
   247
            audio->WaitAudio(audio);
slouken@1895
   248
        }
slouken@1895
   249
    }
slouken@1562
   250
slouken@1895
   251
    /* Wait for the audio to drain.. */
slouken@1895
   252
    if (audio->WaitDone) {
slouken@1895
   253
        audio->WaitDone(audio);
slouken@1895
   254
    }
slouken@1402
   255
#if SDL_AUDIO_DRIVER_AHI
slouken@1895
   256
    D(bug("WaitAudio...Done\n"));
slouken@21
   257
slouken@1895
   258
    audio->CloseAudio(audio);
slouken@21
   259
slouken@1895
   260
    D(bug("CloseAudio..Done, subtask exiting...\n"));
slouken@1895
   261
    audio_configured = 0;
slouken@21
   262
#endif
icculus@1190
   263
#ifdef __OS2__
icculus@1190
   264
#ifdef DEBUG_BUILD
slouken@1895
   265
    printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
icculus@1190
   266
#endif
icculus@1190
   267
#endif
slouken@1895
   268
    return (0);
slouken@0
   269
}
slouken@0
   270
slouken@1895
   271
static void
slouken@1895
   272
SDL_LockAudio_Default(SDL_AudioDevice * audio)
slouken@322
   273
{
slouken@1895
   274
    if (audio->thread && (SDL_ThreadID() == audio->threadid)) {
slouken@1895
   275
        return;
slouken@1895
   276
    }
slouken@1895
   277
    SDL_mutexP(audio->mixer_lock);
slouken@322
   278
}
slouken@322
   279
slouken@1895
   280
static void
slouken@1895
   281
SDL_UnlockAudio_Default(SDL_AudioDevice * audio)
slouken@322
   282
{
slouken@1895
   283
    if (audio->thread && (SDL_ThreadID() == audio->threadid)) {
slouken@1895
   284
        return;
slouken@1895
   285
    }
slouken@1895
   286
    SDL_mutexV(audio->mixer_lock);
slouken@322
   287
}
slouken@322
   288
icculus@1982
   289
static SDL_AudioFormat
slouken@1895
   290
SDL_ParseAudioFormat(const char *string)
slouken@1794
   291
{
icculus@1982
   292
    SDL_AudioFormat format = 0;
slouken@1794
   293
slouken@1895
   294
    switch (*string) {
slouken@1895
   295
    case 'U':
slouken@1895
   296
        ++string;
slouken@1895
   297
        format |= 0x0000;
slouken@1895
   298
        break;
slouken@1895
   299
    case 'S':
slouken@1895
   300
        ++string;
slouken@1895
   301
        format |= 0x8000;
slouken@1895
   302
        break;
slouken@1895
   303
    default:
slouken@1895
   304
        return 0;
slouken@1895
   305
    }
slouken@1895
   306
    switch (SDL_atoi(string)) {
slouken@1895
   307
    case 8:
slouken@1895
   308
        string += 1;
slouken@1895
   309
        format |= 8;
slouken@1895
   310
        break;
slouken@1895
   311
    case 16:
slouken@1895
   312
        string += 2;
slouken@1895
   313
        format |= 16;
slouken@1895
   314
        if (SDL_strcmp(string, "LSB") == 0
slouken@1794
   315
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@1895
   316
            || SDL_strcmp(string, "SYS") == 0
slouken@1794
   317
#endif
slouken@1895
   318
            ) {
slouken@1895
   319
            format |= 0x0000;
slouken@1895
   320
        }
slouken@1895
   321
        if (SDL_strcmp(string, "MSB") == 0
slouken@1794
   322
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
slouken@1895
   323
            || SDL_strcmp(string, "SYS") == 0
slouken@1794
   324
#endif
slouken@1895
   325
            ) {
slouken@1895
   326
            format |= 0x1000;
slouken@1895
   327
        }
slouken@1895
   328
        break;
slouken@1895
   329
    default:
slouken@1895
   330
        return 0;
slouken@1895
   331
    }
slouken@1895
   332
    return format;
slouken@1895
   333
}
slouken@1895
   334
slouken@1895
   335
int
slouken@1895
   336
SDL_GetNumAudioDrivers(void)
slouken@1895
   337
{
slouken@1895
   338
    return (SDL_arraysize(bootstrap) - 1);
slouken@1895
   339
}
slouken@1895
   340
slouken@1895
   341
const char *
slouken@1895
   342
SDL_GetAudioDriver(int index)
slouken@1895
   343
{
slouken@1895
   344
    if (index >= 0 && index < SDL_GetNumAudioDrivers()) {
slouken@1895
   345
        return (bootstrap[index]->name);
slouken@1895
   346
    }
slouken@1895
   347
    return (NULL);
slouken@1794
   348
}
slouken@1794
   349
slouken@1895
   350
int
slouken@1895
   351
SDL_AudioInit(const char *driver_name)
slouken@0
   352
{
slouken@1895
   353
    SDL_AudioDevice *audio;
slouken@1895
   354
    int i = 0, idx;
slouken@0
   355
slouken@1895
   356
    /* Check to make sure we don't overwrite 'current_audio' */
slouken@1895
   357
    if (current_audio != NULL) {
slouken@1895
   358
        SDL_AudioQuit();
slouken@1895
   359
    }
slouken@0
   360
slouken@1895
   361
    /* Select the proper audio driver */
slouken@1895
   362
    audio = NULL;
slouken@1895
   363
    idx = 0;
slouken@1909
   364
    if (driver_name == NULL) {
slouken@1909
   365
        driver_name = SDL_getenv("SDL_AUDIODRIVER");
slouken@1909
   366
    }
slouken@1361
   367
#if SDL_AUDIO_DRIVER_ESD
slouken@1895
   368
    if ((driver_name == NULL) && (SDL_getenv("ESPEAKER") != NULL)) {
slouken@1895
   369
        /* Ahem, we know that if ESPEAKER is set, user probably wants
slouken@1895
   370
           to use ESD, but don't start it if it's not already running.
slouken@1895
   371
           This probably isn't the place to do this, but... Shh! :)
slouken@1895
   372
         */
slouken@1895
   373
        for (i = 0; bootstrap[i]; ++i) {
slouken@1895
   374
            if (SDL_strcmp(bootstrap[i]->name, "esd") == 0) {
slouken@1341
   375
#ifdef HAVE_PUTENV
slouken@1895
   376
                const char *esd_no_spawn;
slouken@0
   377
slouken@1895
   378
                /* Don't start ESD if it's not running */
slouken@1895
   379
                esd_no_spawn = getenv("ESD_NO_SPAWN");
slouken@1895
   380
                if (esd_no_spawn == NULL) {
slouken@1895
   381
                    putenv("ESD_NO_SPAWN=1");
slouken@1895
   382
                }
slouken@1341
   383
#endif
slouken@1895
   384
                if (bootstrap[i]->available()) {
slouken@1895
   385
                    audio = bootstrap[i]->create(0);
slouken@1895
   386
                    break;
slouken@1895
   387
                }
slouken@1341
   388
#ifdef HAVE_UNSETENV
slouken@1895
   389
                if (esd_no_spawn == NULL) {
slouken@1895
   390
                    unsetenv("ESD_NO_SPAWN");
slouken@1895
   391
                }
slouken@0
   392
#endif
slouken@1895
   393
            }
slouken@1895
   394
        }
slouken@1895
   395
    }
slouken@1361
   396
#endif /* SDL_AUDIO_DRIVER_ESD */
slouken@1895
   397
    if (audio == NULL) {
slouken@1895
   398
        if (driver_name != NULL) {
slouken@1895
   399
            for (i = 0; bootstrap[i]; ++i) {
slouken@1895
   400
                if (SDL_strncmp(bootstrap[i]->name, driver_name,
slouken@1895
   401
                                SDL_strlen(bootstrap[i]->name)) == 0) {
slouken@1895
   402
                    if (bootstrap[i]->available()) {
slouken@1895
   403
                        audio = bootstrap[i]->create(idx);
slouken@1895
   404
                    }
slouken@1895
   405
                    break;
slouken@1895
   406
                }
slouken@1895
   407
            }
slouken@1895
   408
        } else {
slouken@1895
   409
            for (i = 0; bootstrap[i]; ++i) {
slouken@1895
   410
                if (bootstrap[i]->available()) {
slouken@1895
   411
                    audio = bootstrap[i]->create(idx);
slouken@1895
   412
                    if (audio != NULL) {
slouken@1895
   413
                        break;
slouken@1895
   414
                    }
slouken@1895
   415
                }
slouken@1895
   416
            }
slouken@1895
   417
        }
slouken@1895
   418
        if (audio == NULL) {
slouken@1895
   419
            if (driver_name) {
slouken@1895
   420
                SDL_SetError("%s not available", driver_name);
slouken@1895
   421
            } else {
slouken@1895
   422
                SDL_SetError("No available audio device");
slouken@1895
   423
            }
slouken@1909
   424
#if 0
slouken@1909
   425
            /* Don't fail SDL_Init() if audio isn't available.
slouken@1909
   426
               SDL_OpenAudio() will handle it at that point.  *sigh*
slouken@1909
   427
             */
slouken@1895
   428
            return (-1);
slouken@0
   429
#endif
slouken@1895
   430
        }
slouken@1895
   431
    }
slouken@1895
   432
    current_audio = audio;
slouken@1895
   433
    if (current_audio) {
slouken@1895
   434
        current_audio->name = bootstrap[i]->name;
slouken@1895
   435
        if (!current_audio->LockAudio && !current_audio->UnlockAudio) {
slouken@1895
   436
            current_audio->LockAudio = SDL_LockAudio_Default;
slouken@1895
   437
            current_audio->UnlockAudio = SDL_UnlockAudio_Default;
slouken@1895
   438
        }
slouken@1895
   439
    }
slouken@1895
   440
    return (0);
slouken@0
   441
}
slouken@0
   442
slouken@1895
   443
/*
slouken@1895
   444
 * Get the current audio driver name
slouken@1895
   445
 */
slouken@1895
   446
const char *
slouken@1895
   447
SDL_GetCurrentAudioDriver()
slouken@0
   448
{
slouken@1895
   449
    if (current_audio) {
slouken@1895
   450
        return current_audio->name;
slouken@1895
   451
    }
slouken@1895
   452
    return (NULL);
slouken@0
   453
}
slouken@0
   454
slouken@1895
   455
int
slouken@1895
   456
SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
slouken@0
   457
{
slouken@1895
   458
    SDL_AudioDevice *audio;
slouken@1895
   459
    const char *env;
slouken@0
   460
slouken@1895
   461
    /* Start up the audio driver, if necessary */
slouken@1895
   462
    if (!current_audio) {
slouken@1895
   463
        if ((SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
slouken@1895
   464
            (current_audio == NULL)) {
slouken@1895
   465
            return (-1);
slouken@1895
   466
        }
slouken@1895
   467
    }
slouken@1895
   468
    audio = current_audio;
slouken@0
   469
slouken@1895
   470
    if (audio->opened) {
slouken@1895
   471
        SDL_SetError("Audio device is already opened");
slouken@1895
   472
        return (-1);
slouken@1895
   473
    }
slouken@262
   474
slouken@1895
   475
    /* Verify some parameters */
slouken@1895
   476
    if (desired->freq == 0) {
slouken@1895
   477
        env = SDL_getenv("SDL_AUDIO_FREQUENCY");
slouken@1895
   478
        if (env) {
slouken@1895
   479
            desired->freq = SDL_atoi(env);
slouken@1895
   480
        }
slouken@1895
   481
    }
slouken@1895
   482
    if (desired->freq == 0) {
slouken@1895
   483
        /* Pick some default audio frequency */
slouken@1895
   484
        desired->freq = 22050;
slouken@1895
   485
    }
slouken@1895
   486
    if (desired->format == 0) {
slouken@1895
   487
        env = SDL_getenv("SDL_AUDIO_FORMAT");
slouken@1895
   488
        if (env) {
slouken@1895
   489
            desired->format = SDL_ParseAudioFormat(env);
slouken@1895
   490
        }
slouken@1895
   491
    }
slouken@1895
   492
    if (desired->format == 0) {
slouken@1895
   493
        /* Pick some default audio format */
slouken@1895
   494
        desired->format = AUDIO_S16;
slouken@1895
   495
    }
slouken@1895
   496
    if (desired->channels == 0) {
slouken@1895
   497
        env = SDL_getenv("SDL_AUDIO_CHANNELS");
slouken@1895
   498
        if (env) {
slouken@1903
   499
            desired->channels = (Uint8) SDL_atoi(env);
slouken@1895
   500
        }
slouken@1895
   501
    }
slouken@1895
   502
    if (desired->channels == 0) {
slouken@1895
   503
        /* Pick a default number of channels */
slouken@1895
   504
        desired->channels = 2;
slouken@1895
   505
    }
slouken@1895
   506
    switch (desired->channels) {
slouken@1895
   507
    case 1:                    /* Mono */
slouken@1895
   508
    case 2:                    /* Stereo */
slouken@1895
   509
    case 4:                    /* surround */
slouken@1895
   510
    case 6:                    /* surround with center and lfe */
slouken@1895
   511
        break;
slouken@1895
   512
    default:
slouken@1895
   513
        SDL_SetError("1 (mono) and 2 (stereo) channels supported");
slouken@1895
   514
        return (-1);
slouken@1895
   515
    }
slouken@1895
   516
    if (desired->samples == 0) {
slouken@1895
   517
        env = SDL_getenv("SDL_AUDIO_SAMPLES");
slouken@1895
   518
        if (env) {
slouken@1903
   519
            desired->samples = (Uint16) SDL_atoi(env);
slouken@1895
   520
        }
slouken@1895
   521
    }
slouken@1895
   522
    if (desired->samples == 0) {
slouken@1895
   523
        /* Pick a default of ~46 ms at desired frequency */
slouken@1895
   524
        int samples = (desired->freq / 1000) * 46;
slouken@1895
   525
        int power2 = 1;
slouken@1895
   526
        while (power2 < samples) {
slouken@1895
   527
            power2 *= 2;
slouken@1895
   528
        }
slouken@1895
   529
        desired->samples = power2;
slouken@1895
   530
    }
slouken@1895
   531
    if (desired->callback == NULL) {
slouken@1895
   532
        SDL_SetError("SDL_OpenAudio() passed a NULL callback");
slouken@1895
   533
        return (-1);
slouken@1895
   534
    }
slouken@1361
   535
#if defined(__MINT__) && SDL_THREADS_DISABLED
slouken@1895
   536
    /* Uses interrupt driven audio, without thread */
slouken@398
   537
#else
slouken@1895
   538
    /* Create a semaphore for locking the sound buffers */
slouken@1895
   539
    audio->mixer_lock = SDL_CreateMutex();
slouken@1895
   540
    if (audio->mixer_lock == NULL) {
slouken@1895
   541
        SDL_SetError("Couldn't create mixer lock");
slouken@1895
   542
        SDL_CloseAudio();
slouken@1895
   543
        return (-1);
slouken@1895
   544
    }
slouken@398
   545
#endif /* __MINT__ */
slouken@0
   546
slouken@1895
   547
    /* Calculate the silence and size of the audio specification */
slouken@1895
   548
    SDL_CalculateAudioSpec(desired);
slouken@0
   549
slouken@1895
   550
    /* Open the audio subsystem */
slouken@1895
   551
    SDL_memcpy(&audio->spec, desired, sizeof(audio->spec));
slouken@1895
   552
    audio->convert.needed = 0;
slouken@1895
   553
    audio->enabled = 1;
slouken@1895
   554
    audio->paused = 1;
slouken@21
   555
slouken@1406
   556
#if !SDL_AUDIO_DRIVER_AHI
slouken@21
   557
slouken@21
   558
/* AmigaOS opens audio inside the main loop */
slouken@1895
   559
    audio->opened = audio->OpenAudio(audio, &audio->spec) + 1;
slouken@21
   560
slouken@1895
   561
    if (!audio->opened) {
slouken@1895
   562
        SDL_CloseAudio();
slouken@1895
   563
        return (-1);
slouken@1895
   564
    }
slouken@21
   565
#else
slouken@1895
   566
    D(bug("Locking semaphore..."));
slouken@1895
   567
    SDL_mutexP(audio->mixer_lock);
slouken@1408
   568
slouken@21
   569
slouken@1895
   570
    audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
slouken@1895
   571
    D(bug("Created thread...\n"));
slouken@21
   572
slouken@1895
   573
    if (audio->thread == NULL) {
slouken@1895
   574
        SDL_mutexV(audio->mixer_lock);
slouken@1895
   575
        SDL_CloseAudio();
slouken@1895
   576
        SDL_SetError("Couldn't create audio thread");
slouken@1895
   577
        return (-1);
slouken@1895
   578
    }
slouken@21
   579
slouken@1895
   580
    while (!audio_configured)
slouken@1895
   581
        SDL_Delay(100);
slouken@21
   582
#endif
slouken@0
   583
slouken@1895
   584
    /* If the audio driver changes the buffer size, accept it */
slouken@1895
   585
    if (audio->spec.samples != desired->samples) {
slouken@1895
   586
        desired->samples = audio->spec.samples;
slouken@1895
   587
        SDL_CalculateAudioSpec(desired);
slouken@1895
   588
    }
slouken@0
   589
slouken@1895
   590
    /* Allocate a fake audio memory buffer */
slouken@1895
   591
    audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
slouken@1895
   592
    if (audio->fake_stream == NULL) {
slouken@1895
   593
        SDL_CloseAudio();
slouken@1895
   594
        SDL_OutOfMemory();
slouken@1895
   595
        return (-1);
slouken@1895
   596
    }
slouken@0
   597
slouken@1895
   598
    /* See if we need to do any conversion */
slouken@1895
   599
    if (obtained != NULL) {
slouken@1895
   600
        SDL_memcpy(obtained, &audio->spec, sizeof(audio->spec));
slouken@1895
   601
    } else if (desired->freq != audio->spec.freq ||
slouken@1895
   602
               desired->format != audio->spec.format ||
slouken@1895
   603
               desired->channels != audio->spec.channels) {
slouken@1895
   604
        /* Build an audio conversion block */
slouken@1895
   605
        if (SDL_BuildAudioCVT(&audio->convert,
slouken@1895
   606
                              desired->format, desired->channels,
slouken@1895
   607
                              desired->freq,
slouken@1895
   608
                              audio->spec.format, audio->spec.channels,
slouken@1895
   609
                              audio->spec.freq) < 0) {
slouken@1895
   610
            SDL_CloseAudio();
slouken@1895
   611
            return (-1);
slouken@1895
   612
        }
slouken@1895
   613
        if (audio->convert.needed) {
slouken@1895
   614
            audio->convert.len = desired->size;
slouken@1895
   615
            audio->convert.buf =
slouken@1895
   616
                (Uint8 *) SDL_AllocAudioMem(audio->convert.len *
slouken@1895
   617
                                            audio->convert.len_mult);
slouken@1895
   618
            if (audio->convert.buf == NULL) {
slouken@1895
   619
                SDL_CloseAudio();
slouken@1895
   620
                SDL_OutOfMemory();
slouken@1895
   621
                return (-1);
slouken@1895
   622
            }
slouken@1895
   623
        }
slouken@1895
   624
    }
slouken@1406
   625
#if !SDL_AUDIO_DRIVER_AHI
slouken@1895
   626
    /* Start the audio thread if necessary */
slouken@1895
   627
    switch (audio->opened) {
slouken@1895
   628
    case 1:
slouken@1895
   629
        /* Start the audio thread */
slouken@1402
   630
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
slouken@1330
   631
#undef SDL_CreateThread
slouken@1895
   632
        audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
slouken@1330
   633
#else
slouken@1895
   634
        audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
slouken@1330
   635
#endif
slouken@1895
   636
        if (audio->thread == NULL) {
slouken@1895
   637
            SDL_CloseAudio();
slouken@1895
   638
            SDL_SetError("Couldn't create audio thread");
slouken@1895
   639
            return (-1);
slouken@1895
   640
        }
slouken@1895
   641
        break;
slouken@0
   642
slouken@1895
   643
    default:
slouken@1895
   644
        /* The audio is now playing */
slouken@1895
   645
        break;
slouken@1895
   646
    }
slouken@21
   647
#else
slouken@1895
   648
    SDL_mutexV(audio->mixer_lock);
slouken@1895
   649
    D(bug("SDL_OpenAudio USCITA...\n"));
slouken@21
   650
slouken@21
   651
#endif
slouken@21
   652
slouken@1895
   653
    return (0);
slouken@1895
   654
}
slouken@1895
   655
slouken@1895
   656
SDL_audiostatus
slouken@1895
   657
SDL_GetAudioStatus(void)
slouken@1895
   658
{
slouken@1895
   659
    SDL_AudioDevice *audio = current_audio;
slouken@1895
   660
    SDL_audiostatus status;
slouken@1895
   661
slouken@1895
   662
    status = SDL_AUDIO_STOPPED;
slouken@1895
   663
    if (audio && audio->enabled) {
slouken@1895
   664
        if (audio->paused) {
slouken@1895
   665
            status = SDL_AUDIO_PAUSED;
slouken@1895
   666
        } else {
slouken@1895
   667
            status = SDL_AUDIO_PLAYING;
slouken@1895
   668
        }
slouken@1895
   669
    }
slouken@1895
   670
    return (status);
slouken@0
   671
}
slouken@0
   672
slouken@1895
   673
void
slouken@1895
   674
SDL_PauseAudio(int pause_on)
slouken@0
   675
{
slouken@1895
   676
    SDL_AudioDevice *audio = current_audio;
slouken@0
   677
slouken@1895
   678
    if (audio) {
slouken@1895
   679
        audio->paused = pause_on;
slouken@1895
   680
    }
slouken@0
   681
}
slouken@0
   682
slouken@1895
   683
void
slouken@1895
   684
SDL_LockAudio(void)
slouken@0
   685
{
slouken@1895
   686
    SDL_AudioDevice *audio = current_audio;
slouken@0
   687
slouken@1895
   688
    /* Obtain a lock on the mixing buffers */
slouken@1895
   689
    if (audio && audio->LockAudio) {
slouken@1895
   690
        audio->LockAudio(audio);
slouken@1895
   691
    }
slouken@0
   692
}
slouken@0
   693
slouken@1895
   694
void
slouken@1895
   695
SDL_UnlockAudio(void)
slouken@0
   696
{
slouken@1895
   697
    SDL_AudioDevice *audio = current_audio;
slouken@0
   698
slouken@1895
   699
    /* Release lock on the mixing buffers */
slouken@1895
   700
    if (audio && audio->UnlockAudio) {
slouken@1895
   701
        audio->UnlockAudio(audio);
slouken@1895
   702
    }
slouken@0
   703
}
slouken@0
   704
slouken@1895
   705
void
slouken@1895
   706
SDL_CloseAudio(void)
slouken@0
   707
{
slouken@1895
   708
    SDL_QuitSubSystem(SDL_INIT_AUDIO);
slouken@0
   709
}
slouken@0
   710
slouken@1895
   711
void
slouken@1895
   712
SDL_AudioQuit(void)
slouken@0
   713
{
slouken@1895
   714
    SDL_AudioDevice *audio = current_audio;
slouken@0
   715
slouken@1895
   716
    if (audio) {
slouken@1895
   717
        audio->enabled = 0;
slouken@1895
   718
        if (audio->thread != NULL) {
slouken@1895
   719
            SDL_WaitThread(audio->thread, NULL);
slouken@1895
   720
        }
slouken@1895
   721
        if (audio->mixer_lock != NULL) {
slouken@1895
   722
            SDL_DestroyMutex(audio->mixer_lock);
slouken@1895
   723
        }
slouken@1895
   724
        if (audio->fake_stream != NULL) {
slouken@1895
   725
            SDL_FreeAudioMem(audio->fake_stream);
slouken@1895
   726
        }
slouken@1895
   727
        if (audio->convert.needed) {
slouken@1895
   728
            SDL_FreeAudioMem(audio->convert.buf);
slouken@21
   729
slouken@1895
   730
        }
slouken@1406
   731
#if !SDL_AUDIO_DRIVER_AHI
slouken@1895
   732
        if (audio->opened) {
slouken@1895
   733
            audio->CloseAudio(audio);
slouken@1895
   734
            audio->opened = 0;
slouken@1895
   735
        }
slouken@21
   736
#endif
slouken@1895
   737
        /* Free the driver data */
slouken@1895
   738
        audio->free(audio);
slouken@1895
   739
        current_audio = NULL;
slouken@1895
   740
    }
slouken@0
   741
}
slouken@0
   742
icculus@1982
   743
#define NUM_FORMATS 10
slouken@0
   744
static int format_idx;
slouken@0
   745
static int format_idx_sub;
icculus@1982
   746
static SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS] = {
slouken@1895
   747
    {AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
icculus@1982
   748
     AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
slouken@1895
   749
    {AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB,
icculus@1982
   750
     AUDIO_U16MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB},
icculus@1982
   751
    {AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S32LSB,
icculus@1982
   752
     AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   753
    {AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S32MSB,
icculus@1982
   754
     AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   755
    {AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_S32LSB,
icculus@1982
   756
     AUDIO_S32MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   757
    {AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_S32MSB,
icculus@1982
   758
     AUDIO_S32LSB, AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   759
    {AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB,
icculus@1982
   760
     AUDIO_S16MSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   761
    {AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB,
icculus@1982
   762
     AUDIO_S16LSB, AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   763
    {AUDIO_F32LSB, AUDIO_F32MSB, AUDIO_S32LSB, AUDIO_S32MSB, AUDIO_U16LSB,
icculus@1982
   764
     AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8},
icculus@1982
   765
    {AUDIO_F32MSB, AUDIO_F32LSB, AUDIO_S32MSB, AUDIO_S32LSB, AUDIO_U16MSB,
icculus@1982
   766
     AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8},
slouken@0
   767
};
slouken@0
   768
icculus@1982
   769
SDL_AudioFormat
icculus@1982
   770
SDL_FirstAudioFormat(SDL_AudioFormat format)
slouken@0
   771
{
slouken@1895
   772
    for (format_idx = 0; format_idx < NUM_FORMATS; ++format_idx) {
slouken@1895
   773
        if (format_list[format_idx][0] == format) {
slouken@1895
   774
            break;
slouken@1895
   775
        }
slouken@1895
   776
    }
slouken@1895
   777
    format_idx_sub = 0;
slouken@1895
   778
    return (SDL_NextAudioFormat());
slouken@0
   779
}
slouken@0
   780
icculus@1982
   781
SDL_AudioFormat
slouken@1895
   782
SDL_NextAudioFormat(void)
slouken@0
   783
{
slouken@1895
   784
    if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) {
slouken@1895
   785
        return (0);
slouken@1895
   786
    }
slouken@1895
   787
    return (format_list[format_idx][format_idx_sub++]);
slouken@0
   788
}
slouken@0
   789
slouken@1895
   790
void
slouken@1895
   791
SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
slouken@0
   792
{
slouken@1895
   793
    switch (spec->format) {
slouken@1895
   794
    case AUDIO_U8:
slouken@1895
   795
        spec->silence = 0x80;
slouken@1895
   796
        break;
slouken@1895
   797
    default:
slouken@1895
   798
        spec->silence = 0x00;
slouken@1895
   799
        break;
slouken@1895
   800
    }
slouken@1895
   801
    spec->size = (spec->format & 0xFF) / 8;
slouken@1895
   802
    spec->size *= spec->channels;
slouken@1895
   803
    spec->size *= spec->samples;
slouken@0
   804
}
slouken@1895
   805
slouken@1895
   806
/* vi: set ts=4 sw=4 expandtab: */