1 /* Title: Main and Miscellanious */
16 std::map
<ALint
,UserCallbacks
> InstalledCallbacks
;
19 #define MAKE_FUNC(x) typeof(x) * p##x
23 MAKE_FUNC(sf_open_virtual
);
25 MAKE_FUNC(sf_readf_short
);
29 void *vorbisfile_handle
;
30 MAKE_FUNC(ov_open_callbacks
);
34 MAKE_FUNC(ov_pcm_seek
);
38 MAKE_FUNC(mpg123_init
);
39 MAKE_FUNC(mpg123_new
);
40 MAKE_FUNC(mpg123_open_64
);
41 MAKE_FUNC(mpg123_open_feed
);
42 MAKE_FUNC(mpg123_delete
);
43 MAKE_FUNC(mpg123_decode
);
44 MAKE_FUNC(mpg123_read
);
45 MAKE_FUNC(mpg123_format_none
);
46 MAKE_FUNC(mpg123_getformat
);
47 MAKE_FUNC(mpg123_format
);
48 MAKE_FUNC(mpg123_seek_64
);
53 static void init_libs()
55 #if defined(HAVE_WINDOWS_H) && defined(HAS_LOADLIBRARY)
56 # define LOAD_FUNC(x, f) do { \
57 p##f = reinterpret_cast<typeof(f)*>(GetProcAddress((HMODULE)x, #f)); \
59 fprintf(stderr, "Could not load "#f"\n"); \
63 sndfile_handle
= LoadLibrary("sndfile.dll");
66 vorbisfile_handle
= LoadLibrary("vorbisfile.dll");
69 mpg123_hdl
= LoadLibrary("mpg123.dll");
72 #elif defined(HAS_DLOPEN)
73 # define LOAD_FUNC(x, f) do { \
74 p##f = reinterpret_cast<typeof(f)*>(dlsym(x, #f)); \
75 if((err=dlerror()) != NULL) { \
76 fprintf(stderr, "Could not load "#f": %s\n", err); \
83 # define VER_POSTFIX ".dylib"
85 # define VER_PREFIX ".so"
91 sndfile_handle
= dlopen("libsndfile"VER_PREFIX
".1"VER_POSTFIX
, RTLD_NOW
);
94 vorbisfile_handle
= dlopen("libvorbisfile"VER_PREFIX
".3"VER_POSTFIX
, RTLD_NOW
);
97 mpg123_hdl
= dlopen("libmpg123"VER_PREFIX
".0"VER_POSTFIX
, RTLD_NOW
);
104 # define LOAD_FUNC(m, x) (p##x = x)
107 sndfile_handle
= (void*)0xDECAFBAD;
109 #ifdef HAS_VORBISFILE
110 vorbisfile_handle
= (void*)0xDEADBEEF;
113 mpg123_hdl
= (void*)0xD00FBA11;
121 LOAD_FUNC(sndfile_handle
, sf_open
);
122 LOAD_FUNC(sndfile_handle
, sf_open_virtual
);
123 LOAD_FUNC(sndfile_handle
, sf_close
);
124 LOAD_FUNC(sndfile_handle
, sf_readf_short
);
125 LOAD_FUNC(sndfile_handle
, sf_seek
);
126 if(!psf_open
|| !psf_open_virtual
|| !psf_close
|| !psf_readf_short
||
128 sndfile_handle
= NULL
;
131 #ifdef HAS_VORBISFILE
132 if(vorbisfile_handle
)
134 LOAD_FUNC(vorbisfile_handle
, ov_open_callbacks
);
135 LOAD_FUNC(vorbisfile_handle
, ov_clear
);
136 LOAD_FUNC(vorbisfile_handle
, ov_info
);
137 LOAD_FUNC(vorbisfile_handle
, ov_read
);
138 LOAD_FUNC(vorbisfile_handle
, ov_pcm_seek
);
139 if(!pov_open_callbacks
|| !pov_clear
|| !pov_info
|| !pov_read
||
141 vorbisfile_handle
= NULL
;
147 LOAD_FUNC(mpg123_hdl
, mpg123_init
);
148 LOAD_FUNC(mpg123_hdl
, mpg123_new
);
149 LOAD_FUNC(mpg123_hdl
, mpg123_open_64
);
150 LOAD_FUNC(mpg123_hdl
, mpg123_open_feed
);
151 LOAD_FUNC(mpg123_hdl
, mpg123_decode
);
152 LOAD_FUNC(mpg123_hdl
, mpg123_read
);
153 LOAD_FUNC(mpg123_hdl
, mpg123_getformat
);
154 LOAD_FUNC(mpg123_hdl
, mpg123_format_none
);
155 LOAD_FUNC(mpg123_hdl
, mpg123_format
);
156 LOAD_FUNC(mpg123_hdl
, mpg123_delete
);
157 LOAD_FUNC(mpg123_hdl
, mpg123_seek_64
);
158 if(!pmpg123_init
|| !pmpg123_new
|| !pmpg123_open_64
||
159 !pmpg123_open_feed
|| !pmpg123_decode
|| !pmpg123_read
||
160 !pmpg123_getformat
|| !pmpg123_format_none
|| !pmpg123_format
||
161 !pmpg123_delete
|| !pmpg123_seek_64
|| pmpg123_init() != MPG123_OK
)
171 static bool done
= false;
179 static const ALchar
*last_error
= "No error";
181 void SetError(const char *err
)
188 /* Function: alureGetErrorString
190 * Returns a string describing the last error encountered.
192 ALURE_API
const ALchar
* ALURE_APIENTRY
alureGetErrorString(void)
194 const ALchar
*ret
= last_error
;
195 last_error
= "No error";
200 /* Function: alureGetDeviceNames
202 * Gets an array of device name strings from OpenAL. This encapsulates
203 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
204 * enumeration, with 'count' being set to the number of returned device
208 * An array of device name strings, or NULL on error.
211 * <alureFreeDeviceNames>
213 ALURE_API
const ALCchar
** ALURE_APIENTRY
alureGetDeviceNames(ALCboolean all
, ALCsizei
*count
)
217 const ALCchar
*list
= NULL
;
218 if(all
&& alcIsExtensionPresent(NULL
, "ALC_ENUMERATE_ALL_EXT"))
219 list
= alcGetString(NULL
, ALC_ALL_DEVICES_SPECIFIER
);
221 list
= alcGetString(NULL
, ALC_DEVICE_SPECIFIER
);
225 SetError("No device names found");
229 const ALCchar
*cur
= list
;
230 ALuint retlistLen
= 0;
233 cur
+= strlen(cur
)+1;
237 const ALCchar
**retlist
= new const ALCchar
*[retlistLen
];
242 retlist
[retlistLen
] = cur
;
243 cur
+= strlen(cur
)+1;
251 /* Function: alureFreeDeviceNames
253 * Frees the device name array returned from alureGetDeviceNames.
256 * <alureGetDeviceNames>
258 ALURE_API ALvoid ALURE_APIENTRY
alureFreeDeviceNames(const ALCchar
**names
)
266 /* Function: alureInitDevice
268 * Opens the named device, creates a context with the given attributes, and
269 * sets that context as current. The name and attribute list would be the same
270 * as what's passed to alcOpenDevice and alcCreateContext respectively.
276 * <alureShutdownDevice>
278 ALURE_API ALboolean ALURE_APIENTRY
alureInitDevice(const ALCchar
*name
, const ALCint
*attribs
)
282 ALCdevice
*device
= alcOpenDevice(name
);
287 SetError("Device open failed");
291 ALCcontext
*context
= alcCreateContext(device
, attribs
);
292 if(alcGetError(device
) != ALC_NO_ERROR
|| !context
)
294 alcCloseDevice(device
);
296 SetError("Context creation failed");
300 alcMakeContextCurrent(context
);
301 if(alcGetError(device
) != AL_NO_ERROR
)
303 alcDestroyContext(context
);
304 alcCloseDevice(device
);
306 SetError("Context setup failed");
313 /* Function: alureShutdownDevice
315 * Destroys the current context and closes its associated device.
323 ALURE_API ALboolean ALURE_APIENTRY
alureShutdownDevice(void)
327 ALCcontext
*context
= alcGetCurrentContext();
328 ALCdevice
*device
= alcGetContextsDevice(context
);
329 if(alcGetError(device
) != ALC_NO_ERROR
|| !device
)
331 SetError("Failed to get current device");
335 alcMakeContextCurrent(NULL
);
336 alcDestroyContext(context
);
337 alcCloseDevice(device
);
344 /* Function: alureGetSampleFormat
346 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
347 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
348 * application should not rely on any particular format enum being returned as
349 * it is dependant on the available extensions. The returned format will be
350 * valid for the current context. Requires an active context.
353 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
356 ALURE_API ALenum ALURE_APIENTRY
alureGetSampleFormat(ALuint channels
, ALuint bits
, ALuint floatbits
)
360 if(alGetError() != AL_NO_ERROR
)
362 SetError("Existing OpenAL error");
366 if(bits
&& floatbits
)
368 SetError("Both bit-types specified");
374 if(channels
== 1) return AL_FORMAT_MONO8
;
375 if(channels
== 2) return AL_FORMAT_STEREO8
;
376 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
378 if(channels
== 4) return AL_FORMAT_QUAD8
;
379 if(channels
== 6) return AL_FORMAT_51CHN8
;
380 if(channels
== 7) return AL_FORMAT_61CHN8
;
381 if(channels
== 8) return AL_FORMAT_71CHN8
;
387 if(channels
== 1) return AL_FORMAT_MONO16
;
388 if(channels
== 2) return AL_FORMAT_STEREO16
;
389 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
391 if(channels
== 4) return AL_FORMAT_QUAD16
;
392 if(channels
== 6) return AL_FORMAT_51CHN16
;
393 if(channels
== 7) return AL_FORMAT_61CHN16
;
394 if(channels
== 8) return AL_FORMAT_71CHN16
;
400 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
402 if(channels
== 1) return AL_FORMAT_MONO_FLOAT32
;
403 if(channels
== 2) return AL_FORMAT_STEREO_FLOAT32
;
404 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
406 if(channels
== 4) return AL_FORMAT_QUAD32
;
407 if(channels
== 6) return AL_FORMAT_51CHN32
;
408 if(channels
== 7) return AL_FORMAT_61CHN32
;
409 if(channels
== 8) return AL_FORMAT_71CHN32
;
419 /* Function: alureInstallDecodeCallbacks
421 * Installs callbacks to enable ALURE to handle more file types. The index is
422 * the order that each given set of callbacks will be tried, starting at the
423 * most negative number (INT_MIN) and going up. Negative indices will be tried
424 * before the built-in decoders, and positive indices will be tried after.
425 * Installing callbacks onto the same index multiple times will remove the
426 * previous callbacks, and removing old callbacks won't affect any opened files
427 * using them (they'll continue to use the old functions until properly closed,
428 * although newly opened files will use the new ones). Passing NULL for all
429 * callbacks is a valid way to remove an installed set, otherwise all callbacks
433 * open_file - This callback is expected to open the named file and prepare it
434 * for decoding. If the callbacks cannot decode the file, NULL
435 * should be returned to indicate failure. Upon success, a non-NULL
436 * handle must be returned, which will be used as a unique
437 * identifier for the decoder instance.
438 * open_memory - This callback behaves the same as open_file, except it takes a
439 * memory segment for input instead of a filename. The given
440 * memory will remain valid while the instance is open.
441 * get_format - This callback is used to retrieve the format of the decoded
442 * data for the given instance. It is the responsibility of the
443 * function to make sure the returned format is valid for the
444 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
445 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
446 * blocksize will cause a failure. Returning AL_FALSE indicates
448 * decode - This callback is called to get more decoded data. Up to the
449 * specified amount of bytes should be written to the data pointer.
450 * The number of bytes written should be a multiple of the block size,
451 * otherwise an OpenAL error may occur during buffering. The function
452 * should return the number of bytes written.
453 * rewind - This callback is for rewinding the instance so that the next decode
454 * calls for it will get audio data from the start of the sound file.
455 * If the stream fails to rewind, AL_FALSE should be returned.
456 * close - This callback is called at the end of processing for a particular
457 * instance. The handle will not be used further and any associated
458 * data may be deleted.
463 ALURE_API ALboolean ALURE_APIENTRY
alureInstallDecodeCallbacks(ALint index
,
464 void* (*open_file
)(const ALchar
*filename
),
465 void* (*open_memory
)(const ALubyte
*data
, ALuint length
),
466 ALboolean (*get_format
)(void *instance
, ALenum
*format
, ALuint
*samplerate
, ALuint
*blocksize
),
467 ALuint (*decode
)(void *instance
, ALubyte
*data
, ALuint bytes
),
468 ALboolean (*rewind
)(void *instance
),
469 void (*close
)(void *instance
))
471 if(!open_file
&& !open_memory
&& !get_format
&& !decode
&& !rewind
&& !close
)
473 std::map
<ALint
,UserCallbacks
>::iterator i
= InstalledCallbacks
.find(index
);
474 if(i
!= InstalledCallbacks
.end())
475 InstalledCallbacks
.erase(i
);
479 if(!open_file
|| !open_memory
|| !get_format
|| !decode
|| !rewind
|| !close
)
481 SetError("Missing callback functions");
486 newcb
.open_file
= open_file
;
487 newcb
.open_mem
= open_memory
;
488 newcb
.get_fmt
= get_format
;
489 newcb
.decode
= decode
;
490 newcb
.rewind
= rewind
;
493 InstalledCallbacks
[index
] = newcb
;
499 /* Function: alureSleep
501 * Rests the calling thread for the given number of seconds.
506 ALURE_API ALboolean ALURE_APIENTRY
alureSleep(ALfloat duration
)
512 SetError("Invalid duration");
516 ALuint seconds
= (ALuint
)duration
;
517 ALfloat rest
= duration
- (ALfloat
)seconds
;
519 #ifdef HAVE_NANOSLEEP
521 struct timespec t
, remainingTime
;
522 t
.tv_sec
= (time_t)seconds
;
523 t
.tv_nsec
= (long)(rest
*1000000000);
525 while(nanosleep(&t
, &remainingTime
) < 0 && errno
== EINTR
)
528 #elif defined(HAVE_WINDOWS_H)
535 Sleep((DWORD
)(rest
* 1000));