changeset 38:71b465ff0622

Added support files.
author Eric Wing <ewing@anscamobile.com>
date Thu, 28 Apr 2011 16:22:30 -0700
parents b346b6608eab
children c07dbd386ded
files Isolated/ALmixer_RWops.c Isolated/ALmixer_RWops.h Isolated/LGPL/SDL_endian_minimal.h Isolated/LGPL/SDL_sound_minimal.c Isolated/LGPL/mpg123.c Isolated/LGPL/oggtremor.c Isolated/LGPL/wav.c Isolated/SimpleMutex.c Isolated/SimpleMutex.h Isolated/SimpleThread.h Isolated/SimpleThreadPosix.c Isolated/SoundDecoder.c Isolated/SoundDecoder.h Isolated/SoundDecoder_Internal.h Isolated/UNUSED/SimpleSemaphore.h Isolated/UNUSED/SimpleSemaphorePosix.c Isolated/coreaudio.c Isolated/luaal/luaal.c Isolated/luaal/luaal.h Isolated/tErrorLib.c Isolated/tErrorLib.h
diffstat 21 files changed, 7023 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/ALmixer_RWops.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,108 @@
+#ifndef ALMIXER_COMPILED_WITH_SDL
+
+#include "ALmixer_RWops.h"
+#include <stdlib.h> /* malloc, free */
+#include <stdio.h> /* fopen, fseek, fread, fclose */
+#include <string.h> /* strerror */
+#include <errno.h> /* errno */
+
+/* (Note this is different than stdio's seek. This returns ftell.)
+ */
+static int stdio_seek(ALmixer_RWops* the_context, long offset, int whence)
+{
+	if(0 == fseek(the_context->hidden.stdio.fp, offset, whence))
+	{
+		return(ftell(the_context->hidden.stdio.fp));
+	}
+	else
+   	{
+/*		ALmixer_SetError("ALmixer_RWops seek failed: %s", strerror(errno)); */
+		return (-1);
+	}
+}
+
+static size_t stdio_read(ALmixer_RWops* the_context, void* ptr, size_t size, size_t nitems)
+{
+	size_t bytes_read;
+
+	bytes_read = fread(ptr, size, nitems, the_context->hidden.stdio.fp);
+	if(0 == bytes_read && ferror(the_context->hidden.stdio.fp))
+	{
+		/* not sure if strerror can convert ferror */
+/*		ALmixer_SetError("ALmixer_RWops read failed: %s", strerror(ferror(the_context->hidden.stdio.fp))); */
+	}
+	return bytes_read;
+}
+
+static size_t stdio_write(ALmixer_RWops* the_context, const void* ptr, size_t size, size_t nitems)
+{
+	size_t bytes_written;
+
+	bytes_written = fwrite(ptr, size, nitems, the_context->hidden.stdio.fp);
+	if(0 == bytes_written && ferror(the_context->hidden.stdio.fp))
+	{
+/*		ALmixer_SetError("ALmixer_RWops write failed: %s", strerror(ferror(the_context->hidden.stdio.fp))); */
+	}
+	return bytes_written;
+}
+
+static int stdio_close(ALmixer_RWops* the_context)
+{
+	int return_status = 0;
+	if(NULL != the_context)
+	{
+		if(0 != the_context->hidden.stdio.autoclose)
+		{
+			if(0 != fclose(the_context->hidden.stdio.fp))
+			{
+/*				ALmixer_SetError("ALmixer_RWops close failed: %s", strerror(errno)); */
+				return_status = -1;
+			}
+		}
+		free(the_context);
+	}
+	return return_status;
+}
+
+ALmixer_RWops* ALmixer_RWFromFP(FILE* file_pointer, char autoclose_flag)
+{
+    ALmixer_RWops* rw_ops = NULL;
+
+	rw_ops = (ALmixer_RWops*)malloc(sizeof(ALmixer_RWops));
+	if(NULL == rw_ops)
+	{
+/*		ALmixer_SetError("ALmixer_RWFromFP: Out of memory"); */
+		return NULL;
+	}
+
+	rw_ops->seek = stdio_seek;
+	rw_ops->read = stdio_read;
+	rw_ops->write = stdio_write;
+	rw_ops->close = stdio_close;
+	rw_ops->hidden.stdio.fp = file_pointer;
+	rw_ops->hidden.stdio.autoclose = autoclose_flag;
+	return rw_ops;
+}
+
+ALmixer_RWops* ALmixer_RWFromFile(const char* file_name, const char* file_mode)
+{
+    ALmixer_RWops* rw_ops = NULL;
+    FILE* file_pointer = NULL;
+    if(NULL == file_name || NULL == file_mode)
+	{
+/*		ALmixer_SetError("ALmixer_RWFromFile: No file or mode specified"); */
+        return NULL;
+    }
+	file_pointer = fopen(file_name, file_mode);
+	if(NULL == file_pointer)
+	{
+/*		ALmixer_SetError("ALmixer_RWFromFile: Could not open file: %s", strerror(errno)); */
+		return NULL;
+    }
+
+	rw_ops = ALmixer_RWFromFP(file_pointer, 1);
+    return rw_ops;
+}
+
+
+#endif /* ALMIXER_COMPILED_WITH_SDL */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/ALmixer_RWops.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,117 @@
+#ifndef ALMIXER_RWOPS
+#define ALMIXER_RWOPS
+
+	#if defined(_WIN32)
+		#if defined(ALMIXER_RWOPS_BUILD_LIBRARY)
+			#define ALMIXER_RWOPS_DECLSPEC __declspec(dllexport)
+		#else
+			#define ALMIXER_RWOPS_DECLSPEC __declspec(dllimport)
+		#endif
+	#else
+		#if defined(ALMIXER_RWOPS_BUILD_LIBRARY)
+			#if defined (__GNUC__) && __GNUC__ >= 4
+				#define ALMIXER_RWOPS_DECLSPEC __attribute__((visibility("default")))
+			#else
+				#define ALMIXER_RWOPS_DECLSPEC
+			#endif
+		#else
+			#define ALMIXER_RWOPS_DECLSPEC
+		#endif
+	#endif
+
+	#if defined(_WIN32)
+		#define ALMIXER_RWOPS_CALL __cdecl
+	#else
+		#define ALMIXER_RWOPS_CALL
+	#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	/* Trying to keep compatibility with SDL_RWops,
+	 * but I don't plan on reimplementing everything.
+	 */
+	#include <stdio.h>
+	#include <stddef.h>
+	/* The 'type' parameter needs to be 32-bits to match SDL_RWops.
+	 * <stdint.h> has been problematic for Visual Studio for years.
+	 * It appears that Visual Studio 2010 finally includes this.
+	 */
+	#include <stdint.h>
+	typedef struct ALmixer_RWops 
+	{
+		/** Seek to 'offset' relative to whence, one of stdio's whence values:
+		 *	SEEK_SET, SEEK_CUR, SEEK_END
+		 *  Returns the final offset in the data source.
+		 *  (Note this is different than stdio's seek. This returns ftell.)
+		 */
+		int (ALMIXER_RWOPS_CALL *seek)(struct ALmixer_RWops* the_context, long offset, int whence);
+
+		/** Read up to 'nitems' objects each of size 'size' from the data
+		 *  source to the area pointed at by 'ptr'.
+		 *  Returns the number of objects read, or -1 if the read failed.
+		 */
+		size_t (ALMIXER_RWOPS_CALL *read)(struct ALmixer_RWops* the_context, void* ptr, size_t size, size_t nitems);
+
+		/** Write exactly 'nitems' objects each of size 'size' from the area
+		 *  pointed at by 'ptr' to data source.
+		 *  Returns 'num', or -1 if the write failed.
+		 */
+		size_t (ALMIXER_RWOPS_CALL *write)(struct ALmixer_RWops* the_context, const void* ptr, size_t size, size_t nitems);
+
+		/** Close and free an allocated ALmixer_RWops structure */
+		int (ALMIXER_RWOPS_CALL *close)(struct ALmixer_RWops* the_context);
+
+		/* type Needs to be a 32-bit to be compatible with SDL */
+		uint32_t type;
+		union 
+		{
+#if defined(__WIN32__) && !defined(__SYMBIAN32__)
+			/* Chances are that I will not implement this path.
+			 * But I want the padding to be the same as SDL.
+			 */
+			struct 
+			{
+				int   append;
+				void *h;
+				struct
+				{
+					void *data;
+					int size;
+					int left;
+				} buffer;
+			} win32io;
+#endif
+	    	struct 
+			{
+				int autoclose;
+	 			FILE* fp;
+	    	} stdio;
+	   		struct 
+			{
+				unsigned char* base;
+			 	unsigned char* here;
+				unsigned char* stop;
+			} mem;
+		  	struct 
+			{
+				void* data1;
+	    	} unknown;
+		} hidden;
+	} ALmixer_RWops;
+
+	extern ALMIXER_RWOPS_DECLSPEC ALmixer_RWops* ALMIXER_RWOPS_CALL ALmixer_RWFromFile(const char* file_name, const char* file_mode);
+	extern ALMIXER_RWOPS_DECLSPEC ALmixer_RWops* ALMIXER_RWOPS_CALL ALmixer_RWFromFP(FILE* file_pointer, char autoclose_flag);
+
+#define ALmixer_RWseek(rwops, offset, whence) (rwops)->seek(rwops, offset, whence)
+#define ALmixer_RWtell(rwops) (rwops)->seek(rwops, 0, SEEK_CUR)
+#define ALmixer_RWread(rwops, ptr, size, nitems) (rwops)->read(rwops, ptr, size, nitems)
+	
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/LGPL/SDL_endian_minimal.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,99 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+ 
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ 
+ Sam Lantinga
+ slouken@libsdl.org
+ */
+
+/* 
+ Attention: This is a stripped down file of SDL_endian for our purposes. 
+ This code is licensed under the LGPL.
+ This means we must not compile this code into anything that we are not willing to
+ publicly release source code. 
+ You should compile this into a separate dynamic library that is isolated from proprietary code.
+ */
+
+
+#ifndef SDL_endian_minimal_h
+#define SDL_endian_minimal_h
+
+#ifdef ANDROID_NDK
+#include <endian.h>
+
+#define SDL_BYTEORDER _BYTE_ORDER
+#define SDL_BIG_ENDIAN _BIG_ENDIAN
+#define SDL_LITTLE_ENDIAN _LITTLE_ENDIAN
+#endif
+
+#include <stdint.h>
+
+
+#if defined(__GNUC__) && defined(__i386__) && \
+   !(__GNUC__ == 2 && __GNUC_MINOR__ <= 95 /* broken gcc version */)
+static __inline__ uint32_t SDL_Swap32(uint32_t x)
+{
+	__asm__("bswap %0" : "=r" (x) : "0" (x));
+	return x;
+}
+#elif defined(__GNUC__) && defined(__x86_64__)
+static __inline__ uint32_t SDL_Swap32(uint32_t x)
+{
+	__asm__("bswapl %0" : "=r" (x) : "0" (x));
+	return x;
+}
+#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
+static __inline__ uint32_t SDL_Swap32(uint32_t x)
+{
+	uint32_t result;
+
+	__asm__("rlwimi %0,%2,24,16,23" : "=&r" (result) : "0" (x>>24), "r" (x));
+	__asm__("rlwimi %0,%2,8,8,15"   : "=&r" (result) : "0" (result),    "r" (x));
+	__asm__("rlwimi %0,%2,24,0,7"   : "=&r" (result) : "0" (result),    "r" (x));
+	return result;
+}
+#elif defined(__GNUC__) && (defined(__M68000__) || defined(__M68020__))
+static __inline__ uint32_t SDL_Swap32(uint32_t x)
+{
+	__asm__("rorw #8,%0\n\tswap %0\n\trorw #8,%0" : "=d" (x) :  "0" (x) : "cc");
+	return x;
+}
+#else
+static __inline__ uint32_t SDL_Swap32(uint32_t x) {
+	return((x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24));
+}
+#endif
+
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define SDL_SwapLE16(X)	SDL_Swap16(X)
+#define SDL_SwapLE32(X)	SDL_Swap32(X)
+#define SDL_SwapLE64(X)	SDL_Swap64(X)
+#define SDL_SwapBE16(X)	(X)
+#define SDL_SwapBE32(X)	(X)
+#define SDL_SwapBE64(X)	(X)
+#else
+#define SDL_SwapLE16(X)	(X)
+#define SDL_SwapLE32(X)	(X)
+#define SDL_SwapLE64(X)	(X)
+#define SDL_SwapBE16(X)	SDL_Swap16(X)
+#define SDL_SwapBE32(X)	SDL_Swap32(X)
+#define SDL_SwapBE64(X)	SDL_Swap64(X)
+#endif
+
+
+#endif // SDL_endian_minimal_h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/LGPL/SDL_sound_minimal.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,41 @@
+/*
+ * SDL_sound -- An abstract sound format decoding API.
+ * Copyright (C) 2001  Ryan C. Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* 
+ Attention: This is a stripped down file of SDL_endian for our purposes. 
+ This code is licensed under the LGPL.
+ This means we must not compile this code into anything that we are not willing to
+ publicly release source code. 
+ You should compile this into a separate dynamic library that is isolated from proprietary code.
+ */
+ 
+ 
+#include <stdint.h>
+#include "SoundDecoder.h"
+
+uint32_t __Sound_convertMsToBytePos(Sound_AudioInfo *info, uint32_t ms)
+{
+    /* "frames" == "sample frames" */
+    float frames_per_ms = ((float) info->rate) / 1000.0f;
+    uint32_t frame_offset = (uint32_t) (frames_per_ms * ((float) ms));
+    uint32_t frame_size = (uint32_t) ((info->format & 0xFF) / 8) * info->channels;
+    return(frame_offset * frame_size);
+} /* __Sound_convertMsToBytePos */
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/LGPL/mpg123.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,393 @@
+/*
+ * SDL_sound -- An abstract sound format decoding API.
+ * Copyright (C) 2001  Ryan C. Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * libmpg123 decoder for SDL_sound. This is a very lightweight MP3 decoder,
+ *  which is included with the SDL_sound source, so that it doesn't rely on
+ *  unnecessary external libraries.
+ *
+ * libmpg123 is part of mpg123, and can be found in its original
+ *  form at: http://www.mpg123.org/
+ *
+ * Please see the file LICENSE.txt in the source's root directory. The included
+ *  source code for libmpg123 falls under the LGPL, which is the same license
+ *  as SDL_sound (so you can consider it a single work).
+ *
+ *  This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_MPG123
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "mpg123.h"
+
+#ifdef ALMIXER_COMPILE_WITHOUT_SDL
+#include "SoundDecoder.h"
+#include "SoundDecoder_Internal.h"
+#include "SimpleMutex.h"
+#include "ALmixer_RWops.h"
+#include <stdint.h>
+		typedef struct SimpleMutex SDL_mutex;
+		typedef struct ALmixer_RWops SDL_RWops;
+		#define SDL_CreateMutex SimpleMutex_CreateMutex
+		#define SDL_DestroyMutex SimpleMutex_DestroyMutex
+		#define SDL_LockMutex SimpleMutex_LockMutex
+		#define SDL_UnlockMutex SimpleMutex_UnlockMutex
+		typedef uint32_t Uint32;
+		#define SDL_RWseek ALmixer_RWseek
+		#define SDL_RWread ALmixer_RWread
+
+#else
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+#endif
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+
+static int MPG123_init(void);
+static void MPG123_quit(void);
+static int MPG123_open(Sound_Sample *sample, const char *ext);
+static void MPG123_close(Sound_Sample *sample);
+static Uint32 MPG123_read(Sound_Sample *sample);
+static int MPG123_rewind(Sound_Sample *sample);
+static int MPG123_seek(Sound_Sample *sample, Uint32 ms);
+
+/* !!! FIXME: MPEG and MPG extensions? */
+static const char *extensions_mpg123[] = { "MP3", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_MPG123 =
+{
+    {
+        extensions_mpg123,
+        "MP3 decoding via internal libmpg123",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://www.icculus.org/SDL_sound/"
+    },
+
+    MPG123_init,       /*   init() method */
+    MPG123_quit,       /*   quit() method */
+    MPG123_open,       /*   open() method */
+    MPG123_close,      /*  close() method */
+    MPG123_read,       /*   read() method */
+    MPG123_rewind,     /* rewind() method */
+    MPG123_seek        /*   seek() method */
+};
+
+
+/* this is what we store in our internal->decoder_private field... */
+typedef mpg123_handle mpg123_t;
+
+static SDL_mutex *mpg123_mutex = NULL;
+static int mpg123_rwops_count = 0;
+static SDL_RWops **mpg123_rwops = NULL;
+
+static void print_decoders(const char *kind, char **decoders)
+{
+    SNDDBG(("%s:", kind));
+    if (*decoders == NULL)
+	{
+        SNDDBG((" [none]"));
+	}
+    else
+    {
+        do
+        {
+            SNDDBG((" %s", *decoders));
+        } while (*(++decoders));
+    } /* else */
+    SNDDBG(("\n"));
+} /* print_decoders */
+
+
+static int MPG123_init(void)
+{
+    int retval = 0;
+    assert(mpg123_mutex == NULL);
+    if (mpg123_init() == MPG123_OK)
+    {
+        char **supported = mpg123_supported_decoders();
+        print_decoders("ALL MPG123 DECODERS", mpg123_decoders());
+        print_decoders("SUPPORTED MPG123 DECODERS", mpg123_supported_decoders());
+        if ((supported != NULL) && (*supported != NULL))
+        {
+            mpg123_mutex = SDL_CreateMutex();
+            if (mpg123_mutex != NULL)
+                retval = 1;  /* at least one decoder available. */
+        } /* if */
+    } /* if */
+
+    return retval;
+} /* MPG123_init */
+
+
+static void MPG123_quit(void)
+{
+    mpg123_exit();
+    SDL_DestroyMutex(mpg123_mutex);
+    mpg123_mutex = NULL;
+    free(mpg123_rwops);
+    mpg123_rwops = NULL;
+    mpg123_rwops_count = 0;
+} /* MPG123_quit */
+
+
+/* bridge rwops reading to libmpg123 hooks. */
+static ssize_t rwread(int fd, void *buf, size_t len)
+{
+    SDL_RWops *rw = NULL;
+    SDL_LockMutex(mpg123_mutex);
+    rw = mpg123_rwops[fd];
+    SDL_UnlockMutex(mpg123_mutex);
+    return (ssize_t) SDL_RWread(rw, buf, 1, len);
+} /* rwread */
+
+
+/* bridge rwops seeking to libmpg123 hooks. */
+static off_t rwseek(int fd, off_t pos, int whence)
+{
+    SDL_RWops *rw = NULL;
+    SDL_LockMutex(mpg123_mutex);
+    rw = mpg123_rwops[fd];
+    SDL_UnlockMutex(mpg123_mutex);
+    return (off_t) SDL_RWseek(rw, pos, whence);
+} /* rwseek */
+
+
+static const char *set_error(mpg123_handle *mp, const int err)
+{
+    char buffer[128];
+    const char *str = NULL;
+    if ((err == MPG123_ERR) && (mp != NULL))
+        str = mpg123_strerror(mp);
+    else
+        str = mpg123_plain_strerror(err);
+
+    snprintf(buffer, sizeof (buffer), "MPG123: %s", str);
+    __Sound_SetError(buffer);
+    
+    return(NULL);  /* this is for BAIL_MACRO to not try to reset the string. */
+} /* set_error */
+
+
+/* Make sure we are only given decoded data in a format we can handle. */
+static int set_formats(mpg123_handle *mp)
+{
+    int rc = 0;
+    const long *rates = NULL;
+    size_t ratecount = 0;
+    const int channels = MPG123_STEREO | MPG123_MONO;
+    const int encodings = /* !!! FIXME: SDL 1.3 can do sint32 and float32.
+                          MPG123_ENC_SIGNED_32 | MPG123_ENC_FLOAT_32 | */
+                          MPG123_ENC_SIGNED_8 | MPG123_ENC_UNSIGNED_8 |
+                          MPG123_ENC_SIGNED_16 | MPG123_ENC_UNSIGNED_16;
+
+    mpg123_rates(&rates, &ratecount);
+
+    rc = mpg123_format_none(mp);
+    while ((ratecount--) && (rc == MPG123_OK))
+        rc = mpg123_format(mp, *(rates++), channels, encodings);
+
+    return(rc);
+} /* set_formats */
+
+
+static int MPG123_open(Sound_Sample *sample, const char *ext)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    mpg123_handle *mp = NULL;
+    long rate = 0;
+    int channels = 0;
+    int fmt = 0;
+    int rc = 0;
+    off_t len = 0;
+    int seekable = 0;
+    void *ptr = NULL;
+    int rwops = 0;
+
+    /* !!! FIXME: so much tapdance because we need a pointer, not an int. */
+    SDL_LockMutex(mpg123_mutex);
+    for (rwops = 0; rwops < mpg123_rwops_count; rwops++)
+    {
+        if (mpg123_rwops[rwops] == NULL)
+        break;
+    } /* for */
+    if (rwops < mpg123_rwops_count)
+        ptr = mpg123_rwops;
+    else
+    {
+        mpg123_rwops_count++;
+        ptr = realloc(mpg123_rwops, sizeof (SDL_RWops *) * mpg123_rwops_count);
+        if (ptr != NULL)
+            mpg123_rwops = (SDL_RWops **) ptr;
+    } /* else */
+    if (ptr != NULL)
+        mpg123_rwops[rwops] = internal->rw;
+    SDL_UnlockMutex(mpg123_mutex);
+    BAIL_IF_MACRO(ptr == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    if ((mp = mpg123_new(NULL, &rc)) == NULL)
+        goto mpg123_open_failed;
+    else if ((rc = set_formats(mp)) != MPG123_OK)
+        goto mpg123_open_failed;
+    else if ((rc = mpg123_replace_reader(mp, rwread, rwseek)) != MPG123_OK)
+        goto mpg123_open_failed;
+    else if ((rc = mpg123_open_fd(mp, rwops)) != MPG123_OK)
+        goto mpg123_open_failed;
+    else if ((rc = mpg123_scan(mp)) != MPG123_OK)
+        goto mpg123_open_failed;  /* !!! FIXME: this may be wrong. */
+    else if ((rc = mpg123_getformat(mp, &rate, &channels, &fmt)) != MPG123_OK)
+        goto mpg123_open_failed;
+
+    if (mpg123_seek(mp, 0, SEEK_END) >= 0)  /* can seek? */
+    {
+        len = mpg123_tell(mp);
+        if ((rc = (int) mpg123_seek(mp, 0, SEEK_SET)) < 0)
+            goto mpg123_open_failed;
+        seekable = 1;
+    } /* if */
+
+    internal->decoder_private = mp;
+    sample->actual.rate = rate;
+    sample->actual.channels = channels;
+
+    rc = MPG123_BAD_OUTFORMAT;  /* in case this fails... */
+    if (fmt == MPG123_ENC_SIGNED_8)
+        sample->actual.format = AUDIO_S8;
+    else if (fmt == MPG123_ENC_UNSIGNED_8)
+        sample->actual.format = AUDIO_U8;
+    else if (fmt == MPG123_ENC_SIGNED_16)
+        sample->actual.format = AUDIO_S16SYS;
+    else if (fmt == MPG123_ENC_UNSIGNED_16)
+         sample->actual.format = AUDIO_U16SYS;
+    /* !!! FIXME: SDL 1.3 can do sint32 and float32 ...
+    else if (fmt == MPG123_ENC_SIGNED_32)
+        sample->actual.format = AUDIO_S32SYS;
+    else if (fmt == MPG123_ENC_FLOAT_32)
+        sample->actual.format = AUDIO_F32SYS;
+    */
+    else
+        goto mpg123_open_failed;
+
+    SNDDBG(("MPG123: Accepting data stream.\n"));
+
+    sample->flags = SOUND_SAMPLEFLAG_NONE;
+    internal->total_time = -1;
+    if (seekable)
+    {
+        sample->flags |= SOUND_SAMPLEFLAG_CANSEEK;
+        internal->total_time = ((len / rate) * 1000) +
+                               (((len % rate) * 1000) / rate);
+    } /* if */
+
+    return(1); /* we'll handle this data. */
+
+mpg123_open_failed:
+    SDL_LockMutex(mpg123_mutex);
+    mpg123_rwops[rwops] = NULL;
+    if (rwops == mpg123_rwops_count)
+        mpg123_rwops_count--;
+    SDL_UnlockMutex(mpg123_mutex);
+    set_error(mp, rc);
+    mpg123_delete(mp);  /* NULL is safe. */
+    return(0);
+} /* MPG123_open */
+
+
+static void MPG123_close(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    mpg123_t *mp = ((mpg123_t *) internal->decoder_private);
+    int i;
+
+    SDL_LockMutex(mpg123_mutex);
+    for (i = 0; i < mpg123_rwops_count; i++)
+    {
+        if (mpg123_rwops[i] == internal->rw)
+            mpg123_rwops[i] = NULL;
+    } /* for */
+
+    for (i = mpg123_rwops_count-1; i >= 0; i--)
+    {
+        if (mpg123_rwops[i] != NULL)
+            break;
+    } /* for */
+    mpg123_rwops_count = i + 1;
+    SDL_UnlockMutex(mpg123_mutex);
+
+    mpg123_close(mp);  /* don't need this at the moment, but it's safe. */
+    mpg123_delete(mp);
+} /* MPG123_close */
+
+
+static Uint32 MPG123_read(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    mpg123_t *mp = ((mpg123_t *) internal->decoder_private);
+    size_t bw = 0;
+    const int rc = mpg123_read(mp, (unsigned char *) internal->buffer,
+                               internal->buffer_size, &bw);
+    if (rc == MPG123_DONE)
+        sample->flags |= SOUND_SAMPLEFLAG_EOF;
+    else if (rc != MPG123_OK)
+    {
+        sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+        set_error(mp, rc);
+    } /* else if */
+
+    return((Uint32) bw);
+} /* MPG123_read */
+
+
+static int MPG123_rewind(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    mpg123_t *mp = ((mpg123_t *) internal->decoder_private);
+    const int rc = (int) mpg123_seek(mp, 0, SEEK_SET);
+    BAIL_IF_MACRO(rc < 0, set_error(mp, rc), 0);
+    return(1);
+} /* MPG123_rewind */
+
+
+static int MPG123_seek(Sound_Sample *sample, Uint32 ms)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    mpg123_t *mp = ((mpg123_t *) internal->decoder_private);
+    const float frames_per_ms = ((float) sample->actual.rate) / 1000.0f;
+    const off_t frame_offset = (off_t) (frames_per_ms * ((float) ms));
+    const int rc = (int) mpg123_seek(mp, frame_offset , SEEK_SET);
+    BAIL_IF_MACRO(rc < 0, set_error(mp, rc), 0);
+    return(1);
+} /* MPG123_seek */
+
+#endif /* SOUND_SUPPORTS_MPG123 */
+
+/* end of mpg123.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/LGPL/oggtremor.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,379 @@
+/*
+ * SDL_sound -- An abstract sound format decoding API.
+ * Copyright (C) 2001  Ryan C. Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Ogg Vorbis decoder for SDL_sound.
+ *
+ * This driver handles .OGG audio files, and depends on libvorbisfile to
+ *  do the actual decoding work. libvorbisfile is part of libvorbis, which
+ *  is part of the Ogg Vorbis project.
+ *
+ *   Ogg Vorbis: http://www.xiph.org/ogg/vorbis/
+ *   vorbisfile documentation: http://www.xiph.org/ogg/vorbis/doc/vorbisfile/
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_OGG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "SoundDecoder.h"
+
+#include "SoundDecoder_Internal.h"
+#include "SDL_endian_minimal.h"
+#include "ALmixer_RWops.h"
+
+//#include <vorbis/codec.h>
+#include <ivorbisfile.h>
+#define ERR_IO_ERROR "I/O error"
+
+
+static int OGG_init(void);
+static void OGG_quit(void);
+static int OGG_open(Sound_Sample *sample, const char *ext);
+static void OGG_close(Sound_Sample *sample);
+static uint32_t OGG_read(Sound_Sample *sample);
+static int OGG_rewind(Sound_Sample *sample);
+static int OGG_seek(Sound_Sample *sample, uint32_t ms);
+
+static const char *extensions_ogg[] = { "OGG", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG =
+{
+    {
+        extensions_ogg,
+        "Ogg Vorbis audio through VorbisFile",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://www.icculus.org/SDL_sound/"
+    },
+
+    OGG_init,       /*   init() method */
+    OGG_quit,       /*   quit() method */
+    OGG_open,       /*   open() method */
+    OGG_close,      /*  close() method */
+    OGG_read,       /*   read() method */
+    OGG_rewind,     /* rewind() method */
+    OGG_seek        /*   seek() method */
+};
+
+
+static int OGG_init(void)
+{
+    return(1);  /* always succeeds. */
+} /* OGG_init */
+
+
+static void OGG_quit(void)
+{
+    /* it's a no-op. */
+} /* OGG_quit */
+
+
+
+    /*
+     * These are callbacks from vorbisfile that let them read data from
+     *  a RWops...
+     */
+
+static size_t RWops_ogg_read(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+    return((size_t) ALmixer_RWread((ALmixer_RWops *) datasource, ptr, size, nmemb));
+} /* RWops_ogg_read */
+
+static int RWops_ogg_seek(void *datasource, ogg_int64_t offset, int whence)
+{
+    return(ALmixer_RWseek((ALmixer_RWops *) datasource, offset, whence));
+} /* RWops_ogg_seek */
+
+static int RWops_ogg_close(void *datasource)
+{
+    /* do nothing; SDL_sound will delete the RWops at a higher level. */
+    return(0);  /* this is success in fclose(), so I guess that's okay. */
+} /* RWops_ogg_close */
+
+static long RWops_ogg_tell(void *datasource)
+{
+    return((long) ALmixer_RWtell((ALmixer_RWops *) datasource));
+} /* RWops_ogg_tell */
+
+static const ov_callbacks RWops_ogg_callbacks =
+{
+    RWops_ogg_read,
+    RWops_ogg_seek,
+    RWops_ogg_close,
+    RWops_ogg_tell
+};
+
+
+    /* Return a human readable version of an VorbisFile error code... */
+#if (defined DEBUG_CHATTER)
+static const char *ogg_error(int errnum)
+{
+    switch(errnum)
+    {
+        case OV_EREAD:
+            return("i/o error");
+        case OV_ENOTVORBIS:
+            return("not a vorbis file");
+        case OV_EVERSION:
+            return("Vorbis version mismatch");
+        case OV_EBADHEADER:
+            return("invalid Vorbis bitstream header");
+        case OV_EFAULT:
+            return("internal logic fault in Vorbis library");
+    } /* switch */
+
+    return("unknown error");
+} /* ogg_error */
+#endif
+
+static __inline__ void output_ogg_comments(OggVorbis_File *vf)
+{
+#if (defined DEBUG_CHATTER)
+    int i;
+    vorbis_comment *vc = ov_comment(vf, -1);
+
+    if (vc == NULL)
+        return;
+
+    SNDDBG(("OGG: vendor == [%s].\n", vc->vendor));
+    for (i = 0; i < vc->comments; i++)
+    {
+        SNDDBG(("OGG: user comment [%s].\n", vc->user_comments[i]));
+    } /* for */
+#endif
+} /* output_ogg_comments */
+
+
+static int OGG_open(Sound_Sample *sample, const char *ext)
+{
+    int rc;
+    double total_time;
+    OggVorbis_File *vf;
+    vorbis_info *info;
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+    vf = (OggVorbis_File *) malloc(sizeof (OggVorbis_File));
+    BAIL_IF_MACRO(vf == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    rc = ov_open_callbacks(internal->rw, vf, NULL, 0, RWops_ogg_callbacks);
+    if (rc != 0)
+    {
+#if (defined DEBUG_CHATTER)		
+        SNDDBG(("OGG: can't grok data. reason: [%s].\n", ogg_error(rc)));
+#endif
+        free(vf);
+        BAIL_MACRO("OGG: Not valid Ogg Vorbis data.", 0);
+    } /* if */
+
+    info = ov_info(vf, -1);
+    if (info == NULL)
+    {
+        ov_clear(vf);
+        free(vf);
+        BAIL_MACRO("OGG: failed to retrieve bitstream info", 0);
+    } /* if */
+
+    output_ogg_comments(vf);
+	
+    SNDDBG(("OGG: bitstream version == (%d).\n", info->version));
+    SNDDBG(("OGG: bitstream channels == (%d).\n", info->channels));
+    SNDDBG(("OGG: bitstream sampling rate == (%ld).\n", info->rate));
+    SNDDBG(("OGG: seekable == {%s}.\n", ov_seekable(vf) ? "TRUE" : "FALSE"));
+    SNDDBG(("OGG: number of logical bitstreams == (%ld).\n", ov_streams(vf)));
+    SNDDBG(("OGG: serial number == (%ld).\n", ov_serialnumber(vf, -1)));
+    SNDDBG(("OGG: total seconds of sample == (%f).\n", ov_time_total(vf, -1)));
+
+    internal->decoder_private = vf;
+    sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+    sample->actual.rate = (uint32_t) info->rate;
+    sample->actual.channels = (uint8_t) info->channels;
+    total_time = ov_time_total(vf, -1);
+    if (OV_EINVAL == total_time)
+      internal->total_time = -1;
+    else
+      internal->total_time = (int32_t)(total_time * 1000.0 + 0.5);
+
+
+    /*
+     * Since we might have more than one logical bitstream in the OGG file,
+     *  and these bitstreams may be in different formats, we might be
+     *  converting two or three times: once in vorbisfile, once again in
+     *  SDL_sound, and perhaps a third time to get it to the sound device's
+     *  format. That's wickedly inefficient.
+     *
+     * To combat this a little, if the user specified a desired format, we
+     *  claim that to be the "actual" format of the collection of logical
+     *  bitstreams. This means that VorbisFile will do a conversion as
+     *  necessary, and SDL_sound will not. If the user didn't specify a
+     *  desired format, then we pretend the "actual" format is something that
+     *  OGG files are apparently commonly encoded in.
+     */
+    sample->actual.format = (sample->desired.format == 0) ?
+                             AUDIO_S16SYS : sample->desired.format;
+    return(1);
+} /* OGG_open */
+
+
+static void OGG_close(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+    ov_clear(vf);
+    free(vf);
+} /* OGG_close */
+
+/* Note: According to the Vorbis documentation:
+ * "ov_read() will  decode at most one vorbis packet per invocation, 
+ * so the value returned will generally be less than length."
+ * Due to this, for buffer sizes like 16384, SDL_Sound was always getting
+ * an underfilled buffer and always setting the EAGAIN flag.
+ * Since the SDL_Sound API implies that the entire buffer
+ * should be filled unless EOF, additional code has been added
+ * to this function to call ov_read() until the buffer is filled.
+ * However, there may still be some corner cases where the buffer
+ * cannot be entirely filled. So be aware.
+ */
+static uint32_t OGG_read(Sound_Sample *sample)
+{
+    int rc;
+    int bitstream;
+	Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+    
+    rc = ov_read(vf, internal->buffer, internal->buffer_size,
+            &bitstream);
+
+        /* Make sure the read went smoothly... */
+    if (rc == 0)
+        sample->flags |= SOUND_SAMPLEFLAG_EOF;
+        
+    else if (rc < 0)
+        sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+    /* If the buffer isn't filled, keep trying to fill it
+     * until no more data can be grabbed */
+    else if ((uint32_t) rc < internal->buffer_size)
+	{
+        /* Creating a pointer to the buffer that denotes where to start
+         * writing new data. */
+        uint8_t* buffer_start_point = NULL;
+        int total_bytes_read = rc;
+        int bytes_remaining = internal->buffer_size - rc;
+
+        /* Keep grabbing data until something prevents
+         * us from getting more. (Could be EOF,
+         * packets are too large to fit in remaining
+         * space, or an error.)
+         */
+        while( (rc > 0) && (bytes_remaining > 0) )
+        {
+        /* Set buffer pointer to end of last write */
+        /* All the messiness is to get rid of the warning for
+         * dereferencing a void*
+         */
+            buffer_start_point = &(((uint8_t*)internal->buffer)[total_bytes_read]);
+            rc = ov_read(vf, buffer_start_point, bytes_remaining,
+                &bitstream);
+            /* Make sure rc > 0 because we don't accidently want
+             * to change the counters if there was an error
+             */
+            if(rc > 0)
+            {
+                total_bytes_read += rc;
+                bytes_remaining = bytes_remaining - rc;
+            }
+	    }
+        /* I think the minimum read size is 2, though I'm
+         * not sure about this. (I've hit cases where I
+         * couldn't read less than 4.) What I don't want to do is
+         * accidently claim we hit EOF when the reason rc == 0
+         * is because the requested amount of data was smaller
+         * than the minimum packet size.
+         * For now, I will be conservative
+         * and not set the EOF flag, and let the next call to 
+         * this function figure it out.
+         * I think the ERROR flag is safe to set because 
+         * it looks like OGG simply returns 0 if the 
+         * read size is too small. 
+         * And in most cases for sensible buffer sizes, 
+         * this fix will fill the buffer,
+         * so we can set the EAGAIN flag without worrying
+         * that it will always be set.
+         */
+        if(rc < 0)
+	    {
+            sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+        }
+        else if(rc == 0)
+        {
+            /* Do nothing for now until there is a better solution */
+            /* sample->flags |= SOUND_SAMPLEFLAG_EOF; */
+        }
+
+        /* Test for a buffer underrun. It should occur less frequently
+         * now, but it still may happen and not necessarily mean
+         * anything useful. */
+        if ((uint32_t) total_bytes_read < internal->buffer_size)
+        {
+            sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+        }
+        /* change rc to the total bytes read so function
+         * can return the correct value.
+         */
+        rc = total_bytes_read;
+    }
+
+    return((uint32_t) rc);
+} /* OGG_read */
+
+
+static int OGG_rewind(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+
+    BAIL_IF_MACRO(ov_raw_seek(vf, 0) < 0, ERR_IO_ERROR, 0);
+    return(1);
+} /* OGG_rewind */
+
+
+static int OGG_seek(Sound_Sample *sample, uint32_t ms)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+    double timepos = (((double) ms) / 1000.0);
+    BAIL_IF_MACRO(ov_time_seek(vf, timepos) < 0, ERR_IO_ERROR, 0);
+    return(1);
+} /* OGG_seek */
+
+#endif /* SOUND_SUPPORTS_OGG */
+
+
+/* end of ogg.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/LGPL/wav.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,846 @@
+/*
+ * SDL_sound -- An abstract sound format decoding API.
+ * Copyright (C) 2001  Ryan C. Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* 
+ Attention: This is a stripped down file of SDL_endian for our purposes. 
+ This code is licensed under the LGPL.
+ This means we must not compile this code into anything that we are not willing to
+ publicly release source code. 
+ You should compile this into a separate dynamic library that is isolated from proprietary code.
+ */
+
+/*
+ * WAV decoder for SDL_sound.
+ *
+ * This driver handles Microsoft .WAVs, in as many of the thousands of
+ *  variations as we can.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_WAV
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+//#include "SDL_sound.h"
+
+//#define __SDL_SOUND_INTERNAL__
+//#include "SDL_sound_internal.h"
+
+
+#include "SoundDecoder.h"
+
+#include "SoundDecoder_Internal.h"
+#include "SDL_endian_minimal.h"
+#include "ALmixer_RWops.h"
+
+#define ERR_IO_ERROR "I/O error"
+#define assert(x)
+
+static int WAV_init(void);
+static void WAV_quit(void);
+static int WAV_open(Sound_Sample *sample, const char *ext);
+static void WAV_close(Sound_Sample *sample);
+static uint32_t WAV_read(Sound_Sample *sample);
+static int WAV_rewind(Sound_Sample *sample);
+static int WAV_seek(Sound_Sample *sample, uint32_t ms);
+
+static const char *extensions_wav[] = { "WAV", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV =
+{
+    {
+        extensions_wav,
+        "Microsoft WAVE audio format",
+        "Ryan C. Gordon <icculus@icculus.org>",
+        "http://www.icculus.org/SDL_sound/"
+    },
+
+    WAV_init,       /*   init() method */
+    WAV_quit,       /*   quit() method */
+    WAV_open,       /*   open() method */
+    WAV_close,      /*  close() method */
+    WAV_read,       /*   read() method */
+    WAV_rewind,     /* rewind() method */
+    WAV_seek        /*   seek() method */
+};
+
+
+/* Better than SDL_ReadLE16, since you can detect i/o errors... */
+static __inline__ int read_le16(ALmixer_RWops *rw, uint16_t *ui16)
+{
+    int rc = ALmixer_RWread(rw, ui16, sizeof (uint16_t), 1);
+    BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
+    *ui16 = SDL_SwapLE16(*ui16);
+    return(1);
+} /* read_le16 */
+
+
+/* Better than SDL_ReadLE32, since you can detect i/o errors... */
+static __inline__ int read_le32(ALmixer_RWops *rw, uint32_t *ui32)
+{
+    int rc = ALmixer_RWread(rw, ui32, sizeof (uint32_t), 1);
+    BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
+    *ui32 = SDL_SwapLE32(*ui32);
+    return(1);
+} /* read_le32 */
+
+
+/* This is just cleaner on the caller's end... */
+static __inline__ int read_uint8_t(ALmixer_RWops *rw, uint8_t *ui8)
+{
+    int rc = ALmixer_RWread(rw, ui8, sizeof (uint8_t), 1);
+    BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
+    return(1);
+} /* read_uint8_t */
+
+
+static __inline__ uint16_t SDL_ReadLE16( ALmixer_RWops *rw )
+{
+	uint16_t result = 0;
+	
+	int rc = read_le16( rw, &result );
+	
+	return result;
+}
+static __inline__ uint32_t SDL_ReadLE32( ALmixer_RWops *rw )
+{
+	uint32_t result = 0;
+	
+	int rc = read_le32( rw, &result );
+	
+	return result;
+}
+
+    /* Chunk management code... */
+
+#define riffID 0x46464952  /* "RIFF", in ascii. */
+#define waveID 0x45564157  /* "WAVE", in ascii. */
+#define factID 0x74636166  /* "fact", in ascii. */
+
+
+/*****************************************************************************
+ * The FORMAT chunk...                                                       *
+ *****************************************************************************/
+
+#define fmtID  0x20746D66  /* "fmt ", in ascii. */
+
+#define FMT_NORMAL 0x0001    /* Uncompressed waveform data.     */
+#define FMT_ADPCM  0x0002    /* ADPCM compressed waveform data. */
+
+typedef struct
+{
+    int16_t iCoef1;
+    int16_t iCoef2;
+} ADPCMCOEFSET;
+
+typedef struct
+{
+    uint8_t bPredictor;
+    uint16_t iDelta;
+    int16_t iSamp1;
+    int16_t iSamp2;
+} ADPCMBLOCKHEADER;
+
+typedef struct S_WAV_FMT_T
+{
+    uint32_t chunkID;
+    int32_t chunkSize;
+    int16_t wFormatTag;
+    uint16_t wChannels;
+    uint32_t dwSamplesPerSec;
+    uint32_t dwAvgBytesPerSec;
+    uint16_t wBlockAlign;
+    uint16_t wBitsPerSample;
+
+    uint32_t next_chunk_offset;
+    
+    uint32_t sample_frame_size;
+    uint32_t data_starting_offset;
+    uint32_t total_bytes;
+
+    void (*free)(struct S_WAV_FMT_T *fmt);
+    uint32_t (*read_sample)(Sound_Sample *sample);
+    int (*rewind_sample)(Sound_Sample *sample);
+    int (*seek_sample)(Sound_Sample *sample, uint32_t ms);
+
+    union
+    {
+        struct
+        {
+            uint16_t cbSize;
+            uint16_t wSamplesPerBlock;
+            uint16_t wNumCoef;
+            ADPCMCOEFSET *aCoef;
+            ADPCMBLOCKHEADER *blockheaders;
+            uint32_t samples_left_in_block;
+            int nibble_state;
+            int8_t nibble;
+        } adpcm;
+
+        /* put other format-specific data here... */
+    } fmt;
+} fmt_t;
+
+
+/*
+ * Read in a fmt_t from disk. This makes this process safe regardless of
+ *  the processor's byte order or how the fmt_t structure is packed.
+ * Note that the union "fmt" is not read in here; that is handled as 
+ *  needed in the read_fmt_* functions.
+ */
+static int read_fmt_chunk(ALmixer_RWops *rw, fmt_t *fmt)
+{
+    /* skip reading the chunk ID, since it was already read at this point... */
+    fmt->chunkID = fmtID;
+
+    BAIL_IF_MACRO(!read_le32(rw, &fmt->chunkSize), NULL, 0);
+    BAIL_IF_MACRO(fmt->chunkSize < 16, "WAV: Invalid chunk size", 0);
+    fmt->next_chunk_offset = ALmixer_RWtell(rw) + fmt->chunkSize;
+    
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->wFormatTag), NULL, 0);
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->wChannels), NULL, 0);
+    BAIL_IF_MACRO(!read_le32(rw, &fmt->dwSamplesPerSec), NULL, 0);
+    BAIL_IF_MACRO(!read_le32(rw, &fmt->dwAvgBytesPerSec), NULL, 0);
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->wBlockAlign), NULL, 0);
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->wBitsPerSample), NULL, 0);
+
+    return(1);
+} /* read_fmt_chunk */
+
+
+
+/*****************************************************************************
+ * The DATA chunk...                                                         *
+ *****************************************************************************/
+
+#define dataID 0x61746164  /* "data", in ascii. */
+
+typedef struct
+{
+    uint32_t chunkID;
+    int32_t chunkSize;
+    /* Then, (chunkSize) bytes of waveform data... */
+} data_t;
+
+
+/*
+ * Read in a data_t from disk. This makes this process safe regardless of
+ *  the processor's byte order or how the fmt_t structure is packed.
+ */
+static int read_data_chunk(ALmixer_RWops *rw, data_t *data)
+{
+    /* skip reading the chunk ID, since it was already read at this point... */
+    data->chunkID = dataID;
+    BAIL_IF_MACRO(!read_le32(rw, &data->chunkSize), NULL, 0);
+    return(1);
+} /* read_data_chunk */
+
+
+
+
+/*****************************************************************************
+ * this is what we store in our internal->decoder_private field...           *
+ *****************************************************************************/
+
+typedef struct
+{
+    fmt_t *fmt;
+    int32_t bytesLeft;
+} wav_t;
+
+
+
+
+/*****************************************************************************
+ * Normal, uncompressed waveform handler...                                  *
+ *****************************************************************************/
+
+/*
+ * Sound_Decode() lands here for uncompressed WAVs...
+ */
+static uint32_t read_sample_fmt_normal(Sound_Sample *sample)
+{
+    uint32_t retval;
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    uint32_t max = (internal->buffer_size < (uint32_t) w->bytesLeft) ?
+                    internal->buffer_size : (uint32_t) w->bytesLeft;
+
+    assert(max > 0);
+
+        /*
+         * We don't actually do any decoding, so we read the wav data
+         *  directly into the internal buffer...
+         */
+    retval = ALmixer_RWread(internal->rw, internal->buffer, 1, max);
+
+    w->bytesLeft -= retval;
+
+        /* Make sure the read went smoothly... */
+    if ((retval == 0) || (w->bytesLeft == 0))
+        sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+    else if (retval == -1)
+        sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+        /* (next call this EAGAIN may turn into an EOF or error.) */
+    else if (retval < internal->buffer_size)
+        sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+    return(retval);
+} /* read_sample_fmt_normal */
+
+
+static int seek_sample_fmt_normal(Sound_Sample *sample, uint32_t ms)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    fmt_t *fmt = w->fmt;
+    int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+    int pos = (int) (fmt->data_starting_offset + offset);
+    int rc = ALmixer_RWseek(internal->rw, pos, SEEK_SET);
+    BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
+    w->bytesLeft = fmt->total_bytes - offset;
+    return(1);  /* success. */
+} /* seek_sample_fmt_normal */
+
+
+static int rewind_sample_fmt_normal(Sound_Sample *sample)
+{
+    /* no-op. */
+    return(1);
+} /* rewind_sample_fmt_normal */
+
+
+static int read_fmt_normal(ALmixer_RWops *rw, fmt_t *fmt)
+{
+    /* (don't need to read more from the RWops...) */
+    fmt->free = NULL;
+    fmt->read_sample = read_sample_fmt_normal;
+    fmt->rewind_sample = rewind_sample_fmt_normal;
+    fmt->seek_sample = seek_sample_fmt_normal;
+    return(1);
+} /* read_fmt_normal */
+
+
+
+/*****************************************************************************
+ * ADPCM compression handler...                                              *
+ *****************************************************************************/
+
+#define FIXED_POINT_COEF_BASE      256
+#define FIXED_POINT_ADAPTION_BASE  256
+#define SMALLEST_ADPCM_DELTA       16
+
+
+static __inline__ int read_adpcm_block_headers(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    ALmixer_RWops *rw = internal->rw;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    fmt_t *fmt = w->fmt;
+    ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+    int i;
+    int max = fmt->wChannels;
+
+    if (w->bytesLeft < fmt->wBlockAlign)
+    {
+        sample->flags |= SOUND_SAMPLEFLAG_EOF;
+        return(0);
+    } /* if */
+
+    w->bytesLeft -= fmt->wBlockAlign;
+
+    for (i = 0; i < max; i++)
+        BAIL_IF_MACRO(!read_uint8_t(rw, &headers[i].bPredictor), NULL, 0);
+
+    for (i = 0; i < max; i++)
+        BAIL_IF_MACRO(!read_le16(rw, &headers[i].iDelta), NULL, 0);
+
+    for (i = 0; i < max; i++)
+        BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp1), NULL, 0);
+
+    for (i = 0; i < max; i++)
+        BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp2), NULL, 0);
+
+    fmt->fmt.adpcm.samples_left_in_block = fmt->fmt.adpcm.wSamplesPerBlock;
+    fmt->fmt.adpcm.nibble_state = 0;
+    return(1);
+} /* read_adpcm_block_headers */
+
+
+static __inline__ void do_adpcm_nibble(uint8_t nib,
+                                       ADPCMBLOCKHEADER *header,
+                                       int32_t lPredSamp)
+{
+	static const int32_t max_audioval = ((1<<(16-1))-1);
+	static const int32_t min_audioval = -(1<<(16-1));
+	static const int32_t AdaptionTable[] =
+    {
+		230, 230, 230, 230, 307, 409, 512, 614,
+		768, 614, 512, 409, 307, 230, 230, 230
+	};
+
+    int32_t lNewSamp;
+    int32_t delta;
+
+    if (nib & 0x08)
+        lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10));
+	else
+        lNewSamp = lPredSamp + (header->iDelta * nib);
+
+        /* clamp value... */
+    if (lNewSamp < min_audioval)
+        lNewSamp = min_audioval;
+    else if (lNewSamp > max_audioval)
+        lNewSamp = max_audioval;
+
+    delta = ((int32_t) header->iDelta * AdaptionTable[nib]) /
+              FIXED_POINT_ADAPTION_BASE;
+
+	if (delta < SMALLEST_ADPCM_DELTA)
+	    delta = SMALLEST_ADPCM_DELTA;
+
+    header->iDelta = delta;
+	header->iSamp2 = header->iSamp1;
+	header->iSamp1 = lNewSamp;
+} /* do_adpcm_nibble */
+
+
+static __inline__ int decode_adpcm_sample_frame(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    fmt_t *fmt = w->fmt;
+    ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+    ALmixer_RWops *rw = internal->rw;
+    int i;
+    int max = fmt->wChannels;
+    int32_t delta;
+    uint8_t nib = fmt->fmt.adpcm.nibble;
+
+    for (i = 0; i < max; i++)
+    {
+        uint8_t byte;
+        int16_t iCoef1 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef1;
+        int16_t iCoef2 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef2;
+        int32_t lPredSamp = ((headers[i].iSamp1 * iCoef1) +
+                            (headers[i].iSamp2 * iCoef2)) / 
+                             FIXED_POINT_COEF_BASE;
+
+        if (fmt->fmt.adpcm.nibble_state == 0)
+        {
+            BAIL_IF_MACRO(!read_uint8_t(rw, &nib), NULL, 0);
+            fmt->fmt.adpcm.nibble_state = 1;
+            do_adpcm_nibble(nib >> 4, &headers[i], lPredSamp);
+        } /* if */
+        else
+        {
+            fmt->fmt.adpcm.nibble_state = 0;
+            do_adpcm_nibble(nib & 0x0F, &headers[i], lPredSamp);
+        } /* else */
+    } /* for */
+
+    fmt->fmt.adpcm.nibble = nib;
+    return(1);
+} /* decode_adpcm_sample_frame */
+
+
+static __inline__ void put_adpcm_sample_frame1(void *_buf, fmt_t *fmt)
+{
+    uint16_t *buf = (uint16_t *) _buf;
+    ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+    int i;
+    for (i = 0; i < fmt->wChannels; i++)
+        *(buf++) = headers[i].iSamp1;
+} /* put_adpcm_sample_frame1 */
+
+
+static __inline__ void put_adpcm_sample_frame2(void *_buf, fmt_t *fmt)
+{
+    uint16_t *buf = (uint16_t *) _buf;
+    ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+    int i;
+    for (i = 0; i < fmt->wChannels; i++)
+        *(buf++) = headers[i].iSamp2;
+} /* put_adpcm_sample_frame2 */
+
+
+/*
+ * Sound_Decode() lands here for ADPCM-encoded WAVs...
+ */
+static uint32_t read_sample_fmt_adpcm(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    fmt_t *fmt = w->fmt;
+    uint32_t bw = 0;
+
+    while (bw < internal->buffer_size)
+    {
+        /* write ongoing sample frame before reading more data... */
+        switch (fmt->fmt.adpcm.samples_left_in_block)
+        {
+            case 0:  /* need to read a new block... */
+                if (!read_adpcm_block_headers(sample))
+                {
+                    if ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0)
+                        sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+                    return(bw);
+                } /* if */
+
+                /* only write first sample frame for now. */
+                put_adpcm_sample_frame2((uint8_t *) internal->buffer + bw, fmt);
+                fmt->fmt.adpcm.samples_left_in_block--;
+                bw += fmt->sample_frame_size;
+                break;
+
+            case 1:  /* output last sample frame of block... */
+                put_adpcm_sample_frame1((uint8_t *) internal->buffer + bw, fmt);
+                fmt->fmt.adpcm.samples_left_in_block--;
+                bw += fmt->sample_frame_size;
+                break;
+
+            default: /* output latest sample frame and read a new one... */
+                put_adpcm_sample_frame1((uint8_t *) internal->buffer + bw, fmt);
+                fmt->fmt.adpcm.samples_left_in_block--;
+                bw += fmt->sample_frame_size;
+
+                if (!decode_adpcm_sample_frame(sample))
+                {
+                    sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+                    return(bw);
+                } /* if */
+        } /* switch */
+    } /* while */
+
+    return(bw);
+} /* read_sample_fmt_adpcm */
+
+
+/*
+ * Sound_FreeSample() lands here for ADPCM-encoded WAVs...
+ */
+static void free_fmt_adpcm(fmt_t *fmt)
+{
+    if (fmt->fmt.adpcm.aCoef != NULL)
+        free(fmt->fmt.adpcm.aCoef);
+
+    if (fmt->fmt.adpcm.blockheaders != NULL)
+        free(fmt->fmt.adpcm.blockheaders);
+} /* free_fmt_adpcm */
+
+
+static int rewind_sample_fmt_adpcm(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    w->fmt->fmt.adpcm.samples_left_in_block = 0;
+    return(1);
+} /* rewind_sample_fmt_adpcm */
+
+
+static int seek_sample_fmt_adpcm(Sound_Sample *sample, uint32_t ms)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    fmt_t *fmt = w->fmt;
+    uint32_t origsampsleft = fmt->fmt.adpcm.samples_left_in_block;
+    int origpos = ALmixer_RWtell(internal->rw);
+    int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+    int bpb = (fmt->fmt.adpcm.wSamplesPerBlock * fmt->sample_frame_size);
+    int skipsize = (offset / bpb) * fmt->wBlockAlign;
+    int pos = skipsize + fmt->data_starting_offset;
+    int rc = ALmixer_RWseek(internal->rw, pos, SEEK_SET);
+    BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
+
+    /* The offset we need is in this block, so we need to decode to there. */
+    skipsize += (offset % bpb);
+    rc = (offset % bpb);  /* bytes into this block we need to decode */
+    if (!read_adpcm_block_headers(sample))
+    {
+        ALmixer_RWseek(internal->rw, origpos, SEEK_SET);  /* try to make sane. */
+        return(0);
+    } /* if */
+
+    /* first sample frame of block is a freebie. :) */
+    fmt->fmt.adpcm.samples_left_in_block--;
+    rc -= fmt->sample_frame_size;
+    while (rc > 0)
+    {
+        if (!decode_adpcm_sample_frame(sample))
+        {
+            ALmixer_RWseek(internal->rw, origpos, SEEK_SET);
+            fmt->fmt.adpcm.samples_left_in_block = origsampsleft;
+            return(0);
+        } /* if */
+
+        fmt->fmt.adpcm.samples_left_in_block--;
+        rc -= fmt->sample_frame_size;
+    } /* while */
+
+    w->bytesLeft = fmt->total_bytes - skipsize;
+    return(1);  /* success. */
+} /* seek_sample_fmt_adpcm */
+
+
+/*
+ * Read in the adpcm-specific info from disk. This makes this process
+ *  safe regardless of the processor's byte order or how the fmt_t 
+ *  structure is packed.
+ */
+static int read_fmt_adpcm(ALmixer_RWops *rw, fmt_t *fmt)
+{
+    size_t i;
+
+    memset(&fmt->fmt.adpcm, '\0', sizeof (fmt->fmt.adpcm));
+    fmt->free = free_fmt_adpcm;
+    fmt->read_sample = read_sample_fmt_adpcm;
+    fmt->rewind_sample = rewind_sample_fmt_adpcm;
+    fmt->seek_sample = seek_sample_fmt_adpcm;
+
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.cbSize), NULL, 0);
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wSamplesPerBlock), NULL, 0);
+    BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wNumCoef), NULL, 0);
+
+    /* fmt->free() is always called, so these malloc()s will be cleaned up. */
+
+    i = sizeof (ADPCMCOEFSET) * fmt->fmt.adpcm.wNumCoef;
+    fmt->fmt.adpcm.aCoef = (ADPCMCOEFSET *) malloc(i);
+    BAIL_IF_MACRO(fmt->fmt.adpcm.aCoef == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    for (i = 0; i < fmt->fmt.adpcm.wNumCoef; i++)
+    {
+        BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef1), NULL, 0);
+        BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef2), NULL, 0);
+    } /* for */
+
+    i = sizeof (ADPCMBLOCKHEADER) * fmt->wChannels;
+    fmt->fmt.adpcm.blockheaders = (ADPCMBLOCKHEADER *) malloc(i);
+    BAIL_IF_MACRO(fmt->fmt.adpcm.blockheaders == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    return(1);
+} /* read_fmt_adpcm */
+
+
+
+/*****************************************************************************
+ * Everything else...                                                        *
+ *****************************************************************************/
+
+static int WAV_init(void)
+{
+    return(1);  /* always succeeds. */
+} /* WAV_init */
+
+
+static void WAV_quit(void)
+{
+    /* it's a no-op. */
+} /* WAV_quit */
+
+
+static int read_fmt(ALmixer_RWops *rw, fmt_t *fmt)
+{
+    /* if it's in this switch statement, we support the format. */
+    switch (fmt->wFormatTag)
+    {
+        case FMT_NORMAL:
+            SNDDBG(("WAV: Appears to be uncompressed audio.\n"));
+            return(read_fmt_normal(rw, fmt));
+
+        case FMT_ADPCM:
+            SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n"));
+            return(read_fmt_adpcm(rw, fmt));
+
+        /* add other types here. */
+
+        default:
+#ifdef ANDROID_NDK
+            SNDDBG(("WAV: Format is unknown.\n"));
+#else
+            SNDDBG(("WAV: Format 0x%X is unknown.\n",
+                    (unsigned int) fmt->wFormatTag));
+#endif
+            BAIL_MACRO("WAV: Unsupported format", 0);
+    } /* switch */
+
+    assert(0);  /* shouldn't hit this point. */
+    return(0);
+} /* read_fmt */
+
+
+/*
+ * Locate a specific chunk in the WAVE file by ID...
+ */
+static int find_chunk(ALmixer_RWops *rw, uint32_t id)
+{
+    int32_t siz = 0;
+    uint32_t _id = 0;
+    uint32_t pos = ALmixer_RWtell(rw);
+
+    while (1)
+    {
+        BAIL_IF_MACRO(!read_le32(rw, &_id), NULL, 0);
+        if (_id == id)
+            return(1);
+
+            /* skip ahead and see what next chunk is... */
+        BAIL_IF_MACRO(!read_le32(rw, &siz), NULL, 0);
+        assert(siz >= 0);
+        pos += (sizeof (uint32_t) * 2) + siz;
+        if (siz > 0)
+            BAIL_IF_MACRO(ALmixer_RWseek(rw, pos, SEEK_SET) != pos, NULL, 0);
+    } /* while */
+
+    return(0);  /* shouldn't hit this, but just in case... */
+} /* find_chunk */
+
+
+static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    ALmixer_RWops *rw = internal->rw;
+    data_t d;
+    wav_t *w;
+    uint32_t pos;
+
+    BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0);
+    SDL_ReadLE32(rw);  /* throw the length away; we get this info later. */
+    BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0);
+    BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0);
+    BAIL_IF_MACRO(!read_fmt_chunk(rw, fmt), "WAV: Can't read format chunk.", 0);
+
+    sample->actual.channels = (uint8_t) fmt->wChannels;
+    sample->actual.rate = fmt->dwSamplesPerSec;
+    if ((fmt->wBitsPerSample == 4) /*|| (fmt->wBitsPerSample == 0) */ )
+        sample->actual.format = AUDIO_S16SYS;
+    else if (fmt->wBitsPerSample == 8)
+        sample->actual.format = AUDIO_U8;
+    else if (fmt->wBitsPerSample == 16)
+        sample->actual.format = AUDIO_S16LSB;
+    else
+    {
+#ifdef ANDROID_NDK
+       SNDDBG(("WAV: unsupported sample size.\n"));
+#else
+        SNDDBG(("WAV: %d bits per sample!?\n", (int) fmt->wBitsPerSample));
+#endif
+        BAIL_MACRO("WAV: Unsupported sample size.", 0);
+    } /* else */
+
+    BAIL_IF_MACRO(!read_fmt(rw, fmt), NULL, 0);
+    ALmixer_RWseek(rw, fmt->next_chunk_offset, SEEK_SET);
+    BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0);
+    BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0);
+
+    w = (wav_t *) malloc(sizeof(wav_t));
+    BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0);
+    w->fmt = fmt;
+    fmt->total_bytes = w->bytesLeft = d.chunkSize;
+    fmt->data_starting_offset = ALmixer_RWtell(rw);
+    fmt->sample_frame_size = ( ((sample->actual.format & 0xFF) / 8) *
+                               sample->actual.channels );
+    internal->decoder_private = (void *) w;
+
+    internal->total_time = (fmt->total_bytes / fmt->dwAvgBytesPerSec) * 1000;
+    internal->total_time += (fmt->total_bytes % fmt->dwAvgBytesPerSec)
+                              *  1000 / fmt->dwAvgBytesPerSec;
+
+    sample->flags = SOUND_SAMPLEFLAG_NONE;
+    if (fmt->seek_sample != NULL)
+        sample->flags |= SOUND_SAMPLEFLAG_CANSEEK;
+
+    SNDDBG(("WAV: Accepting data stream.\n"));
+    return(1); /* we'll handle this data. */
+} /* WAV_open_internal */
+
+
+static int WAV_open(Sound_Sample *sample, const char *ext)
+{
+    int rc;
+
+    fmt_t *fmt = (fmt_t *) malloc(sizeof (fmt_t));
+    BAIL_IF_MACRO(fmt == NULL, ERR_OUT_OF_MEMORY, 0);
+    memset(fmt, '\0', sizeof (fmt_t));
+
+    rc = WAV_open_internal(sample, ext, fmt);
+    if (!rc)
+    {
+        if (fmt->free != NULL)
+            fmt->free(fmt);
+        free(fmt);
+    } /* if */
+
+    return(rc);
+} /* WAV_open */
+
+
+static void WAV_close(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+
+    if (w->fmt->free != NULL)
+        w->fmt->free(w->fmt);
+
+    free(w->fmt);
+    free(w);
+} /* WAV_close */
+
+
+static uint32_t WAV_read(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    return(w->fmt->read_sample(sample));
+} /* WAV_read */
+
+
+static int WAV_rewind(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    fmt_t *fmt = w->fmt;
+    int rc = ALmixer_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET);
+    BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0);
+    w->bytesLeft = fmt->total_bytes;
+    return(fmt->rewind_sample(sample));
+} /* WAV_rewind */
+
+
+static int WAV_seek(Sound_Sample *sample, uint32_t ms)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    wav_t *w = (wav_t *) internal->decoder_private;
+    return(w->fmt->seek_sample(sample, ms));
+} /* WAV_seek */
+
+#endif /* SOUND_SUPPORTS_WAV */
+
+/* end of wav.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SimpleMutex.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,155 @@
+#include "SimpleMutex.h"
+#include <stdlib.h>
+
+#if defined(DEBUG)
+#include <stdio.h>
+#define MUTEXDBG(x) printf x
+#else
+#define MUTEXDBG(x)
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN32__)
+		#include <windows.h>
+		#include <winbase.h> /* For CreateMutex(), LockFile() */
+
+		struct SimpleMutex
+		{
+			HANDLE nativeMutex;
+		};
+
+
+		SimpleMutex* SimpleMutex_CreateMutex()
+		{
+			SimpleMutex* simple_mutex = (SimpleMutex*)malloc(sizeof(SimpleMutex));
+			if(NULL == simple_mutex)
+			{
+				MUTEXDBG(("Out of memory.\n"));				
+				return NULL;		
+			}
+			simple_mutex->nativeMutex = CreateMutex(NULL, FALSE, NULL);
+			if(NULL == simple_mutex->nativeMutex)
+			{
+				MUTEXDBG(("Out of memory.\n"));				
+				free(simple_mutex);
+				return NULL;		
+			}
+			return simple_mutex;
+		}
+		void SimpleMutex_DestroyMutex(SimpleMutex* simple_mutex)
+		{
+			if(NULL == simple_mutex)
+			{
+				return;
+			}
+			CloseHandle(simple_mutex->nativeMutex);
+			free(simple_mutex);
+		}
+		/* This will return true if locking is successful, false if not.
+		 */
+		int SimpleMutex_LockMutex(SimpleMutex* simple_mutex)
+		{
+#ifdef DEBUG
+			if(NULL == simple_mutex)
+			{
+				MUTEXDBG(("SimpleMutex_LockMutex was passed NULL\n"));	
+				return 0;
+			}
+#endif
+			return(
+				WaitForSingleObject(
+					simple_mutex->nativeMutex,
+					INFINITE
+				) != WAIT_FAILED
+			);
+		}
+		void SimpleMutex_UnlockMutex(SimpleMutex* simple_mutex)
+		{
+#ifdef DEBUG
+			if(NULL == simple_mutex)
+			{
+				MUTEXDBG(("SimpleMutex_UnlockMutex was passed NULL\n"));	
+				return;
+			}
+#endif
+			ReleaseMutex(
+				simple_mutex->nativeMutex
+			);
+		}
+#else /* Assuming POSIX...maybe not a good assumption. */
+		#include <pthread.h>
+
+		struct SimpleMutex
+		{
+			pthread_mutex_t* nativeMutex;
+		};
+
+		SimpleMutex* SimpleMutex_CreateMutex()
+		{
+			int ret_val;
+			SimpleMutex* simple_mutex = (SimpleMutex*)malloc(sizeof(SimpleMutex));
+			if(NULL == simple_mutex)
+			{
+				MUTEXDBG(("Out of memory.\n"));				
+				return NULL;		
+			}
+			simple_mutex->nativeMutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
+			if(NULL == simple_mutex->nativeMutex)
+			{
+				MUTEXDBG(("Out of memory.\n"));
+				free(simple_mutex);
+				return NULL;		
+			}
+
+			ret_val = pthread_mutex_init(simple_mutex->nativeMutex, NULL);
+			if(0 != ret_val)
+			{
+				free(simple_mutex->nativeMutex);
+				free(simple_mutex);
+				return NULL;
+			}
+			return simple_mutex;
+		}
+		void SimpleMutex_DestroyMutex(SimpleMutex* simple_mutex)
+		{
+			if(NULL != simple_mutex)
+			{
+				pthread_mutex_destroy(simple_mutex->nativeMutex);
+				free(simple_mutex->nativeMutex);
+				free(simple_mutex);
+			}
+		}
+		/* This will return true if locking is successful, false if not.
+		 * (This is the opposite of pthread_mutex_lock which returns 
+		 * 0 for success.)
+		 */
+		int SimpleMutex_LockMutex(SimpleMutex* simple_mutex)
+		{
+#ifdef DEBUG
+			if(NULL == simple_mutex)
+			{
+				MUTEXDBG(("SimpleMutex_LockMutex was passed NULL\n"));	
+				return 0;
+			}
+#endif
+			return(
+				pthread_mutex_lock(
+					simple_mutex->nativeMutex
+				) == 0
+			);
+		}
+		void SimpleMutex_UnlockMutex(SimpleMutex* simple_mutex)
+		{
+#ifdef DEBUG			
+			if(NULL == simple_mutex)
+			{
+				MUTEXDBG(("SimpleMutex_LockMutex was passed NULL\n"));	
+				return;
+			}
+#endif
+			pthread_mutex_unlock(
+				simple_mutex->nativeMutex
+			);
+		}
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SimpleMutex.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,25 @@
+/* Copyright: Eric Wing 2003 */
+
+#ifndef SIMPLE_MUTEX_H
+#define SIMPLE_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	
+
+typedef struct SimpleMutex SimpleMutex;
+
+SimpleMutex* SimpleMutex_CreateMutex(void);
+void SimpleMutex_DestroyMutex(SimpleMutex* simple_mutex);
+int SimpleMutex_LockMutex(SimpleMutex* simple_mutex);
+void SimpleMutex_UnlockMutex(SimpleMutex* simple_mutex);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SimpleThread.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,30 @@
+#ifndef SIMPLE_THREAD
+#define SIMPLE_THREAD
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	
+#include <stddef.h>
+
+typedef struct SimpleThread SimpleThread;
+
+
+SimpleThread* SimpleThread_CreateThread(int (*user_function)(void*), void* user_data);
+
+size_t SimpleThread_GetCurrentThreadID(void);
+size_t SimpleThread_GetThreadID(SimpleThread* simple_thread);
+
+void SimpleThread_WaitThread(SimpleThread* simple_thread, int* thread_status);
+
+
+int SimpleThread_GetThreadPriority(SimpleThread* simple_thread);
+void SimpleThread_SetThreadPriority(SimpleThread* simple_thread, int priority_level);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SimpleThreadPosix.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,214 @@
+#include "SimpleThread.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <signal.h>
+
+#if defined(DEBUG)
+#include <stdio.h>
+#define THRDDBG(x) printf x
+#else
+#define THRDDBG(x)
+#endif
+
+
+struct SimpleThread
+{
+	size_t threadID;
+	pthread_t nativeThread;
+	int threadStatus;
+//    void* userData;	
+};
+
+typedef struct SimpleThreadArguments
+{
+    int (*userFunction)(void*);
+    void* userData;
+    SimpleThread* simpleThread;
+} SimpleThreadArguments;
+
+
+
+static void* Internal_RunThread(void* user_data)
+{
+	int (*user_function)(void*);
+	void* function_user_data;
+	int* status_val;
+
+#if 0
+	/* disable signals */
+	sigset_t disable_set;
+
+	/*
+	   in the main thread, set up the desired signal mask, common to most threads
+	   any newly created threads will inherit this signal mask
+	   */
+	sigemptyset(&disable_set);
+	sigaddset(&disable_set, SIGHUP);
+	sigaddset(&disable_set, SIGINT);
+	sigaddset(&disable_set, SIGUSR1);
+	sigaddset(&disable_set, SIGUSR2);
+	sigaddset(&disable_set, SIGALRM);
+	sigaddset(&disable_set, SIGQUIT);
+	sigaddset(&disable_set, SIGPIPE);
+	sigaddset(&disable_set, SIGTERM);
+	sigaddset(&disable_set, SIGCHLD);
+	sigaddset(&disable_set, SIGWINCH);
+	sigaddset(&disable_set, SIGVTALRM);
+	sigaddset(&disable_set, SIGPROF);
+
+
+	/* block out these signals */
+	sigprocmask(SIG_BLOCK, &disable_set, NULL);
+#endif
+
+	SimpleThreadArguments* simple_thread_arguments = (SimpleThreadArguments*)user_data;
+	simple_thread_arguments->simpleThread->threadID = SimpleThread_GetCurrentThreadID();
+
+	user_function = simple_thread_arguments->userFunction;
+	function_user_data = simple_thread_arguments->userData;
+	status_val = &simple_thread_arguments->simpleThread->threadStatus;
+
+	
+	/* I hope this is safe to delete on a different thread than it was created for. */
+	free(simple_thread_arguments);
+
+	*status_val = user_function(function_user_data);
+
+	pthread_exit(NULL);
+	return NULL;
+}
+
+
+SimpleThread* SimpleThread_CreateThread(int (*user_function)(void*), void* user_data)
+{
+	pthread_attr_t thread_attributes;
+	int ret_val;
+	SimpleThread* new_thread;
+	SimpleThreadArguments* simple_thread_arguments;
+
+	new_thread = (SimpleThread*)malloc(sizeof(SimpleThread));
+	if(NULL == new_thread)
+	{
+		THRDDBG(("Out of memory.\n"));				
+		return NULL;
+	}
+
+	ret_val = pthread_attr_init(&thread_attributes);
+	if(0 != ret_val)
+	{
+		/* failed */
+		THRDDBG(("pthread_attr_init failed with: %d\n", ret_val));		
+		free(new_thread);
+		return 0;
+	}
+	ret_val = pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
+	if(0 != ret_val)
+	{
+		THRDDBG(("pthread_attr_setdetachstate failed with: %d\n", ret_val));
+		free(new_thread);
+		return NULL;
+	}
+
+	simple_thread_arguments = (SimpleThreadArguments*)malloc(sizeof(SimpleThreadArguments));
+	if(NULL == simple_thread_arguments)
+	{
+		THRDDBG(("Out of memory.\n"));
+		free(new_thread);		
+		return NULL;
+	}
+	simple_thread_arguments->userFunction = user_function;
+	simple_thread_arguments->userData = user_data;
+	simple_thread_arguments->simpleThread = new_thread;
+
+	ret_val = pthread_create(&new_thread->nativeThread, &thread_attributes, Internal_RunThread, simple_thread_arguments);
+	if(0 != ret_val)
+	{
+		THRDDBG(("pthread_create failed with: %d\n", ret_val));
+		free(simple_thread_arguments);		
+		free(new_thread);		
+		return NULL;
+	}
+	
+	return new_thread;
+}
+
+
+
+size_t SimpleThread_GetCurrentThreadID()
+{
+    return (size_t)pthread_self();
+}
+
+void SimpleThread_WaitThread(SimpleThread* simple_thread, int* thread_status)
+{
+	int ret_val;	
+	if(NULL == simple_thread)
+	{
+		THRDDBG(("SimpleThread_WaitThread was passed NULL\n"));	
+		return;
+	}
+
+
+    ret_val = pthread_join(simple_thread->nativeThread, 0);
+	if(0 != ret_val)
+	{
+		THRDDBG(("pthread_join failed with: %d\n", ret_val));
+	}
+	if(NULL != thread_status)
+	{
+		*thread_status = simple_thread->threadStatus;
+	}
+	free(simple_thread);
+}
+
+size_t SimpleThread_GetThreadID(SimpleThread* simple_thread)
+{
+	if(NULL == simple_thread)
+	{
+		THRDDBG(("SimpleThread_GetThreadID was passed NULL\n"));	
+		return 0;
+	}
+	return simple_thread->threadID;
+}
+
+
+int SimpleThread_GetThreadPriority(SimpleThread* simple_thread)
+{
+	struct sched_param schedule_param;
+	int sched_policy;
+	int ret_val;
+	
+	if(NULL == simple_thread)
+	{
+		THRDDBG(("SimpleThread_GetThreadPriority was passed NULL\n"));	
+		return -1; /* Not sure what to return. Do other platforms use negative numbers? */
+	}
+	ret_val = pthread_getschedparam(simple_thread->nativeThread, &sched_policy, &schedule_param);
+	if(0 != ret_val)
+	{
+		THRDDBG(("SimpleThread_GetThreadPriority pthread_getschedparam failed with: %d\n", ret_val));
+		return -1;
+	}
+	return schedule_param.sched_priority;
+}
+
+void SimpleThread_SetThreadPriority(SimpleThread* simple_thread, int priority_level)
+{
+	struct sched_param schedule_param;
+	int ret_val;
+	
+	if(NULL == simple_thread)
+	{
+		THRDDBG(("SimpleThread_SetThreadPriority was passed NULL\n"));	
+		return;
+	}
+	schedule_param.sched_priority = priority_level; /* PTHREAD_MIN_PRIORITY=0 to PTHREAD_MAX_PRIORITY=31 */
+	ret_val = pthread_setschedparam(simple_thread->nativeThread, SCHED_OTHER, &schedule_param);
+	if(0 != ret_val)
+	{
+		THRDDBG(("SimpleThread_SetThreadPriority pthread_setschedparam failed with: %d\n", ret_val));
+		return;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SoundDecoder.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,711 @@
+#ifndef ALMIXER_COMPILED_WITH_SDL
+
+#include "SoundDecoder.h"
+#include "SoundDecoder_Internal.h"
+#include "tErrorLib.h"
+#include "LinkedList.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef ANDROID_NDK
+#include <android/log.h>
+#endif
+
+/* A partial shim reimplementation of SDL_sound to work around the LGPL issues.
+ * This implementation is more limited than SDL_sound. 
+ * For example, there is no generic software conversion routines.
+ * Functions are also not necessarily thread safe.
+ * This implementation relies on the back-end decoder much more heavily 
+ * than SDL_sound. (For example, I bypass the internal->buffer.)
+ */
+
+static LinkedList* s_listOfLoadedSamples = NULL;
+
+static signed char s_isInitialized = 0;
+static TErrorPool* s_errorPool = NULL;
+
+static const SoundDecoder_DecoderInfo** s_availableDecoders = NULL;
+
+#ifdef __APPLE__
+//extern const SoundDecoder_DecoderFunctions __SoundDecoder_DecoderFunctions_CoreAudio;
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_CoreAudio;
+#endif
+#ifdef ANDROID_NDK
+#ifdef SOUND_SUPPORTS_WAV
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV;
+#endif
+#ifdef SOUND_SUPPORTS_MPG123
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MPG123;
+#endif
+#ifdef SOUND_SUPPORTS_OGG
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG;
+#endif
+#endif
+
+typedef struct
+{
+    int available;
+    const SoundDecoder_DecoderFunctions* funcs;
+} SoundElement;
+
+static SoundElement s_linkedDecoders[] =
+{
+#if defined(__APPLE__)
+    { 0, &__Sound_DecoderFunctions_CoreAudio },
+#endif
+#if defined(ANDROID_NDK)
+#ifdef SOUND_SUPPORTS_WAV
+    { 0, &__Sound_DecoderFunctions_WAV },
+#endif
+#ifdef SOUND_SUPPORTS_MPG123
+    { 0, &__Sound_DecoderFunctions_MPG123 },
+#endif
+#ifdef SOUND_SUPPORTS_OGG
+    { 0, &__Sound_DecoderFunctions_OGG },
+#endif
+#endif
+    { 0, NULL }
+};
+
+
+#include <ctype.h>
+int SoundDecoder_strcasecmp(const char* str1, const char* str2)
+{
+	int the_char1;
+	int the_char2;
+	int i = 0;
+	if(str1 == str2)
+	{
+		return 0;
+	}
+	if(NULL == str1)
+	{
+		return -1;
+	}
+	if(NULL == str2)
+	{
+		return 1;
+	}
+
+	do
+	{
+		the_char1 = tolower(str1[i]);
+		the_char2 = tolower(str2[i]);
+		if(the_char1 < the_char2)
+		{
+			return -1;
+		}
+		else if(the_char1 > the_char2)
+		{
+			return 1;
+		}
+		i++;
+	} while( (0 != the_char1) && (0 != the_char2) );
+
+	return 0;
+}
+
+
+#ifdef ANDROID_NDK
+#include <stdarg.h>
+#include <android/log.h>
+int SoundDecoder_DebugPrint(const char* format, ...)
+{
+	va_list arg_list; 
+	int ret_val;
+
+	va_start(arg_list, format); 
+	ret_val = __android_log_vprint(ANDROID_LOG_INFO, "SoundDecoder", format, arg_list); 
+	va_end(arg_list);
+	return ret_val;
+}
+#endif
+
+const char* SoundDecoder_GetError()
+{
+	const char* error_string = NULL;
+	if(NULL == s_errorPool)
+	{
+		return "Error: You should not call SoundDecoder_GetError while Sound is not initialized";
+	}
+	error_string = TError_GetLastErrorStr(s_errorPool);
+	/* SDL returns empty strings instead of NULL */
+	if(NULL == error_string)
+	{
+		return "";
+	}
+	else
+	{
+		return error_string;
+	}
+}
+
+void SoundDecoder_ClearError()
+{
+	if(NULL == s_errorPool)
+	{
+		return;
+	}
+	TError_SetError(s_errorPool, 0, NULL);
+}
+
+void SoundDecoder_SetError(const char* err_str, ...)
+{
+	if(NULL == s_errorPool)
+	{
+		fprintf(stderr, "Error: You should not call SoundDecoder_SetError while Sound is not initialized\n");
+		return;
+	}
+	va_list argp;
+	va_start(argp, err_str);
+	// SDL_SetError which I'm emulating has no number parameter.
+	TError_SetErrorv(s_errorPool, 1, err_str, argp);
+	va_end(argp);
+#ifdef ANDROID_NDK
+	__android_log_print(ANDROID_LOG_INFO, "SoundDecoder_SetError", TError_GetLastErrorStr(s_errorPool));
+#endif
+}
+
+
+void SoundDecoder_GetLinkedVersion(SoundDecoder_Version* the_version)
+{
+	if(NULL != the_version)
+	{
+		the_version->major = SOUNDDECODER_VER_MAJOR;
+		the_version->minor = SOUNDDECODER_VER_MINOR;
+		the_version->patch = SOUNDDECODER_VER_PATCH;
+	}
+}
+
+
+const SoundDecoder_DecoderInfo** SoundDecoder_AvailableDecoders()
+{
+    return(s_availableDecoders);
+}
+
+int SoundDecoder_Init()
+{
+	size_t total_number_of_decoders;
+	size_t i;
+	size_t current_pos = 0;	
+	if(1 == s_isInitialized)
+	{
+		return 1;
+	}
+	if(NULL == s_errorPool)
+	{
+		s_errorPool = TError_CreateErrorPool();
+	}
+	if(NULL == s_errorPool)
+	{
+		return 0;
+	}
+
+	total_number_of_decoders = sizeof(s_linkedDecoders) / sizeof(s_linkedDecoders[0]);
+	s_availableDecoders = (const SoundDecoder_DecoderInfo **)malloc((total_number_of_decoders) * sizeof(SoundDecoder_DecoderInfo*));
+	if(NULL == s_availableDecoders)
+	{
+		SoundDecoder_SetError(ERR_OUT_OF_MEMORY);
+		return 0;
+	}
+
+	/* Allocate memory for linked list of sound samples. */
+	s_listOfLoadedSamples = LinkedList_Create();
+	if(NULL == s_listOfLoadedSamples)
+	{
+		free(s_availableDecoders);
+		s_availableDecoders = NULL;
+		SoundDecoder_SetError(ERR_OUT_OF_MEMORY);
+		return 0;
+	}
+
+	for(i = 0; s_linkedDecoders[i].funcs != NULL; i++)
+	{
+		s_linkedDecoders[i].available = s_linkedDecoders[i].funcs->init();
+		if(s_linkedDecoders[i].available)
+		{
+			s_availableDecoders[current_pos] = &(s_linkedDecoders[i].funcs->info);
+			current_pos++;
+		}
+	}
+
+	s_availableDecoders[current_pos] = NULL;
+	s_isInitialized = 1;
+	return 1;
+}
+
+void SoundDecoder_Quit()
+{
+    size_t i;	
+	if(0 == s_isInitialized)
+	{
+		return;
+	}
+
+	/* 
+	 * SDL_sound actually embeds the linked list in the internal data structure.
+	 * So any sample can potentially reach any other sample.
+	 * But I'm keeping my own separate list.
+	 */
+	while(LinkedList_Size(s_listOfLoadedSamples) > 0)
+	{
+		SoundDecoder_Sample* sound_sample = (SoundDecoder_Sample*)LinkedList_PopBack(s_listOfLoadedSamples);
+		SoundDecoder_FreeSample(sound_sample);
+	}
+	LinkedList_Free(s_listOfLoadedSamples);
+	s_listOfLoadedSamples = NULL;
+
+	
+    for(i = 0; s_linkedDecoders[i].funcs != NULL; i++)
+    {
+        if (s_linkedDecoders[i].available)
+        {
+            s_linkedDecoders[i].funcs->quit();
+            s_linkedDecoders[i].available = 0;
+        }
+    }
+
+    if(NULL != s_availableDecoders)
+	{
+        free(s_availableDecoders);
+	}
+	s_availableDecoders = NULL;
+
+
+	/* Remember: ALmixer_SetError/GetError calls will not work while this is gone. */
+	TError_FreeErrorPool(s_errorPool);
+	s_errorPool = NULL;
+
+	s_isInitialized = 0;	
+}
+
+
+void SoundDecoder_FreeSample(SoundDecoder_Sample* sound_sample)
+{
+	SoundDecoder_SampleInternal* sample_internal;
+
+	/* Quit unloads all samples, so it is not possible to free a sample
+	 * when not initialized.
+	 */
+	if(0 == s_isInitialized)
+	{
+		return;
+	}
+
+	if(sound_sample == NULL)
+	{
+		return;
+	}
+
+	/* SDL_sound keeps a linked list of all the loaded samples.
+	 * We want to remove the current sample from that list.
+	 */
+	LinkedListNode* the_node = LinkedList_Find(s_listOfLoadedSamples, sound_sample, NULL);
+	if(NULL == the_node)
+	{
+		SoundDecoder_SetError("SoundDecoder_FreeSample: Internal Error, sample does not exist in linked list.");
+		return;
+	}
+	LinkedList_Remove(s_listOfLoadedSamples, the_node);
+
+	sample_internal = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+
+	/* Ugh...SDL_sound has a lot of pointers. 
+	 * I hope I didn't miss any dynamic memory.
+	 */
+
+	/* Call close on the decoder */
+	sample_internal->funcs->close(sound_sample);
+
+	if(NULL != sample_internal->rw)
+	{
+		sample_internal->rw->close(sample_internal->rw);
+	}
+
+	/* Ooops. The public buffer might be shared with the internal buffer.
+	 * Make sure to not accidentally double delete.
+	 */
+	if((NULL != sample_internal->buffer)
+		&& (sample_internal->buffer != sound_sample->buffer)
+	)
+	{
+		free(sample_internal->buffer);
+	}
+	free(sample_internal);
+
+	if(NULL != sound_sample->buffer)
+	{
+		free(sound_sample->buffer);
+	}
+	free(sound_sample);
+}
+
+
+
+static int Internal_LoadSample(const SoundDecoder_DecoderFunctions *funcs,
+	SoundDecoder_Sample* sound_sample, const char *ext
+)
+{
+    SoundDecoder_SampleInternal* internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+    long current_file_position = internal_sample->rw->seek(internal_sample->rw, 0, SEEK_CUR);
+
+    /* fill in the funcs for this decoder... */
+    sound_sample->decoder = &funcs->info;
+	internal_sample->funcs = funcs;
+	if (!funcs->open(sound_sample, ext))
+	{
+		internal_sample->rw->seek(internal_sample->rw, current_file_position, SEEK_SET);
+		return 0;
+	}
+
+	/* we found a compatible decoder */
+
+	/* SDL_sound normally goes on to setup a bunch of things to 
+	 * support format conversion via SDL APIs.
+	 * I am not porting any of that stuff.
+	 * My goal is to simply setup the struct properties to values
+	 * that will not cause any confusion with other parts of the implementation.
+	 */
+
+
+	if(0 == sound_sample->desired.format)
+	{
+		sound_sample->desired.format = sound_sample->actual.format;
+	}
+	if(0 == sound_sample->desired.channels)
+	{
+		sound_sample->desired.channels = sound_sample->actual.channels;
+	}
+	if(0 == sound_sample->desired.rate)
+	{
+		sound_sample->desired.rate = sound_sample->actual.rate;
+	}
+
+	/* I'm a little confused at the difference between the internal
+	 * public buffer. I am going to make them the same.
+	 * I assume I already allocated the public buffer.
+	 */
+	internal_sample->buffer = sound_sample->buffer;
+	internal_sample->buffer_size = sound_sample->buffer_size;
+
+	/* Insert the new sample into the linked list of samples. */
+	LinkedList_PushBack(s_listOfLoadedSamples, sound_sample);
+	
+	return 1;
+}
+
+
+
+SoundDecoder_Sample* SoundDecoder_NewSampleFromFile(const char* file_name,
+                                      SoundDecoder_AudioInfo* desired_format,
+                                      size_t buffer_size)
+{
+	
+    const char* file_extension;
+    ALmixer_RWops* rw_ops;
+
+
+	if(0 == s_isInitialized)
+	{
+		SoundDecoder_SetError(ERR_NOT_INITIALIZED);
+		return NULL;
+	}
+	if(NULL == file_name)
+	{
+		SoundDecoder_SetError("No file specified");
+		return NULL;
+	}
+
+    file_extension = strrchr(file_name, '.');
+	if(NULL != file_extension)
+	{
+        file_extension++;
+	}
+
+    rw_ops = ALmixer_RWFromFile(file_name, "rb");
+
+     return SoundDecoder_NewSample(rw_ops, file_extension, desired_format, buffer_size);
+}
+
+
+SoundDecoder_Sample* SoundDecoder_NewSample(ALmixer_RWops* rw_ops, const char* file_extension, SoundDecoder_AudioInfo* desired_format, size_t buffer_size)
+{
+    SoundDecoder_Sample* new_sample;
+    SoundDecoder_SampleInternal* internal_sample;
+    SoundElement* current_decoder;
+
+	if(0 == s_isInitialized)
+	{
+		SoundDecoder_SetError(ERR_NOT_INITIALIZED);
+		return NULL;
+	}
+	if(NULL == rw_ops)
+	{
+		SoundDecoder_SetError("No file specified");
+		return NULL;
+	}
+
+	new_sample = (SoundDecoder_Sample*)calloc(1, sizeof(SoundDecoder_Sample));
+	if(NULL == new_sample)
+	{
+		SoundDecoder_SetError(ERR_OUT_OF_MEMORY);
+		return NULL;
+	}
+	internal_sample = (SoundDecoder_SampleInternal*)calloc(1, sizeof(SoundDecoder_SampleInternal));
+	if(NULL == internal_sample)
+	{
+		free(new_sample);
+		SoundDecoder_SetError(ERR_OUT_OF_MEMORY);
+		return NULL;
+	}
+	new_sample->buffer = calloc(1, buffer_size);
+	if(NULL == new_sample->buffer)
+	{
+		free(internal_sample);
+		free(new_sample);
+		SoundDecoder_SetError(ERR_OUT_OF_MEMORY);
+		return NULL;
+	}
+
+	new_sample->buffer_size = buffer_size;
+
+    if(NULL != desired_format)
+	{
+		memcpy(&new_sample->desired, desired_format, sizeof(SoundDecoder_AudioInfo));
+	}
+
+	internal_sample->rw = rw_ops;
+	new_sample->opaque = internal_sample;
+
+
+    if(NULL != file_extension)
+    {
+        for(current_decoder = &s_linkedDecoders[0]; current_decoder->funcs != NULL; current_decoder++)
+        {
+            if(current_decoder->available)
+            {
+                const char** decoder_file_extension = current_decoder->funcs->info.extensions;
+                while(*decoder_file_extension)
+                {
+                    if(0 == (SoundDecoder_strcasecmp(*decoder_file_extension, file_extension)))
+                    {
+                        if(Internal_LoadSample(current_decoder->funcs, new_sample, file_extension))
+						{
+							return(new_sample);
+						}
+                        break;  /* go to the next decoder */ 
+                    }
+					decoder_file_extension++;
+                }
+            }
+        }
+    }
+
+    /* no direct file_extensionension match? Try everything we've got... */
+	for(current_decoder = &s_linkedDecoders[0]; current_decoder->funcs != NULL; current_decoder++)
+	{
+		if(current_decoder->available)
+		{
+			int already_tried_decoder = 0;
+			const char** decoder_file_extension = current_decoder->funcs->info.extensions;
+
+			/* skip decoders we already tried from the above loop */
+			while(*decoder_file_extension)
+			{
+				if(SoundDecoder_strcasecmp(*decoder_file_extension, file_extension) == 0)
+				{
+					already_tried_decoder = 1;
+					break;
+				}
+				decoder_file_extension++;
+			}
+
+			if(0 == already_tried_decoder)
+			{
+				if (Internal_LoadSample(current_decoder->funcs, new_sample, file_extension))
+				{
+					return new_sample;
+				}
+			}
+		}
+	}
+
+	/* could not find a decoder */
+	SoundDecoder_SetError(ERR_UNSUPPORTED_FORMAT);
+	/* clean up the memory */
+	free(new_sample->opaque);
+	if(NULL != new_sample->buffer)
+	{
+		free(new_sample->buffer);
+	}
+	free(new_sample);
+	
+	rw_ops->close(rw_ops);
+	return NULL;
+}
+
+
+int SoundDecoder_SetBufferSize(SoundDecoder_Sample* sound_sample, size_t new_buffer_size)
+{
+	SoundDecoder_SampleInternal* internal_sample = NULL;
+	void* new_buffer_ptr = NULL;
+
+    BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0);
+	BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0);
+
+    internal_sample = ((SoundDecoder_SampleInternal*)sound_sample->opaque);
+
+
+    new_buffer_ptr = realloc(sound_sample->buffer, new_buffer_size);
+    BAIL_IF_MACRO(NULL == new_buffer_ptr, ERR_OUT_OF_MEMORY, 0);
+
+	sound_sample->buffer = new_buffer_ptr;
+    sound_sample->buffer_size = new_buffer_size;
+	internal_sample->buffer = sound_sample->buffer;
+	internal_sample->buffer_size = sound_sample->buffer_size;
+
+    return 1;
+}
+
+
+size_t SoundDecoder_Decode(SoundDecoder_Sample* sound_sample)
+{
+    SoundDecoder_SampleInternal* internal_sample = NULL;
+    size_t bytes_read = 0;
+
+    BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0);
+	BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0);
+	BAIL_IF_MACRO(sound_sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREVIOUS_SAMPLE_ERROR, 0);
+	BAIL_IF_MACRO(sound_sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_ALREADY_AT_EOF_ERROR, 0);
+
+    internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+
+    assert(sound_sample->buffer != NULL);
+    assert(sound_sample->buffer_size > 0);
+    assert(internal_sample->buffer != NULL);
+    assert(internal_sample->buffer_size > 0);
+
+ 	/* reset EAGAIN. Decoder can flip it back on if it needs to. */
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
+    bytes_read = internal_sample->funcs->read(sound_sample);
+    return bytes_read;
+}
+
+
+size_t SoundDecoder_DecodeAll(SoundDecoder_Sample* sound_sample)
+{
+    SoundDecoder_SampleInternal* internal_sample = NULL;
+    void* data_buffer = NULL;
+    size_t updated_buffer_size = 0;
+
+    BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0);
+	BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0);
+
+	/* My original thought was to call SetBufferSize and resize to 
+	 * the size needed to hold the entire decoded file utilizing total_time,
+	 * but it appears SDL_sound simply loops on SoundDecoder_Decode.
+	 * I suppose it is possible to partially decode or seek a file, and then
+	 * call DecodeAll so you won't have the whole thing in which case
+	 * my idea would waste memory.
+	 */
+    while( (0 == (sound_sample->flags & SOUND_SAMPLEFLAG_EOF) )
+		&& (0 == (sound_sample->flags & SOUND_SAMPLEFLAG_ERROR))
+	)
+    {
+        size_t bytes_decoded = SoundDecoder_Decode(sound_sample);
+        void* realloced_ptr = realloc(data_buffer, updated_buffer_size + bytes_decoded);
+        if(NULL == realloced_ptr)
+        {
+            sound_sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+            SoundDecoder_SetError(ERR_OUT_OF_MEMORY);
+			if(NULL != data_buffer)
+			{
+				free(data_buffer);
+			}
+			return bytes_decoded;
+        }
+		data_buffer = realloced_ptr;
+		/* copy the chunk of decoded PCM to the end of our new data buffer */
+		memcpy( ((char*)data_buffer) + updated_buffer_size, sound_sample->buffer, bytes_decoded );
+		updated_buffer_size += bytes_decoded;
+    }
+
+    internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+	if(internal_sample->buffer != sound_sample->buffer)
+	{
+		free(internal_sample->buffer);
+	}
+    free(sound_sample->buffer);
+
+	sound_sample->buffer = data_buffer;
+	sound_sample->buffer_size = updated_buffer_size;
+	internal_sample->buffer = sound_sample->buffer;
+	internal_sample->buffer_size = sound_sample->buffer_size;
+
+    return sound_sample->buffer_size;
+}
+
+
+int SoundDecoder_Rewind(SoundDecoder_Sample* sound_sample)
+{
+    SoundDecoder_SampleInternal* internal_sample;
+	int ret_val;
+	
+    BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0);
+	BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0);
+
+    internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+	ret_val = internal_sample->funcs->rewind(sound_sample);
+    if(0 == ret_val)
+    {
+        sound_sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+		SoundDecoder_SetError("Rewind failed");		
+        return 0;
+    }
+	/* reset flags */
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_ERROR;
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_EOF;
+
+    return 1;
+}
+
+
+int SoundDecoder_Seek(SoundDecoder_Sample* sound_sample, size_t ms)
+{
+    SoundDecoder_SampleInternal* internal_sample;
+	int ret_val;
+
+    BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0);
+	BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0);
+	
+	BAIL_IF_MACRO(!(sound_sample->flags & SOUND_SAMPLEFLAG_CANSEEK), "Sound sample is not seekable", 0);
+
+    internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+	ret_val = internal_sample->funcs->seek(sound_sample, ms);
+	if(0 == ret_val)
+	{
+        sound_sample->flags |= SOUND_SAMPLEFLAG_ERROR;		
+		SoundDecoder_SetError("Seek failed");
+		return 0;
+	}
+	/* reset flags */
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_ERROR;
+    sound_sample->flags &= ~SOUND_SAMPLEFLAG_EOF;
+
+    return 1;
+}
+
+
+ptrdiff_t SoundDecoder_GetDuration(SoundDecoder_Sample* sound_sample)
+{
+    SoundDecoder_SampleInternal* internal_sample;
+    BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, -1);
+	BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0);	
+    internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque;
+    return internal_sample->total_time;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SoundDecoder.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,200 @@
+
+/*
+ * This is a wrapper interface that tries to provide a similar
+ * front-end interface to SDL_sound.
+ */
+
+#ifndef SOUNDDECODER_H 
+#define SOUNDDECODER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "al.h" /* OpenAL */
+
+/* Compatibility defines for SDL */
+#define AUDIO_U8 0x0008
+#define AUDIO_S8 0x8008
+#define AUDIO_U16LSB 0x0010	
+#define AUDIO_S16LSB 0x8010
+#define AUDIO_U16MSB 0x1010
+#define AUDIO_S16MSB 0x9010
+#define AUDIO_U16 AUDIO_U16LSB
+#define AUDIO_S16 AUDIO_S16LSB
+
+#ifdef ANDROID_NDK
+	#include <endian.h>
+	#if _BYTE_ORDER == _BIG_ENDIAN
+		#define __BIG_ENDIAN__ 1
+	#elif _BYTE_ORDER == _LITTLE_ENDIAN
+		#define __LITTLE_ENDIAN__ 1
+	#else
+		#warning "Android falling back to __LITTLE_ENDIAN__"
+		#define __LITTLE_ENDIAN__ 1
+	#endif
+#endif
+
+#if __BIG_ENDIAN__
+#warning "Using __BIG_ENDIAN__"
+#define AUDIO_U16SYS AUDIO_U16MSB
+#define AUDIO_S16SYS AUDIO_S16MSB
+#elif __LITTLE_ENDIAN__
+#define AUDIO_U16SYS	AUDIO_U16LSB
+#define AUDIO_S16SYS	AUDIO_S16LSB
+#else
+#warning "Using __LITTLE_ENDIAN__ as fallback"
+#define AUDIO_U16SYS	AUDIO_U16LSB
+#define AUDIO_S16SYS	AUDIO_S16LSB
+#endif
+
+struct ALmixer_RWops;
+
+typedef enum
+{
+	SOUND_SAMPLEFLAG_NONE = 0,
+	SOUND_SAMPLEFLAG_CANSEEK = 1,
+	SOUND_SAMPLEFLAG_EOF     = 1 << 29,
+	SOUND_SAMPLEFLAG_ERROR   = 1 << 30,
+	SOUND_SAMPLEFLAG_EAGAIN  = 1 << 31 
+} SoundDecoder_SampleFlags;
+
+#define Sound_SampleFlags SoundDecoder_SampleFlags;
+
+typedef struct SoundDecoder_AudioInfo
+{
+    //uint16_t format;  /**< Equivalent of SDL_AudioSpec.format. */
+    ALushort format;  /**< Equivalent of SDL_AudioSpec.format. */
+    ALubyte channels;
+    // uint8_t channels;
+    //uint32_t rate; 
+    ALuint rate; 
+} SoundDecoder_AudioInfo;
+
+//#define Sound_AudioInfo SoundDecoder_AudioInfo;
+typedef struct SoundDecoder_AudioInfo Sound_AudioInfo;
+
+
+
+typedef struct SoundDecoder_DecoderInfo
+{
+    const char** extensions;
+    const char* description;
+    const char* author;
+    const char* url;
+} SoundDecoder_DecoderInfo;
+
+//#define Sound_DecoderInfo SoundDecoder_DecoderInfo;
+typedef struct SoundDecoder_DecoderInfo Sound_DecoderInfo;
+
+
+
+typedef struct SoundDecoder_Sample
+{
+    void* opaque;
+    const SoundDecoder_DecoderInfo* decoder;
+    SoundDecoder_AudioInfo desired;
+    SoundDecoder_AudioInfo actual;
+    void *buffer;
+    size_t buffer_size;
+    SoundDecoder_SampleFlags flags;
+} SoundDecoder_Sample;
+
+//#define Sound_Sample SoundDecoder_Sample;
+typedef struct SoundDecoder_Sample Sound_Sample;
+
+
+typedef struct SoundDecoder_Version
+{
+    int major;
+    int minor;
+    int patch;
+} SoundDecoder_Version;
+
+//#define Sound_Version SoundDecoder_Version;
+typedef struct SoundDecoder_Version Sound_Version;
+
+
+#define SOUNDDECODER_VER_MAJOR 0
+#define SOUNDDECODER_VER_MINOR 0
+#define SOUNDDECODER_VER_PATCH 1
+
+#define SOUNDDECODER_VERSION(x) \
+{ \
+    (x)->major = SOUNDDECODER_VER_MAJOR; \
+    (x)->minor = SOUNDDECODER_VER_MINOR; \
+    (x)->patch = SOUNDDECODER_VER_PATCH; \
+}
+
+#define SOUND_VERSION SOUNDDECODER_VERSION
+
+void SoundDecoder_GetLinkedVersion(SoundDecoder_Version *ver);
+#define Sound_GetLinkedVersion SoundDecoder_GetLinkedVersion
+
+int SoundDecoder_Init(void);
+#define Sound_Init SoundDecoder_Init
+
+void SoundDecoder_Quit(void);
+#define Sound_Quit SoundDecoder_Quit
+
+
+const SoundDecoder_DecoderInfo** SoundDecoder_AvailableDecoders(void);
+#define Sound_AvailableDecoders SoundDecoder_AvailableDecoders
+
+
+const char* SoundDecoder_GetError(void);
+#define Sound_GetError SoundDecoder_GetError
+
+
+void SoundDecoder_ClearError(void);
+#define Sound_ClearError SoundDecoder_ClearError
+
+
+
+SoundDecoder_Sample* SoundDecoder_NewSample(
+	struct ALmixer_RWops* rw_ops,
+	const char* ext,
+	SoundDecoder_AudioInfo* desired,
+	size_t buffer_size);
+#define Sound_NewSample SoundDecoder_NewSample
+
+SoundDecoder_Sample* SoundDecoder_NewSampleFromFile(const char* file_name,
+	SoundDecoder_AudioInfo* desired,
+	size_t bufferSize);
+#define Sound_NewSampleFromFile SoundDecoder_NewSampleFromFile
+
+
+void SoundDecoder_FreeSample(SoundDecoder_Sample* sound_sample);
+#define Sound_FreeSample SoundDecoder_FreeSample
+
+
+ptrdiff_t SoundDecoder_GetDuration(SoundDecoder_Sample* sound_sample);
+#define Sound_GetDuration SoundDecoder_GetDuration
+
+int SoundDecoder_SetBufferSize(SoundDecoder_Sample* sound_sample, size_t new_buffer_size);
+#define Sound_SetBufferSize SoundDecoder_SetBufferSize
+
+size_t SoundDecoder_Decode(SoundDecoder_Sample* sound_sample);
+#define Sound_Decode SoundDecoder_Decode
+
+size_t SoundDecoder_DecodeAll(SoundDecoder_Sample* sound_sample);
+#define Sound_DecodeAll SoundDecoder_DecodeAll
+
+int SoundDecoder_Rewind(SoundDecoder_Sample* sound_sample);
+#define Sound_Rewind SoundDecoder_Rewind
+
+int SoundDecoder_Seek(SoundDecoder_Sample* sound_sample, size_t ms);
+#define Sound_Seek SoundDecoder_Seek
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/SoundDecoder_Internal.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,84 @@
+#ifndef SOUNDDECODER_INTERNAL_H
+#define SOUNDDECODER_INTERNAL_H
+
+#include <stdio.h>
+#include "al.h" /* OpenAL */
+#include "ALmixer_RWops.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+	
+
+typedef struct SoundDecoder_DecoderFunctions
+{
+    const SoundDecoder_DecoderInfo info;
+    int (*init)(void);
+    void (*quit)(void);
+    int (*open)(SoundDecoder_Sample *sample, const char *ext);
+    void (*close)(SoundDecoder_Sample *sample);
+    size_t (*read)(SoundDecoder_Sample *sample);
+    int (*rewind)(SoundDecoder_Sample *sample);
+    int (*seek)(SoundDecoder_Sample *sample, size_t ms);
+} SoundDecoder_DecoderFunctions;
+
+typedef struct SoundDecoder_DecoderFunctions Sound_DecoderFunctions;
+
+
+
+typedef struct SoundDecoder_SampleInternal
+{
+    ALmixer_RWops *rw;
+    const SoundDecoder_DecoderFunctions *funcs;
+    void *buffer;
+    size_t buffer_size;
+    void *decoder_private;
+    ptrdiff_t total_time;
+} SoundDecoder_SampleInternal;
+
+typedef struct SoundDecoder_SampleInternal Sound_SampleInternal;
+
+#define BAIL_MACRO(e, r) { SoundDecoder_SetError(e); return r; }
+#define BAIL_IF_MACRO(c, e, r) if (c) { SoundDecoder_SetError(e); return r; }
+#define ERR_OUT_OF_MEMORY "Out of memory"
+#define ERR_NOT_INITIALIZED "SoundDecoder not initialized"
+#define ERR_UNSUPPORTED_FORMAT "Unsupported codec"
+#define ERR_NULL_SAMPLE "Sound sample is NULL"
+#define ERR_PREVIOUS_SAMPLE_ERROR "Cannot operate on sample due to previous error"
+#define ERR_ALREADY_AT_EOF_ERROR "Cannot operate on sample because already at EOF"
+
+#ifdef ANDROID_NDK
+
+/* This macro crashes when a format string is used. 
+ * Provide a real function instead.
+#include <android/log.h>
+#define SNDDBG(x) __android_log_print(ANDROID_LOG_INFO, "Corona", x);
+*/
+/* Android doesn't seem to understand the 'restrict' qualifier. */
+int SoundDecoder_DebugPrint(const char* format, ...);
+#define SNDDBG(x) SoundDecoder_DebugPrint x
+
+#else
+
+#if (defined DEBUG_CHATTER)
+#define SNDDBG(x) printf x
+#else
+#define SNDDBG(x)
+#endif
+
+#endif
+
+void SoundDecoder_SetError(const char* err_str, ...);
+#define __Sound_SetError SoundDecoder_SetError
+
+int SoundDecoder_strcasecmp(const char *x, const char *y);
+#define __Sound_strcasecmp SoundDecoder_strcasecmp
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/UNUSED/SimpleSemaphore.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,26 @@
+#ifndef SIMPLE_SEMAPHORE_H
+#define SIMPLE_SEMAPHORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	
+typedef struct SimpleSemaphore SimpleSemaphore;
+
+SimpleSemaphore* SimpleSemaphore_CreateSemaphore(int initial_value);
+
+void SimpleSemaphore_DestroySemaphore(SimpleSemaphore* simple_semaphore);
+
+int SimpleSemaphore_SemaphoreTryWait(SimpleSemaphore* simple_semaphore);
+int SimpleSemaphore_SemaphoreWait(SimpleSemaphore* simple_semaphore);
+int SimpleSemaphore_SemaphoreGetValue(SimpleSemaphore* simple_semaphore);
+int SimpleSemaphore_SemaphorePost(SimpleSemaphore* simple_semaphore);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/UNUSED/SimpleSemaphorePosix.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,122 @@
+#include "SimpleSemaphore.h"
+#include <semaphore.h>
+#include <stdlib.h>
+
+#if defined(DEBUG)
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#define SEMDBG(x) printf x
+#else
+#define SEMDBG(x)
+#endif
+
+
+
+struct SimpleSemaphore
+{
+    sem_t theSemaphore;
+};
+
+SimpleSemaphore* SimpleSemaphore_CreateSemaphore(int initial_value)
+{
+	int ret_val;	
+    SimpleSemaphore* simple_semaphore = (SimpleSemaphore*)malloc(sizeof(SimpleSemaphore));
+	if(NULL == simple_semaphore)
+	{
+		SEMDBG(("Out of memory.\n"));						
+		return NULL;
+	}
+	/* Drat: sem_init isn't available on OS X */
+#ifdef __APPLE__
+	#warning "sem_init (unnamed semaphores) do not work on OS X. This code is broken."
+#endif
+	ret_val = sem_init(&simple_semaphore->theSemaphore, 0, initial_value);
+	if(0 != ret_val)
+	{
+		/* failed */
+		SEMDBG(("sem_init failed with: %d\n", ret_val));		
+		free(simple_semaphore);
+		return 0;
+	}
+
+    return simple_semaphore;
+}
+
+void SimpleSemaphore_DestroySemaphore(SimpleSemaphore* simple_semaphore)
+{
+	if(NULL == simple_semaphore)
+	{
+		return;
+	}
+	sem_destroy(&simple_semaphore->theSemaphore);
+	free(simple_semaphore);
+}
+
+int SimpleSemaphore_SemaphoreTryWait(SimpleSemaphore* simple_semaphore)
+{
+    int ret_val;
+	if(NULL == simple_semaphore)
+	{
+		SEMDBG(("SimpleSemaphore_SemTryWait was passed a NULL semaphore\n"));	
+		return 0;
+	}
+    ret_val = sem_trywait(&simple_semaphore->theSemaphore);
+	if(0 == ret_val)
+	{
+		return 1;
+    }
+	else
+	{
+		return 0;
+	}
+}
+
+int SimpleSemaphore_SemaphoreWait(SimpleSemaphore* simple_semaphore)
+{
+    int ret_val;
+	if(NULL == simple_semaphore)
+	{
+		SEMDBG(("SimpleSemaphore_SemaphoreWait was passed a NULL semaphore\n"));	
+		return 0;
+	}
+    ret_val = sem_wait(&simple_semaphore->theSemaphore);
+	if(0 == ret_val)
+	{
+		return 1;
+    }
+	else
+	{
+		return 0;
+	}
+}
+
+int SimpleSemaphore_SemaphoreGetValue(SimpleSemaphore* simple_semaphore)
+{
+    int ret_val = 0;
+	if(NULL == simple_semaphore)
+	{
+		SEMDBG(("SimpleSemaphore_SemaphoreGetValue was passed a NULL semaphore\n"));	
+		return 0;
+	}
+	sem_getvalue(&simple_semaphore->theSemaphore, &ret_val);
+	return ret_val;
+}
+
+int SimpleSemaphore_SemaphorePost(SimpleSemaphore* simple_semaphore)
+{
+    int ret_val;
+	if(NULL == simple_semaphore)
+	{
+		SEMDBG(("SimpleSemaphore_SemaphorePost was passed a NULL semaphore\n"));	
+		return 0;
+	}
+
+    ret_val = sem_post(&simple_semaphore->theSemaphore);
+ 	if(-1 == ret_val)
+	{
+		SEMDBG(("sem_post failed with: %s\n", strerror(errno)));		
+	}
+    return ret_val;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/coreaudio.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,784 @@
+#ifdef ALMIXER_COMPILE_WITHOUT_SDL
+
+/*
+ * SDL_sound Core Audio backend
+ * Copyright (C) 2010 Eric Wing <ewing . public @ playcontrol.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef __APPLE__
+
+#include <stddef.h> /* NULL */
+#include <stdio.h> /* printf */
+#include <arpa/inet.h> /* htonl */
+#include <AudioToolbox/AudioToolbox.h>
+
+#include "SoundDecoder.h"
+
+#include "SoundDecoder_Internal.h"
+
+typedef struct CoreAudioFileContainer
+{
+	AudioFileID* audioFileID;
+	ExtAudioFileRef extAudioFileRef;
+	AudioStreamBasicDescription* outputFormat;
+} CoreAudioFileContainer;
+
+static int CoreAudio_init(void);
+static void CoreAudio_quit(void);
+static int CoreAudio_open(Sound_Sample *sample, const char *ext);
+static void CoreAudio_close(Sound_Sample *sample);
+static size_t CoreAudio_read(Sound_Sample *sample);
+static int CoreAudio_rewind(Sound_Sample *sample);
+static int CoreAudio_seek(Sound_Sample *sample, size_t ms);
+
+static const char *extensions_coreaudio[] = 
+{
+	"aif",
+	"aiff",
+	"aifc",
+	"wav",
+	"wave",
+	"mp3",
+	"mp4",
+	"m4a",
+	"aac",
+	"adts",
+	"caf",
+	"Sd2f",
+	"Sd2",
+	"au",
+	"snd",
+	"next",
+	"mp2",
+	"mp1",
+	"ac3",
+	"3gpp",
+	"3gp",
+	"3gp2",
+	"3g2",
+	"amrf",
+	"amr",
+	"ima4",
+	"ima",
+	NULL 
+};
+const Sound_DecoderFunctions __Sound_DecoderFunctions_CoreAudio =
+{
+    {
+        extensions_coreaudio,
+        "Decode audio through Core Audio through",
+        "Eric Wing <ewing . public @ playcontrol.net>",
+        "http://playcontrol.net"
+    },
+	
+    CoreAudio_init,       /*   init() method */
+    CoreAudio_quit,       /*   quit() method */
+    CoreAudio_open,       /*   open() method */
+    CoreAudio_close,      /*  close() method */
+    CoreAudio_read,       /*   read() method */
+    CoreAudio_rewind,     /* rewind() method */
+    CoreAudio_seek        /*   seek() method */
+};
+
+
+static int CoreAudio_init(void)
+{
+    return(1);  /* always succeeds. */
+} /* CoreAudio_init */
+
+
+static void CoreAudio_quit(void)
+{
+    /* it's a no-op. */
+} /* CoreAudio_quit */
+
+/*
+   http://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html
+   kAudioFileAIFFType = 'AIFF',
+   kAudioFileAIFCType            = 'AIFC',
+   kAudioFileWAVEType            = 'WAVE',
+   kAudioFileSoundDesigner2Type  = 'Sd2f',
+   kAudioFileNextType            = 'NeXT',
+   kAudioFileMP3Type             = 'MPG3',
+   kAudioFileMP2Type             = 'MPG2',
+   kAudioFileMP1Type             = 'MPG1',
+   kAudioFileAC3Type             = 'ac-3',
+   kAudioFileAAC_ADTSType        = 'adts',
+   kAudioFileMPEG4Type           = 'mp4f',
+   kAudioFileM4AType             = 'm4af',
+   kAudioFileCAFType             = 'caff',
+   kAudioFile3GPType             = '3gpp',
+   kAudioFile3GP2Type            = '3gp2',
+   kAudioFileAMRType             = 'amrf'
+*/
+static AudioFileTypeID CoreAudio_GetAudioTypeForExtension(const char* file_extension)
+{
+	if( (__Sound_strcasecmp(file_extension, "aif") == 0)
+		|| (__Sound_strcasecmp(file_extension, "aiff") == 0)
+		|| (__Sound_strcasecmp(file_extension, "aifc") == 0)
+	)
+	{
+		return kAudioFileAIFCType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "wav") == 0)
+		|| (__Sound_strcasecmp(file_extension, "wave") == 0)
+	)
+	{
+		return kAudioFileWAVEType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "mp3") == 0)
+	)
+	{
+		return kAudioFileMP3Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "mp4") == 0)
+	)
+	{
+		return kAudioFileMPEG4Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "m4a") == 0)
+	)
+	{
+		return kAudioFileM4AType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "aac") == 0)
+	)
+	{
+		return kAudioFileAAC_ADTSType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "adts") == 0)
+	)
+	{
+		return kAudioFileAAC_ADTSType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "caf") == 0)
+		|| (__Sound_strcasecmp(file_extension, "caff") == 0)
+	)
+	{
+		return kAudioFileCAFType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "Sd2f") == 0)
+		|| (__Sound_strcasecmp(file_extension, "sd2") == 0)
+	)
+	{
+		return kAudioFileSoundDesigner2Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "au") == 0)
+		|| (__Sound_strcasecmp(file_extension, "snd") == 0)
+		|| (__Sound_strcasecmp(file_extension, "next") == 0)
+	)
+	{
+		return kAudioFileNextType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "mp2") == 0)
+	)
+	{
+		return kAudioFileMP2Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "mp1") == 0)
+	)
+	{
+		return kAudioFileMP1Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "ac3") == 0)
+	)
+	{
+		return kAudioFileAC3Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "3gpp") == 0)
+			|| (__Sound_strcasecmp(file_extension, "3gp") == 0)
+	)
+	{
+		return kAudioFile3GPType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "3gp2") == 0)
+			|| (__Sound_strcasecmp(file_extension, "3g2") == 0)
+	)
+	{
+		return kAudioFile3GP2Type;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "amrf") == 0)
+		|| (__Sound_strcasecmp(file_extension, "amr") == 0)
+	)
+	{
+		return kAudioFileAMRType;
+	}
+	else if( (__Sound_strcasecmp(file_extension, "ima4") == 0)
+		|| (__Sound_strcasecmp(file_extension, "ima") == 0)
+	)
+	{
+		/* not sure about this one */
+		return kAudioFileCAFType;
+	}
+	else
+	{
+		return 0;
+	}
+
+}
+
+static const char* CoreAudio_FourCCToString(int32_t error_code)
+{
+	static char return_string[16];
+	uint32_t big_endian_code = htonl(error_code);
+	char* big_endian_str = (char*)&big_endian_code;
+	// see if it appears to be a 4-char-code
+	if(isprint(big_endian_str[0])
+	   && isprint(big_endian_str[1])
+	   && isprint(big_endian_str[2])
+	   && isprint (big_endian_str[3]))
+	{
+		return_string[0] = '\'';
+		return_string[1] = big_endian_str[0];
+		return_string[2] = big_endian_str[1];
+		return_string[3] = big_endian_str[2];
+		return_string[4] = big_endian_str[3];
+		return_string[5] = '\'';
+		return_string[6] = '\0';
+	}
+	else if(error_code > -200000 && error_code < 200000)
+	{
+		// no, format it as an integer
+		snprintf(return_string, 16, "%d", error_code);
+	}
+	else
+	{
+		// no, format it as an integer but in hex
+		snprintf(return_string, 16, "0x%x", error_code);
+	}
+	return return_string;
+}
+
+
+
+SInt64 CoreAudio_SizeCallback(void* inClientData)
+{
+	ALmixer_RWops* rw_ops = (ALmixer_RWops*)inClientData;
+	SInt64 current_position = ALmixer_RWtell(rw_ops);
+	SInt64 end_position = ALmixer_RWseek(rw_ops, 0, SEEK_END);
+	ALmixer_RWseek(rw_ops, current_position, SEEK_SET);
+//	fprintf(stderr, "CoreAudio_SizeCallback:%d\n", end_position);
+
+	return end_position;
+}
+
+OSStatus CoreAudio_ReadCallback(
+	void* inClientData,
+	SInt64 inPosition,
+	UInt32 requestCount,
+	void* data_buffer,
+	UInt32* actualCount
+)
+{
+	ALmixer_RWops* rw_ops = (ALmixer_RWops*)inClientData;
+	ALmixer_RWseek(rw_ops, inPosition, SEEK_SET);
+	size_t bytes_actually_read = ALmixer_RWread(rw_ops, data_buffer, 1, requestCount);
+	// Not sure how to test for a read error with ALmixer_RWops
+//	fprintf(stderr, "CoreAudio_ReadCallback:%d, %d\n", requestCount, bytes_actually_read);
+
+	*actualCount = bytes_actually_read;
+	return noErr;
+}
+
+
+static int CoreAudio_open(Sound_Sample *sample, const char *ext)
+{
+	CoreAudioFileContainer* core_audio_file_container;
+	AudioFileID* audio_file_id;
+	OSStatus error_result;
+	Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+	AudioStreamBasicDescription	actual_format;
+	AudioStreamBasicDescription	output_format;
+	Float64 estimated_duration;
+	UInt32 format_size;
+	
+
+	core_audio_file_container = (CoreAudioFileContainer*)malloc(sizeof(CoreAudioFileContainer));
+	BAIL_IF_MACRO(core_audio_file_container == NULL, ERR_OUT_OF_MEMORY, 0);
+
+
+	audio_file_id = (AudioFileID*)malloc(sizeof(AudioFileID));
+	BAIL_IF_MACRO(audio_file_id == NULL, ERR_OUT_OF_MEMORY, 0);
+
+	error_result = AudioFileOpenWithCallbacks(
+		internal->rw,
+		CoreAudio_ReadCallback,
+		NULL,
+		CoreAudio_SizeCallback,
+		NULL,
+		CoreAudio_GetAudioTypeForExtension(ext),
+		audio_file_id
+	);
+	if (error_result != noErr)
+	{
+		AudioFileClose(*audio_file_id);
+		free(audio_file_id);
+		free(core_audio_file_container);
+		SNDDBG(("Core Audio: can't grok data. reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
+		BAIL_MACRO("Core Audio: Not valid audio data.", 0);
+	} /* if */
+	
+    format_size = sizeof(actual_format);
+    error_result = AudioFileGetProperty(
+		*audio_file_id,
+		kAudioFilePropertyDataFormat,
+		&format_size,
+		&actual_format
+	);
+    if (error_result != noErr)
+	{
+		AudioFileClose(*audio_file_id);
+		free(audio_file_id);
+		free(core_audio_file_container);
+		SNDDBG(("Core Audio: AudioFileGetProperty failed. reason: [%s]", CoreAudio_FourCCToString(error_result)));
+		BAIL_MACRO("Core Audio: Not valid audio data.", 0);
+	} /* if */
+
+    format_size = sizeof(estimated_duration);
+    error_result = AudioFileGetProperty(
+		*audio_file_id,
+		kAudioFilePropertyEstimatedDuration,
+		&format_size,
+		&estimated_duration
+	);
+    if (error_result != noErr)
+	{
+		AudioFileClose(*audio_file_id);
+		free(audio_file_id);
+		free(core_audio_file_container);
+		SNDDBG(("Core Audio: AudioFileGetProperty failed. reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
+		BAIL_MACRO("Core Audio: Not valid audio data.", 0);
+	} /* if */
+
+
+	core_audio_file_container->audioFileID = audio_file_id;
+	
+	internal->decoder_private = core_audio_file_container;
+	
+	sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+	sample->actual.rate = (UInt32) actual_format.mSampleRate;
+	sample->actual.channels = (UInt8)actual_format.mChannelsPerFrame;
+	internal->total_time = (SInt32)(estimated_duration * 1000.0 + 0.5);
+
+#if 0
+	/* FIXME: Both Core Audio and SDL 1.3 support float and 32-bit formats */
+	if(actual_format.mFormatFlags & kAudioFormatFlagIsBigEndian)
+	{
+		if(16 == actual_format.mBitsPerChannel)
+		{
+			if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
+			{
+				sample->actual.format = AUDIO_S16MSB;
+			}
+			else
+			{
+				sample->actual.format = AUDIO_U16MSB;				
+			}
+		}
+		else if(8 == actual_format.mBitsPerChannel)
+		{
+			if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
+			{
+				sample->actual.format = AUDIO_S8;
+			}
+			else
+			{
+				sample->actual.format = AUDIO_U8;				
+			}
+		}
+		else // might be 0 for undefined? 
+		{
+			// This case seems to come up a lot for me. Maybe for file types like .m4a?
+			sample->actual.format = AUDIO_S16SYS;
+			SNDDBG(("Core Audio: Unsupported actual_format.mBitsPerChannel: [%d].\n", actual_format.mBitsPerChannel));
+			
+		}
+	}
+	else // little endian
+	{
+		if(16 == actual_format.mBitsPerChannel)
+		{
+			if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
+			{
+				sample->actual.format = AUDIO_S16LSB;
+			}
+			else
+			{
+				sample->actual.format = AUDIO_U16LSB;				
+			}
+		}
+		else if(8 == actual_format.mBitsPerChannel)
+		{
+			if(kAudioFormatFlagIsSignedInteger & actual_format.mFormatFlags)
+			{
+				sample->actual.format = AUDIO_S8;
+			}
+			else
+			{
+				sample->actual.format = AUDIO_U8;				
+			}
+		}
+		else // might be 0 for undefined? 
+		{
+			sample->actual.format = AUDIO_S16SYS;
+			
+			SNDDBG(("Core Audio: Unsupported actual_format.mBitsPerChannel: [%d].\n", actual_format.mBitsPerChannel));
+		}
+
+	}
+#else
+	
+	
+	
+    /*
+     * I want to use Core Audio to do conversion and decoding for performance reasons.
+	 * This is particularly important on mobile devices like iOS.
+	 * Taking from the Ogg Vorbis decode, I pretend the "actual" format is the same 
+	 * as the desired format. 
+     */
+    sample->actual.format = (sample->desired.format == 0) ?
+	AUDIO_S16SYS : sample->desired.format;
+#endif	
+
+
+	SNDDBG(("CoreAudio: channels == (%d).\n", sample->actual.channels));
+	SNDDBG(("CoreAudio: sampling rate == (%d).\n",sample->actual.rate));
+	SNDDBG(("CoreAudio: total seconds of sample == (%d).\n", internal->total_time));
+	SNDDBG(("CoreAudio: sample->actual.format == (%d).\n", sample->actual.format));
+
+
+	
+	error_result = ExtAudioFileWrapAudioFileID(*audio_file_id,
+		false, // set to false for read-only
+		&core_audio_file_container->extAudioFileRef
+	);
+	if(error_result != noErr)
+	{
+		AudioFileClose(*audio_file_id);
+		free(audio_file_id);
+		free(core_audio_file_container);
+		SNDDBG(("Core Audio: can't wrap data. reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
+		BAIL_MACRO("Core Audio: Failed to wrap data.", 0);
+	} /* if */
+
+
+	/* The output format must be linear PCM because that's the only type OpenAL knows how to deal with.
+	 * Set the client format to 16 bit signed integer (native-endian) data because that is the most
+	 * optimal format on iPhone/iPod Touch hardware.
+	 * Maintain the channel count and sample rate of the original source format.
+	 */
+	output_format.mSampleRate = actual_format.mSampleRate; // preserve the original sample rate
+	output_format.mChannelsPerFrame = actual_format.mChannelsPerFrame; // preserve the number of channels
+	output_format.mFormatID = kAudioFormatLinearPCM; // We want linear PCM data
+	output_format.mFramesPerPacket = 1; // We know for linear PCM, the definition is 1 frame per packet
+
+	if(sample->desired.format == 0)
+	{
+		// do AUDIO_S16SYS
+		output_format.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; // I seem to read failures problems without kAudioFormatFlagIsPacked. From a mailing list post, this seems to be a Core Audio bug.
+		output_format.mBitsPerChannel = 16; // We know we want 16-bit
+	}
+	else
+	{
+		output_format.mFormatFlags = 0; // clear flags
+		output_format.mFormatFlags |= kAudioFormatFlagIsPacked; // I seem to read failures problems without kAudioFormatFlagIsPacked. From a mailing list post, this seems to be a Core Audio bug.
+		// Mask against bitsize
+		if(0xFF & sample->desired.format)
+		{
+			output_format.mBitsPerChannel = 16; /* 16-bit */
+		}
+		else
+		{
+			output_format.mBitsPerChannel = 8; /* 8-bit */
+		}
+
+		// Mask for signed/unsigned
+		if((1<<15) & sample->desired.format)
+		{
+			output_format.mFormatFlags = output_format.mFormatFlags | kAudioFormatFlagIsSignedInteger;
+
+		}
+		else
+		{
+			// no flag set for unsigned
+		}
+		// Mask for big/little endian
+		if((1<<12) & sample->desired.format)
+		{
+			output_format.mFormatFlags = output_format.mFormatFlags | kAudioFormatFlagIsBigEndian;
+		}
+		else
+		{
+			// no flag set for little endian 
+		}
+	}
+
+	output_format.mBytesPerPacket = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // e.g. 16-bits/8 * channels => so 2-bytes per channel per frame
+	output_format.mBytesPerFrame = output_format.mBitsPerChannel/8 * output_format.mChannelsPerFrame; // For PCM, since 1 frame is 1 packet, it is the same as mBytesPerPacket
+
+	
+/*
+	output_format.mSampleRate = actual_format.mSampleRate; // preserve the original sample rate
+	output_format.mChannelsPerFrame = actual_format.mChannelsPerFrame; // preserve the number of channels
+	output_format.mFormatID = kAudioFormatLinearPCM; // We want linear PCM data
+//	output_format.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
+	output_format.mFormatFlags = kAudioFormatFlagsNativeEndian |  kAudioFormatFlagIsSignedInteger;
+	output_format.mFramesPerPacket = 1; // We know for linear PCM, the definition is 1 frame per packet
+	output_format.mBitsPerChannel = 16; // We know we want 16-bit
+	output_format.mBytesPerPacket = 2 * output_format.mChannelsPerFrame; // We know we are using 16-bit, so 2-bytes per channel per frame
+	output_format.mBytesPerFrame = 2 * output_format.mChannelsPerFrame; // For PCM, since 1 frame is 1 packet, it is the same as mBytesPerPacket
+*/
+	SNDDBG(("output_format: mSampleRate: %lf\n", output_format.mSampleRate)); 
+	SNDDBG(("output_format: mChannelsPerFrame: %d\n", output_format.mChannelsPerFrame)); 
+	SNDDBG(("output_format: mFormatID: %d\n", output_format.mFormatID)); 
+	SNDDBG(("output_format: mFormatFlags: %d\n", output_format.mFormatFlags)); 
+	SNDDBG(("output_format: mFramesPerPacket: %d\n", output_format.mFramesPerPacket)); 
+	SNDDBG(("output_format: mBitsPerChannel: %d\n", output_format.mBitsPerChannel)); 
+	SNDDBG(("output_format: mBytesPerPacket: %d\n", output_format.mBytesPerPacket)); 
+	SNDDBG(("output_format: mBytesPerFrame: %d\n", output_format.mBytesPerFrame)); 
+	
+	
+	/* Set the desired client (output) data format */
+	error_result = ExtAudioFileSetProperty(core_audio_file_container->extAudioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(output_format), &output_format);
+	if(noErr != error_result)
+	{
+		ExtAudioFileDispose(core_audio_file_container->extAudioFileRef);
+		AudioFileClose(*audio_file_id);
+		free(audio_file_id);
+		free(core_audio_file_container);
+		SNDDBG(("Core Audio: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) failed, reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
+		BAIL_MACRO("Core Audio: Not valid audio data.", 0);
+	}	
+
+
+	core_audio_file_container->outputFormat = (AudioStreamBasicDescription*)malloc(sizeof(AudioStreamBasicDescription));
+	BAIL_IF_MACRO(core_audio_file_container->outputFormat == NULL, ERR_OUT_OF_MEMORY, 0);
+
+
+	
+	/* Copy the output format to the audio_description that was passed in so the 
+	 * info will be returned to the user.
+	 */
+	memcpy(core_audio_file_container->outputFormat, &output_format, sizeof(AudioStreamBasicDescription));
+
+	
+
+	return(1);
+} /* CoreAudio_open */
+
+
+static void CoreAudio_close(Sound_Sample *sample)
+{
+	Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+	CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
+	
+	free(core_audio_file_container->outputFormat);
+	ExtAudioFileDispose(core_audio_file_container->extAudioFileRef);
+	AudioFileClose(*core_audio_file_container->audioFileID);
+	free(core_audio_file_container->audioFileID);
+	free(core_audio_file_container);
+		
+} /* CoreAudio_close */
+
+
+static size_t CoreAudio_read(Sound_Sample *sample)
+{
+	OSStatus error_result = noErr;	
+	/* Documentation/example shows SInt64, but is problematic for big endian
+	 * on 32-bit cast for ExtAudioFileRead() because it takes the upper
+	 * bits which turn to 0.
+	 */
+	UInt32 buffer_size_in_frames = 0;
+	UInt32 buffer_size_in_frames_remaining = 0;
+	UInt32 total_frames_read = 0;
+	UInt32 data_buffer_size = 0;
+	UInt32 bytes_remaining = 0;
+	size_t total_bytes_read = 0;
+	Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+	CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
+	UInt32 max_buffer_size = internal->buffer_size;
+
+//	printf("internal->buffer_size=%d, internal->buffer=0x%x, sample->buffer_size=%d\n", internal->buffer_size, internal->buffer, sample->buffer_size); 
+//	printf("internal->max_buffer_size=%d\n", max_buffer_size); 
+
+	/* Compute how many frames will fit into our max buffer size */
+	/* Warning: If this is not evenly divisible, the buffer will not be completely filled which violates the SDL_sound assumption. */
+	buffer_size_in_frames = max_buffer_size / core_audio_file_container->outputFormat->mBytesPerFrame;
+//	printf("buffer_size_in_frames=%ld, internal->buffer_size=%d, internal->buffer=0x%x outputFormat->mBytesPerFrame=%d, sample->buffer_size=%d\n", buffer_size_in_frames, internal->buffer_size, internal->buffer, core_audio_file_container->outputFormat->mBytesPerFrame, sample->buffer_size); 
+
+
+//	void* temp_buffer = malloc(max_buffer_size);
+	
+	AudioBufferList audio_buffer_list;
+	audio_buffer_list.mNumberBuffers = 1;
+	audio_buffer_list.mBuffers[0].mDataByteSize = max_buffer_size;
+	audio_buffer_list.mBuffers[0].mNumberChannels = core_audio_file_container->outputFormat->mChannelsPerFrame;
+	audio_buffer_list.mBuffers[0].mData = internal->buffer;
+
+
+	bytes_remaining = max_buffer_size;
+	buffer_size_in_frames_remaining = buffer_size_in_frames;
+	
+	// oops. Due to the kAudioFormatFlagIsPacked bug, 
+	// I was misled to believe that Core Audio
+	// was not always filling my entire requested buffer. 
+	// So this while-loop might be unnecessary.
+	// However, I have not exhaustively tested all formats, 
+	// so maybe it is possible this loop is useful.
+	// It might also handle the not-evenly disvisible case above.
+	while(buffer_size_in_frames_remaining > 0 && !(sample->flags & SOUND_SAMPLEFLAG_EOF))
+	{
+		
+		data_buffer_size = (UInt32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame);
+//		printf("data_buffer_size=%d\n", data_buffer_size); 
+
+		buffer_size_in_frames = buffer_size_in_frames_remaining;
+		
+//		printf("reading buffer_size_in_frames=%"PRId64"\n", buffer_size_in_frames); 
+
+
+		audio_buffer_list.mBuffers[0].mDataByteSize = bytes_remaining;
+		audio_buffer_list.mBuffers[0].mData = &(((UInt8*)internal->buffer)[total_bytes_read]);
+
+		
+		/* Read the data into an AudioBufferList */
+		error_result = ExtAudioFileRead(core_audio_file_container->extAudioFileRef, &buffer_size_in_frames, &audio_buffer_list);
+		if(error_result == noErr)
+		{
+		
+		
+			/* Success */
+			
+			total_frames_read += buffer_size_in_frames;
+			buffer_size_in_frames_remaining = buffer_size_in_frames_remaining - buffer_size_in_frames;
+			
+//			printf("read buffer_size_in_frames=%"PRId64", buffer_size_in_frames_remaining=%"PRId64"\n", buffer_size_in_frames, buffer_size_in_frames_remaining); 
+
+			/* ExtAudioFileRead returns the number of frames actually read. Need to convert back to bytes. */
+			data_buffer_size = (UInt32)(buffer_size_in_frames * core_audio_file_container->outputFormat->mBytesPerFrame);
+//			printf("data_buffer_size=%d\n", data_buffer_size); 
+
+			total_bytes_read += data_buffer_size;
+			bytes_remaining = bytes_remaining - data_buffer_size;
+
+			/* Note: 0 == buffer_size_in_frames is a legitimate value meaning we are EOF. */
+			if(0 == buffer_size_in_frames)
+			{
+				sample->flags |= SOUND_SAMPLEFLAG_EOF;			
+			}
+
+		}
+		else 
+		{
+			SNDDBG(("Core Audio: ExtAudioFileReadfailed, reason: [%s].\n", CoreAudio_FourCCToString(error_result)));
+
+			sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+			break;
+			
+		}
+	}
+	
+	if( (!(sample->flags & SOUND_SAMPLEFLAG_EOF)) && (total_bytes_read < max_buffer_size))
+	{
+		SNDDBG(("Core Audio: ExtAudioFileReadfailed SOUND_SAMPLEFLAG_EAGAIN, reason: [total_bytes_read < max_buffer_size], %d, %d.\n", total_bytes_read , max_buffer_size));
+		
+		/* Don't know what to do here. */
+		sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+	}
+	return total_bytes_read;
+} /* CoreAudio_read */
+
+
+static int CoreAudio_rewind(Sound_Sample *sample)
+{
+	OSStatus error_result = noErr;	
+	Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+	CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
+	
+	error_result = ExtAudioFileSeek(core_audio_file_container->extAudioFileRef, 0);
+	if(error_result != noErr)
+	{
+		sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+	}
+	return(1);
+} /* CoreAudio_rewind */
+
+/* Note: I found this tech note:
+ http://developer.apple.com/library/mac/#qa/qa2009/qa1678.html
+ I don't know if this applies to us. So far, I haven't noticed the problem,
+ so I haven't applied any of the techniques.
+ */
+static int CoreAudio_seek(Sound_Sample *sample, size_t ms)
+{
+	OSStatus error_result = noErr;	
+	Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+	CoreAudioFileContainer* core_audio_file_container = (CoreAudioFileContainer *) internal->decoder_private;
+	SInt64 frame_offset = 0;
+
+	/* I'm confused. The Apple documentation says this:
+	 "Seek position is specified in the sample rate and frame count of the file’s audio data format
+	 — not your application’s audio data format."
+	 My interpretation is that I want to get the "actual format of the file and compute the frame offset.
+	 But when I try that, seeking goes to the wrong place.
+	 When I use outputFormat, things seem to work correctly.
+	 I must be misinterpreting the documentation or doing something wrong.
+	 */
+#if 0 /* not working */
+	AudioStreamBasicDescription	actual_format;
+	UInt32 format_size;
+    format_size = sizeof(AudioStreamBasicDescription);
+    error_result = AudioFileGetProperty(
+		*core_audio_file_container->audioFileID,
+		kAudioFilePropertyDataFormat,
+		&format_size,
+		&actual_format
+	);
+    if(error_result != noErr)
+	{
+		sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+		BAIL_MACRO("Core Audio: Could not GetProperty for kAudioFilePropertyDataFormat.", 0);
+	} /* if */
+
+	// packetIndex = (pos * sampleRate) / framesPerPacket
+	frame_offset = (SInt64)((ms/1000.0 * actual_format.mSampleRate) / actual_format.mFramesPerPacket);
+	// computed against actual format and not the client format
+
+	// packetIndex = (pos * sampleRate) / framesPerPacket
+	//	frame_offset = (SInt64)((ms/1000.0 * actual_format.mSampleRate) / actual_format.mFramesPerPacket);
+#else /* seems to work, but I'm confused */
+	// packetIndex = (pos * sampleRate) / framesPerPacket
+	frame_offset = (SInt64)((ms/1000.0 * core_audio_file_container->outputFormat->mSampleRate) / core_audio_file_container->outputFormat->mFramesPerPacket);	
+#endif
+	
+	// computed against actual format and not the client format
+	error_result = ExtAudioFileSeek(core_audio_file_container->extAudioFileRef, frame_offset);
+	if(error_result != noErr)
+	{
+		sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+	}
+	return(1);
+} /* CoreAudio_seek */
+
+#endif /* __APPLE__ */
+
+
+#endif /* ALMIXER_COMPILE_WITHOUT_SDL */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/luaal/luaal.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,671 @@
+/*
+	LuaOpenAL
+	Copyright (C) 2010  Eric Wing <ewing . public @ playcontrol.net>
+
+	Permission is hereby granted, free of charge, to any person obtaining a copy
+	of this software and associated documentation files (the "Software"), to deal
+	in the Software without restriction, including without limitation the rights
+	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+	copies of the Software, and to permit persons to whom the Software is
+	furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be included in
+	all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+	THE SOFTWARE.
+
+*/
+#include "al.h" 
+/* #include "alc.h" */
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#define LUAAL_VERSION "1.1"
+
+typedef struct luaopenal_Enum  
+{
+  const char* stringName;
+  ALenum alValue;
+} luaopenal_Enum;
+
+
+void luaopenal_initenum(lua_State* lua_state, const luaopenal_Enum* al_enums)
+{
+	for( ; al_enums->stringName; al_enums++) 
+	{
+		lua_pushstring(lua_state, al_enums->stringName);
+		lua_pushinteger(lua_state, al_enums->alValue);
+		lua_settable(lua_state, -3);
+	}
+}
+
+
+static const luaopenal_Enum s_luaALEnum[] = {
+	{ "INVALID",						AL_INVALID },
+	{ "NONE",							AL_NONE },
+	{ "FALSE",							AL_FALSE },
+	{ "TRUE",							AL_TRUE },
+	{ "SOURCE_RELATIVE",				AL_SOURCE_RELATIVE },
+	{ "CONE_INNER_ANGLE",				AL_CONE_INNER_ANGLE },
+	{ "CONE_OUTER_ANGLE",				AL_CONE_OUTER_ANGLE },
+	{ "PITCH",							AL_PITCH },
+	{ "POSITION",						AL_POSITION },
+	{ "DIRECTION",						AL_DIRECTION },
+	{ "VELOCITY",						AL_VELOCITY },
+	{ "LOOPING",						AL_LOOPING },
+	{ "BUFFER",							AL_BUFFER },
+	{ "GAIN",							AL_GAIN },
+	{ "MIN_GAIN",						AL_MIN_GAIN },
+	{ "MAX_GAIN",						AL_MAX_GAIN },
+	{ "ORIENTATION",					AL_ORIENTATION },
+/*	{ "CHANNEL_MASK",					AL_CHANNEL_MASK }, */
+	{ "SOURCE_STATE",					AL_SOURCE_STATE },
+	{ "INITIAL",						AL_INITIAL },
+	{ "PLAYING",						AL_PLAYING },
+	{ "PAUSED",							AL_PAUSED },
+	{ "STOPPED",						AL_STOPPED },
+	{ "BUFFERS_QUEUED",					AL_BUFFERS_QUEUED },
+	{ "BUFFERS_PROCESSED",				AL_BUFFERS_PROCESSED },
+	{ "SEC_OFFSET",						AL_SEC_OFFSET },
+	{ "SAMPLE_OFFSET",					AL_SAMPLE_OFFSET },
+	{ "BYTE_OFFSET",					AL_BYTE_OFFSET },
+	{ "SOURCE_TYPE",					AL_SOURCE_TYPE },
+	{ "STATIC",							AL_STATIC },
+	{ "STREAMING",						AL_STREAMING },
+	{ "UNDETERMINED",					AL_UNDETERMINED },
+	{ "FORMAT_MONO8",					AL_FORMAT_MONO8 },
+	{ "FORMAT_MONO16",					AL_FORMAT_MONO16 },
+	{ "FORMAT_STEREO8",					AL_FORMAT_STEREO8 },
+	{ "FORMAT_STEREO16",				AL_FORMAT_STEREO16 },
+	{ "REFERENCE_DISTANCE",				AL_REFERENCE_DISTANCE },
+	{ "ROLLOFF_FACTOR",					AL_ROLLOFF_FACTOR },
+	{ "CONE_OUTER_GAIN",				AL_CONE_OUTER_GAIN },
+	{ "MAX_DISTANCE",					AL_MAX_DISTANCE },
+	{ "FREQUENCY",						AL_FREQUENCY },
+	{ "BITS",							AL_BITS },
+	{ "CHANNELS",						AL_CHANNELS },
+	{ "SIZE",							AL_SIZE },
+/*
+	{ "UNUSED",							AL_UNUSED },
+	{ "PENDING",						AL_PENDING },
+	{ "PROCESSED",						AL_PROCESSED },
+*/
+	{ "NO_ERROR",						AL_NO_ERROR },
+	{ "INVALID_NAME",					AL_INVALID_NAME },
+	{ "ILLEGAL_ENUM",					AL_ILLEGAL_ENUM },
+	{ "INVALID_VALUE",					AL_INVALID_VALUE },
+	{ "ILLEGAL_COMMAND",				AL_ILLEGAL_COMMAND },
+	{ "INVALID_OPERATION",				AL_INVALID_OPERATION },
+	{ "OUT_OF_MEMORY",					AL_OUT_OF_MEMORY },
+	{ "VENDOR",							AL_VENDOR },
+	{ "VERSION",						AL_VERSION },
+	{ "RENDERER",						AL_RENDERER },
+	{ "EXTENSIONS",						AL_EXTENSIONS },
+	{ "DOPPLER_FACTOR",					AL_DOPPLER_FACTOR },
+	{ "DOPPLER_VELOCITY",				AL_DOPPLER_VELOCITY },
+	{ "SPEED_OF_SOUND",					AL_SPEED_OF_SOUND },
+	{ "DISTANCE_MODEL",					AL_DISTANCE_MODEL },
+	{ "INVERSE_DISTANCE",				AL_INVERSE_DISTANCE },
+	{ "INVERSE_DISTANCE_CLAMPED",		AL_INVERSE_DISTANCE_CLAMPED },
+	{ "LINEAR_DISTANCE",				AL_LINEAR_DISTANCE },
+	{ "LINEAR_DISTANCE_CLAMPED",		AL_LINEAR_DISTANCE_CLAMPED },
+	{ "EXPONENT_DISTANCE",				AL_EXPONENT_DISTANCE },
+	{ "EXPONENT_DISTANCE_CLAMPED",		AL_EXPONENT_DISTANCE_CLAMPED },
+	{ 0, 0 }
+};
+
+
+#define LUAOPENAL_BOOL_TYPE 1
+#define LUAOPENAL_INT_TYPE 2
+#define LUAOPENAL_FLOAT_TYPE 3
+
+
+#define LUAOPENAL_INT_3_TYPE 4
+#define LUAOPENAL_FLOAT_3_TYPE 5
+#define LUAOPENAL_FLOAT_6_TYPE 6
+#define LUAOPENAL_STRING_TYPE 7
+
+
+static int lua_getTypeForEnum(ALenum enum_parameter)
+{
+	switch(enum_parameter)
+	{
+		case AL_SOURCE_RELATIVE:
+		case AL_LOOPING:
+		{
+			return LUAOPENAL_BOOL_TYPE;
+			break;
+		}
+
+		case AL_SOURCE_TYPE:
+		case AL_BUFFER:
+		case AL_BUFFERS_QUEUED:
+		case AL_BUFFERS_PROCESSED:
+		{
+			return LUAOPENAL_INT_TYPE;
+			break;
+		}
+		case AL_GAIN:
+		case AL_MIN_GAIN:
+		case AL_MAX_GAIN:
+		case AL_REFERENCE_DISTANCE: /* could be integer */
+		case AL_ROLLOFF_FACTOR: /* could be integer */
+		case AL_MAX_DISTANCE: /* could be integer */
+		case AL_PITCH:
+		case AL_CONE_INNER_ANGLE: /* could be integer */
+		case AL_CONE_OUTER_ANGLE: /* could be integer */
+		case AL_CONE_OUTER_GAIN: /* interesting...only f,fv according to spec */
+		case AL_SAMPLE_OFFSET: /* could be integer */
+		case AL_BYTE_OFFSET: /* could be integer */
+		case AL_SEC_OFFSET: /* could be integer */
+
+		case AL_DOPPLER_FACTOR:
+		case AL_DOPPLER_VELOCITY:
+		case AL_SPEED_OF_SOUND:
+		{
+			return LUAOPENAL_FLOAT_TYPE;
+			break;
+		}
+
+		case AL_POSITION: /* could be integer */
+		case AL_VELOCITY: /* could be integer */
+		case AL_DIRECTION: /* could be integer */
+		{
+			return LUAOPENAL_FLOAT_3_TYPE;
+			break;
+		}
+
+		case AL_ORIENTATION: /* could be integer */
+		{
+			return LUAOPENAL_FLOAT_6_TYPE;
+			break;
+		}
+
+		case AL_NO_ERROR:
+		case AL_INVALID_NAME:
+		case AL_ILLEGAL_ENUM:
+/*		case AL_INVALID_ENUM: */ /* same as AL_ILLEGAL_ENUM */
+		case AL_INVALID_VALUE:
+		case AL_ILLEGAL_COMMAND:
+/*		case AL_INVALID_OPERATION: */ /* same as AL_ILLEGAL_COMMAND */
+		case AL_OUT_OF_MEMORY:
+		case AL_VENDOR:
+		case AL_VERSION:
+		case AL_RENDERER:
+		case AL_EXTENSIONS:
+		{
+			return LUAOPENAL_STRING_TYPE;
+			break;
+		}
+
+	}
+	return 0;
+}
+
+static int lua_alEnable(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	enum_parameter = lua_tointeger(lua_state, 1);
+	alEnable(enum_parameter);
+	return 0;
+}
+
+static int lua_alDisable(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	enum_parameter = lua_tointeger(lua_state, 1);
+	alDisable(enum_parameter);
+	return 0;
+}
+
+static int lua_alIsEnabled(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	ALboolean ret_val;
+	enum_parameter = lua_tointeger(lua_state, 1);
+	ret_val = alIsEnabled(enum_parameter);
+	lua_pushboolean(lua_state, ret_val);
+	return 1;
+}
+
+static int lua_alGetError(lua_State* lua_state)
+{
+	ALenum ret_val;
+	ret_val = alGetError();
+	lua_pushinteger(lua_state, ret_val);
+	return 1;
+}
+
+static int lua_alIsExtensionPresent(lua_State* lua_state)
+{
+	const ALchar* string_name;
+	ALboolean ret_val;
+	string_name = lua_tostring(lua_state, 1);
+	ret_val = alIsExtensionPresent(string_name);
+	lua_pushboolean(lua_state, ret_val);
+	return 1;
+}
+
+/* TODO: alGetProcAddress */
+
+static int lua_alGetEnumValue(lua_State* lua_state)
+{
+	const ALchar* string_name;
+	ALenum ret_val;
+	string_name = lua_tostring(lua_state, 1);
+	ret_val = alGetEnumValue(string_name);
+	lua_pushinteger(lua_state, ret_val);
+	return 1;
+}
+
+
+
+
+static int lua_alGetListener(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	int openal_primitive_type;
+
+	enum_parameter = lua_tointeger(lua_state, 1);
+
+	openal_primitive_type = lua_getTypeForEnum(enum_parameter);
+
+	switch(openal_primitive_type)
+	{
+		case LUAOPENAL_BOOL_TYPE:
+		{
+			ALint ret_val;
+			alGetListeneri(enum_parameter, &ret_val);
+			lua_pushboolean(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_INT_TYPE:
+		{
+			ALint ret_val;
+			alGetListeneri(enum_parameter, &ret_val);
+			lua_pushinteger(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_FLOAT_TYPE:
+		{
+			ALfloat ret_val;
+			alGetListenerf(enum_parameter, &ret_val);
+			lua_pushnumber(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_INT_3_TYPE:
+		{
+			ALint ret_val[3];
+			alGetListeneriv(enum_parameter, ret_val);
+			lua_pushinteger(lua_state, ret_val[0]);
+			lua_pushinteger(lua_state, ret_val[1]);
+			lua_pushinteger(lua_state, ret_val[2]);
+			return 3;
+			break;	
+		}
+		case LUAOPENAL_FLOAT_3_TYPE:
+		{
+			ALfloat ret_val[3];
+			alGetListenerfv(enum_parameter, ret_val);
+			lua_pushnumber(lua_state, ret_val[0]);
+			lua_pushnumber(lua_state, ret_val[1]);
+			lua_pushnumber(lua_state, ret_val[2]);
+			return 3;
+			break;			
+		}
+		case LUAOPENAL_FLOAT_6_TYPE:
+		{
+			ALfloat ret_val[6];
+			alGetListenerfv(enum_parameter, ret_val);
+			lua_pushnumber(lua_state, ret_val[0]);
+			lua_pushnumber(lua_state, ret_val[1]);
+			lua_pushnumber(lua_state, ret_val[2]);
+			lua_pushnumber(lua_state, ret_val[3]);
+			lua_pushnumber(lua_state, ret_val[4]);
+			lua_pushnumber(lua_state, ret_val[5]);
+			return 6;
+			break;			
+		}
+		default:
+		{
+			/* TODO: Figure out how to handle OpenAL extensions. */
+			luaL_error(lua_state, "Unhandled parameter type for alGetSource*");
+		}
+	}
+	return 0;
+}
+
+static int lua_alListener(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	int openal_primitive_type;
+
+	enum_parameter = lua_tointeger(lua_state, 1);
+
+
+	openal_primitive_type = lua_getTypeForEnum(enum_parameter);
+
+	switch(openal_primitive_type)
+	{
+		case LUAOPENAL_BOOL_TYPE:
+		case LUAOPENAL_INT_TYPE:
+		{
+			alListeneri(enum_parameter, lua_tointeger(lua_state, 2));
+			break;
+		}
+		case LUAOPENAL_FLOAT_TYPE:
+		{
+			alListenerf(enum_parameter, lua_tonumber(lua_state, 2));
+			break;
+		}
+		case LUAOPENAL_INT_3_TYPE:
+		{
+			alListener3i(enum_parameter, lua_tointeger(lua_state, 2), lua_tointeger(lua_state, 3),  lua_tointeger(lua_state, 4));
+			break;			
+		}
+		case LUAOPENAL_FLOAT_3_TYPE:
+		{
+			alListener3f(enum_parameter, lua_tonumber(lua_state, 2),  lua_tonumber(lua_state, 3),  lua_tonumber(lua_state, 4));
+			break;			
+		}
+		case LUAOPENAL_FLOAT_6_TYPE:
+		{
+			ALfloat val_array[6] = 
+			{
+				lua_tonumber(lua_state, 2),
+				lua_tonumber(lua_state, 3),
+				lua_tonumber(lua_state, 4),
+				lua_tonumber(lua_state, 5),
+				lua_tonumber(lua_state, 6),
+				lua_tonumber(lua_state, 7)
+			};
+
+			alListenerfv(enum_parameter, val_array);
+			break;			
+		}
+		default:
+		{
+			/* TODO: Figure out how to handle OpenAL extensions. */
+			luaL_error(lua_state, "Unhandled parameter type for alSource*");
+		}
+	}
+	return 0;
+}
+
+
+
+
+static int lua_alGetSource(lua_State* lua_state)
+{
+	ALuint source_id;
+	ALenum enum_parameter;
+	int openal_primitive_type;
+
+	source_id = lua_tointeger(lua_state, 1);
+	enum_parameter = lua_tointeger(lua_state, 2);
+
+	openal_primitive_type = lua_getTypeForEnum(enum_parameter);
+
+	switch(openal_primitive_type)
+	{
+		case LUAOPENAL_BOOL_TYPE:
+		{
+			ALint ret_val;
+			alGetSourcei(source_id, enum_parameter, &ret_val);
+			lua_pushboolean(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_INT_TYPE:
+		{
+			ALint ret_val;
+			alGetSourcei(source_id, enum_parameter, &ret_val);
+			lua_pushinteger(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_FLOAT_TYPE:
+		{
+			ALfloat ret_val;
+			alGetSourcef(source_id, enum_parameter, &ret_val);
+			lua_pushnumber(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_INT_3_TYPE:
+		{
+			ALint ret_val[3];
+			alGetSourceiv(source_id, enum_parameter, ret_val);
+			lua_pushinteger(lua_state, ret_val[0]);
+			lua_pushinteger(lua_state, ret_val[1]);
+			lua_pushinteger(lua_state, ret_val[2]);
+			return 3;
+			break;	
+		}
+		case LUAOPENAL_FLOAT_3_TYPE:
+		{
+			ALfloat ret_val[3];
+			alGetSourcefv(source_id, enum_parameter, ret_val);
+			lua_pushnumber(lua_state, ret_val[0]);
+			lua_pushnumber(lua_state, ret_val[1]);
+			lua_pushnumber(lua_state, ret_val[2]);
+			return 3;
+			break;			
+		}
+		default:
+		{
+			/* TODO: Figure out how to handle OpenAL extensions. */
+			luaL_error(lua_state, "Unhandled parameter type for alGetSource*");
+		}
+	}
+	return 0;
+}
+
+
+static int lua_alSource(lua_State* lua_state)
+{
+	ALuint source_id;
+	ALenum enum_parameter;
+	int openal_primitive_type;
+
+	source_id = lua_tointeger(lua_state, 1);
+	enum_parameter = lua_tointeger(lua_state, 2);
+
+	openal_primitive_type = lua_getTypeForEnum(enum_parameter);
+
+	switch(openal_primitive_type)
+	{
+		case LUAOPENAL_BOOL_TYPE:
+		case LUAOPENAL_INT_TYPE:
+		{
+			alSourcei(source_id, enum_parameter, lua_tointeger(lua_state, 3));
+			break;
+		}
+		case LUAOPENAL_FLOAT_TYPE:
+		{
+			alSourcef(source_id, enum_parameter, lua_tonumber(lua_state, 3));
+			break;
+		}
+		case LUAOPENAL_INT_3_TYPE:
+		{
+			alSource3i(source_id, enum_parameter, lua_tointeger(lua_state, 3), lua_tointeger(lua_state, 4),  lua_tointeger(lua_state, 5));
+			break;			
+		}
+		case LUAOPENAL_FLOAT_3_TYPE:
+		{
+			alSource3f(source_id, enum_parameter, lua_tonumber(lua_state, 3),  lua_tonumber(lua_state, 4),  lua_tonumber(lua_state, 5));
+			break;			
+		}
+		default:
+		{
+			/* TODO: Figure out how to handle OpenAL extensions. */
+			luaL_error(lua_state, "Unhandled parameter type for alSource*");
+		}
+	}
+	return 0;
+}
+
+
+static int lua_alDopplerFactor(lua_State* lua_state)
+{
+	ALfloat the_value;
+	the_value = lua_tonumber(lua_state, 1);
+	alDopplerFactor(the_value);
+	return 0;
+}
+
+static int lua_alDopplerVelocity(lua_State* lua_state)
+{
+	ALfloat the_value;
+	the_value = lua_tonumber(lua_state, 1);
+	alDopplerVelocity(the_value);
+	return 0;
+}
+
+static int lua_alSpeedOfSound(lua_State* lua_state)
+{
+	ALfloat the_value;
+	the_value = lua_tonumber(lua_state, 1);
+	alSpeedOfSound(the_value);
+	return 0;
+}
+
+static int lua_alDistanceModel(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	enum_parameter = lua_tointeger(lua_state, 1);
+	alDistanceModel(enum_parameter);
+	return 0;
+}
+
+static int lua_alGet(lua_State* lua_state)
+{
+	ALenum enum_parameter;
+	int openal_primitive_type;
+
+	enum_parameter = lua_tointeger(lua_state, 1);
+
+	openal_primitive_type = lua_getTypeForEnum(enum_parameter);
+
+	switch(openal_primitive_type)
+	{
+		case LUAOPENAL_BOOL_TYPE:
+		{
+			ALboolean ret_val;
+			ret_val = alGetBoolean(enum_parameter);
+			lua_pushboolean(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_INT_TYPE:
+		{
+			ALint ret_val;
+			ret_val = alGetInteger(enum_parameter);
+			lua_pushinteger(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_FLOAT_TYPE:
+		{
+			ALfloat ret_val;
+			ret_val = alGetFloat(enum_parameter);
+			lua_pushnumber(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		case LUAOPENAL_INT_3_TYPE:
+		{
+			ALint ret_val[3];
+			alGetIntegerv(enum_parameter, ret_val);
+			lua_pushinteger(lua_state, ret_val[0]);
+			lua_pushinteger(lua_state, ret_val[1]);
+			lua_pushinteger(lua_state, ret_val[2]);
+			return 3;
+			break;	
+		}
+		case LUAOPENAL_FLOAT_3_TYPE:
+		{
+			ALfloat ret_val[3];
+			alGetFloatv(enum_parameter, ret_val);
+			lua_pushnumber(lua_state, ret_val[0]);
+			lua_pushnumber(lua_state, ret_val[1]);
+			lua_pushnumber(lua_state, ret_val[2]);
+			return 3;
+			break;			
+		}
+		case LUAOPENAL_FLOAT_6_TYPE:
+		{
+			ALfloat ret_val[6];
+			alGetFloatv(enum_parameter, ret_val);
+			lua_pushnumber(lua_state, ret_val[0]);
+			lua_pushnumber(lua_state, ret_val[1]);
+			lua_pushnumber(lua_state, ret_val[2]);
+			lua_pushnumber(lua_state, ret_val[3]);
+			lua_pushnumber(lua_state, ret_val[4]);
+			lua_pushnumber(lua_state, ret_val[5]);
+			return 6;
+			break;			
+		}
+		case LUAOPENAL_STRING_TYPE:
+		{
+			const ALchar* ret_val;
+			ret_val = alGetString(enum_parameter);
+			lua_pushstring(lua_state, ret_val);
+			return 1;
+			break;
+		}
+		default:
+		{
+			/* TODO: Figure out how to handle OpenAL extensions. */
+			luaL_error(lua_state, "Unhandled parameter type for alGetSource*");
+		}
+	}
+	return 0;
+}
+
+static const luaL_reg luaALFuncs[] =
+{
+	{ "Enable", 								lua_alEnable },
+	{ "Disable", 								lua_alDisable },
+	{ "IsEnabled",								lua_alIsEnabled },
+	{ "Get", 									lua_alGet },
+	{ "GetError",								lua_alGetError },
+	{ "IsExtensionPresent", 					lua_alIsExtensionPresent },
+	{ "GetEnumValue",							lua_alGetEnumValue },
+	{ "Listener",								lua_alListener },
+	{ "GetListener", 							lua_alGetListener },
+	{ "Source", 								lua_alSource },
+	{ "GetSource",								lua_alGetSource },
+	{ "DopplerFactor",							lua_alDopplerFactor },
+	{ "DopplerVelocity", 						lua_alDopplerVelocity },
+	{ "SpeedOfSound",							lua_alSpeedOfSound },
+	{ "DistanceModel",							lua_alDistanceModel },
+	{ "DopplerVelocity", 						lua_alDopplerVelocity },
+	{NULL, NULL}
+};
+
+
+int luaopen_luaal(lua_State *L) 
+{
+  luaL_register(L, "al", luaALFuncs);
+
+  luaopenal_initenum(L, s_luaALEnum);
+
+  lua_pushstring(L, "_VERSION");
+  lua_pushstring(L, LUAAL_VERSION);
+  lua_settable(L,-3);
+
+  return 1;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/luaal/luaal.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,40 @@
+/*
+	LuaOpenAL
+	Copyright (C) 2010  Eric Wing <ewing . public @ playcontrol.net>
+
+	Permission is hereby granted, free of charge, to any person obtaining a copy
+	of this software and associated documentation files (the "Software"), to deal
+	in the Software without restriction, including without limitation the rights
+	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+	copies of the Software, and to permit persons to whom the Software is
+	furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be included in
+	all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+	THE SOFTWARE.
+
+*/
+
+#ifndef __LUAAL_H__
+#define __LUAAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int luaopen_luaal(lua_State* lua_state);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/tErrorLib.c	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,1264 @@
+/* See header file for license information. */
+
+#include "tErrorLib.h"
+#include <stdlib.h> /* for malloc */
+#include <string.h>
+#include <stdarg.h> /* for vasprintf */
+#include <stdio.h> /* also for vasprintf and for printf family */
+#include <stddef.h> /* size_t */
+
+/**
+ * For string-only based usage, this implementation
+ * still expects an actual error number to be set.
+ * I am defining 1 as that error value. This might be changable,
+ * but it is untested. If you change this value, you must recompile
+ * the entire library. This can really be any integer except what 
+ * TERROR_NOERROR_VALUE (in header) is set to.
+ */
+#define TERROR_ERROR_VALUE 1
+
+#ifdef DONT_USE_VASPRINT
+	#define TERROR_DEFAULT_STRING_LENGTH 128
+	/* Visual Studio doesn't define snprintf but _snprintf */
+	#ifdef _MSC_VER
+		#define snprintf _snprintf
+		#define vsnprintf _vsnprintf
+	#endif
+#endif
+
+
+#if defined(_WIN32) && !defined(__CYGWIN32__)
+		#include <windows.h>
+		#include <winbase.h> /* For CreateMutex(), LockFile() */
+
+		static void* Internal_CreateMutex()
+		{
+			return((void*)CreateMutex(NULL, FALSE, NULL));
+		}
+		static void Internal_DestroyMutex(void* mutex)
+		{
+			if(NULL != mutex)
+			{
+				CloseHandle( (HANDLE)mutex );
+			}
+		}
+		/* This will return true if locking is successful, false if not.
+		 */
+		static int Internal_LockMutex(void* mutex)
+		{
+			return(
+				WaitForSingleObject(
+					(HANDLE)mutex,
+					INFINITE
+				) != WAIT_FAILED
+			);
+		}
+		static void Internal_UnlockMutex(void* mutex)
+		{
+			ReleaseMutex(
+				(HANDLE)mutex
+			);
+		}
+		size_t Internal_PlatformPlatformGetThreadID(void)
+		{
+			return((size_t)GetCurrentThreadId());
+		}
+#else /* Assuming POSIX...maybe not a good assumption. */
+		#include <pthread.h>
+		static void* Internal_CreateMutex()
+		{
+			int ret_val;
+			pthread_mutex_t* m = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); 
+			if(NULL == m)
+			{
+				return NULL;
+			}
+			ret_val = pthread_mutex_init(m, NULL);
+			if(0 != ret_val)
+			{
+				free(m);
+				return NULL;
+			}
+			return((void*)m);
+		}
+		static void Internal_DestroyMutex(void* mutex)
+		{
+			if(NULL != mutex)
+			{
+				pthread_mutex_destroy((pthread_mutex_t*) (mutex));
+				free(mutex);
+			}
+		}
+		/* This will return true if locking is successful, false if not.
+		 * (This is the opposite of pthread_mutex_lock which returns 
+		 * 0 for success.)
+		 */
+		static int Internal_LockMutex(void* mutex)
+		{
+			return(
+				pthread_mutex_lock(
+					(pthread_mutex_t*)mutex
+				) == 0
+			);
+		}
+		static void Internal_UnlockMutex(void* mutex)
+		{
+			pthread_mutex_unlock(
+				(pthread_mutex_t*)mutex
+			);
+		}
+
+	size_t Internal_PlatformGetThreadID()
+	{
+		/* Basically, we need to convert a pthread_t into an id number. */
+	    return (size_t)pthread_self();
+	}
+#endif
+
+
+/**
+ * Copies a source string, potentially to a target string, and returns 
+ * the pointer to the copied string.
+ * This function is a intended to be an efficient string copy function.
+ * It's purpose is to copy a string into a string with preallocated memory
+ * and avoid dynamic memory allocation if possible. If memory must 
+ * be allocated, then the old string will be destroyed.
+ *
+ * This is only to be used where target_string was created with dynamic 
+ * memory. This function will destroy the memory and allocate new memory
+ * if there is not enough space in the target string.
+ *
+ * @param target_string This is the string you would like to try 
+ * to copy into. If there is not enough space, a new string will
+ * be created and the target_string will be freed. This string 
+ * must have been created dynamically. This may be NULL if you 
+ * wish for this function to dynamically create a new string 
+ * for you.
+ *
+ * @param target_max_buffer_size This is a pointer that points to 
+ * an address containing the size of the preallocated target_string. 
+ * This size is the maximum buffer length which includes the '\\0'
+ * character as part of that count. This pointer may not be NULL.
+ * If you pass in NULL for the target_string (indicating you want 
+ * a new string allocated for you), then the size should be set to 0.
+ * When the function completes, the size will be set to the new 
+ * max buffer size of the string if the string needed to be reallocated.
+ *
+ * @param source_string This is the string you want to copy. If it's NULL,
+ * the target_string will have it's memory freed.
+ *
+ * @return Will return a pointer to the duplicated string. Be aware 
+ * of several things:
+ * - The returned pointer address may not be the same address as the 
+ * target string passed in (due to a possible reallocation).
+ * - If the pointer to the source and target string 
+ * are the same, the pointer to the target string will be returned.
+ * - If the source string is NULL, the target string
+ * will be freed and will return NULL.
+ * - If an error occurs, NULL will be returned.
+ *
+ * Also note that the value at the address target_max_buffer_size points 
+ * to will be filled with the new max buffer size for the string.
+ *
+ * Example:
+ * @code
+ *
+ * int main()
+ * {
+ * 		const char* original1 = "Hello World";
+ * 		const char* original2 = "Smaller";
+ * 		const char* original3 = "Good-Bye World";
+ * 		char* ret_val;
+ * 		char* target = NULL;
+ * 		size_t target_max_buffer_size = 0;
+ *
+ * 		ret_val = CopyDynamicString(target, &target_max_buffer_size, original1);
+ *
+ * 		if(ret_val)
+ * 		{
+ * 			fprintf(stderr, "Target is '%s' with max size = %d\n", ret_val, target_max_buffer_size);
+ * 		}
+ * 		else
+ * 		{
+ * 			fprintf(stderr, "Error in function\n");
+ * 		}
+ *		target = ret_val;
+ *
+ *		ret_val = CopyDynamicString(target, &target_max_buffer_size, original2);
+ * 		fprintf(stderr, "Target is '%s' with max size = %d\n", ret_val, target_max_buffer_size);
+ *
+ * 		target = ret_val; *
+ * 		ret_val = CopyDynamicString(target, &target_max_buffer_size, original3);
+ * 		fprintf(stderr, "Target is '%s' with max size = %d\n", ret_val, target_max_buffer_size);
+ *
+ * 		return 0;
+ * }
+ * @endcode
+ * This outputs:
+ * @code
+ * Target is 'Hello World' with max size = 12
+ * Target is 'Smaller' with max size = 12
+ * Target is 'Good-Bye World' with max size = 15
+ * @endcode
+ */
+static char* Internal_CopyDynamicString(char* target_string, size_t* target_max_buffer_size, const char* source_string)
+{
+	/* If the pointers are the same, no copy is needed. */
+	if(source_string == target_string)
+	{
+		/* I don't feel like asserting if the sizes are the same. */
+		/* Return 1 instead of 0 because maybe this isn't an error?
+		 */
+		return target_string;
+	}
+
+	/* Make sure the size pointer is valid. */
+	if(NULL == target_max_buffer_size)
+	{
+		return NULL;
+	}
+
+	/* Yikes, if the string is NULL, should we make the target string NULL?
+	 * For now, yes, we destroy the string. If you change this, realize that
+	 * their is code that depends on this behavior.
+	 */
+	if(NULL == source_string)
+	{
+		*target_max_buffer_size = 0;
+		free(target_string);
+		target_string = NULL;
+		return NULL;
+	}
+
+	/* If target_string is NULL, the *target_max_buffer_size should also be 0.
+	 * Technically, the user should set this and this would be an error,
+	 * but I'll be nice for now. An alternate implementation might suggest 
+	 * that the size would be the desired size the user wants for a new string.
+	 */
+	if( (NULL == target_string) && (0 != *target_max_buffer_size) )
+	{
+		*target_max_buffer_size = 0;
+	}
+
+	/* If there is not enough preallocated memory in the target string,
+	 * then we need to reallocate enough memory.
+	 */
+	if( *target_max_buffer_size < (strlen(source_string) + 1) )
+	{
+		*target_max_buffer_size = 0;
+		if(NULL != target_string)
+		{
+			free(target_string);
+		}
+		target_string = (char*)calloc( (strlen(source_string) + 1), sizeof(char) );
+		if(NULL == target_string)
+		{
+			return NULL;
+		}
+		*target_max_buffer_size = strlen(source_string) + 1;
+	}
+
+	/* At this point, there should be enough preallocated 
+	 * memory to call strncpy.
+	 */
+	strncpy(target_string, source_string, *target_max_buffer_size);
+
+	return target_string;
+}
+
+/**
+ * This is a structure that contains everything needed for an 
+ * error message entry (per thread). The linked list stuff
+ * is fused in with it because I didn't want to write an entire 
+ * linked list class.
+ */
+typedef struct TErrorMessageStructType
+{
+	size_t threadID; /** ThreadID for associated message. */
+	int errorAvailable; /** 1 if an error has been set and not been checked. */
+	int errorNumber; /**< For the user error number. */
+	char* errorString; /**< For the user error message. */
+	size_t errorMaxStringLength; /**< Max size of string buffer including \\0. */
+	struct TErrorMessageStructType* nextItem; /**< Pointer to next error message in list. */
+} TErrorMessage;
+
+/**
+ * This is a private struct that contains all private data for an
+ * ErrorPool. Currently it is a linked list containing all error message
+ * structs for every thread.
+ */
+typedef struct
+{
+	TErrorMessage* errorMessageListHead; /**< Head of the error list. */
+	TErrorMessage* lastErrorMessage; /**< Points to the last set element in the list for GetLastError. */
+	/* Mutex */
+} TErrorPoolOpaqueData;
+
+/**
+ * This is a private helper function that creates a new TErrorMessage
+ * and initializes all its values.
+ * @return Returns a pointer to a newly allocated and initialized
+ * TErrorMessage or NULL on failure.
+ */
+static TErrorMessage* Internal_CreateErrorMessageStructure()
+{
+	TErrorMessage* new_message;
+	/* Use calloc to create a fully cleared structure,
+	 * so I don't have to set/clear each member.
+	 */
+	new_message = (TErrorMessage*)calloc(1, sizeof(TErrorMessage));
+	if(NULL == new_message)
+	{
+		/* Very bad, but not sure what to do. */
+		return NULL;
+	}
+	new_message->errorNumber = TERROR_NOERROR_VALUE;
+	return new_message;
+}
+
+/**
+ * This is a private helper function that frees a TErrorMessage.
+ *
+ * @param err_mesg The pointer to the TErrorMessage to be freed.
+ */
+static void Internal_FreeErrorMessageStructure(TErrorMessage* err_mesg)
+{
+	if(NULL == err_mesg)
+	{
+		return;
+	}
+	if(NULL != err_mesg->errorString)
+	{
+		free(err_mesg->errorString);
+		err_mesg->errorString = NULL;
+	}
+	err_mesg->nextItem = NULL;
+	free(err_mesg);
+}
+
+/**
+ * This is a private helper function that will search the error pool 
+ * for the last set error message structure in the Linked list.
+ * If the last error message was on a different thread, the error
+ * data will be copied to the current thread's memory and the 
+ * lastErrorMessage pointer will be set to the current thread's message.
+ * (This is because I expect this message to be marked as cleared/read.)
+ * This function does its own mutex locking.
+ *
+ * @param err_pool The error pool to be used.
+ * @return Returns the a pointer to the TErrorMessage if found,
+ * NULL if not found.
+ */
+static TErrorMessage* Internal_GetLastError(TErrorPool* err_pool)
+{
+	size_t thread_id;
+	TErrorMessage* current_thread_err_mesg;
+	TErrorPoolOpaqueData* err_pool_data;
+
+	thread_id = Internal_PlatformGetThreadID();
+	
+	Internal_LockMutex(err_pool->mutexLock);
+	
+	err_pool_data = err_pool->opaqueData;
+
+	if(NULL == err_pool_data->errorMessageListHead)
+	{
+		Internal_UnlockMutex(err_pool->mutexLock);
+		return NULL;
+	}
+
+	/* I think this is actually an assertion failure.
+	 * I do the check here so I don't have to keep checking below.
+	 */
+	if(NULL == err_pool_data->lastErrorMessage)
+	{
+		Internal_UnlockMutex(err_pool->mutexLock);
+		return NULL;
+	}
+
+	/* We need to determine if the lastMessage pointer is pointing 
+	 * to data on the current thread. If it is we can just return it.
+	 * Otherwise, we need to copy the message to the current thread's
+	 * error message memory area.
+	 * We should also update the lastMessage pointer to point
+	 * to this message since it will likely be marked cleared once read.
+	 */
+	if(thread_id == err_pool_data->lastErrorMessage->threadID)
+	{
+		/* Not copy is needed. The last error message already
+		 * points to the memory on the current thread.
+		 * We can short-circuit and return.
+		 */
+		Internal_UnlockMutex(err_pool->mutexLock);
+		return err_pool_data->lastErrorMessage;
+	}
+
+	/* Sigh, I really should have a dedicated linked list structure,
+	 * but I don't feel like writing it right now.
+	 */
+	for(current_thread_err_mesg = err_pool_data->errorMessageListHead; current_thread_err_mesg != NULL; current_thread_err_mesg = current_thread_err_mesg->nextItem)
+	{
+		/* First find the message (memory) for the current thread. */
+		if(thread_id == current_thread_err_mesg->threadID)
+		{
+			/* Now we need to copy the message data from the lastErrorMessage
+			 * to this thread's message (memory).
+			 */
+			current_thread_err_mesg->errorNumber = err_pool_data->lastErrorMessage->errorNumber;
+			current_thread_err_mesg->errorAvailable = err_pool_data->lastErrorMessage->errorAvailable;
+			/* This will copy the string and set the new errorMaxStringLength as needed. */
+			current_thread_err_mesg->errorString = Internal_CopyDynamicString(current_thread_err_mesg->errorString, &current_thread_err_mesg->errorMaxStringLength, err_pool_data->lastErrorMessage->errorString);
+
+
+			/* Finally, change the last error message to point to 
+			 * the current thread since I expect the message to be
+			 * marked cleared and we don't want to accidentally refetched
+			 * the stale, uncleared entry.
+			 */
+			err_pool_data->lastErrorMessage = current_thread_err_mesg;
+
+			Internal_UnlockMutex(err_pool->mutexLock);
+			return current_thread_err_mesg;
+		}
+	}
+	Internal_UnlockMutex(err_pool->mutexLock);
+	return NULL;
+}
+
+/**
+ * This is a private helper function that will search the error pool 
+ * for an error message structure in the Linked list (by thread ID)
+ * and return the pointer if found. This function does its own mutex
+ * locking.
+ * @param err_pool The error pool to be used.
+ * @return Returns the a pointer to the TErrorMessage if found,
+ * NULL if not found.
+ */
+static TErrorMessage* Internal_GetErrorOnCurrentThread(TErrorPool* err_pool)
+{
+	size_t thread_id;
+	TErrorMessage* current_err_mesg;
+	TErrorPoolOpaqueData* err_pool_data;
+
+	thread_id = Internal_PlatformGetThreadID();
+	
+	Internal_LockMutex(err_pool->mutexLock);
+	
+	err_pool_data = err_pool->opaqueData;
+
+	if(NULL == err_pool_data->errorMessageListHead)
+	{
+		Internal_UnlockMutex(err_pool->mutexLock);
+		return NULL;
+	}
+	
+	/* Sigh, I really should have a dedicated linked list structure,
+	 * but I don't feel like writing it right now.
+	 */
+	for(current_err_mesg = err_pool_data->errorMessageListHead; current_err_mesg != NULL; current_err_mesg = current_err_mesg->nextItem)
+	{
+		if(thread_id == current_err_mesg->threadID)
+		{
+			Internal_UnlockMutex(err_pool->mutexLock);
+			return current_err_mesg;
+		}
+	}
+	Internal_UnlockMutex(err_pool->mutexLock);
+	return NULL;
+}
+
+/**
+ * Given a specific TErrorMessage*, will set the lastErrorMessage pointer to
+ * the provided error message.
+ * This function locks.
+ *
+ * @param err_pool The error pool to be used.
+ * @param error_message The error message to set the lastErrorMessage pointer to
+ */
+static void Internal_SetLastErrorMessagePointerToErrorMessage(TErrorPool* err_pool, TErrorMessage* error_message)
+{
+	TErrorPoolOpaqueData* err_pool_data;	
+	Internal_LockMutex(err_pool->mutexLock);
+	err_pool_data = err_pool->opaqueData;
+	err_pool_data->lastErrorMessage = error_message;
+	Internal_UnlockMutex(err_pool->mutexLock);
+}
+
+
+/**
+ * This is a private helper function that creates a new error message
+ * structure for the current thread.
+ * This currently does not check if an error already exists
+ * before creating a new entry. Call GetErrorOnCurrentThread first
+ * to make sure nothing exists or duplicate entries will be created.
+ * This function does its own mutex locking.
+ * 
+ * @param err_pool The error pool to be used.
+ * @return Returns the a pointer to the TErrorMessage if found,
+ * NULL if there was an allocation error.
+ */
+static TErrorMessage* Internal_CreateErrorOnCurrentThread(TErrorPool* err_pool)
+{
+	TErrorMessage* new_err_mesg;
+	TErrorPoolOpaqueData* err_pool_data;
+
+	new_err_mesg = Internal_CreateErrorMessageStructure();
+	if(NULL == new_err_mesg)
+	{
+		/* Serious problem, not sure what to do. */
+		return NULL;
+	}
+	/* Copy the thread id so we can distinguish between entries. */
+	new_err_mesg->threadID = Internal_PlatformGetThreadID();
+
+	Internal_LockMutex(err_pool->mutexLock);
+
+	err_pool_data = err_pool->opaqueData;
+	/* Add the new message to the top of the list by making 
+	 * its next pointer point to the head of the current list.
+	 * (A formal linked list implementation would make this feel 
+	 * less hacky.)
+	 * This also (should) handle the case where errorMessageListHead
+	 * is NULL.
+	 */
+	new_err_mesg->nextItem = err_pool_data->errorMessageListHead;
+	/* Now set the head of the list to the new message.
+	 */
+	err_pool_data->errorMessageListHead = new_err_mesg;
+	
+	Internal_UnlockMutex(err_pool->mutexLock);
+
+	return new_err_mesg;
+}
+
+/**
+ * This is a private helper function that will clean up all the 
+ * error message structures in the list. This function does its 
+ * own locking.
+ * @param err_pool The error pool to be used.
+ */
+static void Internal_FreeErrorMessageList(TErrorPool* err_pool)
+{
+	TErrorMessage* current_message = NULL;
+	TErrorMessage* next_message = NULL;
+	TErrorPoolOpaqueData* err_pool_data;
+
+	Internal_LockMutex(err_pool->mutexLock);
+	
+	err_pool_data = err_pool->opaqueData;
+
+	if(NULL == err_pool_data->errorMessageListHead)
+	{
+		Internal_UnlockMutex(err_pool->mutexLock);
+		return;
+	}
+	
+	/* Sigh, I really should have a dedicated linked list structure,
+	 * but I don't feel like writing it right now.
+	 */
+	for(current_message = err_pool_data->errorMessageListHead;
+		current_message != NULL;
+		current_message = next_message
+	)
+	{
+		next_message = current_message->nextItem;
+		Internal_FreeErrorMessageStructure(current_message);
+	}
+	err_pool_data->errorMessageListHead = NULL;
+	err_pool_data->lastErrorMessage = NULL;
+
+	Internal_UnlockMutex(err_pool->mutexLock);
+}
+
+/* 
+ * API functions start below.
+ *
+ */
+
+
+void TError_DeleteEntryOnCurrentThread(TErrorPool* err_pool)
+{
+	TErrorMessage* prev_message = NULL;
+	TErrorMessage* current_message = NULL;
+	TErrorMessage* next_message = NULL;
+	size_t thread_id;
+	TErrorPoolOpaqueData* err_pool_data;
+
+	thread_id = Internal_PlatformGetThreadID();
+	
+	Internal_LockMutex(err_pool->mutexLock);
+
+	err_pool_data = err_pool->opaqueData;
+
+	if(NULL == err_pool_data->errorMessageListHead)
+	{
+		Internal_UnlockMutex(err_pool->mutexLock);
+		return;
+	}
+	
+	/* Sigh, I really should have a dedicated linked list structure,
+	 * but I don't feel like writing it right now.
+	 */
+	for(current_message = err_pool_data->errorMessageListHead;
+		current_message != NULL;
+		/* I'm not going to increment here because I
+		 * may delete the item below which would probably 
+		 * cause bad things to happen here.
+		 */
+/* 		current_message = current_message->nextItem */
+	)
+	{
+		next_message = current_message->nextItem;
+		
+		if(thread_id == current_message->threadID)
+		{
+			/* Special case, current is only item in list:
+			 * Both next and prev are NULL in this case.
+			 * We should delete the item and set the errorMessageListHead
+			 * to NULL.
+			 */
+			if((NULL == prev_message) && (NULL == next_message))
+			{
+				Internal_FreeErrorMessageStructure(current_message);
+				current_message = NULL;
+				err_pool_data->errorMessageListHead = NULL;
+				err_pool_data->lastErrorMessage = NULL;
+			}
+			/* Special case, current is at head:
+			 * Prev is NULL but next is not NULL in this case.
+			 * We should delete the item and set the errorMessageListHead
+			 * to point to next.
+			 * (The code for the above case would probably work for 
+			 * this case too, but for clarity, this remains.)
+			 */
+			else if(NULL == prev_message)
+			{
+				/* If the current message happened to be the last message
+				 * set, we need to change the lastErrorMessage pointer
+				 * so it is not dangling.
+				 */
+				if(current_message == err_pool_data->lastErrorMessage)
+				{
+					err_pool_data->lastErrorMessage = NULL;
+				}
+				Internal_FreeErrorMessageStructure(current_message);
+				current_message = NULL;
+				err_pool_data->errorMessageListHead = next_message;
+			}
+			/* Special case, current is at tail.
+			 * Prev is not NULL, but next is NULL in this case.
+			 * We should delete the item and set prev->next to NULL.
+			 */
+			else if(NULL == next_message)
+			{
+				/* If the current message happened to be the last message
+				 * set, we need to change the lastErrorMessage pointer
+				 * so it is not dangling.
+				 */
+				if(current_message == err_pool_data->lastErrorMessage)
+				{
+					err_pool_data->lastErrorMessage = NULL;
+				}
+				Internal_FreeErrorMessageStructure(current_message);
+				current_message = NULL;
+				prev_message->nextItem = NULL;
+			}
+			/* Normal case, current is somewhere in the middle of the list.
+			 * The item should be deleted and
+			 * the prev_message->next should connect to 
+			 * the next_message.
+			 */
+			else
+			{
+				/* If the current message happened to be the last message
+				 * set, we need to change the lastErrorMessage pointer
+				 * so it is not dangling.
+				 */
+				if(current_message == err_pool_data->lastErrorMessage)
+				{
+					err_pool_data->lastErrorMessage = NULL;
+				}
+				Internal_FreeErrorMessageStructure(current_message);
+				current_message = NULL;
+				prev_message->nextItem = next_message;
+			}
+		}
+		/* It's not this thread, so increment everything for the next loop. */
+		else
+		{
+			prev_message = current_message;
+			current_message = next_message;
+		}
+	} /* End for-loop */
+
+	Internal_UnlockMutex(err_pool->mutexLock);
+}
+
+
+void TError_GetLinkedVersion(TErrorVersion* ver)
+{
+	/* Check the pointer */
+	if(NULL == ver)
+	{
+		/* Do nothing */
+		return;
+	}
+	ver->major = TERROR_MAJOR_VERSION;
+	ver->minor = TERROR_MINOR_VERSION;
+	ver->patch = TERROR_PATCH_VERSION;
+}
+
+
+#if 0
+/* This is for global initialization, not pool initialization. */
+int TError_Init()
+{
+	/* initialize platform? */
+	/* initialize mutexes? */
+
+}
+#endif
+
+TErrorPool* TError_CreateErrorPool()
+{
+	TErrorPool* err_pool;
+	TErrorPoolOpaqueData* err_pool_data;
+	
+	err_pool = (TErrorPool*)calloc(1, sizeof(TErrorPool));
+	if(NULL == err_pool)
+	{
+		/* Very bad, but not sure what to do here. */
+		return NULL;
+	}
+	err_pool_data = (TErrorPoolOpaqueData*)calloc(1, sizeof(TErrorPoolOpaqueData));
+	if(NULL == err_pool_data)
+	{
+		/* Very bad, but not sure what to do here. */
+		free(err_pool);
+		return NULL;
+	}
+
+	/* Create mutex */
+	err_pool->mutexLock = Internal_CreateMutex();
+	
+	if(NULL == err_pool->mutexLock)
+	{
+		/* Very bad, but not sure what to do here. */
+		free(err_pool_data);
+		free(err_pool);
+		return NULL;
+	}
+	
+	/* Attach the opaque data to the error pool. */
+	err_pool->opaqueData = err_pool_data;
+
+	/* The OpaqueData will hold the error message list, but it is 
+	 * allowed to be NULL for an empty list so we don't have to allocate
+	 * it here.
+	 */
+
+	return err_pool;
+}
+
+/* There better not be any contention when this is called. */
+void TError_FreeErrorPool(TErrorPool* err_pool)
+{
+	if(NULL == err_pool)
+	{
+		return;
+	}
+	/* Free all the error messages for each thread.
+	 * This locks and unlocks as it needs.
+	 */
+	Internal_FreeErrorMessageList(err_pool);
+
+	/* Free opaque data structure. */
+	free(err_pool->opaqueData);
+
+	/* Delete mutex after all locking functions. */
+	Internal_DestroyMutex(err_pool->mutexLock);
+
+	/* Free main data structure. */
+	free(err_pool);
+}
+
+void TError_SetError(TErrorPool* err_pool, int err_num, const char* err_str, ...)
+{
+	va_list argp;
+	va_start(argp, err_str);
+	TError_SetErrorv(err_pool, err_num, err_str, argp);
+	va_end(argp);
+}
+
+void TError_SetErrorv(TErrorPool* err_pool, int err_num, const char* err_str, va_list argp)
+{
+	TErrorMessage* error_message;
+	int ret_num_chars;
+	
+	if(NULL == err_pool)
+	{
+		return;
+	}
+
+	error_message = Internal_GetErrorOnCurrentThread(err_pool);
+	/* If no error message was found, that means we must allocate
+	 * a new entry for this entry.
+	 */
+	if(NULL == error_message)
+	{
+		error_message = Internal_CreateErrorOnCurrentThread(err_pool);
+		/* If this fails, this is bad...not sure what to do though. */
+		if(NULL == error_message)
+		{
+			return;
+		}
+	}
+
+	/*
+	 * I don't think I have to lock here. The [Get|Create]ErrorOnCurrentThread
+	 * functions lock err_pool as they need access. Here, I don't access
+	 * err_pool (which is shared) and error_message should be unique for 
+	 * each thread so I don't think there is any contention. (Remember that
+	 * simultaneous calls to SetError would only happen if they are in 
+	 * different threads.)
+	 * There *might* be a problem with library calls (strncpy, calloc). 
+	 * I'm not sure if the various platforms are reentrant. 
+	 * I guess for now, I will assume they won't bite me.
+	 */
+
+	/* If the err_str is NULL, we need to free our current string
+	 * for consistency. More aggressive optimizations to hold the 
+	 * memory might be considered in the future.
+	 */
+	if(NULL == err_str)
+	{
+		if(NULL != error_message->errorString)
+		{
+			free(error_message->errorString);
+			error_message->errorString = NULL;
+			error_message->errorMaxStringLength = 0;
+		}
+	}
+	/* Else, copy the string */
+	else
+	{
+		/* I am using vasprintf which is a GNU extension so it is not 
+		 * portable. However, vasprintf makes certain things possible
+		 * which would not be otherwise, which is the reason for my 
+		 * use. The main benefit of asprintf/vasprintf is that you can
+		 * create a string using printf style formatters without 
+		 * worrying about the buffer size. sprintf should never be 
+		 * used because of potential buffer overflows. snprintf
+		 * is safer, but you are limited to a fixed size string
+		 * which from time-to-time, I have exceeded unless you make
+		 * the number really big. 
+		 * Furthermore, snprintf itself is not currently terribly portable
+		 * because it is specified only for C99 which some compilers 
+		 * still have not have embraced.
+		 * If you can't use the vasprintf implementation, 
+		 * you must add -DDONT_USE_VASPRINTF to your compile flags.
+		 */
+#ifdef DONT_USE_VASPRINTF
+		/* This implementation uses vsnprintf instead of 
+		 * vasprintf. It is strongly recommended you use
+		 * the vasprintf implmententation instead.
+		 * Never use vsprintf unless you like 
+		 * buffer overflows and security exploits.
+		 */
+		
+		/* If the string was set to NULL, we must reallocate memory first. */
+		if(NULL == error_message->errorString)
+		{
+			error_message->errorString = (char*)calloc(TERROR_DEFAULT_STRING_LENGTH, sizeof(char));
+			if(NULL == error_message->errorString)
+			{
+				/* Very bad...what should I do?
+				 */
+				error_message->errorMaxStringLength = 0;
+			}
+			else
+			{
+				error_message->errorMaxStringLength = TERROR_DEFAULT_STRING_LENGTH;
+			}
+		}
+		/* Because of the "Very Bad" situation directly above, 
+		 * I need to check again to make sure the string isn't NULL.
+		 * This will let the very bad situation continue on so va_end
+		 * can be called and the error_number still has a chance to be set.
+		 */
+		if(NULL != error_message->errorString)
+		{
+			ret_num_chars = vsnprintf(error_message->errorString, 
+				error_message->errorMaxStringLength,
+				err_str,
+				argp
+			);
+		}
+
+#else /* DONT_USE_VASPRINTF */
+		/* You might be wondering why the #ifdef logic assumes 
+		 * asprintf is available instead of requiring an explicit 
+		 * #define for that. The reason is because asprintf is the 
+		 * better option and I want you to realize that you are not 
+		 * using it. Typically, nobody knows or understands the build
+		 * system and/or files get copied into new projects with a 
+		 * entirely new build system, so it is easy to forget to 
+		 * add a -D flag. So if you compile without asprintf,
+		 * you are encouraged to explicitly know this.
+		 */
+		/* There may be a slight performance advantage to using snprintf
+		 * over asprintf depending how asprintf is written. But this 
+		 * implementation will completely destroy and reallocate a 
+		 * string regardless if a string is set to NULL, so there will
+		 * actually be no performance gains for these cases. 
+		 * (This could be optimized but some additional bookkeeping 
+		 * might be needed which might not be worth the effort and 
+		 * code clutter.)
+		 * As for memory allocation safety, because new messages for 
+		 * different threads must be allocated dynamically, there is no
+		 * way for this library to use purely static memory.
+		 * So I don't believe there is anything to be gained using
+		 * snprintf over asprintf and you lose out on arbitrary lengthed
+		 * error messages.
+		 * If memory allocation must be minimized, I recommend just 
+		 * using the error number interface by itself which 
+		 * will always keep the strings at NULL, and don't mess 
+		 * with the asprintf/sprintf code.
+		 */
+
+		ret_num_chars = vasprintf(&error_message->errorString, err_str, argp);
+		/* vasprintf returns -1 as an error */
+		if(-1 == ret_num_chars)
+		{
+			/* Very bad, but not sure what to do here. */
+			if(NULL != error_message->errorString)
+			{
+				free(error_message->errorString);
+				error_message->errorString = NULL;
+				error_message->errorMaxStringLength = 0;
+				/* Don't return here. Still need to va_end, and
+				 * there is a chance that the err_num might work.
+				 * Plus the availability needs to be set.
+				 */
+			}
+		}
+		/* else vasprint returns the number of characters in the string
+		 * not including the \0 character.
+		 */
+		else
+		{
+			/* I actually don't know how much memory vasprintf allocated
+			 * for the string. But it is at least ret_num_chars+1, so
+			 * I will use that as my max string length (which is 
+			 * mainly used by CopyDynamicString() for efficiency 
+			 * which is becoming less used in this code).
+			 */
+			error_message->errorMaxStringLength = ret_num_chars+1;
+		}	
+#endif /* DONT_USE_VASPRINTF */
+	}
+
+	/* I'm allowing for a user to explicitly clear an error message by 
+	 * clearing both attributes.
+	 */
+	if((TERROR_NOERROR_VALUE == err_num) && (NULL == err_str))
+	{
+		error_message->errorNumber = TERROR_NOERROR_VALUE;
+		error_message->errorAvailable = 0;
+	}
+	/* This is the normal case, copy the error number
+	 * and mark the error as unread.
+	 */
+	else
+	{
+		error_message->errorNumber = err_num;
+		error_message->errorAvailable = 1;
+	}
+
+	/* Now that the data is set, we also want to denote that this
+	 * thread is the last error message. We need to lock for this
+	 * since the lastError pointer is shared across threads.
+	 */
+	Internal_SetLastErrorMessagePointerToErrorMessage(err_pool, error_message);
+}
+
+void TError_SetErrorNoFormat(TErrorPool* err_pool, int err_num, const char* err_str)
+{
+	TErrorMessage* error_message;
+	if(NULL == err_pool)
+	{
+		return;
+	}
+
+	error_message = Internal_GetErrorOnCurrentThread(err_pool);
+	/* If no error message was found, that means we must allocate
+	 * a new entry for this entry.
+	 */
+	if(NULL == error_message)
+	{
+		error_message = Internal_CreateErrorOnCurrentThread(err_pool);
+		/* If this fails, this is bad...not sure what to do though. */
+		if(NULL == error_message)
+		{
+			return;
+		}
+	}
+
+	/*
+	 * I don't think I have to lock here. The [Get|Create]ErrorOnCurrentThread
+	 * functions lock err_pool as they need access. Here, I don't access
+	 * err_pool (which is shared) and error_message should be unique for 
+	 * each thread so I don't think there is any contention. (Remember that
+	 * simultaneous calls to SetError would only happen if they are in 
+	 * different threads.)
+	 * There *might* be a problem with library calls (strncpy, calloc). 
+	 * I'm not sure if the various platforms are reentrant. 
+	 * I guess for now, I will assume they won't bite me.
+	 */
+	error_message->errorNumber = err_num;
+	/* This will copy the string and set the new errorMaxStringLength as needed. */
+	error_message->errorString = Internal_CopyDynamicString(error_message->errorString, &error_message->errorMaxStringLength, err_str);
+	/* I'm allowing for a user to explicitly clear an error message by 
+	 * clearing both attributes.
+	 */
+	if((TERROR_NOERROR_VALUE == err_num) && (NULL == err_str))
+	{
+		error_message->errorAvailable = 0;
+	}
+	else
+	{
+		error_message->errorAvailable = 1;
+	}
+	
+	/* Now that the data is set, we also want to denote that this
+	 * thread is the last error message. We need to lock for this
+	 * since the lastError pointer is shared across threads.
+	 */
+	Internal_SetLastErrorMessagePointerToErrorMessage(err_pool, error_message);
+}
+
+void TError_SetErrorNum(TErrorPool* err_pool, int err_num)
+{
+	TError_SetErrorNoFormat(err_pool, err_num, NULL);
+}
+
+void TError_SetErrorStr(TErrorPool* err_pool, const char* err_str, ...)
+{
+	va_list argp;
+	va_start(argp, err_str);
+	if(NULL == err_str)
+	{
+		TError_SetErrorv(err_pool, TERROR_NOERROR_VALUE, err_str, argp);
+	}
+	else
+	{
+		TError_SetErrorv(err_pool, TERROR_ERROR_VALUE, err_str, argp);
+	}
+	va_end(argp);
+}
+
+void TError_SetErrorStrv(TErrorPool* err_pool, const char* err_str, va_list argp) 
+{
+	if(NULL == err_str)
+	{
+		TError_SetErrorv(err_pool, TERROR_NOERROR_VALUE, err_str, argp);
+	}
+	else
+	{
+		TError_SetErrorv(err_pool, TERROR_ERROR_VALUE, err_str, argp);
+	}
+}
+
+/* If a NULL string is set, then it is presumed no error actually occurred
+ * and this is a reset. So the err_num will be implicitly set to 0. Otherwise
+ * the err_num will be set to 1 (for internal consistency and conventions).
+ */
+void TError_SetErrorStrNoFormat(TErrorPool* err_pool, const char* err_str)
+{
+	if(NULL == err_str)
+	{
+		TError_SetErrorNoFormat(err_pool, TERROR_NOERROR_VALUE, err_str);
+	}
+	else
+	{
+		TError_SetErrorNoFormat(err_pool, TERROR_ERROR_VALUE, err_str);
+	}
+}
+
+/* This currently returns 0 as a "no error found" value.
+ * This could potentially conflict with a user. For now, users 
+ * shouldn't use 0 to represent an error. If this becomes a 
+ * problem, we could introduce a magic number like -999999 and 
+ * define TERROR_NO_ERROR_FOUND.
+ */
+int TError_GetErrorNumOnCurrentThread(TErrorPool* err_pool)
+{
+	TErrorMessage* error_message;
+
+	error_message = Internal_GetErrorOnCurrentThread(err_pool);
+	
+	/* If no error message was found for the thread. */
+	if(NULL == error_message)
+	{
+		return 0;
+	}
+	/* If an error message was found for the thread, but 
+	 * it has already been read/cleared.
+	 */
+	if(0 == error_message->errorAvailable)
+	{
+		return 0;
+	}
+	/* We found a legitimate error message, clear it and return it. */
+	error_message->errorAvailable = 0;
+	return error_message->errorNumber;
+}
+
+const char* TError_GetErrorStrOnCurrentThread(TErrorPool* err_pool)
+{
+	TErrorMessage* error_message;
+
+	error_message = Internal_GetErrorOnCurrentThread(err_pool);
+	
+	/* If no error message was found for the thread. */
+	if(NULL == error_message)
+	{
+		return 0;
+	}
+	/* If an error message was found for the thread, but 
+	 * it has already been read/cleared.
+	 */
+	if(0 == error_message->errorAvailable)
+	{
+		return 0;
+	}
+	/* We found a legitimate error message, clear it and return it. */
+	error_message->errorAvailable = 0;
+	return error_message->errorString;
+}
+
+TErrorStatus TError_GetErrorOnCurrentThread(TErrorPool* err_pool)
+{
+	TErrorMessage* error_message;
+	TErrorStatus error_container;
+	error_container.errorNumber = TERROR_NOERROR_VALUE;
+	error_container.errorString = NULL;
+	
+	error_message = Internal_GetErrorOnCurrentThread(err_pool);
+	
+	/* If no error message was found for the thread. */
+	if(NULL == error_message)
+	{
+		return error_container;
+	}
+	/* If an error message was found for the thread, but 
+	 * it has already been read/cleared.
+	 */
+	if(0 == error_message->errorAvailable)
+	{
+		return error_container;
+	}
+	/* We found a legitimate error message, clear it and return it. */
+	error_message->errorAvailable = 0;
+	
+	error_container.errorNumber = error_message->errorNumber;
+	error_container.errorString = error_message->errorString;
+	return error_container;
+}
+
+/* This function is for alternative usage where you just want one error 
+ * for all threads. The backend will still work the same, but when you
+ * call this function, it will look up the last set error, copy (with locking)
+ * the last error to the current thread's memory, and return the object.
+ * As always, since the returned object is only accessed on this thread, you
+ * don't have to worry about locking.
+ */
+TErrorStatus TError_GetLastError(TErrorPool* err_pool)
+{
+
+	// Lock the error pool to get the lastMessage pointer
+	// if the lastMessage pointer is pointing to data on the current thread,
+	// we can just return it.
+	// Otherwise, we need to copy the message 
+
+	TErrorMessage* error_message;
+	TErrorStatus error_container;
+	error_container.errorNumber = TERROR_NOERROR_VALUE;
+	error_container.errorString = NULL;
+	
+	error_message = Internal_GetLastError(err_pool);
+	
+	/* If no error message was found for the thread. */
+	if(NULL == error_message)
+	{
+		return error_container;
+	}
+	/* If an error message was found for the thread, but 
+	 * it has already been read/cleared.
+	 */
+	if(0 == error_message->errorAvailable)
+	{
+		return error_container;
+	}
+	/* We found a legitimate error message, clear it and return it. */
+	error_message->errorAvailable = 0;
+	
+	error_container.errorNumber = error_message->errorNumber;
+	error_container.errorString = error_message->errorString;
+	return error_container;
+}
+
+/* This currently returns 0 as a "no error found" value.
+ * This could potentially conflict with a user. For now, users 
+ * shouldn't use 0 to represent an error. If this becomes a 
+ * problem, we could introduce a magic number like -999999 and 
+ * define TERROR_NO_ERROR_FOUND.
+ */
+int TError_GetLastErrorNum(TErrorPool* err_pool)
+{
+	TErrorMessage* error_message;
+
+	error_message = Internal_GetLastError(err_pool);
+	
+	/* If no error message was found for the thread. */
+	if(NULL == error_message)
+	{
+		return 0;
+	}
+	/* If an error message was found for the thread, but 
+	 * it has already been read/cleared.
+	 */
+	if(0 == error_message->errorAvailable)
+	{
+		return 0;
+	}
+	/* We found a legitimate error message, clear it and return it. */
+	error_message->errorAvailable = 0;
+	return error_message->errorNumber;
+}
+
+const char* TError_GetLastErrorStr(TErrorPool* err_pool)
+{
+	TErrorMessage* error_message;
+
+	error_message = Internal_GetLastError(err_pool);
+	
+	/* If no error message was found for the thread. */
+	if(NULL == error_message)
+	{
+		return 0;
+	}
+	/* If an error message was found for the thread, but 
+	 * it has already been read/cleared.
+	 */
+	if(0 == error_message->errorAvailable)
+	{
+		return 0;
+	}
+	/* We found a legitimate error message, clear it and return it. */
+	error_message->errorAvailable = 0;
+	return error_message->errorString;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Isolated/tErrorLib.h	Thu Apr 28 16:22:30 2011 -0700
@@ -0,0 +1,714 @@
+/*
+ * zlib license.
+ */
+/*
+   Copyright (c) 2003 Eric Wing <ewing . public @ playcontrol.net>
+
+   This software is provided 'as-is', without any express or implied warranty.
+   In no event will the authors be held liable for any damages arising from
+   the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software in a
+   product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+   3. This notice may not be removed or altered from any source distribution.
+
+*/
+/**
+ * @file
+ * This is a Thread Safe Error handling Library. (How safe is still to be
+ * determined.) The name ErrorLib was already taken. TSError might work, but
+ * Terror was more fun to use. Named tErrorLib just in case of 
+ * any conflicts with others who use "terror".
+ *
+ * This library is a generalized error flagging library. When an error 
+ * occurs, this library allows you to set an error condition (a number 
+ * and/or string) which can be fetched by at a later time (perhaps in a 
+ * different module). It is analgous to perror or glGetError(), though
+ * perhaps a closer analogy might be to SDL_SetError() as this library 
+ * allows you to deal with both integer numbers as well as printf-style
+ * formatted strings.
+ *
+ * This library also attempts to implement a certain degree of thread 
+ * safety. The problem with a general access error system used 
+ * by multiple threads is the risk of clobbering error messages set 
+ * in one thread by error messages set in other threads before you 
+ * get a chance to read them. This library solves that problem by 
+ * creating separate error message structures for every unique thread.
+ *
+ * This library is unique in several ways. First, this is an entirely
+ * self-contained, error-handling-only library. Most people seem to at 
+ * best rewrite their own error handling system for each library they write 
+ * (and at worst, don't write any error handling system at all).
+ * 
+ * Second, because this library is intended for just error handling, 
+ * it was designed with the idea that it could be dropped into any 
+ * library you choose and you are allowed to have separate/isolated 
+ * error "pools". So for example, if you were writing multiple modules,
+ * such as a graphics library, a sound library, and an application core, 
+ * you might desire to have separate error pools for each system so 
+ * they don't collide.
+ * In order to accommodate the possible multiple instance of pools, the 
+ * library has been factored into an object-oriented structure. Since 
+ * this library is C-based, it does impose an additional parameter to 
+ * be passed around than what people might be used to, but this 
+ * API could be wrapped easily that hides the object pointer using a
+ * static or global variable for your module if you choose.
+ *
+ * Finally, this library allows the use of either/both integer or string
+ * errors. Integer error numbers allow for quick access and easy comparison.
+ * It may also allow for easier internationalization of error messages 
+ * if you maintain a look-up-table.
+ * String error messages are nice because you know what the problem is 
+ * immediately (don't have to hunt down or figure out what error 427 means).
+ * They also help make the code self documenting. And if you have errors 
+ * nested down in function call layers, you can easily report the 
+ * function call stack by appending information to the error string
+ * at each function call.
+ * 
+ * Keep in mind that this library isn't meant to replace other error 
+ * reporting conventions, but to supplement them. Functions that return 
+ * error values (true/false,int) and logging systems (Logger) are still
+ * good systems that may address other issues. You might continue 
+ * using error codes for your functions and then use tErrorLib to 
+ * fetch the error string when you need them. And to log the error, 
+ * you might pass the string into Logger.
+ *
+ * There are two different ways to use this library with respect to 
+ * retrieving errors. You can treat each thread separately and let each
+ * live in its own separate world. When you retrieve the error, you only 
+ * retrieve the error for the current thread. You should use the
+ * TError_GetErrorOnCurrentThread family of functions for this scenario.
+ * Alternatively, you can use this library to always return you the last
+ * set error regardless of the thread it was set in. You should use the
+ * TError_GetLastError family of functions for this scenario.
+ * 
+ * Sample Usage:
+ * @code
+ * TErrorPool* err_pool;
+ * TErrorStatus error_status;
+ * 
+ * err_pool = TError_CreateErrorPool();
+ * if(NULL == err_pool)
+ * {
+ *	 	fprintf(stderr, "Error, could not create error pool\n");
+ *  	exit(1);
+ * }
+ *
+ * // Set a hypothetical error
+ * TError_SetError(err_pool, -1234, "Demo error #%d: %s", 222, "Hello");
+ *
+ * // Check/get the error using the isolated thread usage model.
+ * // Might use TError_GetErrorNumOnCurrentThread or TError_GetErrorStrOnCurrentThread instead
+ * error_status = TError_GetErrorOnCurrentThread(err_pool);
+ * // Make sure the string is not NULL before printing it with printf.
+ * // (Some systems let you print NULL, but on Solaris, it seg faults.)
+ * if(NULL != error_status.errorString)
+ * {
+ * 		printf("%d: %s", error_status.errorNumber, error_status.errorString);
+ * }
+ *
+ * // not really necessary to call since single threaded and
+ * // going to delete the entire pool right after, but here for show.
+ * TError_DeleteEntryOnCurrentThread(err_pool);
+ *
+ * TError_FreeErrorPool(err_pool);
+ *
+ * @endcode
+ *
+ * Sample API Wrapping:
+ * This is an example of how you might want to wrap this library into
+ * your own API code so you don't have to expose the error pool.
+ * This example uses the last set error usage model.
+ * (If you didn't want to use both integers and strings, you could 
+ * also make that decision here.)
+ *
+ * @code
+ * #include "tErrorLib.h"
+ * static TErrorPool* s_ErrorPool = NULL; // static error pool for this module 
+ * 
+ * int MyLibraryInit()
+ * {
+ * 		// Presumably you have you application specific code here too.
+ * 		s_ErrorPool = TError_CreateErrorPool();
+ * 		if(NULL == s_ErrorPool)
+ * 		{
+ * 			return 0; // couldn't allocate memory
+ * 		}
+ * 		return 1;
+ * }
+ * 
+ * void MyLibraryQuit()
+ * {
+ * 		TError_FreeErrorPool(s_ErrorPool);
+ * 		s_ErrorPool = NULL;
+ * }
+ * 
+ * void MyLibrarySetError(int err_num, const char* err_str, ...)
+ * {
+ * 		va_list argp;
+ * 		va_start(argp, err_str);
+ * 		TError_SetErrorv(s_ErrorPool, err_num, err_str, argp);
+ * 		va_end(argp);
+ * }
+ *
+ * const char* MyLibraryGetError()
+ * {
+ * 		const char* ret_error = TError_GetLastErrorStr(s_ErrorPool);
+ * 		if(NULL == ret_error)
+ *      {
+ * 		 		return ""; // provide an empty string to make it safe for people using printf without checking.
+ * 		}
+ * 		return ret_error;
+ * }
+ * @endcode
+ *
+ * @note By default, this library attempts to use vasprintf to generate
+ * the printf-style formatted strings. vasprintf is a GNU extension 
+ * which solves the problem of having enough memory allocated in a buffer
+ * to handle an arbitrary length formatted string which you don't know
+ * in advance. I recommend you use this implementation if your library
+ * can support it as it will allow you to always generate correct strings.
+ * (Stack traces can become long and exceed your preallocated buffer sizes.)
+ * For compatibility, an alternative vsnprintf implementation is provided.
+ * If a string is too large, it will be truncated. vsnprintf is specified 
+ * in C99, but it critcal for avoid security related issues surrounding 
+ * sprintf and vsprintf. If your library lacks vsnprintf, you're asking 
+ * for trouble. I currently do not try to handle this case.
+ * 
+ * @note By default, this library assumes 0 is the no-error value.
+ * In addition, if you are using the string-only based APIs, the integer
+ * components will be automatically filled to 0 (for no-error) and 
+ * 1 (for error). If these numbers conflict with your conventions,
+ * you may be able to change these values in the implementation file
+ * and recompile the library. Look for the defines for TERROR_ERROR_VALUE
+ * and TERROR_NOERROR_VALUE.
+ *
+ * @note This version attempts to provide enough thread safety to get by
+ * but it may not be totally safe during creation and destruction of 
+ * instances (partly since locking is done inside the object-level),
+ * so don't create or destroy pools when there is possible contention.
+ * Strings you pass into the functions are not necessarily locked so
+ * be careful if you are modifying strings that are shared among
+ * your threads.
+ *
+ * @note Error strings returned are pointers to tErrorLib's internal 
+ * copies of strings. Do not modify these or delete them. Also keep in 
+ * mind that the pointers to these strings may become invalid when
+ * a new error is set (on a per-thread basis). So if you need a copy 
+ * of the error string, you should make your own copy.
+ *
+ * @warning For code that frequently generates and destroys many threads,
+ * be aware that you should pay attention to memory management with this 
+ * library. This library works by creating a unique error message 
+ * structure for each thread. When the thread dies, the error pool 
+ * will still contain a structure for that thread (if it had called 
+ * this library in that thread). Just before the thread dies (but after 
+ * any final error calls), you should call TError_DeleteEntryOnCurrentThread()
+ * to free the memory for that thread. Otherwise you will have a 
+ * pseudo-memory-leak. (Pseudo in the sense that once you free the error pool,
+ * all memory will be freed, regardless of whether you remembered to call
+ * this function.)
+ * @see TERROR_NOERROR_VALUE, TError_DeleteEntryOnCurrentThread
+ * 
+ * @author Eric Wing
+ */
+
+#ifndef TERRORLIB_H
+#define TERRORLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h> /* for va_list */
+
+/**
+ * This library determines if there is an error by checking 
+ * both the error number and error string. If the error string is NULL
+ * and the error number is 0 (TERROR_NOERROR_VALUE), then it 
+ * is considered a non-error. Because this library allows you to
+ * use just numbers or just strings, a value must be filled in internally
+ * as a place holder. It also must return some default/no-error values
+ * for GetError if there was no error. In these situations,
+ * NULL is set for strings and 0 (TERROR_NOERROR_VALUE)
+ * is set for numbers. This will become a point of confusion if you use 
+ * 0 as an error code to denote a legitimate error and have a NULL error 
+ * string. 
+ * 
+ * To accommodate this problem, this define is provided to let you 
+ * redefine what the no-error value is (though this is untested). 
+ * If you have the opportunity to write code that doesn't rely on 0 denoting
+ * an error, I recommend using this library as is, instead of trying 
+ * to change this. If you do change this value, remember you must recompile
+ * the entire library. Also make sure that TERROR_ERROR_VALUE (in 
+ * implementation file) is not equal to your changed value.
+ * 
+ * For most cases, if you just want to check if there was an 
+ * error, you can check if the error_number == 0. But if
+ * you are thinking that you may want to redefine what the no-error
+ * value is in the future (say -99999), then you can use this 
+ * constant name instead (e.g. error_number == TERROR_NOERROR_VALUE).
+ */
+#define TERROR_NOERROR_VALUE 0
+
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+/** @cond DOXYGEN_SHOULD_IGNORE_THIS */
+
+/* Note: For Doxygen to produce clean output, you should set the 
+ * PREDEFINED option to remove TERROR_TERROR_DECLSPEC, TERROR_CALL, and
+ * the DOXYGEN_SHOULD_IGNORE_THIS blocks.
+ * PREDEFINED = DOXYGEN_SHOULD_IGNORE_THIS=1 TERROR_TERROR_DECLSPEC= TERROR_CALL=
+ */
+
+/** Windows needs to know explicitly which functions to export in a DLL. */
+#if defined(_WIN32)
+	#if defined(TERROR_BUILD_LIBRARY)
+		#define TERROR_DECLSPEC __declspec(dllexport)
+	#else
+		#define TERROR_DECLSPEC __declspec(dllimport)
+	#endif
+#else
+	#if defined(ALMIXER_BUILD_LIBRARY)
+		#if defined (__GNUC__) && __GNUC__ >= 4
+			#define TERROR_DECLSPEC __attribute__((visibility("default")))
+		#else
+			#define TERROR_DECLSPEC
+		#endif
+	#else
+		#define TERROR_DECLSPEC
+	#endif
+#endif
+
+/* For Windows, by default, use the C calling convention */
+#if defined(_WIN32)
+	#define TERROR_CALL __cdecl
+#else
+	#define TERROR_CALL
+#endif
+
+	
+/* Version number is set here.
+ * Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
+ */
+#define TERROR_MAJOR_VERSION		0
+#define TERROR_MINOR_VERSION		1
+#define TERROR_PATCH_VERSION		0
+
+/** @endcond DOXYGEN_SHOULD_IGNORE_THIS */
+#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
+
+
+/**
+ * Struct that contains the version information of this library.
+ * This represents the library's version as three levels: major revision
+ * (increments with massive changes, additions, and enhancements),
+ * minor revision (increments with backwards-compatible changes to the
+ * major revision), and patchlevel (increments with fixes to the minor
+ * revision).
+ * @see TERROR_GET_COMPILED_VERSION, TError_GetLinkedVersion
+ */
+typedef struct
+{
+	int major; /**< major revision. */
+	int minor; /**< minor revision. */
+	int patch; /**< patch revision. */
+} TErrorVersion;
+
+
+/**
+ * Struct that contains all the data needed to represent an error (pool)
+ * instance. This is the object you pass around to all instance
+ * based error functions. Don't touch the data in the struct directly.
+ * This should be considered an opaque data type.
+ */
+typedef struct
+{
+	void* mutexLock; /**< You probably shouldn't touch this either. */
+	void* opaqueData; /**< Don't touch this. */
+} TErrorPool;
+
+/**
+ * Struct that contains both the error number and error string.
+ * This is returned by the TError_GetError functions which 
+ * allows you to fetch both the errorNumber and errorString.
+ * (Other API functions only let you get one or the other).
+ * You may read the values directly, but do not modify the string.
+ * Keep in mind that once a SetError is called again for your thread,
+ * the pointer may become invalid. Copy this data out if you need
+ * to keep it.
+ */
+typedef struct
+{
+	int errorNumber; /**< The error number. */
+	const char* errorString; /**< The error string (read-only). */
+} TErrorStatus;
+
+
+/**
+ * This macro fills in a TError_Version structure with the version of the
+ * library you compiled against. This is determined by what header the
+ * compiler uses. Note that if you dynamically linked the library, you might
+ * have a slightly newer or older version at runtime. That version can be
+ * determined with TError_GetLinkedVersion(), which, unlike 
+ * TERROR_GET_COMPILED_VERSION, is not a macro.
+ *
+ * @param X A pointer to a TError_Version struct to initialize.
+ *
+ * @see TErrorVersion, TError_GetLinkedVersion
+ */
+#define TERROR_GET_COMPILED_VERSION(X) 		\
+{											\
+	if(NULL != (X))							\
+	{										\
+		(X)->major = TERROR_MAJOR_VERSION;	\
+		(X)->minor = TERROR_MINOR_VERSION;	\
+		(X)->patch = TERROR_PATCH_VERSION;	\
+	}										\
+}
+
+/**
+ * Gets the library version of tErrorLib you are using.
+ * This gets the version of tErrorLib that is linked against your program.
+ * If you are using a shared library (DLL) version of tError, then it is
+ * possible that it will be different than the version you compiled against.
+ *
+ * This is a real function; the macro TERROR_GET_COMPILED_VERSION 
+ * tells you what version of tErrorLib you compiled against:
+ *
+ * @code
+ * TErrorVersion compiled;
+ * TErrorVersion linked;
+ *
+ * TERROR_GET_COMPILED_VERSION(&compiled);
+ * TError_GetLinkedVersion(&linked);
+ * printf("We compiled against tError version %d.%d.%d ...\n",
+ *           compiled.major, compiled.minor, compiled.patch);
+ * printf("But we linked against tError version %d.%d.%d.\n",
+ *           linked.major, linked.minor, linked.patch);
+ * @endcode
+ *
+ * @see TErrorVersion, TERROR_GET_COMPILED_VERSION
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_GetLinkedVersion(TErrorVersion* ver);
+
+/**
+ * This creates a new error pool instance.
+ * An error pool is a self-contained object that holds its own 
+ * errors. You may have multiple error pools to isolate errors for 
+ * different subsystems if you choose.
+ *
+ * For most (if not all) other tErrorLib functions, you will
+ * pass this instance to each function when you call them.
+ * 
+ * @return Returns a pointer to an error pool which is the 
+ * instance variable (if successful) or NULL on failure.
+ *
+ * @see TError_FreeErrorPool
+ */
+extern TERROR_DECLSPEC TErrorPool* TERROR_CALL TError_CreateErrorPool(void);
+
+/**
+ * This frees an error pool instance.
+ * This properly frees the memory of an error pool instance created by
+ * CreateErrorPool. Whenever you create a TErrorPool
+ * instance, you should always remember to balance it with a 
+ * FreeErrorPool() call.
+ *
+ * @param err_pool A pointer to the error pool instance you want to free.
+ *
+ * @see TError_CreateErrorPool
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_FreeErrorPool(TErrorPool* err_pool);
+
+/**
+ * This function will delete the error message memory that has been
+ * allocated for the thread you call this function in. 
+ * This reflects a deficiency in this library's design.
+ * If a thread terminates, this library will still have 
+ * allocated memory for it if it had set an error.
+ * If you plan on killing a thread, call this function in that 
+ * thread before it dies so the memory can be freed.
+ * Do not call SetError* again in this thread or memory
+ * will be reallocated.
+ * It is safe to call if no memory has actually be allocated for the 
+ * error for the current thread.
+ * If you cannot use this function to free the memory for some reason, 
+ * this is a pseudo-memory-leak. By pseudo, I mean that you won't
+ * completely leak. When you delete the entire memory pool, it will 
+ * be able to free all error message structures that were associated 
+ * with the pool so you can recover this memory.
+ *
+ * @param err_pool The error pool instance you want to use.
+ */
+extern TERROR_DECLSPEC void TError_DeleteEntryOnCurrentThread(TErrorPool* err_pool);
+
+
+/**
+ * This function sets an error.
+ * Calling this function will set an error (for this thread)
+ * with the specified error number and error string which 
+ * can later be retrieved by a GetError call.
+ * The function usage is similar to printf.
+ * If both the err_num is set to 0 (see other notes TERROR_NOERROR_VALUE)
+ * and the err_str is set to NULL, then this is considered clearing an 
+ * error and no error will be marked.
+ * 
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @param err_num The error number you want to use for this error.
+ * The value for this number is up to you, based on your own 
+ * conventions. But this library reserves one number to denote "no error".
+ * This number for initial implementation and documentation purposes is 0,
+ * and is defined in the implementation as TERROR_NOERROR_VALUE. 
+ * You can still specify this number to be anything you choose 
+ * if and only if you also always specify an error string that is not NULL.
+ * As long as an error string exists, the system will recognize there
+ * is an error. But if you have a NULL string and use 0 to denote an
+ * error, this will be interpreted as a clear error message.
+ * So I recommend you treat 0 as a no-error value and avoid using it 
+ * as an error value in your code to avoid confusion.
+ *
+ * @param err_str This is where your error text goes. It is compatible with
+ * printf style format strings. There is no imposed limit on how long 
+ * the strings can be if you are using the vasprintf backend. The
+ * vsnprintf implemention will automatically truncate the string if it
+ * is too long.
+ * You if don't wish to specify an error string, you may enter NULL here.
+ * But remember to note the effect if this string is NULL and the err_num is
+ * set to 0 (TERROR_NOERROR_VALUE).
+ *
+ * @param ... This is the variable argument list used to accomodate 
+ * printf style format strings.
+ *
+ * @see TError_SetErrorv, TError_SetErrorNoFormat, TError_SetErrorNum,
+ * TError_SetErrorStr, TError_SetErrorStrv, TError_SetErrorStrNoFormat,
+ * TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetError(TErrorPool* err_pool, int err_num, const char* err_str, ...);
+
+
+/**
+ * This function sets an error.
+ * This is the va_list version of TError_SetError.
+ * The same rules apply to this as with TError_SetError.
+ * 
+ * @see TError_SetError
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetErrorv(TErrorPool* err_pool, int err_num, const char* err_str, va_list argp);
+
+/**
+ * This is a "No Format Strings Allowed" version of SetError.
+ * This version of SetError disallows the use of format strings.
+ * This was written if you needed to expose the SetError function to
+ * an untrusted source because it is quite easy to crash a system (or worse)
+ * with an invalid format string. An untrusted source might include 
+ * arguments passed through the command line, any user input that 
+ * gets fed to Logger, or strings taken from runtime generated sources
+ * like scripts.
+ * I was probably being overly paranoid when I created this function,
+ * and there may be ways to achive this level of safety without 
+ * this function, but here it is anyway.
+ * In addition, if your compiler has problems with both vasprintf and 
+ * vsnprintf, (you will have to modify some source code) you might 
+ * consider basing all SetError functions around this function because 
+ * since the strings are known length because there is no argument 
+ * expansion.
+ * 
+ * @see TError_SetError
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetErrorNoFormat(TErrorPool* err_pool, int err_num, const char* err_str);
+
+/**
+ * This function sets an error.
+ * This version only lets you set the error number. The backend
+ * will automatically set the error string to NULL. 
+ * This API call is intended to be used only if you don't plan on using
+ * any error strings in your code.
+ * Also be aware of the notes about TERROR_NOERROR_VALUE.
+ * 
+ * @see TError_SetError, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetErrorNum(TErrorPool* err_pool, int err_num);
+
+/**
+ * This function sets an error.
+ * This version only lets you set the error string. The backend
+ * will automatically set the error number to TERROR_NOERROR_VALUE
+ * which is currently implemented as 0. 
+ * This API call is intended to be used only if you don't plan on using
+ * any error numbers in your code.
+ * Also be aware of the notes about TERROR_NOERROR_VALUE if you use NULL
+ * strings.
+ * 
+ * @see TError_SetError, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetErrorStr(TErrorPool* err_pool, const char* err_str, ...);
+
+/**
+ * This function sets an error.
+ * This is the va_list version of TError_SetErrorStr.
+ * 
+ * @see TError_SetError, TError_SetErrorStr, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetErrorStrv(TErrorPool* err_pool, const char* err_str, va_list argp);
+
+/**
+ * This function sets an error.
+ * This is the "No Format Strings Allowed" version of TError_SetErrorStr.
+ * 
+ * @see TError_SetError, TError_SetErrorNoFormat,
+ * TError_SetErrorStr, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC void TERROR_CALL TError_SetErrorStrNoFormat(TErrorPool* err_pool, const char* err_str);
+
+/**
+ * This function gets the last error to be set by one of the SetError 
+ * functions (from within your current thread). This version of the function
+ * returns just the error number.
+ * After this function is called, the error will be cleared, so your 
+ * next call to a GetError function (with no SetError calls in between)
+ * will return a struct set with no-error values.
+ *
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @return Returns the error number.
+ * If no error was set, the error number will be set 
+ * to 0 (TERROR_NOERROR_VALUE).
+ *
+ * @see TError_GetErrorOnCurrentThread, TError_GetErrorStrOnCurrentThread, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC int TERROR_CALL TError_GetErrorNumOnCurrentThread(TErrorPool* err_pool);
+
+/**
+ * This function gets the last error to be set by one of the SetError 
+ * functions (from within your current thread). This version of the function
+ * returns a pointer to the error string.
+ * After this function is called, the error will be cleared, so your 
+ * next call to a GetError function (with no SetError calls in between)
+ * will return a struct set with no-error values.
+ *
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @return Returns the pointer to the error string. 
+ * The pointer is to tErrorLib's own copy
+ * of the error message so you should not modify this string. Furthermore,
+ * the pointer may become invalid at the next call to SetError within this
+ * same thread, so if you need to keep the string, you must make your
+ * own copy of it.
+ * If no error was set, the error string will be set to NULL.
+ *
+ * @see TError_GetErrorNumOnCurrentThread, TError_GetErrorOnCurrentThread, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC const char* TERROR_CALL TError_GetErrorStrOnCurrentThread(TErrorPool* err_pool);
+
+/**
+ * This function gets the last error to be set by one of the SetError 
+ * functions (from within your current thread). This version of the function
+ * returns a struct containing the error number and a pointer to the 
+ * error string.
+ * After this function is called, the error will be cleared, so your 
+ * next call to a GetError function (with no SetError calls in between)
+ * will return a struct set with no-error values.
+ *
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @return Returns (by-value) a struct containing the error number and
+ * pointer to the error string. The pointer is to tErrorLib's own copy
+ * of the error message so you should not modify this string. Furthermore,
+ * the pointer may become invalid at the next call to SetError within this
+ * same thread, so if you need to keep the string, you must make your
+ * own copy of it.
+ * If no error was set, the error number will be set to 0 (TERROR_NOERROR_VALUE)
+ * and the error string will be set to NULL.
+ *
+ * @see TError_GetErrorNumOnCurrentThread, TError_GetErrorStrOnCurrentThread, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC TErrorStatus TERROR_CALL TError_GetErrorOnCurrentThread(TErrorPool* err_pool);
+
+
+/**
+ * This function gets the last error to be set by one of the SetError 
+ * functions (regardless of thread).
+ * This version of the function
+ * returns just the error number.
+ * After this function is called, the error will be cleared, so your 
+ * next call to a GetError function (with no SetError calls in between)
+ * will return a struct set with no-error values.
+ *
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @return Returns the error number.
+ * If no error was set, the error number will be set 
+ * to 0 (TERROR_NOERROR_VALUE).
+ *
+ * @see TError_GetLastError, TError_GetLastErrorStr, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC int TERROR_CALL TError_GetLastErrorNum(TErrorPool* err_pool);
+
+/**
+ * This function gets the last error to be set by one of the SetError 
+ * functions (regardless of thread).
+ * This version of the function
+ * returns a pointer to the error string.
+ * After this function is called, the error will be cleared, so your 
+ * next call to a GetError function (with no SetError calls in between)
+ * will return a struct set with no-error values.
+ *
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @return Returns the pointer to the error string. 
+ * The pointer is to tErrorLib's own copy
+ * of the error message so you should not modify this string. Furthermore,
+ * the pointer may become invalid at the next call to SetError within this
+ * same thread, so if you need to keep the string, you must make your
+ * own copy of it.
+ * If no error was set, the error string will be set to NULL.
+ *
+ * @see TError_GetLastErrorNum, TError_GetLastError, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC const char* TERROR_CALL TError_GetLastErrorStr(TErrorPool* err_pool);
+
+/**
+ * This function gets the last error to be set by one of the SetError 
+ * functions (regardless of thread). 
+ * This version of the function
+ * returns a struct containing the error number and a pointer to the 
+ * error string.
+ * After this function is called, the error will be cleared, so your 
+ * next call to a GetError function (with no SetError calls in between)
+ * will return a struct set with no-error values.
+ *
+ * @param err_pool The error pool instance you want to use.
+ *
+ * @return Returns (by-value) a struct containing the error number and
+ * pointer to the error string. The pointer is to tErrorLib's own copy
+ * of the error message so you should not modify this string. Furthermore,
+ * the pointer may become invalid at the next call to SetError within this
+ * same thread, so if you need to keep the string, you must make your
+ * own copy of it.
+ * If no error was set, the error number will be set to 0 (TERROR_NOERROR_VALUE)
+ * and the error string will be set to NULL.
+ *
+ * @see TError_GetLastErrorNum, TError_GetLastErrorStr, TERROR_NOERROR_VALUE
+ */
+extern TERROR_DECLSPEC TErrorStatus TERROR_CALL TError_GetLastError(TErrorPool* err_pool);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* TERRORLIB_H */
+