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