changeset 1:a8a8fe374984

Subversion era
author Eric Wing <ewing . public |-at-| gmail . com>
date Wed, 27 Oct 2010 16:51:16 -0700
parents 01e39f9f58d5
children 279d0427ef26
files CircularQueue.c CircularQueue.h SDL_ALmixer.c SDL_ALmixer.h
diffstat 4 files changed, 658 insertions(+), 186 deletions(-) [+]
line wrap: on
line diff
--- a/CircularQueue.c	Wed Oct 27 16:50:19 2010 -0700
+++ b/CircularQueue.c	Wed Oct 27 16:51:16 2010 -0700
@@ -266,6 +266,22 @@
 	fprintf(stderr, "\n");
 }
 
+unsigned int CircularQueueUnsignedInt_ValueAtIndex(CircularQueueUnsignedInt* queue, unsigned int the_index)
+{
+	unsigned int i;
+	if(NULL == queue)
+	{
+		return 0;
+	}
+	if(the_index >= queue->currentSize)
+	{
+		return 0;
+	}
+	i = (queue->headIndex + the_index) % queue->currentSize;
+//	fprintf(stderr, "%d\n", queue->internalQueue[i]);
+	return queue->internalQueue[i];
+}
+
 /*
  * Implementation for void* version starts here.
  */
@@ -485,8 +501,6 @@
 	queue->tailIndex = 0;
 }
 
-/* Not implemented for void* */
-/*
 void CircularQueueVoid_Print(CircularQueueVoid* queue)
 {
 	unsigned int i;
@@ -502,11 +516,25 @@
 		{
 			i=0;
 		}
-		fprintf(stderr, "%d ", queue->internalQueue[i]);
+		fprintf(stderr, "%x ", (unsigned int)queue->internalQueue[i]);
 	}
 	fprintf(stderr, "\n");
 }
-*/
+
+void* CircularQueueVoid_ValueAtIndex(CircularQueueVoid* queue, unsigned int the_index)
+{
+	unsigned int i;
+	if(NULL == queue)
+	{
+		return NULL;
+	}
+	if(the_index >= queue->currentSize)
+	{
+		return NULL;
+	}
+	i = (queue->headIndex + the_index) % queue->currentSize;
+	//	fprintf(stderr, "%d\n", queue->internalQueue[i]);
+	return queue->internalQueue[i];
+}
 
 
-
--- a/CircularQueue.h	Wed Oct 27 16:50:19 2010 -0700
+++ b/CircularQueue.h	Wed Oct 27 16:51:16 2010 -0700
@@ -93,6 +93,14 @@
  * @endcode
  */
 
+/* This is a trick I picked up from Lua. Doing the typedef separately 
+ * (and I guess before the definition) instead of a single 
+ * entry: typedef struct {...} YourName; seems to allow me
+ * to use forward declarations. Doing it the other way (like SDL)
+ * seems to prevent me from using forward declarions as I get conflicting
+ * definition errors. I don't really understand why though.
+ */
+typedef struct CircularQueueUnsignedInt CircularQueueUnsignedInt;
 /**
  * This is the essentially the CircularQueue object.
  * This contains all the data associated with a CircularQueue instance.
@@ -101,14 +109,14 @@
  * other data types.
  * This should be considered an opaque data type. 
  */
-typedef struct 
+struct CircularQueueUnsignedInt
 {
 	unsigned int maxSize; /**< Max size of the queue. */
 	unsigned int currentSize; /**< Current number of entries in the queue. */
 	unsigned int headIndex; /**< The index of where the current head is. */
 	unsigned int tailIndex; /**< The index of where the current tail is. */
 	unsigned int* internalQueue; /**< The array representing the queue. */
-} CircularQueueUnsignedInt;
+};
 
 /**
  * This creates a new CircularQueue (for unsigned int) instance.
@@ -266,7 +274,46 @@
  */
 void CircularQueueUnsignedInt_Print(CircularQueueUnsignedInt* queue);
 
+/**
+ * This returns the element located at the specified index,
+ * where index=0 represents the head/front of the queue.
+ *
+ * @param queue The pointer to the CircularQueue instance.
+ * @param the_index The index of the element you want where 0 represents the 
+ * head/front of the queue and Size-1 is the back.
+ *
+ * @return Returns the value located at the index on success, or 0 on failure.
+ * Be careful to not to confuse an error for a legitmate 0 value.
+ * Any index from 0 to Size-1 (where Size>0) will be a valid index.
+ *
+ * This example traverses through the whole queue and prints out each value.
+ * @code
+ * fprintf(stderr, "Queue: ");
+ * for(i=0;i<CircularQueueUnsignedInt_Size(xValueQueue);i++)
+ * {
+ *     ret_val = CircularQueueUnsignedInt_ValueAtIndex(xValueQueue, i);
+ *     fprintf(stderr, "%d ", ret_val);
+ *
+ * }
+ * fprintf(stderr, "\n");
+ *
+ * @note The implementation uses a modulo operation to compute the index, so 
+ * this may not be the speediest operation in a tight loop.
+ * This implementation was not optimized for random access, though it still 
+ * is technically O(1).
+ *
+ */
+unsigned int CircularQueueUnsignedInt_ValueAtIndex(CircularQueueUnsignedInt* queue, unsigned int the_index);
 
+
+/* This is a trick I picked up from Lua. Doing the typedef separately 
+ * (and I guess before the definition) instead of a single 
+ * entry: typedef struct {...} YourName; seems to allow me
+ * to use forward declarations. Doing it the other way (like SDL)
+ * seems to prevent me from using forward declarions as I get conflicting
+ * definition errors. I don't really understand why though.
+ */
+typedef struct CircularQueueVoid CircularQueueVoid;
 /**
  * This is the essentially the CircularQueue object.
  * This contains all the data associated with a CircularQueue instance.
@@ -275,14 +322,14 @@
  * other data types.
  * This should be considered an opaque data type. 
  */
-typedef struct
+struct CircularQueueVoid
 {
 	unsigned int maxSize; /**< Max size of the queue. */
 	unsigned int currentSize; /**< Current number of entries in the queue. */
 	unsigned int headIndex; /**< The index of where the current head is. */
 	unsigned int tailIndex; /**< The index of where the current tail is. */
 	void** internalQueue; /**< The array representing the queue. */
-} CircularQueueVoid;
+};
 
 /**
  * This creates a new CircularQueue (for void* ) instance.
@@ -429,10 +476,47 @@
  */
 void CircularQueueVoid_Clear(CircularQueueVoid* queue);
 
-/* Not implemented for void* */
-/*
+/**
+ * This is a debugging function that will print all the addresses
+ * of elements in the queue to stderr. 
+ * This function is provided as convenience, but should not be considered
+ * as part of the standard API. Treat this function as deprecated 
+ * as it's implementation may change or be removed entirely.
+ * 
+ * @param queue The pointer to the CircularQueue instance.
+ */
 void CircularQueueVoid_Print(CircularQueueVoid* queue);
