src/audio/windx5/SDL_dx5audio.c
author Darren Alton <dalton@stevens.edu>
Wed, 27 Aug 2008 04:23:38 +0000
branchgsoc2008_nds
changeset 2698 e1da92da346c
parent 2060 866052b01ee5
child 2859 99210400e8b9
permissions -rw-r--r--
Clean up.
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_timer.h"
slouken@0
    27
#include "SDL_audio.h"
slouken@1361
    28
#include "../SDL_audio_c.h"
slouken@0
    29
#include "SDL_dx5audio.h"
slouken@0
    30
icculus@2049
    31
/* !!! FIXME: move this somewhere that other drivers can use it... */
icculus@2049
    32
#if defined(_WIN32_WCE)
icculus@2049
    33
#define WINDOWS_OS_NAME "Windows CE/PocketPC"
icculus@2049
    34
#elif defined(WIN64)
icculus@2049
    35
#define WINDOWS_OS_NAME "Win64"
icculus@2049
    36
#else
icculus@2049
    37
#define WINDOWS_OS_NAME "Win32"
icculus@2049
    38
#endif
slouken@0
    39
slouken@0
    40
/* DirectX function pointers for audio */
slouken@0
    41
static HINSTANCE DSoundDLL = NULL;
slouken@2060
    42
static HRESULT(WINAPI * DSoundCreate) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN) =
slouken@2060
    43
    NULL;
slouken@0
    44
slouken@1895
    45
static void
icculus@2049
    46
DSOUND_Unload(void)
slouken@0
    47
{
slouken@1895
    48
    if (DSoundDLL != NULL) {
slouken@1895
    49
        FreeLibrary(DSoundDLL);
slouken@1895
    50
    }
slouken@0
    51
icculus@2049
    52
    DSoundCreate = NULL;
icculus@2049
    53
    DSoundDLL = NULL;
slouken@0
    54
}
slouken@0
    55
icculus@2049
    56
icculus@2049
    57
static int
icculus@2049
    58
DSOUND_Load(void)
slouken@0
    59
{
icculus@2049
    60
    int loaded = 0;
icculus@2049
    61
icculus@2049
    62
    DSOUND_Unload();
icculus@2049
    63
icculus@2049
    64
    DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
icculus@2049
    65
    if (DSoundDLL == NULL) {
icculus@2049
    66
        SDL_SetError("DirectSound: failed to load DSOUND.DLL");
icculus@2049
    67
    } else {
icculus@2049
    68
        /* Now make sure we have DirectX 5 or better... */
icculus@2049
    69
        /*  (DirectSoundCaptureCreate was added in DX5) */
icculus@2049
    70
        if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate"))) {
icculus@2049
    71
            SDL_SetError("DirectSound: System doesn't appear to have DX5.");
icculus@2049
    72
        } else {
icculus@2049
    73
            DSoundCreate = (void *) GetProcAddress(DSoundDLL,
slouken@2060
    74
                                                   TEXT("DirectSoundCreate"));
icculus@2049
    75
        }
icculus@2049
    76
icculus@2049
    77
        if (!DSoundCreate) {
icculus@2049
    78
            SDL_SetError("DirectSound: Failed to find DirectSoundCreate");
icculus@2049
    79
        } else {
icculus@2049
    80
            loaded = 1;
icculus@2049
    81
        }
icculus@2049
    82
    }
icculus@2049
    83
icculus@2049
    84
    if (!loaded) {
icculus@2049
    85
        DSOUND_Unload();
icculus@2049
    86
    }
icculus@2049
    87
icculus@2049
    88
    return loaded;
slouken@0
    89
}
slouken@0
    90
slouken@0
    91
slouken@1895
    92
static void
slouken@1895
    93
