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
24 /* Title: Main and Miscellanious */
42 std::map
<ALint
,UserCallbacks
> InstalledCallbacks
;
43 CRITICAL_SECTION cs_StreamPlay
;
44 alureStream::ListType
alureStream::StreamList
;
47 #ifdef HAVE_GCC_CONSTRUCTOR
48 static void init_alure(void) __attribute__((constructor
));
49 static void deinit_alure(void) __attribute__((destructor
));
50 static struct MyConstructorClass
{
52 { alureStream::Clear(); };
54 #elif defined(_WIN32) && !defined(ALURE_STATIC_LIBRARY)
55 static void init_alure(void);
56 static void deinit_alure(void);
57 static struct MyConstructorClass
{
59 { alureStream::Clear(); };
62 extern "C" BOOL APIENTRY
DllMain(HINSTANCE module
, DWORD reason
, LPVOID
/*reserved*/)
64 // Perform actions based on the reason for calling.
67 case DLL_PROCESS_ATTACH
:
68 DisableThreadLibraryCalls(module
);
72 case DLL_PROCESS_DETACH
:
79 static void init_alure(void);
80 static void deinit_alure(void);
82 static struct MyConstructorClass
{
86 { alureStream::Clear();
91 static void init_alure(void)
93 InitializeCriticalSection(&cs_StreamPlay
);
95 // These calls actually just return references to the codecs' Decoder
96 // objects. They aren't really used for anything other than to prevent the
97 // compiler from removing the codec initializers.
100 #ifdef HAS_VORBISFILE
101 alure_init_vorbisfile();
107 alure_init_sndfile();
109 #ifdef HAS_FLUIDSYNTH
110 alure_init_fluidsynth();
116 alure_init_modplug();
123 static void deinit_alure(void)
125 DeleteCriticalSection(&cs_StreamPlay
);
130 void *OpenLib(const char*)
131 { return (void*)0xDEADBEEF; }
135 #elif defined(_WIN32)
137 void *OpenLib(const char *libname
)
138 { return LoadLibraryA(libname
); }
139 void CloseLib(void *hdl
)
140 { FreeLibrary((HINSTANCE
)hdl
); }
141 void *GetLibProc(void *hdl
, const char *funcname
)
142 { return (void*)GetProcAddress((HINSTANCE
)hdl
, funcname
); }
146 void *OpenLib(const char *libname
)
148 const char *err
= dlerror();
149 void *hdl
= dlopen(libname
, RTLD_NOW
);
150 if((err
=dlerror()) != NULL
)
152 fprintf(stderr
, "Error loading %s: %s\n", libname
, err
);
157 void *GetLibProc(void *hdl
, const char *funcname
)
159 const char *err
= dlerror();
160 void *fn
= dlsym(hdl
, funcname
);
161 if((err
=dlerror()) != NULL
)
163 fprintf(stderr
, "Error loading %s: %s\n", funcname
, err
);
168 void CloseLib(void *hdl
)
173 static const ALchar
*last_error
= "No error";
174 void SetError(const char *err
)
180 ALuint
DetectBlockAlignment(ALenum format
)
184 #define CHECK_RET(f,s) case (f): return (s)
185 CHECK_RET(AL_FORMAT_MONO8
, sizeof(ALubyte
));
186 CHECK_RET(AL_FORMAT_MONO16
, sizeof(ALshort
));
187 CHECK_RET(AL_FORMAT_MONO_FLOAT32
, sizeof(ALfloat
));
188 CHECK_RET(AL_FORMAT_MONO_DOUBLE_EXT
, sizeof(ALdouble
));
189 CHECK_RET(AL_FORMAT_MONO_MULAW
, sizeof(ALubyte
)*1);
191 CHECK_RET(AL_FORMAT_STEREO8
, sizeof(ALubyte
)*2);
192 CHECK_RET(AL_FORMAT_STEREO16
, sizeof(ALshort
)*2);
193 CHECK_RET(AL_FORMAT_STEREO_FLOAT32
, sizeof(ALfloat
)*2);
194 CHECK_RET(AL_FORMAT_STEREO_DOUBLE_EXT
, sizeof(ALdouble
)*2);
195 CHECK_RET(AL_FORMAT_STEREO_MULAW
, sizeof(ALubyte
)*2);
197 CHECK_RET(AL_FORMAT_QUAD8
, sizeof(ALubyte
)*4);
198 CHECK_RET(AL_FORMAT_QUAD16
, sizeof(ALshort
)*4);
199 CHECK_RET(AL_FORMAT_QUAD32
, sizeof(ALfloat
)*4);
200 CHECK_RET(AL_FORMAT_QUAD_MULAW
, sizeof(ALubyte
)*4);
202 CHECK_RET(AL_FORMAT_REAR8
, sizeof(ALubyte
)*2);
203 CHECK_RET(AL_FORMAT_REAR16
, sizeof(ALshort
)*2);
204 CHECK_RET(AL_FORMAT_REAR32
, sizeof(ALfloat
)*2);
205 CHECK_RET(AL_FORMAT_REAR_MULAW
, sizeof(ALubyte
)*2);
207 CHECK_RET(AL_FORMAT_51CHN8
, sizeof(ALubyte
)*6);
208 CHECK_RET(AL_FORMAT_51CHN16
, sizeof(ALshort
)*6);
209 CHECK_RET(AL_FORMAT_51CHN32
, sizeof(ALfloat
)*6);
210 CHECK_RET(AL_FORMAT_51CHN_MULAW
, sizeof(ALubyte
)*6);
212 CHECK_RET(AL_FORMAT_61CHN8
, sizeof(ALubyte
)*7);
213 CHECK_RET(AL_FORMAT_61CHN16
, sizeof(ALshort
)*7);
214 CHECK_RET(AL_FORMAT_61CHN32
, sizeof(ALfloat
)*7);
215 CHECK_RET(AL_FORMAT_61CHN_MULAW
, sizeof(ALubyte
)*7);
217 CHECK_RET(AL_FORMAT_71CHN8
, sizeof(ALubyte
)*8);
218 CHECK_RET(AL_FORMAT_71CHN16
, sizeof(ALshort
)*8);
219 CHECK_RET(AL_FORMAT_71CHN32
, sizeof(ALfloat
)*8);
220 CHECK_RET(AL_FORMAT_71CHN_MULAW
, sizeof(ALubyte
)*8);
222 CHECK_RET(AL_FORMAT_MONO_IMA4
, 36);
223 CHECK_RET(AL_FORMAT_STEREO_IMA4
, 36*2);
229 ALuint
DetectCompressionRate(ALenum format
)
233 case AL_FORMAT_MONO8
:
234 case AL_FORMAT_MONO16
:
235 case AL_FORMAT_MONO_FLOAT32
:
236 case AL_FORMAT_MONO_DOUBLE_EXT
:
237 case AL_FORMAT_STEREO8
:
238 case AL_FORMAT_STEREO16
:
239 case AL_FORMAT_STEREO_FLOAT32
:
240 case AL_FORMAT_STEREO_DOUBLE_EXT
:
241 case AL_FORMAT_QUAD8
:
242 case AL_FORMAT_QUAD16
:
243 case AL_FORMAT_QUAD32
:
244 case AL_FORMAT_REAR8
:
245 case AL_FORMAT_REAR16
:
246 case AL_FORMAT_REAR32
:
247 case AL_FORMAT_51CHN8
:
248 case AL_FORMAT_51CHN16
:
249 case AL_FORMAT_51CHN32
:
250 case AL_FORMAT_61CHN8
:
251 case AL_FORMAT_61CHN16
:
252 case AL_FORMAT_61CHN32
:
253 case AL_FORMAT_71CHN8
:
254 case AL_FORMAT_71CHN16
:
255 case AL_FORMAT_71CHN32
:
258 case AL_FORMAT_MONO_MULAW
:
259 case AL_FORMAT_STEREO_MULAW
:
260 case AL_FORMAT_QUAD_MULAW
:
261 case AL_FORMAT_REAR_MULAW
:
262 case AL_FORMAT_51CHN_MULAW
:
263 case AL_FORMAT_61CHN_MULAW
:
264 case AL_FORMAT_71CHN_MULAW
:
267 case AL_FORMAT_MONO_IMA4
:
268 case AL_FORMAT_STEREO_IMA4
:
271 fprintf(stderr
, "Alure lib: Unhandled format: %#x\n", format
);
275 ALenum
GetSampleFormat(ALuint channels
, ALuint bits
, bool isFloat
)
277 #define CHECK_FMT_RET(f) do { \
278 ALenum fmt = alGetEnumValue(#f); \
279 if(alGetError() == AL_NO_ERROR && fmt != 0 && fmt != -1) \
286 if(channels
== 1) CHECK_FMT_RET(AL_FORMAT_MONO8
);
287 if(channels
== 2) CHECK_FMT_RET(AL_FORMAT_STEREO8
);
288 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
290 if(channels
== 4) CHECK_FMT_RET(AL_FORMAT_QUAD8
);
291 if(channels
== 6) CHECK_FMT_RET(AL_FORMAT_51CHN8
);
292 if(channels
== 7) CHECK_FMT_RET(AL_FORMAT_61CHN8
);
293 if(channels
== 8) CHECK_FMT_RET(AL_FORMAT_71CHN8
);
295 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
297 if(channels
== 4) CHECK_FMT_RET(AL_FORMAT_QUAD8_LOKI
);
299 SetError("Unsupported 8-bit channel count\n");
304 if(channels
== 1) CHECK_FMT_RET(AL_FORMAT_MONO16
);
305 if(channels
== 2) CHECK_FMT_RET(AL_FORMAT_STEREO16
);
306 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
308 if(channels
== 4) CHECK_FMT_RET(AL_FORMAT_QUAD16
);
309 if(channels
== 6) CHECK_FMT_RET(AL_FORMAT_51CHN16
);
310 if(channels
== 7) CHECK_FMT_RET(AL_FORMAT_61CHN16
);
311 if(channels
== 8) CHECK_FMT_RET(AL_FORMAT_71CHN16
);
313 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
315 if(channels
== 4) CHECK_FMT_RET(AL_FORMAT_QUAD16_LOKI
);
317 SetError("Unsupported 16-bit channel count\n");
320 SetError("Unsupported PCM bit depth\n");
324 if(bits
== 32 && alIsExtensionPresent("AL_EXT_FLOAT32"))
326 if(channels
== 1) CHECK_FMT_RET(AL_FORMAT_MONO_FLOAT32
);
327 if(channels
== 2) CHECK_FMT_RET(AL_FORMAT_STEREO_FLOAT32
);
328 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
330 if(channels
== 4) CHECK_FMT_RET(AL_FORMAT_QUAD32
);
331 if(channels
== 6) CHECK_FMT_RET(AL_FORMAT_51CHN32
);
332 if(channels
== 7) CHECK_FMT_RET(AL_FORMAT_61CHN32
);
333 if(channels
== 8) CHECK_FMT_RET(AL_FORMAT_71CHN32
);
335 SetError("Unsupported float32 channel count\n");
338 if(bits
== 64 && alIsExtensionPresent("AL_EXT_DOUBLE"))
340 if(channels
== 1) CHECK_FMT_RET(AL_FORMAT_MONO_DOUBLE_EXT
);
341 if(channels
== 2) CHECK_FMT_RET(AL_FORMAT_STEREO_DOUBLE_EXT
);
342 SetError("Unsupported double channel count\n");
347 SetError("Unsupported float bit depth\n");
353 /* Function: alureGetVersion
355 * Stores the major and minor version of the library. If either major or minor
356 * are NULL, that value is not provided.
358 ALURE_API
void ALURE_APIENTRY
alureGetVersion(ALuint
*major
, ALuint
*minor
)
360 if(major
) *major
= ALURE_VER_MAJOR
;
361 if(minor
) *minor
= ALURE_VER_MINOR
;
364 /* Function: alureGetErrorString
366 * Returns a string describing the last error encountered.
368 ALURE_API
const ALchar
* ALURE_APIENTRY
alureGetErrorString(void)
370 const ALchar
*ret
= last_error
;
371 last_error
= "No error";
376 /* Function: alureGetDeviceNames
378 * Gets an array of device name strings from OpenAL. This encapsulates
379 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
380 * enumeration, with 'count' being set to the number of returned device
384 * An array of device name strings, or NULL on error.
387 * <alureFreeDeviceNames>
389 ALURE_API
const ALCchar
** ALURE_APIENTRY
alureGetDeviceNames(ALCboolean all
, ALCsizei
*count
)
391 const ALCchar
*list
= NULL
;
392 if(all
&& alcIsExtensionPresent(NULL
, "ALC_ENUMERATE_ALL_EXT"))
393 list
= alcGetString(NULL
, ALC_ALL_DEVICES_SPECIFIER
);
395 list
= alcGetString(NULL
, ALC_DEVICE_SPECIFIER
);
399 SetError("No device names found");
403 const ALCchar
*cur
= list
;
404 ALuint retlistLen
= 0;
407 cur
+= strlen(cur
)+1;
411 const ALCchar
**retlist
= new const ALCchar
*[retlistLen
+1];
416 ALCuint len
= strlen(cur
)+1;
417 ALCchar
*newstr
= new ALCchar
[len
];
419 memcpy(newstr
, cur
, len
);
422 retlist
[retlistLen
] = newstr
;
425 retlist
[retlistLen
] = NULL
;
431 /* Function: alureFreeDeviceNames
433 * Frees the device name array returned from alureGetDeviceNames.
436 * <alureGetDeviceNames>
438 ALURE_API ALvoid ALURE_APIENTRY
alureFreeDeviceNames(const ALCchar
**names
)
442 for(ALCuint i
= 0;names
[i
];i
++)
443 delete[] const_cast<ALCchar
*>(names
[i
]);
449 /* Function: alureInitDevice
451 * Opens the named device, creates a context with the given attributes, and
452 * sets that context as current. The name and attribute list would be the same
453 * as what's passed to alcOpenDevice and alcCreateContext respectively.
459 * <alureShutdownDevice>
461 ALURE_API ALboolean ALURE_APIENTRY
alureInitDevice(const ALCchar
*name
, const ALCint
*attribs
)
463 ALCdevice
*device
= alcOpenDevice(name
);
468 SetError("Device open failed");
472 ALCcontext
*context
= alcCreateContext(device
, attribs
);
473 if(!context
|| alcMakeContextCurrent(context
) == ALC_FALSE
)
476 alcDestroyContext(context
);
477 alcCloseDevice(device
);
479 SetError("Context setup failed");
487 /* Function: alureShutdownDevice
489 * Destroys the current context and closes its associated device.
497 ALURE_API ALboolean ALURE_APIENTRY
alureShutdownDevice(void)
499 ALCcontext
*context
= alcGetCurrentContext();
500 ALCdevice
*device
= alcGetContextsDevice(context
);
501 if(!context
|| !device
)
504 SetError("Failed to get current device");
508 if(alcMakeContextCurrent(NULL
) == ALC_FALSE
)
511 SetError("Failed to unset current context");
515 alcDestroyContext(context
);
516 alcCloseDevice(device
);
523 /* Function: alureGetSampleFormat
525 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
526 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
527 * application should not rely on any particular format enum being returned as
528 * it is dependant on the available extensions. The returned format will be
529 * valid for the current context. Requires an active context.
532 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
535 ALURE_API ALenum ALURE_APIENTRY
alureGetSampleFormat(ALuint channels
, ALuint bits
, ALuint floatbits
)
537 if(alGetError() != AL_NO_ERROR
)
539 SetError("Existing OpenAL error");
543 if(bits
&& floatbits
)
545 SetError("Both bit-types specified");
550 return GetSampleFormat(channels
, bits
, false);
551 return GetSampleFormat(channels
, floatbits
, true);
555 /* Function: alureInstallDecodeCallbacks
557 * Installs callbacks to enable ALURE to handle more file types. The index is
558 * the order that each given set of callbacks will be tried, starting at the
559 * most negative number (INT_MIN) and going up. Negative indices will be tried
560 * before the built-in decoders, and positive indices will be tried after.
561 * Installing callbacks onto the same index multiple times will remove the
562 * previous callbacks, and removing old callbacks won't affect any opened files
563 * using them (they'll continue to use the old functions until properly closed,
564 * although newly opened files will use the new ones). Passing NULL for all
565 * callbacks is a valid way to remove an installed set, otherwise certain
566 * callbacks must be specified. Callbacks that are not specified will assume
570 * open_file - This callback is expected to open the named file and prepare it
571 * for decoding. If the callbacks cannot decode the file, NULL
572 * should be returned to indicate failure. Upon success, a non-NULL
573 * handle must be returned, which will be used as a unique
574 * identifier for the decoder instance. This callback is required
575 * if open_memory is not specified.
576 * open_memory - This callback behaves the same as open_file, except it takes a
577 * memory segment for input instead of a filename. The given
578 * memory will remain valid while the instance is open. This
579 * callback is required if open_file is not specified.
580 * get_format - This callback is used to retrieve the format of the decoded
581 * data for the given instance. It is the responsibility of the
582 * function to make sure the returned format is valid for the
583 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
584 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
585 * samplerate or blocksize, or returning AL_NONE for format, will
586 * cause a failure. Returning AL_FALSE indicates failure. This
587 * callback is required.
588 * decode - This callback is called to get more decoded data. Up to the
589 * specified amount of bytes should be written to the data pointer.
590 * The number of bytes written should be a multiple of the block size,
591 * otherwise an OpenAL error may occur during buffering. The function
592 * should return the number of bytes written. This callback is
594 * rewind - This callback is for rewinding the instance so that the next decode
595 * calls for it will get audio data from the start of the sound file.
596 * If the stream fails to rewind, AL_FALSE should be returned.
597 * close - This callback is called at the end of processing for a particular
598 * instance. The handle will not be used further and any associated
599 * data may be deleted.
604 ALURE_API ALboolean ALURE_APIENTRY
alureInstallDecodeCallbacks(ALint index
,
605 void* (*open_file
)(const ALchar
*filename
),
606 void* (*open_memory
)(const ALubyte
*data
, ALuint length
),
607 ALboolean (*get_format
)(void *instance
, ALenum
*format
, ALuint
*samplerate
, ALuint
*blocksize
),
608 ALuint (*decode
)(void *instance
, ALubyte
*data
, ALuint bytes
),
609 ALboolean (*rewind
)(void *instance
),
610 void (*close
)(void *instance
))
612 if(!open_file
&& !open_memory
&& !get_format
&& !decode
&& !rewind
&& !close
)
614 std::map
<ALint
,UserCallbacks
>::iterator i
= InstalledCallbacks
.find(index
);
615 if(i
!= InstalledCallbacks
.end())
616 InstalledCallbacks
.erase(i
);
620 if((!open_file
&& !open_memory
) || !get_format
|| !decode
)
622 SetError("Missing callback functions");
627 newcb
.open_file
= open_file
;
628 newcb
.open_mem
= open_memory
;
629 newcb
.get_fmt
= get_format
;
630 newcb
.decode
= decode
;
631 newcb
.rewind
= rewind
;
634 InstalledCallbacks
[index
] = newcb
;
640 /* Function: alureSleep
642 * Rests the calling thread for the given number of seconds.
647 ALURE_API ALboolean ALURE_APIENTRY
alureSleep(ALfloat duration
)
651 SetError("Invalid duration");
655 ALuint seconds
= (ALuint
)duration
;
656 ALfloat rest
= duration
- (ALfloat
)seconds
;
658 #ifdef HAVE_NANOSLEEP
660 struct timespec t
, remainingTime
;
661 t
.tv_sec
= (time_t)seconds
;
662 t
.tv_nsec
= (long)(rest
*1000000)*1000;
664 while(nanosleep(&t
, &remainingTime
) < 0 && errno
== EINTR
)
667 #elif defined(HAVE_WINDOWS_H)
674 Sleep((DWORD
)(rest
* 1000));
682 /* Function: alureGetProcAddress
684 * Returns a pointer for the named ALURE function.
689 * *Version Added*: 1.1
691 ALURE_API
void* ALURE_APIENTRY
alureGetProcAddress(const ALchar
*funcname
)
693 static const struct {
697 #define ADD_FUNCTION(x) { #x, (void*)x },
698 ADD_FUNCTION(alureGetVersion
)
699 ADD_FUNCTION(alureGetErrorString
)
700 ADD_FUNCTION(alureGetDeviceNames
)
701 ADD_FUNCTION(alureFreeDeviceNames
)
702 ADD_FUNCTION(alureInitDevice
)
703 ADD_FUNCTION(alureShutdownDevice
)
704 ADD_FUNCTION(alureGetSampleFormat
)
705 ADD_FUNCTION(alureSleep
)
706 ADD_FUNCTION(alureCreateBufferFromFile
)
707 ADD_FUNCTION(alureCreateBufferFromMemory
)
708 ADD_FUNCTION(alureBufferDataFromFile
)
709 ADD_FUNCTION(alureBufferDataFromMemory
)
710 ADD_FUNCTION(alureCreateStreamFromFile
)
711 ADD_FUNCTION(alureCreateStreamFromMemory
)
712 ADD_FUNCTION(alureCreateStreamFromStaticMemory
)
713 ADD_FUNCTION(alureCreateStreamFromCallback
)
714 ADD_FUNCTION(alureRewindStream
)
715 ADD_FUNCTION(alureDestroyStream
)
716 ADD_FUNCTION(alureInstallDecodeCallbacks
)
717 ADD_FUNCTION(alureSetIOCallbacks
)
718 ADD_FUNCTION(alureGetProcAddress
)
719 ADD_FUNCTION(alurePlaySourceStream
)
720 ADD_FUNCTION(alurePlaySource
)
721 ADD_FUNCTION(alureStopSource
)
727 for(i
= 0;FunctionList
[i
].name
;i
++)
729 if(strcmp(FunctionList
[i
].name
, funcname
) == 0)
733 if(!FunctionList
[i
].name
)
734 SetError("Function not found");
735 return FunctionList
[i
].func
;