-*/
+
+/**
+ * This returns the element located at the specified index,
+ * where index=0 represents the head/front of the queue.
+ *
+ * @param queue The pointer to the CircularQueue instance.
+ * @param the_index The index of the element you want where 0 represents the 
+ * head/front of the queue and Size-1 is the back.
+ *
+ * @return Returns the element located at the index on success, or NULL on failure.
+ * Be careful to not to confuse an error for a legitmate NULL value.
+ * Any index from 0 to Size-1 (where Size>0) will be a valid index.
+ *
+ * This example traverses through the whole queue and prints out each value.
+ * @code
+ * fprintf(stderr, "Queue: ");
+ * for(i=0;i<CircularQueueVoid_ValueAtIndex(xValueQueue);i++)
+ * {
+ *     void* ret_val = CircularQueueUnsignedInt_ValueAtIndex(xValueQueue, i);
+ *     fprintf(stderr, "%x ", ret_val);
+ *
+ * }
+ * fprintf(stderr, "\n");
+ *
+ * @note The implementation uses a modulo operation to compute the index, so 
+ * this may not be the speediest operation in a tight loop.
+ * This implementation was not optimized for random access, though it still 
+ * is technically O(1).
+ *
+ */
+void* CircularQueueVoid_ValueAtIndex(CircularQueueVoid* queue, unsigned int the_index);
 
 
 
--- a/SDL_ALmixer.c	Wed Oct 27 16:50:19 2010 -0700
+++ b/SDL_ALmixer.c	Wed Oct 27 16:51:16 2010 -0700
@@ -8,9 +8,20 @@
 #include "SDL_ALmixer.h"
 
 #include "SDL.h" /* For SDL_GetTicks(), SDL_Delay */
+#include "SDL_sound.h"
 #include "al.h" /* OpenAL */
 #include "alc.h" /* For creating OpenAL contexts */
 
+#ifdef __APPLE__
+	/* For performance things like ALC_CONVERT_DATA_UPON_LOADING */
+	/* Note: ALC_CONVERT_DATA_UPON_LOADING used to be in the alc.h header.
+	 * But in the Tiger OpenAL 1.1 release (10.4.7 and Xcode 2.4), the 
+	 * define was moved to a new header file and renamed to
+	 * ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING.
+	 */
+	#include <OpenAL/MacOSX_OALExtensions.h>
+#endif
+
 /* For malloc, bsearch, qsort */
 #include <stdlib.h>
 
@@ -160,7 +171,7 @@
 #endif
 /************ END REMOVE  ME (Don't need anymore) ********/
 
-static Uint8 ALmixer_Initialized = 0;
+static SDL_bool ALmixer_Initialized = 0;
 /* This should be set correctly by Init */
 static Uint32 ALmixer_Frequency_global = ALMIXER_DEFAULT_FREQUENCY;
 
@@ -195,20 +206,65 @@
 static const Uint16 SIGN_TYPE_8_BIT_FORMAT = AUDIO_S8;
 #endif
 
+
+/* This can be private instead of being in the header now that I moved
+ * ALmixer_Data inside here.
+ */
+typedef struct ALmixer_Buffer_Map ALmixer_Buffer_Map;
+
+
+struct ALmixer_Data
+{
+	SDL_bool decoded_all; /* dictates different behaviors */
+	Sint32 total_time; /* total playing time of sample (msec) */
+	
+	Uint32 in_use; /* needed to prevent sharing for streams */
+	SDL_bool eof; /* flag for eof, only used for streams  */
+	
+	Uint32 total_bytes; /* For predecoded */
+	Uint32 loaded_bytes; /* For predecoded (for seek) */
+
+	Sound_Sample* sample; /* SDL_Sound provides the data */
+	ALuint* buffer; /* array of OpenAL buffers (at least 1 for predecoded) */
+
+	/* Needed for streamed buffers */
+	Uint32 max_queue_buffers; /* Max number of queue buffers */
+	Uint32 num_startup_buffers; /* Number of ramp-up buffers */
+	Uint32 num_buffers_in_use; /* number of buffers in use */
+	
+	/* This stuff is for streamed buffers that require data access */
+	ALmixer_Buffer_Map* buffer_map_list; /* translate ALbuffer to index 
+									and holds pointer to copy of data for
+									data access */
+	ALuint current_buffer; /* The current playing buffer */
+
+	/* Nvidia distribution refuses to recognize a simple buffer query command
+	 * unlike all other distributions. It's forcing me to redo the code 
+	 * to accomodate this Nvidia flaw by making me maintain a "best guess"
+	 * copy of what I think the buffer queue state looks like.
+	 * A circular queue would a helpful data structure for this task,
+	 * but I wanted to avoid making an additional header requirement,
+	 * so I'm making it a void* 
+	 */
+	void* circular_buffer_queue; 
+		
+	
+};
+
 static struct ALmixer_Channel
 {
-	Uint8 channel_in_use;
-	Uint8 callback_update; /* For streaming determination */
-	Uint8 needs_stream; /* For streaming determination */
-	Uint8 halted;
-	Uint8 paused;
+	SDL_bool channel_in_use;
+	SDL_bool callback_update; /* For streaming determination */
+	SDL_bool needs_stream; /* For streaming determination */
+	SDL_bool halted;
+	SDL_bool paused;
 	ALuint alsource;
 	ALmixer_Data* almixer_data;
 	Sint32 loops;
 	Sint32 expire_ticks;
 	Uint32 start_time;
 
-	Uint8 fade_enabled;
+	SDL_bool fade_enabled;
 	Uint32 fade_expire_ticks;
 	Uint32 fade_start_time;
 	ALfloat fade_inv_time;
@@ -232,6 +288,14 @@
 	*/
 } *ALmixer_Channel_List = NULL;
 
