diff --git a/project/jni/sdl_sound/Android.mk b/project/jni/sdl_sound/Android.mk new file mode 100644 index 000000000..e6ee8a6dc --- /dev/null +++ b/project/jni/sdl_sound/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := sdl_sound + +LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/../sdl-$(SDL_VERSION)/include $(LOCAL_PATH)/include $(LOCAL_PATH)/decoders $(LOCAL_PATH)/decoders/mpglib \ + $(LOCAL_PATH)/../flac/include $(LOCAL_PATH)/../ogg/include \ + $(LOCAL_PATH)/../vorbis/include $(LOCAL_PATH)/../tremor/include $(LOCAL_PATH)/../mikmod/include \ + $(LOCAL_PATH)/timidity +LOCAL_CFLAGS := -O3 -DHAVE_CONFIG_H -DLAYER1 -DLAYER2 -DLAYER3 + +LOCAL_CPP_EXTENSION := .cpp + +LOCAL_SRC_FILES := $(notdir $(wildcard $(LOCAL_PATH)/*.c)) \ + $(addprefix decoders/, $(notdir $(wildcard $(LOCAL_PATH)/decoders/*.c))) \ + $(addprefix decoders/mpglib/, $(notdir $(wildcard $(LOCAL_PATH)/decoders/mpglib/*.c))) + +LOCAL_SHARED_LIBRARIES := sdl-$(SDL_VERSION) +LOCAL_STATIC_LIBRARIES := flac mikmod vorbis ogg + +LOCAL_LDLIBS := + +include $(BUILD_SHARED_LIBRARY) + diff --git a/project/jni/sdl_sound/CHANGELOG b/project/jni/sdl_sound/CHANGELOG new file mode 100644 index 000000000..1db243b8d --- /dev/null +++ b/project/jni/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 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 (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/project/jni/sdl_sound/COPYING b/project/jni/sdl_sound/COPYING new file mode 100644 index 000000000..6228aac29 --- /dev/null +++ b/project/jni/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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/project/jni/sdl_sound/CREDITS b/project/jni/sdl_sound/CREDITS new file mode 100644 index 000000000..bb9af496c --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/INSTALL b/project/jni/sdl_sound/INSTALL new file mode 100644 index 000000000..8ac35599d --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/README b/project/jni/sdl_sound/README new file mode 100644 index 000000000..54bbd5c15 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/SDL_sound.c b/project/jni/sdl_sound/SDL_sound.c new file mode 100644 index 000000000..8631c298a --- /dev/null +++ b/project/jni/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 +#endif + +#include +#include +#include +#include + +#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/project/jni/sdl_sound/SDL_sound_internal.h b/project/jni/sdl_sound/SDL_sound_internal.h new file mode 100644 index 000000000..d467fc8d9 --- /dev/null +++ b/project/jni/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 +#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/project/jni/sdl_sound/TODO b/project/jni/sdl_sound/TODO new file mode 100644 index 000000000..99a13c013 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/alt_audio_convert.c b/project/jni/sdl_sound/alt_audio_convert.c new file mode 100644 index 000000000..de9b8fd2f --- /dev/null +++ b/project/jni/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 +#endif + +#if SOUND_USE_ALTCVT + +#include "alt_audio_convert.h" +#include + +/* 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/project/jni/sdl_sound/alt_audio_convert.h b/project/jni/sdl_sound/alt_audio_convert.h new file mode 100644 index 000000000..8dd4670e8 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/audio_convert.c b/project/jni/sdl_sound/audio_convert.c new file mode 100644 index 000000000..05564dc48 --- /dev/null +++ b/project/jni/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 +#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/project/jni/sdl_sound/config.h b/project/jni/sdl_sound/config.h new file mode 100644 index 000000000..1d6152bcf --- /dev/null +++ b/project/jni/sdl_sound/config.h @@ -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 header file. */ +#define HAVE_ASSERT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the `setbuf' function. */ +#define HAVE_SETBUF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to disable debugging. */ +/* #define NDEBUG */ + +/* Name of package */ +#define PACKAGE "SDL_sound" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "SDL_sound" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "SDL_sound" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "SDL_sound 1.0.3" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "SDL_sound" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.0.3" + +/* Define if modplug header is in own directory. */ +#undef SOUND_MODPLUG_IN_OWN_PATH + +/* Define if AIFF support is desired. */ +#define SOUND_SUPPORTS_AIFF 1 + +/* Define if AU support is desired. */ +#define SOUND_SUPPORTS_AU 1 + +/* Define if FLAC support is desired. */ +#define SOUND_SUPPORTS_FLAC 1 + +/* Define if MIDI support is desired. */ +#undef SOUND_SUPPORTS_MIDI + +/* Define if MIKMOD support is desired. */ +#define SOUND_SUPPORTS_MIKMOD 1 + +/* Define if MODPLUG support is desired. */ +#undef SOUND_SUPPORTS_MODPLUG + +/* Define if MPGLIB support is desired. */ +#define SOUND_SUPPORTS_MPGLIB 1 + +/* Define if OGG support is desired. */ +#define SOUND_SUPPORTS_OGG 1 + +/* Define if RAW support is desired. */ +#undef SOUND_SUPPORTS_RAW + +/* Define if SHN support is desired. */ +#define SOUND_SUPPORTS_SHN 1 + +/* 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. */ +#define SOUND_SUPPORTS_VOC 1 + +/* Define if WAV support is desired. */ +#define SOUND_SUPPORTS_WAV 1 + +/* Define to use alternate audio converter. */ +#undef SOUND_USE_ALTCVT + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.0.3" + +/* Define to empty if `const' does not conform to ANSI C. */ +/*#undef const*/ + +/* Define to `unsigned int' if does not define. */ +/*#undef size_t*/ diff --git a/project/jni/sdl_sound/decoders/Makefile.am b/project/jni/sdl_sound/decoders/Makefile.am new file mode 100644 index 000000000..e6d4f9b4c --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/Makefile.in b/project/jni/sdl_sound/decoders/Makefile.in new file mode 100644 index 000000000..b18601126 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/aiff.c b/project/jni/sdl_sound/decoders/aiff.c new file mode 100644 index 000000000..52ee0b384 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_AIFF + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/au.c b/project/jni/sdl_sound/decoders/au.c new file mode 100644 index 000000000..ab0ff9f77 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_AU + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/flac.c b/project/jni/sdl_sound/decoders/flac.c new file mode 100644 index 000000000..54aebc0c6 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_FLAC + +#include +#include +#include + +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + +#include + +/* 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 + +#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 + +#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 ", + "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/project/jni/sdl_sound/decoders/midi.c b/project/jni/sdl_sound/decoders/midi.c new file mode 100644 index 000000000..b283c5c6f --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_MIDI + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/mikmod.c b/project/jni/sdl_sound/decoders/mikmod.c new file mode 100644 index 000000000..ebfed455b --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_MIKMOD + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/modplug.c b/project/jni/sdl_sound/decoders/modplug.c new file mode 100644 index 000000000..b2b3233d7 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_MODPLUG + +#include +#include +#include + +#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 ", + "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, ¤t_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(¤t_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/project/jni/sdl_sound/decoders/mpglib.c b/project/jni/sdl_sound/decoders/mpglib.c new file mode 100644 index 000000000..d7ee46862 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_MPGLIB + +#include +#include +#include +#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 ", + "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/project/jni/sdl_sound/decoders/mpglib/CHANGES b/project/jni/sdl_sound/decoders/mpglib/CHANGES new file mode 100644 index 000000000..b9a8c50c1 --- /dev/null +++ b/project/jni/sdl_sound/decoders/mpglib/CHANGES @@ -0,0 +1,4 @@ +14/Oct/1999: + - VBR fix + - Layer2 and Layer1 added + diff --git a/project/jni/sdl_sound/decoders/mpglib/README b/project/jni/sdl_sound/decoders/mpglib/README new file mode 100644 index 000000000..2465ffaa2 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/mpglib/README-sdlsound b/project/jni/sdl_sound/decoders/mpglib/README-sdlsound new file mode 100644 index 000000000..e24073b45 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/mpglib/TODO b/project/jni/sdl_sound/decoders/mpglib/TODO new file mode 100644 index 000000000..e69de29bb diff --git a/project/jni/sdl_sound/decoders/mpglib/dct64_i386.c b/project/jni/sdl_sound/decoders/mpglib/dct64_i386.c new file mode 100644 index 000000000..67c1fa5ef --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/mpglib/decode_i386.c b/project/jni/sdl_sound/decoders/mpglib/decode_i386.c new file mode 100644 index 000000000..0afd52598 --- /dev/null +++ b/project/jni/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 +#include +#include + +#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/project/jni/sdl_sound/decoders/mpglib/huffman.h b/project/jni/sdl_sound/decoders/mpglib/huffman.h new file mode 100644 index 000000000..7fec0d589 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/mpglib/interface.c b/project/jni/sdl_sound/decoders/mpglib/interface.c new file mode 100644 index 000000000..db9a3a5da --- /dev/null +++ b/project/jni/sdl_sound/decoders/mpglib/interface.c @@ -0,0 +1,243 @@ + +#include +#include + +#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/project/jni/sdl_sound/decoders/mpglib/l2tables.h b/project/jni/sdl_sound/decoders/mpglib/l2tables.h new file mode 100644 index 000000000..06d21353b --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/mpglib/layer1.c b/project/jni/sdl_sound/decoders/mpglib/layer1.c new file mode 100644 index 000000000..3df430a88 --- /dev/null +++ b/project/jni/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;istereo) { + int jsbound = fr->jsbound; + register real *f0 = fraction[0]; + register real *f1 = fraction[1]; + ba = balloc; + for (sample=smpb,i=0;istereo; + 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= 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/project/jni/sdl_sound/decoders/mpglib/layer2.c b/project/jni/sdl_sound/decoders/mpglib/layer2.c new file mode 100644 index 000000000..b5ef1e9b2 --- /dev/null +++ b/project/jni/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;jstereo-1; + int sblimit = fr->II_sblimit; + int jsbound = fr->jsbound; + int sblimit2 = fr->II_sblimit<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<bits); + *bita++ = (char) getbits(step); + } + for (i=sblimit-jsbound;i;i--,alloc1+=(1<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<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;ibits; + for (j=0;jbits; + 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;ibits; + 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;ilsf) + 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>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/project/jni/sdl_sound/decoders/mpglib/layer3.c b/project/jni/sdl_sound/decoders/mpglib/layer3.c new file mode 100644 index 000000000..87abb19e5 --- /dev/null +++ b/project/jni/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 +#include + +#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 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; chch[ch].gr[0].scfsi = -1; + si->ch[ch].gr[1].scfsi = getbits_fast(4); + } + + for (gr=0; gr<2; gr++) + { + for (ch=0; chch[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; chch[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;iscalefac_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 (; sbmaxb; 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 (; sbmaxb; 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(;sbstereo; + 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;grlsf) + 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;ilsf); + + 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;imaxb;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;imaxb;i++) + *in0++ = *in1++; + } + break; + } + } + + for(ch=0;ch= 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/project/jni/sdl_sound/decoders/mpglib/mpg123_sdlsound.h b/project/jni/sdl_sound/decoders/mpglib/mpg123_sdlsound.h new file mode 100644 index 000000000..d8fc9bd3b --- /dev/null +++ b/project/jni/sdl_sound/decoders/mpglib/mpg123_sdlsound.h @@ -0,0 +1,199 @@ +#include +#include + +#if !defined(WIN32) && !defined(macintosh) && !defined(_WIN32_WCE) +#include +#endif + +#include + +#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/project/jni/sdl_sound/decoders/mpglib/mpglib_common.c b/project/jni/sdl_sound/decoders/mpglib/mpglib_common.c new file mode 100644 index 000000000..cc14662d2 --- /dev/null +++ b/project/jni/sdl_sound/decoders/mpglib/mpglib_common.c @@ -0,0 +1,243 @@ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include + +#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/project/jni/sdl_sound/decoders/mpglib/mpglib_sdlsound.h b/project/jni/sdl_sound/decoders/mpglib/mpglib_sdlsound.h new file mode 100644 index 000000000..58c7041c4 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/mpglib/tabinit.c b/project/jni/sdl_sound/decoders/mpglib/tabinit.c new file mode 100644 index 000000000..dbd3965c8 --- /dev/null +++ b/project/jni/sdl_sound/decoders/mpglib/tabinit.c @@ -0,0 +1,80 @@ + +#include + +#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 +#endif + +#ifdef SOUND_SUPPORTS_OGG + +#include +#include +#include +#include + +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + +#include +#include + + +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 ", + "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/project/jni/sdl_sound/decoders/quicktime.c b/project/jni/sdl_sound/decoders/quicktime.c new file mode 100644 index 000000000..355ca6e7f --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_QUICKTIME +#ifdef macintosh +typedef long int32_t; +# define OPAQUE_UPP_TYPES 0 +# include +#else +# include +# include +#endif + +#include +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/raw.c b/project/jni/sdl_sound/decoders/raw.c new file mode 100644 index 000000000..be3c810fe --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_RAW + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/shn.c b/project/jni/sdl_sound/decoders/shn.c new file mode 100644 index 000000000..62a316ffb --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_SHN + +#include +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/smpeg.c b/project/jni/sdl_sound/decoders/smpeg.c new file mode 100644 index 000000000..f49589772 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_SMPEG + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/speex.c b/project/jni/sdl_sound/decoders/speex.c new file mode 100644 index 000000000..83a2bda33 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_SPEEX + +#include +#include +#include +#include + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/timidity/CHANGES b/project/jni/sdl_sound/decoders/timidity/CHANGES new file mode 100644 index 000000000..ab79e9931 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/timidity/COPYING b/project/jni/sdl_sound/decoders/timidity/COPYING new file mode 100644 index 000000000..44bb52fba --- /dev/null +++ b/project/jni/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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/project/jni/sdl_sound/decoders/timidity/FAQ b/project/jni/sdl_sound/decoders/timidity/FAQ new file mode 100644 index 000000000..1ee0b77bf --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/FAQ @@ -0,0 +1,100 @@ +---------------------------*-indented-text-*------------------------------ + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + +-------------------------------------------------------------------------- + + 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 ". 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/project/jni/sdl_sound/decoders/timidity/Makefile.am b/project/jni/sdl_sound/decoders/timidity/Makefile.am new file mode 100644 index 000000000..7c64b9331 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/timidity/Makefile.in b/project/jni/sdl_sound/decoders/timidity/Makefile.in new file mode 100644 index 000000000..03b1e4278 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/timidity/Makefile.testmidi b/project/jni/sdl_sound/decoders/timidity/Makefile.testmidi new file mode 100644 index 000000000..8f03fdab6 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/timidity/README b/project/jni/sdl_sound/decoders/timidity/README new file mode 100644 index 000000000..9c9c55aad --- /dev/null +++ b/project/jni/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 + +[(*) Any Registered Trademarks used anywhere in the documentation or +source code for TiMidity are acknowledged as belonging to their +respective owners.] diff --git a/project/jni/sdl_sound/decoders/timidity/TODO b/project/jni/sdl_sound/decoders/timidity/TODO new file mode 100644 index 000000000..69b37ee24 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/timidity/common.c b/project/jni/sdl_sound/decoders/timidity/common.c new file mode 100644 index 000000000..81735d651 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/common.c @@ -0,0 +1,137 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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/project/jni/sdl_sound/decoders/timidity/common.h b/project/jni/sdl_sound/decoders/timidity/common.h new file mode 100644 index 000000000..fbcce9b66 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/common.h @@ -0,0 +1,32 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/dls1.h b/project/jni/sdl_sound/decoders/timidity/dls1.h new file mode 100644 index 000000000..abc2075a5 --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/decoders/timidity/dls2.h b/project/jni/sdl_sound/decoders/timidity/dls2.h new file mode 100644 index 000000000..30cec23a2 --- /dev/null +++ b/project/jni/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 +*/ + +#define F_WAVELINK_MULTICHANNEL 0x0002 + + +/* + DLSID queries for +*/ + +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/project/jni/sdl_sound/decoders/timidity/instrum.c b/project/jni/sdl_sound/decoders/timidity/instrum.c new file mode 100644 index 000000000..e46ecd96f --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/instrum.c @@ -0,0 +1,623 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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; isamples; 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; isamples; 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; jsample[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/project/jni/sdl_sound/decoders/timidity/instrum.h b/project/jni/sdl_sound/decoders/timidity/instrum.h new file mode 100644 index 000000000..e46d2b23b --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/instrum.h @@ -0,0 +1,41 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/instrum_dls.c b/project/jni/sdl_sound/decoders/timidity/instrum_dls.c new file mode 100644 index 000000000..7b8e15c96 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/instrum_dls.c @@ -0,0 +1,1269 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#include + +#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, ®ion->wsmp, ®ion->wsmp_loop); + break; + case FOURCC_LART: + case FOURCC_LAR2: + Parse_lart(data, chunk, ®ion->art, ®ion->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 = ®ion->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/project/jni/sdl_sound/decoders/timidity/instrum_dls.h b/project/jni/sdl_sound/decoders/timidity/instrum_dls.h new file mode 100644 index 000000000..ac3865a03 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/instrum_dls.h @@ -0,0 +1,24 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/mix.c b/project/jni/sdl_sound/decoders/timidity/mix.c new file mode 100644 index 000000000..af8869ae7 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/mix.c @@ -0,0 +1,573 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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<voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<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/project/jni/sdl_sound/decoders/timidity/mix.h b/project/jni/sdl_sound/decoders/timidity/mix.h new file mode 100644 index 000000000..b94c32b9a --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/mix.h @@ -0,0 +1,27 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/options.h b/project/jni/sdl_sound/decoders/timidity/options.h new file mode 100644 index 000000000..4fa2fb7c9 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/options.h @@ -0,0 +1,113 @@ +/* + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/output.c b/project/jni/sdl_sound/decoders/timidity/output.c new file mode 100644 index 000000000..cfe3991c9 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/output.c @@ -0,0 +1,116 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#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/project/jni/sdl_sound/decoders/timidity/output.h b/project/jni/sdl_sound/decoders/timidity/output.h new file mode 100644 index 000000000..9cbe33262 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/output.h @@ -0,0 +1,56 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/playmidi.c b/project/jni/sdl_sound/decoders/timidity/playmidi.c new file mode 100644 index 000000000..cd0b3cda6 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/playmidi.c @@ -0,0 +1,806 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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; ivoice[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; ilow_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; iroot_freq - f; + if (diff<0) diff=-diff; + if (diffvoice[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; jvoice[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 (vcut_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/project/jni/sdl_sound/decoders/timidity/playmidi.h b/project/jni/sdl_sound/decoders/timidity/playmidi.h new file mode 100644 index 000000000..b4545ab27 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/playmidi.h @@ -0,0 +1,64 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/readmidi.c b/project/jni/sdl_sound/decoders/timidity/readmidi.c new file mode 100644 index 000000000..f3435f799 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/readmidi.c @@ -0,0 +1,584 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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 + + 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/project/jni/sdl_sound/decoders/timidity/resample.c b/project/jni/sdl_sound/decoders/timidity/resample.c new file mode 100644 index 000000000..31c739cac --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/resample.c @@ -0,0 +1,612 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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<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/project/jni/sdl_sound/decoders/timidity/resample.h b/project/jni/sdl_sound/decoders/timidity/resample.h new file mode 100644 index 000000000..152cb386a --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/resample.h @@ -0,0 +1,24 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/timidity/tables.c b/project/jni/sdl_sound/decoders/timidity/tables.c new file mode 100644 index 000000000..6c092add9 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/tables.c @@ -0,0 +1,218 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include + +#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/project/jni/sdl_sound/decoders/timidity/tables.h b/project/jni/sdl_sound/decoders/timidity/tables.h new file mode 100644 index 000000000..6b84a3822 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/tables.h @@ -0,0 +1,30 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#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/project/jni/sdl_sound/decoders/timidity/testmidi.c b/project/jni/sdl_sound/decoders/timidity/testmidi.c new file mode 100644 index 000000000..d71fa5574 --- /dev/null +++ b/project/jni/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 +#include +#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/project/jni/sdl_sound/decoders/timidity/timidity.c b/project/jni/sdl_sound/decoders/timidity/timidity.c new file mode 100644 index 000000000..244d6b1ec --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/timidity.c @@ -0,0 +1,602 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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 +#endif + +#include +#include +#include + +#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; i127) + { + 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 '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/project/jni/sdl_sound/decoders/timidity/timidity.h b/project/jni/sdl_sound/decoders/timidity/timidity.h new file mode 100644 index 000000000..53ca825f8 --- /dev/null +++ b/project/jni/sdl_sound/decoders/timidity/timidity.h @@ -0,0 +1,176 @@ +/* + + TiMidity -- Experimental MIDI to WAVE converter + Copyright (C) 1995 Tuukka Toivonen + + 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/project/jni/sdl_sound/decoders/voc.c b/project/jni/sdl_sound/decoders/voc.c new file mode 100644 index 000000000..d7c2795c7 --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_VOC + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/decoders/wav.c b/project/jni/sdl_sound/decoders/wav.c new file mode 100644 index 000000000..cf652f72b --- /dev/null +++ b/project/jni/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 +#endif + +#ifdef SOUND_SUPPORTS_WAV + +#include +#include +#include + +#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 ", + "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/project/jni/sdl_sound/extra_rwops.c b/project/jni/sdl_sound/extra_rwops.c new file mode 100644 index 000000000..6ea92c30f --- /dev/null +++ b/project/jni/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 +#include +#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/project/jni/sdl_sound/extra_rwops.h b/project/jni/sdl_sound/extra_rwops.h new file mode 100644 index 000000000..f86b5564d --- /dev/null +++ b/project/jni/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/project/jni/sdl_sound/include/SDL_sound.h b/project/jni/sdl_sound/include/SDL_sound.h new file mode 100644 index 000000000..b0b8c978d --- /dev/null +++ b/project/jni/sdl_sound/include/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 \" */ + 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 ... */ +