src/audio/windx5/SDL_dx5audio.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 28 May 2006 13:04:16 +0000
branchSDL-1.3
changeset 1662 782fd950bd46
parent 1402 d910939febfa
child 1668 4da1ee79c9af
permissions -rw-r--r--
Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API.

WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid.

The code is now run through a consistent indent format:
indent -i4 -nut -nsc -br -ce

The headers are being converted to automatically generate doxygen documentation.
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
slouken@0
    31
/* Define this if you want to use DirectX 6 DirectSoundNotify interface */
slouken@0
    32
//#define USE_POSITION_NOTIFY
slouken@0
    33
slouken@0
    34
/* DirectX function pointers for audio */
slouken@1662
    35
HRESULT (WINAPI * DSoundCreate) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
slouken@0
    36
slouken@0
    37
/* Audio driver functions */
slouken@1662
    38
static int DX5_OpenAudio (_THIS, SDL_AudioSpec * spec);
slouken@1662
    39
static void DX5_ThreadInit (_THIS);
slouken@1662
    40
static void DX5_WaitAudio_BusyWait (_THIS);
slouken@0
    41
#ifdef USE_POSITION_NOTIFY
slouken@1662
    42
static void DX6_WaitAudio_EventWait (_THIS);
slouken@0
    43
#endif
slouken@1662
    44
static void DX5_PlayAudio (_THIS);
slouken@1662
    45
static Uint8 *DX5_GetAudioBuf (_THIS);
slouken@1662
    46
static void DX5_WaitDone (_THIS);
slouken@1662
    47
static void DX5_CloseAudio (_THIS);
slouken@0
    48
slouken@0
    49
/* Audio driver bootstrap functions */
slouken@0
    50
slouken@1662
    51
static int
slouken@1662
    52
Audio_Available (void)
slouken@0
    53
{
slouken@1662
    54
    HINSTANCE DSoundDLL;
slouken@1662
    55
    int dsound_ok;
slouken@0
    56
slouken@1662
    57
    /* Version check DSOUND.DLL (Is DirectX okay?) */
slouken@1662
    58
    dsound_ok = 0;
slouken@1662
    59
    DSoundDLL = LoadLibrary (TEXT ("DSOUND.DLL"));
slouken@1662
    60
    if (DSoundDLL != NULL) {
slouken@1662
    61
        /* We just use basic DirectSound, we're okay */
slouken@1662
    62
        /* Yay! */
slouken@1662
    63
        /* Unfortunately, the sound drivers on NT have
slouken@1662
    64
           higher latencies than the audio buffers used
slouken@1662
    65
           by many SDL applications, so there are gaps
slouken@1662
    66
           in the audio - it sounds terrible.  Punt for now.
slouken@1662
    67
         */
slouken@1662
    68
        OSVERSIONINFO ver;
slouken@1662
    69
        ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
slouken@1662
    70
        GetVersionEx (&ver);
slouken@1662
    71
        switch (ver.dwPlatformId) {
slouken@1662
    72
        case VER_PLATFORM_WIN32_NT:
slouken@1662
    73
            if (ver.dwMajorVersion > 4) {
slouken@1662
    74
                /* Win2K */
slouken@1662
    75
                dsound_ok = 1;
slouken@1662
    76
            } else {
slouken@1662
    77
                /* WinNT */
slouken@1662
    78
                dsound_ok = 0;
slouken@1662
    79
            }
slouken@1662
    80
            break;
slouken@1662
    81
        default:
slouken@1662
    82
            /* Win95 or Win98 */
slouken@1662
    83
            dsound_ok = 1;
slouken@1662
    84
            break;
slouken@1662
    85
        }
slouken@1662
    86
        /* Now check for DirectX 5 or better - otherwise
slouken@1662
    87
         * we will fail later in DX5_OpenAudio without a chance
slouken@1662
    88
         * to fall back to the DIB driver. */
slouken@1662
    89
        if (dsound_ok) {
slouken@1662
    90
            /* DirectSoundCaptureCreate was added in DX5 */
slouken@1662
    91
            if (!GetProcAddress
slouken@1662
    92
                (DSoundDLL, TEXT ("DirectSoundCaptureCreate")))
slouken@1662
    93
                dsound_ok = 0;
slouken@0
    94
slouken@1662
    95
        }
slouken@1662
    96
        /* Clean up.. */
slouken@1662
    97
        FreeLibrary (DSoundDLL);
slouken@1662
    98
    }
slouken@1662
    99
    return (dsound_ok);
slouken@0
   100
}
slouken@0
   101
slouken@0
   102
/* Functions for loading the DirectX functions dynamically */
slouken@0
   103
static HINSTANCE DSoundDLL = NULL;
slouken@0
   104
slouken@1662
   105
static void
slouken@1662
   106
DX5_Unload (void)
slouken@0
   107
{
slouken@1662
   108
    if (DSoundDLL != NULL) {
slouken@1662
   109
        FreeLibrary (DSoundDLL);
slouken@1662
   110
        DSoundCreate = NULL;
slouken@1662
   111
        DSoundDLL = NULL;
slouken@1662
   112
    }
slouken@0
   113
}
slouken@1662
   114
