Move decoder (de)initialization into their respective classes
[alure.git] / src / alure.cpp
blobe4817584b0c6bec0a8ba1aa2964b0a87abb6f8d9
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;
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 {
51 ~MyConstructorClass()
52 { alureStream::Clear(); };
53 } MyConstructor;
54 #elif defined(_WIN32) && !defined(ALURE_STATIC_LIBRARY)
55 static void init_alure(void);
56 static void deinit_alure(void);
57 static struct MyConstructorClass {
58 ~MyConstructorClass()
59 { alureStream::Clear(); };
60 } MyConstructor;
62 extern "C" BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
64 (void)reserved;
66 // Perform actions based on the reason for calling.
67 switch(reason)
69 case DLL_PROCESS_ATTACH:
70 DisableThreadLibraryCalls(module);
71 init_alure();
72 break;
74 case DLL_PROCESS_DETACH:
75 deinit_alure();
76 break;
78 return TRUE;
80 #else
81 static void init_alure(void);
82 static void deinit_alure(void);
84 static struct MyConstructorClass {
85 MyConstructorClass()
86 { init_alure(); };
87 ~MyConstructorClass()
88 { alureStream::Clear();
89 deinit_alure(); };
90 } MyConstructor;
91 #endif
93 static void init_alure(void)
95 InitializeCriticalSection(&cs_StreamPlay);
98 static void deinit_alure(void)
100 DeleteCriticalSection(&cs_StreamPlay);
104 #ifndef DYNLOAD
105 void *OpenLib(const char*)
106 { return (void*)0xDEADBEEF; }
107 void CloseLib(void*)
110 #elif defined(_WIN32)
112 void *OpenLib(const char *libname)
113 { return LoadLibraryA(libname); }
114 void CloseLib(void *hdl)
115 { FreeLibrary((HINSTANCE)hdl); }
116 void *GetLibProc(void *hdl, const char *funcname)
117 { return (void*)GetProcAddress((HINSTANCE)hdl, funcname); }
119 #else
121 void *OpenLib(const char *libname)
123 const char *err = dlerror();
124 void *hdl = dlopen(libname, RTLD_NOW);
125 if((err=dlerror()) != NULL)
127 fprintf(stderr, "Error loading %s: %s\n", libname, err);
128 return NULL;
130 return hdl;
132 void *GetLibProc(void *hdl, const char *funcname)
134 const char *err = dlerror();
135 void *fn = dlsym(hdl, funcname);
136 if((err=dlerror()) != NULL)
138 fprintf(stderr, "Error loading %s: %s\n", funcname, err);
139 return NULL;
141 return fn;
143 void CloseLib(void *hdl)
144 { dlclose(hdl); }
145 #endif
148 static const ALchar *last_error = "No error";
149 void SetError(const char *err)
151 last_error = err;
155 ALuint DetectBlockAlignment(ALenum format)
157 switch(format)
159 #define CHECK_RET(f,s) case (f): return (s)
160 CHECK_RET(AL_FORMAT_MONO8, sizeof(ALubyte));
161 CHECK_RET(AL_FORMAT_MONO16, sizeof(ALshort));
162 CHECK_RET(AL_FORMAT_MONO_FLOAT32, sizeof(ALfloat));
163 CHECK_RET(AL_FORMAT_MONO_DOUBLE_EXT, sizeof(ALdouble));
164 CHECK_RET(AL_FORMAT_MONO_MULAW, sizeof(ALubyte)*1);
166 CHECK_RET(AL_FORMAT_STEREO8, sizeof(ALubyte)*2);
167 CHECK_RET(AL_FORMAT_STEREO16, sizeof(ALshort)*2);
168 CHECK_RET(AL_FORMAT_STEREO_FLOAT32, sizeof(ALfloat)*2);
169 CHECK_RET(AL_FORMAT_STEREO_DOUBLE_EXT, sizeof(ALdouble)*2);
170 CHECK_RET(AL_FORMAT_STEREO_MULAW, sizeof(ALubyte)*2);
172 CHECK_RET(AL_FORMAT_QUAD8, sizeof(ALubyte)*4);
173 CHECK_RET(AL_FORMAT_QUAD16, sizeof(ALshort)*4);
174 CHECK_RET(AL_FORMAT_QUAD32, sizeof(ALfloat)*4);
175 CHECK_RET(AL_FORMAT_QUAD_MULAW, sizeof(ALubyte)*4);
177 CHECK_RET(AL_FORMAT_REAR8, sizeof(ALubyte)*2);
178 CHECK_RET(AL_FORMAT_REAR16, sizeof(ALshort)*2);
179 CHECK_RET(AL_FORMAT_REAR32, sizeof(ALfloat)*2);
180 CHECK_RET(AL_FORMAT_REAR_MULAW, sizeof(ALubyte)*2);
182 CHECK_RET(AL_FORMAT_51CHN8, sizeof(ALubyte)*6);
183 CHECK_RET(AL_FORMAT_51CHN16, sizeof(ALshort)*6);
184 CHECK_RET(AL_FORMAT_51CHN32, sizeof(ALfloat)*6);
185 CHECK_RET(AL_FORMAT_51CHN_MULAW, sizeof(ALubyte)*6);
187 CHECK_RET(AL_FORMAT_61CHN8, sizeof(ALubyte)*7);
188 CHECK_RET(AL_FORMAT_61CHN16, sizeof(ALshort)*7);
189 CHECK_RET(AL_FORMAT_61CHN32, sizeof(ALfloat)*7);
190 CHECK_RET(AL_FORMAT_61CHN_MULAW, sizeof(ALubyte)*7);
192 CHECK_RET(AL_FORMAT_71CHN8, sizeof(ALubyte)*8);
193 CHECK_RET(AL_FORMAT_71CHN16, sizeof(ALshort)*8);
194 CHECK_RET(AL_FORMAT_71CHN32, sizeof(ALfloat)*8);
195 CHECK_RET(AL_FORMAT_71CHN_MULAW, sizeof(ALubyte)*8);
197 CHECK_RET(AL_FORMAT_MONO_IMA4, 36);
198 CHECK_RET(AL_FORMAT_STEREO_IMA4, 36*2);
199 #undef CHECK_RET
201 return 0;
204 ALuint DetectCompressionRate(ALenum format)
206 switch(format)
208 case AL_FORMAT_MONO8:
209 case AL_FORMAT_MONO16:
210 case AL_FORMAT_MONO_FLOAT32:
211 case AL_FORMAT_MONO_DOUBLE_EXT:
212 case AL_FORMAT_STEREO8:
213 case AL_FORMAT_STEREO16:
214 case AL_FORMAT_STEREO_FLOAT32:
215 case AL_FORMAT_STEREO_DOUBLE_EXT:
216 case AL_FORMAT_QUAD8:
217 case AL_FORMAT_QUAD16:
218 case AL_FORMAT_QUAD32:
219 case AL_FORMAT_REAR8:
220 case AL_FORMAT_REAR16:
221 case AL_FORMAT_REAR32:
222 case AL_FORMAT_51CHN8:
223 case AL_FORMAT_51CHN16:
224 case AL_FORMAT_51CHN32:
225 case AL_FORMAT_61CHN8:
226 case AL_FORMAT_61CHN16:
227 case AL_FORMAT_61CHN32:
228 case AL_FORMAT_71CHN8:
229 case AL_FORMAT_71CHN16:
230 case AL_FORMAT_71CHN32:
231 return 1;
233 case AL_FORMAT_MONO_MULAW:
234 case AL_FORMAT_STEREO_MULAW:
235 case AL_FORMAT_QUAD_MULAW:
236 case AL_FORMAT_REAR_MULAW:
237 case AL_FORMAT_51CHN_MULAW:
238 case AL_FORMAT_61CHN_MULAW:
239 case AL_FORMAT_71CHN_MULAW:
240 return 1;
242 case AL_FORMAT_MONO_IMA4:
243 case AL_FORMAT_STEREO_IMA4:
244 return 65;
246 fprintf(stderr, "Alure lib: Unhandled format: %#x\n", format);
247 return 0;
250 ALenum GetSampleFormat(ALuint channels, ALuint bits, bool isFloat)
252 #define CHECK_FMT_RET(f) do { \
253 ALenum fmt = alGetEnumValue(#f); \
254 if(alGetError() == AL_NO_ERROR && fmt != 0 && fmt != -1) \
255 return fmt; \
256 } while(0)
257 if(!isFloat)
259 if(bits == 8)
261 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO8);
262 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO8);
263 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
265 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8);
266 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN8);
267 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN8);
268 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN8);
270 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
272 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD8_LOKI);
274 SetError("Unsupported 8-bit channel count\n");
275 return AL_NONE;
277 if(bits == 16)
279 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO16);
280 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO16);
281 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
283 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16);
284 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN16);
285 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN16);
286 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN16);
288 if(alIsExtensionPresent("AL_LOKI_quadriphonic"))
290 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD16_LOKI);
292 SetError("Unsupported 16-bit channel count\n");
293 return AL_NONE;
295 SetError("Unsupported PCM bit depth\n");
296 return AL_NONE;
299 if(bits == 32 && alIsExtensionPresent("AL_EXT_FLOAT32"))
301 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_FLOAT32);
302 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_FLOAT32);
303 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
305 if(channels == 4) CHECK_FMT_RET(AL_FORMAT_QUAD32);
306 if(channels == 6) CHECK_FMT_RET(AL_FORMAT_51CHN32);
307 if(channels == 7) CHECK_FMT_RET(AL_FORMAT_61CHN32);
308 if(channels == 8) CHECK_FMT_RET(AL_FORMAT_71CHN32);
310 SetError("Unsupported float32 channel count\n");
311 return AL_NONE;
313 if(bits == 64 && alIsExtensionPresent("AL_EXT_DOUBLE"))
315 if(channels == 1) CHECK_FMT_RET(AL_FORMAT_MONO_DOUBLE_EXT);
316 if(channels == 2) CHECK_FMT_RET(AL_FORMAT_STEREO_DOUBLE_EXT);
317 SetError("Unsupported double channel count\n");
318 return AL_NONE;
320 #undef CHECK_FMT_RET
322 SetError("Unsupported float bit depth\n");
323 return AL_NONE;
326 extern "C" {
328 /* Function: alureGetVersion
330 * Stores the major and minor version of the library. If either major or minor
331 * are NULL, that value is not provided.
333 ALURE_API void ALURE_APIENTRY alureGetVersion(ALuint *major, ALuint *minor)
335 if(major) *major = ALURE_VER_MAJOR;
336 if(minor) *minor = ALURE_VER_MINOR;
339 /* Function: alureGetErrorString
341 * Returns a string describing the last error encountered.
343 ALURE_API const ALchar* ALURE_APIENTRY alureGetErrorString(void)
345 const ALchar *ret = last_error;
346 last_error = "No error";
347 return ret;
351 /* Function: alureGetDeviceNames
353 * Gets an array of device name strings from OpenAL. This encapsulates
354 * AL_ENUMERATE_ALL_EXT (if supported and 'all' is true) and standard
355 * enumeration, with 'count' being set to the number of returned device
356 * names.
358 * Returns:
359 * An array of device name strings, or NULL on error.
361 * See Also:
362 * <alureFreeDeviceNames>
364 ALURE_API const ALCchar** ALURE_APIENTRY alureGetDeviceNames(ALCboolean all, ALCsizei *count)
366 const ALCchar *list = NULL;
367 if(all && alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
368 list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
369 else
370 list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
371 if(!list)
373 alcGetError(NULL);
374 SetError("No device names found");
375 return NULL;
378 const ALCchar *cur = list;
379 ALuint retlistLen = 0;
380 while(*cur)
382 cur += strlen(cur)+1;
383 retlistLen++;
386 const ALCchar **retlist = new const ALCchar*[retlistLen+1];
387 retlistLen = 0;
388 cur = list;
389 while(*cur)
391 ALCuint len = strlen(cur)+1;
392 ALCchar *newstr = new ALCchar[len];
394 memcpy(newstr, cur, len);
395 cur += len;
397 retlist[retlistLen] = newstr;
398 retlistLen++;
400 retlist[retlistLen] = NULL;
402 *count = retlistLen;
403 return retlist;
406 /* Function: alureFreeDeviceNames
408 * Frees the device name array returned from alureGetDeviceNames.
410 * See Also:
411 * <alureGetDeviceNames>
413 ALURE_API ALvoid ALURE_APIENTRY alureFreeDeviceNames(const ALCchar **names)
415 if(names)
417 for(ALCuint i = 0;names[i];i++)
418 delete[] const_cast<ALCchar*>(names[i]);
419 delete[] names;
424 /* Function: alureInitDevice
426 * Opens the named device, creates a context with the given attributes, and
427 * sets that context as current. The name and attribute list would be the same
428 * as what's passed to alcOpenDevice and alcCreateContext respectively.
430 * Returns:
431 * AL_FALSE on error.
433 * See Also:
434 * <alureShutdownDevice>
436 ALURE_API ALboolean ALURE_APIENTRY alureInitDevice(const ALCchar *name, const ALCint *attribs)
438 ALCdevice *device = alcOpenDevice(name);
439 if(!device)
441 alcGetError(NULL);
443 SetError("Device open failed");
444 return AL_FALSE;
447 ALCcontext *context = alcCreateContext(device, attribs);
448 if(!context || alcMakeContextCurrent(context) == ALC_FALSE)
450 if(context)
451 alcDestroyContext(context);
452 alcCloseDevice(device);
454 SetError("Context setup failed");
455 return AL_FALSE;
457 alcGetError(device);
459 return AL_TRUE;
462 /* Function: alureShutdownDevice
464 * Destroys the current context and closes its associated device.
466 * Returns:
467 * AL_FALSE on error.
469 * See Also:
470 * <alureInitDevice>
472 ALURE_API ALboolean ALURE_APIENTRY alureShutdownDevice(void)
474 ALCcontext *context = alcGetCurrentContext();
475 ALCdevice *device = alcGetContextsDevice(context);
476 if(!context || !device)
478 alcGetError(device);
479 SetError("Failed to get current device");
480 return AL_FALSE;
483 if(alcMakeContextCurrent(NULL) == ALC_FALSE)
485 alcGetError(NULL);
486 SetError("Failed to unset current context");
487 return AL_FALSE;
490 alcDestroyContext(context);
491 alcCloseDevice(device);
492 alcGetError(NULL);
494 return AL_TRUE;
498 /* Function: alureGetSampleFormat
500 * Retrieves an OpenAL format for the given sample format. If bits is non-0,
501 * floatbits must be 0, and if floatbits is non-0, bits must be 0. The
502 * application should not rely on any particular format enum being returned as
503 * it is dependant on the available extensions. The returned format will be
504 * valid for the current context. Requires an active context.
506 * Returns:
507 * An OpenAL format enum for the given sample format, or AL_NONE if one can't
508 * be found.
510 ALURE_API ALenum ALURE_APIENTRY alureGetSampleFormat(ALuint channels, ALuint bits, ALuint floatbits)
512 if(alGetError() != AL_NO_ERROR)
514 SetError("Existing OpenAL error");
515 return AL_NONE;
518 if(bits && floatbits)
520 SetError("Both bit-types specified");
521 return AL_NONE;
524 if(bits)
525 return GetSampleFormat(channels, bits, false);
526 return GetSampleFormat(channels, floatbits, true);
530 /* Function: alureInstallDecodeCallbacks
532 * Installs callbacks to enable ALURE to handle more file types. The index is
533 * the order that each given set of callbacks will be tried, starting at the
534 * most negative number (INT_MIN) and going up. Negative indices will be tried
535 * before the built-in decoders, and positive indices will be tried after.
536 * Installing callbacks onto the same index multiple times will remove the
537 * previous callbacks, and removing old callbacks won't affect any opened files
538 * using them (they'll continue to use the old functions until properly closed,
539 * although newly opened files will use the new ones). Passing NULL for all
540 * callbacks is a valid way to remove an installed set, otherwise certain
541 * callbacks must be specified. Callbacks that are not specified will assume
542 * failure.
544 * Parameters:
545 * open_file - This callback is expected to open the named file and prepare it
546 * for decoding. If the callbacks cannot decode the file, NULL
547 * should be returned to indicate failure. Upon success, a non-NULL
548 * handle must be returned, which will be used as a unique
549 * identifier for the decoder instance. This callback is required
550 * if open_memory is not specified.
551 * open_memory - This callback behaves the same as open_file, except it takes a
552 * memory segment for input instead of a filename. The given
553 * memory will remain valid while the instance is open. This
554 * callback is required if open_file is not specified.
555 * get_format - This callback is used to retrieve the format of the decoded
556 * data for the given instance. It is the responsibility of the
557 * function to make sure the returned format is valid for the
558 * current AL context (eg. don't return AL_FORMAT_QUAD16 if the
559 * AL_EXT_MCFORMATS extension isn't available). Returning 0 for
560 * samplerate or blocksize, or returning AL_NONE for format, will
561 * cause a failure. Returning AL_FALSE indicates failure. This
562 * callback is required.
563 * decode - This callback is called to get more decoded data. Up to the
564 * specified amount of bytes should be written to the data pointer.
565 * The number of bytes written should be a multiple of the block size,
566 * otherwise an OpenAL error may occur during buffering. The function
567 * should return the number of bytes written. This callback is
568 * required.
569 * rewind - This callback is for rewinding the instance so that the next decode
570 * calls for it will get audio data from the start of the sound file.
571 * If the stream fails to rewind, AL_FALSE should be returned.
572 * close - This callback is called at the end of processing for a particular
573 * instance. The handle will not be used further and any associated
574 * data may be deleted.
576 * Returns:
577 * AL_FALSE on error.
579 ALURE_API ALboolean ALURE_APIENTRY alureInstallDecodeCallbacks(ALint index,
580 void* (*open_file)(const ALchar *filename),
581 void* (*open_memory)(const ALubyte *data, ALuint length),
582 ALboolean (*get_format)(void *instance, ALenum *format, ALuint *samplerate, ALuint *blocksize),
583 ALuint (*decode)(void *instance, ALubyte *data, ALuint bytes),
584 ALboolean (*rewind)(void *instance),
585 void (*close)(void *instance))
587 if(!open_file && !open_memory && !get_format && !decode && !rewind && !close)
589 std::map<ALint,UserCallbacks>::iterator i = InstalledCallbacks.find(index);
590 if(i != InstalledCallbacks.end())
591 InstalledCallbacks.erase(i);
592 return AL_TRUE;
595 if((!open_file && !open_memory) || !get_format || !decode)
597 SetError("Missing callback functions");
598 return AL_FALSE;
601 UserCallbacks newcb;
602 newcb.open_file = open_file;
603 newcb.open_mem = open_memory;
604 newcb.get_fmt = get_format;
605 newcb.decode = decode;
606 newcb.rewind = rewind;
607 newcb.close = close;
609 InstalledCallbacks[index] = newcb;
611 return AL_TRUE;
615 /* Function: alureSleep
617 * Rests the calling thread for the given number of seconds.
619 * Returns:
620 * AL_FALSE on error.
622 ALURE_API ALboolean ALURE_APIENTRY alureSleep(ALfloat duration)
624 if(duration < 0.0f)
626 SetError("Invalid duration");
627 return AL_FALSE;
630 ALuint seconds = (ALuint)duration;
631 ALfloat rest = duration - (ALfloat)seconds;
633 #ifdef HAVE_NANOSLEEP
635 struct timespec t, remainingTime;
636 t.tv_sec = (time_t)seconds;
637 t.tv_nsec = (long)(rest*1000000)*1000;
639 while(nanosleep(&t, &remainingTime) < 0 && errno == EINTR)
640 t = remainingTime;
642 #elif defined(HAVE_WINDOWS_H)
644 while(seconds > 0)
646 Sleep(1000);
647 seconds--;
649 Sleep((DWORD)(rest * 1000));
651 #endif
653 return AL_TRUE;
657 /* Function: alureGetProcAddress
659 * Returns a pointer for the named ALURE function.
661 * Returns:
662 * NULL on error.
664 * *Version Added*: 1.1
666 ALURE_API void* ALURE_APIENTRY alureGetProcAddress(const ALchar *funcname)
668 static const struct {
669 const char *name;
670 void *func;
671 } FunctionList[] = {
672 #define ADD_FUNCTION(x) { #x, (void*)x },
673 ADD_FUNCTION(alureGetVersion)
674 ADD_FUNCTION(alureGetErrorString)
675 ADD_FUNCTION(alureGetDeviceNames)
676 ADD_FUNCTION(alureFreeDeviceNames)
677 ADD_FUNCTION(alureInitDevice)
678 ADD_FUNCTION(alureShutdownDevice)
679 ADD_FUNCTION(alureGetSampleFormat)
680 ADD_FUNCTION(alureSleep)
681 ADD_FUNCTION(alureCreateBufferFromFile)
682 ADD_FUNCTION(alureCreateBufferFromMemory)
683 ADD_FUNCTION(alureBufferDataFromFile)
684 ADD_FUNCTION(alureBufferDataFromMemory)
685 ADD_FUNCTION(alureCreateStreamFromFile)
686 ADD_FUNCTION(alureCreateStreamFromMemory)
687 ADD_FUNCTION(alureCreateStreamFromStaticMemory)
688 ADD_FUNCTION(alureCreateStreamFromCallback)
689 ADD_FUNCTION(alureRewindStream)
690 ADD_FUNCTION(alureDestroyStream)
691 ADD_FUNCTION(alureInstallDecodeCallbacks)
692 ADD_FUNCTION(alureSetIOCallbacks)
693 ADD_FUNCTION(alureGetProcAddress)
694 ADD_FUNCTION(alurePlaySourceStream)
695 ADD_FUNCTION(alurePlaySource)
696 ADD_FUNCTION(alureStopSource)
697 #undef ADD_FUNCTION
698 { NULL, NULL }
701 size_t i;
702 for(i = 0;FunctionList[i].name;i++)
704 if(strcmp(FunctionList[i].name, funcname) == 0)
705 break;
708 if(!FunctionList[i].name)
709 SetError("Function not found");
710 return FunctionList[i].func;
713 } // extern "C"