• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 */
Audio_Available(void)43 static int Audio_Available(void)
44 {
45     return(1);
46 }
47 
Audio_DeleteDevice(SDL_AudioDevice * device)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 
Audio_CreateDevice(int devindex)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 
SetMMerror(char * function,MMRESULT code)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 
MME_CALLBACK(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,LPARAM dwParam1,LPARAM dwParam2)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 
MME_OpenAudio(_THIS,SDL_AudioSpec * spec)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 
MME_WaitAudio(_THIS)198 static void MME_WaitAudio(_THIS)
199 {
200     while ( inUse[next_buffer] ) {
201 	mmeWaitForCallbacks();
202 	mmeProcessCallbacks();
203     }
204 }
205 
MME_GetAudioBuf(_THIS)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 
MME_PlayAudio(_THIS)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 
MME_WaitDone(_THIS)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 
MME_CloseAudio(_THIS)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