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