static int
slouken@1662
   115
DX5_Load (void)
slouken@0
   116
{
slouken@1662
   117
    int status;
slouken@0
   118
slouken@1662
   119
    DX5_Unload ();
slouken@1662
   120
    DSoundDLL = LoadLibrary (TEXT ("DSOUND.DLL"));
slouken@1662
   121
    if (DSoundDLL != NULL) {
slouken@1662
   122
        DSoundCreate = (void *) GetProcAddress (DSoundDLL,
slouken@1662
   123
                                                TEXT ("DirectSoundCreate"));
slouken@1662
   124
    }
slouken@1662
   125
    if (DSoundDLL && DSoundCreate) {
slouken@1662
   126
        status = 0;
slouken@1662
   127
    } else {
slouken@1662
   128
        DX5_Unload ();
slouken@1662
   129
        status = -1;
slouken@1662
   130
    }
slouken@1662
   131
    return status;
slouken@0
   132
}
slouken@0
   133
slouken@1662
   134
static void
slouken@1662
   135
Audio_DeleteDevice (SDL_AudioDevice * device)
slouken@0
   136
{
slouken@1662
   137
    DX5_Unload ();
slouken@1662
   138
    SDL_free (device->hidden);
slouken@1662
   139
    SDL_free (device);
slouken@0
   140
}
slouken@0
   141
slouken@1662
   142
static SDL_AudioDevice *
slouken@1662
   143
Audio_CreateDevice (int devindex)
slouken@0
   144
{
slouken@1662
   145
    SDL_AudioDevice *this;
slouken@0
   146
slouken@1662
   147
    /* Load DirectX */
slouken@1662
   148
    if (DX5_Load () < 0) {
slouken@1662
   149
        return (NULL);
slouken@1662
   150
    }
slouken@0
   151
slouken@1662
   152
    /* Initialize all variables that we clean on shutdown */
slouken@1662
   153
    this = (SDL_AudioDevice *) SDL_malloc (sizeof (SDL_AudioDevice));
slouken@1662
   154
    if (this) {
slouken@1662
   155
        SDL_memset (this, 0, (sizeof *this));
slouken@1662
   156
        this->hidden = (struct SDL_PrivateAudioData *)
slouken@1662
   157
            SDL_malloc ((sizeof *this->hidden));
slouken@1662
   158
    }
slouken@1662
   159
    if ((this == NULL) || (this->hidden == NULL)) {
slouken@1662
   160
        SDL_OutOfMemory ();
slouken@1662
   161
        if (this) {
slouken@1662
   162
            SDL_free (this);
slouken@1662
   163
        }
slouken@1662
   164
        return (0);
slouken@1662
   165
    }
slouken@1662
   166
    SDL_memset (this->hidden, 0, (sizeof *this->hidden));
slouken@0
   167
slouken@1662
   168
    /* Set the function pointers */
slouken@1662
   169
    this->OpenAudio = DX5_OpenAudio;
slouken@1662
   170
    this->ThreadInit = DX5_ThreadInit;
slouken@1662
   171
    this->WaitAudio = DX5_WaitAudio_BusyWait;
slouken@1662
   172
    this->PlayAudio = DX5_PlayAudio;
slouken@1662
   173
    this->GetAudioBuf = DX5_GetAudioBuf;
slouken@1662
   174
    this->WaitDone = DX5_WaitDone;
slouken@1662
   175
    this->CloseAudio = DX5_CloseAudio;
slouken@0
   176
slouken@1662
   177
    this->free = Audio_DeleteDevice;
slouken@0
   178
slouken@1662
   179
    return this;
slouken@0
   180
}
slouken@0
   181
slouken@0
   182
AudioBootStrap DSOUND_bootstrap = {
slouken@1662
   183
    "dsound", "Win95/98/2000 DirectSound",
slouken@1662
   184
    Audio_Available, Audio_CreateDevice
slouken@0
   185
};
slouken@0
   186
slouken@1662
   187
static void
slouken@1662
   188
