Use a macro to signify building a static lib
[alure.git] / src / alure.cpp
blob78a9c27e17c0e1657d5735d43a254e725ef1af9e
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 std::map<std::string,void*> FunctionList;
40 CRITICAL_SECTION cs_StreamPlay;
41 alureStream::ListType alureStream::StreamList;
43 void *vorbisfile_handle = NULL;
44 void *flac_handle = NULL;
45 void *dumb_handle = NULL;
46 void *mp123_handle = NULL;
47 void *sndfile_handle = NULL;
49 #define MAKE_FUNC(x) typeof(x)* p##x
50 #ifdef HAS_VORBISFILE
51 MAKE_FUNC(ov_clear);
52 MAKE_FUNC(ov_info);
53 MAKE_FUNC(ov_open_callbacks);
54 MAKE_FUNC(ov_pcm_seek);
55 MAKE_FUNC(ov_read);
56 #endif
57 #ifdef HAS_FLAC
58 MAKE_FUNC(FLAC__stream_decoder_get_state);
59 MAKE_FUNC(FLAC__stream_decoder_finish);
60 MAKE_FUNC(FLAC__stream_decoder_new);
61 MAKE_FUNC(FLAC__stream_decoder_seek_absolute);
62 MAKE_FUNC(FLAC__stream_decoder_delete);
63 MAKE_FUNC(FLAC__stream_decoder_process_single);
64 MAKE_FUNC(FLAC__stream_decoder_init_stream);
65 #endif
66 #ifdef HAS_DUMB
67 MAKE_FUNC(dumbfile_open_ex);
68 MAKE_FUNC(dumbfile_close);
69 MAKE_FUNC(dumb_read_mod);
70 MAKE_FUNC(dumb_read_s3m);
71 MAKE_FUNC(dumb_read_xm);
72 MAKE_FUNC(dumb_read_it);
73 MAKE_FUNC(dumb_silence);
74 MAKE_FUNC(duh_sigrenderer_generate_samples);
75 MAKE_FUNC(duh_get_it_sigrenderer);
76 MAKE_FUNC(duh_end_sigrenderer);
77 MAKE_FUNC(unload_duh);
78 MAKE_FUNC(dumb_it_start_at_order);
79 MAKE_FUNC(dumb_it_set_loop_callback);
80 MAKE_FUNC(dumb_it_sr_get_speed);
81 MAKE_FUNC(dumb_it_sr_set_speed);
82 #endif
83 #ifdef HAS_MPG123
84 MAKE_FUNC(mpg123_read);
85 MAKE_FUNC(mpg123_init);
86 MAKE_FUNC(mpg123_open_feed);
87 MAKE_FUNC(mpg123_new);
88 MAKE_FUNC(mpg123_delete);
89 MAKE_FUNC(mpg123_feed);
90 MAKE_FUNC(mpg123_exit);
91 MAKE_FUNC(mpg123_getformat);
92 MAKE_FUNC(mpg123_format_none);
93 MAKE_FUNC(mpg123_decode);
94 MAKE_FUNC(mpg123_format);
95 #endif
96 #ifdef HAS_SNDFILE
97 MAKE_FUNC(sf_close);
98 MAKE_FUNC(sf_open_virtual);
99 MAKE_FUNC(sf_readf_short);
100 MAKE_FUNC(sf_seek);
101 #endif
102 #undef MAKE_FUNC
104 #if defined(_WIN32) && !defined(ALURE_STATIC_LIBRARY)
105 static void init_alure(void);
106 static void deinit_alure(void);
107 static struct MyConstructorClass {
108 ~MyConstructorClass()
109 { alureStream::Clear(); };
110 } MyConstructor;
112 extern "C" BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
114 (void)reserved;
116 // Perform actions based on the reason for calling.
117 switch(reason)
119 case DLL_PROCESS_ATTACH:
120 DisableThreadLibraryCalls(module);
121 init_alure();
122 break;
124 case DLL_PROCESS_DETACH:
125 deinit_alure();
126 break;
128 return TRUE;
130 #elif defined(HAVE_GCC_CONSTRUCTOR)
131 static void init_alure(void) __attribute__((constructor));
132 static void deinit_alure(void) __attribute__((destructor));
133 static struct MyConstructorClass {
134 ~MyConstructorClass()
135 { alureStream::Clear(); };
136 } MyConstructor;
137 #else
138 static void init_alure(void);
139 static void deinit_alure(void);
141 static struct MyConstructorClass {
142 MyConstructorClass()
143 { init_alure(); };
144 ~MyConstructorClass()
145 { alureStream::Clear();
146 deinit_alure(); };
147 } MyConstructor;
148 #endif
150 #ifndef _WIN32
152 #ifdef DYNLOAD
153 static inline void *LoadLibraryA(const char *libname)
155 void *hdl = dlopen(libname, RTLD_NOW);
156 const char *err;
157 if((err=dlerror()) != NULL)
159 fprintf(stderr, "Error loading %s: %s\n", libname, err);
160 return NULL;
162 return hdl;
164 static inline void *GetProcAddress(void *hdl, const char *funcname)
166 void *fn = dlsym(hdl, funcname);
167 const char *err;
168 if((err=dlerror()) != NULL)
170 fprintf(stderr, "Error loading %s: %s\n", funcname, err);
171 return NULL;
173 return fn;
175 static inline void FreeLibrary(void *hdl)
177 dlclose(hdl);
179 #else // DYNLOAD
180 static inline void *LoadLibraryA(const char*)
181 { return (void*)0xDEADBEEF; }
182 static inline void FreeLibrary(void*)
184 #define LOAD_FUNC(h, x) p##x = x
185 #endif
187 #else // _WIN32
189 #define GetProcAddress(x,y) GetProcAddress((HINSTANCE)(x),(y))
190 #define FreeLibrary(x) FreeLibrary((HINSTANCE)(x))
191 #ifndef DYNLOAD
192 #define LOAD_FUNC(h, x) p##x = x
193 #endif
195 #endif
197 static void init_alure(void)
199 InitializeCriticalSection(&cs_StreamPlay);
201 #ifndef LOAD_FUNC
202 #define LOAD_FUNC(h, x) p##x = (typeof(p##x))GetProcAddress(h##_handle, #x); \
203 if(!p##x) \
205 FreeLibrary(h##_handle); \
206 h##_handle = NULL; \
207 break; \
209 #endif
211 #ifdef _WIN32
212 #define VORBISFILE_LIB "vorbisfile.dll"
213 #define FLAC_LIB "libFLAC.dll"
214 #define DUMB_LIB "libdumb.dll"
215 #define MPG123_LIB "libmpg123.dll"
216 #define SNDFILE_LIB "libsndfile-1.dll"
217 #elif defined(__APPLE__)
218 #define VORBISFILE_LIB "libvorbisfile.3.dylib"
219 #define FLAC_LIB "libFLAC.8.dylib"
220 #define DUMB_LIB "libdumb.dylib"
221 #define MPG123_LIB "libmpg123.0.dylib"
222 #define SNDFILE_LIB "libsndfile.1.dylib"
223 #else
224 #define VORBISFILE_LIB "libvorbisfile.so.3"
225 #define FLAC_LIB "libFLAC.so.8"
226 #define DUMB_LIB "libdumb.so"
227 #define MPG123_LIB "libmpg123.so.0"
228 #define SNDFILE_LIB "libsndfile.so.1"
229 #endif
231 #ifdef HAS_VORBISFILE
232 vorbisfile_handle = LoadLibraryA(VORBISFILE_LIB);
233 while(vorbisfile_handle)
235 LOAD_FUNC(vorbisfile, ov_clear);
236 LOAD_FUNC(vorbisfile, ov_info);
237 LOAD_FUNC(vorbisfile, ov_open_callbacks);
238 LOAD_FUNC(vorbisfile, ov_pcm_seek);
239 LOAD_FUNC(vorbisfile, ov_read);
240 break;
242 #endif
244 #ifdef HAS_FLAC
245 flac_handle = LoadLibraryA(FLAC_LIB);
246 while(flac_handle)
248 LOAD_FUNC(flac, FLAC__stream_decoder_get_state);
249 LOAD_FUNC(flac, FLAC__stream_decoder_finish);
250 LOAD_FUNC(flac, FLAC__stream_decoder_new);
251 LOAD_FUNC(flac, FLAC__stream_decoder_seek_absolute);
252 LOAD_FUNC(flac, FLAC__stream_decoder_delete);
253 LOAD_FUNC(flac, FLAC__stream_decoder_process_single);
254 LOAD_FUNC(flac, FLAC__stream_decoder_init_stream);
255 break;
257 #endif
259 #ifdef HAS_DUMB
260 dumb_handle = LoadLibraryA(DUMB_LIB);
261 while(dumb_handle)
263 LOAD_FUNC(dumb, dumbfile_open_ex);
264 LOAD_FUNC(dumb, dumbfile_close);
265 LOAD_FUNC(dumb, dumb_read_mod);
266 LOAD_FUNC(dumb, dumb_read_s3m);
267 LOAD_FUNC(dumb, dumb_read_xm);
268 LOAD_FUNC(dumb, dumb_read_it);
269 LOAD_FUNC(dumb, dumb_silence);
270 LOAD_FUNC(dumb, duh_sigrenderer_generate_samples);
271 LOAD_FUNC(dumb, duh_get_it_sigrenderer);
272 LOAD_FUNC(dumb, duh_end_sigrenderer);
273 LOAD_FUNC(dumb, unload_duh);
274 LOAD_FUNC(dumb, dumb_it_start_at_order);
275 LOAD_FUNC(dumb, dumb_it_set_loop_callback);
276 LOAD_FUNC(dumb, dumb_it_sr_get_speed);
277 LOAD_FUNC(dumb, dumb_it_sr_set_speed);
278 break;
280 #endif
282 #ifdef HAS_MPG123
283 mp123_handle = LoadLibraryA(MPG123_LIB);
284 while(mp123_handle)
286 LOAD_FUNC(mp123, mpg123_read);
287 LOAD_FUNC(mp123, mpg123_init);
288 LOAD_FUNC(mp123, mpg123_open_feed);
289 LOAD_FUNC(mp123, mpg123_new);
290 LOAD_FUNC(mp123, mpg123_delete);
291 LOAD_FUNC(mp123, mpg123_feed);
292 LOAD_FUNC(mp123, mpg123_exit);
293 LOAD_FUNC(mp123, mpg123_getformat);
294 LOAD_FUNC(mp123, mpg123_format_none);
295 LOAD_FUNC(mp123, mpg123_decode);
296 LOAD_FUNC(mp123, mpg123_format);
297 pmpg123_init();
298 break;
300 #endif
302 #ifdef HAS_SNDFILE
303 sndfile_handle = LoadLibraryA(SNDFILE_LIB);
304 while(sndfile_handle)
306 LOAD_FUNC(sndfile, sf_close);
307 LOAD_FUNC(sndfile, sf_open_virtual);
308 LOAD_FUNC(sndfile, sf_readf_short);
309 LOAD_FUNC(sndfile, sf_seek);
310 break;
312 #endif
314 #undef VORBISFILE_LIB
315 #undef FLAC_LIB
316 #undef DUMB_LIB
317 #undef MPG123_LIB
318 #undef SNDFILE_LIB
319 #undef LOAD_FUNC
322 static void deinit_alure(void)
324 #ifdef HAS_VORBISFILE
325 if(vorbisfile_handle)
326 FreeLibrary(vorbisfile_handle);
327 vorbisfile_handle = NULL;
328 #endif
329 #ifdef HAS_FLAC
330 if(flac_handle)
331 FreeLibrary(flac_handle);
332 flac_handle = NULL;
333 #endif
334 #ifdef HAS_DUMB
335 if(dumb_handle)
336 FreeLibrary(dumb_handle);
337 dumb_handle = NULL;
338 #endif
339 #ifdef HAS_MPG123
340 if(mp123_handle)
342 pmpg123_exit();
343 FreeLibrary(mp123_handle);
345 mp123_handle = NULL;
346 #endif
347 #ifdef HAS_SNDFILE
348 if(sndfile_handle)
349 FreeLibrary(sndfile_handle);
350 sndfile_handle = NULL;
351 #endif
353 DeleteCriticalSection(&cs_StreamPlay);
357 static const ALchar *last_error = "No error";
359 void SetError(const char *err)
361 last_error = err;
364 ALuint DetectBlockAlignment(ALenum format)
366 switch(format)
368 #define CHECK_RET(f,s) case (f): return (s)
369 CHECK_RET(AL_FORMAT_MONO8, sizeof(ALubyte));
370 CHECK_RET(AL_FORMAT_MONO16, sizeof(ALshort));
371 CHECK_RET(AL_FORMAT_MONO_FLOAT32, sizeof(ALfloat));
373 CHECK_RET(AL_FORMAT_STEREO8, sizeof(ALubyte)*2);
374 CHECK_RET(AL_FORMAT_STEREO16, sizeof(ALshort)*2);
375 CHECK_RET(AL_FORMAT_STEREO_FLOAT32, sizeof(ALfloat)*2);
377 CHECK_RET(AL_FORMAT_QUAD8, sizeof(ALubyte)*4);
378 CHECK_RET(AL_FORMAT_QUAD16, sizeof(ALshort)*4);
379 CHECK_RET(AL_FORMAT_QUAD32, sizeof(ALfloat)*4);
381 CHECK_RET(AL_FORMAT_REAR8, sizeof(ALubyte)*2);
382 CHECK_RET(AL_FORMAT_REAR16, sizeof(ALshort)*2);
383 CHECK_RET(AL_FORMAT_REAR32, sizeof(ALfloat)*2);
385 CHECK_RET(AL_FORMAT_51CHN8, sizeof(ALubyte)*6);
386 CHECK_RET(AL_FORMAT_51CHN16, sizeof(ALshort)*6);
387 CHECK_RET(AL_FORMAT_51CHN32, sizeof(ALfloat)*6);
389 CHECK_RET(AL_FORMAT_61CHN8, sizeof(ALubyte)*7);
390 CHECK_RET(AL_FORMAT_61CHN16, sizeof(ALshort)*7);
391 CHECK_RET(AL_FORMAT_61CHN32, sizeof(ALfloat)*7);
393 CHECK_RET(AL_FORMAT_71CHN8, sizeof(ALubyte)*8);
394 CHECK_RET(AL_FORMAT_71CHN16, sizeof(ALshort)*8);
395 CHECK_RET(AL_FORMAT_71CHN32, sizeof(ALfloat)*8);
397 CHECK_RET(AL_FORMAT_MONO_IMA4, 36);
398 CHECK_RET(AL_FORMAT_STEREO_IMA4, 36*2);
399 #undef CHECK_RET
401 fprintf(stderr, "Alure lib: Unhandled format: %#x\n", format);
402 return 1;
405 ALenum GetSampleFormat(ALuint channels, ALuint bits, bool isFloat)
407 #define CHECK_FMT_RET(f) do { \
408 ALenum fmt = alGetEnumValue(#f); \
409 if(alGetError() == AL_NO_ERROR && fmt != 0 && fmt != -1) \
410 return fmt; \
411 } while(0)
412 if(!isFloat)
414 if(bits == 8)
416 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO8);
417 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO8);
418 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
420 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8);
421 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN8);
422 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN8);
423 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN8);
425 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
427 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8_LOKI);
429 SetError("Unsupported channel count\n");
430 return AL_NONE;
432 if(bits == 16)
434 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO16);
435 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO16);
436 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
438 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16);
439 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN16);
440 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN16);
441 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN16);
443 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
445 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16_LOKI);
447 SetError("Unsupported channel count\n");
448 return AL_NONE;
451 else
453 if(bits == 32)
455 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
457 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_FLOAT32);
458 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_FLOAT32);
459 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
461 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD32);
462 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN32);
463 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN32);
464 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN32);
466 SetError("Unsupported channel count\n");
467 return AL_NONE;
471 #undef CHECK_FMT_RET
473 if(isFloat)
475 SetError("Unsupported float bit depth\n");
476 return AL_NONE;
478 SetError("Unsupported PCM bit depth\n");
479 return AL_NONE;
482 extern "C" {
484 /* Function: alureGetVersion
486 * Stores the major and minor version of the library. If either major or minor
487 * are NULL, that value is not provided.
489 ALURE_API void ALURE_APIENTRY alureGetVersion(ALuint *major, ALuint *minor)
491 if(major) *major = ALURE_VER_MAJOR;
492 if(minor) *minor = ALURE_VER_MINOR;
495 /* Function: alureGetErrorString
497 * Returns a string describing the last error encountered.
499 ALURE_API const ALchar* ALURE_APIENTRY alureGetErrorString(void)
501 const ALchar *ret = last_error;
502 last_error = "No error";
503 return ret;
507 /* Function: alureGetDeviceNames
509 * Gets an array of device name strings from OpenAL. This encapsulates
510 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
511 * enumeration, with 'count' being set to the number of returned device
512 * names.
514 * Returns:
515 * An array of device name strings, or NULL on error.
517 * See Also:
518 * <alureFreeDeviceNames>
520 ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean all, ALCsizei *count)
522 const ALCchar *list = NULL;
523 if(all && alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
524 list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
525 else
526 list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
527 if(!list)
529 alcGetError(NULL);
530 SetError("No device names found");
531 return NULL;
534 const ALCchar *cur = list;
535 ALuint retlistLen = 0;
536 while(*cur)
538 cur += strlen(cur)+1;
539 retlistLen++;
542 const ALCchar **retlist = new const ALCchar*[retlistLen+1];
543 retlistLen = 0;
544 cur = list;
545 while(*cur)
547 ALCuint len = strlen(cur)+1;
548 ALCchar *newstr = new ALCchar[len];
550 memcpy(newstr, cur, len);
551 cur += len;
553 retlist[retlistLen] = newstr;
554 retlistLen++;
556 retlist[retlistLen] = NULL;
558 *count = retlistLen;
559 return retlist;
562 /* Function: alureFreeDeviceNames
564 * Frees the device name array returned from alureGetDeviceNames.
566 * See Also:
567 * <alureGetDeviceNames>
569 ALURE_API ALvoid ALURE_APIENTRY alureFreeDeviceNames(const ALCchar **names)
571 if(names)
573 for(ALCuint i = 0;names[i];i++)
574 delete[] const_cast<ALCchar*>(names[i]);
575 delete[] names;
580 /* Function: alureInitDevice
582 * Opens the named device, creates a context with the given attributes, and
583 * sets that context as current. The name and attribute list would be the same
584 * as what's passed to alcOpenDevice and alcCreateContext respectively.
586 * Returns:
587 * AL_FALSE on error.
589 * See Also:
590 * <alureShutdownDevice>
592 ALURE_API ALboolean ALURE_APIENTRY alureInitDevice(const ALCchar *name, const ALCint *attribs)
594 ALCdevice *device = alcOpenDevice(name);
595 if(!device)
597 alcGetError(NULL);
599 SetError("Device open failed");
600 return AL_FALSE;
603 ALCcontext *context = alcCreateContext(device, attribs);
604 if(alcGetError(device) != ALC_NO_ERROR || !context)
606 alcCloseDevice(device);
608 SetError("Context creation failed");
609 return AL_FALSE;
612 alcMakeContextCurrent(context);
613 if(alcGetError(device) != AL_NO_ERROR)
615 alcDestroyContext(context);
616 alcCloseDevice(device);
618 SetError("Context setup failed");
619 return AL_FALSE;
622 return AL_TRUE;
625 /* Function: alureShutdownDevice
627 * Destroys the current context and closes its associated device.
629 * Returns:
630 * AL_FALSE on error.
632 * See Also:
633 * <alureInitDevice>
635 ALURE_API ALboolean ALURE_APIENTRY alureShutdownDevice(void)
637 ALCcontext *context = alcGetCurrentContext();
638 ALCdevice *device = alcGetContextsDevice(context);
639 if(alcGetError(device) != ALC_NO_ERROR || !device)
641 SetError("Failed to get current device");
642 return AL_FALSE;
645 if(alcMakeContextCurrent(NULL) == ALC_FALSE)
647 alcGetError(NULL);
648 SetError("Failed to unset current context");
649 return AL_FALSE;
652 alcDestroyContext(context);
653 alcCloseDevice(device);
654 alcGetError(NULL);
656 return AL_TRUE;
660 /* Function: alureGetSampleFormat
662 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
663 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
664 * application should not rely on any particular format enum being returned as
665 * it is dependant on the available extensions. The returned format will be
666 * valid for the current context. Requires an active context.
668 * Returns:
669 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
670 * be found.
672 ALURE_API ALenum ALURE_APIENTRY alureGetSampleFormat(ALuint channels, ALuint bits, ALuint floatbits)
674 if(alGetError() != AL_NO_ERROR)
676 SetError("Existing OpenAL error");
677 return AL_NONE;
680 if(bits && floatbits)
682 SetError("Both bit-types specified");
683 return AL_NONE;
686 if(bits)
687 return GetSampleFormat(channels, bits, false);
688 return GetSampleFormat(channels, floatbits, true);
692 /* Function: alureInstallDecodeCallbacks
694 * Installs callbacks to enable ALURE to handle more file types. The index is
695 * the order that each given set of callbacks will be tried, starting at the
696 * most negative number (INT_MIN) and going up. Negative indices will be tried
697 * before the built-in decoders, and positive indices will be tried after.
698 * Installing callbacks onto the same index multiple times will remove the
699 * previous callbacks, and removing old callbacks won't affect any opened files
700 * using them (they'll continue to use the old functions until properly closed,
701 * although newly opened files will use the new ones). Passing NULL for all
702 * callbacks is a valid way to remove an installed set, otherwise certain
703 * callbacks must be specified. Callbacks that are not specified will assume
704 * failure.
706 * Parameters:
707 * open_file - This callback is expected to open the named file and prepare it
708 * for decoding. If the callbacks cannot decode the file, NULL
709 * should be returned to indicate failure. Upon success, a non-NULL
710 * handle must be returned, which will be used as a unique
711 * identifier for the decoder instance. This callback is required
712 * if open_memory is not specified.
713 * open_memory - This callback behaves the same as open_file, except it takes a
714 * memory segment for input instead of a filename. The given
715 * memory will remain valid while the instance is open. This
716 * callback is required if open_file is not specified.
717 * get_format - This callback is used to retrieve the format of the decoded
718 * data for the given instance. It is the responsibility of the
719 * function to make sure the returned format is valid for the
720 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
721 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
722 * samplerate or blocksize, or returning AL_NONE for format, will
723 * cause a failure. Returning AL_FALSE indicates failure. This
724 * callback is required.
725 * decode - This callback is called to get more decoded data. Up to the
726 * specified amount of bytes should be written to the data pointer.
727 * The number of bytes written should be a multiple of the block size,
728 * otherwise an OpenAL error may occur during buffering. The function
729 * should return the number of bytes written. This callback is
730 * required.
731 * rewind - This callback is for rewinding the instance so that the next decode
732 * calls for it will get audio data from the start of the sound file.
733 * If the stream fails to rewind, AL_FALSE should be returned.
734 * close - This callback is called at the end of processing for a particular
735 * instance. The handle will not be used further and any associated
736 * data may be deleted.
738 * Returns:
739 * AL_FALSE on error.
741 ALURE_API ALboolean ALURE_APIENTRY alureInstallDecodeCallbacks(ALint index,
742 void* (*open_file)(const ALchar *filename),
743 void* (*open_memory)(const ALubyte *data, ALuint length),
744 ALboolean (*get_format)(void *instance, ALenum *format, ALuint *samplerate, ALuint *blocksize),
745 ALuint (*decode)(void *instance, ALubyte *data, ALuint bytes),
746 ALboolean (*rewind)(void *instance),
747 void (*close)(void *instance))
749 if(!open_file && !open_memory && !get_format && !decode && !rewind && !close)
751 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.find(index);
752 if(i != InstalledCallbacks.end())
753 InstalledCallbacks.erase(i);
754 return AL_TRUE;
757 if((!open_file && !open_memory) || !get_format || !decode)
759 SetError("Missing callback functions");
760 return AL_FALSE;
763 UserCallbacks newcb;
764 newcb.open_file = open_file;
765 newcb.open_mem = open_memory;
766 newcb.get_fmt = get_format;
767 newcb.decode = decode;
768 newcb.rewind = rewind;
769 newcb.close = close;
771 InstalledCallbacks[index] = newcb;
773 return AL_TRUE;
777 /* Function: alureSleep
779 * Rests the calling thread for the given number of seconds.
781 * Returns:
782 * AL_FALSE on error.
784 ALURE_API ALboolean ALURE_APIENTRY alureSleep(ALfloat duration)
786 if(duration < 0.0f)
788 SetError("Invalid duration");
789 return AL_FALSE;
792 ALuint seconds = (ALuint)duration;
793 ALfloat rest = duration - (ALfloat)seconds;
795 #ifdef HAVE_NANOSLEEP
797 struct timespec t, remainingTime;
798 t.tv_sec = (time_t)seconds;
799 t.tv_nsec = (long)(rest*1000000)*1000;
801 while(nanosleep(&t, &remainingTime) < 0 && errno == EINTR)
802 t = remainingTime;
804 #elif defined(HAVE_WINDOWS_H)
806 while(seconds > 0)
808 Sleep(1000);
809 seconds--;
811 Sleep((DWORD)(rest * 1000));
813 #endif
815 return AL_TRUE;
819 /* Function: alureGetProcAddress
821 * Returns a pointer for the named ALURE function.
823 * Returns:
824 * NULL on error.
826 ALURE_API void* ALURE_APIENTRY alureGetProcAddress(const ALchar *funcname)
828 if(FunctionList.size() == 0)
830 #define ADD_FUNCTION(x) FunctionList[#x] = (void*)(x)
831 ADD_FUNCTION(alureGetVersion);
832 ADD_FUNCTION(alureGetErrorString);
833 ADD_FUNCTION(alureGetDeviceNames);
834 ADD_FUNCTION(alureFreeDeviceNames);
835 ADD_FUNCTION(alureInitDevice);
836 ADD_FUNCTION(alureShutdownDevice);
837 ADD_FUNCTION(alureGetSampleFormat);
838 ADD_FUNCTION(alureSleep);
839 ADD_FUNCTION(alureCreateBufferFromFile);
840 ADD_FUNCTION(alureCreateBufferFromMemory);
841 ADD_FUNCTION(alureBufferDataFromFile);
842 ADD_FUNCTION(alureBufferDataFromMemory);
843 ADD_FUNCTION(alureCreateStreamFromFile);
844 ADD_FUNCTION(alureCreateStreamFromMemory);
845 ADD_FUNCTION(alureCreateStreamFromStaticMemory);
846 ADD_FUNCTION(alureCreateStreamFromCallback);
847 ADD_FUNCTION(alureRewindStream);
848 ADD_FUNCTION(alureDestroyStream);
849 ADD_FUNCTION(alureInstallDecodeCallbacks);
850 ADD_FUNCTION(alureSetIOCallbacks);
851 ADD_FUNCTION(alureGetProcAddress);
852 ADD_FUNCTION(alurePlaySourceStream);
853 ADD_FUNCTION(alurePlaySource);
854 ADD_FUNCTION(alureStopSource);
855 ADD_FUNCTION(alureGetSourceOffset);
856 #undef ADD_FUNCTION
859 std::map<std::string,void*>::iterator i = FunctionList.find(funcname);
860 if(i != FunctionList.end())
861 return i->second;
863 SetError("Function not found");
864 return NULL;
867 } // extern "C"