+struct ALmixer_Buffer_Map
+{
+	ALuint albuffer;
+	Sint32 index; /* might not need */
+	Uint8* data;
+	Uint32 num_bytes;
+};
+
 /* This will be used to find a channel if the user supplies a source */
 typedef struct Source_Map
 {
@@ -255,7 +319,7 @@
 /* Compare by albuffer */
 static int Compare_Buffer_Map(const void* a, const void* b)
 {
-    return ( ((Buffer_Map*)a)->albuffer - ((Buffer_Map*)b)->albuffer );
+    return ( ((ALmixer_Buffer_Map*)a)->albuffer - ((ALmixer_Buffer_Map*)b)->albuffer );
 }
 
 /* This is for the user defined callback via 
@@ -263,8 +327,8 @@
  */
 static void (*Channel_Done_Callback)(Sint32 channel, void* userdata) = NULL;
 static void* Channel_Done_Callback_Userdata = NULL;
-static void (*Channel_Data_Callback)(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bitdepth, Uint16 format, Uint8 decode_mode) = NULL;
-
+static void (*Channel_Data_Callback)(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bit_depth, SDL_bool is_unsigned, SDL_bool decode_mode_is_predecoded, Uint32 length_in_msec, void* user_data) = NULL;
+static void* Channel_Data_Callback_Userdata = NULL;
 
 /* I thought OpenAL seemed to lack an error number to string converter...
 * but I was wrong. Apparently they call it alGetString() which
@@ -366,6 +430,7 @@
 			source,
 			buffers_queued,
 			buffers_processed);
+
 }
 
 
@@ -583,6 +648,60 @@
 	return AL_FORMAT_STEREO16;
 }
 
+
+/* This will compute the total playing time
+* based upon the number of bytes and audio info.
+* (In prinicple, it should compute the time for any given length) 
+*/
+static Uint32 Compute_Total_Time_Decomposed(Uint32 bytes_per_sample, Uint32 frequency, Uint8 channels, Uint32 total_bytes)
+{
+	double total_sec;
+	Uint32 total_msec;
+	Uint32 bytes_per_sec;
+	
+	if(0 == total_bytes)
+	{
+		return 0;
+	}
+	/* To compute Bytes per second, do
+		* samples_per_sec * bytes_per_sample * number_of_channels
+		*/
+	bytes_per_sec = frequency * bytes_per_sample * channels;
+	
+	/* Now to get total time (sec), do
+		* total_bytes / bytes_per_sec
+		*/
+	total_sec = total_bytes / (double)bytes_per_sec;
+	
+	/* Now convert seconds to milliseconds
+		* Add .5 to the float to do rounding before the final cast
+		*/
+	total_msec = (Uint32) ( (total_sec * 1000) + 0.5 );
+	/*
+	 fprintf(stderr, "freq=%d, bytes_per_sample=%d, channels=%d, total_msec=%d\n", frequency, bytes_per_sample, channels, total_msec);
+	*/
+	return total_msec;
+}
+
+static Uint32 Compute_Total_Time(Sound_AudioInfo *info, Uint32 total_bytes)
+{
+	Uint32 bytes_per_sample;
+	
+	if(0 == total_bytes)
+	{
+		return 0;
+	}
+	/* SDL has a mask trick I was not aware of. Mask the upper bits
+		* of the format, and you get 8 or 16 which is the bits per sample.
+		* Divide by 8bits_per_bytes and you get bytes_per_sample
+		*/
+	bytes_per_sample = (Uint32) ((info->format & 0xFF) / 8);
+	
+	return Compute_Total_Time_Decomposed(bytes_per_sample, info->rate, info->channels, total_bytes);
+} /* End Compute_Total_Time */
+	
+
+
 /**************** REMOVED ****************************/
 /* This was removed because I originally thought
  * OpenAL could return a pointer to the buffer data,
@@ -728,15 +847,15 @@
 	Channel_Done_Callback(channel, Channel_Done_Callback_Userdata);
 }
 
-static Sint32 LookUpBuffer(ALuint buffer, Buffer_Map* buffer_map_list, Uint32 num_items_in_list)
+static Sint32 LookUpBuffer(ALuint buffer, ALmixer_Buffer_Map* buffer_map_list, Uint32 num_items_in_list)
 {
 	/* Only the first value is used for the key */
-	Buffer_Map key = { 0, 0, NULL, 0 };
-	Buffer_Map* found_item = NULL;
+	ALmixer_Buffer_Map key = { 0, 0, NULL, 0 };
+	ALmixer_Buffer_Map* found_item = NULL;
 	key.albuffer = buffer;
 
 	/* Use the ANSI C binary search feature (yea!) */
-	found_item = (Buffer_Map*)bsearch(&key, buffer_map_list, num_items_in_list, sizeof(Buffer_Map), Compare_Buffer_Map);
+	found_item = (ALmixer_Buffer_Map*)bsearch(&key, buffer_map_list, num_items_in_list, sizeof(ALmixer_Buffer_Map), Compare_Buffer_Map);
 	if(NULL == found_item)
 	{
 		ALmixer_SetError("Can't find buffer");
@@ -750,8 +869,30 @@
  * Bit rate, stereo/mono (num chans), time in msec?
  * Precoded/streamed flag so user can plan for future data?
  */
-static void Invoke_Channel_Data_Callback(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint16 format, Uint8 decode_mode)
-{
+/*
+ * channels: 1 for mono, 2 for stereo
+ *
+ */
+static void Invoke_Channel_Data_Callback(Sint32 which_channel, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint16 format, SDL_bool decode_mode_is_predecoded)
+{
+	SDL_bool is_unsigned;
+	Uint8 bits_per_sample = GetBitDepth(format);
+	Uint32 bytes_per_sample;
+	Uint32 length_in_msec;
+
+	if(GetSignednessValue(format) == ALMIXER_UNSIGNED_VALUE)
+	{
+		is_unsigned = 1;
+	}
+	else
+	{
+		is_unsigned = 0;
+	}
+
+	bytes_per_sample = (Uint32) (bits_per_sample / 8);
+
+	length_in_msec = Compute_Total_Time_Decomposed(bytes_per_sample, frequency, channels, num_bytes);
+
 /*
 	fprintf(stderr, "%x %x %x %x, bytes=%d, whichchan=%d, freq=%d, channels=%d\n", data[0], data[1], data[2], data[3], num_bytes, channels, frequency, channels);
 */
@@ -759,7 +900,10 @@
 	{
 		return;
 	}
-	Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, GetBitDepth(format), format, decode_mode);
+	/*
+	 * Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, GetBitDepth(format), format, decode_mode_is_predecoded);
+	*/
+	Channel_Data_Callback(which_channel, data, num_bytes, frequency, channels, bits_per_sample, is_unsigned, decode_mode_is_predecoded, length_in_msec, Channel_Data_Callback_Userdata);
 }
 
 static void Invoke_Predecoded_Channel_Data_Callback(Sint32 channel, ALmixer_Data* data)
@@ -777,7 +921,7 @@
 		data->sample->desired.rate,
 		data->sample->desired.channels,
 		data->sample->desired.format,
-		ALMIXER_DECODE_ALL
+		SDL_TRUE
 	);
 }
 
@@ -802,7 +946,7 @@
 		data->sample->desired.rate,
 		data->sample->desired.channels,
 		data->sample->desired.format,
-		ALMIXER_DECODE_STREAM
+		SDL_FALSE
 	);
 }
 
@@ -909,48 +1053,6 @@
 	return 0;
 }
 
-/* This will compute the total playing time
- * based upon the number of bytes and audio info.
- * (In prinicple, it should compute the time for any given length) 
- */
-static Uint32 Compute_Total_Time(Sound_AudioInfo *info, Uint32 total_bytes)
-{
-	Uint32 bytes_per_sec;
-	Uint32 bytes_per_sample;
-	double total_sec;
-	Uint32 total_msec;
-	
-	if(0 == total_bytes)
-	{
-		return 0;
-	}
-	/* SDL has a mask trick I was not aware of. Mask the upper bits
-	 * of the format, and you get 8 or 16 which is the bits per sample.
-	 * Divide by 8bits_per_bytes and you get bytes_per_sample
-	 */
-	bytes_per_sample = (Uint32) ((info->format & 0xFF) / 8);
-	/* To compute Bytes per second, do
-	 * samples_per_sec * bytes_per_sample * number_of_channels
-	 */
-	bytes_per_sec = info->rate * bytes_per_sample * info->channels;
-
-	/* Now to get total time (sec), do
-	 * total_bytes / bytes_per_sec
-	 */
-	total_sec = total_bytes / (double)bytes_per_sec;
-	
-	/* Now convert seconds to milliseconds
-	 * Add .5 to the float to do rounding before the final cast
-	 */
-	total_msec = (Uint32) ( (total_sec * 1000) + 0.5 );
-	
-	fprintf(stderr, "%d\n", total_msec);
-	return total_msec;
-} /* End Compute_Total_Time */
-
-
-
-
 /* Because we have multiple queue buffers and OpenAL won't let
  * us access them, we need to keep copies of each buffer around
  */