SetDSerror (const char *function, int code)
slouken@0
   189
{
slouken@1662
   190
    static const char *error;
slouken@1662
   191
    static char errbuf[1024];
slouken@0
   192
slouken@1662
   193
    errbuf[0] = 0;
slouken@1662
   194
    switch (code) {
slouken@1662
   195
    case E_NOINTERFACE:
slouken@1662
   196
        error =
slouken@1662
   197
            "Unsupported interface\n-- Is DirectX 5.0 or later installed?";
slouken@1662
   198
        break;
slouken@1662
   199
    case DSERR_ALLOCATED:
slouken@1662
   200
        error = "Audio device in use";
slouken@1662
   201
        break;
slouken@1662
   202
    case DSERR_BADFORMAT:
slouken@1662
   203
        error = "Unsupported audio format";
slouken@1662
   204
        break;
slouken@1662
   205
    case DSERR_BUFFERLOST:
slouken@1662
   206
        error = "Mixing buffer was lost";
slouken@1662
   207
        break;
slouken@1662
   208
    case DSERR_CONTROLUNAVAIL:
slouken@1662
   209
        error = "Control requested is not available";
slouken@1662
   210
        break;
slouken@1662
   211
    case DSERR_INVALIDCALL:
slouken@1662
   212
        error = "Invalid call for the current state";
slouken@1662
   213
        break;
slouken@1662
   214
    case DSERR_INVALIDPARAM:
slouken@1662
   215
        error = "Invalid parameter";
slouken@1662
   216
        break;
slouken@1662
   217
    case DSERR_NODRIVER:
slouken@1662
   218
        error = "No audio device found";
slouken@1662
   219
        break;
slouken@1662
   220
    case DSERR_OUTOFMEMORY:
slouken@1662
   221
        error = "Out of memory";
slouken@1662
   222
        break;
slouken@1662
   223
    case DSERR_PRIOLEVELNEEDED:
slouken@1662
   224
        error = "Caller doesn't have priority";
slouken@1662
   225
        break;
slouken@1662
   226
    case DSERR_UNSUPPORTED:
slouken@1662
   227
        error = "Function not supported";
slouken@1662
   228
        break;
slouken@1662
   229
    default:
slouken@1662
   230
        SDL_snprintf (errbuf, SDL_arraysize (errbuf),
slouken@1662
   231
                      "%s: Unknown DirectSound error: 0x%x", function, code);
slouken@1662
   232
        break;
slouken@1662
   233
    }
slouken@1662
   234
    if (!errbuf[0]) {
slouken@1662
   235
        SDL_snprintf (errbuf, SDL_arraysize (errbuf), "%s: %s", function,
slouken@1662
   236
                      error);
slouken@1662
   237
    }
slouken@1662
   238
    SDL_SetError ("%s", errbuf);
slouken@1662
   239
    return;
slouken@0
   240
}
slouken@0
   241
slouken@0
   242
/* DirectSound needs to be associated with a window */
slouken@0
   243
static HWND mainwin = NULL;
slouken@0
   244
/* */
slouken@1662
   245
void
slouken@1662
   246
DX5_SoundFocus (HWND hwnd)
slouken@0
   247
{
slouken@1662
   248
    mainwin = hwnd;
slouken@0
   249
}
slouken@0
   250
slouken@1662
   251
static void
slouken@1662
   252
DX5_ThreadInit (_THIS)
slouken@0
   253
{
slouken@1662
   254
    SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
slouken@0
   255
}
slouken@0
   256
slouken@1662
   257
static void
slouken@1662
   258
DX5_WaitAudio_BusyWait (_THIS)
slouken@0
   259
{
slouken@1662
   260
    DWORD status;
slouken@1662
   261
    DWORD cursor, junk;
slouken@1662
   262
    HRESULT result;
slouken@0
   263
slouken@1662
   264
    /* Semi-busy wait, since we have no way of getting play notification
slouken@1662
   265
       on a primary mixing buffer located in hardware (DirectX 5.0)
slouken@1662
   266
     */
slouken@1662
   267
    result = IDirectSoundBuffer_GetCurrentPosition (mixbuf, &cursor, &junk);
slouken@1662
   268
    if (result != DS_OK) {
slouken@1662
   269
        if (result == DSERR_BUFFERLOST) {
slouken@1662
   270
            IDirectSoundBuffer_Restore (mixbuf);
slouken@1662
   271
        }
slouken@0
   272
#ifdef DEBUG_SOUND
slouken@1662
   273
        SetDSerror ("DirectSound GetCurrentPosition", result);
slouken@0
   274
#endif
slouken@1662
   275
        return;
slouken@1662
   276
    }
slouken@1662
   277
    cursor /= mixlen;
slouken@0
   278
slouken@1662
   279
    while (cursor == playing) {
slouken@1662
   280
        /* FIXME: find out how much time is left and sleep that long */
slouken@1662
   281
        SDL_Delay (10);
slouken@0
   282
slouken@1662
   283
        /* Try to restore a lost sound buffer */
slouken@1662
   284
        IDirectSoundBuffer_GetStatus (mixbuf, &status);
slouken@1662
   285
        if ((status & DSBSTATUS_BUFFERLOST)) {
slouken@1662
   286
            IDirectSoundBuffer_Restore (mixbuf);
slouken@1662
   287
            IDirectSoundBuffer_GetStatus (mixbuf, &status);
slouken@1662
   288
            if ((status & DSBSTATUS_BUFFERLOST)) {
slouken@1662
   289
                break;
slouken@1662
   290
            }
slouken@1662
   291
        }
slouken@1662
   292
        if (!(status & DSBSTATUS_PLAYING)) {
slouken@1662
   293
            result = IDirectSoundBuffer_Play (mixbuf, 0, 0, DSBPLAY_LOOPING);
slouken@1662
   294
            if (result == DS_OK) {
slouken@1662
   295
                continue;
slouken@1662
   296
            }
slouken@0
   297
#ifdef DEBUG_SOUND
slouken@1662
   298
            SetDSerror ("DirectSound Play", result);
slouken@0
   299
#endif
slouken@1662
   300
            return;
slouken@1662
   301
        }
slouken@0
   302
slouken@1662
   303
        /* Find out where we are playing */
slouken@1662
   304
        result = IDirectSoundBuffer_GetCurrentPosition (mixbuf,
slouken@1662
   305
                                                        &cursor, &junk);
slouken@1662
   306
        if (result != DS_OK) {
slouken@1662
   307
            SetDSerror ("DirectSound GetCurrentPosition", result);
slouken@1662
   308
            return;
slouken@1662
   309
        }
slouken@1662
   310
        cursor /= mixlen;
slouken@1662
   311
    }
slouken@0
   312
}
slouken@0
   313
