Use unique function names for handling external libs, instead of winapi names
[alure.git] / src / alure.cpp
blobd694dfb50ca5cc88550e0a5c2d29027f93044f18
1 /*
2 * ALURE OpenAL utility library
3 * Copyright (c) 2009 by Chris Robinson.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
24 /* Title: Main and Miscellanious */
26 #include "config.h"
28 #include "main.h"
30 #include <string.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <time.h>
34 #ifdef HAVE_WINDOWS_H
35 #include <windows.h>
36 #endif
38 #include <vector>
39 #include <string>
40 #include <map>
42 std::map<ALint,UserCallbacks> InstalledCallbacks;
43 CRITICAL_SECTION cs_StreamPlay;
44 alureStream::ListType alureStream::StreamList;
46 void *vorbisfile_handle = NULL;
47 void *flac_handle = NULL;
48 void *dumb_handle = NULL;
49 void *mod_handle = NULL;
50 void *mp123_handle = NULL;
51 void *sndfile_handle = NULL;
52 void *fsynth_handle = NULL;
54 #define MAKE_FUNC(x) typeof(x)* p##x
55 #ifdef HAS_VORBISFILE
56 MAKE_FUNC(ov_clear);
57 MAKE_FUNC(ov_info);
58 MAKE_FUNC(ov_open_callbacks);
59 MAKE_FUNC(ov_pcm_seek);
60 MAKE_FUNC(ov_read);
61 #endif
62 #ifdef HAS_FLAC
63 MAKE_FUNC(FLAC__stream_decoder_get_state);
64 MAKE_FUNC(FLAC__stream_decoder_finish);
65 MAKE_FUNC(FLAC__stream_decoder_new);
66 MAKE_FUNC(FLAC__stream_decoder_seek_absolute);
67 MAKE_FUNC(FLAC__stream_decoder_delete);
68 MAKE_FUNC(FLAC__stream_decoder_process_single);
69 MAKE_FUNC(FLAC__stream_decoder_init_stream);
70 #endif
71 #ifdef HAS_DUMB
72 MAKE_FUNC(dumbfile_open_ex);
73 MAKE_FUNC(dumbfile_close);
74 MAKE_FUNC(dumb_read_mod);
75 MAKE_FUNC(dumb_read_s3m);
76 MAKE_FUNC(dumb_read_xm);
77 MAKE_FUNC(dumb_read_it);
78 MAKE_FUNC(dumb_silence);
79 MAKE_FUNC(duh_sigrenderer_generate_samples);
80 MAKE_FUNC(duh_get_it_sigrenderer);
81 MAKE_FUNC(duh_end_sigrenderer);
82 MAKE_FUNC(unload_duh);
83 MAKE_FUNC(dumb_it_start_at_order);
84 MAKE_FUNC(dumb_it_set_loop_callback);
85 MAKE_FUNC(dumb_it_sr_get_speed);
86 MAKE_FUNC(dumb_it_sr_set_speed);
87 #endif
88 #ifdef HAS_MODPLUG
89 MAKE_FUNC(ModPlug_Load);
90 MAKE_FUNC(ModPlug_Unload);
91 MAKE_FUNC(ModPlug_Read);
92 MAKE_FUNC(ModPlug_SeekOrder);
93 #endif
94 #ifdef HAS_MPG123
95 MAKE_FUNC(mpg123_read);
96 MAKE_FUNC(mpg123_init);
97 MAKE_FUNC(mpg123_open_feed);
98 MAKE_FUNC(mpg123_new);
99 MAKE_FUNC(mpg123_delete);
100 MAKE_FUNC(mpg123_feed);
101 MAKE_FUNC(mpg123_exit);
102 MAKE_FUNC(mpg123_getformat);
103 MAKE_FUNC(mpg123_format_none);
104 MAKE_FUNC(mpg123_decode);
105 MAKE_FUNC(mpg123_format);
106 #endif
107 #ifdef HAS_SNDFILE
108 MAKE_FUNC(sf_close);
109 MAKE_FUNC(sf_open_virtual);
110 MAKE_FUNC(sf_readf_short);
111 MAKE_FUNC(sf_seek);
112 #endif
113 #ifdef HAS_FLUIDSYNTH
114 MAKE_FUNC(fluid_settings_setstr);
115 MAKE_FUNC(fluid_synth_program_change);
116 MAKE_FUNC(fluid_synth_sfload);
117 MAKE_FUNC(fluid_settings_setnum);
118 MAKE_FUNC(fluid_synth_sysex);
119 MAKE_FUNC(fluid_synth_cc);
120 MAKE_FUNC(fluid_synth_pitch_bend);
121 MAKE_FUNC(fluid_synth_channel_pressure);
122 MAKE_FUNC(fluid_synth_write_float);
123 MAKE_FUNC(new_fluid_synth);
124 MAKE_FUNC(delete_fluid_settings);
125 MAKE_FUNC(delete_fluid_synth);
126 MAKE_FUNC(fluid_synth_program_reset);
127 MAKE_FUNC(fluid_settings_setint);
128 MAKE_FUNC(new_fluid_settings);
129 MAKE_FUNC(fluid_synth_write_s16);
130 MAKE_FUNC(fluid_synth_noteoff);
131 MAKE_FUNC(fluid_synth_sfunload);
132 MAKE_FUNC(fluid_synth_noteon);
133 #endif
134 #undef MAKE_FUNC
136 #ifdef HAVE_GCC_CONSTRUCTOR
137 static void init_alure(void) __attribute__((constructor));
138 static void deinit_alure(void) __attribute__((destructor));
139 static struct MyConstructorClass {
140 ~MyConstructorClass()
141 { alureStream::Clear(); };
142 } MyConstructor;
143 #elif defined(_WIN32) && !defined(ALURE_STATIC_LIBRARY)
144 static void init_alure(void);
145 static void deinit_alure(void);
146 static struct MyConstructorClass {
147 ~MyConstructorClass()
148 { alureStream::Clear(); };
149 } MyConstructor;
151 extern "C" BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
153 (void)reserved;
155 // Perform actions based on the reason for calling.
156 switch(reason)
158 case DLL_PROCESS_ATTACH:
159 DisableThreadLibraryCalls(module);
160 init_alure();
161 break;
163 case DLL_PROCESS_DETACH:
164 deinit_alure();
165 break;
167 return TRUE;
169 #else
170 static void init_alure(void);
171 static void deinit_alure(void);
173 static struct MyConstructorClass {
174 MyConstructorClass()
175 { init_alure(); };
176 ~MyConstructorClass()
177 { alureStream::Clear();
178 deinit_alure(); };
179 } MyConstructor;
180 #endif
183 #ifndef DYNLOAD
184 static inline void *OpenLib(const char*)
185 { return (void*)0xDEADBEEF; }
186 static inline void CloseLib(void*)
188 #define LOAD_FUNC(h, x) p##x = x
190 #else
191 #ifdef _WIN32
193 static inline void *OpenLib(const char *libname)
194 { return LoadLibraryA(libname); }
195 static inline void CloseLib(void*)
196 { FreeLibrary((HINSTANCE)(x)); }
197 static inline void *GetLibProc(void *hdl, const char *funcname)
198 { return GetProcAddress((HINSTANCE)hdl, funcname); }
200 #else
202 static inline void *OpenLib(const char *libname)
204 dlerror();
205 void *hdl = dlopen(libname, RTLD_NOW);
206 const char *err;
207 if((err=dlerror()) != NULL)
209 fprintf(stderr, "Error loading %s: %s\n", libname, err);
210 return NULL;
212 return hdl;
214 static inline void *GetLibProc(void *hdl, const char *funcname)
216 dlerror();
217 void *fn = dlsym(hdl, funcname);
218 const char *err;
219 if((err=dlerror()) != NULL)
221 fprintf(stderr, "Error loading %s: %s\n", funcname, err);
222 return NULL;
224 return fn;
226 static inline void CloseLib(void *hdl)
227 { dlclose(hdl); }
228 #endif
230 #define LOAD_FUNC(h, x) p##x = (typeof(p##x))GetLibProc(h##_handle, #x); \
231 if(!p##x) \
233 CloseLib(h##_handle); \
234 h##_handle = NULL; \
235 break; \
237 #endif
239 static void init_alure(void)
241 InitializeCriticalSection(&cs_StreamPlay);
243 #ifdef _WIN32
244 #define VORBISFILE_LIB "vorbisfile.dll"
245 #define FLAC_LIB "libFLAC.dll"
246 #define DUMB_LIB "libdumb.dll"
247 #define MODPLUG_LIB "libmodplug.dll"
248 #define MPG123_LIB "libmpg123.dll"
249 #define SNDFILE_LIB "libsndfile-1.dll"
250 #define FLUIDSYNTH_LIB "libfluidsynth.dll"
251 #elif defined(__APPLE__)
252 #define VORBISFILE_LIB "libvorbisfile.3.dylib"
253 #define FLAC_LIB "libFLAC.8.dylib"
254 #define DUMB_LIB "libdumb.dylib"
255 #define MODPLUG_LIB "libmodplug.1.dylib"
256 #define MPG123_LIB "libmpg123.0.dylib"
257 #define SNDFILE_LIB "libsndfile.1.dylib"
258 #define FLUIDSYNTH_LIB "libfluidsynth.1.dylib"
259 #else
260 #define VORBISFILE_LIB "libvorbisfile.so.3"
261 #define FLAC_LIB "libFLAC.so.8"
262 #define DUMB_LIB "libdumb.so"
263 #define MODPLUG_LIB "libmodplug.so.1"
264 #define MPG123_LIB "libmpg123.so.0"
265 #define SNDFILE_LIB "libsndfile.so.1"
266 #define FLUIDSYNTH_LIB "libfluidsynth.so.1"
267 #endif
269 #ifdef HAS_VORBISFILE
270 vorbisfile_handle = OpenLib(VORBISFILE_LIB);
271 while(vorbisfile_handle)
273 LOAD_FUNC(vorbisfile, ov_clear);
274 LOAD_FUNC(vorbisfile, ov_info);
275 LOAD_FUNC(vorbisfile, ov_open_callbacks);
276 LOAD_FUNC(vorbisfile, ov_pcm_seek);
277 LOAD_FUNC(vorbisfile, ov_read);
278 break;
280 #endif
282 #ifdef HAS_FLAC
283 flac_handle = OpenLib(FLAC_LIB);
284 while(flac_handle)
286 LOAD_FUNC(flac, FLAC__stream_decoder_get_state);
287 LOAD_FUNC(flac, FLAC__stream_decoder_finish);
288 LOAD_FUNC(flac, FLAC__stream_decoder_new);
289 LOAD_FUNC(flac, FLAC__stream_decoder_seek_absolute);
290 LOAD_FUNC(flac, FLAC__stream_decoder_delete);
291 LOAD_FUNC(flac, FLAC__stream_decoder_process_single);
292 LOAD_FUNC(flac, FLAC__stream_decoder_init_stream);
293 break;
295 #endif
297 #ifdef HAS_DUMB
298 dumb_handle = OpenLib(DUMB_LIB);
299 while(dumb_handle)
301 LOAD_FUNC(dumb, dumbfile_open_ex);
302 LOAD_FUNC(dumb, dumbfile_close);
303 LOAD_FUNC(dumb, dumb_read_mod);
304 LOAD_FUNC(dumb, dumb_read_s3m);
305 LOAD_FUNC(dumb, dumb_read_xm);
306 LOAD_FUNC(dumb, dumb_read_it);
307 LOAD_FUNC(dumb, dumb_silence);
308 LOAD_FUNC(dumb, duh_sigrenderer_generate_samples);
309 LOAD_FUNC(dumb, duh_get_it_sigrenderer);
310 LOAD_FUNC(dumb, duh_end_sigrenderer);
311 LOAD_FUNC(dumb, unload_duh);
312 LOAD_FUNC(dumb, dumb_it_start_at_order);
313 LOAD_FUNC(dumb, dumb_it_set_loop_callback);
314 LOAD_FUNC(dumb, dumb_it_sr_get_speed);
315 LOAD_FUNC(dumb, dumb_it_sr_set_speed);
316 break;
318 #endif
320 #ifdef HAS_MODPLUG
321 mod_handle = OpenLib(MODPLUG_LIB);
322 while(mod_handle)
324 LOAD_FUNC(mod, ModPlug_Load);
325 LOAD_FUNC(mod, ModPlug_Unload);
326 LOAD_FUNC(mod, ModPlug_Read);
327 LOAD_FUNC(mod, ModPlug_SeekOrder);
328 break;
330 #endif
332 #ifdef HAS_MPG123
333 mp123_handle = OpenLib(MPG123_LIB);
334 while(mp123_handle)
336 LOAD_FUNC(mp123, mpg123_read);
337 LOAD_FUNC(mp123, mpg123_init);
338 LOAD_FUNC(mp123, mpg123_open_feed);
339 LOAD_FUNC(mp123, mpg123_new);
340 LOAD_FUNC(mp123, mpg123_delete);
341 LOAD_FUNC(mp123, mpg123_feed);
342 LOAD_FUNC(mp123, mpg123_exit);
343 LOAD_FUNC(mp123, mpg123_getformat);
344 LOAD_FUNC(mp123, mpg123_format_none);
345 LOAD_FUNC(mp123, mpg123_decode);
346 LOAD_FUNC(mp123, mpg123_format);
347 pmpg123_init();
348 break;
350 #endif
352 #ifdef HAS_SNDFILE
353 sndfile_handle = OpenLib(SNDFILE_LIB);
354 while(sndfile_handle)
356 LOAD_FUNC(sndfile, sf_close);
357 LOAD_FUNC(sndfile, sf_open_virtual);
358 LOAD_FUNC(sndfile, sf_readf_short);
359 LOAD_FUNC(sndfile, sf_seek);
360 break;
362 #endif
364 #ifdef HAS_FLUIDSYNTH
365 fsynth_handle = OpenLib(FLUIDSYNTH_LIB);
366 while(fsynth_handle)
368 LOAD_FUNC(fsynth, fluid_settings_setstr);
369 LOAD_FUNC(fsynth, fluid_synth_program_change);
370 LOAD_FUNC(fsynth, fluid_synth_sfload);
371 LOAD_FUNC(fsynth, fluid_settings_setnum);
372 LOAD_FUNC(fsynth, fluid_synth_sysex);
373 LOAD_FUNC(fsynth, fluid_synth_cc);
374 LOAD_FUNC(fsynth, fluid_synth_pitch_bend);
375 LOAD_FUNC(fsynth, fluid_synth_channel_pressure);
376 LOAD_FUNC(fsynth, fluid_synth_write_float);
377 LOAD_FUNC(fsynth, new_fluid_synth);
378 LOAD_FUNC(fsynth, delete_fluid_settings);
379 LOAD_FUNC(fsynth, delete_fluid_synth);
380 LOAD_FUNC(fsynth, fluid_synth_program_reset);
381 LOAD_FUNC(fsynth, fluid_settings_setint);
382 LOAD_FUNC(fsynth, new_fluid_settings);
383 LOAD_FUNC(fsynth, fluid_synth_write_s16);
384 LOAD_FUNC(fsynth, fluid_synth_noteoff);
385 LOAD_FUNC(fsynth, fluid_synth_sfunload);
386 LOAD_FUNC(fsynth, fluid_synth_noteon);
387 break;
389 #endif
391 #undef VORBISFILE_LIB
392 #undef FLAC_LIB
393 #undef DUMB_LIB
394 #undef MPG123_LIB
395 #undef SNDFILE_LIB
396 #undef LOAD_FUNC
399 static void deinit_alure(void)
401 #ifdef HAS_VORBISFILE
402 if(vorbisfile_handle)
403 CloseLib(vorbisfile_handle);
404 vorbisfile_handle = NULL;
405 #endif
406 #ifdef HAS_FLAC
407 if(flac_handle)
408 CloseLib(flac_handle);
409 flac_handle = NULL;
410 #endif
411 #ifdef HAS_DUMB
412 if(dumb_handle)
413 CloseLib(dumb_handle);
414 dumb_handle = NULL;
415 #endif
416 #ifdef HAS_MPG123
417 if(mp123_handle)
419 pmpg123_exit();
420 CloseLib(mp123_handle);
422 mp123_handle = NULL;
423 #endif
424 #ifdef HAS_SNDFILE
425 if(sndfile_handle)
426 CloseLib(sndfile_handle);
427 sndfile_handle = NULL;
428 #endif
430 DeleteCriticalSection(&cs_StreamPlay);
434 static const ALchar *last_error = "No error";
436 void SetError(const char *err)
438 last_error = err;
441 ALuint DetectBlockAlignment(ALenum format)
443 switch(format)
445 #define CHECK_RET(f,s) case (f): return (s)
446 CHECK_RET(AL_FORMAT_MONO8, sizeof(ALubyte));
447 CHECK_RET(AL_FORMAT_MONO16, sizeof(ALshort));
448 CHECK_RET(AL_FORMAT_MONO_FLOAT32, sizeof(ALfloat));
449 CHECK_RET(AL_FORMAT_MONO_DOUBLE_EXT, sizeof(ALdouble));
450 CHECK_RET(AL_FORMAT_MONO_MULAW, sizeof(ALubyte)*1);
452 CHECK_RET(AL_FORMAT_STEREO8, sizeof(ALubyte)*2);
453 CHECK_RET(AL_FORMAT_STEREO16, sizeof(ALshort)*2);
454 CHECK_RET(AL_FORMAT_STEREO_FLOAT32, sizeof(ALfloat)*2);
455 CHECK_RET(AL_FORMAT_STEREO_DOUBLE_EXT, sizeof(ALdouble)*2);
456 CHECK_RET(AL_FORMAT_STEREO_MULAW, sizeof(ALubyte)*2);
458 CHECK_RET(AL_FORMAT_QUAD8, sizeof(ALubyte)*4);
459 CHECK_RET(AL_FORMAT_QUAD16, sizeof(ALshort)*4);
460 CHECK_RET(AL_FORMAT_QUAD32, sizeof(ALfloat)*4);
461 CHECK_RET(AL_FORMAT_QUAD_MULAW, sizeof(ALubyte)*4);
463 CHECK_RET(AL_FORMAT_REAR8, sizeof(ALubyte)*2);
464 CHECK_RET(AL_FORMAT_REAR16, sizeof(ALshort)*2);
465 CHECK_RET(AL_FORMAT_REAR32, sizeof(ALfloat)*2);
466 CHECK_RET(AL_FORMAT_REAR_MULAW, sizeof(ALubyte)*2);
468 CHECK_RET(AL_FORMAT_51CHN8, sizeof(ALubyte)*6);
469 CHECK_RET(AL_FORMAT_51CHN16, sizeof(ALshort)*6);
470 CHECK_RET(AL_FORMAT_51CHN32, sizeof(ALfloat)*6);
471 CHECK_RET(AL_FORMAT_51CHN_MULAW, sizeof(ALubyte)*6);
473 CHECK_RET(AL_FORMAT_61CHN8, sizeof(ALubyte)*7);
474 CHECK_RET(AL_FORMAT_61CHN16, sizeof(ALshort)*7);
475 CHECK_RET(AL_FORMAT_61CHN32, sizeof(ALfloat)*7);
476 CHECK_RET(AL_FORMAT_61CHN_MULAW, sizeof(ALubyte)*7);
478 CHECK_RET(AL_FORMAT_71CHN8, sizeof(ALubyte)*8);
479 CHECK_RET(AL_FORMAT_71CHN16, sizeof(ALshort)*8);
480 CHECK_RET(AL_FORMAT_71CHN32, sizeof(ALfloat)*8);
481 CHECK_RET(AL_FORMAT_71CHN_MULAW, sizeof(ALubyte)*8);
483 CHECK_RET(AL_FORMAT_MONO_IMA4, 36);
484 CHECK_RET(AL_FORMAT_STEREO_IMA4, 36*2);
485 #undef CHECK_RET
487 return 0;
490 ALuint DetectCompressionRate(ALenum format)
492 switch(format)
494 case AL_FORMAT_MONO8:
495 case AL_FORMAT_MONO16:
496 case AL_FORMAT_MONO_FLOAT32:
497 case AL_FORMAT_MONO_DOUBLE_EXT:
498 case AL_FORMAT_STEREO8:
499 case AL_FORMAT_STEREO16:
500 case AL_FORMAT_STEREO_FLOAT32:
501 case AL_FORMAT_STEREO_DOUBLE_EXT:
502 case AL_FORMAT_QUAD8:
503 case AL_FORMAT_QUAD16:
504 case AL_FORMAT_QUAD32:
505 case AL_FORMAT_REAR8:
506 case AL_FORMAT_REAR16:
507 case AL_FORMAT_REAR32:
508 case AL_FORMAT_51CHN8:
509 case AL_FORMAT_51CHN16:
510 case AL_FORMAT_51CHN32:
511 case AL_FORMAT_61CHN8:
512 case AL_FORMAT_61CHN16:
513 case AL_FORMAT_61CHN32:
514 case AL_FORMAT_71CHN8:
515 case AL_FORMAT_71CHN16:
516 case AL_FORMAT_71CHN32:
517 return 1;
519 case AL_FORMAT_MONO_MULAW:
520 case AL_FORMAT_STEREO_MULAW:
521 case AL_FORMAT_QUAD_MULAW:
522 case AL_FORMAT_REAR_MULAW:
523 case AL_FORMAT_51CHN_MULAW:
524 case AL_FORMAT_61CHN_MULAW:
525 case AL_FORMAT_71CHN_MULAW:
526 return 1;
528 case AL_FORMAT_MONO_IMA4:
529 case AL_FORMAT_STEREO_IMA4:
530 return 65;
532 fprintf(stderr, "Alure lib: Unhandled format: %#x\n", format);
533 return 0;
536 ALenum GetSampleFormat(ALuint channels, ALuint bits, bool isFloat)
538 #define CHECK_FMT_RET(f) do { \
539 ALenum fmt = alGetEnumValue(#f); \
540 if(alGetError() == AL_NO_ERROR && fmt != 0 && fmt != -1) \
541 return fmt; \
542 } while(0)
543 if(!isFloat)
545 if(bits == 8)
547 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO8);
548 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO8);
549 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
551 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8);
552 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN8);
553 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN8);
554 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN8);
556 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
558 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8_LOKI);
560 SetError("Unsupported 8-bit channel count\n");
561 return AL_NONE;
563 if(bits == 16)
565 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO16);
566 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO16);
567 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
569 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16);
570 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN16);
571 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN16);
572 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN16);
574 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
576 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16_LOKI);
578 SetError("Unsupported 16-bit channel count\n");
579 return AL_NONE;
581 SetError("Unsupported PCM bit depth\n");
582 return AL_NONE;
585 if(bits == 32 && alIsExtensionPresent("AL_EXT_FLOAT32"))
587 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_FLOAT32);
588 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_FLOAT32);
589 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
591 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD32);
592 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN32);
593 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN32);
594 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN32);
596 SetError("Unsupported float32 channel count\n");
597 return AL_NONE;
599 if(bits == 64 && alIsExtensionPresent("AL_EXT_DOUBLE"))
601 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_DOUBLE_EXT);
602 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_DOUBLE_EXT);
603 SetError("Unsupported double channel count\n");
604 return AL_NONE;
606 #undef CHECK_FMT_RET
608 SetError("Unsupported float bit depth\n");
609 return AL_NONE;
612 extern "C" {
614 /* Function: alureGetVersion
616 * Stores the major and minor version of the library. If either major or minor
617 * are NULL, that value is not provided.
619 ALURE_API void ALURE_APIENTRY alureGetVersion(ALuint *major, ALuint *minor)
621 if(major) *major = ALURE_VER_MAJOR;
622 if(minor) *minor = ALURE_VER_MINOR;
625 /* Function: alureGetErrorString
627 * Returns a string describing the last error encountered.
629 ALURE_API const ALchar* ALURE_APIENTRY alureGetErrorString(void)
631 const ALchar *ret = last_error;
632 last_error = "No error";
633 return ret;
637 /* Function: alureGetDeviceNames
639 * Gets an array of device name strings from OpenAL. This encapsulates
640 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
641 * enumeration, with 'count' being set to the number of returned device
642 * names.
644 * Returns:
645 * An array of device name strings, or NULL on error.
647 * See Also:
648 * <alureFreeDeviceNames>
650 ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean all, ALCsizei *count)
652 const ALCchar *list = NULL;
653 if(all && alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
654 list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
655 else
656 list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
657 if(!list)
659 alcGetError(NULL);
660 SetError("No device names found");
661 return NULL;
664 const ALCchar *cur = list;
665 ALuint retlistLen = 0;
666 while(*cur)
668 cur += strlen(cur)+1;
669 retlistLen++;
672 const ALCchar **retlist = new const ALCchar*[retlistLen+1];
673 retlistLen = 0;
674 cur = list;
675 while(*cur)
677 ALCuint len = strlen(cur)+1;
678 ALCchar *newstr = new ALCchar[len];
680 memcpy(newstr, cur, len);
681 cur += len;
683 retlist[retlistLen] = newstr;
684 retlistLen++;
686 retlist[retlistLen] = NULL;
688 *count = retlistLen;
689 return retlist;
692 /* Function: alureFreeDeviceNames
694 * Frees the device name array returned from alureGetDeviceNames.
696 * See Also:
697 * <alureGetDeviceNames>
699 ALURE_API ALvoid ALURE_APIENTRY alureFreeDeviceNames(const ALCchar **names)
701 if(names)
703 for(ALCuint i = 0;names[i];i++)
704 delete[] const_cast<ALCchar*>(names[i]);
705 delete[] names;
710 /* Function: alureInitDevice
712 * Opens the named device, creates a context with the given attributes, and
713 * sets that context as current. The name and attribute list would be the same
714 * as what's passed to alcOpenDevice and alcCreateContext respectively.
716 * Returns:
717 * AL_FALSE on error.
719 * See Also:
720 * <alureShutdownDevice>
722 ALURE_API ALboolean ALURE_APIENTRY alureInitDevice(const ALCchar *name, const ALCint *attribs)
724 ALCdevice *device = alcOpenDevice(name);
725 if(!device)
727 alcGetError(NULL);
729 SetError("Device open failed");
730 return AL_FALSE;
733 ALCcontext *context = alcCreateContext(device, attribs);
734 if(!context || alcMakeContextCurrent(context) == ALC_FALSE)
736 if(context)
737 alcDestroyContext(context);
738 alcCloseDevice(device);
740 SetError("Context setup failed");
741 return AL_FALSE;
743 alcGetError(device);
745 return AL_TRUE;
748 /* Function: alureShutdownDevice
750 * Destroys the current context and closes its associated device.
752 * Returns:
753 * AL_FALSE on error.
755 * See Also:
756 * <alureInitDevice>
758 ALURE_API ALboolean ALURE_APIENTRY alureShutdownDevice(void)
760 ALCcontext *context = alcGetCurrentContext();
761 ALCdevice *device = alcGetContextsDevice(context);
762 if(!context || !device)
764 alcGetError(device);
765 SetError("Failed to get current device");
766 return AL_FALSE;
769 if(alcMakeContextCurrent(NULL) == ALC_FALSE)
771 alcGetError(NULL);
772 SetError("Failed to unset current context");
773 return AL_FALSE;
776 alcDestroyContext(context);
777 alcCloseDevice(device);
778 alcGetError(NULL);
780 return AL_TRUE;
784 /* Function: alureGetSampleFormat
786 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
787 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
788 * application should not rely on any particular format enum being returned as
789 * it is dependant on the available extensions. The returned format will be
790 * valid for the current context. Requires an active context.
792 * Returns:
793 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
794 * be found.
796 ALURE_API ALenum ALURE_APIENTRY alureGetSampleFormat(ALuint channels, ALuint bits, ALuint floatbits)
798 if(alGetError() != AL_NO_ERROR)
800 SetError("Existing OpenAL error");
801 return AL_NONE;
804 if(bits && floatbits)
806 SetError("Both bit-types specified");
807 return AL_NONE;
810 if(bits)
811 return GetSampleFormat(channels, bits, false);
812 return GetSampleFormat(channels, floatbits, true);
816 /* Function: alureInstallDecodeCallbacks
818 * Installs callbacks to enable ALURE to handle more file types. The index is
819 * the order that each given set of callbacks will be tried, starting at the
820 * most negative number (INT_MIN) and going up. Negative indices will be tried
821 * before the built-in decoders, and positive indices will be tried after.
822 * Installing callbacks onto the same index multiple times will remove the
823 * previous callbacks, and removing old callbacks won't affect any opened files
824 * using them (they'll continue to use the old functions until properly closed,
825 * although newly opened files will use the new ones). Passing NULL for all
826 * callbacks is a valid way to remove an installed set, otherwise certain
827 * callbacks must be specified. Callbacks that are not specified will assume
828 * failure.
830 * Parameters:
831 * open_file - This callback is expected to open the named file and prepare it
832 * for decoding. If the callbacks cannot decode the file, NULL
833 * should be returned to indicate failure. Upon success, a non-NULL
834 * handle must be returned, which will be used as a unique
835 * identifier for the decoder instance. This callback is required
836 * if open_memory is not specified.
837 * open_memory - This callback behaves the same as open_file, except it takes a
838 * memory segment for input instead of a filename. The given
839 * memory will remain valid while the instance is open. This
840 * callback is required if open_file is not specified.
841 * get_format - This callback is used to retrieve the format of the decoded
842 * data for the given instance. It is the responsibility of the
843 * function to make sure the returned format is valid for the
844 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
845 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
846 * samplerate or blocksize, or returning AL_NONE for format, will
847 * cause a failure. Returning AL_FALSE indicates failure. This
848 * callback is required.
849 * decode - This callback is called to get more decoded data. Up to the
850 * specified amount of bytes should be written to the data pointer.
851 * The number of bytes written should be a multiple of the block size,
852 * otherwise an OpenAL error may occur during buffering. The function
853 * should return the number of bytes written. This callback is
854 * required.
855 * rewind - This callback is for rewinding the instance so that the next decode
856 * calls for it will get audio data from the start of the sound file.
857 * If the stream fails to rewind, AL_FALSE should be returned.
858 * close - This callback is called at the end of processing for a particular
859 * instance. The handle will not be used further and any associated
860 * data may be deleted.
862 * Returns:
863 * AL_FALSE on error.
865 ALURE_API ALboolean ALURE_APIENTRY alureInstallDecodeCallbacks(ALint index,
866 void* (*open_file)(const ALchar *filename),
867 void* (*open_memory)(const ALubyte *data, ALuint length),
868 ALboolean (*get_format)(void *instance, ALenum *format, ALuint *samplerate, ALuint *blocksize),
869 ALuint (*decode)(void *instance, ALubyte *data, ALuint bytes),
870 ALboolean (*rewind)(void *instance),
871 void (*close)(void *instance))
873 if(!open_file && !open_memory && !get_format && !decode && !rewind && !close)
875 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.find(index);
876 if(i != InstalledCallbacks.end())
877 InstalledCallbacks.erase(i);
878 return AL_TRUE;
881 if((!open_file && !open_memory) || !get_format || !decode)
883 SetError("Missing callback functions");
884 return AL_FALSE;
887 UserCallbacks newcb;
888 newcb.open_file = open_file;
889 newcb.open_mem = open_memory;
890 newcb.get_fmt = get_format;
891 newcb.decode = decode;
892 newcb.rewind = rewind;
893 newcb.close = close;
895 InstalledCallbacks[index] = newcb;
897 return AL_TRUE;
901 /* Function: alureSleep
903 * Rests the calling thread for the given number of seconds.
905 * Returns:
906 * AL_FALSE on error.
908 ALURE_API ALboolean ALURE_APIENTRY alureSleep(ALfloat duration)
910 if(duration < 0.0f)
912 SetError("Invalid duration");
913 return AL_FALSE;
916 ALuint seconds = (ALuint)duration;
917 ALfloat rest = duration - (ALfloat)seconds;
919 #ifdef HAVE_NANOSLEEP
921 struct timespec t, remainingTime;
922 t.tv_sec = (time_t)seconds;
923 t.tv_nsec = (long)(rest*1000000)*1000;
925 while(nanosleep(&t, &remainingTime) < 0 && errno == EINTR)
926 t = remainingTime;
928 #elif defined(HAVE_WINDOWS_H)
930 while(seconds > 0)
932 Sleep(1000);
933 seconds--;
935 Sleep((DWORD)(rest * 1000));
937 #endif
939 return AL_TRUE;
943 /* Function: alureGetProcAddress
945 * Returns a pointer for the named ALURE function.
947 * Returns:
948 * NULL on error.
950 * *Version Added*: 1.1
952 ALURE_API void* ALURE_APIENTRY alureGetProcAddress(const ALchar *funcname)
954 static const struct {
955 const char *name;
956 void *func;
957 } FunctionList[] = {
958 #define ADD_FUNCTION(x) { #x, (void*)x },
959 ADD_FUNCTION(alureGetVersion)
960 ADD_FUNCTION(alureGetErrorString)
961 ADD_FUNCTION(alureGetDeviceNames)
962 ADD_FUNCTION(alureFreeDeviceNames)
963 ADD_FUNCTION(alureInitDevice)
964 ADD_FUNCTION(alureShutdownDevice)
965 ADD_FUNCTION(alureGetSampleFormat)
966 ADD_FUNCTION(alureSleep)
967 ADD_FUNCTION(alureCreateBufferFromFile)
968 ADD_FUNCTION(alureCreateBufferFromMemory)
969 ADD_FUNCTION(alureBufferDataFromFile)
970 ADD_FUNCTION(alureBufferDataFromMemory)
971 ADD_FUNCTION(alureCreateStreamFromFile)
972 ADD_FUNCTION(alureCreateStreamFromMemory)
973 ADD_FUNCTION(alureCreateStreamFromStaticMemory)
974 ADD_FUNCTION(alureCreateStreamFromCallback)
975 ADD_FUNCTION(alureRewindStream)
976 ADD_FUNCTION(alureDestroyStream)
977 ADD_FUNCTION(alureInstallDecodeCallbacks)
978 ADD_FUNCTION(alureSetIOCallbacks)
979 ADD_FUNCTION(alureGetProcAddress)
980 ADD_FUNCTION(alurePlaySourceStream)
981 ADD_FUNCTION(alurePlaySource)
982 ADD_FUNCTION(alureStopSource)
983 #undef ADD_FUNCTION
984 { NULL, NULL }
987 size_t i;
988 for(i = 0;FunctionList[i].name;i++)
990 if(strcmp(FunctionList[i].name, funcname) == 0)
991 break;
994 if(!FunctionList[i].name)
995 SetError("Function not found");
996 return FunctionList[i].func;
999 } // extern "C"