src/audio/windib/SDL_dibaudio.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. Audio_Available
  2. Audio_DeleteDevice
  3. Audio_CreateDevice
  4. FillSound
  5. SetMMerror
  6. DIB_ThreadInit
  7. DIB_WaitAudio
  8. DIB_GetAudioBuf
  9. DIB_PlayAudio
  10. DIB_WaitDone
  11. DIB_CloseAudio
  12. DIB_OpenAudio

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_dibaudio.c,v 1.1.2.2 2001/02/10 07:20:03 hercules Exp $";
  26 #endif
  27 
  28 /* Allow access to a raw mixing buffer */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <windows.h>
  33 #include <mmsystem.h>
  34 
  35 #include "SDL_audio.h"
  36 #include "SDL_mutex.h"
  37 #include "SDL_timer.h"
  38 #include "SDL_audio_c.h"
  39 #include "SDL_dibaudio.h"
  40 
  41 
  42 /* Audio driver functions */
  43 static int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec);
  44 static void DIB_ThreadInit(_THIS);
  45 static void DIB_WaitAudio(_THIS);
  46 static Uint8 *DIB_GetAudioBuf(_THIS);
  47 static void DIB_PlayAudio(_THIS);
  48 static void DIB_WaitDone(_THIS);
  49 static void DIB_CloseAudio(_THIS);
  50 
  51 /* Audio driver bootstrap functions */
  52 
  53 static int Audio_Available(void)
     /* [<][>][^][v][top][bottom][index][help] */
  54 {
  55         return(1);
  56 }
  57 
  58 static void Audio_DeleteDevice(SDL_AudioDevice *device)
     /* [<][>][^][v][top][bottom][index][help] */
  59 {
  60         free(device->hidden);
  61         free(device);
  62 }
  63 
  64 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66         SDL_AudioDevice *this;
  67 
  68         /* Initialize all variables that we clean on shutdown */
  69         this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
  70         if ( this ) {
  71                 memset(this, 0, (sizeof *this));
  72                 this->hidden = (struct SDL_PrivateAudioData *)
  73                                 malloc((sizeof *this->hidden));
  74         }
  75         if ( (this == NULL) || (this->hidden == NULL) ) {
  76                 SDL_OutOfMemory();
  77                 if ( this ) {
  78                         free(this);
  79                 }
  80                 return(0);
  81         }
  82         memset(this->hidden, 0, (sizeof *this->hidden));
  83 
  84         /* Set the function pointers */
  85         this->OpenAudio = DIB_OpenAudio;
  86         this->ThreadInit = DIB_ThreadInit;
  87         this->WaitAudio = DIB_WaitAudio;
  88         this->PlayAudio = DIB_PlayAudio;
  89         this->GetAudioBuf = DIB_GetAudioBuf;
  90         this->WaitDone = DIB_WaitDone;
  91         this->CloseAudio = DIB_CloseAudio;
  92 
  93         this->free = Audio_DeleteDevice;
  94 
  95         return this;
  96 }
  97 
  98 AudioBootStrap WAVEOUT_bootstrap = {
  99         "waveout", "Win95/98/NT/2000 WaveOut",
 100         Audio_Available, Audio_CreateDevice
 101 };
 102 
 103 
 104 /* The Win32 callback for filling the WAVE device */
 105 static void CALLBACK FillSound(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
     /* [<][>][^][v][top][bottom][index][help] */
 106                                                 DWORD dwParam1, DWORD dwParam2)
 107 {
 108         SDL_AudioDevice *this = (SDL_AudioDevice *)dwInstance;
 109 
 110         /* Only service "buffer done playing" messages */
 111         if ( uMsg != WOM_DONE )
 112                 return;
 113 
 114         /* Signal that we are done playing a buffer */
 115         ReleaseSemaphore(audio_sem, 1, NULL);
 116 }
 117 
 118 static void SetMMerror(char *function, MMRESULT code)
     /* [<][>][^][v][top][bottom][index][help] */
 119 {
 120         int len;
 121         char errbuf[MAXERRORLENGTH];
 122 
 123         sprintf(errbuf, "%s: ", function);
 124         len = strlen(errbuf);
 125         waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
 126         SDL_SetError("%s", errbuf);
 127 }
 128 
 129 /* Set high priority for the audio thread */
 130 static void DIB_ThreadInit(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 131 {
 132         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
 133 }
 134 
 135 void DIB_WaitAudio(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 136 {
 137         /* Wait for an audio chunk to finish */
 138         WaitForSingleObject(audio_sem, INFINITE);
 139 }
 140 
 141 Uint8 *DIB_GetAudioBuf(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 142 {
 143         Uint8 *retval;
 144 
 145         retval = (Uint8 *)(wavebuf[next_buffer].lpData);
 146         return retval;
 147 }
 148 
 149 void DIB_PlayAudio(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 150 {
 151         /* Queue it up */
 152         waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0]));
 153         next_buffer = (next_buffer+1)%NUM_BUFFERS;
 154 }
 155 
 156 void DIB_WaitDone(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 157 {
 158         int i, left;
 159 
 160         do {
 161                 left = NUM_BUFFERS;
 162                 for ( i=0; i<NUM_BUFFERS; ++i ) {
 163                         if ( wavebuf[i].dwFlags & WHDR_DONE ) {
 164                                 --left;
 165                         }
 166                 }
 167                 if ( left > 0 ) {
 168                         SDL_Delay(100);
 169                 }
 170         } while ( left > 0 );
 171 }
 172 
 173 void DIB_CloseAudio(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 174 {
 175         int i;
 176 
 177         /* Close up audio */
 178         if ( audio_sem ) {
 179                 CloseHandle(audio_sem);
 180         }
 181         if ( sound ) {
 182                 waveOutClose(sound);
 183         }
 184 
 185         /* Clean up mixing buffers */
 186         for ( i=0; i<NUM_BUFFERS; ++i ) {
 187                 if ( wavebuf[i].dwUser != 0xFFFF ) {
 188                         waveOutUnprepareHeader(sound, &wavebuf[i],
 189                                                 sizeof(wavebuf[i]));
 190                         wavebuf[i].dwUser = 0xFFFF;
 191                 }
 192         }
 193         /* Free raw mixing buffer */
 194         if ( mixbuf != NULL ) {
 195                 free(mixbuf);
 196                 mixbuf = NULL;
 197         }
 198 }
 199 
 200 int DIB_OpenAudio(_THIS, SDL_AudioSpec *spec)
     /* [<][>][^][v][top][bottom][index][help] */
 201 {
 202         MMRESULT result;
 203         int i;
 204         WAVEFORMATEX waveformat;
 205 
 206         /* Initialize the wavebuf structures for closing */
 207         sound = NULL;
 208         audio_sem = NULL;
 209         for ( i = 0; i < NUM_BUFFERS; ++i )
 210                 wavebuf[i].dwUser = 0xFFFF;
 211         mixbuf = NULL;
 212 
 213         /* Set basic WAVE format parameters */
 214         memset(&waveformat, 0, sizeof(waveformat));
 215         waveformat.wFormatTag = WAVE_FORMAT_PCM;
 216 
 217         /* Determine the audio parameters from the AudioSpec */
 218         switch ( spec->format & 0xFF ) {
 219                 case 8:
 220                         /* Unsigned 8 bit audio data */
 221                         spec->format = AUDIO_U8;
 222                         waveformat.wBitsPerSample = 8;
 223                         break;
 224                 case 16:
 225                         /* Signed 16 bit audio data */
 226                         spec->format = AUDIO_S16;
 227                         waveformat.wBitsPerSample = 16;
 228                         break;
 229                 default:
 230                         SDL_SetError("Unsupported audio format");
 231                         return(-1);
 232         }
 233         waveformat.nChannels = spec->channels;
 234         waveformat.nSamplesPerSec = spec->freq;
 235         waveformat.nBlockAlign =
 236                 waveformat.nChannels * (waveformat.wBitsPerSample/8);
 237         waveformat.nAvgBytesPerSec = 
 238                 waveformat.nSamplesPerSec * waveformat.nBlockAlign;
 239 
 240         /* Check the buffer size -- minimum of 1/4 second (word aligned) */
 241         if ( spec->samples < (spec->freq/4) )
 242                 spec->samples = ((spec->freq/4)+3)&~3;
 243 
 244         /* Update the fragment size as size in bytes */
 245         SDL_CalculateAudioSpec(spec);
 246 
 247         /* Open the audio device */
 248         result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat,
 249                         (DWORD)FillSound, (DWORD)this, CALLBACK_FUNCTION);
 250         if ( result != MMSYSERR_NOERROR ) {
 251                 SetMMerror("waveOutOpen()", result);
 252                 return(-1);
 253         }
 254 
 255 #ifdef SOUND_DEBUG
 256         /* Check the sound device we retrieved */
 257         {
 258                 WAVEOUTCAPS caps;
 259 
 260                 result = waveOutGetDevCaps((UINT)sound, &caps, sizeof(caps));
 261                 if ( result != MMSYSERR_NOERROR ) {
 262                         SetMMerror("waveOutGetDevCaps()", result);
 263                         return(-1);
 264                 }
 265                 printf("Audio device: %s\n", caps.szPname);
 266         }
 267 #endif
 268 
 269         /* Create the audio buffer semaphore */
 270         audio_sem = CreateSemaphore(NULL, NUM_BUFFERS-1, NUM_BUFFERS, NULL);
 271         if ( audio_sem == NULL ) {
 272                 SDL_SetError("Couldn't create semaphore");
 273                 return(-1);
 274         }
 275 
 276         /* Create the sound buffers */
 277         mixbuf = (Uint8 *)malloc(NUM_BUFFERS*spec->size);
 278         if ( mixbuf == NULL ) {
 279                 SDL_SetError("Out of memory");
 280                 return(-1);
 281         }
 282         for ( i = 0; i < NUM_BUFFERS; ++i ) {
 283                 memset(&wavebuf[i], 0, sizeof(wavebuf[i]));
 284                 wavebuf[i].lpData = (LPSTR) &mixbuf[i*spec->size];
 285                 wavebuf[i].dwBufferLength = spec->size;
 286                 wavebuf[i].dwFlags = WHDR_DONE;
 287                 result = waveOutPrepareHeader(sound, &wavebuf[i],
 288                                                         sizeof(wavebuf[i]));
 289                 if ( result != MMSYSERR_NOERROR ) {
 290                         SetMMerror("waveOutPrepareHeader()", result);
 291                         return(-1);
 292                 }
 293         }
 294 
 295         /* Ready to go! */
 296         next_buffer = 0;
 297         return(0);
 298 }

/* [<][>][^][v][top][bottom][index][help] */