SetDSerror(const char *function, int code)
slouken@0
    94
{
slouken@1895
    95
    static const char *error;
slouken@1895
    96
    static char errbuf[1024];
slouken@0
    97
slouken@1895
    98
    errbuf[0] = 0;
slouken@1895
    99
    switch (code) {
slouken@1895
   100
    case E_NOINTERFACE:
icculus@2049
   101
        error = "Unsupported interface -- Is DirectX 5.0 or later installed?";
slouken@1895
   102
        break;
slouken@1895
   103
    case DSERR_ALLOCATED:
slouken@1895
   104
        error = "Audio device in use";
slouken@1895
   105
        break;
slouken@1895
   106
    case DSERR_BADFORMAT:
slouken@1895
   107
        error = "Unsupported audio format";
slouken@1895
   108
        break;
slouken@1895
   109
    case DSERR_BUFFERLOST:
slouken@1895
   110
        error = "Mixing buffer was lost";
slouken@1895
   111
        break;
slouken@1895
   112
    case DSERR_CONTROLUNAVAIL:
slouken@1895
   113
        error = "Control requested is not available";
slouken@1895
   114
        break;
slouken@1895
   115
    case DSERR_INVALIDCALL:
slouken@1895
   116
        error = "Invalid call for the current state";
slouken@1895
   117
        break;
slouken@1895
   118
    case DSERR_INVALIDPARAM:
slouken@1895
   119
        error = "Invalid parameter";
slouken@1895
   120
        break;
slouken@1895
   121
    case DSERR_NODRIVER:
slouken@1895
   122
        error = "No audio device found";
slouken@1895
   123
        break;
slouken@1895
   124
    case DSERR_OUTOFMEMORY:
slouken@1895
   125
        error = "Out of memory";
slouken@1895
   126
        break;
slouken@1895
   127
    case DSERR_PRIOLEVELNEEDED:
slouken@1895
   128
        error = "Caller doesn't have priority";
slouken@1895
   129
        break;
slouken@1895
   130
    case DSERR_UNSUPPORTED:
slouken@1895
   131
        error = "Function not supported";
slouken@1895
   132
        break;
slouken@1895
   133
    default:
slouken@1895
   134
        SDL_snprintf(errbuf, SDL_arraysize(errbuf),
slouken@1895
   135
                     "%s: Unknown DirectSound error: 0x%x", function, code);
slouken@1895
   136
        break;
slouken@1895
   137
    }
slouken@1895
   138
    if (!errbuf[0]) {
slouken@1895
   139
        SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
slouken@1895
   140
                     error);
slouken@1895
   141
    }
slouken@1895
   142
    SDL_SetError("%s", errbuf);
slouken@1895
   143
    return;
slouken@0
   144
}
slouken@0
   145
slouken@0
   146
/* DirectSound needs to be associated with a window */
slouken@0
   147
static HWND mainwin = NULL;
slouken@0
   148
/* */
icculus@2049
   149
slouken@1895
   150
void
icculus@2049
   151
DSOUND_SoundFocus(HWND hwnd)
slouken@0
   152
{
icculus@2049
   153
    /* !!! FIXME: probably broken with multi-window support in SDL 1.3 ... */
slouken@1895
   154
    mainwin = hwnd;
slouken@0
   155
}
slouken@0
   156
slouken@1895
   157
static void
icculus@2049
   158
DSOUND_ThreadInit(_THIS)
slouken@0
   159
{
slouken@1895
   160
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
slouken@0
   161
}
slouken@0
   162
slouken@1895
   163
static void
icculus@2049
   164
DSOUND_WaitDevice(_THIS)
slouken@0
   165
{
icculus@2049
   166
    DWORD status = 0;
icculus@2049
   167
    DWORD cursor = 0;
icculus@2049
   168
    DWORD junk = 0;
icculus@2049
   169
    HRESULT result = DS_OK;
slouken@0
   170
slouken@1895
   171
    /* Semi-busy wait, since we have no way of getting play notification
slouken@1895
   172
       on a primary mixing buffer located in hardware (DirectX 5.0)
slouken@1895
   173
     */
icculus@2049
   174
    result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
icculus@2049
   175
                                                   &junk, &cursor);
slouken@1895
   176
    if (result != DS_OK) {
slouken@1895
   177
        if (result == DSERR_BUFFERLOST) {
icculus@2049
   178
            IDirectSoundBuffer_Restore(this->hidden->mixbuf);
slouken@1895
   179
        }
slouken@0
   180
#ifdef DEBUG_SOUND
slouken@1895
   181
        SetDSerror("DirectSound GetCurrentPosition", result);
slouken@0
   182
#endif
slouken@1895
   183
        return;
slouken@1895
   184
    }
slouken@0
   185
icculus@2049
   186
    while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
slouken@1895
   187
        /* FIXME: find out how much time is left and sleep that long */
slouken@1895
   188
        SDL_Delay(1);
slouken@0
   189
slouken@1895
   190
        /* Try to restore a lost sound buffer */
icculus@2049
   191
        IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
