changeset 4:341cea3e13c6

Initial add.
author Ryan C. Gordon <icculus@icculus.org>
date Mon, 17 Sep 2001 18:12:03 +0000
parents fd6cd0e04e6f
children b97da311bbe2
files CREDITS Makefile SDL_sound.c SDL_sound_internal.h decoders/raw.c playsound/test_sdlsound.c
diffstat 6 files changed, 1415 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CREDITS	Mon Sep 17 18:12:03 2001 +0000
@@ -0,0 +1,10 @@
+Initial API interface and implementation,
+RAW driver,
+Unix support:
+    Ryan C. Gordon
+
+Other stuff:
+    Your name here! Patches go to icculus@clutteredmind.org ...
+
+/* end of CREDITS ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Mon Sep 17 18:12:03 2001 +0000
@@ -0,0 +1,374 @@
+#-----------------------------------------------------------------------------#
+# 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
+#
+#  (Please see the file LICENSE in the source's root directory.)
+#
+#   This file written by Ryan C. Gordon.
+#-----------------------------------------------------------------------------#
+
+
+#-----------------------------------------------------------------------------#
+# Makefile for building SDL_sound on Unix-like systems. Follow the
+#  instructions for editing this file, then run "make" on the command line.
+#-----------------------------------------------------------------------------#
+
+
+#-----------------------------------------------------------------------------#
+# Set to your liking.
+#-----------------------------------------------------------------------------#
+CC = gcc
+LINKER = gcc
+
+
+#-----------------------------------------------------------------------------#
+# If this makefile fails to detect Cygwin correctly, or you want to force
+#  the build process's behaviour, set it to "true" or "false" (w/o quotes).
+#-----------------------------------------------------------------------------#
+#cygwin := true
+#cygwin := false
+cygwin := autodetect
+
+#-----------------------------------------------------------------------------#
+# You only need to set SDL_INC_DIR and SDL_LIB_DIR if you are using cygwin.
+#  SDL_INC_DIR is where SDL.h and associated headers can be found, and
+#  SDL_LIB_DIR is where SDL.lib and SDL.dll are located. These may be set as
+#  environment variables, if you'd prefer to not hack the Makefile.
+#
+# examples:
+#   SDL_INC_DIR := C:/2/SDL-1.1.8/include
+#   SDL_LIB_DIR := C:/2/SDL-1.1.8/lib
+#-----------------------------------------------------------------------------#
+ifeq ($(strip $(SDL_INC_DIR)),)
+  SDL_INC_DIR := please_set_me_cygwin_users
+endif
+
+ifeq ($(strip $(SDL_LIB_DIR)),)
+  SDL_LIB_DIR := please_set_me_cygwin_users
+endif
+
+#-----------------------------------------------------------------------------#
+# Set this to true if you want to create a debug build.
+#-----------------------------------------------------------------------------#
+#debugging := false
+debugging := true
+
+#-----------------------------------------------------------------------------#
+# Set the decoder types you'd like to support.
+#  Note that various decoders may need external libraries.
+#-----------------------------------------------------------------------------#
+use_decoder_raw := true
+use_decoder_voc := false
+
+#-----------------------------------------------------------------------------#
+# Set to "true" if you'd like to build a DLL. Set to "false" otherwise.
+#-----------------------------------------------------------------------------#
+#build_dll := false
+build_dll := true
+
+#-----------------------------------------------------------------------------#
+# Set one of the below. Currently, none of these are used.
+#-----------------------------------------------------------------------------#
+#use_asm = -DUSE_I386_ASM
+use_asm = -DUSE_PORTABLE_C
+
+
+#-----------------------------------------------------------------------------#
+# Set this to where you want SDL_sound installed. It will put the
+#  files in $(install_prefix)/bin, $(install_prefix)/lib, and
+#  $(install_prefix)/include  ...
+#-----------------------------------------------------------------------------#
+install_prefix := /usr/local
+
+
+#-----------------------------------------------------------------------------#
+#-----------------------------------------------------------------------------#
+#-----------------------------------------------------------------------------#
+#-----------------------------------------------------------------------------#
+# Everything below this line is probably okay.
+#-----------------------------------------------------------------------------#
+#-----------------------------------------------------------------------------#
+#-----------------------------------------------------------------------------#
+#-----------------------------------------------------------------------------#
+
+#-----------------------------------------------------------------------------#
+# CygWin autodetect.
+#-----------------------------------------------------------------------------#
+
+ifeq ($(strip $(cygwin)),autodetect)
+  ifneq ($(strip $(shell gcc -v 2>&1 |grep "cygwin")),)
+    cygwin := true
+  else
+    cygwin := false
+  endif
+endif
+
+
+#-----------------------------------------------------------------------------#
+# Platform-specific binary stuff.
+#-----------------------------------------------------------------------------#
+
+ifeq ($(strip $(cygwin)),true)
+  ifeq ($(strip $(SDL_INC_DIR)),please_set_me_cygwin_users)
+    $(error Cygwin users need to set the SDL_INC_DIR envr var.)
+  else
+    SDL_CFLAGS := -I$(SDL_INC_DIR)
+  endif
+
+  ifeq ($(strip $(SDL_LIB_DIR)),please_set_me_cygwin_users)
+    $(error Cygwin users need to set the SDL_LIB_DIR envr var.)
+  else
+    SDL_LDFLAGS := -L$(SDL_LIB_DIR) -lSDL
+  endif
+
+  # !!! FIXME
+  build_dll := false
+  # !!! FIXME
+
+  ASM = nasmw
+  EXE_EXT = .exe
+  DLL_EXT = .dll
+  STATICLIB_EXT = .a
+  ASMOBJFMT = win32
+  ASMDEFS = -dC_IDENTIFIERS_UNDERSCORED
+  CFLAGS += -DC_IDENTIFIERS_UNDERSCORED
+else
+  ASM = nasm
+  EXE_EXT =
+  DLL_EXT = .so
+  STATICLIB_EXT = .a
+  ASMOBJFMT = elf
+  SDL_CFLAGS := $(shell sdl-config --cflags)
+  SDL_LDFLAGS := $(shell sdl-config --libs)
+endif
+
+CFLAGS += $(SDL_CFLAGS)
+LDFLAGS += $(SDL_LDFLAGS)
+
+ifeq ($(strip $(build_dll)),true)
+LIB_EXT := $(DLL_EXT)
+SHAREDFLAGS += -shared
+else
+LIB_EXT := $(STATICLIB_EXT)
+endif
+
+#-----------------------------------------------------------------------------#
+# Version crapola.
+#-----------------------------------------------------------------------------#
+VERMAJOR := $(shell grep "define SOUND_VER_MAJOR" SDL_sound.h | sed "s/\#define SOUND_VER_MAJOR //")
+VERMINOR := $(shell grep "define SOUND_VER_MINOR" SDL_sound.h | sed "s/\#define SOUND_VER_MINOR //")
+VERPATCH := $(shell grep "define SOUND_VER_PATCH" SDL_sound.h | sed "s/\#define SOUND_VER_PATCH //")
+
+VERMAJOR := $(strip $(VERMAJOR))
+VERMINOR := $(strip $(VERMINOR))
+VERPATCH := $(strip $(VERPATCH))
+
+VERFULL := $(VERMAJOR).$(VERMINOR).$(VERPATCH)
+
+#-----------------------------------------------------------------------------#
+# General compiler, assembler, and linker flags.
+#-----------------------------------------------------------------------------#
+
+BINDIR := bin
+SRCDIR := .
+
+CFLAGS += $(use_asm) -I$(SRCDIR) -D_REENTRANT -fsigned-char -DPLATFORM_UNIX
+CFLAGS += -Wall -Werror -fno-exceptions -fno-rtti -ansi -pedantic
+
+LDFLAGS += -lm
+
+ifeq ($(strip $(debugging)),true)
+  CFLAGS += -DDEBUG -g -fno-omit-frame-pointer
+  LDFLAGS += -g -fno-omit-frame-pointer
+else
+  CFLAGS += -DNDEBUG -O2 -fomit-frame-pointer
+  LDFLAGS += -O2 -fomit-frame-pointer
+endif
+
+ASMFLAGS := -f $(ASMOBJFMT) $(ASMDEFS)
+
+#-----------------------------------------------------------------------------#
+# Source and target names.
+#-----------------------------------------------------------------------------#
+
+PUREBASELIBNAME := SDL_sound
+ifeq ($(strip $(cygwin)),true)
+BASELIBNAME := $(strip $(PUREBASELIBNAME))
+else
+BASELIBNAME := lib$(strip $(PUREBASELIBNAME))
+endif
+
+MAINLIB := $(BINDIR)/$(strip $(BASELIBNAME))$(strip $(LIB_EXT))
+
+TESTSRCS := test/test_sdlsound.c
+
+MAINSRCS := SDL_sound.c
+
+ifeq ($(strip $(use_decoder_raw)),true)
+  MAINSRCS += decoders/raw.c
+  CFLAGS += -DSOUND_SUPPORTS_RAW
+endif
+
+ifeq ($(strip $(use_decoder_voc)),true)
+  MAINSRCS += archivers/voc.c
+  CFLAGS += -DSOUND_SUPPORTS_VOC
+endif
+
+#ifeq ($(strip $(cygwin)),true)
+#  MAINSRCS += platform/win32.c
+#  CFLAGS += -DWIN32
+#else
+#  MAINSRCS += platform/unix.c
+#endif
+
+TESTEXE := $(BINDIR)/test_sdlsound$(EXE_EXT)
+
+# Rule for getting list of objects from source
+MAINOBJS1 := $(MAINSRCS:.c=.o)
+MAINOBJS2 := $(MAINOBJS1:.cpp=.o)
+MAINOBJS3 := $(MAINOBJS2:.asm=.o)
+MAINOBJS := $(foreach f,$(MAINOBJS3),$(BINDIR)/$(f))
+MAINSRCS := $(foreach f,$(MAINSRCS),$(SRCDIR)/$(f))
+
+TESTOBJS1 := $(TESTSRCS:.c=.o)
+TESTOBJS2 := $(TESTOBJS1:.cpp=.o)
+TESTOBJS3 := $(TESTOBJS2:.asm=.o)
+TESTOBJS := $(foreach f,$(TESTOBJS3),$(BINDIR)/$(f))
+TESTSRCS := $(foreach f,$(TESTSRCS),$(SRCDIR)/$(f))
+
+CLEANUP = $(wildcard *.exe) $(wildcard *.obj) \
+          $(wildcard $(BINDIR)/*.exe) $(wildcard $(BINDIR)/*.obj) \
+          $(wildcard *~) $(wildcard *.err) \
+          $(wildcard .\#*) core
+
+
+#-----------------------------------------------------------------------------#
+# Rules.
+#-----------------------------------------------------------------------------#
+
+# Rules for turning source files into .o files
+$(BINDIR)/%.o: $(SRCDIR)/%.cpp
+	$(CC) -c -o $@ $< $(CFLAGS)
+
+$(BINDIR)/%.o: $(SRCDIR)/%.c
+	$(CC) -c -o $@ $< $(CFLAGS)
+
+$(BINDIR)/%.o: $(SRCDIR)/%.asm
+	$(ASM) $(ASMFLAGS) -o $@ $<
+
+.PHONY: all clean distclean listobjs install showcfg showflags
+
+all: $(BINDIR) $(EXTRABUILD) $(MAINLIB) $(TESTEXE)
+
+$(MAINLIB) : $(BINDIR) $(MAINOBJS)
+	$(LINKER) -o $(MAINLIB) $(SHAREDFLAGS) $(MAINOBJS) $(LDFLAGS)
+
+$(TESTEXE) : $(MAINLIB) $(TESTOBJS)
+	$(LINKER) -o $(TESTEXE) $(TESTLDFLAGS) $(TESTOBJS) -L$(BINDIR) -l$(strip $(PUREBASELIBNAME)) $(LDFLAGS)
+
+
+install: all
+	rm -f $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERMAJOR)).$(strip $(VERMINOR)).*
+	mkdir -p $(install_prefix)/bin
+	mkdir -p $(install_prefix)/lib
+	mkdir -p $(install_prefix)/include
+	cp $(SRCDIR)/SDL_sound.h $(install_prefix)/include
+	cp $(TESTEXE) $(install_prefix)/bin
+ifeq ($(strip $(cygwin)),true)
+	cp $(MAINLIB) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT))
+else
+	cp $(MAINLIB) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL))
+	ln -sf $(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL)) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT))
+	ln -sf $(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL)) $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERMAJOR))
+	chmod 0755 $(install_prefix)/lib/$(strip $(BASELIBNAME))$(strip $(LIB_EXT)).$(strip $(VERFULL))
+	chmod 0644 $(install_prefix)/include/SDL_sound.h
+endif
+
+$(BINDIR):
+	mkdir -p $(BINDIR)
+	mkdir -p $(BINDIR)/decoders
+	mkdir -p $(BINDIR)/platform
+	mkdir -p $(BINDIR)/test
+
+distclean: clean
+
+clean:
+	rm -f $(CLEANUP)
+	rm -rf $(BINDIR)
+
+listobjs:
+	@echo SOURCES:
+	@echo $(MAINSRCS)
+	@echo
+	@echo OBJECTS:
+	@echo $(MAINOBJS)
+	@echo
+	@echo BINARIES:
+	@echo $(MAINLIB)
+
+showcfg:
+	@echo "Compiler              : $(CC)"
+	@echo "Using CygWin          : $(cygwin)"
+	@echo "Debugging             : $(debugging)"
+	@echo "ASM flag              : $(use_asm)"
+	@echo "SDL_sound version     : $(VERFULL)"
+	@echo "Building DLLs         : $(build_dll)"
+	@echo "Install prefix        : $(install_prefix)"
+	@echo "Supports .RAW         : $(use_decoder_raw)"
+	@echo "Supports .VOC         : $(use_decoder_voc)"
+
+showflags:
+	@echo 'CFLAGS  : $(CFLAGS)'
+	@echo 'LDFLAGS : $(LDFLAGS)'
+
+
+#-----------------------------------------------------------------------------#
+# This section is pretty much just for Ryan's use to make distributions.
+#  You Probably Should Not Touch.
+#-----------------------------------------------------------------------------#
+
+# These are the files needed in a binary distribution, regardless of what
+#  platform is being used.
+BINSCOMMON := LICENSE CHANGELOG SDL_sound.h
+
+.PHONY: package msbins win32bins nocygwin
+package: clean
+	cd .. ; mv SDL_sound SDL_sound-$(VERFULL) ; tar -cyvvf ./SDL_sound-$(VERFULL).tar.bz2 --exclude="*CVS*" SDL_sound-$(VERFULL) ; mv SDL_sound-$(VERFULL) SDL_sound
+
+
+ifeq ($(strip $(cygwin)),true)
+msbins: win32bins
+
+win32bins: clean all
+	cp $(SDL_LIB_DIR)/SDL.dll .
+	echo -e "\r\n\r\n\r\nHEY YOU.\r\n\r\n\r\nTake a look at README-win32bins.txt FIRST.\r\n\r\n\r\n--ryan. (icculus@clutteredmind.org)\r\n\r\n" |zip -9rz ../SDL_sound-win32bins-$(shell date +%m%d%Y).zip $(MAINLIB) SDL.dll $(EXTRAPACKAGELIBS) README-win32bins.txt
+
+else
+
+msbins: nocygwin
+win32bins: nocygwin
+
+nocygwin:
+	@echo This must be done on a Windows box in the Cygwin environment.
+
+endif
+
+#-----------------------------------------------------------------------------#
+# That's all, folks.
+#-----------------------------------------------------------------------------#
+
+# end of Makefile ...
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDL_sound.c	Mon Sep 17 18:12:03 2001 +0000
@@ -0,0 +1,520 @@
+/*
+ * 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
+ */
+
+/**
+ * This file implements the core API, which is relatively simple.
+ *   The real meat of SDL_sound is in the decoders directory.
+ *
+ * Documentation is in SDL_sound.h ... It's verbose, honest.  :)
+ *
+ * Please see the file LICENSE in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon. (icculus@clutteredmind.org)
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "SDL.h"
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+
+/* The various decoder drivers... */
+
+#if (defined SOUND_SUPPORTS_VOC)
+extern const Sound_DecoderFunctions  __Sound_DecoderFunctions_VOC;
+#endif
+
+#if (defined SOUND_SUPPORTS_RAW)
+extern const Sound_DecoderFunctions  __Sound_DecoderFunctions_RAW;
+#endif
+
+static const Sound_DecoderFunctions *decoderFuncs[] =
+{
+#if (defined SOUND_SUPPORTS_VOC)
+    &__Sound_DecoderFunctions_VOC,
+#endif
+
+#if (defined SOUND_SUPPORTS_RAW)
+    &__Sound_DecoderFunctions_RAW,
+#endif
+
+    NULL
+};
+
+
+
+/* General SDL_sound state ... */
+
+static int initialized = 0;
+static Sound_Sample *samplesList = NULL;  /* this is a linked list. */
+static const Sound_DecoderInfo **available_decoders = NULL;
+
+
+/* functions ... */
+
+void Sound_GetLinkedVersion(Sound_Version *ver)
+{
+    if (ver != NULL)
+    {
+        ver->major = SOUND_VER_MAJOR;
+        ver->minor = SOUND_VER_MINOR;
+        ver->patch = SOUND_VER_PATCH;
+    } /* if */
+} /* Sound_GetLinkedVersion */
+
+
+int Sound_Init(void)
+{
+    size_t i;
+    BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
+    samplesList = NULL;
+
+    SDL_Init(SDL_INIT_AUDIO);
+
+    for (i = 0; decoderFuncs[i] != NULL; i++)
+        ; /* do nothing. */
+
+    i++;
+    available_decoders = (const Sound_DecoderInfo **)
+                            malloc(i * sizeof (Sound_DecoderInfo *));
+    BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    for (i = 0; decoderFuncs[i] != NULL; i++)
+        available_decoders[i] = &decoderFuncs[i]->info;
+
+    initialized = 1;
+    return(1);
+} /* Sound_Init */
+
+
+int Sound_Quit(void)
+{
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+
+    while (((volatile Sound_Sample *) samplesList) != NULL)
+        Sound_FreeSample(samplesList);
+
+    if (available_decoders != NULL)
+        free(available_decoders);
+    available_decoders = NULL;
+
+    initialized = 0;
+
+    return(1);
+} /* Sound_Quit */
+
+
+const Sound_DecoderInfo **Sound_AvailableDecoders(void)
+{
+    return(available_decoders);  /* READ. ONLY. */
+} /* Sound_AvailableDecoders */
+
+
+const char *Sound_GetError(void)
+{
+    return(SDL_GetError());
+} /* Sound_GetError */
+
+
+void Sound_ClearError(void)
+{
+    SDL_ClearError();
+} /* Sound_ClearError */
+
+
+/*
+ * This is declared in the internal header.
+ */
+void Sound_SetError(const char *err)
+{
+    if (err != NULL)
+        SDL_SetError(err);
+} /* Sound_SetError */
+
+
+/*
+ * -ansi and -pedantic flags prevent use of strcasecmp() on Linux, and
+ *  I honestly don't want to mess around with figuring out if a given
+ *  platform has "strcasecmp", "stricmp", or
+ *  "compare_two_damned_strings_case_insensitive", which I hear is in the
+ *  next release of Carbon.  :)  This is exported so decoders may use it if
+ *  they like.
+ */
+int __Sound_strcasecmp(const char *x, const char *y)
+{
+    int ux, uy;
+
+    do
+    {
+        ux = toupper((int) *x);
+        uy = toupper((int) *y);
+        if (ux > uy)
+            return(1);
+        else if (ux < uy)
+            return(-1);
+        x++;
+        y++;
+    } while ((ux) && (uy));
+
+    return(0);
+} /* __Sound_strcasecmp */
+
+
+/*
+ * Allocate a Sound_Sample, and fill in most of its fields. Those that need
+ *  to be filled in later, by a decoder, will be initialized to zero.
+ */
+static Sound_Sample *alloc_sample(SDL_RWops *rw, Sound_AudioInfo *desired,
+                                    Uint32 bufferSize)
+{
+    Sound_Sample *retval = malloc(sizeof (Sound_Sample));
+    Sound_SampleInternal *internal = malloc(sizeof (Sound_SampleInternal));
+    if ((retval == NULL) || (internal == NULL))
+    {
+        Sound_SetError(ERR_OUT_OF_MEMORY);
+        if (retval)
+            free(retval);
+        if (internal)
+            free(internal);
+
+        return(NULL);
+    } /* if */
+
+    memset(retval, '\0', sizeof (Sound_Sample));
+    memset(internal, '\0', sizeof (Sound_SampleInternal));
+
+    assert(bufferSize > 0);
+    retval->buffer = malloc(bufferSize);  /* pure ugly. */
+    if (!retval->buffer)
+    {
+        Sound_SetError(ERR_OUT_OF_MEMORY);
+        free(internal);
+        free(retval);
+        return(NULL);
+    } /* if */
+    memset(retval->buffer, '\0', bufferSize);
+    retval->buffer_size = bufferSize;
+
+    if (desired != NULL)
+        memcpy(&retval->desired, desired, sizeof (Sound_AudioInfo));
+
+    internal->rw = rw;
+    retval->opaque = internal;
+    return(retval);
+} /* alloc_sample */
+
+
+/*
+ * The bulk of the Sound_NewSample() work is done here...
+ *  Ask the specified decoder to handle the data in (rw), and if
+ *  so, construct the Sound_Sample. Otherwise, try to wind (rw)'s stream
+ *  back to where it was, and return false.
+ *
+ *  !!! FIXME: This is big, ugly, nasty, and smelly.
+ */
+static int init_sample(const Sound_DecoderFunctions *funcs,
+                        Sound_Sample *sample, const char *ext,
+                        Sound_AudioInfo *_desired)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    int pos = SDL_RWtell(internal->rw);  /* !!! FIXME: Int? Really? */
+    Sound_AudioInfo desired;
+
+        /* fill in the funcs for this decoder... */
+    sample->decoder = &funcs->info;
+    internal->funcs = funcs;
+    if (!funcs->open(sample, ext))
+    {
+        SDL_RWseek(internal->rw, pos, SEEK_SET);  /* set for next try... */
+        return(0);
+    } /* if */
+
+    /* success; we've got a decoder! */
+
+    /* Now we need to set up the conversion buffer... */
+
+    memcpy(&desired, (_desired != NULL) ? _desired : &sample->actual,
+            sizeof (Sound_AudioInfo));
+
+    if (SDL_BuildAudioCVT(&internal->sdlcvt,
+                          sample->actual.format,
+                          sample->actual.channels,
+                          (int) sample->actual.rate,   /* !!! FIXME: Int? Really? */
+                          desired.format,
+                          desired.channels,
+                          (int) desired.rate) == -1) /* !!! FIXME: Int? Really? */
+    {
+        Sound_SetError(SDL_GetError());
+        funcs->close(sample);
+        SDL_RWseek(internal->rw, pos, SEEK_SET);  /* set for next try... */
+        return(0);
+    } /* if */
+
+    if (internal->sdlcvt.len_mult > 1)
+    {
+        void *rc = realloc(sample->buffer,
+                            sample->buffer_size * internal->sdlcvt.len_mult);
+        if (rc == NULL)
+        {
+            funcs->close(sample);
+            SDL_RWseek(internal->rw, pos, SEEK_SET);  /* set for next try... */
+            return(0);
+        } /* if */
+
+        sample->buffer = rc;
+    } /* if */
+
+        /* these pointers are all one and the same. */
+    memcpy(&sample->desired, &desired, sizeof (Sound_AudioInfo));
+    internal->sdlcvt.buf = internal->buffer = sample->buffer;
+    internal->buffer_size = sample->buffer_size / internal->sdlcvt.len_mult;
+    internal->sdlcvt.len = internal->buffer_size;
+
+    /* Prepend our new Sound_Sample to the samplesList... */
+    if (samplesList != NULL)
+    {
+        internal->next = samplesList;
+        if (samplesList != NULL)
+            internal->prev = sample;
+    } /* if */
+    samplesList = sample;
+
+    return(1);
+} /* init_sample */
+
+
+Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext,
+                              Sound_AudioInfo *desired, Uint32 bSize)
+{
+    size_t i;
+    Sound_Sample *retval;
+
+    /* sanity checks. */
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL);
+    BAIL_IF_MACRO(rw == NULL, ERR_INVALID_ARGUMENT, NULL);
+
+    retval = alloc_sample(rw, desired, bSize);
+    if (!retval)
+        return(NULL);  /* alloc_sample() sets error message... */
+
+    if (ext != NULL)
+    {
+        for (i = 0; decoderFuncs[i] != NULL; i++)
+        {
+            const char *decoderExt = decoderFuncs[i]->info.extension;
+            if (__Sound_strcasecmp(decoderExt, ext) == 0)
+            {
+                if (init_sample(decoderFuncs[i], retval, ext, desired))
+                    return(retval);
+            } /* if */
+        } /* for */
+    } /* if */
+
+    /* no direct extension match? Try everything we've got... */
+    for (i = 0; decoderFuncs[i] != NULL; i++)
+    {
+        if (init_sample(decoderFuncs[i], retval, ext, desired))
+            return(retval);
+    } /* for */
+
+    /* nothing could handle the sound data... */
+    free(retval->opaque);
+    if (retval->buffer != NULL)
+        free(retval->buffer);
+    free(retval);
+    SDL_RWclose(rw);
+    Sound_SetError(ERR_UNSUPPORTED_FORMAT);
+    return(NULL);
+} /* Sound_NewSample */
+
+
+Sound_Sample *Sound_NewSampleFromFile(const char *filename,
+                                      Sound_AudioInfo *desired,
+                                      Uint32 bufferSize)
+{
+    const char *ext;
+    SDL_RWops *rw;
+
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL);
+    BAIL_IF_MACRO(filename == NULL, ERR_INVALID_ARGUMENT, NULL);
+
+    ext = strrchr(filename, '.');
+    rw = SDL_RWFromFile(filename, "rb");
+    BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL);
+
+    if (ext != NULL)
+        ext++;
+
+    return(Sound_NewSample(rw, ext, desired, bufferSize));
+} /* Sound_NewSampleFromFile */
+
+
+void Sound_FreeSample(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal;
+
+    if (!initialized)
+    {
+        Sound_SetError(ERR_NOT_INITIALIZED);
+        return;
+    } /* if */
+
+    if (sample == NULL)
+    {
+        Sound_SetError(ERR_INVALID_ARGUMENT);
+        return;
+    } /* if */
+
+    internal = (Sound_SampleInternal *) sample->opaque;
+
+    internal->funcs->close(sample);
+
+    /* update the samplesList... */
+    if (internal->prev != NULL)
+    {
+        Sound_SampleInternal *prevInternal;
+        prevInternal = (Sound_SampleInternal *) internal->prev->opaque;
+        prevInternal->next = internal->next;
+    } /* if */
+    else
+    {
+        assert(samplesList == sample);
+        samplesList = internal->next;
+    } /* else */
+
+    if (internal->next != NULL)
+    {
+        Sound_SampleInternal *nextInternal;
+        nextInternal = (Sound_SampleInternal *) internal->next->opaque;
+        nextInternal->prev = internal->prev;
+    } /* if */
+
+    /* nuke it... */
+    if (internal->rw != NULL)  /* this condition is a "just in case" thing. */
+        SDL_RWclose(internal->rw);
+    assert(internal->buffer != NULL);
+    if (internal->buffer != sample->buffer)
+        free(internal->buffer);
+    free(internal);
+    if (sample->buffer != NULL)
+        free(sample->buffer);
+    free(sample);
+} /* Sound_FreeSample */
+
+
+int Sound_SetBufferSize(Sound_Sample *sample, Uint32 newSize)
+{
+    void *newBuf = NULL;
+    Sound_SampleInternal *internal = NULL;
+
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+    BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0);
+    internal = ((Sound_SampleInternal *) sample->opaque);
+    newBuf = realloc(sample->buffer, newSize * internal->sdlcvt.len_mult);
+    BAIL_IF_MACRO(newBuf == NULL, ERR_OUT_OF_MEMORY, 0);
+
+    internal->sdlcvt.buf = internal->buffer = sample->buffer = newBuf;
+    sample->buffer_size = newSize;
+    internal->buffer_size = newSize / internal->sdlcvt.len_mult;
+    internal->sdlcvt.len = internal->buffer_size;
+
+    return(1);
+} /* Sound_SetBufferSize */
+
+
+Uint32 Sound_Decode(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = NULL;
+    Uint32 retval = 0;
+
+        /* a boatload of sanity checks... */
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+    BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0);
+    BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0);
+    BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0);
+
+    internal = (Sound_SampleInternal *) sample->opaque;
+
+    assert(sample->buffer != NULL);
+    assert(sample->buffer_size > 0);
+    assert(internal->buffer != NULL);
+    assert(internal->buffer_size > 0);
+
+        /* reset EAGAIN. Decoder can flip it back on if it needs to. */
+    sample->flags &= !SOUND_SAMPLEFLAG_EAGAIN;
+
+    retval = internal->funcs->read(sample);
+    if (internal->sdlcvt.needed)
+    {
+        internal->sdlcvt.len = retval;
+        SDL_ConvertAudio(&internal->sdlcvt);
+        retval *= internal->sdlcvt.len_mult;
+    } /* if */
+
+    return(retval);
+} /* Sound_Decode */
+
+
+Uint32 Sound_DecodeAll(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = NULL;
+    void *buf = NULL;
+    Uint32 newBufSize = 0;
+
+    BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+
+    internal = (Sound_SampleInternal *) sample->opaque;
+
+    while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) &&
+            ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) )
+    {
+        void *ptr = realloc(buf, newBufSize + sample->buffer_size);
+        if (ptr == NULL)
+        {
+            sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+            Sound_SetError(ERR_OUT_OF_MEMORY);
+        } /* if */
+        else
+        {
+            Uint32 br = Sound_Decode(sample);
+            memcpy( ((char *) buf) + newBufSize, sample->buffer, br );
+            newBufSize += br;
+        } /* else */
+    } /* while */
+
+    free(sample->buffer);
+    sample->buffer = internal->buffer = internal->sdlcvt.buf = buf;
+    sample->buffer_size = newBufSize;
+    internal->buffer_size = newBufSize / internal->sdlcvt.len_mult;
+    internal->sdlcvt.len_mult = internal->buffer_size;
+
+    return(newBufSize);
+} /* Sound_DecodeAll */
+
+
+/* end of SDL_sound.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDL_sound_internal.h	Mon Sep 17 18:12:03 2001 +0000
@@ -0,0 +1,203 @@
+/*
+ * 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
+ */
+
+/*
+ * Internal function/structure declaration. Do NOT include in your
+ *  application.
+ *
+ * Please see the file LICENSE in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon. (icculus@clutteredmind.org)
+ */
+
+#ifndef _INCLUDE_SDL_SOUND_INTERNAL_H_
+#define _INCLUDE_SDL_SOUND_INTERNAL_H_
+
+#ifndef __SDL_SOUND_INTERNAL__
+#error Do not include this header from your applications.
+#endif
+
+#include "SDL.h"
+
+typedef struct __SOUND_DECODERFUNCTIONS__
+{
+        /* This is a block of info about your decoder. See SDL_sound.h. */
+    const Sound_DecoderInfo info;
+
+        /*
+         * Returns non-zero if (sample) has a valid fileformat that this
+         *  driver can handle. Zero if this driver can NOT handle the data.
+         *
+         * Extension, which may be NULL, is just a hint as to the form of
+         *  data that is being passed in. Most decoders should determine if
+         *  they can handle the data by the data itself, but others, like
+         *  the raw data handler, need this hint to know if they should
+         *  accept the data in the first place.
+         *
+         * (sample)'s (opaque) field should be cast to a Sound_SampleInternal
+         *  pointer:
+         *
+         *   Sound_SampleInternal *internal;
+         *   internal = (Sound_SampleInternal *) sample->opaque;
+         *
+         * Certain fields of sample will be filled in for the decoder before
+         *  this call, and others should be filled in by the decoder. Some
+         *  fields are offlimits, and should NOT be modified. The list:
+         *
+         * in Sound_SampleInternal section:
+         *    Sound_Sample *next;  (offlimits)
+         *    Sound_Sample *prev;  (offlimits)
+         *    SDL_RWops *rw;       (can use, but do NOT close it)
+         *    const Sound_DecoderFunctions *funcs; (that's this structure)
+         *    SDL_AudioCVT sdlcvt; (offlimits)
+         *    void *buffer;        (offlimits until read() method)
+         *    Uint32 buffer_size;  (offlimits until read() method)
+         *
+         * in rest of Sound_Sample:
+         *    void *opaque;        (this was internal section, above)
+         *    const Sound_DecoderInfo *decoder;  (read only)
+         *    Sound_AudioInfo desired; (read only, usually not needed here)
+         *    Sound_AudioInfo actual;  (please fill this in)
+         *    void *buffer;            (offlimits)
+         *    Uint32 buffer_size;      (offlimits)
+         *    Sound_SampleFlags flags; (set appropriately)
+         */
+    int (*open)(Sound_Sample *sample, const char *ext);
+
+        /*
+         * Clean up. SDL_sound is done with this sample, so the decoder should
+         *  clean up any resources it allocated. Anything that wasn't
+         *  explicitly allocated by the decoder should be LEFT ALONE, since
+         *  the higher-level SDL_sound layer will clean up its own mess.
+         */
+    void (*close)(Sound_Sample *sample);
+
+        /*
+         * Get more data from (sample). The decoder should get a pointer to
+         *  the internal structure...
+         *
+         *   Sound_SampleInternal *internal;
+         *   internal = (Sound_SampleInternal *) sample->opaque;
+         *
+         *  ...and then start decoding. Fill in up to internal->buffer_size
+         *  bytes of decoded sound in the space pointed to by
+         *  internal->buffer. The encoded data is read in from internal->rw.
+         *  Data should be decoded in the format specified during the
+         *  decoder's open() method in the sample->actual field. The
+         *  conversion to the desired format is done at a higher level.
+         *
+         * The return value is the number of bytes decoded into
+         *  internal->buffer, which can be no more than internal->buffer_size,
+         *  but can be less. If it is less, you should set a state flag:
+         *
+         *   If there's just no more data (end of file, etc), then do:
+         *      sample->flags |= SOUND_SAMPLEFLAG_EOF;
+         *
+         *   If there's an unrecoverable error, then do:
+         *      Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG);
+         *      sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+         *
+         *   If there's more data, but you'd have to block for considerable
+         *    amounts of time to get at it, or there's a recoverable error,
+         *    then do:
+         *      Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG);
+         *      sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+         *
+         * SDL_sound will not call your read() method for any samples with
+         *  SOUND_SAMPLEFLAG_EOF or SOUND_SAMPLEFLAG_ERROR set. The
+         *  SOUND_SAMPLEFLAG_EAGAIN flag is reset before each call to this
+         *  method.
+         */
+    int (*read)(Sound_Sample *sample);
+} Sound_DecoderFunctions;
+
+
+typedef struct __SOUND_SAMPLEINTERNAL__
+{
+    Sound_Sample *next;
+    Sound_Sample *prev;
+    SDL_RWops *rw;
+    const Sound_DecoderFunctions *funcs;
+    SDL_AudioCVT sdlcvt;
+    void *buffer;
+    Uint32 buffer_size;
+} Sound_SampleInternal;
+
+
+
+/* error messages... */
+#define ERR_IS_INITIALIZED       "Already initialized"
+#define ERR_NOT_INITIALIZED      "Not initialized"
+#define ERR_INVALID_ARGUMENT     "Invalid argument"
+#define ERR_OUT_OF_MEMORY        "Out of memory"
+#define ERR_NOT_SUPPORTED        "Operation not supported"
+#define ERR_UNSUPPORTED_FORMAT   "Sound format unsupported"
+#define ERR_NOT_A_HANDLE         "Not a file handle"
+#define ERR_NO_SUCH_FILE         "No such file"
+#define ERR_PAST_EOF             "Past end of file"
+#define ERR_IO_ERROR             "I/O error"
+#define ERR_COMPRESSION          "(De)compression error"
+#define ERR_PREV_ERROR           "Previous decoding already caused an error"
+#define ERR_PREV_EOF             "Previous decoding already triggered EOF"
+
+/*
+ * Call this to set the message returned by Sound_GetError().
+ *  Please only use the ERR_* constants above, or add new constants to the
+ *  above group, but I want these all in one place.
+ *
+ * Calling this with a NULL argument is a safe no-op.
+ */
+void Sound_SetError(const char *err);
+
+
+/*
+ * Use this if you need a cross-platform stricmp().
+ */
+int __Sound_strcasecmp(const char *x, const char *y);
+
+
+/* These get used all over for lessening code clutter. */
+#define BAIL_MACRO(e, r) { Sound_SetError(e); return r; }
+#define BAIL_IF_MACRO(c, e, r) if (c) { Sound_SetError(e); return r; }
+
+
+
+
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+/*------------                                              ----------------*/
+/*------------  You MUST implement the following functions  ----------------*/
+/*------------        if porting to a new platform.         ----------------*/
+/*------------     (see platform/unix.c for an example)     ----------------*/
+/*------------                                              ----------------*/
+/*--------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------*/
+
+
+/* (None, right now.)  */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#endif /* defined _INCLUDE_SDL_SOUND_INTERNAL_H_ */
+
+/* end of SDL_sound_internal.h ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoders/raw.c	Mon Sep 17 18:12:03 2001 +0000
@@ -0,0 +1,121 @@
+/*
+ * 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
+ */
+
+/*
+ * RAW decoder for SDL_sound. This is as simple as it gets.
+ *
+ * This driver handles raw audio data. You must, regardless of where the
+ *  data is actually coming from, specify the string "RAW" in the extension
+ *  parameter of Sound_NewSample() (or, alternately, open a file with the
+ *  extension ".raw" in Sound_NewSampleFromFile()). The string is checked
+ *  case-insensitive. We need this check, because raw data, being raw, has
+ *  no headers or magic number we can use to determine if we should handle a
+ *  given file, so we needed some way to have this "decoder" discriminate.
+ *
+ * When calling Sound_NewSample*(), you must also specify a "desired"
+ *  audio format. The "actual" format will always match what you specify, so
+ *  there will be no conversion overhead, but these routines need to know how
+ *  to treat the bits, since it's all random garbage otherwise.
+ *
+ * Please see the file LICENSE in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon. (icculus@clutteredmind.org)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#if (!defined SOUND_SUPPORTS_RAW)
+#error SOUND_SUPPORTS_RAW must be defined.
+#endif
+
+
+static int RAW_open(Sound_Sample *sample, const char *ext);
+static void RAW_close(Sound_Sample *sample);
+static int RAW_read(Sound_Sample *sample);
+
+const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW =
+{
+    {
+        "RAW",
+        "Raw audio",
+        "Ryan C. Gordon <icculus@clutteredmind.org>",
+        "http://www.icculus.org/SDL_sound/"
+    },
+
+    RAW_open,       /* open() method       */
+    RAW_close,      /* close() method       */
+    RAW_read        /* read() method       */
+};
+
+
+static int RAW_open(Sound_Sample *sample, const char *ext)
+{
+    if (__Sound_strcasecmp(ext, "RAW") != 0)
+        return(0);
+
+    if ( (sample->desired.channels < 1)  ||
+         (sample->desired.channels > 2)  ||
+         (sample->desired.rate == 0)     ||
+         (sample->desired.format == 0) )
+    {
+        return(0);
+    } /* if */
+
+    memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo));
+    sample->flags = SOUND_SAMPLEFLAG_NONE;
+    return(1);
+} /* RAW_open */
+
+
+static void RAW_close(Sound_Sample *sample)
+{
+    /* we don't allocate anything. That's easy, eh? */
+} /* RAW_close */
+
+
+static int RAW_read(Sound_Sample *sample)
+{
+    int retval;
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    retval = SDL_RWread(internal->rw, internal->buffer,
+                        1, internal->buffer_size);
+
+    if (retval == 0)
+        sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+    else if (retval == -1)
+        sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+        /* next call this may be a EOF or error... */
+    else if (retval < internal->buffer_size)
+        sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+    return(retval);
+} /* RAW_read */
+
+
+/* end of raw.c ... */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/playsound/test_sdlsound.c	Mon Sep 17 18:12:03 2001 +0000
@@ -0,0 +1,187 @@
+/*
+ * 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
+ */
+
+/**
+ * This is a quick and dirty test of SDL_sound.
+ *
+ * Please see the file LICENSE in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon. (icculus@clutteredmind.org)
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include "SDL.h"
+#include "SDL_sound.h"
+
+#define TEST_VERSION_MAJOR  0
+#define TEST_VERSION_MINOR  1
+#define TEST_VERSION_PATCH  0
+
+
+static void output_versions(void)
+{
+    Sound_Version compiled;
+    Sound_Version linked;
+    SDL_version sdl_compiled;
+    const SDL_version *sdl_linked;
+
+    SOUND_VERSION(&compiled);
+    Sound_GetLinkedVersion(&linked);
+    SDL_VERSION(&sdl_compiled);
+    sdl_linked = SDL_Linked_Version();
+
+    printf("test_sdlsound version %d.%d.%d.\n"
+           " Compiled against SDL_sound version %d.%d.%d,\n"
+           " and linked against %d.%d.%d.\n"
+           " Compiled against SDL version %d.%d.%d,\n"
+           " and linked against %d.%d.%d.\n\n",
+            TEST_VERSION_MAJOR, TEST_VERSION_MINOR, TEST_VERSION_PATCH,
+            compiled.major, compiled.minor, compiled.patch,
+            linked.major, linked.minor, linked.patch,
+            sdl_compiled.major, sdl_compiled.minor, sdl_compiled.patch,
+            sdl_linked->major, sdl_linked->minor, sdl_linked->patch);
+} /* output_versions */
+
+
+static void output_decoders(void)
+{
+    const Sound_DecoderInfo **rc = Sound_AvailableDecoders();
+    const Sound_DecoderInfo **i;
+
+    printf("Supported fileformats:\n");
+    if (*rc == NULL)
+        printf(" * Apparently, NONE!\n");
+    else
+    {
+        for (i = rc; *i != NULL; i++)
+        {
+            printf(" * %s: %s\n    Written by %s.\n    %s\n",
+                    (*i)->extension, (*i)->description,
+                    (*i)->author, (*i)->url);
+        } /* for */
+    } /* else */
+
+    printf("\n");
+} /* output_decoders */
+
+
+static volatile int done_flag = 0;
+
+void test_callback(void *userdata, Uint8 *stream, int len)
+{
+    Sound_Sample *sample = (Sound_Sample *) userdata;
+    Uint32 rc = Sound_Decode(sample);
+
+    if (sample->flags & SOUND_SAMPLEFLAG_EOF)
+    {
+        printf("EOF condition in decoding! (this is okay.)\n");
+        done_flag = 1;
+    } /* if */
+
+    else if (sample->flags & SOUND_SAMPLEFLAG_ERROR)
+    {
+        printf("Error condition in decoding! (this is bad.)\n");
+        done_flag = 1;
+    } /* else if */
+
+    assert(rc <= len);
+
+    memcpy(stream, sample->buffer, rc);
+    if (rc < len)
+        memset(stream + rc, '\0', len - rc);  /* (*shrug*) */
+} /* test_callback */
+
+
+int main(int argc, char **argv)
+{
+    Sound_AudioInfo sound_desired;
+    SDL_AudioSpec sdl_desired;
+    Sound_Sample *sample;
+
+    if (SDL_Init(SDL_INIT_AUDIO) == -1)
+    {
+        printf("SDL_Init(SDL_INIT_AUDIO) failed!\n"
+               "  reason: [%s].\n", SDL_GetError());
+        return(42);
+    } /* if */
+
+    if (!Sound_Init())
+    {
+        printf("Sound_Init() failed!\n"
+               "  reason: [%s].\n", Sound_GetError());
+        SDL_Quit();
+        return(42);
+    } /* if */
+
+    output_versions();
+    output_decoders();
+
+    if (argc != 2)
+    {
+        printf("USAGE: %s <oneSupportedFile>\n", argv[0]);
+        Sound_Quit();
+        SDL_Quit();
+        return(42);
+    } /* if */
+
+    sound_desired.rate = 44100;
+    sound_desired.channels = 2;
+    sound_desired.format = AUDIO_S16;
+
+    sample = Sound_NewSampleFromFile(argv[1], &sound_desired, 4096 * 4);
+    if (!sample)
+    {
+        printf("Sound_NewSampleFromFile(\"%s\") failed!\n"
+               "  reason: [%s].\n", argv[1], Sound_GetError());
+        Sound_Quit();
+        SDL_Quit();
+        return(42);
+    } /* if */
+
+	sdl_desired.freq = 44100;
+	sdl_desired.format = AUDIO_S16;
+	sdl_desired.channels = 2;
+	sdl_desired.samples = 4096;
+	sdl_desired.callback = test_callback;
+	sdl_desired.userdata = sample;
+
+	if ( SDL_OpenAudio(&sdl_desired, NULL) < 0 )
+    {
+        printf("SDL_OpenAudio() failed!\n"
+               "  reason: [%s].\n", SDL_GetError());
+        Sound_Quit();
+        SDL_Quit();
+        return(42);
+    } /* if */
+
+    SDL_PauseAudio(0);
+
+    while (!done_flag)
+        SDL_Delay(10);
+
+    Sound_FreeSample(sample);
+
+    Sound_Quit();
+    SDL_Quit();
+    return(0);
+} /* main */
+
+/* end of test_sdlsound.c ... */
+