slouken@0
   314
#ifdef USE_POSITION_NOTIFY
slouken@1662
   315
static void
slouken@1662
   316
DX6_WaitAudio_EventWait (_THIS)
slouken@0
   317
{
slouken@1662
   318
    DWORD status;
slouken@1662
   319
    HRESULT result;
slouken@0
   320
slouken@1662
   321
    /* Try to restore a lost sound buffer */
slouken@1662
   322
    IDirectSoundBuffer_GetStatus (mixbuf, &status);
slouken@1662
   323
    if ((status & DSBSTATUS_BUFFERLOST)) {
slouken@1662
   324
        IDirectSoundBuffer_Restore (mixbuf);
slouken@1662
   325
        IDirectSoundBuffer_GetStatus (mixbuf, &status);
slouken@1662
   326
        if ((status & DSBSTATUS_BUFFERLOST)) {
slouken@1662
   327
            return;
slouken@1662
   328
        }
slouken@1662
   329
    }
slouken@1662
   330
    if (!(status & DSBSTATUS_PLAYING)) {
slouken@1662
   331
        result = IDirectSoundBuffer_Play (mixbuf, 0, 0, DSBPLAY_LOOPING);
slouken@1662
   332
        if (result != DS_OK) {
slouken@0
   333
#ifdef DEBUG_SOUND
slouken@1662
   334
            SetDSerror ("DirectSound Play", result);
slouken@0
   335
#endif
slouken@1662
   336
            return;
slouken@1662
   337
        }
slouken@1662
   338
    }
slouken@1662
   339
    WaitForSingleObject (audio_event, INFINITE);
slouken@0
   340
}
slouken@0
   341
#endif /* USE_POSITION_NOTIFY */
slouken@0
   342
slouken@1662
   343
static void
slouken@1662
   344
DX5_PlayAudio (_THIS)
slouken@0
   345
{
slouken@1662
   346
    /* Unlock the buffer, allowing it to play */
slouken@1662
   347
    if (locked_buf) {
slouken@1662
   348
        IDirectSoundBuffer_Unlock (mixbuf, locked_buf, mixlen, NULL, 0);
slouken@1662
   349
    }
slouken@0
   350
slouken@0
   351
}
slouken@0
   352
slouken@1662
   353
static Uint8 *
slouken@1662
   354
DX5_GetAudioBuf (_THIS)
slouken@0
   355
{
slouken@1662
   356
    DWORD cursor, junk;
slouken@1662
   357
    HRESULT result;
slouken@1662
   358
    DWORD rawlen;
slouken@0
   359
slouken@1662
   360
    /* Figure out which blocks to fill next */
slouken@1662
   361
    locked_buf = NULL;
slouken@1662
   362
    result = IDirectSoundBuffer_GetCurrentPosition (mixbuf, &cursor, &junk);
slouken@1662
   363
    if (result == DSERR_BUFFERLOST) {
slouken@1662
   364
        IDirectSoundBuffer_Restore (mixbuf);
slouken@1662
   365
        result = IDirectSoundBuffer_GetCurrentPosition (mixbuf,
slouken@1662
   366
                                                        &cursor, &junk);
slouken@1662
   367
    }
slouken@1662
   368
    if (result != DS_OK) {
slouken@1662
   369
        SetDSerror ("DirectSound GetCurrentPosition", result);
slouken@1662
   370
        return (NULL);
slouken@1662
   371
    }
slouken@1662
   372
    cursor /= mixlen;
slouken@1662
   373
    playing = cursor;
slouken@1662
   374
    cursor = (cursor + 1) % NUM_BUFFERS;
slouken@1662
   375
    cursor *= mixlen;
slouken@0
   376
slouken@1662
   377
    /* Lock the audio buffer */
slouken@1662
   378
    result = IDirectSoundBuffer_Lock (mixbuf, cursor, mixlen,
slouken@1662
   379
                                      (LPVOID *) & locked_buf, &rawlen, NULL,
slouken@1662
   380
                                      &junk, 0);
slouken@1662
   381
    if (result == DSERR_BUFFERLOST) {
slouken@1662
   382
        IDirectSoundBuffer_Restore (mixbuf);
slouken@1662
   383
        result = IDirectSoundBuffer_Lock (mixbuf, cursor, mixlen,
slouken@1662
   384
                                          (LPVOID *) & locked_buf, &rawlen,
slouken@1662
   385
                                          NULL, &junk, 0);
slouken@1662
   386
    }
slouken@1662
   387
    if (result != DS_OK) {
slouken@1662
   388
        SetDSerror ("DirectSound Lock", result);
slouken@1662
   389
        return (NULL);
slouken@1662
   390
    }
slouken@1662
   391
    return (locked_buf);
slouken@0
   392
}
slouken@0
   393
