Mercurial > fife-parpg
comparison ext/openal-soft/Alc/ALc.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 #define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005 | |
22 | |
23 #include "config.h" | |
24 | |
25 #include <math.h> | |
26 #include <stdlib.h> | |
27 #include <stdio.h> | |
28 #include <memory.h> | |
29 #include <ctype.h> | |
30 #include "alMain.h" | |
31 #include "alSource.h" | |
32 #include "AL/al.h" | |
33 #include "AL/alc.h" | |
34 #include "alThunk.h" | |
35 #include "alSource.h" | |
36 #include "alExtension.h" | |
37 #include "alAuxEffectSlot.h" | |
38 #include "bs2b.h" | |
39 | |
40 /////////////////////////////////////////////////////// | |
41 // DEBUG INFORMATION | |
42 | |
43 char _alDebug[256]; | |
44 | |
45 /////////////////////////////////////////////////////// | |
46 | |
47 | |
48 #define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } | |
49 static struct { | |
50 const char *name; | |
51 void (*Init)(BackendFuncs*); | |
52 BackendFuncs Funcs; | |
53 } BackendList[] = { | |
54 #ifdef HAVE_ALSA | |
55 { "alsa", alc_alsa_init, EmptyFuncs }, | |
56 #endif | |
57 #ifdef HAVE_OSS | |
58 { "oss", alc_oss_init, EmptyFuncs }, | |
59 #endif | |
60 #ifdef HAVE_DSOUND | |
61 { "dsound", alcDSoundInit, EmptyFuncs }, | |
62 #endif | |
63 #ifdef HAVE_WINMM | |
64 { "winmm", alcWinMMInit, EmptyFuncs }, | |
65 #endif | |
66 | |
67 { "wave", alc_wave_init, EmptyFuncs }, | |
68 | |
69 { NULL, NULL, EmptyFuncs } | |
70 }; | |
71 #undef EmptyFuncs | |
72 | |
73 /////////////////////////////////////////////////////// | |
74 | |
75 #define ALC_EFX_MAJOR_VERSION 0x20001 | |
76 #define ALC_EFX_MINOR_VERSION 0x20002 | |
77 #define ALC_MAX_AUXILIARY_SENDS 0x20003 | |
78 | |
79 /////////////////////////////////////////////////////// | |
80 // STRING and EXTENSIONS | |
81 | |
82 typedef struct ALCfunction_struct | |
83 { | |
84 ALCchar *funcName; | |
85 ALvoid *address; | |
86 } ALCfunction; | |
87 | |
88 static ALCfunction alcFunctions[] = { | |
89 { "alcCreateContext", (ALvoid *) alcCreateContext }, | |
90 { "alcMakeContextCurrent", (ALvoid *) alcMakeContextCurrent }, | |
91 { "alcProcessContext", (ALvoid *) alcProcessContext }, | |
92 { "alcSuspendContext", (ALvoid *) alcSuspendContext }, | |
93 { "alcDestroyContext", (ALvoid *) alcDestroyContext }, | |
94 { "alcGetCurrentContext", (ALvoid *) alcGetCurrentContext }, | |
95 { "alcGetContextsDevice", (ALvoid *) alcGetContextsDevice }, | |
96 { "alcOpenDevice", (ALvoid *) alcOpenDevice }, | |
97 { "alcCloseDevice", (ALvoid *) alcCloseDevice }, | |
98 { "alcGetError", (ALvoid *) alcGetError }, | |
99 { "alcIsExtensionPresent", (ALvoid *) alcIsExtensionPresent }, | |
100 { "alcGetProcAddress", (ALvoid *) alcGetProcAddress }, | |
101 { "alcGetEnumValue", (ALvoid *) alcGetEnumValue }, | |
102 { "alcGetString", (ALvoid *) alcGetString }, | |
103 { "alcGetIntegerv", (ALvoid *) alcGetIntegerv }, | |
104 { "alcCaptureOpenDevice", (ALvoid *) alcCaptureOpenDevice }, | |
105 { "alcCaptureCloseDevice", (ALvoid *) alcCaptureCloseDevice }, | |
106 { "alcCaptureStart", (ALvoid *) alcCaptureStart }, | |
107 { "alcCaptureStop", (ALvoid *) alcCaptureStop }, | |
108 { "alcCaptureSamples", (ALvoid *) alcCaptureSamples }, | |
109 { NULL, (ALvoid *) NULL } | |
110 }; | |
111 | |
112 static ALenums enumeration[]={ | |
113 // Types | |
114 { (ALchar *)"ALC_INVALID", ALC_INVALID }, | |
115 { (ALchar *)"ALC_FALSE", ALC_FALSE }, | |
116 { (ALchar *)"ALC_TRUE", ALC_TRUE }, | |
117 | |
118 // ALC Properties | |
119 { (ALchar *)"ALC_MAJOR_VERSION", ALC_MAJOR_VERSION }, | |
120 { (ALchar *)"ALC_MINOR_VERSION", ALC_MINOR_VERSION }, | |
121 { (ALchar *)"ALC_ATTRIBUTES_SIZE", ALC_ATTRIBUTES_SIZE }, | |
122 { (ALchar *)"ALC_ALL_ATTRIBUTES", ALC_ALL_ATTRIBUTES }, | |
123 { (ALchar *)"ALC_DEFAULT_DEVICE_SPECIFIER", ALC_DEFAULT_DEVICE_SPECIFIER }, | |
124 { (ALchar *)"ALC_DEVICE_SPECIFIER", ALC_DEVICE_SPECIFIER }, | |
125 { (ALchar *)"ALC_ALL_DEVICES_SPECIFIER", ALC_ALL_DEVICES_SPECIFIER }, | |
126 { (ALchar *)"ALC_DEFAULT_ALL_DEVICES_SPECIFIER", ALC_DEFAULT_ALL_DEVICES_SPECIFIER }, | |
127 { (ALchar *)"ALC_EXTENSIONS", ALC_EXTENSIONS }, | |
128 { (ALchar *)"ALC_FREQUENCY", ALC_FREQUENCY }, | |
129 { (ALchar *)"ALC_REFRESH", ALC_REFRESH }, | |
130 { (ALchar *)"ALC_SYNC", ALC_SYNC }, | |
131 { (ALchar *)"ALC_MONO_SOURCES", ALC_MONO_SOURCES }, | |
132 { (ALchar *)"ALC_STEREO_SOURCES", ALC_STEREO_SOURCES }, | |
133 { (ALchar *)"ALC_CAPTURE_DEVICE_SPECIFIER", ALC_CAPTURE_DEVICE_SPECIFIER }, | |
134 { (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER}, | |
135 { (ALchar *)"ALC_CAPTURE_SAMPLES", ALC_CAPTURE_SAMPLES }, | |
136 | |
137 // EFX Properties | |
138 { (ALchar *)"ALC_EFX_MAJOR_VERSION", ALC_EFX_MAJOR_VERSION }, | |
139 { (ALchar *)"ALC_EFX_MINOR_VERSION", ALC_EFX_MINOR_VERSION }, | |
140 { (ALchar *)"ALC_MAX_AUXILIARY_SENDS", ALC_MAX_AUXILIARY_SENDS }, | |
141 | |
142 // ALC Error Message | |
143 { (ALchar *)"ALC_NO_ERROR", ALC_NO_ERROR }, | |
144 { (ALchar *)"ALC_INVALID_DEVICE", ALC_INVALID_DEVICE }, | |
145 { (ALchar *)"ALC_INVALID_CONTEXT", ALC_INVALID_CONTEXT }, | |
146 { (ALchar *)"ALC_INVALID_ENUM", ALC_INVALID_ENUM }, | |
147 { (ALchar *)"ALC_INVALID_VALUE", ALC_INVALID_VALUE }, | |
148 { (ALchar *)"ALC_OUT_OF_MEMORY", ALC_OUT_OF_MEMORY }, | |
149 { (ALchar *)NULL, (ALenum)0 } | |
150 }; | |
151 // Error strings | |
152 static const ALCchar alcNoError[] = "No Error"; | |
153 static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; | |
154 static const ALCchar alcErrInvalidContext[] = "Invalid Context"; | |
155 static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; | |
156 static const ALCchar alcErrInvalidValue[] = "Invalid Value"; | |
157 static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; | |
158 | |
159 // Context strings | |
160 static ALCchar alcDeviceList[2048]; | |
161 static ALCchar alcAllDeviceList[2048]; | |
162 static ALCchar alcCaptureDeviceList[2048]; | |
163 // Default is always the first in the list | |
164 static ALCchar *alcDefaultDeviceSpecifier = alcDeviceList; | |
165 static ALCchar *alcDefaultAllDeviceSpecifier = alcAllDeviceList; | |
166 static ALCchar *alcCaptureDefaultDeviceSpecifier = alcCaptureDeviceList; | |
167 | |
168 | |
169 static ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_EFX"; | |
170 static ALCint alcMajorVersion = 1; | |
171 static ALCint alcMinorVersion = 1; | |
172 | |
173 static ALCint alcEFXMajorVersion = 1; | |
174 static ALCint alcEFXMinorVersion = 0; | |
175 | |
176 /////////////////////////////////////////////////////// | |
177 | |
178 | |
179 /////////////////////////////////////////////////////// | |
180 // Global Variables | |
181 | |
182 static ALCdevice *g_pDeviceList = NULL; | |
183 static ALCuint g_ulDeviceCount = 0; | |
184 | |
185 // Context List | |
186 static ALCcontext *g_pContextList = NULL; | |
187 static ALCuint g_ulContextCount = 0; | |
188 | |
189 // Context Error | |
190 static ALCenum g_eLastContextError = ALC_NO_ERROR; | |
191 | |
192 /////////////////////////////////////////////////////// | |
193 | |
194 | |
195 /////////////////////////////////////////////////////// | |
196 // ALC Related helper functions | |
197 | |
198 static void InitAL(void) | |
199 { | |
200 static int done = 0; | |
201 if(!done) | |
202 { | |
203 int i; | |
204 const char *devs, *str; | |
205 | |
206 done = 1; | |
207 | |
208 InitializeCriticalSection(&_alMutex); | |
209 ALTHUNK_INIT(); | |
210 ReadALConfig(); | |
211 | |
212 devs = GetConfigValue(NULL, "drivers", ""); | |
213 if(devs[0]) | |
214 { | |
215 int n; | |
216 size_t len; | |
217 const char *next = devs; | |
218 | |
219 i = 0; | |
220 | |
221 do { | |
222 devs = next; | |
223 next = strchr(devs, ','); | |
224 | |
225 if(!devs[0] || devs[0] == ',') | |
226 continue; | |
227 | |
228 len = (next ? ((size_t)(next-devs)) : strlen(devs)); | |
229 for(n = i;BackendList[n].Init;n++) | |
230 { | |
231 if(len == strlen(BackendList[n].name) && | |
232 strncmp(BackendList[n].name, devs, len) == 0) | |
233 { | |
234 const char *name = BackendList[i].name; | |
235 void (*Init)(BackendFuncs*) = BackendList[i].Init; | |
236 | |
237 BackendList[i].name = BackendList[n].name; | |
238 BackendList[i].Init = BackendList[n].Init; | |
239 | |
240 BackendList[n].name = name; | |
241 BackendList[n].Init = Init; | |
242 | |
243 i++; | |
244 } | |
245 } | |
246 } while(next++); | |
247 | |
248 BackendList[i].name = NULL; | |
249 BackendList[i].Init = NULL; | |
250 } | |
251 | |
252 for(i = 0;BackendList[i].Init;i++) | |
253 BackendList[i].Init(&BackendList[i].Funcs); | |
254 | |
255 str = GetConfigValue(NULL, "stereodup", "false"); | |
256 DuplicateStereo = (strcasecmp(str, "true") == 0 || | |
257 strcasecmp(str, "yes") == 0 || | |
258 strcasecmp(str, "on") == 0 || | |
259 atoi(str) != 0); | |
260 } | |
261 } | |
262 | |
263 ALCchar *AppendDeviceList(char *name) | |
264 { | |
265 static size_t pos; | |
266 ALCchar *ret = alcDeviceList+pos; | |
267 if(pos >= sizeof(alcDeviceList)) | |
268 { | |
269 AL_PRINT("Not enough room to add %s!\n", name); | |
270 return alcDeviceList + sizeof(alcDeviceList) - 1; | |
271 } | |
272 pos += snprintf(alcDeviceList+pos, sizeof(alcDeviceList)-pos-1, "%s", name) + 1; | |
273 return ret; | |
274 } | |
275 | |
276 ALCchar *AppendAllDeviceList(char *name) | |
277 { | |
278 static size_t pos; | |
279 ALCchar *ret = alcAllDeviceList+pos; | |
280 if(pos >= sizeof(alcAllDeviceList)) | |
281 { | |
282 AL_PRINT("Not enough room to add %s!\n", name); | |
283 return alcAllDeviceList + sizeof(alcAllDeviceList) - 1; | |
284 } | |
285 pos += snprintf(alcAllDeviceList+pos, sizeof(alcAllDeviceList)-pos-1, "%s", name) + 1; | |
286 return ret; | |
287 } | |
288 | |
289 ALCchar *AppendCaptureDeviceList(char *name) | |
290 { | |
291 static size_t pos; | |
292 ALCchar *ret = alcCaptureDeviceList+pos; | |
293 if(pos >= sizeof(alcCaptureDeviceList)) | |
294 { | |
295 AL_PRINT("Not enough room to add %s!\n", name); | |
296 return alcCaptureDeviceList + sizeof(alcCaptureDeviceList) - 1; | |
297 } | |
298 pos += snprintf(alcCaptureDeviceList+pos, sizeof(alcCaptureDeviceList)-pos-1, "%s", name) + 1; | |
299 return ret; | |
300 } | |
301 | |
302 /* | |
303 IsContext | |
304 | |
305 Check pContext is a valid Context pointer | |
306 */ | |
307 static ALCboolean IsContext(ALCcontext *pContext) | |
308 { | |
309 ALCcontext *pTempContext; | |
310 | |
311 pTempContext = g_pContextList; | |
312 while (pTempContext && pTempContext != pContext) | |
313 pTempContext = pTempContext->next; | |
314 | |
315 return (pTempContext ? ALC_TRUE : ALC_FALSE); | |
316 } | |
317 | |
318 | |
319 /* | |
320 SetALCError | |
321 | |
322 Store latest ALC Error | |
323 */ | |
324 ALCvoid SetALCError(ALenum errorCode) | |
325 { | |
326 g_eLastContextError = errorCode; | |
327 } | |
328 | |
329 | |
330 /* | |
331 SuspendContext | |
332 | |
333 Thread-safe entry | |
334 */ | |
335 ALCvoid SuspendContext(ALCcontext *pContext) | |
336 { | |
337 (void)pContext; | |
338 EnterCriticalSection(&_alMutex); | |
339 } | |
340 | |
341 | |
342 /* | |
343 ProcessContext | |
344 | |
345 Thread-safe exit | |
346 */ | |
347 ALCvoid ProcessContext(ALCcontext *pContext) | |
348 { | |
349 (void)pContext; | |
350 LeaveCriticalSection(&_alMutex); | |
351 } | |
352 | |
353 | |
354 /* | |
355 InitContext | |
356 | |
357 Initialize Context variables | |
358 */ | |
359 static ALvoid InitContext(ALCcontext *pContext) | |
360 { | |
361 int level; | |
362 | |
363 //Initialise listener | |
364 pContext->Listener.Gain = 1.0f; | |
365 pContext->Listener.MetersPerUnit = 1.0f; | |
366 pContext->Listener.Position[0] = 0.0f; | |
367 pContext->Listener.Position[1] = 0.0f; | |
368 pContext->Listener.Position[2] = 0.0f; | |
369 pContext->Listener.Velocity[0] = 0.0f; | |
370 pContext->Listener.Velocity[1] = 0.0f; | |
371 pContext->Listener.Velocity[2] = 0.0f; | |
372 pContext->Listener.Forward[0] = 0.0f; | |
373 pContext->Listener.Forward[1] = 0.0f; | |
374 pContext->Listener.Forward[2] = -1.0f; | |
375 pContext->Listener.Up[0] = 0.0f; | |
376 pContext->Listener.Up[1] = 1.0f; | |
377 pContext->Listener.Up[2] = 0.0f; | |
378 | |
379 //Validate pContext | |
380 pContext->LastError = AL_NO_ERROR; | |
381 pContext->InUse = AL_FALSE; | |
382 | |
383 //Set output format | |
384 pContext->Frequency = pContext->Device->Frequency; | |
385 | |
386 //Set globals | |
387 pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED; | |
388 pContext->DopplerFactor = 1.0f; | |
389 pContext->DopplerVelocity = 1.0f; | |
390 pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC; | |
391 | |
392 pContext->lNumStereoSources = 1; | |
393 pContext->lNumMonoSources = pContext->Device->MaxNoOfSources - pContext->lNumStereoSources; | |
394 | |
395 strcpy(pContext->ExtensionList, "AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_OFFSET AL_LOKI_quadriphonic"); | |
396 | |
397 level = GetConfigValueInt(NULL, "cf_level", 0); | |
398 if(level > 0 && level <= 6) | |
399 { | |
400 pContext->bs2b = calloc(1, sizeof(*pContext->bs2b)); | |
401 bs2b_set_srate(pContext->bs2b, pContext->Frequency); | |
402 bs2b_set_level(pContext->bs2b, level); | |
403 } | |
404 } | |
405 | |
406 | |
407 /* | |
408 ExitContext | |
409 | |
410 Clean up Context, destroy any remaining Sources | |
411 */ | |
412 static ALCvoid ExitContext(ALCcontext *pContext) | |
413 { | |
414 //Invalidate context | |
415 pContext->LastError = AL_NO_ERROR; | |
416 pContext->InUse = AL_FALSE; | |
417 | |
418 free(pContext->bs2b); | |
419 pContext->bs2b = NULL; | |
420 } | |
421 | |
422 /////////////////////////////////////////////////////// | |
423 | |
424 | |
425 /////////////////////////////////////////////////////// | |
426 // ALC Functions calls | |
427 | |
428 | |
429 // This should probably move to another c file but for now ... | |
430 ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) | |
431 { | |
432 ALCboolean DeviceFound = ALC_FALSE; | |
433 ALCdevice *pDevice = NULL; | |
434 ALCint i; | |
435 | |
436 InitAL(); | |
437 | |
438 if(deviceName && !deviceName[0]) | |
439 deviceName = NULL; | |
440 | |
441 pDevice = malloc(sizeof(ALCdevice)); | |
442 if (pDevice) | |
443 { | |
444 if (SampleSize > 0) | |
445 { | |
446 //Initialise device structure | |
447 memset(pDevice, 0, sizeof(ALCdevice)); | |
448 | |
449 //Validate device | |
450 pDevice->IsCaptureDevice = AL_TRUE; | |
451 | |
452 pDevice->Frequency = frequency; | |
453 pDevice->Format = format; | |
454 | |
455 for(i = 0;BackendList[i].Init;i++) | |
456 { | |
457 pDevice->Funcs = &BackendList[i].Funcs; | |
458 if(ALCdevice_OpenCapture(pDevice, deviceName, frequency, format, SampleSize)) | |
459 { | |
460 SuspendContext(NULL); | |
461 pDevice->next = g_pDeviceList; | |
462 g_pDeviceList = pDevice; | |
463 g_ulDeviceCount++; | |
464 ProcessContext(NULL); | |
465 | |
466 DeviceFound = ALC_TRUE; | |
467 break; | |
468 } | |
469 } | |
470 } | |
471 else | |
472 SetALCError(ALC_INVALID_VALUE); | |
473 | |
474 if(!DeviceFound) | |
475 { | |
476 free(pDevice); | |
477 pDevice = NULL; | |
478 } | |
479 } | |
480 else | |
481 SetALCError(ALC_OUT_OF_MEMORY); | |
482 | |
483 return pDevice; | |
484 } | |
485 | |
486 ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice(ALCdevice *pDevice) | |
487 { | |
488 ALCboolean bReturn = ALC_FALSE; | |
489 ALCdevice **list; | |
490 | |
491 if ((pDevice)&&(pDevice->IsCaptureDevice)) | |
492 { | |
493 SuspendContext(NULL); | |
494 | |
495 list = &g_pDeviceList; | |
496 while(*list != pDevice) | |
497 list = &(*list)->next; | |
498 | |
499 *list = (*list)->next; | |
500 g_ulDeviceCount--; | |
501 | |
502 ProcessContext(NULL); | |
503 | |
504 ALCdevice_CloseCapture(pDevice); | |
505 free(pDevice); | |
506 | |
507 bReturn = ALC_TRUE; | |
508 } | |
509 else | |
510 SetALCError(ALC_INVALID_DEVICE); | |
511 | |
512 return bReturn; | |
513 } | |
514 | |
515 ALCAPI void ALCAPIENTRY alcCaptureStart(ALCdevice *pDevice) | |
516 { | |
517 if ((pDevice)&&(pDevice->IsCaptureDevice)) | |
518 ALCdevice_StartCapture(pDevice); | |
519 else | |
520 SetALCError(ALC_INVALID_DEVICE); | |
521 } | |
522 | |
523 ALCAPI void ALCAPIENTRY alcCaptureStop(ALCdevice *pDevice) | |
524 { | |
525 if ((pDevice)&&(pDevice->IsCaptureDevice)) | |
526 ALCdevice_StopCapture(pDevice); | |
527 else | |
528 SetALCError(ALC_INVALID_DEVICE); | |
529 } | |
530 | |
531 ALCAPI void ALCAPIENTRY alcCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCsizei lSamples) | |
532 { | |
533 if ((pDevice) && (pDevice->IsCaptureDevice)) | |
534 ALCdevice_CaptureSamples(pDevice, pBuffer, lSamples); | |
535 else | |
536 SetALCError(ALC_INVALID_DEVICE); | |
537 } | |
538 | |
539 /* | |
540 alcGetError | |
541 | |
542 Return last ALC generated error code | |
543 */ | |
544 ALCAPI ALCenum ALCAPIENTRY alcGetError(ALCdevice *device) | |
545 { | |
546 ALCenum errorCode; | |
547 | |
548 (void)device; | |
549 | |
550 errorCode = g_eLastContextError; | |
551 g_eLastContextError = ALC_NO_ERROR; | |
552 return errorCode; | |
553 } | |
554 | |
555 | |
556 /* | |
557 alcSuspendContext | |
558 | |
559 Not functional | |
560 */ | |
561 ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext *pContext) | |
562 { | |
563 // Not a lot happens here ! | |
564 (void)pContext; | |
565 } | |
566 | |
567 | |
568 /* | |
569 alcProcessContext | |
570 | |
571 Not functional | |
572 */ | |
573 ALCAPI ALCvoid ALCAPIENTRY alcProcessContext(ALCcontext *pContext) | |
574 { | |
575 // Not a lot happens here ! | |
576 (void)pContext; | |
577 } | |
578 | |
579 | |
580 /* | |
581 alcGetString | |
582 | |
583 Returns information about the Device, and error strings | |
584 */ | |
585 ALCAPI const ALCchar* ALCAPIENTRY alcGetString(ALCdevice *pDevice,ALCenum param) | |
586 { | |
587 const ALCchar *value = NULL; | |
588 | |
589 InitAL(); | |
590 | |
591 switch (param) | |
592 { | |
593 case ALC_NO_ERROR: | |
594 value = alcNoError; | |
595 break; | |
596 | |
597 case ALC_INVALID_ENUM: | |
598 value = alcErrInvalidEnum; | |
599 break; | |
600 | |
601 case ALC_INVALID_VALUE: | |
602 value = alcErrInvalidValue; | |
603 break; | |
604 | |
605 case ALC_INVALID_DEVICE: | |
606 value = alcErrInvalidDevice; | |
607 break; | |
608 | |
609 case ALC_INVALID_CONTEXT: | |
610 value = alcErrInvalidContext; | |
611 break; | |
612 | |
613 case ALC_OUT_OF_MEMORY: | |
614 value = alcErrOutOfMemory; | |
615 break; | |
616 | |
617 case ALC_DEFAULT_DEVICE_SPECIFIER: | |
618 value = alcDefaultDeviceSpecifier; | |
619 break; | |
620 | |
621 case ALC_DEVICE_SPECIFIER: | |
622 if (pDevice) | |
623 value = pDevice->szDeviceName; | |
624 else | |
625 value = alcDeviceList; | |
626 break; | |
627 | |
628 case ALC_ALL_DEVICES_SPECIFIER: | |
629 value = alcAllDeviceList; | |
630 break; | |
631 | |
632 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: | |
633 value = alcDefaultAllDeviceSpecifier; | |
634 break; | |
635 | |
636 case ALC_CAPTURE_DEVICE_SPECIFIER: | |
637 if (pDevice) | |
638 value = pDevice->szDeviceName; | |
639 else | |
640 value = alcCaptureDeviceList; | |
641 break; | |
642 | |
643 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: | |
644 value = alcCaptureDefaultDeviceSpecifier; | |
645 break; | |
646 | |
647 case ALC_EXTENSIONS: | |
648 value = alcExtensionList; | |
649 break; | |
650 | |
651 default: | |
652 SetALCError(ALC_INVALID_ENUM); | |
653 break; | |
654 } | |
655 | |
656 return value; | |
657 } | |
658 | |
659 | |
660 /* | |
661 alcGetIntegerv | |
662 | |
663 Returns information about the Device and the version of Open AL | |
664 */ | |
665 ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data) | |
666 { | |
667 InitAL(); | |
668 | |
669 if ((device)&&(device->IsCaptureDevice)) | |
670 { | |
671 SuspendContext(NULL); | |
672 | |
673 // Capture device | |
674 switch (param) | |
675 { | |
676 case ALC_CAPTURE_SAMPLES: | |
677 if ((size) && (data)) | |
678 *data = ALCdevice_AvailableSamples(device); | |
679 else | |
680 SetALCError(ALC_INVALID_VALUE); | |
681 break; | |
682 | |
683 default: | |
684 SetALCError(ALC_INVALID_ENUM); | |
685 break; | |
686 } | |
687 | |
688 ProcessContext(NULL); | |
689 } | |
690 else | |
691 { | |
692 if(data) | |
693 { | |
694 // Playback Device | |
695 switch (param) | |
696 { | |
697 case ALC_MAJOR_VERSION: | |
698 if(!size) | |
699 SetALCError(ALC_INVALID_VALUE); | |
700 else | |
701 *data = alcMajorVersion; | |
702 break; | |
703 | |
704 case ALC_MINOR_VERSION: | |
705 if(!size) | |
706 SetALCError(ALC_INVALID_VALUE); | |
707 else | |
708 *data = alcMinorVersion; | |
709 break; | |
710 | |
711 case ALC_EFX_MAJOR_VERSION: | |
712 if(!size) | |
713 SetALCError(ALC_INVALID_VALUE); | |
714 else | |
715 *data = alcEFXMajorVersion; | |
716 break; | |
717 | |
718 case ALC_EFX_MINOR_VERSION: | |
719 if(!size) | |
720 SetALCError(ALC_INVALID_VALUE); | |
721 else | |
722 *data = alcEFXMinorVersion; | |
723 break; | |
724 | |
725 case ALC_MAX_AUXILIARY_SENDS: | |
726 if(!size) | |
727 SetALCError(ALC_INVALID_VALUE); | |
728 else | |
729 *data = MAX_SENDS; | |
730 break; | |
731 | |
732 case ALC_ATTRIBUTES_SIZE: | |
733 if(!device) | |
734 SetALCError(ALC_INVALID_DEVICE); | |
735 else if(!size) | |
736 SetALCError(ALC_INVALID_VALUE); | |
737 else | |
738 *data = 12; | |
739 break; | |
740 | |
741 case ALC_ALL_ATTRIBUTES: | |
742 if(!device) | |
743 SetALCError(ALC_INVALID_DEVICE); | |
744 else if (size < 7) | |
745 SetALCError(ALC_INVALID_VALUE); | |
746 else | |
747 { | |
748 int i = 0; | |
749 | |
750 data[i++] = ALC_FREQUENCY; | |
751 data[i++] = device->Frequency; | |
752 | |
753 data[i++] = ALC_REFRESH; | |
754 data[i++] = device->Frequency / device->UpdateSize; | |
755 | |
756 data[i++] = ALC_SYNC; | |
757 data[i++] = ALC_FALSE; | |
758 | |
759 SuspendContext(NULL); | |
760 if(device->Context && size >= 12) | |
761 { | |
762 data[i++] = ALC_MONO_SOURCES; | |
763 data[i++] = device->Context->lNumMonoSources; | |
764 | |
765 data[i++] = ALC_STEREO_SOURCES; | |
766 data[i++] = device->Context->lNumStereoSources; | |
767 | |
768 data[i++] = ALC_MAX_AUXILIARY_SENDS; | |
769 data[i++] = MAX_SENDS; | |
770 } | |
771 ProcessContext(NULL); | |
772 | |
773 data[i++] = 0; | |
774 } | |
775 break; | |
776 | |
777 case ALC_FREQUENCY: | |
778 if(!device) | |
779 SetALCError(ALC_INVALID_DEVICE); | |
780 else if(!size) | |
781 SetALCError(ALC_INVALID_VALUE); | |
782 else | |
783 *data = device->Frequency; | |
784 break; | |
785 | |
786 case ALC_REFRESH: | |
787 if(!device) | |
788 SetALCError(ALC_INVALID_DEVICE); | |
789 else if(!size) | |
790 SetALCError(ALC_INVALID_VALUE); | |
791 else | |
792 *data = device->Frequency / device->UpdateSize; | |
793 break; | |
794 | |
795 case ALC_SYNC: | |
796 if(!device) | |
797 SetALCError(ALC_INVALID_DEVICE); | |
798 else if(!size) | |
799 SetALCError(ALC_INVALID_VALUE); | |
800 else | |
801 *data = ALC_FALSE; | |
802 break; | |
803 | |
804 case ALC_MONO_SOURCES: | |
805 if(!device || !device->Context) | |
806 SetALCError(ALC_INVALID_DEVICE); | |
807 else if (size != 1) | |
808 SetALCError(ALC_INVALID_VALUE); | |
809 else | |
810 *data = device->Context->lNumMonoSources; | |
811 break; | |
812 | |
813 case ALC_STEREO_SOURCES: | |
814 if(!device || !device->Context) | |
815 SetALCError(ALC_INVALID_DEVICE); | |
816 else if (size != 1) | |
817 SetALCError(ALC_INVALID_VALUE); | |
818 else | |
819 *data = device->Context->lNumStereoSources; | |
820 break; | |
821 | |
822 default: | |
823 SetALCError(ALC_INVALID_ENUM); | |
824 break; | |
825 } | |
826 } | |
827 else if(size) | |
828 SetALCError(ALC_INVALID_VALUE); | |
829 } | |
830 | |
831 return; | |
832 } | |
833 | |
834 | |
835 /* | |
836 alcIsExtensionPresent | |
837 | |
838 Determines if there is support for a particular extension | |
839 */ | |
840 ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) | |
841 { | |
842 ALCboolean bResult = ALC_FALSE; | |
843 | |
844 (void)device; | |
845 | |
846 if (extName) | |
847 { | |
848 const char *ptr; | |
849 size_t len; | |
850 | |
851 len = strlen(extName); | |
852 ptr = alcExtensionList; | |
853 while(ptr && *ptr) | |
854 { | |
855 if(strncasecmp(ptr, extName, len) == 0 && | |
856 (ptr[len] == '\0' || isspace(ptr[len]))) | |
857 { | |
858 bResult = ALC_TRUE; | |
859 break; | |
860 } | |
861 if((ptr=strchr(ptr, ' ')) != NULL) | |
862 { | |
863 do { | |
864 ++ptr; | |
865 } while(isspace(*ptr)); | |
866 } | |
867 } | |
868 } | |
869 else | |
870 SetALCError(ALC_INVALID_VALUE); | |
871 | |
872 return bResult; | |
873 } | |
874 | |
875 | |
876 /* | |
877 alcGetProcAddress | |
878 | |
879 Retrieves the function address for a particular extension function | |
880 */ | |
881 ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) | |
882 { | |
883 ALCvoid *pFunction = NULL; | |
884 ALsizei i = 0; | |
885 | |
886 (void)device; | |
887 | |
888 if (funcName) | |
889 { | |
890 while(alcFunctions[i].funcName && | |
891 strcmp(alcFunctions[i].funcName,funcName) != 0) | |
892 i++; | |
893 pFunction = alcFunctions[i].address; | |
894 } | |
895 else | |
896 SetALCError(ALC_INVALID_VALUE); | |
897 | |
898 return pFunction; | |
899 } | |
900 | |
901 | |
902 /* | |
903 alcGetEnumValue | |
904 | |
905 Get the value for a particular ALC Enumerated Value | |
906 */ | |
907 ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) | |
908 { | |
909 ALsizei i = 0; | |
910 ALCenum val; | |
911 | |
912 (void)device; | |
913 | |
914 while ((enumeration[i].enumName)&&(strcmp(enumeration[i].enumName,enumName))) | |
915 i++; | |
916 val = enumeration[i].value; | |
917 | |
918 if(!enumeration[i].enumName) | |
919 SetALCError(ALC_INVALID_VALUE); | |
920 | |
921 return val; | |
922 } | |
923 | |
924 | |
925 /* | |
926 alcCreateContext | |
927 | |
928 Create and attach a Context to a particular Device. | |
929 */ | |
930 ALCAPI ALCcontext* ALCAPIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) | |
931 { | |
932 ALCcontext *ALContext = NULL; | |
933 ALuint ulAttributeIndex, ulRequestedStereoSources; | |
934 | |
935 if ((device)&&(!device->IsCaptureDevice)) | |
936 { | |
937 // Reset Context Last Error code | |
938 g_eLastContextError = ALC_NO_ERROR; | |
939 | |
940 // Current implementation only allows one Context per Device | |
941 if(!device->Context) | |
942 { | |
943 ALContext = calloc(1, sizeof(ALCcontext)); | |
944 if(!ALContext) | |
945 { | |
946 SetALCError(ALC_OUT_OF_MEMORY); | |
947 return NULL; | |
948 } | |
949 | |
950 ALContext->Device = device; | |
951 InitContext(ALContext); | |
952 | |
953 device->Context = ALContext; | |
954 | |
955 SuspendContext(NULL); | |
956 | |
957 ALContext->next = g_pContextList; | |
958 g_pContextList = ALContext; | |
959 g_ulContextCount++; | |
960 | |
961 ProcessContext(NULL); | |
962 | |
963 // Check for Voice Count attributes | |
964 if (attrList) | |
965 { | |
966 ulAttributeIndex = 0; | |
967 while ((ulAttributeIndex < 10) && (attrList[ulAttributeIndex])) | |
968 { | |
969 if (attrList[ulAttributeIndex] == ALC_STEREO_SOURCES) | |
970 { | |
971 ulRequestedStereoSources = attrList[ulAttributeIndex + 1]; | |
972 | |
973 if (ulRequestedStereoSources > ALContext->Device->MaxNoOfSources) | |
974 ulRequestedStereoSources = ALContext->Device->MaxNoOfSources; | |
975 | |
976 ALContext->lNumStereoSources = ulRequestedStereoSources; | |
977 ALContext->lNumMonoSources = ALContext->Device->MaxNoOfSources - ALContext->lNumStereoSources; | |
978 break; | |
979 } | |
980 | |
981 ulAttributeIndex += 2; | |
982 } | |
983 } | |
984 } | |
985 else | |
986 { | |
987 SetALCError(ALC_INVALID_VALUE); | |
988 ALContext = NULL; | |
989 } | |
990 } | |
991 else | |
992 SetALCError(ALC_INVALID_DEVICE); | |
993 | |
994 return ALContext; | |
995 } | |
996 | |
997 | |
998 /* | |
999 alcDestroyContext | |
1000 | |
1001 Remove a Context | |
1002 */ | |
1003 ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context) | |
1004 { | |
1005 ALCcontext **list; | |
1006 | |
1007 InitAL(); | |
1008 | |
1009 // Lock context list | |
1010 SuspendContext(NULL); | |
1011 | |
1012 if (IsContext(context)) | |
1013 { | |
1014 // Lock context | |
1015 SuspendContext(context); | |
1016 | |
1017 ReleaseALSources(context); | |
1018 ReleaseALAuxiliaryEffectSlots(context); | |
1019 | |
1020 context->Device->Context = NULL; | |
1021 | |
1022 list = &g_pContextList; | |
1023 while(*list != context) | |
1024 list = &(*list)->next; | |
1025 | |
1026 *list = (*list)->next; | |
1027 g_ulContextCount--; | |
1028 | |
1029 // Unlock context | |
1030 ProcessContext(context); | |
1031 | |
1032 ExitContext(context); | |
1033 | |
1034 // Free memory (MUST do this after ProcessContext) | |
1035 memset(context, 0, sizeof(ALCcontext)); | |
1036 free(context); | |
1037 } | |
1038 else | |
1039 SetALCError(ALC_INVALID_CONTEXT); | |
1040 | |
1041 ProcessContext(NULL); | |
1042 } | |
1043 | |
1044 | |
1045 /* | |
1046 alcGetCurrentContext | |
1047 | |
1048 Returns the currently active Context | |
1049 */ | |
1050 ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext(ALCvoid) | |
1051 { | |
1052 ALCcontext *pContext = NULL; | |
1053 | |
1054 InitAL(); | |
1055 | |
1056 SuspendContext(NULL); | |
1057 | |
1058 pContext = g_pContextList; | |
1059 while ((pContext) && (!pContext->InUse)) | |
1060 pContext = pContext->next; | |
1061 | |
1062 ProcessContext(NULL); | |
1063 | |
1064 return pContext; | |
1065 } | |
1066 | |
1067 | |
1068 /* | |
1069 alcGetContextsDevice | |
1070 | |
1071 Returns the Device that a particular Context is attached to | |
1072 */ | |
1073 ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *pContext) | |
1074 { | |
1075 ALCdevice *pDevice = NULL; | |
1076 | |
1077 InitAL(); | |
1078 | |
1079 SuspendContext(NULL); | |
1080 if (IsContext(pContext)) | |
1081 pDevice = pContext->Device; | |
1082 else | |
1083 SetALCError(ALC_INVALID_CONTEXT); | |
1084 ProcessContext(NULL); | |
1085 | |
1086 return pDevice; | |
1087 } | |
1088 | |
1089 | |
1090 /* | |
1091 alcMakeContextCurrent | |
1092 | |
1093 Makes the given Context the active Context | |
1094 */ | |
1095 ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context) | |
1096 { | |
1097 ALCcontext *ALContext; | |
1098 ALboolean bReturn = AL_TRUE; | |
1099 | |
1100 InitAL(); | |
1101 | |
1102 SuspendContext(NULL); | |
1103 | |
1104 // context must be a valid Context or NULL | |
1105 if ((IsContext(context)) || (context == NULL)) | |
1106 { | |
1107 if ((ALContext=alcGetCurrentContext())) | |
1108 { | |
1109 SuspendContext(ALContext); | |
1110 ALContext->InUse=AL_FALSE; | |
1111 ProcessContext(ALContext); | |
1112 } | |
1113 | |
1114 if ((ALContext=context) && (ALContext->Device)) | |
1115 { | |
1116 SuspendContext(ALContext); | |
1117 ALContext->InUse=AL_TRUE; | |
1118 ProcessContext(ALContext); | |
1119 } | |
1120 } | |
1121 else | |
1122 { | |
1123 SetALCError(ALC_INVALID_CONTEXT); | |
1124 bReturn = AL_FALSE; | |
1125 } | |
1126 | |
1127 ProcessContext(NULL); | |
1128 | |
1129 return bReturn; | |
1130 } | |
1131 | |
1132 | |
1133 /* | |
1134 alcOpenDevice | |
1135 | |
1136 Open the Device specified. | |
1137 */ | |
1138 ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(const ALCchar *deviceName) | |
1139 { | |
1140 ALboolean bDeviceFound = AL_FALSE; | |
1141 ALCdevice *device; | |
1142 ALint i; | |
1143 | |
1144 InitAL(); | |
1145 | |
1146 if(deviceName && !deviceName[0]) | |
1147 deviceName = NULL; | |
1148 | |
1149 device = malloc(sizeof(ALCdevice)); | |
1150 if (device) | |
1151 { | |
1152 const char *fmt; | |
1153 | |
1154 //Initialise device structure | |
1155 memset(device, 0, sizeof(ALCdevice)); | |
1156 | |
1157 //Validate device | |
1158 device->IsCaptureDevice = AL_FALSE; | |
1159 | |
1160 //Set output format | |
1161 device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE); | |
1162 if((ALint)device->Frequency <= 0) | |
1163 device->Frequency = SWMIXER_OUTPUT_RATE; | |
1164 | |
1165 fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16"); | |
1166 if(fmt[0]) | |
1167 device->Format = alGetEnumValue(fmt); | |
1168 | |
1169 if(!aluChannelsFromFormat(device->Format)) | |
1170 device->Format = AL_FORMAT_STEREO16; | |
1171 | |
1172 device->UpdateSize = GetConfigValueInt(NULL, "refresh", 8192); | |
1173 if((ALint)device->UpdateSize <= 0) | |
1174 device->UpdateSize = 8192; | |
1175 | |
1176 device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256); | |
1177 if((ALint)device->MaxNoOfSources <= 0) | |
1178 device->MaxNoOfSources = 256; | |
1179 | |
1180 // Find a playback device to open | |
1181 for(i = 0;BackendList[i].Init;i++) | |
1182 { | |
1183 device->Funcs = &BackendList[i].Funcs; | |
1184 if(ALCdevice_OpenPlayback(device, deviceName)) | |
1185 { | |
1186 SuspendContext(NULL); | |
1187 device->next = g_pDeviceList; | |
1188 g_pDeviceList = device; | |
1189 g_ulDeviceCount++; | |
1190 ProcessContext(NULL); | |
1191 | |
1192 bDeviceFound = AL_TRUE; | |
1193 break; | |
1194 } | |
1195 } | |
1196 | |
1197 if (!bDeviceFound) | |
1198 { | |
1199 // No suitable output device found | |
1200 free(device); | |
1201 device = NULL; | |
1202 } | |
1203 } | |
1204 | |
1205 return device; | |
1206 } | |
1207 | |
1208 | |
1209 /* | |
1210 alcCloseDevice | |
1211 | |
1212 Close the specified Device | |
1213 */ | |
1214 ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice(ALCdevice *pDevice) | |
1215 { | |
1216 ALCboolean bReturn = ALC_FALSE; | |
1217 ALCdevice **list; | |
1218 | |
1219 if ((pDevice)&&(!pDevice->IsCaptureDevice)) | |
1220 { | |
1221 SuspendContext(NULL); | |
1222 | |
1223 list = &g_pDeviceList; | |
1224 while(*list != pDevice) | |
1225 list = &(*list)->next; | |
1226 | |
1227 *list = (*list)->next; | |
1228 g_ulDeviceCount--; | |
1229 | |
1230 ProcessContext(NULL); | |
1231 | |
1232 if(pDevice->Context) | |
1233 alcDestroyContext(pDevice->Context); | |
1234 ALCdevice_ClosePlayback(pDevice); | |
1235 | |
1236 //Release device structure | |
1237 memset(pDevice, 0, sizeof(ALCdevice)); | |
1238 free(pDevice); | |
1239 | |
1240 bReturn = ALC_TRUE; | |
1241 } | |
1242 else | |
1243 SetALCError(ALC_INVALID_DEVICE); | |
1244 | |
1245 return bReturn; | |
1246 } | |
1247 | |
1248 | |
1249 ALCvoid ReleaseALC(ALCvoid) | |
1250 { | |
1251 #ifdef _DEBUG | |
1252 if(g_ulContextCount > 0) | |
1253 AL_PRINT("exit() %u device(s) and %u context(s) NOT deleted\n", g_ulDeviceCount, g_ulContextCount); | |
1254 #endif | |
1255 | |
1256 while(g_pDeviceList) | |
1257 { | |
1258 if(g_pDeviceList->IsCaptureDevice) | |
1259 alcCaptureCloseDevice(g_pDeviceList); | |
1260 else | |
1261 alcCloseDevice(g_pDeviceList); | |
1262 } | |
1263 } | |
1264 | |
1265 /////////////////////////////////////////////////////// |