Mark new functions as added in 1.1
[alure.git] / src / alure.cpp
blob2a0a47224e49e85df3a10ccb5469c9b5fa99ce22
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (C) 2009 by Chris Robinson.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 /* Title: Main and Miscellanious */
23 #include "config.h"
25 #include "main.h"
27 #include <string.h>
28 #include <errno.h>
29 #include <time.h>
30 #ifdef HAVE_WINDOWS_H
31 #include <windows.h>
32 #endif
34 #include <vector>
35 #include <string>
36 #include <map>
38 std::map<ALint,UserCallbacks> InstalledCallbacks;
39 CRITICAL_SECTION cs_StreamPlay;
40 alureStream::ListType alureStream::StreamList;
42 void *vorbisfile_handle = NULL;
43 void *flac_handle = NULL;
44 void *dumb_handle = NULL;
45 void *mp123_handle = NULL;
46 void *sndfile_handle = NULL;
48 #define MAKE_FUNC(x) typeof(x)* p##x
49 #ifdef HAS_VORBISFILE
50 MAKE_FUNC(ov_clear);
51 MAKE_FUNC(ov_info);
52 MAKE_FUNC(ov_open_callbacks);
53 MAKE_FUNC(ov_pcm_seek);
54 MAKE_FUNC(ov_read);
55 #endif
56 #ifdef HAS_FLAC
57 MAKE_FUNC(FLAC__stream_decoder_get_state);
58 MAKE_FUNC(FLAC__stream_decoder_finish);
59 MAKE_FUNC(FLAC__stream_decoder_new);
60 MAKE_FUNC(FLAC__stream_decoder_seek_absolute);
61 MAKE_FUNC(FLAC__stream_decoder_delete);
62 MAKE_FUNC(FLAC__stream_decoder_process_single);
63 MAKE_FUNC(FLAC__stream_decoder_init_stream);
64 #endif
65 #ifdef HAS_DUMB
66 MAKE_FUNC(dumbfile_open_ex);
67 MAKE_FUNC(dumbfile_close);
68 MAKE_FUNC(dumb_read_mod);
69 MAKE_FUNC(dumb_read_s3m);
70 MAKE_FUNC(dumb_read_xm);
71 MAKE_FUNC(dumb_read_it);
72 MAKE_FUNC(dumb_silence);
73 MAKE_FUNC(duh_sigrenderer_generate_samples);
74 MAKE_FUNC(duh_get_it_sigrenderer);
75 MAKE_FUNC(duh_end_sigrenderer);
76 MAKE_FUNC(unload_duh);
77 MAKE_FUNC(dumb_it_start_at_order);
78 MAKE_FUNC(dumb_it_set_loop_callback);
79 MAKE_FUNC(dumb_it_sr_get_speed);
80 MAKE_FUNC(dumb_it_sr_set_speed);
81 #endif
82 #ifdef HAS_MPG123
83 MAKE_FUNC(mpg123_read);
84 MAKE_FUNC(mpg123_init);
85 MAKE_FUNC(mpg123_open_feed);
86 MAKE_FUNC(mpg123_new);
87 MAKE_FUNC(mpg123_delete);
88 MAKE_FUNC(mpg123_feed);
89 MAKE_FUNC(mpg123_exit);
90 MAKE_FUNC(mpg123_getformat);
91 MAKE_FUNC(mpg123_format_none);
92 MAKE_FUNC(mpg123_decode);
93 MAKE_FUNC(mpg123_format);
94 #endif
95 #ifdef HAS_SNDFILE
96 MAKE_FUNC(sf_close);
97 MAKE_FUNC(sf_open_virtual);
98 MAKE_FUNC(sf_readf_short);
99 MAKE_FUNC(sf_seek);
100 #endif
101 #undef MAKE_FUNC
103 #if defined(_WIN32) && !defined(ALURE_STATIC_LIBRARY)
104 static void init_alure(void);
105 static void deinit_alure(void);
106 static struct MyConstructorClass {
107 ~MyConstructorClass()
108 { alureStream::Clear(); };
109 } MyConstructor;
111 extern "C" BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
113 (void)reserved;
115 // Perform actions based on the reason for calling.
116 switch(reason)
118 case DLL_PROCESS_ATTACH:
119 DisableThreadLibraryCalls(module);
120 init_alure();
121 break;
123 case DLL_PROCESS_DETACH:
124 deinit_alure();
125 break;
127 return TRUE;
129 #elif defined(HAVE_GCC_CONSTRUCTOR)
130 static void init_alure(void) __attribute__((constructor));
131 static void deinit_alure(void) __attribute__((destructor));
132 static struct MyConstructorClass {
133 ~MyConstructorClass()
134 { alureStream::Clear(); };
135 } MyConstructor;
136 #else
137 static void init_alure(void);
138 static void deinit_alure(void);
140 static struct MyConstructorClass {
141 MyConstructorClass()
142 { init_alure(); };
143 ~MyConstructorClass()
144 { alureStream::Clear();
145 deinit_alure(); };
146 } MyConstructor;
147 #endif
149 #ifndef _WIN32
151 #ifdef DYNLOAD
152 static inline void *LoadLibraryA(const char *libname)
154 void *hdl = dlopen(libname, RTLD_NOW);
155 const char *err;
156 if((err=dlerror()) != NULL)
158 fprintf(stderr, "Error loading %s: %s\n", libname, err);
159 return NULL;
161 return hdl;
163 static inline void *GetProcAddress(void *hdl, const char *funcname)
165 void *fn = dlsym(hdl, funcname);
166 const char *err;
167 if((err=dlerror()) != NULL)
169 fprintf(stderr, "Error loading %s: %s\n", funcname, err);
170 return NULL;
172 return fn;
174 static inline void FreeLibrary(void *hdl)
176 dlclose(hdl);
178 #else // DYNLOAD
179 static inline void *LoadLibraryA(const char*)
180 { return (void*)0xDEADBEEF; }
181 static inline void FreeLibrary(void*)
183 #define LOAD_FUNC(h, x) p##x = x
184 #endif
186 #else // _WIN32
188 #ifndef DYNLOAD
189 #define LoadLibraryA(x) ((void*)0xDEADBEEF)
190 #define FreeLibrary(x)
191 #define LOAD_FUNC(h, x) p##x = x
192 #else
193 #define GetProcAddress(x,y) GetProcAddress((HINSTANCE)(x),(y))
194 #define FreeLibrary(x) FreeLibrary((HINSTANCE)(x))
195 #endif
197 #endif
199 static void init_alure(void)
201 InitializeCriticalSection(&cs_StreamPlay);
203 #ifndef LOAD_FUNC
204 #define LOAD_FUNC(h, x) p##x = (typeof(p##x))GetProcAddress(h##_handle, #x); \
205 if(!p##x) \
207 FreeLibrary(h##_handle); \
208 h##_handle = NULL; \
209 break; \
211 #endif
213 #ifdef _WIN32
214 #define VORBISFILE_LIB "vorbisfile.dll"
215 #define FLAC_LIB "libFLAC.dll"
216 #define DUMB_LIB "libdumb.dll"
217 #define MPG123_LIB "libmpg123.dll"
218 #define SNDFILE_LIB "libsndfile-1.dll"
219 #elif defined(__APPLE__)
220 #define VORBISFILE_LIB "libvorbisfile.3.dylib"
221 #define FLAC_LIB "libFLAC.8.dylib"
222 #define DUMB_LIB "libdumb.dylib"
223 #define MPG123_LIB "libmpg123.0.dylib"
224 #define SNDFILE_LIB "libsndfile.1.dylib"
225 #else
226 #define VORBISFILE_LIB "libvorbisfile.so.3"
227 #define FLAC_LIB "libFLAC.so.8"
228 #define DUMB_LIB "libdumb.so"
229 #define MPG123_LIB "libmpg123.so.0"
230 #define SNDFILE_LIB "libsndfile.so.1"
231 #endif
233 #ifdef HAS_VORBISFILE
234 vorbisfile_handle = LoadLibraryA(VORBISFILE_LIB);
235 while(vorbisfile_handle)
237 LOAD_FUNC(vorbisfile, ov_clear);
238 LOAD_FUNC(vorbisfile, ov_info);
239 LOAD_FUNC(vorbisfile, ov_open_callbacks);
240 LOAD_FUNC(vorbisfile, ov_pcm_seek);
241 LOAD_FUNC(vorbisfile, ov_read);
242 break;
244 #endif
246 #ifdef HAS_FLAC
247 flac_handle = LoadLibraryA(FLAC_LIB);
248 while(flac_handle)
250 LOAD_FUNC(flac, FLAC__stream_decoder_get_state);
251 LOAD_FUNC(flac, FLAC__stream_decoder_finish);
252 LOAD_FUNC(flac, FLAC__stream_decoder_new);
253 LOAD_FUNC(flac, FLAC__stream_decoder_seek_absolute);
254 LOAD_FUNC(flac, FLAC__stream_decoder_delete);
255 LOAD_FUNC(flac, FLAC__stream_decoder_process_single);
256 LOAD_FUNC(flac, FLAC__stream_decoder_init_stream);
257 break;
259 #endif
261 #ifdef HAS_DUMB
262 dumb_handle = LoadLibraryA(DUMB_LIB);
263 while(dumb_handle)
265 LOAD_FUNC(dumb, dumbfile_open_ex);
266 LOAD_FUNC(dumb, dumbfile_close);
267 LOAD_FUNC(dumb, dumb_read_mod);
268 LOAD_FUNC(dumb, dumb_read_s3m);
269 LOAD_FUNC(dumb, dumb_read_xm);
270 LOAD_FUNC(dumb, dumb_read_it);
271 LOAD_FUNC(dumb, dumb_silence);
272 LOAD_FUNC(dumb, duh_sigrenderer_generate_samples);
273 LOAD_FUNC(dumb, duh_get_it_sigrenderer);
274 LOAD_FUNC(dumb, duh_end_sigrenderer);
275 LOAD_FUNC(dumb, unload_duh);
276 LOAD_FUNC(dumb, dumb_it_start_at_order);
277 LOAD_FUNC(dumb, dumb_it_set_loop_callback);
278 LOAD_FUNC(dumb, dumb_it_sr_get_speed);
279 LOAD_FUNC(dumb, dumb_it_sr_set_speed);
280 break;
282 #endif
284 #ifdef HAS_MPG123
285 mp123_handle = LoadLibraryA(MPG123_LIB);
286 while(mp123_handle)
288 LOAD_FUNC(mp123, mpg123_read);
289 LOAD_FUNC(mp123, mpg123_init);
290 LOAD_FUNC(mp123, mpg123_open_feed);
291 LOAD_FUNC(mp123, mpg123_new);
292 LOAD_FUNC(mp123, mpg123_delete);
293 LOAD_FUNC(mp123, mpg123_feed);
294 LOAD_FUNC(mp123, mpg123_exit);
295 LOAD_FUNC(mp123, mpg123_getformat);
296 LOAD_FUNC(mp123, mpg123_format_none);
297 LOAD_FUNC(mp123, mpg123_decode);
298 LOAD_FUNC(mp123, mpg123_format);
299 pmpg123_init();
300 break;
302 #endif
304 #ifdef HAS_SNDFILE
305 sndfile_handle = LoadLibraryA(SNDFILE_LIB);
306 while(sndfile_handle)
308 LOAD_FUNC(sndfile, sf_close);
309 LOAD_FUNC(sndfile, sf_open_virtual);
310 LOAD_FUNC(sndfile, sf_readf_short);
311 LOAD_FUNC(sndfile, sf_seek);
312 break;
314 #endif
316 #undef VORBISFILE_LIB
317 #undef FLAC_LIB
318 #undef DUMB_LIB
319 #undef MPG123_LIB
320 #undef SNDFILE_LIB
321 #undef LOAD_FUNC
324 static void deinit_alure(void)
326 #ifdef HAS_VORBISFILE
327 if(vorbisfile_handle)
328 FreeLibrary(vorbisfile_handle);
329 vorbisfile_handle = NULL;
330 #endif
331 #ifdef HAS_FLAC
332 if(flac_handle)
333 FreeLibrary(flac_handle);
334 flac_handle = NULL;
335 #endif
336 #ifdef HAS_DUMB
337 if(dumb_handle)
338 FreeLibrary(dumb_handle);
339 dumb_handle = NULL;
340 #endif
341 #ifdef HAS_MPG123
342 if(mp123_handle)
344 pmpg123_exit();
345 FreeLibrary(mp123_handle);
347 mp123_handle = NULL;
348 #endif
349 #ifdef HAS_SNDFILE
350 if(sndfile_handle)
351 FreeLibrary(sndfile_handle);
352 sndfile_handle = NULL;
353 #endif
355 DeleteCriticalSection(&cs_StreamPlay);
359 static const ALchar *last_error = "No error";
361 void SetError(const char *err)
363 last_error = err;
366 ALuint DetectBlockAlignment(ALenum format)
368 switch(format)
370 #define CHECK_RET(f,s) case (f): return (s)
371 CHECK_RET(AL_FORMAT_MONO8, sizeof(ALubyte));
372 CHECK_RET(AL_FORMAT_MONO16, sizeof(ALshort));
373 CHECK_RET(AL_FORMAT_MONO_FLOAT32, sizeof(ALfloat));
374 CHECK_RET(AL_FORMAT_MONO_DOUBLE_EXT, sizeof(ALdouble));
375 CHECK_RET(AL_FORMAT_MONO_MULAW, sizeof(ALubyte)*1);
377 CHECK_RET(AL_FORMAT_STEREO8, sizeof(ALubyte)*2);
378 CHECK_RET(AL_FORMAT_STEREO16, sizeof(ALshort)*2);
379 CHECK_RET(AL_FORMAT_STEREO_FLOAT32, sizeof(ALfloat)*2);
380 CHECK_RET(AL_FORMAT_STEREO_DOUBLE_EXT, sizeof(ALdouble)*2);
381 CHECK_RET(AL_FORMAT_STEREO_MULAW, sizeof(ALubyte)*2);
383 CHECK_RET(AL_FORMAT_QUAD8, sizeof(ALubyte)*4);
384 CHECK_RET(AL_FORMAT_QUAD16, sizeof(ALshort)*4);
385 CHECK_RET(AL_FORMAT_QUAD32, sizeof(ALfloat)*4);
386 CHECK_RET(AL_FORMAT_QUAD_MULAW, sizeof(ALubyte)*4);
388 CHECK_RET(AL_FORMAT_REAR8, sizeof(ALubyte)*2);
389 CHECK_RET(AL_FORMAT_REAR16, sizeof(ALshort)*2);
390 CHECK_RET(AL_FORMAT_REAR32, sizeof(ALfloat)*2);
391 CHECK_RET(AL_FORMAT_REAR_MULAW, sizeof(ALubyte)*2);
393 CHECK_RET(AL_FORMAT_51CHN8, sizeof(ALubyte)*6);
394 CHECK_RET(AL_FORMAT_51CHN16, sizeof(ALshort)*6);
395 CHECK_RET(AL_FORMAT_51CHN32, sizeof(ALfloat)*6);
396 CHECK_RET(AL_FORMAT_51CHN_MULAW, sizeof(ALubyte)*6);
398 CHECK_RET(AL_FORMAT_61CHN8, sizeof(ALubyte)*7);
399 CHECK_RET(AL_FORMAT_61CHN16, sizeof(ALshort)*7);
400 CHECK_RET(AL_FORMAT_61CHN32, sizeof(ALfloat)*7);
401 CHECK_RET(AL_FORMAT_61CHN_MULAW, sizeof(ALubyte)*7);
403 CHECK_RET(AL_FORMAT_71CHN8, sizeof(ALubyte)*8);
404 CHECK_RET(AL_FORMAT_71CHN16, sizeof(ALshort)*8);
405 CHECK_RET(AL_FORMAT_71CHN32, sizeof(ALfloat)*8);
406 CHECK_RET(AL_FORMAT_71CHN_MULAW, sizeof(ALubyte)*8);
408 CHECK_RET(AL_FORMAT_MONO_IMA4, 36);
409 CHECK_RET(AL_FORMAT_STEREO_IMA4, 36*2);
410 #undef CHECK_RET
412 fprintf(stderr, "Alure lib: Unhandled format: %#x\n", format);
413 return 1;
416 void DetectCompressionRate(ALenum format, ALuint *framesperblock)
418 switch(format)
420 #define CHECK_RET(f,s) case (f): *framesperblock = (s); return
421 case AL_FORMAT_MONO8:
422 case AL_FORMAT_MONO16:
423 case AL_FORMAT_MONO_FLOAT32:
424 case AL_FORMAT_MONO_DOUBLE_EXT:
425 case AL_FORMAT_STEREO8:
426 case AL_FORMAT_STEREO16:
427 case AL_FORMAT_STEREO_FLOAT32:
428 case AL_FORMAT_STEREO_DOUBLE_EXT:
429 case AL_FORMAT_QUAD8:
430 case AL_FORMAT_QUAD16:
431 case AL_FORMAT_QUAD32:
432 case AL_FORMAT_REAR8:
433 case AL_FORMAT_REAR16:
434 case AL_FORMAT_REAR32:
435 case AL_FORMAT_51CHN8:
436 case AL_FORMAT_51CHN16:
437 case AL_FORMAT_51CHN32:
438 case AL_FORMAT_61CHN8:
439 case AL_FORMAT_61CHN16:
440 case AL_FORMAT_61CHN32:
441 case AL_FORMAT_71CHN8:
442 case AL_FORMAT_71CHN16:
443 case AL_FORMAT_71CHN32:
444 *framesperblock = 1;
445 return;
447 case AL_FORMAT_MONO_MULAW:
448 case AL_FORMAT_STEREO_MULAW:
449 case AL_FORMAT_QUAD_MULAW:
450 case AL_FORMAT_REAR_MULAW:
451 case AL_FORMAT_51CHN_MULAW:
452 case AL_FORMAT_61CHN_MULAW:
453 case AL_FORMAT_71CHN_MULAW:
454 *framesperblock = 1;
455 return;
457 case AL_FORMAT_MONO_IMA4:
458 case AL_FORMAT_STEREO_IMA4:
459 *framesperblock = 65;
460 return;
462 fprintf(stderr, "Alure lib: Unhandled format: %#x\n", format);
463 *framesperblock = 1;
466 ALenum GetSampleFormat(ALuint channels, ALuint bits, bool isFloat)
468 #define CHECK_FMT_RET(f) do { \
469 ALenum fmt = alGetEnumValue(#f); \
470 if(alGetError() == AL_NO_ERROR && fmt != 0 && fmt != -1) \
471 return fmt; \
472 } while(0)
473 if(!isFloat)
475 if(bits == 8)
477 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO8);
478 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO8);
479 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
481 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8);
482 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN8);
483 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN8);
484 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN8);
486 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
488 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8_LOKI);
490 SetError("Unsupported channel count\n");
491 return AL_NONE;
493 if(bits == 16)
495 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO16);
496 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO16);
497 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
499 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16);
500 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN16);
501 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN16);
502 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN16);
504 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
506 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16_LOKI);
508 SetError("Unsupported channel count\n");
509 return AL_NONE;
512 else
514 if(bits == 32)
516 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
518 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_FLOAT32);
519 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_FLOAT32);
520 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
522 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD32);
523 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN32);
524 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN32);
525 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN32);
527 SetError("Unsupported channel count\n");
528 return AL_NONE;
532 #undef CHECK_FMT_RET
534 if(isFloat)
536 SetError("Unsupported float bit depth\n");
537 return AL_NONE;
539 SetError("Unsupported PCM bit depth\n");
540 return AL_NONE;
543 extern "C" {
545 /* Function: alureGetVersion
547 * Stores the major and minor version of the library. If either major or minor
548 * are NULL, that value is not provided.
550 ALURE_API void ALURE_APIENTRY alureGetVersion(ALuint *major, ALuint *minor)
552 if(major) *major = ALURE_VER_MAJOR;
553 if(minor) *minor = ALURE_VER_MINOR;
556 /* Function: alureGetErrorString
558 * Returns a string describing the last error encountered.
560 ALURE_API const ALchar* ALURE_APIENTRY alureGetErrorString(void)
562 const ALchar *ret = last_error;
563 last_error = "No error";
564 return ret;
568 /* Function: alureGetDeviceNames
570 * Gets an array of device name strings from OpenAL. This encapsulates
571 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
572 * enumeration, with 'count' being set to the number of returned device
573 * names.
575 * Returns:
576 * An array of device name strings, or NULL on error.
578 * See Also:
579 * <alureFreeDeviceNames>
581 ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean all, ALCsizei *count)
583 const ALCchar *list = NULL;
584 if(all && alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
585 list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
586 else
587 list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
588 if(!list)
590 alcGetError(NULL);
591 SetError("No device names found");
592 return NULL;
595 const ALCchar *cur = list;
596 ALuint retlistLen = 0;
597 while(*cur)
599 cur += strlen(cur)+1;
600 retlistLen++;
603 const ALCchar **retlist = new const ALCchar*[retlistLen+1];
604 retlistLen = 0;
605 cur = list;
606 while(*cur)
608 ALCuint len = strlen(cur)+1;
609 ALCchar *newstr = new ALCchar[len];
611 memcpy(newstr, cur, len);
612 cur += len;
614 retlist[retlistLen] = newstr;
615 retlistLen++;
617 retlist[retlistLen] = NULL;
619 *count = retlistLen;
620 return retlist;
623 /* Function: alureFreeDeviceNames
625 * Frees the device name array returned from alureGetDeviceNames.
627 * See Also:
628 * <alureGetDeviceNames>
630 ALURE_API ALvoid ALURE_APIENTRY alureFreeDeviceNames(const ALCchar **names)
632 if(names)
634 for(ALCuint i = 0;names[i];i++)
635 delete[] const_cast<ALCchar*>(names[i]);
636 delete[] names;
641 /* Function: alureInitDevice
643 * Opens the named device, creates a context with the given attributes, and
644 * sets that context as current. The name and attribute list would be the same
645 * as what's passed to alcOpenDevice and alcCreateContext respectively.
647 * Returns:
648 * AL_FALSE on error.
650 * See Also:
651 * <alureShutdownDevice>
653 ALURE_API ALboolean ALURE_APIENTRY alureInitDevice(const ALCchar *name, const ALCint *attribs)
655 ALCdevice *device = alcOpenDevice(name);
656 if(!device)
658 alcGetError(NULL);
660 SetError("Device open failed");
661 return AL_FALSE;
664 ALCcontext *context = alcCreateContext(device, attribs);
665 if(alcGetError(device) != ALC_NO_ERROR || !context)
667 alcCloseDevice(device);
669 SetError("Context creation failed");
670 return AL_FALSE;
673 alcMakeContextCurrent(context);
674 if(alcGetError(device) != AL_NO_ERROR)
676 alcDestroyContext(context);
677 alcCloseDevice(device);
679 SetError("Context setup failed");
680 return AL_FALSE;
683 return AL_TRUE;
686 /* Function: alureShutdownDevice
688 * Destroys the current context and closes its associated device.
690 * Returns:
691 * AL_FALSE on error.
693 * See Also:
694 * <alureInitDevice>
696 ALURE_API ALboolean ALURE_APIENTRY alureShutdownDevice(void)
698 ALCcontext *context = alcGetCurrentContext();
699 ALCdevice *device = alcGetContextsDevice(context);
700 if(alcGetError(device) != ALC_NO_ERROR || !device)
702 SetError("Failed to get current device");
703 return AL_FALSE;
706 if(alcMakeContextCurrent(NULL) == ALC_FALSE)
708 alcGetError(NULL);
709 SetError("Failed to unset current context");
710 return AL_FALSE;
713 alcDestroyContext(context);
714 alcCloseDevice(device);
715 alcGetError(NULL);
717 return AL_TRUE;
721 /* Function: alureGetSampleFormat
723 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
724 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
725 * application should not rely on any particular format enum being returned as
726 * it is dependant on the available extensions. The returned format will be
727 * valid for the current context. Requires an active context.
729 * Returns:
730 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
731 * be found.
733 ALURE_API ALenum ALURE_APIENTRY alureGetSampleFormat(ALuint channels, ALuint bits, ALuint floatbits)
735 if(alGetError() != AL_NO_ERROR)
737 SetError("Existing OpenAL error");
738 return AL_NONE;
741 if(bits && floatbits)
743 SetError("Both bit-types specified");
744 return AL_NONE;
747 if(bits)
748 return GetSampleFormat(channels, bits, false);
749 return GetSampleFormat(channels, floatbits, true);
753 /* Function: alureInstallDecodeCallbacks
755 * Installs callbacks to enable ALURE to handle more file types. The index is
756 * the order that each given set of callbacks will be tried, starting at the
757 * most negative number (INT_MIN) and going up. Negative indices will be tried
758 * before the built-in decoders, and positive indices will be tried after.
759 * Installing callbacks onto the same index multiple times will remove the
760 * previous callbacks, and removing old callbacks won't affect any opened files
761 * using them (they'll continue to use the old functions until properly closed,
762 * although newly opened files will use the new ones). Passing NULL for all
763 * callbacks is a valid way to remove an installed set, otherwise certain
764 * callbacks must be specified. Callbacks that are not specified will assume
765 * failure.
767 * Parameters:
768 * open_file - This callback is expected to open the named file and prepare it
769 * for decoding. If the callbacks cannot decode the file, NULL
770 * should be returned to indicate failure. Upon success, a non-NULL
771 * handle must be returned, which will be used as a unique
772 * identifier for the decoder instance. This callback is required
773 * if open_memory is not specified.
774 * open_memory - This callback behaves the same as open_file, except it takes a
775 * memory segment for input instead of a filename. The given
776 * memory will remain valid while the instance is open. This
777 * callback is required if open_file is not specified.
778 * get_format - This callback is used to retrieve the format of the decoded
779 * data for the given instance. It is the responsibility of the
780 * function to make sure the returned format is valid for the
781 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
782 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
783 * samplerate or blocksize, or returning AL_NONE for format, will
784 * cause a failure. Returning AL_FALSE indicates failure. This
785 * callback is required.
786 * decode - This callback is called to get more decoded data. Up to the
787 * specified amount of bytes should be written to the data pointer.
788 * The number of bytes written should be a multiple of the block size,
789 * otherwise an OpenAL error may occur during buffering. The function
790 * should return the number of bytes written. This callback is
791 * required.
792 * rewind - This callback is for rewinding the instance so that the next decode
793 * calls for it will get audio data from the start of the sound file.
794 * If the stream fails to rewind, AL_FALSE should be returned.
795 * close - This callback is called at the end of processing for a particular
796 * instance. The handle will not be used further and any associated
797 * data may be deleted.
799 * Returns:
800 * AL_FALSE on error.
802 ALURE_API ALboolean ALURE_APIENTRY alureInstallDecodeCallbacks(ALint index,
803 void* (*open_file)(const ALchar *filename),
804 void* (*open_memory)(const ALubyte *data, ALuint length),
805 ALboolean (*get_format)(void *instance, ALenum *format, ALuint *samplerate, ALuint *blocksize),
806 ALuint (*decode)(void *instance, ALubyte *data, ALuint bytes),
807 ALboolean (*rewind)(void *instance),
808 void (*close)(void *instance))
810 if(!open_file && !open_memory && !get_format && !decode && !rewind && !close)
812 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.find(index);
813 if(i != InstalledCallbacks.end())
814 InstalledCallbacks.erase(i);
815 return AL_TRUE;
818 if((!open_file && !open_memory) || !get_format || !decode)
820 SetError("Missing callback functions");
821 return AL_FALSE;
824 UserCallbacks newcb;
825 newcb.open_file = open_file;
826 newcb.open_mem = open_memory;
827 newcb.get_fmt = get_format;
828 newcb.decode = decode;
829 newcb.rewind = rewind;
830 newcb.close = close;
832 InstalledCallbacks[index] = newcb;
834 return AL_TRUE;
838 /* Function: alureSleep
840 * Rests the calling thread for the given number of seconds.
842 * Returns:
843 * AL_FALSE on error.
845 ALURE_API ALboolean ALURE_APIENTRY alureSleep(ALfloat duration)
847 if(duration < 0.0f)
849 SetError("Invalid duration");
850 return AL_FALSE;
853 ALuint seconds = (ALuint)duration;
854 ALfloat rest = duration - (ALfloat)seconds;
856 #ifdef HAVE_NANOSLEEP
858 struct timespec t, remainingTime;
859 t.tv_sec = (time_t)seconds;
860 t.tv_nsec = (long)(rest*1000000)*1000;
862 while(nanosleep(&t, &remainingTime) < 0 && errno == EINTR)
863 t = remainingTime;
865 #elif defined(HAVE_WINDOWS_H)
867 while(seconds > 0)
869 Sleep(1000);
870 seconds--;
872 Sleep((DWORD)(rest * 1000));
874 #endif
876 return AL_TRUE;
880 /* Function: alureGetProcAddress
882 * Returns a pointer for the named ALURE function.
884 * Returns:
885 * NULL on error.
887 * *Version Added*: 1.1
889 ALURE_API void* ALURE_APIENTRY alureGetProcAddress(const ALchar *funcname)
891 static const struct {
892 const char *name;
893 void *func;
894 } FunctionList[] = {
895 #define ADD_FUNCTION(x) { #x, (void*)x },
896 ADD_FUNCTION(alureGetVersion)
897 ADD_FUNCTION(alureGetErrorString)
898 ADD_FUNCTION(alureGetDeviceNames)
899 ADD_FUNCTION(alureFreeDeviceNames)
900 ADD_FUNCTION(alureInitDevice)
901 ADD_FUNCTION(alureShutdownDevice)
902 ADD_FUNCTION(alureGetSampleFormat)
903 ADD_FUNCTION(alureSleep)
904 ADD_FUNCTION(alureCreateBufferFromFile)
905 ADD_FUNCTION(alureCreateBufferFromMemory)
906 ADD_FUNCTION(alureBufferDataFromFile)
907 ADD_FUNCTION(alureBufferDataFromMemory)
908 ADD_FUNCTION(alureCreateStreamFromFile)
909 ADD_FUNCTION(alureCreateStreamFromMemory)
910 ADD_FUNCTION(alureCreateStreamFromStaticMemory)
911 ADD_FUNCTION(alureCreateStreamFromCallback)
912 ADD_FUNCTION(alureRewindStream)
913 ADD_FUNCTION(alureDestroyStream)
914 ADD_FUNCTION(alureInstallDecodeCallbacks)
915 ADD_FUNCTION(alureSetIOCallbacks)
916 ADD_FUNCTION(alureGetProcAddress)
917 ADD_FUNCTION(alurePlaySourceStream)
918 ADD_FUNCTION(alurePlaySource)
919 ADD_FUNCTION(alureStopSource)
920 ADD_FUNCTION(alureGetSourceOffset)
921 #undef ADD_FUNCTION
922 { NULL, NULL }
925 size_t i;
926 for(i = 0;FunctionList[i].name;i++)
928 if(strcmp(FunctionList[i].name, funcname) == 0)
929 break;
932 if(!FunctionList[i].name)
933 SetError("Function not found");
934 return FunctionList[i].func;
937 } // extern "C"