slouken@1662
   394
static void
slouken@1662
   395
DX5_WaitDone (_THIS)
slouken@0
   396
{
slouken@1662
   397
    Uint8 *stream;
slouken@0
   398
slouken@1662
   399
    /* Wait for the playing chunk to finish */
slouken@1662
   400
    stream = this->GetAudioBuf (this);
slouken@1662
   401
    if (stream != NULL) {
slouken@1662
   402
        SDL_memset (stream, silence, mixlen);
slouken@1662
   403
        this->PlayAudio (this);
slouken@1662
   404
    }
slouken@1662
   405
    this->WaitAudio (this);
slouken@0
   406
slouken@1662
   407
    /* Stop the looping sound buffer */
slouken@1662
   408
    IDirectSoundBuffer_Stop (mixbuf);
slouken@0
   409
}
slouken@0
   410
slouken@1662
   411
static void
slouken@1662
   412
DX5_CloseAudio (_THIS)
slouken@0
   413
{
slouken@1662
   414
    if (sound != NULL) {
slouken@1662
   415
        if (mixbuf != NULL) {
slouken@1662
   416
            /* Clean up the audio buffer */
slouken@1662
   417
            IDirectSoundBuffer_Release (mixbuf);
slouken@1662
   418
            mixbuf = NULL;
slouken@1662
   419
        }
slouken@1662
   420
        if (audio_event != NULL) {
slouken@1662
   421
            CloseHandle (audio_event);
slouken@1662
   422
            audio_event = NULL;
slouken@1662
   423
        }
slouken@1662
   424
        IDirectSound_Release (sound);
slouken@1662
   425
        sound = NULL;
slouken@1662
   426
    }
slouken@0
   427
}
slouken@0
   428
slouken@469
   429
#ifdef USE_PRIMARY_BUFFER
slouken@0
   430
/* This function tries to create a primary audio buffer, and returns the
slouken@0
   431
   number of audio chunks available in the created buffer.
slouken@0
   432
*/
slouken@1662
   433
static int
slouken@1662
   434
CreatePrimary (LPDIRECTSOUND sndObj, HWND focus,
slouken@1662
   435
               LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
slouken@1662
   436
               Uint32 chunksize)
slouken@0
   437
{
slouken@1662
   438
    HRESULT result;
slouken@1662
   439
    DSBUFFERDESC format;
slouken@1662
   440
    DSBCAPS caps;
slouken@1662
   441
    int numchunks;
slouken@0
   442
slouken@1662
   443
    /* Try to set primary mixing privileges */
slouken@1662
   444
    result = IDirectSound_SetCooperativeLevel (sndObj, focus,
slouken@1662
   445
                                               DSSCL_WRITEPRIMARY);
slouken@1662
   446
    if (result != DS_OK) {
slouken@0
   447
#ifdef DEBUG_SOUND
slouken@1662
   448
        SetDSerror ("DirectSound SetCooperativeLevel", result);
slouken@0
   449
#endif
slouken@1662
   450
        return (-1);
slouken@1662
   451
    }
slouken@0
   452
slouken@1662
   453
    /* Try to create the primary buffer */
slouken@1662
   454
    SDL_memset (&format, 0, sizeof (format));
slouken@1662
   455
    format.dwSize = sizeof (format);
slouken@1662
   456
    format.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2);
slouken@1662
   457
    format.dwFlags |= DSBCAPS_STICKYFOCUS;
slouken@0
   458
#ifdef USE_POSITION_NOTIFY
slouken@1662
   459
    format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
slouken@0
   460
#endif
slouken@1662
   461
    result = IDirectSound_CreateSoundBuffer (sndObj, &format, sndbuf, NULL);
slouken@1662
   462
    if (result != DS_OK) {
slouken@0
   463
#ifdef DEBUG_SOUND
slouken@1662
   464
        SetDSerror ("DirectSound CreateSoundBuffer", result);
slouken@0
   465
#endif
slouken@1662
   466
        return (-1);
slouken@1662
   467
    }
slouken@0
   468
slouken@1662
   469
    /* Check the size of the fragment buffer */
slouken@1662
   470
    SDL_memset (&caps, 0, sizeof (caps));
slouken@1662
   471
    caps.dwSize = sizeof (caps);
slouken@1662
   472
    result = IDirectSoundBuffer_GetCaps (*sndbuf, &caps);