@@ -2983,11 +3085,11 @@
 	alGetSourcef(ALmixer_Channel_List[channel].alsource,
 		AL_MAX_GAIN, &value);
 	ALmixer_Channel_List[channel].fade_end_volume = value;
+	fprintf(stderr, "MAX gain: %f\n", value);
 	*/
 	ALmixer_Channel_List[channel].fade_end_volume = 
 		ALmixer_Channel_List[channel].max_volume;
 
-	fprintf(stderr, "MAX gain: %f\n", value);
 	/* Get the Min volume */
 	alGetSourcef(ALmixer_Channel_List[channel].alsource,
 		AL_MIN_GAIN, &value);
@@ -4439,10 +4541,17 @@
 						}
 						if(buffers_still_queued > 0)
 						{
-							/*
+
+#if 0 /* This triggers an error in OS X Core Audio. */
+							alSourceUnqueueBuffers(
+								ALmixer_Channel_List[i].alsource,
+								1, 
+								ALmixer_Channel_List[i].almixer_data->buffer
+							);
+#else
+/*							fprintf(stderr, "In the Bob Aron section...about to clear source\n");
 							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
-							*/
-							
+*/							
 							/* Rather than force unqueuing the buffer, let's see if
 							 * setting the buffer to none works (the OpenAL 1.0 
 							 * Reference Annotation suggests this should work).							 
@@ -4452,6 +4561,7 @@
 							/*
 							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
 							*/	
+#endif								
 							if((error = alGetError()) != AL_NO_ERROR)
 							{
 		fprintf(stderr, "Error with unqueue, after alSourceUnqueueBuffers, buffers_still_queued=%d, error is: %s", buffers_still_queued,
@@ -4595,6 +4705,17 @@
 					Uint32 queue_ret_flag;
 					Uint8 is_out_of_sync = 0;
 					Uint32 my_queue_size = CircularQueueUnsignedInt_Size(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
+					/* Ugh, I have to deal with signed/unsigned mismatch here. */
+					ALint buffers_unplayed_int = buffers_still_queued - buffers_processed;
+					Uint32 unplayed_buffers;
+					if(buffers_unplayed_int < 0)
+					{
+						unplayed_buffers = 0;
+					}
+					else
+					{
+						unplayed_buffers = (Uint32)buffers_unplayed_int;
+					}
 /*
 					fprintf(stderr, "Queue in processed check, before pop, buffers_processed=%d\n", buffers_processed);
 					CircularQueueUnsignedInt_Print(ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
@@ -4622,11 +4743,11 @@
 					#if 0
 					fprintf(stderr, "inside, Buffers processed=%d, Buffers queued=%d, my queue=%d\n",
 							buffers_processed, buffers_still_queued, my_queue_size);
-					#endif			
-					if(my_queue_size > (buffers_still_queued - buffers_processed))
+					#endif	
+					if(my_queue_size > unplayed_buffers)
 					{
 						is_out_of_sync = 1;
-						for(k=0; k<(my_queue_size - (buffers_still_queued - buffers_processed)); k++)
+						for(k=0; k<(my_queue_size - unplayed_buffers); k++)
 						{
 							queue_ret_flag = CircularQueueUnsignedInt_PopFront(
 								ALmixer_Channel_List[i].almixer_data->circular_buffer_queue);
@@ -4679,7 +4800,10 @@
 						}
 						else
 						{
+/*
 							fprintf(stderr, "53b, Notice/Warning:, OpenAL queue has been depleted.\n");
+							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
+*/
 							/* In this case, we might either be in an underrun or finished with playback */
 							ALmixer_Channel_List[i].almixer_data->current_buffer = 0;
 						}
@@ -4732,11 +4856,11 @@
 					if(ALmixer_Channel_List[i].almixer_data->num_buffers_in_use 
 						< ALmixer_Channel_List[i].almixer_data->max_queue_buffers) 
 					{		
-						/*
+#if 0
 						fprintf(stderr, "Getting more data in NOT_EOF and num_buffers_in_use (%d) < max_queue (%d)\n", 
 								ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
 								ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
-						*/
+#endif
 						/* Going to add an unused packet.
 						 * Grab next packet */
 						bytes_returned = GetMoreData(
@@ -4787,31 +4911,87 @@
 						/* Might want to check state */
 						/* In case the playback stopped,
 						 * we need to resume */
+						#if 1 
+						/* Try not refetching the state here because I'm getting a duplicate
+						 buffer playback (hiccup) */
 						alGetSourcei(
 							ALmixer_Channel_List[i].alsource,
 							AL_SOURCE_STATE, &state
 						);
-	if((error = alGetError()) != AL_NO_ERROR)
-	{
-		fprintf(stderr, "54Testing error: %s\n",
-			aluGetErrorString(error));				
-	}
+						if((error = alGetError()) != AL_NO_ERROR)
+						{
+							fprintf(stderr, "54bTesting error: %s\n",
+								aluGetErrorString(error));				
+						}
+						/* Get the number of buffers processed
+						 */
+						alGetSourcei(
+							ALmixer_Channel_List[i].alsource,
+							AL_BUFFERS_PROCESSED, 
+							&buffers_processed
+						);
+						if((error = alGetError()) != AL_NO_ERROR)
+						{
+							fprintf(stderr, "54cError, Can't get buffers_processed: %s\n",
+								aluGetErrorString(error));				
+						}
+#endif
 						if(AL_STOPPED == state)
 						{
 							/* Resuming in not eof, but nothing to buffer */
+
+							/* Okay, here's another lately discovered problem:
+							 * I can't find it in the spec, but for at least some of the 
+							 * implementations, if I call play on a stopped source that 
+							 * has processed buffers, all those buffers get marked as unprocessed
+							 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
+							 * processed, on resume, the earlier 24 buffers will get replayed,
+							 * causing a "hiccup" like sound in the playback.
+							 * To avoid this, I must unqueue all processed buffers before
+							 * calling play. But to complicate things, I need to worry about resyncing
+							 * the circular queue with this since I designed this thing
+							 * with some correlation between the two. However, I might
+							 * have already handled this, so I will try writing this code without
+							 * syncing for now.
+							 * There is currently an assumption that a buffer 
+							 * was queued above so I actually have something
+							 * to play.
+							 */
+							ALint temp_count;
+/*							
+							fprintf(stderr, "STOPPED1, need to clear processed, status is:\n");
+							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
+*/
+							for(temp_count=0; temp_count<buffers_processed; temp_count++)
+							{
+								alSourceUnqueueBuffers(
+									ALmixer_Channel_List[i].alsource,
+									1, &unqueued_buffer_id
+								);
+								if((error = alGetError()) != AL_NO_ERROR)
+								{
+									fprintf(stderr, "55aTesting error: %s\n",
+										aluGetErrorString(error));				
+									error_flag--;
+								}
+							}
+/*
+							fprintf(stderr, "After unqueue clear...:\n");
+							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
+*/
 							alSourcePlay(ALmixer_Channel_List[i].alsource);
-	if((error = alGetError()) != AL_NO_ERROR)
-	{
-		fprintf(stderr, "55Testing error: %s\n",
-			aluGetErrorString(error));				
-	}
+							if((error = alGetError()) != AL_NO_ERROR)
+							{
+								fprintf(stderr, "55Tbesting error: %s\n",
+									aluGetErrorString(error));				
+							}
 						}
 						/* Let's escape to the next loop.
 						 * All code below this point is for queuing up 
 						 */
 						/*
-		fprintf(stderr, "Entry: Nothing to do...continue\n\n");
-		*/				
+						   fprintf(stderr, "Entry: Nothing to do...continue\n\n");
+						 */				
 						continue;
 					}
 					/* We now know we have to fill an available
@@ -4934,10 +5114,11 @@
 							 * let things be handled correctly
 							 * in future update calls
 							 */
+/*
 						fprintf(stderr, "SHOULD BE EOF\n");
 							
 							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
-							
+*/							
 							continue;
 						}
 					} /* END if bytes_returned == 0 */
@@ -4956,10 +5137,11 @@
 						 * to queue so we can return the value 
 						 */
 						retval++;
+						/*
 						fprintf(stderr, "NOT_EOF???, about to Queue more data for num_buffers (%d) < max_queue (%d)\n",
 								ALmixer_Channel_List[i].almixer_data->num_buffers_in_use,
 								ALmixer_Channel_List[i].almixer_data->max_queue_buffers);
-								
+						*/		
 						alSourceQueueBuffers(
 							ALmixer_Channel_List[i].alsource,
 							1, 
@@ -5056,24 +5238,83 @@
 					/* Might want to check state */
 					/* In case the playback stopped,
 					 * we need to resume */
+					#if 1 
+					/* Try not refetching the state here because I'm getting a duplicate
+						 buffer playback (hiccup) */
 					alGetSourcei(
 						ALmixer_Channel_List[i].alsource,
 						AL_SOURCE_STATE, &state
 					);
-	if((error = alGetError()) != AL_NO_ERROR)
-	{
-		fprintf(stderr, "57Testing error: %s\n",
-			aluGetErrorString(error));				
-	}
+					if((error = alGetError()) != AL_NO_ERROR)
+					{
+						fprintf(stderr, "57bTesting error: %s\n",
+							aluGetErrorString(error));				
+					}
+					/* Get the number of buffers processed
+					 */
+					alGetSourcei(
+						ALmixer_Channel_List[i].alsource,
+						AL_BUFFERS_PROCESSED, 
+						&buffers_processed
+					);
+					if((error = alGetError()) != AL_NO_ERROR)
+					{
+						fprintf(stderr, "57cError, Can't get buffers_processed: %s\n",
+							aluGetErrorString(error));				
+					}
+					#endif
 					if(AL_STOPPED == state)
 					{
+					/*
 						fprintf(stderr, "Resuming in not eof\n");
-						alSourcePlay(ALmixer_Channel_List[i].alsource);
-	if((error = alGetError()) != AL_NO_ERROR)
-	{
-		fprintf(stderr, "58Testing error: %s\n",
-			aluGetErrorString(error));				
-	}
+					*/
+							/* Okay, here's another lately discovered problem:
+							 * I can't find it in the spec, but for at least some of the 
+							 * implementations, if I call play on a stopped source that 
+							 * has processed buffers, all those buffers get marked as unprocessed
+							 * on alSourcePlay. So if I had a queue of 25 with 24 of the buffers
+							 * processed, on resume, the earlier 24 buffers will get replayed,
+							 * causing a "hiccup" like sound in the playback.
+							 * To avoid this, I must unqueue all processed buffers before
+							 * calling play. But to complicate things, I need to worry about resyncing
+							 * the circular queue with this since I designed this thing
+							 * with some correlation between the two. However, I might
+							 * have already handled this, so I will try writing this code without
+							 * syncing for now.
+							 * There is currently an assumption that a buffer 
+							 * was queued above so I actually have something
+							 * to play.
+							 */
+							ALint temp_count;
+/*
+							fprintf(stderr, "STOPPED2, need to clear processed, status is:\n");
+							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
+*/
+
+							for(temp_count=0; temp_count<buffers_processed; temp_count++)
+							{
+								alSourceUnqueueBuffers(
+									ALmixer_Channel_List[i].alsource,
+									1, &unqueued_buffer_id
+								);
+								if((error = alGetError()) != AL_NO_ERROR)
+								{
+									fprintf(stderr, "58aTesting error: %s\n",
+										aluGetErrorString(error));				
+									error_flag--;
+								}
+							}
+/*
+							fprintf(stderr, "After unqueue clear...:\n");
+							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
+*/
+
+							alSourcePlay(ALmixer_Channel_List[i].alsource);
+							if((error = alGetError()) != AL_NO_ERROR)
+							{
+								fprintf(stderr, "55Tbesting 8rror: %s\n",
+									aluGetErrorString(error));				
+							}
 					}
 					continue;
 				} /* END if( ! eof) */
@@ -5200,9 +5441,9 @@
 						if(AL_STOPPED == state)
 						{
 		fprintf(stderr, "Shouldn't be here. %d Buffers still in queue, but play stopped. This might be correct though because race conditions could have caused the STOP to happen right after our other tests...Checking queue status...\n", buffers_still_queued);
-
+/*
 							PrintQueueStatus(ALmixer_Channel_List[i].alsource);
-							
+*/							
 							/* Rather than force unqueuing the buffer, let's see if
 							* setting the buffer to none works (the OpenAL 1.0 
 							* Reference Annotation suggests this should work).								 
@@ -5632,7 +5873,7 @@
 	 *	calls to alBufferData().
 	 */	
 #ifdef __APPLE__
-	alEnable(ALC_CONVERT_DATA_UPON_LOADING);
+	alEnable(ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING);
 #endif
 	
 
@@ -5654,6 +5895,7 @@
 	Channel_Done_Callback = NULL;
 	Channel_Done_Callback_Userdata = NULL;
 	Channel_Data_Callback = NULL;
+	Channel_Data_Callback_Userdata = NULL;
 
 	/* Allocate memory for the list of channels */
 	ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel));
@@ -6112,7 +6354,7 @@
 	 *	calls to alBufferData().
 	 */	
 #ifdef __APPLE__
-	alEnable(ALC_CONVERT_DATA_UPON_LOADING);
+	alEnable(ALC_MAC_OSX_CONVERT_DATA_UPON_LOADING);
 #endif
 	
 	return 0;
@@ -6142,6 +6384,7 @@
 	Channel_Done_Callback = NULL;
 	Channel_Done_Callback_Userdata = NULL;
 	Channel_Data_Callback = NULL;
+	Channel_Data_Callback_Userdata = NULL;
 
 	/* Allocate memory for the list of channels */
 	ALmixer_Channel_List = (struct ALmixer_Channel*) malloc(Number_of_Channels_global * sizeof(struct ALmixer_Channel));
@@ -6330,7 +6573,7 @@
 	return;
 }
 
