src/audio/mme/SDL_mmeaudio.c
author Sam Lantinga
Tue, 07 Feb 2006 12:15:46 +0000
changeset 1342 d73be99e9420
parent 1338 604d73db6802
child 1358 c71e05b4dc2e
permissions -rw-r--r--
Fixed it Hayashi Naoyuki's way. :)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2004 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@libsdl.org
    21 */
    22 
    23 /* Tru64 UNIX MME support */
    24 #include <mme_api.h>
    25 
    26 #include "SDL_stdlib.h"
    27 #include "SDL_string.h"
    28 #include "SDL_audio.h"
    29 #include "SDL_mutex.h"
    30 #include "SDL_timer.h"
    31 #include "SDL_audio_c.h"
    32 
    33 #include "SDL_mmeaudio.h"
    34 
    35 static BOOL inUse[NUM_BUFFERS];
    36 
    37 /* Audio driver functions */
    38 static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec);
    39 static void MME_WaitAudio(_THIS);
    40 static Uint8 *MME_GetAudioBuf(_THIS);
    41 static void MME_PlayAudio(_THIS);
    42 static void MME_WaitDone(_THIS);
    43 static void MME_CloseAudio(_THIS);
    44 
    45 /* Audio driver bootstrap functions */
    46 static int Audio_Available(void)
    47 {
    48     return(1);
    49 }
    50 
    51 static void Audio_DeleteDevice(SDL_AudioDevice *device)
    52 {
    53     if ( device ) {
    54 	if ( device->hidden ) {
    55 	    SDL_free(device->hidden);
    56 	    device->hidden = NULL;
    57 	}
    58 	SDL_free(device);
    59 	device = NULL;
    60     }
    61 }
    62 
    63 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
    64 {
    65     SDL_AudioDevice *this;
    66 
    67 /* Initialize all variables that we clean on shutdown */
    68     this = SDL_malloc(sizeof(SDL_AudioDevice));
    69     if ( this ) {
    70 	SDL_memset(this, 0, (sizeof *this));
    71 	this->hidden = SDL_malloc((sizeof *this->hidden));
    72     }
    73     if ( (this == NULL) || (this->hidden == NULL) ) {
    74 	SDL_OutOfMemory();
    75 	if ( this ) {
    76 	    SDL_free(this);
    77 	}
    78 	return(0);
    79     }
    80     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    81     /* Set the function pointers */
    82     this->OpenAudio       =       MME_OpenAudio;
    83     this->WaitAudio       =       MME_WaitAudio;
    84     this->PlayAudio       =       MME_PlayAudio;
    85     this->GetAudioBuf     =     MME_GetAudioBuf;
    86     this->WaitDone        =        MME_WaitDone;
    87     this->CloseAudio      =      MME_CloseAudio;
    88     this->free            =  Audio_DeleteDevice;
    89 
    90     return this;
    91 }
    92 
    93 AudioBootStrap MMEAUDIO_bootstrap = {
    94     "waveout", "Tru64 MME WaveOut",
    95     Audio_Available, Audio_CreateDevice
    96 };
    97 
    98 static void SetMMerror(char *function, MMRESULT code)
    99 {
   100     int len;
   101     char errbuf[MAXERRORLENGTH];
   102 
   103     SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
   104     len = SDL_strlen(errbuf);
   105     waveOutGetErrorText(code, errbuf+len, MAXERRORLENGTH-len);
   106     SDL_SetError("%s",errbuf);
   107 }
   108 
   109 static void CALLBACK MME_CALLBACK(HWAVEOUT hwo,
   110 				  UINT uMsg,
   111 				  DWORD dwInstance,
   112 				  LPARAM dwParam1,
   113 				  LPARAM dwParam2)
   114 {
   115     WAVEHDR *wp = (WAVEHDR *) dwParam1;
   116 
   117     if ( uMsg == WOM_DONE )
   118 	inUse[wp->dwUser] = FALSE;
   119 }
   120 
   121 static int MME_OpenAudio(_THIS, SDL_AudioSpec *spec)
   122 {
   123     MMRESULT result;
   124     int i;
   125 
   126     mixbuf = NULL;
   127 
   128     /* Set basic WAVE format parameters */
   129     shm = mmeAllocMem(sizeof(*shm));
   130     if ( shm == NULL ) {
   131 	SDL_SetError("Out of memory: shm");
   132 	return(-1);
   133     }
   134     shm->sound = 0;
   135     shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
   136 
   137     /* Determine the audio parameters from the AudioSpec */
   138     switch ( spec->format & 0xFF ) {
   139 	case 8:
   140 	    /* Unsigned 8 bit audio data */
   141 	    spec->format = AUDIO_U8;
   142 	    shm->wFmt.wBitsPerSample = 8;
   143 	    break;
   144 	case 16:
   145 	    /* Signed 16 bit audio data */
   146 	    spec->format = AUDIO_S16;
   147 	    shm->wFmt.wBitsPerSample = 16;
   148 	    break;
   149 	    default:
   150 	    SDL_SetError("Unsupported audio format");
   151 	    return(-1);
   152     }
   153 
   154     shm->wFmt.wf.nChannels = spec->channels;
   155     shm->wFmt.wf.nSamplesPerSec = spec->freq;
   156     shm->wFmt.wf.nBlockAlign =
   157 	shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
   158     shm->wFmt.wf.nAvgBytesPerSec =
   159 	shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
   160 
   161     /* Check the buffer size -- minimum of 1/4 second (word aligned) */
   162     if ( spec->samples < (spec->freq/4) )
   163 	spec->samples = ((spec->freq/4)+3)&~3;
   164 
   165     /* Update the fragment size as size in bytes */
   166     SDL_CalculateAudioSpec(spec);
   167 
   168     /* Open the audio device */
   169     result = waveOutOpen(&(shm->sound),
   170 			 WAVE_MAPPER,
   171 			 &(shm->wFmt.wf),
   172 			 MME_CALLBACK,
   173 			 NULL,
   174 			 (CALLBACK_FUNCTION|WAVE_OPEN_SHAREABLE));
   175     if ( result != MMSYSERR_NOERROR ) {
   176 	    SetMMerror("waveOutOpen()", result);
   177 	    return(-1);
   178     }
   179 
   180     /* Create the sound buffers */
   181     mixbuf = (Uint8 *)mmeAllocBuffer(NUM_BUFFERS * (spec->size));
   182     if ( mixbuf == NULL ) {
   183 	SDL_SetError("Out of memory: mixbuf");
   184 	return(-1);
   185     }
   186 
   187     for (i = 0; i < NUM_BUFFERS; i++) {
   188 	shm->wHdr[i].lpData         = &mixbuf[i * (spec->size)];
   189 	shm->wHdr[i].dwBufferLength = spec->size;
   190 	shm->wHdr[i].dwFlags        = 0;
   191 	shm->wHdr[i].dwUser         = i;
   192 	shm->wHdr[i].dwLoops        = 0;       /* loop control counter */
   193 	shm->wHdr[i].lpNext         = NULL;    /* reserved for driver */
   194 	shm->wHdr[i].reserved       = 0;
   195 	inUse[i] = FALSE;
   196     }
   197     next_buffer = 0;
   198     return 0;
   199 }
   200 
   201 static void MME_WaitAudio(_THIS)
   202 {
   203     while ( inUse[next_buffer] ) {
   204 	mmeWaitForCallbacks();
   205 	mmeProcessCallbacks();
   206     }
   207 }
   208 
   209 static Uint8 *MME_GetAudioBuf(_THIS)
   210 {
   211     Uint8 *retval;
   212 
   213     inUse[next_buffer] = TRUE;
   214     retval = (Uint8 *)(shm->wHdr[next_buffer].lpData);
   215     return retval;
   216 }
   217 
   218 static void MME_PlayAudio(_THIS)
   219 {
   220     /* Queue it up */
   221     waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
   222     next_buffer = (next_buffer+1)%NUM_BUFFERS;
   223 }
   224 
   225 static void MME_WaitDone(_THIS)
   226 {
   227     MMRESULT result;
   228     int i;
   229 
   230     if ( shm->sound ) {
   231 	for (i = 0; i < NUM_BUFFERS; i++)
   232 	    while ( inUse[i] ) {
   233 		mmeWaitForCallbacks();
   234 		mmeProcessCallbacks();
   235 	    }
   236 	result = waveOutReset(shm->sound);
   237 	if ( result != MMSYSERR_NOERROR )
   238 	    SetMMerror("waveOutReset()", result);
   239 	mmeProcessCallbacks();
   240     }
   241 }
   242 
   243 static void MME_CloseAudio(_THIS)
   244 {
   245     MMRESULT result;
   246 
   247     if ( mixbuf ) {
   248 	result = mmeFreeBuffer(mixbuf);
   249 	if (result != MMSYSERR_NOERROR )
   250 	    SetMMerror("mmeFreeBuffer", result);
   251 	mixbuf = NULL;
   252     }
   253 
   254     if ( shm ) {
   255 	if ( shm->sound ) {
   256 	    result = waveOutClose(shm->sound);
   257 	    if (result != MMSYSERR_NOERROR )
   258 		SetMMerror("waveOutClose()", result);
   259 	    mmeProcessCallbacks();
   260 	}
   261 	result = mmeFreeMem(shm);
   262 	if (result != MMSYSERR_NOERROR )
   263 	    SetMMerror("mmeFreeMem()", result);
   264 	shm = NULL;
   265     }
   266 }
   267