comparison src/audio/mme/SDL_mmeaudio.c @ 3827:1806fd1acba4 SDL-ryan-multiple-audio-device

Moved mme audio driver to 1.3 API.
author Ryan C. Gordon <icculus@icculus.org>
date Sat, 07 Oct 2006 07:54:13 +0000
parents c8b3d3d13ed1
children 29e83f221c62
comparison
equal deleted inserted replaced
3826:5b483ce86357 3827:1806fd1acba4
29 #include "../SDL_audio_c.h" 29 #include "../SDL_audio_c.h"
30 #include "SDL_mmeaudio.h" 30 #include "SDL_mmeaudio.h"
31 31
32 static BOOL inUse[NUM_BUFFERS]; 32 static BOOL inUse[NUM_BUFFERS];
33 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 34 static int
44 Audio_Available(void) 35 MME_Available(void)
45 { 36 {
46 return (1); 37 return 1;
47 } 38 }
48
49 static void
50 Audio_DeleteDevice(SDL_AudioDevice * device)
51 {
52 if (device) {
53 if (device->hidden) {
54 SDL_free(device->hidden);
55 device->hidden = NULL;
56 }
57 SDL_free(device);
58 device = NULL;
59 }
60 }
61
62 static SDL_AudioDevice *
63 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, 0
96 };
97 39
98 static void 40 static void
99 SetMMerror(char *function, MMRESULT code) 41 SetMMerror(char *function, MMRESULT code)
100 { 42 {
101 int len; 43 int len;
106 waveOutGetErrorText(code, errbuf + len, MAXERRORLENGTH - len); 48 waveOutGetErrorText(code, errbuf + len, MAXERRORLENGTH - len);
107 SDL_SetError("%s", errbuf); 49 SDL_SetError("%s", errbuf);
108 } 50 }
109 51
110 static void CALLBACK 52 static void CALLBACK
111 MME_CALLBACK(HWAVEOUT hwo, 53 MME_Callback(HWAVEOUT hwo,
112 UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2) 54 UINT uMsg, DWORD dwInstance, LPARAM dwParam1, LPARAM dwParam2)
113 { 55 {
114 WAVEHDR *wp = (WAVEHDR *) dwParam1; 56 WAVEHDR *wp = (WAVEHDR *) dwParam1;
115 57
116 if (uMsg == WOM_DONE) 58 if (uMsg == WOM_DONE)
117 inUse[wp->dwUser] = FALSE; 59 inUse[wp->dwUser] = FALSE;
118 } 60 }
119 61
120 static int 62 static int
121 MME_OpenAudio(_THIS, SDL_AudioSpec * spec) 63 MME_OpenDevice(_THIS, const char *devname, int iscapture)
64 {
65 int valid_format = 0;
66 MMRESULT result;
67 Uint8 *mixbuf = NULL;
68 int i;
69
70 /* Initialize all variables that we clean on shutdown */
71 this->hidden = (struct SDL_PrivateAudioData *)
72 SDL_malloc((sizeof *this->hidden));
73 if (this->hidden == NULL) {
74 SDL_OutOfMemory();
75 return 0;
76 }
77 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
78
79 /* Set basic WAVE format parameters */
80 this->hidden->shm = mmeAllocMem(sizeof(*this->hidden->shm));
81 if (this->hidden->shm == NULL) {
82 MME_CloseDevice(this);
83 SDL_OutOfMemory();
84 return 0;
85 }
86
87 memset(this->hidden->shm, '\0', sizeof (*this->hidden->shm));
88 this->hidden->shm->sound = 0;
89 this->hidden->shm->wFmt.wf.wFormatTag = WAVE_FORMAT_PCM;
90
91 /* Determine the audio parameters from the AudioSpec */
92 /* Try for a closest match on audio format */
93 for (test_format = SDL_FirstAudioFormat(this->spec.format);
94 !valid_format && test_format;) {
95 valid_format = 1;
96 switch (test_format) {
97 case AUDIO_U8:
98 case AUDIO_S16:
99 case AUDIO_S32:
100 break;
101 default:
102 valid_format = 0;
103 test_format = SDL_NextAudioFormat();
104 }
105 }
106
107 if (!valid_format) {
108 MME_CloseDevice(this);
109 SDL_SetError("Unsupported audio format");
110 return 0;
111 }
112
113 this->spec.format = test_format;
114 this->hidden->shm->wFmt.wBitsPerSample = SDL_AUDIO_BITSIZE(test_format);
115
116 /* !!! FIXME: Can this handle more than stereo? */
117 this->hidden->shm->wFmt.wf.nChannels = this->spec.channels;
118 this->hidden->shm->wFmt.wf.nSamplesPerSec = this->spec.freq;
119 this->hidden->shm->wFmt.wf.nBlockAlign =
120 this->hidden->shm->wFmt.wf.nChannels *
121 this->hidden->shm->wFmt.wBitsPerSample / 8;
122 this->hidden->shm->wFmt.wf.nAvgBytesPerSec =
123 this->hidden->shm->wFmt.wf.nSamplesPerSec *
124 this->hidden->shm->wFmt.wf.nBlockAlign;
125
126 /* Check the buffer size -- minimum of 1/4 second (word aligned) */
127 if (this->spec.samples < (this->spec.freq / 4))
128 this->spec.samples = ((this->spec.freq / 4) + 3) & ~3;
129
130 /* Update the fragment size as size in bytes */
131 SDL_CalculateAudioSpec(&this->spec);
132
133 /* Open the audio device */
134 result = waveOutOpen(&(this->hidden->shm->sound),
135 WAVE_MAPPER,
136 &(this->hidden->shm->wFmt.wf),
137 MME_Callback,
138 NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
139 if (result != MMSYSERR_NOERROR) {
140 MME_CloseDevice(this);
141 SetMMerror("waveOutOpen()", result);
142 return 0;
143 }
144
145 /* Create the sound buffers */
146 mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (this->spec.size));
147 if (mixbuf == NULL) {
148 MME_CloseDevice(this);
149 SDL_OutOfMemory();
150 return 0;
151 }
152 this->hidden->mixbuf = mixbuf;
153
154 for (i = 0; i < NUM_BUFFERS; i++) {
155 this->hidden->shm->wHdr[i].lpData = &mixbuf[i * (this->spec.size)];
156 this->hidden->shm->wHdr[i].dwBufferLength = this->spec.size;
157 this->hidden->shm->wHdr[i].dwFlags = 0;
158 this->hidden->shm->wHdr[i].dwUser = i;
159 this->hidden->shm->wHdr[i].dwLoops = 0; /* loop control counter */
160 this->hidden->shm->wHdr[i].lpNext = NULL; /* reserved for driver */
161 this->hidden->shm->wHdr[i].reserved = 0;
162 inUse[i] = FALSE;
163 }
164 this->hidden->next_buffer = 0;
165
166 return 1;
167 }
168
169 static void
170 MME_WaitDevice(_THIS)
171 {
172 while (inUse[this->hidden->next_buffer]) {
173 mmeWaitForCallbacks();
174 mmeProcessCallbacks();
175 }
176 }
177
178 static Uint8 *
179 MME_GetDeviceBuf(_THIS)
180 {
181 void *retval = this->hidden->shm->wHdr[this->hidden->next_buffer].lpData;
182 inUse[this->hidden->next_buffer] = TRUE;
183 return (Uint8 *) retval;
184 }
185
186 static void
187 MME_PlayDevice(_THIS)
188 {
189 /* Queue it up */
190 waveOutWrite(this->hidden->shm->sound,
191 &(this->hidden->shm->wHdr[this->hidden->next_buffer]),
192 sizeof (WAVEHDR));
193 this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
194 }
195
196 static void
197 MME_WaitDone(_THIS)
122 { 198 {
123 MMRESULT result; 199 MMRESULT result;
124 int i; 200 int i;
125 201
126 mixbuf = NULL; 202 if (this->hidden->shm->sound) {
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 (SDL_AUDIO_BITSIZE(spec->format)) {
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 case 32:
150 /* Signed 32 bit audio data */
151 spec->format = AUDIO_S32;
152 shm->wFmt.wBitsPerSample = 32;
153 break;
154 default:
155 SDL_SetError("Unsupported audio format");
156 return (-1);
157 }
158
159 /* !!! FIXME: Can this handle more than stereo? */
160 shm->wFmt.wf.nChannels = spec->channels;
161 shm->wFmt.wf.nSamplesPerSec = spec->freq;
162 shm->wFmt.wf.nBlockAlign =
163 shm->wFmt.wf.nChannels * shm->wFmt.wBitsPerSample / 8;
164 shm->wFmt.wf.nAvgBytesPerSec =
165 shm->wFmt.wf.nSamplesPerSec * shm->wFmt.wf.nBlockAlign;
166
167 /* Check the buffer size -- minimum of 1/4 second (word aligned) */
168 if (spec->samples < (spec->freq / 4))
169 spec->samples = ((spec->freq / 4) + 3) & ~3;
170
171 /* Update the fragment size as size in bytes */
172 SDL_CalculateAudioSpec(spec);
173
174 /* Open the audio device */
175 result = waveOutOpen(&(shm->sound),
176 WAVE_MAPPER,
177 &(shm->wFmt.wf),
178 MME_CALLBACK,
179 NULL, (CALLBACK_FUNCTION | WAVE_OPEN_SHAREABLE));
180 if (result != MMSYSERR_NOERROR) {
181 SetMMerror("waveOutOpen()", result);
182 return (-1);
183 }
184
185 /* Create the sound buffers */
186 mixbuf = (Uint8 *) mmeAllocBuffer(NUM_BUFFERS * (spec->size));
187 if (mixbuf == NULL) {
188 SDL_SetError("Out of memory: mixbuf");
189 return (-1);
190 }
191
192 for (i = 0; i < NUM_BUFFERS; i++) {
193 shm->wHdr[i].lpData = &mixbuf[i * (spec->size)];
194 shm->wHdr[i].dwBufferLength = spec->size;
195 shm->wHdr[i].dwFlags = 0;
196 shm->wHdr[i].dwUser = i;
197 shm->wHdr[i].dwLoops = 0; /* loop control counter */
198 shm->wHdr[i].lpNext = NULL; /* reserved for driver */
199 shm->wHdr[i].reserved = 0;
200 inUse[i] = FALSE;
201 }
202 next_buffer = 0;
203 return 0;
204 }
205
206 static void
207 MME_WaitAudio(_THIS)
208 {
209 while (inUse[next_buffer]) {
210 mmeWaitForCallbacks();
211 mmeProcessCallbacks();
212 }
213 }
214
215 static Uint8 *
216 MME_GetAudioBuf(_THIS)
217 {
218 Uint8 *retval;
219
220 inUse[next_buffer] = TRUE;
221 retval = (Uint8 *) (shm->wHdr[next_buffer].lpData);
222 return retval;
223 }
224
225 static void
226 MME_PlayAudio(_THIS)
227 {
228 /* Queue it up */
229 waveOutWrite(shm->sound, &(shm->wHdr[next_buffer]), sizeof(WAVEHDR));
230 next_buffer = (next_buffer + 1) % NUM_BUFFERS;
231 }
232
233 static void
234 MME_WaitDone(_THIS)
235 {
236 MMRESULT result;
237 int i;
238
239 if (shm->sound) {
240 for (i = 0; i < NUM_BUFFERS; i++) 203 for (i = 0; i < NUM_BUFFERS; i++)
241 while (inUse[i]) { 204 while (inUse[i]) {
242 mmeWaitForCallbacks(); 205 mmeWaitForCallbacks();
243 mmeProcessCallbacks(); 206 mmeProcessCallbacks();
244 } 207 }
245 result = waveOutReset(shm->sound); 208 result = waveOutReset(this->hidden->shm->sound);
246 if (result != MMSYSERR_NOERROR) 209 if (result != MMSYSERR_NOERROR)
247 SetMMerror("waveOutReset()", result); 210 SetMMerror("waveOutReset()", result);
248 mmeProcessCallbacks(); 211 mmeProcessCallbacks();
249 } 212 }
250 } 213 }
251 214
252 static void 215 static void
253 MME_CloseAudio(_THIS) 216 MME_CloseDevice(_THIS)
254 { 217 {
255 MMRESULT result; 218 if (this->hidden != NULL) {
256 219 MMRESULT result;
257 if (mixbuf) { 220
258 result = mmeFreeBuffer(mixbuf); 221 if (this->hidden->mixbuf) {
259 if (result != MMSYSERR_NOERROR) 222 result = mmeFreeBuffer(this->hidden->mixbuf);
260 SetMMerror("mmeFreeBuffer", result);
261 mixbuf = NULL;
262 }
263
264 if (shm) {
265 if (shm->sound) {
266 result = waveOutClose(shm->sound);
267 if (result != MMSYSERR_NOERROR) 223 if (result != MMSYSERR_NOERROR)
268 SetMMerror("waveOutClose()", result); 224 SetMMerror("mmeFreeBuffer", result);
269 mmeProcessCallbacks(); 225 this->hidden->mixbuf = NULL;
270 } 226 }
271 result = mmeFreeMem(shm); 227
272 if (result != MMSYSERR_NOERROR) 228 if (this->hidden->shm) {
273 SetMMerror("mmeFreeMem()", result); 229 if (this->hidden->shm->sound) {
274 shm = NULL; 230 result = waveOutClose(this->hidden->shm->sound);
275 } 231 if (result != MMSYSERR_NOERROR)
276 } 232 SetMMerror("waveOutClose()", result);
233 mmeProcessCallbacks();
234 }
235 result = mmeFreeMem(this->hidden->shm);
236 if (result != MMSYSERR_NOERROR)
237 SetMMerror("mmeFreeMem()", result);
238 this->hidden->shm = NULL;
239 }
240
241 SDL_free(this->hidden);
242 this->hidden = NULL;
243 }
244 }
245
246 static int
247 MME_Init(SDL_AudioDriverImpl *impl)
248 {
249 /* Set the function pointers */
250 impl->OpenDevice = MME_OpenDevice;
251 impl->WaitDevice = MME_WaitDevice;
252 impl->WaitDone = MME_WaitDone;
253 impl->PlayDevice = MME_PlayDevice;
254 impl->GetDeviceBuf = MME_GetDeviceBuf;
255 impl->CloseDevice = MME_CloseDevice;
256 impl->OnlyHasDefaultOutputDevice = 1;
257
258 return 1;
259 }
260
261 /* !!! FIXME: Windows "windib" driver is called waveout, too */
262 AudioBootStrap MMEAUDIO_bootstrap = {
263 "waveout", "Tru64 MME WaveOut",
264 MME_Available, MME_Init, 0
265 };
277 266
278 /* vi: set ts=4 sw=4 expandtab: */ 267 /* vi: set ts=4 sw=4 expandtab: */