-Uint8 ALmixer_IsInitialized()
+SDL_bool ALmixer_IsInitialized()
 {
 	return ALmixer_Initialized;
 }
@@ -6490,7 +6733,7 @@
 	
 
 
-static ALmixer_Data* DoLoad(Sound_Sample* sample, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data)
+static ALmixer_Data* DoLoad(Sound_Sample* sample, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data)
 {
 	Uint32 bytes_decoded;
 	ALmixer_Data* ret_data;
@@ -6552,7 +6795,7 @@
 	/* Different cases for Streamed and Predecoded 
 	 * Streamed might turn into a predecoded if buffersize
 	 * is large enough */
-	if(ALMIXER_DECODE_STREAM == decode_mode)
+	if(SDL_FALSE == decode_mode_is_predecoded)
 	{
 		bytes_decoded = Sound_Decode(sample);
 		if(sample->flags & SOUND_SAMPLEFLAG_ERROR)
@@ -6793,7 +7036,7 @@
 				/* Create buffers for data access
 				 * Should be the same number as the number of queue buffers
 				 */
-				ret_data->buffer_map_list = (Buffer_Map*)malloc( sizeof(Buffer_Map) * max_queue_buffers);
+				ret_data->buffer_map_list = (ALmixer_Buffer_Map*)malloc( sizeof(ALmixer_Buffer_Map) * max_queue_buffers);
 				if(NULL == ret_data->buffer_map_list)
 				{
 					ALmixer_SetError("Out of Memory");
@@ -6845,14 +7088,14 @@
 
 				/* The Buffer_Map_List must be sorted by albuffer for binary searches
 	 			*/
-				qsort(ret_data->buffer_map_list, max_queue_buffers, sizeof(Buffer_Map), Compare_Buffer_Map);
+				qsort(ret_data->buffer_map_list, max_queue_buffers, sizeof(ALmixer_Buffer_Map), Compare_Buffer_Map);
 			} /* End if access_data==true */
 
 			
 		} /* End of do stream */
 	} /* end of DECODE_STREAM */
 	/* User requested decode all (easy, nothing to figure out) */
