Mercurial > sdl-ios-xcode
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: */ |