Mercurial > fife-parpg
comparison ext/openal-soft/Alc/dsound.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
1 /** | |
2 * OpenAL cross platform audio library | |
3 * Copyright (C) 1999-2007 by authors. | |
4 * This library is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU Library General Public | |
6 * License as published by the Free Software Foundation; either | |
7 * version 2 of the License, or (at your option) any later version. | |
8 * | |
9 * This library is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * Library General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU Library General Public | |
15 * License along with this library; if not, write to the | |
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
17 * Boston, MA 02111-1307, USA. | |
18 * Or go to http://www.gnu.org/copyleft/lgpl.html | |
19 */ | |
20 | |
21 #include "config.h" | |
22 | |
23 #define INITGUID | |
24 #include <stdlib.h> | |
25 #include <stdio.h> | |
26 #include <memory.h> | |
27 | |
28 #include <dsound.h> | |
29 #include <mmreg.h> | |
30 | |
31 #include "alMain.h" | |
32 #include "AL/al.h" | |
33 #include "AL/alc.h" | |
34 | |
35 #ifndef DSSPEAKER_7POINT1 | |
36 #define DSSPEAKER_7POINT1 7 | |
37 #endif | |
38 | |
39 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); | |
40 | |
41 // Since DSound doesn't report the fragment size, just assume 4 fragments | |
42 #define DS_FRAGS 4 | |
43 | |
44 typedef struct { | |
45 // DirectSound Playback Device | |
46 LPDIRECTSOUND lpDS; | |
47 LPDIRECTSOUNDBUFFER DSpbuffer; | |
48 LPDIRECTSOUNDBUFFER DSsbuffer; | |
49 | |
50 int killNow; | |
51 ALvoid *thread; | |
52 } DSoundData; | |
53 | |
54 | |
55 typedef struct { | |
56 ALCchar *name; | |
57 GUID guid; | |
58 } DevMap; | |
59 static DevMap DeviceList[16]; | |
60 | |
61 | |
62 static ALuint DSoundProc(ALvoid *ptr) | |
63 { | |
64 ALCdevice *pDevice = (ALCdevice*)ptr; | |
65 DSoundData *pData = (DSoundData*)pDevice->ExtraData; | |
66 DWORD LastCursor = 0; | |
67 DWORD PlayCursor; | |
68 VOID *WritePtr1, *WritePtr2; | |
69 DWORD WriteCnt1, WriteCnt2; | |
70 DWORD BufferSize; | |
71 DWORD avail; | |
72 HRESULT err; | |
73 | |
74 BufferSize = pDevice->UpdateSize * DS_FRAGS * | |
75 aluBytesFromFormat(pDevice->Format) * | |
76 aluChannelsFromFormat(pDevice->Format); | |
77 | |
78 while(!pData->killNow) | |
79 { | |
80 // Get current play and write cursors | |
81 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); | |
82 avail = (PlayCursor-LastCursor+BufferSize) % BufferSize; | |
83 | |
84 if(avail == 0) | |
85 { | |
86 Sleep(1); | |
87 continue; | |
88 } | |
89 | |
90 // Lock output buffer | |
91 WriteCnt1 = 0; | |
92 WriteCnt2 = 0; | |
93 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); | |
94 | |
95 // If the buffer is lost, restore it, play and lock | |
96 if(err == DSERR_BUFFERLOST) | |
97 { | |
98 err = IDirectSoundBuffer_Restore(pData->DSsbuffer); | |
99 if(SUCCEEDED(err)) | |
100 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); | |
101 if(SUCCEEDED(err)) | |
102 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); | |
103 } | |
104 | |
105 // Successfully locked the output buffer | |
106 if(SUCCEEDED(err)) | |
107 { | |
108 // If we have an active context, mix data directly into output buffer otherwise fill with silence | |
109 SuspendContext(NULL); | |
110 aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format); | |
111 aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format); | |
112 ProcessContext(NULL); | |
113 | |
114 // Unlock output buffer only when successfully locked | |
115 IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); | |
116 } | |
117 else | |
118 AL_PRINT("Buffer lock error: %#lx\n", err); | |
119 | |
120 // Update old write cursor location | |
121 LastCursor += WriteCnt1+WriteCnt2; | |
122 LastCursor %= BufferSize; | |
123 } | |
124 | |
125 return 0; | |
126 } | |
127 | |
128 static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) | |
129 { | |
130 DSBUFFERDESC DSBDescription; | |
131 DSoundData *pData = NULL; | |
132 WAVEFORMATEXTENSIBLE OutputType; | |
133 DWORD frameSize = 0; | |
134 LPGUID guid = NULL; | |
135 DWORD speakers; | |
136 HRESULT hr; | |
137 | |
138 if(deviceName) | |
139 { | |
140 int i; | |
141 for(i = 0;DeviceList[i].name;i++) | |
142 { | |
143 if(strcmp(deviceName, DeviceList[i].name) == 0) | |
144 { | |
145 device->szDeviceName = DeviceList[i].name; | |
146 if(i > 0) | |
147 guid = &DeviceList[i].guid; | |
148 break; | |
149 } | |
150 } | |
151 if(!DeviceList[i].name) | |
152 return ALC_FALSE; | |
153 } | |
154 else | |
155 device->szDeviceName = DeviceList[0].name; | |
156 | |
157 memset(&OutputType, 0, sizeof(OutputType)); | |
158 | |
159 //Initialise requested device | |
160 | |
161 pData = calloc(1, sizeof(DSoundData)); | |
162 if(!pData) | |
163 { | |
164 SetALCError(ALC_OUT_OF_MEMORY); | |
165 return ALC_FALSE; | |
166 } | |
167 | |
168 //DirectSound Init code | |
169 hr = DirectSoundCreate(guid, &pData->lpDS, NULL); | |
170 if(SUCCEEDED(hr)) | |
171 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); | |
172 | |
173 if(SUCCEEDED(hr)) | |
174 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers); | |
175 if(SUCCEEDED(hr)) | |
176 { | |
177 speakers = DSSPEAKER_CONFIG(speakers); | |
178 if(speakers == DSSPEAKER_MONO) | |
179 { | |
180 if(aluBytesFromFormat(device->Format) == 1) | |
181 device->Format = AL_FORMAT_MONO8; | |
182 else | |
183 device->Format = AL_FORMAT_MONO16; | |
184 } | |
185 else if(speakers == DSSPEAKER_STEREO) | |
186 { | |
187 if(aluBytesFromFormat(device->Format) == 1) | |
188 device->Format = AL_FORMAT_STEREO8; | |
189 else | |
190 device->Format = AL_FORMAT_STEREO16; | |
191 } | |
192 else if(speakers == DSSPEAKER_QUAD) | |
193 { | |
194 if(aluBytesFromFormat(device->Format) == 1) | |
195 device->Format = AL_FORMAT_QUAD8; | |
196 else | |
197 device->Format = AL_FORMAT_QUAD16; | |
198 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
199 SPEAKER_FRONT_RIGHT | | |
200 SPEAKER_BACK_LEFT | | |
201 SPEAKER_BACK_RIGHT; | |
202 } | |
203 else if(speakers == DSSPEAKER_5POINT1) | |
204 { | |
205 if(aluBytesFromFormat(device->Format) == 1) | |
206 device->Format = AL_FORMAT_51CHN8; | |
207 else | |
208 device->Format = AL_FORMAT_51CHN16; | |
209 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
210 SPEAKER_FRONT_RIGHT | | |
211 SPEAKER_FRONT_CENTER | | |
212 SPEAKER_LOW_FREQUENCY | | |
213 SPEAKER_BACK_LEFT | | |
214 SPEAKER_BACK_RIGHT; | |
215 } | |
216 else if(speakers == DSSPEAKER_7POINT1) | |
217 { | |
218 if(aluBytesFromFormat(device->Format) == 1) | |
219 device->Format = AL_FORMAT_71CHN8; | |
220 else | |
221 device->Format = AL_FORMAT_71CHN16; | |
222 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
223 SPEAKER_FRONT_RIGHT | | |
224 SPEAKER_FRONT_CENTER | | |
225 SPEAKER_LOW_FREQUENCY | | |
226 SPEAKER_BACK_LEFT | | |
227 SPEAKER_BACK_RIGHT | | |
228 SPEAKER_SIDE_LEFT | | |
229 SPEAKER_SIDE_RIGHT; | |
230 } | |
231 frameSize = aluBytesFromFormat(device->Format) * | |
232 aluChannelsFromFormat(device->Format); | |
233 | |
234 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; | |
235 OutputType.Format.nChannels = aluChannelsFromFormat(device->Format); | |
236 OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8; | |
237 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; | |
238 OutputType.Format.nSamplesPerSec = device->Frequency; | |
239 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; | |
240 OutputType.Format.cbSize = 0; | |
241 | |
242 device->UpdateSize /= DS_FRAGS; | |
243 } | |
244 | |
245 if(OutputType.Format.nChannels > 2) | |
246 { | |
247 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | |
248 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; | |
249 OutputType.Format.cbSize = 22; | |
250 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | |
251 } | |
252 else | |
253 { | |
254 if(SUCCEEDED(hr)) | |
255 { | |
256 memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); | |
257 DSBDescription.dwSize=sizeof(DSBUFFERDESC); | |
258 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; | |
259 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL); | |
260 } | |
261 if(SUCCEEDED(hr)) | |
262 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format); | |
263 } | |
264 | |
265 if(SUCCEEDED(hr)) | |
266 { | |
267 memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); | |
268 DSBDescription.dwSize=sizeof(DSBUFFERDESC); | |
269 DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2; | |
270 DSBDescription.dwBufferBytes=device->UpdateSize * DS_FRAGS * frameSize; | |
271 DSBDescription.lpwfxFormat=&OutputType.Format; | |
272 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); | |
273 } | |
274 | |
275 if(SUCCEEDED(hr)) | |
276 hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); | |
277 | |
278 device->ExtraData = pData; | |
279 pData->thread = StartThread(DSoundProc, device); | |
280 if(!pData->thread) | |
281 hr = E_FAIL; | |
282 | |
283 if(FAILED(hr)) | |
284 { | |
285 if (pData->DSsbuffer) | |
286 IDirectSoundBuffer_Release(pData->DSsbuffer); | |
287 if (pData->DSpbuffer) | |
288 IDirectSoundBuffer_Release(pData->DSpbuffer); | |
289 if (pData->lpDS) | |
290 IDirectSound_Release(pData->lpDS); | |
291 | |
292 free(pData); | |
293 return ALC_FALSE; | |
294 } | |
295 | |
296 return ALC_TRUE; | |
297 } | |
298 | |
299 static void DSoundClosePlayback(ALCdevice *device) | |
300 { | |
301 DSoundData *pData = device->ExtraData; | |
302 | |
303 pData->killNow = 1; | |
304 StopThread(pData->thread); | |
305 | |
306 IDirectSoundBuffer_Release(pData->DSsbuffer); | |
307 if (pData->DSpbuffer) | |
308 IDirectSoundBuffer_Release(pData->DSpbuffer); | |
309 IDirectSound_Release(pData->lpDS); | |
310 | |
311 free(pData); | |
312 device->ExtraData = NULL; | |
313 } | |
314 | |
315 | |
316 static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) | |
317 { | |
318 (void)pDevice; | |
319 (void)deviceName; | |
320 (void)frequency; | |
321 (void)format; | |
322 (void)SampleSize; | |
323 return ALC_FALSE; | |
324 } | |
325 | |
326 static void DSoundCloseCapture(ALCdevice *pDevice) | |
327 { | |
328 (void)pDevice; | |
329 } | |
330 | |
331 static void DSoundStartCapture(ALCdevice *pDevice) | |
332 { | |
333 (void)pDevice; | |
334 } | |
335 | |
336 static void DSoundStopCapture(ALCdevice *pDevice) | |
337 { | |
338 (void)pDevice; | |
339 } | |
340 | |
341 static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) | |
342 { | |
343 (void)pDevice; | |
344 (void)pBuffer; | |
345 (void)lSamples; | |
346 } | |
347 | |
348 static ALCuint DSoundAvailableSamples(ALCdevice *pDevice) | |
349 { | |
350 (void)pDevice; | |
351 return 0; | |
352 } | |
353 | |
354 | |
355 BackendFuncs DSoundFuncs = { | |
356 DSoundOpenPlayback, | |
357 DSoundClosePlayback, | |
358 DSoundOpenCapture, | |
359 DSoundCloseCapture, | |
360 DSoundStartCapture, | |
361 DSoundStopCapture, | |
362 DSoundCaptureSamples, | |
363 DSoundAvailableSamples | |
364 }; | |
365 | |
366 static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data) | |
367 { | |
368 size_t *iter = data; | |
369 (void)drvname; | |
370 | |
371 if(guid) | |
372 { | |
373 char str[128]; | |
374 snprintf(str, sizeof(str), "DirectSound Software on %s", desc); | |
375 DeviceList[*iter].name = AppendAllDeviceList(str); | |
376 DeviceList[*iter].guid = *guid; | |
377 (*iter)++; | |
378 } | |
379 else | |
380 DeviceList[0].name = AppendDeviceList("DirectSound Software"); | |
381 | |
382 return TRUE; | |
383 } | |
384 | |
385 void alcDSoundInit(BackendFuncs *FuncList) | |
386 { | |
387 size_t iter = 1; | |
388 HRESULT hr; | |
389 | |
390 *FuncList = DSoundFuncs; | |
391 | |
392 hr = DirectSoundEnumerate(DSoundEnumDevices, &iter); | |
393 if(FAILED(hr)) | |
394 AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); | |
395 } |