-	else if(ALMIXER_DECODE_ALL == decode_mode)
+	else if(SDL_TRUE == decode_mode_is_predecoded)
 	{
 		bytes_decoded = Sound_DecodeAll(sample);
 		if(sample->flags & SOUND_SAMPLEFLAG_ERROR)
@@ -6995,7 +7238,7 @@
  * must specify it, so I had to bring it back.
  * Remember I must close the rwops if there is an error before NewSample()
  */
-ALmixer_Data* ALmixer_LoadSample_RW(SDL_RWops* rwops, const char* fileext, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data)
+ALmixer_Data* ALmixer_LoadSample_RW(SDL_RWops* rwops, const char* fileext, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data)
 {
 	Sound_Sample* sample = NULL;
 	Sound_AudioInfo target;
@@ -7031,7 +7274,7 @@
 		return NULL;
 	}
 
-	return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data));
+	return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
 }
 
 
@@ -7041,7 +7284,7 @@
  * error checking and the fact that streamed/predecoded files
  * must be treated differently.
  */
-ALmixer_Data* ALmixer_LoadSample(const char* filename, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data)
+ALmixer_Data* ALmixer_LoadSample(const char* filename, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data)
 {
 	Sound_Sample* sample = NULL;
 	Sound_AudioInfo target;
@@ -7135,23 +7378,41 @@
 
 		fprintf(stderr, "Correction test: Actual rate=%d, desired=%d, actual format=%d, desired format=%d\n", sample->actual.rate, sample->desired.rate, sample->actual.format, sample->desired.format);
 
-	return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data));
+	return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
 }
 
 
 /* This is a back door for RAW samples or if you need the
  * AudioInfo field. Use at your own risk.
  */
-ALmixer_Data* ALmixer_LoadSample_RAW_RW(SDL_RWops* rwops, const char* fileext, Sound_AudioInfo* desired, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data)
+ALmixer_Data* ALmixer_LoadSample_RAW_RW(SDL_RWops* rwops, const char* fileext, ALmixer_AudioInfo* desired, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data)
 {
 	Sound_Sample* sample = NULL;
-	sample = Sound_NewSample(rwops, fileext, desired, buffersize);
+	Sound_AudioInfo sound_desired;
+	/* Rather than copying the data from struct to struct, I could just
+	 * cast the thing since the structs are meant to be identical. 
+	 * But if SDL_sound changes it's implementation, bad things
+	 * will probably happen. (Or if I change my implementation and 
+	 * forget about the cast, same bad scenario.) Since this is a load
+	 * function, performance of this is negligible.
+	 */
+	if(NULL == desired)
+	{
+		sample = Sound_NewSample(rwops, fileext, NULL, buffersize);
+	}
+	else
+	{
+	   sound_desired.format = desired->format;
+	   sound_desired.channels = desired->channels;
+	   sound_desired.rate = desired->rate;
+	   sample = Sound_NewSample(rwops, fileext, &sound_desired, buffersize);
+	}
 	if(NULL == sample)
 	{
 		ALmixer_SetError(Sound_GetError());
 		return NULL;
 	}
-	return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data));
+	return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
 }
 
 
@@ -7160,16 +7421,35 @@
 /* This is a back door for RAW samples or if you need the
  * AudioInfo field. Use at your own risk.
  */
-ALmixer_Data* ALmixer_LoadSample_RAW(const char* filename, Sound_AudioInfo* desired, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data)
+ALmixer_Data* ALmixer_LoadSample_RAW(const char* filename, ALmixer_AudioInfo* desired, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data)
 {
 	Sound_Sample* sample = NULL;
-	sample = Sound_NewSampleFromFile(filename, desired, buffersize);
+	Sound_AudioInfo sound_desired;
+	/* Rather than copying the data from struct to struct, I could just
+	 * cast the thing since the structs are meant to be identical. 
+	 * But if SDL_sound changes it's implementation, bad things
+	 * will probably happen. (Or if I change my implementation and 
+	 * forget about the cast, same bad scenario.) Since this is a load
+	 * function, performance of this is negligible.
+	 */
+	if(NULL == desired)
+	{
+		sample = Sound_NewSampleFromFile(filename, NULL, buffersize);
+	}
+	else
+	{
+	   sound_desired.format = desired->format;
+	   sound_desired.channels = desired->channels;
+	   sound_desired.rate = desired->rate;
+	   sample = Sound_NewSampleFromFile(filename, &sound_desired, buffersize);
+	}
+
 	if(NULL == sample)
 	{
 		ALmixer_SetError(Sound_GetError());
 		return NULL;
 	}
-	return( DoLoad(sample, buffersize, decode_mode, max_queue_buffers, num_startup_buffers, access_data));
+	return( DoLoad(sample, buffersize, decode_mode_is_predecoded, max_queue_buffers, num_startup_buffers, access_data));
 }
 
 
@@ -7304,10 +7584,11 @@
 }
 
 
-void ALmixer_ChannelData(void (*channel_data)(Sint32 which_chan, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bitdepth, Uint16 format, Uint8 decode_mode))
+void ALmixer_ChannelData(void (*channel_data)(Sint32 which_chan, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bit_depth, SDL_bool is_unsigned, SDL_bool decode_mode_is_predecoded, Uint32 length_in_msec, void* user_data), void* user_data)
 {
 	SDL_LockMutex(simple_lock);
 	Channel_Data_Callback = channel_data;
+	Channel_Data_Callback_Userdata = user_data;
 	SDL_UnlockMutex(simple_lock);
 }
 
@@ -7709,7 +7990,16 @@
 	return retval;
 }
 
