diff --git a/ALUT.cabal b/ALUT.cabal
--- a/ALUT.cabal
+++ b/ALUT.cabal
@@ -1,10 +1,10 @@
 name:		ALUT
-version:	2.1.0.1
+version:	2.1.0.2
 license:	BSD3
 license-file:	LICENSE
 maintainer:	Sven Panne <sven.panne@aedion.de>
 bug-reports:	mailto:sven.panne@aedion.de
-homepage:	http://www.openal.org/
+homepage:	http://connect.creativelabs.com/openal/
 category:	Sound
 synopsis:	A binding for the OpenAL Utility Toolkit
 description:
@@ -12,12 +12,17 @@
 	managing of OpenAL contexts, loading sounds in various formats
 	and creating waveforms very easy. For more information about the
 	C library on which this binding is based, please see:
-	<http://www.openal.org/openal_webstf/specs/alut.html>.
+	<http://connect.creativelabs.com/openal/Documentation/The%20OpenAL%20Utility%20Toolkit.pdf>.
 build-type:     Configure
 extra-source-files:
-	config.guess config.sub install-sh
-	configure.ac configure ALUT.buildinfo.in
-	include/HsALUTConfig.h.in include/HsALUT.h.in
+	ALUT.buildinfo.in README aclocal.m4 config.guess config.sub configure
+	configure.ac examples/Basic/HelloWorld.hs examples/Basic/OpenALInfo.hs
+	examples/Basic/PlayFile.hs examples/TestSuite/TestErrorStuff.hs
+	examples/TestSuite/TestFileLoader.hs
+	examples/TestSuite/TestMemoryLoader.hs examples/TestSuite/TestVersion.hs
+	examples/TestSuite/TestWaveforms.hs examples/TestSuite/file1.wav
+	examples/TestSuite/file2.au examples/TestSuite/file3.raw
+	include/HsALUT.h.in include/HsALUTConfig.h.in install-sh
 extra-tmp-files:
 	config.log config.status autom4te.cache
 	ALUT.buildinfo include/HsALUTConfig.h include/HsALUT.h
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,4 @@
+To build this package using Cabal directly from darcs, you must run
+"autoreconf" before the usual Cabal build steps (configure/build/install).
+autoreconf is included in the GNU autoconf tools.  There is no need to run
+the "configure" script: the "setup configure" step will do this for you.
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,190 @@
+# FP_COMPUTE_INT(EXPRESSION, VARIABLE, INCLUDES, IF-FAILS)
+# ---------------------------------------------------------
+# Assign VARIABLE the value of the compile-time EXPRESSION using INCLUDES for
+# compilation. Execute IF-FAILS when unable to determine the value. Works for
+# cross-compilation, too.
+#
+# Implementation note: We are lazy and use an internal autoconf macro, but it
+# is supported in autoconf versions 2.50 up to the actual 2.57, so there is
+# little risk.
+AC_DEFUN([FP_COMPUTE_INT],
+[_AC_COMPUTE_INT([$1], [$2], [$3], [$4])[]dnl
+])# FP_COMPUTE_INT
+
+
+# FP_CHECK_CONST(EXPRESSION, [INCLUDES = DEFAULT-INCLUDES], [VALUE-IF-FAIL = -1])
+# -------------------------------------------------------------------------------
+# Defines CONST_EXPRESSION to the value of the compile-time EXPRESSION, using
+# INCLUDES. If the value cannot be determined, use VALUE-IF-FAIL.
+AC_DEFUN([FP_CHECK_CONST],
+[AS_VAR_PUSHDEF([fp_Cache], [fp_cv_const_$1])[]dnl
+AC_CACHE_CHECK([value of $1], fp_Cache,
+[FP_COMPUTE_INT([$1], fp_check_const_result, [AC_INCLUDES_DEFAULT([$2])],
+                [fp_check_const_result=m4_default([$3], ['-1'])])
+AS_VAR_SET(fp_Cache, [$fp_check_const_result])])[]dnl
+AC_DEFINE_UNQUOTED(AS_TR_CPP([CONST_$1]), AS_VAR_GET(fp_Cache), [The value of $1.])[]dnl
+AS_VAR_POPDEF([fp_Cache])[]dnl
+])# FP_CHECK_CONST
+
+
+# FP_CHECK_CONSTS_TEMPLATE(EXPRESSION...)
+# ---------------------------------------
+# autoheader helper for FP_CHECK_CONSTS
+m4_define([FP_CHECK_CONSTS_TEMPLATE],
+[AC_FOREACH([fp_Const], [$1],
+  [AH_TEMPLATE(AS_TR_CPP(CONST_[]fp_Const),
+               [The value of ]fp_Const[.])])[]dnl
+])# FP_CHECK_CONSTS_TEMPLATE
+
+
+# FP_CHECK_CONSTS(EXPRESSION..., [INCLUDES = DEFAULT-INCLUDES], [VALUE-IF-FAIL = -1])
+# -----------------------------------------------------------------------------------
+# List version of FP_CHECK_CONST
+AC_DEFUN([FP_CHECK_CONSTS],
+[FP_CHECK_CONSTS_TEMPLATE([$1])dnl
+for fp_const_name in $1
+do
+FP_CHECK_CONST([$fp_const_name], [$2], [$3])
+done
+])# FP_CHECK_CONSTS
+
+# FP_ARG_OPENAL
+# -------------
+AC_DEFUN([FP_ARG_OPENAL],
+[AC_ARG_ENABLE([openal],
+  [AC_HELP_STRING([--enable-openal],
+    [build a Haskell binding for OpenAL (default=autodetect)])],
+  [enable_openal=$enableval],
+  [enable_openal=yes])
+])# FP_ARG_OPENAL
+
+
+# FP_ARG_ALUT
+# -------------
+AC_DEFUN([FP_ARG_ALUT],
+[AC_ARG_ENABLE([alut],
+  [AC_HELP_STRING([--enable-alut],
+    [build a Haskell binding for ALUT (default=autodetect)])],
+  [enable_alut=$enableval],
+  [enable_alut=yes])
+])# FP_ARG_ALUT
+
+
+# FP_CHECK_ALUT
+# -------------
+AC_DEFUN([FP_CHECK_ALUT],
+[AC_REQUIRE([AC_CANONICAL_TARGET])
+ALUT_CFLAGS=
+case $target_os in
+darwin*)
+  ALUT_LIBS=
+  ALUT_FRAMEWORKS=ALUT
+  ;;
+*)
+  AL_LIBS=no
+  AC_SEARCH_LIBS([alGenSources], [openal openal32], [AL_LIBS="$ac_cv_search_alGenSources"])
+  test x"$AL_LIBS" = x"none required" && AL_LIBS=
+
+  fp_save_libs="$LIBS"
+  LIBS="$AL_LIBS $LIBS"
+  AC_SEARCH_LIBS([alutExit], [alut alut32], [ALUT_LIBS="$ac_cv_search_alutExit"])
+  test x"$ALUT_LIBS" = x"none required" && ALUT_LIBS=
+  LIBS="$fp_save_libs"
+  ALUT_FRAMEWORKS=
+  ;;
+esac
+AC_SUBST([ALUT_CFLAGS])
+AC_SUBST([ALUT_LIBS])
+AC_SUBST([ALUT_FRAMEWORKS])
+])# FP_CHECK_ALUT
+
+
+# FP_HEADER_ALUT
+# --------------
+# Check for an ALUT header, setting the variable fp_found_alut_header to no/yes,
+# depending on the outcome.
+AC_DEFUN([FP_HEADER_ALUT],
+[if test -z "$fp_found_alut_header"; then
+  fp_found_alut_header=no
+  AC_CHECK_HEADERS([AL/alut.h OpenAL/alut.h], [fp_found_alut_header=yes; break])
+fi
+]) # FP_HEADER_AL
+
+
+# FP_CHECK_FUNC_ALUT(FUNCTION, ARGUMENTS)
+# ---------------------------------------
+AC_DEFUN([FP_CHECK_FUNC_ALUT],
+[AS_VAR_PUSHDEF([alut_var], [alut_cv_func_$1])dnl
+AC_CACHE_CHECK([for $1],
+  alut_var,
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#if HAVE_AL_ALUT_H
+#include <AL/alut.h>
+#elif HAVE_OPENAL_ALUT_H
+#include <OpenAL/alut.h>
+#endif]],
+                    [$1 $2;])],
+                  [AS_VAR_SET(alut_var, yes)],
+                  [AS_VAR_SET(alut_var, no)])])
+if test AS_VAR_GET(alut_var) = yes; then
+  AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1]), [1],
+                    [Define to 1 if you have the `$1' function.])
+fi
+AS_VAR_POPDEF([alut_var])dnl
+])# FP_CHECK_FUNC_ALUT
+
+
+# FP_FUNC_ALUTINIT_VOID
+# ---------------------
+# Defines ALUTINIT_VOID to 1 if `alutInit' returns void.
+AC_DEFUN([FP_FUNC_ALUTINIT_VOID],
+[AC_REQUIRE([FP_HEADER_ALUT])
+AC_CACHE_CHECK([whether alutInit returns void],
+  [fp_cv_func_alutInit_void],
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
+#if HAVE_AL_ALUT_H
+#include <AL/alut.h>
+#elif HAVE_OPENAL_ALUT_H
+#include <OpenAL/alut.h>
+#endif
+],
+ [[int x = (int)alutInit((int *)0, (char **)0);]])],
+ [fp_cv_func_alutInit_void=no],
+ [fp_cv_func_alutInit_void=yes])])
+if test x"$fp_cv_func_alutInit_void" = xyes; then
+  AC_DEFINE([ALUTINIT_VOID], [1], [Define to 1 if `alutInit' returns void.])
+fi
+]) # FP_FUNC_ALUTINIT_VOID
+
+
+# FP_FUNC_ALUTEXIT_VOID
+# ---------------------
+# Defines ALUTEXIT_VOID to 1 if `alutExit' returns void.
+AC_DEFUN([FP_FUNC_ALUTEXIT_VOID],
+[AC_REQUIRE([FP_HEADER_ALUT])
+AC_CACHE_CHECK([whether alutExit returns void],
+  [fp_cv_func_alutExit_void],
+  [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
+#if HAVE_AL_ALUT_H
+#include <AL/alut.h>
+#elif HAVE_OPENAL_ALUT_H
+#include <OpenAL/alut.h>
+#endif
+],
+ [[int x = (int)alutExit();]])],
+ [fp_cv_func_alutExit_void=no],
+ [fp_cv_func_alutExit_void=yes])])
+if test x"$fp_cv_func_alutExit_void" = xyes; then
+  AC_DEFINE([ALUTEXIT_VOID], [1], [Define to 1 if `alutExit' returns void.])
+fi
+]) # FP_FUNC_ALUTEXIT_VOID
+
+
+# FP_ARG_COMPILER
+# -------------
+AC_DEFUN([FP_ARG_COMPILER],
+[AC_ARG_WITH([compiler],
+  [AC_HELP_STRING([--with-compiler@<:@=HC@:>@],
+    [use the given Haskell compiler (default=ghc)])],
+  [with_compiler=$withval],
+  [with_compiler=ghc])
+])# FP_ARG_COMPILER
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for Haskell ALUT package 2.1.0.1.
+# Generated by GNU Autoconf 2.63 for Haskell ALUT package 2.1.0.2.
 #
 # Report bugs to <sven.panne@aedion.de>.
 #
@@ -596,8 +596,8 @@
 # Identity of this package.
 PACKAGE_NAME='Haskell ALUT package'
 PACKAGE_TARNAME='ALUT'
-PACKAGE_VERSION='2.1.0.1'
-PACKAGE_STRING='Haskell ALUT package 2.1.0.1'
+PACKAGE_VERSION='2.1.0.2'
+PACKAGE_STRING='Haskell ALUT package 2.1.0.2'
 PACKAGE_BUGREPORT='sven.panne@aedion.de'
 
 ac_unique_file="include/HsALUT.h.in"
@@ -1270,7 +1270,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures Haskell ALUT package 2.1.0.1 to adapt to many kinds of systems.
+\`configure' configures Haskell ALUT package 2.1.0.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1336,7 +1336,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Haskell ALUT package 2.1.0.1:";;
+     short | recursive ) echo "Configuration of Haskell ALUT package 2.1.0.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1428,7 +1428,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Haskell ALUT package configure 2.1.0.1
+Haskell ALUT package configure 2.1.0.2
 generated by GNU Autoconf 2.63
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1442,7 +1442,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Haskell ALUT package $as_me 2.1.0.1, which was
+It was created by Haskell ALUT package $as_me 2.1.0.2, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   $ $0 $@
@@ -6142,7 +6142,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Haskell ALUT package $as_me 2.1.0.1, which was
+This file was extended by Haskell ALUT package $as_me 2.1.0.2, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6201,7 +6201,7 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-Haskell ALUT package config.status 2.1.0.1
+Haskell ALUT package config.status 2.1.0.2
 configured by $0, generated by GNU Autoconf 2.63,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([Haskell ALUT package], [2.1.0.1], [sven.panne@aedion.de], [ALUT])
+AC_INIT([Haskell ALUT package], [2.1.0.2], [sven.panne@aedion.de], [ALUT])
 
 # Safety check: Ensure that we are in the correct source directory.
 AC_CONFIG_SRCDIR([include/HsALUT.h.in])
diff --git a/examples/Basic/HelloWorld.hs b/examples/Basic/HelloWorld.hs
new file mode 100644
--- /dev/null
+++ b/examples/Basic/HelloWorld.hs
@@ -0,0 +1,20 @@
+{-
+   HelloWorld.hs (adapted from hello_world.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Sound.ALUT
+
+-- This is the Haskell version of the 'Hello World' program from the ALUT
+-- reference manual.
+
+main :: IO ()
+main =
+   withProgNameAndArgs runALUT $ \_progName _args -> do
+      helloBuffer <- createBuffer HelloWorld
+      [helloSource] <- genObjectNames 1
+      buffer helloSource $= Just helloBuffer
+      play [helloSource]
+      sleep 1
diff --git a/examples/Basic/OpenALInfo.hs b/examples/Basic/OpenALInfo.hs
new file mode 100644
--- /dev/null
+++ b/examples/Basic/OpenALInfo.hs
@@ -0,0 +1,34 @@
+{-
+   OpenALInfo.hs (modeled after OpenGL's glxinfo)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Text.PrettyPrint
+import Sound.ALUT
+
+-- This program prints some basic information about ALC and AL.
+
+printVar :: (a -> Doc) -> GettableStateVar a -> IO ()
+printVar format var = get var >>= putStrLn . render . format
+
+printStringVar :: String -> GettableStateVar String -> IO ()
+printStringVar header = printVar (\v -> text header <> colon <+> text v)
+
+printStringListVar :: String -> GettableStateVar [String] -> IO ()
+printStringListVar header =
+   printVar (\xs -> text header <> colon $$
+                    nest 4 (fsep (punctuate comma (map text xs))))
+
+main :: IO ()
+main =
+   withProgNameAndArgs runALUT $ \_progName _args -> do
+      Just ctx <- get currentContext
+      Just dev <- get (contextsDevice ctx)
+      printStringVar "ALC version" alcVersion
+      printStringListVar "ALC extensions" (alcExtensions dev)
+      printStringVar "AL version" alVersion
+      printStringVar "AL renderer" alRenderer
+      printStringVar "AL vendor" alVendor
+      printStringListVar "AL extensions" alExtensions
diff --git a/examples/Basic/PlayFile.hs b/examples/Basic/PlayFile.hs
new file mode 100644
--- /dev/null
+++ b/examples/Basic/PlayFile.hs
@@ -0,0 +1,51 @@
+{-
+   PlayFile.hs (adapted from playfile.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Control.Monad ( when, unless )
+import Data.List ( intersperse )
+import Sound.ALUT
+import System.Exit ( exitFailure )
+import System.IO ( hPutStrLn, stderr )
+
+-- This program loads and plays a variety of files.
+
+playFile :: FilePath -> IO ()
+playFile fileName = do
+   -- Create an AL buffer from the given sound file.
+   buf <- createBuffer (File fileName)
+
+   -- Generate a single source, attach the buffer to it and start playing.
+   [source] <- genObjectNames 1
+   buffer source $= Just buf
+   play [source]
+
+   -- Normally nothing should go wrong above, but one never knows...
+   errs <- get alErrors
+   unless (null errs) $ do
+      hPutStrLn stderr (concat (intersperse "," [ d | ALError _ d <- errs ]))
+      exitFailure
+
+   -- Check every 0.1 seconds if the sound is still playing.
+   let waitWhilePlaying = do
+          sleep 0.1
+          state <- get (sourceState source)
+          when (state == Playing) $
+             waitWhilePlaying
+   waitWhilePlaying
+
+main :: IO ()
+main = do
+   -- Initialise ALUT and eat any ALUT-specific commandline flags.
+   withProgNameAndArgs runALUT $ \progName args -> do
+
+      -- Check for correct usage.
+      unless (length args == 1) $ do
+         hPutStrLn stderr ("usage: " ++ progName ++ " <fileName>")
+         exitFailure
+
+      -- If everything is OK, play the sound file and exit when finished.
+      playFile (head args)
diff --git a/examples/TestSuite/TestErrorStuff.hs b/examples/TestSuite/TestErrorStuff.hs
new file mode 100644
--- /dev/null
+++ b/examples/TestSuite/TestErrorStuff.hs
@@ -0,0 +1,20 @@
+{-
+   TestErrorStuff.hs (adapted from test_errorstuff.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Sound.ALUT
+import System.Exit ( exitFailure, exitWith, ExitCode(ExitSuccess) )
+import System.IO ( hPutStrLn, stderr )
+
+-- This is a minimal test for error handling.
+
+main :: IO ()
+main = do
+   withProgNameAndArgs runALUT $ \_progName _args ->
+     createBuffer (File "no_such_file_in_existance.wav")
+       `catch` const (exitWith ExitSuccess)
+   hPutStrLn stderr "expected an I/O error"
+   exitFailure
diff --git a/examples/TestSuite/TestFileLoader.hs b/examples/TestSuite/TestFileLoader.hs
new file mode 100644
--- /dev/null
+++ b/examples/TestSuite/TestFileLoader.hs
@@ -0,0 +1,47 @@
+{-
+   TestFileLoader.hs (adapted from test_fileloader.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Control.Monad ( when, unless )
+import Data.List ( intersperse )
+import Sound.ALUT
+import System.Exit ( exitFailure )
+import System.IO ( hPutStrLn, stderr )
+
+-- This program loads and plays a variety of files, basically an automated
+-- version of Basic/PlayFile.hs.
+
+playFile :: FilePath -> IO ()
+playFile fileName = do
+   -- Create an AL buffer from the given sound file.
+   buf <- createBuffer (File fileName)
+
+   -- Generate a single source, attach the buffer to it and start playing.
+   [source] <- genObjectNames 1
+   buffer source $= Just buf
+   play [source]
+
+   -- Normally nothing should go wrong above, but one never knows...
+   errs <- get alErrors
+   unless (null errs) $ do
+      hPutStrLn stderr (concat (intersperse "," [ d | ALError _ d <- errs ]))
+      exitFailure
+
+   -- Check every 0.1 seconds if the sound is still playing.
+   let waitWhilePlaying = do
+          sleep 0.1
+          state <- get (sourceState source)
+          when (state == Playing) $
+             waitWhilePlaying
+   waitWhilePlaying
+
+main :: IO ()
+main =
+   -- Initialise ALUT and eat any ALUT-specific commandline flags.
+   withProgNameAndArgs runALUT $ \_progName _args -> do
+
+     -- If everything is OK, play the sound files and exit when finished.
+     mapM_ playFile [ "file1.wav", "file2.au", "file3.raw" ]
diff --git a/examples/TestSuite/TestMemoryLoader.hs b/examples/TestSuite/TestMemoryLoader.hs
new file mode 100644
--- /dev/null
+++ b/examples/TestSuite/TestMemoryLoader.hs
@@ -0,0 +1,63 @@
+{-
+   TestMemoryLoader.hs (adapted from test_memoryloader.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Control.Exception ( bracket )
+import Control.Monad ( when, unless )
+import Data.List ( intersperse )
+import Foreign.Marshal.Alloc ( allocaBytes )
+import Sound.ALUT
+import System.Exit ( exitFailure )
+import System.IO (
+   openBinaryFile, IOMode(ReadMode), hClose, hFileSize, hGetBuf, hPutStrLn,
+   stderr )
+
+-- This program loads and plays a variety of files from memory, basically a
+-- modified version of TestFileLoader.hs.
+
+withFileContents :: FilePath -> (MemoryRegion a -> IO b) -> IO b
+withFileContents filePath action =
+   bracket (openBinaryFile filePath ReadMode) hClose $ \handle -> do
+      numBytes <- fmap fromIntegral (hFileSize handle)
+      allocaBytes numBytes $ \buf -> do
+         bytesRead <- hGetBuf handle buf numBytes
+         when (bytesRead /= numBytes) $
+            ioError (userError "hGetBuf")
+         action (MemoryRegion buf (fromIntegral numBytes))
+
+playFile :: FilePath -> IO ()
+playFile fileName = do
+   -- Load the sound file into memory and create an AL buffer from it.
+   buf <- withFileContents fileName (createBuffer . FileImage)
+
+   -- Generate a single source, attach the buffer to it and start playing.
+   [source] <- genObjectNames 1
+   buffer source $= Just buf
+   play [source]
+
+   -- Normally nothing should go wrong above, but one never knows...
+   errs <- get alErrors
+   unless (null errs) $ do
+      hPutStrLn stderr (concat (intersperse "," [ d | ALError _ d <- errs ]))
+      exitFailure
+
+   -- Check every 0.1 seconds if the sound is still playing.
+   let waitWhilePlaying = do
+          sleep 0.1
+          state <- get (sourceState source)
+          when (state == Playing) $
+             waitWhilePlaying
+   waitWhilePlaying
+
+main :: IO ()
+main =
+   -- Initialise ALUT and eat any ALUT-specific commandline flags.
+   withProgNameAndArgs runALUT $ \_progName _args -> do
+
+     -- If everything is OK, play the sound files and exit when finished. Note
+     -- that we can not play raw sound files from memory because the format
+     -- can't be guessed without a file name.
+     mapM_ playFile [ "file1.wav", "file2.au" ]
diff --git a/examples/TestSuite/TestVersion.hs b/examples/TestSuite/TestVersion.hs
new file mode 100644
--- /dev/null
+++ b/examples/TestSuite/TestVersion.hs
@@ -0,0 +1,23 @@
+{-
+   TestVersion.hs (adapted from test_version.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Control.Monad ( unless )
+import Sound.ALUT
+import System.Exit ( exitFailure )
+import System.IO ( hPutStrLn, stderr )
+
+-- This program checks that the version of OpenAL in the library agrees with the
+-- header file we're compiled against.
+
+main :: IO ()
+main =
+   withProgNameAndArgs runALUT $ \_progName _args -> do
+      av <- get alutVersion
+      unless (av == alutAPIVersion) $ do
+         hPutStrLn stderr ("WARNING: The ALUT library is version " ++ av ++ ".x but the ALUT binding says it's " ++ alutAPIVersion ++ ".x!")
+         exitFailure
+      hPutStrLn stderr ("The ALUT library is at version " ++ av ++ ".x")
diff --git a/examples/TestSuite/TestWaveforms.hs b/examples/TestSuite/TestWaveforms.hs
new file mode 100644
--- /dev/null
+++ b/examples/TestSuite/TestWaveforms.hs
@@ -0,0 +1,23 @@
+{-
+   TestWaveforms.hs (adapted from test_waveforms.c in freealut)
+   Copyright (c) Sven Panne 2005 <sven.panne@aedion.de>
+   This file is part of the ALUT package & distributed under a BSD-style license
+   See the file libraries/ALUT/LICENSE
+-}
+
+import Sound.ALUT
+
+-- This program plays a 440Hz tone using a variety of waveforms.
+
+playTone :: (Frequency -> Phase -> Duration -> SoundDataSource a) -> IO ()
+playTone soundDataSource = do
+   buf <- createBuffer (soundDataSource 440 0 1)
+   [source] <- genObjectNames 1
+   buffer source $= Just buf
+   play [source]
+   sleep 1
+
+main :: IO ()
+main =
+   withProgNameAndArgs runALUT $ \_progName _args ->
+      mapM_ playTone [ Sine, Square, Sawtooth, (const (const WhiteNoise)), Impulse ]
diff --git a/examples/TestSuite/file1.wav b/examples/TestSuite/file1.wav
new file mode 100644
Binary files /dev/null and b/examples/TestSuite/file1.wav differ
diff --git a/examples/TestSuite/file2.au b/examples/TestSuite/file2.au
new file mode 100644
Binary files /dev/null and b/examples/TestSuite/file2.au differ
diff --git a/examples/TestSuite/file3.raw b/examples/TestSuite/file3.raw
new file mode 100644
--- /dev/null
+++ b/examples/TestSuite/file3.raw
@@ -0,0 +1,1 @@
+~~~~~~~}~~||}y|~||}z{zysn{xip{wmwxhwz|}ik~{px|~otw}{|vjnwu}{|powx{wlxt}|||ymt||}~xtn{w~ywjxt}|}qpuw}jx}}snnr}~}|w}x~{}rwz}~so~pu{y|}yrr~ptxryy|}|}t{xw|~}q~v~jzp}r}|ymx}prturymvmt{o||y{|xtuxy|tvrxmup}{r}{{ty{r{y|w os~xu{zzq}~vr~k}vv}p}xuwxvuz}uvzmwy{s}w|v|~ywskqxtpyt{w|}nvsv~utzz}nxpzzs|xtz|x{zszmypzzpzozxuuszx~{yq{ppr}sw{lsnyy{~rv||~yuqunzzzqvuy~t}wq~vq~xy{v}~u~tw|t{zzztztwvz|v~yrzt}yqzyy~rxos~}q~vx}px~}rzxv{twpt}wu{vt}t~v{vx~xt{swtp|r~vy~t~{|wx~ovxvv{zn~yt}vtwuryt|x~sz}|tvrpv{wpxztwtwow~}|ws|x|wrxppw}yt{xyx}{~{y}symxz|vwrvx}w|uryzvxz}ws~rwx|uwvyvyy~}z{zwxvvy|u}{p}~}uur~r|v|pvzpu|yw|r|zzxwzuz{x|nxqv{pzzypuyssptmyzyxouzw{pvvr|tzsrwv}xxz{w~{|sy~{|z}|y|s|wwzx{}v}w~uuxpwr}z}wt|{z~|v{zyx|xps~u}ss{{xsv|~r~}{{{|x}tu~||~~zxt|~y|}y|py~r~wx~z{zw|x|vxz{{zxt~vuxsrtyx{tywx}t|yvw}|}yvyvy}wqq~~uu}sxtxzy~rs}v}zv}wv{x}sr{~}~w}}s|{vv{pt{u|}uvu~zrzwyqzz|tz~zpt{yzxypwtx~y{{{v~{v}z}vzx~wxzuu~zxvt~~v}xs{{tx~v}yrsy}|u|stwvp~~|}}{vn{}r~|{wtxz{~w~zv~y}v}{u}||xy{st~xt{}t}vx~tw~{wvqz|v|vvy{{z|w{r}v~zw|xw||z}ywoy}tyxr|yrw}pv}uyxuvp{ytr~qp|w|~}|~z}}w~~yv|~pwutzw|u{~w}r|yw~~~|yy|}|||v|{vz|z|~}}|yt}sy~uv|~zv|xvzr}~so~|~wux}to{qz~u~zx|~|~}~w}}}w|{x{~vxqt}w}rvqxypyxrr~x{~|y~yu}yyxy{x|}|uttsrs||vuyzx~}wyxuyxytxsy}w}xo~}rowstxuwvtt}uz{x~}~zz}{x{}ywz}xyq~t|{uv{s|y}}uy~wtsy{||~z|}}twwwn~zt{yv||}x~z||~|t|xx}w{wy||}|}|~qszx{|yywsx{z}xvyyn}}vz}z}zu{{}{{yvutwv}||y}{|t~}~s|~x{zvy~}|xuxt~t{~~{|~yzzz~|sxz{|zyyu~zyz|||tv}uxxz{}x}uszqz~tz{z|~xuzvtvsyxyzw}vvsu{zysu{{uz{}pqstt|xstz}~{wzywxz|ss{vz||xw|vwx|}~~|x}t}|xst{{wwx|~xxt||x|w~sz~y{yqxzzy{x|t|zx~u~||sz~||}z{uy}z}v~uy|z||xxw}wt}py|u}x}{{~~~y{|z~p{{v}}u{r|wwx|xr|z{w}}~|}~}{~~yy{|zzu{~u}zxyy|zt}{}xx{|}xuyuz~~wv~~zv~{sr{}t|uyvz|sqt}zy~v{yx|}xqq~|x~}{v}y~xvyvyw}yz{{}~x~xz}~xyt}|{yxy~}~}~wzz~xxuxzyyxw~y{{yu}}|}qyusqyp}v~vt}|}yww~~{ysw~}|~y{z|{~yq|}y|z{|s|xvpv|tyvx}{}|~|yywrtt}zz|zzy~|{xx{{s|y|}~xyps~}|w|yy{vqr{w}wx|~{}~~t|yx}stx~~z{{~~s~vuy{t|~|||}{~x{}t~uvswwxzu~turx~|{wzw{{~yxwp{zrst~tyvz|}wwu|tru|}vvz||{|t}zu}|t}|xx~~u~~ux{~z|yprs|~y|~|vz~v}y}u~vy{|z}{y}zz~|~y{s|xu}{{{}xx~|z}|zs{z|sxy}{rzztz|{~|}v{}|szxz~zywz~zz|w{zwuz|u{y~~~zyyx{~|yx|{xy}zz}|~{}}|ysxyu{|yv|wy|||zy|x}{vy~wv~}zwvw|u~zztpy~wt}yvyxu|{x}xwvwwqtuyyxy{|||}~}z{w}wz}xt}~~ttxvx}~vy{{z}x~x{}|yxtv}ryyzz{}tv~|vuqs|x{}zyz|yts||{purx{}{|z{|yx}xx{zyx~x}|z{sv}~q}|t{s~rwq}|w}ty}y|~{z}}zwxz~z{{xx|~yzs{u}zvu~xuu{sq}yt~zxy{~|w~~tx{w|{~|ts|}}|xxuxz|vrx|}x{w}~~uyzy~v{tsxyy}y~|}{mxuzsztu{~u|{~~|}wy}|xpzu|u{{}~}{~uw}wszryvu~zy{w~yy{z{z|zy|tzy{s|||x}~|xys|{vvyyw~|}y}}}}x}y}w~uz{wx{}~~{~~~{|}{v~{u|vzw{|}{~}t{|wxxu{xxzw|}z|~{~{yz{|ww{xr~xvty|~z~xw}zxwv|q|zy{~z}}y|p}~||uvvyy{}zy~wxy|v~~~su|tvu|yzuwx~u~zu{{w}~{zz}vt|x}t}xzx|v|u{}|v~{qtuyxy{|wswywty~~|zyz~z{xxyy{|x~~~{yuu|{}|{z}~vyz}wu~wtx}zt|}{~|~}v{{uzuz|xy~w|yxtw|}v|s|xy{z~~~}vzs|{}{vuw{|z{|~{~{~z|vw~|{wyxx}y{~||v~|}syxu{u{xxyw|x~zw{v}xv{~wxw{yy{}~}|vuvz|}xy}yz~~zwp}z}txty}wzv}|tz}~{w~ws}|zxz|~~|uz{~{|vz}vz{|y|{}yyt{~zvvv~}xz}}x||{z|{vz~u{ww||{}x|qz{~|wuvyyvrzy~yx|~y~r}yq|vx|}y{x~~yz~xywxsyy~vv{|x}{z~~yyr}}uy|xu~v{x|z~~}~~}~vy~z}~vyv{~{y|}}|{}z~||wr~vz|uz{x{|~xxww|t|vx~{u~ux~{~~y}ww||s~zwt{}}v|y|~~~yvuy~v}xxxy~xw~y~s}~}|zwzz~}~x{z}z~zw|x~{~v~~~wv{u~turt~v~zz}}|}xt{~{{vw}x}|x}vvz{uytzyy~vu~vz}u|{||~}v~~}}~vzw|z|xuwv{w{}z~trxv~~ww{{ww|}ys|~zuyvt|}zzzz|tzz|yyyuqy|~xzyyp|}x{||y|uzzx}ts{|~yu|y{u}}}~wz|~uy|{{}~z|~~}~~|vy{~}}||~|~}~x}~~t~}x{{|}}zs~|z|}|z|us||z~~~~~}}~}xw~~{|yx}}}~~~~|yv~|}|}|{}~}|}||{}zz}~|x~}}z|z~~}|{}|}~}~}yz~{~~~}}|{}z|}|}~}~{~x|~}~~|y|~~~}~}}{~|}}}}}~~~|{}}~}|}}~||~}|~|{}}~~}~~|{~}~~||}~~||~}~}~~|{}~|}~||~}}~}}|~|~~}~~~~~~}}}|~~}~~}|~~~}}~~}~}~~}||~}~~~}||~~|~}}{~|}}~}~||{~~~}}z~~|~}~{{~}~~}~~~
