Remove the DYNLOAD option. It's buggy and causes problems.
[alure.git] / src / alure.cpp
blobdbad5580ebc4e79324da317144650a6b7d4b0c1b
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 PFNALCSETTHREADCONTEXTPROC palcSetThreadContext;
47 PFNALCGETTHREADCONTEXTPROC palcGetThreadContext;
50 template<typename T>
51 static inline void LoadALCProc(ALCdevice *dev, const char *name, T **ptr)
52 { *ptr = reinterpret_cast<T*>(alcGetProcAddress(dev, name)); }
55 #ifdef HAVE_GCC_CONSTRUCTOR
56 static void init_alure(void) __attribute__((constructor));
57 static void deinit_alure(void) __attribute__((destructor));
58 static struct MyConstructorClass {
59 ~MyConstructorClass()
60 { alureStream::Clear(); };
61 } MyConstructor;
62 #elif defined(_WIN32) && !defined(ALURE_STATIC_LIBRARY)
63 static void init_alure(void);
64 static void deinit_alure(void);
65 static struct MyConstructorClass {
66 ~MyConstructorClass()
67 { alureStream::Clear(); };
68 } MyConstructor;
70 extern "C" BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/)
72 // Perform actions based on the reason for calling.
73 switch(reason)
75 case DLL_PROCESS_ATTACH:
76 DisableThreadLibraryCalls(module);
77 init_alure();
78 break;
80 case DLL_PROCESS_DETACH:
81 deinit_alure();
82 break;
84 return TRUE;
86 #else
87 static void init_alure(void);
88 static void deinit_alure(void);
90 static struct MyConstructorClass {
91 MyConstructorClass()
92 { init_alure(); };
93 ~MyConstructorClass()
94 { alureStream::Clear();
95 deinit_alure(); };
96 } MyConstructor;
97 #endif
99 static void init_alure(void)
101 InitializeCriticalSection(&cs_StreamPlay);
103 // These calls actually just return references to the codecs' Decoder
104 // objects. They aren't really used for anything other than to prevent the
105 // compiler from removing the codec initializers.
106 alure_init_wav();
107 alure_init_aiff();
108 #ifdef HAS_VORBISFILE
109 alure_init_vorbisfile();
110 #endif
111 #ifdef HAS_FLAC
112 alure_init_flac();
113 #endif
114 #ifdef HAS_SNDFILE
115 alure_init_sndfile();
116 #endif
117 #ifdef HAS_FLUIDSYNTH
118 alure_init_fluidsynth();
119 #endif
120 #ifdef HAS_DUMB
121 alure_init_dumb();
122 #endif
123 #ifdef HAS_MODPLUG
124 alure_init_modplug();
125 #endif
126 #ifdef HAS_MPG123
127 alure_init_mpg123();
128 #endif
130 if(alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context"))
132 LoadALCProc(NULL, "alcSetThreadContext", &palcSetThreadContext);
133 LoadALCProc(NULL, "alcGetThreadContext", &palcGetThreadContext);
134 if(!palcSetThreadContext || !palcGetThreadContext)
136 fprintf(stderr, "Alure lib: ALC_EXT_thread_local_context advertised, but missing function:\n"
137 " alcSetThreadContext=%p\n"
138 " alcGetThreadContext=%p\n",
139 palcSetThreadContext, palcGetThreadContext);
140 palcSetThreadContext = NULL;
141 palcGetThreadContext = NULL;
146 static void deinit_alure(void)
148 alureUpdateInterval(0.0f);
149 DeleteCriticalSection(&cs_StreamPlay);
153 #ifndef HAVE_WINDOWS_H
155 void EnterCriticalSection(CRITICAL_SECTION *cs)
157 int ret;
158 ret = pthread_mutex_lock(cs);
159 assert(ret == 0);
161 void LeaveCriticalSection(CRITICAL_SECTION *cs)
163 int ret;
164 ret = pthread_mutex_unlock(cs);
165 assert(ret == 0);
167 void InitializeCriticalSection(CRITICAL_SECTION *cs)
169 pthread_mutexattr_t attrib;
170 int ret;
172 ret = pthread_mutexattr_init(&attrib);
173 assert(ret == 0);
175 ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
176 #ifdef HAVE_PTHREAD_NP_H
177 if(ret != 0)
178 ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
179 #endif
180 assert(ret == 0);
181 ret = pthread_mutex_init(cs, &attrib);
182 assert(ret == 0);
184 pthread_mutexattr_destroy(&attrib);
186 void DeleteCriticalSection(CRITICAL_SECTION *cs)
188 int ret;
189 ret = pthread_mutex_destroy(cs);
190 assert(ret == 0);
193 #endif
196 static const ALchar *last_error = "No error";
197 void SetError(const char *err)
199 last_error = err;
203 ALuint DetectBlockAlignment(ALenum format)
205 switch(format)
207 #define CHECK_RET(f,s) case (f): return (s)
208 CHECK_RET(AL_FORMAT_MONO8, sizeof(ALubyte));
209 CHECK_RET(AL_FORMAT_MONO16, sizeof(ALshort));
210 CHECK_RET(AL_FORMAT_MONO_FLOAT32, sizeof(ALfloat));
211 CHECK_RET(AL_FORMAT_MONO_DOUBLE_EXT, sizeof(ALdouble));
212 CHECK_RET(AL_FORMAT_MONO_MULAW, sizeof(ALubyte)*1);
214 CHECK_RET(AL_FORMAT_STEREO8, sizeof(ALubyte)*2);
215 CHECK_RET(AL_FORMAT_STEREO16, sizeof(ALshort)*2);
216 CHECK_RET(AL_FORMAT_STEREO_FLOAT32, sizeof(ALfloat)*2);
217 CHECK_RET(AL_FORMAT_STEREO_DOUBLE_EXT, sizeof(ALdouble)*2);
218 CHECK_RET(AL_FORMAT_STEREO_MULAW, sizeof(ALubyte)*2);
220 CHECK_RET(AL_FORMAT_QUAD8, sizeof(ALubyte)*4);
221 CHECK_RET(AL_FORMAT_QUAD16, sizeof(ALshort)*4);
222 CHECK_RET(AL_FORMAT_QUAD32, sizeof(ALfloat)*4);
223 CHECK_RET(AL_FORMAT_QUAD_MULAW, sizeof(ALubyte)*4);
225 CHECK_RET(AL_FORMAT_REAR8, sizeof(ALubyte)*2);
226 CHECK_RET(AL_FORMAT_REAR16, sizeof(ALshort)*2);
227 CHECK_RET(AL_FORMAT_REAR32, sizeof(ALfloat)*2);
228 CHECK_RET(AL_FORMAT_REAR_MULAW, sizeof(ALubyte)*2);
230 CHECK_RET(AL_FORMAT_51CHN8, sizeof(ALubyte)*6);
231 CHECK_RET(AL_FORMAT_51CHN16, sizeof(ALshort)*6);
232 CHECK_RET(AL_FORMAT_51CHN32, sizeof(ALfloat)*6);
233 CHECK_RET(AL_FORMAT_51CHN_MULAW, sizeof(ALubyte)*6);
235 CHECK_RET(AL_FORMAT_61CHN8, sizeof(ALubyte)*7);
236 CHECK_RET(AL_FORMAT_61CHN16, sizeof(ALshort)*7);
237 CHECK_RET(AL_FORMAT_61CHN32, sizeof(ALfloat)*7);
238 CHECK_RET(AL_FORMAT_61CHN_MULAW, sizeof(ALubyte)*7);
240 CHECK_RET(AL_FORMAT_71CHN8, sizeof(ALubyte)*8);
241 CHECK_RET(AL_FORMAT_71CHN16, sizeof(ALshort)*8);
242 CHECK_RET(AL_FORMAT_71CHN32, sizeof(ALfloat)*8);
243 CHECK_RET(AL_FORMAT_71CHN_MULAW, sizeof(ALubyte)*8);
245 CHECK_RET(AL_FORMAT_MONO_IMA4, 36);
246 CHECK_RET(AL_FORMAT_STEREO_IMA4, 36*2);
247 #undef CHECK_RET
249 return 0;
252 ALuint DetectCompressionRate(ALenum format)
254 switch(format)
256 case AL_FORMAT_MONO8:
257 case AL_FORMAT_MONO16:
258 case AL_FORMAT_MONO_FLOAT32:
259 case AL_FORMAT_MONO_DOUBLE_EXT:
260 case AL_FORMAT_STEREO8:
261 case AL_FORMAT_STEREO16:
262 case AL_FORMAT_STEREO_FLOAT32:
263 case AL_FORMAT_STEREO_DOUBLE_EXT:
264 case AL_FORMAT_QUAD8:
265 case AL_FORMAT_QUAD16:
266 case AL_FORMAT_QUAD32:
267 case AL_FORMAT_REAR8:
268 case AL_FORMAT_REAR16:
269 case AL_FORMAT_REAR32:
270 case AL_FORMAT_51CHN8:
271 case AL_FORMAT_51CHN16:
272 case AL_FORMAT_51CHN32:
273 case AL_FORMAT_61CHN8:
274 case AL_FORMAT_61CHN16:
275 case AL_FORMAT_61CHN32:
276 case AL_FORMAT_71CHN8:
277 case AL_FORMAT_71CHN16:
278 case AL_FORMAT_71CHN32:
279 return 1;
281 case AL_FORMAT_MONO_MULAW:
282 case AL_FORMAT_STEREO_MULAW:
283 case AL_FORMAT_QUAD_MULAW:
284 case AL_FORMAT_REAR_MULAW:
285 case AL_FORMAT_51CHN_MULAW:
286 case AL_FORMAT_61CHN_MULAW:
287 case AL_FORMAT_71CHN_MULAW:
288 return 1;
290 case AL_FORMAT_MONO_IMA4:
291 case AL_FORMAT_STEREO_IMA4:
292 return 65;
294 fprintf(stderr, "Alure lib: Unhandled format: %#x\n", format);
295 return 0;
298 ALenum GetSampleFormat(ALuint channels, ALuint bits, bool isFloat)
300 #define CHECK_FMT_RET(f) do { \
301 ALenum fmt = alGetEnumValue(#f); \
302 if(alGetError() == AL_NO_ERROR && fmt != 0 && fmt != -1) \
303 return fmt; \
304 } while(0)
305 if(!isFloat)
307 if(bits == 8)
309 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO8);
310 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO8);
311 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
313 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8);
314 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN8);
315 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN8);
316 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN8);
318 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
320 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8_LOKI);
322 SetError("Unsupported 8-bit channel count\n");
323 return AL_NONE;
325 if(bits == 16)
327 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO16);
328 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO16);
329 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
331 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16);
332 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN16);
333 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN16);
334 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN16);
336 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
338 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16_LOKI);
340 SetError("Unsupported 16-bit channel count\n");
341 return AL_NONE;
343 SetError("Unsupported PCM bit depth\n");
344 return AL_NONE;
347 if(bits == 32 && alIsExtensionPresent("AL_EXT_FLOAT32"))
349 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_FLOAT32);
350 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_FLOAT32);
351 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
353 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD32);
354 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN32);
355 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN32);
356 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN32);
358 SetError("Unsupported float32 channel count\n");
359 return AL_NONE;
361 if(bits == 64 && alIsExtensionPresent("AL_EXT_DOUBLE"))
363 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_DOUBLE_EXT);
364 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_DOUBLE_EXT);
365 SetError("Unsupported double channel count\n");
366 return AL_NONE;
368 #undef CHECK_FMT_RET
370 SetError("Unsupported float bit depth\n");
371 return AL_NONE;
374 extern "C" {
376 /* Function: alureGetVersion
378 * Stores the major and minor version of the library. If either major or minor
379 * are NULL, that value is not provided.
381 ALURE_API void ALURE_APIENTRY alureGetVersion(ALuint *major, ALuint *minor)
383 if(major) *major = ALURE_VER_MAJOR;
384 if(minor) *minor = ALURE_VER_MINOR;
387 /* Function: alureGetErrorString
389 * Returns a string describing the last error encountered.
391 ALURE_API const ALchar* ALURE_APIENTRY alureGetErrorString(void)
393 const ALchar *ret = last_error;
394 last_error = "No error";
395 return ret;
399 /* Function: alureGetDeviceNames
401 * Gets an array of device name strings from OpenAL. This encapsulates
402 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
403 * enumeration, with 'count' being set to the number of returned device
404 * names.
406 * Returns:
407 * An array of device name strings, or NULL on error.
409 * See Also:
410 * <alureFreeDeviceNames>
412 ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean all, ALCsizei *count)
414 const ALCchar *list = NULL;
415 if(all && alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
416 list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
417 else
418 list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
419 if(!list)
421 alcGetError(NULL);
422 SetError("No device names found");
423 return NULL;
426 const ALCchar *cur = list;
427 ALuint retlistLen = 0;
428 while(*cur)
430 cur += strlen(cur)+1;
431 retlistLen++;
434 const ALCchar **retlist = new const ALCchar*[retlistLen+1];
435 retlistLen = 0;
436 cur = list;
437 while(*cur)
439 ALCuint len = strlen(cur)+1;
440 ALCchar *newstr = new ALCchar[len];
442 memcpy(newstr, cur, len);
443 cur += len;
445 retlist[retlistLen] = newstr;
446 retlistLen++;
448 retlist[retlistLen] = NULL;
450 *count = retlistLen;
451 return retlist;
454 /* Function: alureFreeDeviceNames
456 * Frees the device name array returned from alureGetDeviceNames.
458 * See Also:
459 * <alureGetDeviceNames>
461 ALURE_API ALvoid ALURE_APIENTRY alureFreeDeviceNames(const ALCchar **names)
463 if(names)
465 for(ALCuint i = 0;names[i];i++)
466 delete[] const_cast<ALCchar*>(names[i]);
467 delete[] names;
472 /* Function: alureInitDevice
474 * Opens the named device, creates a context with the given attributes, and
475 * sets that context as current. The name and attribute list would be the same
476 * as what's passed to alcOpenDevice and alcCreateContext respectively.
478 * Returns:
479 * AL_FALSE on error.
481 * See Also:
482 * <alureShutdownDevice>
484 ALURE_API ALboolean ALURE_APIENTRY alureInitDevice(const ALCchar *name, const ALCint *attribs)
486 ALCdevice *device = alcOpenDevice(name);
487 if(!device)
489 alcGetError(NULL);
491 SetError("Device open failed");
492 return AL_FALSE;
495 ALCcontext *context = alcCreateContext(device, attribs);
496 if(!context || alcMakeContextCurrent(context) == ALC_FALSE)
498 if(context)
499 alcDestroyContext(context);
500 alcCloseDevice(device);
502 SetError("Context setup failed");
503 return AL_FALSE;
505 alcGetError(device);
507 return AL_TRUE;
510 /* Function: alureShutdownDevice
512 * Destroys the current context and closes its associated device.
514 * Returns:
515 * AL_FALSE on error.
517 * See Also:
518 * <alureInitDevice>
520 ALURE_API ALboolean ALURE_APIENTRY alureShutdownDevice(void)
522 ALCcontext *context = alcGetCurrentContext();
523 ALCdevice *device = alcGetContextsDevice(context);
524 if(!context || !device)
526 alcGetError(device);
527 SetError("Failed to get current device");
528 return AL_FALSE;
531 if(alcMakeContextCurrent(NULL) == ALC_FALSE)
533 alcGetError(NULL);
534 SetError("Failed to unset current context");
535 return AL_FALSE;
538 alcDestroyContext(context);
539 alcCloseDevice(device);
540 alcGetError(NULL);
542 return AL_TRUE;
546 /* Function: alureGetSampleFormat
548 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
549 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
550 * application should not rely on any particular format enum being returned as
551 * it is dependant on the available extensions. The returned format will be
552 * valid for the current context. Requires an active context.
554 * Returns:
555 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
556 * be found.
558 ALURE_API ALenum ALURE_APIENTRY alureGetSampleFormat(ALuint channels, ALuint bits, ALuint floatbits)
560 if(alGetError() != AL_NO_ERROR)
562 SetError("Existing OpenAL error");
563 return AL_NONE;
566 if(bits && floatbits)
568 SetError("Both bit-types specified");
569 return AL_NONE;
572 if(bits)
573 return GetSampleFormat(channels, bits, false);
574 return GetSampleFormat(channels, floatbits, true);
578 /* Function: alureInstallDecodeCallbacks
580 * Installs callbacks to enable ALURE to handle more file types. The index is
581 * the order that each given set of callbacks will be tried, starting at the
582 * most negative number (INT_MIN) and going up. Negative indices will be tried
583 * before the built-in decoders, and positive indices will be tried after.
584 * Installing callbacks onto the same index multiple times will remove the
585 * previous callbacks, and removing old callbacks won't affect any opened files
586 * using them (they'll continue to use the old functions until properly closed,
587 * although newly opened files will use the new ones). Passing NULL for all
588 * callbacks is a valid way to remove an installed set, otherwise certain
589 * callbacks must be specified. Callbacks that are not specified will assume
590 * failure.
592 * Parameters:
593 * open_file - This callback is expected to open the named file and prepare it
594 * for decoding. If the callbacks cannot decode the file, NULL
595 * should be returned to indicate failure. Upon success, a non-NULL
596 * handle must be returned, which will be used as a unique
597 * identifier for the decoder instance. This callback is required
598 * if open_memory is not specified.
599 * open_memory - This callback behaves the same as open_file, except it takes a
600 * memory segment for input instead of a filename. The given
601 * memory will remain valid while the instance is open. This
602 * callback is required if open_file is not specified.
603 * get_format - This callback is used to retrieve the format of the decoded
604 * data for the given instance. It is the responsibility of the
605 * function to make sure the returned format is valid for the
606 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
607 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
608 * samplerate or blocksize, or returning AL_NONE for format, will
609 * cause a failure. Returning AL_FALSE indicates failure. This
610 * callback is required.
611 * decode - This callback is called to get more decoded data. Up to the
612 * specified amount of bytes should be written to the data pointer.
613 * The number of bytes written should be a multiple of the block size,
614 * otherwise an OpenAL error may occur during buffering. The function
615 * should return the number of bytes written. This callback is
616 * required.
617 * rewind - This callback is for rewinding the instance so that the next decode
618 * calls for it will get audio data from the start of the sound file.
619 * If the stream fails to rewind, AL_FALSE should be returned.
620 * close - This callback is called at the end of processing for a particular
621 * instance. The handle will not be used further and any associated
622 * data may be deleted.
624 * Returns:
625 * AL_FALSE on error.
627 ALURE_API ALboolean ALURE_APIENTRY alureInstallDecodeCallbacks(ALint index,
628 void* (*open_file)(const ALchar *filename),
629 void* (*open_memory)(const ALubyte *data, ALuint length),
630 ALboolean (*get_format)(void *instance, ALenum *format, ALuint *samplerate, ALuint *blocksize),
631 ALuint (*decode)(void *instance, ALubyte *data, ALuint bytes),
632 ALboolean (*rewind)(void *instance),
633 void (*close)(void *instance))
635 if(!open_file && !open_memory && !get_format && !decode && !rewind && !close)
637 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.find(index);
638 if(i != InstalledCallbacks.end())
639 InstalledCallbacks.erase(i);
640 return AL_TRUE;
643 if((!open_file && !open_memory) || !get_format || !decode)
645 SetError("Missing callback functions");
646 return AL_FALSE;
649 UserCallbacks newcb;
650 newcb.open_file = open_file;
651 newcb.open_mem = open_memory;
652 newcb.get_fmt = get_format;
653 newcb.decode = decode;
654 newcb.rewind = rewind;
655 newcb.close = close;
657 InstalledCallbacks[index] = newcb;
659 return AL_TRUE;
663 /* Function: alureSleep
665 * Rests the calling thread for the given number of seconds.
667 * Returns:
668 * AL_FALSE on error.
670 ALURE_API ALboolean ALURE_APIENTRY alureSleep(ALfloat duration)
672 if(duration < 0.0f)
674 SetError("Invalid duration");
675 return AL_FALSE;
678 ALuint seconds = (ALuint)duration;
679 ALdouble rest = duration - (ALdouble)seconds;
681 #ifdef HAVE_NANOSLEEP
683 struct timespec t, remainingTime;
684 t.tv_sec = (time_t)seconds;
685 t.tv_nsec = (long)(rest*1000000000);
687 while(nanosleep(&t, &remainingTime) < 0 && errno == EINTR)
688 t = remainingTime;
690 #elif defined(HAVE_WINDOWS_H)
692 while(seconds > 0)
694 Sleep(1000);
695 seconds--;
697 Sleep((DWORD)(rest * 1000));
699 #endif
701 return AL_TRUE;
705 /* Function: alureGetProcAddress
707 * Returns a pointer for the named ALURE function.
709 * Returns:
710 * NULL on error.
712 * *Version Added*: 1.1
714 ALURE_API void* ALURE_APIENTRY alureGetProcAddress(const ALchar *funcname)
716 static const struct {
717 const char *name;
718 void *func;
719 } FunctionList[] = {
720 #define ADD_FUNCTION(x) { #x, (void*)x },
721 ADD_FUNCTION(alureGetVersion)
722 ADD_FUNCTION(alureGetErrorString)
723 ADD_FUNCTION(alureGetDeviceNames)
724 ADD_FUNCTION(alureFreeDeviceNames)
725 ADD_FUNCTION(alureInitDevice)
726 ADD_FUNCTION(alureShutdownDevice)
727 ADD_FUNCTION(alureGetSampleFormat)
728 ADD_FUNCTION(alureSleep)
729 ADD_FUNCTION(alureCreateBufferFromFile)
730 ADD_FUNCTION(alureCreateBufferFromMemory)
731 ADD_FUNCTION(alureBufferDataFromFile)
732 ADD_FUNCTION(alureBufferDataFromMemory)
733 ADD_FUNCTION(alureCreateStreamFromFile)
734 ADD_FUNCTION(alureCreateStreamFromMemory)
735 ADD_FUNCTION(alureCreateStreamFromStaticMemory)
736 ADD_FUNCTION(alureCreateStreamFromCallback)
737 ADD_FUNCTION(alureGetStreamLength)
738 ADD_FUNCTION(alureRewindStream)
739 ADD_FUNCTION(alureDestroyStream)
740 ADD_FUNCTION(alureSetStreamOrder)
741 ADD_FUNCTION(alureSetStreamPatchset)
742 ADD_FUNCTION(alureInstallDecodeCallbacks)
743 ADD_FUNCTION(alureSetIOCallbacks)
744 ADD_FUNCTION(alureGetProcAddress)
745 ADD_FUNCTION(alurePlaySourceStream)
746 ADD_FUNCTION(alurePlaySource)
747 ADD_FUNCTION(alureStopSource)
748 #undef ADD_FUNCTION
749 { NULL, NULL }
752 size_t i;
753 for(i = 0;FunctionList[i].name;i++)
755 if(strcmp(FunctionList[i].name, funcname) == 0)
756 break;
759 if(!FunctionList[i].name)
760 SetError("Function not found");
761 return FunctionList[i].func;
764 } // extern "C"