slouken@1895
   192
        if ((status & DSBSTATUS_BUFFERLOST)) {
icculus@2049
   193
            IDirectSoundBuffer_Restore(this->hidden->mixbuf);
icculus@2049
   194
            IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
slouken@1895
   195
            if ((status & DSBSTATUS_BUFFERLOST)) {
slouken@1895
   196
                break;
slouken@1895
   197
            }
slouken@1895
   198
        }
slouken@1895
   199
        if (!(status & DSBSTATUS_PLAYING)) {
icculus@2049
   200
            result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
icculus@2049
   201
                                             DSBPLAY_LOOPING);
slouken@1895
   202
            if (result == DS_OK) {
slouken@1895
   203
                continue;
slouken@1895
   204
            }
slouken@0
   205
#ifdef DEBUG_SOUND
slouken@1895
   206
            SetDSerror("DirectSound Play", result);
slouken@0
   207
#endif
slouken@1895
   208
            return;
slouken@1895
   209
        }
slouken@0
   210
slouken@1895
   211
        /* Find out where we are playing */
icculus@2049
   212
        result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
slouken@1895
   213
                                                       &junk, &cursor);
slouken@1895
   214
        if (result != DS_OK) {
slouken@1895
   215
            SetDSerror("DirectSound GetCurrentPosition", result);
slouken@1895
   216
            return;
slouken@1895
   217
        }
slouken@1895
   218
    }
slouken@0
   219
}
slouken@0
   220
slouken@1895
   221
static void
icculus@2049
   222
DSOUND_PlayDevice(_THIS)
slouken@0
   223
{
slouken@1895
   224
    /* Unlock the buffer, allowing it to play */
icculus@2049
   225
    if (this->hidden->locked_buf) {
icculus@2049
   226
        IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
icculus@2049
   227
                                  this->hidden->locked_buf,
icculus@2049
   228
                                  this->hidden->mixlen, NULL, 0);
slouken@1895
   229
    }
slouken@0
   230
slouken@0
   231
}
slouken@0
   232
slouken@1895
   233
static Uint8 *
icculus@2049
   234
DSOUND_GetDeviceBuf(_THIS)
slouken@0
   235
{
icculus@2049
   236
    DWORD cursor = 0;
icculus@2049
   237
    DWORD junk = 0;
icculus@2049
   238
    HRESULT result = DS_OK;
icculus@2049
   239
    DWORD rawlen = 0;
slouken@0
   240
slouken@1895
   241
    /* Figure out which blocks to fill next */
icculus@2049
   242
    this->hidden->locked_buf = NULL;
icculus@2049
   243
    result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
icculus@2049
   244
                                                   &junk, &cursor);
slouken@1895
   245
    if (result == DSERR_BUFFERLOST) {
icculus@2049
   246
        IDirectSoundBuffer_Restore(this->hidden->mixbuf);
icculus@2049
   247
        result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
slouken@1895
   248
                                                       &junk, &cursor);
slouken@1895
   249
    }
slouken@1895
   250
    if (result != DS_OK) {
slouken@1895
   251
        SetDSerror("DirectSound GetCurrentPosition", result);
slouken@1895
   252
        return (NULL);
slouken@1895
   253
    }
icculus@2049
   254
    cursor /= this->hidden->mixlen;
slouken@1877
   255
#ifdef DEBUG_SOUND
slouken@1895
   256
    /* Detect audio dropouts */
slouken@1895
   257
    {
slouken@1895
   258
        DWORD spot = cursor;
icculus@2049
   259
        if (spot < this->hidden->lastchunk) {
icculus@2049
   260
            spot += this->hidden->num_buffers;
slouken@1895
   261
        }
icculus@2049
   262
        if (spot > this->hidden->lastchunk + 1) {
slouken@1895
   263
            fprintf(stderr, "Audio dropout, missed %d fragments\n",
icculus@2049
   264
                    (spot - (this->hidden->lastchunk + 1)));
slouken@1895
   265
        }
slouken@1895
   266
    }
slouken@1877
   267
#endif
icculus@2049
   268
    this->hidden->lastchunk = cursor;
icculus@2049
   269
    cursor = (cursor + 1) % this->hidden->num_buffers;
icculus@2049
   270
    cursor *= this->hidden->mixlen;
slouken@0
   271
slouken@1895
   272
    /* Lock the audio buffer */
icculus@2049
   273
    result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
icculus@2049
   274
                                     this->hidden->mixlen,
slouken@2060
   275
                                     (LPVOID *) & this->hidden->locked_buf,
icculus@2049
   276
                                     &rawlen, NULL, &junk, 0);