-
-
-
-
+SDL_bool ALmixer_IsPredecoded(ALmixer_Data* data)
+{
+	if(NULL == data)
+	{
+		return SDL_FALSE;
+	}
+	return data->decoded_all;
+}
+
+
+
+
+
--- a/SDL_ALmixer.h	Wed Oct 27 16:50:19 2010 -0700
+++ b/SDL_ALmixer.h	Wed Oct 27 16:51:16 2010 -0700
@@ -23,19 +23,25 @@
 #define _SDL_ALMIXER_H_
 
 #include "SDL_types.h"
+#include "SDL_rwops.h"
+#include "SDL_error.h"
+#include "SDL_version.h"
 /*
-#include "SDL_rwops.h"
 #include "SDL_audio.h"
 #include "SDL_byteorder.h"
 */
-#include "SDL_version.h"
 
 /*
 #include "begin_code.h"
 */
 
+/*
 #include "SDL_sound.h"
+*/
+/* Crap! altypes.h is missing from 1.1
 #include "altypes.h"
+*/
+#include "al.h"
 
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
@@ -81,56 +87,43 @@
 /* Default startup buffers should be at least 1 */
 #define ALMIXER_DEFAULT_STARTUP_BUFFERS 2
 
+/*
 #define ALMIXER_DECODE_STREAM 	0
 #define ALMIXER_DECODE_ALL 		1
+*/
 
 
 #define ALmixer_GetError 	SDL_GetError
 #define ALmixer_SetError 	SDL_SetError
 
-typedef struct {
-	ALuint albuffer;
-	Sint32 index; /* might not need */
-	Uint8* data;
-	Uint32 num_bytes;
-} Buffer_Map;
 
-typedef struct {
-	Uint8 decoded_all; /* dictates different behaviors */
-	Sint32 total_time; /* total playing time of sample (msec) */
-	
-	Uint32 in_use; /* needed to prevent sharing for streams */
-	Uint8 eof; /* flag for eof, only used for streams  */
-	
-	Uint32 total_bytes; /* For predecoded */
-	Uint32 loaded_bytes; /* For predecoded (for seek) */
-
-	Sound_Sample* sample; /* SDL_Sound provides the data */
-	ALuint* buffer; /* array of OpenAL buffers (at least 1 for predecoded) */
+/* This is a trick I picked up from Lua. Doing the typedef separately 
+* (and I guess before the definition) instead of a single 
+* entry: typedef struct {...} YourName; seems to allow me
+* to use forward declarations. Doing it the other way (like SDL)
+* seems to prevent me from using forward declarions as I get conflicting
+* definition errors. I don't really understand why though.
+*/
+typedef struct ALmixer_Data ALmixer_Data;
+typedef struct ALmixer_AudioInfo ALmixer_AudioInfo;
 
-	/* Needed for streamed buffers */
-	Uint32 max_queue_buffers; /* Max number of queue buffers */
-	Uint32 num_startup_buffers; /* Number of ramp-up buffers */
-	Uint8 num_buffers_in_use; /* number of buffers in use */
-	
-	/* This stuff is for streamed buffers that require data access */
-	Buffer_Map* buffer_map_list; /* translate ALbuffer to index 
-									and holds pointer to copy of data for
-									data access */
-	ALuint current_buffer; /* The current playing buffer */
-
-	/* Nvidia distribution refuses to recognize a simple buffer query command
-	 * unlike all other distributions. It's forcing me to redo the code 
-	 * to accomodate this Nvidia flaw by making me maintain a "best guess"
-	 * copy of what I think the buffer queue state looks like.
-	 * A circular queue would a helpful data structure for this task,
-	 * but I wanted to avoid making an additional header requirement,
-	 * so I'm making it a void* 
-	 */
-	void* circular_buffer_queue; 
-		
-	
-} ALmixer_Data;
+/**
+ * Equvialent to the Sound_AudioInfo struct in SDL_sound.
+ * Originally, I just used the Sound_AudioInfo directly, but
+ * I've been trying to reduce the header dependencies for this file.
+ * But more to the point, I've been interested in dealing with the 
+ * WinMain override problem Josh faced when trying to use SDL components
+ * in an MFC app which didn't like losing control of WinMain. 
+ * My theory is that if I can purge the header of any thing that 
+ * #include's SDL_main.h, then this might work.
+ * So I am now introducing my own AudioInfo struct.
+ */
+struct ALmixer_AudioInfo
+{
+	Uint16 format;  /**< Equivalent of SDL_AudioSpec.format. */
+	Uint8 channels; /**< Number of sound channels. 1 == mono, 2 == stereo. */
+	Uint32 rate;    /**< Sample rate; frequency of sample points per second. */
+};
 
 
 #if 0
@@ -174,37 +167,37 @@
 extern DECLSPEC Sint32 SDLCALL ALmixer_Init_Mixer(Sint32 num_sources);
 
 extern DECLSPEC void SDLCALL ALmixer_Quit();
-extern DECLSPEC Uint8 SDLCALL ALmixer_IsInitialized();
+extern DECLSPEC SDL_bool SDLCALL ALmixer_IsInitialized();
 
 extern DECLSPEC Uint32 SDLCALL ALmixer_GetFrequency();
 
 extern DECLSPEC Sint32 SDLCALL ALmixer_AllocateChannels(Sint32 numchans);
 extern DECLSPEC Sint32 SDLCALL ALmixer_ReserveChannels(Sint32 num);
 
-extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample_RW(SDL_RWops* rwops, const char* fileext, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data);
+extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample_RW(SDL_RWops* rwops, const char* fileext, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data);
 
 
-#define ALmixer_LoadStream_RW(rwops,fileext,buffersize,max_queue_buffers,num_startup_buffers,access_data) ALmixer_LoadSample_RW(rwops,fileext,buffersize,ALMIXER_DECODE_STREAM, max_queue_buffers, num_startup_buffers,access_data)
+#define ALmixer_LoadStream_RW(rwops,fileext,buffersize,max_queue_buffers,num_startup_buffers,access_data) ALmixer_LoadSample_RW(rwops,fileext,buffersize, SDL_FALSE, max_queue_buffers, num_startup_buffers,access_data)
 
-#define ALmixer_LoadAll_RW(rwops,fileext,buffersize,access_data) ALmixer_LoadSample_RW(rwops,fileext,buffersize,ALMIXER_DECODE_ALL, 0, 0,access_data)
+#define ALmixer_LoadAll_RW(rwops,fileext,buffersize,access_data) ALmixer_LoadSample_RW(rwops,fileext,buffersize, SDL_TRUE, 0, 0,access_data)
 
 
 
-extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample(const char* filename, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data);
+extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample(const char* filename, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data);
 
 
-#define ALmixer_LoadStream(filename,buffersize,max_queue_buffers,num_startup_buffers,access_data) ALmixer_LoadSample(filename,buffersize,ALMIXER_DECODE_STREAM, max_queue_buffers, num_startup_buffers,access_data)
+#define ALmixer_LoadStream(filename,buffersize,max_queue_buffers,num_startup_buffers,access_data) ALmixer_LoadSample(filename,buffersize, SDL_FALSE, max_queue_buffers, num_startup_buffers,access_data)
 