slouken@1662
   473
    if (result != DS_OK) {
slouken@0
   474
#ifdef DEBUG_SOUND
slouken@1662
   475
        SetDSerror ("DirectSound GetCaps", result);
slouken@0
   476
#endif
slouken@1662
   477
        IDirectSoundBuffer_Release (*sndbuf);
slouken@1662
   478
        return (-1);
slouken@1662
   479
    }
slouken@1662
   480
    if ((chunksize > caps.dwBufferBytes) ||
slouken@1662
   481
        ((caps.dwBufferBytes % chunksize) != 0)) {
slouken@1662
   482
        /* The primary buffer size is not a multiple of 'chunksize'
slouken@1662
   483
           -- this hopefully doesn't happen when 'chunksize' is a 
slouken@1662
   484
           power of 2.
slouken@1662
   485
         */
slouken@1662
   486
        IDirectSoundBuffer_Release (*sndbuf);
slouken@1662
   487
        SDL_SetError
slouken@1662
   488
            ("Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
slouken@1662
   489
             caps.dwBufferBytes, chunksize);
slouken@1662
   490
        return (-1);
slouken@1662
   491
    }
slouken@1662
   492
    numchunks = (caps.dwBufferBytes / chunksize);
slouken@0
   493
slouken@1662
   494
    /* Set the primary audio format */
slouken@1662
   495
    result = IDirectSoundBuffer_SetFormat (*sndbuf, wavefmt);
slouken@1662
   496
    if (result != DS_OK) {
slouken@0
   497
#ifdef DEBUG_SOUND
slouken@1662
   498
        SetDSerror ("DirectSound SetFormat", result);
slouken@0
   499
#endif
slouken@1662
   500
        IDirectSoundBuffer_Release (*sndbuf);
slouken@1662
   501
        return (-1);
slouken@1662
   502
    }
slouken@1662
   503
    return (numchunks);
slouken@0
   504
}
slouken@469
   505
#endif /* USE_PRIMARY_BUFFER */
slouken@0
   506
slouken@0
   507
/* This function tries to create a secondary audio buffer, and returns the
slouken@0
   508
   number of audio chunks available in the created buffer.
slouken@0
   509
*/
slouken@1662
   510
static int
slouken@1662
   511
CreateSecondary (LPDIRECTSOUND sndObj, HWND focus,
slouken@1662
   512
                 LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
slouken@1662
   513
                 Uint32 chunksize)