slouken@1895
   277
    if (result == DSERR_BUFFERLOST) {
icculus@2049
   278
        IDirectSoundBuffer_Restore(this->hidden->mixbuf);
icculus@2049
   279
        result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
icculus@2049
   280
                                         this->hidden->mixlen,
dalton@2698
   281
                                         (LPVOID *) & this->
dalton@2698
   282
                                         hidden->locked_buf, &rawlen, NULL,
dalton@2698
   283
                                         &junk, 0);
slouken@1895
   284
    }
slouken@1895
   285
    if (result != DS_OK) {
slouken@1895
   286
        SetDSerror("DirectSound Lock", result);
slouken@1895
   287
        return (NULL);
slouken@1895
   288
    }
icculus@2049
   289
    return (this->hidden->locked_buf);
slouken@0
   290
}
slouken@0
   291
slouken@1895
   292
static void
icculus@2049
   293
DSOUND_WaitDone(_THIS)
slouken@0
   294
{
icculus@2049
   295
    Uint8 *stream = DSOUND_GetDeviceBuf(this);
slouken@0
   296
slouken@1895
   297
    /* Wait for the playing chunk to finish */
slouken@1895
   298
    if (stream != NULL) {
icculus@2049
   299
        SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
icculus@2049
   300
        DSOUND_PlayDevice(this);
slouken@1895
   301
    }
icculus@2049
   302
    DSOUND_WaitDevice(this);
slouken@0
   303
slouken@1895
   304
    /* Stop the looping sound buffer */
icculus@2049
   305
    IDirectSoundBuffer_Stop(this->hidden->mixbuf);
slouken@0
   306
}
slouken@0
   307
slouken@1895
   308
static void
icculus@2049
   309
DSOUND_CloseDevice(_THIS)
slouken@0
   310
{
icculus@2049
   311
    if (this->hidden != NULL) {
icculus@2049
   312
        if (this->hidden->sound != NULL) {
icculus@2049
   313
            if (this->hidden->mixbuf != NULL) {
icculus@2049
   314
                /* Clean up the audio buffer */
icculus@2049
   315
                IDirectSoundBuffer_Release(this->hidden->mixbuf);
icculus@2049
   316
                this->hidden->mixbuf = NULL;
icculus@2049
   317
            }
icculus@2049
   318
            IDirectSound_Release(this->hidden->sound);
icculus@2049
   319
            this->hidden->sound = NULL;
slouken@1895
   320
        }
icculus@2049
   321
icculus@2049
   322
        SDL_free(this->hidden);
icculus@2049
   323
        this->hidden = NULL;
slouken@1895
   324
    }
slouken@0
   325
}
slouken@0
   326
slouken@0
   327
/* This function tries to create a secondary audio buffer, and returns the
slouken@0
   328
   number of audio chunks available in the created buffer.
slouken@0
   329
*/
slouken@1895
   330
static int
slouken@2060
   331
