Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
1019 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/util/sdl/sound/CHANGELOG b/util/sdl/sound/CHANGELOG
new file mode 100644
index 00000000..1db243b8
--- /dev/null
+++ b/util/sdl/sound/CHANGELOG
@@ -0,0 +1,376 @@
+/*
+ * CHANGELOG.
+ */
+
+04202008 - Upped version to 1.0.3 (brown paper bag release for soname bug).
+04192008 - Apparently MICRO_VERSION in configure.in doesn't do what I think;
+ reset for binary compatibility (thanks, Hans!).
+04182008 - Include <math.h> in shn.c.
+04172008 - Look for Speex includes in new directory. Converted all text
+ encoding from ISO-8859-1 to UTF-8. Fixed "make dist" script for
+ dealing with Subversion instead of CVS. Added Speex to the README.
+ Upped version to 1.0.2.
+04112008 - Check if Speex header has bogus data (CVE-2008-1686).
+08062007 - Updated my email address.
+07152007 - Minor correction in Timidity resampling code (Thanks, Sam!).
+07062007 - Fixed uninitialized buffer in mpglib. (Thanks, Phil!).
+10292006 - Fixed bogus memory dereference when SMPEG fails init (thanks, Chris!)
+10272006 - FLAC 1.1.3 breaks their API _again_, so we try to do the right
+ thing at build time. (Thanks, Josh!).
+05122006 - Patched to get mpglib compiling again (thanks, Sam!).
+12172005 - Fixed gcc4 whining in playsound_simple.c.
+12062005 - Trimmed a bunch of junk out of the build system, and now it works
+ on Mac OS X again.
+10122005 - Check for libmodplug headers in two possible places (thanks, Tyler!)
+10012005 - Added playsound_simple.c.
+05302005 - Backport from devtree: Fixed automake nonsense.
+11122004 - Backport from devtree: fix .voc decoder crash on file open.
+05082004 - Fixed "bootstrap" to work with MacOSX.
+05072004 - Backed out some commits, converted repository to Subversion, and
+ branched off to a 1.1.0 development tree. Changed MikMod URL...old
+ one is now a porn site. :(
+10252003 - VOC decoder was broken. Now it isn't.
+10142003 - Build system fix: acinclude.m4 had some word wrapping badness.
+10122003 - Fixed "make dist" behaviour to not packaged generated docs, and
+ made sure other files are always packaged, regardless of config.
+ Upped version to 1.0.1.
+10102003 - Changed some SDL_Error()s to __Sound_SetError() in new DLS code
+ to fix linking issues.
+10052003 - Fixed memory corruption when freeing DLS instruments,
+ and bug when timidity is initialized multiple times (Thanks, Sam!).
+09252003 - Sam Lantinga added support for DLS instruments to the MIDI decoder.
+09132003 - Happy September. Added Speex (.spx) decoder.
+08052003 - Fixed MIDI decoder on bigendian systems.
+03102003 - Never actually created samplelist_mutex (Thanks, Glenn Maynard!).
+01302003 - Patches to make SDL_sound more Visual C happy (Thanks, Eric!).
+01122003 - Fix to smpeg.c's rewinding code (Thanks, Eric). Put Visual C 6
+ project files in CVS, without external binaries (Thanks, Eric).
+12212002 - Fixed ogg.c to decode a full buffer at a time instead of one ogg
+ packet per call, and mikmod has a check during initialization to
+ prevent a clash with SDL_mixer (Thanks, Eric).
+12092002 - Changed Sound_Init()'s call to SDL_Init() to SDL_InitSubSystem(),
+ to prevent unwanted use of the SDL parachute (thanks, Glenn).
+10092002 - Fixed a "make dist" issue and upped version to 1.0.0! Woohoo!
+09302002 - libFLAC broke their API (again!) for version 1.0.4. That was the
+ last straw. I ripped the version detection and obsolete FLAC
+ support out, so you need libFLAC 1.0.4 for that decoder now (and
+ they'll probably break the API again for 1.0.5. Argh).
+09262002 - Happy September. Fixed SDLCALL issues in SDL_sound.h, so it should
+ work with Win32/WinCE builds again. I hope. Merged latest altcvt
+ from Frank into CVS.
+08222002 - Borland project files in CVS, thanks to Dominique Louis. There are
+ project files for C++ Builder 6 (Windows), C++ Builder for Linux
+ (aka Kylix 3) and Borland's C++ Command line compiler.
+08172002 - Timidity memory leak cleanup by Torbjörn.
+07292002 - Valgrind cleanups; memory leak patches, etc.
+07212002 - done_flag was not being reset between files in playsound, so the
+ first file would playback, and then any following tracks in a given
+ run would "finish" immediately. Fixed.
+07132002 - More altcvt fixes from Frank Ranostaj.
+07122002 - Changed inline keyword to compile universally.
+07102002 - Fixed a bug in command line handling in playsound.c. Fixes from
+ Torbjörn and myself to get flac.c friendly between versions of
+ libFLAC. Mutex'd a potential race condition in decoders/modplug.c.
+ FIXME cleanups here and there.
+07092002 - Fixed typo in documentation (SDL_sound.h).
+07052002 - Cleaned up some stuff in playsound.c, removing some FIXMEs.
+ Commandline validation is improved, too. FIXME removal in
+ voc.c; should report i/o errors correctly now. Changed DECLSPEC
+ to SNDDECLSPEC to prevent SDL conflict, and added SDLCALL support.
+ Removed all instances of Sound_SetError()...now they are either
+ __Sound_SetError or BAIL*_MACRO.
+07022002 - Added WinCE support pack to website, updated INSTALL with CE info.
+ More altcvt fixes from Frank Ranostaj.
+07012002 - Fixed configure.in to work around bug in older autoconfs. Started
+ merging Tyler's WinCE (PocketPC) port. Added checks for assert.h
+ and signal.h to configure.in/config.h.in, and #if HAVE_*_H checks
+ where appropriate in the code. Moved #include <assert.h> (along
+ with the HAVE_ASSERT_H check) to SDL_sound_internal.h, and removed
+ unnecessary #includes from the individual source files. Added
+ "md_reverb = 1;" to MIKMOD_init(). Modplug got some WinCE-specific
+ setting tweaks, and some settings maintanance code. configure.in
+ checks if setbuf() is available.
+06292002 - More altcvt fixes from Frank Ranostaj...mostly working now?
+06252002 - More altcvt fixes from Frank Ranostaj.
+06132002 - Patch from Torbjörn to fix stereo AIFF files.
+06212002 - More altcvt fixes from Frank Ranostaj.
+06132002 - Patch from Torbjörn to make the WAV decoder more tolerant.
+06122002 - Committed some altcvt enhancements from Frank Ranostaj.
+06112002 - Fixed some debug messages in smpeg.c and mpglib.c.
+06072002 - Manpages! Finally installed Doxygen and scratched together a
+ Doxyfile. After some revision to physfs.h, we've got a rather
+ nice API reference.
+06062002 - Added URLs for official and unofficial versions of ModPlug in
+ decoders/modplug.c. Cleaned up some FIXMEs.
+05222002 - Torbjörn sent in some more fixes for altcvt: mono to stereo
+ conversion works, now.
+05222002 - Torbjörn sent in some initial cleanups and fixes for altcvt, and
+ fixed a bug in playsound when not all three of --rate, --channels
+ and --format are specified.
+05202002 - Some .cvsignores from Max and me. Added a seek implementations for
+ the SMPEG, ogg, aiff, wav-adpcm, voc, and au decoders. Added a seek
+ stub to quicktime.c. playsound now takes milliseconds in the seek
+ lists: --seek "00:00:400" or whatnot. Corrected playsound's usage
+ text. Other au.c cleanups for extra robustness. Added an
+ experimental audio converter that Frank Ranostaj sent to the SDL
+ mailing list about a month ago: enable it with --enable-altcvt at
+ configure time, but be warned that it doesn't work very well right
+ now.
+04292002 - Darrell Walisser updated the Mac Classic and OS X project
+ files, fixed some portability issues, and added an
+ experimental decoder that uses Apple's QuickTime libraries
+ (see decoders/quicktime.c). I've included the Mac project files
+ in CVS, now. Removed all use of alloca() from playsound.
+04242002 - Added --seek option and bugfixes to playsound.c. Torbjörn comes
+ through with seek support for the FLAC, MIDI, and ModPlug
+ decoders (and some stub code for MikMod), and a bugfix for sample
+ flag manipulation in the base library (and his own --seek code for
+ playsound, which unfortunately we're not using).
+04232002 - Cleaned up the playsound command line handling. Most command line
+ options (--rate, --format, --predecode, etc) are specified per-file
+ and reset to their defaults after each sample is played back.
+ --loop now takes a numeric argument: --loop 2 will playback the
+ sample three times (one playback and two loops). Added Darrell
+ to the playsound credits.
+04212002 - Initial work to add a Sound_Seek() API. Removed the NEEDSEEK
+ sample flag (replaced it with CANSEEK). Hack to change the internal
+ Sound_SetError() function to __Sound_SetError(). Added internal
+ function __Sound_convertMsToBytePos().
+04082002 - Cleaned up the archive support in playsound a little bit, and
+ fixed a PhysicsFS bug in the process.
+03252002 - Win32 patches and fixes from Tyler Montbriand: handled "inline"
+ keyword, fixed SNDDBG macros in mpglib, and renamed a conflicting
+ file (decoders/mpglib/common.c to decoders/mpglib/mpglib_common.c).
+03172002 - Removed an unneeded #include in mpglib that broke build on BeOS.
+ mpglib seems to work find on BeOS. Reworked some of mpglib.c so we
+ can determine the audio format when accepting the data stream. Some
+ other minor cleanups here and there.
+03162002 - Tied the PhysicsFS code into the build system (code disabled if
+ physfs not found or --disable-physfs passed to ./configure.)
+03152002 - Added PhysicsFS support to playsound, so you can play sound files
+ that are in ZIP files without unzipping them. Needs to be merged
+ into build system (I was just testing my PhysFS->RWops glue code).
+03142002 - Changed configure script's --enable-vorbis to --enable-ogg. Removed
+ global state variable from mpglib, so it should be reentrant now
+ (patches sent to mpglib's actual maintainer). playsound can now
+ read from stdin.
+03102002 - Added a FIXME note to decoders/mpglib.c. playsound now reports
+ errors in the thread where they occured, which also fixes a double
+ report of errors during predecoding. Removed all calls to exit() in
+ mpglib. These calls now report errors correctly to SDL_sound, which
+ passes them on to the application (patch also sent to mpglib's
+ actual maintainer). Replaced all stderr chatter in mpglib with
+ Sound_SetError() calls.
+03072002 - decoders/mpglib.c now disregards ID3 tags instead of passing them
+ on as valid MP3 data to mpglib. Added some (buggy) example code for
+ adjusting an audio stream's volume (via the new --volume command
+ line in playsound).
+03032002 - Fixed mpglib's build configuration to include general build flags
+ so that things like --enable-debug work as expected.
+02212002 - Changed SMPEG's URL to point to the icculus.org site. Added an
+ mpglib decoder (internal to SDL_sound; relies on no external libs)
+ and changes mp3.c to smpeg.c (and other associated things).
+02112002 - Committed a patch from Torbjörn to fix incorrect memory accesses
+ in the Timidity code. Changed the magic number in the AU decoder
+ to be bigendian (seems appropriate). Updated README for
+ completeness, and TODO for accuracy. Darrell sent in updated
+ MacOS X Project Builder files (on the website).
+02072002 - Committed a patch Torbjörn sent in awhile ago for preventing
+ confusion with Timidity++-specific stuff in the timidity.cfg file.
+ Tyler Montbriand sent in an updated Visual C package.
+ Updated SDL_sound.h's comments a little. Upped version to 0.1.5.
+02052002 - Fixed a cleanup I broke last night. Added CWProject.sit to the
+ EXTRA_DIST section of Makefile.am, and updated the README with
+ MacOS (9/X) install instructions.
+02042002 - Darrell Walisser submitted some cleanups and CodeWarrior project
+ files for MacOS 9. Sweet!
+01232002 - Max fixed decoders/Makefile.am to work with seperate build
+ directories, and corrected some dates in this file.
+01192002 - Torbjörn sent in patches implementing the rewind method for the
+ rest of the decoders except shn.c, for which I added a kludged
+ implementation. Added more info to the README. Hunted down the
+ reason why SMPEG can't decode before calling SDL_OpenAudio(), and
+ it can't be fixed without a change to SMPEG (not MY fault! :) ).
+ Made ModPlug take priority over MikMod when selecting a decoder.
+ Mutex-protected the internal samples list, and fixed some bugs in
+ the management of that list. Changed some stuff to use uniform
+ coding conventions.
+01182002 - SDL_sound/playsound builds and runs on BeOS now. Fixed an assertion
+ bug I introduced yesterday.
+01172002 - Implemented Sound_Rewind(), and added a --loop command line to
+ playsound for testing. Rewrote the audio callback to handle looping
+ with both predecoded and streamed samples. Most of the decoders
+ just have an assert(0) in their internal rewinding method at this
+ point. I implemented the WAV, VOC, AU, AIFF, and RAW ones, for now.
+ (...and skeleton.c, for what that's worth.) A few tweaks in the
+ core API implementation to fix unlikely but possible leaks.
+01112002 - Mattias Engdegård sent in an .AU decoder. Nice! He also tweaked
+ playsound to try and wait until SDL has completed playing a given
+ sound before closing the audio device. Changed a macro in
+ decoders/shn.c to be more uniform with the other decoders.
+ SDL_sound error messages are now maintained on a per-thread basis,
+ and do not interfere with SDL_[GS]etError() anymore.
+01112002 - Committed the rest of Torbjörn's MOD patches, to clean up file
+ extension handling.
+01092002 - Torbjörn comes through with a ModPlug-based decoder, which should
+ work nicely for decoding multiple .MODs at once. Now we need to
+ figure out what to do with two decoders that can decode the same
+ file. For now, if you explicitly want either MikMod or ModPlug, you
+ should explicitly enable one decoder and disable the other on the
+ configure command line ("--enable-modplug --disable-mikmod", for
+ example), otherwise configure will try to sort out the best one for
+ your system. Choice is a wonderful thing. :)
+01042002 - Forgot to bump playsound's version to match SDL_sound's. Fixed.
+ Added some notes to the top of COPYING about other libraries, etc.
+ A real MIDI decoder (using a hacked version of the hacked version
+ of Timidity from SDL_mixer) is now in place and working well,
+ thanks to Torbjörn.
+01012002 - Happy New Year. Added some debug output to wav.c for future
+ codecs (GSM comes to mind). Fixed the SMPEG decoder's URL to point
+ to Loki's webpage.
+12302001 - Upped version to 0.1.4.
+12272001 - Added --audiobuf and --decodebuf options to playsound to make
+ tracking down a bug in the ADPCM decoder easier (plus, it could
+ help for benchmarking, etc later on...). Found a printf() bug in
+ playsound (extra comma in there...). ADPCM decoder appears to be
+ functional now. Tried to add ElectricFence support to
+ configure.in, and failed. All this libtool/autoconf stuff makes my
+ head hurt.
+12262001 - Changed remaining references to the "LICENSE" file into "COPYING".
+ Work progresses on the ADPCM-compressed .wav decoder. Updates to
+ the documentation in SDL_sound.h. Hhmm...find_chunk() in wav.c was
+ badly broken. Fixed.
+12162001 - FLAC decoder now checks for the magic number unless the file
+ extension is recognized. This was changed back because searching
+ for metadata, while probably more effective, is VERY expensive (and
+ useless) on non-FLAC streams.
+12052001 - Put our names in a "--credits" option in playsound, and put the
+ standard GNU disclaimers in there too, for good measure. Renamed
+ LICENSE to COPYING to match GNU standards more closely (and to
+ end Max's torment. :) ) Tweaks to wav.c, and work on aiff.c to
+ make it easier to support multiple audio formats (for compression
+ handling later down the road).
+11302001 - Torbjörn and I make Sound_DecodeAll() more robust: checks for
+ previous decoding failures and sets an appropriate error, handles
+ decoders that change their buffers on the fly (such as the FLAC
+ decoder), and deals with out-of-memory conditions more gracefully.
+11252001 - (With thanks to Andreas Umbach for pointing it out) Fixed some
+ problems with Sound_DecodeAll(). For local testing of this bug,
+ added a --predecode command line to playsound. Minor fixes to
+ theoretical bugs in Sound_FreeSample(). playsound no longer
+ buffers stdout and stderr. Updated Sound_DecodeAll()'s comments in
+ SDL_sound.h ...
+11192001 - FLAC decoder cleanups from Torbjörn.
+11092001 - Torbjörn fixes playsound's audio callback after I broke it, again.
+ A bug in configure.in was preventing SMPEG from being used unless
+ --enable-debug was set; fixed. Changed this file to list latest
+ changes first. Torbjörn submitted a FLAC decoder that utilizes
+ libFLAC (http://flac.sf.net/). Cool.
+11012001 - API COMPATIBILITY BREAKAGE: Decoders can now list multiple file
+ extensions each. Playsound has been updated to handle this.
+ Playsound now registers a SIGINT handler, so you can skip tracks
+ and/or abort the way that mpg123 does.
+10232001 - Rewrote playsound.c's audio_callback() to no longer need the
+ overflow buffer hack, which streamlines it a little and trims the
+ memory requirements for playsound by about 16 kilobytes.
+10172001 - Torbjörn catches a problem with the overflow buffer in playsound's
+ audio callback.
+10152001 - Torbjörn sends in a default sample format for the MIDI decoder,
+ and the starts of the audio conversion funcitonality (ripped
+ from SDL). Officially released 0.1.3. Added LICENSE and
+ CHANGELOG to the distribution. (Again, from Torbjörn) added in
+ the start of a tweaked audio converter.
+10122001 - Torbjörn Andersson submitted command line enhancements to
+ playsound, and I cleaned up the --help output.
+10092001 - Patches to shn.c for Visual C compatibility. Visual C project files
+ available from the website. Changed Corona688 to Tyler Montbriand
+ in CREDITS. Upped version to 0.1.3.
+10082001 - Restructured decoders/wav.c to allow for multiple formats, and
+ put the start of a handler for the ADPCM format in place.
+10072001 - Changed the way decoders/mod.c handles samplerate so that it should
+ work universally. This isn't an ideal solution, but it's probably
+ the best we can do without rewriting mikmod. Made a change to ogg.c
+ for portability: changed an int64_t to ogg_int64_t.
+10062001 - Made a change to SDL_sound.c for compiling on non-GNU toolchains.
+10052001 - Removed #include "SDL_endian" from aiff.c.
+10042001 - Changed some #if (defined SOUND_SUPPORTS_*) lines to
+ #ifdef SOUND_SUPPORTS_* in voc.c and shn.c, for consistency with
+ the other decoders.
+10032001 - After hours of tracking down a bogus pointer, the SHN decoder works!
+ I can die happy. :) Max placated me with an --enable-debug option
+ so I could stop my whining. Other autoconf goodies (such as
+ reenabling -Werror for debug builds, etc). Torbjörn brings in a
+ MIDI decoder, which reads from a Timidity process through a pipe.
+ Changed playsound to open the audio device to match the properties
+ of each sound file, which results in less conversion (and therefore,
+ more chance of correct playback).
+10022001 - Changed a comment in mod.c to not refer to "the mikmod
+ directory" anymore. Committed Torbjörn's patch for MP3 detection.
+ (better late than never). __Sound_strcasecmp() now handles NULL
+ strings gracefully, fixing the crash with "playsound bootstrap".
+ More work on the SHN decoder.
+10012001 - Fixed a memory leak that Torbjörn found in the MOD decoder.
+09252001 - More autoconf work. Gave Max Horn write access to the CVS
+ repository, so I don't drive him nuts tweaking this thing. :)
+ Fixed a const complaint and some other stuff needed for compilation
+ under Visual C++ 6.0 (no, it isn't ported yet). Put the SHN source
+ in CVS, even though it isn't ready (and doesn't even compile). Do
+ NOT enable it in your build!
+09242001 - Thank goodness, Torbjörn came through with the MP3 fix. Apparently
+ SMPEG mixes each chunk of decoded data with whatever is already
+ in the buffer you give it. I hate that. I'm going to patch SMPEG
+ to let the programmer enable and disable that behaviour in a given
+ (SMPEG *), since it's just a CPU eater in this case. The _D(())
+ macro is now SNDDBG(()), since _D is taken on MacOS X's version of
+ gcc (which was bound to happen on some platform sooner than later
+ anyhow). Renamed test_sdlsound to playsound, and made it more
+ robust in general: fixed potential overflow in audio_callback,
+ made it chatter less, made it take multiple files and some other
+ command lines. Initial autoconf support, thanks to Max Horn.
+09222001 - Torbjörn Andersson strikes again, with a collection of patches.
+ First, some cosmetic tweaks for decoders/aiff.c. Next, a MOD player
+ based on MikMod. This inspired me to add two more methods to
+ Sound_DecoderFunctions: init() and quit(). Third, a fix to
+ decoders/mp3.c so that SMPEG won't claim every stream it sees, MP3
+ or not. I removed the multiple-streams-per-rwops code, after
+ discussion on the mailing list. The init() and quit() methods
+ led to the possibility that certain decoders will flag themselves
+ as unavailable at runtime, and SDL_sound now handles this.
+ Added [LIB|INC]PATH_[OGG|MOD]. Bigendian fixes; now works on
+ PowerPC Linux. MikMod tweaks. Changed version to 0.1.2.
+09202001 - Torbjörn Andersson submitted several patches: fixed a comment in
+ the .WAV decoder (whoops...screwed up my own search-and-replace.
+ Hah.), made an attempt at putting multiple sound streams behind
+ one RWops (gotta think on that one first), and, most importantly,
+ added an AIFF decoder, which is very cool.
+09192001 - Added a skeleton decoder source file. Changed voc_read() to
+ voc_read_waveform(), so it wouldn't be confused with VOC_read().
+ Fixed a byte ordering bug in voc.c (reported as AUDIO_S16LSB, but
+ we were swapping byte order of data ourselves. Fixed). Added basic
+ .WAV support. Fixed Makefile so that -I. is always first;
+ otherwise, a previously installed header might get used for the
+ compiles, which is not good. SDL_sound.h now includes SDL_endian.h,
+ since SDL.h doesn't, for some reason. Moved version defines in
+ SDL_sound.h to top of file so I can find them. :)
+ Changed version to 0.1.1. Committed patch from Tsuyoshi Iguchi to
+ fix a segfault (I forgot to put a NULL terminator at the end of
+ the available_decoders array), fixing the only bug preventing the
+ test program from running on FreeBSD 4.3. Sweet. Added Ogg Vorbis
+ decoder. Rewrote the test program's SDL audio callback to be more
+ robust (Ogg exposed a nasty bug in it). Fixed a byte-ordering issue
+ in the VOC decoder.
+09182001 - Implemented MP3 support through SMPEG (not working yet, though) and
+ wrote the Reference Counting RWops wrapper. Added other little
+ things like the _D(()) macro. Added VOC support, which went up with
+ surprisingly little struggle, which means it MUST be leaking
+ memory. :)
+09172001 - Changed some overlooked "voice" to "sound". Implemented base API.
+ So...tired. Everything's different. :)
+ Also put in a RAW decoder and a simple test program.
+09142001 - Changed name to SDL_sound, added Sound_DecodeAll() to spec.
+09132001 - Initial spec proposed on SDL mailing list, under name "SDL_voice".
+
+--ryan. (icculus@icculus.org)
+
+/* end of CHANGELOG ... */
+
diff --git a/util/sdl/sound/COPYING b/util/sdl/sound/COPYING
new file mode 100644
index 00000000..6228aac2
--- /dev/null
+++ b/util/sdl/sound/COPYING
@@ -0,0 +1,524 @@
+Please note that the included source from Timidity, the MIDI decoder, is also
+ licensed under the following terms (GNU LGPL), but can also be used
+ separately under the GNU GPL, or the Perl Artistic License. Those licensing
+ terms are not reprinted here, but can be found on the web easily.
+
+Other external libraries (such as Ogg Vorbis, SMPEG, etc) have their own
+ licenses which you should be aware of before including the related code
+ in your configuration. Most (if not all) are also under the LGPL, but are
+ external projects and we've got no control over them.
+
+If you want to use SDL_sound under a closed-source license, please contact
+ Ryan (icculus@icculus.org), and we can discuss an alternate license for
+ money to be distributed between the contributors to this work, but I'd
+ encourage you to abide by the LGPL, since the usual concern is whether you
+ can use this library without releasing your own source code (you can).
+
+
+-------------------
+
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/util/sdl/sound/CREDITS b/util/sdl/sound/CREDITS
new file mode 100644
index 00000000..bb9af496
--- /dev/null
+++ b/util/sdl/sound/CREDITS
@@ -0,0 +1,66 @@
+ ----------------------
+ | SDL_sound credits. |
+ ----------------------
+
+Initial API interface and implementation,
+RAW driver,
+VOC driver,
+SMPEG driver,
+MPGLIB driver,
+WAV driver,
+OGG driver,
+SHN driver,
+Unix support,
+BeOS support:
+ Ryan C. Gordon
+
+Bug fixes,
+FreeBSD testing:
+ Tsuyoshi Iguchi
+
+Code cleanups,
+SMPEG fixes,
+AIFF driver,
+MikMod driver,
+MIDI driver,
+ModPlug driver,
+FLAC driver:
+ Torbjörn Andersson
+
+autoconf,
+MacOS X support:
+ Max Horn
+
+win32 support,
+PocketPC support,
+other fixes:
+ Tyler Montbriand
+
+AU driver,
+ Mattias Engdegård
+
+MacOS Classic support,
+quicktime decoder,
+OS X fixes:
+ Darrell Walisser
+
+Alternate audio conversion code:
+ Frank Ranostaj
+
+Initial Borland C++ project files:
+ Dominique Louis
+
+Bugfixes and stuff:
+ Eric Wing
+
+FLAC 1.1.3 updates:
+ Josh Coalson
+
+SMPEG fixes:
+ Chris Nelson
+
+Other stuff:
+ Your name here! Patches go to icculus@icculus.org ...
+
+/* end of CREDITS ... */
+
diff --git a/util/sdl/sound/Doxyfile b/util/sdl/sound/Doxyfile
new file mode 100644
index 00000000..33cf6708
--- /dev/null
+++ b/util/sdl/sound/Doxyfile
@@ -0,0 +1,946 @@
+# Doxyfile 1.2.16
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = SDL_sound
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 1.0.1
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean,
+# Norwegian, Polish, Portuguese, Romanian, Russian, Slovak, Slovene,
+# Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = SDL_sound.h
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse.
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED = DOXYGEN_SHOULD_IGNORE_THIS=1 SDLCALL= SNDDECLSPEC=
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line and do not end with a semicolon. Such function macros are typically
+# used for boiler-plate code, and will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/util/sdl/sound/INSTALL b/util/sdl/sound/INSTALL
new file mode 100644
index 00000000..8ac35599
--- /dev/null
+++ b/util/sdl/sound/INSTALL
@@ -0,0 +1,105 @@
+Building is pretty easy. Please read README, too, as it duplicates and
+expands upon much of this information.
+
+
+ALL PLATFORMS:
+
+Please understand your rights and mine: read the text file COPYING in the root
+of the source tree. If you can't abide by it, delete this source tree now.
+
+The best documentation for the SDL_sound API is SDL_sound.h. It is VERY
+heavily commented, and makes an excellent, in-depth reference to all the
+functions. The official API reference is generated from this file with
+a program called "Doxygen" (http://www.doxygen.org/)
+
+
+Borland C++ Builder for Linux (Kylix 3):
+ Unzip the "borland.zip" file in the root of the source tree and use the
+ project files in the newly-created Borland/k3 directory. Makefiles for the
+ command line compiler are in Borland/freebcc ...
+
+
+Unix:
+ (If you pulled the source from CVS), run ./bootstrap
+
+ run ./configure --help, and see if there's any options you need. Rerun
+ configure with those options. If this is confusing to you, just run
+ ./configure with no options: the defaults are generally decent, and
+ configure is usually smart enough to figure out what's best..
+
+ If configuration succeeded, run "make".
+
+ Run "make install" as root to install the library for use on your system.
+
+ This should work for most Unix-style systems, including Linux, *BSD, BeOS, and
+ MacOS X. Reports of success and failure are welcome.
+
+
+MacOS 9 users:
+ Included with the source is CWProject.sit, which contains project files for
+ CodeWarrior 5.0 and later.
+
+
+MacOS X command line tools:
+ You can use the "UNIX" instructions above if you like the command line tools.
+
+
+MacOS X Project Builder:
+ If you prefer to use Project Builder, use the project files included with
+ this source: PBProjects.tar.gz...unpack it in the root of the SDL_sound
+ folder. This archive contains several external libraries you would have
+ to download/install manually if you used the command line tools (these
+ libraries are for extra decoders, and are NOT required for SDL_sound to
+ function...however, without them, the number of sound formats you can
+ decode is reduced.)
+
+
+BeOS:
+ You can use the "UNIX" instructions above, too.
+
+
+Win32 Visual C:
+ For Visual C, use:
+ http://icculus.org/SDL_sound/downloads/sdl_sound_visualc_srcs.zip
+ ...and unzip it somewhere. This zipfile has a complete copy of the
+ SDL_sound sources, Visual C project files, and several external libraries,
+ too. This zip is everything you should need, and you can scrap this copy of
+ the source.
+
+
+Win32 Cygwin:
+ Cygwin users can try their luck with the Unix build instructions in this
+ tarball instead.
+
+
+Win32 Borland C++ Builder 6:
+ Unzip the "borland.zip" file in the root of the source tree and use the
+ project files in the newly-created Borland/bcb6 directory. Makefiles for the
+ command line compiler are in Borland/freebcc ... these are unmaintained, and
+ you will need to go find the external libraries you want to use (those that
+ wish to maintain these project files should contact me).
+
+
+If building is successful, there will be a shared library and a binary
+ called "playsound".
+
+
+Windows CE (Microsoft PocketPC):
+ You'll need Microsoft's PocketPC development environment, and this zipfile:
+ http://icculus.org/SDL_sound/downloads/SDL_soundCE.zip
+
+ Unzip that into the root of this source tree. The new "wce" directory has
+ project files, and the source to some of the external decoders is included.
+ Note that not all of the decoders are supported on PocketPC (but please, do
+ send us patches if you get them working!)
+
+
+OTHER PLATFORMS:
+
+Send me patches, and instructions, and I'll list them here. Consider
+joining the SDL_sound mailing list. Details are at:
+ http://icculus.org/SDL_sound/
+
+--ryan. (icculus@icculus.org)
+
+
diff --git a/util/sdl/sound/Makefile.am b/util/sdl/sound/Makefile.am
new file mode 100644
index 00000000..4927a521
--- /dev/null
+++ b/util/sdl/sound/Makefile.am
@@ -0,0 +1,53 @@
+lib_LTLIBRARIES = libSDL_sound.la
+
+SUBDIRS = decoders . playsound
+
+libSDL_soundincludedir = $(includedir)/SDL
+libSDL_soundinclude_HEADERS = \
+ SDL_sound.h
+
+libSDL_sound_la_SOURCES = \
+ SDL_sound.c \
+ SDL_sound_internal.h \
+ alt_audio_convert.c \
+ alt_audio_convert.h \
+ audio_convert.c \
+ extra_rwops.c \
+ extra_rwops.h
+
+if USE_TIMIDITY
+TIMIDITY_LIB = decoders/timidity/libtimidity.la
+else
+TIMIDITY_LIB =
+endif
+
+if USE_MPGLIB
+MPGLIB_LIB = decoders/mpglib/libmpglib.la
+else
+MPGLIB_LIB =
+endif
+
+libSDL_sound_la_LDFLAGS = \
+ -release $(LT_RELEASE) \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+libSDL_sound_la_LIBADD = \
+ decoders/libdecoders.la \
+ $(TIMIDITY_LIB) $(MPGLIB_LIB)
+
+EXTRA_DIST = \
+ CREDITS \
+ COPYING \
+ CHANGELOG \
+ CWProject.sit \
+ PBProjects.tar.gz \
+ borland.zip \
+ Doxyfile \
+ VisualC
+
+dist-hook:
+ mkdir $(distdir)/docs
+ echo "Docs are generated with the program "Doxygen" (http://www.doxygen.org/)," >> $(distdir)/docs/README
+ echo " or can be read online at http://icculus.org/SDL_sound/docs/" >> $(distdir)/docs/README
+ echo >> $(distdir)/docs/README
+ rm -rf `find $(distdir) -type d -name ".svn"`
+
diff --git a/util/sdl/sound/Makefile.in b/util/sdl/sound/Makefile.in
new file mode 100644
index 00000000..35cce45a
--- /dev/null
+++ b/util/sdl/sound/Makefile.in
@@ -0,0 +1,808 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = .
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = README $(am__configure_deps) \
+ $(libSDL_soundinclude_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/configure COPYING INSTALL TODO compile \
+ config.guess config.sub depcomp install-sh ltmain.sh missing
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(libSDL_soundincludedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+@USE_TIMIDITY_TRUE@am__DEPENDENCIES_1 = \
+@USE_TIMIDITY_TRUE@ decoders/timidity/libtimidity.la
+@USE_MPGLIB_TRUE@am__DEPENDENCIES_2 = decoders/mpglib/libmpglib.la
+libSDL_sound_la_DEPENDENCIES = decoders/libdecoders.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
+am_libSDL_sound_la_OBJECTS = SDL_sound.lo alt_audio_convert.lo \
+ audio_convert.lo extra_rwops.lo
+libSDL_sound_la_OBJECTS = $(am_libSDL_sound_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libSDL_sound_la_SOURCES)
+DIST_SOURCES = $(libSDL_sound_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+libSDL_soundincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(libSDL_soundinclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERFACE_AGE = @INTERFACE_AGE@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_MPGLIB_FALSE = @USE_MPGLIB_FALSE@
+USE_MPGLIB_TRUE = @USE_MPGLIB_TRUE@
+USE_PHYSICSFS_FALSE = @USE_PHYSICSFS_FALSE@
+USE_PHYSICSFS_TRUE = @USE_PHYSICSFS_TRUE@
+USE_TIMIDITY_FALSE = @USE_TIMIDITY_FALSE@
+USE_TIMIDITY_TRUE = @USE_TIMIDITY_TRUE@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+lib_LTLIBRARIES = libSDL_sound.la
+SUBDIRS = decoders . playsound
+libSDL_soundincludedir = $(includedir)/SDL
+libSDL_soundinclude_HEADERS = \
+ SDL_sound.h
+
+libSDL_sound_la_SOURCES = \
+ SDL_sound.c \
+ SDL_sound_internal.h \
+ alt_audio_convert.c \
+ alt_audio_convert.h \
+ audio_convert.c \
+ extra_rwops.c \
+ extra_rwops.h
+
+@USE_TIMIDITY_FALSE@TIMIDITY_LIB =
+@USE_TIMIDITY_TRUE@TIMIDITY_LIB = decoders/timidity/libtimidity.la
+@USE_MPGLIB_FALSE@MPGLIB_LIB =
+@USE_MPGLIB_TRUE@MPGLIB_LIB = decoders/mpglib/libmpglib.la
+libSDL_sound_la_LDFLAGS = \
+ -release $(LT_RELEASE) \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+libSDL_sound_la_LIBADD = \
+ decoders/libdecoders.la \
+ $(TIMIDITY_LIB) $(MPGLIB_LIB)
+
+EXTRA_DIST = \
+ CREDITS \
+ COPYING \
+ CHANGELOG \
+ CWProject.sit \
+ PBProjects.tar.gz \
+ borland.zip \
+ Doxyfile \
+ VisualC
+
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+ cd $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libSDL_sound.la: $(libSDL_sound_la_OBJECTS) $(libSDL_sound_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libSDL_sound_la_LDFLAGS) $(libSDL_sound_la_OBJECTS) $(libSDL_sound_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SDL_sound.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alt_audio_convert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio_convert.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extra_rwops.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-libSDL_soundincludeHEADERS: $(libSDL_soundinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libSDL_soundincludedir)" || $(mkdir_p) "$(DESTDIR)$(libSDL_soundincludedir)"
+ @list='$(libSDL_soundinclude_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(libSDL_soundincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libSDL_soundincludedir)/$$f'"; \
+ $(libSDL_soundincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libSDL_soundincludedir)/$$f"; \
+ done
+
+uninstall-libSDL_soundincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libSDL_soundinclude_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(libSDL_soundincludedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(libSDL_soundincludedir)/$$f"; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libSDL_soundincludedir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-libSDL_soundincludeHEADERS
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \
+ uninstall-libSDL_soundincludeHEADERS
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+ check-am clean clean-generic clean-libLTLIBRARIES \
+ clean-libtool clean-recursive ctags ctags-recursive dist \
+ dist-all dist-bzip2 dist-gzip dist-hook dist-shar dist-tarZ \
+ dist-zip distcheck distclean distclean-compile \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-recursive distclean-tags distcleancheck distdir \
+ distuninstallcheck dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-libLTLIBRARIES install-libSDL_soundincludeHEADERS \
+ install-man install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am uninstall-info-am \
+ uninstall-libLTLIBRARIES uninstall-libSDL_soundincludeHEADERS
+
+
+dist-hook:
+ mkdir $(distdir)/docs
+ echo "Docs are generated with the program "Doxygen" (http://www.doxygen.org/)," >> $(distdir)/docs/README
+ echo " or can be read online at http://icculus.org/SDL_sound/docs/" >> $(distdir)/docs/README
+ echo >> $(distdir)/docs/README
+ rm -rf `find $(distdir) -type d -name ".svn"`
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/sdl/sound/README b/util/sdl/sound/README
new file mode 100644
index 00000000..54bbd5c1
--- /dev/null
+++ b/util/sdl/sound/README
@@ -0,0 +1,58 @@
+SDL_sound. An abstract soundfile decoder.
+
+SDL_sound is a library that handles the decoding of several popular sound file
+ formats, such as .WAV and .MP3. It is meant to make the programmer's sound
+ playback tasks simpler. The programmer gives SDL_sound a filename, or feeds
+ it data directly from one of many sources, and then reads the decoded
+ waveform data back at her leisure. If resource constraints are a concern,
+ SDL_sound can process sound data in programmer-specified blocks. Alternately,
+ SDL_sound can decode a whole sound file and hand back a single pointer to the
+ whole waveform. SDL_sound can also handle sample rate, audio format, and
+ channel conversion on-the-fly and behind-the-scenes, if the programmer
+ desires.
+
+Please check the website for the most up-to-date information about SDL_sound:
+ http://icculus.org/SDL_sound/
+
+SDL_sound _REQUIRES_ Simple Directmedia Layer (SDL) to function, and cannot
+ be built without it. You can get SDL from http://www.libsdl.org/. SDL_sound
+ has only been tried with the SDL 1.2 series, but may work on older versions.
+ Reports of success or failure are welcome.
+
+Some optional external libraries that SDL_sound can use and where to find them:
+ SMPEG (used to decode MP3s): http://icculus.org/smpeg/
+ libvorbisfile (used to decode OGGs): http://www.xiph.org/ogg/vorbis/
+ libSpeex (used to decode SPXs): http://speex.org/
+ libFLAC (used to decode FLACs): http://flac.sourceforge.net/
+ libModPlug (used to decode MODs, etc): http://modplug-xmms.sourceforge.net/
+ libMikMod (used to decode MODs, etc, too): http://www.mikmod.org/
+
+ Experimental QuickTime support for the Mac is included, but has not been
+ integrated with the build system, and probably doesn't work with
+ QuickTime for Windows.
+
+These external libraries are OPTIONAL. SDL_sound will build and function
+ without them, but various sound file formats are not supported unless these
+ libraries are available. Unless explicitly disabled during initial build
+ configuration, SDL_sound always supports these file formats internally:
+
+ - Microsoft .WAV files (uncompressed and MS-ADPCM encoded).
+ - Creative Labs .VOC files
+ - Shorten (.SHN) files
+ - Audio Interchange format (AIFF) files
+ - Sun Audio (.AU) files
+ - MIDI files
+ - MP3 files (internal decoder, different than the one SMPEG uses)
+ - Raw waveform data
+
+Building/Installing:
+ Please read the INSTALL document.
+
+Reporting bugs/commenting:
+ There is a mailing list available. To subscribe, send a blank email to
+ sdlsound-subscribe@icculus.org. This is the best way to get in touch with
+ SDL_sound developers.
+
+--ryan. (icculus@icculus.org)
+
+
diff --git a/util/sdl/sound/SDL_sound.c b/util/sdl/sound/SDL_sound.c
new file mode 100644
index 00000000..8631c298
--- /dev/null
+++ b/util/sdl/sound/SDL_sound.c
@@ -0,0 +1,905 @@
+/*
+ * 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 COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+
+/* The various decoder drivers... */
+
+#if (defined SOUND_SUPPORTS_SMPEG)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SMPEG;
+#endif
+
+#if (defined SOUND_SUPPORTS_MPGLIB)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MPGLIB;
+#endif
+
+#if (defined SOUND_SUPPORTS_MIKMOD)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MIKMOD;
+#endif
+
+#if (defined SOUND_SUPPORTS_MODPLUG)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MODPLUG;
+#endif
+
+#if (defined SOUND_SUPPORTS_WAV)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV;
+#endif
+
+#if (defined SOUND_SUPPORTS_AIFF)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_AIFF;
+#endif
+
+#if (defined SOUND_SUPPORTS_AU)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_AU;
+#endif
+
+#if (defined SOUND_SUPPORTS_OGG)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG;
+#endif
+
+#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
+
+#if (defined SOUND_SUPPORTS_SHN)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SHN;
+#endif
+
+#if (defined SOUND_SUPPORTS_MIDI)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MIDI;
+#endif
+
+#if (defined SOUND_SUPPORTS_FLAC)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC;
+#endif
+
+#if (defined SOUND_SUPPORTS_QUICKTIME)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime;
+#endif
+
+#if (defined SOUND_SUPPORTS_SPEEX)
+extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SPEEX;
+#endif
+
+typedef struct
+{
+ int available;
+ const Sound_DecoderFunctions *funcs;
+} decoder_element;
+
+static decoder_element decoders[] =
+{
+#if (defined SOUND_SUPPORTS_SMPEG)
+ { 0, &__Sound_DecoderFunctions_SMPEG },
+#endif
+
+#if (defined SOUND_SUPPORTS_MPGLIB)
+ { 0, &__Sound_DecoderFunctions_MPGLIB },
+#endif
+
+#if (defined SOUND_SUPPORTS_MODPLUG)
+ { 0, &__Sound_DecoderFunctions_MODPLUG },
+#endif
+
+#if (defined SOUND_SUPPORTS_MIKMOD)
+ { 0, &__Sound_DecoderFunctions_MIKMOD },
+#endif
+
+#if (defined SOUND_SUPPORTS_WAV)
+ { 0, &__Sound_DecoderFunctions_WAV },
+#endif
+
+#if (defined SOUND_SUPPORTS_AIFF)
+ { 0, &__Sound_DecoderFunctions_AIFF },
+#endif
+
+#if (defined SOUND_SUPPORTS_AU)
+ { 0, &__Sound_DecoderFunctions_AU },
+#endif
+
+#if (defined SOUND_SUPPORTS_OGG)
+ { 0, &__Sound_DecoderFunctions_OGG },
+#endif
+
+#if (defined SOUND_SUPPORTS_VOC)
+ { 0, &__Sound_DecoderFunctions_VOC },
+#endif
+
+#if (defined SOUND_SUPPORTS_RAW)
+ { 0, &__Sound_DecoderFunctions_RAW },
+#endif
+
+#if (defined SOUND_SUPPORTS_SHN)
+ { 0, &__Sound_DecoderFunctions_SHN },
+#endif
+
+#if (defined SOUND_SUPPORTS_FLAC)
+ { 0, &__Sound_DecoderFunctions_FLAC },
+#endif
+
+#if (defined SOUND_SUPPORTS_MIDI)
+ { 0, &__Sound_DecoderFunctions_MIDI },
+#endif
+
+#if (defined SOUND_SUPPORTS_QUICKTIME)
+ { 0, &__Sound_DecoderFunctions_QuickTime },
+#endif
+
+#if (defined SOUND_SUPPORTS_SPEEX)
+ { 0, &__Sound_DecoderFunctions_SPEEX },
+#endif
+
+ { 0, NULL }
+};
+
+
+
+/* General SDL_sound state ... */
+
+typedef struct __SOUND_ERRMSGTYPE__
+{
+ Uint32 tid;
+ int error_available;
+ char error_string[128];
+ struct __SOUND_ERRMSGTYPE__ *next;
+} ErrMsg;
+
+static ErrMsg *error_msgs = NULL;
+static SDL_mutex *errorlist_mutex = NULL;
+
+static Sound_Sample *sample_list = NULL; /* this is a linked list. */
+static SDL_mutex *samplelist_mutex = NULL;
+
+static const Sound_DecoderInfo **available_decoders = NULL;
+static int initialized = 0;
+
+
+/* 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;
+ size_t pos = 0;
+ size_t total = sizeof (decoders) / sizeof (decoders[0]);
+ BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
+
+ sample_list = NULL;
+ error_msgs = NULL;
+
+ available_decoders = (const Sound_DecoderInfo **)
+ malloc((total) * sizeof (Sound_DecoderInfo *));
+ BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0);
+
+ SDL_InitSubSystem(SDL_INIT_AUDIO);
+
+ errorlist_mutex = SDL_CreateMutex();
+ samplelist_mutex = SDL_CreateMutex();
+
+ for (i = 0; decoders[i].funcs != NULL; i++)
+ {
+ decoders[i].available = decoders[i].funcs->init();
+ if (decoders[i].available)
+ {
+ available_decoders[pos] = &(decoders[i].funcs->info);
+ pos++;
+ } /* if */
+ } /* for */
+
+ available_decoders[pos] = NULL;
+
+ initialized = 1;
+ return(1);
+} /* Sound_Init */
+
+
+int Sound_Quit(void)
+{
+ ErrMsg *err;
+ ErrMsg *nexterr = NULL;
+ size_t i;
+
+ BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+
+ while (((volatile Sound_Sample *) sample_list) != NULL)
+ Sound_FreeSample(sample_list);
+
+ initialized = 0;
+
+ SDL_DestroyMutex(samplelist_mutex);
+ samplelist_mutex = NULL;
+ sample_list = NULL;
+
+ for (i = 0; decoders[i].funcs != NULL; i++)
+ {
+ if (decoders[i].available)
+ {
+ decoders[i].funcs->quit();
+ decoders[i].available = 0;
+ } /* if */
+ } /* for */
+
+ if (available_decoders != NULL)
+ free((void *) available_decoders);
+ available_decoders = NULL;
+
+ /* clean up error state for each thread... */
+ SDL_LockMutex(errorlist_mutex);
+ for (err = error_msgs; err != NULL; err = nexterr)
+ {
+ nexterr = err->next;
+ free(err);
+ } /* for */
+ error_msgs = NULL;
+ SDL_UnlockMutex(errorlist_mutex);
+ SDL_DestroyMutex(errorlist_mutex);
+ errorlist_mutex = NULL;
+
+ return(1);
+} /* Sound_Quit */
+
+
+const Sound_DecoderInfo **Sound_AvailableDecoders(void)
+{
+ return(available_decoders); /* READ. ONLY. */
+} /* Sound_AvailableDecoders */
+
+
+static ErrMsg *findErrorForCurrentThread(void)
+{
+ ErrMsg *i;
+ Uint32 tid;
+
+ if (error_msgs != NULL)
+ {
+ tid = SDL_ThreadID();
+
+ SDL_LockMutex(errorlist_mutex);
+ for (i = error_msgs; i != NULL; i = i->next)
+ {
+ if (i->tid == tid)
+ {
+ SDL_UnlockMutex(errorlist_mutex);
+ return(i);
+ } /* if */
+ } /* for */
+ SDL_UnlockMutex(errorlist_mutex);
+ } /* if */
+
+ return(NULL); /* no error available. */
+} /* findErrorForCurrentThread */
+
+
+const char *Sound_GetError(void)
+{
+ const char *retval = NULL;
+ ErrMsg *err;
+
+ if (!initialized)
+ return(ERR_NOT_INITIALIZED);
+
+ err = findErrorForCurrentThread();
+ if ((err != NULL) && (err->error_available))
+ {
+ retval = err->error_string;
+ err->error_available = 0;
+ } /* if */
+
+ return(retval);
+} /* Sound_GetError */
+
+
+void Sound_ClearError(void)
+{
+ ErrMsg *err;
+
+ if (!initialized)
+ return;
+
+ err = findErrorForCurrentThread();
+ if (err != NULL)
+ err->error_available = 0;
+} /* Sound_ClearError */
+
+
+/*
+ * This is declared in the internal header.
+ */
+void __Sound_SetError(const char *str)
+{
+ ErrMsg *err;
+
+ if (str == NULL)
+ return;
+
+ SNDDBG(("__Sound_SetError(\"%s\");%s\n", str,
+ (initialized) ? "" : " [NOT INITIALIZED!]"));
+
+ if (!initialized)
+ return;
+
+ err = findErrorForCurrentThread();
+ if (err == NULL)
+ {
+ err = (ErrMsg *) malloc(sizeof (ErrMsg));
+ if (err == NULL)
+ return; /* uhh...? */
+
+ memset((void *) err, '\0', sizeof (ErrMsg));
+ err->tid = SDL_ThreadID();
+
+ SDL_LockMutex(errorlist_mutex);
+ err->next = error_msgs;
+ error_msgs = err;
+ SDL_UnlockMutex(errorlist_mutex);
+ } /* if */
+
+ err->error_available = 1;
+ strncpy(err->error_string, str, sizeof (err->error_string));
+ err->error_string[sizeof (err->error_string) - 1] = '\0';
+} /* __Sound_SetError */
+
+
+Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms)
+{
+ /* "frames" == "sample frames" */
+ float frames_per_ms = ((float) info->rate) / 1000.0f;
+ Uint32 frame_offset = (Uint32) (frames_per_ms * ((float) ms));
+ Uint32 frame_size = (Uint32) ((info->format & 0xFF) / 8) * info->channels;
+ return(frame_offset * frame_size);
+} /* __Sound_convertMsToBytePos */
+
+
+/*
+ * -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;
+
+ if (x == y) /* same pointer? Both NULL? */
+ return(0);
+
+ if (x == NULL)
+ return(-1);
+
+ if (y == NULL)
+ return(1);
+
+ 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 */
+
+
+#if (defined DEBUG_CHATTER)
+static __inline__ const char *fmt_to_str(Uint16 fmt)
+{
+ switch(fmt)
+ {
+ case AUDIO_U8:
+ return("U8");
+ case AUDIO_S8:
+ return("S8");
+ case AUDIO_U16LSB:
+ return("U16LSB");
+ case AUDIO_S16LSB:
+ return("S16LSB");
+ case AUDIO_U16MSB:
+ return("U16MSB");
+ case AUDIO_S16MSB:
+ return("S16MSB");
+ } /* switch */
+
+ return("Unknown");
+} /* fmt_to_str */
+#endif
+
+
+/*
+ * 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.
+ */
+static int init_sample(const Sound_DecoderFunctions *funcs,
+ Sound_Sample *sample, const char *ext,
+ Sound_AudioInfo *_desired)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ Sound_AudioInfo desired;
+ int pos = SDL_RWtell(internal->rw);
+
+ /* 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 (desired.format == 0)
+ desired.format = sample->actual.format;
+ if (desired.channels == 0)
+ desired.channels = sample->actual.channels;
+ if (desired.rate == 0)
+ desired.rate = sample->actual.rate;
+
+ if (Sound_BuildAudioCVT(&internal->sdlcvt,
+ sample->actual.format,
+ sample->actual.channels,
+ sample->actual.rate,
+ desired.format,
+ desired.channels,
+ desired.rate,
+ sample->buffer_size) == -1)
+ {
+ __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 sample_list... */
+ SDL_LockMutex(samplelist_mutex);
+ internal->next = sample_list;
+ if (sample_list != NULL)
+ ((Sound_SampleInternal *) sample_list->opaque)->prev = sample;
+ sample_list = sample;
+ SDL_UnlockMutex(samplelist_mutex);
+
+ SNDDBG(("New sample DESIRED format: %s format, %d rate, %d channels.\n",
+ fmt_to_str(sample->desired.format),
+ sample->desired.rate,
+ sample->desired.channels));
+
+ SNDDBG(("New sample ACTUAL format: %s format, %d rate, %d channels.\n",
+ fmt_to_str(sample->actual.format),
+ sample->actual.rate,
+ sample->actual.channels));
+
+ SNDDBG(("On-the-fly conversion: %s.\n",
+ internal->sdlcvt.needed ? "ENABLED" : "DISABLED"));
+
+ return(1);
+} /* init_sample */
+
+
+Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext,
+ Sound_AudioInfo *desired, Uint32 bSize)
+{
+ Sound_Sample *retval;
+ decoder_element *decoder;
+
+ /* 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 (decoder = &decoders[0]; decoder->funcs != NULL; decoder++)
+ {
+ if (decoder->available)
+ {
+ const char **decoderExt = decoder->funcs->info.extensions;
+ while (*decoderExt)
+ {
+ if (__Sound_strcasecmp(*decoderExt, ext) == 0)
+ {
+ if (init_sample(decoder->funcs, retval, ext, desired))
+ return(retval);
+ break; /* done with this decoder either way. */
+ } /* if */
+ decoderExt++;
+ } /* while */
+ } /* if */
+ } /* for */
+ } /* if */
+
+ /* no direct extension match? Try everything we've got... */
+ for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++)
+ {
+ if (decoder->available)
+ {
+ int should_try = 1;
+ const char **decoderExt = decoder->funcs->info.extensions;
+
+ /* skip if we would have tried decoder above... */
+ while (*decoderExt)
+ {
+ if (__Sound_strcasecmp(*decoderExt, ext) == 0)
+ {
+ should_try = 0;
+ break;
+ } /* if */
+ decoderExt++;
+ } /* while */
+
+ if (should_try)
+ {
+ if (init_sample(decoder->funcs, retval, ext, desired))
+ return(retval);
+ } /* if */
+ } /* if */
+ } /* 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;
+
+ SDL_LockMutex(samplelist_mutex);
+
+ /* update the sample_list... */
+ if (internal->prev != NULL)
+ {
+ Sound_SampleInternal *prevInternal;
+ prevInternal = (Sound_SampleInternal *) internal->prev->opaque;
+ prevInternal->next = internal->next;
+ } /* if */
+ else
+ {
+ assert(sample_list == sample);
+ sample_list = internal->next;
+ } /* else */
+
+ if (internal->next != NULL)
+ {
+ Sound_SampleInternal *nextInternal;
+ nextInternal = (Sound_SampleInternal *) internal->next->opaque;
+ nextInternal->prev = internal->prev;
+ } /* if */
+
+ SDL_UnlockMutex(samplelist_mutex);
+
+ /* nuke it... */
+ internal->funcs->close(sample);
+
+ if (internal->rw != NULL) /* this condition is a "just in case" thing. */
+ SDL_RWclose(internal->rw);
+
+ if ((internal->buffer != NULL) && (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 (retval > 0 && internal->sdlcvt.needed)
+ {
+ internal->sdlcvt.len = retval;
+ Sound_ConvertAudio(&internal->sdlcvt);
+ retval = internal->sdlcvt.len_cvt;
+ } /* 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);
+ BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0);
+ BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0);
+
+ internal = (Sound_SampleInternal *) sample->opaque;
+
+ while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) &&
+ ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) )
+ {
+ Uint32 br = Sound_Decode(sample);
+ void *ptr = realloc(buf, newBufSize + br);
+ if (ptr == NULL)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ __Sound_SetError(ERR_OUT_OF_MEMORY);
+ } /* if */
+ else
+ {
+ buf = ptr;
+ memcpy( ((char *) buf) + newBufSize, sample->buffer, br );
+ newBufSize += br;
+ } /* else */
+ } /* while */
+
+ if (buf == NULL) /* ...in case first call to realloc() fails... */
+ return(sample->buffer_size);
+
+ if (internal->buffer != sample->buffer)
+ free(internal->buffer);
+
+ free(sample->buffer);
+
+ internal->sdlcvt.buf = internal->buffer = sample->buffer = buf;
+ sample->buffer_size = newBufSize;
+ internal->buffer_size = newBufSize / internal->sdlcvt.len_mult;
+ internal->sdlcvt.len = internal->buffer_size;
+
+ return(newBufSize);
+} /* Sound_DecodeAll */
+
+
+int Sound_Rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal;
+ BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+
+ internal = (Sound_SampleInternal *) sample->opaque;
+ if (!internal->funcs->rewind(sample))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(0);
+ } /* if */
+
+ sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
+ sample->flags &= ~SOUND_SAMPLEFLAG_ERROR;
+ sample->flags &= ~SOUND_SAMPLEFLAG_EOF;
+
+ return(1);
+} /* Sound_Rewind */
+
+
+int Sound_Seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal;
+
+ BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
+ if (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK))
+ BAIL_MACRO(ERR_CANNOT_SEEK, 0);
+
+ internal = (Sound_SampleInternal *) sample->opaque;
+ BAIL_IF_MACRO(!internal->funcs->seek(sample, ms), NULL, 0);
+
+ sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
+ sample->flags &= ~SOUND_SAMPLEFLAG_ERROR;
+ sample->flags &= ~SOUND_SAMPLEFLAG_EOF;
+
+ return(1);
+} /* Sound_Rewind */
+
+
+/* end of SDL_sound.c ... */
+
diff --git a/util/sdl/sound/SDL_sound.h b/util/sdl/sound/SDL_sound.h
new file mode 100644
index 00000000..b0b8c978
--- /dev/null
+++ b/util/sdl/sound/SDL_sound.h
@@ -0,0 +1,674 @@
+/** \file SDL_sound.h */
+
+/*
+ * 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
+ */
+
+/**
+ * \mainpage SDL_sound
+ *
+ * The latest version of SDL_sound can be found at:
+ * http://icculus.org/SDL_sound/
+ *
+ * The basic gist of SDL_sound is that you use an SDL_RWops to get sound data
+ * into this library, and SDL_sound will take that data, in one of several
+ * popular formats, and decode it into raw waveform data in the format of
+ * your choice. This gives you a nice abstraction for getting sound into your
+ * game or application; just feed it to SDL_sound, and it will handle
+ * decoding and converting, so you can just pass it to your SDL audio
+ * callback (or whatever). Since it gets data from an SDL_RWops, you can get
+ * the initial sound data from any number of sources: file, memory buffer,
+ * network connection, etc.
+ *
+ * As the name implies, this library depends on SDL: Simple Directmedia Layer,
+ * which is a powerful, free, and cross-platform multimedia library. It can
+ * be found at http://www.libsdl.org/
+ *
+ * Support is in place or planned for the following sound formats:
+ * - .WAV (Microsoft WAVfile RIFF data, internal.)
+ * - .VOC (Creative Labs' Voice format, internal.)
+ * - .MP3 (MPEG-1 Layer 3 support, via the SMPEG and mpglib libraries.)
+ * - .MID (MIDI music converted to Waveform data, internal.)
+ * - .MOD (MOD files, via MikMod and ModPlug.)
+ * - .OGG (Ogg files, via Ogg Vorbis libraries.)
+ * - .SPX (Speex files, via libspeex.)
+ * - .SHN (Shorten files, internal.)
+ * - .RAW (Raw sound data in any format, internal.)
+ * - .AU (Sun's Audio format, internal.)
+ * - .AIFF (Audio Interchange format, internal.)
+ * - .FLAC (Lossless audio compression, via libFLAC.)
+ *
+ * (...and more to come...)
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * \author Ryan C. Gordon (icculus@icculus.org)
+ * \author many others, please see CREDITS in the source's root directory.
+ */
+
+#ifndef _INCLUDE_SDL_SOUND_H_
+#define _INCLUDE_SDL_SOUND_H_
+
+#include "SDL.h"
+#include "SDL_endian.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DOXYGEN_SHOULD_IGNORE_THIS
+
+#ifndef SDLCALL /* may not be defined with older SDL releases. */
+#define SDLCALL
+#endif
+
+#ifdef SDL_SOUND_DLL_EXPORTS
+# define SNDDECLSPEC __declspec(dllexport)
+#else
+# define SNDDECLSPEC
+#endif
+
+#define SOUND_VER_MAJOR 1
+#define SOUND_VER_MINOR 0
+#define SOUND_VER_PATCH 3
+#endif
+
+
+/**
+ * \enum Sound_SampleFlags
+ * \brief Flags that are used in a Sound_Sample to show various states.
+ *
+ * To use:
+ * \code
+ * if (sample->flags & SOUND_SAMPLEFLAG_ERROR) { dosomething(); }
+ * \endcode
+ *
+ * \sa Sound_SampleNew
+ * \sa Sound_SampleNewFromFile
+ * \sa Sound_SampleDecode
+ * \sa Sound_SampleDecodeAll
+ * \sa Sound_SampleSeek
+ */
+typedef enum
+{
+ SOUND_SAMPLEFLAG_NONE = 0, /**< No special attributes. */
+
+ /* these are set at sample creation time... */
+ SOUND_SAMPLEFLAG_CANSEEK = 1, /**< Sample can seek to arbitrary points. */
+
+ /* these are set during decoding... */
+ SOUND_SAMPLEFLAG_EOF = 1 << 29, /**< End of input stream. */
+ SOUND_SAMPLEFLAG_ERROR = 1 << 30, /**< Unrecoverable error. */
+ SOUND_SAMPLEFLAG_EAGAIN = 1 << 31 /**< Function would block, or temp error. */
+} Sound_SampleFlags;
+
+
+/**
+ * \struct Sound_AudioInfo
+ * \brief Information about an existing sample's format.
+ *
+ * These are the basics of a decoded sample's data structure: data format
+ * (see AUDIO_U8 and friends in SDL_audio.h), number of channels, and sample
+ * rate. If you need more explanation than that, you should stop developing
+ * sound code right now.
+ *
+ * \sa Sound_SampleNew
+ * \sa Sound_SampleNewFromFile
+ */
+typedef struct
+{
+ 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. */
+} Sound_AudioInfo;
+
+
+/**
+ * \struct Sound_DecoderInfo
+ * \brief Information about available soudn decoders.
+ *
+ * Each decoder sets up one of these structs, which can be retrieved via
+ * the Sound_AvailableDecoders() function. EVERY FIELD IN THIS IS READ-ONLY.
+ *
+ * The extensions field is a NULL-terminated list of ASCIZ strings. You
+ * should read it like this:
+ *
+ * \code
+ * const char **ext;
+ * for (ext = info->extensions; *ext != NULL; ext++) {
+ * printf(" File extension \"%s\"\n", *ext);
+ * }
+ * \endcode
+ *
+ * \sa Sound_AvailableDecoders
+ */
+typedef struct
+{
+ const char **extensions; /**< File extensions, list ends with NULL. */
+ const char *description; /**< Human readable description of decoder. */
+ const char *author; /**< "Name Of Author \<email@emailhost.dom\>" */
+ const char *url; /**< URL specific to this decoder. */
+} Sound_DecoderInfo;
+
+
+
+/**
+ * \struct Sound_Sample
+ * \brief Represents sound data in the process of being decoded.
+ *
+ * The Sound_Sample structure is the heart of SDL_sound. This holds
+ * information about a source of sound data as it is being decoded.
+ * EVERY FIELD IN THIS IS READ-ONLY. Please use the API functions to
+ * change them.
+ */
+typedef struct
+{
+ void *opaque; /**< Internal use only. Don't touch. */
+ const Sound_DecoderInfo *decoder; /**< Decoder used for this sample. */
+ Sound_AudioInfo desired; /**< Desired audio format for conversion. */
+ Sound_AudioInfo actual; /**< Actual audio format of sample. */
+ void *buffer; /**< Decoded sound data lands in here. */
+ Uint32 buffer_size; /**< Current size of (buffer), in bytes (Uint8). */
+ Sound_SampleFlags flags; /**< Flags relating to this sample. */
+} Sound_Sample;
+
+
+/**
+ * \struct Sound_Version
+ * \brief Information the version of SDL_sound in use.
+ *
+ * Represents the library's version as three levels: major revision
+ * (increments with massive changes, additions, and enhancements),
+ * minor revision (increments with backwards-compatible changes to the
+ * major revision), and patchlevel (increments with fixes to the minor
+ * revision).
+ *
+ * \sa SOUND_VERSION
+ * \sa Sound_GetLinkedVersion
+ */
+typedef struct
+{
+ int major; /**< major revision */
+ int minor; /**< minor revision */
+ int patch; /**< patchlevel */
+} Sound_Version;
+
+
+/* functions and macros... */
+
+/**
+ * \def SOUND_VERSION(x)
+ * \brief Macro to determine SDL_sound version program was compiled against.
+ *
+ * This macro fills in a Sound_Version structure with the version of the
+ * library you compiled against. This is determined by what header the
+ * compiler uses. Note that if you dynamically linked the library, you might
+ * have a slightly newer or older version at runtime. That version can be
+ * determined with Sound_GetLinkedVersion(), which, unlike SOUND_VERSION,
+ * is not a macro.
+ *
+ * \param x A pointer to a Sound_Version struct to initialize.
+ *
+ * \sa Sound_Version
+ * \sa Sound_GetLinkedVersion
+ */
+#define SOUND_VERSION(x) \
+{ \
+ (x)->major = SOUND_VER_MAJOR; \
+ (x)->minor = SOUND_VER_MINOR; \
+ (x)->patch = SOUND_VER_PATCH; \
+}
+
+
+/**
+ * \fn void Sound_GetLinkedVersion(Sound_Version *ver)
+ * \brief Get the version of SDL_sound that is linked against your program.
+ *
+ * If you are using a shared library (DLL) version of SDL_sound, then it is
+ * possible that it will be different than the version you compiled against.
+ *
+ * This is a real function; the macro SOUND_VERSION tells you what version
+ * of SDL_sound you compiled against:
+ *
+ * \code
+ * Sound_Version compiled;
+ * Sound_Version linked;
+ *
+ * SOUND_VERSION(&compiled);
+ * Sound_GetLinkedVersion(&linked);
+ * printf("We compiled against SDL_sound version %d.%d.%d ...\n",
+ * compiled.major, compiled.minor, compiled.patch);
+ * printf("But we linked against SDL_sound version %d.%d.%d.\n",
+ * linked.major, linked.minor, linked.patch);
+ * \endcode
+ *
+ * This function may be called safely at any time, even before Sound_Init().
+ *
+ * \param ver Sound_Version structure to fill with shared library's version.
+ *
+ * \sa Sound_Version
+ * \sa SOUND_VERSION
+ */
+SNDDECLSPEC void SDLCALL Sound_GetLinkedVersion(Sound_Version *ver);
+
+
+/**
+ * \fn Sound_Init(void)
+ * \brief Initialize SDL_sound.
+ *
+ * This must be called before any other SDL_sound function (except perhaps
+ * Sound_GetLinkedVersion()). You should call SDL_Init() before calling this.
+ * Sound_Init() will attempt to call SDL_Init(SDL_INIT_AUDIO), just in case.
+ * This is a safe behaviour, but it may not configure SDL to your liking by
+ * itself.
+ *
+ * \return nonzero on success, zero on error. Specifics of the
+ * error can be gleaned from Sound_GetError().
+ *
+ * \sa Sound_Quit
+ */
+SNDDECLSPEC int SDLCALL Sound_Init(void);
+
+
+/**
+ * \fn Sound_Quit(void)
+ * \brief Shutdown SDL_sound.
+ *
+ * This closes any SDL_RWops that were being used as sound sources, and frees
+ * any resources in use by SDL_sound.
+ *
+ * All Sound_Sample pointers you had prior to this call are INVALIDATED.
+ *
+ * Once successfully deinitialized, Sound_Init() can be called again to
+ * restart the subsystem. All default API states are restored at this
+ * point.
+ *
+ * You should call this BEFORE SDL_Quit(). This will NOT call SDL_Quit()
+ * for you!
+ *
+ * \return nonzero on success, zero on error. Specifics of the error
+ * can be gleaned from Sound_GetError(). If failure, state of
+ * SDL_sound is undefined, and probably badly screwed up.
+ *
+ * \sa Sound_Init
+ */
+SNDDECLSPEC int SDLCALL Sound_Quit(void);
+
+
+/**
+ * \fn const Sound_DecoderInfo **Sound_AvailableDecoders(void)
+ * \brief Get a list of sound formats supported by this version of SDL_sound.
+ *
+ * This is for informational purposes only. Note that the extension listed is
+ * merely convention: if we list "MP3", you can open an MPEG-1 Layer 3 audio
+ * file with an extension of "XYZ", if you like. The file extensions are
+ * informational, and only required as a hint to choosing the correct
+ * decoder, since the sound data may not be coming from a file at all, thanks
+ * to the abstraction that an SDL_RWops provides.
+ *
+ * The returned value is an array of pointers to Sound_DecoderInfo structures,
+ * with a NULL entry to signify the end of the list:
+ *
+ * \code
+ * Sound_DecoderInfo **i;
+ *
+ * for (i = Sound_AvailableDecoders(); *i != NULL; i++)
+ * {
+ * printf("Supported sound format: [%s], which is [%s].\n",
+ * i->extension, i->description);
+ * // ...and other fields...
+ * }
+ * \endcode
+ *
+ * The return values are pointers to static internal memory, and should
+ * be considered READ ONLY, and never freed.
+ *
+ * \return READ ONLY Null-terminated array of READ ONLY structures.
+ *
+ * \sa Sound_DecoderInfo
+ */
+SNDDECLSPEC const Sound_DecoderInfo ** SDLCALL Sound_AvailableDecoders(void);
+
+
+/**
+ * \fn const char *Sound_GetError(void)
+ * \brief Get the last SDL_sound error message as a null-terminated string.
+ *
+ * This will be NULL if there's been no error since the last call to this
+ * function. The pointer returned by this call points to an internal buffer,
+ * and should not be deallocated. Each thread has a unique error state
+ * associated with it, but each time a new error message is set, it will
+ * overwrite the previous one associated with that thread. It is safe to call
+ * this function at anytime, even before Sound_Init().
+ *
+ * \return READ ONLY string of last error message.
+ *
+ * \sa Sound_ClearError
+ */
+SNDDECLSPEC const char * SDLCALL Sound_GetError(void);
+
+
+/**
+ * \fn void Sound_ClearError(void)
+ * \brief Clear the current error message.
+ *
+ * The next call to Sound_GetError() after Sound_ClearError() will return NULL.
+ *
+ * \sa Sound_GetError
+ */
+SNDDECLSPEC void SDLCALL Sound_ClearError(void);
+
+
+/**
+ * \fn Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, Sound_AudioInfo *desired, Uint32 bufferSize)
+ * \brief Start decoding a new sound sample.
+ *
+ * The data is read via an SDL_RWops structure (see SDL_rwops.h in the SDL
+ * include directory), so it may be coming from memory, disk, network stream,
+ * etc. The (ext) parameter is merely a hint to determining the correct
+ * decoder; if you specify, for example, "mp3" for an extension, and one of
+ * the decoders lists that as a handled extension, then that decoder is given
+ * first shot at trying to claim the data for decoding. If none of the
+ * extensions match (or the extension is NULL), then every decoder examines
+ * the data to determine if it can handle it, until one accepts it. In such a
+ * case your SDL_RWops will need to be capable of rewinding to the start of
+ * the stream.
+ *
+ * If no decoders can handle the data, a NULL value is returned, and a human
+ * readable error message can be fetched from Sound_GetError().
+ *
+ * Optionally, a desired audio format can be specified. If the incoming data
+ * is in a different format, SDL_sound will convert it to the desired format
+ * on the fly. Note that this can be an expensive operation, so it may be
+ * wise to convert data before you need to play it back, if possible, or
+ * make sure your data is initially in the format that you need it in.
+ * If you don't want to convert the data, you can specify NULL for a desired
+ * format. The incoming format of the data, preconversion, can be found
+ * in the Sound_Sample structure.
+ *
+ * Note that the raw sound data "decoder" needs you to specify both the
+ * extension "RAW" and a "desired" format, or it will refuse to handle
+ * the data. This is to prevent it from catching all formats unsupported
+ * by the other decoders.
+ *
+ * Finally, specify an initial buffer size; this is the number of bytes that
+ * will be allocated to store each read from the sound buffer. The more you
+ * can safely allocate, the more decoding can be done in one block, but the
+ * more resources you have to use up, and the longer each decoding call will
+ * take. Note that different data formats require more or less space to
+ * store. This buffer can be resized via Sound_SetBufferSize() ...
+ *
+ * The buffer size specified must be a multiple of the size of a single
+ * sample point. So, if you want 16-bit, stereo samples, then your sample
+ * point size is (2 channels * 16 bits), or 32 bits per sample, which is four
+ * bytes. In such a case, you could specify 128 or 132 bytes for a buffer,
+ * but not 129, 130, or 131 (although in reality, you'll want to specify a
+ * MUCH larger buffer).
+ *
+ * When you are done with this Sound_Sample pointer, you can dispose of it
+ * via Sound_FreeSample().
+ *
+ * You do not have to keep a reference to (rw) around. If this function
+ * suceeds, it stores (rw) internally (and disposes of it during the call
+ * to Sound_FreeSample()). If this function fails, it will dispose of the
+ * SDL_RWops for you.
+ *
+ * \param rw SDL_RWops with sound data.
+ * \param ext File extension normally associated with a data format.
+ * Can usually be NULL.
+ * \param desired Format to convert sound data into. Can usually be NULL,
+ * if you don't need conversion.
+ * \param bufferSize Size, in bytes, to allocate for the decoding buffer.
+ * \return Sound_Sample pointer, which is used as a handle to several other
+ * SDL_sound APIs. NULL on error. If error, use
+ * Sound_GetError() to see what went wrong.
+ *
+ * \sa Sound_NewSampleFromFile
+ * \sa Sound_SetBufferSize
+ * \sa Sound_Decode
+ * \sa Sound_DecodeAll
+ * \sa Sound_Seek
+ * \sa Sound_Rewind
+ * \sa Sound_FreeSample
+ */
+SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSample(SDL_RWops *rw,
+ const char *ext,
+ Sound_AudioInfo *desired,
+ Uint32 bufferSize);
+
+/**
+ * \fn Sound_Sample *Sound_NewSampleFromFile(const char *filename, Sound_AudioInfo *desired, Uint32 bufferSize)
+ * \brief Start decoding a new sound sample from a file on disk.
+ *
+ * This is identical to Sound_NewSample(), but it creates an SDL_RWops for you
+ * from the file located in (filename). Note that (filename) is specified in
+ * platform-dependent notation. ("C:\\music\\mysong.mp3" on windows, and
+ * "/home/icculus/music/mysong.mp3" or whatever on Unix, etc.)
+ * Sound_NewSample()'s "ext" parameter is gleaned from the contents of
+ * (filename).
+ *
+ * \param filename file containing sound data.
+ * \param desired Format to convert sound data into. Can usually be NULL,
+ * if you don't need conversion.
+ * \param bufferSize size, in bytes, of initial read buffer.
+ * \return Sound_Sample pointer, which is used as a handle to several other
+ * SDL_sound APIs. NULL on error. If error, use
+ * Sound_GetError() to see what went wrong.
+ *
+ * \sa Sound_NewSample
+ * \sa Sound_SetBufferSize
+ * \sa Sound_Decode
+ * \sa Sound_DecodeAll
+ * \sa Sound_Seek
+ * \sa Sound_Rewind
+ * \sa Sound_FreeSample
+ */
+SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSampleFromFile(const char *fname,
+ Sound_AudioInfo *desired,
+ Uint32 bufferSize);
+
+/**
+ * \fn void Sound_FreeSample(Sound_Sample *sample)
+ * \brief Dispose of a Sound_Sample.
+ *
+ * This will also close/dispose of the SDL_RWops that was used at creation
+ * time, so there's no need to keep a reference to that around.
+ * The Sound_Sample pointer is invalid after this call, and will almost
+ * certainly result in a crash if you attempt to keep using it.
+ *
+ * \param sample The Sound_Sample to delete.
+ *
+ * \sa Sound_NewSample
+ * \sa Sound_NewSampleFromFile
+ */
+SNDDECLSPEC void SDLCALL Sound_FreeSample(Sound_Sample *sample);
+
+
+/**
+ * \fn int Sound_SetBufferSize(Sound_Sample *sample, Uint32 new_size)
+ * \brief Change the current buffer size for a sample.
+ *
+ * If the buffer size could be changed, then the sample->buffer and
+ * sample->buffer_size fields will reflect that. If they could not be
+ * changed, then your original sample state is preserved. If the buffer is
+ * shrinking, the data at the end of buffer is truncated. If the buffer is
+ * growing, the contents of the new space at the end is undefined until you
+ * decode more into it or initialize it yourself.
+ *
+ * The buffer size specified must be a multiple of the size of a single
+ * sample point. So, if you want 16-bit, stereo samples, then your sample
+ * point size is (2 channels * 16 bits), or 32 bits per sample, which is four
+ * bytes. In such a case, you could specify 128 or 132 bytes for a buffer,
+ * but not 129, 130, or 131 (although in reality, you'll want to specify a
+ * MUCH larger buffer).
+ *
+ * \param sample The Sound_Sample whose buffer to modify.
+ * \param new_size The desired size, in bytes, of the new buffer.
+ * \return non-zero if buffer size changed, zero on failure.
+ *
+ * \sa Sound_Decode
+ * \sa Sound_DecodeAll
+ */
+SNDDECLSPEC int SDLCALL Sound_SetBufferSize(Sound_Sample *sample,
+ Uint32 new_size);
+
+
+/**
+ * \fn Uint32 Sound_Decode(Sound_Sample *sample)
+ * \brief Decode more of the sound data in a Sound_Sample.
+ *
+ * It will decode at most sample->buffer_size bytes into sample->buffer in the
+ * desired format, and return the number of decoded bytes.
+ * If sample->buffer_size bytes could not be decoded, then please refer to
+ * sample->flags to determine if this was an end-of-stream or error condition.
+ *
+ * \param sample Do more decoding to this Sound_Sample.
+ * \return number of bytes decoded into sample->buffer. If it is less than
+ * sample->buffer_size, then you should check sample->flags to see
+ * what the current state of the sample is (EOF, error, read again).
+ *
+ * \sa Sound_DecodeAll
+ * \sa Sound_SetBufferSize
+ * \sa Sound_Seek
+ * \sa Sound_Rewind
+ */
+SNDDECLSPEC Uint32 SDLCALL Sound_Decode(Sound_Sample *sample);
+
+
+/**
+ * \fn Uint32 Sound_DecodeAll(Sound_Sample *sample)
+ * \brief Decode the remainder of the sound data in a Sound_Sample.
+ *
+ * This will dynamically allocate memory for the ENTIRE remaining sample.
+ * sample->buffer_size and sample->buffer will be updated to reflect the
+ * new buffer. Please refer to sample->flags to determine if the decoding
+ * finished due to an End-of-stream or error condition.
+ *
+ * Be aware that sound data can take a large amount of memory, and that
+ * this function may block for quite awhile while processing. Also note
+ * that a streaming source (for example, from a SDL_RWops that is getting
+ * fed from an Internet radio feed that doesn't end) may fill all available
+ * memory before giving up...be sure to use this on finite sound sources
+ * only!
+ *
+ * When decoding the sample in its entirety, the work is done one buffer at a
+ * time. That is, sound is decoded in sample->buffer_size blocks, and
+ * appended to a continually-growing buffer until the decoding completes.
+ * That means that this function will need enough RAM to hold approximately
+ * sample->buffer_size bytes plus the complete decoded sample at most. The
+ * larger your buffer size, the less overhead this function needs, but beware
+ * the possibility of paging to disk. Best to make this user-configurable if
+ * the sample isn't specific and small.
+ *
+ * \param sample Do all decoding for this Sound_Sample.
+ * \return number of bytes decoded into sample->buffer. You should check
+ * sample->flags to see what the current state of the sample is
+ * (EOF, error, read again).
+ *
+ * \sa Sound_Decode
+ * \sa Sound_SetBufferSize
+ */
+SNDDECLSPEC Uint32 SDLCALL Sound_DecodeAll(Sound_Sample *sample);
+
+
+/**
+ * \fn int Sound_Rewind(Sound_Sample *sample)
+ * \brief Rewind a sample to the start.
+ *
+ * Restart a sample at the start of its waveform data, as if newly
+ * created with Sound_NewSample(). If successful, the next call to
+ * Sound_Decode[All]() will give audio data from the earliest point
+ * in the stream.
+ *
+ * Beware that this function will fail if the SDL_RWops that feeds the
+ * decoder can not be rewound via it's seek method, but this can
+ * theoretically be avoided by wrapping it in some sort of buffering
+ * SDL_RWops.
+ *
+ * This function should ONLY fail if the RWops is not seekable, or
+ * SDL_sound is not initialized. Both can be controlled by the application,
+ * and thus, it is up to the developer's paranoia to dictate whether this
+ * function's return value need be checked at all.
+ *
+ * If this function fails, the state of the sample is undefined, but it
+ * is still safe to call Sound_FreeSample() to dispose of it.
+ *
+ * On success, ERROR, EOF, and EAGAIN are cleared from sample->flags. The
+ * ERROR flag is set on error.
+ *
+ * \param sample The Sound_Sample to rewind.
+ * \return nonzero on success, zero on error. Specifics of the
+ * error can be gleaned from Sound_GetError().
+ *
+ * \sa Sound_Seek
+ */
+SNDDECLSPEC int SDLCALL Sound_Rewind(Sound_Sample *sample);
+
+
+/**
+ * \fn int Sound_Seek(Sound_Sample *sample, Uint32 ms)
+ * \brief Seek to a different point in a sample.
+ *
+ * Reposition a sample's stream. If successful, the next call to
+ * Sound_Decode[All]() will give audio data from the offset you
+ * specified.
+ *
+ * The offset is specified in milliseconds from the start of the
+ * sample.
+ *
+ * Beware that this function can fail for several reasons. If the
+ * SDL_RWops that feeds the decoder can not seek, this call will almost
+ * certainly fail, but this can theoretically be avoided by wrapping it
+ * in some sort of buffering SDL_RWops. Some decoders can never seek,
+ * others can only seek with certain files. The decoders will set a flag
+ * in the sample at creation time to help you determine this.
+ *
+ * You should check sample->flags & SOUND_SAMPLEFLAG_CANSEEK
+ * before attempting. Sound_Seek() reports failure immediately if this
+ * flag isn't set. This function can still fail for other reasons if the
+ * flag is set.
+ *
+ * This function can be emulated in the application with Sound_Rewind()
+ * and predecoding a specific amount of the sample, but this can be
+ * extremely inefficient. Sound_Seek() accelerates the seek on a
+ * with decoder-specific code.
+ *
+ * If this function fails, the sample should continue to function as if
+ * this call was never made. If there was an unrecoverable error,
+ * sample->flags & SOUND_SAMPLEFLAG_ERROR will be set, which you regular
+ * decoding loop can pick up.
+ *
+ * On success, ERROR, EOF, and EAGAIN are cleared from sample->flags.
+ *
+ * \param sample The Sound_Sample to seek.
+ * \param ms The new position, in milliseconds from start of sample.
+ * \return nonzero on success, zero on error. Specifics of the
+ * error can be gleaned from Sound_GetError().
+ *
+ * \sa Sound_Rewind
+ */
+SNDDECLSPEC int SDLCALL Sound_Seek(Sound_Sample *sample, Uint32 ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined _INCLUDE_SDL_SOUND_H_ */
+
+/* end of SDL_sound.h ... */
+
diff --git a/util/sdl/sound/SDL_sound_internal.h b/util/sdl/sound/SDL_sound_internal.h
new file mode 100644
index 00000000..d467fc8d
--- /dev/null
+++ b/util/sdl/sound/SDL_sound_internal.h
@@ -0,0 +1,326 @@
+/*
+ * 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 COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.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"
+
+/* SDL 1.2.4 defines this, but better safe than sorry. */
+#if (!defined(__inline__))
+# define __inline__
+#endif
+
+#if (defined DEBUG_CHATTER)
+#define SNDDBG(x) printf x
+#else
+#define SNDDBG(x)
+#endif
+
+#if HAVE_ASSERT_H
+# include <assert.h>
+#endif
+
+#ifdef _WIN32_WCE
+ extern char *strrchr(const char *s, int c);
+# ifdef NDEBUG
+# define assert(x)
+# else
+# define assert(x) if(!x) { fprintf(stderr,"Assertion failed in %s, line %s.\n",__FILE__,__LINE__); fclose(stderr); fclose(stdout); exit(1); }
+# endif
+#endif
+
+
+#if (!defined assert) /* if all else fails. */
+# define assert(x)
+#endif
+
+
+typedef struct __SOUND_DECODERFUNCTIONS__
+{
+ /* This is a block of info about your decoder. See SDL_sound.h. */
+ const Sound_DecoderInfo info;
+
+ /*
+ * This is called during the Sound_Init() function. Use this to
+ * set up any global state that your decoder needs, such as
+ * initializing an external library, etc.
+ *
+ * Return non-zero if initialization is successful, zero if there's
+ * a fatal error. If this method fails, then this decoder is
+ * flagged as unavailable until SDL_sound() is shut down and
+ * reinitialized, in which case this method will be tried again.
+ *
+ * Note that the decoders quit() method won't be called if this
+ * method fails, so if you can't intialize, you'll have to clean
+ * up the half-initialized state in this method.
+ */
+ int (*init)(void);
+
+ /*
+ * This is called during the Sound_Quit() function. Use this to
+ * clean up any global state that your decoder has used during its
+ * lifespan.
+ */
+ void (*quit)(void);
+
+ /*
+ * 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)
+ * Sound_AudioCVT sdlcvt; (offlimits)
+ * void *buffer; (offlimits until read() method)
+ * Uint32 buffer_size; (offlimits until read() method)
+ * void *decoder_private; (read and write access)
+ *
+ * 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.
+ */
+ Uint32 (*read)(Sound_Sample *sample);
+
+ /*
+ * Reset the decoding to the beginning of the stream. Nonzero on
+ * success, zero on failure.
+ *
+ * The purpose of this method is to allow for higher efficiency than
+ * an application could get by just recreating the sample externally;
+ * not only do they not have to reopen the RWops, reallocate buffers,
+ * and potentially pass the data through several rejecting decoders,
+ * but certain decoders will not have to recreate their existing
+ * state (search for metadata, etc) since they already know they
+ * have a valid audio stream with a given set of characteristics.
+ *
+ * The decoder is responsible for calling seek() on the associated
+ * SDL_RWops. A failing call to seek() should be the ONLY reason that
+ * this method should ever fail!
+ */
+ int (*rewind)(Sound_Sample *sample);
+
+ /*
+ * Reposition the decoding to an arbitrary point. Nonzero on
+ * success, zero on failure.
+ *
+ * The purpose of this method is to allow for higher efficiency than
+ * an application could get by just rewinding the sample and
+ * decoding to a given point.
+ *
+ * The decoder is responsible for calling seek() on the associated
+ * SDL_RWops.
+ *
+ * If there is an error, try to recover so that the next read will
+ * continue as if nothing happened.
+ */
+ int (*seek)(Sound_Sample *sample, Uint32 ms);
+} Sound_DecoderFunctions;
+
+
+/* A structure to hold a set of audio conversion filters and buffers */
+#if (defined SOUND_USE_ALTCVT)
+#include "alt_audio_convert.h"
+#else
+typedef struct Sound_AudioCVT
+{
+ int needed; /* Set to 1 if conversion possible */
+ Uint16 src_format; /* Source audio format */
+ Uint16 dst_format; /* Target audio format */
+ double rate_incr; /* Rate conversion increment */
+ Uint8 *buf; /* Buffer to hold entire audio data */
+ int len; /* Length of original audio buffer */
+ int len_cvt; /* Length of converted audio buffer */
+ int len_mult; /* buffer must be len*len_mult big */
+ double len_ratio; /* Given len, final size is len*len_ratio */
+ void (*filters[20])(struct Sound_AudioCVT *cvt, Uint16 *format);
+ int filter_index; /* Current audio conversion function */
+} Sound_AudioCVT;
+#endif
+
+extern SNDDECLSPEC int Sound_BuildAudioCVT(Sound_AudioCVT *cvt,
+ Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
+ Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate,
+ Uint32 dst_size);
+
+extern SNDDECLSPEC int Sound_ConvertAudio(Sound_AudioCVT *cvt);
+
+
+
+typedef struct __SOUND_SAMPLEINTERNAL__
+{
+ Sound_Sample *next;
+ Sound_Sample *prev;
+ SDL_RWops *rw;
+ const Sound_DecoderFunctions *funcs;
+ Sound_AudioCVT sdlcvt;
+ void *buffer;
+ Uint32 buffer_size;
+ void *decoder_private;
+} 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"
+#define ERR_CANNOT_SEEK "Sample is not seekable"
+
+/*
+ * 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);
+
+/*
+ * Call this to convert milliseconds to an actual byte position, based on
+ * audio data characteristics.
+ */
+Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms);
+
+/*
+ * 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 ... */
+
diff --git a/util/sdl/sound/TODO b/util/sdl/sound/TODO
new file mode 100644
index 00000000..99a13c01
--- /dev/null
+++ b/util/sdl/sound/TODO
@@ -0,0 +1,29 @@
+More immediate:
+- Fix the crappy rewind implementation in shn.c's SHN_rewind().
+- Finish implementing seek() method in decoders, see below.
+- Add a sdlsound-config script?
+- Make sure we can build shared libs on Cygwin, BeOS, Mac OS X...
+
+Decoders still needing seek() method:
+ (If decoder can't seek, clean up the stub and report an error.)
+- mikmod.c
+- shn.c
+- mpglib.c
+- quicktime.c
+
+General stuff TODO:
+- Hack on the experimental audio conversion routines.
+- Handle compression and other chunks in WAV files.
+- Handle compression and other chunks in AIFF-C files.
+
+Quicktime stuff that'd be cool, but isn't crucial:
+- Integrate decoders/quicktime.c with build system (for OS X)?
+- Make decoders/quicktime.c more robust.
+- Make decoders/quicktime.c work on win32?
+- There's no seek() method.
+
+Ongoing:
+- look for "FIXME"s in the code.
+
+/* end of TODO ... */
+
diff --git a/util/sdl/sound/acinclude.m4 b/util/sdl/sound/acinclude.m4
new file mode 100644
index 00000000..99f8af36
--- /dev/null
+++ b/util/sdl/sound/acinclude.m4
@@ -0,0 +1,173 @@
+dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
+dnl
+AC_DEFUN([AM_PATH_SDL],
+[dnl
+dnl Get the cflags and libraries from the sdl-config script
+dnl
+AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)],
+ sdl_prefix="$withval", sdl_prefix="")
+AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
+ sdl_exec_prefix="$withval", sdl_exec_prefix="")
+AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and run a test SDL program],
+ , enable_sdltest=yes)
+
+ if test x$sdl_exec_prefix != x ; then
+ sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+ if test x${SDL_CONFIG+set} != xset ; then
+ SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+ fi
+ fi
+ if test x$sdl_prefix != x ; then
+ sdl_args="$sdl_args --prefix=$sdl_prefix"
+ if test x${SDL_CONFIG+set} != xset ; then
+ SDL_CONFIG=$sdl_prefix/bin/sdl-config
+ fi
+ fi
+
+ AC_REQUIRE([AC_CANONICAL_TARGET])
+ PATH="$prefix/bin:$prefix/usr/bin:$PATH"
+ AC_PATH_PROG(SDL_CONFIG, sdl-config, no, [$PATH])
+ min_sdl_version=ifelse([$1], ,0.11.0,$1)
+ AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
+ no_sdl=""
+ if test "$SDL_CONFIG" = "no" ; then
+ no_sdl=yes
+ else
+ SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+ SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+
+ sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x$enable_sdltest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SDL is sufficiently new. (Also sanity
+dnl checks the results of sdl-config to some extent
+dnl
+ rm -f conf.sdltest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+ char *new_str;
+
+ if (str)
+ {
+ new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+ strcpy (new_str, str);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ /* This hangs on some systems (?)
+ system ("touch conf.sdltest");
+ */
+ { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = my_strdup("$min_sdl_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_sdl_version");
+ exit(1);
+ }
+
+ if (($sdl_major_version > major) ||
+ (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+ (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+ printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+ printf("*** best to upgrade to the required version.\n");
+ printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+ printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+ printf("*** config.cache before re-running configure\n");
+ return 1;
+ }
+}
+
+],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ if test "x$no_sdl" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$SDL_CONFIG" = "no" ; then
+ echo "*** The sdl-config script installed by SDL could not be found"
+ echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the SDL_CONFIG environment variable to the"
+ echo "*** full path to sdl-config."
+ else
+ if test -f conf.sdltest ; then
+ :
+ else
+ echo "*** Could not run SDL test program, checking why..."
+ CFLAGS="$CFLAGS $SDL_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $SDL_CFLAGS"
+ LIBS="$LIBS $SDL_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include "SDL.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef main
+#define main K_and_R_C_main
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding SDL or finding the wrong"
+ echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+ echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+ echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ SDL_CFLAGS=""
+ SDL_CXXFLAGS=""
+ SDL_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(SDL_CFLAGS)
+ AC_SUBST(SDL_LIBS)
+ rm -f conf.sdltest
+])
diff --git a/util/sdl/sound/alt_audio_convert.c b/util/sdl/sound/alt_audio_convert.c
new file mode 100644
index 00000000..de9b8fd2
--- /dev/null
+++ b/util/sdl/sound/alt_audio_convert.c
@@ -0,0 +1,1057 @@
+/*
+ * Extended Audio Converter for SDL (Simple DirectMedia Layer)
+ * Copyright (C) 2002 Frank Ranostaj
+ * Institute of Applied Physik
+ * Johann Wolfgang Goethe-Universität
+ * Frankfurt am Main, Germany
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Frank Ranostaj
+ * ranostaj@stud.uni-frankfurt.de
+ *
+ * (This code blatantly abducted for SDL_sound. Thanks, Frank! --ryan.)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if SOUND_USE_ALTCVT
+
+#include "alt_audio_convert.h"
+#include <math.h>
+
+/* just to make sure this is defined... */
+
+#ifndef min
+#define min(x, y) ( ((x) < (y)) ? (x) : (y) )
+#endif
+
+#ifndef max
+#define max(x, y) ( ((x) > (y)) ? (x) : (y) )
+#endif
+
+#ifndef abs
+#define abs(x) ( ((x) > (0)) ? (x) : -(x) )
+#endif
+
+
+/* some macros for "parsing" format */
+
+#define IS_8BIT(x) ((x).format & 0x0008)
+#define IS_16BIT(x) ((x).format & 0x0010)
+#define IS_FLOAT(x) ((x).format & 0x0020)
+#define IS_SIGNED(x) ((x).format & 0x8000)
+#define IS_SYSENDIAN(x) ((~AUDIO_U16SYS ^ (x).format) & 0x1000)
+#define SDL_MSB_POSITION_IN_SHORT ((0x1000 & AUDIO_U16SYS)>>12)
+
+
+/*-------------------------------------------------------------------------*/
+/* the purpose of the RateConverterBuffer is to provide a continous storage
+ for head and tail of the (sample)-buffer. This allows a simple and
+ perfomant implemantation of the sample rate converters. Depending of the
+ operation mode, two layouts for the RateConverterBuffer.inbuffer are
+ possible:
+
+ in the Loop Mode:
+ ... T-4 T-3 T-2 T-1 H+0 H+1 H+2 H+3 H+4 ...
+ |
+ linp, finp
+
+ in the Single Mode (non Loop):
+ ... T-4 T-3 T-2 T-1 0 0 0 ... 0 0 0 H+0 H+1 H+2 H+3 H+4 ...
+ | |
+ linp finp
+
+ The RateConverterBuffer allows an accurate attack and decay of the
+ filters in the rate Converters.
+
+ The pointer finp are actually shifted against the depicted position so
+ that on the first invocation of the rate converter the input of the
+ filter is nearly complete in the zero region, only one input value is
+ used. After the calculation of the first output value, the pointer are
+ incremented or decremented depending on down or up conversion and the
+ first two input value are taken into account. This procedure repeats
+ until the filter has processed all zeroes. The distance of the pointer
+ movement is stored in flength, always positive.
+
+ Further a pointer cinp to the sample buffer itself is stored. The pointer
+ to the sample buffer is shifted too, so that on the first use of this
+ pointer the filter is complete in the sample buffer. The pointer moves
+ over the sample buffer until it reaches the other end. The distance of
+ the movement is stored in clength.
+
+ Finally the decay of the filter is done by linp and llength like finp,
+ flength, but in reverse order.
+
+ buffer denotes the start or the end of the output buffer, depending
+ on direction of the rate conversion.
+
+ All pointer and length referring the buffer as Sint16. All length
+ are refering to the input buffer */
+
+typedef struct
+{
+ Sint16 inbuffer[24*_fsize];
+ Sint16 *finp, *cinp, *linp;
+ int flength, clength, llength;
+ Sint16 *buffer;
+ VarFilter *filter;
+} RateConverterBuffer;
+
+typedef struct
+{
+ Sint16 carry;
+ Sint16 pos;
+} RateAux;
+
+
+/* Mono (1 channel ) */
+#define Suffix(x) x##1
+#include "filter_templates.h"
+#undef Suffix
+
+/* Stereo (2 channel ) */
+#define Suffix(x) x##2
+#include "filter_templates.h"
+#undef Suffix
+
+
+/*-------------------------------------------------------------------------*/
+int Sound_estimateBufferSize( Sound_AudioCVT *Data, int size )
+{
+ size *= Data->len_mult;
+ size += Data->len_add;
+ return ( size + 3 ) & -4; /* force Size in multipels of 4 Byte */
+}
+
+/*-------------------------------------------------------------------------*/
+int Sound_AltConvertAudio( Sound_AudioCVT *Data,
+ Uint8* buffer, int length, int mode )
+{
+ AdapterC Temp;
+ int i;
+
+ /* Make sure there's a converter */
+ if( Data == NULL ) {
+ SDL_SetError("No converter given");
+ return(-1);
+ }
+
+ /* Make sure there's data to convert */
+ if( buffer == NULL ) {
+ SDL_SetError("No buffer allocated for conversion");
+ return(-1);
+ }
+
+ if( length < 0 ) {
+ SDL_SetError("Lenght < 0");
+ return(-1);
+ }
+
+ /* Set up the conversion and go! */
+ Temp.buffer = buffer;
+ Temp.mode = mode;
+ Temp.filter = &Data->filter;
+
+ for( i = 0; Data->adapter[i] != NULL; i++ )
+ length = (*Data->adapter[i])( Temp, length);
+
+ return length;
+}
+
+int Sound_ConvertAudio( Sound_AudioCVT *Data )
+{
+ int length;
+ /* !!! FIXME: Try the looping stuff under certain circumstances? --ryan. */
+ length = Sound_AltConvertAudio( Data, Data->buf, Data->len, 0 );
+ Data->len_cvt = length;
+ return length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int expand8BitTo16BitSys( AdapterC Data, int length )
+{
+ int i;
+ Uint8* inp = Data.buffer - 1;
+ Uint16* buffer = (Uint16*)Data.buffer - 1;
+ for( i = length + 1; --i; )
+ buffer[i] = inp[i]<<8;
+ return 2*length;
+}
+
+static int expand8BitTo16BitWrong( AdapterC Data, int length )
+{
+ int i;
+ Uint8* inp = Data.buffer - 1;
+ Uint16* buffer = (Uint16*)Data.buffer - 1;
+ for( i = length + 1; --i; )
+ buffer[i] = inp[i];
+ return 2*length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int expand16BitToFloat( AdapterC Data, int length )
+{
+ int i;
+ Sint16* inp = (Sint16*)Data.buffer - 1;
+ float* buffer = (float*)Data.buffer - 1;
+ for( i = length>>1 + 1; --i; )
+ buffer[i] = inp[i]*(1./32767);
+ return 2*length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int swapBytes( AdapterC Data, int length )
+{
+ /*
+ * !!! FIXME !!!
+ *
+ *
+ * Use the faster SDL-Macros to swap
+ * - Frank
+ */
+
+ int i;
+ Uint16 a,b;
+ Uint16* buffer = (Uint16*) Data.buffer - 1;
+ for( i = length>>1 + 1; --i; )
+ {
+ a = b = buffer[i];
+ buffer[i] = ( a << 8 ) | ( b >> 8 );
+ }
+ return length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int cutFloatTo16Bit( AdapterC Data, int length )
+{
+ int i;
+ float* inp = (float*) Data.buffer;
+ Sint16* buffer = (Sint16*) Data.buffer;
+ length>>=2;
+ for( i = 0; i < length; i++ )
+ {
+ if( inp[i] > 1. )
+ buffer[i] = 32767;
+ else if( inp[i] < -1. )
+ buffer[i] = -32768;
+ else
+ buffer[i] = 32767 * inp[i];
+ }
+ return 2*length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int cut16BitTo8Bit( AdapterC Data, int length, int off )
+{
+ int i;
+ Uint8* inp = Data.buffer + off;
+ Uint8* buffer = Data.buffer;
+ length >>= 1;
+ for( i = 0; i < length; i++ )
+ buffer[i] = inp[2*i];
+ return length;
+}
+
+static int cut16BitSysTo8Bit( AdapterC Data, int length )
+{
+ return cut16BitTo8Bit( Data, length, SDL_MSB_POSITION_IN_SHORT );
+}
+
+static int cut16BitWrongTo8Bit( AdapterC Data, int length )
+{
+ return cut16BitTo8Bit( Data, length, 1-SDL_MSB_POSITION_IN_SHORT );
+}
+
+/*-------------------------------------------------------------------------*/
+/* poor mans mmx :-) */
+static int changeSigned( AdapterC Data, int length, Uint32 XOR )
+{
+ int i;
+ Uint32* buffer = (Uint32*) Data.buffer - 1;
+ for( i = ( length + 7 ) >> 2; --i; )
+ buffer[i] ^= XOR;
+ return length;
+}
+
+static int changeSigned16BitSys( AdapterC Data, int length )
+{
+ return changeSigned( Data, length, 0x80008000 );
+}
+
+static int changeSigned16BitWrong( AdapterC Data, int length )
+{
+ return changeSigned( Data, length, 0x00800080 );
+}
+
+static int changeSigned8Bit( AdapterC Data, int length )
+{
+ return changeSigned( Data, length, 0x80808080 );
+}
+
+/*-------------------------------------------------------------------------*/
+static int convertStereoToMonoS16Bit( AdapterC Data, int length )
+{
+ int i;
+ Sint16* buffer = (Sint16*) Data.buffer;
+ Sint16* src = (Sint16*) Data.buffer;
+ length >>= 2;
+ for( i = 0; i < length; i++, src+=2 )
+ buffer[i] = ((int) src[0] + src[1] ) >> 1;
+ return 2*length;
+}
+
+static int convertStereoToMonoU16Bit( AdapterC Data, int length )
+{
+ int i;
+ Uint16* buffer = (Uint16*) Data.buffer;
+ Uint16* src = (Uint16*) Data.buffer;
+ length >>= 2;
+ for( i = 0; i < length; i++, src+=2 )
+ buffer[i] = ((int) src[0] + src[1] ) >> 1;
+ return 2*length;
+}
+
+static int convertStereoToMonoS8Bit( AdapterC Data, int length )
+{
+ int i;
+ Sint8* buffer = (Sint8*) Data.buffer;
+ Sint8* src = (Sint8*) Data.buffer;
+ length >>= 1;
+ for( i = 0; i < length; i++, src+=2 )
+ buffer[i] = ((int) src[0] + src[1] ) >> 1;
+ return length;
+}
+
+static int convertStereoToMonoU8Bit( AdapterC Data, int length )
+{
+ int i;
+ Uint8* buffer = (Uint8*) Data.buffer;
+ Uint8* src = (Uint8*) Data.buffer;
+ length >>= 1;
+ for( i = 0; i < length; i++, src+=2 )
+ buffer[i] = ((int) src[0] + src[1] ) >> 1;
+ return length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int convertMonoToStereo16Bit( AdapterC Data, int length )
+{
+ int i;
+ Uint16* buffer;
+ Uint16* dst;
+
+ length >>=1;
+ buffer = (Uint16*)Data.buffer - 1;
+ dst = (Uint16*)Data.buffer + 2*length - 2;
+ for( i = length + 1; --i; dst-=2 )
+ dst[0] = dst[1] = buffer[i];
+ return 4*length;
+}
+
+static int convertMonoToStereo8Bit( AdapterC Data, int length )
+{
+ int i;
+ Uint8* buffer = Data.buffer - 1;
+ Uint8* dst = Data.buffer + 2*length - 2;
+ for( i = length + 1; --i; dst-=2 )
+ dst[0] = dst[1] = buffer[i];
+ return 2*length;
+}
+
+/*-------------------------------------------------------------------------*/
+static int minus5dB( AdapterC Data, int length )
+{
+ int i;
+ Sint16* buffer = (Sint16*) Data.buffer;
+ for(i = length>>1 + 1; --i; )
+ buffer[i] = (38084 * (int)buffer[i]) >> 16;
+ return length;
+}
+
+/*-------------------------------------------------------------------------*/
+const Fraction Half = {1, 2};
+const Fraction Double = {2, 1};
+const Fraction One = {1, 1};
+
+
+static void initStraigthBuffer( RateConverterBuffer *rcb,
+ int length, Fraction r )
+{
+ int i, size, minsize;
+ size = 8 * _fsize;
+ minsize = min( size, length );
+
+ for( i = 0; i < minsize; i++ )
+ {
+ rcb->inbuffer[i] = rcb->buffer[length-size+i];
+ rcb->inbuffer[i+size] = 0;
+ rcb->inbuffer[i+2*size] = rcb->buffer[i];
+ }
+ for( ; i < size; i++ )
+ {
+ rcb->inbuffer[i] = 0;
+ rcb->inbuffer[i+size] = 0;
+ rcb->inbuffer[i+2*size] = 0;
+ }
+
+ length = max( length, size );
+ rcb->flength = rcb->llength = size;
+ rcb->clength = length - size;
+
+ if( r.numerator < r.denominator )
+ {
+ rcb->finp = rcb->inbuffer + 5*size/2;
+ rcb->cinp = rcb->buffer + length - size/2;
+ rcb->linp = rcb->inbuffer + 3*size/2;
+ rcb->buffer += ( 1 + r.denominator * ( length + size )
+ / r.numerator ) & -2;
+ }
+ else
+ {
+ rcb->finp = rcb->inbuffer + size/2;
+ rcb->cinp = rcb->buffer + size/2;
+ rcb->linp = rcb->inbuffer + 3*size/2;
+ }
+}
+
+static void initLoopBuffer( RateConverterBuffer *rcb,
+ int length, Fraction r )
+{
+ /* !!!FIXME: modulo length, take scale into account,
+ check against the Straight part -frank */
+ int i, size;
+ size = 8 * _fsize;
+ for( i = 0; i < size; i++ )
+ {
+ rcb->inbuffer[i] = rcb->buffer[length-size+i];
+ rcb->inbuffer[i+size] = rcb->buffer[i];
+ }
+ rcb->finp = rcb->linp = rcb->inbuffer + size;
+ if( size < 0 )
+ rcb->buffer += r.numerator * ( length + 2 * size )
+ / r.denominator;
+}
+
+static void initRateConverterBuffer( RateConverterBuffer *rcb,
+ AdapterC* Data, int length, Fraction ratio )
+{
+ length >>= 1;
+ rcb->buffer = (Sint16*)( Data->buffer );
+ rcb->filter = Data->filter;
+
+ if( Data->mode & SDL_SOUND_Loop )
+ initLoopBuffer( rcb, length, ratio );
+ else
+ initStraigthBuffer( rcb, length, ratio );
+
+ fprintf( stderr, " finp: %8x length: %8x\n", rcb->finp, rcb->flength );
+ fprintf( stderr, " cinp: %8x length: %8x\n", rcb->cinp, rcb->clength );
+ fprintf( stderr, " linp: %8x length: %8x\n", rcb->linp, rcb->llength );
+}
+
+static void nextRateConverterBuffer( RateConverterBuffer *rcb )
+{
+ rcb->buffer++;
+ rcb->finp++;
+ rcb->cinp++;
+ rcb->linp++;
+}
+
+typedef Sint16* (*RateConverter)( Sint16*, Sint16*, int,
+ VarFilter*, RateAux* );
+
+static Sint16* doRateConversion( RateConverterBuffer* rcb, RateConverter rc )
+{
+ RateAux aux = {0,0};
+ Sint16 *outp = rcb->buffer;
+ VarFilter* filter = rcb->filter;
+
+ outp = (*rc)( outp, rcb->finp, rcb->flength, filter, &aux );
+ fprintf( stderr, " outp: %8x aux.carry: %8x\n", outp, aux.carry );
+ outp = (*rc)( outp, rcb->cinp, rcb->clength, filter, &aux );
+ fprintf( stderr, " outp: %8x aux.carry: %8x\n", outp, aux.carry );
+ outp = (*rc)( outp, rcb->linp, rcb->llength, filter, &aux );
+ fprintf( stderr, " outp: %8x aux.carry: %8x\n", outp, aux.carry );
+ return outp;
+}
+
+
+/*-------------------------------------------------------------------------*/
+static void clearSint16Buffer( Sint8* buffer, Sint16*r )
+{
+ while( r >= (Sint16*)buffer ) *r-- = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static int doubleRateMono( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ initRateConverterBuffer( &rcb, &Data, length, Half );
+ r = 1 + doRateConversion( &rcb, doubleRate1 );
+ clearSint16Buffer( Data.buffer, r );
+ return 2 * ( rcb.buffer - (Sint16*)Data.buffer + 2 );
+}
+
+static int doubleRateStereo( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ fprintf( stderr, "\n Buffer: %8x length: %8x\n", Data.buffer, length );
+ initRateConverterBuffer( &rcb, &Data, length, Half );
+ doRateConversion( &rcb, doubleRate2 );
+ nextRateConverterBuffer( &rcb );
+ r = 2 + doRateConversion( &rcb, doubleRate2 );
+ clearSint16Buffer( Data.buffer, r );
+ return 2 * ( rcb.buffer - (Sint16*)Data.buffer + 3 );
+}
+
+/*-------------------------------------------------------------------------*/
+static int halfRateMono( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ initRateConverterBuffer( &rcb, &Data, length, Double );
+ r = doRateConversion( &rcb, halfRate1 );
+ return 2 * ( r - (Sint16*)Data.buffer );
+}
+
+static int halfRateStereo( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ initRateConverterBuffer( &rcb, &Data, length, Double );
+ doRateConversion( &rcb, halfRate2 );
+ nextRateConverterBuffer( &rcb );
+ r = doRateConversion( &rcb, halfRate2 );
+ return 2 * ( r - (Sint16*)Data.buffer );
+}
+
+/*-------------------------------------------------------------------------*/
+static int increaseRateMono( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ initRateConverterBuffer( &rcb, &Data, length, Data.filter->ratio );
+ r = doRateConversion( &rcb, increaseRate1 );
+ clearSint16Buffer( Data.buffer, r );
+ return 2 * ( rcb.buffer - (Sint16*)Data.buffer + 1 );
+}
+
+static int increaseRateStereo( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ fprintf( stderr, "\n Buffer: %8x length: %8x\n", Data.buffer, length );
+ initRateConverterBuffer( &rcb, &Data, length, Data.filter->ratio );
+ doRateConversion( &rcb, increaseRate2 );
+ nextRateConverterBuffer( &rcb );
+ r = doRateConversion( &rcb, increaseRate2 );
+ clearSint16Buffer( Data.buffer, r );
+ return 2 * ( rcb.buffer - (Sint16*)Data.buffer + 1 );
+}
+
+/*-------------------------------------------------------------------------*/
+static int decreaseRateMono( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ initRateConverterBuffer( &rcb, &Data, length, Data.filter->ratio );
+ r = doRateConversion( &rcb, decreaseRate1 );
+ return 2 * ( r - (Sint16*)Data.buffer );
+}
+
+static int decreaseRateStereo( AdapterC Data, int length )
+{
+ Sint16* r;
+ RateConverterBuffer rcb;
+ initRateConverterBuffer( &rcb, &Data, length, Data.filter->ratio );
+ doRateConversion( &rcb, decreaseRate2 );
+ nextRateConverterBuffer( &rcb );
+ r = doRateConversion( &rcb, decreaseRate2 );
+ return 2 * ( r - (Sint16*)Data.buffer );
+}
+
+/*-------------------------------------------------------------------------*/
+/* gives a maximal error of 3% and typical less than 0.2% */
+static Fraction findFraction( float Value )
+{
+ const Sint8 frac[95]={
+ 2, -1, /* /1 */
+ 1, 3, -1, /* /2 */
+ 2, 4, 5, -1, /* /3 */
+ 3, 5, 7, -1, /* /4 */
+ 3, 4, 6, 7, 8, 9, -1, /* /5 */
+ 5, 7, 11, -1, /* /6 */
+ 4, 5, 6, 8, 9, 10, 11, 12, 13, -1, /* /7 */
+ 5, 7, 9, 11, 13, 15, -1, /* /8 */
+ 5, 7, 8, 10, 11, 13, 14, 16, -1, /* /9 */
+ 7, 9, 11, 13, -1, /* /10 */
+ 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, -1, /* /11 */
+ 7, 11, 13, -1, /* /12 */
+ 7, 8, 9, 10, 11, 12, 14, 15, 16, -1, /* /13 */
+ 9, 11, 13, 15, -1, /* /14 */
+ 8, 11, 13, 14, 16, -1, /* /15 */
+ 9, 11, 13, 15 }; /* /16 */
+
+
+ Fraction Result = {0,0};
+ int i,num,den=1;
+
+ float RelErr, BestErr = 0;
+ if( Value < 31/64. || Value > 64/31. ) return Result;
+
+ for( i = 0; i < SDL_TABLESIZE(frac); i++ )
+ {
+ num = frac[i];
+ if( num < 0 ) den++;
+ RelErr = Value * num / den;
+ RelErr = min( RelErr, 1/RelErr );
+ if( RelErr > BestErr )
+ {
+ BestErr = RelErr;
+ Result.denominator = den;
+ Result.numerator = num;
+ }
+ }
+ return Result;
+}
+
+/*-------------------------------------------------------------------------*/
+static float sinc( float x )
+{
+ if( x > -1e-24 && x < 1e-24 ) return 1.;
+ else return sin(x)/x;
+}
+
+static float calculateVarFilter( Sint16* dst,
+ float Ratio, float phase, float scale )
+{
+ const Uint16 KaiserWindow7[]= {
+ 22930, 16292, 14648, 14288, 14470, 14945, 15608, 16404,
+ 17304, 18289, 19347, 20467, 21644, 22872, 24145, 25460,
+ 26812, 28198, 29612, 31052, 32513, 33991, 35482, 36983,
+ 38487, 39993, 41494, 42986, 44466, 45928, 47368, 48782,
+ 50165, 51513, 52821, 54086, 55302, 56466, 57575, 58624,
+ 59610, 60529, 61379, 62156, 62858, 63483, 64027, 64490,
+ 64870, 65165, 65375, 65498, 65535, 65484, 65347, 65124,
+ 64815, 64422, 63946, 63389, 62753, 62039, 61251, 60391 };
+ int i;
+ float w;
+ const float fg = -.018 + .5 * Ratio;
+ const float omega = 2 * M_PI * fg;
+ fprintf( stderr, " phase: %6g \n", phase );
+ phase += 63;
+ for( i = 0; i < 64; i++)
+ {
+ w = scale * ( KaiserWindow7[i] * ( i + 1 ));
+ dst[i] = w * sinc( omega * (i-phase) );
+ dst[127-i] = w * sinc( omega * (127-i-phase) );
+ }
+ fprintf( stderr, " center: %6d %6d \n", dst[63], dst[64] );
+ return fg;
+}
+
+static Fraction setupVarFilter( Sound_AudioCVT *Data, float Ratio )
+{
+ int pos,n,d, incr, phase = 0;
+ float Scale, rd, fg;
+ Fraction IRatio;
+ VarFilter* filter = &Data->filter;
+
+ IRatio = findFraction( Ratio );
+// Scale = Ratio < 1. ? 0.0364733 : 0.0211952;
+ Scale = 0.0084778;
+ Ratio = min( Ratio, 0.97 );
+
+ filter->ratio = IRatio;
+ n = IRatio.numerator;
+ d = IRatio.denominator;
+ rd = 1. / d;
+
+ fprintf( stderr, "Filter:\n" );
+
+ for( pos = 0; pos < d; pos++ )
+ {
+ fg = calculateVarFilter( filter->c[pos], Ratio, phase*rd, Scale );
+ phase += n;
+ filter->incr[pos] = phase / d;
+ phase %= d;
+ }
+ fprintf( stderr, " fg: %6g\n\n", fg );
+/* !!!FIXME: get rid of the inversion -Frank*/
+ IRatio.numerator = d;
+ IRatio.denominator = n;
+ return IRatio;
+}
+/*-------------------------------------------------------------------------*/
+static void initAudioCVT( Sound_AudioCVT *Data )
+{
+ Data->len_ratio = 1.;
+ Data->len_mult = 1;
+ Data->add = 0;
+ Data->len_add = 0;
+ Data->filter_index = 0;
+}
+
+static void adjustSize( Sound_AudioCVT *Data, int add, Fraction f )
+{
+ double ratio = f.numerator / (double) f.denominator;
+ Data->len_ratio *= ratio;
+ Data->len_mult = max( Data->len_mult, ceil(Data->len_ratio) );
+ Data->add = ratio * (Data->add + add);
+ Data->len_add = max( Data->len_add, ceil(Data->add) );
+}
+
+static Adapter* addAdapter( Sound_AudioCVT *Data, Adapter a )
+{
+ Data->adapter[Data->filter_index] = a;
+ return &Data->adapter[Data->filter_index++];
+}
+
+static void addHAdapter( Sound_AudioCVT *Data, Adapter a )
+{
+ adjustSize( Data, 0, Half );
+ addAdapter( Data, a );
+}
+
+static void addDAdapter( Sound_AudioCVT *Data, Adapter a )
+{
+ adjustSize( Data, 0, Double );
+ addAdapter( Data, a );
+}
+
+
+/*-------------------------------------------------------------------------*/
+const Adapter doubleRate[2] = { doubleRateMono, doubleRateStereo };
+const Adapter halfRate[2] = { halfRateMono, halfRateStereo };
+const Adapter increaseRate[2] = { increaseRateMono, increaseRateStereo };
+const Adapter decreaseRate[2] = { decreaseRateMono, decreaseRateStereo };
+
+static int createRateConverter( Sound_AudioCVT *Data,
+ int SrcRate, int DestRate, int channel )
+{
+ const int c = channel - 1;
+ const int size = 16 * channel * _fsize;
+ Adapter* AdapterPos;
+ float Ratio = DestRate;
+ Fraction f;
+
+ if( SrcRate < 1 || SrcRate > 1<<18 ||
+ DestRate < 1 || DestRate > 1<<18 ) return -1;
+ Ratio /= SrcRate;
+
+ AdapterPos = addAdapter( Data, minus5dB );
+
+ while( Ratio > 64./31.)
+ {
+ Ratio /= 2.;
+ addAdapter( Data, doubleRate[c] );
+ adjustSize( Data, size, Double );
+ }
+
+ while( Ratio < 31./64. )
+ {
+ Ratio *= 2;
+ addAdapter( Data, halfRate[c] );
+ adjustSize( Data, size, Half );
+ }
+
+ if( Ratio > 1. )
+ {
+ *AdapterPos = increaseRate[c];
+ f = setupVarFilter( Data, Ratio );
+ adjustSize( Data, size, f );
+ }
+ else
+ {
+ f = setupVarFilter( Data, Ratio );
+ addAdapter( Data, decreaseRate[c]);
+ adjustSize( Data, size, f );
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static void createFormatConverter16Bit(Sound_AudioCVT *Data,
+ SDL_AudioSpec src, SDL_AudioSpec dst )
+{
+ if( src.channels == 2 && dst.channels == 1 )
+ {
+ if( !IS_SYSENDIAN(src) )
+ addAdapter( Data, swapBytes );
+
+ if( IS_SIGNED(src) )
+ addHAdapter( Data, convertStereoToMonoS16Bit );
+ else
+ addHAdapter( Data, convertStereoToMonoU16Bit );
+
+ if( !IS_SYSENDIAN(dst) )
+ addAdapter( Data, swapBytes );
+ }
+ else if( IS_SYSENDIAN(src) != IS_SYSENDIAN(dst) )
+ addAdapter( Data, swapBytes );
+
+ if( IS_SIGNED(src) != IS_SIGNED(dst) )
+ {
+ if( IS_SYSENDIAN(dst) )
+ addAdapter( Data, changeSigned16BitSys );
+ else
+ addAdapter( Data, changeSigned16BitWrong );
+ }
+
+ if( src.channels == 1 && dst.channels == 2 )
+ addDAdapter( Data, convertMonoToStereo16Bit );
+}
+
+/*-------------------------------------------------------------------------*/
+static void createFormatConverter8Bit(Sound_AudioCVT *Data,
+ SDL_AudioSpec src, SDL_AudioSpec dst )
+{
+ if( IS_16BIT(src) )
+ {
+ if( IS_SYSENDIAN(src) )
+ addHAdapter( Data, cut16BitSysTo8Bit );
+ else
+ addHAdapter( Data, cut16BitWrongTo8Bit );
+ }
+
+ if( src.channels == 2 && dst.channels == 1 )
+ {
+ if( IS_SIGNED(src) )
+ addHAdapter( Data, convertStereoToMonoS8Bit );
+ else
+ addHAdapter( Data, convertStereoToMonoU8Bit );
+ }
+
+ if( IS_SIGNED(src) != IS_SIGNED(dst) )
+ addDAdapter( Data, changeSigned8Bit );
+
+ if( src.channels == 1 && dst.channels == 2 )
+ addDAdapter( Data, convertMonoToStereo8Bit );
+
+ if( !IS_8BIT(dst) )
+ {
+ if( IS_SYSENDIAN(dst) )
+ addDAdapter( Data, expand8BitTo16BitSys );
+ else
+ addDAdapter( Data, expand8BitTo16BitWrong );
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+static void createFormatConverter(Sound_AudioCVT *Data,
+ SDL_AudioSpec src, SDL_AudioSpec dst )
+{
+ if( IS_FLOAT(src) )
+ addHAdapter( Data, cutFloatTo16Bit );
+
+ if( IS_8BIT(src) || IS_8BIT(dst) )
+ createFormatConverter8Bit( Data, src, dst);
+ else
+ createFormatConverter16Bit( Data, src, dst);
+
+ if( IS_FLOAT(dst) )
+ addDAdapter( Data, expand16BitToFloat );
+}
+
+/*-------------------------------------------------------------------------*/
+int Sound_AltBuildAudioCVT( Sound_AudioCVT *Data,
+ SDL_AudioSpec src, SDL_AudioSpec dst )
+{
+ SDL_AudioSpec im;
+
+ if( Data == NULL ) return -1;
+
+ initAudioCVT( Data );
+ Data->filter.ratio.denominator = 0;
+ Data->filter.mask = dst.size - 1;
+
+ /* Check channels */
+ if( src.channels < 1 || src.channels > 2 ||
+ dst.channels < 1 || dst.channels > 2 ) goto error_exit;
+
+ if( src.freq != dst.freq )
+ {
+ /* Convert to intermidiate format: signed 16Bit System-Endian */
+ im.format = AUDIO_S16SYS;
+ im.channels = min( src.channels, dst.channels );
+ createFormatConverter( Data, src, im );
+
+ /* Do rate conversion */
+ if( createRateConverter( Data, src.freq, dst.freq, im.channels ) )
+ goto error_exit;
+
+ src = im;
+ }
+
+ /* Convert to final format */
+ createFormatConverter( Data, src, dst );
+
+ /* Finalize adapter list */
+ addAdapter( Data, NULL );
+/* !!! FIXME: Is it okay to assign NULL to a function pointer?
+ Borland says no. -frank */
+ return 0;
+
+error_exit:
+/* !!! FIXME: Is it okay to assign NULL to a function pointer?
+ Borland says no. -frank */
+ Data->adapter[0] = NULL;
+ return -1;
+}
+
+/*-------------------------------------------------------------------------*/
+static char *fmt_to_str(Uint16 fmt)
+{
+ switch (fmt)
+ {
+ case AUDIO_U8: return " U8";
+ case AUDIO_S8: return " S8";
+ case AUDIO_U16MSB: return "U16MSB";
+ case AUDIO_S16MSB: return "S16MSB";
+ case AUDIO_U16LSB: return "U16LSB";
+ case AUDIO_S16LSB: return "S16LSB";
+ }
+ return "??????";
+}
+
+#define AdapterDesc(x) { x, #x }
+
+static void show_AudioCVT( Sound_AudioCVT *Data )
+{
+ int i,j;
+ const struct{ int (*adapter) ( AdapterC, int); Sint8 *name; }
+ AdapterDescription[] = {
+ AdapterDesc(expand8BitTo16BitSys),
+ AdapterDesc(expand8BitTo16BitWrong),
+ AdapterDesc(expand16BitToFloat),
+ AdapterDesc(swapBytes),
+ AdapterDesc(cut16BitSysTo8Bit),
+ AdapterDesc(cut16BitWrongTo8Bit),
+ AdapterDesc(cutFloatTo16Bit),
+ AdapterDesc(changeSigned16BitSys),
+ AdapterDesc(changeSigned16BitWrong),
+ AdapterDesc(changeSigned8Bit),
+ AdapterDesc(convertStereoToMonoS16Bit),
+ AdapterDesc(convertStereoToMonoU16Bit),
+ AdapterDesc(convertStereoToMonoS8Bit),
+ AdapterDesc(convertStereoToMonoU8Bit),
+ AdapterDesc(convertMonoToStereo16Bit),
+ AdapterDesc(convertMonoToStereo8Bit),
+ AdapterDesc(minus5dB),
+ AdapterDesc(doubleRateMono),
+ AdapterDesc(doubleRateStereo),
+ AdapterDesc(halfRateMono),
+ AdapterDesc(halfRateStereo),
+ AdapterDesc(increaseRateMono),
+ AdapterDesc(increaseRateStereo),
+ AdapterDesc(decreaseRateMono),
+ AdapterDesc(decreaseRateStereo),
+ { NULL, "----------NULL-----------\n" }
+ };
+
+ fprintf( stderr, "Sound_AudioCVT:\n" );
+ fprintf( stderr, " needed: %8d\n", Data->needed );
+ fprintf( stderr, " add: %8g\n", Data->add );
+ fprintf( stderr, " len_add: %8d\n", Data->len_add );
+ fprintf( stderr, " len_ratio: %8g\n", Data->len_ratio );
+ fprintf( stderr, " len_mult: %8d\n", Data->len_mult );
+ fprintf( stderr, " filter->mask: %#7x\n", Data->filter.mask );
+ fprintf( stderr, "\n" );
+
+ fprintf( stderr, "Adapter List: \n" );
+ for( i = 0; i < 32; i++ )
+ {
+ for( j = 0; j < SDL_TABLESIZE(AdapterDescription); j++ )
+ {
+ if( Data->adapter[i] == AdapterDescription[j].adapter )
+ {
+ fprintf( stderr, " %s \n", AdapterDescription[j].name );
+ if( Data->adapter[i] == NULL ) goto sucess_exit;
+ goto cont;
+ }
+ }
+ fprintf( stderr, " Error: unknown adapter\n" );
+
+ cont:
+ }
+ fprintf( stderr, " Error: NULL adapter missing\n" );
+ sucess_exit:
+ if( Data->filter.ratio.denominator )
+ {
+ fprintf( stderr, "Variable Rate Converter:\n"
+ " numerator: %3d\n"
+ " denominator: %3d\n",
+ Data->filter.ratio.denominator,
+ Data->filter.ratio.numerator );
+
+ fprintf( stderr, " increment sequence:\n"
+ " " );
+ for( i = 0; i < Data->filter.ratio.denominator; i++ )
+ fprintf( stderr, "%1d ", Data->filter.incr[i] );
+
+ fprintf( stderr, "\n" );
+ }
+ else
+ {
+ fprintf( stderr, "No Variable Rate Converter\n" );
+ }
+}
+
+
+int Sound_BuildAudioCVT(Sound_AudioCVT *Data,
+ Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
+ Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate, Uint32 bufsize)
+{
+ SDL_AudioSpec src, dst;
+ int ret;
+
+ fprintf (stderr,
+ "Sound_BuildAudioCVT():\n"
+ "-----------------------------\n"
+ "format: %s -> %s\n"
+ "channels: %6d -> %6d\n"
+ "rate: %6d -> %6d\n"
+ "size: don't care -> %#7x\n\n",
+ fmt_to_str (src_format), fmt_to_str (dst_format),
+ src_channels, dst_channels,
+ src_rate, dst_rate );
+
+ src.format = src_format;
+ src.channels = src_channels;
+ src.freq = src_rate;
+
+ dst.format = dst_format;
+ dst.channels = dst_channels;
+ dst.freq = dst_rate;
+
+ ret = Sound_AltBuildAudioCVT( Data, src, dst );
+ Data->needed = 1;
+
+ show_AudioCVT( Data );
+ fprintf (stderr, "\n"
+ "return value: %d \n\n\n", ret );
+ return ret;
+}
+
+#endif /* SOUND_USE_ALTCVT */
+
+/* end of alt_audio_convert.c ... */
+
diff --git a/util/sdl/sound/alt_audio_convert.h b/util/sdl/sound/alt_audio_convert.h
new file mode 100644
index 00000000..8dd4670e
--- /dev/null
+++ b/util/sdl/sound/alt_audio_convert.h
@@ -0,0 +1,89 @@
+/*
+ * Extended Audio Converter for SDL (Simple DirectMedia Layer)
+ * Copyright (C) 2002 Frank Ranostaj
+ * Institute of Applied Physik
+ * Johann Wolfgang Goethe-Universität
+ * Frankfurt am Main, Germany
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Frank Ranostaj
+ * ranostaj@stud.uni-frankfurt.de
+ *
+ * (This code blatantly abducted for SDL_sound. Thanks, Frank! --ryan.)
+ */
+
+#ifndef _INCLUDE_AUDIO_CONVERT_H_
+#define _INCLUDE_AUDIO_CONVERT_H_
+
+#include "SDL_audio.h"
+#define Sound_AI_Loop 0x2
+#define _fsize 32
+
+typedef struct{
+ Sint16 numerator;
+ Sint16 denominator;
+} Fraction;
+
+typedef struct{
+ Sint16 c[16][4*_fsize];
+ Uint8 incr[16];
+ Fraction ratio;
+ int mask;
+} VarFilter;
+
+typedef struct{
+ Uint8* buffer;
+ int mode;
+ VarFilter *filter;
+} AdapterC;
+
+typedef int (*Adapter) ( AdapterC Data, int length );
+
+typedef struct{
+ VarFilter filter;
+ int filter_index;
+ Adapter adapter[32];
+/* buffer must be len*len_mult(+len_add) big */
+ int len_mult;
+ int len_add;
+ double add;
+
+/* the following elements are provided for compatibility: */
+/* the size of the output is approx len*len_ratio */
+ double len_ratio;
+ Uint8* buf; /* input/output buffer */
+ int needed; /* 0 if nothing to be done, 1 otherwise */
+ int len; /* Length of the input */
+ int len_cvt; /* Length of converted audio buffer */
+} Sound_AudioCVT;
+
+#define SDL_SOUND_Loop 0x10
+
+#ifndef SNDDECLSPEC
+#define SNDDECLSPEC DECLSPEC
+#endif
+
+extern SNDDECLSPEC int Sound_AltConvertAudio( Sound_AudioCVT *Data,
+ Uint8* buffer, int length, int mode );
+
+extern SNDDECLSPEC int Sound_AltBuildAudioCVT( Sound_AudioCVT *Data,
+ SDL_AudioSpec src, SDL_AudioSpec dst );
+
+extern SNDDECLSPEC int Sound_estimateBufferSize( Sound_AudioCVT *Data,
+ int length );
+
+#endif /* _INCLUDE_AUDIO_CONVERT_H_ */
+
diff --git a/util/sdl/sound/audio_convert.c b/util/sdl/sound/audio_convert.c
new file mode 100644
index 00000000..05564dc4
--- /dev/null
+++ b/util/sdl/sound/audio_convert.c
@@ -0,0 +1,739 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Sam Lantinga
+ slouken@devolution.com
+*/
+
+/*
+ * This file was derived from SDL's SDL_audiocvt.c and is an attempt to
+ * address the shortcomings of it.
+ *
+ * Perhaps we can adapt some good filters from SoX?
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !SOUND_USE_ALTCVT
+
+#include "SDL.h"
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+/* Functions for audio drivers to perform runtime conversion of audio format */
+
+
+/*
+ * Toggle endianness. This filter is, of course, only applied to 16-bit
+ * audio data.
+ */
+
+static void Sound_ConvertEndian(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *data, tmp;
+
+ /* SNDDBG(("Converting audio endianness\n")); */
+
+ data = cvt->buf;
+
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ tmp = data[0];
+ data[0] = data[1];
+ data[1] = tmp;
+ data += 2;
+ } /* for */
+
+ *format = (*format ^ 0x1000);
+} /* Sound_ConvertEndian */
+
+
+/*
+ * Toggle signed/unsigned. Apparently this is done by toggling the most
+ * significant bit of each sample.
+ */
+
+static void Sound_ConvertSign(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *data;
+
+ /* SNDDBG(("Converting audio signedness\n")); */
+
+ data = cvt->buf;
+
+ /* 16-bit sound? */
+ if ((*format & 0xFF) == 16)
+ {
+ /* Little-endian? */
+ if ((*format & 0x1000) != 0x1000)
+ ++data;
+
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ *data ^= 0x80;
+ data += 2;
+ } /* for */
+ } /* if */
+ else
+ {
+ for (i = cvt->len_cvt; i; --i)
+ *data++ ^= 0x80;
+ } /* else */
+
+ *format = (*format ^ 0x8000);
+} /* Sound_ConvertSign */
+
+
+/*
+ * Convert 16-bit to 8-bit. This is done by taking the most significant byte
+ * of each 16-bit sample.
+ */
+
+static void Sound_Convert8(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+ /* SNDDBG(("Converting to 8-bit\n")); */
+
+ src = cvt->buf;
+ dst = cvt->buf;
+
+ /* Little-endian? */
+ if ((*format & 0x1000) != 0x1000)
+ ++src;
+
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ *dst = *src;
+ src += 2;
+ dst += 1;
+ } /* for */
+
+ *format = ((*format & ~0x9010) | AUDIO_U8);
+ cvt->len_cvt /= 2;
+} /* Sound_Convert8 */
+
+
+/* Convert 8-bit to 16-bit - LSB */
+
+static void Sound_Convert16LSB(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+ /* SNDDBG(("Converting to 16-bit LSB\n")); */
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 2;
+
+ for (i = cvt->len_cvt; i; --i)
+ {
+ src -= 1;
+ dst -= 2;
+ dst[1] = *src;
+ dst[0] = 0;
+ } /* for */
+
+ *format = ((*format & ~0x0008) | AUDIO_U16LSB);
+ cvt->len_cvt *= 2;
+} /* Sound_Convert16LSB */
+
+
+/* Convert 8-bit to 16-bit - MSB */
+
+static void Sound_Convert16MSB(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+ /* SNDDBG(("Converting to 16-bit MSB\n")); */
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 2;
+
+ for (i = cvt->len_cvt; i; --i)
+ {
+ src -= 1;
+ dst -= 2;
+ dst[0] = *src;
+ dst[1] = 0;
+ } /* for */
+
+ *format = ((*format & ~0x0008) | AUDIO_U16MSB);
+ cvt->len_cvt *= 2;
+} /* Sound_Convert16MSB */
+
+
+/* Duplicate a mono channel to both stereo channels */
+
+static void Sound_ConvertStereo(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+
+ /* SNDDBG(("Converting to stereo\n")); */
+
+ /* 16-bit sound? */
+ if ((*format & 0xFF) == 16)
+ {
+ Uint16 *src, *dst;
+
+ src = (Uint16 *) (cvt->buf + cvt->len_cvt);
+ dst = (Uint16 *) (cvt->buf + cvt->len_cvt * 2);
+
+ for (i = cvt->len_cvt/2; i; --i)
+ {
+ dst -= 2;
+ src -= 1;
+ dst[0] = src[0];
+ dst[1] = src[0];
+ } /* for */
+ } /* if */
+ else
+ {
+ Uint8 *src, *dst;
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt * 2;
+
+ for (i = cvt->len_cvt; i; --i)
+ {
+ dst -= 2;
+ src -= 1;
+ dst[0] = src[0];
+ dst[1] = src[0];
+ } /* for */
+ } /* else */
+
+ cvt->len_cvt *= 2;
+} /* Sound_ConvertStereo */
+
+
+/* Effectively mix right and left channels into a single channel */
+
+static void Sound_ConvertMono(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Sint32 sample;
+ Uint8 *u_src, *u_dst;
+ Sint8 *s_src, *s_dst;
+
+ /* SNDDBG(("Converting to mono\n")); */
+
+ switch (*format)
+ {
+ case AUDIO_U8:
+ u_src = cvt->buf;
+ u_dst = cvt->buf;
+
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ sample = u_src[0] + u_src[1];
+ *u_dst = (sample > 255) ? 255 : sample;
+ u_src += 2;
+ u_dst += 1;
+ } /* for */
+ break;
+
+ case AUDIO_S8:
+ s_src = (Sint8 *) cvt->buf;
+ s_dst = (Sint8 *) cvt->buf;
+
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ sample = s_src[0] + s_src[1];
+ if (sample > 127)
+ *s_dst = 127;
+ else if (sample < -128)
+ *s_dst = -128;
+ else
+ *s_dst = sample;
+
+ s_src += 2;
+ s_dst += 1;
+ } /* for */
+ break;
+
+ case AUDIO_U16MSB:
+ u_src = cvt->buf;
+ u_dst = cvt->buf;
+
+ for (i = cvt->len_cvt / 4; i; --i)
+ {
+ sample = (Uint16) ((u_src[0] << 8) | u_src[1])
+ + (Uint16) ((u_src[2] << 8) | u_src[3]);
+ if (sample > 65535)
+ {
+ u_dst[0] = 0xFF;
+ u_dst[1] = 0xFF;
+ } /* if */
+ else
+ {
+ u_dst[1] = (sample & 0xFF);
+ sample >>= 8;
+ u_dst[0] = (sample & 0xFF);
+ } /* else */
+ u_src += 4;
+ u_dst += 2;
+ } /* for */
+ break;
+
+ case AUDIO_U16LSB:
+ u_src = cvt->buf;
+ u_dst = cvt->buf;
+
+ for (i = cvt->len_cvt / 4; i; --i)
+ {
+ sample = (Uint16) ((u_src[1] << 8) | u_src[0])
+ + (Uint16) ((u_src[3] << 8) | u_src[2]);
+ if (sample > 65535)
+ {
+ u_dst[0] = 0xFF;
+ u_dst[1] = 0xFF;
+ } /* if */
+ else
+ {
+ u_dst[0] = (sample & 0xFF);
+ sample >>= 8;
+ u_dst[1] = (sample & 0xFF);
+ } /* else */
+ u_src += 4;
+ u_dst += 2;
+ } /* for */
+ break;
+
+ case AUDIO_S16MSB:
+ u_src = cvt->buf;
+ u_dst = cvt->buf;
+
+ for (i = cvt->len_cvt / 4; i; --i)
+ {
+ sample = (Sint16) ((u_src[0] << 8) | u_src[1])
+ + (Sint16) ((u_src[2] << 8) | u_src[3]);
+ if (sample > 32767)
+ {
+ u_dst[0] = 0x7F;
+ u_dst[1] = 0xFF;
+ } /* if */
+ else if (sample < -32768)
+ {
+ u_dst[0] = 0x80;
+ u_dst[1] = 0x00;
+ } /* else if */
+ else
+ {
+ u_dst[1] = (sample & 0xFF);
+ sample >>= 8;
+ u_dst[0] = (sample & 0xFF);
+ } /* else */
+ u_src += 4;
+ u_dst += 2;
+ } /* for */
+ break;
+
+ case AUDIO_S16LSB:
+ u_src = cvt->buf;
+ u_dst = cvt->buf;
+
+ for (i = cvt->len_cvt / 4; i; --i)
+ {
+ sample = (Sint16) ((u_src[1] << 8) | u_src[0])
+ + (Sint16) ((u_src[3] << 8) | u_src[2]);
+ if (sample > 32767)
+ {
+ u_dst[1] = 0x7F;
+ u_dst[0] = 0xFF;
+ } /* if */
+ else if (sample < -32768)
+ {
+ u_dst[1] = 0x80;
+ u_dst[0] = 0x00;
+ } /* else if */
+ else
+ {
+ u_dst[0] = (sample & 0xFF);
+ sample >>= 8;
+ u_dst[1] = (sample & 0xFF);
+ } /* else */
+ u_src += 4;
+ u_dst += 2;
+ } /* for */
+ break;
+ } /* switch */
+
+ cvt->len_cvt /= 2;
+} /* Sound_ConvertMono */
+
+
+/* Convert rate up by multiple of 2 */
+
+static void Sound_RateMUL2(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+ /* SNDDBG(("Converting audio rate * 2\n")); */
+
+ src = cvt->buf + cvt->len_cvt;
+ dst = cvt->buf + cvt->len_cvt*2;
+
+ /* 8- or 16-bit sound? */
+ switch (*format & 0xFF)
+ {
+ case 8:
+ for (i = cvt->len_cvt; i; --i)
+ {
+ src -= 1;
+ dst -= 2;
+ dst[0] = src[0];
+ dst[1] = src[0];
+ } /* for */
+ break;
+
+ case 16:
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ src -= 2;
+ dst -= 4;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst[3] = src[1];
+ } /* for */
+ break;
+ } /* switch */
+
+ cvt->len_cvt *= 2;
+} /* Sound_RateMUL2 */
+
+
+/* Convert rate down by multiple of 2 */
+
+static void Sound_RateDIV2(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ int i;
+ Uint8 *src, *dst;
+
+ /* SNDDBG(("Converting audio rate / 2\n")); */
+
+ src = cvt->buf;
+ dst = cvt->buf;
+
+ /* 8- or 16-bit sound? */
+ switch (*format & 0xFF)
+ {
+ case 8:
+ for (i = cvt->len_cvt / 2; i; --i)
+ {
+ dst[0] = src[0];
+ src += 2;
+ dst += 1;
+ } /* for */
+ break;
+
+ case 16:
+ for (i = cvt->len_cvt / 4; i; --i)
+ {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 4;
+ dst += 2;
+ }
+ break;
+ } /* switch */
+
+ cvt->len_cvt /= 2;
+} /* Sound_RateDIV2 */
+
+
+/* Very slow rate conversion routine */
+
+static void Sound_RateSLOW(Sound_AudioCVT *cvt, Uint16 *format)
+{
+ double ipos;
+ int i, clen;
+ Uint8 *output8;
+ Uint16 *output16;
+
+ /* SNDDBG(("Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr)); */
+
+ clen = (int) ((double) cvt->len_cvt / cvt->rate_incr);
+
+ if (cvt->rate_incr > 1.0)
+ {
+ /* 8- or 16-bit sound? */
+ switch (*format & 0xFF)
+ {
+ case 8:
+ output8 = cvt->buf;
+
+ ipos = 0.0;
+ for (i = clen; i; --i)
+ {
+ *output8 = cvt->buf[(int) ipos];
+ ipos += cvt->rate_incr;
+ output8 += 1;
+ } /* for */
+ break;
+
+ case 16:
+ output16 = (Uint16 *) cvt->buf;
+
+ clen &= ~1;
+ ipos = 0.0;
+ for (i = clen / 2; i; --i)
+ {
+ *output16 = ((Uint16 *) cvt->buf)[(int) ipos];
+ ipos += cvt->rate_incr;
+ output16 += 1;
+ } /* for */
+ break;
+ } /* switch */
+ } /* if */
+ else
+ {
+ /* 8- or 16-bit sound */
+ switch (*format & 0xFF)
+ {
+ case 8:
+ output8 = cvt->buf + clen;
+
+ ipos = (double) cvt->len_cvt;
+ for (i = clen; i; --i)
+ {
+ ipos -= cvt->rate_incr;
+ output8 -= 1;
+ *output8 = cvt->buf[(int) ipos];
+ } /* for */
+ break;
+
+ case 16:
+ clen &= ~1;
+ output16 = (Uint16 *) (cvt->buf + clen);
+ ipos = (double) cvt->len_cvt / 2;
+ for (i = clen / 2; i; --i)
+ {
+ ipos -= cvt->rate_incr;
+ output16 -= 1;
+ *output16 = ((Uint16 *) cvt->buf)[(int) ipos];
+ } /* for */
+ break;
+ } /* switch */
+ } /* else */
+
+ cvt->len_cvt = clen;
+} /* Sound_RateSLOW */
+
+
+int Sound_ConvertAudio(Sound_AudioCVT *cvt)
+{
+ Uint16 format;
+
+ /* Make sure there's data to convert */
+ if (cvt->buf == NULL)
+ {
+ __Sound_SetError("No buffer allocated for conversion");
+ return(-1);
+ } /* if */
+
+ /* Return okay if no conversion is necessary */
+ cvt->len_cvt = cvt->len;
+ if (cvt->filters[0] == NULL)
+ return(0);
+
+ /* Set up the conversion and go! */
+ format = cvt->src_format;
+ for (cvt->filter_index = 0; cvt->filters[cvt->filter_index];
+ cvt->filter_index++)
+ {
+ cvt->filters[cvt->filter_index](cvt, &format);
+ }
+ return(0);
+} /* Sound_ConvertAudio */
+
+
+/*
+ * Creates a set of audio filters to convert from one format to another.
+ * Returns -1 if the format conversion is not supported, or 1 if the
+ * audio filter is set up.
+ */
+
+int Sound_BuildAudioCVT(Sound_AudioCVT *cvt,
+ Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
+ Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate,
+ Uint32 dst_size)
+{
+ /* Start off with no conversion necessary */
+ cvt->needed = 0;
+ cvt->filter_index = 0;
+ cvt->filters[0] = NULL;
+ cvt->len_mult = 1;
+ cvt->len_ratio = 1.0;
+
+ /* First filter: Endian conversion from src to dst */
+ if ((src_format & 0x1000) != (dst_format & 0x1000) &&
+ ((src_format & 0xff) != 8))
+ {
+ SNDDBG(("Adding filter: Sound_ConvertEndian\n"));
+ cvt->filters[cvt->filter_index++] = Sound_ConvertEndian;
+ } /* if */
+
+ /* Second filter: Sign conversion -- signed/unsigned */
+ if ((src_format & 0x8000) != (dst_format & 0x8000))
+ {
+ SNDDBG(("Adding filter: Sound_ConvertSign\n"));
+ cvt->filters[cvt->filter_index++] = Sound_ConvertSign;
+ } /* if */
+
+ /* Next filter: Convert 16 bit <--> 8 bit PCM. */
+ if ((src_format & 0xFF) != (dst_format & 0xFF))
+ {
+ switch (dst_format & 0x10FF)
+ {
+ case AUDIO_U8:
+ SNDDBG(("Adding filter: Sound_Convert8\n"));
+ cvt->filters[cvt->filter_index++] = Sound_Convert8;
+ cvt->len_ratio /= 2;
+ break;
+
+ case AUDIO_U16LSB:
+ SNDDBG(("Adding filter: Sound_Convert16LSB\n"));
+ cvt->filters[cvt->filter_index++] = Sound_Convert16LSB;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ break;
+
+ case AUDIO_U16MSB:
+ SNDDBG(("Adding filter: Sound_Convert16MSB\n"));
+ cvt->filters[cvt->filter_index++] = Sound_Convert16MSB;
+ cvt->len_mult *= 2;
+ cvt->len_ratio *= 2;
+ break;
+ } /* switch */
+ } /* if */
+
+ /* Next filter: Mono/Stereo conversion */
+ if (src_channels != dst_channels)
+ {
+ while ((src_channels * 2) <= dst_channels)
+ {
+ SNDDBG(("Adding filter: Sound_ConvertStereo\n"));
+ cvt->filters[cvt->filter_index++] = Sound_ConvertStereo;
+ cvt->len_mult *= 2;
+ src_channels *= 2;
+ cvt->len_ratio *= 2;
+ } /* while */
+
+ /* This assumes that 4 channel audio is in the format:
+ * Left {front/back} + Right {front/back}
+ * so converting to L/R stereo works properly.
+ */
+ while (((src_channels % 2) == 0) &&
+ ((src_channels / 2) >= dst_channels))
+ {
+ SNDDBG(("Adding filter: Sound_ConvertMono\n"));
+ cvt->filters[cvt->filter_index++] = Sound_ConvertMono;
+ src_channels /= 2;
+ cvt->len_ratio /= 2;
+ } /* while */
+
+ if ( src_channels != dst_channels ) {
+ /* Uh oh.. */;
+ } /* if */
+ } /* if */
+
+ /* Do rate conversion */
+ cvt->rate_incr = 0.0;
+ if ((src_rate / 100) != (dst_rate / 100))
+ {
+ Uint32 hi_rate, lo_rate;
+ int len_mult;
+ double len_ratio;
+ void (*rate_cvt)(Sound_AudioCVT *cvt, Uint16 *format);
+
+ if (src_rate > dst_rate)
+ {
+ hi_rate = src_rate;
+ lo_rate = dst_rate;
+ SNDDBG(("Adding filter: Sound_RateDIV2\n"));
+ rate_cvt = Sound_RateDIV2;
+ len_mult = 1;
+ len_ratio = 0.5;
+ } /* if */
+ else
+ {
+ hi_rate = dst_rate;
+ lo_rate = src_rate;
+ SNDDBG(("Adding filter: Sound_RateMUL2\n"));
+ rate_cvt = Sound_RateMUL2;
+ len_mult = 2;
+ len_ratio = 2.0;
+ } /* else */
+
+ /* If hi_rate = lo_rate*2^x then conversion is easy */
+ while (((lo_rate * 2) / 100) <= (hi_rate / 100))
+ {
+ cvt->filters[cvt->filter_index++] = rate_cvt;
+ cvt->len_mult *= len_mult;
+ lo_rate *= 2;
+ cvt->len_ratio *= len_ratio;
+ } /* while */
+
+ /* We may need a slow conversion here to finish up */
+ if ((lo_rate / 100) != (hi_rate / 100))
+ {
+ if (src_rate < dst_rate)
+ {
+ cvt->rate_incr = (double) lo_rate / hi_rate;
+ cvt->len_mult *= 2;
+ cvt->len_ratio /= cvt->rate_incr;
+ } /* if */
+ else
+ {
+ cvt->rate_incr = (double) hi_rate / lo_rate;
+ cvt->len_ratio *= cvt->rate_incr;
+ } /* else */
+ SNDDBG(("Adding filter: Sound_RateSLOW\n"));
+ cvt->filters[cvt->filter_index++] = Sound_RateSLOW;
+ } /* if */
+ } /* if */
+
+ /* Set up the filter information */
+ if (cvt->filter_index != 0)
+ {
+ cvt->needed = 1;
+ cvt->src_format = src_format;
+ cvt->dst_format = dst_format;
+ cvt->len = 0;
+ cvt->buf = NULL;
+ cvt->filters[cvt->filter_index] = NULL;
+ } /* if */
+
+ return(cvt->needed);
+} /* Sound_BuildAudioCVT */
+
+#endif /* !SOUND_USE_ALTCVT */
+
+/* end of audio_convert.c ... */
+
diff --git a/util/sdl/sound/compile b/util/sdl/sound/compile
new file mode 100755
index 00000000..1b1d2321
--- /dev/null
+++ b/util/sdl/sound/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/util/sdl/sound/config.h.in b/util/sdl/sound/config.h.in
new file mode 100644
index 00000000..d07258da
--- /dev/null
+++ b/util/sdl/sound/config.h.in
@@ -0,0 +1,133 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define for debug builds. */
+#undef DEBUG
+
+/* Define for debug build chattering. */
+#undef DEBUG_CHATTER
+
+/* Define to 1 if you have the <assert.h> header file. */
+#undef HAVE_ASSERT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the `setbuf' function. */
+#undef HAVE_SETBUF
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strrchr' function. */
+#undef HAVE_STRRCHR
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to disable debugging. */
+#undef NDEBUG
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define if modplug header is in own directory. */
+#undef SOUND_MODPLUG_IN_OWN_PATH
+
+/* Define if AIFF support is desired. */
+#undef SOUND_SUPPORTS_AIFF
+
+/* Define if AU support is desired. */
+#undef SOUND_SUPPORTS_AU
+
+/* Define if FLAC support is desired. */
+#undef SOUND_SUPPORTS_FLAC
+
+/* Define if MIDI support is desired. */
+#undef SOUND_SUPPORTS_MIDI
+
+/* Define if MIKMOD support is desired. */
+#undef SOUND_SUPPORTS_MIKMOD
+
+/* Define if MODPLUG support is desired. */
+#undef SOUND_SUPPORTS_MODPLUG
+
+/* Define if MPGLIB support is desired. */
+#undef SOUND_SUPPORTS_MPGLIB
+
+/* Define if OGG support is desired. */
+#undef SOUND_SUPPORTS_OGG
+
+/* Define if RAW support is desired. */
+#undef SOUND_SUPPORTS_RAW
+
+/* Define if SHN support is desired. */
+#undef SOUND_SUPPORTS_SHN
+
+/* Define if SMPEG support is desired. */
+#undef SOUND_SUPPORTS_SMPEG
+
+/* Define if SPEEX support is desired. */
+#undef SOUND_SUPPORTS_SPEEX
+
+/* Define if VOC support is desired. */
+#undef SOUND_SUPPORTS_VOC
+
+/* Define if WAV support is desired. */
+#undef SOUND_SUPPORTS_WAV
+
+/* Define to use alternate audio converter. */
+#undef SOUND_USE_ALTCVT
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/util/sdl/sound/decoders/Makefile.am b/util/sdl/sound/decoders/Makefile.am
new file mode 100644
index 00000000..e6d4f9b4
--- /dev/null
+++ b/util/sdl/sound/decoders/Makefile.am
@@ -0,0 +1,22 @@
+noinst_LTLIBRARIES = libdecoders.la
+
+SUBDIRS = timidity mpglib
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/decoders/timidity
+
+libdecoders_la_SOURCES = \
+ aiff.c \
+ au.c \
+ mikmod.c \
+ modplug.c \
+ mpglib.c \
+ smpeg.c \
+ ogg.c \
+ raw.c \
+ shn.c \
+ voc.c \
+ midi.c \
+ flac.c \
+ speex.c \
+ quicktime.c \
+ wav.c
diff --git a/util/sdl/sound/decoders/Makefile.in b/util/sdl/sound/decoders/Makefile.in
new file mode 100644
index 00000000..b1860112
--- /dev/null
+++ b/util/sdl/sound/decoders/Makefile.in
@@ -0,0 +1,593 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = decoders
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libdecoders_la_LIBADD =
+am_libdecoders_la_OBJECTS = aiff.lo au.lo mikmod.lo modplug.lo \
+ mpglib.lo smpeg.lo ogg.lo raw.lo shn.lo voc.lo midi.lo flac.lo \
+ speex.lo quicktime.lo wav.lo
+libdecoders_la_OBJECTS = $(am_libdecoders_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libdecoders_la_SOURCES)
+DIST_SOURCES = $(libdecoders_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERFACE_AGE = @INTERFACE_AGE@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_MPGLIB_FALSE = @USE_MPGLIB_FALSE@
+USE_MPGLIB_TRUE = @USE_MPGLIB_TRUE@
+USE_PHYSICSFS_FALSE = @USE_PHYSICSFS_FALSE@
+USE_PHYSICSFS_TRUE = @USE_PHYSICSFS_TRUE@
+USE_TIMIDITY_FALSE = @USE_TIMIDITY_FALSE@
+USE_TIMIDITY_TRUE = @USE_TIMIDITY_TRUE@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+noinst_LTLIBRARIES = libdecoders.la
+SUBDIRS = timidity mpglib
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/decoders/timidity
+libdecoders_la_SOURCES = \
+ aiff.c \
+ au.c \
+ mikmod.c \
+ modplug.c \
+ mpglib.c \
+ smpeg.c \
+ ogg.c \
+ raw.c \
+ shn.c \
+ voc.c \
+ midi.c \
+ flac.c \
+ speex.c \
+ quicktime.c \
+ wav.c
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign decoders/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign decoders/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libdecoders.la: $(libdecoders_la_OBJECTS) $(libdecoders_la_DEPENDENCIES)
+ $(LINK) $(libdecoders_la_LDFLAGS) $(libdecoders_la_OBJECTS) $(libdecoders_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aiff.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/au.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mikmod.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modplug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpglib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quicktime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shn.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smpeg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/voc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wav.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \
+ clean clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-recursive ctags ctags-recursive distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-recursive distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/sdl/sound/decoders/aiff.c b/util/sdl/sound/decoders/aiff.c
new file mode 100644
index 00000000..52ee0b38
--- /dev/null
+++ b/util/sdl/sound/decoders/aiff.c
@@ -0,0 +1,569 @@
+/*
+ * 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
+ */
+
+/*
+ * AIFF decoder for SDL_sound
+ *
+ * [Insert something profound about the AIFF file format here.]
+ *
+ * This code was ripped from a decoder I had written for SDL_mixer, which was
+ * based on SDL_mixer's old AIFF music loader. (This loader was unfortunately
+ * completely broken, but it was still useful because all the pieces were
+ * still there, so to speak.)
+ *
+ * When rewriting it for SDL_sound, I changed its structure to be more like
+ * the WAV loader Ryan wrote. Had they not both been part of the same project
+ * it would have been embarrassing how similar they are.
+ *
+ * It is not the most feature-complete AIFF loader the world has ever seen.
+ * For instance, it only makes a token attempt at implementing the AIFF-C
+ * standard; basically the parts of it that I can easily understand and test.
+ * It's a start, though.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file was written by Torbjörn Andersson. (d91tan@Update.UU.SE)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_AIFF
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static Uint32 SANE_to_Uint32 (Uint8 *sanebuf);
+
+
+static int AIFF_init(void);
+static void AIFF_quit(void);
+static int AIFF_open(Sound_Sample *sample, const char *ext);
+static void AIFF_close(Sound_Sample *sample);
+static Uint32 AIFF_read(Sound_Sample *sample);
+static int AIFF_rewind(Sound_Sample *sample);
+static int AIFF_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_aiff[] = { "AIFF", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_AIFF =
+{
+ {
+ extensions_aiff,
+ "Audio Interchange File Format",
+ "Torbjörn Andersson <d91tan@Update.UU.SE>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ AIFF_init, /* init() method */
+ AIFF_quit, /* quit() method */
+ AIFF_open, /* open() method */
+ AIFF_close, /* close() method */
+ AIFF_read, /* read() method */
+ AIFF_rewind, /* rewind() method */
+ AIFF_seek /* seek() method */
+};
+
+
+/*****************************************************************************
+ * aiff_t is what we store in our internal->decoder_private field... *
+ *****************************************************************************/
+typedef struct S_AIFF_FMT_T
+{
+ Uint32 type;
+
+ Uint32 total_bytes;
+ Uint32 data_starting_offset;
+
+ void (*free)(struct S_AIFF_FMT_T *fmt);
+ Uint32 (*read_sample)(Sound_Sample *sample);
+ int (*rewind_sample)(Sound_Sample *sample);
+ int (*seek_sample)(Sound_Sample *sample, Uint32 ms);
+
+
+#if 0
+/*
+ this is ripped from wav.c as ann example of format-specific data.
+ please replace with something more appropriate when the need arises.
+*/
+ union
+ {
+ struct
+ {
+ Uint16 cbSize;
+ Uint16 wSamplesPerBlock;
+ Uint16 wNumCoef;
+ ADPCMCOEFSET *aCoeff;
+ } adpcm;
+
+ /* put other format-specific data here... */
+ } fmt;
+#endif
+} fmt_t;
+
+
+typedef struct
+{
+ fmt_t fmt;
+ Sint32 bytesLeft;
+} aiff_t;
+
+
+
+ /* Chunk management code... */
+
+#define formID 0x4D524F46 /* "FORM", in ascii. */
+#define aiffID 0x46464941 /* "AIFF", in ascii. */
+#define aifcID 0x43464941 /* "AIFC", in ascii. */
+#define ssndID 0x444E5353 /* "SSND", in ascii. */
+
+
+/*****************************************************************************
+ * The COMM chunk... *
+ *****************************************************************************/
+
+#define commID 0x4D4D4F43 /* "COMM", in ascii. */
+
+/* format/compression types... */
+#define noneID 0x454E4F4E /* "NONE", in ascii. */
+
+typedef struct
+{
+ Uint32 ckID;
+ Uint32 ckDataSize;
+ Uint16 numChannels;
+ Uint32 numSampleFrames;
+ Uint16 sampleSize;
+ Uint32 sampleRate;
+ /*
+ * We don't handle AIFF-C compressed audio yet, but for those
+ * interested the allowed compression types are supposed to be
+ *
+ * compressionType compressionName meaning
+ * ---------------------------------------------------------------
+ * 'NONE' "not compressed" uncompressed, that is,
+ * straight digitized samples
+ * 'ACE2' "ACE 2-to-1" 2-to-1 IIGS ACE (Audio
+ * Compression / Expansion)
+ * 'ACE8' "ACE 8-to-3" 8-to-3 IIGS ACE (Audio
+ * Compression / Expansion)
+ * 'MAC3' "MACE 3-to-1" 3-to-1 Macintosh Audio
+ * Compression / Expansion
+ * 'MAC6' "MACE 6-to-1" 6-to-1 Macintosh Audio
+ * Compression / Expansion
+ *
+ * A pstring is a "Pascal-style string", that is, "one byte followed
+ * by test bytes followed when needed by one pad byte. The total
+ * number of bytes in a pstring must be even. The pad byte is
+ * included when the number of text bytes is even, so the total of
+ * text bytes + one count byte + one pad byte will be even. This pad
+ * byte is not reflected in the count."
+ *
+ * As for how these compression algorithms work, your guess is as
+ * good as mine.
+ */
+ Uint32 compressionType;
+#if 0
+ pstring compressionName;
+#endif
+} comm_t;
+
+
+/*
+ * Read in a comm_t from disk. This makes this process safe regardless of
+ * the processor's byte order or how the comm_t structure is packed.
+ */
+
+static int read_comm_chunk(SDL_RWops *rw, comm_t *comm)
+{
+ Uint8 sampleRate[10];
+
+ /* skip reading the chunk ID, since it was already read at this point... */
+ comm->ckID = commID;
+
+ if (SDL_RWread(rw, &comm->ckDataSize, sizeof (comm->ckDataSize), 1) != 1)
+ return(0);
+ comm->ckDataSize = SDL_SwapBE32(comm->ckDataSize);
+
+ if (SDL_RWread(rw, &comm->numChannels, sizeof (comm->numChannels), 1) != 1)
+ return(0);
+ comm->numChannels = SDL_SwapBE16(comm->numChannels);
+
+ if (SDL_RWread(rw, &comm->numSampleFrames,
+ sizeof (comm->numSampleFrames), 1) != 1)
+ return(0);
+ comm->numSampleFrames = SDL_SwapBE32(comm->numSampleFrames);
+
+ if (SDL_RWread(rw, &comm->sampleSize, sizeof (comm->sampleSize), 1) != 1)
+ return(0);
+ comm->sampleSize = SDL_SwapBE16(comm->sampleSize);
+
+ if (SDL_RWread(rw, sampleRate, sizeof (sampleRate), 1) != 1)
+ return(0);
+ comm->sampleRate = SANE_to_Uint32(sampleRate);
+
+ if (comm->ckDataSize > sizeof(comm->numChannels)
+ + sizeof(comm->numSampleFrames)
+ + sizeof(comm->sampleSize)
+ + sizeof(sampleRate))
+ {
+ if (SDL_RWread(rw, &comm->compressionType,
+ sizeof (comm->compressionType), 1) != 1)
+ return(0);
+ comm->compressionType = SDL_SwapBE32(comm->compressionType);
+ } /* if */
+ else
+ {
+ comm->compressionType = noneID;
+ } /* else */
+
+ return(1);
+} /* read_comm_chunk */
+
+
+
+/*****************************************************************************
+ * The SSND chunk... *
+ *****************************************************************************/
+
+typedef struct
+{
+ Uint32 ckID;
+ Uint32 ckDataSize;
+ Uint32 offset;
+ Uint32 blockSize;
+ /*
+ * Then, comm->numSampleFrames sample frames. (It's better to get the
+ * length from numSampleFrames than from ckDataSize.)
+ */
+} ssnd_t;
+
+
+static int read_ssnd_chunk(SDL_RWops *rw, ssnd_t *ssnd)
+{
+ /* skip reading the chunk ID, since it was already read at this point... */
+ ssnd->ckID = ssndID;
+
+ if (SDL_RWread(rw, &ssnd->ckDataSize, sizeof (ssnd->ckDataSize), 1) != 1)
+ return(0);
+ ssnd->ckDataSize = SDL_SwapBE32(ssnd->ckDataSize);
+
+ if (SDL_RWread(rw, &ssnd->offset, sizeof (ssnd->offset), 1) != 1)
+ return(0);
+ ssnd->offset = SDL_SwapBE32(ssnd->offset);
+
+ if (SDL_RWread(rw, &ssnd->blockSize, sizeof (ssnd->blockSize), 1) != 1)
+ return(0);
+ ssnd->blockSize = SDL_SwapBE32(ssnd->blockSize);
+
+ /* Leave the SDL_RWops position indicator at the start of the samples */
+ if (SDL_RWseek(rw, (int) ssnd->offset, SEEK_CUR) == -1)
+ return(0);
+
+ return(1);
+} /* read_ssnd_chunk */
+
+
+
+/*****************************************************************************
+ * Normal, uncompressed aiff handler... *
+ *****************************************************************************/
+
+static Uint32 read_sample_fmt_normal(Sound_Sample *sample)
+{
+ Uint32 retval;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ aiff_t *a = (aiff_t *) internal->decoder_private;
+ Uint32 max = (internal->buffer_size < (Uint32) a->bytesLeft) ?
+ internal->buffer_size : (Uint32) a->bytesLeft;
+
+ assert(max > 0);
+
+ /*
+ * We don't actually do any decoding, so we read the AIFF data
+ * directly into the internal buffer...
+ */
+ retval = SDL_RWread(internal->rw, internal->buffer, 1, max);
+
+ a->bytesLeft -= retval;
+
+ /* Make sure the read went smoothly... */
+ if ((retval == 0) || (a->bytesLeft == 0))
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+ else if (retval == -1)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+ /* (next call this EAGAIN may turn into an EOF or error.) */
+ else if (retval < internal->buffer_size)
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+ return(retval);
+} /* read_sample_fmt_normal */
+
+
+static int rewind_sample_fmt_normal(Sound_Sample *sample)
+{
+ /* no-op. */
+ return(1);
+} /* rewind_sample_fmt_normal */
+
+
+static int seek_sample_fmt_normal(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ aiff_t *a = (aiff_t *) internal->decoder_private;
+ fmt_t *fmt = &a->fmt;
+ int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+ int pos = (int) (fmt->data_starting_offset + offset);
+ int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
+ BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
+ a->bytesLeft = fmt->total_bytes - offset;
+ return(1); /* success. */
+} /* seek_sample_fmt_normal */
+
+
+static void free_fmt_normal(fmt_t *fmt)
+{
+ /* it's a no-op. */
+} /* free_fmt_normal */
+
+
+static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt)
+{
+ /* (don't need to read more from the RWops...) */
+ fmt->free = free_fmt_normal;
+ fmt->read_sample = read_sample_fmt_normal;
+ fmt->rewind_sample = rewind_sample_fmt_normal;
+ fmt->seek_sample = seek_sample_fmt_normal;
+ return(1);
+} /* read_fmt_normal */
+
+
+
+
+/*****************************************************************************
+ * Everything else... *
+ *****************************************************************************/
+
+static int AIFF_init(void)
+{
+ return(1); /* always succeeds. */
+} /* AIFF_init */
+
+
+static void AIFF_quit(void)
+{
+ /* it's a no-op. */
+} /* AIFF_quit */
+
+
+/*
+ * Sample rate is encoded as an "80 bit IEEE Standard 754 floating point
+ * number (Standard Apple Numeric Environment [SANE] data type Extended)".
+ * Whose bright idea was that?
+ *
+ * This function was adapted from libsndfile, and while I do know a little
+ * bit about the IEEE floating point standard I don't pretend to fully
+ * understand this.
+ */
+static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
+{
+ /* Is the frequency outside of what we can represent with Uint32? */
+ if ( (sanebuf[0] & 0x80)
+ || (sanebuf[0] <= 0x3F)
+ || (sanebuf[0] > 0x40)
+ || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) )
+ return 0;
+
+ return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
+ | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
+} /* SANE_to_Uint32 */
+
+
+static int find_chunk(SDL_RWops *rw, Uint32 id)
+{
+ Sint32 siz = 0;
+ Uint32 _id = 0;
+
+ while (1)
+ {
+ BAIL_IF_MACRO(SDL_RWread(rw, &_id, sizeof (_id), 1) != 1, NULL, 0);
+ if (SDL_SwapLE32(_id) == id)
+ return(1);
+
+ BAIL_IF_MACRO(SDL_RWread(rw, &siz, sizeof (siz), 1) != 1, NULL, 0);
+ siz = SDL_SwapBE32(siz);
+ assert(siz > 0);
+ BAIL_IF_MACRO(SDL_RWseek(rw, siz, SEEK_CUR) == -1, NULL, 0);
+ } /* while */
+
+ return(0); /* shouldn't hit this, but just in case... */
+} /* find_chunk */
+
+
+static int read_fmt(SDL_RWops *rw, comm_t *c, fmt_t *fmt)
+{
+ fmt->type = c->compressionType;
+
+ /* if it's in this switch statement, we support the format. */
+ switch (fmt->type)
+ {
+ case noneID:
+ SNDDBG(("AIFF: Appears to be uncompressed audio.\n"));
+ return(read_fmt_normal(rw, fmt));
+
+ /* add other types here. */
+
+ default:
+ SNDDBG(("AIFF: Format %lu is unknown.\n",
+ (unsigned int) fmt->type));
+ BAIL_MACRO("AIFF: Unsupported format", 0);
+ } /* switch */
+
+ assert(0); /* shouldn't hit this point. */
+ return(0);
+} /* read_fmt */
+
+
+static int AIFF_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ Uint32 chunk_id;
+ int bytes_per_sample;
+ long pos;
+ comm_t c;
+ ssnd_t s;
+ aiff_t *a;
+
+ BAIL_IF_MACRO(SDL_ReadLE32(rw) != formID, "AIFF: Not a FORM file.", 0);
+ SDL_ReadBE32(rw); /* throw the length away; we don't need it. */
+
+ chunk_id = SDL_ReadLE32(rw);
+ BAIL_IF_MACRO(chunk_id != aiffID && chunk_id != aifcID,
+ "AIFF: Not an AIFF or AIFC file.", 0);
+
+ /* Chunks may appear in any order, so we establish base camp here. */
+ pos = SDL_RWtell(rw);
+
+ BAIL_IF_MACRO(!find_chunk(rw, commID), "AIFF: No common chunk.", 0);
+ BAIL_IF_MACRO(!read_comm_chunk(rw, &c),
+ "AIFF: Can't read common chunk.", 0);
+
+ sample->actual.channels = (Uint8) c.numChannels;
+ sample->actual.rate = c.sampleRate;
+
+ if (c.sampleSize <= 8)
+ {
+ sample->actual.format = AUDIO_S8;
+ bytes_per_sample = c.numChannels;
+ } /* if */
+ else if (c.sampleSize <= 16)
+ {
+ sample->actual.format = AUDIO_S16MSB;
+ bytes_per_sample = 2 * c.numChannels;
+ } /* if */
+ else
+ {
+ BAIL_MACRO("AIFF: Unsupported sample size.", 0);
+ } /* else */
+
+ BAIL_IF_MACRO(c.sampleRate == 0, "AIFF: Unsupported sample rate.", 0);
+
+ a = (aiff_t *) malloc(sizeof(aiff_t));
+ BAIL_IF_MACRO(a == NULL, ERR_OUT_OF_MEMORY, 0);
+
+ if (!read_fmt(rw, &c, &(a->fmt)))
+ {
+ free(a);
+ return(0);
+ } /* if */
+
+ SDL_RWseek(rw, pos, SEEK_SET); /* if the seek fails, let it go... */
+
+ if (!find_chunk(rw, ssndID))
+ {
+ free(a);
+ BAIL_MACRO("AIFF: No sound data chunk.", 0);
+ } /* if */
+
+ if (!read_ssnd_chunk(rw, &s))
+ {
+ free(a);
+ BAIL_MACRO("AIFF: Can't read sound data chunk.", 0);
+ } /* if */
+
+ a->fmt.total_bytes = a->bytesLeft = bytes_per_sample * c.numSampleFrames;
+ a->fmt.data_starting_offset = SDL_RWtell(rw);
+ internal->decoder_private = (void *) a;
+
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+
+ SNDDBG(("AIFF: Accepting data stream.\n"));
+ return(1); /* we'll handle this data. */
+} /* AIFF_open */
+
+
+static void AIFF_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ aiff_t *a = (aiff_t *) internal->decoder_private;
+ a->fmt.free(&(a->fmt));
+ free(a);
+} /* AIFF_close */
+
+
+static Uint32 AIFF_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ aiff_t *a = (aiff_t *) internal->decoder_private;
+ return(a->fmt.read_sample(sample));
+} /* AIFF_read */
+
+
+static int AIFF_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ aiff_t *a = (aiff_t *) internal->decoder_private;
+ fmt_t *fmt = &a->fmt;
+ int rc = SDL_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET);
+ BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0);
+ a->bytesLeft = fmt->total_bytes;
+ return(fmt->rewind_sample(sample));
+} /* AIFF_rewind */
+
+
+static int AIFF_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ aiff_t *a = (aiff_t *) internal->decoder_private;
+ return(a->fmt.seek_sample(sample, ms));
+} /* AIFF_seek */
+
+#endif /* SOUND_SUPPORTS_AIFF */
+
+/* end of aiff.c ... */
+
diff --git a/util/sdl/sound/decoders/au.c b/util/sdl/sound/decoders/au.c
new file mode 100644
index 00000000..ab0ff9f7
--- /dev/null
+++ b/util/sdl/sound/decoders/au.c
@@ -0,0 +1,376 @@
+/*
+ * 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
+ */
+
+/*
+ * Sun/NeXT .au decoder for SDL_sound.
+ * Formats supported: 8 and 16 bit linear PCM, 8 bit µ-law.
+ * Files without valid header are assumed to be 8 bit µ-law, 8kHz, mono.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Mattias Engdegård. (f91-men@nada.kth.se)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_AU
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int AU_init(void);
+static void AU_quit(void);
+static int AU_open(Sound_Sample *sample, const char *ext);
+static void AU_close(Sound_Sample *sample);
+static Uint32 AU_read(Sound_Sample *sample);
+static int AU_rewind(Sound_Sample *sample);
+static int AU_seek(Sound_Sample *sample, Uint32 ms);
+
+/*
+ * Sometimes the extension ".snd" is used for these files (mostly on the NeXT),
+ * and the magic number comes from this. However it may clash with other
+ * formats and is somewhat of an anachronism, so only .au is used here.
+ */
+static const char *extensions_au[] = { "AU", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_AU =
+{
+ {
+ extensions_au,
+ "Sun/NeXT audio file format",
+ "Mattias Engdegård <f91-men@nada.kth.se>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ AU_init, /* init() method */
+ AU_quit, /* quit() method */
+ AU_open, /* open() method */
+ AU_close, /* close() method */
+ AU_read, /* read() method */
+ AU_rewind, /* rewind() method */
+ AU_seek /* seek() method */
+};
+
+/* no init/deinit needed */
+static int AU_init(void)
+{
+ return(1);
+} /* AU_init */
+
+static void AU_quit(void)
+{
+ /* no-op. */
+} /* AU_quit */
+
+struct au_file_hdr
+{
+ Uint32 magic;
+ Uint32 hdr_size;
+ Uint32 data_size;
+ Uint32 encoding;
+ Uint32 sample_rate;
+ Uint32 channels;
+};
+
+#define HDR_SIZE 24
+
+enum
+{
+ AU_ENC_ULAW_8 = 1, /* 8-bit ISDN µ-law */
+ AU_ENC_LINEAR_8 = 2, /* 8-bit linear PCM */
+ AU_ENC_LINEAR_16 = 3, /* 16-bit linear PCM */
+
+ /* the rest are unsupported (I have never seen them in the wild) */
+ AU_ENC_LINEAR_24 = 4, /* 24-bit linear PCM */
+ AU_ENC_LINEAR_32 = 5, /* 32-bit linear PCM */
+ AU_ENC_FLOAT = 6, /* 32-bit IEEE floating point */
+ AU_ENC_DOUBLE = 7, /* 64-bit IEEE floating point */
+ /* more Sun formats, not supported either */
+ AU_ENC_ADPCM_G721 = 23,
+ AU_ENC_ADPCM_G722 = 24,
+ AU_ENC_ADPCM_G723_3 = 25,
+ AU_ENC_ADPCM_G723_5 = 26,
+ AU_ENC_ALAW_8 = 27
+};
+
+struct audec
+{
+ Uint32 total;
+ Uint32 remaining;
+ Uint32 start_offset;
+ int encoding;
+};
+
+
+/*
+ * Read in the AU header from disk. This makes this process safe
+ * regardless of the processor's byte order or how the au_file_hdr
+ * structure is packed.
+ */
+static int read_au_header(SDL_RWops *rw, struct au_file_hdr *hdr)
+{
+ if (SDL_RWread(rw, &hdr->magic, sizeof (hdr->magic), 1) != 1)
+ return(0);
+ hdr->magic = SDL_SwapBE32(hdr->magic);
+
+ if (SDL_RWread(rw, &hdr->hdr_size, sizeof (hdr->hdr_size), 1) != 1)
+ return(0);
+ hdr->hdr_size = SDL_SwapBE32(hdr->hdr_size);
+
+ if (SDL_RWread(rw, &hdr->data_size, sizeof (hdr->data_size), 1) != 1)
+ return(0);
+ hdr->data_size = SDL_SwapBE32(hdr->data_size);
+
+ if (SDL_RWread(rw, &hdr->encoding, sizeof (hdr->encoding), 1) != 1)
+ return(0);
+ hdr->encoding = SDL_SwapBE32(hdr->encoding);
+
+ if (SDL_RWread(rw, &hdr->sample_rate, sizeof (hdr->sample_rate), 1) != 1)
+ return(0);
+ hdr->sample_rate = SDL_SwapBE32(hdr->sample_rate);
+
+ if (SDL_RWread(rw, &hdr->channels, sizeof (hdr->channels), 1) != 1)
+ return(0);
+ hdr->channels = SDL_SwapBE32(hdr->channels);
+
+ return(1);
+} /* read_au_header */
+
+
+#define AU_MAGIC 0x2E736E64 /* ".snd", in ASCII (bigendian number) */
+
+static int AU_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ int skip, hsize, i;
+ struct au_file_hdr hdr;
+ struct audec *dec;
+ char c;
+
+ /* read_au_header() will do byte order swapping. */
+ BAIL_IF_MACRO(!read_au_header(rw, &hdr), "AU: bad header", 0);
+
+ dec = malloc(sizeof *dec);
+ BAIL_IF_MACRO(dec == NULL, ERR_OUT_OF_MEMORY, 0);
+ internal->decoder_private = dec;
+
+ if (hdr.magic == AU_MAGIC)
+ {
+ /* valid magic */
+ dec->encoding = hdr.encoding;
+ switch(dec->encoding)
+ {
+ case AU_ENC_ULAW_8:
+ /* Convert 8-bit µ-law to 16-bit linear on the fly. This is
+ slightly wasteful if the audio driver must convert them
+ back, but µ-law only devices are rare (mostly _old_ Suns) */
+ sample->actual.format = AUDIO_S16SYS;
+ break;
+
+ case AU_ENC_LINEAR_8:
+ sample->actual.format = AUDIO_S8;
+ break;
+
+ case AU_ENC_LINEAR_16:
+ sample->actual.format = AUDIO_S16MSB;
+ break;
+
+ default:
+ free(dec);
+ BAIL_MACRO("AU: Unsupported .au encoding", 0);
+ } /* switch */
+
+ sample->actual.rate = hdr.sample_rate;
+ sample->actual.channels = hdr.channels;
+ dec->remaining = hdr.data_size;
+ hsize = hdr.hdr_size;
+
+ /* skip remaining part of header (input may be unseekable) */
+ for (i = HDR_SIZE; i < hsize; i++)
+ {
+ if (SDL_RWread(rw, &c, 1, 1) != 1)
+ {
+ free(dec);
+ BAIL_MACRO(ERR_IO_ERROR, 0);
+ } /* if */
+ } /* for */
+ } /* if */
+
+ else if (__Sound_strcasecmp(ext, "au") == 0)
+ {
+ /*
+ * A number of files in the wild have the .au extension but no valid
+ * header; these are traditionally assumed to be 8kHz µ-law. Handle
+ * them here only if the extension is recognized.
+ */
+
+ SNDDBG(("AU: Invalid header, assuming raw 8kHz µ-law.\n"));
+ /* if seeking fails, we lose 24 samples. big deal */
+ SDL_RWseek(rw, -HDR_SIZE, SEEK_CUR);
+ dec->encoding = AU_ENC_ULAW_8;
+ dec->remaining = (Uint32)-1; /* no limit */
+ sample->actual.format = AUDIO_S16SYS;
+ sample->actual.rate = 8000;
+ sample->actual.channels = 1;
+ } /* else if */
+
+ else
+ {
+ free(dec);
+ BAIL_MACRO("AU: Not an .AU stream.", 0);
+ } /* else */
+
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+ dec->total = dec->remaining;
+ dec->start_offset = SDL_RWtell(rw);
+
+ SNDDBG(("AU: Accepting data stream.\n"));
+ return(1);
+} /* AU_open */
+
+
+static void AU_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = sample->opaque;
+ free(internal->decoder_private);
+} /* AU_close */
+
+
+/* table to convert from µ-law encoding to signed 16-bit samples,
+ generated by a throwaway perl script */
+static Sint16 ulaw_to_linear[256] = {
+ -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
+ -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
+ -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
+ -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
+ -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+ -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+ -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+ -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+ -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+ -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
+ -876, -844, -812, -780, -748, -716, -684, -652,
+ -620, -588, -556, -524, -492, -460, -428, -396,
+ -372, -356, -340, -324, -308, -292, -276, -260,
+ -244, -228, -212, -196, -180, -164, -148, -132,
+ -120, -112, -104, -96, -88, -80, -72, -64,
+ -56, -48, -40, -32, -24, -16, -8, 0,
+ 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+ 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+ 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+ 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
+ 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
+ 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
+ 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
+ 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
+ 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
+ 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
+ 876, 844, 812, 780, 748, 716, 684, 652,
+ 620, 588, 556, 524, 492, 460, 428, 396,
+ 372, 356, 340, 324, 308, 292, 276, 260,
+ 244, 228, 212, 196, 180, 164, 148, 132,
+ 120, 112, 104, 96, 88, 80, 72, 64,
+ 56, 48, 40, 32, 24, 16, 8, 0
+};
+
+
+static Uint32 AU_read(Sound_Sample *sample)
+{
+ int ret;
+ Sound_SampleInternal *internal = sample->opaque;
+ struct audec *dec = internal->decoder_private;
+ int maxlen;
+ Uint8 *buf;
+
+ maxlen = internal->buffer_size;
+ buf = internal->buffer;
+ if (dec->encoding == AU_ENC_ULAW_8)
+ {
+ /* We read µ-law samples into the second half of the buffer, so
+ we can expand them to 16-bit samples afterwards */
+ maxlen >>= 1;
+ buf += maxlen;
+ } /* if */
+
+ if (maxlen > dec->remaining)
+ maxlen = dec->remaining;
+ ret = SDL_RWread(internal->rw, buf, 1, maxlen);
+ if (ret == 0)
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ else if (ret == -1)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ else
+ {
+ dec->remaining -= ret;
+ if (ret < maxlen)
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+ if (dec->encoding == AU_ENC_ULAW_8)
+ {
+ int i;
+ Sint16 *dst = internal->buffer;
+ for (i = 0; i < ret; i++)
+ dst[i] = ulaw_to_linear[buf[i]];
+ ret <<= 1; /* return twice as much as read */
+ } /* if */
+ } /* else */
+
+ return(ret);
+} /* AU_read */
+
+
+static int AU_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ struct audec *dec = (struct audec *) internal->decoder_private;
+ int rc = SDL_RWseek(internal->rw, dec->start_offset, SEEK_SET);
+ BAIL_IF_MACRO(rc != dec->start_offset, ERR_IO_ERROR, 0);
+ dec->remaining = dec->total;
+ return(1);
+} /* AU_rewind */
+
+
+static int AU_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ struct audec *dec = (struct audec *) internal->decoder_private;
+ int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+ int rc;
+ int pos;
+
+ if (dec->encoding == AU_ENC_ULAW_8)
+ offset >>= 1; /* halve the byte offset for compression. */
+
+ pos = (int) (dec->start_offset + offset);
+ rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
+ BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
+ dec->remaining = dec->total - offset;
+ return(1);
+} /* AU_seek */
+
+#endif /* SOUND_SUPPORTS_AU */
+
diff --git a/util/sdl/sound/decoders/flac.c b/util/sdl/sound/decoders/flac.c
new file mode 100644
index 00000000..54aebc0c
--- /dev/null
+++ b/util/sdl/sound/decoders/flac.c
@@ -0,0 +1,566 @@
+/*
+ * 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
+ */
+
+/*
+ * FLAC decoder for SDL_sound.
+ *
+ * This driver handles FLAC audio, that is to say the Free Lossless Audio
+ * Codec. It depends on libFLAC for decoding, which can be grabbed from:
+ * http://flac.sourceforge.net
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Torbjörn Andersson. (d91tan@Update.UU.SE)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_FLAC
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include <FLAC/export.h>
+
+/* FLAC 1.1.3 has FLAC_API_VERSION_CURRENT == 8 */
+#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
+#define LEGACY_FLAC
+#else
+#undef LEGACY_FLAC
+#endif
+
+#ifdef LEGACY_FLAC
+#include <FLAC/seekable_stream_decoder.h>
+
+#define D_END_OF_STREAM FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM
+
+#define d_new() FLAC__seekable_stream_decoder_new()
+#define d_init(x) FLAC__seekable_stream_decoder_init(x)
+#define d_process_metadata(x) FLAC__seekable_stream_decoder_process_until_end_of_metadata(x)
+#define d_process_one_frame(x) FLAC__seekable_stream_decoder_process_single(x)
+#define d_get_state(x) FLAC__seekable_stream_decoder_get_state(x)
+#define d_finish(x) FLAC__seekable_stream_decoder_finish(x)
+#define d_delete(x) FLAC__seekable_stream_decoder_delete(x)
+#define d_set_read_callback(x, y) FLAC__seekable_stream_decoder_set_read_callback(x, y)
+#define d_set_write_callback(x, y) FLAC__seekable_stream_decoder_set_write_callback(x, y)
+#define d_set_metadata_callback(x, y) FLAC__seekable_stream_decoder_set_metadata_callback(x, y)
+#define d_set_error_callback(x, y) FLAC__seekable_stream_decoder_set_error_callback(x, y)
+#define d_set_client_data(x, y) FLAC__seekable_stream_decoder_set_client_data(x, y)
+
+typedef FLAC__SeekableStreamDecoder decoder_t;
+typedef FLAC__SeekableStreamDecoderReadStatus d_read_status_t;
+
+#define D_SEEK_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK
+#define D_SEEK_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
+#define D_TELL_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK
+#define D_TELL_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
+#define D_LENGTH_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK
+#define D_LENGTH_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
+
+#define d_set_seek_callback(x, y) FLAC__seekable_stream_decoder_set_seek_callback(x, y)
+#define d_set_tell_callback(x, y) FLAC__seekable_stream_decoder_set_tell_callback(x, y)
+#define d_set_length_callback(x, y) FLAC__seekable_stream_decoder_set_length_callback(x, y)
+#define d_set_eof_callback(x, y) FLAC__seekable_stream_decoder_set_eof_callback(x, y)
+#define d_seek_absolute(x, y) FLAC__seekable_stream_decoder_seek_absolute(x, y)
+
+typedef FLAC__SeekableStreamDecoderSeekStatus d_seek_status_t;
+typedef FLAC__SeekableStreamDecoderTellStatus d_tell_status_t;
+typedef FLAC__SeekableStreamDecoderLengthStatus d_length_status_t;
+#else
+#include <FLAC/stream_decoder.h>
+
+#define D_END_OF_STREAM FLAC__STREAM_DECODER_END_OF_STREAM
+
+#define d_new() FLAC__stream_decoder_new()
+#define d_process_metadata(x) FLAC__stream_decoder_process_until_end_of_metadata(x)
+#define d_process_one_frame(x) FLAC__stream_decoder_process_single(x)
+#define d_get_state(x) FLAC__stream_decoder_get_state(x)
+#define d_finish(x) FLAC__stream_decoder_finish(x)
+#define d_delete(x) FLAC__stream_decoder_delete(x)
+
+typedef FLAC__StreamDecoder decoder_t;
+typedef FLAC__StreamDecoderReadStatus d_read_status_t;
+
+#define D_SEEK_STATUS_OK FLAC__STREAM_DECODER_SEEK_STATUS_OK
+#define D_SEEK_STATUS_ERROR FLAC__STREAM_DECODER_SEEK_STATUS_ERROR
+#define D_TELL_STATUS_OK FLAC__STREAM_DECODER_TELL_STATUS_OK
+#define D_TELL_STATUS_ERROR FLAC__STREAM_DECODER_TELL_STATUS_ERROR
+#define D_LENGTH_STATUS_OK FLAC__STREAM_DECODER_LENGTH_STATUS_OK
+#define D_LENGTH_STATUS_ERROR FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR
+
+#define d_seek_absolute(x, y) FLAC__stream_decoder_seek_absolute(x, y)
+
+typedef FLAC__StreamDecoderSeekStatus d_seek_status_t;
+typedef FLAC__StreamDecoderTellStatus d_tell_status_t;
+typedef FLAC__StreamDecoderLengthStatus d_length_status_t;
+#endif
+
+#define D_WRITE_CONTINUE FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
+#define D_READ_END_OF_STREAM FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
+#define D_READ_ABORT FLAC__STREAM_DECODER_READ_STATUS_ABORT
+#define D_READ_CONTINUE FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
+
+#define d_error_status_string FLAC__StreamDecoderErrorStatusString
+
+typedef FLAC__StreamDecoderErrorStatus d_error_status_t;
+typedef FLAC__StreamMetadata d_metadata_t;
+typedef FLAC__StreamDecoderWriteStatus d_write_status_t;
+
+
+static int FLAC_init(void);
+static void FLAC_quit(void);
+static int FLAC_open(Sound_Sample *sample, const char *ext);
+static void FLAC_close(Sound_Sample *sample);
+static Uint32 FLAC_read(Sound_Sample *sample);
+static int FLAC_rewind(Sound_Sample *sample);
+static int FLAC_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_flac[] = { "FLAC", "FLA", NULL };
+
+const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC =
+{
+ {
+ extensions_flac,
+ "Free Lossless Audio Codec",
+ "Torbjörn Andersson <d91tan@Update.UU.SE>",
+ "http://flac.sourceforge.net/"
+ },
+
+ FLAC_init, /* init() method */
+ FLAC_quit, /* quit() method */
+ FLAC_open, /* open() method */
+ FLAC_close, /* close() method */
+ FLAC_read, /* read() method */
+ FLAC_rewind, /* rewind() method */
+ FLAC_seek /* seek() method */
+};
+
+ /* This is what we store in our internal->decoder_private field. */
+typedef struct
+{
+ decoder_t *decoder;
+ SDL_RWops *rw;
+ Sound_Sample *sample;
+ Uint32 frame_size;
+ Uint8 is_flac;
+ Uint32 stream_length;
+} flac_t;
+
+
+static void free_flac(flac_t *f)
+{
+ d_finish(f->decoder);
+ d_delete(f->decoder);
+ free(f);
+} /* free_flac */
+
+
+#ifdef LEGACY_FLAC
+static d_read_status_t read_callback(
+ const decoder_t *decoder, FLAC__byte buffer[],
+ unsigned int *bytes, void *client_data)
+#else
+static d_read_status_t read_callback(
+ const decoder_t *decoder, FLAC__byte buffer[],
+ size_t *bytes, void *client_data)
+#endif
+{
+ flac_t *f = (flac_t *) client_data;
+ Uint32 retval;
+
+ retval = SDL_RWread(f->rw, (Uint8 *) buffer, 1, *bytes);
+
+ if (retval == 0)
+ {
+ *bytes = 0;
+ f->sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(D_READ_END_OF_STREAM);
+ } /* if */
+
+ if (retval == -1)
+ {
+ *bytes = 0;
+ f->sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(D_READ_ABORT);
+ } /* if */
+
+ if (retval < *bytes)
+ {
+ *bytes = retval;
+ f->sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+ } /* if */
+
+ return(D_READ_CONTINUE);
+} /* read_callback */
+
+
+static d_write_status_t write_callback(
+ const decoder_t *decoder, const FLAC__Frame *frame,
+ const FLAC__int32 * const buffer[],
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+ Uint32 i, j;
+ Uint32 sample;
+ Uint8 *dst;
+
+ f->frame_size = frame->header.channels * frame->header.blocksize
+ * frame->header.bits_per_sample / 8;
+
+ if (f->frame_size > f->sample->buffer_size)
+ Sound_SetBufferSize(f->sample, f->frame_size);
+
+ dst = f->sample->buffer;
+
+ /* If the sample is neither exactly 8-bit nor 16-bit, it will have to
+ * be converted. Unfortunately the buffer is read-only, so we either
+ * have to check for each sample, or make a copy of the buffer. I'm
+ * not sure which way is best, so I've arbitrarily picked the former.
+ */
+ if (f->sample->actual.format == AUDIO_S8)
+ {
+ for (i = 0; i < frame->header.blocksize; i++)
+ for (j = 0; j < frame->header.channels; j++)
+ {
+ sample = buffer[j][i];
+ if (frame->header.bits_per_sample < 8)
+ sample <<= (8 - frame->header.bits_per_sample);
+ *dst++ = sample & 0x00ff;
+ } /* for */
+ } /* if */
+ else
+ {
+ for (i = 0; i < frame->header.blocksize; i++)
+ for (j = 0; j < frame->header.channels; j++)
+ {
+ sample = buffer[j][i];
+ if (frame->header.bits_per_sample < 16)
+ sample <<= (16 - frame->header.bits_per_sample);
+ else if (frame->header.bits_per_sample > 16)
+ sample >>= (frame->header.bits_per_sample - 16);
+ *dst++ = (sample & 0xff00) >> 8;
+ *dst++ = sample & 0x00ff;
+ } /* for */
+ } /* else */
+
+ return(D_WRITE_CONTINUE);
+} /* write_callback */
+
+
+static void metadata_callback(
+ const decoder_t *decoder,
+ const d_metadata_t *metadata,
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+
+ SNDDBG(("FLAC: Metadata callback.\n"));
+
+ /* There are several kinds of metadata, but STREAMINFO is the only
+ * one that always has to be there.
+ */
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
+ {
+ SNDDBG(("FLAC: Metadata is streaminfo.\n"));
+
+ f->is_flac = 1;
+ f->sample->actual.channels = metadata->data.stream_info.channels;
+ f->sample->actual.rate = metadata->data.stream_info.sample_rate;
+
+ if (metadata->data.stream_info.bits_per_sample > 8)
+ f->sample->actual.format = AUDIO_S16MSB;
+ else
+ f->sample->actual.format = AUDIO_S8;
+ } /* if */
+} /* metadata_callback */
+
+
+static void error_callback(
+ const decoder_t *decoder,
+ d_error_status_t status,
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+
+ __Sound_SetError(d_error_status_string[status]);
+ f->sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+} /* error_callback */
+
+
+static d_seek_status_t seek_callback(
+ const decoder_t *decoder,
+ FLAC__uint64 absolute_byte_offset,
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+
+ if (SDL_RWseek(f->rw, absolute_byte_offset, SEEK_SET) >= 0)
+ {
+ return(D_SEEK_STATUS_OK);
+ } /* if */
+
+ return(D_SEEK_STATUS_ERROR);
+} /* seek_callback*/
+
+
+static d_tell_status_t tell_callback(
+ const decoder_t *decoder,
+ FLAC__uint64 *absolute_byte_offset,
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+ int pos;
+
+ pos = SDL_RWtell(f->rw);
+
+ if (pos < 0)
+ {
+ return(D_TELL_STATUS_ERROR);
+ } /* if */
+
+ *absolute_byte_offset = pos;
+ return(D_TELL_STATUS_OK);
+} /* tell_callback */
+
+
+static d_length_status_t length_callback(
+ const decoder_t *decoder,
+ FLAC__uint64 *stream_length,
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+
+ if (f->sample->flags & SOUND_SAMPLEFLAG_CANSEEK)
+ {
+ *stream_length = f->stream_length;
+ return(D_LENGTH_STATUS_OK);
+ } /* if */
+
+ return(D_LENGTH_STATUS_ERROR);
+} /* length_callback */
+
+
+static FLAC__bool eof_callback(
+ const decoder_t *decoder,
+ void *client_data)
+{
+ flac_t *f = (flac_t *) client_data;
+ int pos;
+
+ /* Maybe we could check for SOUND_SAMPLEFLAG_EOF here instead? */
+ pos = SDL_RWtell(f->rw);
+
+ if (pos >= 0 && pos >= f->stream_length)
+ {
+ return(true);
+ } /* if */
+
+ return(false);
+} /* eof_callback */
+
+
+static int FLAC_init(void)
+{
+ return(1); /* always succeeds. */
+} /* FLAC_init */
+
+
+static void FLAC_quit(void)
+{
+ /* it's a no-op. */
+} /* FLAC_quit */
+
+
+#define FLAC_MAGIC 0x43614C66 /* "fLaC" in ASCII. */
+
+static int FLAC_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ decoder_t *decoder;
+ flac_t *f;
+ int i;
+ int has_extension = 0;
+ Uint32 pos;
+
+ /*
+ * If the extension is "flac", we'll believe that this is really meant
+ * to be a FLAC stream, and will try to grok it from existing metadata.
+ * metadata searching can be a very expensive operation, however, so
+ * unless the user swears that it is a FLAC stream through the extension,
+ * we decide what to do based on the existance of a 32-bit magic number.
+ */
+ for (i = 0; extensions_flac[i] != NULL; i++)
+ {
+ if (__Sound_strcasecmp(ext, extensions_flac[i]) == 0)
+ {
+ has_extension = 1;
+ break;
+ } /* if */
+ } /* for */
+
+ if (!has_extension)
+ {
+ int rc;
+ Uint32 flac_magic = SDL_ReadLE32(rw);
+ BAIL_IF_MACRO(flac_magic != FLAC_MAGIC, "FLAC: Not a FLAC stream.", 0);
+
+ /* move back over magic number for metadata scan... */
+ rc = SDL_RWseek(internal->rw, -sizeof (flac_magic), SEEK_CUR);
+ BAIL_IF_MACRO(rc < 0, ERR_IO_ERROR, 0);
+ } /* if */
+
+ f = (flac_t *) malloc(sizeof (flac_t));
+ BAIL_IF_MACRO(f == NULL, ERR_OUT_OF_MEMORY, 0);
+
+ decoder = d_new();
+ if (decoder == NULL)
+ {
+ free(f);
+ BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+ } /* if */
+
+#ifdef LEGACY_FLAC
+ d_set_read_callback(decoder, read_callback);
+ d_set_write_callback(decoder, write_callback);
+ d_set_metadata_callback(decoder, metadata_callback);
+ d_set_error_callback(decoder, error_callback);
+ d_set_seek_callback(decoder, seek_callback);
+ d_set_tell_callback(decoder, tell_callback);
+ d_set_length_callback(decoder, length_callback);
+ d_set_eof_callback(decoder, eof_callback);
+
+ d_set_client_data(decoder, f);
+#endif
+
+ f->rw = internal->rw;
+ f->sample = sample;
+ f->decoder = decoder;
+ f->sample->actual.format = 0;
+ f->is_flac = 0 /* !!! FIXME: should be "has_extension", not "0". */;
+
+ internal->decoder_private = f;
+ /* really should check the init return value here: */
+#ifdef LEGACY_FLAC
+ d_init(decoder);
+#else
+ FLAC__stream_decoder_init_stream(decoder, read_callback, seek_callback,
+ tell_callback, length_callback,
+ eof_callback, write_callback,
+ metadata_callback, error_callback, f);
+#endif
+
+ sample->flags = SOUND_SAMPLEFLAG_NONE;
+
+ pos = SDL_RWtell(f->rw);
+ if (SDL_RWseek(f->rw, 0, SEEK_END) > 0)
+ {
+ f->stream_length = SDL_RWtell(f->rw);
+ if (SDL_RWseek(f->rw, pos, SEEK_SET) == -1)
+ {
+ free_flac(f);
+ BAIL_MACRO(ERR_IO_ERROR, 0);
+ } /* if */
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+ } /* if */
+
+ /*
+ * If we are not sure this is a FLAC stream, check for the STREAMINFO
+ * metadata block. If not, we'd have to peek at the first audio frame
+ * and get the sound format from there, but that is not yet
+ * implemented.
+ */
+ if (!f->is_flac)
+ {
+ d_process_metadata(decoder);
+
+ /* Still not FLAC? Give up. */
+ if (!f->is_flac)
+ {
+ free_flac(f);
+ BAIL_MACRO("FLAC: No metadata found. Not a FLAC stream?", 0);
+ } /* if */
+ } /* if */
+
+ SNDDBG(("FLAC: Accepting data stream.\n"));
+ return(1);
+} /* FLAC_open */
+
+
+static void FLAC_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ flac_t *f = (flac_t *) internal->decoder_private;
+
+ free_flac(f);
+} /* FLAC_close */
+
+
+static Uint32 FLAC_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ flac_t *f = (flac_t *) internal->decoder_private;
+ Uint32 len;
+
+ if (!d_process_one_frame(f->decoder))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ BAIL_MACRO("FLAC: Couldn't decode frame.", 0);
+ } /* if */
+
+ if (d_get_state(f->decoder) == D_END_OF_STREAM)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(0);
+ } /* if */
+
+ /* An error may have been signalled through the error callback. */
+ if (sample->flags & SOUND_SAMPLEFLAG_ERROR)
+ return(0);
+
+ return(f->frame_size);
+} /* FLAC_read */
+
+
+static int FLAC_rewind(Sound_Sample *sample)
+{
+ return FLAC_seek(sample, 0);
+} /* FLAC_rewind */
+
+
+static int FLAC_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ flac_t *f = (flac_t *) internal->decoder_private;
+
+ d_seek_absolute(f->decoder, (ms * sample->actual.rate) / 1000);
+ return(1);
+} /* FLAC_seek */
+
+#endif /* SOUND_SUPPORTS_FLAC */
+
+/* end of flac.c ... */
diff --git a/util/sdl/sound/decoders/midi.c b/util/sdl/sound/decoders/midi.c
new file mode 100644
index 00000000..b283c5c6
--- /dev/null
+++ b/util/sdl/sound/decoders/midi.c
@@ -0,0 +1,175 @@
+/*
+ * 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
+ */
+
+/*
+ * MIDI decoder for SDL_sound.
+ *
+ * This driver handles MIDI data through a stripped-down version of TiMidity.
+ * See the documentation in the timidity subdirectory.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Torbjörn Andersson. (d91tan@Update.UU.SE)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_MIDI
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+
+
+static int MIDI_init(void);
+static void MIDI_quit(void);
+static int MIDI_open(Sound_Sample *sample, const char *ext);
+static void MIDI_close(Sound_Sample *sample);
+static Uint32 MIDI_read(Sound_Sample *sample);
+static int MIDI_rewind(Sound_Sample *sample);
+static int MIDI_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_midi[] = { "MIDI", "MID", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_MIDI =
+{
+ {
+ extensions_midi,
+ "MIDI decoder, using a subset of TiMidity",
+ "Torbjörn Andersson <d91tan@Update.UU.SE>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ MIDI_init, /* init() method */
+ MIDI_quit, /* quit() method */
+ MIDI_open, /* open() method */
+ MIDI_close, /* close() method */
+ MIDI_read, /* read() method */
+ MIDI_rewind, /* rewind() method */
+ MIDI_seek /* seek() method */
+};
+
+
+static int MIDI_init(void)
+{
+ BAIL_IF_MACRO(Timidity_Init() < 0, "MIDI: Could not initialise", 0);
+ return(1);
+} /* MIDI_init */
+
+
+static void MIDI_quit(void)
+{
+ Timidity_Exit();
+} /* MIDI_quit */
+
+
+static int MIDI_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ SDL_AudioSpec spec;
+ MidiSong *song;
+
+ spec.channels = 2;
+ spec.format = AUDIO_S16SYS;
+ spec.freq = 44100;
+ spec.samples = 4096;
+
+ song = Timidity_LoadSong(rw, &spec);
+ BAIL_IF_MACRO(song == NULL, "MIDI: Not a MIDI file.", 0);
+ Timidity_SetVolume(song, 100);
+ Timidity_Start(song);
+
+ SNDDBG(("MIDI: Accepting data stream.\n"));
+
+ internal->decoder_private = (void *) song;
+
+ sample->actual.channels = 2;
+ sample->actual.rate = 44100;
+ sample->actual.format = AUDIO_S16SYS;
+
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+ return(1); /* we'll handle this data. */
+} /* MIDI_open */
+
+
+static void MIDI_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MidiSong *song = (MidiSong *) internal->decoder_private;
+
+ Timidity_FreeSong(song);
+} /* MIDI_close */
+
+
+static Uint32 MIDI_read(Sound_Sample *sample)
+{
+ Uint32 retval;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MidiSong *song = (MidiSong *) internal->decoder_private;
+
+ retval = Timidity_PlaySome(song, internal->buffer, internal->buffer_size);
+
+ /* Make sure the read went smoothly... */
+ if (retval == 0)
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+ else if (retval == -1)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+ /* (next call this EAGAIN may turn into an EOF or error.) */
+ else if (retval < internal->buffer_size)
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+ return(retval);
+} /* MIDI_read */
+
+
+static int MIDI_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MidiSong *song = (MidiSong *) internal->decoder_private;
+
+ Timidity_Start(song);
+ return(1);
+} /* MIDI_rewind */
+
+
+static int MIDI_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MidiSong *song = (MidiSong *) internal->decoder_private;
+
+ Timidity_Seek(song, ms);
+ return(1);
+} /* MIDI_seek */
+
+#endif /* SOUND_SUPPORTS_MIDI */
+
+
+/* end of midi.c ... */
+
diff --git a/util/sdl/sound/decoders/mikmod.c b/util/sdl/sound/decoders/mikmod.c
new file mode 100644
index 00000000..ebfed455
--- /dev/null
+++ b/util/sdl/sound/decoders/mikmod.c
@@ -0,0 +1,344 @@
+/*
+ * 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
+ */
+
+/*
+ * Module player for SDL_sound. This driver handles anything MikMod does, and
+ * is based on SDL_mixer.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Torbjörn Andersson (d91tan@Update.UU.SE)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_MIKMOD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "mikmod.h"
+
+
+static int MIKMOD_init(void);
+static void MIKMOD_quit(void);
+static int MIKMOD_open(Sound_Sample *sample, const char *ext);
+static void MIKMOD_close(Sound_Sample *sample);
+static Uint32 MIKMOD_read(Sound_Sample *sample);
+static int MIKMOD_rewind(Sound_Sample *sample);
+static int MIKMOD_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_mikmod[] =
+{
+ "669", /* Composer 669 */
+ "AMF", /* DMP Advanced Module Format */
+ "DSM", /* DSIK internal format */
+ "FAR", /* Farandole module */
+ "GDM", /* General DigiMusic module */
+ "IMF", /* Imago Orpheus module */
+ "IT", /* Impulse tracker */
+ "M15", /* 15 instrument MOD / Ultimate Sound Tracker (old M15 format) */
+ "MED", /* Amiga MED module */
+ "MOD", /* Generic MOD (Protracker, StarTracker, FastTracker, etc) */
+ "MTM", /* MTM module */
+ "OKT", /* Oktalyzer module */
+ "S3M", /* Screamtracker module */
+ "STM", /* Screamtracker 2 module */
+ "STX", /* STMIK 0.2 module */
+ "ULT", /* Ultratracker module */
+ "UNI", /* UNIMOD - libmikmod's and APlayer's internal module format */
+ "XM", /* Fasttracker module */
+ NULL
+};
+
+const Sound_DecoderFunctions __Sound_DecoderFunctions_MIKMOD =
+{
+ {
+ extensions_mikmod,
+ "Play modules through MikMod",
+ "Torbjörn Andersson <d91tan@Update.UU.SE>",
+ "http://mikmod.raphnet.net/"
+ },
+
+ MIKMOD_init, /* init() method */
+ MIKMOD_quit, /* quit() method */
+ MIKMOD_open, /* open() method */
+ MIKMOD_close, /* close() method */
+ MIKMOD_read, /* read() method */
+ MIKMOD_rewind, /* rewind() method */
+ MIKMOD_seek /* seek() method */
+};
+
+
+/* Make MikMod read from a RWops... */
+
+typedef struct MRWOPSREADER {
+ MREADER core;
+ Sound_Sample *sample;
+ int end;
+} MRWOPSREADER;
+
+static BOOL _mm_RWopsReader_eof(MREADER *reader)
+{
+ MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
+ Sound_Sample *sample = rwops_reader->sample;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ int pos = SDL_RWtell(internal->rw);
+
+ if (rwops_reader->end == pos)
+ return(1);
+
+ return(0);
+} /* _mm_RWopsReader_eof */
+
+
+static BOOL _mm_RWopsReader_read(MREADER *reader, void *ptr, size_t size)
+{
+ MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
+ Sound_Sample *sample = rwops_reader->sample;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ return(SDL_RWread(internal->rw, ptr, size, 1));
+} /* _mm_RWopsReader_Read */
+
+
+static int _mm_RWopsReader_get(MREADER *reader)
+{
+ char buf;
+ MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
+ Sound_Sample *sample = rwops_reader->sample;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ if (SDL_RWread(internal->rw, &buf, 1, 1) != 1)
+ return(EOF);
+
+ return((int) buf);
+} /* _mm_RWopsReader_get */
+
+
+static BOOL _mm_RWopsReader_seek(MREADER *reader, long offset, int whence)
+{
+ MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
+ Sound_Sample *sample = rwops_reader->sample;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ return(SDL_RWseek(internal->rw, offset, whence));
+} /* _mm_RWopsReader_seek */
+
+
+static long _mm_RWopsReader_tell(MREADER *reader)
+{
+ MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
+ Sound_Sample *sample = rwops_reader->sample;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ return(SDL_RWtell(internal->rw));
+} /* _mm_RWopsReader_tell */
+
+
+static MREADER *_mm_new_rwops_reader(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ MRWOPSREADER *reader = (MRWOPSREADER *) malloc(sizeof (MRWOPSREADER));
+ if (reader != NULL)
+ {
+ int failed_seek = 1;
+ int here;
+ reader->core.Eof = _mm_RWopsReader_eof;
+ reader->core.Read = _mm_RWopsReader_read;
+ reader->core.Get = _mm_RWopsReader_get;
+ reader->core.Seek = _mm_RWopsReader_seek;
+ reader->core.Tell = _mm_RWopsReader_tell;
+ reader->sample = sample;
+
+ /* RWops does not explicitly support an eof check, so we shall find
+ the end manually - this requires seek support for the RWop */
+ here = SDL_RWtell(internal->rw);
+ if (here != -1)
+ {
+ reader->end = SDL_RWseek(internal->rw, 0, SEEK_END);
+ if (reader->end != -1)
+ {
+ /* Move back */
+ if (SDL_RWseek(internal->rw, here, SEEK_SET) != -1)
+ failed_seek = 0;
+ } /* if */
+ } /* if */
+
+ if (failed_seek)
+ {
+ free(reader);
+ reader = NULL;
+ } /* if */
+ } /* if */
+
+ return((MREADER *) reader);
+} /* _mm_new_rwops_reader */
+
+
+static void _mm_delete_rwops_reader(MREADER *reader)
+{
+ /* SDL_sound will delete the RWops and sample at a higher level... */
+ if (reader != NULL)
+ free(reader);
+} /* _mm_delete_rwops_reader */
+
+
+
+static int MIKMOD_init(void)
+{
+ MikMod_RegisterDriver(&drv_nos);
+
+ /* Quick and dirty hack to prevent an infinite loop problem
+ * found when using SDL_mixer and SDL_sound together and
+ * both have MikMod compiled in. So, check to see if
+ * MikMod has already been registered first before calling
+ * RegisterAllLoaders()
+ */
+ if(MikMod_InfoLoader() == NULL)
+ {
+ MikMod_RegisterAllLoaders();
+ }
+ /*
+ * Both DMODE_SOFT_MUSIC and DMODE_16BITS should be set by default,
+ * so this is just for clarity. I haven't experimented with any of
+ * the other flags. There are a few which are said to give better
+ * sound quality.
+ */
+ md_mode |= (DMODE_SOFT_MUSIC | DMODE_16BITS);
+ md_mixfreq = 0;
+ md_reverb = 1;
+
+ BAIL_IF_MACRO(MikMod_Init(""), MikMod_strerror(MikMod_errno), 0);
+
+ return(1); /* success. */
+} /* MIKMOD_init */
+
+
+static void MIKMOD_quit(void)
+{
+ MikMod_Exit();
+ md_mixfreq = 0;
+} /* MIKMOD_quit */
+
+
+static int MIKMOD_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MREADER *reader;
+ MODULE *module;
+
+ reader = _mm_new_rwops_reader(sample);
+ BAIL_IF_MACRO(reader == NULL, ERR_OUT_OF_MEMORY, 0);
+ module = Player_LoadGeneric(reader, 64, 0);
+ _mm_delete_rwops_reader(reader);
+ BAIL_IF_MACRO(module == NULL, "MIKMOD: Not a module file.", 0);
+
+ module->extspd = 1;
+ module->panflag = 1;
+ module->wrap = 0;
+ module->loop = 0;
+
+ if (md_mixfreq == 0)
+ md_mixfreq = (!sample->desired.rate) ? 44100 : sample->desired.rate;
+
+ sample->actual.channels = 2;
+ sample->actual.rate = md_mixfreq;
+ sample->actual.format = AUDIO_S16SYS;
+ internal->decoder_private = (void *) module;
+
+ Player_Start(module);
+ Player_SetPosition(0);
+
+ sample->flags = SOUND_SAMPLEFLAG_NONE;
+
+ SNDDBG(("MIKMOD: Name: %s\n", module->songname));
+ SNDDBG(("MIKMOD: Type: %s\n", module->modtype));
+ SNDDBG(("MIKMOD: Accepting data stream\n"));
+
+ return(1); /* we'll handle this data. */
+} /* MIKMOD_open */
+
+
+static void MIKMOD_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MODULE *module = (MODULE *) internal->decoder_private;
+
+ Player_Free(module);
+} /* MIKMOD_close */
+
+
+static Uint32 MIKMOD_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MODULE *module = (MODULE *) internal->decoder_private;
+
+ /* Switch to the current module, stopping any previous one. */
+ Player_Start(module);
+ if (!Player_Active())
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(0);
+ } /* if */
+ return((Uint32) VC_WriteBytes(internal->buffer, internal->buffer_size));
+} /* MIKMOD_read */
+
+
+static int MIKMOD_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MODULE *module = (MODULE *) internal->decoder_private;
+
+ Player_Start(module);
+ Player_SetPosition(0);
+ return(1);
+} /* MIKMOD_rewind */
+
+
+static int MIKMOD_seek(Sound_Sample *sample, Uint32 ms)
+{
+#if 0
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ MODULE *module = (MODULE *) internal->decoder_private;
+
+ /*
+ * Heaven may know what the argument to Player_SetPosition() is.
+ * I, however, haven't the faintest idea.
+ */
+ Player_Start(module);
+ Player_SetPosition(ms);
+ return(1);
+#else
+ BAIL_MACRO("MIKMOD: Seeking not implemented", 0);
+#endif
+} /* MIKMOD_seek */
+
+#endif /* SOUND_SUPPORTS_MIKMOD */
+
+
+/* end of mikmod.c ... */
diff --git a/util/sdl/sound/decoders/modplug.c b/util/sdl/sound/decoders/modplug.c
new file mode 100644
index 00000000..b2b3233d
--- /dev/null
+++ b/util/sdl/sound/decoders/modplug.c
@@ -0,0 +1,340 @@
+/*
+ * 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
+ */
+
+/*
+ * Module player for SDL_sound. This driver handles anything that ModPlug does.
+ *
+ * ModPlug can be found at http://sourceforge.net/projects/modplug-xmms
+ *
+ * An unofficial version of modplug with all C++ dependencies removed is also
+ * available: http://freecraft.net/snapshots/
+ * (Look for something like "libmodplug-johns-*.tar.gz")
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Torbjörn Andersson (d91tan@Update.UU.SE)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_MODPLUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#if SOUND_MODPLUG_IN_OWN_PATH
+#include "libmodplug/modplug.h"
+#else
+#include "modplug.h"
+#endif
+
+static int MODPLUG_init(void);
+static void MODPLUG_quit(void);
+static int MODPLUG_open(Sound_Sample *sample, const char *ext);
+static void MODPLUG_close(Sound_Sample *sample);
+static Uint32 MODPLUG_read(Sound_Sample *sample);
+static int MODPLUG_rewind(Sound_Sample *sample);
+static int MODPLUG_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_modplug[] =
+{
+ /* The XMMS plugin is apparently able to load compressed modules as
+ * well, but libmodplug does not handle this.
+ */
+ "669", /* Composer 669 / UNIS 669 module */
+ "AMF", /* ASYLUM Music Format / Advanced Music Format(DSM) */
+ "AMS", /* AMS module */
+ "DBM", /* DigiBooster Pro Module */
+ "DMF", /* DMF DELUSION DIGITAL MUSIC FILEFORMAT (X-Tracker) */
+ "DSM", /* DSIK Internal Format module */
+ "FAR", /* Farandole module */
+ "IT", /* Impulse Tracker IT file */
+ "MDL", /* DigiTracker module */
+#if 0
+ "J2B", /* Not implemented? What is it anyway? */
+#endif
+ "MED", /* OctaMed MED file */
+ "MOD", /* ProTracker / NoiseTracker MOD/NST file */
+ "MT2", /* MadTracker 2.0 */
+ "MTM", /* MTM file */
+ "OKT", /* Oktalyzer module */
+ "PTM", /* PTM PolyTracker module */
+ "PSM", /* PSM module */
+ "S3M", /* ScreamTracker file */
+ "STM", /* ST 2.xx */
+ "ULT",
+ "UMX",
+ "XM", /* FastTracker II */
+ NULL
+};
+
+const Sound_DecoderFunctions __Sound_DecoderFunctions_MODPLUG =
+{
+ {
+ extensions_modplug,
+ "Play modules through ModPlug",
+ "Torbjörn Andersson <d91tan@Update.UU.SE>",
+ "http://modplug-xmms.sourceforge.net/"
+ },
+
+ MODPLUG_init, /* init() method */
+ MODPLUG_quit, /* quit() method */
+ MODPLUG_open, /* open() method */
+ MODPLUG_close, /* close() method */
+ MODPLUG_read, /* read() method */
+ MODPLUG_rewind, /* rewind() method */
+ MODPLUG_seek /* seek() method */
+};
+
+
+static ModPlug_Settings settings;
+static Sound_AudioInfo current_audioinfo;
+static unsigned int total_mods_decoding = 0;
+static SDL_mutex *modplug_mutex = NULL;
+
+static int MODPLUG_init(void)
+{
+ assert(modplug_mutex == NULL);
+
+ /*
+ * The settings will require some experimenting. I've borrowed some
+ * of them from the XMMS ModPlug plugin.
+ */
+ settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING;
+
+#ifndef _WIN32_WCE
+ settings.mFlags |= MODPLUG_ENABLE_NOISE_REDUCTION |
+ MODPLUG_ENABLE_REVERB |
+ MODPLUG_ENABLE_MEGABASS |
+ MODPLUG_ENABLE_SURROUND;
+
+ settings.mReverbDepth = 30;
+ settings.mReverbDelay = 100;
+ settings.mBassAmount = 40;
+ settings.mBassRange = 30;
+ settings.mSurroundDepth = 20;
+ settings.mSurroundDelay = 20;
+#endif
+
+ settings.mChannels = 2;
+ settings.mBits = 16;
+ settings.mFrequency = 44100;
+ settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
+ settings.mLoopCount = 0;
+
+ current_audioinfo.channels = 2;
+ current_audioinfo.rate = 44100;
+ current_audioinfo.format = AUDIO_S16SYS;
+ total_mods_decoding = 0;
+
+ modplug_mutex = SDL_CreateMutex();
+
+ ModPlug_SetSettings(&settings);
+ return(1); /* success. */
+} /* MODPLUG_init */
+
+
+static void MODPLUG_quit(void)
+{
+ assert(total_mods_decoding == 0);
+
+ if (modplug_mutex != NULL)
+ {
+ SDL_DestroyMutex(modplug_mutex);
+ modplug_mutex = NULL;
+ } /* if */
+} /* MODPLUG_quit */
+
+
+/*
+ * Most MOD files I've seen have tended to be a few hundred KB, even if some
+ * of them were much smaller than that.
+ */
+#define CHUNK_SIZE 65536
+
+static int MODPLUG_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ ModPlugFile *module;
+ Uint8 *data;
+ size_t size;
+ Uint32 retval;
+ int has_extension = 0;
+ int i;
+
+ /*
+ * Apparently ModPlug's loaders are too forgiving. They gladly accept
+ * streams that they shouldn't. For now, rely on file extension instead.
+ */
+ for (i = 0; extensions_modplug[i] != NULL; i++)
+ {
+ if (__Sound_strcasecmp(ext, extensions_modplug[i]) == 0)
+ {
+ has_extension = 1;
+ break;
+ } /* if */
+ } /* for */
+
+ if (!has_extension)
+ {
+ SNDDBG(("MODPLUG: Unrecognized file type: %s\n", ext));
+ BAIL_MACRO("MODPLUG: Not a module file.", 0);
+ } /* if */
+
+ /*
+ * ModPlug needs the entire stream in one big chunk. I don't like it,
+ * but I don't think there's any way around it.
+ */
+ data = (Uint8 *) malloc(CHUNK_SIZE);
+ BAIL_IF_MACRO(data == NULL, ERR_OUT_OF_MEMORY, 0);
+ size = 0;
+
+ do
+ {
+ retval = SDL_RWread(internal->rw, &data[size], 1, CHUNK_SIZE);
+ size += retval;
+ if (retval == CHUNK_SIZE)
+ {
+ data = (Uint8 *) realloc(data, size + CHUNK_SIZE);
+ BAIL_IF_MACRO(data == NULL, ERR_OUT_OF_MEMORY, 0);
+ } /* if */
+ } while (retval > 0);
+
+ /*
+ * It's only safe to change these settings when there're
+ * no other mods being decoded...
+ */
+ if (modplug_mutex != NULL)
+ SDL_LockMutex(modplug_mutex);
+
+ if (total_mods_decoding > 0)
+ {
+ /* other mods decoding: use the same settings they are. */
+ memcpy(&sample->actual, &current_audioinfo, sizeof (Sound_AudioInfo));
+ } /* if */
+ else
+ {
+ /* no other mods decoding: define the new ModPlug output settings. */
+ memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo));
+ if (sample->actual.rate == 0)
+ sample->actual.rate = 44100;
+ if (sample->actual.channels == 0)
+ sample->actual.channels = 2;
+ if (sample->actual.format == 0)
+ sample->actual.format = AUDIO_S16SYS;
+
+ memcpy(&current_audioinfo, &sample->actual, sizeof (Sound_AudioInfo));
+ settings.mChannels=sample->actual.channels;
+ settings.mFrequency=sample->actual.rate;
+ settings.mBits = sample->actual.format & 0xFF;
+ ModPlug_SetSettings(&settings);
+ } /* else */
+
+ /*
+ * The buffer may be a bit too large, but that doesn't matter. I think
+ * it's safe to free it as soon as ModPlug_Load() is finished anyway.
+ */
+ module = ModPlug_Load((void *) data, size);
+ free(data);
+ if (module == NULL)
+ {
+ if (modplug_mutex != NULL)
+ SDL_UnlockMutex(modplug_mutex);
+
+ BAIL_MACRO("MODPLUG: Not a module file.", 0);
+ } /* if */
+
+ total_mods_decoding++;
+
+ if (modplug_mutex != NULL)
+ SDL_UnlockMutex(modplug_mutex);
+
+ SNDDBG(("MODPLUG: [%d ms] %s\n",
+ ModPlug_GetLength(module), ModPlug_GetName(module)));
+
+ internal->decoder_private = (void *) module;
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+
+ SNDDBG(("MODPLUG: Accepting data stream\n"));
+ return(1); /* we'll handle this data. */
+} /* MODPLUG_open */
+
+
+static void MODPLUG_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
+
+ if (modplug_mutex != NULL)
+ SDL_LockMutex(modplug_mutex);
+
+ total_mods_decoding--;
+
+ if (modplug_mutex != NULL)
+ SDL_UnlockMutex(modplug_mutex);
+
+ ModPlug_Unload(module);
+} /* MODPLUG_close */
+
+
+static Uint32 MODPLUG_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
+ int retval;
+
+ retval = ModPlug_Read(module, internal->buffer, internal->buffer_size);
+ if (retval == 0)
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(retval);
+} /* MODPLUG_read */
+
+
+static int MODPLUG_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
+
+ ModPlug_Seek(module, 0);
+ return(1);
+} /* MODPLUG_rewind */
+
+
+static int MODPLUG_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
+
+ /* Assume that this will work. */
+ ModPlug_Seek(module, ms);
+ return(1);
+} /* MODPLUG_seek */
+
+#endif /* SOUND_SUPPORTS_MODPLUG */
+
+
+/* end of modplug.c ... */
diff --git a/util/sdl/sound/decoders/mpglib.c b/util/sdl/sound/decoders/mpglib.c
new file mode 100644
index 00000000..d7ee4686
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib.c
@@ -0,0 +1,298 @@
+/*
+ * 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
+ */
+
+/*
+ * MPGLIB decoder for SDL_sound. This is a very lightweight MP3 decoder,
+ * which is included with the SDL_sound source, so that it doesn't rely on
+ * unnecessary external libraries.
+ *
+ * The SMPEG decoder plays back more forms of MPEGs, and may behave better or
+ * worse under various conditions. mpglib is (apparently) more efficient than
+ * SMPEG, and, again, doesn't need an external library. You should test both
+ * decoders and use what you find works best for you.
+ *
+ * mpglib is an LGPL'd portion of mpg123, which can be found in its original
+ * form at: http://www.mpg123.de/
+ *
+ * Please see the file COPYING in the source's root directory. The included
+ * source code for mpglib falls under the LGPL, which is the same license as
+ * SDL_sound (so you can consider it a single work).
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_MPGLIB
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mpglib/mpg123_sdlsound.h"
+#include "mpglib/mpglib_sdlsound.h"
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int MPGLIB_init(void);
+static void MPGLIB_quit(void);
+static int MPGLIB_open(Sound_Sample *sample, const char *ext);
+static void MPGLIB_close(Sound_Sample *sample);
+static Uint32 MPGLIB_read(Sound_Sample *sample);
+static int MPGLIB_rewind(Sound_Sample *sample);
+static int MPGLIB_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_mpglib[] = { "MP3", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_MPGLIB =
+{
+ {
+ extensions_mpglib,
+ "MP3 decoding via internal mpglib",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ MPGLIB_init, /* init() method */
+ MPGLIB_quit, /* quit() method */
+ MPGLIB_open, /* open() method */
+ MPGLIB_close, /* close() method */
+ MPGLIB_read, /* read() method */
+ MPGLIB_rewind, /* rewind() method */
+ MPGLIB_seek /* seek() method */
+};
+
+
+/* this is what we store in our internal->decoder_private field... */
+typedef struct
+{
+ struct mpstr mp;
+ Uint8 inbuf[16384];
+ Uint8 outbuf[8192];
+ int outleft;
+ int outpos;
+} mpglib_t;
+
+
+
+static int MPGLIB_init(void)
+{
+ return(1); /* always succeeds. */
+} /* MPGLIB_init */
+
+
+static void MPGLIB_quit(void)
+{
+ /* it's a no-op. */
+} /* MPGLIB_quit */
+
+
+static int MPGLIB_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ mpglib_t *mpg = NULL;
+ int rc;
+
+ /*
+ * If I understand things correctly, MP3 files don't really have any
+ * magic header we can check for. The MP3 player is expected to just
+ * pick the first thing that looks like a valid frame and start
+ * playing from there.
+ *
+ * So here's what we do: If the caller insists that this is really
+ * MP3 we'll take his word for it. Otherwise, use the same test as
+ * SDL_mixer does and check if the stream starts with something that
+ * looks like a frame.
+ *
+ * A frame begins with 11 bits of frame sync (all bits must be set),
+ * followed by a two-bit MPEG Audio version ID:
+ *
+ * 00 - MPEG Version 2.5 (later extension of MPEG 2)
+ * 01 - reserved
+ * 10 - MPEG Version 2 (ISO/IEC 13818-3)
+ * 11 - MPEG Version 1 (ISO/IEC 11172-3)
+ *
+ * Apparently we don't handle MPEG Version 2.5.
+ */
+ if (__Sound_strcasecmp(ext, "MP3") != 0)
+ {
+ Uint8 mp3_magic[2];
+
+ if (SDL_RWread(internal->rw, mp3_magic, sizeof (mp3_magic), 1) != 1)
+ BAIL_MACRO("MPGLIB: Could not read MP3 magic.", 0);
+
+ if (mp3_magic[0] != 0xFF || (mp3_magic[1] & 0xF0) != 0xF0)
+ BAIL_MACRO("MPGLIB: Not an MP3 stream.", 0);
+
+ /* If the seek fails, we'll probably miss a frame, but oh well. */
+ SDL_RWseek(internal->rw, -sizeof (mp3_magic), SEEK_CUR);
+ } /* if */
+
+ mpg = (mpglib_t *) malloc(sizeof (mpglib_t));
+ BAIL_IF_MACRO(mpg == NULL, ERR_OUT_OF_MEMORY, 0);
+ memset(mpg, '\0', sizeof (mpglib_t));
+ InitMP3(&mpg->mp);
+
+ rc = SDL_RWread(internal->rw, mpg->inbuf, 1, sizeof (mpg->inbuf));
+ if (rc <= 0)
+ {
+ free(mpg);
+ BAIL_MACRO("MPGLIB: Failed to read any data at all", 0);
+ } /* if */
+
+ if (decodeMP3(&mpg->mp, mpg->inbuf, rc,
+ mpg->outbuf, sizeof (mpg->outbuf),
+ &mpg->outleft) == MP3_ERR)
+ {
+ free(mpg);
+ BAIL_MACRO("MPGLIB: Not an MP3 stream?", 0);
+ } /* if */
+
+ SNDDBG(("MPGLIB: Accepting data stream.\n"));
+
+ internal->decoder_private = mpg;
+ sample->actual.rate = mpglib_freqs[mpg->mp.fr.sampling_frequency];
+ sample->actual.channels = mpg->mp.fr.stereo;
+ sample->actual.format = AUDIO_S16SYS;
+ sample->flags = SOUND_SAMPLEFLAG_NONE;
+
+ return(1); /* we'll handle this data. */
+} /* MPGLIB_open */
+
+
+static void MPGLIB_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ mpglib_t *mpg = ((mpglib_t *) internal->decoder_private);
+ ExitMP3(&mpg->mp);
+ free(mpg);
+} /* MPGLIB_close */
+
+
+static Uint32 MPGLIB_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ mpglib_t *mpg = ((mpglib_t *) internal->decoder_private);
+ Uint32 bw = 0;
+ int rc;
+
+ while (bw < internal->buffer_size)
+ {
+ if (mpg->outleft > 0)
+ {
+ size_t cpysize = internal->buffer_size - bw;
+ if (cpysize > mpg->outleft)
+ cpysize = mpg->outleft;
+ memcpy(((Uint8 *) internal->buffer) + bw,
+ mpg->outbuf + mpg->outpos, cpysize);
+ bw += cpysize;
+ mpg->outpos += cpysize;
+ mpg->outleft -= cpysize;
+ continue;
+ } /* if */
+
+ /* need to decode more from the MP3 stream... */
+ mpg->outpos = 0;
+ rc = decodeMP3(&mpg->mp, NULL, 0, mpg->outbuf,
+ sizeof (mpg->outbuf), &mpg->outleft);
+ if (rc == MP3_ERR)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(bw);
+ } /* if */
+
+ else if (rc == MP3_NEED_MORE)
+ {
+ rc = SDL_RWread(internal->rw, mpg->inbuf, 1, sizeof (mpg->inbuf));
+ if (rc == -1)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(bw);
+ } /* if */
+
+ else if (rc == 0)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(bw);
+ } /* else if */
+
+ /* make sure there isn't an ID3 tag. */
+ /*
+ * !!! FIXME: This can fail under the following circumstances:
+ * First, if there's the sequence "TAG" 128 bytes from the end
+ * of a read that isn't the EOF. This is unlikely.
+ * Second, if the TAG sequence is split between two reads (ie,
+ * the last byte of a read is 'T', and the next read is the
+ * final 127 bytes of the stream, being the rest of the ID3 tag).
+ * While this is more likely, it's still not very likely at all.
+ * Still, something SHOULD be done about this.
+ * ID3v2 tags are more complex, too, not to mention LYRICS tags,
+ * etc, which aren't handled, either. Hey, this IS meant to be
+ * a lightweight decoder. Use SMPEG if you need an all-purpose
+ * decoder. mpglib really assumes you control all your assets.
+ */
+ if (rc >= 128)
+ {
+ Uint8 *ptr = &mpg->inbuf[rc - 128];
+ if ((ptr[0] == 'T') && (ptr[1] == 'A') && (ptr[2] == 'G'))
+ rc -= 128; /* disregard it. */
+ } /* if */
+
+ rc = decodeMP3(&mpg->mp, mpg->inbuf, rc,
+ mpg->outbuf, sizeof (mpg->outbuf),
+ &mpg->outleft);
+ if (rc == MP3_ERR)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(bw);
+ } /* if */
+ } /* else if */
+ } /* while */
+
+ return(bw);
+} /* MPGLIB_read */
+
+
+static int MPGLIB_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ mpglib_t *mpg = ((mpglib_t *) internal->decoder_private);
+ BAIL_IF_MACRO(SDL_RWseek(internal->rw, 0, SEEK_SET) != 0, ERR_IO_ERROR, 0);
+
+ /* this is just resetting some fields in a structure; it's very fast. */
+ ExitMP3(&mpg->mp);
+ InitMP3(&mpg->mp);
+ mpg->outpos = mpg->outleft = 0;
+ return(1);
+} /* MPGLIB_rewind */
+
+
+static int MPGLIB_seek(Sound_Sample *sample, Uint32 ms)
+{
+ BAIL_MACRO("MPGLIB: Seeking not implemented", 0);
+} /* MPGLIB_seek */
+
+#endif /* SOUND_SUPPORTS_MPGLIB */
+
+
+/* end of mpglib.c ... */
+
diff --git a/util/sdl/sound/decoders/mpglib/CHANGES b/util/sdl/sound/decoders/mpglib/CHANGES
new file mode 100644
index 00000000..b9a8c50c
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/CHANGES
@@ -0,0 +1,4 @@
+14/Oct/1999:
+ - VBR fix
+ - Layer2 and Layer1 added
+
diff --git a/util/sdl/sound/decoders/mpglib/Makefile.am b/util/sdl/sound/decoders/mpglib/Makefile.am
new file mode 100644
index 00000000..8f9a8d8e
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/Makefile.am
@@ -0,0 +1,23 @@
+if USE_MPGLIB
+noinst_LTLIBRARIES = libmpglib.la
+endif
+
+INCLUDES = -I$(top_srcdir)
+libmpglib_la_CFLAGS = -DLAYER1 -DLAYER2 -DLAYER3
+
+libmpglib_la_SOURCES = \
+ mpglib_common.c \
+ huffman.h \
+ layer1.c \
+ tabinit.c \
+ dct64_i386.c \
+ interface.c \
+ layer2.c \
+ mpg123_sdlsound.h \
+ decode_i386.c \
+ l2tables.h \
+ layer3.c \
+ mpglib_sdlsound.h
+
+EXTRA_DIST = CHANGES README README-sdlsound TODO main.c
+
diff --git a/util/sdl/sound/decoders/mpglib/Makefile.in b/util/sdl/sound/decoders/mpglib/Makefile.in
new file mode 100644
index 00000000..dd346f88
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/Makefile.in
@@ -0,0 +1,532 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = decoders/mpglib
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in TODO
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmpglib_la_LIBADD =
+am_libmpglib_la_OBJECTS = libmpglib_la-mpglib_common.lo \
+ libmpglib_la-layer1.lo libmpglib_la-tabinit.lo \
+ libmpglib_la-dct64_i386.lo libmpglib_la-interface.lo \
+ libmpglib_la-layer2.lo libmpglib_la-decode_i386.lo \
+ libmpglib_la-layer3.lo
+libmpglib_la_OBJECTS = $(am_libmpglib_la_OBJECTS)
+@USE_MPGLIB_TRUE@am_libmpglib_la_rpath =
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libmpglib_la_SOURCES)
+DIST_SOURCES = $(libmpglib_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERFACE_AGE = @INTERFACE_AGE@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_MPGLIB_FALSE = @USE_MPGLIB_FALSE@
+USE_MPGLIB_TRUE = @USE_MPGLIB_TRUE@
+USE_PHYSICSFS_FALSE = @USE_PHYSICSFS_FALSE@
+USE_PHYSICSFS_TRUE = @USE_PHYSICSFS_TRUE@
+USE_TIMIDITY_FALSE = @USE_TIMIDITY_FALSE@
+USE_TIMIDITY_TRUE = @USE_TIMIDITY_TRUE@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+@USE_MPGLIB_TRUE@noinst_LTLIBRARIES = libmpglib.la
+INCLUDES = -I$(top_srcdir)
+libmpglib_la_CFLAGS = -DLAYER1 -DLAYER2 -DLAYER3
+libmpglib_la_SOURCES = \
+ mpglib_common.c \
+ huffman.h \
+ layer1.c \
+ tabinit.c \
+ dct64_i386.c \
+ interface.c \
+ layer2.c \
+ mpg123_sdlsound.h \
+ decode_i386.c \
+ l2tables.h \
+ layer3.c \
+ mpglib_sdlsound.h
+
+EXTRA_DIST = CHANGES README README-sdlsound TODO main.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign decoders/mpglib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign decoders/mpglib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libmpglib.la: $(libmpglib_la_OBJECTS) $(libmpglib_la_DEPENDENCIES)
+ $(LINK) $(am_libmpglib_la_rpath) $(libmpglib_la_LDFLAGS) $(libmpglib_la_OBJECTS) $(libmpglib_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-dct64_i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-decode_i386.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-layer1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-layer2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-layer3.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-mpglib_common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmpglib_la-tabinit.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libmpglib_la-mpglib_common.lo: mpglib_common.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-mpglib_common.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-mpglib_common.Tpo" -c -o libmpglib_la-mpglib_common.lo `test -f 'mpglib_common.c' || echo '$(srcdir)/'`mpglib_common.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-mpglib_common.Tpo" "$(DEPDIR)/libmpglib_la-mpglib_common.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-mpglib_common.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mpglib_common.c' object='libmpglib_la-mpglib_common.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-mpglib_common.lo `test -f 'mpglib_common.c' || echo '$(srcdir)/'`mpglib_common.c
+
+libmpglib_la-layer1.lo: layer1.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-layer1.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-layer1.Tpo" -c -o libmpglib_la-layer1.lo `test -f 'layer1.c' || echo '$(srcdir)/'`layer1.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-layer1.Tpo" "$(DEPDIR)/libmpglib_la-layer1.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-layer1.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='layer1.c' object='libmpglib_la-layer1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-layer1.lo `test -f 'layer1.c' || echo '$(srcdir)/'`layer1.c
+
+libmpglib_la-tabinit.lo: tabinit.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-tabinit.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-tabinit.Tpo" -c -o libmpglib_la-tabinit.lo `test -f 'tabinit.c' || echo '$(srcdir)/'`tabinit.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-tabinit.Tpo" "$(DEPDIR)/libmpglib_la-tabinit.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-tabinit.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tabinit.c' object='libmpglib_la-tabinit.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-tabinit.lo `test -f 'tabinit.c' || echo '$(srcdir)/'`tabinit.c
+
+libmpglib_la-dct64_i386.lo: dct64_i386.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-dct64_i386.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-dct64_i386.Tpo" -c -o libmpglib_la-dct64_i386.lo `test -f 'dct64_i386.c' || echo '$(srcdir)/'`dct64_i386.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-dct64_i386.Tpo" "$(DEPDIR)/libmpglib_la-dct64_i386.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-dct64_i386.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dct64_i386.c' object='libmpglib_la-dct64_i386.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-dct64_i386.lo `test -f 'dct64_i386.c' || echo '$(srcdir)/'`dct64_i386.c
+
+libmpglib_la-interface.lo: interface.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-interface.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-interface.Tpo" -c -o libmpglib_la-interface.lo `test -f 'interface.c' || echo '$(srcdir)/'`interface.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-interface.Tpo" "$(DEPDIR)/libmpglib_la-interface.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-interface.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='interface.c' object='libmpglib_la-interface.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-interface.lo `test -f 'interface.c' || echo '$(srcdir)/'`interface.c
+
+libmpglib_la-layer2.lo: layer2.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-layer2.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-layer2.Tpo" -c -o libmpglib_la-layer2.lo `test -f 'layer2.c' || echo '$(srcdir)/'`layer2.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-layer2.Tpo" "$(DEPDIR)/libmpglib_la-layer2.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-layer2.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='layer2.c' object='libmpglib_la-layer2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-layer2.lo `test -f 'layer2.c' || echo '$(srcdir)/'`layer2.c
+
+libmpglib_la-decode_i386.lo: decode_i386.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-decode_i386.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-decode_i386.Tpo" -c -o libmpglib_la-decode_i386.lo `test -f 'decode_i386.c' || echo '$(srcdir)/'`decode_i386.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-decode_i386.Tpo" "$(DEPDIR)/libmpglib_la-decode_i386.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-decode_i386.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='decode_i386.c' object='libmpglib_la-decode_i386.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-decode_i386.lo `test -f 'decode_i386.c' || echo '$(srcdir)/'`decode_i386.c
+
+libmpglib_la-layer3.lo: layer3.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -MT libmpglib_la-layer3.lo -MD -MP -MF "$(DEPDIR)/libmpglib_la-layer3.Tpo" -c -o libmpglib_la-layer3.lo `test -f 'layer3.c' || echo '$(srcdir)/'`layer3.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libmpglib_la-layer3.Tpo" "$(DEPDIR)/libmpglib_la-layer3.Plo"; else rm -f "$(DEPDIR)/libmpglib_la-layer3.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='layer3.c' object='libmpglib_la-layer3.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmpglib_la_CFLAGS) $(CFLAGS) -c -o libmpglib_la-layer3.lo `test -f 'layer3.c' || echo '$(srcdir)/'`layer3.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/sdl/sound/decoders/mpglib/README b/util/sdl/sound/decoders/mpglib/README
new file mode 100644
index 00000000..2465ffaa
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/README
@@ -0,0 +1,39 @@
+MP3 library
+-----------
+Version 0.2a
+
+This decoder is a 'light' version (thrown out all unnecessay parts)
+from the mpg123 package. I made this for a company.
+
+Currently only Layer3 is enabled to save some space. Layer1,2 isn't
+tested at all. The interface will not change significantly.
+A backport to the mpg123 package is planed.
+
+compiled and tested only on Solaris 2.6
+main.c contains a simple demo application for library.
+
+COPYING: you may use this source under LGPL terms!
+ (Yes, I switched to LGPL for the _mpglib_ part!)
+
+PLEASE NOTE: This software may contain patented algorithms (at least
+ patented in some countries). It may be not allowed to sell/use products
+ based on this source code in these countries. Check this out first!
+
+COPYRIGHT of MP3 music:
+ Please note, that the duplicating of copyrighted music without explicit
+ permission violates the rights of the owner.
+
+SENDING PATCHES:
+ The current version is under LGPL. Please consider this when sending patches or
+ changes. I also want to have the freedom to sell the code to companies that
+ cannot or do not want to use the code under LGPL. So, if you send me
+ significant patches, I need your explicit permission to do this. Of course,
+ there will always be the LGPLed open source version of the 100% same code.
+ In the case you cannot accept this: the code is free, it's your freedom
+ to distribute your changes again under LGPL.
+
+FEEDBACK:
+ I'm interessted to here from you, when you use this package as part
+ of another project.
+
+
diff --git a/util/sdl/sound/decoders/mpglib/README-sdlsound b/util/sdl/sound/decoders/mpglib/README-sdlsound
new file mode 100644
index 00000000..e24073b4
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/README-sdlsound
@@ -0,0 +1,7 @@
+This package, according to the README, is under the LGPL, which means it uses
+the same license as SDL_sound.
+
+mpglib is part of mpg123, which can be found at http://www.mpg123.de/ ...
+
+--ryan.
+
diff --git a/util/sdl/sound/decoders/mpglib/TODO b/util/sdl/sound/decoders/mpglib/TODO
new file mode 100644
index 00000000..e69de29b
diff --git a/util/sdl/sound/decoders/mpglib/dct64_i386.c b/util/sdl/sound/decoders/mpglib/dct64_i386.c
new file mode 100644
index 00000000..67c1fa5e
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/dct64_i386.c
@@ -0,0 +1,315 @@
+
+/*
+ * Discrete Cosine Tansform (DCT) for subband synthesis
+ * optimized for machines with no auto-increment.
+ * The performance is highly compiler dependend. Maybe
+ * the dct64.c version for 'normal' processor may be faster
+ * even for Intel processors.
+ */
+
+#include "mpg123_sdlsound.h"
+
+static void dct64_1(real *out0,real *out1,real *b1,real *b2,real *samples)
+{
+
+ {
+ register real *costab = pnts[0];
+
+ b1[0x00] = samples[0x00] + samples[0x1F];
+ b1[0x1F] = (samples[0x00] - samples[0x1F]) * costab[0x0];
+
+ b1[0x01] = samples[0x01] + samples[0x1E];
+ b1[0x1E] = (samples[0x01] - samples[0x1E]) * costab[0x1];
+
+ b1[0x02] = samples[0x02] + samples[0x1D];
+ b1[0x1D] = (samples[0x02] - samples[0x1D]) * costab[0x2];
+
+ b1[0x03] = samples[0x03] + samples[0x1C];
+ b1[0x1C] = (samples[0x03] - samples[0x1C]) * costab[0x3];
+
+ b1[0x04] = samples[0x04] + samples[0x1B];
+ b1[0x1B] = (samples[0x04] - samples[0x1B]) * costab[0x4];
+
+ b1[0x05] = samples[0x05] + samples[0x1A];
+ b1[0x1A] = (samples[0x05] - samples[0x1A]) * costab[0x5];
+
+ b1[0x06] = samples[0x06] + samples[0x19];
+ b1[0x19] = (samples[0x06] - samples[0x19]) * costab[0x6];
+
+ b1[0x07] = samples[0x07] + samples[0x18];
+ b1[0x18] = (samples[0x07] - samples[0x18]) * costab[0x7];
+
+ b1[0x08] = samples[0x08] + samples[0x17];
+ b1[0x17] = (samples[0x08] - samples[0x17]) * costab[0x8];
+
+ b1[0x09] = samples[0x09] + samples[0x16];
+ b1[0x16] = (samples[0x09] - samples[0x16]) * costab[0x9];
+
+ b1[0x0A] = samples[0x0A] + samples[0x15];
+ b1[0x15] = (samples[0x0A] - samples[0x15]) * costab[0xA];
+
+ b1[0x0B] = samples[0x0B] + samples[0x14];
+ b1[0x14] = (samples[0x0B] - samples[0x14]) * costab[0xB];
+
+ b1[0x0C] = samples[0x0C] + samples[0x13];
+ b1[0x13] = (samples[0x0C] - samples[0x13]) * costab[0xC];
+
+ b1[0x0D] = samples[0x0D] + samples[0x12];
+ b1[0x12] = (samples[0x0D] - samples[0x12]) * costab[0xD];
+
+ b1[0x0E] = samples[0x0E] + samples[0x11];
+ b1[0x11] = (samples[0x0E] - samples[0x11]) * costab[0xE];
+
+ b1[0x0F] = samples[0x0F] + samples[0x10];
+ b1[0x10] = (samples[0x0F] - samples[0x10]) * costab[0xF];
+ }
+
+
+ {
+ register real *costab = pnts[1];
+
+ b2[0x00] = b1[0x00] + b1[0x0F];
+ b2[0x0F] = (b1[0x00] - b1[0x0F]) * costab[0];
+ b2[0x01] = b1[0x01] + b1[0x0E];
+ b2[0x0E] = (b1[0x01] - b1[0x0E]) * costab[1];
+ b2[0x02] = b1[0x02] + b1[0x0D];
+ b2[0x0D] = (b1[0x02] - b1[0x0D]) * costab[2];
+ b2[0x03] = b1[0x03] + b1[0x0C];
+ b2[0x0C] = (b1[0x03] - b1[0x0C]) * costab[3];
+ b2[0x04] = b1[0x04] + b1[0x0B];
+ b2[0x0B] = (b1[0x04] - b1[0x0B]) * costab[4];
+ b2[0x05] = b1[0x05] + b1[0x0A];
+ b2[0x0A] = (b1[0x05] - b1[0x0A]) * costab[5];
+ b2[0x06] = b1[0x06] + b1[0x09];
+ b2[0x09] = (b1[0x06] - b1[0x09]) * costab[6];
+ b2[0x07] = b1[0x07] + b1[0x08];
+ b2[0x08] = (b1[0x07] - b1[0x08]) * costab[7];
+
+ b2[0x10] = b1[0x10] + b1[0x1F];
+ b2[0x1F] = (b1[0x1F] - b1[0x10]) * costab[0];
+ b2[0x11] = b1[0x11] + b1[0x1E];
+ b2[0x1E] = (b1[0x1E] - b1[0x11]) * costab[1];
+ b2[0x12] = b1[0x12] + b1[0x1D];
+ b2[0x1D] = (b1[0x1D] - b1[0x12]) * costab[2];
+ b2[0x13] = b1[0x13] + b1[0x1C];
+ b2[0x1C] = (b1[0x1C] - b1[0x13]) * costab[3];
+ b2[0x14] = b1[0x14] + b1[0x1B];
+ b2[0x1B] = (b1[0x1B] - b1[0x14]) * costab[4];
+ b2[0x15] = b1[0x15] + b1[0x1A];
+ b2[0x1A] = (b1[0x1A] - b1[0x15]) * costab[5];
+ b2[0x16] = b1[0x16] + b1[0x19];
+ b2[0x19] = (b1[0x19] - b1[0x16]) * costab[6];
+ b2[0x17] = b1[0x17] + b1[0x18];
+ b2[0x18] = (b1[0x18] - b1[0x17]) * costab[7];
+ }
+
+ {
+ register real *costab = pnts[2];
+
+ b1[0x00] = b2[0x00] + b2[0x07];
+ b1[0x07] = (b2[0x00] - b2[0x07]) * costab[0];
+ b1[0x01] = b2[0x01] + b2[0x06];
+ b1[0x06] = (b2[0x01] - b2[0x06]) * costab[1];
+ b1[0x02] = b2[0x02] + b2[0x05];
+ b1[0x05] = (b2[0x02] - b2[0x05]) * costab[2];
+ b1[0x03] = b2[0x03] + b2[0x04];
+ b1[0x04] = (b2[0x03] - b2[0x04]) * costab[3];
+
+ b1[0x08] = b2[0x08] + b2[0x0F];
+ b1[0x0F] = (b2[0x0F] - b2[0x08]) * costab[0];
+ b1[0x09] = b2[0x09] + b2[0x0E];
+ b1[0x0E] = (b2[0x0E] - b2[0x09]) * costab[1];
+ b1[0x0A] = b2[0x0A] + b2[0x0D];
+ b1[0x0D] = (b2[0x0D] - b2[0x0A]) * costab[2];
+ b1[0x0B] = b2[0x0B] + b2[0x0C];
+ b1[0x0C] = (b2[0x0C] - b2[0x0B]) * costab[3];
+
+ b1[0x10] = b2[0x10] + b2[0x17];
+ b1[0x17] = (b2[0x10] - b2[0x17]) * costab[0];
+ b1[0x11] = b2[0x11] + b2[0x16];
+ b1[0x16] = (b2[0x11] - b2[0x16]) * costab[1];
+ b1[0x12] = b2[0x12] + b2[0x15];
+ b1[0x15] = (b2[0x12] - b2[0x15]) * costab[2];
+ b1[0x13] = b2[0x13] + b2[0x14];
+ b1[0x14] = (b2[0x13] - b2[0x14]) * costab[3];
+
+ b1[0x18] = b2[0x18] + b2[0x1F];
+ b1[0x1F] = (b2[0x1F] - b2[0x18]) * costab[0];
+ b1[0x19] = b2[0x19] + b2[0x1E];
+ b1[0x1E] = (b2[0x1E] - b2[0x19]) * costab[1];
+ b1[0x1A] = b2[0x1A] + b2[0x1D];
+ b1[0x1D] = (b2[0x1D] - b2[0x1A]) * costab[2];
+ b1[0x1B] = b2[0x1B] + b2[0x1C];
+ b1[0x1C] = (b2[0x1C] - b2[0x1B]) * costab[3];
+ }
+
+ {
+ register real const cos0 = pnts[3][0];
+ register real const cos1 = pnts[3][1];
+
+ b2[0x00] = b1[0x00] + b1[0x03];
+ b2[0x03] = (b1[0x00] - b1[0x03]) * cos0;
+ b2[0x01] = b1[0x01] + b1[0x02];
+ b2[0x02] = (b1[0x01] - b1[0x02]) * cos1;
+
+ b2[0x04] = b1[0x04] + b1[0x07];
+ b2[0x07] = (b1[0x07] - b1[0x04]) * cos0;
+ b2[0x05] = b1[0x05] + b1[0x06];
+ b2[0x06] = (b1[0x06] - b1[0x05]) * cos1;
+
+ b2[0x08] = b1[0x08] + b1[0x0B];
+ b2[0x0B] = (b1[0x08] - b1[0x0B]) * cos0;
+ b2[0x09] = b1[0x09] + b1[0x0A];
+ b2[0x0A] = (b1[0x09] - b1[0x0A]) * cos1;
+
+ b2[0x0C] = b1[0x0C] + b1[0x0F];
+ b2[0x0F] = (b1[0x0F] - b1[0x0C]) * cos0;
+ b2[0x0D] = b1[0x0D] + b1[0x0E];
+ b2[0x0E] = (b1[0x0E] - b1[0x0D]) * cos1;
+
+ b2[0x10] = b1[0x10] + b1[0x13];
+ b2[0x13] = (b1[0x10] - b1[0x13]) * cos0;
+ b2[0x11] = b1[0x11] + b1[0x12];
+ b2[0x12] = (b1[0x11] - b1[0x12]) * cos1;
+
+ b2[0x14] = b1[0x14] + b1[0x17];
+ b2[0x17] = (b1[0x17] - b1[0x14]) * cos0;
+ b2[0x15] = b1[0x15] + b1[0x16];
+ b2[0x16] = (b1[0x16] - b1[0x15]) * cos1;
+
+ b2[0x18] = b1[0x18] + b1[0x1B];
+ b2[0x1B] = (b1[0x18] - b1[0x1B]) * cos0;
+ b2[0x19] = b1[0x19] + b1[0x1A];
+ b2[0x1A] = (b1[0x19] - b1[0x1A]) * cos1;
+
+ b2[0x1C] = b1[0x1C] + b1[0x1F];
+ b2[0x1F] = (b1[0x1F] - b1[0x1C]) * cos0;
+ b2[0x1D] = b1[0x1D] + b1[0x1E];
+ b2[0x1E] = (b1[0x1E] - b1[0x1D]) * cos1;
+ }
+
+ {
+ register real const cos0 = pnts[4][0];
+
+ b1[0x00] = b2[0x00] + b2[0x01];
+ b1[0x01] = (b2[0x00] - b2[0x01]) * cos0;
+ b1[0x02] = b2[0x02] + b2[0x03];
+ b1[0x03] = (b2[0x03] - b2[0x02]) * cos0;
+ b1[0x02] += b1[0x03];
+
+ b1[0x04] = b2[0x04] + b2[0x05];
+ b1[0x05] = (b2[0x04] - b2[0x05]) * cos0;
+ b1[0x06] = b2[0x06] + b2[0x07];
+ b1[0x07] = (b2[0x07] - b2[0x06]) * cos0;
+ b1[0x06] += b1[0x07];
+ b1[0x04] += b1[0x06];
+ b1[0x06] += b1[0x05];
+ b1[0x05] += b1[0x07];
+
+ b1[0x08] = b2[0x08] + b2[0x09];
+ b1[0x09] = (b2[0x08] - b2[0x09]) * cos0;
+ b1[0x0A] = b2[0x0A] + b2[0x0B];
+ b1[0x0B] = (b2[0x0B] - b2[0x0A]) * cos0;
+ b1[0x0A] += b1[0x0B];
+
+ b1[0x0C] = b2[0x0C] + b2[0x0D];
+ b1[0x0D] = (b2[0x0C] - b2[0x0D]) * cos0;
+ b1[0x0E] = b2[0x0E] + b2[0x0F];
+ b1[0x0F] = (b2[0x0F] - b2[0x0E]) * cos0;
+ b1[0x0E] += b1[0x0F];
+ b1[0x0C] += b1[0x0E];
+ b1[0x0E] += b1[0x0D];
+ b1[0x0D] += b1[0x0F];
+
+ b1[0x10] = b2[0x10] + b2[0x11];
+ b1[0x11] = (b2[0x10] - b2[0x11]) * cos0;
+ b1[0x12] = b2[0x12] + b2[0x13];
+ b1[0x13] = (b2[0x13] - b2[0x12]) * cos0;
+ b1[0x12] += b1[0x13];
+
+ b1[0x14] = b2[0x14] + b2[0x15];
+ b1[0x15] = (b2[0x14] - b2[0x15]) * cos0;
+ b1[0x16] = b2[0x16] + b2[0x17];
+ b1[0x17] = (b2[0x17] - b2[0x16]) * cos0;
+ b1[0x16] += b1[0x17];
+ b1[0x14] += b1[0x16];
+ b1[0x16] += b1[0x15];
+ b1[0x15] += b1[0x17];
+
+ b1[0x18] = b2[0x18] + b2[0x19];
+ b1[0x19] = (b2[0x18] - b2[0x19]) * cos0;
+ b1[0x1A] = b2[0x1A] + b2[0x1B];
+ b1[0x1B] = (b2[0x1B] - b2[0x1A]) * cos0;
+ b1[0x1A] += b1[0x1B];
+
+ b1[0x1C] = b2[0x1C] + b2[0x1D];
+ b1[0x1D] = (b2[0x1C] - b2[0x1D]) * cos0;
+ b1[0x1E] = b2[0x1E] + b2[0x1F];
+ b1[0x1F] = (b2[0x1F] - b2[0x1E]) * cos0;
+ b1[0x1E] += b1[0x1F];
+ b1[0x1C] += b1[0x1E];
+ b1[0x1E] += b1[0x1D];
+ b1[0x1D] += b1[0x1F];
+ }
+
+ out0[0x10*16] = b1[0x00];
+ out0[0x10*12] = b1[0x04];
+ out0[0x10* 8] = b1[0x02];
+ out0[0x10* 4] = b1[0x06];
+ out0[0x10* 0] = b1[0x01];
+ out1[0x10* 0] = b1[0x01];
+ out1[0x10* 4] = b1[0x05];
+ out1[0x10* 8] = b1[0x03];
+ out1[0x10*12] = b1[0x07];
+
+ b1[0x08] += b1[0x0C];
+ out0[0x10*14] = b1[0x08];
+ b1[0x0C] += b1[0x0a];
+ out0[0x10*10] = b1[0x0C];
+ b1[0x0A] += b1[0x0E];
+ out0[0x10* 6] = b1[0x0A];
+ b1[0x0E] += b1[0x09];
+ out0[0x10* 2] = b1[0x0E];
+ b1[0x09] += b1[0x0D];
+ out1[0x10* 2] = b1[0x09];
+ b1[0x0D] += b1[0x0B];
+ out1[0x10* 6] = b1[0x0D];
+ b1[0x0B] += b1[0x0F];
+ out1[0x10*10] = b1[0x0B];
+ out1[0x10*14] = b1[0x0F];
+
+ b1[0x18] += b1[0x1C];
+ out0[0x10*15] = b1[0x10] + b1[0x18];
+ out0[0x10*13] = b1[0x18] + b1[0x14];
+ b1[0x1C] += b1[0x1a];
+ out0[0x10*11] = b1[0x14] + b1[0x1C];
+ out0[0x10* 9] = b1[0x1C] + b1[0x12];
+ b1[0x1A] += b1[0x1E];
+ out0[0x10* 7] = b1[0x12] + b1[0x1A];
+ out0[0x10* 5] = b1[0x1A] + b1[0x16];
+ b1[0x1E] += b1[0x19];
+ out0[0x10* 3] = b1[0x16] + b1[0x1E];
+ out0[0x10* 1] = b1[0x1E] + b1[0x11];
+ b1[0x19] += b1[0x1D];
+ out1[0x10* 1] = b1[0x11] + b1[0x19];
+ out1[0x10* 3] = b1[0x19] + b1[0x15];
+ b1[0x1D] += b1[0x1B];
+ out1[0x10* 5] = b1[0x15] + b1[0x1D];
+ out1[0x10* 7] = b1[0x1D] + b1[0x13];
+ b1[0x1B] += b1[0x1F];
+ out1[0x10* 9] = b1[0x13] + b1[0x1B];
+ out1[0x10*11] = b1[0x1B] + b1[0x17];
+ out1[0x10*13] = b1[0x17] + b1[0x1F];
+ out1[0x10*15] = b1[0x1F];
+}
+
+/*
+ * the call via dct64 is a trick to force GCC to use
+ * (new) registers for the b1,b2 pointer to the bufs[xx] field
+ */
+void dct64(real *a,real *b,real *c)
+{
+ real bufs[0x40];
+ dct64_1(a,b,bufs,bufs+0x20,c);
+}
+
diff --git a/util/sdl/sound/decoders/mpglib/decode_i386.c b/util/sdl/sound/decoders/mpglib/decode_i386.c
new file mode 100644
index 00000000..0afd5259
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/decode_i386.c
@@ -0,0 +1,153 @@
+/*
+ * Mpeg Layer-1,2,3 audio decoder
+ * ------------------------------
+ * copyright (c) 1995,1996,1997 by Michael Hipp, All rights reserved.
+ * See also 'README'
+ *
+ * slighlty optimized for machines without autoincrement/decrement.
+ * The performance is highly compiler dependend. Maybe
+ * the decode.c version for 'normal' processor may be faster
+ * even for Intel processors.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "mpg123_sdlsound.h"
+#include "mpglib_sdlsound.h"
+
+ /* old WRITE_SAMPLE */
+#define WRITE_SAMPLE(samples,sum,clip) \
+ if( (sum) > 32767.0) { *(samples) = 0x7fff; (clip)++; } \
+ else if( (sum) < -32768.0) { *(samples) = -0x8000; (clip)++; } \
+ else { *(samples) = sum; }
+
+int synth_1to1_mono(real *bandPtr,unsigned char *samples,
+ int *pnt, struct mpstr *mp)
+{
+ short samples_tmp[64];
+ short *tmp1 = samples_tmp;
+ int i,ret;
+ int pnt1 = 0;
+
+ ret = synth_1to1(bandPtr,0,(unsigned char *) samples_tmp,&pnt1,mp);
+ samples += *pnt;
+
+ for(i=0;i<32;i++) {
+ *( (short *) samples) = *tmp1;
+ samples += 2;
+ tmp1 += 2;
+ }
+ *pnt += 64;
+
+ return ret;
+}
+
+
+int synth_1to1(real *bandPtr,int channel,unsigned char *out,
+ int *pnt, struct mpstr *mp)
+{
+ static const int step = 2;
+ int bo;
+ short *samples = (short *) (out + *pnt);
+
+ real *b0,(*buf)[0x110];
+ int clip = 0;
+ int bo1;
+
+ bo = mp->synth_bo;
+
+ if(!channel) {
+ bo--;
+ bo &= 0xf;
+ buf = mp->synth_buffs[0];
+ }
+ else {
+ samples++;
+ buf = mp->synth_buffs[1];
+ }
+
+ if(bo & 0x1) {
+ b0 = buf[0];
+ bo1 = bo;
+ dct64(buf[1]+((bo+1)&0xf),buf[0]+bo,bandPtr);
+ }
+ else {
+ b0 = buf[1];
+ bo1 = bo+1;
+ dct64(buf[0]+bo,buf[1]+bo+1,bandPtr);
+ }
+
+ mp->synth_bo = bo;
+
+ {
+ register int j;
+ real *window = decwin + 16 - bo1;
+
+ for (j=16;j;j--,b0+=0x10,window+=0x20,samples+=step)
+ {
+ real sum;
+ sum = window[0x0] * b0[0x0];
+ sum -= window[0x1] * b0[0x1];
+ sum += window[0x2] * b0[0x2];
+ sum -= window[0x3] * b0[0x3];
+ sum += window[0x4] * b0[0x4];
+ sum -= window[0x5] * b0[0x5];
+ sum += window[0x6] * b0[0x6];
+ sum -= window[0x7] * b0[0x7];
+ sum += window[0x8] * b0[0x8];
+ sum -= window[0x9] * b0[0x9];
+ sum += window[0xA] * b0[0xA];
+ sum -= window[0xB] * b0[0xB];
+ sum += window[0xC] * b0[0xC];
+ sum -= window[0xD] * b0[0xD];
+ sum += window[0xE] * b0[0xE];
+ sum -= window[0xF] * b0[0xF];
+
+ WRITE_SAMPLE(samples,sum,clip);
+ }
+
+ {
+ real sum;
+ sum = window[0x0] * b0[0x0];
+ sum += window[0x2] * b0[0x2];
+ sum += window[0x4] * b0[0x4];
+ sum += window[0x6] * b0[0x6];
+ sum += window[0x8] * b0[0x8];
+ sum += window[0xA] * b0[0xA];
+ sum += window[0xC] * b0[0xC];
+ sum += window[0xE] * b0[0xE];
+ WRITE_SAMPLE(samples,sum,clip);
+ b0-=0x10,window-=0x20,samples+=step;
+ }
+ window += bo1<<1;
+
+ for (j=15;j;j--,b0-=0x10,window-=0x20,samples+=step)
+ {
+ real sum;
+ sum = -window[-0x1] * b0[0x0];
+ sum -= window[-0x2] * b0[0x1];
+ sum -= window[-0x3] * b0[0x2];
+ sum -= window[-0x4] * b0[0x3];
+ sum -= window[-0x5] * b0[0x4];
+ sum -= window[-0x6] * b0[0x5];
+ sum -= window[-0x7] * b0[0x6];
+ sum -= window[-0x8] * b0[0x7];
+ sum -= window[-0x9] * b0[0x8];
+ sum -= window[-0xA] * b0[0x9];
+ sum -= window[-0xB] * b0[0xA];
+ sum -= window[-0xC] * b0[0xB];
+ sum -= window[-0xD] * b0[0xC];
+ sum -= window[-0xE] * b0[0xD];
+ sum -= window[-0xF] * b0[0xE];
+ sum -= window[-0x0] * b0[0xF];
+
+ WRITE_SAMPLE(samples,sum,clip);
+ }
+ }
+ *pnt += 128;
+
+ return clip;
+}
+
diff --git a/util/sdl/sound/decoders/mpglib/huffman.h b/util/sdl/sound/decoders/mpglib/huffman.h
new file mode 100644
index 00000000..7fec0d58
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/huffman.h
@@ -0,0 +1,332 @@
+/*
+ * huffman tables ... recalcualted to work with my optimzed
+ * decoder scheme (MH)
+ *
+ * probably we could save a few bytes of memory, because the
+ * smaller tables are often the part of a bigger table
+ */
+
+struct newhuff
+{
+ unsigned int linbits;
+ short *table;
+};
+
+static short tab0[] =
+{
+ 0
+};
+
+static short tab1[] =
+{
+ -5, -3, -1, 17, 1, 16, 0
+};
+
+static short tab2[] =
+{
+ -15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1,
+ 16, 0
+};
+
+static short tab3[] =
+{
+ -13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1,
+ 1, 0
+};
+
+static short tab5[] =
+{
+ -29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19,
+ 3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16,
+ 0
+};
+
+static short tab6[] =
+{
+ -25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19,
+ 49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16,
+ 0
+};
+
+static short tab7[] =
+{
+ -69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83,
+ -1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1,
+ 80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7,
+ -3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18,
+ -5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0
+};
+
+static short tab8[] =
+{
+ -65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83,
+ -3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52,
+ 67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4,
+ 64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1,
+ 2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0
+};
+
+static short tab9[] =
+{
+ -63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1,
+ 84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67,
+ -1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5,
+ -3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2,
+ 18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0
+};
+
+static short tab10[] =
+{
+-125,-121,-111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118,
+ 87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3,
+ -1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1,
+ 100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23,
+ -17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81,
+ -1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7,
+ -3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1,
+ 50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1,
+ 2, 32, 17, -1, 1, 16, 0
+};
+
+static short tab11[] =
+{
+-121,-113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117,
+ -3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55,
+ -1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114,
+ -1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96,
+ -1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38,
+ 6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1,
+ 36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50,
+ -1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2,
+ 32, 17, -3, -1, 1, 16, 0
+};
+
+static short tab12[] =
+{
+-115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87,
+ 117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115,
+ 85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7,
+ 112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5,
+ -1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37,
+ 82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4,
+ 36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3,
+ -1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1,
+ 2, 32, 0, 17, -1, 1, 16
+};
+
+static short tab13[] =
+{
+-509,-503,-475,-405,-333,-265,-205,-153,-115, -83, -53, -35, -21, -13, -9,
+ -7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238,
+ 207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1,
+ 236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249,
+ 234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158,
+ -5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1,
+ 203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245,
+ 231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1,
+ 63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15,
+ -5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1,
+ 200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1,
+ 240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1,
+ 46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3,
+ -1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1,
+ 198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5,
+ -1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167,
+ 151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76,
+ 196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137,
+ 28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106,
+ -5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43,
+ -1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178,
+ -11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1,
+ 58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161,
+ -3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88,
+ -1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1,
+ 131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25,
+ 145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100,
+ 40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113,
+ -1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38,
+ -1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6,
+ 96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81,
+ -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11,
+ -5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3,
+ -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
+ 0
+};
+
+static short tab15[] =
+{
+-495,-445,-355,-263,-183,-115, -77, -43, -27, -13, -7, -3, -1, 255, 239,
+ -1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237,
+ 191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3,
+ -1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219,
+ -3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173,
+ -3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246,
+ -3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9,
+ -3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243,
+ 216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1,
+ 31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1,
+ 125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3,
+ -1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5,
+ -1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124,
+ 199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1,
+ 198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183,
+ -5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76,
+ -1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1,
+ 122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15,
+ -7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106,
+ -5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5,
+ -1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74,
+ -1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1,
+ 42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134,
+ 73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29,
+ -13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7,
+ -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7,
+ -3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86,
+ -3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100,
+ 23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69,
+ -1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9,
+ -5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1,
+ 5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20,
+ 4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48,
+ 34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16,
+ 0
+};
+
+static short tab16[] =
+{
+-509,-503,-461,-323,-103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223,
+ 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3,
+ -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5,
+ -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19,
+ -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1,
+ 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5,
+ -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125,
+ 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13,
+ -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3,
+ -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186,
+ -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1,
+ 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169,
+ -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213,
+ -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154,
+ 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1,
+ 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1,
+ 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45,
+ -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107,
+ -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12,
+ -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1,
+ 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74,
+ 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33,
+ -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3,
+ -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147,
+ -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1,
+ 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3,
+ -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1,
+ 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3,
+ -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1,
+ 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9,
+ -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33,
+ -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20,
+ -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1,
+ 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16,
+ 0
+};
+
+static short tab24[] =
+{
+-451,-117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1,
+ 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9,
+ -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79,
+ 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31,
+ 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1,
+ 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3,
+ -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3,
+ -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255,-235,
+-143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3,
+ -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9,
+ -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1,
+ 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185,
+ 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199,
+ 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3,
+ -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3,
+ -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196,
+ -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1,
+ 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1,
+ 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10,
+ 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9,
+ 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165,
+ 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135,
+ -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104,
+ -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3,
+ -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3,
+ -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7,
+ -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86,
+ 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15,
+ -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84,
+ -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1,
+ 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5,
+ 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5,
+ -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1,
+ 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16,
+ 0
+};
+
+static short tab_c0[] =
+{
+ -29, -21, -13, -7, -3, -1, 11, 15, -1, 13, 14, -3, -1, 7, 5,
+ 9, -3, -1, 6, 3, -1, 10, 12, -3, -1, 2, 1, -1, 4, 8,
+ 0
+};
+
+static short tab_c1[] =
+{
+ -15, -7, -3, -1, 15, 14, -1, 13, 12, -3, -1, 11, 10, -1, 9,
+ 8, -7, -3, -1, 7, 6, -1, 5, 4, -3, -1, 3, 2, -1, 1,
+ 0
+};
+
+
+
+static struct newhuff ht[] =
+{
+ { /* 0 */ 0 , tab0 } ,
+ { /* 2 */ 0 , tab1 } ,
+ { /* 3 */ 0 , tab2 } ,
+ { /* 3 */ 0 , tab3 } ,
+ { /* 0 */ 0 , tab0 } ,
+ { /* 4 */ 0 , tab5 } ,
+ { /* 4 */ 0 , tab6 } ,
+ { /* 6 */ 0 , tab7 } ,
+ { /* 6 */ 0 , tab8 } ,
+ { /* 6 */ 0 , tab9 } ,
+ { /* 8 */ 0 , tab10 } ,
+ { /* 8 */ 0 , tab11 } ,
+ { /* 8 */ 0 , tab12 } ,
+ { /* 16 */ 0 , tab13 } ,
+ { /* 0 */ 0 , tab0 } ,
+ { /* 16 */ 0 , tab15 } ,
+
+ { /* 16 */ 1 , tab16 } ,
+ { /* 16 */ 2 , tab16 } ,
+ { /* 16 */ 3 , tab16 } ,
+ { /* 16 */ 4 , tab16 } ,
+ { /* 16 */ 6 , tab16 } ,
+ { /* 16 */ 8 , tab16 } ,
+ { /* 16 */ 10, tab16 } ,
+ { /* 16 */ 13, tab16 } ,
+ { /* 16 */ 4 , tab24 } ,
+ { /* 16 */ 5 , tab24 } ,
+ { /* 16 */ 6 , tab24 } ,
+ { /* 16 */ 7 , tab24 } ,
+ { /* 16 */ 8 , tab24 } ,
+ { /* 16 */ 9 , tab24 } ,
+ { /* 16 */ 11, tab24 } ,
+ { /* 16 */ 13, tab24 }
+};
+
+static struct newhuff htc[] =
+{
+ { /* 1 , 1 , */ 0 , tab_c0 } ,
+ { /* 1 , 1 , */ 0 , tab_c1 }
+};
+
+
diff --git a/util/sdl/sound/decoders/mpglib/interface.c b/util/sdl/sound/decoders/mpglib/interface.c
new file mode 100644
index 00000000..db9a3a5d
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/interface.c
@@ -0,0 +1,243 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "mpg123_sdlsound.h"
+#include "mpglib_sdlsound.h"
+
+
+BOOL InitMP3(struct mpstr *mp)
+{
+ static int init = 0;
+
+ memset(mp,0,sizeof(struct mpstr));
+
+ mp->framesize = 0;
+ mp->fsizeold = -1;
+ mp->bsize = 0;
+ mp->head = mp->tail = NULL;
+ mp->fr.single = -1;
+ mp->bsnum = 0;
+ mp->synth_bo = 1;
+
+ if(!init) {
+ init = 1;
+ make_decode_tables(32767);
+ init_layer2();
+ init_layer3(SBLIMIT);
+ }
+
+ return !0;
+}
+
+void ExitMP3(struct mpstr *mp)
+{
+ struct buf *b,*bn;
+
+ b = mp->tail;
+ while(b) {
+ free(b->pnt);
+ bn = b->next;
+ free(b);
+ b = bn;
+ }
+}
+
+static struct buf *addbuf(struct mpstr *mp,char *buf,int size)
+{
+ struct buf *nbuf;
+
+ nbuf = malloc( sizeof(struct buf) );
+ BAIL_IF_MACRO(!nbuf, ERR_OUT_OF_MEMORY, NULL);
+
+ nbuf->pnt = malloc(size);
+ if(!nbuf->pnt) {
+ free(nbuf);
+ BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
+ }
+ nbuf->size = size;
+ memcpy(nbuf->pnt,buf,size);
+ nbuf->next = NULL;
+ nbuf->prev = mp->head;
+ nbuf->pos = 0;
+
+ if(!mp->tail) {
+ mp->tail = nbuf;
+ }
+ else {
+ mp->head->next = nbuf;
+ }
+
+ mp->head = nbuf;
+ mp->bsize += size;
+
+ return nbuf;
+}
+
+static void remove_buf(struct mpstr *mp)
+{
+ struct buf *buf = mp->tail;
+
+ mp->tail = buf->next;
+ if(mp->tail)
+ mp->tail->prev = NULL;
+ else {
+ mp->tail = mp->head = NULL;
+ }
+
+ free(buf->pnt);
+ free(buf);
+
+}
+
+static int read_buf_byte(struct mpstr *mp, unsigned long *retval)
+{
+ int pos;
+
+ pos = mp->tail->pos;
+ while(pos >= mp->tail->size) {
+ remove_buf(mp);
+ pos = mp->tail->pos;
+ if(!mp->tail) {
+ BAIL_MACRO("MPGLIB: Short read in read_buf_byte()!", 0);
+ }
+ }
+
+ if (retval != NULL)
+ *retval = mp->tail->pnt[pos];
+
+ mp->bsize--;
+ mp->tail->pos++;
+
+ return 1;
+}
+
+static int read_head(struct mpstr *mp)
+{
+ unsigned long val;
+ unsigned long head;
+
+ if (!read_buf_byte(mp, &val))
+ return 0;
+
+ head = val << 8;
+
+ if (!read_buf_byte(mp, &val))
+ return 0;
+
+ head |= val;
+ head <<= 8;
+
+ if (!read_buf_byte(mp, &val))
+ return 0;
+
+ head |= val;
+ head <<= 8;
+
+ if (!read_buf_byte(mp, &val))
+ return 0;
+
+ head |= val;
+ mp->header = head;
+ return 1;
+}
+
+int decodeMP3(struct mpstr *mp,char *in,int isize,char *out,
+ int osize,int *done)
+{
+ int len;
+
+ BAIL_IF_MACRO(osize < 4608, "MPGLIB: Output buffer too small", MP3_ERR);
+
+ if(in) {
+ if(addbuf(mp,in,isize) == NULL) {
+ return MP3_ERR;
+ }
+ }
+
+ /* First decode header */
+ if(mp->framesize == 0) {
+ if(mp->bsize < 4) {
+ return MP3_NEED_MORE;
+ }
+
+ if (!read_head(mp))
+ return MP3_ERR;
+
+ if (!decode_header(&mp->fr,mp->header))
+ return MP3_ERR;
+
+ mp->framesize = mp->fr.framesize;
+ }
+
+ if(mp->fr.framesize > mp->bsize)
+ return MP3_NEED_MORE;
+
+ wordpointer = mp->bsspace[mp->bsnum] + 512;
+ mp->bsnum = (mp->bsnum + 1) & 0x1;
+ bitindex = 0;
+
+ len = 0;
+ while(len < mp->framesize) {
+ int nlen;
+ int blen = mp->tail->size - mp->tail->pos;
+ if( (mp->framesize - len) <= blen) {
+ nlen = mp->framesize-len;
+ }
+ else {
+ nlen = blen;
+ }
+ memcpy(wordpointer+len,mp->tail->pnt+mp->tail->pos,nlen);
+ len += nlen;
+ mp->tail->pos += nlen;
+ mp->bsize -= nlen;
+ if(mp->tail->pos == mp->tail->size) {
+ remove_buf(mp);
+ }
+ }
+
+ *done = 0;
+ if(mp->fr.error_protection)
+ getbits(16);
+ switch(mp->fr.lay) {
+ case 1:
+ do_layer1(&mp->fr,(unsigned char *) out,done,mp);
+ break;
+ case 2:
+ do_layer2(&mp->fr,(unsigned char *) out,done,mp);
+ break;
+ case 3:
+ do_layer3(&mp->fr,(unsigned char *) out,done,mp);
+ break;
+ }
+
+ mp->fsizeold = mp->framesize;
+ mp->framesize = 0;
+
+ return MP3_OK;
+}
+
+int set_pointer(long backstep, struct mpstr *mp)
+{
+ unsigned char *bsbufold;
+ if(mp->fsizeold < 0 && backstep > 0) {
+ char err[128];
+ snprintf(err, sizeof (err), "MPGLIB: Can't step back! %ld!", backstep);
+ BAIL_MACRO(err, MP3_ERR);
+ }
+ bsbufold = mp->bsspace[mp->bsnum] + 512;
+ wordpointer -= backstep;
+ if (backstep)
+ memcpy(wordpointer,bsbufold+mp->fsizeold-backstep,backstep);
+ bitindex = 0;
+ return MP3_OK;
+}
+
+
+
+
diff --git a/util/sdl/sound/decoders/mpglib/l2tables.h b/util/sdl/sound/decoders/mpglib/l2tables.h
new file mode 100644
index 00000000..06d21353
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/l2tables.h
@@ -0,0 +1,160 @@
+/*
+ * Layer 2 Alloc tables ..
+ * most other tables are calculated on program start (which is (of course)
+ * not ISO-conform) ..
+ * Layer-3 huffman table is in huffman.h
+ */
+
+struct al_table
+{
+ short bits;
+ short d;
+};
+
+struct al_table alloc_0[] = {
+ {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
+ {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
+ {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
+ {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
+ {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
+ {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767} };
+
+struct al_table alloc_1[] = {
+ {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
+ {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
+ {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
+ {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
+ {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
+ {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767},
+ {2,0},{5,3},{7,5},{16,-32767} };
+
+struct al_table alloc_2[] = {
+ {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
+ {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
+ {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
+ {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63} };
+
+struct al_table alloc_3[] = {
+ {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
+ {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
+ {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
+ {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63} };
+
+struct al_table alloc_4[] = {
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
+ {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
+ {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9},
+ {2,0},{5,3},{7,5},{10,9} };
+
diff --git a/util/sdl/sound/decoders/mpglib/layer1.c b/util/sdl/sound/decoders/mpglib/layer1.c
new file mode 100644
index 00000000..3df430a8
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/layer1.c
@@ -0,0 +1,148 @@
+/*
+ * Mpeg Layer-1 audio decoder
+ * --------------------------
+ * copyright (c) 1995 by Michael Hipp, All rights reserved. See also 'README'
+ * near unoptimzed ...
+ *
+ * may have a few bugs after last optimization ...
+ *
+ */
+
+#include "mpg123_sdlsound.h"
+
+void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT],struct frame *fr)
+{
+ unsigned int *ba=balloc;
+ unsigned int *sca = (unsigned int *) scale_index;
+
+ if(fr->stereo) {
+ int i;
+ int jsbound = fr->jsbound;
+ for (i=0;i<jsbound;i++) {
+ *ba++ = getbits(4);
+ *ba++ = getbits(4);
+ }
+ for (i=jsbound;i<SBLIMIT;i++)
+ *ba++ = getbits(4);
+
+ ba = balloc;
+
+ for (i=0;i<jsbound;i++) {
+ if ((*ba++))
+ *sca++ = getbits(6);
+ if ((*ba++))
+ *sca++ = getbits(6);
+ }
+ for (i=jsbound;i<SBLIMIT;i++)
+ if ((*ba++)) {
+ *sca++ = getbits(6);
+ *sca++ = getbits(6);
+ }
+ }
+ else {
+ int i;
+ for (i=0;i<SBLIMIT;i++)
+ *ba++ = getbits(4);
+ ba = balloc;
+ for (i=0;i<SBLIMIT;i++)
+ if ((*ba++))
+ *sca++ = getbits(6);
+ }
+}
+
+void I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT],
+ unsigned int scale_index[2][SBLIMIT],struct frame *fr)
+{
+ int i,n;
+ int smpb[2*SBLIMIT]; /* values: 0-65535 */
+ int *sample;
+ register unsigned int *ba;
+ register unsigned int *sca = (unsigned int *) scale_index;
+
+ if(fr->stereo) {
+ int jsbound = fr->jsbound;
+ register real *f0 = fraction[0];
+ register real *f1 = fraction[1];
+ ba = balloc;
+ for (sample=smpb,i=0;i<jsbound;i++) {
+ if ((n = *ba++))
+ *sample++ = getbits(n+1);
+ if ((n = *ba++))
+ *sample++ = getbits(n+1);
+ }
+ for (i=jsbound;i<SBLIMIT;i++)
+ if ((n = *ba++))
+ *sample++ = getbits(n+1);
+
+ ba = balloc;
+ for (sample=smpb,i=0;i<jsbound;i++) {
+ if((n=*ba++))
+ *f0++ = (real) ( ((-1)<<n) + (*sample++) + 1) * muls[n+1][*sca++];
+ else
+ *f0++ = 0.0;
+ if((n=*ba++))
+ *f1++ = (real) ( ((-1)<<n) + (*sample++) + 1) * muls[n+1][*sca++];
+ else
+ *f1++ = 0.0;
+ }
+ for (i=jsbound;i<SBLIMIT;i++) {
+ if ((n=*ba++)) {
+ real samp = ( ((-1)<<n) + (*sample++) + 1);
+ *f0++ = samp * muls[n+1][*sca++];
+ *f1++ = samp * muls[n+1][*sca++];
+ }
+ else
+ *f0++ = *f1++ = 0.0;
+ }
+ }
+ else {
+ register real *f0 = fraction[0];
+ ba = balloc;
+ for (sample=smpb,i=0;i<SBLIMIT;i++)
+ if ((n = *ba++))
+ *sample++ = getbits(n+1);
+ ba = balloc;
+ for (sample=smpb,i=0;i<SBLIMIT;i++) {
+ if((n=*ba++))
+ *f0++ = (real) ( ((-1)<<n) + (*sample++) + 1) * muls[n+1][*sca++];
+ else
+ *f0++ = 0.0;
+ }
+ }
+}
+
+int do_layer1(struct frame *fr,unsigned char *pcm_sample,
+ int *pcm_point,struct mpstr *mp)
+{
+ int clip=0;
+ int i,stereo = fr->stereo;
+ unsigned int balloc[2*SBLIMIT];
+ unsigned int scale_index[2][SBLIMIT];
+ real fraction[2][SBLIMIT];
+ int single = fr->single;
+
+ fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ? (fr->mode_ext<<2)+4 : 32;
+
+ if(stereo == 1 || single == 3)
+ single = 0;
+
+ I_step_one(balloc,scale_index,fr);
+
+ for (i=0;i<SCALE_BLOCK;i++)
+ {
+ I_step_two(fraction,balloc,scale_index,fr);
+
+ if(single >= 0) {
+ clip += synth_1to1_mono( (real*)fraction[single],pcm_sample,pcm_point,mp);
+ }
+ else {
+ int p1 = *pcm_point;
+ clip += synth_1to1( (real*)fraction[0],0,pcm_sample,&p1,mp);
+ clip += synth_1to1( (real*)fraction[1],1,pcm_sample,pcm_point,mp);
+ }
+ }
+
+ return clip;
+}
+
+
diff --git a/util/sdl/sound/decoders/mpglib/layer2.c b/util/sdl/sound/decoders/mpglib/layer2.c
new file mode 100644
index 00000000..b5ef1e9b
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/layer2.c
@@ -0,0 +1,289 @@
+/*
+ * Mpeg Layer-2 audio decoder
+ * --------------------------
+ * copyright (c) 1995 by Michael Hipp, All rights reserved. See also 'README'
+ *
+ */
+
+#include "mpg123_sdlsound.h"
+#include "l2tables.h"
+
+static int grp_3tab[32 * 3] = { 0, }; /* used: 27 */
+static int grp_5tab[128 * 3] = { 0, }; /* used: 125 */
+static int grp_9tab[1024 * 3] = { 0, }; /* used: 729 */
+
+real muls[27][64]; /* also used by layer 1 */
+
+void init_layer2(void)
+{
+ static double mulmul[27] = {
+ 0.0 , -2.0/3.0 , 2.0/3.0 ,
+ 2.0/7.0 , 2.0/15.0 , 2.0/31.0, 2.0/63.0 , 2.0/127.0 , 2.0/255.0 ,
+ 2.0/511.0 , 2.0/1023.0 , 2.0/2047.0 , 2.0/4095.0 , 2.0/8191.0 ,
+ 2.0/16383.0 , 2.0/32767.0 , 2.0/65535.0 ,
+ -4.0/5.0 , -2.0/5.0 , 2.0/5.0, 4.0/5.0 ,
+ -8.0/9.0 , -4.0/9.0 , -2.0/9.0 , 2.0/9.0 , 4.0/9.0 , 8.0/9.0 };
+ static int base[3][9] = {
+ { 1 , 0, 2 , } ,
+ { 17, 18, 0 , 19, 20 , } ,
+ { 21, 1, 22, 23, 0, 24, 25, 2, 26 } };
+ int i,j,k,l,len;
+ real *table;
+ static int tablen[3] = { 3 , 5 , 9 };
+ static int *itable,*tables[3] = { grp_3tab , grp_5tab , grp_9tab };
+
+ for(i=0;i<3;i++)
+ {
+ itable = tables[i];
+ len = tablen[i];
+ for(j=0;j<len;j++)
+ for(k=0;k<len;k++)
+ for(l=0;l<len;l++)
+ {
+ *itable++ = base[i][l];
+ *itable++ = base[i][k];
+ *itable++ = base[i][j];
+ }
+ }
+
+ for(k=0;k<27;k++)
+ {
+ double m=mulmul[k];
+ table = muls[k];
+ for(j=3,i=0;i<63;i++,j--)
+ *table++ = m * pow(2.0,(double) j / 3.0);
+ *table++ = 0.0;
+ }
+}
+
+
+void II_step_one(unsigned int *bit_alloc,int *scale,struct frame *fr)
+{
+ int stereo = fr->stereo-1;
+ int sblimit = fr->II_sblimit;
+ int jsbound = fr->jsbound;
+ int sblimit2 = fr->II_sblimit<<stereo;
+ struct al_table *alloc1 = fr->alloc;
+ int i;
+ static unsigned int scfsi_buf[64];
+ unsigned int *scfsi,*bita;
+ int sc,step;
+
+ bita = bit_alloc;
+ if(stereo)
+ {
+ for (i=jsbound;i;i--,alloc1+=(1<<step))
+ {
+ *bita++ = (char) getbits(step=alloc1->bits);
+ *bita++ = (char) getbits(step);
+ }
+ for (i=sblimit-jsbound;i;i--,alloc1+=(1<<step))
+ {
+ bita[0] = (char) getbits(step=alloc1->bits);
+ bita[1] = bita[0];
+ bita+=2;
+ }
+ bita = bit_alloc;
+ scfsi=scfsi_buf;
+ for (i=sblimit2;i;i--)
+ if (*bita++)
+ *scfsi++ = (char) getbits_fast(2);
+ }
+ else /* mono */
+ {
+ for (i=sblimit;i;i--,alloc1+=(1<<step))
+ *bita++ = (char) getbits(step=alloc1->bits);
+ bita = bit_alloc;
+ scfsi=scfsi_buf;
+ for (i=sblimit;i;i--)
+ if (*bita++)
+ *scfsi++ = (char) getbits_fast(2);
+ }
+
+ bita = bit_alloc;
+ scfsi=scfsi_buf;
+ for (i=sblimit2;i;i--)
+ if (*bita++)
+ switch (*scfsi++)
+ {
+ case 0:
+ *scale++ = getbits_fast(6);
+ *scale++ = getbits_fast(6);
+ *scale++ = getbits_fast(6);
+ break;
+ case 1 :
+ *scale++ = sc = getbits_fast(6);
+ *scale++ = sc;
+ *scale++ = getbits_fast(6);
+ break;
+ case 2:
+ *scale++ = sc = getbits_fast(6);
+ *scale++ = sc;
+ *scale++ = sc;
+ break;
+ default: /* case 3 */
+ *scale++ = getbits_fast(6);
+ *scale++ = sc = getbits_fast(6);
+ *scale++ = sc;
+ break;
+ }
+
+}
+
+void II_step_two(unsigned int *bit_alloc,real fraction[2][4][SBLIMIT],int *scale,struct frame *fr,int x1)
+{
+ int i,j,k,ba;
+ int stereo = fr->stereo;
+ int sblimit = fr->II_sblimit;
+ int jsbound = fr->jsbound;
+ struct al_table *alloc2,*alloc1 = fr->alloc;
+ unsigned int *bita=bit_alloc;
+ int d1,step;
+
+ for (i=0;i<jsbound;i++,alloc1+=(1<<step))
+ {
+ step = alloc1->bits;
+ for (j=0;j<stereo;j++)
+ {
+ if ( (ba=*bita++) )
+ {
+ k=(alloc2 = alloc1+ba)->bits;
+ if( (d1=alloc2->d) < 0)
+ {
+ real cm=muls[k][scale[x1]];
+ fraction[j][0][i] = ((real) ((int)getbits(k) + d1)) * cm;
+ fraction[j][1][i] = ((real) ((int)getbits(k) + d1)) * cm;
+ fraction[j][2][i] = ((real) ((int)getbits(k) + d1)) * cm;
+ }
+ else
+ {
+ static int *table[] = { 0,0,0,grp_3tab,0,grp_5tab,0,0,0,grp_9tab };
+ unsigned int idx,*tab,m=scale[x1];
+ idx = (unsigned int) getbits(k);
+ tab = (unsigned int *) (table[d1] + idx + idx + idx);
+ fraction[j][0][i] = muls[*tab++][m];
+ fraction[j][1][i] = muls[*tab++][m];
+ fraction[j][2][i] = muls[*tab][m];
+ }
+ scale+=3;
+ }
+ else
+ fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
+ }
+ }
+
+ for (i=jsbound;i<sblimit;i++,alloc1+=(1<<step))
+ {
+ step = alloc1->bits;
+ bita++; /* channel 1 and channel 2 bitalloc are the same */
+ if ( (ba=*bita++) )
+ {
+ k=(alloc2 = alloc1+ba)->bits;
+ if( (d1=alloc2->d) < 0)
+ {
+ real cm;
+ cm=muls[k][scale[x1+3]];
+ fraction[1][0][i] = (fraction[0][0][i] = (real) ((int)getbits(k) + d1) ) * cm;
+ fraction[1][1][i] = (fraction[0][1][i] = (real) ((int)getbits(k) + d1) ) * cm;
+ fraction[1][2][i] = (fraction[0][2][i] = (real) ((int)getbits(k) + d1) ) * cm;
+ cm=muls[k][scale[x1]];
+ fraction[0][0][i] *= cm; fraction[0][1][i] *= cm; fraction[0][2][i] *= cm;
+ }
+ else
+ {
+ static int *table[] = { 0,0,0,grp_3tab,0,grp_5tab,0,0,0,grp_9tab };
+ unsigned int idx,*tab,m1,m2;
+ m1 = scale[x1]; m2 = scale[x1+3];
+ idx = (unsigned int) getbits(k);
+ tab = (unsigned int *) (table[d1] + idx + idx + idx);
+ fraction[0][0][i] = muls[*tab][m1]; fraction[1][0][i] = muls[*tab++][m2];
+ fraction[0][1][i] = muls[*tab][m1]; fraction[1][1][i] = muls[*tab++][m2];
+ fraction[0][2][i] = muls[*tab][m1]; fraction[1][2][i] = muls[*tab][m2];
+ }
+ scale+=6;
+ }
+ else {
+ fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] =
+ fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0;
+ }
+/*
+ should we use individual scalefac for channel 2 or
+ is the current way the right one , where we just copy channel 1 to
+ channel 2 ??
+ The current 'strange' thing is, that we throw away the scalefac
+ values for the second channel ...!!
+-> changed .. now we use the scalefac values of channel one !!
+*/
+ }
+
+ for(i=sblimit;i<SBLIMIT;i++)
+ for (j=0;j<stereo;j++)
+ fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
+
+}
+
+static void II_select_table(struct frame *fr)
+{
+ static int translate[3][2][16] =
+ { { { 0,2,2,2,2,2,2,0,0,0,1,1,1,1,1,0 } ,
+ { 0,2,2,0,0,0,1,1,1,1,1,1,1,1,1,0 } } ,
+ { { 0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0 } ,
+ { 0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0 } } ,
+ { { 0,3,3,3,3,3,3,0,0,0,1,1,1,1,1,0 } ,
+ { 0,3,3,0,0,0,1,1,1,1,1,1,1,1,1,0 } } };
+
+ int table,sblim;
+ static struct al_table *tables[5] =
+ { alloc_0, alloc_1, alloc_2, alloc_3 , alloc_4 };
+ static int sblims[5] = { 27 , 30 , 8, 12 , 30 };
+
+ if(fr->lsf)
+ table = 4;
+ else
+ table = translate[fr->sampling_frequency][2-fr->stereo][fr->bitrate_index];
+ sblim = sblims[table];
+
+ fr->alloc = tables[table];
+ fr->II_sblimit = sblim;
+}
+
+int do_layer2(struct frame *fr,unsigned char *pcm_sample,
+ int *pcm_point,struct mpstr *mp)
+{
+ int clip=0;
+ int i,j;
+ int stereo = fr->stereo;
+ real fraction[2][4][SBLIMIT]; /* pick_table clears unused subbands */
+ unsigned int bit_alloc[64];
+ int scale[192];
+ int single = fr->single;
+
+ II_select_table(fr);
+ fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ?
+ (fr->mode_ext<<2)+4 : fr->II_sblimit;
+
+ if(stereo == 1 || single == 3)
+ single = 0;
+
+ II_step_one(bit_alloc, scale, fr);
+
+ for (i=0;i<SCALE_BLOCK;i++)
+ {
+ II_step_two(bit_alloc,fraction,scale,fr,i>>2);
+ for (j=0;j<3;j++) {
+ if(single >= 0) {
+ clip += synth_1to1_mono(fraction[0][j],pcm_sample,pcm_point,mp);
+ }
+ else {
+ int p1 = *pcm_point;
+ clip += synth_1to1(fraction[0][j],0,pcm_sample,&p1,mp);
+ clip += synth_1to1(fraction[1][j],1,pcm_sample,pcm_point,mp);
+ }
+
+ }
+ }
+
+ return clip;
+}
+
+
diff --git a/util/sdl/sound/decoders/mpglib/layer3.c b/util/sdl/sound/decoders/mpglib/layer3.c
new file mode 100644
index 00000000..87abb19e
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/layer3.c
@@ -0,0 +1,2020 @@
+/*
+ * Mpeg Layer-3 audio decoder
+ * --------------------------
+ * copyright (c) 1995,1996,1997 by Michael Hipp.
+ * All rights reserved. See also 'README'
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "mpg123_sdlsound.h"
+#include "mpglib_sdlsound.h"
+#include "huffman.h"
+
+#define MPEG1
+
+static real ispow[8207];
+static real aa_ca[8],aa_cs[8];
+static real COS1[12][6];
+static real win[4][36];
+static real win1[4][36];
+static real gainpow2[256+118+4];
+static real COS9[9];
+static real COS6_1,COS6_2;
+static real tfcos36[9];
+static real tfcos12[3];
+
+struct bandInfoStruct {
+ short longIdx[23];
+ short longDiff[22];
+ short shortIdx[14];
+ short shortDiff[13];
+};
+
+int longLimit[9][23];
+int shortLimit[9][14];
+
+struct bandInfoStruct bandInfo[9] = {
+
+/* MPEG 1.0 */
+ { {0,4,8,12,16,20,24,30,36,44,52,62,74, 90,110,134,162,196,238,288,342,418,576},
+ {4,4,4,4,4,4,6,6,8, 8,10,12,16,20,24,28,34,42,50,54, 76,158},
+ {0,4*3,8*3,12*3,16*3,22*3,30*3,40*3,52*3,66*3, 84*3,106*3,136*3,192*3},
+ {4,4,4,4,6,8,10,12,14,18,22,30,56} } ,
+
+ { {0,4,8,12,16,20,24,30,36,42,50,60,72, 88,106,128,156,190,230,276,330,384,576},
+ {4,4,4,4,4,4,6,6,6, 8,10,12,16,18,22,28,34,40,46,54, 54,192},
+ {0,4*3,8*3,12*3,16*3,22*3,28*3,38*3,50*3,64*3, 80*3,100*3,126*3,192*3},
+ {4,4,4,4,6,6,10,12,14,16,20,26,66} } ,
+
+ { {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576} ,
+ {4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102, 26} ,
+ {0,4*3,8*3,12*3,16*3,22*3,30*3,42*3,58*3,78*3,104*3,138*3,180*3,192*3} ,
+ {4,4,4,4,6,8,12,16,20,26,34,42,12} } ,
+
+/* MPEG 2.0 */
+ { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576},
+ {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 } ,
+ {0,4*3,8*3,12*3,18*3,24*3,32*3,42*3,56*3,74*3,100*3,132*3,174*3,192*3} ,
+ {4,4,4,6,6,8,10,14,18,26,32,42,18 } } ,
+
+ { {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576},
+ {6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,52,64,70,76,36 } ,
+ {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,136*3,180*3,192*3} ,
+ {4,4,4,6,8,10,12,14,18,24,32,44,12 } } ,
+
+ { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576},
+ {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 },
+ {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,134*3,174*3,192*3},
+ {4,4,4,6,8,10,12,14,18,24,30,40,18 } } ,
+/* MPEG 2.5 */
+ { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576} ,
+ {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54},
+ {0,12,24,36,54,78,108,144,186,240,312,402,522,576},
+ {4,4,4,6,8,10,12,14,18,24,30,40,18} },
+ { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576} ,
+ {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54},
+ {0,12,24,36,54,78,108,144,186,240,312,402,522,576},
+ {4,4,4,6,8,10,12,14,18,24,30,40,18} },
+ { {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576},
+ {12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2},
+ {0, 24, 48, 72,108,156,216,288,372,480,486,492,498,576},
+ {8,8,8,12,16,20,24,28,36,2,2,2,26} } ,
+};
+
+static int mapbuf0[9][152];
+static int mapbuf1[9][156];
+static int mapbuf2[9][44];
+static int *map[9][3];
+static int *mapend[9][3];
+
+static unsigned int n_slen2[512]; /* MPEG 2.0 slen for 'normal' mode */
+static unsigned int i_slen2[256]; /* MPEG 2.0 slen for intensity stereo */
+
+static real tan1_1[16],tan2_1[16],tan1_2[16],tan2_2[16];
+static real pow1_1[2][16],pow2_1[2][16],pow1_2[2][16],pow2_2[2][16];
+
+/*
+ * init tables for layer-3
+ */
+void init_layer3(int down_sample_sblimit)
+{
+ int i,j,k,l;
+
+ for(i=-256;i<118+4;i++)
+ gainpow2[i+256] = pow((double)2.0,-0.25 * (double) (i+210) );
+
+ for(i=0;i<8207;i++)
+ ispow[i] = pow((double)i,(double)4.0/3.0);
+
+ for (i=0;i<8;i++)
+ {
+ static double Ci[8]={-0.6,-0.535,-0.33,-0.185,-0.095,-0.041,-0.0142,-0.0037};
+ double sq=sqrt(1.0+Ci[i]*Ci[i]);
+ aa_cs[i] = 1.0/sq;
+ aa_ca[i] = Ci[i]/sq;
+ }
+
+ for(i=0;i<18;i++)
+ {
+ win[0][i] = win[1][i] = 0.5 * sin( M_PI / 72.0 * (double) (2*(i+0) +1) ) / cos ( M_PI * (double) (2*(i+0) +19) / 72.0 );
+ win[0][i+18] = win[3][i+18] = 0.5 * sin( M_PI / 72.0 * (double) (2*(i+18)+1) ) / cos ( M_PI * (double) (2*(i+18)+19) / 72.0 );
+ }
+ for(i=0;i<6;i++)
+ {
+ win[1][i+18] = 0.5 / cos ( M_PI * (double) (2*(i+18)+19) / 72.0 );
+ win[3][i+12] = 0.5 / cos ( M_PI * (double) (2*(i+12)+19) / 72.0 );
+ win[1][i+24] = 0.5 * sin( M_PI / 24.0 * (double) (2*i+13) ) / cos ( M_PI * (double) (2*(i+24)+19) / 72.0 );
+ win[1][i+30] = win[3][i] = 0.0;
+ win[3][i+6 ] = 0.5 * sin( M_PI / 24.0 * (double) (2*i+1) ) / cos ( M_PI * (double) (2*(i+6 )+19) / 72.0 );
+ }
+
+ for(i=0;i<9;i++)
+ COS9[i] = cos( M_PI / 18.0 * (double) i);
+
+ for(i=0;i<9;i++)
+ tfcos36[i] = 0.5 / cos ( M_PI * (double) (i*2+1) / 36.0 );
+ for(i=0;i<3;i++)
+ tfcos12[i] = 0.5 / cos ( M_PI * (double) (i*2+1) / 12.0 );
+
+ COS6_1 = cos( M_PI / 6.0 * (double) 1);
+ COS6_2 = cos( M_PI / 6.0 * (double) 2);
+
+ for(i=0;i<12;i++)
+ {
+ win[2][i] = 0.5 * sin( M_PI / 24.0 * (double) (2*i+1) ) / cos ( M_PI * (double) (2*i+7) / 24.0 );
+ for(j=0;j<6;j++)
+ COS1[i][j] = cos( M_PI / 24.0 * (double) ((2*i+7)*(2*j+1)) );
+ }
+
+ for(j=0;j<4;j++) {
+ static int len[4] = { 36,36,12,36 };
+ for(i=0;i<len[j];i+=2)
+ win1[j][i] = + win[j][i];
+ for(i=1;i<len[j];i+=2)
+ win1[j][i] = - win[j][i];
+ }
+
+ for(i=0;i<16;i++)
+ {
+ double t = tan( (double) i * M_PI / 12.0 );
+ tan1_1[i] = t / (1.0+t);
+ tan2_1[i] = 1.0 / (1.0 + t);
+ tan1_2[i] = M_SQRT2 * t / (1.0+t);
+ tan2_2[i] = M_SQRT2 / (1.0 + t);
+
+ for(j=0;j<2;j++) {
+ double base = pow(2.0,-0.25*(j+1.0));
+ double p1=1.0,p2=1.0;
+ if(i > 0) {
+ if( i & 1 )
+ p1 = pow(base,(i+1.0)*0.5);
+ else
+ p2 = pow(base,i*0.5);
+ }
+ pow1_1[j][i] = p1;
+ pow2_1[j][i] = p2;
+ pow1_2[j][i] = M_SQRT2 * p1;
+ pow2_2[j][i] = M_SQRT2 * p2;
+ }
+ }
+
+ for(j=0;j<9;j++)
+ {
+ struct bandInfoStruct *bi = &bandInfo[j];
+ int *mp;
+ int cb,lwin;
+ short *bdf;
+
+ mp = map[j][0] = mapbuf0[j];
+ bdf = bi->longDiff;
+ for(i=0,cb = 0; cb < 8 ; cb++,i+=*bdf++) {
+ *mp++ = (*bdf) >> 1;
+ *mp++ = i;
+ *mp++ = 3;
+ *mp++ = cb;
+ }
+ bdf = bi->shortDiff+3;
+ for(cb=3;cb<13;cb++) {
+ int l = (*bdf++) >> 1;
+ for(lwin=0;lwin<3;lwin++) {
+ *mp++ = l;
+ *mp++ = i + lwin;
+ *mp++ = lwin;
+ *mp++ = cb;
+ }
+ i += 6*l;
+ }
+ mapend[j][0] = mp;
+
+ mp = map[j][1] = mapbuf1[j];
+ bdf = bi->shortDiff+0;
+ for(i=0,cb=0;cb<13;cb++) {
+ int l = (*bdf++) >> 1;
+ for(lwin=0;lwin<3;lwin++) {
+ *mp++ = l;
+ *mp++ = i + lwin;
+ *mp++ = lwin;
+ *mp++ = cb;
+ }
+ i += 6*l;
+ }
+ mapend[j][1] = mp;
+
+ mp = map[j][2] = mapbuf2[j];
+ bdf = bi->longDiff;
+ for(cb = 0; cb < 22 ; cb++) {
+ *mp++ = (*bdf++) >> 1;
+ *mp++ = cb;
+ }
+ mapend[j][2] = mp;
+
+ }
+
+ for(j=0;j<9;j++) {
+ for(i=0;i<23;i++) {
+ longLimit[j][i] = (bandInfo[j].longIdx[i] - 1 + 8) / 18 + 1;
+ if(longLimit[j][i] > (down_sample_sblimit) )
+ longLimit[j][i] = down_sample_sblimit;
+ }
+ for(i=0;i<14;i++) {
+ shortLimit[j][i] = (bandInfo[j].shortIdx[i] - 1) / 18 + 1;
+ if(shortLimit[j][i] > (down_sample_sblimit) )
+ shortLimit[j][i] = down_sample_sblimit;
+ }
+ }
+
+ for(i=0;i<5;i++) {
+ for(j=0;j<6;j++) {
+ for(k=0;k<6;k++) {
+ int n = k + j * 6 + i * 36;
+ i_slen2[n] = i|(j<<3)|(k<<6)|(3<<12);
+ }
+ }
+ }
+ for(i=0;i<4;i++) {
+ for(j=0;j<4;j++) {
+ for(k=0;k<4;k++) {
+ int n = k + j * 4 + i * 16;
+ i_slen2[n+180] = i|(j<<3)|(k<<6)|(4<<12);
+ }
+ }
+ }
+ for(i=0;i<4;i++) {
+ for(j=0;j<3;j++) {
+ int n = j + i * 3;
+ i_slen2[n+244] = i|(j<<3) | (5<<12);
+ n_slen2[n+500] = i|(j<<3) | (2<<12) | (1<<15);
+ }
+ }
+
+ for(i=0;i<5;i++) {
+ for(j=0;j<5;j++) {
+ for(k=0;k<4;k++) {
+ for(l=0;l<4;l++) {
+ int n = l + k * 4 + j * 16 + i * 80;
+ n_slen2[n] = i|(j<<3)|(k<<6)|(l<<9)|(0<<12);
+ }
+ }
+ }
+ }
+ for(i=0;i<5;i++) {
+ for(j=0;j<5;j++) {
+ for(k=0;k<4;k++) {
+ int n = k + j * 4 + i * 20;
+ n_slen2[n+400] = i|(j<<3)|(k<<6)|(1<<12);
+ }
+ }
+ }
+}
+
+/*
+ * read additional side information
+ */
+#ifdef MPEG1
+static int III_get_side_info_1(struct III_sideinfo *si,int stereo,
+ int ms_stereo,long sfreq,int single)
+{
+ int ch, gr;
+ int powdiff = (single == 3) ? 4 : 0;
+
+ si->main_data_begin = getbits(9);
+ if (stereo == 1)
+ si->private_bits = getbits_fast(5);
+ else
+ si->private_bits = getbits_fast(3);
+
+ for (ch=0; ch<stereo; ch++) {
+ si->ch[ch].gr[0].scfsi = -1;
+ si->ch[ch].gr[1].scfsi = getbits_fast(4);
+ }
+
+ for (gr=0; gr<2; gr++)
+ {
+ for (ch=0; ch<stereo; ch++)
+ {
+ register struct gr_info_s *gr_info = &(si->ch[ch].gr[gr]);
+
+ gr_info->part2_3_length = getbits(12);
+ gr_info->big_values = getbits_fast(9);
+ if(gr_info->big_values > 288) {
+ SNDDBG(("MPGLIB: big_values too large!\n"));
+ gr_info->big_values = 288;
+ }
+ gr_info->pow2gain = gainpow2+256 - getbits_fast(8) + powdiff;
+ if(ms_stereo)
+ gr_info->pow2gain += 2;
+ gr_info->scalefac_compress = getbits_fast(4);
+/* window-switching flag == 1 for block_Type != 0 .. and block-type == 0 -> win-sw-flag = 0 */
+ if(get1bit())
+ {
+ int i;
+ gr_info->block_type = getbits_fast(2);
+ gr_info->mixed_block_flag = get1bit();
+ gr_info->table_select[0] = getbits_fast(5);
+ gr_info->table_select[1] = getbits_fast(5);
+ /*
+ * table_select[2] not needed, because there is no region2,
+ * but to satisfy some verifications tools we set it either.
+ */
+ gr_info->table_select[2] = 0;
+ for(i=0;i<3;i++)
+ gr_info->full_gain[i] = gr_info->pow2gain + (getbits_fast(3)<<3);
+
+ if(gr_info->block_type == 0) {
+ BAIL_MACRO("MPGLIB: Blocktype == 0 and window-switching == 1 not allowed.", 0);
+ }
+ /* region_count/start parameters are implicit in this case. */
+ gr_info->region1start = 36>>1;
+ gr_info->region2start = 576>>1;
+ }
+ else
+ {
+ int i,r0c,r1c;
+ for (i=0; i<3; i++)
+ gr_info->table_select[i] = getbits_fast(5);
+ r0c = getbits_fast(4);
+ r1c = getbits_fast(3);
+ gr_info->region1start = bandInfo[sfreq].longIdx[r0c+1] >> 1 ;
+ gr_info->region2start = bandInfo[sfreq].longIdx[r0c+1+r1c+1] >> 1;
+ gr_info->block_type = 0;
+ gr_info->mixed_block_flag = 0;
+ }
+ gr_info->preflag = get1bit();
+ gr_info->scalefac_scale = get1bit();
+ gr_info->count1table_select = get1bit();
+ }
+ }
+ return !0;
+}
+#endif
+
+/*
+ * Side Info for MPEG 2.0 / LSF
+ */
+static int III_get_side_info_2(struct III_sideinfo *si,int stereo,
+ int ms_stereo,long sfreq,int single)
+{
+ int ch;
+ int powdiff = (single == 3) ? 4 : 0;
+
+ si->main_data_begin = getbits(8);
+ if (stereo == 1)
+ si->private_bits = get1bit();
+ else
+ si->private_bits = getbits_fast(2);
+
+ for (ch=0; ch<stereo; ch++)
+ {
+ register struct gr_info_s *gr_info = &(si->ch[ch].gr[0]);
+
+ gr_info->part2_3_length = getbits(12);
+ gr_info->big_values = getbits_fast(9);
+ if(gr_info->big_values > 288) {
+ SNDDBG(("MPGLIB: big_values too large!\n"));
+ gr_info->big_values = 288;
+ }
+ gr_info->pow2gain = gainpow2+256 - getbits_fast(8) + powdiff;
+ if(ms_stereo)
+ gr_info->pow2gain += 2;
+ gr_info->scalefac_compress = getbits(9);
+/* window-switching flag == 1 for block_Type != 0 .. and block-type == 0 -> win-sw-flag = 0 */
+ if(get1bit())
+ {
+ int i;
+ gr_info->block_type = getbits_fast(2);
+ gr_info->mixed_block_flag = get1bit();
+ gr_info->table_select[0] = getbits_fast(5);
+ gr_info->table_select[1] = getbits_fast(5);
+ /*
+ * table_select[2] not needed, because there is no region2,
+ * but to satisfy some verifications tools we set it either.
+ */
+ gr_info->table_select[2] = 0;
+ for(i=0;i<3;i++)
+ gr_info->full_gain[i] = gr_info->pow2gain + (getbits_fast(3)<<3);
+
+ if(gr_info->block_type == 0) {
+ BAIL_MACRO("MPGLIB: Blocktype == 0 and window-switching == 1 not allowed.", 0);
+ }
+ /* region_count/start parameters are implicit in this case. */
+/* check this again! */
+ if(gr_info->block_type == 2)
+ gr_info->region1start = 36>>1;
+ else if(sfreq == 8)
+/* check this for 2.5 and sfreq=8 */
+ gr_info->region1start = 108>>1;
+ else
+ gr_info->region1start = 54>>1;
+ gr_info->region2start = 576>>1;
+ }
+ else
+ {
+ int i,r0c,r1c;
+ for (i=0; i<3; i++)
+ gr_info->table_select[i] = getbits_fast(5);
+ r0c = getbits_fast(4);
+ r1c = getbits_fast(3);
+ gr_info->region1start = bandInfo[sfreq].longIdx[r0c+1] >> 1 ;
+ gr_info->region2start = bandInfo[sfreq].longIdx[r0c+1+r1c+1] >> 1;
+ gr_info->block_type = 0;
+ gr_info->mixed_block_flag = 0;
+ }
+ gr_info->scalefac_scale = get1bit();
+ gr_info->count1table_select = get1bit();
+ }
+ return !0;
+}
+
+/*
+ * read scalefactors
+ */
+#ifdef MPEG1
+static int III_get_scale_factors_1(int *scf,struct gr_info_s *gr_info)
+{
+ static const unsigned char slen[2][16] = {
+ {0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4},
+ {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}
+ };
+ int numbits;
+ int num0 = slen[0][gr_info->scalefac_compress];
+ int num1 = slen[1][gr_info->scalefac_compress];
+
+ if (gr_info->block_type == 2) {
+ int i=18;
+ numbits = (num0 + num1) * 18;
+
+ if (gr_info->mixed_block_flag) {
+ for (i=8;i;i--)
+ *scf++ = getbits_fast(num0);
+ i = 9;
+ numbits -= num0; /* num0 * 17 + num1 * 18 */
+ }
+
+ for (;i;i--)
+ *scf++ = getbits_fast(num0);
+ for (i = 18; i; i--)
+ *scf++ = getbits_fast(num1);
+ *scf++ = 0; *scf++ = 0; *scf++ = 0; /* short[13][0..2] = 0 */
+ }
+ else {
+ int i;
+ int scfsi = gr_info->scfsi;
+
+ if(scfsi < 0) { /* scfsi < 0 => granule == 0 */
+ for(i=11;i;i--)
+ *scf++ = getbits_fast(num0);
+ for(i=10;i;i--)
+ *scf++ = getbits_fast(num1);
+ numbits = (num0 + num1) * 10 + num0;
+ *scf++ = 0;
+ }
+ else {
+ numbits = 0;
+ if(!(scfsi & 0x8)) {
+ for (i=0;i<6;i++)
+ *scf++ = getbits_fast(num0);
+ numbits += num0 * 6;
+ }
+ else {
+ scf += 6;
+ }
+
+ if(!(scfsi & 0x4)) {
+ for (i=0;i<5;i++)
+ *scf++ = getbits_fast(num0);
+ numbits += num0 * 5;
+ }
+ else {
+ scf += 5;
+ }
+
+ if(!(scfsi & 0x2)) {
+ for(i=0;i<5;i++)
+ *scf++ = getbits_fast(num1);
+ numbits += num1 * 5;
+ }
+ else {
+ scf += 5;
+ }
+
+ if(!(scfsi & 0x1)) {
+ for (i=0;i<5;i++)
+ *scf++ = getbits_fast(num1);
+ numbits += num1 * 5;
+ }
+ else {
+ scf += 5;
+ }
+ *scf++ = 0; /* no l[21] in original sources */
+ }
+ }
+ return numbits;
+}
+#endif
+
+
+static int III_get_scale_factors_2(int *scf,struct gr_info_s *gr_info,int i_stereo)
+{
+ unsigned char *pnt;
+ int i,j;
+ unsigned int slen;
+ int n = 0;
+ int numbits = 0;
+
+ static unsigned char stab[3][6][4] = {
+ { { 6, 5, 5,5 } , { 6, 5, 7,3 } , { 11,10,0,0} ,
+ { 7, 7, 7,0 } , { 6, 6, 6,3 } , { 8, 8,5,0} } ,
+ { { 9, 9, 9,9 } , { 9, 9,12,6 } , { 18,18,0,0} ,
+ {12,12,12,0 } , {12, 9, 9,6 } , { 15,12,9,0} } ,
+ { { 6, 9, 9,9 } , { 6, 9,12,6 } , { 15,18,0,0} ,
+ { 6,15,12,0 } , { 6,12, 9,6 } , { 6,18,9,0} } };
+
+ if(i_stereo) /* i_stereo AND second channel -> do_layer3() checks this */
+ slen = i_slen2[gr_info->scalefac_compress>>1];
+ else
+ slen = n_slen2[gr_info->scalefac_compress];
+
+ gr_info->preflag = (slen>>15) & 0x1;
+
+ n = 0;
+ if( gr_info->block_type == 2 ) {
+ n++;
+ if(gr_info->mixed_block_flag)
+ n++;
+ }
+
+ pnt = stab[n][(slen>>12)&0x7];
+
+ for(i=0;i<4;i++) {
+ int num = slen & 0x7;
+ slen >>= 3;
+ if(num) {
+ for(j=0;j<(int)(pnt[i]);j++)
+ *scf++ = getbits_fast(num);
+ numbits += pnt[i] * num;
+ }
+ else {
+ for(j=0;j<(int)(pnt[i]);j++)
+ *scf++ = 0;
+ }
+ }
+
+ n = (n << 1) + 1;
+ for(i=0;i<n;i++)
+ *scf++ = 0;
+
+ return numbits;
+}
+
+static int pretab1[22] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0};
+static int pretab2[22] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/*
+ * don't forget to apply the same changes to III_dequantize_sample_ms() !!!
+ */
+static int III_dequantize_sample(real xr[SBLIMIT][SSLIMIT],int *scf,
+ struct gr_info_s *gr_info,int sfreq,int part2bits)
+{
+ int shift = 1 + gr_info->scalefac_scale;
+ real *xrpnt = (real *) xr;
+ int l[3],l3;
+ int part2remain = gr_info->part2_3_length - part2bits;
+ int *me;
+
+ {
+ int bv = gr_info->big_values;
+ int region1 = gr_info->region1start;
+ int region2 = gr_info->region2start;
+
+ l3 = ((576>>1)-bv)>>1;
+/*
+ * we may lose the 'odd' bit here !!
+ * check this later again
+ */
+ if(bv <= region1) {
+ l[0] = bv; l[1] = 0; l[2] = 0;
+ }
+ else {
+ l[0] = region1;
+ if(bv <= region2) {
+ l[1] = bv - l[0]; l[2] = 0;
+ }
+ else {
+ l[1] = region2 - l[0]; l[2] = bv - region2;
+ }
+ }
+ }
+
+ if(gr_info->block_type == 2) {
+ /*
+ * decoding with short or mixed mode BandIndex table
+ */
+ int i,max[4];
+ int step=0,lwin=0,cb=0;
+ register real v = 0.0;
+ register int *m,mc;
+
+ if(gr_info->mixed_block_flag) {
+ max[3] = -1;
+ max[0] = max[1] = max[2] = 2;
+ m = map[sfreq][0];
+ me = mapend[sfreq][0];
+ }
+ else {
+ max[0] = max[1] = max[2] = max[3] = -1;
+ /* max[3] not really needed in this case */
+ m = map[sfreq][1];
+ me = mapend[sfreq][1];
+ }
+
+ mc = 0;
+ for(i=0;i<2;i++) {
+ int lp = l[i];
+ struct newhuff *h = ht+gr_info->table_select[i];
+ for(;lp;lp--,mc--) {
+ register int x,y;
+ if( (!mc) ) {
+ mc = *m++;
+ xrpnt = ((real *) xr) + (*m++);
+ lwin = *m++;
+ cb = *m++;
+ if(lwin == 3) {
+ v = gr_info->pow2gain[(*scf++) << shift];
+ step = 1;
+ }
+ else {
+ v = gr_info->full_gain[lwin][(*scf++) << shift];
+ step = 3;
+ }
+ }
+ {
+ register short *val = h->table;
+ while((y=*val++)<0) {
+ if (get1bit())
+ val -= y;
+ part2remain--;
+ }
+ x = y >> 4;
+ y &= 0xf;
+ }
+ if(x == 15) {
+ max[lwin] = cb;
+ part2remain -= h->linbits+1;
+ x += getbits(h->linbits);
+ if(get1bit())
+ *xrpnt = -ispow[x] * v;
+ else
+ *xrpnt = ispow[x] * v;
+ }
+ else if(x) {
+ max[lwin] = cb;
+ if(get1bit())
+ *xrpnt = -ispow[x] * v;
+ else
+ *xrpnt = ispow[x] * v;
+ part2remain--;
+ }
+ else
+ *xrpnt = 0.0;
+ xrpnt += step;
+ if(y == 15) {
+ max[lwin] = cb;
+ part2remain -= h->linbits+1;
+ y += getbits(h->linbits);
+ if(get1bit())
+ *xrpnt = -ispow[y] * v;
+ else
+ *xrpnt = ispow[y] * v;
+ }
+ else if(y) {
+ max[lwin] = cb;
+ if(get1bit())
+ *xrpnt = -ispow[y] * v;
+ else
+ *xrpnt = ispow[y] * v;
+ part2remain--;
+ }
+ else
+ *xrpnt = 0.0;
+ xrpnt += step;
+ }
+ }
+ for(;l3 && (part2remain > 0);l3--) {
+ struct newhuff *h = htc+gr_info->count1table_select;
+ register short *val = h->table,a;
+
+ while((a=*val++)<0) {
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ a = 0;
+ break;
+ }
+ if (get1bit())
+ val -= a;
+ }
+
+ for(i=0;i<4;i++) {
+ if(!(i & 1)) {
+ if(!mc) {
+ mc = *m++;
+ xrpnt = ((real *) xr) + (*m++);
+ lwin = *m++;
+ cb = *m++;
+ if(lwin == 3) {
+ v = gr_info->pow2gain[(*scf++) << shift];
+ step = 1;
+ }
+ else {
+ v = gr_info->full_gain[lwin][(*scf++) << shift];
+ step = 3;
+ }
+ }
+ mc--;
+ }
+ if( (a & (0x8>>i)) ) {
+ max[lwin] = cb;
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ break;
+ }
+ if(get1bit())
+ *xrpnt = -v;
+ else
+ *xrpnt = v;
+ }
+ else
+ *xrpnt = 0.0;
+ xrpnt += step;
+ }
+ }
+
+ while( m < me ) {
+ if(!mc) {
+ mc = *m++;
+ xrpnt = ((real *) xr) + *m++;
+ if( (*m++) == 3)
+ step = 1;
+ else
+ step = 3;
+ m++; /* cb */
+ }
+ mc--;
+ *xrpnt = 0.0;
+ xrpnt += step;
+ *xrpnt = 0.0;
+ xrpnt += step;
+/* we could add a little opt. here:
+ * if we finished a band for window 3 or a long band
+ * further bands could copied in a simple loop without a
+ * special 'map' decoding
+ */
+ }
+
+ gr_info->maxband[0] = max[0]+1;
+ gr_info->maxband[1] = max[1]+1;
+ gr_info->maxband[2] = max[2]+1;
+ gr_info->maxbandl = max[3]+1;
+
+ {
+ int rmax = max[0] > max[1] ? max[0] : max[1];
+ rmax = (rmax > max[2] ? rmax : max[2]) + 1;
+ gr_info->maxb = rmax ? shortLimit[sfreq][rmax] : longLimit[sfreq][max[3]+1];
+ }
+
+ }
+ else {
+ /*
+ * decoding with 'long' BandIndex table (block_type != 2)
+ */
+ int *pretab = gr_info->preflag ? pretab1 : pretab2;
+ int i,max = -1;
+ int cb = 0;
+ register int *m = map[sfreq][2];
+ register real v = 0.0;
+ register int mc = 0;
+#if 0
+ me = mapend[sfreq][2];
+#endif
+
+ /*
+ * long hash table values
+ */
+ for(i=0;i<3;i++) {
+ int lp = l[i];
+ struct newhuff *h = ht+gr_info->table_select[i];
+
+ for(;lp;lp--,mc--) {
+ int x,y;
+
+ if(!mc) {
+ mc = *m++;
+ v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift];
+ cb = *m++;
+ }
+ {
+ register short *val = h->table;
+ while((y=*val++)<0) {
+ if (get1bit())
+ val -= y;
+ part2remain--;
+ }
+ x = y >> 4;
+ y &= 0xf;
+ }
+ if (x == 15) {
+ max = cb;
+ part2remain -= h->linbits+1;
+ x += getbits(h->linbits);
+ if(get1bit())
+ *xrpnt++ = -ispow[x] * v;
+ else
+ *xrpnt++ = ispow[x] * v;
+ }
+ else if(x) {
+ max = cb;
+ if(get1bit())
+ *xrpnt++ = -ispow[x] * v;
+ else
+ *xrpnt++ = ispow[x] * v;
+ part2remain--;
+ }
+ else
+ *xrpnt++ = 0.0;
+
+ if (y == 15) {
+ max = cb;
+ part2remain -= h->linbits+1;
+ y += getbits(h->linbits);
+ if(get1bit())
+ *xrpnt++ = -ispow[y] * v;
+ else
+ *xrpnt++ = ispow[y] * v;
+ }
+ else if(y) {
+ max = cb;
+ if(get1bit())
+ *xrpnt++ = -ispow[y] * v;
+ else
+ *xrpnt++ = ispow[y] * v;
+ part2remain--;
+ }
+ else
+ *xrpnt++ = 0.0;
+ }
+ }
+
+ /*
+ * short (count1table) values
+ */
+ for(;l3 && (part2remain > 0);l3--) {
+ struct newhuff *h = htc+gr_info->count1table_select;
+ register short *val = h->table,a;
+
+ while((a=*val++)<0) {
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ a = 0;
+ break;
+ }
+ if (get1bit())
+ val -= a;
+ }
+
+ for(i=0;i<4;i++) {
+ if(!(i & 1)) {
+ if(!mc) {
+ mc = *m++;
+ cb = *m++;
+ v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift];
+ }
+ mc--;
+ }
+ if ( (a & (0x8>>i)) ) {
+ max = cb;
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ break;
+ }
+ if(get1bit())
+ *xrpnt++ = -v;
+ else
+ *xrpnt++ = v;
+ }
+ else
+ *xrpnt++ = 0.0;
+ }
+ }
+
+ /*
+ * zero part
+ */
+ for(i=(&xr[SBLIMIT][0]-xrpnt)>>1;i;i--) {
+ *xrpnt++ = 0.0;
+ *xrpnt++ = 0.0;
+ }
+
+ gr_info->maxbandl = max+1;
+ gr_info->maxb = longLimit[sfreq][gr_info->maxbandl];
+ }
+
+ while( part2remain > 16 ) {
+ getbits(16); /* Dismiss stuffing Bits */
+ part2remain -= 16;
+ }
+ if(part2remain > 0)
+ getbits(part2remain);
+ else if(part2remain < 0) {
+ char err[128];
+ snprintf(err, sizeof (err),
+ "MPGLIB: Can't rewind stream by %d bits!",
+ -part2remain);
+ BAIL_MACRO(err, 1); /* -> error */
+ }
+ return 0;
+}
+
+#if 0
+static int III_dequantize_sample_ms(real xr[2][SBLIMIT][SSLIMIT],int *scf,
+ struct gr_info_s *gr_info,int sfreq,int part2bits)
+{
+ int shift = 1 + gr_info->scalefac_scale;
+ real *xrpnt = (real *) xr[1];
+ real *xr0pnt = (real *) xr[0];
+ int l[3],l3;
+ int part2remain = gr_info->part2_3_length - part2bits;
+ int *me;
+
+ {
+ int bv = gr_info->big_values;
+ int region1 = gr_info->region1start;
+ int region2 = gr_info->region2start;
+
+ l3 = ((576>>1)-bv)>>1;
+/*
+ * we may lose the 'odd' bit here !!
+ * check this later gain
+ */
+ if(bv <= region1) {
+ l[0] = bv; l[1] = 0; l[2] = 0;
+ }
+ else {
+ l[0] = region1;
+ if(bv <= region2) {
+ l[1] = bv - l[0]; l[2] = 0;
+ }
+ else {
+ l[1] = region2 - l[0]; l[2] = bv - region2;
+ }
+ }
+ }
+
+ if(gr_info->block_type == 2) {
+ int i,max[4];
+ int step=0,lwin=0,cb=0;
+ register real v = 0.0;
+ register int *m,mc = 0;
+
+ if(gr_info->mixed_block_flag) {
+ max[3] = -1;
+ max[0] = max[1] = max[2] = 2;
+ m = map[sfreq][0];
+ me = mapend[sfreq][0];
+ }
+ else {
+ max[0] = max[1] = max[2] = max[3] = -1;
+ /* max[3] not really needed in this case */
+ m = map[sfreq][1];
+ me = mapend[sfreq][1];
+ }
+
+ for(i=0;i<2;i++) {
+ int lp = l[i];
+ struct newhuff *h = ht+gr_info->table_select[i];
+ for(;lp;lp--,mc--) {
+ int x,y;
+
+ if(!mc) {
+ mc = *m++;
+ xrpnt = ((real *) xr[1]) + *m;
+ xr0pnt = ((real *) xr[0]) + *m++;
+ lwin = *m++;
+ cb = *m++;
+ if(lwin == 3) {
+ v = gr_info->pow2gain[(*scf++) << shift];
+ step = 1;
+ }
+ else {
+ v = gr_info->full_gain[lwin][(*scf++) << shift];
+ step = 3;
+ }
+ }
+ {
+ register short *val = h->table;
+ while((y=*val++)<0) {
+ if (get1bit())
+ val -= y;
+ part2remain--;
+ }
+ x = y >> 4;
+ y &= 0xf;
+ }
+ if(x == 15) {
+ max[lwin] = cb;
+ part2remain -= h->linbits+1;
+ x += getbits(h->linbits);
+ if(get1bit()) {
+ real a = ispow[x] * v;
+ *xrpnt = *xr0pnt + a;
+ *xr0pnt -= a;
+ }
+ else {
+ real a = ispow[x] * v;
+ *xrpnt = *xr0pnt - a;
+ *xr0pnt += a;
+ }
+ }
+ else if(x) {
+ max[lwin] = cb;
+ if(get1bit()) {
+ real a = ispow[x] * v;
+ *xrpnt = *xr0pnt + a;
+ *xr0pnt -= a;
+ }
+ else {
+ real a = ispow[x] * v;
+ *xrpnt = *xr0pnt - a;
+ *xr0pnt += a;
+ }
+ part2remain--;
+ }
+ else
+ *xrpnt = *xr0pnt;
+ xrpnt += step;
+ xr0pnt += step;
+
+ if(y == 15) {
+ max[lwin] = cb;
+ part2remain -= h->linbits+1;
+ y += getbits(h->linbits);
+ if(get1bit()) {
+ real a = ispow[y] * v;
+ *xrpnt = *xr0pnt + a;
+ *xr0pnt -= a;
+ }
+ else {
+ real a = ispow[y] * v;
+ *xrpnt = *xr0pnt - a;
+ *xr0pnt += a;
+ }
+ }
+ else if(y) {
+ max[lwin] = cb;
+ if(get1bit()) {
+ real a = ispow[y] * v;
+ *xrpnt = *xr0pnt + a;
+ *xr0pnt -= a;
+ }
+ else {
+ real a = ispow[y] * v;
+ *xrpnt = *xr0pnt - a;
+ *xr0pnt += a;
+ }
+ part2remain--;
+ }
+ else
+ *xrpnt = *xr0pnt;
+ xrpnt += step;
+ xr0pnt += step;
+ }
+ }
+
+ for(;l3 && (part2remain > 0);l3--) {
+ struct newhuff *h = htc+gr_info->count1table_select;
+ register short *val = h->table,a;
+
+ while((a=*val++)<0) {
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ a = 0;
+ break;
+ }
+ if (get1bit())
+ val -= a;
+ }
+
+ for(i=0;i<4;i++) {
+ if(!(i & 1)) {
+ if(!mc) {
+ mc = *m++;
+ xrpnt = ((real *) xr[1]) + *m;
+ xr0pnt = ((real *) xr[0]) + *m++;
+ lwin = *m++;
+ cb = *m++;
+ if(lwin == 3) {
+ v = gr_info->pow2gain[(*scf++) << shift];
+ step = 1;
+ }
+ else {
+ v = gr_info->full_gain[lwin][(*scf++) << shift];
+ step = 3;
+ }
+ }
+ mc--;
+ }
+ if( (a & (0x8>>i)) ) {
+ max[lwin] = cb;
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ break;
+ }
+ if(get1bit()) {
+ *xrpnt = *xr0pnt + v;
+ *xr0pnt -= v;
+ }
+ else {
+ *xrpnt = *xr0pnt - v;
+ *xr0pnt += v;
+ }
+ }
+ else
+ *xrpnt = *xr0pnt;
+ xrpnt += step;
+ xr0pnt += step;
+ }
+ }
+
+ while( m < me ) {
+ if(!mc) {
+ mc = *m++;
+ xrpnt = ((real *) xr[1]) + *m;
+ xr0pnt = ((real *) xr[0]) + *m++;
+ if(*m++ == 3)
+ step = 1;
+ else
+ step = 3;
+ m++; /* cb */
+ }
+ mc--;
+ *xrpnt = *xr0pnt;
+ xrpnt += step;
+ xr0pnt += step;
+ *xrpnt = *xr0pnt;
+ xrpnt += step;
+ xr0pnt += step;
+/* we could add a little opt. here:
+ * if we finished a band for window 3 or a long band
+ * further bands could copied in a simple loop without a
+ * special 'map' decoding
+ */
+ }
+
+ gr_info->maxband[0] = max[0]+1;
+ gr_info->maxband[1] = max[1]+1;
+ gr_info->maxband[2] = max[2]+1;
+ gr_info->maxbandl = max[3]+1;
+
+ {
+ int rmax = max[0] > max[1] ? max[0] : max[1];
+ rmax = (rmax > max[2] ? rmax : max[2]) + 1;
+ gr_info->maxb = rmax ? shortLimit[sfreq][rmax] : longLimit[sfreq][max[3]+1];
+ }
+ }
+ else {
+ int *pretab = gr_info->preflag ? pretab1 : pretab2;
+ int i,max = -1;
+ int cb = 0;
+ register int mc=0,*m = map[sfreq][2];
+ register real v = 0.0;
+#if 0
+ me = mapend[sfreq][2];
+#endif
+
+ for(i=0;i<3;i++) {
+ int lp = l[i];
+ struct newhuff *h = ht+gr_info->table_select[i];
+
+ for(;lp;lp--,mc--) {
+ int x,y;
+ if(!mc) {
+ mc = *m++;
+ cb = *m++;
+ v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift];
+ }
+ {
+ register short *val = h->table;
+ while((y=*val++)<0) {
+ if (get1bit())
+ val -= y;
+ part2remain--;
+ }
+ x = y >> 4;
+ y &= 0xf;
+ }
+ if (x == 15) {
+ max = cb;
+ part2remain -= h->linbits+1;
+ x += getbits(h->linbits);
+ if(get1bit()) {
+ real a = ispow[x] * v;
+ *xrpnt++ = *xr0pnt + a;
+ *xr0pnt++ -= a;
+ }
+ else {
+ real a = ispow[x] * v;
+ *xrpnt++ = *xr0pnt - a;
+ *xr0pnt++ += a;
+ }
+ }
+ else if(x) {
+ max = cb;
+ if(get1bit()) {
+ real a = ispow[x] * v;
+ *xrpnt++ = *xr0pnt + a;
+ *xr0pnt++ -= a;
+ }
+ else {
+ real a = ispow[x] * v;
+ *xrpnt++ = *xr0pnt - a;
+ *xr0pnt++ += a;
+ }
+ part2remain--;
+ }
+ else
+ *xrpnt++ = *xr0pnt++;
+
+ if (y == 15) {
+ max = cb;
+ part2remain -= h->linbits+1;
+ y += getbits(h->linbits);
+ if(get1bit()) {
+ real a = ispow[y] * v;
+ *xrpnt++ = *xr0pnt + a;
+ *xr0pnt++ -= a;
+ }
+ else {
+ real a = ispow[y] * v;
+ *xrpnt++ = *xr0pnt - a;
+ *xr0pnt++ += a;
+ }
+ }
+ else if(y) {
+ max = cb;
+ if(get1bit()) {
+ real a = ispow[y] * v;
+ *xrpnt++ = *xr0pnt + a;
+ *xr0pnt++ -= a;
+ }
+ else {
+ real a = ispow[y] * v;
+ *xrpnt++ = *xr0pnt - a;
+ *xr0pnt++ += a;
+ }
+ part2remain--;
+ }
+ else
+ *xrpnt++ = *xr0pnt++;
+ }
+ }
+
+ for(;l3 && (part2remain > 0);l3--) {
+ struct newhuff *h = htc+gr_info->count1table_select;
+ register short *val = h->table,a;
+
+ while((a=*val++)<0) {
+ part2remain--;
+ if(part2remain < 0) {
+ part2remain++;
+ a = 0;
+ break;
+ }
+ if (get1bit())
+ val -= a;
+ }
+
+ for(i=0;i<4;i++) {
+ if(!(i & 1)) {
+ if(!mc) {
+ mc = *m++;
+ cb = *m++;
+ v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift];
+ }
+ mc--;
+ }
+ if ( (a & (0x8>>i)) ) {
+ max = cb;
+ part2remain--;
+ if(part2remain <= 0) {
+ part2remain++;
+ break;
+ }
+ if(get1bit()) {
+ *xrpnt++ = *xr0pnt + v;
+ *xr0pnt++ -= v;
+ }
+ else {
+ *xrpnt++ = *xr0pnt - v;
+ *xr0pnt++ += v;
+ }
+ }
+ else
+ *xrpnt++ = *xr0pnt++;
+ }
+ }
+ for(i=(&xr[1][SBLIMIT][0]-xrpnt)>>1;i;i--) {
+ *xrpnt++ = *xr0pnt++;
+ *xrpnt++ = *xr0pnt++;
+ }
+
+ gr_info->maxbandl = max+1;
+ gr_info->maxb = longLimit[sfreq][gr_info->maxbandl];
+ }
+
+ while ( part2remain > 16 ) {
+ getbits(16); /* Dismiss stuffing Bits */
+ part2remain -= 16;
+ }
+ if(part2remain > 0 )
+ getbits(part2remain);
+ else if(part2remain < 0) {
+ char err[128];
+ snprintf(err, sizeof (err),
+ "MPGLIB: Can't rewind stream by %d bits!",
+ -part2remain);
+ BAIL_MACRO(err, 1); /* -> error */
+ }
+ return 0;
+}
+#endif
+
+/*
+ * III_stereo: calculate real channel values for Joint-I-Stereo-mode
+ */
+static void III_i_stereo(real xr_buf[2][SBLIMIT][SSLIMIT],int *scalefac,
+ struct gr_info_s *gr_info,int sfreq,int ms_stereo,int lsf)
+{
+ real (*xr)[SBLIMIT*SSLIMIT] = (real (*)[SBLIMIT*SSLIMIT] ) xr_buf;
+ struct bandInfoStruct *bi = &bandInfo[sfreq];
+ real *tab1,*tab2;
+
+ if(lsf) {
+ int p = gr_info->scalefac_compress & 0x1;
+ if(ms_stereo) {
+ tab1 = pow1_2[p]; tab2 = pow2_2[p];
+ }
+ else {
+ tab1 = pow1_1[p]; tab2 = pow2_1[p];
+ }
+ }
+ else {
+ if(ms_stereo) {
+ tab1 = tan1_2; tab2 = tan2_2;
+ }
+ else {
+ tab1 = tan1_1; tab2 = tan2_1;
+ }
+ }
+
+ if (gr_info->block_type == 2)
+ {
+ int lwin,do_l = 0;
+ if( gr_info->mixed_block_flag )
+ do_l = 1;
+
+ for (lwin=0;lwin<3;lwin++) /* process each window */
+ {
+ /* get first band with zero values */
+ int is_p,sb,idx,sfb = gr_info->maxband[lwin]; /* sfb is minimal 3 for mixed mode */
+ if(sfb > 3)
+ do_l = 0;
+
+ for(;sfb<12;sfb++)
+ {
+ is_p = scalefac[sfb*3+lwin-gr_info->mixed_block_flag]; /* scale: 0-15 */
+ if(is_p != 7) {
+ real t1,t2;
+ sb = bi->shortDiff[sfb];
+ idx = bi->shortIdx[sfb] + lwin;
+ t1 = tab1[is_p]; t2 = tab2[is_p];
+ for (; sb > 0; sb--,idx+=3)
+ {
+ real v = xr[0][idx];
+ xr[0][idx] = v * t1;
+ xr[1][idx] = v * t2;
+ }
+ }
+ }
+
+#if 1
+/* in the original: copy 10 to 11 , here: copy 11 to 12
+maybe still wrong??? (copy 12 to 13?) */
+ is_p = scalefac[11*3+lwin-gr_info->mixed_block_flag]; /* scale: 0-15 */
+ sb = bi->shortDiff[12];
+ idx = bi->shortIdx[12] + lwin;
+#else
+ is_p = scalefac[10*3+lwin-gr_info->mixed_block_flag]; /* scale: 0-15 */
+ sb = bi->shortDiff[11];
+ idx = bi->shortIdx[11] + lwin;
+#endif
+ if(is_p != 7)
+ {
+ real t1,t2;
+ t1 = tab1[is_p]; t2 = tab2[is_p];
+ for ( ; sb > 0; sb--,idx+=3 )
+ {
+ real v = xr[0][idx];
+ xr[0][idx] = v * t1;
+ xr[1][idx] = v * t2;
+ }
+ }
+ } /* end for(lwin; .. ; . ) */
+
+ if (do_l)
+ {
+/* also check l-part, if ALL bands in the three windows are 'empty'
+ * and mode = mixed_mode
+ */
+ int sfb = gr_info->maxbandl;
+ int idx = bi->longIdx[sfb];
+
+ for ( ; sfb<8; sfb++ )
+ {
+ int sb = bi->longDiff[sfb];
+ int is_p = scalefac[sfb]; /* scale: 0-15 */
+ if(is_p != 7) {
+ real t1,t2;
+ t1 = tab1[is_p]; t2 = tab2[is_p];
+ for ( ; sb > 0; sb--,idx++)
+ {
+ real v = xr[0][idx];
+ xr[0][idx] = v * t1;
+ xr[1][idx] = v * t2;
+ }
+ }
+ else
+ idx += sb;
+ }
+ }
+ }
+ else /* ((gr_info->block_type != 2)) */
+ {
+ int sfb = gr_info->maxbandl;
+ int is_p,idx = bi->longIdx[sfb];
+ for ( ; sfb<21; sfb++)
+ {
+ int sb = bi->longDiff[sfb];
+ is_p = scalefac[sfb]; /* scale: 0-15 */
+ if(is_p != 7) {
+ real t1,t2;
+ t1 = tab1[is_p]; t2 = tab2[is_p];
+ for ( ; sb > 0; sb--,idx++)
+ {
+ real v = xr[0][idx];
+ xr[0][idx] = v * t1;
+ xr[1][idx] = v * t2;
+ }
+ }
+ else
+ idx += sb;
+ }
+
+ is_p = scalefac[20]; /* copy l-band 20 to l-band 21 */
+ if(is_p != 7)
+ {
+ int sb;
+ real t1 = tab1[is_p],t2 = tab2[is_p];
+
+ for ( sb = bi->longDiff[21]; sb > 0; sb--,idx++ )
+ {
+ real v = xr[0][idx];
+ xr[0][idx] = v * t1;
+ xr[1][idx] = v * t2;
+ }
+ }
+ } /* ... */
+}
+
+static void III_antialias(real xr[SBLIMIT][SSLIMIT],struct gr_info_s *gr_info)
+{
+ int sblim;
+
+ if(gr_info->block_type == 2)
+ {
+ if(!gr_info->mixed_block_flag)
+ return;
+ sblim = 1;
+ }
+ else {
+ sblim = gr_info->maxb-1;
+ }
+
+ /* 31 alias-reduction operations between each pair of sub-bands */
+ /* with 8 butterflies between each pair */
+
+ {
+ int sb;
+ real *xr1=(real *) xr[1];
+
+ for(sb=sblim;sb;sb--,xr1+=10)
+ {
+ int ss;
+ real *cs=aa_cs,*ca=aa_ca;
+ real *xr2 = xr1;
+
+ for(ss=7;ss>=0;ss--)
+ { /* upper and lower butterfly inputs */
+ register real bu = *--xr2,bd = *xr1;
+ *xr2 = (bu * (*cs) ) - (bd * (*ca) );
+ *xr1++ = (bd * (*cs++) ) + (bu * (*ca++) );
+ }
+ }
+ }
+}
+
+/*
+ DCT insipired by Jeff Tsay's DCT from the maplay package
+ this is an optimized version with manual unroll.
+
+ References:
+ [1] S. Winograd: "On Computing the Discrete Fourier Transform",
+ Mathematics of Computation, Volume 32, Number 141, January 1978,
+ Pages 175-199
+*/
+
+static void dct36(real *inbuf,real *o1,real *o2,real *wintab,real *tsbuf)
+{
+ {
+ register real *in = inbuf;
+
+ in[17]+=in[16]; in[16]+=in[15]; in[15]+=in[14];
+ in[14]+=in[13]; in[13]+=in[12]; in[12]+=in[11];
+ in[11]+=in[10]; in[10]+=in[9]; in[9] +=in[8];
+ in[8] +=in[7]; in[7] +=in[6]; in[6] +=in[5];
+ in[5] +=in[4]; in[4] +=in[3]; in[3] +=in[2];
+ in[2] +=in[1]; in[1] +=in[0];
+
+ in[17]+=in[15]; in[15]+=in[13]; in[13]+=in[11]; in[11]+=in[9];
+ in[9] +=in[7]; in[7] +=in[5]; in[5] +=in[3]; in[3] +=in[1];
+
+
+ {
+
+#define MACRO0(v) { \
+ real tmp; \
+ out2[9+(v)] = (tmp = sum0 + sum1) * w[27+(v)]; \
+ out2[8-(v)] = tmp * w[26-(v)]; } \
+ sum0 -= sum1; \
+ ts[SBLIMIT*(8-(v))] = out1[8-(v)] + sum0 * w[8-(v)]; \
+ ts[SBLIMIT*(9+(v))] = out1[9+(v)] + sum0 * w[9+(v)];
+#define MACRO1(v) { \
+ real sum0,sum1; \
+ sum0 = tmp1a + tmp2a; \
+ sum1 = (tmp1b + tmp2b) * tfcos36[(v)]; \
+ MACRO0(v); }
+#define MACRO2(v) { \
+ real sum0,sum1; \
+ sum0 = tmp2a - tmp1a; \
+ sum1 = (tmp2b - tmp1b) * tfcos36[(v)]; \
+ MACRO0(v); }
+
+ register const real *c = COS9;
+ register real *out2 = o2;
+ register real *w = wintab;
+ register real *out1 = o1;
+ register real *ts = tsbuf;
+
+ real ta33,ta66,tb33,tb66;
+
+ ta33 = in[2*3+0] * c[3];
+ ta66 = in[2*6+0] * c[6];
+ tb33 = in[2*3+1] * c[3];
+ tb66 = in[2*6+1] * c[6];
+
+ {
+ real tmp1a,tmp2a,tmp1b,tmp2b;
+ tmp1a = in[2*1+0] * c[1] + ta33 + in[2*5+0] * c[5] + in[2*7+0] * c[7];
+ tmp1b = in[2*1+1] * c[1] + tb33 + in[2*5+1] * c[5] + in[2*7+1] * c[7];
+ tmp2a = in[2*0+0] + in[2*2+0] * c[2] + in[2*4+0] * c[4] + ta66 + in[2*8+0] * c[8];
+ tmp2b = in[2*0+1] + in[2*2+1] * c[2] + in[2*4+1] * c[4] + tb66 + in[2*8+1] * c[8];
+
+ MACRO1(0);
+ MACRO2(8);
+ }
+
+ {
+ real tmp1a,tmp2a,tmp1b,tmp2b;
+ tmp1a = ( in[2*1+0] - in[2*5+0] - in[2*7+0] ) * c[3];
+ tmp1b = ( in[2*1+1] - in[2*5+1] - in[2*7+1] ) * c[3];
+ tmp2a = ( in[2*2+0] - in[2*4+0] - in[2*8+0] ) * c[6] - in[2*6+0] + in[2*0+0];
+ tmp2b = ( in[2*2+1] - in[2*4+1] - in[2*8+1] ) * c[6] - in[2*6+1] + in[2*0+1];
+
+ MACRO1(1);
+ MACRO2(7);
+ }
+
+ {
+ real tmp1a,tmp2a,tmp1b,tmp2b;
+ tmp1a = in[2*1+0] * c[5] - ta33 - in[2*5+0] * c[7] + in[2*7+0] * c[1];
+ tmp1b = in[2*1+1] * c[5] - tb33 - in[2*5+1] * c[7] + in[2*7+1] * c[1];
+ tmp2a = in[2*0+0] - in[2*2+0] * c[8] - in[2*4+0] * c[2] + ta66 + in[2*8+0] * c[4];
+ tmp2b = in[2*0+1] - in[2*2+1] * c[8] - in[2*4+1] * c[2] + tb66 + in[2*8+1] * c[4];
+
+ MACRO1(2);
+ MACRO2(6);
+ }
+
+ {
+ real tmp1a,tmp2a,tmp1b,tmp2b;
+ tmp1a = in[2*1+0] * c[7] - ta33 + in[2*5+0] * c[1] - in[2*7+0] * c[5];
+ tmp1b = in[2*1+1] * c[7] - tb33 + in[2*5+1] * c[1] - in[2*7+1] * c[5];
+ tmp2a = in[2*0+0] - in[2*2+0] * c[4] + in[2*4+0] * c[8] + ta66 - in[2*8+0] * c[2];
+ tmp2b = in[2*0+1] - in[2*2+1] * c[4] + in[2*4+1] * c[8] + tb66 - in[2*8+1] * c[2];
+
+ MACRO1(3);
+ MACRO2(5);
+ }
+
+ {
+ real sum0,sum1;
+ sum0 = in[2*0+0] - in[2*2+0] + in[2*4+0] - in[2*6+0] + in[2*8+0];
+ sum1 = (in[2*0+1] - in[2*2+1] + in[2*4+1] - in[2*6+1] + in[2*8+1] ) * tfcos36[4];
+ MACRO0(4);
+ }
+ }
+
+ }
+}
+
+/*
+ * new DCT12
+ */
+static void dct12(real *in,real *rawout1,real *rawout2,register real *wi,register real *ts)
+{
+#define DCT12_PART1 \
+ in5 = in[5*3]; \
+ in5 += (in4 = in[4*3]); \
+ in4 += (in3 = in[3*3]); \
+ in3 += (in2 = in[2*3]); \
+ in2 += (in1 = in[1*3]); \
+ in1 += (in0 = in[0*3]); \
+ \
+ in5 += in3; in3 += in1; \
+ \
+ in2 *= COS6_1; \
+ in3 *= COS6_1; \
+
+#define DCT12_PART2 \
+ in0 += in4 * COS6_2; \
+ \
+ in4 = in0 + in2; \
+ in0 -= in2; \
+ \
+ in1 += in5 * COS6_2; \
+ \
+ in5 = (in1 + in3) * tfcos12[0]; \
+ in1 = (in1 - in3) * tfcos12[2]; \
+ \
+ in3 = in4 + in5; \
+ in4 -= in5; \
+ \
+ in2 = in0 + in1; \
+ in0 -= in1;
+
+
+ {
+ real in0,in1,in2,in3,in4,in5;
+ register real *out1 = rawout1;
+ ts[SBLIMIT*0] = out1[0]; ts[SBLIMIT*1] = out1[1]; ts[SBLIMIT*2] = out1[2];
+ ts[SBLIMIT*3] = out1[3]; ts[SBLIMIT*4] = out1[4]; ts[SBLIMIT*5] = out1[5];
+
+ DCT12_PART1
+
+ {
+ real tmp0,tmp1 = (in0 - in4);
+ {
+ real tmp2 = (in1 - in5) * tfcos12[1];
+ tmp0 = tmp1 + tmp2;
+ tmp1 -= tmp2;
+ }
+ ts[(17-1)*SBLIMIT] = out1[17-1] + tmp0 * wi[11-1];
+ ts[(12+1)*SBLIMIT] = out1[12+1] + tmp0 * wi[6+1];
+ ts[(6 +1)*SBLIMIT] = out1[6 +1] + tmp1 * wi[1];
+ ts[(11-1)*SBLIMIT] = out1[11-1] + tmp1 * wi[5-1];
+ }
+
+ DCT12_PART2
+
+ ts[(17-0)*SBLIMIT] = out1[17-0] + in2 * wi[11-0];
+ ts[(12+0)*SBLIMIT] = out1[12+0] + in2 * wi[6+0];
+ ts[(12+2)*SBLIMIT] = out1[12+2] + in3 * wi[6+2];
+ ts[(17-2)*SBLIMIT] = out1[17-2] + in3 * wi[11-2];
+
+ ts[(6+0)*SBLIMIT] = out1[6+0] + in0 * wi[0];
+ ts[(11-0)*SBLIMIT] = out1[11-0] + in0 * wi[5-0];
+ ts[(6+2)*SBLIMIT] = out1[6+2] + in4 * wi[2];
+ ts[(11-2)*SBLIMIT] = out1[11-2] + in4 * wi[5-2];
+ }
+
+ in++;
+
+ {
+ real in0,in1,in2,in3,in4,in5;
+ register real *out2 = rawout2;
+
+ DCT12_PART1
+
+ {
+ real tmp0,tmp1 = (in0 - in4);
+ {
+ real tmp2 = (in1 - in5) * tfcos12[1];
+ tmp0 = tmp1 + tmp2;
+ tmp1 -= tmp2;
+ }
+ out2[5-1] = tmp0 * wi[11-1];
+ out2[0+1] = tmp0 * wi[6+1];
+ ts[(12+1)*SBLIMIT] += tmp1 * wi[1];
+ ts[(17-1)*SBLIMIT] += tmp1 * wi[5-1];
+ }
+
+ DCT12_PART2
+
+ out2[5-0] = in2 * wi[11-0];
+ out2[0+0] = in2 * wi[6+0];
+ out2[0+2] = in3 * wi[6+2];
+ out2[5-2] = in3 * wi[11-2];
+
+ ts[(12+0)*SBLIMIT] += in0 * wi[0];
+ ts[(17-0)*SBLIMIT] += in0 * wi[5-0];
+ ts[(12+2)*SBLIMIT] += in4 * wi[2];
+ ts[(17-2)*SBLIMIT] += in4 * wi[5-2];
+ }
+
+ in++;
+
+ {
+ real in0,in1,in2,in3,in4,in5;
+ register real *out2 = rawout2;
+ out2[12]=out2[13]=out2[14]=out2[15]=out2[16]=out2[17]=0.0;
+
+ DCT12_PART1
+
+ {
+ real tmp0,tmp1 = (in0 - in4);
+ {
+ real tmp2 = (in1 - in5) * tfcos12[1];
+ tmp0 = tmp1 + tmp2;
+ tmp1 -= tmp2;
+ }
+ out2[11-1] = tmp0 * wi[11-1];
+ out2[6 +1] = tmp0 * wi[6+1];
+ out2[0+1] += tmp1 * wi[1];
+ out2[5-1] += tmp1 * wi[5-1];
+ }
+
+ DCT12_PART2
+
+ out2[11-0] = in2 * wi[11-0];
+ out2[6 +0] = in2 * wi[6+0];
+ out2[6 +2] = in3 * wi[6+2];
+ out2[11-2] = in3 * wi[11-2];
+
+ out2[0+0] += in0 * wi[0];
+ out2[5-0] += in0 * wi[5-0];
+ out2[0+2] += in4 * wi[2];
+ out2[5-2] += in4 * wi[5-2];
+ }
+}
+
+/*
+ * III_hybrid
+ */
+static void III_hybrid(real fsIn[SBLIMIT][SSLIMIT],real tsOut[SSLIMIT][SBLIMIT],
+ int ch,struct gr_info_s *gr_info,struct mpstr *mp)
+{
+ real *tspnt = (real *) tsOut;
+ real (*block)[2][SBLIMIT*SSLIMIT] = mp->hybrid_block;
+ int *blc = mp->hybrid_blc;
+ real *rawout1,*rawout2;
+ int bt;
+ int sb = 0;
+
+ {
+ int b = blc[ch];
+ rawout1=block[b][ch];
+ b=-b+1;
+ rawout2=block[b][ch];
+ blc[ch] = b;
+ }
+
+
+ if(gr_info->mixed_block_flag) {
+ sb = 2;
+ dct36(fsIn[0],rawout1,rawout2,win[0],tspnt);
+ dct36(fsIn[1],rawout1+18,rawout2+18,win1[0],tspnt+1);
+ rawout1 += 36; rawout2 += 36; tspnt += 2;
+ }
+
+ bt = gr_info->block_type;
+ if(bt == 2) {
+ for (; sb<gr_info->maxb; sb+=2,tspnt+=2,rawout1+=36,rawout2+=36) {
+ dct12(fsIn[sb],rawout1,rawout2,win[2],tspnt);
+ dct12(fsIn[sb+1],rawout1+18,rawout2+18,win1[2],tspnt+1);
+ }
+ }
+ else {
+ for (; sb<gr_info->maxb; sb+=2,tspnt+=2,rawout1+=36,rawout2+=36) {
+ dct36(fsIn[sb],rawout1,rawout2,win[bt],tspnt);
+ dct36(fsIn[sb+1],rawout1+18,rawout2+18,win1[bt],tspnt+1);
+ }
+ }
+
+ for(;sb<SBLIMIT;sb++,tspnt++) {
+ int i;
+ for(i=0;i<SSLIMIT;i++) {
+ tspnt[i*SBLIMIT] = *rawout1++;
+ *rawout2++ = 0.0;
+ }
+ }
+}
+
+/*
+ * main layer3 handler
+ */
+int do_layer3(struct frame *fr,unsigned char *pcm_sample,
+ int *pcm_point,struct mpstr *mp)
+{
+ int gr, ch, ss,clip=0;
+ int scalefacs[2][39]; /* max 39 for short[13][3] mode, mixed: 38, long: 22 */
+ struct III_sideinfo sideinfo;
+ int stereo = fr->stereo;
+ int single = fr->single;
+ int ms_stereo,i_stereo;
+ int sfreq = fr->sampling_frequency;
+ int stereo1,granules;
+
+ if(stereo == 1) { /* stream is mono */
+ stereo1 = 1;
+ single = 0;
+ }
+ else if(single >= 0) /* stream is stereo, but force to mono */
+ stereo1 = 1;
+ else
+ stereo1 = 2;
+
+ if(fr->mode == MPG_MD_JOINT_STEREO) {
+ ms_stereo = fr->mode_ext & 0x2;
+ i_stereo = fr->mode_ext & 0x1;
+ }
+ else
+ ms_stereo = i_stereo = 0;
+
+ if(fr->lsf) {
+ granules = 1;
+ if(!III_get_side_info_2(&sideinfo,stereo,ms_stereo,sfreq,single))
+ return -1;
+ }
+ else {
+ granules = 2;
+#ifdef MPEG1
+ if(!III_get_side_info_1(&sideinfo,stereo,ms_stereo,sfreq,single))
+ return -1;
+#else
+ __Sound_SetError("MPGLIB: Not supported!");
+#endif
+ }
+
+ if(set_pointer(sideinfo.main_data_begin,mp) == MP3_ERR)
+ return -1;
+
+ for (gr=0;gr<granules;gr++)
+ {
+ real hybridIn[2][SBLIMIT][SSLIMIT];
+ real hybridOut[2][SSLIMIT][SBLIMIT];
+ memset(hybridIn, '\0', sizeof (hybridIn));
+
+ {
+ struct gr_info_s *gr_info = &(sideinfo.ch[0].gr[gr]);
+ long part2bits;
+ if(fr->lsf)
+ part2bits = III_get_scale_factors_2(scalefacs[0],gr_info,0);
+ else {
+#ifdef MPEG1
+ part2bits = III_get_scale_factors_1(scalefacs[0],gr_info);
+#else
+ __Sound_SetError("MPGLIB: Not supported!");
+#endif
+ }
+ if(III_dequantize_sample(hybridIn[0], scalefacs[0],gr_info,sfreq,part2bits))
+ return clip;
+ }
+ if(stereo == 2) {
+ struct gr_info_s *gr_info = &(sideinfo.ch[1].gr[gr]);
+ long part2bits;
+ if(fr->lsf)
+ part2bits = III_get_scale_factors_2(scalefacs[1],gr_info,i_stereo);
+ else {
+#ifdef MPEG1
+ part2bits = III_get_scale_factors_1(scalefacs[1],gr_info);
+#else
+ __Sound_SetError("MPGLIB: Not supported!");
+#endif
+ }
+
+ if(III_dequantize_sample(hybridIn[1],scalefacs[1],gr_info,sfreq,part2bits))
+ return clip;
+
+ if(ms_stereo) {
+ int i;
+ for(i=0;i<SBLIMIT*SSLIMIT;i++) {
+ real tmp0,tmp1;
+ tmp0 = ((real *) hybridIn[0])[i];
+ tmp1 = ((real *) hybridIn[1])[i];
+ ((real *) hybridIn[0])[i] = tmp0 + tmp1;
+ ((real *) hybridIn[1])[i] = tmp0 - tmp1;
+ }
+ }
+
+ if(i_stereo)
+ III_i_stereo(hybridIn,scalefacs[1],gr_info,sfreq,ms_stereo,fr->lsf);
+
+ if(ms_stereo || i_stereo || (single == 3) ) {
+ if(gr_info->maxb > sideinfo.ch[0].gr[gr].maxb)
+ sideinfo.ch[0].gr[gr].maxb = gr_info->maxb;
+ else
+ gr_info->maxb = sideinfo.ch[0].gr[gr].maxb;
+ }
+
+ switch(single) {
+ case 3:
+ {
+ register int i;
+ register real *in0 = (real *) hybridIn[0],*in1 = (real *) hybridIn[1];
+ for(i=0;i<SSLIMIT*gr_info->maxb;i++,in0++)
+ *in0 = (*in0 + *in1++); /* *0.5 done by pow-scale */
+ }
+ break;
+ case 1:
+ {
+ register int i;
+ register real *in0 = (real *) hybridIn[0],*in1 = (real *) hybridIn[1];
+ for(i=0;i<SSLIMIT*gr_info->maxb;i++)
+ *in0++ = *in1++;
+ }
+ break;
+ }
+ }
+
+ for(ch=0;ch<stereo1;ch++) {
+ struct gr_info_s *gr_info = &(sideinfo.ch[ch].gr[gr]);
+ III_antialias(hybridIn[ch],gr_info);
+ III_hybrid(hybridIn[ch], hybridOut[ch], ch,gr_info,mp);
+ }
+
+ for(ss=0;ss<SSLIMIT;ss++) {
+ if(single >= 0) {
+ clip += synth_1to1_mono(hybridOut[0][ss],pcm_sample,pcm_point,mp);
+ }
+ else {
+ int p1 = *pcm_point;
+ clip += synth_1to1(hybridOut[0][ss],0,pcm_sample,&p1,mp);
+ clip += synth_1to1(hybridOut[1][ss],1,pcm_sample,pcm_point,mp);
+ }
+ }
+ }
+
+ return clip;
+}
+
+
diff --git a/util/sdl/sound/decoders/mpglib/main.c b/util/sdl/sound/decoders/mpglib/main.c
new file mode 100644
index 00000000..5063958d
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/main.c
@@ -0,0 +1,33 @@
+
+#include "mpg123_sdlsound.h"
+#include "mpglib_sdlsound.h"
+
+#error This is for example usage. Do not compile for SDL_sound.
+
+char buf[16384];
+struct mpstr mp;
+
+int main(int argc,char **argv)
+{
+ int size;
+ char out[8192];
+ int len,ret;
+
+
+ InitMP3(&mp);
+
+ while(1) {
+ len = read(0,buf,16384);
+ if(len <= 0)
+ break;
+ ret = decodeMP3(&mp,buf,len,out,8192,&size);
+ while(ret == MP3_OK) {
+ write(1,out,size);
+ ret = decodeMP3(&mp,NULL,0,out,8192,&size);
+ }
+ }
+
+ return 0;
+
+}
+
diff --git a/util/sdl/sound/decoders/mpglib/mpg123_sdlsound.h b/util/sdl/sound/decoders/mpglib/mpg123_sdlsound.h
new file mode 100644
index 00000000..d8fc9bd3
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/mpg123_sdlsound.h
@@ -0,0 +1,199 @@
+#include <stdio.h>
+#include <string.h>
+
+#if !defined(WIN32) && !defined(macintosh) && !defined(_WIN32_WCE)
+#include <unistd.h>
+#endif
+
+#include <math.h>
+
+#if defined(_WIN32)
+# undef WIN32
+# define WIN32
+#endif
+
+#if defined(WIN32) || defined(macintosh) || defined(_WIN32_WCE)
+
+# define M_PI 3.14159265358979323846
+# define M_SQRT2 1.41421356237309504880
+# define REAL_IS_FLOAT
+# define NEW_DCT9
+
+# define random rand
+# define srandom srand
+
+#endif
+
+#ifdef REAL_IS_FLOAT
+# define real float
+#elif defined(REAL_IS_LONG_DOUBLE)
+# define real long double
+#else
+# define real double
+#endif
+
+#ifdef __GNUC__
+#define INLINE inline
+#elif ((defined _MSC_VER) || (defined __inline__))
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+
+/* AUDIOBUFSIZE = n*64 with n=1,2,3 ... */
+#define AUDIOBUFSIZE 16384
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef FALSE
+#define TRUE 1
+#endif
+
+#define SBLIMIT 32
+#define SSLIMIT 18
+
+#define SCALE_BLOCK 12
+
+
+#define MPG_MD_STEREO 0
+#define MPG_MD_JOINT_STEREO 1
+#define MPG_MD_DUAL_CHANNEL 2
+#define MPG_MD_MONO 3
+
+#define MAXFRAMESIZE 1792
+
+
+/* Pre Shift fo 16 to 8 bit converter table */
+#define AUSHIFT (3)
+
+struct frame {
+ int stereo;
+ int jsbound;
+ int single;
+ int lsf;
+ int mpeg25;
+ int header_change;
+ int lay;
+ int error_protection;
+ int bitrate_index;
+ int sampling_frequency;
+ int padding;
+ int extension;
+ int mode;
+ int mode_ext;
+ int copyright;
+ int original;
+ int emphasis;
+ int framesize; /* computed framesize */
+
+ /* layer2 stuff */
+ int II_sblimit;
+ void *alloc;
+};
+
+struct parameter {
+ int quiet; /* shut up! */
+ int tryresync; /* resync stream after error */
+ int verbose; /* verbose level */
+ int checkrange;
+};
+
+struct mpstr; /* forward declaration. */
+
+extern unsigned int get1bit(void);
+extern unsigned int getbits(int);
+extern unsigned int getbits_fast(int);
+extern int set_pointer(long,struct mpstr *);
+
+extern unsigned char *wordpointer;
+extern int bitindex;
+
+extern void make_decode_tables(long scaleval);
+extern int do_layer3(struct frame *fr,unsigned char *,int *,struct mpstr *);
+extern int do_layer2(struct frame *fr,unsigned char *,int *,struct mpstr *);
+extern int do_layer1(struct frame *fr,unsigned char *,int *,struct mpstr *);
+extern int decode_header(struct frame *fr,unsigned long newhead);
+
+
+
+struct gr_info_s {
+ int scfsi;
+ unsigned part2_3_length;
+ unsigned big_values;
+ unsigned scalefac_compress;
+ unsigned block_type;
+ unsigned mixed_block_flag;
+ unsigned table_select[3];
+ unsigned subblock_gain[3];
+ unsigned maxband[3];
+ unsigned maxbandl;
+ unsigned maxb;
+ unsigned region1start;
+ unsigned region2start;
+ unsigned preflag;
+ unsigned scalefac_scale;
+ unsigned count1table_select;
+ real *full_gain[3];
+ real *pow2gain;
+};
+
+struct III_sideinfo
+{
+ unsigned main_data_begin;
+ unsigned private_bits;
+ struct {
+ struct gr_info_s gr[2];
+ } ch[2];
+};
+
+
+extern int synth_1to1 (real *,int,unsigned char *,int *,struct mpstr *);
+extern int synth_1to1_8bit (real *,int,unsigned char *,int *);
+extern int synth_1to1_mono (real *,unsigned char *,int *,struct mpstr *);
+extern int synth_1to1_mono2stereo (real *,unsigned char *,int *);
+extern int synth_1to1_8bit_mono (real *,unsigned char *,int *);
+extern int synth_1to1_8bit_mono2stereo (real *,unsigned char *,int *);
+
+extern int synth_2to1 (real *,int,unsigned char *,int *);
+extern int synth_2to1_8bit (real *,int,unsigned char *,int *);
+extern int synth_2to1_mono (real *,unsigned char *,int *);
+extern int synth_2to1_mono2stereo (real *,unsigned char *,int *);
+extern int synth_2to1_8bit_mono (real *,unsigned char *,int *);
+extern int synth_2to1_8bit_mono2stereo (real *,unsigned char *,int *);
+
+extern int synth_4to1 (real *,int,unsigned char *,int *);
+extern int synth_4to1_8bit (real *,int,unsigned char *,int *);
+extern int synth_4to1_mono (real *,unsigned char *,int *);
+extern int synth_4to1_mono2stereo (real *,unsigned char *,int *);
+extern int synth_4to1_8bit_mono (real *,unsigned char *,int *);
+extern int synth_4to1_8bit_mono2stereo (real *,unsigned char *,int *);
+
+extern int synth_ntom (real *,int,unsigned char *,int *);
+extern int synth_ntom_8bit (real *,int,unsigned char *,int *);
+extern int synth_ntom_mono (real *,unsigned char *,int *);
+extern int synth_ntom_mono2stereo (real *,unsigned char *,int *);
+extern int synth_ntom_8bit_mono (real *,unsigned char *,int *);
+extern int synth_ntom_8bit_mono2stereo (real *,unsigned char *,int *);
+
+extern void rewindNbits(int bits);
+extern int hsstell(void);
+extern int get_songlen(struct frame *fr,int no);
+
+extern void init_layer3(int);
+extern void init_layer2(void);
+extern void make_decode_tables(long scale);
+extern void make_conv16to8_table(int);
+extern void dct64(real *,real *,real *);
+
+extern void synth_ntom_set_step(long,long);
+
+extern unsigned char *conv16to8;
+extern long mpglib_freqs[9];
+extern real muls[27][64];
+extern real decwin[512+32];
+extern real *pnts[5];
+
+extern struct parameter param;
+
+
diff --git a/util/sdl/sound/decoders/mpglib/mpglib_common.c b/util/sdl/sound/decoders/mpglib/mpglib_common.c
new file mode 100644
index 00000000..cc14662d
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/mpglib_common.c
@@ -0,0 +1,243 @@
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "mpg123_sdlsound.h"
+
+struct parameter param = { 1 , 1 , 0 , 0 };
+
+int tabsel_123[2][3][16] = {
+ { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
+ {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
+ {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
+
+ { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
+ {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
+ {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
+};
+
+long mpglib_freqs[9] = { 44100, 48000, 32000,
+ 22050, 24000, 16000 ,
+ 11025 , 12000 , 8000 };
+
+int bitindex;
+unsigned char *wordpointer;
+unsigned char *pcm_sample;
+int pcm_point = 0;
+
+
+#define HDRCMPMASK 0xfffffd00
+
+#if 0
+int head_check(unsigned long head)
+{
+ if( (head & 0xffe00000) != 0xffe00000)
+ return FALSE;
+ if(!((head>>17)&3))
+ return FALSE;
+ if( ((head>>12)&0xf) == 0xf)
+ return FALSE;
+ if( ((head>>10)&0x3) == 0x3 )
+ return FALSE;
+ return TRUE;
+}
+#endif
+
+
+/*
+ * the code a header and write the information
+ * into the frame structure
+ */
+int decode_header(struct frame *fr,unsigned long newhead)
+{
+ if( newhead & (1<<20) ) {
+ fr->lsf = (newhead & (1<<19)) ? 0x0 : 0x1;
+ fr->mpeg25 = 0;
+ }
+ else {
+ fr->lsf = 1;
+ fr->mpeg25 = 1;
+ }
+
+ fr->lay = 4-((newhead>>17)&3);
+ if( ((newhead>>10)&0x3) == 0x3) {
+ BAIL_MACRO("MPGLIB: Corrupted header", 0);
+ }
+ if(fr->mpeg25) {
+ fr->sampling_frequency = 6 + ((newhead>>10)&0x3);
+ }
+ else
+ fr->sampling_frequency = ((newhead>>10)&0x3) + (fr->lsf*3);
+ fr->error_protection = ((newhead>>16)&0x1)^0x1;
+
+ if(fr->mpeg25) /* allow Bitrate change for 2.5 ... */
+ fr->bitrate_index = ((newhead>>12)&0xf);
+
+ fr->bitrate_index = ((newhead>>12)&0xf);
+ fr->padding = ((newhead>>9)&0x1);
+ fr->extension = ((newhead>>8)&0x1);
+ fr->mode = ((newhead>>6)&0x3);
+ fr->mode_ext = ((newhead>>4)&0x3);
+ fr->copyright = ((newhead>>3)&0x1);
+ fr->original = ((newhead>>2)&0x1);
+ fr->emphasis = newhead & 0x3;
+
+ fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
+
+ if(!fr->bitrate_index)
+ {
+ BAIL_MACRO("MPGLIB: Free format not supported.", 0);
+ }
+
+ switch(fr->lay)
+ {
+ case 1:
+#ifdef LAYER1
+#if 0
+ fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ?
+ (fr->mode_ext<<2)+4 : 32;
+#endif
+ fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
+ fr->framesize /= mpglib_freqs[fr->sampling_frequency];
+ fr->framesize = ((fr->framesize+fr->padding)<<2)-4;
+#else
+ __Sound_SetError("MPGLIB: Not supported!");
+#endif
+ break;
+ case 2:
+#ifdef LAYER2
+#if 0
+ fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ?
+ (fr->mode_ext<<2)+4 : fr->II_sblimit;
+#endif
+ fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
+ fr->framesize /= mpglib_freqs[fr->sampling_frequency];
+ fr->framesize += fr->padding - 4;
+#else
+ __Sound_SetError("MPGLIB: Not supported!");
+#endif
+ break;
+ case 3:
+#if 0
+ fr->do_layer = do_layer3;
+ if(fr->lsf)
+ ssize = (fr->stereo == 1) ? 9 : 17;
+ else
+ ssize = (fr->stereo == 1) ? 17 : 32;
+#endif
+
+#if 0
+ if(fr->error_protection)
+ ssize += 2;
+#endif
+ fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
+ fr->framesize /= mpglib_freqs[fr->sampling_frequency]<<(fr->lsf);
+ fr->framesize = fr->framesize + fr->padding - 4;
+ break;
+ default:
+ BAIL_MACRO("MPGLIB: Unknown layer type.", 0);
+ }
+ return 1;
+}
+
+#if 0
+void print_header(struct frame *fr)
+{
+ static char *modes[4] = { "Stereo", "Joint-Stereo", "Dual-Channel", "Single-Channel" };
+ static char *layers[4] = { "Unknown" , "I", "II", "III" };
+
+ fprintf(stderr,"MPEG %s, Layer: %s, Freq: %ld, mode: %s, modext: %d, BPF : %d\n",
+ fr->mpeg25 ? "2.5" : (fr->lsf ? "2.0" : "1.0"),
+ layers[fr->lay],mpglib_freqs[fr->sampling_frequency],
+ modes[fr->mode],fr->mode_ext,fr->framesize+4);
+ fprintf(stderr,"Channels: %d, copyright: %s, original: %s, CRC: %s, emphasis: %d.\n",
+ fr->stereo,fr->copyright?"Yes":"No",
+ fr->original?"Yes":"No",fr->error_protection?"Yes":"No",
+ fr->emphasis);
+ fprintf(stderr,"Bitrate: %d Kbits/s, Extension value: %d\n",
+ tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index],fr->extension);
+}
+
+void print_header_compact(struct frame *fr)
+{
+ static char *modes[4] = { "stereo", "joint-stereo", "dual-channel", "mono" };
+ static char *layers[4] = { "Unknown" , "I", "II", "III" };
+
+ fprintf(stderr,"MPEG %s layer %s, %d kbit/s, %ld Hz %s\n",
+ fr->mpeg25 ? "2.5" : (fr->lsf ? "2.0" : "1.0"),
+ layers[fr->lay],
+ tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index],
+ mpglib_freqs[fr->sampling_frequency], modes[fr->mode]);
+}
+
+#endif
+
+unsigned int getbits(int number_of_bits)
+{
+ unsigned long rval;
+
+ if(!number_of_bits)
+ return 0;
+
+ {
+ rval = wordpointer[0];
+ rval <<= 8;
+ rval |= wordpointer[1];
+ rval <<= 8;
+ rval |= wordpointer[2];
+ rval <<= bitindex;
+ rval &= 0xffffff;
+
+ bitindex += number_of_bits;
+
+ rval >>= (24-number_of_bits);
+
+ wordpointer += (bitindex>>3);
+ bitindex &= 7;
+ }
+ return rval;
+}
+
+unsigned int getbits_fast(int number_of_bits)
+{
+ unsigned long rval;
+
+ {
+ rval = wordpointer[0];
+ rval <<= 8;
+ rval |= wordpointer[1];
+ rval <<= bitindex;
+ rval &= 0xffff;
+ bitindex += number_of_bits;
+
+ rval >>= (16-number_of_bits);
+
+ wordpointer += (bitindex>>3);
+ bitindex &= 7;
+ }
+ return rval;
+}
+
+unsigned int get1bit(void)
+{
+ unsigned char rval;
+ rval = *wordpointer << bitindex;
+
+ bitindex++;
+ wordpointer += (bitindex>>3);
+ bitindex &= 7;
+
+ return rval>>7;
+}
+
+
+
diff --git a/util/sdl/sound/decoders/mpglib/mpglib_sdlsound.h b/util/sdl/sound/decoders/mpglib/mpglib_sdlsound.h
new file mode 100644
index 00000000..58c7041c
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/mpglib_sdlsound.h
@@ -0,0 +1,63 @@
+
+#ifndef _INCLUDE_MPGLIB_SDLSOUND_H_
+#define _INCLUDE_MPGLIB_SDLSOUND_H_
+
+#ifdef _MSC_VER
+ #define snprintf _snprintf
+#endif
+
+struct buf {
+ unsigned char *pnt;
+ long size;
+ long pos;
+ struct buf *next;
+ struct buf *prev;
+};
+
+struct framebuf {
+ struct buf *buf;
+ long pos;
+ struct frame *next;
+ struct frame *prev;
+};
+
+struct mpstr {
+ struct buf *head,*tail;
+ int bsize;
+ int framesize;
+ int fsizeold;
+ struct frame fr;
+ unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */
+ real hybrid_block[2][2][SBLIMIT*SSLIMIT];
+ int hybrid_blc[2];
+ unsigned long header;
+ int bsnum;
+ real synth_buffs[2][2][0x110];
+ int synth_bo;
+};
+
+#ifndef BOOL
+#define BOOL int
+#endif
+
+#define MP3_ERR -1
+#define MP3_OK 0
+#define MP3_NEED_MORE 1
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+BOOL InitMP3(struct mpstr *mp);
+int decodeMP3(struct mpstr *mp,char *inmemory,int inmemsize,
+ char *outmemory,int outmemsize,int *done);
+void ExitMP3(struct mpstr *mp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/util/sdl/sound/decoders/mpglib/tabinit.c b/util/sdl/sound/decoders/mpglib/tabinit.c
new file mode 100644
index 00000000..dbd3965c
--- /dev/null
+++ b/util/sdl/sound/decoders/mpglib/tabinit.c
@@ -0,0 +1,80 @@
+
+#include <stdlib.h>
+
+#include "mpg123_sdlsound.h"
+
+real decwin[512+32];
+static real cos64[16],cos32[8],cos16[4],cos8[2],cos4[1];
+real *pnts[] = { cos64,cos32,cos16,cos8,cos4 };
+
+#if 0
+static unsigned char *conv16to8_buf = NULL;
+unsigned char *conv16to8;
+#endif
+
+static long intwinbase[] = {
+ 0, -1, -1, -1, -1, -1, -1, -2, -2, -2,
+ -2, -3, -3, -4, -4, -5, -5, -6, -7, -7,
+ -8, -9, -10, -11, -13, -14, -16, -17, -19, -21,
+ -24, -26, -29, -31, -35, -38, -41, -45, -49, -53,
+ -58, -63, -68, -73, -79, -85, -91, -97, -104, -111,
+ -117, -125, -132, -139, -147, -154, -161, -169, -176, -183,
+ -190, -196, -202, -208, -213, -218, -222, -225, -227, -228,
+ -228, -227, -224, -221, -215, -208, -200, -189, -177, -163,
+ -146, -127, -106, -83, -57, -29, 2, 36, 72, 111,
+ 153, 197, 244, 294, 347, 401, 459, 519, 581, 645,
+ 711, 779, 848, 919, 991, 1064, 1137, 1210, 1283, 1356,
+ 1428, 1498, 1567, 1634, 1698, 1759, 1817, 1870, 1919, 1962,
+ 2001, 2032, 2057, 2075, 2085, 2087, 2080, 2063, 2037, 2000,
+ 1952, 1893, 1822, 1739, 1644, 1535, 1414, 1280, 1131, 970,
+ 794, 605, 402, 185, -45, -288, -545, -814, -1095, -1388,
+ -1692, -2006, -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
+ -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, -7910, -8209,
+ -8491, -8755, -8998, -9219, -9416, -9585, -9727, -9838, -9916, -9959,
+ -9966, -9935, -9863, -9750, -9592, -9389, -9139, -8840, -8492, -8092,
+ -7640, -7134, -6574, -5959, -5288, -4561, -3776, -2935, -2037, -1082,
+ -70, 998, 2122, 3300, 4533, 5818, 7154, 8540, 9975, 11455,
+ 12980, 14548, 16155, 17799, 19478, 21189, 22929, 24694, 26482, 28289,
+ 30112, 31947, 33791, 35640, 37489, 39336, 41176, 43006, 44821, 46617,
+ 48390, 50137, 51853, 53534, 55178, 56778, 58333, 59838, 61289, 62684,
+ 64019, 65290, 66494, 67629, 68692, 69679, 70590, 71420, 72169, 72835,
+ 73415, 73908, 74313, 74630, 74856, 74992, 75038 };
+
+void make_decode_tables(long scaleval)
+{
+ int i,j,k,kr,divv;
+ real *table,*costab;
+
+
+ for(i=0;i<5;i++)
+ {
+ kr=0x10>>i; divv=0x40>>i;
+ costab = pnts[i];
+ for(k=0;k<kr;k++)
+ costab[k] = 1.0 / (2.0 * cos(M_PI * ((double) k * 2.0 + 1.0) / (double) divv));
+ }
+
+ table = decwin;
+ scaleval = -scaleval;
+ for(i=0,j=0;i<256;i++,j++,table+=32)
+ {
+ if(table < decwin+512+16)
+ table[16] = table[0] = (double) intwinbase[j] / 65536.0 * (double) scaleval;
+ if(i % 32 == 31)
+ table -= 1023;
+ if(i % 64 == 63)
+ scaleval = - scaleval;
+ }
+
+ for( /* i=256 */ ;i<512;i++,j--,table+=32)
+ {
+ if(table < decwin+512+16)
+ table[16] = table[0] = (double) intwinbase[j] / 65536.0 * (double) scaleval;
+ if(i % 32 == 31)
+ table -= 1023;
+ if(i % 64 == 63)
+ scaleval = - scaleval;
+ }
+}
+
+
diff --git a/util/sdl/sound/decoders/ogg.c b/util/sdl/sound/decoders/ogg.c
new file mode 100644
index 00000000..da81c387
--- /dev/null
+++ b/util/sdl/sound/decoders/ogg.c
@@ -0,0 +1,375 @@
+/*
+ * SDL_sound -- An abstract sound format decoding API.
+ * Copyright (C) 2001 Ryan C. Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Ogg Vorbis decoder for SDL_sound.
+ *
+ * This driver handles .OGG audio files, and depends on libvorbisfile to
+ * do the actual decoding work. libvorbisfile is part of libvorbis, which
+ * is part of the Ogg Vorbis project.
+ *
+ * Ogg Vorbis: http://www.xiph.org/ogg/vorbis/
+ * vorbisfile documentation: http://www.xiph.org/ogg/vorbis/doc/vorbisfile/
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_OGG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include <vorbis/codec.h>
+#include <vorbis/vorbisfile.h>
+
+
+static int OGG_init(void);
+static void OGG_quit(void);
+static int OGG_open(Sound_Sample *sample, const char *ext);
+static void OGG_close(Sound_Sample *sample);
+static Uint32 OGG_read(Sound_Sample *sample);
+static int OGG_rewind(Sound_Sample *sample);
+static int OGG_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_ogg[] = { "OGG", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG =
+{
+ {
+ extensions_ogg,
+ "Ogg Vorbis audio through VorbisFile",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ OGG_init, /* init() method */
+ OGG_quit, /* quit() method */
+ OGG_open, /* open() method */
+ OGG_close, /* close() method */
+ OGG_read, /* read() method */
+ OGG_rewind, /* rewind() method */
+ OGG_seek /* seek() method */
+};
+
+
+static int OGG_init(void)
+{
+ return(1); /* always succeeds. */
+} /* OGG_init */
+
+
+static void OGG_quit(void)
+{
+ /* it's a no-op. */
+} /* OGG_quit */
+
+
+
+ /*
+ * These are callbacks from vorbisfile that let them read data from
+ * a RWops...
+ */
+
+static size_t RWops_ogg_read(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+ return((size_t) SDL_RWread((SDL_RWops *) datasource, ptr, size, nmemb));
+} /* RWops_ogg_read */
+
+static int RWops_ogg_seek(void *datasource, ogg_int64_t offset, int whence)
+{
+ return(SDL_RWseek((SDL_RWops *) datasource, offset, whence));
+} /* RWops_ogg_seek */
+
+static int RWops_ogg_close(void *datasource)
+{
+ /* do nothing; SDL_sound will delete the RWops at a higher level. */
+ return(0); /* this is success in fclose(), so I guess that's okay. */
+} /* RWops_ogg_close */
+
+static long RWops_ogg_tell(void *datasource)
+{
+ return((long) SDL_RWtell((SDL_RWops *) datasource));
+} /* RWops_ogg_tell */
+
+static const ov_callbacks RWops_ogg_callbacks =
+{
+ RWops_ogg_read,
+ RWops_ogg_seek,
+ RWops_ogg_close,
+ RWops_ogg_tell
+};
+
+
+ /* Return a human readable version of an VorbisFile error code... */
+#if (defined DEBUG_CHATTER)
+static const char *ogg_error(int errnum)
+{
+ switch(errnum)
+ {
+ case OV_EREAD:
+ return("i/o error");
+ case OV_ENOTVORBIS:
+ return("not a vorbis file");
+ case OV_EVERSION:
+ return("Vorbis version mismatch");
+ case OV_EBADHEADER:
+ return("invalid Vorbis bitstream header");
+ case OV_EFAULT:
+ return("internal logic fault in Vorbis library");
+ } /* switch */
+
+ return("unknown error");
+} /* ogg_error */
+#endif
+
+static __inline__ void output_ogg_comments(OggVorbis_File *vf)
+{
+#if (defined DEBUG_CHATTER)
+ int i;
+ vorbis_comment *vc = ov_comment(vf, -1);
+
+ if (vc == NULL)
+ return;
+
+ SNDDBG(("OGG: vendor == [%s].\n", vc->vendor));
+ for (i = 0; i < vc->comments; i++)
+ {
+ SNDDBG(("OGG: user comment [%s].\n", vc->user_comments[i]));
+ } /* for */
+#endif
+} /* output_ogg_comments */
+
+
+static int OGG_open(Sound_Sample *sample, const char *ext)
+{
+ int rc;
+ OggVorbis_File *vf;
+ vorbis_info *info;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ vf = (OggVorbis_File *) malloc(sizeof (OggVorbis_File));
+ BAIL_IF_MACRO(vf == NULL, ERR_OUT_OF_MEMORY, 0);
+
+ rc = ov_open_callbacks(internal->rw, vf, NULL, 0, RWops_ogg_callbacks);
+ if (rc != 0)
+ {
+ SNDDBG(("OGG: can't grok data. reason: [%s].\n", ogg_error(rc)));
+ free(vf);
+ BAIL_MACRO("OGG: Not valid Ogg Vorbis data.", 0);
+ } /* if */
+
+ info = ov_info(vf, -1);
+ if (info == NULL)
+ {
+ ov_clear(vf);
+ free(vf);
+ BAIL_MACRO("OGG: failed to retrieve bitstream info", 0);
+ } /* if */
+
+ SNDDBG(("OGG: Accepting data stream.\n"));
+
+ output_ogg_comments(vf);
+ SNDDBG(("OGG: bitstream version == (%d).\n", info->version));
+ SNDDBG(("OGG: bitstream channels == (%d).\n", info->channels));
+ SNDDBG(("OGG: bitstream sampling rate == (%ld).\n", info->rate));
+ SNDDBG(("OGG: seekable == {%s}.\n", ov_seekable(vf) ? "TRUE" : "FALSE"));
+ SNDDBG(("OGG: number of logical bitstreams == (%ld).\n", ov_streams(vf)));
+ SNDDBG(("OGG: serial number == (%ld).\n", ov_serialnumber(vf, -1)));
+ SNDDBG(("OGG: total seconds of sample == (%f).\n", ov_time_total(vf, -1)));
+
+ internal->decoder_private = vf;
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+ sample->actual.rate = (Uint32) info->rate;
+ sample->actual.channels = (Uint8) info->channels;
+
+ /*
+ * Since we might have more than one logical bitstream in the OGG file,
+ * and these bitstreams may be in different formats, we might be
+ * converting two or three times: once in vorbisfile, once again in
+ * SDL_sound, and perhaps a third time to get it to the sound device's
+ * format. That's wickedly inefficient.
+ *
+ * To combat this a little, if the user specified a desired format, we
+ * claim that to be the "actual" format of the collection of logical
+ * bitstreams. This means that VorbisFile will do a conversion as
+ * necessary, and SDL_sound will not. If the user didn't specify a
+ * desired format, then we pretend the "actual" format is something that
+ * OGG files are apparently commonly encoded in.
+ */
+ sample->actual.format = (sample->desired.format == 0) ?
+ AUDIO_S16LSB : sample->desired.format;
+ return(1);
+} /* OGG_open */
+
+
+static void OGG_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+ ov_clear(vf);
+ free(vf);
+} /* OGG_close */
+
+/* Note: According to the Vorbis documentation:
+ * "ov_read() will decode at most one vorbis packet per invocation,
+ * so the value returned will generally be less than length."
+ * Due to this, for buffer sizes like 16384, SDL_Sound was always getting
+ * an underfilled buffer and always setting the EAGAIN flag.
+ * Since the SDL_Sound API implies that the entire buffer
+ * should be filled unless EOF, additional code has been added
+ * to this function to call ov_read() until the buffer is filled.
+ * However, there may still be some corner cases where the buffer
+ * cannot be entirely filled. So be aware.
+ */
+static Uint32 OGG_read(Sound_Sample *sample)
+{
+ int rc;
+ int bitstream;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+
+ rc = ov_read(vf, internal->buffer, internal->buffer_size,
+ ((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */
+ ((sample->actual.format & 0xFF) / 8), /* bytes per sample point */
+ ((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */
+ &bitstream);
+
+ /* Make sure the read went smoothly... */
+ if (rc == 0)
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+ else if (rc < 0)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+ /* If the buffer isn't filled, keep trying to fill it
+ * until no more data can be grabbed */
+ else if ((Uint32) rc < internal->buffer_size)
+ {
+ /* Creating a pointer to the buffer that denotes where to start
+ * writing new data. */
+ Uint8* buffer_start_point = NULL;
+ int total_bytes_read = rc;
+ int bytes_remaining = internal->buffer_size - rc;
+
+ /* Keep grabbing data until something prevents
+ * us from getting more. (Could be EOF,
+ * packets are too large to fit in remaining
+ * space, or an error.)
+ */
+ while( (rc > 0) && (bytes_remaining > 0) )
+ {
+ /* Set buffer pointer to end of last write */
+ /* All the messiness is to get rid of the warning for
+ * dereferencing a void*
+ */
+ buffer_start_point = &(((Uint8*)internal->buffer)[total_bytes_read]);
+ rc = ov_read(vf, buffer_start_point, bytes_remaining,
+ ((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */
+ ((sample->actual.format & 0xFF) / 8), /* bytes per sample point */
+ ((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */
+ &bitstream);
+ /* Make sure rc > 0 because we don't accidently want
+ * to change the counters if there was an error
+ */
+ if(rc > 0)
+ {
+ total_bytes_read += rc;
+ bytes_remaining = bytes_remaining - rc;
+ }
+ }
+ /* I think the minimum read size is 2, though I'm
+ * not sure about this. (I've hit cases where I
+ * couldn't read less than 4.) What I don't want to do is
+ * accidently claim we hit EOF when the reason rc == 0
+ * is because the requested amount of data was smaller
+ * than the minimum packet size.
+ * For now, I will be conservative
+ * and not set the EOF flag, and let the next call to
+ * this function figure it out.
+ * I think the ERROR flag is safe to set because
+ * it looks like OGG simply returns 0 if the
+ * read size is too small.
+ * And in most cases for sensible buffer sizes,
+ * this fix will fill the buffer,
+ * so we can set the EAGAIN flag without worrying
+ * that it will always be set.
+ */
+ if(rc < 0)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ }
+ else if(rc == 0)
+ {
+ /* Do nothing for now until there is a better solution */
+ /* sample->flags |= SOUND_SAMPLEFLAG_EOF; */
+ }
+
+ /* Test for a buffer underrun. It should occur less frequently
+ * now, but it still may happen and not necessarily mean
+ * anything useful. */
+ if ((Uint32) total_bytes_read < internal->buffer_size)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+ }
+ /* change rc to the total bytes read so function
+ * can return the correct value.
+ */
+ rc = total_bytes_read;
+ }
+
+ return((Uint32) rc);
+} /* OGG_read */
+
+
+static int OGG_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+
+ BAIL_IF_MACRO(ov_raw_seek(vf, 0) < 0, ERR_IO_ERROR, 0);
+ return(1);
+} /* OGG_rewind */
+
+
+static int OGG_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
+ double timepos = (((double) ms) / 1000.0);
+ BAIL_IF_MACRO(ov_time_seek(vf, timepos) < 0, ERR_IO_ERROR, 0);
+ return(1);
+} /* OGG_seek */
+
+#endif /* SOUND_SUPPORTS_OGG */
+
+
+/* end of ogg.c ... */
+
diff --git a/util/sdl/sound/decoders/quicktime.c b/util/sdl/sound/decoders/quicktime.c
new file mode 100644
index 00000000..355ca6e7
--- /dev/null
+++ b/util/sdl/sound/decoders/quicktime.c
@@ -0,0 +1,591 @@
+/*
+ * 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
+ */
+
+/*
+ * QuickTime decoder for sound formats that QuickTime supports.
+ * April 28, 2002
+ *
+ * This driver handles .mov files with a sound track. In
+ * theory, it could handle any format that QuickTime supports.
+ * In practice, it may only handle a select few of these formats.
+ *
+ * It seems able to play back AIFF and other standard Mac formats.
+ * Rewinding is not supported yet.
+ *
+ * The routine QT_create_data_ref() needs to be
+ * tweaked to support different media types.
+ * This code was originally written to get MP3 support,
+ * as it turns out, this isn't possible using this method.
+ *
+ * The only way to get streaming MP3 support through QuickTime,
+ * and hence support for SDL_RWops, is to write
+ * a DataHandler component, which suddenly gets much more difficult :-(
+ *
+ * This file was written by Darrell Walisser (walisser@mac.com)
+ * Portions have been borrowed from the "MP3Player" sample code,
+ * courtesy of Apple.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_QUICKTIME
+#ifdef macintosh
+typedef long int32_t;
+# define OPAQUE_UPP_TYPES 0
+# include <QuickTime.h>
+#else
+# include <QuickTime/QuickTime.h>
+# include <Carbon/Carbon.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int QT_init(void);
+static void QT_quit(void);
+static int QT_open(Sound_Sample *sample, const char *ext);
+static void QT_close(Sound_Sample *sample);
+static Uint32 QT_read(Sound_Sample *sample);
+static int QT_rewind(Sound_Sample *sample);
+static int QT_seek(Sound_Sample *sample, Uint32 ms);
+
+#define QT_MAX_INPUT_BUFFER (32*1024) /* Maximum size of internal buffer (internal->buffer_size) */
+
+static const char *extensions_quicktime[] = { "mov", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime =
+ {
+ {
+ extensions_quicktime,
+ "QuickTime format",
+ "Darrell Walisser <dwaliss1@purdue.edu>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ QT_init, /* init() method */
+ QT_quit, /* quit() method */
+ QT_open, /* open() method */
+ QT_close, /* close() method */
+ QT_read, /* read() method */
+ QT_rewind, /* rewind() method */
+ QT_seek /* seek() method */
+ };
+
+typedef struct {
+
+ ExtendedSoundComponentData compData;
+ Handle hSource; /* source media buffer */
+ Media sourceMedia; /* sound media identifier */
+ TimeValue getMediaAtThisTime;
+ TimeValue sourceDuration;
+ Boolean isThereMoreSource;
+ UInt32 maxBufferSize;
+
+} SCFillBufferData, *SCFillBufferDataPtr;
+
+typedef struct {
+
+ Movie movie;
+ Track track;
+ Media media;
+ AudioFormatAtomPtr atom;
+ SoundComponentData source_format;
+ SoundComponentData dest_format;
+ SoundConverter converter;
+ SCFillBufferData buffer_data;
+ SoundConverterFillBufferDataUPP fill_buffer_proc;
+
+} qt_t;
+
+
+
+
+/*
+ * This procedure creates a description of the raw data
+ * read from SDL_RWops so that QuickTime can identify
+ * the codec it needs to use to decompress it.
+ */
+static Handle QT_create_data_ref (const char *file_extension) {
+
+ Handle tmp_handle, data_ref;
+ StringPtr file_name = "\p"; /* empty since we don't know the file name! */
+ OSType file_type;
+ StringPtr mime_type;
+ long atoms[3];
+
+/*
+ if (__Sound_strcasecmp (file_extension, "mp3")==0) {
+ file_type = 'MPEG';
+ mime_type = "\pvideo/mpeg";
+ }
+ else {
+
+ return NULL;
+ }
+*/
+
+ if (__Sound_strcasecmp (file_extension, "mov") == 0) {
+
+ file_type = 'MooV';
+ mime_type = "\pvideo/quicktime";
+ }
+ else {
+
+ return NULL;
+ }
+
+ tmp_handle = NewHandle(0);
+ assert (tmp_handle != NULL);
+ assert (noErr == PtrToHand (&tmp_handle, &data_ref, sizeof(Handle)));
+ assert (noErr == PtrAndHand (file_name, data_ref, file_name[0]+1));
+
+ atoms[0] = EndianU32_NtoB (sizeof(long) * 3);
+ atoms[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
+ atoms[2] = EndianU32_NtoB (file_type);
+
+ assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*3));
+
+ atoms[0] = EndianU32_NtoB (sizeof(long)*2 + mime_type[0]+1);
+ atoms[1] = EndianU32_NtoB (kDataRefExtensionMIMEType);
+
+ assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*2));
+ assert (noErr == PtrAndHand (mime_type, data_ref, mime_type[0]+1));
+
+ return data_ref;
+}
+
+/*
+ * This procedure is a hook for QuickTime to grab data from the
+ * SDL_RWOps data structure when it needs it
+ */
+static pascal OSErr QT_get_movie_data_proc (long offset, long size,
+ void *data, void *user_data)
+{
+ SDL_RWops* rw = (SDL_RWops*)user_data;
+ OSErr error;
+
+ if (offset == SDL_RWseek (rw, offset, SEEK_SET)) {
+
+ if (size == SDL_RWread (rw, data, 1, size)) {
+ error = noErr;
+ }
+ else {
+ error = notEnoughDataErr;
+ }
+ }
+ else {
+ error = fileOffsetTooBigErr;
+ }
+
+ return (error);
+}
+
+/* * ----------------------------
+ * SoundConverterFillBufferDataProc
+ *
+ * the callback routine that provides the source data for conversion -
+ * it provides data by setting outData to a pointer to a properly
+ * filled out ExtendedSoundComponentData structure
+ */
+static pascal Boolean QT_sound_converter_fill_buffer_data_proc (SoundComponentDataPtr *outData, void *inRefCon)
+{
+ SCFillBufferDataPtr pFillData = (SCFillBufferDataPtr)inRefCon;
+
+ OSErr err = noErr;
+
+ /* if after getting the last chunk of data the total time is over
+ * the duration, we're done
+ */
+ if (pFillData->getMediaAtThisTime >= pFillData->sourceDuration) {
+ pFillData->isThereMoreSource = false;
+ pFillData->compData.desc.buffer = NULL;
+ pFillData->compData.desc.sampleCount = 0;
+ pFillData->compData.bufferSize = 0;
+ }
+
+ if (pFillData->isThereMoreSource) {
+
+ long sourceBytesReturned;
+ long numberOfSamples;
+ TimeValue sourceReturnedTime, durationPerSample;
+
+ HUnlock(pFillData->hSource);
+
+ err = GetMediaSample
+ (pFillData->sourceMedia,/* specifies the media for this operation */
+ pFillData->hSource, /* function returns the sample data into this handle */
+ pFillData->maxBufferSize, /* maximum number of bytes of sample data to be returned */
+ &sourceBytesReturned, /* the number of bytes of sample data returned */
+ pFillData->getMediaAtThisTime,/* starting time of the sample to
+ be retrieved (must be in
+ Media's TimeScale) */
+ &sourceReturnedTime,/* indicates the actual time of the returned sample data */
+ &durationPerSample, /* duration of each sample in the media */
+ NULL, /* sample description corresponding to the returned sample data (NULL to ignore) */
+ NULL, /* index value to the sample description that corresponds
+ to the returned sample data (NULL to ignore) */
+ 0, /* maximum number of samples to be returned (0 to use a
+ value that is appropriate for the media) */
+ &numberOfSamples, /* number of samples it actually returned */
+ NULL); /* flags that describe the sample (NULL to ignore) */
+
+ HLock(pFillData->hSource);
+
+ if ((noErr != err) || (sourceBytesReturned == 0)) {
+ pFillData->isThereMoreSource = false;
+ pFillData->compData.desc.buffer = NULL;
+ pFillData->compData.desc.sampleCount = 0;
+
+ if ((err != noErr) && (sourceBytesReturned > 0))
+ DebugStr("\pGetMediaSample - Failed in FillBufferDataProc");
+ }
+
+ pFillData->getMediaAtThisTime = sourceReturnedTime + (durationPerSample * numberOfSamples);
+ pFillData->compData.bufferSize = sourceBytesReturned;
+ }
+
+ /* set outData to a properly filled out ExtendedSoundComponentData struct */
+ *outData = (SoundComponentDataPtr)&pFillData->compData;
+
+ return (pFillData->isThereMoreSource);
+}
+
+
+static int QT_init_internal () {
+
+ OSErr error;
+
+ error = EnterMovies(); /* initialize the movie toolbox */
+
+ return (error == noErr);
+}
+
+static void QT_quit_internal () {
+
+ ExitMovies();
+}
+
+static qt_t* QT_open_internal (Sound_Sample *sample, const char *extension)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ qt_t *instance;
+ OSErr error;
+ Movie movie;
+ Track sound_track;
+ Media sound_track_media;
+ AudioFormatAtomPtr source_sound_decomp_atom;
+
+ SoundDescriptionV1Handle source_sound_description;
+ Handle source_sound_description_extension;
+ Size source_sound_description_extension_size;
+ Handle data_ref;
+
+ data_ref = QT_create_data_ref (extension);
+
+ /* create a movie that will read data using SDL_RWops */
+ error = NewMovieFromUserProc
+ (&movie,
+ 0,
+ NULL,
+ NewGetMovieUPP(QT_get_movie_data_proc),
+ (void*) internal->rw,
+ data_ref,
+ 'hndl');
+
+ if (error != noErr) {
+
+ return NULL;
+ }
+
+ /* get the first sound track of the movie; other tracks will be ignored */
+ sound_track = GetMovieIndTrackType (movie, 1, SoundMediaType, movieTrackMediaType);
+ if (sound_track == NULL) {
+
+ /* movie needs a sound track! */
+
+ return NULL;
+ }
+
+ /* get and return the sound track media */
+ sound_track_media = GetTrackMedia (sound_track);
+ if (sound_track_media == NULL) {
+
+ return NULL;
+ }
+
+ /* create a description of the source sound so we can convert it later */
+ source_sound_description = (SoundDescriptionV1Handle)NewHandle(0);
+ assert (source_sound_description != NULL); /* out of memory */
+
+ GetMediaSampleDescription (sound_track_media, 1,
+ (SampleDescriptionHandle)source_sound_description);
+ error = GetMoviesError();
+ if (error != noErr) {
+
+ return NULL;
+ }
+
+ source_sound_description_extension = NewHandle(0);
+ assert (source_sound_description_extension != NULL); /* out of memory */
+
+ error = GetSoundDescriptionExtension ((SoundDescriptionHandle) source_sound_description,
+ &source_sound_description_extension,
+ siDecompressionParams);
+
+ if (error == noErr) {
+
+ /* copy extension to atom format description if we have an extension */
+
+ source_sound_description_extension_size =
+ GetHandleSize (source_sound_description_extension);
+ HLock (source_sound_description_extension);
+
+ source_sound_decomp_atom = (AudioFormatAtom*)
+ NewPtr (source_sound_description_extension_size);
+ assert (source_sound_decomp_atom != NULL); /* out of memory */
+
+ BlockMoveData (*source_sound_description_extension,
+ source_sound_decomp_atom,
+ source_sound_description_extension_size);
+
+ HUnlock (source_sound_description_extension);
+ }
+
+ else {
+
+ source_sound_decomp_atom = NULL;
+ }
+
+ instance = (qt_t*) malloc (sizeof(*instance));
+ assert (instance != NULL); /* out of memory */
+
+ instance->movie = movie;
+ instance->track = sound_track;
+ instance->media = sound_track_media;
+ instance->atom = source_sound_decomp_atom;
+
+ instance->source_format.flags = 0;
+ instance->source_format.format = (*source_sound_description)->desc.dataFormat;
+ instance->source_format.numChannels = (*source_sound_description)->desc.numChannels;
+ instance->source_format.sampleSize = (*source_sound_description)->desc.sampleSize;
+ instance->source_format.sampleRate = (*source_sound_description)->desc.sampleRate;
+ instance->source_format.sampleCount = 0;
+ instance->source_format.buffer = NULL;
+ instance->source_format.reserved = 0;
+
+ instance->dest_format.flags = 0;
+ instance->dest_format.format = kSoundNotCompressed;
+ instance->dest_format.numChannels = (*source_sound_description)->desc.numChannels;
+ instance->dest_format.sampleSize = (*source_sound_description)->desc.sampleSize;
+ instance->dest_format.sampleRate = (*source_sound_description)->desc.sampleRate;
+ instance->dest_format.sampleCount = 0;
+ instance->dest_format.buffer = NULL;
+ instance->dest_format.reserved = 0;
+
+ sample->actual.channels = (*source_sound_description)->desc.numChannels;
+ sample->actual.rate = (*source_sound_description)->desc.sampleRate >> 16;
+
+ if ((*source_sound_description)->desc.sampleSize == 16) {
+
+ sample->actual.format = AUDIO_S16SYS;
+ }
+ else if ((*source_sound_description)->desc.sampleSize == 8) {
+
+ sample->actual.format = AUDIO_U8;
+ }
+ else {
+
+ /* 24-bit or others... (which SDL can't handle) */
+ return NULL;
+ }
+
+ DisposeHandle (source_sound_description_extension);
+ DisposeHandle ((Handle)source_sound_description);
+
+ /* This next code sets up the SoundConverter component */
+ error = SoundConverterOpen (&instance->source_format, &instance->dest_format,
+ &instance->converter);
+
+ if (error != noErr) {
+
+ return NULL;
+ }
+
+ error = SoundConverterSetInfo (instance->converter, siDecompressionParams,
+ instance->atom);
+ if (error == siUnknownInfoType) {
+
+ /* ignore */
+ }
+ else if (error != noErr) {
+
+ /* reall error */
+ return NULL;
+ }
+
+ error = SoundConverterBeginConversion (instance->converter);
+ if (error != noErr) {
+
+ return NULL;
+ }
+
+ instance->buffer_data.sourceMedia = instance->media;
+ instance->buffer_data.getMediaAtThisTime = 0;
+ instance->buffer_data.sourceDuration = GetMediaDuration(instance->media);
+ instance->buffer_data.isThereMoreSource = true;
+ instance->buffer_data.maxBufferSize = QT_MAX_INPUT_BUFFER;
+ /* allocate source media buffer */
+ instance->buffer_data.hSource = NewHandle((long)instance->buffer_data.maxBufferSize);
+ assert (instance->buffer_data.hSource != NULL); /* out of memory */
+
+ instance->buffer_data.compData.desc = instance->source_format;
+ instance->buffer_data.compData.desc.buffer = (Byte *)*instance->buffer_data.hSource;
+ instance->buffer_data.compData.desc.flags = kExtendedSoundData;
+ instance->buffer_data.compData.recordSize = sizeof(ExtendedSoundComponentData);
+ instance->buffer_data.compData.extendedFlags =
+ kExtendedSoundSampleCountNotValid | kExtendedSoundBufferSizeValid;
+ instance->buffer_data.compData.bufferSize = 0;
+
+ instance->fill_buffer_proc =
+ NewSoundConverterFillBufferDataUPP (QT_sound_converter_fill_buffer_data_proc);
+
+ return (instance);
+
+} /* QT_open_internal */
+
+static void QT_close_internal (qt_t *instance)
+{
+
+} /* QT_close_internal */
+
+static Uint32 QT_read_internal(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ qt_t *instance = (qt_t*) internal->decoder_private;
+ long output_bytes, output_frames, output_flags;
+ OSErr error;
+
+ error = SoundConverterFillBuffer
+ (instance->converter, /* a sound converter */
+ instance->fill_buffer_proc, /* the callback UPP */
+ &instance->buffer_data, /* refCon passed to FillDataProc */
+ internal->buffer, /* the decompressed data 'play' buffer */
+ internal->buffer_size, /* size of the 'play' buffer */
+ &output_bytes, /* number of output bytes */
+ &output_frames, /* number of output frames */
+ &output_flags); /* fillbuffer retured advisor flags */
+
+ if (output_flags & kSoundConverterHasLeftOverData) {
+
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+ }
+ else {
+
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ }
+
+ if (error != noErr) {
+
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ }
+
+ return (output_bytes);
+
+} /* QT_read_internal */
+
+static int QT_rewind_internal (Sound_Sample *sample)
+{
+
+ return 0;
+
+} /* QT_rewind_internal */
+
+
+
+static int QT_init(void)
+{
+ return (QT_init_internal());
+
+} /* QT_init */
+
+static void QT_quit(void)
+{
+ QT_quit_internal();
+
+} /* QT_quit */
+
+static int QT_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ qt_t *instance;
+
+ instance = QT_open_internal(sample, ext);
+ internal->decoder_private = (void*)instance;
+
+ return(instance != NULL);
+
+} /* QT_open */
+
+
+static void QT_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ qt_t *instance = (qt_t *) internal->decoder_private;
+
+ QT_close_internal (instance);
+
+ free (instance);
+
+} /* QT_close */
+
+
+static Uint32 QT_read(Sound_Sample *sample)
+{
+ return(QT_read_internal(sample));
+
+} /* QT_read */
+
+
+static int QT_rewind(Sound_Sample *sample)
+{
+
+ return(QT_rewind_internal(sample));
+
+} /* QT_rewind */
+
+
+static int QT_seek(Sound_Sample *sample, Uint32 ms)
+{
+ BAIL_MACRO("QUICKTIME: Seeking not implemented", 0);
+} /* QT_seek */
+
+
+#endif /* SOUND_SUPPORTS_QUICKTIME */
+
+/* end of quicktime.c ... */
+
diff --git a/util/sdl/sound/decoders/raw.c b/util/sdl/sound/decoders/raw.c
new file mode 100644
index 00000000..be3c810f
--- /dev/null
+++ b/util/sdl/sound/decoders/raw.c
@@ -0,0 +1,184 @@
+/*
+ * 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 COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_RAW
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int RAW_init(void);
+static void RAW_quit(void);
+static int RAW_open(Sound_Sample *sample, const char *ext);
+static void RAW_close(Sound_Sample *sample);
+static Uint32 RAW_read(Sound_Sample *sample);
+static int RAW_rewind(Sound_Sample *sample);
+static int RAW_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_raw[] = { "RAW", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW =
+{
+ {
+ extensions_raw,
+ "Raw audio",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ RAW_init, /* init() method */
+ RAW_quit, /* quit() method */
+ RAW_open, /* open() method */
+ RAW_close, /* close() method */
+ RAW_read, /* read() method */
+ RAW_rewind, /* rewind() method */
+ RAW_seek /* seek() method */
+};
+
+
+static int RAW_init(void)
+{
+ return(1); /* always succeeds. */
+} /* RAW_init */
+
+
+static void RAW_quit(void)
+{
+ /* it's a no-op. */
+} /* RAW_quit */
+
+
+static int RAW_open(Sound_Sample *sample, const char *ext)
+{
+ /*
+ * We check this explicitly, since we have no other way to
+ * determine whether we should handle this data or not.
+ */
+ if (__Sound_strcasecmp(ext, "RAW") != 0)
+ BAIL_MACRO("RAW: extension isn't explicitly \"RAW\".", 0);
+
+ /*
+ * You must also specify a desired format, so we know how to
+ * treat the bits that are otherwise binary garbage.
+ */
+ if ( (sample->desired.channels < 1) ||
+ (sample->desired.channels > 2) ||
+ (sample->desired.rate == 0) ||
+ (sample->desired.format == 0) )
+ {
+ BAIL_MACRO("RAW: invalid desired format.", 0);
+ } /* if */
+
+ SNDDBG(("RAW: Accepting data stream.\n"));
+
+ /*
+ * We never convert raw samples; what you ask for is what you get.
+ */
+ memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo));
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+
+ return(1); /* we'll handle this data. */
+} /* RAW_open */
+
+
+static void RAW_close(Sound_Sample *sample)
+{
+ /* we don't allocate anything that we need to free. That's easy, eh? */
+} /* RAW_close */
+
+
+static Uint32 RAW_read(Sound_Sample *sample)
+{
+ Uint32 retval;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+
+ /*
+ * We don't actually do any decoding, so we read the raw data
+ * directly into the internal buffer...
+ */
+ retval = SDL_RWread(internal->rw, internal->buffer,
+ 1, internal->buffer_size);
+
+ /* Make sure the read went smoothly... */
+ if (retval == 0)
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+ else if (retval == -1)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+ /* (next call this EAGAIN may turn into an EOF or error.) */
+ else if (retval < internal->buffer_size)
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+ return(retval);
+} /* RAW_read */
+
+
+static int RAW_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ BAIL_IF_MACRO(SDL_RWseek(internal->rw, 0, SEEK_SET) != 0, ERR_IO_ERROR, 0);
+ return(1);
+} /* RAW_rewind */
+
+
+static int RAW_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ int pos = (int) __Sound_convertMsToBytePos(&sample->actual, ms);
+ int err = (SDL_RWseek(internal->rw, pos, SEEK_SET) != pos);
+ BAIL_IF_MACRO(err, ERR_IO_ERROR, 0);
+ return(1);
+} /* RAW_seek */
+
+
+#endif /* SOUND_SUPPORTS_RAW */
+
+
+/* end of raw.c ... */
+
diff --git a/util/sdl/sound/decoders/shn.c b/util/sdl/sound/decoders/shn.c
new file mode 100644
index 00000000..62a316ff
--- /dev/null
+++ b/util/sdl/sound/decoders/shn.c
@@ -0,0 +1,1341 @@
+/*
+ * 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
+ */
+
+/*
+ * Shorten decoder for SDL_sound.
+ *
+ * This driver handles Shorten-compressed waveforms. Despite the fact that
+ * SHNs tend to be much bigger than MP3s, they are still the de facto
+ * standard in online music trading communities. If an MP3 crunches the
+ * waveform to 10-20 percent of its original size, SHNs only go to about
+ * 50-60%. Why do the Phish fans of the world use this format then? Rabid
+ * music traders appreciate the sound quality; SHNs, unlike MP3s, do not
+ * throw away any part of the waveform. Yes, there are people that notice
+ * this, and further more, they demand it...and if they can't get a good
+ * transfer of those larger files over the 'net, they haven't underestimated
+ * the bandwidth of CDs travelling the world through the postal system.
+ *
+ * Shorten homepage: http://www.softsound.com/Shorten.html
+ *
+ * The Shorten format was gleaned from the shorten codebase, by Tony
+ * Robinson and SoftSound Limited.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_SHN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int SHN_init(void);
+static void SHN_quit(void);
+static int SHN_open(Sound_Sample *sample, const char *ext);
+static void SHN_close(Sound_Sample *sample);
+static Uint32 SHN_read(Sound_Sample *sample);
+static int SHN_rewind(Sound_Sample *sample);
+static int SHN_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_shn[] = { "SHN", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_SHN =
+{
+ {
+ extensions_shn,
+ "Shorten-compressed audio data",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ SHN_init, /* init() method */
+ SHN_quit, /* quit() method */
+ SHN_open, /* open() method */
+ SHN_close, /* close() method */
+ SHN_read, /* read() method */
+ SHN_rewind, /* rewind() method */
+ SHN_seek /* seek() method */
+};
+
+
+#define SHN_BUFSIZ 512
+
+typedef struct
+{
+ Sint32 version;
+ Sint32 datatype;
+ Sint32 nchan;
+ Sint32 blocksize;
+ Sint32 maxnlpc;
+ Sint32 nmean;
+ Sint32 nwrap;
+ Sint32 **buffer;
+ Sint32 **offset;
+ Sint32 *qlpc;
+ Sint32 lpcqoffset;
+ Sint32 bitshift;
+ int nbitget;
+ int nbyteget;
+ Uint8 *getbuf;
+ Uint8 *getbufp;
+ Uint32 gbuffer;
+ Uint8 *backBuffer;
+ Uint32 backBufferSize;
+ Uint32 backBufLeft;
+ Uint32 start_pos;
+} shn_t;
+
+
+static const Uint32 mask_table[] =
+{
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F,
+ 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
+ 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF,
+ 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
+ 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF,
+ 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
+
+
+static const Uint8 ulaw_outward[13][256] = {
+{127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128},
+{112,114,116,118,120,122,124,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,113,115,117,119,121,123,125,255,253,251,249,247,245,243,241,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,252,250,248,246,244,242,240},
+{96,98,100,102,104,106,108,110,112,113,114,116,117,118,120,121,122,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,97,99,101,103,105,107,109,111,115,119,123,255,251,247,243,239,237,235,233,231,229,227,225,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,250,249,248,246,245,244,242,241,240,238,236,234,232,230,228,226,224},
+{80,82,84,86,88,90,92,94,96,97,98,100,101,102,104,105,106,108,109,110,112,113,114,115,116,117,118,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,81,83,85,87,89,91,93,95,99,103,107,111,119,255,247,239,235,231,227,223,221,219,217,215,213,211,209,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,246,245,244,243,242,241,240,238,237,236,234,233,232,230,229,228,226,225,224,222,220,218,216,214,212,210,208},
+{64,66,68,70,72,74,76,78,80,81,82,84,85,86,88,89,90,92,93,94,96,97,98,99,100,101,102,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,65,67,69,71,73,75,77,79,83,87,91,95,103,111,255,239,231,223,219,215,211,207,205,203,201,199,197,195,193,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,238,237,236,235,234,233,232,230,229,228,227,226,225,224,222,221,220,218,217,216,214,213,212,210,209,208,206,204,202,200,198,196,194,192},
+{49,51,53,55,57,59,61,63,64,66,67,68,70,71,72,74,75,76,78,79,80,81,82,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,50,52,54,56,58,60,62,65,69,73,77,83,91,103,255,231,219,211,205,201,197,193,190,188,186,184,182,180,178,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,230,229,228,227,226,225,224,223,222,221,220,218,217,216,215,214,213,212,210,209,208,207,206,204,203,202,200,199,198,196,195,194,192,191,189,187,185,183,181,179,177},
+{32,34,36,38,40,42,44,46,48,49,51,52,53,55,56,57,59,60,61,63,64,65,66,67,68,70,71,72,73,74,75,76,78,79,80,81,82,83,84,85,86,87,88,89,90,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,35,37,39,41,43,45,47,50,54,58,62,69,77,91,255,219,205,197,190,186,182,178,175,173,171,169,167,165,163,161,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,218,217,216,215,214,213,212,211,210,209,208,207,206,204,203,202,201,200,199,198,196,195,194,193,192,191,189,188,187,185,184,183,181,180,179,177,176,174,172,170,168,166,164,162,160},
+{16,18,20,22,24,26,28,30,32,33,34,36,37,38,40,41,42,44,45,46,48,49,50,51,52,53,55,56,57,58,59,60,61,63,64,65,66,67,68,69,70,71,72,73,74,75,76,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,19,21,23,25,27,29,31,35,39,43,47,54,62,77,255,205,190,182,175,171,167,163,159,157,155,153,151,149,147,145,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,204,203,202,201,200,199,198,197,196,195,194,193,192,191,189,188,187,186,185,184,183,181,180,179,178,177,176,174,173,172,170,169,168,166,165,164,162,161,160,158,156,154,152,150,148,146,144},
+{2,4,6,8,10,12,14,16,17,18,20,21,22,24,25,26,28,29,30,32,33,34,35,36,37,38,40,41,42,43,44,45,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,1,3,5,7,9,11,13,15,19,23,27,31,39,47,62,255,190,175,167,159,155,151,147,143,141,139,137,135,133,131,129,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,189,188,187,186,185,184,183,182,181,180,179,178,177,176,174,173,172,171,170,169,168,166,165,164,163,162,161,160,158,157,156,154,153,152,150,149,148,146,145,144,142,140,138,136,134,132,130,128},
+{1,2,4,5,6,8,9,10,12,13,14,16,17,18,19,20,21,22,24,25,26,27,28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,3,7,11,15,23,31,47,255,175,159,151,143,139,135,131,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,158,157,156,155,154,153,152,150,149,148,147,146,145,144,142,141,140,138,137,136,134,133,132,130,129,128},
+{1,2,3,4,5,6,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,7,15,31,255,159,143,135,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,142,141,140,139,138,137,136,134,133,132,131,130,129,128},
+{1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,15,255,143,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128},
+{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,0,255,254,253,252,251,250,249,248,247,246,245,244,243,242,241,240,239,238,237,236,235,234,233,232,231,230,229,228,227,226,225,224,223,222,221,220,219,218,217,216,215,214,213,212,211,210,209,208,207,206,205,204,203,202,201,200,199,198,197,196,195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164,163,162,161,160,159,158,157,156,155,154,153,152,151,150,149,148,147,146,145,144,143,142,141,140,139,138,137,136,135,134,133,132,131,130,129,128}
+};
+
+
+#ifndef MIN_MACRO
+#define MIN_MACRO(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX_MACRO
+#define MAX_MACRO(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#define POSITIVE_ULAW_ZERO 0xff
+#define NEGATIVE_ULAW_ZERO 0x7f
+
+#define CAPMAXSCHAR(x) ((x > 127) ? 127 : x)
+#define CAPMAXUCHAR(x) ((x > 255) ? 255 : x)
+#define CAPMAXSHORT(x) ((x > 32767) ? 32767 : x)
+#define CAPMAXUSHORT(x) ((x > 65535) ? 65535 : x)
+
+#define UNDEFINED_UINT -1
+#define DEFAULT_BLOCK_SIZE 256
+#define DEFAULT_V0NMEAN 0
+#define DEFAULT_V2NMEAN 4
+#define DEFAULT_MAXNLPC 0
+#define DEFAULT_NCHAN 1
+#define DEFAULT_NSKIP 0
+#define DEFAULT_NDISCARD 0
+#define NBITPERLONG 32
+#define DEFAULT_MINSNR 256
+#define DEFAULT_QUANTERROR 0
+#define MINBITRATE 2.5
+
+#define MEAN_VERSION0 0
+#define MEAN_VERSION2 4
+
+#define SHN_FN_DIFF0 0
+#define SHN_FN_DIFF1 1
+#define SHN_FN_DIFF2 2
+#define SHN_FN_DIFF3 3
+#define SHN_FN_QUIT 4
+#define SHN_FN_BLOCKSIZE 5
+#define SHN_FN_BITSHIFT 6
+#define SHN_FN_QLPC 7
+#define SHN_FN_ZERO 8
+#define SHN_FN_VERBATIM 9
+
+#define SHN_TYPE_AU1 0
+#define SHN_TYPE_S8 1
+#define SHN_TYPE_U8 2
+#define SHN_TYPE_S16HL 3
+#define SHN_TYPE_U16HL 4
+#define SHN_TYPE_S16LH 5
+#define SHN_TYPE_U16LH 6
+#define SHN_TYPE_ULAW 7
+#define SHN_TYPE_AU2 8
+#define SHN_TYPE_AU3 9
+#define SHN_TYPE_ALAW 10
+#define SHN_TYPE_RIFF_WAVE 11
+#define SHN_TYPE_EOF 12
+#define SHN_TYPE_GENERIC_ULAW 128
+#define SHN_TYPE_GENERIC_ALAW 129
+
+#define SHN_FNSIZE 2
+#define SHN_CHANNELSIZE 0
+#define SHN_TYPESIZE 4
+#define SHN_ULONGSIZE 2
+#define SHN_NSKIPSIZE 1
+#define SHN_LPCQSIZE 2
+#define SHN_LPCQUANT 5
+#define SHN_XBYTESIZE 7
+#define SHN_VERBATIM_CKSIZE_SIZE 5
+#define SHN_VERBATIM_BYTE_SIZE 8
+#define SHN_ENERGYSIZE 3
+#define SHN_BITSHIFTSIZE 2
+
+#define SHN_LPCQOFFSET_VER2 (1 << SHN_LPCQUANT)
+
+
+#define SHN_MAGIC 0x676B6A61 /* looks like "ajkg" as chars. */
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+static int word_get(shn_t *shn, SDL_RWops *rw, Uint32 *word)
+{
+ if (shn->nbyteget < 4)
+ {
+ shn->nbyteget += SDL_RWread(rw, shn->getbuf, 1, SHN_BUFSIZ);
+ BAIL_IF_MACRO(shn->nbyteget < 4, NULL, 0);
+ shn->getbufp = shn->getbuf;
+ } /* if */
+
+ if (word != NULL)
+ {
+ *word = (((Sint32) shn->getbufp[0]) << 24) |
+ (((Sint32) shn->getbufp[1]) << 16) |
+ (((Sint32) shn->getbufp[2]) << 8) |
+ (((Sint32) shn->getbufp[3]) );
+ } /* if */
+
+ shn->getbufp += 4;
+ shn->nbyteget -= 4;
+
+ return(1);
+} /* word_get */
+
+
+static int uvar_get(int nbin, shn_t *shn, SDL_RWops *rw, Sint32 *word)
+{
+ Sint32 result;
+
+ if (shn->nbitget == 0)
+ {
+ BAIL_IF_MACRO(!word_get(shn, rw, &shn->gbuffer), NULL, 0);
+ shn->nbitget = 32;
+ } /* if */
+
+ for (result = 0; !(shn->gbuffer & (1L << --shn->nbitget)); result++)
+ {
+ if (shn->nbitget == 0)
+ {
+ BAIL_IF_MACRO(!word_get(shn, rw, &shn->gbuffer), NULL, 0);
+ shn->nbitget = 32;
+ } /* if */
+ } /* for */
+
+ while (nbin != 0)
+ {
+ if (shn->nbitget >= nbin)
+ {
+ result = ( (result << nbin) |
+ ((shn->gbuffer >> (shn->nbitget - nbin)) &
+ mask_table[nbin]) );
+ shn->nbitget -= nbin;
+ break;
+ } /* if */
+ else
+ {
+ result = (result << shn->nbitget) |
+ (shn->gbuffer & mask_table[shn->nbitget]);
+ BAIL_IF_MACRO(!word_get(shn, rw, &shn->gbuffer), NULL, 0);
+ nbin -= shn->nbitget;
+ shn->nbitget = 32;
+ } /* else */
+ } /* while */
+
+ if (word != NULL)
+ *word = result;
+
+ return(1);
+} /* uvar_get */
+
+
+static int var_get(int nbin, shn_t *shn, SDL_RWops *rw, Sint32 *word)
+{
+ BAIL_IF_MACRO(!uvar_get(nbin + 1, shn, rw, word), NULL, 0);
+
+ if ((*word) & 1)
+ *word = (Sint32) ~((*word) >> 1);
+ else
+ *word = (Sint32) ((*word) >> 1);
+
+ return(1);
+} /* var_get */
+
+
+static int ulong_get(shn_t *shn, SDL_RWops *rw, Sint32 *word)
+{
+ Sint32 nbit;
+ Sint32 retval;
+ BAIL_IF_MACRO(!uvar_get(SHN_ULONGSIZE, shn, rw, &nbit), NULL, 0);
+ BAIL_IF_MACRO(!uvar_get(nbit, shn, rw, &retval), NULL, 0);
+
+ if (word != NULL)
+ *word = retval;
+
+ return(1);
+} /* ulong_get */
+
+
+static __inline__ int uint_get(int nbit, shn_t *shn, SDL_RWops *rw, Sint32 *w)
+{
+ return((shn->version == 0) ?
+ uvar_get(nbit, shn, rw, w) :
+ ulong_get(shn, rw, w));
+} /* uint_get */
+
+
+static int SHN_init(void)
+{
+ return(1); /* initialization always successful. */
+} /* SHN_init */
+
+
+static void SHN_quit(void)
+{
+ /* it's a no-op. */
+} /* SHN_quit */
+
+
+/*
+ * Look through the whole file for a SHN magic number. This is costly, so
+ * it should only be done if the user SWEARS they have a Shorten stream...
+ */
+static __inline__ int extended_shn_magic_search(Sound_Sample *sample)
+{
+ SDL_RWops *rw = ((Sound_SampleInternal *) sample->opaque)->rw;
+ Uint32 word = 0;
+ Uint8 ch;
+
+ while (1)
+ {
+ BAIL_IF_MACRO(SDL_RWread(rw, &ch, sizeof (ch), 1) != 1, NULL, -1);
+ word = ((word << 8) & 0xFFFFFF00) | ch;
+ if (SDL_SwapBE32(word) == SHN_MAGIC)
+ {
+ BAIL_IF_MACRO(SDL_RWread(rw, &ch, sizeof (ch), 1) != 1, NULL, -1);
+ return((int) ch);
+ } /* if */
+ } /* while */
+
+ return((int) ch);
+} /* extended_shn_magic_search */
+
+
+/* look for the magic number in the RWops and see what kind of file this is. */
+static __inline__ int determine_shn_version(Sound_Sample *sample,
+ const char *ext)
+{
+ SDL_RWops *rw = ((Sound_SampleInternal *) sample->opaque)->rw;
+ Uint32 magic;
+ Uint8 ch;
+
+ /*
+ * Apparently the magic number can start at any byte offset in the file,
+ * and we should just discard prior data, but I'm going to restrict it
+ * to offset zero for now, so we don't chug down every file that might
+ * happen to pass through here. If the extension is explicitly "SHN", we
+ * check the whole stream, though.
+ */
+
+ if (__Sound_strcasecmp(ext, "shn") == 0)
+ return(extended_shn_magic_search(sample));
+
+ BAIL_IF_MACRO(SDL_RWread(rw, &magic, sizeof (magic), 1) != 1, NULL, -1);
+ BAIL_IF_MACRO(SDL_SwapLE32(magic) != SHN_MAGIC, "SHN: Not a SHN file", -1);
+ BAIL_IF_MACRO(SDL_RWread(rw, &ch, sizeof (ch), 1) != 1, NULL, -1);
+ BAIL_IF_MACRO(ch > 3, "SHN: Unsupported file version", -1);
+
+ return((int) ch);
+} /* determine_shn_version */
+
+
+static void init_shn_offset(Sint32 **offset, int nchan, int nblock, int ftype)
+{
+ Sint32 mean = 0;
+ int chan;
+
+ switch (ftype)
+ {
+ case SHN_TYPE_AU1:
+ case SHN_TYPE_S8:
+ case SHN_TYPE_S16HL:
+ case SHN_TYPE_S16LH:
+ case SHN_TYPE_ULAW:
+ case SHN_TYPE_AU2:
+ case SHN_TYPE_AU3:
+ case SHN_TYPE_ALAW:
+ mean = 0;
+ break;
+ case SHN_TYPE_U8:
+ mean = 0x80;
+ break;
+ case SHN_TYPE_U16HL:
+ case SHN_TYPE_U16LH:
+ mean = 0x8000;
+ break;
+ default:
+ __Sound_SetError("SHN: unknown file type");
+ return;
+ } /* switch */
+
+ for(chan = 0; chan < nchan; chan++)
+ {
+ int i;
+ for(i = 0; i < nblock; i++)
+ offset[chan][i] = mean;
+ } /* for */
+} /* init_shn_offset */
+
+
+static __inline__ Uint16 cvt_shnftype_to_sdlfmt(Sint16 shntype)
+{
+ switch (shntype)
+ {
+ case SHN_TYPE_S8:
+ return(AUDIO_S8);
+
+ case SHN_TYPE_ALAW:
+ case SHN_TYPE_ULAW:
+ case SHN_TYPE_AU1:
+ case SHN_TYPE_AU2:
+ case SHN_TYPE_AU3:
+ case SHN_TYPE_U8:
+ return(AUDIO_U8);
+
+ case SHN_TYPE_S16HL:
+ return(AUDIO_S16MSB);
+
+ case SHN_TYPE_S16LH:
+ return(AUDIO_S16LSB);
+
+ case SHN_TYPE_U16HL:
+ return(AUDIO_U16MSB);
+
+ case SHN_TYPE_U16LH:
+ return(AUDIO_U16LSB);
+ } /* switch */
+
+ return(0);
+} /* cvt_shnftype_to_sdlfmt */
+
+
+static __inline__ int skip_bits(shn_t *shn, SDL_RWops *rw)
+{
+ int i;
+ Sint32 skip;
+ Sint32 trash;
+
+ BAIL_IF_MACRO(!uint_get(SHN_NSKIPSIZE, shn, rw, &skip), NULL, 0);
+ for(i = 0; i < skip; i++)
+ {
+ BAIL_IF_MACRO(!uint_get(SHN_XBYTESIZE, shn, rw, &trash), NULL, 0);
+ } /* for */
+
+ return(1);
+} /* skip_bits */
+
+
+static Sint32 **shn_long2d(Uint32 n0, Uint32 n1)
+{
+ Sint32 **array0;
+ Uint32 size = (n0 * sizeof (Sint32 *)) + (n0 * n1 * sizeof (Sint32));
+
+ array0 = (Sint32 **) malloc(size);
+ if (array0 != NULL)
+ {
+ int i;
+ Sint32 *array1 = (Sint32 *) (array0 + n0);
+ for(i = 0; i < n0; i++)
+ array0[i] = array1 + (i * n1);
+ } /* if */
+
+ return(array0);
+} /* shn_long2d */
+
+#define riffID 0x46464952 /* "RIFF", in ascii. */
+#define waveID 0x45564157 /* "WAVE", in ascii. */
+#define fmtID 0x20746D66 /* "fmt ", in ascii. */
+#define dataID 0x61746164 /* "data", in ascii. */
+
+static int verb_ReadLE32(shn_t *shn, SDL_RWops *rw, Uint32 *word)
+{
+ int i;
+ Uint8 chars[4];
+ Sint32 byte;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (!uvar_get(SHN_VERBATIM_BYTE_SIZE, shn, rw, &byte))
+ return(0);
+ chars[i] = (Uint8) byte;
+ } /* for */
+
+ memcpy(word, chars, sizeof (*word));
+ *word = SDL_SwapLE32(*word);
+
+ return(1);
+} /* verb_ReadLE32 */
+
+
+static int verb_ReadLE16(shn_t *shn, SDL_RWops *rw, Uint16 *word)
+{
+ int i;
+ Uint8 chars[2];
+ Sint32 byte;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (!uvar_get(SHN_VERBATIM_BYTE_SIZE, shn, rw, &byte))
+ return(0);
+ chars[i] = (Uint8) byte;
+ } /* for */
+
+ memcpy(word, chars, sizeof (*word));
+ *word = SDL_SwapLE16(*word);
+
+ return(1);
+} /* verb_ReadLE16 */
+
+
+static __inline__ int parse_riff_header(shn_t *shn, Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ Uint16 u16;
+ Uint32 u32;
+ Sint32 cklen;
+
+ BAIL_IF_MACRO(!uvar_get(SHN_VERBATIM_CKSIZE_SIZE, shn, rw, &cklen), NULL, 0);
+
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* RIFF header */
+ BAIL_IF_MACRO(u32 != riffID, "SHN: No RIFF header.", 0);
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* length */
+
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* WAVE header */
+ BAIL_IF_MACRO(u32 != waveID, "SHN: No WAVE header.", 0);
+
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* 'fmt ' header */
+ BAIL_IF_MACRO(u32 != fmtID, "SHN: No 'fmt ' header.", 0);
+
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* chunksize */
+ BAIL_IF_MACRO(!verb_ReadLE16(shn, rw, &u16), NULL, 0); /* format */
+ BAIL_IF_MACRO(!verb_ReadLE16(shn, rw, &u16), NULL, 0); /* channels */
+ sample->actual.channels = u16;
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* sample rate */
+ sample->actual.rate = u32;
+
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* bytespersec */
+ BAIL_IF_MACRO(!verb_ReadLE16(shn, rw, &u16), NULL, 0); /* blockalign */
+ BAIL_IF_MACRO(!verb_ReadLE16(shn, rw, &u16), NULL, 0); /* bitspersample */
+
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* 'data' header */
+ BAIL_IF_MACRO(u32 != dataID, "SHN: No 'data' header.", 0);
+ BAIL_IF_MACRO(!verb_ReadLE32(shn, rw, &u32), NULL, 0); /* chunksize */
+
+ return(1);
+} /* parse_riff_header */
+
+
+static int SHN_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ shn_t _shn;
+ shn_t *shn = &_shn; /* malloc and copy later. */
+ Sint32 cmd;
+ Sint32 chan;
+
+ memset(shn, '\0', sizeof (shn_t));
+ shn->getbufp = shn->getbuf = (Uint8 *) malloc(SHN_BUFSIZ);
+ shn->datatype = SHN_TYPE_EOF;
+ shn->nchan = DEFAULT_NCHAN;
+ shn->blocksize = DEFAULT_BLOCK_SIZE;
+ shn->maxnlpc = DEFAULT_MAXNLPC;
+ shn->nmean = UNDEFINED_UINT;
+ shn->version = determine_shn_version(sample, ext);
+
+ if (shn->version == -1) goto shn_open_puke;
+ if (!uint_get(SHN_TYPESIZE, shn, rw, &shn->datatype)) goto shn_open_puke;
+ if (!uint_get(SHN_CHANNELSIZE, shn, rw, &shn->nchan)) goto shn_open_puke;
+
+ sample->actual.format = cvt_shnftype_to_sdlfmt(shn->datatype);
+ if (sample->actual.format == 0)
+ {
+ SDL_SetError(ERR_UNSUPPORTED_FORMAT);
+ goto shn_open_puke;
+ } /* if */
+
+ if (shn->version > 0)
+ {
+ int rc = uint_get((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2),
+ shn, rw, &shn->blocksize);
+ if (!rc) goto shn_open_puke;;
+ if (!uint_get(SHN_LPCQSIZE, shn, rw, &shn->maxnlpc)) goto shn_open_puke;
+ if (!uint_get(0, shn, rw, &shn->nmean)) goto shn_open_puke;
+ if (!skip_bits(shn, rw)) goto shn_open_puke;
+ } /* else */
+
+ shn->nwrap = (shn->maxnlpc > 3) ? shn->maxnlpc : 3;
+
+ /* grab some space for the input buffer */
+ shn->buffer = shn_long2d((Uint32) shn->nchan, shn->blocksize + shn->nwrap);
+ shn->offset = shn_long2d((Uint32) shn->nchan, MAX_MACRO(1, shn->nmean));
+
+ for (chan = 0; chan < shn->nchan; chan++)
+ {
+ int i;
+ for(i = 0; i < shn->nwrap; i++)
+ shn->buffer[chan][i] = 0;
+ shn->buffer[chan] += shn->nwrap;
+ } /* for */
+
+ if (shn->maxnlpc > 0)
+ {
+ shn->qlpc = (int *) malloc((Uint32) (shn->maxnlpc * sizeof (Sint32)));
+ if (shn->qlpc == NULL)
+ {
+ __Sound_SetError(ERR_OUT_OF_MEMORY);
+ goto shn_open_puke;
+ } /* if */
+ } /* if */
+
+ if (shn->version > 1)
+ shn->lpcqoffset = SHN_LPCQOFFSET_VER2;
+
+ init_shn_offset(shn->offset, shn->nchan,
+ MAX_MACRO(1, shn->nmean), shn->datatype);
+
+ if ( (!uvar_get(SHN_FNSIZE, shn, rw, &cmd)) ||
+ (cmd != SHN_FN_VERBATIM) ||
+ (!parse_riff_header(shn, sample)) )
+ {
+ if (cmd != SHN_FN_VERBATIM) /* the other conditions set error state */
+ __Sound_SetError("SHN: Expected VERBATIM function");
+
+ goto shn_open_puke;
+ return(0);
+ } /* if */
+
+ shn->start_pos = SDL_RWtell(rw);
+
+ shn = (shn_t *) malloc(sizeof (shn_t));
+ if (shn == NULL)
+ {
+ __Sound_SetError(ERR_OUT_OF_MEMORY);
+ goto shn_open_puke;
+ } /* if */
+
+ memcpy(shn, &_shn, sizeof (shn_t));
+ internal->decoder_private = shn;
+
+ SNDDBG(("SHN: Accepting data stream.\n"));
+ sample->flags = SOUND_SAMPLEFLAG_NONE;
+ return(1); /* we'll handle this data. */
+
+shn_open_puke:
+ if (_shn.getbuf)
+ free(_shn.getbuf);
+ if (_shn.buffer != NULL)
+ free(_shn.buffer);
+ if (_shn.offset != NULL)
+ free(_shn.offset);
+ if (_shn.qlpc != NULL)
+ free(_shn.qlpc);
+
+ return(0);
+} /* SHN_open */
+
+
+static void fix_bitshift(Sint32 *buffer, int nitem, int bitshift, int ftype)
+{
+ int i;
+
+ if (ftype == SHN_TYPE_AU1)
+ {
+ for (i = 0; i < nitem; i++)
+ buffer[i] = ulaw_outward[bitshift][buffer[i] + 128];
+ } /* if */
+ else if (ftype == SHN_TYPE_AU2)
+ {
+ for(i = 0; i < nitem; i++)
+ {
+ if (buffer[i] >= 0)
+ buffer[i] = ulaw_outward[bitshift][buffer[i] + 128];
+ else if (buffer[i] == -1)
+ buffer[i] = NEGATIVE_ULAW_ZERO;
+ else
+ buffer[i] = ulaw_outward[bitshift][buffer[i] + 129];
+ } /* for */
+ } /* else if */
+ else
+ {
+ if (bitshift != 0)
+ {
+ for(i = 0; i < nitem; i++)
+ buffer[i] <<= bitshift;
+ } /* if */
+ } /* else */
+} /* fix_bitshift */
+
+
+static void SHN_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ shn_t *shn = (shn_t *) internal->decoder_private;
+
+ if (shn->qlpc != NULL)
+ free(shn->qlpc);
+
+ if (shn->backBuffer != NULL)
+ free(shn->backBuffer);
+
+ if (shn->offset != NULL)
+ free(shn->offset);
+
+ if (shn->buffer != NULL)
+ free(shn->buffer);
+
+ if (shn->getbuf != NULL)
+ free(shn->getbuf);
+
+ free(shn);
+} /* SHN_close */
+
+
+/* xLaw conversions... */
+
+/* adapted by ajr for int input */
+static Uint8 Slinear2ulaw(int sample)
+{
+/*
+** This routine converts from linear to ulaw.
+**
+** Craig Reese: IDA/Supercomputing Research Center
+** Joe Campbell: Department of Defense
+** 29 September 1989
+**
+** References:
+** 1) CCITT Recommendation G.711 (very difficult to follow)
+** 2) "A New Digital Technique for Implementation of Any
+** Continuous PCM Companding Law," Villeret, Michel,
+** et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
+** 1973, pg. 11.12-11.17
+** 3) MIL-STD-188-113,"Interoperability and Performance Standards
+** for Analog-to_Digital Conversion Techniques,"
+** 17 February 1987
+**
+** Input: Signed 16 bit linear sample
+** Output: 8 bit ulaw sample
+*/
+
+#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
+#define CLIP 32635
+
+ int sign, exponent, mantissa;
+ Uint8 ulawbyte;
+ static const int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
+
+ /* Get the sample into sign-magnitude. */
+ if (sample >= 0)
+ sign = 0;
+ else
+ {
+ sign = 0x80;
+ sample = -sample;
+ } /* else */
+
+ /* clip the magnitude */
+ if (sample > CLIP)
+ sample = CLIP;
+
+ /* Convert from 16 bit linear to ulaw. */
+ sample = sample + BIAS;
+ exponent = exp_lut[( sample >> 7 ) & 0xFF];
+ mantissa = (sample >> (exponent + 3)) & 0x0F;
+ ulawbyte = ~(sign | (exponent << 4) | mantissa);
+
+ return(ulawbyte);
+} /* Slinear2ulaw */
+
+
+/* this is derived from the Sun code - it is a bit simpler and has int input */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define NSEGS (8) /* Number of A-law segments. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+
+
+static Uint8 Slinear2alaw(Sint32 linear)
+{
+ int seg;
+ Uint8 aval, mask;
+ static const Sint32 seg_aend[NSEGS] =
+ {
+ 0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,0x7ff,0xfff
+ };
+
+ linear >>= 3;
+ if(linear >= 0)
+ mask = 0xd5; /* sign (7th) bit = 1 */
+ else
+ {
+ mask = 0x55; /* sign bit = 0 */
+ linear = -linear - 1;
+ } /* else */
+
+ /* Convert the scaled magnitude to segment number. */
+ for (seg = 0; (seg < NSEGS) && (linear > seg_aend[seg]); seg++);
+
+ /* Combine the sign, segment, and quantization bits. */
+ if (seg >= NSEGS) /* out of range, return maximum value. */
+ return((Uint8) (0x7F ^ mask));
+
+ aval = (Uint8) seg << SEG_SHIFT;
+ if (seg < 2)
+ aval |= (linear >> 1) & QUANT_MASK;
+ else
+ aval |= (linear >> seg) & QUANT_MASK;
+
+ return (aval ^ mask);
+} /* Slinear2alaw */
+
+
+/* convert from signed ints to a given type and write */
+static Uint32 put_to_buffers(Sound_Sample *sample, Uint32 bw)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ shn_t *shn = (shn_t *) internal->decoder_private;
+ int i, chan;
+ Sint32 *data0 = shn->buffer[0];
+ Sint32 nitem = shn->blocksize;
+ int datasize = ((sample->actual.format & 0xFF) / 8);
+ Uint32 bsiz = shn->nchan * nitem * datasize;
+
+ assert(shn->backBufLeft == 0);
+
+ if (shn->backBufferSize < bsiz)
+ {
+ void *rc = realloc(shn->backBuffer, bsiz);
+ if (rc == NULL)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
+ } /* if */
+ shn->backBuffer = (Uint8 *) rc;
+ shn->backBufferSize = bsiz;
+ } /* if */
+
+ switch (shn->datatype)
+ {
+ case SHN_TYPE_AU1: /* leave the conversion to fix_bitshift() */
+ case SHN_TYPE_AU2:
+ {
+ Uint8 *writebufp = shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for (i = 0; i < nitem; i++)
+ *writebufp++ = data0[i];
+ } /* if */
+ else
+ {
+ for (i = 0; i < nitem; i++)
+ {
+ for (chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = shn->buffer[chan][i];
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_U8:
+ {
+ Uint8 *writebufp = shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for (i = 0; i < nitem; i++)
+ *writebufp++ = CAPMAXUCHAR(data0[i]);
+ } /* if */
+ else
+ {
+ for (i = 0; i < nitem; i++)
+ {
+ for (chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = CAPMAXUCHAR(shn->buffer[chan][i]);
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_S8:
+ {
+ Sint8 *writebufp = (Sint8 *) shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for(i = 0; i < nitem; i++)
+ *writebufp++ = CAPMAXSCHAR(data0[i]);
+ } /* if */
+ else
+ {
+ for(i = 0; i < nitem; i++)
+ {
+ for(chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = CAPMAXSCHAR(shn->buffer[chan][i]);
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_S16HL:
+ case SHN_TYPE_S16LH:
+ {
+ Sint16 *writebufp = (Sint16 *) shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for (i = 0; i < nitem; i++)
+ *writebufp++ = CAPMAXSHORT(data0[i]);
+ } /* if */
+ else
+ {
+ for (i = 0; i < nitem; i++)
+ {
+ for (chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = CAPMAXSHORT(shn->buffer[chan][i]);
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_U16HL:
+ case SHN_TYPE_U16LH:
+ {
+ Uint16 *writebufp = (Uint16 *) shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for (i = 0; i < nitem; i++)
+ *writebufp++ = CAPMAXUSHORT(data0[i]);
+ } /* if */
+ else
+ {
+ for (i = 0; i < nitem; i++)
+ {
+ for (chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = CAPMAXUSHORT(shn->buffer[chan][i]);
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_ULAW:
+ {
+ Uint8 *writebufp = shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for(i = 0; i < nitem; i++)
+ *writebufp++ = Slinear2ulaw(CAPMAXSHORT((data0[i] << 3)));
+ } /* if */
+ else
+ {
+ for(i = 0; i < nitem; i++)
+ {
+ for(chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = Slinear2ulaw(CAPMAXSHORT((shn->buffer[chan][i] << 3)));
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_AU3:
+ {
+ Uint8 *writebufp = shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for (i = 0; i < nitem; i++)
+ if(data0[i] < 0)
+ *writebufp++ = (127 - data0[i]) ^ 0xd5;
+ else
+ *writebufp++ = (data0[i] + 128) ^ 0x55;
+ } /* if */
+ else
+ {
+ for (i = 0; i < nitem; i++)
+ {
+ for (chan = 0; chan < shn->nchan; chan++)
+ {
+ if (shn->buffer[chan][i] < 0)
+ *writebufp++ = (127 - shn->buffer[chan][i]) ^ 0xd5;
+ else
+ *writebufp++ = (shn->buffer[chan][i] + 128) ^ 0x55;
+ } /* for */
+ } /* for */
+ } /* else */
+ } /* case */
+ break;
+
+ case SHN_TYPE_ALAW:
+ {
+ Uint8 *writebufp = shn->backBuffer;
+ if (shn->nchan == 1)
+ {
+ for (i = 0; i < nitem; i++)
+ *writebufp++ = Slinear2alaw(CAPMAXSHORT((data0[i] << 3)));
+ } /* if */
+ else
+ {
+ for (i = 0; i < nitem; i++)
+ {
+ for(chan = 0; chan < shn->nchan; chan++)
+ *writebufp++ = Slinear2alaw(CAPMAXSHORT((shn->buffer[chan][i] << 3)));
+ } /* for */
+ }/* else */
+ } /* case */
+ break;
+ } /* switch */
+
+ i = MIN_MACRO(internal->buffer_size - bw, bsiz);
+ memcpy((char *)internal->buffer + bw, shn->backBuffer, i);
+ shn->backBufLeft = bsiz - i;
+ memcpy(shn->backBuffer, shn->backBuffer + i, shn->backBufLeft);
+ return(i);
+} /* put_to_buffers */
+
+
+#define ROUNDEDSHIFTDOWN(x, n) (((n) == 0) ? (x) : ((x) >> ((n) - 1)) >> 1)
+
+static Uint32 SHN_read(Sound_Sample *sample)
+{
+ Uint32 retval = 0;
+ Sint32 chan = 0;
+ Uint32 cpyBytes = 0;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ shn_t *shn = (shn_t *) internal->decoder_private;
+ Sint32 cmd;
+
+ assert(shn->backBufLeft >= 0);
+
+ /* see if there are leftovers to copy... */
+ if (shn->backBufLeft > 0)
+ {
+ retval = MIN_MACRO(shn->backBufLeft, internal->buffer_size);
+ memcpy(internal->buffer, shn->backBuffer, retval);
+ shn->backBufLeft -= retval;
+ memcpy(shn->backBuffer, shn->backBuffer + retval, shn->backBufLeft);
+ } /* if */
+
+ assert((shn->backBufLeft == 0) || (retval == internal->buffer_size));
+
+ /* get commands from file and execute them */
+ while (retval < internal->buffer_size)
+ {
+ if (!uvar_get(SHN_FNSIZE, shn, rw, &cmd))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+
+ if (cmd == SHN_FN_QUIT)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(retval);
+ } /* if */
+
+ switch(cmd)
+ {
+ case SHN_FN_ZERO:
+ case SHN_FN_DIFF0:
+ case SHN_FN_DIFF1:
+ case SHN_FN_DIFF2:
+ case SHN_FN_DIFF3:
+ case SHN_FN_QLPC:
+ {
+ Sint32 i;
+ Sint32 coffset, *cbuffer = shn->buffer[chan];
+ Sint32 resn = 0, nlpc, j;
+
+ if (cmd != SHN_FN_ZERO)
+ {
+ if (!uvar_get(SHN_ENERGYSIZE, shn, rw, &resn))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+
+ /* version 0 differed in definition of var_get */
+ if (shn->version == 0)
+ resn--;
+ } /* if */
+
+ /* find mean offset : N.B. this code duplicated */
+ if (shn->nmean == 0)
+ coffset = shn->offset[chan][0];
+ else
+ {
+ Sint32 sum = (shn->version < 2) ? 0 : shn->nmean / 2;
+ for (i = 0; i < shn->nmean; i++)
+ sum += shn->offset[chan][i];
+
+ if (shn->version < 2)
+ coffset = sum / shn->nmean;
+ else
+ coffset = ROUNDEDSHIFTDOWN(sum / shn->nmean, shn->bitshift);
+ } /* else */
+
+ switch (cmd)
+ {
+ case SHN_FN_ZERO:
+ for (i = 0; i < shn->blocksize; i++)
+ cbuffer[i] = 0;
+ break;
+
+ case SHN_FN_DIFF0:
+ for(i = 0; i < shn->blocksize; i++)
+ {
+ if (!var_get(resn, shn, rw, &cbuffer[i]))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ cbuffer[i] += coffset;
+ } /* for */
+ break;
+
+ case SHN_FN_DIFF1:
+ for(i = 0; i < shn->blocksize; i++)
+ {
+ if (!var_get(resn, shn, rw, &cbuffer[i]))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ cbuffer[i] += cbuffer[i - 1];
+ } /* for */
+ break;
+
+ case SHN_FN_DIFF2:
+ for (i = 0; i < shn->blocksize; i++)
+ {
+ if (!var_get(resn, shn, rw, &cbuffer[i]))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ cbuffer[i] += (2 * cbuffer[i-1] - cbuffer[i-2]);
+ } /* for */
+ break;
+
+ case SHN_FN_DIFF3:
+ for (i = 0; i < shn->blocksize; i++)
+ {
+ if (!var_get(resn, shn, rw, &cbuffer[i]))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ cbuffer[i] += 3 * (cbuffer[i - 1] - cbuffer[i - 2]) + cbuffer[i - 3];
+ } /* for */
+ break;
+
+ case SHN_FN_QLPC:
+ if (!uvar_get(SHN_LPCQSIZE, shn, rw, &nlpc))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+
+ for(i = 0; i < nlpc; i++)
+ {
+ if (!var_get(SHN_LPCQUANT, shn, rw, &shn->qlpc[i]))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ } /* for */
+
+ for(i = 0; i < nlpc; i++)
+ cbuffer[i - nlpc] -= coffset;
+
+ for(i = 0; i < shn->blocksize; i++)
+ {
+ Sint32 sum = shn->lpcqoffset;
+
+ for(j = 0; j < nlpc; j++)
+ sum += shn->qlpc[j] * cbuffer[i - j - 1];
+
+ if (!var_get(resn, shn, rw, &cbuffer[i]))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ cbuffer[i] += (sum >> SHN_LPCQUANT);
+ } /* for */
+
+ if (coffset != 0)
+ {
+ for(i = 0; i < shn->blocksize; i++)
+ cbuffer[i] += coffset;
+ } /* if */
+
+ break;
+ } /* switch */
+
+ /* store mean value if appropriate : N.B. Duplicated code */
+ if (shn->nmean > 0)
+ {
+ Sint32 sum = (shn->version < 2) ? 0 : shn->blocksize / 2;
+ for (i = 0; i < shn->blocksize; i++)
+ sum += cbuffer[i];
+
+ for(i = 1; i < shn->nmean; i++)
+ shn->offset[chan][i - 1] = shn->offset[chan][i];
+
+ if (shn->version < 2)
+ shn->offset[chan][shn->nmean - 1] = sum / shn->blocksize;
+ else
+ shn->offset[chan][shn->nmean - 1] = (sum / shn->blocksize) << shn->bitshift;
+ } /* if */
+
+ /* do the wrap */
+ for(i = -shn->nwrap; i < 0; i++)
+ cbuffer[i] = cbuffer[i + shn->blocksize];
+
+ fix_bitshift(cbuffer, shn->blocksize, shn->bitshift, shn->datatype);
+
+ if (chan == shn->nchan - 1)
+ {
+ retval += put_to_buffers(sample, retval);
+ if (sample->flags & SOUND_SAMPLEFLAG_ERROR)
+ return(retval);
+ } /* if */
+
+ chan = (chan + 1) % shn->nchan;
+ break;
+ } /* case */
+
+ case SHN_FN_BLOCKSIZE:
+ if (!uint_get((int) (log((double) shn->blocksize) / M_LN2),
+ shn, rw, &shn->blocksize))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ break;
+
+ case SHN_FN_BITSHIFT:
+ if (!uvar_get(SHN_BITSHIFTSIZE, shn, rw, &shn->bitshift))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(retval);
+ } /* if */
+ break;
+
+ case SHN_FN_VERBATIM:
+ default:
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ BAIL_MACRO("SHN: Unhandled function.", retval);
+ } /* switch */
+ } /* while */
+
+ return(retval);
+} /* SHN_read */
+
+
+static int SHN_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ shn_t *shn = (shn_t *) internal->decoder_private;
+
+#if 0
+ int rc = SDL_RWseek(internal->rw, shn->start_pos, SEEK_SET);
+ BAIL_IF_MACRO(rc != shn->start_pos, ERR_IO_ERROR, 0);
+ /* !!! FIXME: set state. */
+ return(1);
+#else
+ /*
+ * !!! FIXME: This is really unacceptable; state should be reset and
+ * !!! FIXME: the RWops should be pointed to the start of the data
+ * !!! FIXME: to decode. The below kludge adds unneeded overhead and
+ * !!! FIXME: risk of failure.
+ */
+ BAIL_IF_MACRO(SDL_RWseek(internal->rw, 0, SEEK_SET) != 0, ERR_IO_ERROR, 0);
+ SHN_close(sample);
+ return(SHN_open(sample, "SHN"));
+#endif
+} /* SHN_rewind */
+
+
+static int SHN_seek(Sound_Sample *sample, Uint32 ms)
+{
+ /*
+ * (This CAN be done for SHNs that have a seek table at the end of the
+ * stream, btw.)
+ */
+ BAIL_MACRO("SHN: Seeking not implemented", 0);
+} /* SHN_seek */
+
+
+#endif /* defined SOUND_SUPPORTS_SHN */
+
+/* end of shn.c ... */
+
diff --git a/util/sdl/sound/decoders/smpeg.c b/util/sdl/sound/decoders/smpeg.c
new file mode 100644
index 00000000..f4958977
--- /dev/null
+++ b/util/sdl/sound/decoders/smpeg.c
@@ -0,0 +1,310 @@
+/*
+ * 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
+ */
+
+/*
+ * MPEG-1 Layer 3, or simply, "MP3", decoder for SDL_sound.
+ *
+ * This driver handles all those highly compressed songs you stole through
+ * Napster. :) It depends on the SMPEG library for decoding, which can
+ * be grabbed from: http://www.lokigames.com/development/smpeg.php3
+ *
+ * This should also be able to extract the audio stream from an MPEG movie.
+ *
+ * There is an alternative MP3 decoder available, called "mpglib", which
+ * doesn't depend on external libraries (the decoder itself is part of
+ * SDL_sound), and may be more efficient, but less flexible than SMPEG. YMMV.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_SMPEG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "smpeg.h"
+#include "extra_rwops.h"
+
+
+static int _SMPEG_init(void);
+static void _SMPEG_quit(void);
+static int _SMPEG_open(Sound_Sample *sample, const char *ext);
+static void _SMPEG_close(Sound_Sample *sample);
+static Uint32 _SMPEG_read(Sound_Sample *sample);
+static int _SMPEG_rewind(Sound_Sample *sample);
+static int _SMPEG_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_smpeg[] = { "MP3", "MPEG", "MPG", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_SMPEG =
+{
+ {
+ extensions_smpeg,
+ "MPEG-1 Layer 3 audio through SMPEG",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://icculus.org/smpeg/"
+ },
+
+ _SMPEG_init, /* init() method */
+ _SMPEG_quit, /* quit() method */
+ _SMPEG_open, /* open() method */
+ _SMPEG_close, /* close() method */
+ _SMPEG_read, /* read() method */
+ _SMPEG_rewind, /* rewind() method */
+ _SMPEG_seek /* seek() method */
+};
+
+
+static int _SMPEG_init(void)
+{
+ return(1); /* always succeeds. */
+} /* _SMPEG_init */
+
+
+static void _SMPEG_quit(void)
+{
+ /* it's a no-op. */
+} /* _SMPEG_quit */
+
+
+static __inline__ void output_version(void)
+{
+ static int first_time = 1;
+
+ if (first_time)
+ {
+ SMPEG_version v;
+ SMPEG_VERSION(&v);
+ SNDDBG(("SMPEG: Compiled against SMPEG v%d.%d.%d.\n",
+ v.major, v.minor, v.patch));
+ first_time = 0;
+ } /* if */
+} /* output_version */
+
+
+static int _SMPEG_open(Sound_Sample *sample, const char *ext)
+{
+ SMPEG *smpeg;
+ SMPEG_Info smpeg_info;
+ SDL_AudioSpec spec;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *refCounter;
+ const char *err = NULL;
+
+ output_version();
+
+ /*
+ * If I understand things correctly, MP3 files don't really have any
+ * magic header we can check for. The MP3 player is expected to just
+ * pick the first thing that looks like a valid frame and start
+ * playing from there.
+ *
+ * So here's what we do: If the caller insists that this is really
+ * MP3 we'll take his word for it. Otherwise, use the same test as
+ * SDL_mixer does and check if the stream starts with something that
+ * looks like a frame.
+ *
+ * A frame begins with 11 bits of frame sync (all bits must be set),
+ * followed by a two-bit MPEG Audio version ID:
+ *
+ * 00 - MPEG Version 2.5 (later extension of MPEG 2)
+ * 01 - reserved
+ * 10 - MPEG Version 2 (ISO/IEC 13818-3)
+ * 11 - MPEG Version 1 (ISO/IEC 11172-3)
+ *
+ * Apparently we don't handle MPEG Version 2.5.
+ */
+ if (__Sound_strcasecmp(ext, "MP3") != 0)
+ {
+ Uint8 mp3_magic[2];
+
+ if (SDL_RWread(internal->rw, mp3_magic, sizeof (mp3_magic), 1) != 1)
+ BAIL_MACRO("SMPEG: Could not read MP3 magic.", 0);
+
+ if (mp3_magic[0] != 0xFF || (mp3_magic[1] & 0xF0) != 0xF0)
+ BAIL_MACRO("SMPEG: Not an MP3 stream.", 0);
+
+ /* If the seek fails, we'll probably miss a frame, but oh well */
+ SDL_RWseek(internal->rw, -sizeof (mp3_magic), SEEK_CUR);
+ } /* if */
+
+ refCounter = RWops_RWRefCounter_new(internal->rw);
+ if (refCounter == NULL)
+ {
+ SNDDBG(("SMPEG: Failed to create reference counting RWops.\n"));
+ return(0);
+ } /* if */
+
+ /* replace original RWops. This is safe. Honest. :) */
+ internal->rw = refCounter;
+
+ /*
+ * increment the refcount, since SMPEG will nuke the RWops if it can't
+ * accept the contained data...
+ */
+ RWops_RWRefCounter_addRef(refCounter);
+ smpeg = SMPEG_new_rwops(refCounter, &smpeg_info, 0);
+
+ err = SMPEG_error(smpeg);
+ if (err != NULL)
+ {
+ __Sound_SetError(err); /* make a copy before SMPEG_delete()... */
+ SMPEG_delete(smpeg);
+ return(0);
+ } /* if */
+
+ if (!smpeg_info.has_audio)
+ {
+ SMPEG_delete(smpeg);
+ BAIL_MACRO("SMPEG: No audio stream found in data.", 0);
+ } /* if */
+
+ SNDDBG(("SMPEG: Accepting data stream.\n"));
+ SNDDBG(("SMPEG: has_audio == {%s}.\n", smpeg_info.has_audio ? "TRUE" : "FALSE"));
+ SNDDBG(("SMPEG: has_video == {%s}.\n", smpeg_info.has_video ? "TRUE" : "FALSE"));
+ SNDDBG(("SMPEG: width == (%d).\n", smpeg_info.width));
+ SNDDBG(("SMPEG: height == (%d).\n", smpeg_info.height));
+ SNDDBG(("SMPEG: current_frame == (%d).\n", smpeg_info.current_frame));
+ SNDDBG(("SMPEG: current_fps == (%f).\n", smpeg_info.current_fps));
+ SNDDBG(("SMPEG: audio_string == [%s].\n", smpeg_info.audio_string));
+ SNDDBG(("SMPEG: audio_current_frame == (%d).\n", smpeg_info.audio_current_frame));
+ SNDDBG(("SMPEG: current_offset == (%d).\n", smpeg_info.current_offset));
+ SNDDBG(("SMPEG: total_size == (%d).\n", smpeg_info.total_size));
+ SNDDBG(("SMPEG: current_time == (%f).\n", smpeg_info.current_time));
+ SNDDBG(("SMPEG: total_time == (%f).\n", smpeg_info.total_time));
+
+ SMPEG_enablevideo(smpeg, 0);
+ SMPEG_enableaudio(smpeg, 1);
+ SMPEG_loop(smpeg, 0);
+
+ SMPEG_wantedSpec(smpeg, &spec);
+
+ /*
+ * One of the MP3s I tried wouldn't work unless I added this line
+ * to tell SMPEG that yes, it may have the spec it wants.
+ */
+ SMPEG_actualSpec(smpeg, &spec);
+ sample->actual.format = spec.format;
+ sample->actual.rate = spec.freq;
+ sample->actual.channels = spec.channels;
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+ internal->decoder_private = smpeg;
+
+ SMPEG_play(smpeg);
+ return(1);
+} /* _SMPEG_open */
+
+
+static void _SMPEG_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SMPEG_delete((SMPEG *) internal->decoder_private);
+} /* _SMPEG_close */
+
+
+static Uint32 _SMPEG_read(Sound_Sample *sample)
+{
+ Uint32 retval;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SMPEG *smpeg = (SMPEG *) internal->decoder_private;
+
+ /*
+ * We have to clear the buffer because apparently SMPEG_playAudio()
+ * will mix the decoded audio with whatever's already in it. Nasty.
+ */
+ memset(internal->buffer, '\0', internal->buffer_size);
+ retval = SMPEG_playAudio(smpeg, internal->buffer, internal->buffer_size);
+ if (retval < internal->buffer_size)
+ {
+ char *errMsg = SMPEG_error(smpeg);
+ if (errMsg == NULL)
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ else
+ {
+ __Sound_SetError(errMsg);
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ } /* else */
+ } /* if */
+
+ return(retval);
+} /* _SMPEG_read */
+
+
+static int _SMPEG_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SMPEG *smpeg = (SMPEG *) internal->decoder_private;
+ SMPEGstatus status;
+
+ /*
+ * SMPEG_rewind() really means "stop and rewind", so we may have to
+ * restart it afterwards.
+ */
+ status = SMPEG_status(smpeg);
+ SMPEG_rewind(smpeg);
+ /* EW: I think SMPEG_play() has an independent and unrelated meaning
+ * to the flag, "SMPEG_PLAYING". This is why the SMPEG_play() call
+ * is done in the open() function even though the file is not yet
+ * technically playing. I believe SMPEG_play() must always be active
+ * because this seems to be what's causing the:
+ * "Can't rewind after the file has finished playing once" problem,
+ * because always recalling it here seems to make the problem go away.
+ */
+ /*
+ if (status == SMPEG_PLAYING)
+ SMPEG_play(smpeg);
+ */
+ SMPEG_play(smpeg);
+ return(1);
+} /* _SMPEG_rewind */
+
+
+static int _SMPEG_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SMPEG *smpeg = (SMPEG *) internal->decoder_private;
+ SMPEGstatus status;
+
+ /*
+ * SMPEG_rewind() really means "stop and rewind", so we may have to
+ * restart it afterwards.
+ */
+ status = SMPEG_status(smpeg);
+ SMPEG_rewind(smpeg);
+ SMPEG_skip(smpeg, ((float) ms) / 1000.0);
+ if (status == SMPEG_PLAYING)
+ SMPEG_play(smpeg);
+ return(1);
+} /* _SMPEG_seek */
+
+#endif /* SOUND_SUPPORTS_SMPEG */
+
+/* end of smpeg.c ... */
+
diff --git a/util/sdl/sound/decoders/speex.c b/util/sdl/sound/decoders/speex.c
new file mode 100644
index 00000000..83a2bda3
--- /dev/null
+++ b/util/sdl/sound/decoders/speex.c
@@ -0,0 +1,436 @@
+/*
+ * 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
+ */
+
+/*
+ * Speex decoder for SDL_sound.
+ *
+ * This driver handles Speex audio data. Speex is a codec for speech that is
+ * meant to be transmitted over narrowband network connections. Epic Games
+ * estimates that their VoIP solution, built on top of Speex, uses around
+ * 500 bytes per second or less to transmit relatively good sounding speech.
+ *
+ * This decoder processes the .spx files that the speexenc program produces.
+ *
+ * Speex isn't meant for general audio compression. Something like Ogg Vorbis
+ * will give better results in that case.
+ *
+ * Further Speex information can be found at http://www.speex.org/
+ *
+ * This code is based on speexdec.c (see the Speex website).
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_SPEEX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <ogg/ogg.h>
+#include <speex/speex.h>
+#include <speex/speex_header.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int SPEEX_init(void);
+static void SPEEX_quit(void);
+static int SPEEX_open(Sound_Sample *sample, const char *ext);
+static void SPEEX_close(Sound_Sample *sample);
+static Uint32 SPEEX_read(Sound_Sample *sample);
+static int SPEEX_rewind(Sound_Sample *sample);
+static int SPEEX_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_speex[] = { "spx", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_SPEEX =
+{
+ {
+ extensions_speex,
+ "SPEEX speech compression format",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ SPEEX_init, /* init() method */
+ SPEEX_quit, /* quit() method */
+ SPEEX_open, /* open() method */
+ SPEEX_close, /* close() method */
+ SPEEX_read, /* read() method */
+ SPEEX_rewind, /* rewind() method */
+ SPEEX_seek /* seek() method */
+};
+
+#define SPEEX_USE_PERCEPTUAL_ENHANCER 1
+#define SPEEX_MAGIC 0x5367674F /* "OggS" in ASCII (littleendian) */
+#define SPEEX_OGG_BUFSIZE 200
+
+/* this is what we store in our internal->decoder_private field... */
+typedef struct
+{
+ ogg_sync_state oy;
+ ogg_page og;
+ ogg_packet op;
+ ogg_stream_state os;
+ void *state;
+ SpeexBits bits;
+ int header_count;
+ int frame_size;
+ int nframes;
+ int frames_avail;
+ float *decode_buf;
+ int decode_total;
+ int decode_pos;
+ int have_ogg_packet;
+} speex_t;
+
+
+static int SPEEX_init(void)
+{
+ return(1); /* no-op. */
+} /* SPEEX_init */
+
+
+static void SPEEX_quit(void)
+{
+ /* no-op. */
+} /* SPEEX_quit */
+
+
+static int process_header(speex_t *speex, Sound_Sample *sample)
+{
+ SpeexMode *mode;
+ SpeexHeader *hptr;
+ SpeexHeader header;
+ int enh_enabled = SPEEX_USE_PERCEPTUAL_ENHANCER;
+ int tmp;
+
+ hptr = speex_packet_to_header((char*) speex->op.packet, speex->op.bytes);
+ BAIL_IF_MACRO(!hptr, "SPEEX: Cannot read header", 0);
+ memcpy(&header, hptr, sizeof (SpeexHeader)); /* move to stack. */
+ free(hptr); /* lame that this forces you to malloc... */
+
+ BAIL_IF_MACRO(header.mode >= SPEEX_NB_MODES, "SPEEX: Unknown mode", 0);
+ BAIL_IF_MACRO(header.mode < 0, "SPEEX: Unknown mode", 0);
+ mode = speex_mode_list[header.mode];
+ BAIL_IF_MACRO(header.speex_version_id > 1, "SPEEX: Unknown version", 0);
+ BAIL_IF_MACRO(mode->bitstream_version < header.mode_bitstream_version,
+ "SPEEX: Unsupported bitstream version", 0);
+ BAIL_IF_MACRO(mode->bitstream_version > header.mode_bitstream_version,
+ "SPEEX: Unsupported bitstream version", 0);
+
+ speex->state = speex_decoder_init(mode);
+ BAIL_IF_MACRO(!speex->state, "SPEEX: Decoder initialization error", 0);
+
+ speex_decoder_ctl(speex->state, SPEEX_SET_ENH, &enh_enabled);
+ speex_decoder_ctl(speex->state, SPEEX_GET_FRAME_SIZE, &speex->frame_size);
+
+ speex->decode_buf = (float *) malloc(speex->frame_size * sizeof (float));
+ BAIL_IF_MACRO(!speex->decode_buf, ERR_OUT_OF_MEMORY, 0);
+
+ speex->nframes = header.frames_per_packet;
+ if (!speex->nframes)
+ speex->nframes = 1;
+
+ /* !!! FIXME: Write converters to match desired format.
+ !!! FIXME: We have to convert from Float32 anyhow. */
+ /* !!! FIXME: Is it a performance hit to alter sampling rate?
+ !!! FIXME: If not, try to match desired rate. */
+ /* !!! FIXME: We force mono output, but speexdec.c has code for stereo.
+ !!! FIXME: Use that if sample->desired.channels == 2? */
+ tmp = header.rate;
+ speex_decoder_ctl(speex->state, SPEEX_SET_SAMPLING_RATE, &tmp);
+ speex_decoder_ctl(speex->state, SPEEX_GET_SAMPLING_RATE, &tmp);
+ sample->actual.rate = tmp;
+ sample->actual.channels = 1;
+ sample->actual.format = AUDIO_S16SYS;
+
+ SNDDBG(("SPEEX: %dHz, mono, %svbr, %s mode.\n",
+ (int) sample->actual.rate,
+ header.vbr ? "" : "not ",
+ mode->modeName));
+
+ /* plus 2: one for this header, one for the comment header. */
+ speex->header_count = header.extra_headers + 2;
+ return(1);
+} /* process_header */
+
+
+/* !!! FIXME: this code sucks. */
+static int SPEEX_open(Sound_Sample *sample, const char *ext)
+{
+ int set_error_str = 1;
+ int bitstream_initialized = 0;
+ Uint8 *buffer = NULL;
+ int packet_count = 0;
+ speex_t *speex = NULL;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ Uint32 magic;
+
+ /* Quick rejection. */
+ /*
+ * !!! FIXME: If (ext) is .spx, ignore bad magic number and assume
+ * !!! FIXME: this is a corrupted file...try to sync up further in
+ * !!! FIXME: stream. But for general purposes we can't read the
+ * !!! FIXME: whole RWops here in case it's not a Speex file at all.
+ */
+ magic = SDL_ReadLE32(rw); /* make sure this is an ogg stream. */
+ BAIL_IF_MACRO(magic != SPEEX_MAGIC, "SPEEX: Not a complete ogg stream", 0);
+ BAIL_IF_MACRO(SDL_RWseek(rw, -4, SEEK_CUR) < 0, ERR_IO_ERROR, 0);
+
+ speex = (speex_t *) malloc(sizeof (speex_t));
+ BAIL_IF_MACRO(speex == NULL, ERR_OUT_OF_MEMORY, 0);
+ memset(speex, '\0', sizeof (speex_t));
+
+ speex_bits_init(&speex->bits);
+ if (ogg_sync_init(&speex->oy) != 0) goto speex_open_failed;
+
+ while (1)
+ {
+ int rc;
+ Uint8 *buffer = (Uint8*)ogg_sync_buffer(&speex->oy, SPEEX_OGG_BUFSIZE);
+ if (buffer == NULL) goto speex_open_failed;
+ rc = SDL_RWread(rw, buffer, 1, SPEEX_OGG_BUFSIZE);
+ if (rc <= 0) goto speex_open_failed;
+ if (ogg_sync_wrote(&speex->oy, rc) != 0) goto speex_open_failed;
+ while (ogg_sync_pageout(&speex->oy, &speex->og) == 1)
+ {
+ if (!bitstream_initialized)
+ {
+ if (ogg_stream_init(&speex->os, ogg_page_serialno(&speex->og)))
+ goto speex_open_failed;
+ bitstream_initialized = 1;
+ } /* if */
+
+ if (ogg_stream_pagein(&speex->os, &speex->og) != 0)
+ goto speex_open_failed;
+
+ while (ogg_stream_packetout(&speex->os, &speex->op) == 1)
+ {
+ if (speex->op.e_o_s)
+ goto speex_open_failed; /* end of stream already?! */
+
+ packet_count++;
+ if (packet_count == 1) /* need speex header. */
+ {
+ if (!process_header(speex, sample))
+ {
+ set_error_str = 0; /* process_header will set error string. */
+ goto speex_open_failed;
+ } /* if */
+ } /* if */
+
+ if (packet_count > speex->header_count)
+ {
+ /* if you made it here, you're ready to get a waveform. */
+ SNDDBG(("SPEEX: Accepting data stream.\n"));
+
+ /* sample->actual is configured in process_header()... */
+ speex->have_ogg_packet = 1;
+ sample->flags = SOUND_SAMPLEFLAG_NONE;
+ internal->decoder_private = speex;
+ return(1); /* we'll handle this data. */
+ } /* if */
+ } /* while */
+
+ } /* while */
+
+ } /* while */
+
+ assert(0); /* shouldn't hit this point. */
+
+speex_open_failed:
+ if (speex != NULL)
+ {
+ if (speex->state != NULL)
+ speex_decoder_destroy(speex->state);
+ if (bitstream_initialized)
+ ogg_stream_clear(&speex->os);
+ speex_bits_destroy(&speex->bits);
+ ogg_sync_clear(&speex->oy);
+ free(speex->decode_buf);
+ free(speex);
+ } /* if */
+
+ if (set_error_str)
+ BAIL_MACRO("SPEEX: decoding error", 0);
+
+ return(0);
+} /* SPEEX_open */
+
+
+static void SPEEX_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ speex_t *speex = (speex_t *) internal->decoder_private;
+ speex_decoder_destroy(speex->state);
+ ogg_stream_clear(&speex->os);
+ speex_bits_destroy(&speex->bits);
+ ogg_sync_clear(&speex->oy);
+ free(speex->decode_buf);
+ free(speex);
+} /* SPEEX_close */
+
+
+static Uint32 copy_from_decoded(speex_t *speex,
+ Sound_SampleInternal *internal,
+ Uint32 _cpypos)
+{
+ /*
+ * !!! FIXME: Obviously, this all needs to change if we allow for
+ * !!! FIXME: more than mono, S16SYS data.
+ */
+ Uint32 cpypos = _cpypos >> 1;
+ Sint16 *dst = ((Sint16 *) internal->buffer) + cpypos;
+ Sint16 *max;
+ Uint32 maxoutput = (internal->buffer_size >> 1) - cpypos;
+ Uint32 maxavail = speex->decode_total - speex->decode_pos;
+ float *src = speex->decode_buf + speex->decode_pos;
+
+ if (maxavail < maxoutput)
+ maxoutput = maxavail;
+
+ speex->decode_pos += maxoutput;
+ cpypos += maxoutput;
+
+ for (max = dst + maxoutput; dst < max; dst++, src++)
+ {
+ /* !!! FIXME: This screams for vectorization. */
+ register float f = *src;
+ if (f > 32000.0f) /* eh, speexdec.c clamps like this, too. */
+ f = 32000.0f;
+ else if (f < -32000.0f)
+ f = -32000.0f;
+ *dst = (Sint16) (0.5f + f);
+ } /* for */
+
+ return(cpypos << 1);
+} /* copy_from_decoded */
+
+
+/* !!! FIXME: this code sucks. */
+static Uint32 SPEEX_read(Sound_Sample *sample)
+{
+ Uint32 retval = 0;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ speex_t *speex = (speex_t *) internal->decoder_private;
+ SDL_RWops *rw = internal->rw;
+ Uint8 *buffer;
+ int rc;
+
+ while (1)
+ {
+ /* see if there's some already-decoded leftovers... */
+ if (speex->decode_total != speex->decode_pos)
+ {
+ retval = copy_from_decoded(speex, internal, retval);
+ if (retval >= internal->buffer_size)
+ return(retval); /* whee. */
+ } /* if */
+
+ /* okay, decoded buffer is spent. What else do we have? */
+ speex->decode_total = speex->decode_pos = 0;
+
+ if (speex->frames_avail) /* have more frames to decode? */
+ {
+ rc = speex_decode(speex->state, &speex->bits, speex->decode_buf);
+ if (rc < 0) goto speex_read_failed;
+ if (speex_bits_remaining(&speex->bits) < 0) goto speex_read_failed;
+ speex->frames_avail--;
+ speex->decode_total = speex->frame_size;
+ continue; /* go fill the output buffer... */
+ } /* if */
+
+ /* need to get more speex frames from available ogg packets... */
+ if (speex->have_ogg_packet)
+ {
+ speex_bits_read_from(&speex->bits,
+ (char *) speex->op.packet,
+ speex->op.bytes);
+
+ speex->frames_avail += speex->nframes;
+ if (ogg_stream_packetout(&speex->os, &speex->op) <= 0)
+ speex->have_ogg_packet = 0;
+ continue; /* go decode these frames. */
+ } /* if */
+
+ /* need to get more ogg packets from bitstream... */
+
+ if (speex->op.e_o_s) /* okay, we're really spent. */
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(retval);
+ } /* if */
+
+ while ((!speex->op.e_o_s) && (!speex->have_ogg_packet))
+ {
+ buffer = (Uint8 *) ogg_sync_buffer(&speex->oy, SPEEX_OGG_BUFSIZE);
+ if (buffer == NULL) goto speex_read_failed;
+ rc = SDL_RWread(rw, buffer, 1, SPEEX_OGG_BUFSIZE);
+ if (rc <= 0) goto speex_read_failed;
+ if (ogg_sync_wrote(&speex->oy, rc) != 0) goto speex_read_failed;
+
+ /* got complete ogg page? */
+ if (ogg_sync_pageout(&speex->oy, &speex->og) == 1)
+ {
+ if (ogg_stream_pagein(&speex->os, &speex->og) != 0)
+ goto speex_read_failed;
+
+ /* got complete ogg packet? */
+ if (ogg_stream_packetout(&speex->os, &speex->op) == 1)
+ speex->have_ogg_packet = 1;
+ } /* if */
+ } /* while */
+ } /* while */
+
+ assert(0); /* never hit this. Either return or goto speex_read_failed */
+
+speex_read_failed:
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ /* !!! FIXME: "i/o error" is better in some situations. */
+ BAIL_MACRO("SPEEX: Decoding error", retval);
+} /* SPEEX_read */
+
+
+static int SPEEX_rewind(Sound_Sample *sample)
+{
+ /* !!! FIXME */ return(0);
+} /* SPEEX_rewind */
+
+
+static int SPEEX_seek(Sound_Sample *sample, Uint32 ms)
+{
+ /* !!! FIXME */ return(0);
+} /* SPEEX_seek */
+
+
+#endif /* SOUND_SUPPORTS_SPEEX */
+
+/* end of speex.c ... */
+
diff --git a/util/sdl/sound/decoders/timidity/CHANGES b/util/sdl/sound/decoders/timidity/CHANGES
new file mode 100644
index 00000000..ab79e993
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/CHANGES
@@ -0,0 +1,77 @@
+This version of TiMidity should contain all the fixes from the
+September 25 2003 SDL_mixer CVS snapshot. In addition, I've made some
+changes of my own, e.g.:
+
+* All file access is done through SDL_RWops. This means the MIDI
+ stream no longer has to be a file. (The config file and instruments
+ still have to be though.)
+
+* Replacing of TiMidity's endian-handling with SDL's.
+
+* Removal of much unused or unnecessary code, such as
+
+ + The "hooks" for putting a user interface onto TiMidity.
+ + The antialias filter. It wasn't active, and even at 4 kHz I
+ couldn't hear any difference when activating it.
+ + Removed all traces of LOOKUP_HACK and LOOKUP_INTERPOLATION.
+ According to the code comments they weren't very good anyway.
+ ("degrades sound quality noticeably"). I also removed the
+ disclaimer about the "8-bit uLaw to 16-bit PCM and the 13-bit-PCM
+ to 8-bit uLaw tables" disclaimer, since I believe those were the
+ tables I removed.
+ + Removed LOOKUP_SINE since it was already commented out. I think we
+ can count on our target audience having math co-processors
+ nowadays.
+ + Removed USE_LDEXP since it wasn't being used and "it doesn't make
+ much of a difference either way".
+ + Removed decompress hack from open_file() since it didn't look very
+ portable.
+ + Removed heaps of unnecessary constants.
+ + Removed unused functions.
+ + Assume that LINEAR_INTERPOLATION is always used, so remove all
+ code dealing with it not being so. It's not that I think the
+ difference in audio quality is that great, but since it wouldn't
+ compile without code changes I assume no one's used it for quite
+ some time...
+ + Assume PRECALC_LOOPS is always defined. Judging by the comments it
+ may not make much of a difference either way, so why maintain two
+ versions of the same code?
+
+* Moving several static globals into the MidiSong struct. This
+ includes sample rate, formate, etc. which are now all per-song.
+
+* Moved some typedefs (e.g. MidiSong) to timidity.h for easy inclusion
+ into the MIDI decoder.
+
+* Added free_pathlist().
+
+* Replaced TiMidity's own 8, 16 and 32-bit types with SDL's.
+
+* Made TiMidity look for its configuration file in both /etc and
+ /usr/local/lib/timidity. (Windows version remains unchanged.)
+
+* Timidity_PlaySome() now takes three arguments. A MidiSong, a decode
+ buffer and decode buffer size in bytes. (MidiSong is a new argument,
+ and buffer size used to be in samples.)
+
+ In addition, it will return the number of bytes decoded.
+
+* Added Timidity_Exit().
+
+* Removed Timidity_Stop() and Timidity_Active(). Stopping playback
+ should be handled by SDL_sound, and Timidity_PlaySome() will return
+ 0 when the MIDI stream is finished.
+
+* Modified the ToneBank stuff to allow some data to be shared between
+ MidiSongs.
+
+* The following files have been removed: controls.c, controls.h,
+ filter.c, filter.h, sdl_a.c, sdl_c.c
+
+* config.h has been renamed as options.h to avoid confusion with the
+ automatically generated config.h for SDL_sound.
+
+* Added support for loading DLS format instruments:
+ Timidity_LoadDLS(), Timidity_FreeDLS(), Timidity_LoadDLSSong()
+
+* Added Timidity_Init_NoConfig()
diff --git a/util/sdl/sound/decoders/timidity/COPYING b/util/sdl/sound/decoders/timidity/COPYING
new file mode 100644
index 00000000..44bb52fb
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/COPYING
@@ -0,0 +1,519 @@
+Please note that the included source from Timidity, the MIDI decoder, is also
+ licensed under the following terms (GNU LGPL), but can also be used
+ separately under the GNU GPL, or the Perl Artistic License. Those licensing
+ terms are not reprinted here, but can be found on the web easily.
+
+If you want to use SDL_sound under a closed-source license, please contact
+ Ryan (icculus@icculus.org), and we can discuss an alternate license for
+ money to be distributed between the contributors to this work, but I'd
+ encourage you to abide by the LGPL, since the usual concern is whether you
+ can use this library without releasing your own source code (you can).
+
+
+-------------------
+
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/util/sdl/sound/decoders/timidity/FAQ b/util/sdl/sound/decoders/timidity/FAQ
new file mode 100644
index 00000000..1ee0b77b
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/FAQ
@@ -0,0 +1,100 @@
+---------------------------*-indented-text-*------------------------------
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+--------------------------------------------------------------------------
+
+ Frequently Asked Questions with answers:
+
+--------------------------------------------------------------------------
+Q: What is it?
+
+A: Where? Well Chris, TiMidity is a software-only synthesizer, MIDI
+ renderer, MIDI to WAVE converter, realtime MIDI player for UNIX machines,
+ even (I've heard) a Netscape helper application. It takes a MIDI file
+ and writes a WAVE or raw PCM data or plays it on your digital audio
+ device. It sounds much more realistic than FM synthesis, but you need a
+ ~100Mhz processor to listen to 32kHz stereo music in the background while
+ you work. 11kHz mono can be played on a low-end 486, and, to some, it
+ still sounds better than FM.
+
+--------------------------------------------------------------------------
+Q: I don't have a GUS, can I use TiMidity?
+
+A: Yes. That's the point. You don't need a Gravis Ultrasound to use
+ TiMidity, you just need GUS-compatible patches, which are freely
+ available on the Internet. See below for pointers.
+
+--------------------------------------------------------------------------
+Q: I have a GUS, can I use TiMidity?
+
+A: The DOS port doesn't have GUS support, and TiMidity won't be taking
+ advantage of the board's internal synthesizer under other operating
+ systems either. So it kind of defeats the purpose. But you can use it.
+
+--------------------------------------------------------------------------
+Q: I tried playing a MIDI file I got off the Net but all I got was a
+ dozen warnings saying "No instrument mapped to tone bank 0, program
+ xx - this instrument will not be heard". What's wrong?
+
+A: The General MIDI standard specifies 128 melodic instruments and
+ some sixty percussion sounds. If you wish to play arbitrary General
+ MIDI files, you'll need to get more patch files.
+
+ There's a program called Midia for SGI's, which also plays MIDI
+ files and has a lot more bells and whistles than TiMidity. It uses
+ GUS-compatible patches, too -- so you can get the 8 MB set at
+ ftp://archive.cs.umbc.edu/pub/midia for pretty good GM compatibility.
+
+ There are also many excellent patches on the Ultrasound FTP sites.
+ I can recommend Dustin McCartney's collections gsdrum*.zip and
+ wow*.zip in the "[.../]sound/patches/files" directory. The huge
+ ProPats series (pp3-*.zip) contains good patches as well. General
+ MIDI files can also be found on these sites.
+
+ This site list is from the GUS FAQ:
+
+> FTP Sites Archive Directories
+> --------- -------------------
+> Main N.American Site: archive.orst.edu pub/packages/gravis
+> wuarchive.wustl.edu systems/ibmpc/ultrasound
+> Main Asian Site: nctuccca.edu.tw PC/ultrasound
+> Main European Site: src.doc.ic.ac.uk packages/ultrasound
+> Main Australian Site: ftp.mpx.com.au /ultrasound/general
+> /ultrasound/submit
+> South African Site: ftp.sun.ac.za /pub/packages/ultrasound
+> Submissions: archive.epas.utoronto.ca pub/pc/ultrasound/submit
+> Newly Validated Files: archive.epas.utoronto.ca pub/pc/ultrasound
+>
+> Mirrors: garbo.uwasa.fi mirror/ultrasound
+> ftp.st.nepean.uws.edu.au pc/ultrasound
+> ftp.luth.se pub/msdos/ultrasound
+
+--------------------------------------------------------------------------
+Q: Some files have awful clicks and pops.
+
+A: Find out which patch is responsible for the clicking (try "timidity
+ -P<patch> <midi/test-decay|midi/test-panning>". Add "strip=tail" in
+ the config file after its name. If this doesn't fix it, mail me the
+ patch.
+
+--------------------------------------------------------------------------
+Q: I'm playing Fantasie Impromptu in the background. When I run Netscape,
+ the sound gets choppy and it takes ten minutes to load. What can I do?
+
+A: Here are some things to try:
+
+ - Use a lower sampling rate.
+
+ - Use mono output. This can improve performance by 10-30%.
+ (Using 8-bit instead of 16-bit output makes no difference.)
+
+ - Use a smaller number of simultaneous voices.
+
+ - Make sure you compiled with FAST_DECAY enabled in options.h
+
+ - Recompile with an Intel-optimized gcc for a 5-15%
+ performance increase.
+
+--------------------------------------------------------------------------
diff --git a/util/sdl/sound/decoders/timidity/Makefile.am b/util/sdl/sound/decoders/timidity/Makefile.am
new file mode 100644
index 00000000..7c64b933
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/Makefile.am
@@ -0,0 +1,33 @@
+if USE_TIMIDITY
+noinst_LTLIBRARIES = libtimidity.la
+endif
+
+INCLUDES = -I$(top_srcdir)
+
+libtimidity_la_SOURCES = \
+ common.c \
+ common.h \
+ dls1.h \
+ dls2.h \
+ instrum.c \
+ instrum.h \
+ instrum_dls.c \
+ instrum_dls.h \
+ mix.c \
+ mix.h \
+ options.h \
+ output.c \
+ output.h \
+ playmidi.c \
+ playmidi.h \
+ readmidi.c \
+ readmidi.h \
+ resample.c \
+ resample.h \
+ tables.c \
+ tables.h \
+ timidity.c \
+ timidity.h
+
+EXTRA_DIST = CHANGES COPYING FAQ README TODO Makefile.testmidi testmidi.c
+
diff --git a/util/sdl/sound/decoders/timidity/Makefile.in b/util/sdl/sound/decoders/timidity/Makefile.in
new file mode 100644
index 00000000..03b1e427
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/Makefile.in
@@ -0,0 +1,487 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = decoders/timidity
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ COPYING TODO
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libtimidity_la_LIBADD =
+am_libtimidity_la_OBJECTS = common.lo instrum.lo instrum_dls.lo mix.lo \
+ output.lo playmidi.lo readmidi.lo resample.lo tables.lo \
+ timidity.lo
+libtimidity_la_OBJECTS = $(am_libtimidity_la_OBJECTS)
+@USE_TIMIDITY_TRUE@am_libtimidity_la_rpath =
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libtimidity_la_SOURCES)
+DIST_SOURCES = $(libtimidity_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERFACE_AGE = @INTERFACE_AGE@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_MPGLIB_FALSE = @USE_MPGLIB_FALSE@
+USE_MPGLIB_TRUE = @USE_MPGLIB_TRUE@
+USE_PHYSICSFS_FALSE = @USE_PHYSICSFS_FALSE@
+USE_PHYSICSFS_TRUE = @USE_PHYSICSFS_TRUE@
+USE_TIMIDITY_FALSE = @USE_TIMIDITY_FALSE@
+USE_TIMIDITY_TRUE = @USE_TIMIDITY_TRUE@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+@USE_TIMIDITY_TRUE@noinst_LTLIBRARIES = libtimidity.la
+INCLUDES = -I$(top_srcdir)
+libtimidity_la_SOURCES = \
+ common.c \
+ common.h \
+ dls1.h \
+ dls2.h \
+ instrum.c \
+ instrum.h \
+ instrum_dls.c \
+ instrum_dls.h \
+ mix.c \
+ mix.h \
+ options.h \
+ output.c \
+ output.h \
+ playmidi.c \
+ playmidi.h \
+ readmidi.c \
+ readmidi.h \
+ resample.c \
+ resample.h \
+ tables.c \
+ tables.h \
+ timidity.c \
+ timidity.h
+
+EXTRA_DIST = CHANGES COPYING FAQ README TODO Makefile.testmidi testmidi.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign decoders/timidity/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign decoders/timidity/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libtimidity.la: $(libtimidity_la_OBJECTS) $(libtimidity_la_DEPENDENCIES)
+ $(LINK) $(am_libtimidity_la_rpath) $(libtimidity_la_LDFLAGS) $(libtimidity_la_OBJECTS) $(libtimidity_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instrum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/instrum_dls.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playmidi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readmidi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resample.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timidity.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/sdl/sound/decoders/timidity/Makefile.testmidi b/util/sdl/sound/decoders/timidity/Makefile.testmidi
new file mode 100644
index 00000000..8f03fdab
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/Makefile.testmidi
@@ -0,0 +1,38 @@
+# Silly test makefile
+
+CC = gcc
+
+# Standard SDL_sound debugging
+CFLAGS = -g -I../.. -ansi -pedantic -Wall `sdl-config --cflags` -DDEBUG_CHATTER
+LIBS = `sdl-config --libs`
+
+# Electric Fence debugging
+# CFLAGS = -g -I../.. -ansi -pedantic -Wall `sdl-config --cflags`
+# LIBS = `sdl-config --libs` -lefence
+
+OBJECTS = common.o instrum.o mix.o output.o playmidi.o readmidi.o resample.o \
+ tables.o timidity.o testmidi.o
+
+all: testmidi
+
+testmidi: $(OBJECTS)
+ $(CC) $(OBJECTS) $(CFLAGS) -o testmidi $(LIBS)
+
+clean:
+ $(RM) testmidi *.o *~
+
+common.o: common.c options.h common.h
+instrum.o: instrum.c timidity.h options.h common.h instrum.h resample.h \
+ tables.h
+mix.o: mix.c timidity.h options.h instrum.h playmidi.h output.h tables.h \
+ resample.h mix.h
+output.o: output.c options.h output.h
+playmidi.o: playmidi.c timidity.h options.h instrum.h playmidi.h output.h \
+ mix.h tables.h
+readmidi.o: readmidi.c timidity.h common.h instrum.h playmidi.h
+resample.o: resample.c timidity.h options.h common.h instrum.h playmidi.h \
+ tables.h resample.h
+tables.o: tables.c tables.h
+testmidi.o: testmidi.c common.h timidity.h
+timidity.o: timidity.c options.h common.h instrum.h playmidi.h readmidi.h \
+ output.h timidity.h tables.h
diff --git a/util/sdl/sound/decoders/timidity/README b/util/sdl/sound/decoders/timidity/README
new file mode 100644
index 00000000..9c9c55aa
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/README
@@ -0,0 +1,61 @@
+[This version of timidity has been stripped for simplicity in porting to SDL,
+and then even further for SDL_sound]
+---------------------------------*-text-*---------------------------------
+
+ From http://www.cgs.fi/~tt/discontinued.html :
+
+ If you'd like to continue hacking on TiMidity, feel free. I'm
+ hereby extending the TiMidity license agreement: you can now
+ select the most convenient license for your needs from (1) the
+ GNU GPL, (2) the GNU LGPL, or (3) the Perl Artistic License.
+
+--------------------------------------------------------------------------
+
+ This is the README file for TiMidity v0.2i
+
+ TiMidity is a MIDI to WAVE converter that uses Gravis
+Ultrasound(*)-compatible patch files to generate digital audio data
+from General MIDI files. The audio data can be played through any
+sound device or stored on disk. On a fast machine, music can be
+played in real time. TiMidity runs under Linux, FreeBSD, HP-UX, SunOS, and
+Win32, and porting to other systems with gcc should be easy.
+
+ TiMidity Features:
+
+ * 32 or more dynamically allocated fully independent voices
+ * Compatibility with GUS patch files
+ * Output to 16- or 8-bit PCM or uLaw audio device, file, or
+ stdout at any sampling rate
+ * Optional interactive mode with real-time status display
+ under ncurses and SLang terminal control libraries. Also
+ a user friendly motif interface since version 0.2h
+ * Support for transparent loading of compressed MIDI files and
+ patch files
+
+ * Support for the following MIDI events:
+ - Program change
+ - Key pressure
+ - Channel main volume
+ - Tempo
+ - Panning
+ - Damper pedal (Sustain)
+ - Pitch wheel
+ - Pitch wheel sensitivity
+ - Change drum set
+
+* The GNU General Public License can, as always, be found in the file
+ "../COPYING".
+
+* TiMidity requires sampled instruments (patches) to play MIDI files. You
+ should get the file "timidity-lib-0.1.tar.gz" and unpack it in the same
+ directory where you unpacked the source code archive. You'll want more
+ patches later -- read the file "FAQ" for pointers.
+
+* Timidity is no longer supported, but can be found by searching the web.
+
+
+ Tuukka Toivonen <toivonen@clinet.fi>
+
+[(*) Any Registered Trademarks used anywhere in the documentation or
+source code for TiMidity are acknowledged as belonging to their
+respective owners.]
diff --git a/util/sdl/sound/decoders/timidity/TODO b/util/sdl/sound/decoders/timidity/TODO
new file mode 100644
index 00000000..69b37ee2
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/TODO
@@ -0,0 +1,37 @@
+* I don't like the indentation style at all, but for the most part
+ I've left it alone.
+
+* Much of the code looks ugly to me.
+
+* The return value from SDL_RWread() is checked inconsistenly.
+
+* Group the members of MidiSong into logical units, i.e. structs?
+
+* The debug messages are probably a bit too noisy. I've removed one
+ particularly annoying one, but...
+
+ Some of them should be turned into error messages instead.
+
+* Can the instrument handling be made more efficient? At the moment
+ different MidiSongs may separately load the same instrument.
+
+ Note that the MidiSong's audio format affects how the instrument is
+ loaded, so it's not as easy as just letting all MidiSongs share tone
+ and drum banks.
+
+ At the moment they do share the data that is simply read from the
+ config file, but that's just a quick hack to avoid having to read
+ the config file every time a MIDI song is loaded.
+
+* Check if any of MidiStruct's members can safely be made into static
+ globals again.
+
+* TiMidity++ adds a number of undocumented (?) extensions to the
+ configuration syntax. These are not implemented here. In particular,
+ the "map" keyword used by the "eawpats".
+
+* The other decoders generally only read as much of the file as is
+ necessary. Could we do that in this decoder as well? (Currently it
+ seems to convert the entire file into MIDI events first.)
+
+* Can it be optimized?
diff --git a/util/sdl/sound/decoders/timidity/common.c b/util/sdl/sound/decoders/timidity/common.c
new file mode 100644
index 00000000..81735d65
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/common.c
@@ -0,0 +1,137 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ common.c
+
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "options.h"
+#include "common.h"
+
+/* The paths in this list will be tried whenever we're reading a file */
+static PathList *pathlist = NULL; /* This is a linked list */
+
+/* This is meant to find and open files for reading */
+SDL_RWops *open_file(char *name)
+{
+ SDL_RWops *rw;
+
+ if (!name || !(*name))
+ {
+ SNDDBG(("Attempted to open nameless file.\n"));
+ return 0;
+ }
+
+ /* First try the given name */
+
+ SNDDBG(("Trying to open %s\n", name));
+ if ((rw = SDL_RWFromFile(name, "rb")))
+ return rw;
+
+ if (name[0] != PATH_SEP)
+ {
+ char current_filename[1024];
+ PathList *plp = pathlist;
+ int l;
+
+ while (plp) /* Try along the path then */
+ {
+ *current_filename = 0;
+ l = strlen(plp->path);
+ if(l)
+ {
+ strcpy(current_filename, plp->path);
+ if(current_filename[l - 1] != PATH_SEP)
+ {
+ current_filename[l] = PATH_SEP;
+ current_filename[l + 1] = '\0';
+ }
+ }
+ strcat(current_filename, name);
+ SNDDBG(("Trying to open %s\n", current_filename));
+ if ((rw = SDL_RWFromFile(current_filename, "rb")))
+ return rw;
+ plp = plp->next;
+ }
+ }
+
+ /* Nothing could be opened. */
+ SNDDBG(("Could not open %s\n", name));
+ return 0;
+}
+
+/* This'll allocate memory or die. */
+void *safe_malloc(size_t count)
+{
+ void *p;
+
+ p = malloc(count);
+ if (p == NULL)
+ SNDDBG(("Sorry. Couldn't malloc %d bytes.\n", count));
+
+ return p;
+}
+
+/* This adds a directory to the path list */
+void add_to_pathlist(char *s)
+{
+ PathList *plp = safe_malloc(sizeof(PathList));
+
+ if (plp == NULL)
+ return;
+
+ plp->path = safe_malloc(strlen(s) + 1);
+ if (plp->path == NULL)
+ {
+ free(plp);
+ return;
+ }
+
+ strcpy(plp->path, s);
+ plp->next = pathlist;
+ pathlist = plp;
+}
+
+void free_pathlist(void)
+{
+ PathList *plp = pathlist;
+ PathList *next;
+
+ while (plp)
+ {
+ next = plp->next;
+ free(plp->path);
+ free(plp);
+ plp = next;
+ }
+ pathlist = NULL;
+}
diff --git a/util/sdl/sound/decoders/timidity/common.h b/util/sdl/sound/decoders/timidity/common.h
new file mode 100644
index 00000000..fbcce9b6
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/common.h
@@ -0,0 +1,32 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+ common.h
+*/
+
+typedef struct {
+ char *path;
+ void *next;
+} PathList;
+
+extern SDL_RWops *open_file(char *name);
+extern void add_to_pathlist(char *s);
+extern void *safe_malloc(size_t count);
+extern void free_pathlist(void);
diff --git a/util/sdl/sound/decoders/timidity/dls1.h b/util/sdl/sound/decoders/timidity/dls1.h
new file mode 100644
index 00000000..abc2075a
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/dls1.h
@@ -0,0 +1,266 @@
+/*==========================================================================;
+//
+// dls1.h
+//
+//
+// Description:
+//
+// Interface defines and structures for the Instrument Collection Form
+// RIFF DLS.
+//
+//
+// Written by Sonic Foundry 1996. Released for public use.
+//
+//=========================================================================*/
+
+#ifndef _INC_DLS1
+#define _INC_DLS1
+
+/*//////////////////////////////////////////////////////////////////////////
+//
+//
+// Layout of an instrument collection:
+//
+//
+// RIFF [] 'DLS ' [dlid,colh,INSTLIST,WAVEPOOL,INFOLIST]
+//
+// INSTLIST
+// LIST [] 'lins'
+// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST]
+// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST]
+// LIST [] 'ins ' [dlid,insh,RGNLIST,ARTLIST,INFOLIST]
+//
+// RGNLIST
+// LIST [] 'lrgn'
+// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST]
+// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST]
+// LIST [] 'rgn ' [rgnh,wsmp,wlnk,ARTLIST]
+//
+// ARTLIST
+// LIST [] 'lart'
+// 'art1' level 1 Articulation connection graph
+// 'art2' level 2 Articulation connection graph
+// '3rd1' Possible 3rd party articulation structure 1
+// '3rd2' Possible 3rd party articulation structure 2 .... and so on
+//
+// WAVEPOOL
+// ptbl [] [pool table]
+// LIST [] 'wvpl'
+// [path],
+// [path],
+// LIST [] 'wave' [dlid,RIFFWAVE]
+// LIST [] 'wave' [dlid,RIFFWAVE]
+// LIST [] 'wave' [dlid,RIFFWAVE]
+// LIST [] 'wave' [dlid,RIFFWAVE]
+// LIST [] 'wave' [dlid,RIFFWAVE]
+//
+// INFOLIST
+// LIST [] 'INFO'
+// 'icmt' 'One of those crazy comments.'
+// 'icop' 'Copyright (C) 1996 Sonic Foundry'
+//
+/////////////////////////////////////////////////////////////////////////*/
+
+
+/*/////////////////////////////////////////////////////////////////////////
+// FOURCC's used in the DLS file
+/////////////////////////////////////////////////////////////////////////*/
+
+#define FOURCC_DLS mmioFOURCC('D','L','S',' ')
+#define FOURCC_DLID mmioFOURCC('d','l','i','d')
+#define FOURCC_COLH mmioFOURCC('c','o','l','h')
+#define FOURCC_WVPL mmioFOURCC('w','v','p','l')
+#define FOURCC_PTBL mmioFOURCC('p','t','b','l')
+#define FOURCC_PATH mmioFOURCC('p','a','t','h')
+#define FOURCC_wave mmioFOURCC('w','a','v','e')
+#define FOURCC_LINS mmioFOURCC('l','i','n','s')
+#define FOURCC_INS mmioFOURCC('i','n','s',' ')
+#define FOURCC_INSH mmioFOURCC('i','n','s','h')
+#define FOURCC_LRGN mmioFOURCC('l','r','g','n')
+#define FOURCC_RGN mmioFOURCC('r','g','n',' ')
+#define FOURCC_RGNH mmioFOURCC('r','g','n','h')
+#define FOURCC_LART mmioFOURCC('l','a','r','t')
+#define FOURCC_ART1 mmioFOURCC('a','r','t','1')
+#define FOURCC_WLNK mmioFOURCC('w','l','n','k')
+#define FOURCC_WSMP mmioFOURCC('w','s','m','p')
+#define FOURCC_VERS mmioFOURCC('v','e','r','s')
+
+/*/////////////////////////////////////////////////////////////////////////
+// Articulation connection graph definitions
+/////////////////////////////////////////////////////////////////////////*/
+
+/* Generic Sources */
+#define CONN_SRC_NONE 0x0000
+#define CONN_SRC_LFO 0x0001
+#define CONN_SRC_KEYONVELOCITY 0x0002
+#define CONN_SRC_KEYNUMBER 0x0003
+#define CONN_SRC_EG1 0x0004
+#define CONN_SRC_EG2 0x0005
+#define CONN_SRC_PITCHWHEEL 0x0006
+
+/* Midi Controllers 0-127 */
+#define CONN_SRC_CC1 0x0081
+#define CONN_SRC_CC7 0x0087
+#define CONN_SRC_CC10 0x008a
+#define CONN_SRC_CC11 0x008b
+
+/* Generic Destinations */
+#define CONN_DST_NONE 0x0000
+#define CONN_DST_ATTENUATION 0x0001
+#define CONN_DST_PITCH 0x0003
+#define CONN_DST_PAN 0x0004
+
+/* LFO Destinations */
+#define CONN_DST_LFO_FREQUENCY 0x0104
+#define CONN_DST_LFO_STARTDELAY 0x0105
+
+/* EG1 Destinations */
+#define CONN_DST_EG1_ATTACKTIME 0x0206
+#define CONN_DST_EG1_DECAYTIME 0x0207
+#define CONN_DST_EG1_RELEASETIME 0x0209
+#define CONN_DST_EG1_SUSTAINLEVEL 0x020a
+
+/* EG2 Destinations */
+#define CONN_DST_EG2_ATTACKTIME 0x030a
+#define CONN_DST_EG2_DECAYTIME 0x030b
+#define CONN_DST_EG2_RELEASETIME 0x030d
+#define CONN_DST_EG2_SUSTAINLEVEL 0x030e
+
+#define CONN_TRN_NONE 0x0000
+#define CONN_TRN_CONCAVE 0x0001
+
+typedef struct _DLSID {
+ ULONG ulData1;
+ USHORT usData2;
+ USHORT usData3;
+ BYTE abData4[8];
+} DLSID, FAR *LPDLSID;
+
+typedef struct _DLSVERSION {
+ DWORD dwVersionMS;
+ DWORD dwVersionLS;
+} DLSVERSION, FAR *LPDLSVERSION;
+
+
+typedef struct _CONNECTION {
+ USHORT usSource;
+ USHORT usControl;
+ USHORT usDestination;
+ USHORT usTransform;
+ LONG lScale;
+} CONNECTION, FAR *LPCONNECTION;
+
+
+/* Level 1 Articulation Data */
+
+typedef struct _CONNECTIONLIST {
+ ULONG cbSize; /* size of the connection list structure */
+ ULONG cConnections; /* count of connections in the list */
+} CONNECTIONLIST, FAR *LPCONNECTIONLIST;
+
+
+
+/*/////////////////////////////////////////////////////////////////////////
+// Generic type defines for regions and instruments
+/////////////////////////////////////////////////////////////////////////*/
+
+typedef struct _RGNRANGE {
+ USHORT usLow;
+ USHORT usHigh;
+} RGNRANGE, FAR * LPRGNRANGE;
+
+#define F_INSTRUMENT_DRUMS 0x80000000
+
+typedef struct _MIDILOCALE {
+ ULONG ulBank;
+ ULONG ulInstrument;
+} MIDILOCALE, FAR *LPMIDILOCALE;
+
+/*/////////////////////////////////////////////////////////////////////////
+// Header structures found in an DLS file for collection, instruments, and
+// regions.
+/////////////////////////////////////////////////////////////////////////*/
+
+#define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001
+
+typedef struct _RGNHEADER {
+ RGNRANGE RangeKey; /* Key range */
+ RGNRANGE RangeVelocity; /* Velocity Range */
+ USHORT fusOptions; /* Synthesis options for this range */
+ USHORT usKeyGroup; /* Key grouping for non simultaneous play */
+ /* 0 = no group, 1 up is group */
+ /* for Level 1 only groups 1-15 are allowed */
+} RGNHEADER, FAR *LPRGNHEADER;
+
+typedef struct _INSTHEADER {
+ ULONG cRegions; /* Count of regions in this instrument */
+ MIDILOCALE Locale; /* Intended MIDI locale of this instrument */
+} INSTHEADER, FAR *LPINSTHEADER;
+
+typedef struct _DLSHEADER {
+ ULONG cInstruments; /* Count of instruments in the collection */
+} DLSHEADER, FAR *LPDLSHEADER;
+
+/*////////////////////////////////////////////////////////////////////////////
+// definitions for the Wave link structure
+////////////////////////////////////////////////////////////////////////////*/
+
+/* **** For level 1 only WAVELINK_CHANNEL_MONO is valid **** */
+/* ulChannel allows for up to 32 channels of audio with each bit position */
+/* specifiying a channel of playback */
+
+#define WAVELINK_CHANNEL_LEFT 0x0001l
+#define WAVELINK_CHANNEL_RIGHT 0x0002l
+
+#define F_WAVELINK_PHASE_MASTER 0x0001
+
+typedef struct _WAVELINK { /* any paths or links are stored right after struct */
+ USHORT fusOptions; /* options flags for this wave */
+ USHORT usPhaseGroup; /* Phase grouping for locking channels */
+ ULONG ulChannel; /* channel placement */
+ ULONG ulTableIndex; /* index into the wave pool table, 0 based */
+} WAVELINK, FAR *LPWAVELINK;
+
+#define POOL_CUE_NULL 0xffffffffl
+
+typedef struct _POOLCUE {
+ ULONG ulOffset; /* Offset to the entry in the list */
+} POOLCUE, FAR *LPPOOLCUE;
+
+typedef struct _POOLTABLE {
+ ULONG cbSize; /* size of the pool table structure */
+ ULONG cCues; /* count of cues in the list */
+} POOLTABLE, FAR *LPPOOLTABLE;
+
+/*////////////////////////////////////////////////////////////////////////////
+// Structures for the "wsmp" chunk
+////////////////////////////////////////////////////////////////////////////*/
+
+#define F_WSMP_NO_TRUNCATION 0x0001l
+#define F_WSMP_NO_COMPRESSION 0x0002l
+
+
+typedef struct _rwsmp {
+ ULONG cbSize;
+ USHORT usUnityNote; /* MIDI Unity Playback Note */
+ SHORT sFineTune; /* Fine Tune in log tuning */
+ LONG lAttenuation; /* Overall Attenuation to be applied to data */
+ ULONG fulOptions; /* Flag options */
+ ULONG cSampleLoops; /* Count of Sample loops, 0 loops is one shot */
+} WSMPL, FAR *LPWSMPL;
+
+
+/* This loop type is a normal forward playing loop which is continually */
+/* played until the envelope reaches an off threshold in the release */
+/* portion of the volume envelope */
+
+#define WLOOP_TYPE_FORWARD 0
+
+typedef struct _rloop {
+ ULONG cbSize;
+ ULONG ulType; /* Loop Type */
+ ULONG ulStart; /* Start of loop in samples */
+ ULONG ulLength; /* Length of loop in samples */
+} WLOOP, FAR *LPWLOOP;
+
+#endif /*_INC_DLS1 */
diff --git a/util/sdl/sound/decoders/timidity/dls2.h b/util/sdl/sound/decoders/timidity/dls2.h
new file mode 100644
index 00000000..30cec23a
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/dls2.h
@@ -0,0 +1,130 @@
+/*
+
+ dls2.h
+
+ Description:
+
+ Interface defines and structures for the DLS2 extensions of DLS.
+
+
+ Written by Microsoft 1998. Released for public use.
+
+*/
+
+#ifndef _INC_DLS2
+#define _INC_DLS2
+
+/*
+ FOURCC's used in the DLS2 file, in addition to DLS1 chunks
+*/
+
+#define FOURCC_RGN2 mmioFOURCC('r','g','n','2')
+#define FOURCC_LAR2 mmioFOURCC('l','a','r','2')
+#define FOURCC_ART2 mmioFOURCC('a','r','t','2')
+#define FOURCC_CDL mmioFOURCC('c','d','l',' ')
+#define FOURCC_DLID mmioFOURCC('d','l','i','d')
+
+/*
+ Articulation connection graph definitions. These are in addition to
+ the definitions in the DLS1 header.
+*/
+
+/* Generic Sources (in addition to DLS1 sources. */
+#define CONN_SRC_POLYPRESSURE 0x0007 /* Polyphonic Pressure */
+#define CONN_SRC_CHANNELPRESSURE 0x0008 /* Channel Pressure */
+#define CONN_SRC_VIBRATO 0x0009 /* Vibrato LFO */
+#define CONN_SRC_MONOPRESSURE 0x000a /* MIDI Mono pressure */
+
+
+/* Midi Controllers */
+#define CONN_SRC_CC91 0x00db /* Reverb Send */
+#define CONN_SRC_CC93 0x00dd /* Chorus Send */
+
+
+/* Generic Destinations */
+#define CONN_DST_GAIN 0x0001 /* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */
+#define CONN_DST_KEYNUMBER 0x0005 /* Key Number Generator */
+
+/* Audio Channel Output Destinations */
+#define CONN_DST_LEFT 0x0010 /* Left Channel Send */
+#define CONN_DST_RIGHT 0x0011 /* Right Channel Send */
+#define CONN_DST_CENTER 0x0012 /* Center Channel Send */
+#define CONN_DST_LEFTREAR 0x0013 /* Left Rear Channel Send */
+#define CONN_DST_RIGHTREAR 0x0014 /* Right Rear Channel Send */
+#define CONN_DST_LFE_CHANNEL 0x0015 /* LFE Channel Send */
+#define CONN_DST_CHORUS 0x0080 /* Chorus Send */
+#define CONN_DST_REVERB 0x0081 /* Reverb Send */
+
+/* Vibrato LFO Destinations */
+#define CONN_DST_VIB_FREQUENCY 0x0114 /* Vibrato Frequency */
+#define CONN_DST_VIB_STARTDELAY 0x0115 /* Vibrato Start Delay */
+
+/* EG1 Destinations */
+#define CONN_DST_EG1_DELAYTIME 0x020B /* EG1 Delay Time */
+#define CONN_DST_EG1_HOLDTIME 0x020C /* EG1 Hold Time */
+#define CONN_DST_EG1_SHUTDOWNTIME 0x020D /* EG1 Shutdown Time */
+
+
+/* EG2 Destinations */
+#define CONN_DST_EG2_DELAYTIME 0x030F /* EG2 Delay Time */
+#define CONN_DST_EG2_HOLDTIME 0x0310 /* EG2 Hold Time */
+
+
+/* Filter Destinations */
+#define CONN_DST_FILTER_CUTOFF 0x0500 /* Filter Cutoff Frequency */
+#define CONN_DST_FILTER_Q 0x0501 /* Filter Resonance */
+
+
+/* Transforms */
+#define CONN_TRN_CONVEX 0x0002 /* Convex Transform */
+#define CONN_TRN_SWITCH 0x0003 /* Switch Transform */
+
+
+/* Conditional chunk operators */
+ #define DLS_CDL_AND 0x0001 /* X = X & Y */
+ #define DLS_CDL_OR 0x0002 /* X = X | Y */
+ #define DLS_CDL_XOR 0x0003 /* X = X ^ Y */
+ #define DLS_CDL_ADD 0x0004 /* X = X + Y */
+ #define DLS_CDL_SUBTRACT 0x0005 /* X = X - Y */
+ #define DLS_CDL_MULTIPLY 0x0006 /* X = X * Y */
+ #define DLS_CDL_DIVIDE 0x0007 /* X = X / Y */
+ #define DLS_CDL_LOGICAL_AND 0x0008 /* X = X && Y */
+ #define DLS_CDL_LOGICAL_OR 0x0009 /* X = X || Y */
+ #define DLS_CDL_LT 0x000A /* X = (X < Y) */
+ #define DLS_CDL_LE 0x000B /* X = (X <= Y) */
+ #define DLS_CDL_GT 0x000C /* X = (X > Y) */
+ #define DLS_CDL_GE 0x000D /* X = (X >= Y) */
+ #define DLS_CDL_EQ 0x000E /* X = (X == Y) */
+ #define DLS_CDL_NOT 0x000F /* X = !X */
+ #define DLS_CDL_CONST 0x0010 /* 32-bit constant */
+ #define DLS_CDL_QUERY 0x0011 /* 32-bit value returned from query */
+ #define DLS_CDL_QUERYSUPPORTED 0x0012 /* Test to see if query is supported by synth */
+
+/*
+ Loop and release
+*/
+
+#define WLOOP_TYPE_RELEASE 1
+
+/*
+ WaveLink chunk <wlnk-ck>
+*/
+
+#define F_WAVELINK_MULTICHANNEL 0x0002
+
+
+/*
+ DLSID queries for <cdl-ck>
+*/
+
+DEFINE_GUID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
+DEFINE_GUID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
+DEFINE_GUID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+DEFINE_GUID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+DEFINE_GUID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
+
+#endif /* _INC_DLS2 */
diff --git a/util/sdl/sound/decoders/timidity/instrum.c b/util/sdl/sound/decoders/timidity/instrum.c
new file mode 100644
index 00000000..e46ecd96
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/instrum.c
@@ -0,0 +1,623 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ instrum.c
+
+ Code to load and unload GUS-compatible instrument patches.
+
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "instrum_dls.h"
+#include "resample.h"
+#include "tables.h"
+
+static void free_instrument(Instrument *ip)
+{
+ Sample *sp;
+ int i;
+ if (!ip) return;
+ for (i=0; i<ip->samples; i++)
+ {
+ sp=&(ip->sample[i]);
+ free(sp->data);
+ }
+ free(ip->sample);
+ free(ip);
+}
+
+static void free_bank(MidiSong *song, int dr, int b)
+{
+ int i;
+ ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]);
+ for (i=0; i<128; i++)
+ if (bank->instrument[i])
+ {
+ /* Not that this could ever happen, of course */
+ if (bank->instrument[i] != MAGIC_LOAD_INSTRUMENT)
+ free_instrument(bank->instrument[i]);
+ bank->instrument[i]=0;
+ }
+}
+
+static Sint32 convert_envelope_rate(MidiSong *song, Uint8 rate)
+{
+ Sint32 r;
+
+ r = 3 - ((rate >> 6) & 0x3);
+ r *= 3;
+ r = (Sint32) (rate & 0x3f) << r; /* 6.9 fixed point */
+
+ /* 15.15 fixed point. */
+ r = ((r * 44100) / song->rate) * song->control_ratio;
+
+#ifdef FAST_DECAY
+ return r << 10;
+#else
+ return r << 9;
+#endif
+}
+
+static Sint32 convert_envelope_offset(Uint8 offset)
+{
+ /* This is not too good... Can anyone tell me what these values mean?
+ Are they GUS-style "exponential" volumes? And what does that mean? */
+
+ /* 15.15 fixed point */
+ return offset << (7+15);
+}
+
+static Sint32 convert_tremolo_sweep(MidiSong *song, Uint8 sweep)
+{
+ if (!sweep)
+ return 0;
+
+ return
+ ((song->control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
+ (song->rate * sweep);
+}
+
+static Sint32 convert_vibrato_sweep(MidiSong *song, Uint8 sweep,
+ Sint32 vib_control_ratio)
+{
+ if (!sweep)
+ return 0;
+
+ return
+ (Sint32) (FSCALE((double) (vib_control_ratio) * SWEEP_TUNING, SWEEP_SHIFT)
+ / (double)(song->rate * sweep));
+
+ /* this was overflowing with seashore.pat
+
+ ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
+ (song->rate * sweep); */
+}
+
+static Sint32 convert_tremolo_rate(MidiSong *song, Uint8 rate)
+{
+ return
+ ((SINE_CYCLE_LENGTH * song->control_ratio * rate) << RATE_SHIFT) /
+ (TREMOLO_RATE_TUNING * song->rate);
+}
+
+static Sint32 convert_vibrato_rate(MidiSong *song, Uint8 rate)
+{
+ /* Return a suitable vibrato_control_ratio value */
+ return
+ (VIBRATO_RATE_TUNING * song->rate) /
+ (rate * 2 * VIBRATO_SAMPLE_INCREMENTS);
+}
+
+static void reverse_data(Sint16 *sp, Sint32 ls, Sint32 le)
+{
+ Sint16 s, *ep=sp+le;
+ sp+=ls;
+ le-=ls;
+ le/=2;
+ while (le--)
+ {
+ s=*sp;
+ *sp++=*ep;
+ *ep--=s;
+ }
+}
+
+/*
+ If panning or note_to_use != -1, it will be used for all samples,
+ instead of the sample-specific values in the instrument file.
+
+ For note_to_use, any value <0 or >127 will be forced to 0.
+
+ For other parameters, 1 means yes, 0 means no, other values are
+ undefined.
+
+ TODO: do reverse loops right */
+static Instrument *load_instrument(MidiSong *song, char *name, int percussion,
+ int panning, int amp, int note_to_use,
+ int strip_loop, int strip_envelope,
+ int strip_tail)
+{
+ Instrument *ip;
+ Sample *sp;
+ SDL_RWops *rw;
+ char tmp[1024];
+ int i,j,noluck=0;
+ static char *patch_ext[] = PATCH_EXT_LIST;
+
+ if (!name) return 0;
+
+ /* Open patch file */
+ if ((rw=open_file(name)) == NULL)
+ {
+ noluck=1;
+ /* Try with various extensions */
+ for (i=0; patch_ext[i]; i++)
+ {
+ if (strlen(name)+strlen(patch_ext[i])<1024)
+ {
+ strcpy(tmp, name);
+ strcat(tmp, patch_ext[i]);
+ if ((rw=open_file(tmp)) != NULL)
+ {
+ noluck=0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (noluck)
+ {
+ SNDDBG(("Instrument `%s' can't be found.\n", name));
+ return 0;
+ }
+
+ SNDDBG(("Loading instrument %s\n", tmp));
+
+ /* Read some headers and do cursory sanity checks. There are loads
+ of magic offsets. This could be rewritten... */
+
+ if ((239 != SDL_RWread(rw, tmp, 1, 239)) ||
+ (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
+ memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
+ differences are */
+ {
+ SNDDBG(("%s: not an instrument\n", name));
+ return 0;
+ }
+
+ if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers,
+ 0 means 1 */
+ {
+ SNDDBG(("Can't handle patches with %d instruments\n", tmp[82]));
+ return 0;
+ }
+
+ if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
+ {
+ SNDDBG(("Can't handle instruments with %d layers\n", tmp[151]));
+ return 0;
+ }
+
+ ip=safe_malloc(sizeof(Instrument));
+ ip->samples = tmp[198];
+ ip->sample = safe_malloc(sizeof(Sample) * ip->samples);
+ for (i=0; i<ip->samples; i++)
+ {
+
+ Uint8 fractions;
+ Sint32 tmplong;
+ Uint16 tmpshort;
+ Uint8 tmpchar;
+
+#define READ_CHAR(thing) \
+ if (1 != SDL_RWread(rw, &tmpchar, 1, 1)) goto fail; \
+ thing = tmpchar;
+#define READ_SHORT(thing) \
+ if (1 != SDL_RWread(rw, &tmpshort, 2, 1)) goto fail; \
+ thing = SDL_SwapLE16(tmpshort);
+#define READ_LONG(thing) \
+ if (1 != SDL_RWread(rw, &tmplong, 4, 1)) goto fail; \
+ thing = SDL_SwapLE32(tmplong);
+
+ SDL_RWseek(rw, 7, SEEK_CUR); /* Skip the wave name */
+
+ if (1 != SDL_RWread(rw, &fractions, 1, 1))
+ {
+ fail:
+ SNDDBG(("Error reading sample %d\n", i));
+ for (j=0; j<i; j++)
+ free(ip->sample[j].data);
+ free(ip->sample);
+ free(ip);
+ return 0;
+ }
+
+ sp=&(ip->sample[i]);
+
+ READ_LONG(sp->data_length);
+ READ_LONG(sp->loop_start);
+ READ_LONG(sp->loop_end);
+ READ_SHORT(sp->sample_rate);
+ READ_LONG(sp->low_freq);
+ READ_LONG(sp->high_freq);
+ READ_LONG(sp->root_freq);
+ sp->low_vel = 0;
+ sp->high_vel = 127;
+ SDL_RWseek(rw, 2, SEEK_CUR); /* Why have a "root frequency" and then
+ * "tuning"?? */
+
+ READ_CHAR(tmp[0]);
+
+ if (panning==-1)
+ sp->panning = (tmp[0] * 8 + 4) & 0x7f;
+ else
+ sp->panning=(Uint8)(panning & 0x7F);
+
+ /* envelope, tremolo, and vibrato */
+ if (18 != SDL_RWread(rw, tmp, 1, 18)) goto fail;
+
+ if (!tmp[13] || !tmp[14])
+ {
+ sp->tremolo_sweep_increment=
+ sp->tremolo_phase_increment=sp->tremolo_depth=0;
+ SNDDBG((" * no tremolo\n"));
+ }
+ else
+ {
+ sp->tremolo_sweep_increment=convert_tremolo_sweep(song, tmp[12]);
+ sp->tremolo_phase_increment=convert_tremolo_rate(song, tmp[13]);
+ sp->tremolo_depth=tmp[14];
+ SNDDBG((" * tremolo: sweep %d, phase %d, depth %d\n",
+ sp->tremolo_sweep_increment, sp->tremolo_phase_increment,
+ sp->tremolo_depth));
+ }
+
+ if (!tmp[16] || !tmp[17])
+ {
+ sp->vibrato_sweep_increment=
+ sp->vibrato_control_ratio=sp->vibrato_depth=0;
+ SNDDBG((" * no vibrato\n"));
+ }
+ else
+ {
+ sp->vibrato_control_ratio=convert_vibrato_rate(song, tmp[16]);
+ sp->vibrato_sweep_increment=
+ convert_vibrato_sweep(song, tmp[15], sp->vibrato_control_ratio);
+ sp->vibrato_depth=tmp[17];
+ SNDDBG((" * vibrato: sweep %d, ctl %d, depth %d\n",
+ sp->vibrato_sweep_increment, sp->vibrato_control_ratio,
+ sp->vibrato_depth));
+
+ }
+
+ READ_CHAR(sp->modes);
+
+ SDL_RWseek(rw, 40, SEEK_CUR); /* skip the useless scale frequency, scale
+ factor (what's it mean?), and reserved
+ space */
+
+ /* Mark this as a fixed-pitch instrument if such a deed is desired. */
+ if (note_to_use!=-1)
+ sp->note_to_use=(Uint8)(note_to_use);
+ else
+ sp->note_to_use=0;
+
+ /* seashore.pat in the Midia patch set has no Sustain. I don't
+ understand why, and fixing it by adding the Sustain flag to
+ all looped patches probably breaks something else. We do it
+ anyway. */
+
+ if (sp->modes & MODES_LOOPING)
+ sp->modes |= MODES_SUSTAIN;
+
+ /* Strip any loops and envelopes we're permitted to */
+ if ((strip_loop==1) &&
+ (sp->modes & (MODES_SUSTAIN | MODES_LOOPING |
+ MODES_PINGPONG | MODES_REVERSE)))
+ {
+ SNDDBG((" - Removing loop and/or sustain\n"));
+ sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING |
+ MODES_PINGPONG | MODES_REVERSE);
+ }
+
+ if (strip_envelope==1)
+ {
+ if (sp->modes & MODES_ENVELOPE)
+ SNDDBG((" - Removing envelope\n"));
+ sp->modes &= ~MODES_ENVELOPE;
+ }
+ else if (strip_envelope != 0)
+ {
+ /* Have to make a guess. */
+ if (!(sp->modes & (MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE)))
+ {
+ /* No loop? Then what's there to sustain? No envelope needed
+ either... */
+ sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE);
+ SNDDBG((" - No loop, removing sustain and envelope\n"));
+ }
+ else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100)
+ {
+ /* Envelope rates all maxed out? Envelope end at a high "offset"?
+ That's a weird envelope. Take it out. */
+ sp->modes &= ~MODES_ENVELOPE;
+ SNDDBG((" - Weirdness, removing envelope\n"));
+ }
+ else if (!(sp->modes & MODES_SUSTAIN))
+ {
+ /* No sustain? Then no envelope. I don't know if this is
+ justified, but patches without sustain usually don't need the
+ envelope either... at least the Gravis ones. They're mostly
+ drums. I think. */
+ sp->modes &= ~MODES_ENVELOPE;
+ SNDDBG((" - No sustain, removing envelope\n"));
+ }
+ }
+
+ for (j=0; j<6; j++)
+ {
+ sp->envelope_rate[j]=
+ convert_envelope_rate(song, tmp[j]);
+ sp->envelope_offset[j]=
+ convert_envelope_offset(tmp[6+j]);
+ }
+
+ /* Then read the sample data */
+ sp->data = safe_malloc(sp->data_length);
+ if (1 != SDL_RWread(rw, sp->data, sp->data_length, 1))
+ goto fail;
+
+ if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
+ {
+ Sint32 i=sp->data_length;
+ Uint8 *cp=(Uint8 *)(sp->data);
+ Uint16 *tmp,*new;
+ tmp=new=safe_malloc(sp->data_length*2);
+ while (i--)
+ *tmp++ = (Uint16)(*cp++) << 8;
+ cp=(Uint8 *)(sp->data);
+ sp->data = (sample_t *)new;
+ free(cp);
+ sp->data_length *= 2;
+ sp->loop_start *= 2;
+ sp->loop_end *= 2;
+ }
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ else
+ /* convert to machine byte order */
+ {
+ Sint32 i=sp->data_length/2;
+ Sint16 *tmp=(Sint16 *)sp->data,s;
+ while (i--)
+ {
+ s=SDL_SwapLE16(*tmp);
+ *tmp++=s;
+ }
+ }
+#endif
+
+ if (sp->modes & MODES_UNSIGNED) /* convert to signed data */
+ {
+ Sint32 i=sp->data_length/2;
+ Sint16 *tmp=(Sint16 *)sp->data;
+ while (i--)
+ *tmp++ ^= 0x8000;
+ }
+
+ /* Reverse reverse loops and pass them off as normal loops */
+ if (sp->modes & MODES_REVERSE)
+ {
+ Sint32 t;
+ /* The GUS apparently plays reverse loops by reversing the
+ whole sample. We do the same because the GUS does not SUCK. */
+
+ SNDDBG(("Reverse loop in %s\n", name));
+ reverse_data((Sint16 *)sp->data, 0, sp->data_length/2);
+
+ t=sp->loop_start;
+ sp->loop_start=sp->data_length - sp->loop_end;
+ sp->loop_end=sp->data_length - t;
+
+ sp->modes &= ~MODES_REVERSE;
+ sp->modes |= MODES_LOOPING; /* just in case */
+ }
+
+#ifdef ADJUST_SAMPLE_VOLUMES
+ if (amp!=-1)
+ sp->volume=(float)((amp) / 100.0);
+ else
+ {
+ /* Try to determine a volume scaling factor for the sample.
+ This is a very crude adjustment, but things sound more
+ balanced with it. Still, this should be a runtime option. */
+ Sint32 i=sp->data_length/2;
+ Sint16 maxamp=0,a;
+ Sint16 *tmp=(Sint16 *)sp->data;
+ while (i--)
+ {
+ a=*tmp++;
+ if (a<0) a=-a;
+ if (a>maxamp)
+ maxamp=a;
+ }
+ sp->volume=(float)(32768.0 / maxamp);
+ SNDDBG((" * volume comp: %f\n", sp->volume));
+ }
+#else
+ if (amp!=-1)
+ sp->volume=(double)(amp) / 100.0;
+ else
+ sp->volume=1.0;
+#endif
+
+ sp->data_length /= 2; /* These are in bytes. Convert into samples. */
+ sp->loop_start /= 2;
+ sp->loop_end /= 2;
+
+ /* Then fractional samples */
+ sp->data_length <<= FRACTION_BITS;
+ sp->loop_start <<= FRACTION_BITS;
+ sp->loop_end <<= FRACTION_BITS;
+
+ /* Adjust for fractional loop points. This is a guess. Does anyone
+ know what "fractions" really stands for? */
+ sp->loop_start |=
+ (fractions & 0x0F) << (FRACTION_BITS-4);
+ sp->loop_end |=
+ ((fractions>>4) & 0x0F) << (FRACTION_BITS-4);
+
+ /* If this instrument will always be played on the same note,
+ and it's not looped, we can resample it now. */
+ if (sp->note_to_use && !(sp->modes & MODES_LOOPING))
+ pre_resample(song, sp);
+
+ if (strip_tail==1)
+ {
+ /* Let's not really, just say we did. */
+ SNDDBG((" - Stripping tail\n"));
+ sp->data_length = sp->loop_end;
+ }
+ }
+
+ SDL_RWclose(rw);
+ return ip;
+}
+
+static int fill_bank(MidiSong *song, int dr, int b)
+{
+ int i, errors=0;
+ ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]);
+ if (!bank)
+ {
+ SNDDBG(("Huh. Tried to load instruments in non-existent %s %d\n",
+ (dr) ? "drumset" : "tone bank", b));
+ return 0;
+ }
+ for (i=0; i<128; i++)
+ {
+ if (bank->instrument[i]==MAGIC_LOAD_INSTRUMENT)
+ {
+ bank->instrument[i]=load_instrument_dls(song, dr, b, i);
+ if (bank->instrument[i])
+ {
+ continue;
+ }
+ if (!(bank->tone[i].name))
+ {
+ SNDDBG(("No instrument mapped to %s %d, program %d%s\n",
+ (dr)? "drum set" : "tone bank", b, i,
+ (b!=0) ? "" : " - this instrument will not be heard"));
+ if (b!=0)
+ {
+ /* Mark the corresponding instrument in the default
+ bank / drumset for loading (if it isn't already) */
+ if (!dr)
+ {
+ if (!(song->tonebank[0]->instrument[i]))
+ song->tonebank[0]->instrument[i] =
+ MAGIC_LOAD_INSTRUMENT;
+ }
+ else
+ {
+ if (!(song->drumset[0]->instrument[i]))
+ song->drumset[0]->instrument[i] =
+ MAGIC_LOAD_INSTRUMENT;
+ }
+ }
+ bank->instrument[i] = 0;
+ errors++;
+ }
+ else if (!(bank->instrument[i] =
+ load_instrument(song,
+ bank->tone[i].name,
+ (dr) ? 1 : 0,
+ bank->tone[i].pan,
+ bank->tone[i].amp,
+ (bank->tone[i].note!=-1) ?
+ bank->tone[i].note :
+ ((dr) ? i : -1),
+ (bank->tone[i].strip_loop!=-1) ?
+ bank->tone[i].strip_loop :
+ ((dr) ? 1 : -1),
+ (bank->tone[i].strip_envelope != -1) ?
+ bank->tone[i].strip_envelope :
+ ((dr) ? 1 : -1),
+ bank->tone[i].strip_tail )))
+ {
+ SNDDBG(("Couldn't load instrument %s (%s %d, program %d)\n",
+ bank->tone[i].name,
+ (dr)? "drum set" : "tone bank", b, i));
+ errors++;
+ }
+ }
+ }
+ return errors;
+}
+
+int load_missing_instruments(MidiSong *song)
+{
+ int i=128,errors=0;
+ while (i--)
+ {
+ if (song->tonebank[i])
+ errors+=fill_bank(song,0,i);
+ if (song->drumset[i])
+ errors+=fill_bank(song,1,i);
+ }
+ return errors;
+}
+
+void free_instruments(MidiSong *song)
+{
+ int i=128;
+ while(i--)
+ {
+ if (song->tonebank[i])
+ free_bank(song, 0, i);
+ if (song->drumset[i])
+ free_bank(song, 1, i);
+ }
+}
+
+int set_default_instrument(MidiSong *song, char *name)
+{
+ Instrument *ip;
+ if (!(ip=load_instrument(song, name, 0, -1, -1, -1, 0, 0, 0)))
+ return -1;
+ song->default_instrument = ip;
+ song->default_program = SPECIAL_PROGRAM;
+ return 0;
+}
diff --git a/util/sdl/sound/decoders/timidity/instrum.h b/util/sdl/sound/decoders/timidity/instrum.h
new file mode 100644
index 00000000..e46d2b23
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/instrum.h
@@ -0,0 +1,41 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ instrum.h
+
+ */
+
+/* Bits in modes: */
+#define MODES_16BIT (1<<0)
+#define MODES_UNSIGNED (1<<1)
+#define MODES_LOOPING (1<<2)
+#define MODES_PINGPONG (1<<3)
+#define MODES_REVERSE (1<<4)
+#define MODES_SUSTAIN (1<<5)
+#define MODES_ENVELOPE (1<<6)
+
+/* A hack to delay instrument loading until after reading the
+ entire MIDI file. */
+#define MAGIC_LOAD_INSTRUMENT ((Instrument *) (-1))
+
+#define SPECIAL_PROGRAM -1
+
+extern int load_missing_instruments(MidiSong *song);
+extern void free_instruments(MidiSong *song);
+extern int set_default_instrument(MidiSong *song, char *name);
diff --git a/util/sdl/sound/decoders/timidity/instrum_dls.c b/util/sdl/sound/decoders/timidity/instrum_dls.c
new file mode 100644
index 00000000..7b8e15c9
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/instrum_dls.c
@@ -0,0 +1,1269 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ instrum.h
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL.h"
+#include "SDL_endian.h"
+#include "SDL_rwops.h"
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "options.h"
+#include "instrum.h"
+#include "tables.h"
+#include "common.h"
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+typedef struct _RIFF_Chunk {
+ Uint32 magic;
+ Uint32 length;
+ Uint32 subtype;
+ Uint8 *data;
+ struct _RIFF_Chunk *child;
+ struct _RIFF_Chunk *next;
+} RIFF_Chunk;
+
+extern DECLSPEC RIFF_Chunk* SDLCALL LoadRIFF(SDL_RWops *src);
+extern DECLSPEC void SDLCALL FreeRIFF(RIFF_Chunk *chunk);
+extern DECLSPEC void SDLCALL PrintRIFF(RIFF_Chunk *chunk, int level);
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+#define RIFF 0x46464952 /* "RIFF" */
+#define LIST 0x5453494c /* "LIST" */
+
+static RIFF_Chunk *AllocRIFFChunk()
+{
+ RIFF_Chunk *chunk = (RIFF_Chunk *)malloc(sizeof(*chunk));
+ if ( !chunk ) {
+ __Sound_SetError(ERR_OUT_OF_MEMORY);
+ return NULL;
+ }
+ memset(chunk, 0, sizeof(*chunk));
+ return chunk;
+}
+
+static void FreeRIFFChunk(RIFF_Chunk *chunk)
+{
+ if ( chunk->child ) {
+ FreeRIFFChunk(chunk->child);
+ }
+ if ( chunk->next ) {
+ FreeRIFFChunk(chunk->next);
+ }
+ free(chunk);
+}
+
+static int ChunkHasSubType(Uint32 magic)
+{
+ static Uint32 chunk_list[] = {
+ RIFF, LIST
+ };
+ int i;
+ for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) {
+ if ( magic == chunk_list[i] ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int ChunkHasSubChunks(Uint32 magic)
+{
+ static Uint32 chunk_list[] = {
+ RIFF, LIST
+ };
+ int i;
+ for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) {
+ if ( magic == chunk_list[i] ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void LoadSubChunks(RIFF_Chunk *chunk, Uint8 *data, Uint32 left)
+{
+ Uint8 *subchunkData;
+ Uint32 subchunkDataLen;
+
+ while ( left > 8 ) {
+ RIFF_Chunk *child = AllocRIFFChunk();
+ RIFF_Chunk *next, *prev = NULL;
+ for ( next = chunk->child; next; next = next->next ) {
+ prev = next;
+ }
+ if ( prev ) {
+ prev->next = child;
+ } else {
+ chunk->child = child;
+ }
+
+ child->magic = (data[0] << 0) |
+ (data[1] << 8) |
+ (data[2] << 16) |
+ (data[3] << 24);
+ data += 4;
+ left -= 4;
+ child->length = (data[0] << 0) |
+ (data[1] << 8) |
+ (data[2] << 16) |
+ (data[3] << 24);
+ data += 4;
+ left -= 4;
+ child->data = data;
+
+ if ( child->length > left ) {
+ child->length = left;
+ }
+
+ subchunkData = child->data;
+ subchunkDataLen = child->length;
+ if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) {
+ child->subtype = (subchunkData[0] << 0) |
+ (subchunkData[1] << 8) |
+ (subchunkData[2] << 16) |
+ (subchunkData[3] << 24);
+ subchunkData += 4;
+ subchunkDataLen -= 4;
+ }
+ if ( ChunkHasSubChunks(child->magic) ) {
+ LoadSubChunks(child, subchunkData, subchunkDataLen);
+ }
+
+ data += child->length;
+ left -= child->length;
+ }
+}
+
+RIFF_Chunk *LoadRIFF(SDL_RWops *src)
+{
+ RIFF_Chunk *chunk;
+ Uint8 *subchunkData;
+ Uint32 subchunkDataLen;
+
+ /* Allocate the chunk structure */
+ chunk = AllocRIFFChunk();
+
+ /* Make sure the file is in RIFF format */
+ chunk->magic = SDL_ReadLE32(src);
+ chunk->length = SDL_ReadLE32(src);
+ if ( chunk->magic != RIFF ) {
+ __Sound_SetError("Not a RIFF file");
+ FreeRIFFChunk(chunk);
+ return NULL;
+ }
+ chunk->data = (Uint8 *)malloc(chunk->length);
+ if ( chunk->data == NULL ) {
+ __Sound_SetError(ERR_OUT_OF_MEMORY);
+ FreeRIFFChunk(chunk);
+ return NULL;
+ }
+ if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
+ __Sound_SetError(ERR_IO_ERROR);
+ FreeRIFF(chunk);
+ return NULL;
+ }
+ subchunkData = chunk->data;
+ subchunkDataLen = chunk->length;
+ if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) {
+ chunk->subtype = (subchunkData[0] << 0) |
+ (subchunkData[1] << 8) |
+ (subchunkData[2] << 16) |
+ (subchunkData[3] << 24);
+ subchunkData += 4;
+ subchunkDataLen -= 4;
+ }
+ if ( ChunkHasSubChunks(chunk->magic) ) {
+ LoadSubChunks(chunk, subchunkData, subchunkDataLen);
+ }
+ return chunk;
+}
+
+void FreeRIFF(RIFF_Chunk *chunk)
+{
+ free(chunk->data);
+ FreeRIFFChunk(chunk);
+}
+
+void PrintRIFF(RIFF_Chunk *chunk, int level)
+{
+ static char prefix[128];
+
+ if ( level == sizeof(prefix)-1 ) {
+ return;
+ }
+ if ( level > 0 ) {
+ prefix[(level-1)*2] = ' ';
+ prefix[(level-1)*2+1] = ' ';
+ }
+ prefix[level*2] = '\0';
+ printf("%sChunk: %c%c%c%c (%d bytes)", prefix,
+ ((chunk->magic >> 0) & 0xFF),
+ ((chunk->magic >> 8) & 0xFF),
+ ((chunk->magic >> 16) & 0xFF),
+ ((chunk->magic >> 24) & 0xFF), chunk->length);
+ if ( chunk->subtype ) {
+ printf(" subtype: %c%c%c%c",
+ ((chunk->subtype >> 0) & 0xFF),
+ ((chunk->subtype >> 8) & 0xFF),
+ ((chunk->subtype >> 16) & 0xFF),
+ ((chunk->subtype >> 24) & 0xFF));
+ }
+ printf("\n");
+ if ( chunk->child ) {
+ printf("%s{\n", prefix);
+ PrintRIFF(chunk->child, level + 1);
+ printf("%s}\n", prefix);
+ }
+ if ( chunk->next ) {
+ PrintRIFF(chunk->next, level);
+ }
+ if ( level > 0 ) {
+ prefix[(level-1)*2] = '\0';
+ }
+}
+
+#ifdef TEST_MAIN_RIFF
+
+main(int argc, char *argv[])
+{
+ int i;
+ for ( i = 1; i < argc; ++i ) {
+ RIFF_Chunk *chunk;
+ SDL_RWops *src = SDL_RWFromFile(argv[i], "rb");
+ if ( !src ) {
+ fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError());
+ continue;
+ }
+ chunk = LoadRIFF(src);
+ if ( chunk ) {
+ PrintRIFF(chunk, 0);
+ FreeRIFF(chunk);
+ } else {
+ fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError());
+ }
+ SDL_RWclose(src);
+ }
+}
+
+#endif // TEST_MAIN
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_dls.h * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+/* This code is based on the DLS spec version 1.1, available at:
+ http://www.midi.org/about-midi/dls/dlsspec.shtml
+*/
+
+/* Some typedefs so the public dls headers don't need to be modified */
+#define FAR
+typedef Uint8 BYTE;
+typedef Sint16 SHORT;
+typedef Uint16 USHORT;
+typedef Uint16 WORD;
+typedef Sint32 LONG;
+typedef Uint32 ULONG;
+typedef Uint32 DWORD;
+#define mmioFOURCC(A, B, C, D) \
+ (((A) << 0) | ((B) << 8) | ((C) << 16) | ((D) << 24))
+#define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M)
+
+#include "dls1.h"
+#include "dls2.h"
+
+typedef struct _WaveFMT {
+ WORD wFormatTag;
+ WORD wChannels;
+ DWORD dwSamplesPerSec;
+ DWORD dwAvgBytesPerSec;
+ WORD wBlockAlign;
+ WORD wBitsPerSample;
+} WaveFMT;
+
+typedef struct _DLS_Wave {
+ WaveFMT *format;
+ Uint8 *data;
+ Uint32 length;
+ WSMPL *wsmp;
+ WLOOP *wsmp_loop;
+} DLS_Wave;
+
+typedef struct _DLS_Region {
+ RGNHEADER *header;
+ WAVELINK *wlnk;
+ WSMPL *wsmp;
+ WLOOP *wsmp_loop;
+ CONNECTIONLIST *art;
+ CONNECTION *artList;
+} DLS_Region;
+
+typedef struct _DLS_Instrument {
+ const char *name;
+ INSTHEADER *header;
+ DLS_Region *regions;
+ CONNECTIONLIST *art;
+ CONNECTION *artList;
+} DLS_Instrument;
+
+typedef struct _DLS_Data {
+ struct _RIFF_Chunk *chunk;
+
+ Uint32 cInstruments;
+ DLS_Instrument *instruments;
+
+ POOLTABLE *ptbl;
+ POOLCUE *ptblList;
+ DLS_Wave *waveList;
+
+ const char *name;
+ const char *artist;
+ const char *copyright;
+ const char *comments;
+} DLS_Data;
+
+extern DECLSPEC DLS_Data* SDLCALL LoadDLS(SDL_RWops *src);
+extern DECLSPEC void SDLCALL FreeDLS(DLS_Data *chunk);
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * load_dls.c * * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+
+#define FOURCC_LIST 0x5453494c /* "LIST" */
+#define FOURCC_FMT 0x20746D66 /* "fmt " */
+#define FOURCC_DATA 0x61746164 /* "data" */
+#define FOURCC_INFO mmioFOURCC('I','N','F','O')
+#define FOURCC_IARL mmioFOURCC('I','A','R','L')
+#define FOURCC_IART mmioFOURCC('I','A','R','T')
+#define FOURCC_ICMS mmioFOURCC('I','C','M','S')
+#define FOURCC_ICMT mmioFOURCC('I','C','M','T')
+#define FOURCC_ICOP mmioFOURCC('I','C','O','P')
+#define FOURCC_ICRD mmioFOURCC('I','C','R','D')
+#define FOURCC_IENG mmioFOURCC('I','E','N','G')
+#define FOURCC_IGNR mmioFOURCC('I','G','N','R')
+#define FOURCC_IKEY mmioFOURCC('I','K','E','Y')
+#define FOURCC_IMED mmioFOURCC('I','M','E','D')
+#define FOURCC_INAM mmioFOURCC('I','N','A','M')
+#define FOURCC_IPRD mmioFOURCC('I','P','R','D')
+#define FOURCC_ISBJ mmioFOURCC('I','S','B','J')
+#define FOURCC_ISFT mmioFOURCC('I','S','F','T')
+#define FOURCC_ISRC mmioFOURCC('I','S','R','C')
+#define FOURCC_ISRF mmioFOURCC('I','S','R','F')
+#define FOURCC_ITCH mmioFOURCC('I','T','C','H')
+
+
+static void FreeRegions(DLS_Instrument *instrument)
+{
+ if ( instrument->regions ) {
+ free(instrument->regions);
+ }
+}
+
+static void AllocRegions(DLS_Instrument *instrument)
+{
+ int datalen = (instrument->header->cRegions * sizeof(DLS_Region));
+ FreeRegions(instrument);
+ instrument->regions = (DLS_Region *)malloc(datalen);
+ if ( instrument->regions ) {
+ memset(instrument->regions, 0, datalen);
+ }
+}
+
+static void FreeInstruments(DLS_Data *data)
+{
+ if ( data->instruments ) {
+ Uint32 i;
+ for ( i = 0; i < data->cInstruments; ++i ) {
+ FreeRegions(&data->instruments[i]);
+ }
+ free(data->instruments);
+ }
+}
+
+static void AllocInstruments(DLS_Data *data)
+{
+ int datalen = (data->cInstruments * sizeof(DLS_Instrument));
+ FreeInstruments(data);
+ data->instruments = (DLS_Instrument *)malloc(datalen);
+ if ( data->instruments ) {
+ memset(data->instruments, 0, datalen);
+ }
+}
+
+static void FreeWaveList(DLS_Data *data)
+{
+ if ( data->waveList ) {
+ free(data->waveList);
+ }
+}
+
+static void AllocWaveList(DLS_Data *data)
+{
+ int datalen = (data->ptbl->cCues * sizeof(DLS_Wave));
+ FreeWaveList(data);
+ data->waveList = (DLS_Wave *)malloc(datalen);
+ if ( data->waveList ) {
+ memset(data->waveList, 0, datalen);
+ }
+}
+
+static void Parse_colh(DLS_Data *data, RIFF_Chunk *chunk)
+{
+ data->cInstruments = SDL_SwapLE32(*(Uint32 *)chunk->data);
+ AllocInstruments(data);
+}
+
+static void Parse_insh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+ INSTHEADER *header = (INSTHEADER *)chunk->data;
+ header->cRegions = SDL_SwapLE32(header->cRegions);
+ header->Locale.ulBank = SDL_SwapLE32(header->Locale.ulBank);
+ header->Locale.ulInstrument = SDL_SwapLE32(header->Locale.ulInstrument);
+ instrument->header = header;
+ AllocRegions(instrument);
+}
+
+static void Parse_rgnh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region)
+{
+ RGNHEADER *header = (RGNHEADER *)chunk->data;
+ header->RangeKey.usLow = SDL_SwapLE16(header->RangeKey.usLow);
+ header->RangeKey.usHigh = SDL_SwapLE16(header->RangeKey.usHigh);
+ header->RangeVelocity.usLow = SDL_SwapLE16(header->RangeVelocity.usLow);
+ header->RangeVelocity.usHigh = SDL_SwapLE16(header->RangeVelocity.usHigh);
+ header->fusOptions = SDL_SwapLE16(header->fusOptions);
+ header->usKeyGroup = SDL_SwapLE16(header->usKeyGroup);
+ region->header = header;
+}
+
+static void Parse_wlnk(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region)
+{
+ WAVELINK *wlnk = (WAVELINK *)chunk->data;
+ wlnk->fusOptions = SDL_SwapLE16(wlnk->fusOptions);
+ wlnk->usPhaseGroup = SDL_SwapLE16(wlnk->usPhaseGroup);
+ wlnk->ulChannel = SDL_SwapLE16(wlnk->ulChannel);
+ wlnk->ulTableIndex = SDL_SwapLE16(wlnk->ulTableIndex);
+ region->wlnk = wlnk;
+}
+
+static void Parse_wsmp(DLS_Data *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr)
+{
+ Uint32 i;
+ WSMPL *wsmp = (WSMPL *)chunk->data;
+ WLOOP *loop;
+ wsmp->cbSize = SDL_SwapLE32(wsmp->cbSize);
+ wsmp->usUnityNote = SDL_SwapLE16(wsmp->usUnityNote);
+ wsmp->sFineTune = SDL_SwapLE16(wsmp->sFineTune);
+ wsmp->lAttenuation = SDL_SwapLE32(wsmp->lAttenuation);
+ wsmp->fulOptions = SDL_SwapLE32(wsmp->fulOptions);
+ wsmp->cSampleLoops = SDL_SwapLE32(wsmp->cSampleLoops);
+ loop = (WLOOP *)((Uint8 *)chunk->data + wsmp->cbSize);
+ *wsmp_ptr = wsmp;
+ *wsmp_loop_ptr = loop;
+ for ( i = 0; i < wsmp->cSampleLoops; ++i ) {
+ loop->cbSize = SDL_SwapLE32(loop->cbSize);
+ loop->ulType = SDL_SwapLE32(loop->ulType);
+ loop->ulStart = SDL_SwapLE32(loop->ulStart);
+ loop->ulLength = SDL_SwapLE32(loop->ulLength);
+ ++loop;
+ }
+}
+
+static void Parse_art(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr)
+{
+ Uint32 i;
+ CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data;
+ CONNECTION *artList;
+ art->cbSize = SDL_SwapLE32(art->cbSize);
+ art->cConnections = SDL_SwapLE32(art->cConnections);
+ artList = (CONNECTION *)((Uint8 *)chunk->data + art->cbSize);
+ *art_ptr = art;
+ *artList_ptr = artList;
+ for ( i = 0; i < art->cConnections; ++i ) {
+ artList->usSource = SDL_SwapLE16(artList->usSource);
+ artList->usControl = SDL_SwapLE16(artList->usControl);
+ artList->usDestination = SDL_SwapLE16(artList->usDestination);
+ artList->usTransform = SDL_SwapLE16(artList->usTransform);
+ artList->lScale = SDL_SwapLE32(artList->lScale);
+ ++artList;
+ }
+}
+
+static void Parse_lart(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr)
+{
+ /* FIXME: This only supports one set of connections */
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_ART1:
+ case FOURCC_ART2:
+ Parse_art(data, chunk, conn_ptr, connList_ptr);
+ return;
+ }
+ }
+}
+
+static void Parse_rgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region)
+{
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_RGNH:
+ Parse_rgnh(data, chunk, region);
+ break;
+ case FOURCC_WLNK:
+ Parse_wlnk(data, chunk, region);
+ break;
+ case FOURCC_WSMP:
+ Parse_wsmp(data, chunk, &region->wsmp, &region->wsmp_loop);
+ break;
+ case FOURCC_LART:
+ case FOURCC_LAR2:
+ Parse_lart(data, chunk, &region->art, &region->artList);
+ break;
+ }
+ }
+}
+
+static void Parse_lrgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+ Uint32 region = 0;
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_RGN:
+ case FOURCC_RGN2:
+ if ( region < instrument->header->cRegions ) {
+ Parse_rgn(data, chunk, &instrument->regions[region++]);
+ }
+ break;
+ }
+ }
+}
+
+static void Parse_INFO_INS(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_INAM: /* Name */
+ instrument->name = chunk->data;
+ break;
+ }
+ }
+}
+
+static void Parse_ins(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
+{
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_INSH:
+ Parse_insh(data, chunk, instrument);
+ break;
+ case FOURCC_LRGN:
+ Parse_lrgn(data, chunk, instrument);
+ break;
+ case FOURCC_LART:
+ case FOURCC_LAR2:
+ Parse_lart(data, chunk, &instrument->art, &instrument->artList);
+ break;
+ case FOURCC_INFO:
+ Parse_INFO_INS(data, chunk, instrument);
+ break;
+ }
+ }
+}
+
+static void Parse_lins(DLS_Data *data, RIFF_Chunk *chunk)
+{
+ Uint32 instrument = 0;
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_INS:
+ if ( instrument < data->cInstruments ) {
+ Parse_ins(data, chunk, &data->instruments[instrument++]);
+ }
+ break;
+ }
+ }
+}
+
+static void Parse_ptbl(DLS_Data *data, RIFF_Chunk *chunk)
+{
+ Uint32 i;
+ POOLTABLE *ptbl = (POOLTABLE *)chunk->data;
+ ptbl->cbSize = SDL_SwapLE32(ptbl->cbSize);
+ ptbl->cCues = SDL_SwapLE32(ptbl->cCues);
+ data->ptbl = ptbl;
+ data->ptblList = (POOLCUE *)((Uint8 *)chunk->data + ptbl->cbSize);
+ for ( i = 0; i < ptbl->cCues; ++i ) {
+ data->ptblList[i].ulOffset = SDL_SwapLE32(data->ptblList[i].ulOffset);
+ }
+ AllocWaveList(data);
+}
+
+static void Parse_fmt(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave)
+{
+ WaveFMT *fmt = (WaveFMT *)chunk->data;
+ fmt->wFormatTag = SDL_SwapLE16(fmt->wFormatTag);
+ fmt->wChannels = SDL_SwapLE16(fmt->wChannels);
+ fmt->dwSamplesPerSec = SDL_SwapLE32(fmt->dwSamplesPerSec);
+ fmt->dwAvgBytesPerSec = SDL_SwapLE32(fmt->dwAvgBytesPerSec);
+ fmt->wBlockAlign = SDL_SwapLE16(fmt->wBlockAlign);
+ fmt->wBitsPerSample = SDL_SwapLE16(fmt->wBitsPerSample);
+ wave->format = fmt;
+}
+
+static void Parse_data(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave)
+{
+ wave->data = chunk->data;
+ wave->length = chunk->length;
+}
+
+static void Parse_wave(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave)
+{
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_FMT:
+ Parse_fmt(data, chunk, wave);
+ break;
+ case FOURCC_DATA:
+ Parse_data(data, chunk, wave);
+ break;
+ case FOURCC_WSMP:
+ Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop);
+ break;
+ }
+ }
+}
+
+static void Parse_wvpl(DLS_Data *data, RIFF_Chunk *chunk)
+{
+ Uint32 wave = 0;
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_wave:
+ if ( wave < data->ptbl->cCues ) {
+ Parse_wave(data, chunk, &data->waveList[wave++]);
+ }
+ break;
+ }
+ }
+}
+
+static void Parse_INFO_DLS(DLS_Data *data, RIFF_Chunk *chunk)
+{
+ for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_IARL: /* Archival Location */
+ break;
+ case FOURCC_IART: /* Artist */
+ data->artist = chunk->data;
+ break;
+ case FOURCC_ICMS: /* Commisioned */
+ break;
+ case FOURCC_ICMT: /* Comments */
+ data->comments = chunk->data;
+ break;
+ case FOURCC_ICOP: /* Copyright */
+ data->copyright = chunk->data;
+ break;
+ case FOURCC_ICRD: /* Creation Date */
+ break;
+ case FOURCC_IENG: /* Engineer */
+ break;
+ case FOURCC_IGNR: /* Genre */
+ break;
+ case FOURCC_IKEY: /* Keywords */
+ break;
+ case FOURCC_IMED: /* Medium */
+ break;
+ case FOURCC_INAM: /* Name */
+ data->name = chunk->data;
+ break;
+ case FOURCC_IPRD: /* Product */
+ break;
+ case FOURCC_ISBJ: /* Subject */
+ break;
+ case FOURCC_ISFT: /* Software */
+ break;
+ case FOURCC_ISRC: /* Source */
+ break;
+ case FOURCC_ISRF: /* Source Form */
+ break;
+ case FOURCC_ITCH: /* Technician */
+ break;
+ }
+ }
+}
+
+DLS_Data *LoadDLS(SDL_RWops *src)
+{
+ RIFF_Chunk *chunk;
+ DLS_Data *data = (DLS_Data *)malloc(sizeof(*data));
+ if ( !data ) {
+ __Sound_SetError(ERR_OUT_OF_MEMORY);
+ return NULL;
+ }
+ memset(data, 0, sizeof(*data));
+
+ data->chunk = LoadRIFF(src);
+ if ( !data->chunk ) {
+ FreeDLS(data);
+ return NULL;
+ }
+
+ for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) {
+ Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
+ switch(magic) {
+ case FOURCC_COLH:
+ Parse_colh(data, chunk);
+ break;
+ case FOURCC_LINS:
+ Parse_lins(data, chunk);
+ break;
+ case FOURCC_PTBL:
+ Parse_ptbl(data, chunk);
+ break;
+ case FOURCC_WVPL:
+ Parse_wvpl(data, chunk);
+ break;
+ case FOURCC_INFO:
+ Parse_INFO_DLS(data, chunk);
+ break;
+ }
+ }
+ return data;
+}
+
+void FreeDLS(DLS_Data *data)
+{
+ if ( data->chunk ) {
+ FreeRIFF(data->chunk);
+ }
+ FreeInstruments(data);
+ FreeWaveList(data);
+ free(data);
+}
+
+static const char *SourceToString(USHORT usSource)
+{
+ switch(usSource) {
+ case CONN_SRC_NONE:
+ return "NONE";
+ case CONN_SRC_LFO:
+ return "LFO";
+ case CONN_SRC_KEYONVELOCITY:
+ return "KEYONVELOCITY";
+ case CONN_SRC_KEYNUMBER:
+ return "KEYNUMBER";
+ case CONN_SRC_EG1:
+ return "EG1";
+ case CONN_SRC_EG2:
+ return "EG2";
+ case CONN_SRC_PITCHWHEEL:
+ return "PITCHWHEEL";
+ case CONN_SRC_CC1:
+ return "CC1";
+ case CONN_SRC_CC7:
+ return "CC7";
+ case CONN_SRC_CC10:
+ return "CC10";
+ case CONN_SRC_CC11:
+ return "CC11";
+ case CONN_SRC_POLYPRESSURE:
+ return "POLYPRESSURE";
+ case CONN_SRC_CHANNELPRESSURE:
+ return "CHANNELPRESSURE";
+ case CONN_SRC_VIBRATO:
+ return "VIBRATO";
+ case CONN_SRC_MONOPRESSURE:
+ return "MONOPRESSURE";
+ case CONN_SRC_CC91:
+ return "CC91";
+ case CONN_SRC_CC93:
+ return "CC93";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static const char *TransformToString(USHORT usTransform)
+{
+ switch (usTransform) {
+ case CONN_TRN_NONE:
+ return "NONE";
+ case CONN_TRN_CONCAVE:
+ return "CONCAVE";
+ case CONN_TRN_CONVEX:
+ return "CONVEX";
+ case CONN_TRN_SWITCH:
+ return "SWITCH";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static const char *DestinationToString(USHORT usDestination)
+{
+ switch (usDestination) {
+ case CONN_DST_NONE:
+ return "NONE";
+ case CONN_DST_ATTENUATION:
+ return "ATTENUATION";
+ case CONN_DST_PITCH:
+ return "PITCH";
+ case CONN_DST_PAN:
+ return "PAN";
+ case CONN_DST_LFO_FREQUENCY:
+ return "LFO_FREQUENCY";
+ case CONN_DST_LFO_STARTDELAY:
+ return "LFO_STARTDELAY";
+ case CONN_DST_EG1_ATTACKTIME:
+ return "EG1_ATTACKTIME";
+ case CONN_DST_EG1_DECAYTIME:
+ return "EG1_DECAYTIME";
+ case CONN_DST_EG1_RELEASETIME:
+ return "EG1_RELEASETIME";
+ case CONN_DST_EG1_SUSTAINLEVEL:
+ return "EG1_SUSTAINLEVEL";
+ case CONN_DST_EG2_ATTACKTIME:
+ return "EG2_ATTACKTIME";
+ case CONN_DST_EG2_DECAYTIME:
+ return "EG2_DECAYTIME";
+ case CONN_DST_EG2_RELEASETIME:
+ return "EG2_RELEASETIME";
+ case CONN_DST_EG2_SUSTAINLEVEL:
+ return "EG2_SUSTAINLEVEL";
+ case CONN_DST_KEYNUMBER:
+ return "KEYNUMBER";
+ case CONN_DST_LEFT:
+ return "LEFT";
+ case CONN_DST_RIGHT:
+ return "RIGHT";
+ case CONN_DST_CENTER:
+ return "CENTER";
+ case CONN_DST_LEFTREAR:
+ return "LEFTREAR";
+ case CONN_DST_RIGHTREAR:
+ return "RIGHTREAR";
+ case CONN_DST_LFE_CHANNEL:
+ return "LFE_CHANNEL";
+ case CONN_DST_CHORUS:
+ return "CHORUS";
+ case CONN_DST_REVERB:
+ return "REVERB";
+ case CONN_DST_VIB_FREQUENCY:
+ return "VIB_FREQUENCY";
+ case CONN_DST_VIB_STARTDELAY:
+ return "VIB_STARTDELAY";
+ case CONN_DST_EG1_DELAYTIME:
+ return "EG1_DELAYTIME";
+ case CONN_DST_EG1_HOLDTIME:
+ return "EG1_HOLDTIME";
+ case CONN_DST_EG1_SHUTDOWNTIME:
+ return "EG1_SHUTDOWNTIME";
+ case CONN_DST_EG2_DELAYTIME:
+ return "EG2_DELAYTIME";
+ case CONN_DST_EG2_HOLDTIME:
+ return "EG2_HOLDTIME";
+ case CONN_DST_FILTER_CUTOFF:
+ return "FILTER_CUTOFF";
+ case CONN_DST_FILTER_Q:
+ return "FILTER_Q";
+ default:
+ return "UNKOWN";
+ }
+}
+
+static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList)
+{
+ Uint32 i;
+ printf("%s Connections:\n", type);
+ for ( i = 0; i < art->cConnections; ++i ) {
+ printf(" Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n",
+ SourceToString(artList[i].usSource),
+ SourceToString(artList[i].usControl),
+ DestinationToString(artList[i].usDestination),
+ TransformToString(artList[i].usTransform),
+ artList[i].lScale);
+ }
+}
+
+static void PrintWave(DLS_Wave *wave, Uint32 index)
+{
+ WaveFMT *format = wave->format;
+ if ( format ) {
+ printf(" Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length);
+ }
+ if ( wave->wsmp ) {
+ Uint32 i;
+ printf(" wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote);
+ printf(" wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune);
+ printf(" wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation);
+ printf(" wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions);
+ printf(" wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops);
+ for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) {
+ WLOOP *loop = &wave->wsmp_loop[i];
+ printf(" Loop %u:\n", i);
+ printf(" ulStart = %u\n", loop->ulStart);
+ printf(" ulLength = %u\n", loop->ulLength);
+ }
+ }
+}
+
+static void PrintRegion(DLS_Region *region, Uint32 index)
+{
+ printf(" Region %u:\n", index);
+ if ( region->header ) {
+ printf(" RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh);
+ printf(" RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh);
+ printf(" fusOptions = 0x%4.4hx\n", region->header->fusOptions);
+ printf(" usKeyGroup = %hu\n", region->header->usKeyGroup);
+ }
+ if ( region->wlnk ) {
+ printf(" wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions);
+ printf(" wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup);
+ printf(" wlnk->ulChannel = %u\n", region->wlnk->ulChannel);
+ printf(" wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex);
+ }
+ if ( region->wsmp ) {
+ Uint32 i;
+ printf(" wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote);
+ printf(" wsmp->sFineTune = %hd\n", region->wsmp->sFineTune);
+ printf(" wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation);
+ printf(" wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions);
+ printf(" wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops);
+ for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) {
+ WLOOP *loop = &region->wsmp_loop[i];
+ printf(" Loop %u:\n", i);
+ printf(" ulStart = %u\n", loop->ulStart);
+ printf(" ulLength = %u\n", loop->ulLength);
+ }
+ }
+ if ( region->art && region->art->cConnections > 0 ) {
+ PrintArt("Region", region->art, region->artList);
+ }
+}
+
+static void PrintInstrument(DLS_Instrument *instrument, Uint32 index)
+{
+ printf("Instrument %u:\n", index);
+ if ( instrument->name ) {
+ printf(" Name: %s\n", instrument->name);
+ }
+ if ( instrument->header ) {
+ Uint32 i;
+ printf(" ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank);
+ printf(" ulInstrument = %u\n", instrument->header->Locale.ulInstrument);
+ printf(" Regions: %u\n", instrument->header->cRegions);
+ for ( i = 0; i < instrument->header->cRegions; ++i ) {
+ PrintRegion(&instrument->regions[i], i);
+ }
+ }
+ if ( instrument->art && instrument->art->cConnections > 0 ) {
+ PrintArt("Instrument", instrument->art, instrument->artList);
+ }
+};
+
+void PrintDLS(DLS_Data *data)
+{
+ printf("DLS Data:\n");
+ printf("cInstruments = %u\n", data->cInstruments);
+ if ( data->instruments ) {
+ Uint32 i;
+ for ( i = 0; i < data->cInstruments; ++i ) {
+ PrintInstrument(&data->instruments[i], i);
+ }
+ }
+ if ( data->ptbl && data->ptbl->cCues > 0 ) {
+ Uint32 i;
+ printf("Cues: ");
+ for ( i = 0; i < data->ptbl->cCues; ++i ) {
+ if ( i > 0 ) {
+ printf(", ");
+ }
+ printf("%u", data->ptblList[i].ulOffset);
+ }
+ printf("\n");
+ }
+ if ( data->waveList ) {
+ Uint32 i;
+ printf("Waves:\n");
+ for ( i = 0; i < data->ptbl->cCues; ++i ) {
+ PrintWave(&data->waveList[i], i);
+ }
+ }
+ if ( data->name ) {
+ printf("Name: %s\n", data->name);
+ }
+ if ( data->artist ) {
+ printf("Artist: %s\n", data->artist);
+ }
+ if ( data->copyright ) {
+ printf("Copyright: %s\n", data->copyright);
+ }
+ if ( data->comments ) {
+ printf("Comments: %s\n", data->comments);
+ }
+}
+
+#ifdef TEST_MAIN_DLS
+
+main(int argc, char *argv[])
+{
+ int i;
+ for ( i = 1; i < argc; ++i ) {
+ DLS_Data *data;
+ SDL_RWops *src = SDL_RWFromFile(argv[i], "rb");
+ if ( !src ) {
+ fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError());
+ continue;
+ }
+ data = LoadDLS(src);
+ if ( data ) {
+ PrintRIFF(data->chunk, 0);
+ PrintDLS(data);
+ FreeDLS(data);
+ } else {
+ fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError());
+ }
+ SDL_RWclose(src);
+ }
+}
+
+#endif // TEST_MAIN
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*-------------------------------------------------------------------------*/
+/* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */
+/*-------------------------------------------------------------------------*/
+
+DLS_Data *Timidity_LoadDLS(SDL_RWops *src)
+{
+ DLS_Data *patches = LoadDLS(src);
+ if (!patches) {
+ SNDDBG(("%s", SDL_GetError()));
+ }
+ return patches;
+}
+
+void Timidity_FreeDLS(DLS_Data *patches)
+{
+ FreeDLS(patches);
+}
+
+/* convert timecents to sec */
+static double to_msec(int timecent)
+{
+ if (timecent == 0x80000000 || timecent == 0)
+ return 0.0;
+ return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0);
+}
+
+/* convert decipercent to {0..1} */
+static double to_normalized_percent(int decipercent)
+{
+ return ((double)(decipercent / 65536)) / 1000.0;
+}
+
+/* convert from 8bit value to fractional offset (15.15) */
+static Sint32 to_offset(int offset)
+{
+ return (Sint32)offset << (7+15);
+}
+
+/* calculate ramp rate in fractional unit;
+ * diff = 8bit, time = msec
+ */
+static Sint32 calc_rate(MidiSong *song, int diff, int sample_rate, double msec)
+{
+ double rate;
+
+ if(msec < 6)
+ msec = 6;
+ if(diff == 0)
+ diff = 255;
+ diff <<= (7+15);
+ rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec;
+ return (Sint32)rate;
+}
+
+static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination)
+{
+ ULONG i;
+ int value = 0;
+ for (i = 0; i < cConnections; ++i) {
+ CONNECTION *conn = &artList[i];
+ if(conn->usDestination == destination) {
+ // The formula for the destination is:
+ // usDestination = usDestination + usTransform(usSource * (usControl * lScale))
+ // Since we are only handling source/control of NONE and identity
+ // transform, this simplifies to: usDestination = usDestination + lScale
+ if (conn->usSource == CONN_SRC_NONE &&
+ conn->usControl == CONN_SRC_NONE &&
+ conn->usTransform == CONN_TRN_NONE)
+ value += conn->lScale;
+ }
+ }
+ return value;
+}
+
+static void load_region_dls(MidiSong *song, Sample *sample, DLS_Instrument *ins, Uint32 index)
+{
+ DLS_Region *rgn = &ins->regions[index];
+ DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex];
+
+ sample->low_freq = freq_table[rgn->header->RangeKey.usLow];
+ sample->high_freq = freq_table[rgn->header->RangeKey.usHigh];
+ sample->root_freq = freq_table[rgn->wsmp->usUnityNote];
+ sample->low_vel = rgn->header->RangeVelocity.usLow;
+ sample->high_vel = rgn->header->RangeVelocity.usHigh;
+
+ sample->modes = MODES_16BIT;
+ sample->sample_rate = wave->format->dwSamplesPerSec;
+ sample->data_length = wave->length / 2;
+ sample->data = (sample_t *)safe_malloc(wave->length);
+ memcpy(sample->data, wave->data, wave->length);
+ if (rgn->wsmp->cSampleLoops) {
+ sample->modes |= (MODES_LOOPING|MODES_SUSTAIN);
+ sample->loop_start = rgn->wsmp_loop->ulStart / 2;
+ sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
+ }
+ sample->volume = 1.0f;
+
+ if (sample->modes & MODES_SUSTAIN) {
+ int value;
+ double attack, hold, decay, release; int sustain;
+ CONNECTIONLIST *art = NULL;
+ CONNECTION *artList = NULL;
+
+ if (ins->art && ins->art->cConnections > 0 && ins->artList) {
+ art = ins->art;
+ artList = ins->artList;
+ } else {
+ art = rgn->art;
+ artList = rgn->artList;
+ }
+
+ value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
+ attack = to_msec(value);
+ value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
+ hold = to_msec(value);
+ value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
+ decay = to_msec(value);
+ value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
+ release = to_msec(value);
+ value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
+ sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0);
+ value = load_connection(art->cConnections, artList, CONN_DST_PAN);
+ sample->panning = (int)((0.5 + to_normalized_percent(value)) * 127.0);
+
+/*
+printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release);
+*/
+
+ sample->envelope_offset[0] = to_offset(255);
+ sample->envelope_rate[0] = calc_rate(song, 255, sample->sample_rate, attack);
+
+ sample->envelope_offset[1] = to_offset(250);
+ sample->envelope_rate[1] = calc_rate(song, 5, sample->sample_rate, hold);
+
+ sample->envelope_offset[2] = to_offset(sustain);
+ sample->envelope_rate[2] = calc_rate(song, 255 - sustain, sample->sample_rate, decay);
+
+ sample->envelope_offset[3] = to_offset(0);
+ sample->envelope_rate[3] = calc_rate(song, 5 + sustain, sample->sample_rate, release);
+
+ sample->envelope_offset[4] = to_offset(0);
+ sample->envelope_rate[4] = to_offset(1);
+
+ sample->envelope_offset[5] = to_offset(0);
+ sample->envelope_rate[5] = to_offset(1);
+
+ sample->modes |= MODES_ENVELOPE;
+ }
+
+ sample->data_length <<= FRACTION_BITS;
+ sample->loop_start <<= FRACTION_BITS;
+ sample->loop_end <<= FRACTION_BITS;
+}
+
+Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument)
+{
+ Instrument *inst;
+ Uint32 i;
+ DLS_Instrument *dls_ins;
+
+ if (!song->patches)
+ return(NULL);
+
+ drum = drum ? 0x80000000 : 0;
+ for (i = 0; i < song->patches->cInstruments; ++i) {
+ dls_ins = &song->patches->instruments[i];
+ if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum &&
+ ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == bank &&
+ dls_ins->header->Locale.ulInstrument == instrument)
+ break;
+ }
+ if (i == song->patches->cInstruments && !bank) {
+ for (i = 0; i < song->patches->cInstruments; ++i) {
+ dls_ins = &song->patches->instruments[i];
+ if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum &&
+ dls_ins->header->Locale.ulInstrument == instrument)
+ break;
+ }
+ }
+ if (i == song->patches->cInstruments) {
+ SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank));
+ return(NULL);
+ }
+
+ inst = (Instrument *)safe_malloc(sizeof(*inst));
+ inst->samples = dls_ins->header->cRegions;
+ inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(*inst->sample));
+ memset(inst->sample, 0, inst->samples * sizeof(*inst->sample));
+/*
+printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples);
+*/
+ for (i = 0; i < dls_ins->header->cRegions; ++i) {
+ load_region_dls(song, &inst->sample[i], dls_ins, i);
+ }
+ return(inst);
+}
diff --git a/util/sdl/sound/decoders/timidity/instrum_dls.h b/util/sdl/sound/decoders/timidity/instrum_dls.h
new file mode 100644
index 00000000..ac3865a0
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/instrum_dls.h
@@ -0,0 +1,24 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ instrum.h
+
+ */
+
+extern Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument);
diff --git a/util/sdl/sound/decoders/timidity/mix.c b/util/sdl/sound/decoders/timidity/mix.c
new file mode 100644
index 00000000..af8869ae
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/mix.c
@@ -0,0 +1,573 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ Suddenly, you realize that this program is free software; you get
+ an overwhelming urge to redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received another copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ I bet they'll be amazed.
+
+ mix.c */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "options.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "output.h"
+#include "tables.h"
+#include "resample.h"
+#include "mix.h"
+
+/* Returns 1 if envelope runs out */
+int recompute_envelope(MidiSong *song, int v)
+{
+ int stage;
+
+ stage = song->voice[v].envelope_stage;
+
+ if (stage>5)
+ {
+ /* Envelope ran out. */
+ song->voice[v].status = VOICE_FREE;
+ return 1;
+ }
+
+ if (song->voice[v].sample->modes & MODES_ENVELOPE)
+ {
+ if (song->voice[v].status==VOICE_ON || song->voice[v].status==VOICE_SUSTAINED)
+ {
+ if (stage>2)
+ {
+ /* Freeze envelope until note turns off. Trumpets want this. */
+ song->voice[v].envelope_increment=0;
+ return 0;
+ }
+ }
+ }
+ song->voice[v].envelope_stage=stage+1;
+
+ if (song->voice[v].envelope_volume==song->voice[v].sample->envelope_offset[stage])
+ return recompute_envelope(song, v);
+ song->voice[v].envelope_target = song->voice[v].sample->envelope_offset[stage];
+ song->voice[v].envelope_increment = song->voice[v].sample->envelope_rate[stage];
+ if (song->voice[v].envelope_target < song->voice[v].envelope_volume)
+ song->voice[v].envelope_increment = -song->voice[v].envelope_increment;
+ return 0;
+}
+
+void apply_envelope_to_amp(MidiSong *song, int v)
+{
+ float lamp = song->voice[v].left_amp, ramp;
+ Sint32 la,ra;
+ if (song->voice[v].panned == PANNED_MYSTERY)
+ {
+ ramp = song->voice[v].right_amp;
+ if (song->voice[v].tremolo_phase_increment)
+ {
+ lamp *= song->voice[v].tremolo_volume;
+ ramp *= song->voice[v].tremolo_volume;
+ }
+ if (song->voice[v].sample->modes & MODES_ENVELOPE)
+ {
+ lamp *= (float)vol_table[song->voice[v].envelope_volume>>23];
+ ramp *= (float)vol_table[song->voice[v].envelope_volume>>23];
+ }
+
+ la = (Sint32)FSCALE(lamp,AMP_BITS);
+
+ if (la>MAX_AMP_VALUE)
+ la=MAX_AMP_VALUE;
+
+ ra = (Sint32)FSCALE(ramp,AMP_BITS);
+ if (ra>MAX_AMP_VALUE)
+ ra=MAX_AMP_VALUE;
+
+ song->voice[v].left_mix = la;
+ song->voice[v].right_mix = ra;
+ }
+ else
+ {
+ if (song->voice[v].tremolo_phase_increment)
+ lamp *= song->voice[v].tremolo_volume;
+ if (song->voice[v].sample->modes & MODES_ENVELOPE)
+ lamp *= (float)vol_table[song->voice[v].envelope_volume>>23];
+
+ la = (Sint32)FSCALE(lamp,AMP_BITS);
+
+ if (la>MAX_AMP_VALUE)
+ la=MAX_AMP_VALUE;
+
+ song->voice[v].left_mix = la;
+ }
+}
+
+static int update_envelope(MidiSong *song, int v)
+{
+ song->voice[v].envelope_volume += song->voice[v].envelope_increment;
+ /* Why is there no ^^ operator?? */
+ if (((song->voice[v].envelope_increment < 0) &&
+ (song->voice[v].envelope_volume <= song->voice[v].envelope_target)) ||
+ ((song->voice[v].envelope_increment > 0) &&
+ (song->voice[v].envelope_volume >= song->voice[v].envelope_target)))
+ {
+ song->voice[v].envelope_volume = song->voice[v].envelope_target;
+ if (recompute_envelope(song, v))
+ return 1;
+ }
+ return 0;
+}
+
+static void update_tremolo(MidiSong *song, int v)
+{
+ Sint32 depth = song->voice[v].sample->tremolo_depth << 7;
+
+ if (song->voice[v].tremolo_sweep)
+ {
+ /* Update sweep position */
+
+ song->voice[v].tremolo_sweep_position += song->voice[v].tremolo_sweep;
+ if (song->voice[v].tremolo_sweep_position >= (1 << SWEEP_SHIFT))
+ song->voice[v].tremolo_sweep=0; /* Swept to max amplitude */
+ else
+ {
+ /* Need to adjust depth */
+ depth *= song->voice[v].tremolo_sweep_position;
+ depth >>= SWEEP_SHIFT;
+ }
+ }
+
+ song->voice[v].tremolo_phase += song->voice[v].tremolo_phase_increment;
+
+ /* if (song->voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<<RATE_SHIFT))
+ song->voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<<RATE_SHIFT; */
+
+ song->voice[v].tremolo_volume = (float)
+ (1.0 - FSCALENEG((sine(song->voice[v].tremolo_phase >> RATE_SHIFT) + 1.0)
+ * depth * TREMOLO_AMPLITUDE_TUNING,
+ 17));
+
+ /* I'm not sure about the +1.0 there -- it makes tremoloed voices'
+ volumes on average the lower the higher the tremolo amplitude. */
+}
+
+/* Returns 1 if the note died */
+static int update_signal(MidiSong *song, int v)
+{
+ if (song->voice[v].envelope_increment && update_envelope(song, v))
+ return 1;
+
+ if (song->voice[v].tremolo_phase_increment)
+ update_tremolo(song, v);
+
+ apply_envelope_to_amp(song, v);
+ return 0;
+}
+
+#define MIXATION(a) *lp++ += (a)*s;
+
+static void mix_mystery_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
+ int count)
+{
+ Voice *vp = song->voice + v;
+ final_volume_t
+ left=vp->left_mix,
+ right=vp->right_mix;
+ int cc;
+ sample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ right = vp->right_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(right);
+ }
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ right = vp->right_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(right);
+ }
+ return;
+ }
+}
+
+static void mix_center_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
+ int count)
+{
+ Voice *vp = song->voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ sample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ return;
+ }
+}
+
+static void mix_single_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
+ int count)
+{
+ Voice *vp = song->voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ sample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ lp++;
+ }
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ lp++;
+ }
+ return;
+ }
+}
+
+static void mix_mono_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
+ int count)
+{
+ Voice *vp = song->voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ sample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ }
+ cc = song->control_ratio;
+ if (update_signal(song, v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ }
+ return;
+ }
+}
+
+static void mix_mystery(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
+{
+ final_volume_t
+ left = song->voice[v].left_mix,
+ right = song->voice[v].right_mix;
+ sample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(right);
+ }
+}
+
+static void mix_center(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
+{
+ final_volume_t
+ left = song->voice[v].left_mix;
+ sample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(left);
+ }
+}
+
+static void mix_single(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
+{
+ final_volume_t
+ left = song->voice[v].left_mix;
+ sample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ lp++;
+ }
+}
+
+static void mix_mono(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
+{
+ final_volume_t
+ left = song->voice[v].left_mix;
+ sample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ }
+}
+
+/* Ramp a note out in c samples */
+static void ramp_out(MidiSong *song, sample_t *sp, Sint32 *lp, int v, Sint32 c)
+{
+
+ /* should be final_volume_t, but Uint8 gives trouble. */
+ Sint32 left, right, li, ri;
+
+ sample_t s=0; /* silly warning about uninitialized s */
+
+ /* Fix by James Caldwell */
+ if ( c == 0 ) c = 1;
+
+ left=song->voice[v].left_mix;
+ li=-(left/c);
+ if (!li) li=-1;
+
+ /* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */
+
+ if (!(song->encoding & PE_MONO))
+ {
+ if (song->voice[v].panned==PANNED_MYSTERY)
+ {
+ right=song->voice[v].right_mix;
+ ri=-(right/c);
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ left=0;
+ right += ri;
+ if (right<0)
+ right=0;
+ s=*sp++;
+ MIXATION(left);
+ MIXATION(right);
+ }
+ }
+ else if (song->voice[v].panned==PANNED_CENTER)
+ {
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+ else if (song->voice[v].panned==PANNED_LEFT)
+ {
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ MIXATION(left);
+ lp++;
+ }
+ }
+ else if (song->voice[v].panned==PANNED_RIGHT)
+ {
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ lp++;
+ MIXATION(left);
+ }
+ }
+ }
+ else
+ {
+ /* Mono output. */
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ MIXATION(left);
+ }
+ }
+}
+
+
+/**************** interface function ******************/
+
+void mix_voice(MidiSong *song, Sint32 *buf, int v, Sint32 c)
+{
+ Voice *vp = song->voice + v;
+ sample_t *sp;
+ if (vp->status==VOICE_DIE)
+ {
+ if (c>=MAX_DIE_TIME)
+ c=MAX_DIE_TIME;
+ sp=resample_voice(song, v, &c);
+ ramp_out(song, sp, buf, v, c);
+ vp->status=VOICE_FREE;
+ }
+ else
+ {
+ sp=resample_voice(song, v, &c);
+ if (song->encoding & PE_MONO)
+ {
+ /* Mono output. */
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_mono_signal(song, sp, buf, v, c);
+ else
+ mix_mono(song, sp, buf, v, c);
+ }
+ else
+ {
+ if (vp->panned == PANNED_MYSTERY)
+ {
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_mystery_signal(song, sp, buf, v, c);
+ else
+ mix_mystery(song, sp, buf, v, c);
+ }
+ else if (vp->panned == PANNED_CENTER)
+ {
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_center_signal(song, sp, buf, v, c);
+ else
+ mix_center(song, sp, buf, v, c);
+ }
+ else
+ {
+ /* It's either full left or full right. In either case,
+ every other sample is 0. Just get the offset right: */
+ if (vp->panned == PANNED_RIGHT) buf++;
+
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_single_signal(song, sp, buf, v, c);
+ else
+ mix_single(song, sp, buf, v, c);
+ }
+ }
+ }
+}
diff --git a/util/sdl/sound/decoders/timidity/mix.h b/util/sdl/sound/decoders/timidity/mix.h
new file mode 100644
index 00000000..b94c32b9
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/mix.h
@@ -0,0 +1,27 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ In case you haven't heard, this program is free software;
+ you can redistribute it and/or modify it under the terms of the
+ GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ mix.h
+
+*/
+
+extern void mix_voice(MidiSong *song, Sint32 *buf, int v, Sint32 c);
+extern int recompute_envelope(MidiSong *song, int v);
+extern void apply_envelope_to_amp(MidiSong *song, int v);
diff --git a/util/sdl/sound/decoders/timidity/options.h b/util/sdl/sound/decoders/timidity/options.h
new file mode 100644
index 00000000..4fa2fb7c
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/options.h
@@ -0,0 +1,113 @@
+/*
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* When a patch file can't be opened, one of these extensions is
+ appended to the filename and the open is tried again.
+ */
+#define PATCH_EXT_LIST { ".pat", 0 }
+
+/* Acoustic Grand Piano seems to be the usual default instrument. */
+#define DEFAULT_PROGRAM 0
+
+/* 9 here is MIDI channel 10, which is the standard percussion channel.
+ Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too.
+ On the other hand, some files know that 16 is not a drum channel and
+ try to play music on it. This is now a runtime option, so this isn't
+ a critical choice anymore. */
+#define DEFAULT_DRUMCHANNELS ((1<<9) | (1<<15))
+
+/* In percent. */
+#define DEFAULT_AMPLIFICATION 70
+
+/* Default polyphony */
+#define DEFAULT_VOICES 32
+
+/* 1000 here will give a control ratio of 22:1 with 22 kHz output.
+ Higher CONTROLS_PER_SECOND values allow more accurate rendering
+ of envelopes and tremolo. The cost is CPU time. */
+#define CONTROLS_PER_SECOND 1000
+
+/* Make envelopes twice as fast. Saves ~20% CPU time (notes decay
+ faster) and sounds more like a GUS. There is now a command line
+ option to toggle this as well. */
+#define FAST_DECAY
+
+/* How many bits to use for the fractional part of sample positions.
+ This affects tonal accuracy. The entire position counter must fit
+ in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of
+ a sample is 1048576 samples (2 megabytes in memory). The GUS gets
+ by with just 9 bits and a little help from its friends...
+ "The GUS does not SUCK!!!" -- a happy user :) */
+#define FRACTION_BITS 12
+
+/* For some reason the sample volume is always set to maximum in all
+ patch files. Define this for a crude adjustment that may help
+ equalize instrument volumes. */
+#define ADJUST_SAMPLE_VOLUMES
+
+/* The number of samples to use for ramping out a dying note. Affects
+ click removal. */
+#define MAX_DIE_TIME 20
+
+/**************************************************************************/
+/* Anything below this shouldn't need to be changed unless you're porting
+ to a new machine with other than 32-bit, big-endian words. */
+/**************************************************************************/
+
+/* change FRACTION_BITS above, not these */
+#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS)
+#define FRACTION_MASK (~ INTEGER_MASK)
+
+/* This is enforced by some computations that must fit in an int */
+#define MAX_CONTROL_RATIO 255
+
+#define MAX_AMPLIFICATION 800
+
+/* The TiMidity configuration file */
+#define CONFIG_FILE "timidity.cfg"
+
+/* These affect general volume */
+#define GUARD_BITS 3
+#define AMP_BITS (15-GUARD_BITS)
+
+#define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1)
+
+#define FSCALE(a,b) (float)((a) * (double)(1<<(b)))
+#define FSCALENEG(a,b) (float)((a) * (1.0L / (double)(1<<(b))))
+
+/* Vibrato and tremolo Choices of the Day */
+#define SWEEP_TUNING 38
+#define VIBRATO_AMPLITUDE_TUNING 1.0L
+#define VIBRATO_RATE_TUNING 38
+#define TREMOLO_AMPLITUDE_TUNING 1.0L
+#define TREMOLO_RATE_TUNING 38
+
+#define SWEEP_SHIFT 16
+#define RATE_SHIFT 5
+
+#ifndef PI
+ #define PI 3.14159265358979323846
+#endif
+
+/* The path separator (D.M.) */
+#ifdef WIN32
+# define PATH_SEP '\\'
+#else
+# define PATH_SEP '/'
+#endif
diff --git a/util/sdl/sound/decoders/timidity/output.c b/util/sdl/sound/decoders/timidity/output.c
new file mode 100644
index 00000000..cfe3991c
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/output.c
@@ -0,0 +1,116 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ output.c
+
+ Audio output (to file / device) functions.
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "options.h"
+#include "output.h"
+
+/*****************************************************************/
+/* Some functions to convert signed 32-bit data to other formats */
+
+void s32tos8(void *dp, Sint32 *lp, Sint32 c)
+{
+ Sint8 *cp=(Sint8 *)(dp);
+ Sint32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-8-GUARD_BITS);
+ if (l>127) l=127;
+ else if (l<-128) l=-128;
+ *cp++ = (Sint8) (l);
+ }
+}
+
+void s32tou8(void *dp, Sint32 *lp, Sint32 c)
+{
+ Uint8 *cp=(Uint8 *)(dp);
+ Sint32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-8-GUARD_BITS);
+ if (l>127) l=127;
+ else if (l<-128) l=-128;
+ *cp++ = 0x80 ^ ((Uint8) l);
+ }
+}
+
+void s32tos16(void *dp, Sint32 *lp, Sint32 c)
+{
+ Sint16 *sp=(Sint16 *)(dp);
+ Sint32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = (Sint16)(l);
+ }
+}
+
+void s32tou16(void *dp, Sint32 *lp, Sint32 c)
+{
+ Uint16 *sp=(Uint16 *)(dp);
+ Sint32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = 0x8000 ^ (Uint16)(l);
+ }
+}
+
+void s32tos16x(void *dp, Sint32 *lp, Sint32 c)
+{
+ Sint16 *sp=(Sint16 *)(dp);
+ Sint32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = SDL_Swap16((Sint16)(l));
+ }
+}
+
+void s32tou16x(void *dp, Sint32 *lp, Sint32 c)
+{
+ Uint16 *sp=(Uint16 *)(dp);
+ Sint32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = SDL_Swap16(0x8000 ^ (Uint16)(l));
+ }
+}
diff --git a/util/sdl/sound/decoders/timidity/output.h b/util/sdl/sound/decoders/timidity/output.h
new file mode 100644
index 00000000..9cbe3326
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/output.h
@@ -0,0 +1,56 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ output.h
+
+*/
+
+/* Data format encoding bits */
+
+#define PE_MONO 0x01 /* versus stereo */
+#define PE_SIGNED 0x02 /* versus unsigned */
+#define PE_16BIT 0x04 /* versus 8-bit */
+
+/* Conversion functions -- These overwrite the Sint32 data in *lp with
+ data in another format */
+
+/* 8-bit signed and unsigned*/
+extern void s32tos8(void *dp, Sint32 *lp, Sint32 c);
+extern void s32tou8(void *dp, Sint32 *lp, Sint32 c);
+
+/* 16-bit */
+extern void s32tos16(void *dp, Sint32 *lp, Sint32 c);
+extern void s32tou16(void *dp, Sint32 *lp, Sint32 c);
+
+/* byte-exchanged 16-bit */
+extern void s32tos16x(void *dp, Sint32 *lp, Sint32 c);
+extern void s32tou16x(void *dp, Sint32 *lp, Sint32 c);
+
+/* little-endian and big-endian specific */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define s32tou16l s32tou16
+#define s32tou16b s32tou16x
+#define s32tos16l s32tos16
+#define s32tos16b s32tos16x
+#else
+#define s32tou16l s32tou16x
+#define s32tou16b s32tou16
+#define s32tos16l s32tos16x
+#define s32tos16b s32tos16
+#endif
diff --git a/util/sdl/sound/decoders/timidity/playmidi.c b/util/sdl/sound/decoders/timidity/playmidi.c
new file mode 100644
index 00000000..cd0b3cda
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/playmidi.c
@@ -0,0 +1,806 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ playmidi.c -- random stuff in need of rearrangement
+
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "options.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "output.h"
+#include "mix.h"
+#include "tables.h"
+
+static void adjust_amplification(MidiSong *song)
+{
+ song->master_volume = (float)(song->amplification) / (float)100.0;
+}
+
+static void reset_voices(MidiSong *song)
+{
+ int i;
+ for (i=0; i<MAX_VOICES; i++)
+ song->voice[i].status=VOICE_FREE;
+}
+
+/* Process the Reset All Controllers event */
+static void reset_controllers(MidiSong *song, int c)
+{
+ song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */
+ song->channel[c].expression=127; /* SCC-1 does this. */
+ song->channel[c].sustain=0;
+ song->channel[c].pitchbend=0x2000;
+ song->channel[c].pitchfactor=0; /* to be computed */
+}
+
+static void reset_midi(MidiSong *song)
+{
+ int i;
+ for (i=0; i<16; i++)
+ {
+ reset_controllers(song, i);
+ /* The rest of these are unaffected by the Reset All Controllers event */
+ song->channel[i].program=song->default_program;
+ song->channel[i].panning=NO_PANNING;
+ song->channel[i].pitchsens=2;
+ song->channel[i].bank=0; /* tone bank or drum set */
+ }
+ reset_voices(song);
+}
+
+static void select_sample(MidiSong *song, int v, Instrument *ip, int vel)
+{
+ Sint32 f, cdiff, diff;
+ int s,i;
+ Sample *sp, *closest;
+
+ s=ip->samples;
+ sp=ip->sample;
+
+ if (s==1)
+ {
+ song->voice[v].sample=sp;
+ return;
+ }
+
+ f=song->voice[v].orig_frequency;
+ for (i=0; i<s; i++)
+ {
+ if (sp->low_vel <= vel && sp->high_vel >= vel &&
+ sp->low_freq <= f && sp->high_freq >= f)
+ {
+ song->voice[v].sample=sp;
+ return;
+ }
+ sp++;
+ }
+
+ /*
+ No suitable sample found! We'll select the sample whose root
+ frequency is closest to the one we want. (Actually we should
+ probably convert the low, high, and root frequencies to MIDI note
+ values and compare those.) */
+
+ cdiff=0x7FFFFFFF;
+ closest=sp=ip->sample;
+ for(i=0; i<s; i++)
+ {
+ diff=sp->root_freq - f;
+ if (diff<0) diff=-diff;
+ if (diff<cdiff)
+ {
+ cdiff=diff;
+ closest=sp;
+ }
+ sp++;
+ }
+ song->voice[v].sample=closest;
+ return;
+}
+
+static void recompute_freq(MidiSong *song, int v)
+{
+ int
+ sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */
+ pb=song->channel[song->voice[v].channel].pitchbend;
+ double a;
+
+ if (!song->voice[v].sample->sample_rate)
+ return;
+
+ if (song->voice[v].vibrato_control_ratio)
+ {
+ /* This instrument has vibrato. Invalidate any precomputed
+ sample_increments. */
+
+ int i=VIBRATO_SAMPLE_INCREMENTS;
+ while (i--)
+ song->voice[v].vibrato_sample_increment[i]=0;
+ }
+
+ if (pb==0x2000 || pb<0 || pb>0x3FFF)
+ song->voice[v].frequency = song->voice[v].orig_frequency;
+ else
+ {
+ pb-=0x2000;
+ if (!(song->channel[song->voice[v].channel].pitchfactor))
+ {
+ /* Damn. Somebody bent the pitch. */
+ Sint32 i=pb*song->channel[song->voice[v].channel].pitchsens;
+ if (pb<0)
+ i=-i;
+ song->channel[song->voice[v].channel].pitchfactor=
+ (float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]);
+ }
+ if (pb>0)
+ song->voice[v].frequency=
+ (Sint32)(song->channel[song->voice[v].channel].pitchfactor *
+ (double)(song->voice[v].orig_frequency));
+ else
+ song->voice[v].frequency=
+ (Sint32)((double)(song->voice[v].orig_frequency) /
+ song->channel[song->voice[v].channel].pitchfactor);
+ }
+
+ a = FSCALE(((double)(song->voice[v].sample->sample_rate) *
+ (double)(song->voice[v].frequency)) /
+ ((double)(song->voice[v].sample->root_freq) *
+ (double)(song->rate)),
+ FRACTION_BITS);
+
+ if (sign)
+ a = -a; /* need to preserve the loop direction */
+
+ song->voice[v].sample_increment = (Sint32)(a);
+}
+
+static void recompute_amp(MidiSong *song, int v)
+{
+ Sint32 tempamp;
+
+ /* TODO: use fscale */
+
+ tempamp= (song->voice[v].velocity *
+ song->channel[song->voice[v].channel].volume *
+ song->channel[song->voice[v].channel].expression); /* 21 bits */
+
+ if (!(song->encoding & PE_MONO))
+ {
+ if (song->voice[v].panning > 60 && song->voice[v].panning < 68)
+ {
+ song->voice[v].panned=PANNED_CENTER;
+
+ song->voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+ 21);
+ }
+ else if (song->voice[v].panning<5)
+ {
+ song->voice[v].panned = PANNED_LEFT;
+
+ song->voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+ 20);
+ }
+ else if (song->voice[v].panning>123)
+ {
+ song->voice[v].panned = PANNED_RIGHT;
+
+ song->voice[v].left_amp= /* left_amp will be used */
+ FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+ 20);
+ }
+ else
+ {
+ song->voice[v].panned = PANNED_MYSTERY;
+
+ song->voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+ 27);
+ song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning);
+ song->voice[v].left_amp *= (float)(127 - song->voice[v].panning);
+ }
+ }
+ else
+ {
+ song->voice[v].panned = PANNED_CENTER;
+
+ song->voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
+ 21);
+ }
+}
+
+static void start_note(MidiSong *song, MidiEvent *e, int i)
+{
+ Instrument *ip;
+ int j;
+
+ if (ISDRUMCHANNEL(song, e->channel))
+ {
+ if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a]))
+ {
+ if (!(ip=song->drumset[0]->instrument[e->a]))
+ return; /* No instrument? Then we can't play. */
+ }
+ if (ip->samples != 1)
+ {
+ SNDDBG(("Strange: percussion instrument with %d samples!",
+ ip->samples));
+ }
+
+ if (ip->sample->note_to_use) /* Do we have a fixed pitch? */
+ song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
+ else
+ song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
+
+ /* drums are supposed to have only one sample */
+ song->voice[i].sample = ip->sample;
+ }
+ else
+ {
+ if (song->channel[e->channel].program == SPECIAL_PROGRAM)
+ ip=song->default_instrument;
+ else if (!(ip=song->tonebank[song->channel[e->channel].bank]->
+ instrument[song->channel[e->channel].program]))
+ {
+ if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program]))
+ return; /* No instrument? Then we can't play. */
+ }
+
+ if (ip->sample->note_to_use) /* Fixed-pitch instrument? */
+ song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
+ else
+ song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
+ select_sample(song, i, ip, e->b);
+ }
+
+ song->voice[i].status = VOICE_ON;
+ song->voice[i].channel = e->channel;
+ song->voice[i].note = e->a;
+ song->voice[i].velocity = e->b;
+ song->voice[i].sample_offset = 0;
+ song->voice[i].sample_increment = 0; /* make sure it isn't negative */
+
+ song->voice[i].tremolo_phase = 0;
+ song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment;
+ song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment;
+ song->voice[i].tremolo_sweep_position = 0;
+
+ song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment;
+ song->voice[i].vibrato_sweep_position = 0;
+ song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio;
+ song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0;
+ for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)
+ song->voice[i].vibrato_sample_increment[j] = 0;
+
+ if (song->channel[e->channel].panning != NO_PANNING)
+ song->voice[i].panning = song->channel[e->channel].panning;
+ else
+ song->voice[i].panning = song->voice[i].sample->panning;
+
+ recompute_freq(song, i);
+ recompute_amp(song, i);
+ if (song->voice[i].sample->modes & MODES_ENVELOPE)
+ {
+ /* Ramp up from 0 */
+ song->voice[i].envelope_stage = 0;
+ song->voice[i].envelope_volume = 0;
+ song->voice[i].control_counter = 0;
+ recompute_envelope(song, i);
+ apply_envelope_to_amp(song, i);
+ }
+ else
+ {
+ song->voice[i].envelope_increment = 0;
+ apply_envelope_to_amp(song, i);
+ }
+}
+
+static void kill_note(MidiSong *song, int i)
+{
+ song->voice[i].status = VOICE_DIE;
+}
+
+/* Only one instance of a note can be playing on a single channel. */
+static void note_on(MidiSong *song)
+{
+ int i = song->voices, lowest=-1;
+ Sint32 lv=0x7FFFFFFF, v;
+ MidiEvent *e = song->current_event;
+
+ while (i--)
+ {
+ if (song->voice[i].status == VOICE_FREE)
+ lowest=i; /* Can't get a lower volume than silence */
+ else if (song->voice[i].channel==e->channel &&
+ (song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono))
+ kill_note(song, i);
+ }
+
+ if (lowest != -1)
+ {
+ /* Found a free voice. */
+ start_note(song,e,lowest);
+ return;
+ }
+
+ /* Look for the decaying note with the lowest volume */
+ i = song->voices;
+ while (i--)
+ {
+ if ((song->voice[i].status != VOICE_ON) &&
+ (song->voice[i].status != VOICE_DIE))
+ {
+ v = song->voice[i].left_mix;
+ if ((song->voice[i].panned == PANNED_MYSTERY)
+ && (song->voice[i].right_mix > v))
+ v = song->voice[i].right_mix;
+ if (v<lv)
+ {
+ lv=v;
+ lowest=i;
+ }
+ }
+ }
+
+ if (lowest != -1)
+ {
+ /* This can still cause a click, but if we had a free voice to
+ spare for ramping down this note, we wouldn't need to kill it
+ in the first place... Still, this needs to be fixed. Perhaps
+ we could use a reserve of voices to play dying notes only. */
+
+ song->cut_notes++;
+ song->voice[lowest].status=VOICE_FREE;
+ start_note(song,e,lowest);
+ }
+ else
+ song->lost_notes++;
+}
+
+static void finish_note(MidiSong *song, int i)
+{
+ if (song->voice[i].sample->modes & MODES_ENVELOPE)
+ {
+ /* We need to get the envelope out of Sustain stage */
+ song->voice[i].envelope_stage = 3;
+ song->voice[i].status = VOICE_OFF;
+ recompute_envelope(song, i);
+ apply_envelope_to_amp(song, i);
+ }
+ else
+ {
+ /* Set status to OFF so resample_voice() will let this voice out
+ of its loop, if any. In any case, this voice dies when it
+ hits the end of its data (ofs>=data_length). */
+ song->voice[i].status = VOICE_OFF;
+ }
+}
+
+static void note_off(MidiSong *song)
+{
+ int i = song->voices;
+ MidiEvent *e = song->current_event;
+
+ while (i--)
+ if (song->voice[i].status == VOICE_ON &&
+ song->voice[i].channel == e->channel &&
+ song->voice[i].note == e->a)
+ {
+ if (song->channel[e->channel].sustain)
+ {
+ song->voice[i].status = VOICE_SUSTAINED;
+ }
+ else
+ finish_note(song, i);
+ return;
+ }
+}
+
+/* Process the All Notes Off event */
+static void all_notes_off(MidiSong *song)
+{
+ int i = song->voices;
+ int c = song->current_event->channel;
+
+ SNDDBG(("All notes off on channel %d", c));
+ while (i--)
+ if (song->voice[i].status == VOICE_ON &&
+ song->voice[i].channel == c)
+ {
+ if (song->channel[c].sustain)
+ song->voice[i].status = VOICE_SUSTAINED;
+ else
+ finish_note(song, i);
+ }
+}
+
+/* Process the All Sounds Off event */
+static void all_sounds_off(MidiSong *song)
+{
+ int i = song->voices;
+ int c = song->current_event->channel;
+
+ while (i--)
+ if (song->voice[i].channel == c &&
+ song->voice[i].status != VOICE_FREE &&
+ song->voice[i].status != VOICE_DIE)
+ {
+ kill_note(song, i);
+ }
+}
+
+static void adjust_pressure(MidiSong *song)
+{
+ MidiEvent *e = song->current_event;
+ int i = song->voices;
+
+ while (i--)
+ if (song->voice[i].status == VOICE_ON &&
+ song->voice[i].channel == e->channel &&
+ song->voice[i].note == e->a)
+ {
+ song->voice[i].velocity = e->b;
+ recompute_amp(song, i);
+ apply_envelope_to_amp(song, i);
+ return;
+ }
+}
+
+static void drop_sustain(MidiSong *song)
+{
+ int i = song->voices;
+ int c = song->current_event->channel;
+
+ while (i--)
+ if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c)
+ finish_note(song, i);
+}
+
+static void adjust_pitchbend(MidiSong *song)
+{
+ int c = song->current_event->channel;
+ int i = song->voices;
+
+ while (i--)
+ if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c)
+ {
+ recompute_freq(song, i);
+ }
+}
+
+static void adjust_volume(MidiSong *song)
+{
+ int c = song->current_event->channel;
+ int i = song->voices;
+
+ while (i--)
+ if (song->voice[i].channel == c &&
+ (song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED))
+ {
+ recompute_amp(song, i);
+ apply_envelope_to_amp(song, i);
+ }
+}
+
+static void seek_forward(MidiSong *song, Sint32 until_time)
+{
+ reset_voices(song);
+ while (song->current_event->time < until_time)
+ {
+ switch(song->current_event->type)
+ {
+ /* All notes stay off. Just handle the parameter changes. */
+
+ case ME_PITCH_SENS:
+ song->channel[song->current_event->channel].pitchsens =
+ song->current_event->a;
+ song->channel[song->current_event->channel].pitchfactor = 0;
+ break;
+
+ case ME_PITCHWHEEL:
+ song->channel[song->current_event->channel].pitchbend =
+ song->current_event->a + song->current_event->b * 128;
+ song->channel[song->current_event->channel].pitchfactor = 0;
+ break;
+
+ case ME_MAINVOLUME:
+ song->channel[song->current_event->channel].volume =
+ song->current_event->a;
+ break;
+
+ case ME_PAN:
+ song->channel[song->current_event->channel].panning =
+ song->current_event->a;
+ break;
+
+ case ME_EXPRESSION:
+ song->channel[song->current_event->channel].expression =
+ song->current_event->a;
+ break;
+
+ case ME_PROGRAM:
+ if (ISDRUMCHANNEL(song, song->current_event->channel))
+ /* Change drum set */
+ song->channel[song->current_event->channel].bank =
+ song->current_event->a;
+ else
+ song->channel[song->current_event->channel].program =
+ song->current_event->a;
+ break;
+
+ case ME_SUSTAIN:
+ song->channel[song->current_event->channel].sustain =
+ song->current_event->a;
+ break;
+
+ case ME_RESET_CONTROLLERS:
+ reset_controllers(song, song->current_event->channel);
+ break;
+
+ case ME_TONE_BANK:
+ song->channel[song->current_event->channel].bank =
+ song->current_event->a;
+ break;
+
+ case ME_EOT:
+ song->current_sample = song->current_event->time;
+ return;
+ }
+ song->current_event++;
+ }
+ /*song->current_sample=song->current_event->time;*/
+ if (song->current_event != song->events)
+ song->current_event--;
+ song->current_sample=until_time;
+}
+
+static void skip_to(MidiSong *song, Sint32 until_time)
+{
+ if (song->current_sample > until_time)
+ song->current_sample = 0;
+
+ reset_midi(song);
+ song->buffered_count = 0;
+ song->buffer_pointer = song->common_buffer;
+ song->current_event = song->events;
+
+ if (until_time)
+ seek_forward(song, until_time);
+}
+
+static void do_compute_data(MidiSong *song, Sint32 count)
+{
+ int i;
+ memset(song->buffer_pointer, 0,
+ (song->encoding & PE_MONO) ? (count * 4) : (count * 8));
+ for (i = 0; i < song->voices; i++)
+ {
+ if(song->voice[i].status != VOICE_FREE)
+ mix_voice(song, song->buffer_pointer, i, count);
+ }
+ song->current_sample += count;
+}
+
+/* count=0 means flush remaining buffered data to output device, then
+ flush the device itself */
+static void compute_data(MidiSong *song, void *stream, Sint32 count)
+{
+ int channels;
+
+ if ( song->encoding & PE_MONO )
+ channels = 1;
+ else
+ channels = 2;
+
+ if (!count)
+ {
+ if (song->buffered_count)
+ song->write(stream, song->common_buffer, channels * song->buffered_count);
+ song->buffer_pointer = song->common_buffer;
+ song->buffered_count = 0;
+ return;
+ }
+
+ while ((count + song->buffered_count) >= song->buffer_size)
+ {
+ do_compute_data(song, song->buffer_size - song->buffered_count);
+ count -= song->buffer_size - song->buffered_count;
+ song->write(stream, song->common_buffer, channels * song->buffer_size);
+ song->buffer_pointer = song->common_buffer;
+ song->buffered_count = 0;
+ }
+ if (count>0)
+ {
+ do_compute_data(song, count);
+ song->buffered_count += count;
+ song->buffer_pointer += (song->encoding & PE_MONO) ? count : count*2;
+ }
+}
+
+void Timidity_Start(MidiSong *song)
+{
+ song->playing = 1;
+ adjust_amplification(song);
+ skip_to(song, 0);
+}
+
+void Timidity_Seek(MidiSong *song, Uint32 ms)
+{
+ skip_to(song, (ms * song->rate) / 1000);
+}
+
+int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len)
+{
+ Sint32 start_sample, end_sample, samples;
+ int bytes_per_sample;
+
+ if (!song->playing)
+ return 0;
+
+ bytes_per_sample =
+ ((song->encoding & PE_MONO) ? 1 : 2)
+ * ((song->encoding & PE_16BIT) ? 2 : 1);
+ samples = len / bytes_per_sample;
+
+ start_sample = song->current_sample;
+ end_sample = song->current_sample+samples;
+ while ( song->current_sample < end_sample ) {
+ /* Handle all events that should happen at this time */
+ while (song->current_event->time <= song->current_sample) {
+ switch(song->current_event->type) {
+
+ /* Effects affecting a single note */
+
+ case ME_NOTEON:
+ if (!(song->current_event->b)) /* Velocity 0? */
+ note_off(song);
+ else
+ note_on(song);
+ break;
+
+ case ME_NOTEOFF:
+ note_off(song);
+ break;
+
+ case ME_KEYPRESSURE:
+ adjust_pressure(song);
+ break;
+
+ /* Effects affecting a single channel */
+
+ case ME_PITCH_SENS:
+ song->channel[song->current_event->channel].pitchsens =
+ song->current_event->a;
+ song->channel[song->current_event->channel].pitchfactor = 0;
+ break;
+
+ case ME_PITCHWHEEL:
+ song->channel[song->current_event->channel].pitchbend =
+ song->current_event->a + song->current_event->b * 128;
+ song->channel[song->current_event->channel].pitchfactor = 0;
+ /* Adjust pitch for notes already playing */
+ adjust_pitchbend(song);
+ break;
+
+ case ME_MAINVOLUME:
+ song->channel[song->current_event->channel].volume =
+ song->current_event->a;
+ adjust_volume(song);
+ break;
+
+ case ME_PAN:
+ song->channel[song->current_event->channel].panning =
+ song->current_event->a;
+ break;
+
+ case ME_EXPRESSION:
+ song->channel[song->current_event->channel].expression =
+ song->current_event->a;
+ adjust_volume(song);
+ break;
+
+ case ME_PROGRAM:
+ if (ISDRUMCHANNEL(song, song->current_event->channel)) {
+ /* Change drum set */
+ song->channel[song->current_event->channel].bank =
+ song->current_event->a;
+ }
+ else
+ song->channel[song->current_event->channel].program =
+ song->current_event->a;
+ break;
+
+ case ME_SUSTAIN:
+ song->channel[song->current_event->channel].sustain =
+ song->current_event->a;
+ if (!song->current_event->a)
+ drop_sustain(song);
+ break;
+
+ case ME_RESET_CONTROLLERS:
+ reset_controllers(song, song->current_event->channel);
+ break;
+
+ case ME_ALL_NOTES_OFF:
+ all_notes_off(song);
+ break;
+
+ case ME_ALL_SOUNDS_OFF:
+ all_sounds_off(song);
+ break;
+
+ case ME_TONE_BANK:
+ song->channel[song->current_event->channel].bank =
+ song->current_event->a;
+ break;
+
+ case ME_EOT:
+ /* Give the last notes a couple of seconds to decay */
+ SNDDBG(("Playing time: ~%d seconds\n",
+ song->current_sample/song->rate+2));
+ SNDDBG(("Notes cut: %d\n", song->cut_notes));
+ SNDDBG(("Notes lost totally: %d\n", song->lost_notes));
+ song->playing = 0;
+ return (song->current_sample - start_sample) * bytes_per_sample;
+ }
+ song->current_event++;
+ }
+ if (song->current_event->time > end_sample)
+ compute_data(song, stream, end_sample-song->current_sample);
+ else
+ compute_data(song, stream, song->current_event->time-song->current_sample);
+ }
+ return samples * bytes_per_sample;
+}
+
+void Timidity_SetVolume(MidiSong *song, int volume)
+{
+ int i;
+ if (volume > MAX_AMPLIFICATION)
+ song->amplification = MAX_AMPLIFICATION;
+ else
+ if (volume < 0)
+ song->amplification = 0;
+ else
+ song->amplification = volume;
+ adjust_amplification(song);
+ for (i = 0; i < song->voices; i++)
+ if (song->voice[i].status != VOICE_FREE)
+ {
+ recompute_amp(song, i);
+ apply_envelope_to_amp(song, i);
+ }
+}
diff --git a/util/sdl/sound/decoders/timidity/playmidi.h b/util/sdl/sound/decoders/timidity/playmidi.h
new file mode 100644
index 00000000..b4545ab2
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/playmidi.h
@@ -0,0 +1,64 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ playmidi.h
+
+ */
+
+/* Midi events */
+#define ME_NONE 0
+#define ME_NOTEON 1
+#define ME_NOTEOFF 2
+#define ME_KEYPRESSURE 3
+#define ME_MAINVOLUME 4
+#define ME_PAN 5
+#define ME_SUSTAIN 6
+#define ME_EXPRESSION 7
+#define ME_PITCHWHEEL 8
+#define ME_PROGRAM 9
+#define ME_TEMPO 10
+#define ME_PITCH_SENS 11
+
+#define ME_ALL_SOUNDS_OFF 12
+#define ME_RESET_CONTROLLERS 13
+#define ME_ALL_NOTES_OFF 14
+#define ME_TONE_BANK 15
+
+#define ME_LYRIC 16
+
+#define ME_EOT 99
+
+/* Causes the instrument's default panning to be used. */
+#define NO_PANNING -1
+
+/* Voice status options: */
+#define VOICE_FREE 0
+#define VOICE_ON 1
+#define VOICE_SUSTAINED 2
+#define VOICE_OFF 3
+#define VOICE_DIE 4
+
+/* Voice panned options: */
+#define PANNED_MYSTERY 0
+#define PANNED_LEFT 1
+#define PANNED_RIGHT 2
+#define PANNED_CENTER 3
+/* Anything but PANNED_MYSTERY only uses the left volume */
+
+#define ISDRUMCHANNEL(s, c) (((s)->drumchannels & (1<<(c))))
diff --git a/util/sdl/sound/decoders/timidity/readmidi.c b/util/sdl/sound/decoders/timidity/readmidi.c
new file mode 100644
index 00000000..f3435f79
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/readmidi.c
@@ -0,0 +1,584 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+
+/* Computes how many (fractional) samples one MIDI delta-time unit contains */
+static void compute_sample_increment(MidiSong *song, Sint32 tempo,
+ Sint32 divisions)
+{
+ double a;
+ a = (double) (tempo) * (double) (song->rate) * (65536.0/1000000.0) /
+ (double)(divisions);
+
+ song->sample_correction = (Sint32)(a) & 0xFFFF;
+ song->sample_increment = (Sint32)(a) >> 16;
+
+ SNDDBG(("Samples per delta-t: %d (correction %d)",
+ song->sample_increment, song->sample_correction));
+}
+
+/* Read variable-length number (7 bits per byte, MSB first) */
+static Sint32 getvl(SDL_RWops *rw)
+{
+ Sint32 l=0;
+ Uint8 c;
+ for (;;)
+ {
+ SDL_RWread(rw, &c, 1, 1);
+ l += (c & 0x7f);
+ if (!(c & 0x80)) return l;
+ l<<=7;
+ }
+}
+
+/* Print a string from the file, followed by a newline. Any non-ASCII
+ or unprintable characters will be converted to periods. */
+static int dumpstring(SDL_RWops *rw, Sint32 len, char *label)
+{
+ signed char *s=safe_malloc(len+1);
+ if (len != (Sint32) SDL_RWread(rw, s, 1, len))
+ {
+ free(s);
+ return -1;
+ }
+ s[len]='\0';
+ while (len--)
+ {
+ if (s[len]<32)
+ s[len]='.';
+ }
+ SNDDBG(("%s%s", label, s));
+ free(s);
+ return 0;
+}
+
+#define MIDIEVENT(at,t,ch,pa,pb) \
+ new=safe_malloc(sizeof(MidiEventList)); \
+ new->event.time=at; new->event.type=t; new->event.channel=ch; \
+ new->event.a=pa; new->event.b=pb; new->next=0;\
+ return new;
+
+#define MAGIC_EOT ((MidiEventList *)(-1))
+
+/* Read a MIDI event, returning a freshly allocated element that can
+ be linked to the event list */
+static MidiEventList *read_midi_event(MidiSong *song)
+{
+ static Uint8 laststatus, lastchan;
+ static Uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */
+ Uint8 me, type, a,b,c;
+ Sint32 len;
+ MidiEventList *new;
+
+ for (;;)
+ {
+ song->at += getvl(song->rw);
+ if (SDL_RWread(song->rw, &me, 1, 1) != 1)
+ {
+ SNDDBG(("read_midi_event: SDL_RWread() failure\n"));
+ return 0;
+ }
+
+ if(me==0xF0 || me == 0xF7) /* SysEx event */
+ {
+ len=getvl(song->rw);
+ SDL_RWseek(song->rw, len, SEEK_CUR);
+ }
+ else if(me==0xFF) /* Meta event */
+ {
+ SDL_RWread(song->rw, &type, 1, 1);
+ len=getvl(song->rw);
+ if (type>0 && type<16)
+ {
+ static char *label[]={
+ "Text event: ", "Text: ", "Copyright: ", "Track name: ",
+ "Instrument: ", "Lyric: ", "Marker: ", "Cue point: "};
+ dumpstring(song->rw, len, label[(type>7) ? 0 : type]);
+ }
+ else
+ switch(type)
+ {
+ case 0x2F: /* End of Track */
+ return MAGIC_EOT;
+
+ case 0x51: /* Tempo */
+ SDL_RWread(song->rw, &a, 1, 1);
+ SDL_RWread(song->rw, &b, 1, 1);
+ SDL_RWread(song->rw, &c, 1, 1);
+ MIDIEVENT(song->at, ME_TEMPO, c, a, b);
+
+ default:
+ SNDDBG(("(Meta event type 0x%02x, length %d)\n", type, len));
+ SDL_RWseek(song->rw, len, SEEK_CUR);
+ break;
+ }
+ }
+ else
+ {
+ a=me;
+ if (a & 0x80) /* status byte */
+ {
+ lastchan=a & 0x0F;
+ laststatus=(a>>4) & 0x07;
+ SDL_RWread(song->rw, &a, 1, 1);
+ a &= 0x7F;
+ }
+ switch(laststatus)
+ {
+ case 0: /* Note off */
+ SDL_RWread(song->rw, &b, 1, 1);
+ b &= 0x7F;
+ MIDIEVENT(song->at, ME_NOTEOFF, lastchan, a,b);
+
+ case 1: /* Note on */
+ SDL_RWread(song->rw, &b, 1, 1);
+ b &= 0x7F;
+ MIDIEVENT(song->at, ME_NOTEON, lastchan, a,b);
+
+ case 2: /* Key Pressure */
+ SDL_RWread(song->rw, &b, 1, 1);
+ b &= 0x7F;
+ MIDIEVENT(song->at, ME_KEYPRESSURE, lastchan, a, b);
+
+ case 3: /* Control change */
+ SDL_RWread(song->rw, &b, 1, 1);
+ b &= 0x7F;
+ {
+ int control=255;
+ switch(a)
+ {
+ case 7: control=ME_MAINVOLUME; break;
+ case 10: control=ME_PAN; break;
+ case 11: control=ME_EXPRESSION; break;
+ case 64: control=ME_SUSTAIN; break;
+ case 120: control=ME_ALL_SOUNDS_OFF; break;
+ case 121: control=ME_RESET_CONTROLLERS; break;
+ case 123: control=ME_ALL_NOTES_OFF; break;
+
+ /* These should be the SCC-1 tone bank switch
+ commands. I don't know why there are two, or
+ why the latter only allows switching to bank 0.
+ Also, some MIDI files use 0 as some sort of
+ continuous controller. This will cause lots of
+ warnings about undefined tone banks. */
+ case 0: control=ME_TONE_BANK; break;
+ case 32:
+ if (b!=0)
+ SNDDBG(("(Strange: tone bank change 0x20%02x)\n", b));
+ else
+ control=ME_TONE_BANK;
+ break;
+
+ case 100: nrpn=0; rpn_msb[lastchan]=b; break;
+ case 101: nrpn=0; rpn_lsb[lastchan]=b; break;
+ case 99: nrpn=1; rpn_msb[lastchan]=b; break;
+ case 98: nrpn=1; rpn_lsb[lastchan]=b; break;
+
+ case 6:
+ if (nrpn)
+ {
+ SNDDBG(("(Data entry (MSB) for NRPN %02x,%02x: %d)\n",
+ rpn_msb[lastchan], rpn_lsb[lastchan], b));
+ break;
+ }
+
+ switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan])
+ {
+ case 0x0000: /* Pitch bend sensitivity */
+ control=ME_PITCH_SENS;
+ break;
+
+ case 0x7F7F: /* RPN reset */
+ /* reset pitch bend sensitivity to 2 */
+ MIDIEVENT(song->at, ME_PITCH_SENS, lastchan, 2, 0);
+
+ default:
+ SNDDBG(("(Data entry (MSB) for RPN %02x,%02x: %d)\n",
+ rpn_msb[lastchan], rpn_lsb[lastchan], b));
+ break;
+ }
+ break;
+
+ default:
+ SNDDBG(("(Control %d: %d)\n", a, b));
+ break;
+ }
+ if (control != 255)
+ {
+ MIDIEVENT(song->at, control, lastchan, b, 0);
+ }
+ }
+ break;
+
+ case 4: /* Program change */
+ a &= 0x7f;
+ MIDIEVENT(song->at, ME_PROGRAM, lastchan, a, 0);
+
+ case 5: /* Channel pressure - NOT IMPLEMENTED */
+ break;
+
+ case 6: /* Pitch wheel */
+ SDL_RWread(song->rw, &b, 1, 1);
+ b &= 0x7F;
+ MIDIEVENT(song->at, ME_PITCHWHEEL, lastchan, a, b);
+
+ default:
+ SNDDBG(("*** Can't happen: status 0x%02X, channel 0x%02X\n",
+ laststatus, lastchan));
+ break;
+ }
+ }
+ }
+
+ return new;
+}
+
+#undef MIDIEVENT
+
+/* Read a midi track into the linked list, either merging with any previous
+ tracks or appending to them. */
+static int read_track(MidiSong *song, int append)
+{
+ MidiEventList *meep;
+ MidiEventList *next, *new;
+ Sint32 len;
+ char tmp[4];
+
+ meep = song->evlist;
+ if (append && meep)
+ {
+ /* find the last event in the list */
+ for (; meep->next; meep=meep->next)
+ ;
+ song->at = meep->event.time;
+ }
+ else
+ song->at=0;
+
+ /* Check the formalities */
+
+ if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1)
+ {
+ SNDDBG(("Can't read track header.\n"));
+ return -1;
+ }
+ len=SDL_SwapBE32(len);
+ if (memcmp(tmp, "MTrk", 4))
+ {
+ SNDDBG(("Corrupt MIDI file.\n"));
+ return -2;
+ }
+
+ for (;;)
+ {
+ if (!(new=read_midi_event(song))) /* Some kind of error */
+ return -2;
+
+ if (new==MAGIC_EOT) /* End-of-track Hack. */
+ {
+ return 0;
+ }
+
+ next=meep->next;
+ while (next && (next->event.time < new->event.time))
+ {
+ meep=next;
+ next=meep->next;
+ }
+
+ new->next=next;
+ meep->next=new;
+
+ song->event_count++; /* Count the event. (About one?) */
+ meep=new;
+ }
+}
+
+/* Free the linked event list from memory. */
+static void free_midi_list(MidiSong *song)
+{
+ MidiEventList *meep, *next;
+ if (!(meep = song->evlist)) return;
+ while (meep)
+ {
+ next=meep->next;
+ free(meep);
+ meep=next;
+ }
+ song->evlist=0;
+}
+
+/* Allocate an array of MidiEvents and fill it from the linked list of
+ events, marking used instruments for loading. Convert event times to
+ samples: handle tempo changes. Strip unnecessary events from the list.
+ Free the linked list. */
+static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp,
+ Sint32 *samplesp)
+{
+ MidiEvent *groomed_list, *lp;
+ MidiEventList *meep;
+ Sint32 i, our_event_count, tempo, skip_this_event, new_value;
+ Sint32 sample_cum, samples_to_do, at, st, dt, counting_time;
+
+ int current_bank[16], current_set[16], current_program[16];
+ /* Or should each bank have its own current program? */
+
+ for (i=0; i<16; i++)
+ {
+ current_bank[i]=0;
+ current_set[i]=0;
+ current_program[i]=song->default_program;
+ }
+
+ tempo=500000;
+ compute_sample_increment(song, tempo, divisions);
+
+ /* This may allocate a bit more than we need */
+ groomed_list=lp=safe_malloc(sizeof(MidiEvent) * (song->event_count+1));
+ meep=song->evlist;
+
+ our_event_count=0;
+ st=at=sample_cum=0;
+ counting_time=2; /* We strip any silence before the first NOTE ON. */
+
+ for (i = 0; i < song->event_count; i++)
+ {
+ skip_this_event=0;
+
+ if (meep->event.type==ME_TEMPO)
+ {
+ tempo=
+ meep->event.channel + meep->event.b * 256 + meep->event.a * 65536;
+ compute_sample_increment(song, tempo, divisions);
+ skip_this_event=1;
+ }
+ else switch (meep->event.type)
+ {
+ case ME_PROGRAM:
+ if (ISDRUMCHANNEL(song, meep->event.channel))
+ {
+ if (song->drumset[meep->event.a]) /* Is this a defined drumset? */
+ new_value=meep->event.a;
+ else
+ {
+ SNDDBG(("Drum set %d is undefined\n", meep->event.a));
+ new_value=meep->event.a=0;
+ }
+ if (current_set[meep->event.channel] != new_value)
+ current_set[meep->event.channel]=new_value;
+ else
+ skip_this_event=1;
+ }
+ else
+ {
+ new_value=meep->event.a;
+ if ((current_program[meep->event.channel] != SPECIAL_PROGRAM)
+ && (current_program[meep->event.channel] != new_value))
+ current_program[meep->event.channel] = new_value;
+ else
+ skip_this_event=1;
+ }
+ break;
+
+ case ME_NOTEON:
+ if (counting_time)
+ counting_time=1;
+ if (ISDRUMCHANNEL(song, meep->event.channel))
+ {
+ /* Mark this instrument to be loaded */
+ if (!(song->drumset[current_set[meep->event.channel]]
+ ->instrument[meep->event.a]))
+ song->drumset[current_set[meep->event.channel]]
+ ->instrument[meep->event.a] = MAGIC_LOAD_INSTRUMENT;
+ }
+ else
+ {
+ if (current_program[meep->event.channel]==SPECIAL_PROGRAM)
+ break;
+ /* Mark this instrument to be loaded */
+ if (!(song->tonebank[current_bank[meep->event.channel]]
+ ->instrument[current_program[meep->event.channel]]))
+ song->tonebank[current_bank[meep->event.channel]]
+ ->instrument[current_program[meep->event.channel]] =
+ MAGIC_LOAD_INSTRUMENT;
+ }
+ break;
+
+ case ME_TONE_BANK:
+ if (ISDRUMCHANNEL(song, meep->event.channel))
+ {
+ skip_this_event=1;
+ break;
+ }
+ if (song->tonebank[meep->event.a]) /* Is this a defined tone bank? */
+ new_value=meep->event.a;
+ else
+ {
+ SNDDBG(("Tone bank %d is undefined\n", meep->event.a));
+ new_value=meep->event.a=0;
+ }
+ if (current_bank[meep->event.channel]!=new_value)
+ current_bank[meep->event.channel]=new_value;
+ else
+ skip_this_event=1;
+ break;
+ }
+
+ /* Recompute time in samples*/
+ if ((dt=meep->event.time - at) && !counting_time)
+ {
+ samples_to_do = song->sample_increment * dt;
+ sample_cum += song->sample_correction * dt;
+ if (sample_cum & 0xFFFF0000)
+ {
+ samples_to_do += ((sample_cum >> 16) & 0xFFFF);
+ sample_cum &= 0x0000FFFF;
+ }
+ st += samples_to_do;
+ }
+ else if (counting_time==1) counting_time=0;
+ if (!skip_this_event)
+ {
+ /* Add the event to the list */
+ *lp=meep->event;
+ lp->time=st;
+ lp++;
+ our_event_count++;
+ }
+ at=meep->event.time;
+ meep=meep->next;
+ }
+ /* Add an End-of-Track event */
+ lp->time=st;
+ lp->type=ME_EOT;
+ our_event_count++;
+ free_midi_list(song);
+
+ *eventsp=our_event_count;
+ *samplesp=st;
+ return groomed_list;
+}
+
+MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp)
+{
+ Sint32 len, divisions;
+ Sint16 format, tracks, divisions_tmp;
+ int i;
+ char tmp[4];
+
+ song->event_count=0;
+ song->at=0;
+ song->evlist=0;
+
+ if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1)
+ {
+ SNDDBG(("Not a MIDI file!\n"));
+ return 0;
+ }
+ len=SDL_SwapBE32(len);
+ if (memcmp(tmp, "MThd", 4) || len < 6)
+ {
+ SNDDBG(("Not a MIDI file!\n"));
+ return 0;
+ }
+
+ SDL_RWread(song->rw, &format, 2, 1);
+ SDL_RWread(song->rw, &tracks, 2, 1);
+ SDL_RWread(song->rw, &divisions_tmp, 2, 1);
+ format=SDL_SwapBE16(format);
+ tracks=SDL_SwapBE16(tracks);
+ divisions_tmp=SDL_SwapBE16(divisions_tmp);
+
+ if (divisions_tmp<0)
+ {
+ /* SMPTE time -- totally untested. Got a MIDI file that uses this? */
+ divisions=
+ (Sint32)(-(divisions_tmp/256)) * (Sint32)(divisions_tmp & 0xFF);
+ }
+ else divisions=(Sint32)(divisions_tmp);
+
+ if (len > 6)
+ {
+ SNDDBG(("MIDI file header size %u bytes", len));
+ SDL_RWseek(song->rw, len-6, SEEK_CUR); /* skip the excess */
+ }
+ if (format<0 || format >2)
+ {
+ SNDDBG(("Unknown MIDI file format %d\n", format));
+ return 0;
+ }
+ SNDDBG(("Format: %d Tracks: %d Divisions: %d\n",
+ format, tracks, divisions));
+
+ /* Put a do-nothing event first in the list for easier processing */
+ song->evlist=safe_malloc(sizeof(MidiEventList));
+ song->evlist->event.time=0;
+ song->evlist->event.type=ME_NONE;
+ song->evlist->next=0;
+ song->event_count++;
+
+ switch(format)
+ {
+ case 0:
+ if (read_track(song, 0))
+ {
+ free_midi_list(song);
+ return 0;
+ }
+ break;
+
+ case 1:
+ for (i=0; i<tracks; i++)
+ if (read_track(song, 0))
+ {
+ free_midi_list(song);
+ return 0;
+ }
+ break;
+
+ case 2: /* We simply play the tracks sequentially */
+ for (i=0; i<tracks; i++)
+ if (read_track(song, 1))
+ {
+ free_midi_list(song);
+ return 0;
+ }
+ break;
+ }
+ return groom_list(song, divisions, count, sp);
+}
diff --git a/util/sdl/sound/decoders/timidity/readmidi.h b/util/sdl/sound/decoders/timidity/readmidi.h
new file mode 100644
index 00000000..0d129a05
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/readmidi.h
@@ -0,0 +1,24 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ readmidi.h
+
+ */
+
+extern MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp);
diff --git a/util/sdl/sound/decoders/timidity/resample.c b/util/sdl/sound/decoders/timidity/resample.c
new file mode 100644
index 00000000..31c739ca
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/resample.c
@@ -0,0 +1,612 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ resample.c
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "tables.h"
+#include "resample.h"
+
+/*************** resampling with fixed increment *****************/
+
+static sample_t *rs_plain(MidiSong *song, int v, Sint32 *countptr)
+{
+
+ /* Play sample until end, then free the voice. */
+
+ sample_t v1, v2;
+ Voice
+ *vp=&(song->voice[v]);
+ sample_t
+ *dest=song->resample_buffer,
+ *src=vp->sample->data;
+ Sint32
+ ofs=vp->sample_offset,
+ incr=vp->sample_increment,
+ le=vp->sample->data_length,
+ count=*countptr;
+ Sint32 i;
+
+ if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
+
+ /* Precalc how many times we should go through the loop.
+ NOTE: Assumes that incr > 0 and that ofs <= le */
+ i = (le - ofs) / incr + 1;
+
+ if (i > count)
+ {
+ i = count;
+ count = 0;
+ }
+ else count -= i;
+
+ while (i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+
+ if (ofs >= le)
+ {
+ if (ofs == le)
+ *dest++ = src[ofs >> FRACTION_BITS];
+ vp->status=VOICE_FREE;
+ *countptr-=count+1;
+ }
+
+ vp->sample_offset=ofs; /* Update offset */
+ return song->resample_buffer;
+}
+
+static sample_t *rs_loop(MidiSong *song, Voice *vp, Sint32 count)
+{
+
+ /* Play sample until end-of-loop, skip back and continue. */
+
+ sample_t v1, v2;
+ Sint32
+ ofs=vp->sample_offset,
+ incr=vp->sample_increment,
+ le=vp->sample->loop_end,
+ ll=le - vp->sample->loop_start;
+ sample_t
+ *dest=song->resample_buffer,
+ *src=vp->sample->data;
+ Sint32 i;
+
+ while (count)
+ {
+ if (ofs >= le)
+ /* NOTE: Assumes that ll > incr and that incr > 0. */
+ ofs -= ll;
+ /* Precalc how many times we should go through the loop */
+ i = (le - ofs) / incr + 1;
+ if (i > count)
+ {
+ i = count;
+ count = 0;
+ }
+ else count -= i;
+ while (i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+ }
+
+ vp->sample_offset=ofs; /* Update offset */
+ return song->resample_buffer;
+}
+
+static sample_t *rs_bidir(MidiSong *song, Voice *vp, Sint32 count)
+{
+ sample_t v1, v2;
+ Sint32
+ ofs=vp->sample_offset,
+ incr=vp->sample_increment,
+ le=vp->sample->loop_end,
+ ls=vp->sample->loop_start;
+ sample_t
+ *dest=song->resample_buffer,
+ *src=vp->sample->data;
+ Sint32
+ le2 = le<<1,
+ ls2 = ls<<1,
+ i;
+ /* Play normally until inside the loop region */
+
+ if (ofs <= ls)
+ {
+ /* NOTE: Assumes that incr > 0, which is NOT always the case
+ when doing bidirectional looping. I have yet to see a case
+ where both ofs <= ls AND incr < 0, however. */
+ i = (ls - ofs) / incr + 1;
+ if (i > count)
+ {
+ i = count;
+ count = 0;
+ }
+ else count -= i;
+ while (i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+ }
+
+ /* Then do the bidirectional looping */
+
+ while(count)
+ {
+ /* Precalc how many times we should go through the loop */
+ i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
+ if (i > count)
+ {
+ i = count;
+ count = 0;
+ }
+ else count -= i;
+ while (i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+ if (ofs>=le)
+ {
+ /* fold the overshoot back in */
+ ofs = le2 - ofs;
+ incr *= -1;
+ }
+ else if (ofs <= ls)
+ {
+ ofs = ls2 - ofs;
+ incr *= -1;
+ }
+ }
+
+ vp->sample_increment=incr;
+ vp->sample_offset=ofs; /* Update offset */
+ return song->resample_buffer;
+}
+
+/*********************** vibrato versions ***************************/
+
+/* We only need to compute one half of the vibrato sine cycle */
+static int vib_phase_to_inc_ptr(int phase)
+{
+ if (phase < VIBRATO_SAMPLE_INCREMENTS/2)
+ return VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
+ else if (phase >= 3*VIBRATO_SAMPLE_INCREMENTS/2)
+ return 5*VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
+ else
+ return phase-VIBRATO_SAMPLE_INCREMENTS/2;
+}
+
+static Sint32 update_vibrato(MidiSong *song, Voice *vp, int sign)
+{
+ Sint32 depth;
+ int phase, pb;
+ double a;
+
+ if (vp->vibrato_phase++ >= 2*VIBRATO_SAMPLE_INCREMENTS-1)
+ vp->vibrato_phase=0;
+ phase=vib_phase_to_inc_ptr(vp->vibrato_phase);
+
+ if (vp->vibrato_sample_increment[phase])
+ {
+ if (sign)
+ return -vp->vibrato_sample_increment[phase];
+ else
+ return vp->vibrato_sample_increment[phase];
+ }
+
+ /* Need to compute this sample increment. */
+
+ depth=vp->sample->vibrato_depth<<7;
+
+ if (vp->vibrato_sweep)
+ {
+ /* Need to update sweep */
+ vp->vibrato_sweep_position += vp->vibrato_sweep;
+ if (vp->vibrato_sweep_position >= (1<<SWEEP_SHIFT))
+ vp->vibrato_sweep=0;
+ else
+ {
+ /* Adjust depth */
+ depth *= vp->vibrato_sweep_position;
+ depth >>= SWEEP_SHIFT;
+ }
+ }
+
+ a = FSCALE(((double)(vp->sample->sample_rate) *
+ (double)(vp->frequency)) /
+ ((double)(vp->sample->root_freq) *
+ (double)(song->rate)),
+ FRACTION_BITS);
+
+ pb=(int)((sine(vp->vibrato_phase *
+ (SINE_CYCLE_LENGTH/(2*VIBRATO_SAMPLE_INCREMENTS)))
+ * (double)(depth) * VIBRATO_AMPLITUDE_TUNING));
+
+ if (pb<0)
+ {
+ pb=-pb;
+ a /= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
+ }
+ else
+ a *= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
+
+ /* If the sweep's over, we can store the newly computed sample_increment */
+ if (!vp->vibrato_sweep)
+ vp->vibrato_sample_increment[phase]=(Sint32) a;
+
+ if (sign)
+ a = -a; /* need to preserve the loop direction */
+
+ return (Sint32) a;
+}
+
+static sample_t *rs_vib_plain(MidiSong *song, int v, Sint32 *countptr)
+{
+
+ /* Play sample until end, then free the voice. */
+
+ sample_t v1, v2;
+ Voice *vp=&(song->voice[v]);
+ sample_t
+ *dest=song->resample_buffer,
+ *src=vp->sample->data;
+ Sint32
+ le=vp->sample->data_length,
+ ofs=vp->sample_offset,
+ incr=vp->sample_increment,
+ count=*countptr;
+ int
+ cc=vp->vibrato_control_counter;
+
+ /* This has never been tested */
+
+ if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
+
+ while (count--)
+ {
+ if (!cc--)
+ {
+ cc=vp->vibrato_control_ratio;
+ incr=update_vibrato(song, vp, 0);
+ }
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ if (ofs >= le)
+ {
+ if (ofs == le)
+ *dest++ = src[ofs >> FRACTION_BITS];
+ vp->status=VOICE_FREE;
+ *countptr-=count+1;
+ break;
+ }
+ }
+
+ vp->vibrato_control_counter=cc;
+ vp->sample_increment=incr;
+ vp->sample_offset=ofs; /* Update offset */
+ return song->resample_buffer;
+}
+
+static sample_t *rs_vib_loop(MidiSong *song, Voice *vp, Sint32 count)
+{
+
+ /* Play sample until end-of-loop, skip back and continue. */
+
+ sample_t v1, v2;
+ Sint32
+ ofs=vp->sample_offset,
+ incr=vp->sample_increment,
+ le=vp->sample->loop_end,
+ ll=le - vp->sample->loop_start;
+ sample_t
+ *dest=song->resample_buffer,
+ *src=vp->sample->data;
+ int
+ cc=vp->vibrato_control_counter;
+ Sint32 i;
+ int
+ vibflag=0;
+
+ while (count)
+ {
+ /* Hopefully the loop is longer than an increment */
+ if(ofs >= le)
+ ofs -= ll;
+ /* Precalc how many times to go through the loop, taking
+ the vibrato control ratio into account this time. */
+ i = (le - ofs) / incr + 1;
+ if(i > count) i = count;
+ if(i > cc)
+ {
+ i = cc;
+ vibflag = 1;
+ }
+ else cc -= i;
+ count -= i;
+ while(i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+ if(vibflag)
+ {
+ cc = vp->vibrato_control_ratio;
+ incr = update_vibrato(song, vp, 0);
+ vibflag = 0;
+ }
+ }
+
+ vp->vibrato_control_counter=cc;
+ vp->sample_increment=incr;
+ vp->sample_offset=ofs; /* Update offset */
+ return song->resample_buffer;
+}
+
+static sample_t *rs_vib_bidir(MidiSong *song, Voice *vp, Sint32 count)
+{
+ sample_t v1, v2;
+ Sint32
+ ofs=vp->sample_offset,
+ incr=vp->sample_increment,
+ le=vp->sample->loop_end,
+ ls=vp->sample->loop_start;
+ sample_t
+ *dest=song->resample_buffer,
+ *src=vp->sample->data;
+ int
+ cc=vp->vibrato_control_counter;
+ Sint32
+ le2=le<<1,
+ ls2=ls<<1,
+ i;
+ int
+ vibflag = 0;
+
+ /* Play normally until inside the loop region */
+ while (count && (ofs <= ls))
+ {
+ i = (ls - ofs) / incr + 1;
+ if (i > count) i = count;
+ if (i > cc)
+ {
+ i = cc;
+ vibflag = 1;
+ }
+ else cc -= i;
+ count -= i;
+ while (i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+ if (vibflag)
+ {
+ cc = vp->vibrato_control_ratio;
+ incr = update_vibrato(song, vp, 0);
+ vibflag = 0;
+ }
+ }
+
+ /* Then do the bidirectional looping */
+
+ while (count)
+ {
+ /* Precalc how many times we should go through the loop */
+ i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
+ if(i > count) i = count;
+ if(i > cc)
+ {
+ i = cc;
+ vibflag = 1;
+ }
+ else cc -= i;
+ count -= i;
+ while (i--)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS)+1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ ofs += incr;
+ }
+ if (vibflag)
+ {
+ cc = vp->vibrato_control_ratio;
+ incr = update_vibrato(song, vp, (incr < 0));
+ vibflag = 0;
+ }
+ if (ofs >= le)
+ {
+ /* fold the overshoot back in */
+ ofs = le2 - ofs;
+ incr *= -1;
+ }
+ else if (ofs <= ls)
+ {
+ ofs = ls2 - ofs;
+ incr *= -1;
+ }
+ }
+
+ vp->vibrato_control_counter=cc;
+ vp->sample_increment=incr;
+ vp->sample_offset=ofs; /* Update offset */
+ return song->resample_buffer;
+}
+
+sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr)
+{
+ Sint32 ofs;
+ Uint8 modes;
+ Voice *vp=&(song->voice[v]);
+
+ if (!(vp->sample->sample_rate))
+ {
+ /* Pre-resampled data -- just update the offset and check if
+ we're out of data. */
+ ofs=vp->sample_offset >> FRACTION_BITS; /* Kind of silly to use
+ FRACTION_BITS here... */
+ if (*countptr >= (vp->sample->data_length>>FRACTION_BITS) - ofs)
+ {
+ /* Note finished. Free the voice. */
+ vp->status = VOICE_FREE;
+
+ /* Let the caller know how much data we had left */
+ *countptr = (vp->sample->data_length>>FRACTION_BITS) - ofs;
+ }
+ else
+ vp->sample_offset += *countptr << FRACTION_BITS;
+
+ return vp->sample->data+ofs;
+ }
+
+ /* Need to resample. Use the proper function. */
+ modes=vp->sample->modes;
+
+ if (vp->vibrato_control_ratio)
+ {
+ if ((modes & MODES_LOOPING) &&
+ ((modes & MODES_ENVELOPE) ||
+ (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
+ {
+ if (modes & MODES_PINGPONG)
+ return rs_vib_bidir(song, vp, *countptr);
+ else
+ return rs_vib_loop(song, vp, *countptr);
+ }
+ else
+ return rs_vib_plain(song, v, countptr);
+ }
+ else
+ {
+ if ((modes & MODES_LOOPING) &&
+ ((modes & MODES_ENVELOPE) ||
+ (vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
+ {
+ if (modes & MODES_PINGPONG)
+ return rs_bidir(song, vp, *countptr);
+ else
+ return rs_loop(song, vp, *countptr);
+ }
+ else
+ return rs_plain(song, v, countptr);
+ }
+}
+
+void pre_resample(MidiSong *song, Sample *sp)
+{
+ double a, xdiff;
+ Sint32 incr, ofs, newlen, count;
+ Sint16 *newdata, *dest, *src = (Sint16 *) sp->data;
+ Sint16 v1, v2, v3, v4, *vptr;
+#ifdef DEBUG_CHATTER
+ static const char note_name[12][3] =
+ {
+ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
+ };
+#endif
+
+ SNDDBG((" * pre-resampling for note %d (%s%d)\n",
+ sp->note_to_use,
+ note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12));
+
+ a = ((double) (sp->sample_rate) * freq_table[(int) (sp->note_to_use)]) /
+ ((double) (sp->root_freq) * song->rate);
+ newlen = (Sint32)(sp->data_length / a);
+ dest = newdata = safe_malloc(newlen >> (FRACTION_BITS - 1));
+
+ count = (newlen >> FRACTION_BITS) - 1;
+ ofs = incr = (sp->data_length - (1 << FRACTION_BITS)) / count;
+
+ if (--count)
+ *dest++ = src[0];
+
+ /* Since we're pre-processing and this doesn't have to be done in
+ real-time, we go ahead and do the full sliding cubic interpolation. */
+ while (--count)
+ {
+ vptr = src + (ofs >> FRACTION_BITS);
+ /*
+ * Electric Fence to the rescue: Accessing *(vptr - 1) is not a
+ * good thing to do when vptr <= src. (TiMidity++ has a similar
+ * safe-guard here.)
+ */
+ v1 = (vptr == src) ? *vptr : *(vptr - 1);
+ v2 = *vptr;
+ v3 = *(vptr + 1);
+ v4 = *(vptr + 2);
+ xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS);
+ *dest++ = (Sint16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 +
+ xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4))));
+ ofs += incr;
+ }
+
+ if (ofs & FRACTION_MASK)
+ {
+ v1 = src[ofs >> FRACTION_BITS];
+ v2 = src[(ofs >> FRACTION_BITS) + 1];
+ *dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
+ }
+ else
+ *dest++ = src[ofs >> FRACTION_BITS];
+
+ sp->data_length = newlen;
+ sp->loop_start = (Sint32)(sp->loop_start / a);
+ sp->loop_end = (Sint32)(sp->loop_end / a);
+ free(sp->data);
+ sp->data = (sample_t *) newdata;
+ sp->sample_rate = 0;
+}
diff --git a/util/sdl/sound/decoders/timidity/resample.h b/util/sdl/sound/decoders/timidity/resample.h
new file mode 100644
index 00000000..152cb386
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/resample.h
@@ -0,0 +1,24 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ resample.h
+*/
+
+extern sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr);
+extern void pre_resample(MidiSong *song, Sample *sp);
diff --git a/util/sdl/sound/decoders/timidity/tables.c b/util/sdl/sound/decoders/timidity/tables.c
new file mode 100644
index 00000000..6c092add
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/tables.c
@@ -0,0 +1,218 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "tables.h"
+
+const Sint32 freq_table[128]=
+{
+ 8176, 8662, 9177, 9723,
+ 10301, 10913, 11562, 12250,
+ 12978, 13750, 14568, 15434,
+
+ 16352, 17324, 18354, 19445,
+ 20602, 21827, 23125, 24500,
+ 25957, 27500, 29135, 30868,
+
+ 32703, 34648, 36708, 38891,
+ 41203, 43654, 46249, 48999,
+ 51913, 55000, 58270, 61735,
+
+ 65406, 69296, 73416, 77782,
+ 82407, 87307, 92499, 97999,
+ 103826, 110000, 116541, 123471,
+
+ 130813, 138591, 146832, 155563,
+ 164814, 174614, 184997, 195998,
+ 207652, 220000, 233082, 246942,
+
+ 261626, 277183, 293665, 311127,
+ 329628, 349228, 369994, 391995,
+ 415305, 440000, 466164, 493883,
+
+ 523251, 554365, 587330, 622254,
+ 659255, 698456, 739989, 783991,
+ 830609, 880000, 932328, 987767,
+
+ 1046502, 1108731, 1174659, 1244508,
+ 1318510, 1396913, 1479978, 1567982,
+ 1661219, 1760000, 1864655, 1975533,
+
+ 2093005, 2217461, 2349318, 2489016,
+ 2637020, 2793826, 2959955, 3135963,
+ 3322438, 3520000, 3729310, 3951066,
+
+ 4186009, 4434922, 4698636, 4978032,
+ 5274041, 5587652, 5919911, 6271927,
+ 6644875, 7040000, 7458620, 7902133,
+
+ 8372018, 8869844, 9397273, 9956063,
+ 10548082, 11175303, 11839822, 12543854
+};
+
+/* v=2.^((x/127-1) * 6) */
+const double vol_table[128] =
+{
+ 0.015625, 0.016145143728351113, 0.016682602624583379, 0.017237953096759438,
+ 0.017811790741104401, 0.01840473098076444, 0.019017409725829021, 0.019650484055324921,
+ 0.020304632921913132, 0.020980557880044631, 0.021678983838355849, 0.02240065983711079,
+ 0.023146359851523596, 0.023916883621822989, 0.024713057510949051, 0.025535735390801884,
+ 0.026385799557992876, 0.027264161680080529, 0.028171763773305786, 0.029109579212875332,
+ 0.030078613776876421, 0.031079906724942836, 0.032114531912828696, 0.033183598944085631,
+ 0.034288254360078256, 0.035429682869614412, 0.036609108619508737, 0.037827796507442342,
+ 0.039087053538526394, 0.040388230227024875, 0.041732722044739302, 0.043121970917609151,
+ 0.044557466772132896, 0.046040749133268132, 0.047573408775524545, 0.049157089429020417,
+ 0.050793489542332405, 0.05248436410402918, 0.054231526524842463, 0.056036850582493913,
+ 0.057902272431264008, 0.059829792678457581, 0.061821478529993396, 0.063879466007418645,
+ 0.066005962238725971, 0.068203247825430205, 0.070473679288442961, 0.072819691595368496,
+ 0.075243800771931268, 0.077748606600335793, 0.080336795407452768, 0.083011142945821612,
+ 0.085774517370559328, 0.088629882315368294, 0.091580300070941839, 0.094628934869176312,
+ 0.097779056276712184, 0.10103404270144323, 0.1043973850157546, 0.1078726903003755,
+ 0.11146368571286204, 0.11517422248485852, 0.11900828005242428, 0.12296997032385605,
+ 0.12706354208958254, 0.13129338557886089, 0.13566403716816194, 0.14018018424629392,
+ 0.14484667024148207, 0.14966849981579558, 0.15465084423249356, 0.15979904690204472,
+ 0.16511862911277009, 0.17061529595225433, 0.17629494242587571, 0.18216365977901747,
+ 0.18822774202974024, 0.19449369271892172, 0.20096823188510385, 0.20765830327152621,
+ 0.21457108177307616, 0.22171398113114205, 0.2290946618846218, 0.23672103958561411,
+ 0.2446012932886038, 0.25274387432224471, 0.26115751535314891, 0.26985123975140174,
+ 0.27883437126784744, 0.28811654403352405, 0.29770771289197112, 0.30761816407549192,
+ 0.31785852623682015, 0.32843978184802081, 0.33937327897885317, 0.3506707434672246,
+ 0.36234429149478936, 0.37440644258117928, 0.38687013301080181, 0.39974872970660535,
+ 0.41305604456569134, 0.42680634927214656, 0.44101439060298442, 0.45569540624360722,
+ 0.47086514112975281, 0.48653986433345225, 0.50273638651110641, 0.51947207793239625,
+ 0.53676488710936021, 0.55463336004561792, 0.57309666012638816, 0.59217458867062556,
+ 0.61188760616732485, 0.63225685421876243, 0.65330417821421161, 0.67505215075844849,
+ 0.69752409588017272, 0.72074411404630734, 0.74473710800900605, 0.76952880951308478,
+ 0.79514580689252357, 0.82161557358563286, 0.84896649759946774, 0.87722791195508854,
+ 0.90643012614631979, 0.93660445864574493, 0.96778327049280244, 1
+};
+
+const double bend_fine[256] = {
+ 1, 1.0002256593050698, 1.0004513695322617, 1.0006771306930664,
+ 1.0009029427989777, 1.0011288058614922, 1.0013547198921082, 1.0015806849023274,
+ 1.0018067009036538, 1.002032767907594, 1.0022588859256572, 1.0024850549693551,
+ 1.0027112750502025, 1.0029375461797159, 1.0031638683694153, 1.0033902416308227,
+ 1.0036166659754628, 1.0038431414148634, 1.0040696679605541, 1.0042962456240678,
+ 1.0045228744169397, 1.0047495543507072, 1.0049762854369111, 1.0052030676870944,
+ 1.0054299011128027, 1.0056567857255843, 1.00588372153699, 1.006110708558573,
+ 1.0063377468018897, 1.0065648362784985, 1.0067919769999607, 1.0070191689778405,
+ 1.0072464122237039, 1.0074737067491204, 1.0077010525656616, 1.0079284496849015,
+ 1.0081558981184175, 1.008383397877789, 1.008610948974598, 1.0088385514204294,
+ 1.0090662052268706, 1.0092939104055114, 1.0095216669679448, 1.0097494749257656,
+ 1.009977334290572, 1.0102052450739643, 1.0104332072875455, 1.0106612209429215,
+ 1.0108892860517005, 1.0111174026254934, 1.0113455706759138, 1.0115737902145781,
+ 1.0118020612531047, 1.0120303838031153, 1.0122587578762337, 1.012487183484087,
+ 1.0127156606383041, 1.0129441893505169, 1.0131727696323602, 1.0134014014954713,
+ 1.0136300849514894, 1.0138588200120575, 1.0140876066888203, 1.0143164449934257,
+ 1.0145453349375237, 1.0147742765327674, 1.0150032697908125, 1.0152323147233171,
+ 1.015461411341942, 1.0156905596583505, 1.0159197596842091, 1.0161490114311862,
+ 1.0163783149109531, 1.0166076701351838, 1.0168370771155553, 1.0170665358637463,
+ 1.0172960463914391, 1.0175256087103179, 1.0177552228320703, 1.0179848887683858,
+ 1.0182146065309567, 1.0184443761314785, 1.0186741975816487, 1.0189040708931674,
+ 1.0191339960777379, 1.0193639731470658, 1.0195940021128593, 1.0198240829868295,
+ 1.0200542157806898, 1.0202844005061564, 1.0205146371749483, 1.0207449257987866,
+ 1.0209752663893958, 1.0212056589585028, 1.0214361035178368, 1.0216666000791297,
+ 1.0218971486541166, 1.0221277492545349, 1.0223584018921241, 1.0225891065786274,
+ 1.0228198633257899, 1.0230506721453596, 1.023281533049087, 1.0235124460487257,
+ 1.0237434111560313, 1.0239744283827625, 1.0242054977406807, 1.0244366192415495,
+ 1.0246677928971357, 1.0248990187192082, 1.025130296719539, 1.0253616269099028,
+ 1.0255930093020766, 1.0258244439078401, 1.0260559307389761, 1.0262874698072693,
+ 1.0265190611245079, 1.0267507047024822, 1.0269824005529853, 1.027214148687813,
+ 1.0274459491187637, 1.0276778018576387, 1.0279097069162415, 1.0281416643063788,
+ 1.0283736740398595, 1.0286057361284953, 1.0288378505841009, 1.0290700174184932,
+ 1.0293022366434921, 1.0295345082709197, 1.0297668323126017, 1.0299992087803651,
+ 1.030231637686041, 1.0304641190414621, 1.0306966528584645, 1.0309292391488862,
+ 1.0311618779245688, 1.0313945691973556, 1.0316273129790936, 1.0318601092816313,
+ 1.0320929581168212, 1.0323258594965172, 1.0325588134325767, 1.0327918199368598,
+ 1.0330248790212284, 1.0332579906975481, 1.0334911549776868, 1.033724371873515,
+ 1.0339576413969056, 1.0341909635597348, 1.0344243383738811, 1.0346577658512259,
+ 1.034891246003653, 1.0351247788430489, 1.0353583643813031, 1.0355920026303078,
+ 1.0358256936019572, 1.0360594373081489, 1.0362932337607829, 1.0365270829717617,
+ 1.0367609849529913, 1.0369949397163791, 1.0372289472738365, 1.0374630076372766,
+ 1.0376971208186156, 1.0379312868297725, 1.0381655056826686, 1.0383997773892284,
+ 1.0386341019613787, 1.0388684794110492, 1.0391029097501721, 1.0393373929906822,
+ 1.0395719291445176, 1.0398065182236185, 1.0400411602399278, 1.0402758552053915,
+ 1.0405106031319582, 1.0407454040315787, 1.0409802579162071, 1.0412151647977996,
+ 1.0414501246883161, 1.0416851375997183, 1.0419202035439705, 1.0421553225330404,
+ 1.042390494578898, 1.042625719693516, 1.0428609978888699, 1.043096329176938,
+ 1.0433317135697009, 1.0435671510791424, 1.0438026417172486, 1.0440381854960086,
+ 1.0442737824274138, 1.044509432523459, 1.044745135796141, 1.0449808922574599,
+ 1.0452167019194181, 1.0454525647940205, 1.0456884808932754, 1.0459244502291931,
+ 1.0461604728137874, 1.0463965486590741, 1.046632677777072, 1.0468688601798024,
+ 1.0471050958792898, 1.047341384887561, 1.0475777272166455, 1.047814122878576,
+ 1.048050571885387, 1.0482870742491166, 1.0485236299818055, 1.0487602390954964,
+ 1.0489969016022356, 1.0492336175140715, 1.0494703868430555, 1.0497072096012419,
+ 1.0499440858006872, 1.0501810154534512, 1.050417998571596, 1.0506550351671864,
+ 1.0508921252522903, 1.0511292688389782, 1.0513664659393229, 1.0516037165654004,
+ 1.0518410207292894, 1.0520783784430709, 1.0523157897188296, 1.0525532545686513,
+ 1.0527907730046264, 1.0530283450388465, 1.0532659706834067, 1.0535036499504049,
+ 1.0537413828519411, 1.0539791694001188, 1.0542170096070436, 1.0544549034848243,
+ 1.0546928510455722, 1.0549308523014012, 1.0551689072644284, 1.0554070159467728,
+ 1.0556451783605572, 1.0558833945179062, 1.0561216644309479, 1.0563599881118126,
+ 1.0565983655726334, 1.0568367968255465, 1.0570752818826903, 1.0573138207562065,
+ 1.057552413458239, 1.0577910600009348, 1.0580297603964437, 1.058268514656918,
+ 1.0585073227945128, 1.0587461848213857, 1.058985100749698, 1.0592240705916123
+};
+
+const double bend_coarse[128] = {
+ 1, 1.0594630943592953, 1.122462048309373, 1.189207115002721,
+ 1.2599210498948732, 1.3348398541700344, 1.4142135623730951, 1.4983070768766815,
+ 1.5874010519681994, 1.681792830507429, 1.7817974362806785, 1.8877486253633868,
+ 2, 2.1189261887185906, 2.244924096618746, 2.3784142300054421,
+ 2.5198420997897464, 2.6696797083400687, 2.8284271247461903, 2.996614153753363,
+ 3.1748021039363992, 3.363585661014858, 3.5635948725613571, 3.7754972507267741,
+ 4, 4.2378523774371812, 4.4898481932374912, 4.7568284600108841,
+ 5.0396841995794928, 5.3393594166801366, 5.6568542494923806, 5.993228307506727,
+ 6.3496042078727974, 6.727171322029716, 7.1271897451227151, 7.5509945014535473,
+ 8, 8.4757047548743625, 8.9796963864749824, 9.5136569200217682,
+ 10.079368399158986, 10.678718833360273, 11.313708498984761, 11.986456615013454,
+ 12.699208415745595, 13.454342644059432, 14.25437949024543, 15.101989002907095,
+ 16, 16.951409509748721, 17.959392772949972, 19.027313840043536,
+ 20.158736798317967, 21.357437666720553, 22.627416997969522, 23.972913230026901,
+ 25.398416831491197, 26.908685288118864, 28.508758980490853, 30.203978005814196,
+ 32, 33.902819019497443, 35.918785545899944, 38.054627680087073,
+ 40.317473596635935, 42.714875333441107, 45.254833995939045, 47.945826460053802,
+ 50.796833662982394, 53.817370576237728, 57.017517960981706, 60.407956011628393,
+ 64, 67.805638038994886, 71.837571091799887, 76.109255360174146,
+ 80.63494719327187, 85.429750666882214, 90.509667991878089, 95.891652920107603,
+ 101.59366732596479, 107.63474115247546, 114.03503592196341, 120.81591202325679,
+ 128, 135.61127607798977, 143.67514218359977, 152.21851072034829,
+ 161.26989438654374, 170.85950133376443, 181.01933598375618, 191.78330584021521,
+ 203.18733465192958, 215.26948230495091, 228.07007184392683, 241.63182404651357,
+ 256, 271.22255215597971, 287.35028436719938, 304.43702144069658,
+ 322.53978877308765, 341.71900266752868, 362.03867196751236, 383.56661168043064,
+ 406.37466930385892, 430.53896460990183, 456.14014368785394, 483.26364809302686,
+ 512, 542.44510431195943, 574.70056873439876, 608.87404288139317,
+ 645.0795775461753, 683.43800533505737, 724.07734393502471, 767.13322336086128,
+ 812.74933860771785, 861.07792921980365, 912.28028737570787, 966.52729618605372,
+ 1024, 1084.8902086239189, 1149.4011374687975, 1217.7480857627863,
+ 1290.1591550923506, 1366.8760106701147, 1448.1546878700494, 1534.2664467217226
+};
diff --git a/util/sdl/sound/decoders/timidity/tables.h b/util/sdl/sound/decoders/timidity/tables.h
new file mode 100644
index 00000000..6b84a382
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/tables.h
@@ -0,0 +1,30 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ tables.h
+*/
+
+#include <math.h>
+#define sine(x) (sin((2*PI/1024.0) * (x)))
+
+#define SINE_CYCLE_LENGTH 1024
+extern const Sint32 freq_table[];
+extern const double vol_table[];
+extern const double bend_fine[];
+extern const double bend_coarse[];
diff --git a/util/sdl/sound/decoders/timidity/testmidi.c b/util/sdl/sound/decoders/timidity/testmidi.c
new file mode 100644
index 00000000..d71fa557
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/testmidi.c
@@ -0,0 +1,105 @@
+/*
+ * 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
+ */
+
+/**
+ * Program to test the TiMidity core, without having to worry about decoder
+ * and/or playsound bugs. It's not meant to be robust or user-friendly.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "SDL.h"
+#include "timidity.h"
+
+int done_flag = 0;
+MidiSong *song;
+
+static void audio_callback(void *userdata, Uint8 *stream, int len)
+{
+ if (Timidity_PlaySome(song, stream, len) == 0)
+ done_flag = 1;
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_AudioSpec audio;
+ SDL_RWops *rw;
+
+ if (SDL_Init(SDL_INIT_AUDIO) < 0)
+ {
+ fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ atexit(SDL_Quit);
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "Usage: %s midifile\n", argv[0]);
+ return 1;
+ }
+
+ audio.freq = 44100;
+ audio.format = AUDIO_S16SYS;
+ audio.channels = 2;
+ audio.samples = 4096;
+ audio.callback = audio_callback;
+
+ if (SDL_OpenAudio(&audio, NULL) < 0)
+ {
+ fprintf(stderr, "Couldn't open audio device. %s\n", SDL_GetError());
+ return 1;
+ }
+
+ if (Timidity_Init() < 0)
+ {
+ fprintf(stderr, "Could not initialise TiMidity.\n");
+ return 1;
+ }
+
+ rw = SDL_RWFromFile(argv[1], "rb");
+ if (rw == NULL)
+ {
+ fprintf(stderr, "Could not create RWops from MIDI file.\n");
+ return 1;
+ }
+
+ song = Timidity_LoadSong(rw, &audio);
+ SDL_RWclose(rw);
+
+ if (song == NULL)
+ {
+ fprintf(stderr, "Could not open MIDI file.\n");
+ return 1;
+ }
+
+ Timidity_SetVolume(song, 100);
+ Timidity_Start(song);
+
+ SDL_PauseAudio(0);
+ while (!done_flag)
+ {
+ SDL_Delay(10);
+ }
+ SDL_PauseAudio(1);
+ Timidity_FreeSong(song);
+ Timidity_Exit();
+
+ return 0;
+}
diff --git a/util/sdl/sound/decoders/timidity/timidity.c b/util/sdl/sound/decoders/timidity/timidity.c
new file mode 100644
index 00000000..244d6b1e
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/timidity.c
@@ -0,0 +1,602 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "timidity.h"
+
+#include "options.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "readmidi.h"
+#include "output.h"
+
+#include "tables.h"
+
+ToneBank *master_tonebank[128], *master_drumset[128];
+
+static char def_instr_name[256] = "";
+
+#define MAXWORDS 10
+
+/* Quick-and-dirty fgets() replacement. */
+
+static char *RWgets(SDL_RWops *rw, char *s, int size)
+{
+ int num_read = 0;
+ int newline = 0;
+
+ while (num_read < size && !newline)
+ {
+ if (SDL_RWread(rw, &s[num_read], 1, 1) != 1)
+ break;
+
+ /* Unlike fgets(), don't store newline. Under Windows/DOS we'll
+ * probably get an extra blank line for every line that's being
+ * read, but that should be ok.
+ */
+ if (s[num_read] == '\n' || s[num_read] == '\r')
+ {
+ s[num_read] = '\0';
+ newline = 1;
+ }
+
+ num_read++;
+ }
+
+ s[num_read] = '\0';
+
+ return (num_read != 0) ? s : NULL;
+}
+
+static int read_config_file(char *name)
+{
+ SDL_RWops *rw;
+ char tmp[1024], *w[MAXWORDS], *cp;
+ ToneBank *bank=0;
+ int i, j, k, line=0, words;
+ static int rcf_count=0;
+
+ if (rcf_count>50)
+ {
+ SNDDBG(("Probable source loop in configuration files\n"));
+ return (-1);
+ }
+
+ if (!(rw=open_file(name)))
+ return -1;
+
+ while (RWgets(rw, tmp, sizeof(tmp)))
+ {
+ line++;
+ w[words=0]=strtok(tmp, " \t\240");
+ if (!w[0]) continue;
+
+ /* Originally the TiMidity++ extensions were prefixed like this */
+ if (strcmp(w[0], "#extension") == 0)
+ words = -1;
+ else if (*w[0] == '#')
+ continue;
+
+ while (w[words] && *w[words] != '#' && (words < MAXWORDS))
+ w[++words]=strtok(0," \t\240");
+
+ /*
+ * TiMidity++ adds a number of extensions to the config file format.
+ * Many of them are completely irrelevant to SDL_sound, but at least
+ * we shouldn't choke on them.
+ *
+ * Unfortunately the documentation for these extensions is often quite
+ * vague, gramatically strange or completely absent.
+ */
+ if (
+ !strcmp(w[0], "comm") /* "comm" program second */
+ || !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port */
+ || !strcmp(w[0], "FTPproxy") /* "FTPproxy" hostname:port */
+ || !strcmp(w[0], "mailaddr") /* "mailaddr" your-mail-address */
+ || !strcmp(w[0], "opt") /* "opt" timidity-options */
+ )
+ {
+ /*
+ * + "comm" sets some kind of comment -- the documentation is too
+ * vague for me to understand at this time.
+ * + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data
+ * over a network, rather than from the file system.
+ * + "opt" specifies default options for TiMidity++.
+ *
+ * These are all quite useless for our version of TiMidity, so
+ * they can safely remain no-ops.
+ */
+ } else if (!strcmp(w[0], "timeout")) /* "timeout" program second */
+ {
+ /*
+ * Specifies a timeout value of the program. A number of seconds
+ * before TiMidity kills the note. This may be useful to implement
+ * later, but I don't see any urgent need for it.
+ */
+ SNDDBG(("FIXME: Implement \"timeout\" in TiMidity config.\n"));
+ } else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */
+ || !strcmp(w[0], "copybank")) /* "copybank" bank */
+ {
+ /*
+ * Copies all the settings of the specified drumset or bank to
+ * the current drumset or bank. May be useful later, but not a
+ * high priority.
+ */
+ SNDDBG(("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]));
+ } else if (!strcmp(w[0], "undef")) /* "undef" progno */
+ {
+ /*
+ * Undefines the tone "progno" of the current tone bank (or
+ * drum set?). Not a high priority.
+ */
+ SNDDBG(("FIXME: Implement \"undef\" in TiMidity config.\n"));
+ } else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */
+ {
+ /*
+ * Sets the alternate assign for drum set. Whatever that's
+ * supposed to mean.
+ */
+ SNDDBG(("FIXME: Implement \"altassign\" in TiMidity config.\n"));
+ } else if (!strcmp(w[0], "soundfont")
+ || !strcmp(w[0], "font"))
+ {
+ /*
+ * I can't find any documentation for these, but I guess they're
+ * an alternative way of loading/unloading instruments.
+ *
+ * "soundfont" sf_file "remove"
+ * "soundfont" sf_file ["order=" order] ["cutoff=" cutoff]
+ * ["reso=" reso] ["amp=" amp]
+ * "font" "exclude" bank preset keynote
+ * "font" "order" order bank preset keynote
+ */
+ SNDDBG(("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0]));
+ } else if (!strcmp(w[0], "progbase"))
+ {
+ /*
+ * The documentation for this makes absolutely no sense to me, but
+ * apparently it sets some sort of base offset for tone numbers.
+ * Why anyone would want to do this is beyond me.
+ */
+ SNDDBG(("FIXME: Implement \"progbase\" in TiMidity config.\n"));
+ } else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */
+ {
+ /*
+ * This extension is the one we will need to implement, as it is
+ * used by the "eawpats". Unfortunately I cannot find any
+ * documentation whatsoever for it, but it looks like it's used
+ * for remapping one instrument to another somehow.
+ */
+ SNDDBG(("FIXME: Implement \"map\" in TiMidity config.\n"));
+ }
+
+ /* Standard TiMidity config */
+
+ else if (!strcmp(w[0], "dir"))
+ {
+ if (words < 2)
+ {
+ SNDDBG(("%s: line %d: No directory given\n", name, line));
+ return -2;
+ }
+ for (i=1; i<words; i++)
+ add_to_pathlist(w[i]);
+ }
+ else if (!strcmp(w[0], "source"))
+ {
+ if (words < 2)
+ {
+ SNDDBG(("%s: line %d: No file name given\n", name, line));
+ return -2;
+ }
+ for (i=1; i<words; i++)
+ {
+ rcf_count++;
+ read_config_file(w[i]);
+ rcf_count--;
+ }
+ }
+ else if (!strcmp(w[0], "default"))
+ {
+ if (words != 2)
+ {
+ SNDDBG(("%s: line %d: Must specify exactly one patch name\n",
+ name, line));
+ return -2;
+ }
+ strncpy(def_instr_name, w[1], 255);
+ def_instr_name[255]='\0';
+ }
+ else if (!strcmp(w[0], "drumset"))
+ {
+ if (words < 2)
+ {
+ SNDDBG(("%s: line %d: No drum set number given\n", name, line));
+ return -2;
+ }
+ i=atoi(w[1]);
+ if (i<0 || i>127)
+ {
+ SNDDBG(("%s: line %d: Drum set must be between 0 and 127\n",
+ name, line));
+ return -2;
+ }
+ if (!master_drumset[i])
+ {
+ master_drumset[i] = safe_malloc(sizeof(ToneBank));
+ memset(master_drumset[i], 0, sizeof(ToneBank));
+ master_drumset[i]->tone = safe_malloc(128 * sizeof(ToneBankElement));
+ memset(master_drumset[i]->tone, 0, 128 * sizeof(ToneBankElement));
+ }
+ bank=master_drumset[i];
+ }
+ else if (!strcmp(w[0], "bank"))
+ {
+ if (words < 2)
+ {
+ SNDDBG(("%s: line %d: No bank number given\n", name, line));
+ return -2;
+ }
+ i=atoi(w[1]);
+ if (i<0 || i>127)
+ {
+ SNDDBG(("%s: line %d: Tone bank must be between 0 and 127\n",
+ name, line));
+ return -2;
+ }
+ if (!master_tonebank[i])
+ {
+ master_tonebank[i] = safe_malloc(sizeof(ToneBank));
+ memset(master_tonebank[i], 0, sizeof(ToneBank));
+ master_tonebank[i]->tone = safe_malloc(128 * sizeof(ToneBankElement));
+ memset(master_tonebank[i]->tone, 0, 128 * sizeof(ToneBankElement));
+ }
+ bank=master_tonebank[i];
+ }
+ else
+ {
+ if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
+ {
+ SNDDBG(("%s: line %d: syntax error\n", name, line));
+ return -2;
+ }
+ i=atoi(w[0]);
+ if (i<0 || i>127)
+ {
+ SNDDBG(("%s: line %d: Program must be between 0 and 127\n",
+ name, line));
+ return -2;
+ }
+ if (!bank)
+ {
+ SNDDBG(("%s: line %d: Must specify tone bank or drum set before assignment\n",
+ name, line));
+ return -2;
+ }
+ if (bank->tone[i].name)
+ free(bank->tone[i].name);
+ strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]);
+ bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
+ bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
+ bank->tone[i].strip_tail=-1;
+
+ for (j=2; j<words; j++)
+ {
+ if (!(cp=strchr(w[j], '=')))
+ {
+ SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j]));
+ return -2;
+ }
+ *cp++=0;
+ if (!strcmp(w[j], "amp"))
+ {
+ k=atoi(cp);
+ if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
+ {
+ SNDDBG(("%s: line %d: amplification must be between 0 and %d\n",
+ name, line, MAX_AMPLIFICATION));
+ return -2;
+ }
+ bank->tone[i].amp=k;
+ }
+ else if (!strcmp(w[j], "note"))
+ {
+ k=atoi(cp);
+ if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
+ {
+ SNDDBG(("%s: line %d: note must be between 0 and 127\n",
+ name, line));
+ return -2;
+ }
+ bank->tone[i].note=k;
+ }
+ else if (!strcmp(w[j], "pan"))
+ {
+ if (!strcmp(cp, "center"))
+ k=64;
+ else if (!strcmp(cp, "left"))
+ k=0;
+ else if (!strcmp(cp, "right"))
+ k=127;
+ else
+ k=((atoi(cp)+100) * 100) / 157;
+ if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
+ {
+ SNDDBG(("%s: line %d: panning must be left, right, center, or between -100 and 100\n",
+ name, line));
+ return -2;
+ }
+ bank->tone[i].pan=k;
+ }
+ else if (!strcmp(w[j], "keep"))
+ {
+ if (!strcmp(cp, "env"))
+ bank->tone[i].strip_envelope=0;
+ else if (!strcmp(cp, "loop"))
+ bank->tone[i].strip_loop=0;
+ else
+ {
+ SNDDBG(("%s: line %d: keep must be env or loop\n", name, line));
+ return -2;
+ }
+ }
+ else if (!strcmp(w[j], "strip"))
+ {
+ if (!strcmp(cp, "env"))
+ bank->tone[i].strip_envelope=1;
+ else if (!strcmp(cp, "loop"))
+ bank->tone[i].strip_loop=1;
+ else if (!strcmp(cp, "tail"))
+ bank->tone[i].strip_tail=1;
+ else
+ {
+ SNDDBG(("%s: line %d: strip must be env, loop, or tail\n",
+ name, line));
+ return -2;
+ }
+ }
+ else
+ {
+ SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j]));
+ return -2;
+ }
+ }
+ }
+ }
+ SDL_RWclose(rw);
+ return 0;
+}
+
+int Timidity_Init_NoConfig()
+{
+ /* Allocate memory for the standard tonebank and drumset */
+ master_tonebank[0] = safe_malloc(sizeof(ToneBank));
+ memset(master_tonebank[0], 0, sizeof(ToneBank));
+ master_tonebank[0]->tone = safe_malloc(128 * sizeof(ToneBankElement));
+ memset(master_tonebank[0]->tone, 0, 128 * sizeof(ToneBankElement));
+
+ master_drumset[0] = safe_malloc(sizeof(ToneBank));
+ memset(master_drumset[0], 0, sizeof(ToneBank));
+ master_drumset[0]->tone = safe_malloc(128 * sizeof(ToneBankElement));
+ memset(master_drumset[0]->tone, 0, 128 * sizeof(ToneBankElement));
+
+ return 0;
+}
+
+int Timidity_Init()
+{
+ /* !!! FIXME: This may be ugly, but slightly less so than requiring the
+ * default search path to have only one element. I think.
+ *
+ * We only need to include the likely locations for the config
+ * file itself since that file should contain any other directory
+ * that needs to be added to the search path.
+ */
+#ifdef WIN32
+ add_to_pathlist("\\TIMIDITY");
+#else
+ add_to_pathlist("/usr/local/lib/timidity");
+ add_to_pathlist("/etc");
+#endif
+
+ Timidity_Init_NoConfig();
+
+ return read_config_file(CONFIG_FILE);
+}
+
+MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio)
+{
+ MidiSong *song;
+ Sint32 events;
+ int i;
+
+ if (rw == NULL)
+ return NULL;
+
+ /* Allocate memory for the song */
+ song = (MidiSong *)safe_malloc(sizeof(*song));
+ memset(song, 0, sizeof(*song));
+ song->patches = patches;
+
+ for (i = 0; i < 128; i++)
+ {
+ if (master_tonebank[i])
+ {
+ song->tonebank[i] = safe_malloc(sizeof(ToneBank));
+ memset(song->tonebank[i], 0, sizeof(ToneBank));
+ song->tonebank[i]->tone = master_tonebank[i]->tone;
+ }
+ if (master_drumset[i])
+ {
+ song->drumset[i] = safe_malloc(sizeof(ToneBank));
+ memset(song->drumset[i], 0, sizeof(ToneBank));
+ song->drumset[i]->tone = master_drumset[i]->tone;
+ }
+ }
+
+ song->amplification = DEFAULT_AMPLIFICATION;
+ song->voices = DEFAULT_VOICES;
+ song->drumchannels = DEFAULT_DRUMCHANNELS;
+
+ song->rw = rw;
+
+ song->rate = audio->freq;
+ song->encoding = 0;
+ if ((audio->format & 0xFF) == 16)
+ song->encoding |= PE_16BIT;
+ if (audio->format & 0x8000)
+ song->encoding |= PE_SIGNED;
+ if (audio->channels == 1)
+ song->encoding |= PE_MONO;
+ switch (audio->format) {
+ case AUDIO_S8:
+ song->write = s32tos8;
+ break;
+ case AUDIO_U8:
+ song->write = s32tou8;
+ break;
+ case AUDIO_S16LSB:
+ song->write = s32tos16l;
+ break;
+ case AUDIO_S16MSB:
+ song->write = s32tos16b;
+ break;
+ case AUDIO_U16LSB:
+ song->write = s32tou16l;
+ break;
+ default:
+ SNDDBG(("Unsupported audio format"));
+ song->write = s32tou16l;
+ break;
+ }
+
+ song->buffer_size = audio->samples;
+ song->resample_buffer = safe_malloc(audio->samples * sizeof(sample_t));
+ song->common_buffer = safe_malloc(audio->samples * 2 * sizeof(Sint32));
+
+ song->control_ratio = audio->freq / CONTROLS_PER_SECOND;
+ if (song->control_ratio < 1)
+ song->control_ratio = 1;
+ else if (song->control_ratio > MAX_CONTROL_RATIO)
+ song->control_ratio = MAX_CONTROL_RATIO;
+
+ song->lost_notes = 0;
+ song->cut_notes = 0;
+
+ song->events = read_midi_file(song, &events, &song->samples);
+
+ /* The RWops can safely be closed at this point, but let's make that the
+ * responsibility of the caller.
+ */
+
+ /* Make sure everything is okay */
+ if (!song->events) {
+ free(song);
+ return(NULL);
+ }
+
+ song->default_instrument = 0;
+ song->default_program = DEFAULT_PROGRAM;
+
+ if (*def_instr_name)
+ set_default_instrument(song, def_instr_name);
+
+ load_missing_instruments(song);
+
+ return(song);
+}
+
+MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
+{
+ return Timidity_LoadDLSSong(rw, NULL, audio);
+}
+
+void Timidity_FreeSong(MidiSong *song)
+{
+ int i;
+
+ free_instruments(song);
+
+ for (i = 0; i < 128; i++)
+ {
+ if (song->tonebank[i])
+ free(song->tonebank[i]);
+ if (song->drumset[i])
+ free(song->drumset[i]);
+ }
+
+ free(song->common_buffer);
+ free(song->resample_buffer);
+ free(song->events);
+ free(song);
+}
+
+void Timidity_Exit(void)
+{
+ int i, j;
+
+ for (i = 0; i < 128; i++)
+ {
+ if (master_tonebank[i])
+ {
+ ToneBankElement *e = master_tonebank[i]->tone;
+ if (e != NULL)
+ {
+ for (j = 0; j < 128; j++)
+ {
+ if (e[j].name != NULL)
+ free(e[j].name);
+ }
+ free(e);
+ }
+ free(master_tonebank[i]);
+ }
+ if (master_drumset[i])
+ {
+ ToneBankElement *e = master_drumset[i]->tone;
+ if (e != NULL)
+ {
+ for (j = 0; j < 128; j++)
+ {
+ if (e[j].name != NULL)
+ free(e[j].name);
+ }
+ free(e);
+ }
+ free(master_drumset[i]);
+ }
+ }
+
+ free_pathlist();
+}
diff --git a/util/sdl/sound/decoders/timidity/timidity.h b/util/sdl/sound/decoders/timidity/timidity.h
new file mode 100644
index 00000000..53ca825f
--- /dev/null
+++ b/util/sdl/sound/decoders/timidity/timidity.h
@@ -0,0 +1,176 @@
+/*
+
+ TiMidity -- Experimental MIDI to WAVE converter
+ Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef TIMIDITY_H
+#define TIMIDITY_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef Sint16 sample_t;
+typedef Sint32 final_volume_t;
+
+#define VIBRATO_SAMPLE_INCREMENTS 32
+
+/* Maximum polyphony. */
+#define MAX_VOICES 48
+
+typedef struct {
+ Sint32
+ loop_start, loop_end, data_length,
+ sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq;
+ Sint32
+ envelope_rate[6], envelope_offset[6];
+ float
+ volume;
+ sample_t *data;
+ Sint32
+ tremolo_sweep_increment, tremolo_phase_increment,
+ vibrato_sweep_increment, vibrato_control_ratio;
+ Uint8
+ tremolo_depth, vibrato_depth,
+ modes;
+ Sint8
+ panning, note_to_use;
+} Sample;
+
+typedef struct {
+ int
+ bank, program, volume, sustain, panning, pitchbend, expression,
+ mono, /* one note only on this channel -- not implemented yet */
+ pitchsens;
+ /* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar
+ processor near you */
+ float
+ pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
+} Channel;
+
+typedef struct {
+ Uint8
+ status, channel, note, velocity;
+ Sample *sample;
+ Sint32
+ orig_frequency, frequency,
+ sample_offset, sample_increment,
+ envelope_volume, envelope_target, envelope_increment,
+ tremolo_sweep, tremolo_sweep_position,
+ tremolo_phase, tremolo_phase_increment,
+ vibrato_sweep, vibrato_sweep_position;
+
+ final_volume_t left_mix, right_mix;
+
+ float
+ left_amp, right_amp, tremolo_volume;
+ Sint32
+ vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS];
+ int
+ vibrato_phase, vibrato_control_ratio, vibrato_control_counter,
+ envelope_stage, control_counter, panning, panned;
+
+} Voice;
+
+typedef struct {
+ int samples;
+ Sample *sample;
+} Instrument;
+
+/* Shared data */
+typedef struct {
+ char *name;
+ int note, amp, pan, strip_loop, strip_envelope, strip_tail;
+} ToneBankElement;
+
+typedef struct {
+ ToneBankElement *tone;
+ Instrument *instrument[128];
+} ToneBank;
+
+typedef struct {
+ Sint32 time;
+ Uint8 channel, type, a, b;
+} MidiEvent;
+
+typedef struct {
+ MidiEvent event;
+ void *next;
+} MidiEventList;
+
+struct _DLS_Data;
+typedef struct _DLS_Data DLS_Patches;
+
+typedef struct {
+ int playing;
+ SDL_RWops *rw;
+ Sint32 rate;
+ Sint32 encoding;
+ float master_volume;
+ Sint32 amplification;
+ DLS_Patches *patches;
+ ToneBank *tonebank[128];
+ ToneBank *drumset[128];
+ Instrument *default_instrument;
+ int default_program;
+ void (*write)(void *dp, Sint32 *lp, Sint32 c);
+ int buffer_size;
+ sample_t *resample_buffer;
+ Sint32 *common_buffer;
+ Sint32 *buffer_pointer;
+ /* These would both fit into 32 bits, but they are often added in
+ large multiples, so it's simpler to have two roomy ints */
+ /* samples per MIDI delta-t */
+ Sint32 sample_increment;
+ Sint32 sample_correction;
+ Channel channel[16];
+ Voice voice[MAX_VOICES];
+ int voices;
+ Sint32 drumchannels;
+ Sint32 buffered_count;
+ Sint32 control_ratio;
+ Sint32 lost_notes;
+ Sint32 cut_notes;
+ Sint32 samples;
+ MidiEvent *events;
+ MidiEvent *current_event;
+ MidiEventList *evlist;
+ Sint32 current_sample;
+ Sint32 event_count;
+ Sint32 at;
+} MidiSong;
+
+/* Some of these are not defined in timidity.c but are here for convenience */
+
+extern int Timidity_Init(void);
+extern int Timidity_Init_NoConfig(void);
+extern void Timidity_SetVolume(MidiSong *song, int volume);
+extern int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len);
+extern DLS_Patches *Timidity_LoadDLS(SDL_RWops *rw);
+extern void Timidity_FreeDLS(DLS_Patches *patches);
+extern MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio);
+extern MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio);
+extern void Timidity_Start(MidiSong *song);
+extern void Timidity_Seek(MidiSong *song, Uint32 ms);
+extern void Timidity_FreeSong(MidiSong *song);
+extern void Timidity_Exit(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TIMIDITY_H */
diff --git a/util/sdl/sound/decoders/voc.c b/util/sdl/sound/decoders/voc.c
new file mode 100644
index 00000000..d7c2795c
--- /dev/null
+++ b/util/sdl/sound/decoders/voc.c
@@ -0,0 +1,569 @@
+/*
+ * 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
+ */
+
+/*
+ * VOC decoder for SDL_sound.
+ *
+ * This driver handles Creative Labs VOC audio data...this is a legacy format,
+ * but there's some game ports that could make use of such a decoder. Plus,
+ * VOC is fairly straightforward to decode, so this is a more complex, but
+ * still palatable example of an SDL_sound decoder. Y'know, in case the
+ * RAW decoder didn't do it for you. :)
+ *
+ * This code was ripped from a decoder I had written for SDL_mixer, which was
+ * largely ripped from sox v12.17.1's voc.c.
+ *
+ * SDL_mixer: http://www.libsdl.org/projects/SDL_mixer/
+ * sox: http://www.freshmeat.net/projects/sox/
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_VOC
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int VOC_init(void);
+static void VOC_quit(void);
+static int VOC_open(Sound_Sample *sample, const char *ext);
+static void VOC_close(Sound_Sample *sample);
+static Uint32 VOC_read(Sound_Sample *sample);
+static int VOC_rewind(Sound_Sample *sample);
+static int VOC_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_voc[] = { "VOC", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC =
+{
+ {
+ extensions_voc,
+ "Creative Labs Voice format",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ VOC_init, /* init() method */
+ VOC_quit, /* quit() method */
+ VOC_open, /* open() method */
+ VOC_close, /* close() method */
+ VOC_read, /* read() method */
+ VOC_rewind, /* rewind() method */
+ VOC_seek /* seek() method */
+};
+
+
+/* Private data for VOC file */
+typedef struct vocstuff {
+ Uint32 rest; /* bytes remaining in current block */
+ Uint32 rate; /* rate code (byte) of this chunk */
+ int silent; /* sound or silence? */
+ Uint32 srate; /* rate code (byte) of silence */
+ Uint32 blockseek; /* start of current output block */
+ Uint32 samples; /* number of samples output */
+ Uint32 size; /* word length of data */
+ Uint8 channels; /* number of sound channels */
+ int extended; /* Has an extended block been read? */
+ Uint32 bufpos; /* byte position in internal->buffer. */
+ Uint32 start_pos; /* offset to seek to in stream when rewinding. */
+ int error; /* error condition (as opposed to EOF). */
+} vs_t;
+
+
+/* Size field */
+/* SJB: note that the 1st 3 are sometimes used as sizeof(type) */
+#define ST_SIZE_BYTE 1
+#define ST_SIZE_8BIT 1
+#define ST_SIZE_WORD 2
+#define ST_SIZE_16BIT 2
+#define ST_SIZE_DWORD 4
+#define ST_SIZE_32BIT 4
+#define ST_SIZE_FLOAT 5
+#define ST_SIZE_DOUBLE 6
+#define ST_SIZE_IEEE 7 /* IEEE 80-bit floats. */
+
+/* Style field */
+#define ST_ENCODING_UNSIGNED 1 /* unsigned linear: Sound Blaster */
+#define ST_ENCODING_SIGN2 2 /* signed linear 2's comp: Mac */
+#define ST_ENCODING_ULAW 3 /* U-law signed logs: US telephony, SPARC */
+#define ST_ENCODING_ALAW 4 /* A-law signed logs: non-US telephony */
+#define ST_ENCODING_ADPCM 5 /* Compressed PCM */
+#define ST_ENCODING_IMA_ADPCM 6 /* Compressed PCM */
+#define ST_ENCODING_GSM 7 /* GSM 6.10 33-byte frame lossy compression */
+
+#define VOC_TERM 0
+#define VOC_DATA 1
+#define VOC_CONT 2
+#define VOC_SILENCE 3
+#define VOC_MARKER 4
+#define VOC_TEXT 5
+#define VOC_LOOP 6
+#define VOC_LOOPEND 7
+#define VOC_EXTENDED 8
+#define VOC_DATA_16 9
+
+
+static int VOC_init(void)
+{
+ return(1); /* always succeeds. */
+} /* VOC_init */
+
+
+static void VOC_quit(void)
+{
+ /* it's a no-op. */
+} /* VOC_quit */
+
+
+static __inline__ int voc_readbytes(SDL_RWops *src, vs_t *v, void *p, int size)
+{
+ if (SDL_RWread(src, p, size, 1) != 1)
+ {
+ v->error = 1;
+ BAIL_MACRO("VOC: i/o error", 0);
+ } /* if */
+
+ return(1);
+} /* voc_readbytes */
+
+
+static __inline__ int voc_check_header(SDL_RWops *src)
+{
+ /* VOC magic header */
+ Uint8 signature[20]; /* "Creative Voice File\032" */
+ Uint16 datablockofs;
+ vs_t v; /* dummy struct for voc_readbytes */
+
+ if (!voc_readbytes(src, &v, signature, sizeof (signature)))
+ return(0);
+
+ if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0)
+ {
+ BAIL_MACRO("VOC: Wrong signature; not a VOC file.", 0);
+ } /* if */
+
+ /* get the offset where the first datablock is located */
+ if (!voc_readbytes(src, &v, &datablockofs, sizeof (Uint16)))
+ return(0);
+
+ datablockofs = SDL_SwapLE16(datablockofs);
+
+ if (SDL_RWseek(src, datablockofs, SEEK_SET) != datablockofs)
+ {
+ BAIL_MACRO("VOC: Failed to seek to data block.", 0);
+ } /* if */
+
+ return(1); /* success! */
+} /* voc_check_header */
+
+
+/* Read next block header, save info, leave position at start of data */
+static int voc_get_block(Sound_Sample *sample, vs_t *v)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *src = internal->rw;
+ Uint8 bits24[3];
+ Uint8 uc, block;
+ Uint32 sblen;
+ Uint16 new_rate_short;
+ Uint32 new_rate_long;
+ Uint8 trash[6];
+ Uint16 period;
+ int i;
+
+ v->silent = 0;
+ while (v->rest == 0)
+ {
+ if (SDL_RWread(src, &block, sizeof (block), 1) != 1)
+ return 1; /* assume that's the end of the file. */
+
+ if (block == VOC_TERM)
+ return 1;
+
+ if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1)
+ return 1; /* assume that's the end of the file. */
+
+ /* Size is an 24-bit value. Ugh. */
+ sblen = ( (bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16) );
+
+ switch(block)
+ {
+ case VOC_DATA:
+ if (!voc_readbytes(src, v, &uc, sizeof (uc)))
+ return 0;
+
+ /* When DATA block preceeded by an EXTENDED */
+ /* block, the DATA blocks rate value is invalid */
+ if (!v->extended)
+ {
+ BAIL_IF_MACRO(uc == 0, "VOC: Sample rate is zero?", 0);
+
+ if ((v->rate != -1) && (uc != v->rate))
+ BAIL_MACRO("VOC sample rate codes differ", 0);
+
+ v->rate = uc;
+ v->channels = 1;
+ sample->actual.rate = 1000000.0/(256 - v->rate);
+ sample->actual.channels = 1;
+ } /* if */
+
+ if (!voc_readbytes(src, v, &uc, sizeof (uc)))
+ return(0);
+
+ BAIL_IF_MACRO(uc != 0, "VOC: only supports 8-bit data", 0);
+
+ v->extended = 0;
+ v->rest = sblen - 2;
+ v->size = ST_SIZE_BYTE;
+ return 1;
+
+ case VOC_DATA_16:
+ if (!voc_readbytes(src, v, &new_rate_long, sizeof (Uint32)))
+ return 0;
+
+ new_rate_long = SDL_SwapLE32(new_rate_long);
+ BAIL_IF_MACRO(!new_rate_long, "VOC: Sample rate is zero?", 0);
+
+ if ((v->rate != -1) && (new_rate_long != v->rate))
+ BAIL_MACRO("VOC: sample rate codes differ", 0);
+
+ v->rate = new_rate_long;
+ sample->actual.rate = new_rate_long;
+
+ if (!voc_readbytes(src, v, &uc, sizeof (uc)))
+ return 0;
+
+ switch (uc)
+ {
+ case 8: v->size = ST_SIZE_BYTE; break;
+ case 16: v->size = ST_SIZE_WORD; break;
+ default:
+ BAIL_MACRO("VOC: unknown data size", 0);
+ } /* switch */
+
+ if (!voc_readbytes(src, v, &v->channels, sizeof (Uint8)))
+ return 0;
+
+ if (!voc_readbytes(src, v, trash, sizeof (Uint8) * 6))
+ return 0;
+
+ v->rest = sblen - 12;
+ return 1;
+
+ case VOC_CONT:
+ v->rest = sblen;
+ return 1;
+
+ case VOC_SILENCE:
+ if (!voc_readbytes(src, v, &period, sizeof (period)))
+ return 0;
+
+ period = SDL_SwapLE16(period);
+
+ if (!voc_readbytes(src, v, &uc, sizeof (uc)))
+ return 0;
+
+ BAIL_IF_MACRO(uc == 0, "VOC: silence sample rate is zero", 0);
+
+ /*
+ * Some silence-packed files have gratuitously
+ * different sample rate codes in silence.
+ * Adjust period.
+ */
+ if ((v->rate != -1) && (uc != v->rate))
+ period = (period * (256 - uc))/(256 - v->rate);
+ else
+ v->rate = uc;
+ v->rest = period;
+ v->silent = 1;
+ return 1;
+
+ case VOC_LOOP:
+ case VOC_LOOPEND:
+ for(i = 0; i < sblen; i++) /* skip repeat loops. */
+ {
+ if (!voc_readbytes(src, v, trash, sizeof (Uint8)))
+ return 0;
+ } /* for */
+ break;
+
+ case VOC_EXTENDED:
+ /* An Extended block is followed by a data block */
+ /* Set this byte so we know to use the rate */
+ /* value from the extended block and not the */
+ /* data block. */
+ v->extended = 1;
+ if (!voc_readbytes(src, v, &new_rate_short, sizeof (Uint16)))
+ return 0;
+
+ new_rate_short = SDL_SwapLE16(new_rate_short);
+ BAIL_IF_MACRO(!new_rate_short, "VOC: sample rate is zero", 0);
+
+ if ((v->rate != -1) && (new_rate_short != v->rate))
+ BAIL_MACRO("VOC: sample rate codes differ", 0);
+
+ v->rate = new_rate_short;
+
+ if (!voc_readbytes(src, v, &uc, sizeof (uc)))
+ return 0;
+
+ BAIL_IF_MACRO(uc != 0, "VOC: only supports 8-bit data", 0);
+
+ if (!voc_readbytes(src, v, &uc, sizeof (uc)))
+ return 0;
+
+ if (uc)
+ sample->actual.channels = 2; /* Stereo */
+
+ /* Needed number of channels before finishing
+ compute for rate */
+ sample->actual.rate =
+ (256000000L/(65536L - v->rate)) / sample->actual.channels;
+ /* An extended block must be followed by a data */
+ /* block to be valid so loop back to top so it */
+ /* can be grabed. */
+ continue;
+
+ case VOC_MARKER:
+ if (!voc_readbytes(src, v, trash, sizeof (Uint8) * 2))
+ return 0;
+
+ /* Falling! Falling! */
+
+ default: /* text block or other krapola. */
+ for(i = 0; i < sblen; i++) /* skip repeat loops. */
+ {
+ if (!voc_readbytes(src, v, trash, sizeof (Uint8)))
+ return 0;
+ } /* for */
+
+ if (block == VOC_TEXT)
+ continue; /* get next block */
+ } /* switch */
+ } /* while */
+
+ return 1;
+} /* voc_get_block */
+
+
+static int voc_read_waveform(Sound_Sample *sample, int fill_buf, Uint32 max)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *src = internal->rw;
+ vs_t *v = (vs_t *) internal->decoder_private;
+ int done = 0;
+ Uint8 silence = 0x80;
+ Uint8 *buf = internal->buffer;
+
+ if (v->rest == 0)
+ {
+ if (!voc_get_block(sample, v))
+ return 0;
+ } /* if */
+
+ if (v->rest == 0)
+ return 0;
+
+ max = (v->rest < max) ? v->rest : max;
+
+ if (v->silent)
+ {
+ if (v->size == ST_SIZE_WORD)
+ silence = 0x00;
+
+ /* Fill in silence */
+ if (fill_buf)
+ memset(buf + v->bufpos, silence, max);
+
+ done = max;
+ v->rest -= done;
+ } /* if */
+
+ else
+ {
+ if (fill_buf)
+ {
+ done = SDL_RWread(src, buf + v->bufpos, 1, max);
+ if (done < max)
+ {
+ __Sound_SetError("VOC: i/o error");
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ } /* if */
+ } /* if */
+
+ else
+ {
+ int cur, rc;
+ cur = SDL_RWtell(src);
+ if (cur >= 0)
+ {
+ rc = SDL_RWseek(src, max, SEEK_CUR);
+ if (rc >= 0)
+ done = rc - cur;
+ else
+ {
+ __Sound_SetError("VOC: seek error");
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ } /* else */
+ } /* if */
+ } /* else */
+
+ v->rest -= done;
+ v->bufpos += done;
+ } /* else */
+
+ return(done);
+} /* voc_read_waveform */
+
+
+static int VOC_open(Sound_Sample *sample, const char *ext)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ vs_t *v = NULL;
+
+ if (!voc_check_header(internal->rw))
+ return(0);
+
+ v = (vs_t *) malloc(sizeof (vs_t));
+ BAIL_IF_MACRO(v == NULL, ERR_OUT_OF_MEMORY, 0);
+ memset(v, '\0', sizeof (vs_t));
+
+ v->start_pos = SDL_RWtell(internal->rw);
+ v->rate = -1;
+ if (!voc_get_block(sample, v))
+ {
+ free(v);
+ return(0);
+ } /* if */
+
+ if (v->rate == -1)
+ {
+ free(v);
+ BAIL_MACRO("VOC: data had no sound!", 0);
+ } /* if */
+
+ SNDDBG(("VOC: Accepting data stream.\n"));
+ sample->actual.format = (v->size == ST_SIZE_WORD) ? AUDIO_S16LSB:AUDIO_U8;
+ sample->actual.channels = v->channels;
+ sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
+ internal->decoder_private = v;
+ return(1);
+} /* VOC_open */
+
+
+static void VOC_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ free(internal->decoder_private);
+} /* VOC_close */
+
+
+static Uint32 VOC_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ vs_t *v = (vs_t *) internal->decoder_private;
+
+ v->bufpos = 0;
+ while (v->bufpos < internal->buffer_size)
+ {
+ Uint32 rc = voc_read_waveform(sample, 1, internal->buffer_size);
+ if (rc == 0)
+ {
+ sample->flags |= (v->error) ?
+ SOUND_SAMPLEFLAG_ERROR :
+ SOUND_SAMPLEFLAG_EOF;
+ break;
+ } /* if */
+
+ if (!voc_get_block(sample, v))
+ {
+ sample->flags |= (v->error) ?
+ SOUND_SAMPLEFLAG_ERROR :
+ SOUND_SAMPLEFLAG_EOF;
+ break;
+ } /* if */
+ } /* while */
+
+ return(v->bufpos);
+} /* VOC_read */
+
+
+static int VOC_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ vs_t *v = (vs_t *) internal->decoder_private;
+ int rc = SDL_RWseek(internal->rw, v->start_pos, SEEK_SET);
+ BAIL_IF_MACRO(rc != v->start_pos, ERR_IO_ERROR, 0);
+ v->rest = 0;
+ return(1);
+} /* VOC_rewind */
+
+
+static int VOC_seek(Sound_Sample *sample, Uint32 ms)
+{
+ /*
+ * VOCs don't lend themselves well to seeking, since you have to
+ * parse each section, which is an arbitrary size. The best we can do
+ * is rewind, set a flag saying not to write the waveforms to a buffer,
+ * and decode to the point that we want. Ugh. Fortunately, there's
+ * really no such thing as a large VOC, due to the era and hardware that
+ * spawned them, so even though this is inefficient, this is still a
+ * relatively fast operation in most cases.
+ */
+
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ vs_t *v = (vs_t *) internal->decoder_private;
+ int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+ int origpos = SDL_RWtell(internal->rw);
+ int origrest = v->rest;
+
+ BAIL_IF_MACRO(!VOC_rewind(sample), NULL, 0);
+
+ v->bufpos = 0;
+
+ while (offset > 0)
+ {
+ Uint32 rc = voc_read_waveform(sample, 0, offset);
+ if ( (rc == 0) || (!voc_get_block(sample, v)) )
+ {
+ SDL_RWseek(internal->rw, origpos, SEEK_SET);
+ v->rest = origrest;
+ return(0);
+ } /* if */
+
+ offset -= rc;
+ } /* while */
+
+ return(1);
+} /* VOC_seek */
+
+#endif /* SOUND_SUPPORTS_VOC */
+
+/* end of voc.c ... */
diff --git a/util/sdl/sound/decoders/wav.c b/util/sdl/sound/decoders/wav.c
new file mode 100644
index 00000000..cf652f72
--- /dev/null
+++ b/util/sdl/sound/decoders/wav.c
@@ -0,0 +1,800 @@
+/*
+ * 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
+ */
+
+/*
+ * WAV decoder for SDL_sound.
+ *
+ * This driver handles Microsoft .WAVs, in as many of the thousands of
+ * variations as we can.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_WAV
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+static int WAV_init(void);
+static void WAV_quit(void);
+static int WAV_open(Sound_Sample *sample, const char *ext);
+static void WAV_close(Sound_Sample *sample);
+static Uint32 WAV_read(Sound_Sample *sample);
+static int WAV_rewind(Sound_Sample *sample);
+static int WAV_seek(Sound_Sample *sample, Uint32 ms);
+
+static const char *extensions_wav[] = { "WAV", NULL };
+const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV =
+{
+ {
+ extensions_wav,
+ "Microsoft WAVE audio format",
+ "Ryan C. Gordon <icculus@icculus.org>",
+ "http://www.icculus.org/SDL_sound/"
+ },
+
+ WAV_init, /* init() method */
+ WAV_quit, /* quit() method */
+ WAV_open, /* open() method */
+ WAV_close, /* close() method */
+ WAV_read, /* read() method */
+ WAV_rewind, /* rewind() method */
+ WAV_seek /* seek() method */
+};
+
+
+/* Better than SDL_ReadLE16, since you can detect i/o errors... */
+static __inline__ int read_le16(SDL_RWops *rw, Uint16 *ui16)
+{
+ int rc = SDL_RWread(rw, ui16, sizeof (Uint16), 1);
+ BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
+ *ui16 = SDL_SwapLE16(*ui16);
+ return(1);
+} /* read_le16 */
+
+
+/* Better than SDL_ReadLE32, since you can detect i/o errors... */
+static __inline__ int read_le32(SDL_RWops *rw, Uint32 *ui32)
+{
+ int rc = SDL_RWread(rw, ui32, sizeof (Uint32), 1);
+ BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
+ *ui32 = SDL_SwapLE32(*ui32);
+ return(1);
+} /* read_le32 */
+
+
+/* This is just cleaner on the caller's end... */
+static __inline__ int read_uint8(SDL_RWops *rw, Uint8 *ui8)
+{
+ int rc = SDL_RWread(rw, ui8, sizeof (Uint8), 1);
+ BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
+ return(1);
+} /* read_uint8 */
+
+
+ /* Chunk management code... */
+
+#define riffID 0x46464952 /* "RIFF", in ascii. */
+#define waveID 0x45564157 /* "WAVE", in ascii. */
+#define factID 0x74636166 /* "fact", in ascii. */
+
+
+/*****************************************************************************
+ * The FORMAT chunk... *
+ *****************************************************************************/
+
+#define fmtID 0x20746D66 /* "fmt ", in ascii. */
+
+#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */
+#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */
+
+typedef struct
+{
+ Sint16 iCoef1;
+ Sint16 iCoef2;
+} ADPCMCOEFSET;
+
+typedef struct
+{
+ Uint8 bPredictor;
+ Uint16 iDelta;
+ Sint16 iSamp1;
+ Sint16 iSamp2;
+} ADPCMBLOCKHEADER;
+
+typedef struct S_WAV_FMT_T
+{
+ Uint32 chunkID;
+ Sint32 chunkSize;
+ Sint16 wFormatTag;
+ Uint16 wChannels;
+ Uint32 dwSamplesPerSec;
+ Uint32 dwAvgBytesPerSec;
+ Uint16 wBlockAlign;
+ Uint16 wBitsPerSample;
+
+ Uint32 next_chunk_offset;
+
+ Uint32 sample_frame_size;
+ Uint32 data_starting_offset;
+ Uint32 total_bytes;
+
+ void (*free)(struct S_WAV_FMT_T *fmt);
+ Uint32 (*read_sample)(Sound_Sample *sample);
+ int (*rewind_sample)(Sound_Sample *sample);
+ int (*seek_sample)(Sound_Sample *sample, Uint32 ms);
+
+ union
+ {
+ struct
+ {
+ Uint16 cbSize;
+ Uint16 wSamplesPerBlock;
+ Uint16 wNumCoef;
+ ADPCMCOEFSET *aCoef;
+ ADPCMBLOCKHEADER *blockheaders;
+ Uint32 samples_left_in_block;
+ int nibble_state;
+ Sint8 nibble;
+ } adpcm;
+
+ /* put other format-specific data here... */
+ } fmt;
+} fmt_t;
+
+
+/*
+ * Read in a fmt_t from disk. This makes this process safe regardless of
+ * the processor's byte order or how the fmt_t structure is packed.
+ * Note that the union "fmt" is not read in here; that is handled as
+ * needed in the read_fmt_* functions.
+ */
+static int read_fmt_chunk(SDL_RWops *rw, fmt_t *fmt)
+{
+ /* skip reading the chunk ID, since it was already read at this point... */
+ fmt->chunkID = fmtID;
+
+ BAIL_IF_MACRO(!read_le32(rw, &fmt->chunkSize), NULL, 0);
+ BAIL_IF_MACRO(fmt->chunkSize < 16, "WAV: Invalid chunk size", 0);
+ fmt->next_chunk_offset = SDL_RWtell(rw) + fmt->chunkSize;
+
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->wFormatTag), NULL, 0);
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->wChannels), NULL, 0);
+ BAIL_IF_MACRO(!read_le32(rw, &fmt->dwSamplesPerSec), NULL, 0);
+ BAIL_IF_MACRO(!read_le32(rw, &fmt->dwAvgBytesPerSec), NULL, 0);
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->wBlockAlign), NULL, 0);
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->wBitsPerSample), NULL, 0);
+
+ return(1);
+} /* read_fmt_chunk */
+
+
+
+/*****************************************************************************
+ * The DATA chunk... *
+ *****************************************************************************/
+
+#define dataID 0x61746164 /* "data", in ascii. */
+
+typedef struct
+{
+ Uint32 chunkID;
+ Sint32 chunkSize;
+ /* Then, (chunkSize) bytes of waveform data... */
+} data_t;
+
+
+/*
+ * Read in a data_t from disk. This makes this process safe regardless of
+ * the processor's byte order or how the fmt_t structure is packed.
+ */
+static int read_data_chunk(SDL_RWops *rw, data_t *data)
+{
+ /* skip reading the chunk ID, since it was already read at this point... */
+ data->chunkID = dataID;
+ BAIL_IF_MACRO(!read_le32(rw, &data->chunkSize), NULL, 0);
+ return(1);
+} /* read_data_chunk */
+
+
+
+
+/*****************************************************************************
+ * this is what we store in our internal->decoder_private field... *
+ *****************************************************************************/
+
+typedef struct
+{
+ fmt_t *fmt;
+ Sint32 bytesLeft;
+} wav_t;
+
+
+
+
+/*****************************************************************************
+ * Normal, uncompressed waveform handler... *
+ *****************************************************************************/
+
+/*
+ * Sound_Decode() lands here for uncompressed WAVs...
+ */
+static Uint32 read_sample_fmt_normal(Sound_Sample *sample)
+{
+ Uint32 retval;
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ Uint32 max = (internal->buffer_size < (Uint32) w->bytesLeft) ?
+ internal->buffer_size : (Uint32) w->bytesLeft;
+
+ assert(max > 0);
+
+ /*
+ * We don't actually do any decoding, so we read the wav data
+ * directly into the internal buffer...
+ */
+ retval = SDL_RWread(internal->rw, internal->buffer, 1, max);
+
+ w->bytesLeft -= retval;
+
+ /* Make sure the read went smoothly... */
+ if ((retval == 0) || (w->bytesLeft == 0))
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+
+ else if (retval == -1)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+
+ /* (next call this EAGAIN may turn into an EOF or error.) */
+ else if (retval < internal->buffer_size)
+ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+
+ return(retval);
+} /* read_sample_fmt_normal */
+
+
+static int seek_sample_fmt_normal(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ fmt_t *fmt = w->fmt;
+ int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+ int pos = (int) (fmt->data_starting_offset + offset);
+ int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
+ BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
+ w->bytesLeft = fmt->total_bytes - offset;
+ return(1); /* success. */
+} /* seek_sample_fmt_normal */
+
+
+static int rewind_sample_fmt_normal(Sound_Sample *sample)
+{
+ /* no-op. */
+ return(1);
+} /* rewind_sample_fmt_normal */
+
+
+static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt)
+{
+ /* (don't need to read more from the RWops...) */
+ fmt->free = NULL;
+ fmt->read_sample = read_sample_fmt_normal;
+ fmt->rewind_sample = rewind_sample_fmt_normal;
+ fmt->seek_sample = seek_sample_fmt_normal;
+ return(1);
+} /* read_fmt_normal */
+
+
+
+/*****************************************************************************
+ * ADPCM compression handler... *
+ *****************************************************************************/
+
+#define FIXED_POINT_COEF_BASE 256
+#define FIXED_POINT_ADAPTION_BASE 256
+#define SMALLEST_ADPCM_DELTA 16
+
+
+static __inline__ int read_adpcm_block_headers(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ fmt_t *fmt = w->fmt;
+ ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+ int i;
+ int max = fmt->wChannels;
+
+ if (w->bytesLeft < fmt->wBlockAlign)
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_EOF;
+ return(0);
+ } /* if */
+
+ w->bytesLeft -= fmt->wBlockAlign;
+
+ for (i = 0; i < max; i++)
+ BAIL_IF_MACRO(!read_uint8(rw, &headers[i].bPredictor), NULL, 0);
+
+ for (i = 0; i < max; i++)
+ BAIL_IF_MACRO(!read_le16(rw, &headers[i].iDelta), NULL, 0);
+
+ for (i = 0; i < max; i++)
+ BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp1), NULL, 0);
+
+ for (i = 0; i < max; i++)
+ BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp2), NULL, 0);
+
+ fmt->fmt.adpcm.samples_left_in_block = fmt->fmt.adpcm.wSamplesPerBlock;
+ fmt->fmt.adpcm.nibble_state = 0;
+ return(1);
+} /* read_adpcm_block_headers */
+
+
+static __inline__ void do_adpcm_nibble(Uint8 nib,
+ ADPCMBLOCKHEADER *header,
+ Sint32 lPredSamp)
+{
+ static const Sint32 max_audioval = ((1<<(16-1))-1);
+ static const Sint32 min_audioval = -(1<<(16-1));
+ static const Sint32 AdaptionTable[] =
+ {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+ };
+
+ Sint32 lNewSamp;
+ Sint32 delta;
+
+ if (nib & 0x08)
+ lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10));
+ else
+ lNewSamp = lPredSamp + (header->iDelta * nib);
+
+ /* clamp value... */
+ if (lNewSamp < min_audioval)
+ lNewSamp = min_audioval;
+ else if (lNewSamp > max_audioval)
+ lNewSamp = max_audioval;
+
+ delta = ((Sint32) header->iDelta * AdaptionTable[nib]) /
+ FIXED_POINT_ADAPTION_BASE;
+
+ if (delta < SMALLEST_ADPCM_DELTA)
+ delta = SMALLEST_ADPCM_DELTA;
+
+ header->iDelta = delta;
+ header->iSamp2 = header->iSamp1;
+ header->iSamp1 = lNewSamp;
+} /* do_adpcm_nibble */
+
+
+static __inline__ int decode_adpcm_sample_frame(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ fmt_t *fmt = w->fmt;
+ ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+ SDL_RWops *rw = internal->rw;
+ int i;
+ int max = fmt->wChannels;
+ Sint32 delta;
+ Uint8 nib = fmt->fmt.adpcm.nibble;
+
+ for (i = 0; i < max; i++)
+ {
+ Uint8 byte;
+ Sint16 iCoef1 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef1;
+ Sint16 iCoef2 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef2;
+ Sint32 lPredSamp = ((headers[i].iSamp1 * iCoef1) +
+ (headers[i].iSamp2 * iCoef2)) /
+ FIXED_POINT_COEF_BASE;
+
+ if (fmt->fmt.adpcm.nibble_state == 0)
+ {
+ BAIL_IF_MACRO(!read_uint8(rw, &nib), NULL, 0);
+ fmt->fmt.adpcm.nibble_state = 1;
+ do_adpcm_nibble(nib >> 4, &headers[i], lPredSamp);
+ } /* if */
+ else
+ {
+ fmt->fmt.adpcm.nibble_state = 0;
+ do_adpcm_nibble(nib & 0x0F, &headers[i], lPredSamp);
+ } /* else */
+ } /* for */
+
+ fmt->fmt.adpcm.nibble = nib;
+ return(1);
+} /* decode_adpcm_sample_frame */
+
+
+static __inline__ void put_adpcm_sample_frame1(void *_buf, fmt_t *fmt)
+{
+ Uint16 *buf = (Uint16 *) _buf;
+ ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+ int i;
+ for (i = 0; i < fmt->wChannels; i++)
+ *(buf++) = headers[i].iSamp1;
+} /* put_adpcm_sample_frame1 */
+
+
+static __inline__ void put_adpcm_sample_frame2(void *_buf, fmt_t *fmt)
+{
+ Uint16 *buf = (Uint16 *) _buf;
+ ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
+ int i;
+ for (i = 0; i < fmt->wChannels; i++)
+ *(buf++) = headers[i].iSamp2;
+} /* put_adpcm_sample_frame2 */
+
+
+/*
+ * Sound_Decode() lands here for ADPCM-encoded WAVs...
+ */
+static Uint32 read_sample_fmt_adpcm(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ fmt_t *fmt = w->fmt;
+ Uint32 bw = 0;
+
+ while (bw < internal->buffer_size)
+ {
+ /* write ongoing sample frame before reading more data... */
+ switch (fmt->fmt.adpcm.samples_left_in_block)
+ {
+ case 0: /* need to read a new block... */
+ if (!read_adpcm_block_headers(sample))
+ {
+ if ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0)
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(bw);
+ } /* if */
+
+ /* only write first sample frame for now. */
+ put_adpcm_sample_frame2((Uint8 *) internal->buffer + bw, fmt);
+ fmt->fmt.adpcm.samples_left_in_block--;
+ bw += fmt->sample_frame_size;
+ break;
+
+ case 1: /* output last sample frame of block... */
+ put_adpcm_sample_frame1((Uint8 *) internal->buffer + bw, fmt);
+ fmt->fmt.adpcm.samples_left_in_block--;
+ bw += fmt->sample_frame_size;
+ break;
+
+ default: /* output latest sample frame and read a new one... */
+ put_adpcm_sample_frame1((Uint8 *) internal->buffer + bw, fmt);
+ fmt->fmt.adpcm.samples_left_in_block--;
+ bw += fmt->sample_frame_size;
+
+ if (!decode_adpcm_sample_frame(sample))
+ {
+ sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+ return(bw);
+ } /* if */
+ } /* switch */
+ } /* while */
+
+ return(bw);
+} /* read_sample_fmt_adpcm */
+
+
+/*
+ * Sound_FreeSample() lands here for ADPCM-encoded WAVs...
+ */
+static void free_fmt_adpcm(fmt_t *fmt)
+{
+ if (fmt->fmt.adpcm.aCoef != NULL)
+ free(fmt->fmt.adpcm.aCoef);
+
+ if (fmt->fmt.adpcm.blockheaders != NULL)
+ free(fmt->fmt.adpcm.blockheaders);
+} /* free_fmt_adpcm */
+
+
+static int rewind_sample_fmt_adpcm(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ w->fmt->fmt.adpcm.samples_left_in_block = 0;
+ return(1);
+} /* rewind_sample_fmt_adpcm */
+
+
+static int seek_sample_fmt_adpcm(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ fmt_t *fmt = w->fmt;
+ Uint32 origsampsleft = fmt->fmt.adpcm.samples_left_in_block;
+ int origpos = SDL_RWtell(internal->rw);
+ int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
+ int bpb = (fmt->fmt.adpcm.wSamplesPerBlock * fmt->sample_frame_size);
+ int skipsize = (offset / bpb) * fmt->wBlockAlign;
+ int pos = skipsize + fmt->data_starting_offset;
+ int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
+ BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
+
+ /* The offset we need is in this block, so we need to decode to there. */
+ skipsize += (offset % bpb);
+ rc = (offset % bpb); /* bytes into this block we need to decode */
+ if (!read_adpcm_block_headers(sample))
+ {
+ SDL_RWseek(internal->rw, origpos, SEEK_SET); /* try to make sane. */
+ return(0);
+ } /* if */
+
+ /* first sample frame of block is a freebie. :) */
+ fmt->fmt.adpcm.samples_left_in_block--;
+ rc -= fmt->sample_frame_size;
+ while (rc > 0)
+ {
+ if (!decode_adpcm_sample_frame(sample))
+ {
+ SDL_RWseek(internal->rw, origpos, SEEK_SET);
+ fmt->fmt.adpcm.samples_left_in_block = origsampsleft;
+ return(0);
+ } /* if */
+
+ fmt->fmt.adpcm.samples_left_in_block--;
+ rc -= fmt->sample_frame_size;
+ } /* while */
+
+ w->bytesLeft = fmt->total_bytes - skipsize;
+ return(1); /* success. */
+} /* seek_sample_fmt_adpcm */
+
+
+/*
+ * Read in the adpcm-specific info from disk. This makes this process
+ * safe regardless of the processor's byte order or how the fmt_t
+ * structure is packed.
+ */
+static int read_fmt_adpcm(SDL_RWops *rw, fmt_t *fmt)
+{
+ size_t i;
+
+ memset(&fmt->fmt.adpcm, '\0', sizeof (fmt->fmt.adpcm));
+ fmt->free = free_fmt_adpcm;
+ fmt->read_sample = read_sample_fmt_adpcm;
+ fmt->rewind_sample = rewind_sample_fmt_adpcm;
+ fmt->seek_sample = seek_sample_fmt_adpcm;
+
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.cbSize), NULL, 0);
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wSamplesPerBlock), NULL, 0);
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wNumCoef), NULL, 0);
+
+ /* fmt->free() is always called, so these malloc()s will be cleaned up. */
+
+ i = sizeof (ADPCMCOEFSET) * fmt->fmt.adpcm.wNumCoef;
+ fmt->fmt.adpcm.aCoef = (ADPCMCOEFSET *) malloc(i);
+ BAIL_IF_MACRO(fmt->fmt.adpcm.aCoef == NULL, ERR_OUT_OF_MEMORY, 0);
+
+ for (i = 0; i < fmt->fmt.adpcm.wNumCoef; i++)
+ {
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef1), NULL, 0);
+ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef2), NULL, 0);
+ } /* for */
+
+ i = sizeof (ADPCMBLOCKHEADER) * fmt->wChannels;
+ fmt->fmt.adpcm.blockheaders = (ADPCMBLOCKHEADER *) malloc(i);
+ BAIL_IF_MACRO(fmt->fmt.adpcm.blockheaders == NULL, ERR_OUT_OF_MEMORY, 0);
+
+ return(1);
+} /* read_fmt_adpcm */
+
+
+
+/*****************************************************************************
+ * Everything else... *
+ *****************************************************************************/
+
+static int WAV_init(void)
+{
+ return(1); /* always succeeds. */
+} /* WAV_init */
+
+
+static void WAV_quit(void)
+{
+ /* it's a no-op. */
+} /* WAV_quit */
+
+
+static int read_fmt(SDL_RWops *rw, fmt_t *fmt)
+{
+ /* if it's in this switch statement, we support the format. */
+ switch (fmt->wFormatTag)
+ {
+ case FMT_NORMAL:
+ SNDDBG(("WAV: Appears to be uncompressed audio.\n"));
+ return(read_fmt_normal(rw, fmt));
+
+ case FMT_ADPCM:
+ SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n"));
+ return(read_fmt_adpcm(rw, fmt));
+
+ /* add other types here. */
+
+ default:
+ SNDDBG(("WAV: Format 0x%X is unknown.\n",
+ (unsigned int) fmt->wFormatTag));
+ BAIL_MACRO("WAV: Unsupported format", 0);
+ } /* switch */
+
+ assert(0); /* shouldn't hit this point. */
+ return(0);
+} /* read_fmt */
+
+
+/*
+ * Locate a specific chunk in the WAVE file by ID...
+ */
+static int find_chunk(SDL_RWops *rw, Uint32 id)
+{
+ Sint32 siz = 0;
+ Uint32 _id = 0;
+ Uint32 pos = SDL_RWtell(rw);
+
+ while (1)
+ {
+ BAIL_IF_MACRO(!read_le32(rw, &_id), NULL, 0);
+ if (_id == id)
+ return(1);
+
+ /* skip ahead and see what next chunk is... */
+ BAIL_IF_MACRO(!read_le32(rw, &siz), NULL, 0);
+ assert(siz >= 0);
+ pos += (sizeof (Uint32) * 2) + siz;
+ if (siz > 0)
+ BAIL_IF_MACRO(SDL_RWseek(rw, pos, SEEK_SET) != pos, NULL, 0);
+ } /* while */
+
+ return(0); /* shouldn't hit this, but just in case... */
+} /* find_chunk */
+
+
+static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ SDL_RWops *rw = internal->rw;
+ data_t d;
+ wav_t *w;
+ Uint32 pos;
+
+ BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0);
+ SDL_ReadLE32(rw); /* throw the length away; we get this info later. */
+ BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0);
+ BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0);
+ BAIL_IF_MACRO(!read_fmt_chunk(rw, fmt), "WAV: Can't read format chunk.", 0);
+
+ sample->actual.channels = (Uint8) fmt->wChannels;
+ sample->actual.rate = fmt->dwSamplesPerSec;
+ if ((fmt->wBitsPerSample == 4) /*|| (fmt->wBitsPerSample == 0) */ )
+ sample->actual.format = AUDIO_S16SYS;
+ else if (fmt->wBitsPerSample == 8)
+ sample->actual.format = AUDIO_U8;
+ else if (fmt->wBitsPerSample == 16)
+ sample->actual.format = AUDIO_S16LSB;
+ else
+ {
+ SNDDBG(("WAV: %d bits per sample!?\n", (int) fmt->wBitsPerSample));
+ BAIL_MACRO("WAV: Unsupported sample size.", 0);
+ } /* else */
+
+ BAIL_IF_MACRO(!read_fmt(rw, fmt), NULL, 0);
+ SDL_RWseek(rw, fmt->next_chunk_offset, SEEK_SET);
+ BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0);
+ BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0);
+
+ w = (wav_t *) malloc(sizeof(wav_t));
+ BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0);
+ w->fmt = fmt;
+ fmt->total_bytes = w->bytesLeft = d.chunkSize;
+ fmt->data_starting_offset = SDL_RWtell(rw);
+ fmt->sample_frame_size = ( ((sample->actual.format & 0xFF) / 8) *
+ sample->actual.channels );
+
+ internal->decoder_private = (void *) w;
+
+ sample->flags = SOUND_SAMPLEFLAG_NONE;
+ if (fmt->seek_sample != NULL)
+ sample->flags |= SOUND_SAMPLEFLAG_CANSEEK;
+
+ SNDDBG(("WAV: Accepting data stream.\n"));
+ return(1); /* we'll handle this data. */
+} /* WAV_open_internal */
+
+
+static int WAV_open(Sound_Sample *sample, const char *ext)
+{
+ int rc;
+
+ fmt_t *fmt = (fmt_t *) malloc(sizeof (fmt_t));
+ BAIL_IF_MACRO(fmt == NULL, ERR_OUT_OF_MEMORY, 0);
+ memset(fmt, '\0', sizeof (fmt_t));
+
+ rc = WAV_open_internal(sample, ext, fmt);
+ if (!rc)
+ {
+ if (fmt->free != NULL)
+ fmt->free(fmt);
+ free(fmt);
+ } /* if */
+
+ return(rc);
+} /* WAV_open */
+
+
+static void WAV_close(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+
+ if (w->fmt->free != NULL)
+ w->fmt->free(w->fmt);
+
+ free(w->fmt);
+ free(w);
+} /* WAV_close */
+
+
+static Uint32 WAV_read(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ return(w->fmt->read_sample(sample));
+} /* WAV_read */
+
+
+static int WAV_rewind(Sound_Sample *sample)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ fmt_t *fmt = w->fmt;
+ int rc = SDL_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET);
+ BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0);
+ w->bytesLeft = fmt->total_bytes;
+ return(fmt->rewind_sample(sample));
+} /* WAV_rewind */
+
+
+static int WAV_seek(Sound_Sample *sample, Uint32 ms)
+{
+ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+ wav_t *w = (wav_t *) internal->decoder_private;
+ return(w->fmt->seek_sample(sample, ms));
+} /* WAV_seek */
+
+#endif /* SOUND_SUPPORTS_WAV */
+
+/* end of wav.c ... */
+
diff --git a/util/sdl/sound/docs/README b/util/sdl/sound/docs/README
new file mode 100644
index 00000000..4f9d16f4
--- /dev/null
+++ b/util/sdl/sound/docs/README
@@ -0,0 +1,3 @@
+Docs are generated with the program Doxygen (http://www.doxygen.org/),
+ or can be read online at http://icculus.org/SDL_sound/docs/
+
diff --git a/util/sdl/sound/extra_rwops.c b/util/sdl/sound/extra_rwops.c
new file mode 100644
index 00000000..6ea92c30
--- /dev/null
+++ b/util/sdl/sound/extra_rwops.c
@@ -0,0 +1,135 @@
+/*
+ * 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
+ */
+
+/*
+ * Some extra RWops that are needed or are just handy to have.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "SDL.h"
+
+
+ /*
+ * The Reference Counter RWops...
+ */
+
+
+typedef struct
+{
+ SDL_RWops *rw; /* The actual RWops we're refcounting... */
+ int refcount; /* The refcount; starts at 1. If goes to 0, delete. */
+} RWRefCounterData;
+
+
+/* Just pass through to the actual SDL_RWops's method... */
+static int refcounter_seek(SDL_RWops *rw, int offset, int whence)
+{
+ RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
+ return(data->rw->seek(data->rw, offset, whence));
+} /* refcounter_seek */
+
+
+/* Just pass through to the actual SDL_RWops's method... */
+static int refcounter_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+{
+ RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
+ return(data->rw->read(data->rw, ptr, size, maxnum));
+} /* refcounter_read */
+
+
+/* Just pass through to the actual SDL_RWops's method... */
+static int refcounter_write(SDL_RWops *rw, const void *ptr, int size, int num)
+{
+ RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
+ return(data->rw->write(data->rw, ptr, size, num));
+} /* refcounter_write */
+
+
+/*
+ * Decrement the reference count. If there are no more references, pass
+ * through to the actual SDL_RWops's method, and then clean ourselves up.
+ */
+static int refcounter_close(SDL_RWops *rw)
+{
+ int retval = 0;
+ RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
+ data->refcount--;
+ if (data->refcount <= 0)
+ {
+ retval = data->rw->close(data->rw);
+ free(data);
+ SDL_FreeRW(rw);
+ } /* if */
+
+ return(retval);
+} /* refcounter_close */
+
+
+void RWops_RWRefCounter_addRef(SDL_RWops *rw)
+{
+ RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
+ data->refcount++;
+} /* RWops_RWRefCounter_addRef */
+
+
+SDL_RWops *RWops_RWRefCounter_new(SDL_RWops *rw)
+{
+ SDL_RWops *retval = NULL;
+
+ if (rw == NULL)
+ {
+ SDL_SetError("NULL argument to RWops_RWRefCounter_new().");
+ return(NULL);
+ } /* if */
+
+ retval = SDL_AllocRW();
+ if (retval != NULL)
+ {
+ RWRefCounterData *data;
+ data = (RWRefCounterData *) malloc(sizeof (RWRefCounterData));
+ if (data == NULL)
+ {
+ SDL_SetError("Out of memory.");
+ SDL_FreeRW(retval);
+ retval = NULL;
+ } /* if */
+ else
+ {
+ data->rw = rw;
+ data->refcount = 1;
+ retval->hidden.unknown.data1 = data;
+ retval->seek = refcounter_seek;
+ retval->read = refcounter_read;
+ retval->write = refcounter_write;
+ retval->close = refcounter_close;
+ } /* else */
+ } /* if */
+
+ return(retval);
+} /* RWops_RWRefCounter_new */
+
+
+/* end of extra_rwops.c ... */
+
+
diff --git a/util/sdl/sound/extra_rwops.h b/util/sdl/sound/extra_rwops.h
new file mode 100644
index 00000000..f86b5564
--- /dev/null
+++ b/util/sdl/sound/extra_rwops.h
@@ -0,0 +1,71 @@
+/*
+ * 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
+ */
+
+/*
+ * Some extra RWops that are needed or are just handy to have.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#ifndef _INCLUDE_EXTRA_RWOPS_H_
+#define _INCLUDE_EXTRA_RWOPS_H_
+
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The Reference Counter RWops...
+ *
+ * This wraps another RWops with a reference counter. When you create a
+ * reference counter RWops, it sets a counter to one. Everytime you call
+ * RWops_RWRefCounter_new(), that's RWops's counter increments by one.
+ * Everytime you call that RWops's close() method, the counter decrements
+ * by one. If the counter hits zero, the original RWops's close() method
+ * is called, and the reference counting wrapper deletes itself. The read,
+ * write, and seek methods just pass through to the original.
+ *
+ * This is handy if you have two libraries (in the original case, SDL_sound
+ * and SMPEG), who both want an SDL_RWops, and both want to close it when
+ * they are finished. This resolves that contention. The user creates a
+ * RWops, passes it to SDL_sound, which wraps it in a reference counter and
+ * increments the number of references, and passes the wrapped RWops to
+ * SMPEG. SMPEG "closes" this wrapped RWops when the MP3 has finished
+ * playing, and SDL_sound then closes it, too. This second closing removes
+ * the last reference, and the RWops is smoothly destructed.
+ */
+
+/* Return a SDL_RWops that is a reference counting wrapper of (rw). */
+SDL_RWops *RWops_RWRefCounter_new(SDL_RWops *rw);
+
+/* Increment a reference counting RWops's refcount by one. */
+void RWops_RWRefCounter_addRef(SDL_RWops *rw);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined _INCLUDE_EXTRA_RWOPS_H_ */
+
+/* end of extra_rwops.h ... */
+
diff --git a/util/sdl/sound/install-sh b/util/sdl/sound/install-sh
new file mode 100755
index 00000000..4d4a9519
--- /dev/null
+++ b/util/sdl/sound/install-sh
@@ -0,0 +1,323 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2005-05-14.22
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ *) # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ test -n "$dir_arg$dstarg" && break
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+ break;;
+ esac
+done
+
+if test -z "$1"; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ src=
+
+ if test -d "$dst"; then
+ mkdircmd=:
+ chmodcmd=
+ else
+ mkdircmd=$mkdirprog
+ fi
+ else
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dst=$dst/`basename "$src"`
+ fi
+ fi
+
+ # This sed command emulates the dirname command.
+ dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+
+ # Make sure that the destination directory exists.
+
+ # Skip lots of stat calls in the usual case.
+ if test ! -d "$dstdir"; then
+ defaultIFS='
+ '
+ IFS="${IFS-$defaultIFS}"
+
+ oIFS=$IFS
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+ shift
+ IFS=$oIFS
+
+ pathcomp=
+
+ while test $# -ne 0 ; do
+ pathcomp=$pathcomp$1
+ shift
+ if test ! -d "$pathcomp"; then
+ $mkdirprog "$pathcomp"
+ # mkdir can fail with a `File exist' error in case several
+ # install-sh are creating the directory concurrently. This
+ # is OK.
+ test -d "$pathcomp" || exit
+ fi
+ pathcomp=$pathcomp/
+ done
+ fi
+
+ if test -n "$dir_arg"; then
+ $doit $mkdircmd "$dst" \
+ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+ else
+ dstfile=`basename "$dst"`
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Copy the file name to the temp name.
+ $doit $cpprog "$src" "$dsttmp" &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dstdir/$dstfile"; then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+ || {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit 1
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+ }
+ }
+ fi || { (exit 1); exit 1; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+ (exit 0); exit 0
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/util/sdl/sound/playsound/Makefile.am b/util/sdl/sound/playsound/Makefile.am
new file mode 100644
index 00000000..4886b909
--- /dev/null
+++ b/util/sdl/sound/playsound/Makefile.am
@@ -0,0 +1,19 @@
+bin_PROGRAMS = playsound playsound_simple
+
+INCLUDES = -I$(top_srcdir)
+
+if USE_PHYSICSFS
+PHYSFS_CFLG = -DSUPPORT_PHYSFS=1
+PHYSFS_LIBS = -lphysfs
+else
+PHYSFS_CFLG =
+PHYSFS_SRCS =
+PHYSFS_LIBS =
+endif
+
+playsound_CFLAGS = $(PHYSFS_CFLG)
+playsound_LDADD = ../libSDL_sound.la $(PHYSFS_LIBS)
+playsound_SOURCES = playsound.c physfsrwops.c physfsrwops.h
+
+playsound_simple_LDADD = ../libSDL_sound.la
+playsound_simple_SOURCES = playsound_simple.c
diff --git a/util/sdl/sound/playsound/Makefile.in b/util/sdl/sound/playsound/Makefile.in
new file mode 100644
index 00000000..d2142867
--- /dev/null
+++ b/util/sdl/sound/playsound/Makefile.in
@@ -0,0 +1,520 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS = playsound$(EXEEXT) playsound_simple$(EXEEXT)
+subdir = playsound
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am_playsound_OBJECTS = playsound-playsound.$(OBJEXT) \
+ playsound-physfsrwops.$(OBJEXT)
+playsound_OBJECTS = $(am_playsound_OBJECTS)
+am__DEPENDENCIES_1 =
+playsound_DEPENDENCIES = ../libSDL_sound.la $(am__DEPENDENCIES_1)
+am_playsound_simple_OBJECTS = playsound_simple.$(OBJEXT)
+playsound_simple_OBJECTS = $(am_playsound_simple_OBJECTS)
+playsound_simple_DEPENDENCIES = ../libSDL_sound.la
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(playsound_SOURCES) $(playsound_simple_SOURCES)
+DIST_SOURCES = $(playsound_SOURCES) $(playsound_simple_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_AGE = @BINARY_AGE@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERFACE_AGE = @INTERFACE_AGE@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAJOR_VERSION = @MAJOR_VERSION@
+MAKEINFO = @MAKEINFO@
+MICRO_VERSION = @MICRO_VERSION@
+MINOR_VERSION = @MINOR_VERSION@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_MPGLIB_FALSE = @USE_MPGLIB_FALSE@
+USE_MPGLIB_TRUE = @USE_MPGLIB_TRUE@
+USE_PHYSICSFS_FALSE = @USE_PHYSICSFS_FALSE@
+USE_PHYSICSFS_TRUE = @USE_PHYSICSFS_TRUE@
+USE_TIMIDITY_FALSE = @USE_TIMIDITY_FALSE@
+USE_TIMIDITY_TRUE = @USE_TIMIDITY_TRUE@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = -I$(top_srcdir)
+@USE_PHYSICSFS_FALSE@PHYSFS_CFLG =
+@USE_PHYSICSFS_TRUE@PHYSFS_CFLG = -DSUPPORT_PHYSFS=1
+@USE_PHYSICSFS_FALSE@PHYSFS_LIBS =
+@USE_PHYSICSFS_TRUE@PHYSFS_LIBS = -lphysfs
+@USE_PHYSICSFS_FALSE@PHYSFS_SRCS =
+playsound_CFLAGS = $(PHYSFS_CFLG)
+playsound_LDADD = ../libSDL_sound.la $(PHYSFS_LIBS)
+playsound_SOURCES = playsound.c physfsrwops.c physfsrwops.h
+playsound_simple_LDADD = ../libSDL_sound.la
+playsound_simple_SOURCES = playsound_simple.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign playsound/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign playsound/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ || test -f $$p1 \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f $$p $$f"; \
+ rm -f $$p $$f ; \
+ done
+playsound$(EXEEXT): $(playsound_OBJECTS) $(playsound_DEPENDENCIES)
+ @rm -f playsound$(EXEEXT)
+ $(LINK) $(playsound_LDFLAGS) $(playsound_OBJECTS) $(playsound_LDADD) $(LIBS)
+playsound_simple$(EXEEXT): $(playsound_simple_OBJECTS) $(playsound_simple_DEPENDENCIES)
+ @rm -f playsound_simple$(EXEEXT)
+ $(LINK) $(playsound_simple_LDFLAGS) $(playsound_simple_OBJECTS) $(playsound_simple_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playsound-physfsrwops.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playsound-playsound.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playsound_simple.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+playsound-playsound.o: playsound.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -MT playsound-playsound.o -MD -MP -MF "$(DEPDIR)/playsound-playsound.Tpo" -c -o playsound-playsound.o `test -f 'playsound.c' || echo '$(srcdir)/'`playsound.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/playsound-playsound.Tpo" "$(DEPDIR)/playsound-playsound.Po"; else rm -f "$(DEPDIR)/playsound-playsound.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='playsound.c' object='playsound-playsound.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -c -o playsound-playsound.o `test -f 'playsound.c' || echo '$(srcdir)/'`playsound.c
+
+playsound-playsound.obj: playsound.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -MT playsound-playsound.obj -MD -MP -MF "$(DEPDIR)/playsound-playsound.Tpo" -c -o playsound-playsound.obj `if test -f 'playsound.c'; then $(CYGPATH_W) 'playsound.c'; else $(CYGPATH_W) '$(srcdir)/playsound.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/playsound-playsound.Tpo" "$(DEPDIR)/playsound-playsound.Po"; else rm -f "$(DEPDIR)/playsound-playsound.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='playsound.c' object='playsound-playsound.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -c -o playsound-playsound.obj `if test -f 'playsound.c'; then $(CYGPATH_W) 'playsound.c'; else $(CYGPATH_W) '$(srcdir)/playsound.c'; fi`
+
+playsound-physfsrwops.o: physfsrwops.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -MT playsound-physfsrwops.o -MD -MP -MF "$(DEPDIR)/playsound-physfsrwops.Tpo" -c -o playsound-physfsrwops.o `test -f 'physfsrwops.c' || echo '$(srcdir)/'`physfsrwops.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/playsound-physfsrwops.Tpo" "$(DEPDIR)/playsound-physfsrwops.Po"; else rm -f "$(DEPDIR)/playsound-physfsrwops.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='physfsrwops.c' object='playsound-physfsrwops.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -c -o playsound-physfsrwops.o `test -f 'physfsrwops.c' || echo '$(srcdir)/'`physfsrwops.c
+
+playsound-physfsrwops.obj: physfsrwops.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -MT playsound-physfsrwops.obj -MD -MP -MF "$(DEPDIR)/playsound-physfsrwops.Tpo" -c -o playsound-physfsrwops.obj `if test -f 'physfsrwops.c'; then $(CYGPATH_W) 'physfsrwops.c'; else $(CYGPATH_W) '$(srcdir)/physfsrwops.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/playsound-physfsrwops.Tpo" "$(DEPDIR)/playsound-physfsrwops.Po"; else rm -f "$(DEPDIR)/playsound-physfsrwops.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='physfsrwops.c' object='playsound-physfsrwops.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(playsound_CFLAGS) $(CFLAGS) -c -o playsound-physfsrwops.obj `if test -f 'physfsrwops.c'; then $(CYGPATH_W) 'physfsrwops.c'; else $(CYGPATH_W) '$(srcdir)/physfsrwops.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/util/sdl/sound/playsound/physfsrwops.c b/util/sdl/sound/playsound/physfsrwops.c
new file mode 100644
index 00000000..42377fe5
--- /dev/null
+++ b/util/sdl/sound/playsound/physfsrwops.c
@@ -0,0 +1,195 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ * Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ * correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ * verbatim into a closed-source project, exploiting it commercially, and
+ * removing any trace of my name from the source (although I hope you won't
+ * do that). I welcome enhancements and corrections to this file, but I do
+ * not require you to send me patches if you make changes.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser
+ * General Public License: http://www.gnu.org/licenses/lgpl.txt
+ *
+ * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/
+ *
+ * This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#if SUPPORT_PHYSFS
+
+#include <stdio.h> /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
+#include "physfsrwops.h"
+
+static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
+{
+ PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
+ int pos = 0;
+
+ if (whence == SEEK_SET)
+ {
+ pos = offset;
+ } /* if */
+
+ else if (whence == SEEK_CUR)
+ {
+ PHYSFS_sint64 current = PHYSFS_tell(handle);
+ if (current == -1)
+ {
+ SDL_SetError("Can't find position in file: %s",
+ PHYSFS_getLastError());
+ return(-1);
+ } /* if */
+
+ pos = (int) current;
+ if ( ((PHYSFS_sint64) pos) != current )
+ {
+ SDL_SetError("Can't fit current file position in an int!");
+ return(-1);
+ } /* if */
+
+ if (offset == 0) /* this is a "tell" call. We're done. */
+ return(pos);
+
+ pos += offset;
+ } /* else if */
+
+ else if (whence == SEEK_END)
+ {
+ PHYSFS_sint64 len = PHYSFS_fileLength(handle);
+ if (len == -1)
+ {
+ SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
+ return(-1);
+ } /* if */
+
+ pos = (int) len;
+ if ( ((PHYSFS_sint64) pos) != len )
+ {
+ SDL_SetError("Can't fit end-of-file position in an int!");
+ return(-1);
+ } /* if */
+
+ pos += offset;
+ } /* else if */
+
+ else
+ {
+ SDL_SetError("Invalid 'whence' parameter.");
+ return(-1);
+ } /* else */
+
+ if ( pos < 0 )
+ {
+ SDL_SetError("Attempt to seek past start of file.");
+ return(-1);
+ } /* if */
+
+ if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
+ {
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ return(-1);
+ } /* if */
+
+ return(pos);
+} /* physfsrwops_seek */
+
+
+static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
+{
+ PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
+ PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum);
+ if (rc != maxnum)
+ {
+ if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ } /* if */
+
+ return((int) rc);
+} /* physfsrwops_read */
+
+
+static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
+{
+ PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
+ PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num);
+ if (rc != num)
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+
+ return((int) rc);
+} /* physfsrwops_write */
+
+
+static int physfsrwops_close(SDL_RWops *rw)
+{
+ PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
+ if (!PHYSFS_close(handle))
+ {
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ return(-1);
+ } /* if */
+
+ SDL_FreeRW(rw);
+ return(0);
+} /* physfsrwops_close */
+
+
+static SDL_RWops *create_rwops(PHYSFS_file *handle)
+{
+ SDL_RWops *retval = NULL;
+
+ if (handle == NULL)
+ SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
+ else
+ {
+ retval = SDL_AllocRW();
+ if (retval != NULL)
+ {
+ retval->seek = physfsrwops_seek;
+ retval->read = physfsrwops_read;
+ retval->write = physfsrwops_write;
+ retval->close = physfsrwops_close;
+ retval->hidden.unknown.data1 = handle;
+ } /* if */
+ } /* else */
+
+ return(retval);
+} /* create_rwops */
+
+
+SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle)
+{
+ SDL_RWops *retval = NULL;
+ if (handle == NULL)
+ SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
+ else
+ retval = create_rwops(handle);
+
+ return(retval);
+} /* PHYSFSRWOPS_makeRWops */
+
+
+SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
+{
+ return(create_rwops(PHYSFS_openRead(fname)));
+} /* PHYSFSRWOPS_openRead */
+
+
+SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
+{
+ return(create_rwops(PHYSFS_openWrite(fname)));
+} /* PHYSFSRWOPS_openWrite */
+
+
+SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
+{
+ return(create_rwops(PHYSFS_openAppend(fname)));
+} /* PHYSFSRWOPS_openAppend */
+
+#endif
+
+/* end of physfsrwops.c ... */
+
diff --git a/util/sdl/sound/playsound/physfsrwops.h b/util/sdl/sound/playsound/physfsrwops.h
new file mode 100644
index 00000000..5ff519a1
--- /dev/null
+++ b/util/sdl/sound/playsound/physfsrwops.h
@@ -0,0 +1,87 @@
+/*
+ * This code provides a glue layer between PhysicsFS and Simple Directmedia
+ * Layer's (SDL) RWops i/o abstraction.
+ *
+ * License: this code is public domain. I make no warranty that it is useful,
+ * correct, harmless, or environmentally safe.
+ *
+ * This particular file may be used however you like, including copying it
+ * verbatim into a closed-source project, exploiting it commercially, and
+ * removing any trace of my name from the source (although I hope you won't
+ * do that). I welcome enhancements and corrections to this file, but I do
+ * not require you to send me patches if you make changes.
+ *
+ * Unless otherwise stated, the rest of PhysicsFS falls under the GNU Lesser
+ * General Public License: http://www.gnu.org/licenses/lgpl.txt
+ *
+ * SDL falls under the LGPL, too. You can get SDL at http://www.libsdl.org/
+ *
+ * This file was written by Ryan C. Gordon. (icculus@icculus.org).
+ */
+
+#ifndef _INCLUDE_PHYSFSRWOPS_H_
+#define _INCLUDE_PHYSFSRWOPS_H_
+
+#include "physfs.h"
+#include "SDL.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Open a platform-independent filename for reading, and make it accessible
+ * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ * RWops is closed. PhysicsFS should be configured to your liking before
+ * opening files through this method.
+ *
+ * @param filename File to open in platform-independent notation.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openRead(const char *fname);
+
+/**
+ * Open a platform-independent filename for writing, and make it accessible
+ * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ * RWops is closed. PhysicsFS should be configured to your liking before
+ * opening files through this method.
+ *
+ * @param filename File to open in platform-independent notation.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname);
+
+/**
+ * Open a platform-independent filename for appending, and make it accessible
+ * via an SDL_RWops structure. The file will be closed in PhysicsFS when the
+ * RWops is closed. PhysicsFS should be configured to your liking before
+ * opening files through this method.
+ *
+ * @param filename File to open in platform-independent notation.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname);
+
+/**
+ * Make a SDL_RWops from an existing PhysicsFS file handle. You should
+ * dispose of any references to the handle after successful creation of
+ * the RWops. The actual PhysicsFS handle will be destroyed when the
+ * RWops is closed.
+ *
+ * @param handle a valid PhysicsFS file handle.
+ * @return A valid SDL_RWops structure on success, NULL on error. Specifics
+ * of the error can be gleaned from PHYSFS_getLastError().
+ */
+__EXPORT__ SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* include-once blocker */
+
+/* end of physfsrwops.h ... */
+
diff --git a/util/sdl/sound/playsound/playsound.c b/util/sdl/sound/playsound/playsound.c
new file mode 100644
index 00000000..d160e053
--- /dev/null
+++ b/util/sdl/sound/playsound/playsound.c
@@ -0,0 +1,1062 @@
+/*
+ * 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 COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_ASSERT_H
+# include <assert.h>
+#elif (!defined assert)
+# define assert(x)
+#endif
+
+#if HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+#include "SDL.h"
+#include "SDL_sound.h"
+
+#if SUPPORT_PHYSFS
+#include "physfs.h"
+#include "physfsrwops.h"
+#endif
+
+#define DEFAULT_DECODEBUF 16384
+#define DEFAULT_AUDIOBUF 4096
+
+#define PLAYSOUND_VER_MAJOR 0
+#define PLAYSOUND_VER_MINOR 1
+#define PLAYSOUND_VER_PATCH 5
+
+
+static const char *option_list[] =
+{
+ "--rate", "n Playback at sample rate of n HZ.",
+ "--format", "fmt Playback in fmt format (see below).",
+ "--channels", "n Playback on n channels (1 or 2).",
+ "--decodebuf", "n Buffer n decoded bytes at a time (default 16384).",
+ "--audiobuf", "n Buffer n samples to audio device (default 4096).",
+ "--volume", "n Playback volume multiplier (default 1.0).",
+ "--stdin", "[ext] Read from stdin (treat data as format [ext])",
+ "--version", " Display version information and exit.",
+ "--decoders", " List supported data formats and exit.",
+ "--predecode", " Decode entire sample before playback.",
+ "--loop", "n Loop playback n times.",
+ "--seek", "list List of seek points and playback durations.",
+ "--credits", " Shameless promotion.",
+ "--help", " Display this information and exit.",
+ NULL, NULL
+};
+
+
+static void output_versions(const char *argv0)
+{
+ 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();
+
+ fprintf(stdout,
+ "%s version %d.%d.%d\n"
+ "Copyright 2001 Ryan C. Gordon\n"
+ "This program is free software, covered by the GNU Lesser General\n"
+ "Public License, and you are welcome to change it and/or\n"
+ "distribute copies of it under certain conditions. There is\n"
+ "absolutely NO WARRANTY for this program.\n"
+ "\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",
+ argv0,
+ PLAYSOUND_VER_MAJOR, PLAYSOUND_VER_MINOR, PLAYSOUND_VER_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;
+ const char **ext;
+
+ fprintf(stdout, "Supported sound formats:\n");
+ if (rc == NULL)
+ fprintf(stdout, " * Apparently, NONE!\n");
+ else
+ {
+ for (i = rc; *i != NULL; i++)
+ {
+ fprintf(stdout, " * %s\n", (*i)->description);
+
+ for (ext = (*i)->extensions; *ext != NULL; ext++)
+ fprintf(stdout, " File extension \"%s\"\n", *ext);
+
+ fprintf(stdout, " Written by %s.\n %s\n\n",
+ (*i)->author, (*i)->url);
+ } /* for */
+ } /* else */
+
+ fprintf(stdout, "\n");
+} /* output_decoders */
+
+
+static void output_usage(const char *argv0)
+{
+ const char **i = option_list;
+
+ fprintf(stderr,
+ "USAGE: %s [...options...] [soundFile1] ... [soundFileN]\n"
+ "\n"
+ " Options:\n",
+ argv0);
+
+ while (*i != NULL)
+ {
+ const char *option = *(i++);
+ const char *optiondesc = *(i++);
+ fprintf(stderr, " %s %s\n", option, optiondesc);
+ } /* while */
+
+ fprintf(stderr,
+ "\n"
+ " Valid arguments to the --format option are:\n"
+ " U8 Unsigned 8-bit.\n"
+ " S8 Signed 8-bit.\n"
+ " U16LSB Unsigned 16-bit (least significant byte first).\n"
+ " U16MSB Unsigned 16-bit (most significant byte first).\n"
+ " S16LSB Signed 16-bit (least significant byte first).\n"
+ " S16MSB Signed 16-bit (most significant byte first).\n"
+ "\n"
+ " Valid arguments to the --seek options look like:\n"
+ " --seek \"mm:SS:ss;mm:SS:ss;mm:SS:ss\"\n"
+ " Where the first \"mm:SS:ss\" is the position, in minutes,\n"
+ " seconds and milliseconds to seek to at start of playback. The\n"
+ " next mm:SS:ss is how long to play audio from that point.\n"
+ " The third mm:SS:ss is another seek after the duration of\n"
+ " playback has completed. If the final playback duration is\n"
+ " omitted, playback continues until the end of the file.\n"
+ " The \"mm\" and \"SS\" portions may be omitted. --loop\n"
+ " and --seek can coexist.\n"
+ "\n");
+} /* output_usage */
+
+
+static void output_credits(void)
+{
+ fprintf(stdout,
+ "playsound version %d.%d.%d\n"
+ "Copyright 2001 Ryan C. Gordon\n"
+ "playsound is free software, covered by the GNU Lesser General\n"
+ "Public License, and you are welcome to change it and/or\n"
+ "distribute copies of it under certain conditions. There is\n"
+ "absolutely NO WARRANTY for playsound.\n"
+ "\n"
+ " Written by Ryan C. Gordon, Torbjörn Andersson, Max Horn,\n"
+ " Tsuyoshi Iguchi, Tyler Montbriand, Darrell Walisser,\n"
+ " and a cast of thousands.\n"
+ "\n"
+ " Website and source code: http://icculus.org/SDL_sound/\n"
+ "\n",
+ PLAYSOUND_VER_MAJOR, PLAYSOUND_VER_MINOR, PLAYSOUND_VER_PATCH);
+} /* output_credits */
+
+
+
+/* archive stuff... */
+
+static int init_archive(const char *argv0)
+{
+ int retval = 1;
+
+#if SUPPORT_PHYSFS
+ retval = PHYSFS_init(argv0);
+ if (!retval)
+ {
+ fprintf(stderr, "Couldn't init PhysicsFS: %s\n",
+ PHYSFS_getLastError());
+ } /* if */
+#endif
+
+ return(retval);
+} /* init_archive */
+
+
+#if SUPPORT_PHYSFS
+static SDL_RWops *rwops_from_physfs(const char *filename)
+{
+ SDL_RWops *retval = NULL;
+
+ char *path = (char *) malloc(strlen(filename) + 1);
+ char *archive;
+
+ if (path == NULL)
+ {
+ fprintf(stderr, "Out of memory!\n");
+ return(NULL);
+ } /* if */
+
+ strcpy(path, filename);
+ archive = strchr(path, '@');
+ if (archive != NULL)
+ {
+ *(archive++) = '\0'; /* blank '@', point to archive name. */
+ if (!PHYSFS_addToSearchPath(archive, 0))
+ {
+ fprintf(stderr, "Couldn't open archive: %s\n",
+ PHYSFS_getLastError());
+ free(path);
+ return(NULL);
+ } /* if */
+
+ retval = PHYSFSRWOPS_openRead(path);
+ } /* if */
+
+ free(path);
+ return(retval);
+} /* rwops_from_physfs */
+#endif
+
+
+static Sound_Sample *sample_from_archive(const char *fname,
+ Sound_AudioInfo *desired,
+ Uint32 decode_buffersize)
+{
+ Sound_Sample *retval = NULL;
+
+#if SUPPORT_PHYSFS
+ SDL_RWops *rw = rwops_from_physfs(fname);
+ if (rw != NULL)
+ {
+ char *path = (char *) malloc(strlen(fname) + 1);
+ char *ptr;
+ strcpy(path, fname);
+ ptr = strchr(path, '@');
+ *ptr = '\0';
+ ptr = strrchr(path, '.');
+ if (ptr != NULL)
+ ptr++;
+
+ retval = Sound_NewSample(rw, ptr, desired, decode_buffersize);
+ free(path);
+ } /* if */
+#endif
+
+ return(retval);
+} /* sample_from_archive */
+
+
+static void close_archive(const char *filename)
+{
+#if SUPPORT_PHYSFS
+ char *archive_name = strchr(filename, '@');
+ if (archive_name != NULL)
+ PHYSFS_removeFromSearchPath(archive_name + 1);
+#endif
+} /* close_archive */
+
+
+static void deinit_archive(void)
+{
+#if SUPPORT_PHYSFS
+ PHYSFS_deinit();
+#endif
+} /* deinit_archive */
+
+
+
+static volatile int done_flag = 0;
+
+#if HAVE_SIGNAL_H
+void sigint_catcher(int signum)
+{
+ static Uint32 last_sigint = 0;
+ Uint32 ticks = SDL_GetTicks();
+
+ assert(signum == SIGINT);
+
+ if ((last_sigint != 0) && (ticks - last_sigint < 500))
+ {
+ SDL_PauseAudio(1);
+ SDL_CloseAudio();
+ Sound_Quit();
+ SDL_Quit();
+ deinit_archive();
+ exit(1);
+ } /* if */
+
+ else
+ {
+ last_sigint = ticks;
+ done_flag = 1;
+ } /* else */
+} /* sigint_catcher */
+#endif
+
+
+/* global decoding state. */
+typedef struct
+{
+ Uint8 *decoded_ptr;
+ Uint32 decoded_bytes;
+ int predecode;
+ int looping;
+ int wants_volume_change;
+ float volume;
+ Uint32 total_seeks;
+ Uint32 *seek_list;
+ Uint32 seek_index;
+ Sint32 bytes_before_next_seek;
+} playsound_global_state;
+
+static volatile playsound_global_state global_state;
+
+
+static Uint32 cvtMsToBytePos(Sound_AudioInfo *info, Uint32 ms)
+{
+ /* "frames" == "sample frames" */
+ float frames_per_ms = ((float) info->rate) / 1000.0;
+ Uint32 frame_offset = (Uint32) (frames_per_ms * ((float) ms));
+ Uint32 frame_size = (Uint32) ((info->format & 0xFF) / 8) * info->channels;
+ return(frame_offset * frame_size);
+} /* cvtMsToBytePos */
+
+
+static void do_seek(Sound_Sample *sample)
+{
+ Uint32 *seek_list = global_state.seek_list;
+ Uint32 seek_index = global_state.seek_index;
+ Uint32 total_seeks = global_state.total_seeks;
+
+ fprintf(stdout, "Seeking to %.2d:%.2d:%.4d...\n",
+ (int) ((seek_list[seek_index] / 1000) / 60),
+ (int) ((seek_list[seek_index] / 1000) % 60),
+ (int) ((seek_list[seek_index] % 1000)));
+
+ if (global_state.predecode)
+ {
+ Uint32 pos = cvtMsToBytePos(&sample->desired, seek_list[seek_index]);
+ if (pos > sample->buffer_size)
+ {
+ fprintf(stderr, "Seek past end of predecoded buffer.\n");
+ done_flag = 1;
+ } /* if */
+ else
+ {
+ global_state.decoded_ptr = (((Uint8 *) sample->buffer) + pos);
+ global_state.decoded_bytes = sample->buffer_size - pos;
+ } /* else */
+ } /* if */
+ else
+ {
+ if (!Sound_Seek(sample, seek_list[seek_index]))
+ {
+ fprintf(stderr, "Sound_Seek() failed: %s\n", Sound_GetError());
+ done_flag = 1;
+ } /* if */
+ } /* else */
+
+ seek_index++;
+ if (seek_index >= total_seeks)
+ global_state.bytes_before_next_seek = -1; /* no more seeks. */
+ else
+ {
+ global_state.bytes_before_next_seek = cvtMsToBytePos(&sample->desired,
+ seek_list[seek_index]);
+ seek_index++;
+ } /* else */
+
+ global_state.seek_index = seek_index;
+} /* do_seek */
+
+
+/*
+ * This updates (decoded_bytes) and (decoded_ptr) with more audio data,
+ * taking into account potential looping, seeking and predecoding.
+ */
+static int read_more_data(Sound_Sample *sample)
+{
+ if (done_flag) /* probably a sigint; stop trying to read. */
+ {
+ global_state.decoded_bytes = 0;
+ return(0);
+ } /* if */
+
+ if ((global_state.bytes_before_next_seek >= 0) &&
+ (global_state.decoded_bytes > global_state.bytes_before_next_seek))
+ {
+ global_state.decoded_bytes = global_state.bytes_before_next_seek;
+ } /* if */
+
+ if (global_state.decoded_bytes > 0) /* don't need more data; just return. */
+ return(global_state.decoded_bytes);
+
+ /* Need more audio data. See if we're supposed to seek... */
+ if ((global_state.bytes_before_next_seek == 0) &&
+ (global_state.seek_index < global_state.total_seeks))
+ {
+ do_seek(sample); /* do it, baby! */
+ return(read_more_data(sample)); /* handle loops conditions. */
+ } /* if */
+
+ /* See if there's more to be read... */
+ if ( (global_state.bytes_before_next_seek != 0) &&
+ (!(sample->flags & (SOUND_SAMPLEFLAG_ERROR | SOUND_SAMPLEFLAG_EOF))) )
+ {
+ global_state.decoded_bytes = Sound_Decode(sample);
+ if (sample->flags & SOUND_SAMPLEFLAG_ERROR)
+ {
+ fprintf(stderr, "Error in decoding sound file!\n"
+ " reason: [%s].\n", Sound_GetError());
+ } /* if */
+
+ global_state.decoded_ptr = sample->buffer;
+ return(read_more_data(sample)); /* handle loops conditions. */
+ } /* if */
+
+ /* No more to be read from stream, but we may want to loop the sample. */
+
+ if (!global_state.looping)
+ return(0);
+
+ global_state.looping--;
+
+ global_state.seek_index = 0;
+ global_state.bytes_before_next_seek =
+ (global_state.total_seeks > 0) ? 0 : -1;
+
+ /* we just need to point predecoded samples to the start of the buffer. */
+ if (global_state.predecode)
+ {
+ global_state.decoded_bytes = sample->buffer_size;
+ global_state.decoded_ptr = sample->buffer;
+ } /* if */
+ else
+ {
+ Sound_Rewind(sample); /* error is checked in recursion. */
+ } /* else */
+
+ return(read_more_data(sample));
+} /* read_more_data */
+
+
+static void memcpy_with_volume(Sound_Sample *sample,
+ Uint8 *dst, Uint8 *src, int len)
+{
+ int i;
+ Uint16 *u16src = NULL;
+ Uint16 *u16dst = NULL;
+ Sint16 *s16src = NULL;
+ Sint16 *s16dst = NULL;
+ float volume = global_state.volume;
+
+ if (!global_state.wants_volume_change)
+ {
+ memcpy(dst, src, len);
+ return;
+ } /* if */
+
+ /* !!! FIXME: This would be more efficient with a lookup table. */
+ switch (sample->desired.format)
+ {
+ case AUDIO_U8:
+ for (i = 0; i < len; i++, src++, dst++)
+ *dst = (Uint8) (((float) (*src)) * volume);
+ break;
+
+ case AUDIO_S8:
+ for (i = 0; i < len; i++, src++, dst++)
+ *dst = (Sint8) (((float) (*src)) * volume);
+ break;
+
+ case AUDIO_U16LSB:
+ u16src = (Uint16 *) src;
+ u16dst = (Uint16 *) dst;
+ for (i = 0; i < len; i += sizeof (Uint16), u16src++, u16dst++)
+ {
+ *u16dst = (Uint16) (((float) (SDL_SwapLE16(*u16src))) * volume);
+ *u16dst = SDL_SwapLE16(*u16dst);
+ } /* for */
+ break;
+
+ case AUDIO_S16LSB:
+ s16src = (Sint16 *) src;
+ s16dst = (Sint16 *) dst;
+ for (i = 0; i < len; i += sizeof (Sint16), s16src++, s16dst++)
+ {
+ *s16dst = (Sint16) (((float) (SDL_SwapLE16(*s16src))) * volume);
+ *s16dst = SDL_SwapLE16(*s16dst);
+ } /* for */
+ break;
+
+ case AUDIO_U16MSB:
+ u16src = (Uint16 *) src;
+ u16dst = (Uint16 *) dst;
+ for (i = 0; i < len; i += sizeof (Uint16), u16src++, u16dst++)
+ {
+ *u16dst = (Uint16) (((float) (SDL_SwapBE16(*u16src))) * volume);
+ *u16dst = SDL_SwapBE16(*u16dst);
+ } /* for */
+ break;
+
+ case AUDIO_S16MSB:
+ s16src = (Sint16 *) src;
+ s16dst = (Sint16 *) dst;
+ for (i = 0; i < len; i += sizeof (Sint16), s16src++, s16dst++)
+ {
+ *s16dst = (Sint16) (((float) (SDL_SwapBE16(*s16src))) * volume);
+ *s16dst = SDL_SwapBE16(*s16dst);
+ } /* for */
+ break;
+ } /* switch */
+} /* memcpy_with_volume */
+
+
+static void audio_callback(void *userdata, Uint8 *stream, int len)
+{
+ Sound_Sample *sample = (Sound_Sample *) userdata;
+ int bw = 0; /* bytes written to stream this time through the callback */
+
+ while (bw < len)
+ {
+ int cpysize; /* bytes to copy on this iteration of the loop. */
+
+ if (!read_more_data(sample)) /* read more data, if needed. */
+ {
+ /* ...there isn't any more data to read! */
+ memset(stream + bw, '\0', len - bw);
+ done_flag = 1;
+ return;
+ } /* if */
+
+ /* decoded_bytes and decoder_ptr are updated as necessary... */
+
+ cpysize = len - bw;
+ if (cpysize > global_state.decoded_bytes)
+ cpysize = global_state.decoded_bytes;
+
+ if (cpysize > 0)
+ {
+ memcpy_with_volume(sample, stream + bw,
+ (Uint8 *) global_state.decoded_ptr,
+ cpysize);
+
+ bw += cpysize;
+ global_state.decoded_ptr += cpysize;
+ global_state.decoded_bytes -= cpysize;
+ if (global_state.bytes_before_next_seek >= 0)
+ global_state.bytes_before_next_seek -= cpysize;
+ } /* if */
+ } /* while */
+} /* audio_callback */
+
+
+static int count_seek_list(const char *list)
+{
+ const char *ptr;
+ int retval = 0;
+
+ for (ptr = list; ptr != NULL; ptr = strchr(ptr + 1, ';'))
+ retval++;
+
+ return(retval);
+} /* count_seek_list */
+
+
+static Uint32 parse_time_str(char *str)
+{
+ Uint32 minutes = 0;
+ Uint32 seconds = 0;
+ Uint32 ms = 0;
+
+ char *ptr = strchr(str, ':');
+ if (ptr != NULL)
+ {
+ char *ptr2;
+
+ *ptr = '\0';
+ ptr2 = strchr(ptr + 1, ':');
+ if (ptr2 != NULL)
+ {
+ *ptr2 = '\0';
+ minutes = atoi(str);
+ str = ptr + 1;
+ ptr = ptr2;
+ } /* if */
+
+ seconds = atoi(str);
+ str = ptr + 1;
+ } /* if */
+
+ ms = atoi(str);
+ return( (((minutes * 60) + seconds) * 1000) + ms );
+} /* parse_time_str */
+
+
+static void parse_seek_list(const char *_list)
+{
+ Uint32 i;
+
+ char *list = (char*) malloc(strlen(_list) + 1);
+ char *save_list = list;
+ if (list == NULL)
+ {
+ fprintf(stderr, "malloc() failed. Skipping seek list.\n");
+ return;
+ } /* if */
+
+ strcpy(list, _list);
+
+ if (global_state.seek_list != NULL)
+ free((void *) global_state.seek_list);
+
+ global_state.total_seeks = count_seek_list(list);
+
+ global_state.seek_list =
+ (Uint32 *) malloc(global_state.total_seeks * sizeof (Uint32));
+
+ if (global_state.seek_list == NULL)
+ {
+ fprintf(stderr, "malloc() failed. Skipping seek list.\n");
+ global_state.total_seeks = 0;
+ return;
+ } /* if */
+
+ for (i = 0; i < global_state.total_seeks; i++)
+ {
+ char *ptr = strchr(list, ';');
+ if (ptr != NULL)
+ *ptr = '\0';
+ global_state.seek_list[i] = parse_time_str(list);
+ list = ptr + 1;
+ } /* for */
+
+ global_state.bytes_before_next_seek = 0;
+
+ free(save_list);
+} /* parse_seek_list */
+
+
+static int str_to_fmt(char *str)
+{
+ if (strcmp(str, "U8") == 0)
+ return AUDIO_U8;
+ if (strcmp(str, "S8") == 0)
+ return AUDIO_S8;
+ if (strcmp(str, "U16LSB") == 0)
+ return AUDIO_U16LSB;
+ if (strcmp(str, "S16LSB") == 0)
+ return AUDIO_S16LSB;
+ if (strcmp(str, "U16MSB") == 0)
+ return AUDIO_U16MSB;
+ if (strcmp(str, "S16MSB") == 0)
+ return AUDIO_S16MSB;
+ return 0;
+} /* str_to_fmt */
+
+
+static int valid_cmdline(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 2) /* no command line? Show help text and quit. */
+ {
+ output_usage(argv[0]);
+ return(0);
+ } /* if */
+
+ /* Make sure all command line options are valid. */
+ for (i = 1; i < argc; i++)
+ {
+ const char **opts = option_list;
+
+ if (strncmp(argv[i], "--", 2) != 0) /* not an option; skip it. */
+ continue;
+
+ while (*opts != NULL)
+ {
+ if (strcmp(argv[i], *(opts++)) == 0)
+ break;
+
+ opts++; /* skip option description. */
+ } /* else */
+
+ if (*opts == NULL) /* didn't find it in option_list... */
+ {
+ fprintf(stderr, "unknown option: \"%s\"\n", argv[i]);
+ return(0);
+ } /* if */
+ } /* for */
+
+ return(1); /* everything appears to be in order. */
+} /* valid_cmdline */
+
+
+int main(int argc, char **argv)
+{
+ Sound_AudioInfo sound_desired;
+ SDL_AudioSpec sdl_desired;
+ Uint32 audio_buffersize;
+ Uint32 decode_buffersize;
+ Sound_Sample *sample;
+ int use_specific_audiofmt = 0;
+ int i;
+ int delay;
+ int new_sample = 1;
+ Uint32 sdl_init_flags = SDL_INIT_AUDIO;
+
+ #if ENABLE_EVENTS
+ SDL_Surface *screen = NULL;
+ SDL_Event event;
+
+ sdl_init_flags |= SDL_INIT_VIDEO;
+ #endif
+
+ #ifdef HAVE_SETBUF
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ #endif
+
+ if (!valid_cmdline(argc, argv))
+ return(42);
+
+ /* Handle some command lines upfront. */
+ for (i = 0; i < argc; i++)
+ {
+ if (strncmp(argv[i], "--", 2) != 0)
+ continue;
+
+ if (strcmp(argv[i], "--version") == 0)
+ {
+ output_versions(argv[0]);
+ return(42);
+ } /* if */
+
+ if (strcmp(argv[i], "--credits") == 0)
+ {
+ output_credits();
+ return(42);
+ } /* if */
+
+ else if (strcmp(argv[i], "--help") == 0)
+ {
+ output_usage(argv[0]);
+ return(42);
+ } /* if */
+
+ else if (strcmp(argv[i], "--decoders") == 0)
+ {
+ if (!Sound_Init())
+ {
+ fprintf(stderr, "Sound_Init() failed!\n"
+ " reason: [%s].\n", Sound_GetError());
+ SDL_Quit();
+ return(42);
+ } /* if */
+
+ output_decoders();
+ Sound_Quit();
+ return(0);
+ } /* else if */
+ } /* for */
+
+ if (!init_archive(argv[0]))
+ return(42);
+
+ if (SDL_Init(sdl_init_flags) == -1)
+ {
+ fprintf(stderr, "SDL_Init() failed!\n"
+ " reason: [%s].\n", SDL_GetError());
+ return(42);
+ } /* if */
+
+ if (!Sound_Init())
+ {
+ fprintf(stderr, "Sound_Init() failed!\n"
+ " reason: [%s].\n", Sound_GetError());
+ SDL_Quit();
+ return(42);
+ } /* if */
+
+ #if HAVE_SIGNAL_H
+ signal(SIGINT, sigint_catcher);
+ #endif
+
+ #if ENABLE_EVENTS
+ screen = SDL_SetVideoMode(320, 240, 8, 0);
+ assert(screen != NULL);
+ #endif
+
+ for (i = 1; i < argc; i++)
+ {
+ char *filename = NULL;
+
+ /* set variables back to defaults for next file... */
+ if (new_sample)
+ {
+ if (global_state.seek_list != NULL)
+ free((void *) global_state.seek_list);
+
+ memset((void *) &global_state, '\0', sizeof (global_state));
+ memset(&sdl_desired, '\0', sizeof (SDL_AudioSpec));
+ global_state.volume = 1.0;
+ global_state.bytes_before_next_seek = -1;
+ audio_buffersize = DEFAULT_AUDIOBUF;
+ decode_buffersize = DEFAULT_DECODEBUF;
+ new_sample = 0;
+ } /* if */
+
+ if (strcmp(argv[i], "--rate") == 0 && argc > i + 1)
+ {
+ use_specific_audiofmt = 1;
+ sound_desired.rate = atoi(argv[++i]);
+ if (sound_desired.rate <= 0)
+ {
+ fprintf(stderr, "Bad argument to --rate!\n");
+ return(42);
+ } /* if */
+ } /* else if */
+
+ else if (strcmp(argv[i], "--format") == 0 && argc > i + 1)
+ {
+ use_specific_audiofmt = 1;
+ sound_desired.format = str_to_fmt(argv[++i]);
+ if (sound_desired.format == 0)
+ {
+ fprintf(stderr, "Bad argument to --format! Try one of:\n"
+ "U8, S8, U16LSB, S16LSB, U16MSB, S16MSB\n");
+ return(42);
+ } /* if */
+ } /* else if */
+
+ else if (strcmp(argv[i], "--channels") == 0 && argc > i + 1)
+ {
+ use_specific_audiofmt = 1;
+ sound_desired.channels = atoi(argv[++i]);
+ if (sound_desired.channels < 1 || sound_desired.channels > 2)
+ {
+ fprintf(stderr,
+ "Bad argument to --channels! Try 1 (mono) or 2 "
+ "(stereo).\n");
+ return(42);
+ } /* if */
+ } /* else if */
+
+ else if (strcmp(argv[i], "--audiobuf") == 0 && argc > i + 1)
+ {
+ audio_buffersize = atoi(argv[++i]);
+ } /* else if */
+
+ else if (strcmp(argv[i], "--decodebuf") == 0 && argc > i + 1)
+ {
+ decode_buffersize = atoi(argv[++i]);
+ } /* else if */
+
+ else if (strcmp(argv[i], "--volume") == 0 && argc > i + 1)
+ {
+ global_state.volume = atof(argv[++i]);
+ if (global_state.volume != 1.0)
+ global_state.wants_volume_change = 1;
+ } /* else if */
+
+ else if (strcmp(argv[i], "--predecode") == 0)
+ {
+ global_state.predecode = 1;
+ } /* else if */
+
+ else if (strcmp(argv[i], "--loop") == 0)
+ {
+ global_state.looping = atoi(argv[++i]);
+ } /* else if */
+
+ else if (strcmp(argv[i], "--seek") == 0)
+ {
+ parse_seek_list(argv[++i]);
+ } /* else if */
+
+ else if (strcmp(argv[i], "--stdin") == 0)
+ {
+ SDL_RWops *rw = SDL_RWFromFP(stdin, 1);
+ filename = "...from stdin...";
+
+ /*
+ * The second argument will be NULL if --stdin is the last
+ * thing on the command line. This is correct behaviour.
+ */
+ sample = Sound_NewSample(rw, argv[++i],
+ use_specific_audiofmt ? &sound_desired : NULL,
+ decode_buffersize);
+ } /* if */
+
+ else if (strncmp(argv[i], "--", 2) == 0)
+ {
+ /* ignore it, since it was handled at startup. */
+ } /* else if */
+
+ else
+ {
+ filename = argv[i];
+ sample = sample_from_archive(filename,
+ use_specific_audiofmt ? &sound_desired : NULL,
+ decode_buffersize);
+
+ if (sample == NULL)
+ {
+ sample = Sound_NewSampleFromFile(filename,
+ use_specific_audiofmt ? &sound_desired : NULL,
+ decode_buffersize);
+ } /* if */
+ } /* else */
+
+ if (filename == NULL) /* still parsing command line stuff? */
+ continue;
+
+ new_sample = 1;
+
+ if (sample == NULL)
+ {
+ fprintf(stderr, "Couldn't load \"%s\"!\n"
+ " reason: [%s].\n",
+ filename, Sound_GetError());
+ continue;
+ } /* if */
+
+ if (global_state.total_seeks > 0)
+ {
+ if ((!global_state.predecode) &&
+ (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK)))
+ {
+ fprintf(stderr, "Want seeks, but sample cannot handle it!\n");
+ Sound_FreeSample(sample);
+ close_archive(filename);
+ continue;
+ } /* if */
+ } /* if */
+
+ /*
+ * Unless explicitly specified, pick the format from the sound
+ * to be played.
+ */
+ if (use_specific_audiofmt)
+ {
+ sdl_desired.freq = sample->desired.rate;
+ sdl_desired.format = sample->desired.format;
+ sdl_desired.channels = sample->desired.channels;
+ } /* if */
+ else
+ {
+ sdl_desired.freq = sample->actual.rate;
+ sdl_desired.format = sample->actual.format;
+ sdl_desired.channels = sample->actual.channels;
+ } /* else */
+
+ sdl_desired.samples = audio_buffersize;
+ sdl_desired.callback = audio_callback;
+ sdl_desired.userdata = sample;
+
+ if (SDL_OpenAudio(&sdl_desired, NULL) < 0)
+ {
+ fprintf(stderr, "Couldn't open audio device!\n"
+ " reason: [%s].\n", SDL_GetError());
+ Sound_Quit();
+ SDL_Quit();
+ return(42);
+ } /* if */
+
+ fprintf(stdout, "Now playing [%s]...\n", filename);
+
+ if (global_state.predecode)
+ {
+ fprintf(stdout, " predecoding...");
+ global_state.decoded_bytes = Sound_DecodeAll(sample);
+ global_state.decoded_ptr = sample->buffer;
+ if (sample->flags & SOUND_SAMPLEFLAG_ERROR)
+ {
+ fprintf(stderr,
+ "Couldn't fully decode \"%s\"!\n"
+ " reason: [%s].\n"
+ " (playing first %lu bytes of decoded data...)\n",
+ filename, Sound_GetError(), global_state.decoded_bytes);
+ } /* if */
+ else
+ {
+ fprintf(stdout, "done.\n");
+ } /* else */
+ } /* if */
+
+ SDL_PauseAudio(0);
+
+ done_flag = 0; /* the audio callback will flip this flag. */
+ while (!done_flag)
+ {
+ #if ENABLE_EVENTS
+ SDL_PollEvent(&event);
+ if ((event.type == SDL_KEYDOWN) || (event.type == SDL_QUIT))
+ done_flag = 1;
+ #endif
+
+ SDL_Delay(10);
+ } /* while */
+
+ SDL_PauseAudio(1);
+
+ /*
+ * Sleep two buffers' worth of audio before closing, in order
+ * to allow the playback to finish. This isn't always enough;
+ * perhaps SDL needs a way to explicitly wait for device drain?
+ */
+ delay = 2 * 1000 * sdl_desired.samples / sdl_desired.freq;
+ SDL_Delay(delay);
+
+ SDL_CloseAudio(); /* reopen with next sample's format if possible */
+ Sound_FreeSample(sample);
+
+ close_archive(filename);
+ } /* for */
+
+ Sound_Quit();
+ SDL_Quit();
+ deinit_archive();
+ return(0);
+} /* main */
+
+/* end of playsound.c ... */
+
diff --git a/util/sdl/sound/playsound/playsound_simple.c b/util/sdl/sound/playsound/playsound_simple.c
new file mode 100644
index 00000000..16ce506b
--- /dev/null
+++ b/util/sdl/sound/playsound/playsound_simple.c
@@ -0,0 +1,197 @@
+/*
+ * 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 just a simple "decode sound, play it through SDL" example.
+ * The much more complex, fancy, and robust code is playsound.c.
+ *
+ * Please see the file COPYING in the source's root directory.
+ *
+ * This file written by Ryan C. Gordon. (icculus@icculus.org)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL.h"
+#include "SDL_sound.h"
+
+/* global decoding state. */
+typedef struct
+{
+ Sound_Sample *sample;
+ SDL_AudioSpec devformat;
+ Uint8 *decoded_ptr;
+ Uint32 decoded_bytes;
+} PlaysoundAudioCallbackData;
+
+/*
+ * This variable is flipped to non-zero when the audio callback has
+ * finished playing the whole file.
+ */
+static volatile int global_done_flag = 0;
+
+
+/*
+ * The audio callback. SDL calls this frequently to feed the audio device.
+ * We decode the audio file being played in here in small chunks and feed
+ * the device as necessary. Other solutions may want to predecode more
+ * (or all) of the file, since this needs to run fast and frequently,
+ * but since we're only sitting here and waiting for the file to play,
+ * the only real requirement is that we can decode a given audio file
+ * faster than realtime, which isn't really a problem with any modern format
+ * on even pretty old hardware at this point.
+ */
+static void audio_callback(void *userdata, Uint8 *stream, int len)
+{
+ PlaysoundAudioCallbackData *data = (PlaysoundAudioCallbackData *) userdata;
+ Sound_Sample *sample = data->sample;
+ int bw = 0; /* bytes written to stream this time through the callback */
+
+ while (bw < len)
+ {
+ int cpysize; /* bytes to copy on this iteration of the loop. */
+
+ if (data->decoded_bytes == 0) /* need more data! */
+ {
+ /* if there wasn't previously an error or EOF, read more. */
+ if ( ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) &&
+ ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) )
+ {
+ data->decoded_bytes = Sound_Decode(sample);
+ data->decoded_ptr = sample->buffer;
+ } /* if */
+
+ if (data->decoded_bytes == 0)
+ {
+ /* ...there isn't any more data to read! */
+ memset(stream + bw, '\0', len - bw); /* write silence. */
+ global_done_flag = 1;
+ return; /* we're done playback, one way or another. */
+ } /* if */
+ } /* if */
+
+ /* we have data decoded and ready to write to the device... */
+ cpysize = len - bw; /* len - bw == amount device still wants. */
+ if (cpysize > data->decoded_bytes)
+ cpysize = data->decoded_bytes; /* clamp to what we have left. */
+
+ /* if it's 0, next iteration will decode more or decide we're done. */
+ if (cpysize > 0)
+ {
+ /* write this iteration's data to the device. */
+ memcpy(stream + bw, (Uint8 *) data->decoded_ptr, cpysize);
+
+ /* update state for next iteration or callback */
+ bw += cpysize;
+ data->decoded_ptr += cpysize;
+ data->decoded_bytes -= cpysize;
+ } /* if */
+ } /* while */
+} /* audio_callback */
+
+
+
+static void playOneSoundFile(const char *fname)
+{
+ PlaysoundAudioCallbackData data;
+
+ memset(&data, '\0', sizeof (PlaysoundAudioCallbackData));
+ data.sample = Sound_NewSampleFromFile(fname, NULL, 65536);
+ if (data.sample == NULL)
+ {
+ fprintf(stderr, "Couldn't load '%s': %s.\n", fname, Sound_GetError());
+ return;
+ } /* if */
+
+ /*
+ * Open device in format of the the sound to be played.
+ * We open and close the device for each sound file, so that SDL
+ * handles the data conversion to hardware format; this is the
+ * easy way out, but isn't practical for most apps. Usually you'll
+ * want to pick one format for all the data or one format for the
+ * audio device and convert the data when needed. This is a more
+ * complex issue than I can describe in a source code comment, though.
+ */
+ data.devformat.freq = data.sample->actual.rate;
+ data.devformat.format = data.sample->actual.format;
+ data.devformat.channels = data.sample->actual.channels;
+ data.devformat.samples = 4096; /* I just picked a largish number here. */
+ data.devformat.callback = audio_callback;
+ data.devformat.userdata = &data;
+ if (SDL_OpenAudio(&data.devformat, NULL) < 0)
+ {
+ fprintf(stderr, "Couldn't open audio device: %s.\n", SDL_GetError());
+ Sound_FreeSample(data.sample);
+ return;
+ } /* if */
+
+ printf("Now playing [%s]...\n", fname);
+ SDL_PauseAudio(0); /* SDL audio device is "paused" right after opening. */
+
+ global_done_flag = 0; /* the audio callback will flip this flag. */
+ while (!global_done_flag)
+ SDL_Delay(10); /* just wait for the audio callback to finish. */
+
+ /* at this point, we've played the entire audio file. */
+ SDL_PauseAudio(1); /* so stop the device. */
+
+ /*
+ * Sleep two buffers' worth of audio before closing, in order
+ * to allow the playback to finish. This isn't always enough;
+ * perhaps SDL needs a way to explicitly wait for device drain?
+ * Most apps don't have this issue, since they aren't explicitly
+ * closing the device as soon as a sound file is done playback.
+ * As an alternative for this app, you could also change the callback
+ * to write silence for a call or two before flipping global_done_flag.
+ */
+ SDL_Delay(2 * 1000 * data.devformat.samples / data.devformat.freq);
+
+ /* if there was an error, tell the user. */
+ if (data.sample->flags & SOUND_SAMPLEFLAG_ERROR)
+ fprintf(stderr, "Error decoding file: %s\n", Sound_GetError());
+
+ Sound_FreeSample(data.sample); /* clean up SDL_Sound resources... */
+ SDL_CloseAudio(); /* will reopen with next file's format. */
+} /* playOneSoundFile */
+
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (!Sound_Init()) /* this calls SDL_Init(SDL_INIT_AUDIO) ... */
+ {
+ fprintf(stderr, "Sound_Init() failed: %s.\n", Sound_GetError());
+ SDL_Quit();
+ return(42);
+ } /* if */
+
+ for (i = 1; i < argc; i++) /* each arg is an audio file to play. */
+ playOneSoundFile(argv[i]);
+
+ /* Shutdown the libraries... */
+ Sound_Quit();
+ SDL_Quit();
+ return(0);
+} /* main */
+
+/* end of playsound-simple.c ... */
+

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 12:51 PM (3 w, 4 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
29/51/f7a6437c72393162543fe7d04c80
Default Alt Text
(1019 KB)

Event Timeline