slouken@0
   514
{
slouken@1662
   515
    const int numchunks = 2;
slouken@1662
   516
    HRESULT result;
slouken@1662
   517
    DSBUFFERDESC format;
slouken@1662
   518
    LPVOID pvAudioPtr1, pvAudioPtr2;
slouken@1662
   519
    DWORD dwAudioBytes1, dwAudioBytes2;
slouken@0
   520
slouken@1662
   521
    /* Try to set primary mixing privileges */
slouken@1662
   522
    if (focus) {
slouken@1662
   523
        result = IDirectSound_SetCooperativeLevel (sndObj,
slouken@1662
   524
                                                   focus, DSSCL_PRIORITY);
slouken@1662
   525
    } else {
slouken@1662
   526
        result = IDirectSound_SetCooperativeLevel (sndObj,
slouken@1662
   527
                                                   GetDesktopWindow (),
slouken@1662
   528
                                                   DSSCL_NORMAL);
slouken@1662
   529
    }
slouken@1662
   530
    if (result != DS_OK) {
slouken@0
   531
#ifdef DEBUG_SOUND
slouken@1662
   532
        SetDSerror ("DirectSound SetCooperativeLevel", result);
slouken@0
   533
#endif
slouken@1662
   534
        return (-1);
slouken@1662
   535
    }
slouken@0
   536
slouken@1662
   537
    /* Try to create the secondary buffer */
slouken@1662
   538
    SDL_memset (&format, 0, sizeof (format));
slouken@1662
   539
    format.dwSize = sizeof (format);
slouken@1662
   540
    format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
slouken@0
   541
#ifdef USE_POSITION_NOTIFY
slouken@1662
   542
    format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
slouken@0
   543
#endif
slouken@1662
   544
    if (!focus) {
slouken@1662
   545
        format.dwFlags |= DSBCAPS_GLOBALFOCUS;
slouken@1662
   546
    } else {
slouken@1662
   547
        format.dwFlags |= DSBCAPS_STICKYFOCUS;
slouken@1662
   548
    }
slouken@1662
   549
    format.dwBufferBytes = numchunks * chunksize;
slouken@1662
   550
    if ((format.dwBufferBytes < DSBSIZE_MIN) ||
slouken@1662
   551
        (format.dwBufferBytes > DSBSIZE_MAX)) {
slouken@1662
   552
        SDL_SetError ("Sound buffer size must be between %d and %d",
slouken@1662
   553
                      DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
slouken@1662
   554
        return (-1);
slouken@1662
   555
    }
slouken@1662
   556
    format.dwReserved = 0;
slouken@1662
   557
    format.lpwfxFormat = wavefmt;
slouken@1662
   558
    result = IDirectSound_CreateSoundBuffer (sndObj, &format, sndbuf, NULL);
slouken@1662
   559
    if (result != DS_OK) {
slouken@1662
   560
        SetDSerror ("DirectSound CreateSoundBuffer", result);
slouken@1662
   561
        return (-1);
slouken@1662
   562
    }
slouken@1662
   563
    IDirectSoundBuffer_SetFormat (*sndbuf, wavefmt);
slouken@0
   564
slouken@1662
   565
    /* Silence the initial audio buffer */
slouken@1662
   566
    result = IDirectSoundBuffer_Lock (*sndbuf, 0, format.dwBufferBytes,
slouken@1662
   567
                                      (LPVOID *) & pvAudioPtr1,
slouken@1662
   568
                                      &dwAudioBytes1,
slouken@1662
   569
                                      (LPVOID *) & pvAudioPtr2,
slouken@1662
   570
                                      &dwAudioBytes2, DSBLOCK_ENTIREBUFFER);
slouken@1662
   571
    if (result == DS_OK) {
slouken@1662
   572
        if (wavefmt->wBitsPerSample == 8) {
slouken@1662
   573
            SDL_memset (pvAudioPtr1, 0x80, dwAudioBytes1);
slouken@1662
   574
        } else {
slouken@1662
   575
            SDL_memset (pvAudioPtr1, 0x00, dwAudioBytes1);
slouken@1662
   576
        }
slouken@1662
   577
        IDirectSoundBuffer_Unlock (*sndbuf,
slouken@1662
   578
                                   (LPVOID) pvAudioPtr1, dwAudioBytes1,
slouken@1662
   579
                                   (LPVOID) pvAudioPtr2, dwAudioBytes2);
slouken@1662
   580
    }
slouken@118
   581
slouken@1662
   582
    /* We're ready to go */
slouken@1662
   583
    return (numchunks);
slouken@0
   584
}
slouken@0
   585
slouken@0
   586
/* This function tries to set position notify events on the mixing buffer */
slouken@0
   587
#ifdef USE_POSITION_NOTIFY
slouken@1662
   588
static int
slouken@1662
   589
CreateAudioEvent (_THIS)
slouken@0
   590
{
slouken@1662
   591
    LPDIRECTSOUNDNOTIFY notify;
slouken@1662
   592
    DSBPOSITIONNOTIFY *notify_positions;
slouken@1662
   593
    int i, retval;
slouken@1662
   594
    HRESULT result;
slouken@0
   595
slouken@1662
   596
    /* Default to fail on exit */
slouken@1662
   597
    retval = -1;
slouken@1662
   598
    notify = NULL;
slouken@0
   599
slouken@1662
   600
    /* Query for the interface */
slouken@1662
   601
    result = IDirectSoundBuffer_QueryInterface (mixbuf,
slouken@1662
   602
                                                &IID_IDirectSoundNotify,
slouken@1662
   603
                                                (void *) &notify);
slouken@1662
   604
    if (result != DS_OK) {
slouken@1662
   605
        goto done;
slouken@1662
   606
    }
slouken@0
   607
slouken@1662
   608
    /* Allocate the notify structures */
slouken@1662
   609
    notify_positions = (DSBPOSITIONNOTIFY *) SDL_malloc (NUM_BUFFERS *
slouken@1662
   610
                                                         sizeof
slouken@1662
   611
                                                         (*notify_positions));
slouken@1662
   612
    if (notify_positions == NULL) {
slouken@1662
   613
        goto done;
slouken@1662
   614
    }
slouken@0
   615
slouken@1662
   616
    /* Create the notify event */
slouken@1662
   617
    audio_event = CreateEvent (NULL, FALSE, FALSE, NULL);
slouken@1662
   618
    if (audio_event == NULL) {
slouken@1662
   619
        goto done;
slouken@1662
   620
    }
slouken@0
   621
slouken@1662
   622
    /* Set up the notify structures */
slouken@1662
   623
    for (i = 0; i < NUM_BUFFERS; ++i) {
slouken@1662
   624
        notify_positions[i].dwOffset = i * mixlen;
slouken@1662
   625
        notify_positions[i].hEventNotify = audio_event;
slouken@1662
   626
    }
slouken@1662
   627
    result = IDirectSoundNotify_SetNotificationPositions (notify,
slouken@1662
   628
                                                          NUM_BUFFERS,
slouken@1662
   629
                                                          notify_positions);
slouken@1662
   630
    if (result == DS_OK) {
slouken@1662
   631
        retval = 0;
slouken@1662
   632
    }
slouken@1662
   633
  done:
slouken@1662
   634
    if (notify != NULL) {
slouken@1662
   635
        IDirectSoundNotify_Release (notify);
slouken@1662
   636
    }
slouken@1662
   637
    return (retval);
slouken@0
   638
}
slouken@0
   639
#endif /* USE_POSITION_NOTIFY */
slouken@0
   640
slouken@1662
   641
static int
slouken@1662
   642
DX5_OpenAudio (_THIS, SDL_AudioSpec * spec)
slouken@0
   643
{
slouken@1662
   644
    HRESULT result;
slouken@1662
   645
    WAVEFORMATEX waveformat;
slouken@0
   646
slouken@1662
   647
    /* Set basic WAVE format parameters */
slouken@1662
   648
    SDL_memset (&waveformat, 0, sizeof (waveformat));
slouken@1662
   649
    waveformat.wFormatTag = WAVE_FORMAT_PCM;
slouken@0
   650
slouken@1662
   651
    /* Determine the audio parameters from the AudioSpec */
slouken@1662
   652
    switch (spec->format & 0xFF) {
slouken@1662
   653
    case 8:
slouken@1662
   654
        /* Unsigned 8 bit audio data */
slouken@1662
   655
        spec->format = AUDIO_U8;
slouken@1662
   656
        silence = 0x80;
slouken@1662
   657
        waveformat.wBitsPerSample = 8;
slouken@1662
   658
        break;
slouken@1662
   659
    case 16:
slouken@1662
   660
        /* Signed 16 bit audio data */
slouken@1662
   661
        spec->format = AUDIO_S16;
slouken@1662
   662
        silence = 0x00;
slouken@1662
   663
        waveformat.wBitsPerSample = 16;
slouken@1662
   664
        break;
slouken@1662
   665
    default:
slouken@1662
   666
        SDL_SetError ("Unsupported audio format");
slouken@1662
   667
        return (-1);
slouken@1662
   668
    }
slouken@1662
   669
    waveformat.nChannels = spec->channels;
slouken@1662
   670
    waveformat.nSamplesPerSec = spec->freq;
slouken@1662
   671
    waveformat.nBlockAlign =
slouken@1662
   672
        waveformat.nChannels * (waveformat.wBitsPerSample / 8);
slouken@1662
   673
    waveformat.nAvgBytesPerSec =
slouken@1662
   674
        waveformat.nSamplesPerSec * waveformat.nBlockAlign;
slouken@0
   675
slouken@1662
   676
    /* Update the fragment size as size in bytes */
slouken@1662
   677
    SDL_CalculateAudioSpec (spec);
slouken@0
   678
slouken@1662
   679
    /* Open the audio device */
slouken@1662
   680
    result = DSoundCreate (NULL, &sound, NULL);
slouken@1662
   681
    if (result != DS_OK) {
slouken@1662
   682
        SetDSerror ("DirectSoundCreate", result);
slouken@1662
   683
        return (-1);
slouken@1662
   684
    }
slouken@0
   685
slouken@1662
   686
    /* Create the audio buffer to which we write */
slouken@1662
   687
    NUM_BUFFERS = -1;
slouken@375
   688
#ifdef USE_PRIMARY_BUFFER
slouken@1662
   689
    if (mainwin) {
slouken@1662
   690
        NUM_BUFFERS = CreatePrimary (sound, mainwin, &mixbuf,
slouken@1662
   691
                                     &waveformat, spec->size);
slouken@1662
   692
    }
slouken@375
   693
#endif /* USE_PRIMARY_BUFFER */
slouken@1662
   694
    if (NUM_BUFFERS < 0) {
slouken@1662
   695
        NUM_BUFFERS = CreateSecondary (sound, mainwin, &mixbuf,
slouken@1662
   696
                                       &waveformat, spec->size);
slouken@1662
   697
        if (NUM_BUFFERS < 0) {
slouken@1662
   698
            return (-1);
slouken@1662
   699
        }
slouken@0
   700
#ifdef DEBUG_SOUND
slouken@1662
   701
        fprintf (stderr, "Using secondary audio buffer\n");
slouken@0
   702
#endif
slouken@1662
   703
    }
slouken@0
   704
#ifdef DEBUG_SOUND
slouken@1662
   705
    else
slouken@1662
   706
        fprintf (stderr, "Using primary audio buffer\n");
slouken@0
   707
#endif
slouken@0
   708
slouken@1662
   709
    /* The buffer will auto-start playing in DX5_WaitAudio() */
slouken@1662
   710
    playing = 0;
slouken@1662
   711
    mixlen = spec->size;
slouken@0
   712
slouken@0
   713
#ifdef USE_POSITION_NOTIFY
slouken@1662
   714
    /* See if we can use DirectX 6 event notification */
slouken@1662
   715
    if (CreateAudioEvent (this) == 0) {
slouken@1662
   716
        this->WaitAudio = DX6_WaitAudio_EventWait;
slouken@1662
   717
    } else {
slouken@1662
   718
        this->WaitAudio = DX5_WaitAudio_BusyWait;
slouken@1662
   719
    }
slouken@0
   720
#endif
slouken@1662
   721
    return (0);
slouken@0
   722
}
slouken@0
   723
slouken@1662
   724
/* vi: set ts=4 sw=4 expandtab: */