CreateSecondary(_THIS, HWND focus, WAVEFORMATEX * wavefmt)
slouken@0
   332
{
icculus@2049
   333
    LPDIRECTSOUND sndObj = this->hidden->sound;
icculus@2051
   334
    LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
icculus@2049
   335
    Uint32 chunksize = this->spec.size;
slouken@1895
   336
    const int numchunks = 8;
icculus@2049
   337
    HRESULT result = DS_OK;
slouken@1895
   338
    DSBUFFERDESC format;
slouken@1895
   339
    LPVOID pvAudioPtr1, pvAudioPtr2;
slouken@1895
   340
    DWORD dwAudioBytes1, dwAudioBytes2;
slouken@0
   341
slouken@1895
   342
    /* Try to set primary mixing privileges */
slouken@1895
   343
    if (focus) {
slouken@1895
   344
        result = IDirectSound_SetCooperativeLevel(sndObj,
slouken@1895
   345
                                                  focus, DSSCL_PRIORITY);
slouken@1895
   346
    } else {
slouken@1895
   347
        result = IDirectSound_SetCooperativeLevel(sndObj,
slouken@1895
   348
                                                  GetDesktopWindow(),
slouken@1895
   349
                                                  DSSCL_NORMAL);
slouken@1895
   350
    }
slouken@1895
   351
    if (result != DS_OK) {
slouken@1895
   352
        SetDSerror("DirectSound SetCooperativeLevel", result);
slouken@1895
   353
        return (-1);
slouken@1895
   354
    }
slouken@0
   355
slouken@1895
   356
    /* Try to create the secondary buffer */
slouken@1895
   357
    SDL_memset(&format, 0, sizeof(format));
slouken@1895
   358
    format.dwSize = sizeof(format);
slouken@1895
   359
    format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
slouken@1895
   360
    if (!focus) {
slouken@1895
   361
        format.dwFlags |= DSBCAPS_GLOBALFOCUS;
slouken@1895
   362
    } else {
slouken@1895
   363
        format.dwFlags |= DSBCAPS_STICKYFOCUS;
slouken@1895
   364
    }
slouken@1895
   365
    format.dwBufferBytes = numchunks * chunksize;
slouken@1895
   366
    if ((format.dwBufferBytes < DSBSIZE_MIN) ||
slouken@1895
   367
        (format.dwBufferBytes > DSBSIZE_MAX)) {
slouken@1895
   368
        SDL_SetError("Sound buffer size must be between %d and %d",
slouken@1895
   369
                     DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
slouken@1895
   370
        return (-1);
slouken@1895
   371
    }
slouken@1895
   372
    format.dwReserved = 0;
slouken@1895
   373
    format.lpwfxFormat = wavefmt;
slouken@1895
   374
    result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
slouken@1895
   375
    if (result != DS_OK) {
slouken@1895
   376
        SetDSerror("DirectSound CreateSoundBuffer", result);
slouken@1895
   377
        return (-1);
slouken@1895
   378
    }
slouken@1895
   379
    IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
slouken@0
   380
slouken@1895
   381
    /* Silence the initial audio buffer */
slouken@1895
   382
    result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
slouken@1895
   383
                                     (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
slouken@1895
   384
                                     (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
slouken@1895
   385
                                     DSBLOCK_ENTIREBUFFER);
slouken@1895
   386
    if (result == DS_OK) {
icculus@2049
   387
        SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
slouken@1895
   388
        IDirectSoundBuffer_Unlock(*sndbuf,
slouken@1895
   389
                                  (LPVOID) pvAudioPtr1, dwAudioBytes1,
slouken@1895
   390
                                  (LPVOID) pvAudioPtr2, dwAudioBytes2);
slouken@1895
   391
    }
slouken@118
   392
slouken@1895
   393
    /* We're ready to go */
slouken@1895
   394
    return (numchunks);
slouken@0
   395
}
slouken@0
   396
slouken@1895
   397
static int
icculus@2049
   398
DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
slouken@0
   399
{
slouken@1895
   400
    HRESULT result;
slouken@1895
   401
    WAVEFORMATEX waveformat;
icculus@2049
   402
    int valid_format = 0;
icculus@2049
   403
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
slouken@0
   404
icculus@2049
   405
    /* !!! FIXME: handle devname */
icculus@2049
   406
    /* !!! FIXME: handle iscapture */
icculus@2049
   407
icculus@2049
   408
    /* Initialize all variables that we clean on shutdown */
icculus@2049
   409
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2060
   410
        SDL_malloc((sizeof *this->hidden));
icculus@2049
   411
    if (this->hidden == NULL) {
icculus@2049
   412
        SDL_OutOfMemory();
icculus@2049
   413
        return 0;
icculus@2049
   414
    }
icculus@2049
   415
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
icculus@2049
   416
icculus@2049
   417
    while ((!valid_format) && (test_format)) {
icculus@2049
   418
        switch (test_format) {
slouken@2060
   419
        case AUDIO_U8:
slouken@2060
   420
        case AUDIO_S16:
slouken@2060
   421
        case AUDIO_S32:
slouken@2060
   422
            this->spec.format = test_format;
slouken@2060
   423
            valid_format = 1;
slouken@2060
   424
            break;
icculus@2049
   425
        }
icculus@2049
   426
        test_format = SDL_NextAudioFormat();
icculus@2049
   427
    }
icculus@2049
   428
icculus@2049
   429
    if (!valid_format) {
icculus@2049
   430
        DSOUND_CloseDevice(this);
icculus@2049
   431
        SDL_SetError("DirectSound: Unsupported audio format");
icculus@2049
   432
        return 0;
icculus@2049
   433
    }
icculus@2049
   434
slouken@1895
   435
    SDL_memset(&waveformat, 0, sizeof(waveformat));
slouken@1895
   436
    waveformat.wFormatTag = WAVE_FORMAT_PCM;
icculus@2049
   437
    waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
icculus@2049
   438
    waveformat.nChannels = this->spec.channels;
icculus@2049
   439
    waveformat.nSamplesPerSec = this->spec.freq;
slouken@1895
   440
    waveformat.nBlockAlign =
slouken@1895
   441
        waveformat.nChannels * (waveformat.wBitsPerSample / 8);
slouken@1895
   442
    waveformat.nAvgBytesPerSec =
slouken@1895
   443
        waveformat.nSamplesPerSec * waveformat.nBlockAlign;
slouken@0
   444
slouken@1895
   445
    /* Update the fragment size as size in bytes */
icculus@2049
   446
    SDL_CalculateAudioSpec(&this->spec);
slouken@0
   447
slouken@1895
   448
    /* Open the audio device */
icculus@2049
   449
    result = DSoundCreate(NULL, &this->hidden->sound, NULL);
slouken@1895
   450
    if (result != DS_OK) {
icculus@2049
   451
        DSOUND_CloseDevice(this);
slouken@1895
   452
        SetDSerror("DirectSoundCreate", result);
icculus@2049
   453
        return 0;
slouken@1895
   454
    }
slouken@0
   455
slouken@1895
   456
    /* Create the audio buffer to which we write */
icculus@2049
   457
    this->hidden->num_buffers = CreateSecondary(this, mainwin, &waveformat);
icculus@2049
   458
    if (this->hidden->num_buffers < 0) {
icculus@2049
   459
        DSOUND_CloseDevice(this);
icculus@2049
   460
        return 0;
slouken@1895
   461
    }
slouken@0
   462
icculus@2049
   463
    /* The buffer will auto-start playing in DSOUND_WaitDevice() */
icculus@2049
   464
    this->hidden->mixlen = this->spec.size;
slouken@0
   465
slouken@2060
   466
    return 1;                   /* good to go. */
slouken@0
   467
}
slouken@0
   468
icculus@2049
   469
icculus@2049
   470
static void
icculus@2049
   471
DSOUND_Deinitialize(void)
icculus@2049
   472
{
icculus@2049
   473
    DSOUND_Unload();
icculus@2049
   474
}
icculus@2049
   475
icculus@2049
   476
icculus@2049
   477
static int
slouken@2060
   478
DSOUND_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   479
{
icculus@2049
   480
    OSVERSIONINFO ver;
icculus@2049
   481
icculus@2049
   482
    /*
icculus@2049
   483
     * Unfortunately, the sound drivers on NT have higher latencies than the
icculus@2049
   484
     *  audio buffers used by many SDL applications, so there are gaps in the
icculus@2049
   485
     *  audio - it sounds terrible.  Punt for now.
icculus@2049
   486
     */
slouken@2060
   487
    SDL_memset(&ver, '\0', sizeof(OSVERSIONINFO));
icculus@2049
   488
    ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
icculus@2049
   489
    GetVersionEx(&ver);
icculus@2050
   490
    if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
icculus@2049
   491
        if (ver.dwMajorVersion <= 4) {
slouken@2060
   492
            return 0;           /* NT4.0 or earlier. Disable dsound support. */
icculus@2049
   493
        }
icculus@2049
   494
    }
icculus@2049
   495
icculus@2049
   496
    if (!DSOUND_Load()) {
icculus@2049
   497
        return 0;
icculus@2049
   498
    }
icculus@2049
   499
icculus@2049
   500
    /* Set the function pointers */
icculus@2049
   501
    impl->OpenDevice = DSOUND_OpenDevice;
icculus@2049
   502
    impl->PlayDevice = DSOUND_PlayDevice;
icculus@2049
   503
    impl->WaitDevice = DSOUND_WaitDevice;
icculus@2049
   504
    impl->WaitDone = DSOUND_WaitDone;
icculus@2049
   505
    impl->ThreadInit = DSOUND_ThreadInit;
icculus@2049
   506
    impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
icculus@2049
   507
    impl->CloseDevice = DSOUND_CloseDevice;
icculus@2049
   508
    impl->Deinitialize = DSOUND_Deinitialize;
slouken@2060
   509
    impl->OnlyHasDefaultOutputDevice = 1;       /* !!! FIXME */
icculus@2049
   510
icculus@2049
   511
    return 1;
icculus@2049
   512
}
icculus@2049
   513
icculus@2049
   514
AudioBootStrap DSOUND_bootstrap = {
icculus@2049
   515
    "dsound", WINDOWS_OS_NAME "DirectSound", DSOUND_Init, 0
icculus@2049
   516
};
icculus@2049
   517
slouken@1895
   518
/* vi: set ts=4 sw=4 expandtab: */