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