-#define ALmixer_LoadAll(filename,buffersize,access_data) ALmixer_LoadSample(filename,buffersize,ALMIXER_DECODE_ALL, 0, 0,access_data)
+#define ALmixer_LoadAll(filename,buffersize,access_data) ALmixer_LoadSample(filename,buffersize, SDL_TRUE, 0, 0,access_data)
 
 
-extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample_RAW_RW(SDL_RWops* rwops, const char* fileext, Sound_AudioInfo* desired, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data);
+extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample_RAW_RW(SDL_RWops* rwops, const char* fileext, ALmixer_AudioInfo* desired, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data);
 
-#define ALmixer_LoadStream_RAW_RW(rwops,fileext,desired,buffersize,max_queue_buffers,num_startup_buffers,access_data) ALmixer_LoadSample_RAW_RW(rwops,fileext,desired,buffersize,ALMIXER_DECODE_STREAM, max_queue_buffers, num_startup_buffers,access_data)
+#define ALmixer_LoadStream_RAW_RW(rwops,fileext,desired,buffersize,max_queue_buffers,num_startup_buffers,access_data) ALmixer_LoadSample_RAW_RW(rwops,fileext,desired,buffersize, SDL_FALSE, max_queue_buffers, num_startup_buffers,access_data)
 
-#define ALmixer_LoadAll_RAW_RW(rwops,fileext,desired,buffersize,access_data) ALmixer_LoadSample_RAW_RW(rwops,fileext,desired,buffersize,ALMIXER_DECODE_ALL, 0, 0,access_data)
+#define ALmixer_LoadAll_RAW_RW(rwops,fileext,desired,buffersize,access_data) ALmixer_LoadSample_RAW_RW(rwops,fileext,desired,buffersize, SDL_TRUE, 0, 0,access_data)
 
-extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample_RAW(const char* filename, Sound_AudioInfo* desired, Uint32 buffersize, Uint8 decode_mode, Uint32 max_queue_buffers, Uint32 num_startup_buffers, Uint8 access_data);
+extern DECLSPEC ALmixer_Data * SDLCALL ALmixer_LoadSample_RAW(const char* filename, ALmixer_AudioInfo* desired, Uint32 buffersize, SDL_bool decode_mode_is_predecoded, Uint32 max_queue_buffers, Uint32 num_startup_buffers, SDL_bool access_data);
 
 
 
@@ -249,7 +242,82 @@
 extern DECLSPEC Sint32 SDLCALL ALmixer_FindFreeChannel(Sint32 start_channel);
 
 extern DECLSPEC void SDLCALL ALmixer_ChannelFinished(void (*channel_finished)(Sint32 channel, void* userdata), void* userdata);
+
+/*
 extern DECLSPEC void SDLCALL ALmixer_ChannelData(void (*channel_data)(Sint32 which_chan, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bitdepth, Uint16 format, Uint8 decode_mode));
+*/
+/**
+ * Audio data callback system.
+ * This is a callback function pointer that when set, will trigger a function
+ * anytime there is new data loaded for a sample. The appropriate load 
+ * parameter must be set in order for a sample to appear here.
+ * Keep in mind the the current backend implementation must do an end run
+ * around OpenAL because OpenAL lacks support for this kind of thing.
+ * As such, buffers are copied at decode time, and there is no attempt to do
+ * fine grained timing syncronization. You will be provided the entire buffer
+ * that is decoded regardless of length. So if you predecoded the entire 
+ * audio file, the entire data buffer will be provided in a single callback.
+ * If you stream the data, you will be getting chunk sizes that are the same as
+ * what you specified the decode size to be. Unfortunely, this means if you 
+ * pick smaller buffers, you get finer detail at the expense/risk of buffer 
+ * underruns. If you decode more data, you have to deal with the syncronization
+ * issues if you want to display the data during playback in something like an
+ * oscilloscope.
+ * 
+ * @param which_chan The ALmixer channel that the data is currently playing on.
+ * @param data This is a pointer to the data buffer containing ALmixer's 
+ * version of the decoded data. Consider this data as read-only. In the 
+ * non-threaded backend, this data will persist until potentially the next call
+ * to Update(). Currently, data buffers are preallocated and not destroyed
+ * until FreeData() is called (though this behavior is subject to change),
+ * but the contents will change when the buffer needs to be reused for a 
+ * future callback. The buffer reuse is tied to the amount of buffers that
+ * may be queued.
+ * But assuming I don't change this, this may allow for some optimization
+ * so you can try referencing data from these buffers without worrying 
+ * about crashing. (You still need to be aware that the data could be 
+ * modified behind the scenes on an Update().)
+ *
+ * The data type listed is an Unsigned 8-bit format, but the real data may
+ * not actually be this. Uint8 was chosen as a convenience. If you have 
+ * a 16 bit format, you will want to cast the data and also divide the num_bytes
+ * by 2. Typically, data is either Sint16 or Uint8. This seems to be a 
+ * convention audio people seem to follow though I'm not sure what the 
+ * underlying reasons (if any) are for this. I suspect that there may be 
+ * some nice alignment/conversion property if you need to cast from Uint8
+ * to Sint16.
+ * 
+ * @param num_bytes This is the total length of the data buffer. It presumes
+ * that this length is measured for Uint8. So if you have Sint16 data, you
+ * should divide num_bytes by two if you access the data as Sint16.
+ * 
+ * @param frequency The frequency the data was decoded at.
+ *
+ * @param channels 1 for mono, 2 for stereo.
+ *
+ * @param bit_depth Bits per sample. This is expected to be 8 or 16. This 
+ * number will tell you if you if you need to treat the data buffer as 
+ * 16 bit or not.
+ * 
+ * @param is_unsigned 1 if the data is unsigned, 0 if signed. Using this
+ * combined with bit_depth will tell you if you need to treat the data
+ * as Uint8, Sint8, Uint32, or Sint32.
+ *
+ * @param decode_mode_is_predecoded This is here to tell you if the data was totally 
+ * predecoded or loaded as a stream. If predecoded, you will only get 
+ * one data callback per playback instance. (This might also be true for 
+ * looping the same sample...I don't remember how it was implemented. 
+ * Maybe this should be fixed.)
+ * 0 (ALMIXER_DECODE_STREAM) for streamed.
+ * 1 (ALMIXER_DECODE_ALL) for predecoded.
+ *
+ * @param length_in_msec This returns the total length (time) of the data 
+ * buffer in milliseconds. This could be computed yourself, but is provided
+ * as a convenince.
+ *
+ * 
+ */
+extern DECLSPEC void SDLCALL ALmixer_ChannelData(void (*channel_data)(Sint32 which_chan, Uint8* data, Uint32 num_bytes, Uint32 frequency, Uint8 channels, Uint8 bit_depth, SDL_bool is_unsigned, SDL_bool decode_mode_is_predecoded, Uint32 length_in_msec, void* user_data), void* user_data);
 
 
 extern DECLSPEC Sint32 SDLCALL ALmixer_HaltChannel(Sint32 channel);
@@ -322,6 +390,8 @@
 #define ALmixer_CountTotalChannels() ALmixer_AllocateChannels(-1)
 #define ALmixer_CountReservedChannels() ALmixer_ReserveChannels(-1)
 
+extern DECLSPEC SDL_bool SDLCALL ALmixer_IsPredecoded(ALmixer_Data* data);
+
 
 
 /* For testing */