Added SDL_sound lib

This commit is contained in:
pelya
2011-02-07 12:59:02 +00:00
parent a66c54c992
commit c794561f84
81 changed files with 25500 additions and 0 deletions

View File

@@ -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)

View File

@@ -0,0 +1,376 @@
/*
* CHANGELOG.
*/
04202008 - Upped version to 1.0.3 (brown paper bag release for soname bug).
04192008 - Apparently MICRO_VERSION in configure.in doesn't do what I think;
reset for binary compatibility (thanks, Hans!).
04182008 - Include <math.h> in shn.c.
04172008 - Look for Speex includes in new directory. Converted all text
encoding from ISO-8859-1 to UTF-8. Fixed "make dist" script for
dealing with Subversion instead of CVS. Added Speex to the README.
Upped version to 1.0.2.
04112008 - Check if Speex header has bogus data (CVE-2008-1686).
08062007 - Updated my email address.
07152007 - Minor correction in Timidity resampling code (Thanks, Sam!).
07062007 - Fixed uninitialized buffer in mpglib. (Thanks, Phil!).
10292006 - Fixed bogus memory dereference when SMPEG fails init (thanks, Chris!)
10272006 - FLAC 1.1.3 breaks their API _again_, so we try to do the right
thing at build time. (Thanks, Josh!).
05122006 - Patched to get mpglib compiling again (thanks, Sam!).
12172005 - Fixed gcc4 whining in playsound_simple.c.
12062005 - Trimmed a bunch of junk out of the build system, and now it works
on Mac OS X again.
10122005 - Check for libmodplug headers in two possible places (thanks, Tyler!)
10012005 - Added playsound_simple.c.
05302005 - Backport from devtree: Fixed automake nonsense.
11122004 - Backport from devtree: fix .voc decoder crash on file open.
05082004 - Fixed "bootstrap" to work with MacOSX.
05072004 - Backed out some commits, converted repository to Subversion, and
branched off to a 1.1.0 development tree. Changed MikMod URL...old
one is now a porn site. :(
10252003 - VOC decoder was broken. Now it isn't.
10142003 - Build system fix: acinclude.m4 had some word wrapping badness.
10122003 - Fixed "make dist" behaviour to not packaged generated docs, and
made sure other files are always packaged, regardless of config.
Upped version to 1.0.1.
10102003 - Changed some SDL_Error()s to __Sound_SetError() in new DLS code
to fix linking issues.
10052003 - Fixed memory corruption when freeing DLS instruments,
and bug when timidity is initialized multiple times (Thanks, Sam!).
09252003 - Sam Lantinga added support for DLS instruments to the MIDI decoder.
09132003 - Happy September. Added Speex (.spx) decoder.
08052003 - Fixed MIDI decoder on bigendian systems.
03102003 - Never actually created samplelist_mutex (Thanks, Glenn Maynard!).
01302003 - Patches to make SDL_sound more Visual C happy (Thanks, Eric!).
01122003 - Fix to smpeg.c's rewinding code (Thanks, Eric). Put Visual C 6
project files in CVS, without external binaries (Thanks, Eric).
12212002 - Fixed ogg.c to decode a full buffer at a time instead of one ogg
packet per call, and mikmod has a check during initialization to
prevent a clash with SDL_mixer (Thanks, Eric).
12092002 - Changed Sound_Init()'s call to SDL_Init() to SDL_InitSubSystem(),
to prevent unwanted use of the SDL parachute (thanks, Glenn).
10092002 - Fixed a "make dist" issue and upped version to 1.0.0! Woohoo!
09302002 - libFLAC broke their API (again!) for version 1.0.4. That was the
last straw. I ripped the version detection and obsolete FLAC
support out, so you need libFLAC 1.0.4 for that decoder now (and
they'll probably break the API again for 1.0.5. Argh).
09262002 - Happy September. Fixed SDLCALL issues in SDL_sound.h, so it should
work with Win32/WinCE builds again. I hope. Merged latest altcvt
from Frank into CVS.
08222002 - Borland project files in CVS, thanks to Dominique Louis. There are
project files for C++ Builder 6 (Windows), C++ Builder for Linux
(aka Kylix 3) and Borland's C++ Command line compiler.
08172002 - Timidity memory leak cleanup by Torbjörn.
07292002 - Valgrind cleanups; memory leak patches, etc.
07212002 - done_flag was not being reset between files in playsound, so the
first file would playback, and then any following tracks in a given
run would "finish" immediately. Fixed.
07132002 - More altcvt fixes from Frank Ranostaj.
07122002 - Changed inline keyword to compile universally.
07102002 - Fixed a bug in command line handling in playsound.c. Fixes from
Torbjörn and myself to get flac.c friendly between versions of
libFLAC. Mutex'd a potential race condition in decoders/modplug.c.
FIXME cleanups here and there.
07092002 - Fixed typo in documentation (SDL_sound.h).
07052002 - Cleaned up some stuff in playsound.c, removing some FIXMEs.
Commandline validation is improved, too. FIXME removal in
voc.c; should report i/o errors correctly now. Changed DECLSPEC
to SNDDECLSPEC to prevent SDL conflict, and added SDLCALL support.
Removed all instances of Sound_SetError()...now they are either
__Sound_SetError or BAIL*_MACRO.
07022002 - Added WinCE support pack to website, updated INSTALL with CE info.
More altcvt fixes from Frank Ranostaj.
07012002 - Fixed configure.in to work around bug in older autoconfs. Started
merging Tyler's WinCE (PocketPC) port. Added checks for assert.h
and signal.h to configure.in/config.h.in, and #if HAVE_*_H checks
where appropriate in the code. Moved #include <assert.h> (along
with the HAVE_ASSERT_H check) to SDL_sound_internal.h, and removed
unnecessary #includes from the individual source files. Added
"md_reverb = 1;" to MIKMOD_init(). Modplug got some WinCE-specific
setting tweaks, and some settings maintanance code. configure.in
checks if setbuf() is available.
06292002 - More altcvt fixes from Frank Ranostaj...mostly working now?
06252002 - More altcvt fixes from Frank Ranostaj.
06132002 - Patch from Torbjörn to fix stereo AIFF files.
06212002 - More altcvt fixes from Frank Ranostaj.
06132002 - Patch from Torbjörn to make the WAV decoder more tolerant.
06122002 - Committed some altcvt enhancements from Frank Ranostaj.
06112002 - Fixed some debug messages in smpeg.c and mpglib.c.
06072002 - Manpages! Finally installed Doxygen and scratched together a
Doxyfile. After some revision to physfs.h, we've got a rather
nice API reference.
06062002 - Added URLs for official and unofficial versions of ModPlug in
decoders/modplug.c. Cleaned up some FIXMEs.
05222002 - Torbjörn sent in some more fixes for altcvt: mono to stereo
conversion works, now.
05222002 - Torbjörn sent in some initial cleanups and fixes for altcvt, and
fixed a bug in playsound when not all three of --rate, --channels
and --format are specified.
05202002 - Some .cvsignores from Max and me. Added a seek implementations for
the SMPEG, ogg, aiff, wav-adpcm, voc, and au decoders. Added a seek
stub to quicktime.c. playsound now takes milliseconds in the seek
lists: --seek "00:00:400" or whatnot. Corrected playsound's usage
text. Other au.c cleanups for extra robustness. Added an
experimental audio converter that Frank Ranostaj sent to the SDL
mailing list about a month ago: enable it with --enable-altcvt at
configure time, but be warned that it doesn't work very well right
now.
04292002 - Darrell Walisser updated the Mac Classic and OS X project
files, fixed some portability issues, and added an
experimental decoder that uses Apple's QuickTime libraries
(see decoders/quicktime.c). I've included the Mac project files
in CVS, now. Removed all use of alloca() from playsound.
04242002 - Added --seek option and bugfixes to playsound.c. Torbjörn comes
through with seek support for the FLAC, MIDI, and ModPlug
decoders (and some stub code for MikMod), and a bugfix for sample
flag manipulation in the base library (and his own --seek code for
playsound, which unfortunately we're not using).
04232002 - Cleaned up the playsound command line handling. Most command line
options (--rate, --format, --predecode, etc) are specified per-file
and reset to their defaults after each sample is played back.
--loop now takes a numeric argument: --loop 2 will playback the
sample three times (one playback and two loops). Added Darrell
to the playsound credits.
04212002 - Initial work to add a Sound_Seek() API. Removed the NEEDSEEK
sample flag (replaced it with CANSEEK). Hack to change the internal
Sound_SetError() function to __Sound_SetError(). Added internal
function __Sound_convertMsToBytePos().
04082002 - Cleaned up the archive support in playsound a little bit, and
fixed a PhysicsFS bug in the process.
03252002 - Win32 patches and fixes from Tyler Montbriand: handled "inline"
keyword, fixed SNDDBG macros in mpglib, and renamed a conflicting
file (decoders/mpglib/common.c to decoders/mpglib/mpglib_common.c).
03172002 - Removed an unneeded #include in mpglib that broke build on BeOS.
mpglib seems to work find on BeOS. Reworked some of mpglib.c so we
can determine the audio format when accepting the data stream. Some
other minor cleanups here and there.
03162002 - Tied the PhysicsFS code into the build system (code disabled if
physfs not found or --disable-physfs passed to ./configure.)
03152002 - Added PhysicsFS support to playsound, so you can play sound files
that are in ZIP files without unzipping them. Needs to be merged
into build system (I was just testing my PhysFS->RWops glue code).
03142002 - Changed configure script's --enable-vorbis to --enable-ogg. Removed
global state variable from mpglib, so it should be reentrant now
(patches sent to mpglib's actual maintainer). playsound can now
read from stdin.
03102002 - Added a FIXME note to decoders/mpglib.c. playsound now reports
errors in the thread where they occured, which also fixes a double
report of errors during predecoding. Removed all calls to exit() in
mpglib. These calls now report errors correctly to SDL_sound, which
passes them on to the application (patch also sent to mpglib's
actual maintainer). Replaced all stderr chatter in mpglib with
Sound_SetError() calls.
03072002 - decoders/mpglib.c now disregards ID3 tags instead of passing them
on as valid MP3 data to mpglib. Added some (buggy) example code for
adjusting an audio stream's volume (via the new --volume command
line in playsound).
03032002 - Fixed mpglib's build configuration to include general build flags
so that things like --enable-debug work as expected.
02212002 - Changed SMPEG's URL to point to the icculus.org site. Added an
mpglib decoder (internal to SDL_sound; relies on no external libs)
and changes mp3.c to smpeg.c (and other associated things).
02112002 - Committed a patch from Torbjörn to fix incorrect memory accesses
in the Timidity code. Changed the magic number in the AU decoder
to be bigendian (seems appropriate). Updated README for
completeness, and TODO for accuracy. Darrell sent in updated
MacOS X Project Builder files (on the website).
02072002 - Committed a patch Torbjörn sent in awhile ago for preventing
confusion with Timidity++-specific stuff in the timidity.cfg file.
Tyler Montbriand sent in an updated Visual C package.
Updated SDL_sound.h's comments a little. Upped version to 0.1.5.
02052002 - Fixed a cleanup I broke last night. Added CWProject.sit to the
EXTRA_DIST section of Makefile.am, and updated the README with
MacOS (9/X) install instructions.
02042002 - Darrell Walisser submitted some cleanups and CodeWarrior project
files for MacOS 9. Sweet!
01232002 - Max fixed decoders/Makefile.am to work with seperate build
directories, and corrected some dates in this file.
01192002 - Torbjörn sent in patches implementing the rewind method for the
rest of the decoders except shn.c, for which I added a kludged
implementation. Added more info to the README. Hunted down the
reason why SMPEG can't decode before calling SDL_OpenAudio(), and
it can't be fixed without a change to SMPEG (not MY fault! :) ).
Made ModPlug take priority over MikMod when selecting a decoder.
Mutex-protected the internal samples list, and fixed some bugs in
the management of that list. Changed some stuff to use uniform
coding conventions.
01182002 - SDL_sound/playsound builds and runs on BeOS now. Fixed an assertion
bug I introduced yesterday.
01172002 - Implemented Sound_Rewind(), and added a --loop command line to
playsound for testing. Rewrote the audio callback to handle looping
with both predecoded and streamed samples. Most of the decoders
just have an assert(0) in their internal rewinding method at this
point. I implemented the WAV, VOC, AU, AIFF, and RAW ones, for now.
(...and skeleton.c, for what that's worth.) A few tweaks in the
core API implementation to fix unlikely but possible leaks.
01112002 - Mattias Engdegård sent in an .AU decoder. Nice! He also tweaked
playsound to try and wait until SDL has completed playing a given
sound before closing the audio device. Changed a macro in
decoders/shn.c to be more uniform with the other decoders.
SDL_sound error messages are now maintained on a per-thread basis,
and do not interfere with SDL_[GS]etError() anymore.
01112002 - Committed the rest of Torbjörn's MOD patches, to clean up file
extension handling.
01092002 - Torbjörn comes through with a ModPlug-based decoder, which should
work nicely for decoding multiple .MODs at once. Now we need to
figure out what to do with two decoders that can decode the same
file. For now, if you explicitly want either MikMod or ModPlug, you
should explicitly enable one decoder and disable the other on the
configure command line ("--enable-modplug --disable-mikmod", for
example), otherwise configure will try to sort out the best one for
your system. Choice is a wonderful thing. :)
01042002 - Forgot to bump playsound's version to match SDL_sound's. Fixed.
Added some notes to the top of COPYING about other libraries, etc.
A real MIDI decoder (using a hacked version of the hacked version
of Timidity from SDL_mixer) is now in place and working well,
thanks to Torbjörn.
01012002 - Happy New Year. Added some debug output to wav.c for future
codecs (GSM comes to mind). Fixed the SMPEG decoder's URL to point
to Loki's webpage.
12302001 - Upped version to 0.1.4.
12272001 - Added --audiobuf and --decodebuf options to playsound to make
tracking down a bug in the ADPCM decoder easier (plus, it could
help for benchmarking, etc later on...). Found a printf() bug in
playsound (extra comma in there...). ADPCM decoder appears to be
functional now. Tried to add ElectricFence support to
configure.in, and failed. All this libtool/autoconf stuff makes my
head hurt.
12262001 - Changed remaining references to the "LICENSE" file into "COPYING".
Work progresses on the ADPCM-compressed .wav decoder. Updates to
the documentation in SDL_sound.h. Hhmm...find_chunk() in wav.c was
badly broken. Fixed.
12162001 - FLAC decoder now checks for the magic number unless the file
extension is recognized. This was changed back because searching
for metadata, while probably more effective, is VERY expensive (and
useless) on non-FLAC streams.
12052001 - Put our names in a "--credits" option in playsound, and put the
standard GNU disclaimers in there too, for good measure. Renamed
LICENSE to COPYING to match GNU standards more closely (and to
end Max's torment. :) ) Tweaks to wav.c, and work on aiff.c to
make it easier to support multiple audio formats (for compression
handling later down the road).
11302001 - Torbjörn and I make Sound_DecodeAll() more robust: checks for
previous decoding failures and sets an appropriate error, handles
decoders that change their buffers on the fly (such as the FLAC
decoder), and deals with out-of-memory conditions more gracefully.
11252001 - (With thanks to Andreas Umbach for pointing it out) Fixed some
problems with Sound_DecodeAll(). For local testing of this bug,
added a --predecode command line to playsound. Minor fixes to
theoretical bugs in Sound_FreeSample(). playsound no longer
buffers stdout and stderr. Updated Sound_DecodeAll()'s comments in
SDL_sound.h ...
11192001 - FLAC decoder cleanups from Torbjörn.
11092001 - Torbjörn fixes playsound's audio callback after I broke it, again.
A bug in configure.in was preventing SMPEG from being used unless
--enable-debug was set; fixed. Changed this file to list latest
changes first. Torbjörn submitted a FLAC decoder that utilizes
libFLAC (http://flac.sf.net/). Cool.
11012001 - API COMPATIBILITY BREAKAGE: Decoders can now list multiple file
extensions each. Playsound has been updated to handle this.
Playsound now registers a SIGINT handler, so you can skip tracks
and/or abort the way that mpg123 does.
10232001 - Rewrote playsound.c's audio_callback() to no longer need the
overflow buffer hack, which streamlines it a little and trims the
memory requirements for playsound by about 16 kilobytes.
10172001 - Torbjörn catches a problem with the overflow buffer in playsound's
audio callback.
10152001 - Torbjörn sends in a default sample format for the MIDI decoder,
and the starts of the audio conversion funcitonality (ripped
from SDL). Officially released 0.1.3. Added LICENSE and
CHANGELOG to the distribution. (Again, from Torbjörn) added in
the start of a tweaked audio converter.
10122001 - Torbjörn Andersson submitted command line enhancements to
playsound, and I cleaned up the --help output.
10092001 - Patches to shn.c for Visual C compatibility. Visual C project files
available from the website. Changed Corona688 to Tyler Montbriand
in CREDITS. Upped version to 0.1.3.
10082001 - Restructured decoders/wav.c to allow for multiple formats, and
put the start of a handler for the ADPCM format in place.
10072001 - Changed the way decoders/mod.c handles samplerate so that it should
work universally. This isn't an ideal solution, but it's probably
the best we can do without rewriting mikmod. Made a change to ogg.c
for portability: changed an int64_t to ogg_int64_t.
10062001 - Made a change to SDL_sound.c for compiling on non-GNU toolchains.
10052001 - Removed #include "SDL_endian" from aiff.c.
10042001 - Changed some #if (defined SOUND_SUPPORTS_*) lines to
#ifdef SOUND_SUPPORTS_* in voc.c and shn.c, for consistency with
the other decoders.
10032001 - After hours of tracking down a bogus pointer, the SHN decoder works!
I can die happy. :) Max placated me with an --enable-debug option
so I could stop my whining. Other autoconf goodies (such as
reenabling -Werror for debug builds, etc). Torbjörn brings in a
MIDI decoder, which reads from a Timidity process through a pipe.
Changed playsound to open the audio device to match the properties
of each sound file, which results in less conversion (and therefore,
more chance of correct playback).
10022001 - Changed a comment in mod.c to not refer to "the mikmod
directory" anymore. Committed Torbjörn's patch for MP3 detection.
(better late than never). __Sound_strcasecmp() now handles NULL
strings gracefully, fixing the crash with "playsound bootstrap".
More work on the SHN decoder.
10012001 - Fixed a memory leak that Torbjörn found in the MOD decoder.
09252001 - More autoconf work. Gave Max Horn write access to the CVS
repository, so I don't drive him nuts tweaking this thing. :)
Fixed a const complaint and some other stuff needed for compilation
under Visual C++ 6.0 (no, it isn't ported yet). Put the SHN source
in CVS, even though it isn't ready (and doesn't even compile). Do
NOT enable it in your build!
09242001 - Thank goodness, Torbjörn came through with the MP3 fix. Apparently
SMPEG mixes each chunk of decoded data with whatever is already
in the buffer you give it. I hate that. I'm going to patch SMPEG
to let the programmer enable and disable that behaviour in a given
(SMPEG *), since it's just a CPU eater in this case. The _D(())
macro is now SNDDBG(()), since _D is taken on MacOS X's version of
gcc (which was bound to happen on some platform sooner than later
anyhow). Renamed test_sdlsound to playsound, and made it more
robust in general: fixed potential overflow in audio_callback,
made it chatter less, made it take multiple files and some other
command lines. Initial autoconf support, thanks to Max Horn.
09222001 - Torbjörn Andersson strikes again, with a collection of patches.
First, some cosmetic tweaks for decoders/aiff.c. Next, a MOD player
based on MikMod. This inspired me to add two more methods to
Sound_DecoderFunctions: init() and quit(). Third, a fix to
decoders/mp3.c so that SMPEG won't claim every stream it sees, MP3
or not. I removed the multiple-streams-per-rwops code, after
discussion on the mailing list. The init() and quit() methods
led to the possibility that certain decoders will flag themselves
as unavailable at runtime, and SDL_sound now handles this.
Added [LIB|INC]PATH_[OGG|MOD]. Bigendian fixes; now works on
PowerPC Linux. MikMod tweaks. Changed version to 0.1.2.
09202001 - Torbjörn Andersson submitted several patches: fixed a comment in
the .WAV decoder (whoops...screwed up my own search-and-replace.
Hah.), made an attempt at putting multiple sound streams behind
one RWops (gotta think on that one first), and, most importantly,
added an AIFF decoder, which is very cool.
09192001 - Added a skeleton decoder source file. Changed voc_read() to
voc_read_waveform(), so it wouldn't be confused with VOC_read().
Fixed a byte ordering bug in voc.c (reported as AUDIO_S16LSB, but
we were swapping byte order of data ourselves. Fixed). Added basic
.WAV support. Fixed Makefile so that -I. is always first;
otherwise, a previously installed header might get used for the
compiles, which is not good. SDL_sound.h now includes SDL_endian.h,
since SDL.h doesn't, for some reason. Moved version defines in
SDL_sound.h to top of file so I can find them. :)
Changed version to 0.1.1. Committed patch from Tsuyoshi Iguchi to
fix a segfault (I forgot to put a NULL terminator at the end of
the available_decoders array), fixing the only bug preventing the
test program from running on FreeBSD 4.3. Sweet. Added Ogg Vorbis
decoder. Rewrote the test program's SDL audio callback to be more
robust (Ogg exposed a nasty bug in it). Fixed a byte-ordering issue
in the VOC decoder.
09182001 - Implemented MP3 support through SMPEG (not working yet, though) and
wrote the Reference Counting RWops wrapper. Added other little
things like the _D(()) macro. Added VOC support, which went up with
surprisingly little struggle, which means it MUST be leaking
memory. :)
09172001 - Changed some overlooked "voice" to "sound". Implemented base API.
So...tired. Everything's different. :)
Also put in a RAW decoder and a simple test program.
09142001 - Changed name to SDL_sound, added Sound_DecodeAll() to spec.
09132001 - Initial spec proposed on SDL mailing list, under name "SDL_voice".
--ryan. (icculus@icculus.org)
/* end of CHANGELOG ... */

View File

@@ -0,0 +1,524 @@
Please note that the included source from Timidity, the MIDI decoder, is also
licensed under the following terms (GNU LGPL), but can also be used
separately under the GNU GPL, or the Perl Artistic License. Those licensing
terms are not reprinted here, but can be found on the web easily.
Other external libraries (such as Ogg Vorbis, SMPEG, etc) have their own
licenses which you should be aware of before including the related code
in your configuration. Most (if not all) are also under the LGPL, but are
external projects and we've got no control over them.
If you want to use SDL_sound under a closed-source license, please contact
Ryan (icculus@icculus.org), and we can discuss an alternate license for
money to be distributed between the contributors to this work, but I'd
encourage you to abide by the LGPL, since the usual concern is whether you
can use this library without releasing your own source code (you can).
-------------------
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -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 ... */

View File

@@ -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)

View File

@@ -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)

View File

@@ -0,0 +1,905 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* This file implements the core API, which is relatively simple.
* The real meat of SDL_sound is in the decoders directory.
*
* Documentation is in SDL_sound.h ... It's verbose, honest. :)
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
/* The various decoder drivers... */
#if (defined SOUND_SUPPORTS_SMPEG)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SMPEG;
#endif
#if (defined SOUND_SUPPORTS_MPGLIB)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MPGLIB;
#endif
#if (defined SOUND_SUPPORTS_MIKMOD)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MIKMOD;
#endif
#if (defined SOUND_SUPPORTS_MODPLUG)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MODPLUG;
#endif
#if (defined SOUND_SUPPORTS_WAV)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV;
#endif
#if (defined SOUND_SUPPORTS_AIFF)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_AIFF;
#endif
#if (defined SOUND_SUPPORTS_AU)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_AU;
#endif
#if (defined SOUND_SUPPORTS_OGG)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG;
#endif
#if (defined SOUND_SUPPORTS_VOC)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC;
#endif
#if (defined SOUND_SUPPORTS_RAW)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW;
#endif
#if (defined SOUND_SUPPORTS_SHN)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SHN;
#endif
#if (defined SOUND_SUPPORTS_MIDI)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MIDI;
#endif
#if (defined SOUND_SUPPORTS_FLAC)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC;
#endif
#if (defined SOUND_SUPPORTS_QUICKTIME)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime;
#endif
#if (defined SOUND_SUPPORTS_SPEEX)
extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SPEEX;
#endif
typedef struct
{
int available;
const Sound_DecoderFunctions *funcs;
} decoder_element;
static decoder_element decoders[] =
{
#if (defined SOUND_SUPPORTS_SMPEG)
{ 0, &__Sound_DecoderFunctions_SMPEG },
#endif
#if (defined SOUND_SUPPORTS_MPGLIB)
{ 0, &__Sound_DecoderFunctions_MPGLIB },
#endif
#if (defined SOUND_SUPPORTS_MODPLUG)
{ 0, &__Sound_DecoderFunctions_MODPLUG },
#endif
#if (defined SOUND_SUPPORTS_MIKMOD)
{ 0, &__Sound_DecoderFunctions_MIKMOD },
#endif
#if (defined SOUND_SUPPORTS_WAV)
{ 0, &__Sound_DecoderFunctions_WAV },
#endif
#if (defined SOUND_SUPPORTS_AIFF)
{ 0, &__Sound_DecoderFunctions_AIFF },
#endif
#if (defined SOUND_SUPPORTS_AU)
{ 0, &__Sound_DecoderFunctions_AU },
#endif
#if (defined SOUND_SUPPORTS_OGG)
{ 0, &__Sound_DecoderFunctions_OGG },
#endif
#if (defined SOUND_SUPPORTS_VOC)
{ 0, &__Sound_DecoderFunctions_VOC },
#endif
#if (defined SOUND_SUPPORTS_RAW)
{ 0, &__Sound_DecoderFunctions_RAW },
#endif
#if (defined SOUND_SUPPORTS_SHN)
{ 0, &__Sound_DecoderFunctions_SHN },
#endif
#if (defined SOUND_SUPPORTS_FLAC)
{ 0, &__Sound_DecoderFunctions_FLAC },
#endif
#if (defined SOUND_SUPPORTS_MIDI)
{ 0, &__Sound_DecoderFunctions_MIDI },
#endif
#if (defined SOUND_SUPPORTS_QUICKTIME)
{ 0, &__Sound_DecoderFunctions_QuickTime },
#endif
#if (defined SOUND_SUPPORTS_SPEEX)
{ 0, &__Sound_DecoderFunctions_SPEEX },
#endif
{ 0, NULL }
};
/* General SDL_sound state ... */
typedef struct __SOUND_ERRMSGTYPE__
{
Uint32 tid;
int error_available;
char error_string[128];
struct __SOUND_ERRMSGTYPE__ *next;
} ErrMsg;
static ErrMsg *error_msgs = NULL;
static SDL_mutex *errorlist_mutex = NULL;
static Sound_Sample *sample_list = NULL; /* this is a linked list. */
static SDL_mutex *samplelist_mutex = NULL;
static const Sound_DecoderInfo **available_decoders = NULL;
static int initialized = 0;
/* functions ... */
void Sound_GetLinkedVersion(Sound_Version *ver)
{
if (ver != NULL)
{
ver->major = SOUND_VER_MAJOR;
ver->minor = SOUND_VER_MINOR;
ver->patch = SOUND_VER_PATCH;
} /* if */
} /* Sound_GetLinkedVersion */
int Sound_Init(void)
{
size_t i;
size_t pos = 0;
size_t total = sizeof (decoders) / sizeof (decoders[0]);
BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
sample_list = NULL;
error_msgs = NULL;
available_decoders = (const Sound_DecoderInfo **)
malloc((total) * sizeof (Sound_DecoderInfo *));
BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0);
SDL_InitSubSystem(SDL_INIT_AUDIO);
errorlist_mutex = SDL_CreateMutex();
samplelist_mutex = SDL_CreateMutex();
for (i = 0; decoders[i].funcs != NULL; i++)
{
decoders[i].available = decoders[i].funcs->init();
if (decoders[i].available)
{
available_decoders[pos] = &(decoders[i].funcs->info);
pos++;
} /* if */
} /* for */
available_decoders[pos] = NULL;
initialized = 1;
return(1);
} /* Sound_Init */
int Sound_Quit(void)
{
ErrMsg *err;
ErrMsg *nexterr = NULL;
size_t i;
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
while (((volatile Sound_Sample *) sample_list) != NULL)
Sound_FreeSample(sample_list);
initialized = 0;
SDL_DestroyMutex(samplelist_mutex);
samplelist_mutex = NULL;
sample_list = NULL;
for (i = 0; decoders[i].funcs != NULL; i++)
{
if (decoders[i].available)
{
decoders[i].funcs->quit();
decoders[i].available = 0;
} /* if */
} /* for */
if (available_decoders != NULL)
free((void *) available_decoders);
available_decoders = NULL;
/* clean up error state for each thread... */
SDL_LockMutex(errorlist_mutex);
for (err = error_msgs; err != NULL; err = nexterr)
{
nexterr = err->next;
free(err);
} /* for */
error_msgs = NULL;
SDL_UnlockMutex(errorlist_mutex);
SDL_DestroyMutex(errorlist_mutex);
errorlist_mutex = NULL;
return(1);
} /* Sound_Quit */
const Sound_DecoderInfo **Sound_AvailableDecoders(void)
{
return(available_decoders); /* READ. ONLY. */
} /* Sound_AvailableDecoders */
static ErrMsg *findErrorForCurrentThread(void)
{
ErrMsg *i;
Uint32 tid;
if (error_msgs != NULL)
{
tid = SDL_ThreadID();
SDL_LockMutex(errorlist_mutex);
for (i = error_msgs; i != NULL; i = i->next)
{
if (i->tid == tid)
{
SDL_UnlockMutex(errorlist_mutex);
return(i);
} /* if */
} /* for */
SDL_UnlockMutex(errorlist_mutex);
} /* if */
return(NULL); /* no error available. */
} /* findErrorForCurrentThread */
const char *Sound_GetError(void)
{
const char *retval = NULL;
ErrMsg *err;
if (!initialized)
return(ERR_NOT_INITIALIZED);
err = findErrorForCurrentThread();
if ((err != NULL) && (err->error_available))
{
retval = err->error_string;
err->error_available = 0;
} /* if */
return(retval);
} /* Sound_GetError */
void Sound_ClearError(void)
{
ErrMsg *err;
if (!initialized)
return;
err = findErrorForCurrentThread();
if (err != NULL)
err->error_available = 0;
} /* Sound_ClearError */
/*
* This is declared in the internal header.
*/
void __Sound_SetError(const char *str)
{
ErrMsg *err;
if (str == NULL)
return;
SNDDBG(("__Sound_SetError(\"%s\");%s\n", str,
(initialized) ? "" : " [NOT INITIALIZED!]"));
if (!initialized)
return;
err = findErrorForCurrentThread();
if (err == NULL)
{
err = (ErrMsg *) malloc(sizeof (ErrMsg));
if (err == NULL)
return; /* uhh...? */
memset((void *) err, '\0', sizeof (ErrMsg));
err->tid = SDL_ThreadID();
SDL_LockMutex(errorlist_mutex);
err->next = error_msgs;
error_msgs = err;
SDL_UnlockMutex(errorlist_mutex);
} /* if */
err->error_available = 1;
strncpy(err->error_string, str, sizeof (err->error_string));
err->error_string[sizeof (err->error_string) - 1] = '\0';
} /* __Sound_SetError */
Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms)
{
/* "frames" == "sample frames" */
float frames_per_ms = ((float) info->rate) / 1000.0f;
Uint32 frame_offset = (Uint32) (frames_per_ms * ((float) ms));
Uint32 frame_size = (Uint32) ((info->format & 0xFF) / 8) * info->channels;
return(frame_offset * frame_size);
} /* __Sound_convertMsToBytePos */
/*
* -ansi and -pedantic flags prevent use of strcasecmp() on Linux, and
* I honestly don't want to mess around with figuring out if a given
* platform has "strcasecmp", "stricmp", or
* "compare_two_damned_strings_case_insensitive", which I hear is in the
* next release of Carbon. :) This is exported so decoders may use it if
* they like.
*/
int __Sound_strcasecmp(const char *x, const char *y)
{
int ux, uy;
if (x == y) /* same pointer? Both NULL? */
return(0);
if (x == NULL)
return(-1);
if (y == NULL)
return(1);
do
{
ux = toupper((int) *x);
uy = toupper((int) *y);
if (ux > uy)
return(1);
else if (ux < uy)
return(-1);
x++;
y++;
} while ((ux) && (uy));
return(0);
} /* __Sound_strcasecmp */
/*
* Allocate a Sound_Sample, and fill in most of its fields. Those that need
* to be filled in later, by a decoder, will be initialized to zero.
*/
static Sound_Sample *alloc_sample(SDL_RWops *rw, Sound_AudioInfo *desired,
Uint32 bufferSize)
{
Sound_Sample *retval = malloc(sizeof (Sound_Sample));
Sound_SampleInternal *internal = malloc(sizeof (Sound_SampleInternal));
if ((retval == NULL) || (internal == NULL))
{
__Sound_SetError(ERR_OUT_OF_MEMORY);
if (retval)
free(retval);
if (internal)
free(internal);
return(NULL);
} /* if */
memset(retval, '\0', sizeof (Sound_Sample));
memset(internal, '\0', sizeof (Sound_SampleInternal));
assert(bufferSize > 0);
retval->buffer = malloc(bufferSize); /* pure ugly. */
if (!retval->buffer)
{
__Sound_SetError(ERR_OUT_OF_MEMORY);
free(internal);
free(retval);
return(NULL);
} /* if */
memset(retval->buffer, '\0', bufferSize);
retval->buffer_size = bufferSize;
if (desired != NULL)
memcpy(&retval->desired, desired, sizeof (Sound_AudioInfo));
internal->rw = rw;
retval->opaque = internal;
return(retval);
} /* alloc_sample */
#if (defined DEBUG_CHATTER)
static __inline__ const char *fmt_to_str(Uint16 fmt)
{
switch(fmt)
{
case AUDIO_U8:
return("U8");
case AUDIO_S8:
return("S8");
case AUDIO_U16LSB:
return("U16LSB");
case AUDIO_S16LSB:
return("S16LSB");
case AUDIO_U16MSB:
return("U16MSB");
case AUDIO_S16MSB:
return("S16MSB");
} /* switch */
return("Unknown");
} /* fmt_to_str */
#endif
/*
* The bulk of the Sound_NewSample() work is done here...
* Ask the specified decoder to handle the data in (rw), and if
* so, construct the Sound_Sample. Otherwise, try to wind (rw)'s stream
* back to where it was, and return false.
*/
static int init_sample(const Sound_DecoderFunctions *funcs,
Sound_Sample *sample, const char *ext,
Sound_AudioInfo *_desired)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
Sound_AudioInfo desired;
int pos = SDL_RWtell(internal->rw);
/* fill in the funcs for this decoder... */
sample->decoder = &funcs->info;
internal->funcs = funcs;
if (!funcs->open(sample, ext))
{
SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */
return(0);
} /* if */
/* success; we've got a decoder! */
/* Now we need to set up the conversion buffer... */
memcpy(&desired, (_desired != NULL) ? _desired : &sample->actual,
sizeof (Sound_AudioInfo));
if (desired.format == 0)
desired.format = sample->actual.format;
if (desired.channels == 0)
desired.channels = sample->actual.channels;
if (desired.rate == 0)
desired.rate = sample->actual.rate;
if (Sound_BuildAudioCVT(&internal->sdlcvt,
sample->actual.format,
sample->actual.channels,
sample->actual.rate,
desired.format,
desired.channels,
desired.rate,
sample->buffer_size) == -1)
{
__Sound_SetError(SDL_GetError());
funcs->close(sample);
SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */
return(0);
} /* if */
if (internal->sdlcvt.len_mult > 1)
{
void *rc = realloc(sample->buffer,
sample->buffer_size * internal->sdlcvt.len_mult);
if (rc == NULL)
{
funcs->close(sample);
SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */
return(0);
} /* if */
sample->buffer = rc;
} /* if */
/* these pointers are all one and the same. */
memcpy(&sample->desired, &desired, sizeof (Sound_AudioInfo));
internal->sdlcvt.buf = internal->buffer = sample->buffer;
internal->buffer_size = sample->buffer_size / internal->sdlcvt.len_mult;
internal->sdlcvt.len = internal->buffer_size;
/* Prepend our new Sound_Sample to the sample_list... */
SDL_LockMutex(samplelist_mutex);
internal->next = sample_list;
if (sample_list != NULL)
((Sound_SampleInternal *) sample_list->opaque)->prev = sample;
sample_list = sample;
SDL_UnlockMutex(samplelist_mutex);
SNDDBG(("New sample DESIRED format: %s format, %d rate, %d channels.\n",
fmt_to_str(sample->desired.format),
sample->desired.rate,
sample->desired.channels));
SNDDBG(("New sample ACTUAL format: %s format, %d rate, %d channels.\n",
fmt_to_str(sample->actual.format),
sample->actual.rate,
sample->actual.channels));
SNDDBG(("On-the-fly conversion: %s.\n",
internal->sdlcvt.needed ? "ENABLED" : "DISABLED"));
return(1);
} /* init_sample */
Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext,
Sound_AudioInfo *desired, Uint32 bSize)
{
Sound_Sample *retval;
decoder_element *decoder;
/* sanity checks. */
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL);
BAIL_IF_MACRO(rw == NULL, ERR_INVALID_ARGUMENT, NULL);
retval = alloc_sample(rw, desired, bSize);
if (!retval)
return(NULL); /* alloc_sample() sets error message... */
if (ext != NULL)
{
for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++)
{
if (decoder->available)
{
const char **decoderExt = decoder->funcs->info.extensions;
while (*decoderExt)
{
if (__Sound_strcasecmp(*decoderExt, ext) == 0)
{
if (init_sample(decoder->funcs, retval, ext, desired))
return(retval);
break; /* done with this decoder either way. */
} /* if */
decoderExt++;
} /* while */
} /* if */
} /* for */
} /* if */
/* no direct extension match? Try everything we've got... */
for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++)
{
if (decoder->available)
{
int should_try = 1;
const char **decoderExt = decoder->funcs->info.extensions;
/* skip if we would have tried decoder above... */
while (*decoderExt)
{
if (__Sound_strcasecmp(*decoderExt, ext) == 0)
{
should_try = 0;
break;
} /* if */
decoderExt++;
} /* while */
if (should_try)
{
if (init_sample(decoder->funcs, retval, ext, desired))
return(retval);
} /* if */
} /* if */
} /* for */
/* nothing could handle the sound data... */
free(retval->opaque);
if (retval->buffer != NULL)
free(retval->buffer);
free(retval);
SDL_RWclose(rw);
__Sound_SetError(ERR_UNSUPPORTED_FORMAT);
return(NULL);
} /* Sound_NewSample */
Sound_Sample *Sound_NewSampleFromFile(const char *filename,
Sound_AudioInfo *desired,
Uint32 bufferSize)
{
const char *ext;
SDL_RWops *rw;
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL);
BAIL_IF_MACRO(filename == NULL, ERR_INVALID_ARGUMENT, NULL);
ext = strrchr(filename, '.');
rw = SDL_RWFromFile(filename, "rb");
BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL);
if (ext != NULL)
ext++;
return(Sound_NewSample(rw, ext, desired, bufferSize));
} /* Sound_NewSampleFromFile */
void Sound_FreeSample(Sound_Sample *sample)
{
Sound_SampleInternal *internal;
if (!initialized)
{
__Sound_SetError(ERR_NOT_INITIALIZED);
return;
} /* if */
if (sample == NULL)
{
__Sound_SetError(ERR_INVALID_ARGUMENT);
return;
} /* if */
internal = (Sound_SampleInternal *) sample->opaque;
SDL_LockMutex(samplelist_mutex);
/* update the sample_list... */
if (internal->prev != NULL)
{
Sound_SampleInternal *prevInternal;
prevInternal = (Sound_SampleInternal *) internal->prev->opaque;
prevInternal->next = internal->next;
} /* if */
else
{
assert(sample_list == sample);
sample_list = internal->next;
} /* else */
if (internal->next != NULL)
{
Sound_SampleInternal *nextInternal;
nextInternal = (Sound_SampleInternal *) internal->next->opaque;
nextInternal->prev = internal->prev;
} /* if */
SDL_UnlockMutex(samplelist_mutex);
/* nuke it... */
internal->funcs->close(sample);
if (internal->rw != NULL) /* this condition is a "just in case" thing. */
SDL_RWclose(internal->rw);
if ((internal->buffer != NULL) && (internal->buffer != sample->buffer))
free(internal->buffer);
free(internal);
if (sample->buffer != NULL)
free(sample->buffer);
free(sample);
} /* Sound_FreeSample */
int Sound_SetBufferSize(Sound_Sample *sample, Uint32 newSize)
{
void *newBuf = NULL;
Sound_SampleInternal *internal = NULL;
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0);
internal = ((Sound_SampleInternal *) sample->opaque);
newBuf = realloc(sample->buffer, newSize * internal->sdlcvt.len_mult);
BAIL_IF_MACRO(newBuf == NULL, ERR_OUT_OF_MEMORY, 0);
internal->sdlcvt.buf = internal->buffer = sample->buffer = newBuf;
sample->buffer_size = newSize;
internal->buffer_size = newSize / internal->sdlcvt.len_mult;
internal->sdlcvt.len = internal->buffer_size;
return(1);
} /* Sound_SetBufferSize */
Uint32 Sound_Decode(Sound_Sample *sample)
{
Sound_SampleInternal *internal = NULL;
Uint32 retval = 0;
/* a boatload of sanity checks... */
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0);
BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0);
internal = (Sound_SampleInternal *) sample->opaque;
assert(sample->buffer != NULL);
assert(sample->buffer_size > 0);
assert(internal->buffer != NULL);
assert(internal->buffer_size > 0);
/* reset EAGAIN. Decoder can flip it back on if it needs to. */
sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
retval = internal->funcs->read(sample);
if (retval > 0 && internal->sdlcvt.needed)
{
internal->sdlcvt.len = retval;
Sound_ConvertAudio(&internal->sdlcvt);
retval = internal->sdlcvt.len_cvt;
} /* if */
return(retval);
} /* Sound_Decode */
Uint32 Sound_DecodeAll(Sound_Sample *sample)
{
Sound_SampleInternal *internal = NULL;
void *buf = NULL;
Uint32 newBufSize = 0;
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0);
BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0);
internal = (Sound_SampleInternal *) sample->opaque;
while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) &&
((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) )
{
Uint32 br = Sound_Decode(sample);
void *ptr = realloc(buf, newBufSize + br);
if (ptr == NULL)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
__Sound_SetError(ERR_OUT_OF_MEMORY);
} /* if */
else
{
buf = ptr;
memcpy( ((char *) buf) + newBufSize, sample->buffer, br );
newBufSize += br;
} /* else */
} /* while */
if (buf == NULL) /* ...in case first call to realloc() fails... */
return(sample->buffer_size);
if (internal->buffer != sample->buffer)
free(internal->buffer);
free(sample->buffer);
internal->sdlcvt.buf = internal->buffer = sample->buffer = buf;
sample->buffer_size = newBufSize;
internal->buffer_size = newBufSize / internal->sdlcvt.len_mult;
internal->sdlcvt.len = internal->buffer_size;
return(newBufSize);
} /* Sound_DecodeAll */
int Sound_Rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal;
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
internal = (Sound_SampleInternal *) sample->opaque;
if (!internal->funcs->rewind(sample))
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(0);
} /* if */
sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
sample->flags &= ~SOUND_SAMPLEFLAG_ERROR;
sample->flags &= ~SOUND_SAMPLEFLAG_EOF;
return(1);
} /* Sound_Rewind */
int Sound_Seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal;
BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
if (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK))
BAIL_MACRO(ERR_CANNOT_SEEK, 0);
internal = (Sound_SampleInternal *) sample->opaque;
BAIL_IF_MACRO(!internal->funcs->seek(sample, ms), NULL, 0);
sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN;
sample->flags &= ~SOUND_SAMPLEFLAG_ERROR;
sample->flags &= ~SOUND_SAMPLEFLAG_EOF;
return(1);
} /* Sound_Rewind */
/* end of SDL_sound.c ... */

View File

@@ -0,0 +1,326 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Internal function/structure declaration. Do NOT include in your
* application.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#ifndef _INCLUDE_SDL_SOUND_INTERNAL_H_
#define _INCLUDE_SDL_SOUND_INTERNAL_H_
#ifndef __SDL_SOUND_INTERNAL__
#error Do not include this header from your applications.
#endif
#include "SDL.h"
/* SDL 1.2.4 defines this, but better safe than sorry. */
#if (!defined(__inline__))
# define __inline__
#endif
#if (defined DEBUG_CHATTER)
#define SNDDBG(x) printf x
#else
#define SNDDBG(x)
#endif
#if HAVE_ASSERT_H
# include <assert.h>
#endif
#ifdef _WIN32_WCE
extern char *strrchr(const char *s, int c);
# ifdef NDEBUG
# define assert(x)
# else
# define assert(x) if(!x) { fprintf(stderr,"Assertion failed in %s, line %s.\n",__FILE__,__LINE__); fclose(stderr); fclose(stdout); exit(1); }
# endif
#endif
#if (!defined assert) /* if all else fails. */
# define assert(x)
#endif
typedef struct __SOUND_DECODERFUNCTIONS__
{
/* This is a block of info about your decoder. See SDL_sound.h. */
const Sound_DecoderInfo info;
/*
* This is called during the Sound_Init() function. Use this to
* set up any global state that your decoder needs, such as
* initializing an external library, etc.
*
* Return non-zero if initialization is successful, zero if there's
* a fatal error. If this method fails, then this decoder is
* flagged as unavailable until SDL_sound() is shut down and
* reinitialized, in which case this method will be tried again.
*
* Note that the decoders quit() method won't be called if this
* method fails, so if you can't intialize, you'll have to clean
* up the half-initialized state in this method.
*/
int (*init)(void);
/*
* This is called during the Sound_Quit() function. Use this to
* clean up any global state that your decoder has used during its
* lifespan.
*/
void (*quit)(void);
/*
* Returns non-zero if (sample) has a valid fileformat that this
* driver can handle. Zero if this driver can NOT handle the data.
*
* Extension, which may be NULL, is just a hint as to the form of
* data that is being passed in. Most decoders should determine if
* they can handle the data by the data itself, but others, like
* the raw data handler, need this hint to know if they should
* accept the data in the first place.
*
* (sample)'s (opaque) field should be cast to a Sound_SampleInternal
* pointer:
*
* Sound_SampleInternal *internal;
* internal = (Sound_SampleInternal *) sample->opaque;
*
* Certain fields of sample will be filled in for the decoder before
* this call, and others should be filled in by the decoder. Some
* fields are offlimits, and should NOT be modified. The list:
*
* in Sound_SampleInternal section:
* Sound_Sample *next; (offlimits)
* Sound_Sample *prev; (offlimits)
* SDL_RWops *rw; (can use, but do NOT close it)
* const Sound_DecoderFunctions *funcs; (that's this structure)
* Sound_AudioCVT sdlcvt; (offlimits)
* void *buffer; (offlimits until read() method)
* Uint32 buffer_size; (offlimits until read() method)
* void *decoder_private; (read and write access)
*
* in rest of Sound_Sample:
* void *opaque; (this was internal section, above)
* const Sound_DecoderInfo *decoder; (read only)
* Sound_AudioInfo desired; (read only, usually not needed here)
* Sound_AudioInfo actual; (please fill this in)
* void *buffer; (offlimits)
* Uint32 buffer_size; (offlimits)
* Sound_SampleFlags flags; (set appropriately)
*/
int (*open)(Sound_Sample *sample, const char *ext);
/*
* Clean up. SDL_sound is done with this sample, so the decoder should
* clean up any resources it allocated. Anything that wasn't
* explicitly allocated by the decoder should be LEFT ALONE, since
* the higher-level SDL_sound layer will clean up its own mess.
*/
void (*close)(Sound_Sample *sample);
/*
* Get more data from (sample). The decoder should get a pointer to
* the internal structure...
*
* Sound_SampleInternal *internal;
* internal = (Sound_SampleInternal *) sample->opaque;
*
* ...and then start decoding. Fill in up to internal->buffer_size
* bytes of decoded sound in the space pointed to by
* internal->buffer. The encoded data is read in from internal->rw.
* Data should be decoded in the format specified during the
* decoder's open() method in the sample->actual field. The
* conversion to the desired format is done at a higher level.
*
* The return value is the number of bytes decoded into
* internal->buffer, which can be no more than internal->buffer_size,
* but can be less. If it is less, you should set a state flag:
*
* If there's just no more data (end of file, etc), then do:
* sample->flags |= SOUND_SAMPLEFLAG_EOF;
*
* If there's an unrecoverable error, then do:
* __Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG);
* sample->flags |= SOUND_SAMPLEFLAG_ERROR;
*
* If there's more data, but you'd have to block for considerable
* amounts of time to get at it, or there's a recoverable error,
* then do:
* __Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG);
* sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
*
* SDL_sound will not call your read() method for any samples with
* SOUND_SAMPLEFLAG_EOF or SOUND_SAMPLEFLAG_ERROR set. The
* SOUND_SAMPLEFLAG_EAGAIN flag is reset before each call to this
* method.
*/
Uint32 (*read)(Sound_Sample *sample);
/*
* Reset the decoding to the beginning of the stream. Nonzero on
* success, zero on failure.
*
* The purpose of this method is to allow for higher efficiency than
* an application could get by just recreating the sample externally;
* not only do they not have to reopen the RWops, reallocate buffers,
* and potentially pass the data through several rejecting decoders,
* but certain decoders will not have to recreate their existing
* state (search for metadata, etc) since they already know they
* have a valid audio stream with a given set of characteristics.
*
* The decoder is responsible for calling seek() on the associated
* SDL_RWops. A failing call to seek() should be the ONLY reason that
* this method should ever fail!
*/
int (*rewind)(Sound_Sample *sample);
/*
* Reposition the decoding to an arbitrary point. Nonzero on
* success, zero on failure.
*
* The purpose of this method is to allow for higher efficiency than
* an application could get by just rewinding the sample and
* decoding to a given point.
*
* The decoder is responsible for calling seek() on the associated
* SDL_RWops.
*
* If there is an error, try to recover so that the next read will
* continue as if nothing happened.
*/
int (*seek)(Sound_Sample *sample, Uint32 ms);
} Sound_DecoderFunctions;
/* A structure to hold a set of audio conversion filters and buffers */
#if (defined SOUND_USE_ALTCVT)
#include "alt_audio_convert.h"
#else
typedef struct Sound_AudioCVT
{
int needed; /* Set to 1 if conversion possible */
Uint16 src_format; /* Source audio format */
Uint16 dst_format; /* Target audio format */
double rate_incr; /* Rate conversion increment */
Uint8 *buf; /* Buffer to hold entire audio data */
int len; /* Length of original audio buffer */
int len_cvt; /* Length of converted audio buffer */
int len_mult; /* buffer must be len*len_mult big */
double len_ratio; /* Given len, final size is len*len_ratio */
void (*filters[20])(struct Sound_AudioCVT *cvt, Uint16 *format);
int filter_index; /* Current audio conversion function */
} Sound_AudioCVT;
#endif
extern SNDDECLSPEC int Sound_BuildAudioCVT(Sound_AudioCVT *cvt,
Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate,
Uint32 dst_size);
extern SNDDECLSPEC int Sound_ConvertAudio(Sound_AudioCVT *cvt);
typedef struct __SOUND_SAMPLEINTERNAL__
{
Sound_Sample *next;
Sound_Sample *prev;
SDL_RWops *rw;
const Sound_DecoderFunctions *funcs;
Sound_AudioCVT sdlcvt;
void *buffer;
Uint32 buffer_size;
void *decoder_private;
} Sound_SampleInternal;
/* error messages... */
#define ERR_IS_INITIALIZED "Already initialized"
#define ERR_NOT_INITIALIZED "Not initialized"
#define ERR_INVALID_ARGUMENT "Invalid argument"
#define ERR_OUT_OF_MEMORY "Out of memory"
#define ERR_NOT_SUPPORTED "Operation not supported"
#define ERR_UNSUPPORTED_FORMAT "Sound format unsupported"
#define ERR_NOT_A_HANDLE "Not a file handle"
#define ERR_NO_SUCH_FILE "No such file"
#define ERR_PAST_EOF "Past end of file"
#define ERR_IO_ERROR "I/O error"
#define ERR_COMPRESSION "(De)compression error"
#define ERR_PREV_ERROR "Previous decoding already caused an error"
#define ERR_PREV_EOF "Previous decoding already triggered EOF"
#define ERR_CANNOT_SEEK "Sample is not seekable"
/*
* Call this to set the message returned by Sound_GetError().
* Please only use the ERR_* constants above, or add new constants to the
* above group, but I want these all in one place.
*
* Calling this with a NULL argument is a safe no-op.
*/
void __Sound_SetError(const char *err);
/*
* Call this to convert milliseconds to an actual byte position, based on
* audio data characteristics.
*/
Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms);
/*
* Use this if you need a cross-platform stricmp().
*/
int __Sound_strcasecmp(const char *x, const char *y);
/* These get used all over for lessening code clutter. */
#define BAIL_MACRO(e, r) { __Sound_SetError(e); return r; }
#define BAIL_IF_MACRO(c, e, r) if (c) { __Sound_SetError(e); return r; }
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*------------ ----------------*/
/*------------ You MUST implement the following functions ----------------*/
/*------------ if porting to a new platform. ----------------*/
/*------------ (see platform/unix.c for an example) ----------------*/
/*------------ ----------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* (None, right now.) */
#ifdef __cplusplus
extern "C" {
#endif
#endif /* defined _INCLUDE_SDL_SOUND_INTERNAL_H_ */
/* end of SDL_sound_internal.h ... */

View File

@@ -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 ... */

File diff suppressed because it is too large Load Diff

View File

@@ -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_ */

View File

@@ -0,0 +1,739 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
* This file was derived from SDL's SDL_audiocvt.c and is an attempt to
* address the shortcomings of it.
*
* Perhaps we can adapt some good filters from SoX?
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#if !SOUND_USE_ALTCVT
#include "SDL.h"
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
/* Functions for audio drivers to perform runtime conversion of audio format */
/*
* Toggle endianness. This filter is, of course, only applied to 16-bit
* audio data.
*/
static void Sound_ConvertEndian(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *data, tmp;
/* SNDDBG(("Converting audio endianness\n")); */
data = cvt->buf;
for (i = cvt->len_cvt / 2; i; --i)
{
tmp = data[0];
data[0] = data[1];
data[1] = tmp;
data += 2;
} /* for */
*format = (*format ^ 0x1000);
} /* Sound_ConvertEndian */
/*
* Toggle signed/unsigned. Apparently this is done by toggling the most
* significant bit of each sample.
*/
static void Sound_ConvertSign(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *data;
/* SNDDBG(("Converting audio signedness\n")); */
data = cvt->buf;
/* 16-bit sound? */
if ((*format & 0xFF) == 16)
{
/* Little-endian? */
if ((*format & 0x1000) != 0x1000)
++data;
for (i = cvt->len_cvt / 2; i; --i)
{
*data ^= 0x80;
data += 2;
} /* for */
} /* if */
else
{
for (i = cvt->len_cvt; i; --i)
*data++ ^= 0x80;
} /* else */
*format = (*format ^ 0x8000);
} /* Sound_ConvertSign */
/*
* Convert 16-bit to 8-bit. This is done by taking the most significant byte
* of each 16-bit sample.
*/
static void Sound_Convert8(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *src, *dst;
/* SNDDBG(("Converting to 8-bit\n")); */
src = cvt->buf;
dst = cvt->buf;
/* Little-endian? */
if ((*format & 0x1000) != 0x1000)
++src;
for (i = cvt->len_cvt / 2; i; --i)
{
*dst = *src;
src += 2;
dst += 1;
} /* for */
*format = ((*format & ~0x9010) | AUDIO_U8);
cvt->len_cvt /= 2;
} /* Sound_Convert8 */
/* Convert 8-bit to 16-bit - LSB */
static void Sound_Convert16LSB(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *src, *dst;
/* SNDDBG(("Converting to 16-bit LSB\n")); */
src = cvt->buf + cvt->len_cvt;
dst = cvt->buf + cvt->len_cvt * 2;
for (i = cvt->len_cvt; i; --i)
{
src -= 1;
dst -= 2;
dst[1] = *src;
dst[0] = 0;
} /* for */
*format = ((*format & ~0x0008) | AUDIO_U16LSB);
cvt->len_cvt *= 2;
} /* Sound_Convert16LSB */
/* Convert 8-bit to 16-bit - MSB */
static void Sound_Convert16MSB(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *src, *dst;
/* SNDDBG(("Converting to 16-bit MSB\n")); */
src = cvt->buf + cvt->len_cvt;
dst = cvt->buf + cvt->len_cvt * 2;
for (i = cvt->len_cvt; i; --i)
{
src -= 1;
dst -= 2;
dst[0] = *src;
dst[1] = 0;
} /* for */
*format = ((*format & ~0x0008) | AUDIO_U16MSB);
cvt->len_cvt *= 2;
} /* Sound_Convert16MSB */
/* Duplicate a mono channel to both stereo channels */
static void Sound_ConvertStereo(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
/* SNDDBG(("Converting to stereo\n")); */
/* 16-bit sound? */
if ((*format & 0xFF) == 16)
{
Uint16 *src, *dst;
src = (Uint16 *) (cvt->buf + cvt->len_cvt);
dst = (Uint16 *) (cvt->buf + cvt->len_cvt * 2);
for (i = cvt->len_cvt/2; i; --i)
{
dst -= 2;
src -= 1;
dst[0] = src[0];
dst[1] = src[0];
} /* for */
} /* if */
else
{
Uint8 *src, *dst;
src = cvt->buf + cvt->len_cvt;
dst = cvt->buf + cvt->len_cvt * 2;
for (i = cvt->len_cvt; i; --i)
{
dst -= 2;
src -= 1;
dst[0] = src[0];
dst[1] = src[0];
} /* for */
} /* else */
cvt->len_cvt *= 2;
} /* Sound_ConvertStereo */
/* Effectively mix right and left channels into a single channel */
static void Sound_ConvertMono(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Sint32 sample;
Uint8 *u_src, *u_dst;
Sint8 *s_src, *s_dst;
/* SNDDBG(("Converting to mono\n")); */
switch (*format)
{
case AUDIO_U8:
u_src = cvt->buf;
u_dst = cvt->buf;
for (i = cvt->len_cvt / 2; i; --i)
{
sample = u_src[0] + u_src[1];
*u_dst = (sample > 255) ? 255 : sample;
u_src += 2;
u_dst += 1;
} /* for */
break;
case AUDIO_S8:
s_src = (Sint8 *) cvt->buf;
s_dst = (Sint8 *) cvt->buf;
for (i = cvt->len_cvt / 2; i; --i)
{
sample = s_src[0] + s_src[1];
if (sample > 127)
*s_dst = 127;
else if (sample < -128)
*s_dst = -128;
else
*s_dst = sample;
s_src += 2;
s_dst += 1;
} /* for */
break;
case AUDIO_U16MSB:
u_src = cvt->buf;
u_dst = cvt->buf;
for (i = cvt->len_cvt / 4; i; --i)
{
sample = (Uint16) ((u_src[0] << 8) | u_src[1])
+ (Uint16) ((u_src[2] << 8) | u_src[3]);
if (sample > 65535)
{
u_dst[0] = 0xFF;
u_dst[1] = 0xFF;
} /* if */
else
{
u_dst[1] = (sample & 0xFF);
sample >>= 8;
u_dst[0] = (sample & 0xFF);
} /* else */
u_src += 4;
u_dst += 2;
} /* for */
break;
case AUDIO_U16LSB:
u_src = cvt->buf;
u_dst = cvt->buf;
for (i = cvt->len_cvt / 4; i; --i)
{
sample = (Uint16) ((u_src[1] << 8) | u_src[0])
+ (Uint16) ((u_src[3] << 8) | u_src[2]);
if (sample > 65535)
{
u_dst[0] = 0xFF;
u_dst[1] = 0xFF;
} /* if */
else
{
u_dst[0] = (sample & 0xFF);
sample >>= 8;
u_dst[1] = (sample & 0xFF);
} /* else */
u_src += 4;
u_dst += 2;
} /* for */
break;
case AUDIO_S16MSB:
u_src = cvt->buf;
u_dst = cvt->buf;
for (i = cvt->len_cvt / 4; i; --i)
{
sample = (Sint16) ((u_src[0] << 8) | u_src[1])
+ (Sint16) ((u_src[2] << 8) | u_src[3]);
if (sample > 32767)
{
u_dst[0] = 0x7F;
u_dst[1] = 0xFF;
} /* if */
else if (sample < -32768)
{
u_dst[0] = 0x80;
u_dst[1] = 0x00;
} /* else if */
else
{
u_dst[1] = (sample & 0xFF);
sample >>= 8;
u_dst[0] = (sample & 0xFF);
} /* else */
u_src += 4;
u_dst += 2;
} /* for */
break;
case AUDIO_S16LSB:
u_src = cvt->buf;
u_dst = cvt->buf;
for (i = cvt->len_cvt / 4; i; --i)
{
sample = (Sint16) ((u_src[1] << 8) | u_src[0])
+ (Sint16) ((u_src[3] << 8) | u_src[2]);
if (sample > 32767)
{
u_dst[1] = 0x7F;
u_dst[0] = 0xFF;
} /* if */
else if (sample < -32768)
{
u_dst[1] = 0x80;
u_dst[0] = 0x00;
} /* else if */
else
{
u_dst[0] = (sample & 0xFF);
sample >>= 8;
u_dst[1] = (sample & 0xFF);
} /* else */
u_src += 4;
u_dst += 2;
} /* for */
break;
} /* switch */
cvt->len_cvt /= 2;
} /* Sound_ConvertMono */
/* Convert rate up by multiple of 2 */
static void Sound_RateMUL2(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *src, *dst;
/* SNDDBG(("Converting audio rate * 2\n")); */
src = cvt->buf + cvt->len_cvt;
dst = cvt->buf + cvt->len_cvt*2;
/* 8- or 16-bit sound? */
switch (*format & 0xFF)
{
case 8:
for (i = cvt->len_cvt; i; --i)
{
src -= 1;
dst -= 2;
dst[0] = src[0];
dst[1] = src[0];
} /* for */
break;
case 16:
for (i = cvt->len_cvt / 2; i; --i)
{
src -= 2;
dst -= 4;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[0];
dst[3] = src[1];
} /* for */
break;
} /* switch */
cvt->len_cvt *= 2;
} /* Sound_RateMUL2 */
/* Convert rate down by multiple of 2 */
static void Sound_RateDIV2(Sound_AudioCVT *cvt, Uint16 *format)
{
int i;
Uint8 *src, *dst;
/* SNDDBG(("Converting audio rate / 2\n")); */
src = cvt->buf;
dst = cvt->buf;
/* 8- or 16-bit sound? */
switch (*format & 0xFF)
{
case 8:
for (i = cvt->len_cvt / 2; i; --i)
{
dst[0] = src[0];
src += 2;
dst += 1;
} /* for */
break;
case 16:
for (i = cvt->len_cvt / 4; i; --i)
{
dst[0] = src[0];
dst[1] = src[1];
src += 4;
dst += 2;
}
break;
} /* switch */
cvt->len_cvt /= 2;
} /* Sound_RateDIV2 */
/* Very slow rate conversion routine */
static void Sound_RateSLOW(Sound_AudioCVT *cvt, Uint16 *format)
{
double ipos;
int i, clen;
Uint8 *output8;
Uint16 *output16;
/* SNDDBG(("Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr)); */
clen = (int) ((double) cvt->len_cvt / cvt->rate_incr);
if (cvt->rate_incr > 1.0)
{
/* 8- or 16-bit sound? */
switch (*format & 0xFF)
{
case 8:
output8 = cvt->buf;
ipos = 0.0;
for (i = clen; i; --i)
{
*output8 = cvt->buf[(int) ipos];
ipos += cvt->rate_incr;
output8 += 1;
} /* for */
break;
case 16:
output16 = (Uint16 *) cvt->buf;
clen &= ~1;
ipos = 0.0;
for (i = clen / 2; i; --i)
{
*output16 = ((Uint16 *) cvt->buf)[(int) ipos];
ipos += cvt->rate_incr;
output16 += 1;
} /* for */
break;
} /* switch */
} /* if */
else
{
/* 8- or 16-bit sound */
switch (*format & 0xFF)
{
case 8:
output8 = cvt->buf + clen;
ipos = (double) cvt->len_cvt;
for (i = clen; i; --i)
{
ipos -= cvt->rate_incr;
output8 -= 1;
*output8 = cvt->buf[(int) ipos];
} /* for */
break;
case 16:
clen &= ~1;
output16 = (Uint16 *) (cvt->buf + clen);
ipos = (double) cvt->len_cvt / 2;
for (i = clen / 2; i; --i)
{
ipos -= cvt->rate_incr;
output16 -= 1;
*output16 = ((Uint16 *) cvt->buf)[(int) ipos];
} /* for */
break;
} /* switch */
} /* else */
cvt->len_cvt = clen;
} /* Sound_RateSLOW */
int Sound_ConvertAudio(Sound_AudioCVT *cvt)
{
Uint16 format;
/* Make sure there's data to convert */
if (cvt->buf == NULL)
{
__Sound_SetError("No buffer allocated for conversion");
return(-1);
} /* if */
/* Return okay if no conversion is necessary */
cvt->len_cvt = cvt->len;
if (cvt->filters[0] == NULL)
return(0);
/* Set up the conversion and go! */
format = cvt->src_format;
for (cvt->filter_index = 0; cvt->filters[cvt->filter_index];
cvt->filter_index++)
{
cvt->filters[cvt->filter_index](cvt, &format);
}
return(0);
} /* Sound_ConvertAudio */
/*
* Creates a set of audio filters to convert from one format to another.
* Returns -1 if the format conversion is not supported, or 1 if the
* audio filter is set up.
*/
int Sound_BuildAudioCVT(Sound_AudioCVT *cvt,
Uint16 src_format, Uint8 src_channels, Uint32 src_rate,
Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate,
Uint32 dst_size)
{
/* Start off with no conversion necessary */
cvt->needed = 0;
cvt->filter_index = 0;
cvt->filters[0] = NULL;
cvt->len_mult = 1;
cvt->len_ratio = 1.0;
/* First filter: Endian conversion from src to dst */
if ((src_format & 0x1000) != (dst_format & 0x1000) &&
((src_format & 0xff) != 8))
{
SNDDBG(("Adding filter: Sound_ConvertEndian\n"));
cvt->filters[cvt->filter_index++] = Sound_ConvertEndian;
} /* if */
/* Second filter: Sign conversion -- signed/unsigned */
if ((src_format & 0x8000) != (dst_format & 0x8000))
{
SNDDBG(("Adding filter: Sound_ConvertSign\n"));
cvt->filters[cvt->filter_index++] = Sound_ConvertSign;
} /* if */
/* Next filter: Convert 16 bit <--> 8 bit PCM. */
if ((src_format & 0xFF) != (dst_format & 0xFF))
{
switch (dst_format & 0x10FF)
{
case AUDIO_U8:
SNDDBG(("Adding filter: Sound_Convert8\n"));
cvt->filters[cvt->filter_index++] = Sound_Convert8;
cvt->len_ratio /= 2;
break;
case AUDIO_U16LSB:
SNDDBG(("Adding filter: Sound_Convert16LSB\n"));
cvt->filters[cvt->filter_index++] = Sound_Convert16LSB;
cvt->len_mult *= 2;
cvt->len_ratio *= 2;
break;
case AUDIO_U16MSB:
SNDDBG(("Adding filter: Sound_Convert16MSB\n"));
cvt->filters[cvt->filter_index++] = Sound_Convert16MSB;
cvt->len_mult *= 2;
cvt->len_ratio *= 2;
break;
} /* switch */
} /* if */
/* Next filter: Mono/Stereo conversion */
if (src_channels != dst_channels)
{
while ((src_channels * 2) <= dst_channels)
{
SNDDBG(("Adding filter: Sound_ConvertStereo\n"));
cvt->filters[cvt->filter_index++] = Sound_ConvertStereo;
cvt->len_mult *= 2;
src_channels *= 2;
cvt->len_ratio *= 2;
} /* while */
/* This assumes that 4 channel audio is in the format:
* Left {front/back} + Right {front/back}
* so converting to L/R stereo works properly.
*/
while (((src_channels % 2) == 0) &&
((src_channels / 2) >= dst_channels))
{
SNDDBG(("Adding filter: Sound_ConvertMono\n"));
cvt->filters[cvt->filter_index++] = Sound_ConvertMono;
src_channels /= 2;
cvt->len_ratio /= 2;
} /* while */
if ( src_channels != dst_channels ) {
/* Uh oh.. */;
} /* if */
} /* if */
/* Do rate conversion */
cvt->rate_incr = 0.0;
if ((src_rate / 100) != (dst_rate / 100))
{
Uint32 hi_rate, lo_rate;
int len_mult;
double len_ratio;
void (*rate_cvt)(Sound_AudioCVT *cvt, Uint16 *format);
if (src_rate > dst_rate)
{
hi_rate = src_rate;
lo_rate = dst_rate;
SNDDBG(("Adding filter: Sound_RateDIV2\n"));
rate_cvt = Sound_RateDIV2;
len_mult = 1;
len_ratio = 0.5;
} /* if */
else
{
hi_rate = dst_rate;
lo_rate = src_rate;
SNDDBG(("Adding filter: Sound_RateMUL2\n"));
rate_cvt = Sound_RateMUL2;
len_mult = 2;
len_ratio = 2.0;
} /* else */
/* If hi_rate = lo_rate*2^x then conversion is easy */
while (((lo_rate * 2) / 100) <= (hi_rate / 100))
{
cvt->filters[cvt->filter_index++] = rate_cvt;
cvt->len_mult *= len_mult;
lo_rate *= 2;
cvt->len_ratio *= len_ratio;
} /* while */
/* We may need a slow conversion here to finish up */
if ((lo_rate / 100) != (hi_rate / 100))
{
if (src_rate < dst_rate)
{
cvt->rate_incr = (double) lo_rate / hi_rate;
cvt->len_mult *= 2;
cvt->len_ratio /= cvt->rate_incr;
} /* if */
else
{
cvt->rate_incr = (double) hi_rate / lo_rate;
cvt->len_ratio *= cvt->rate_incr;
} /* else */
SNDDBG(("Adding filter: Sound_RateSLOW\n"));
cvt->filters[cvt->filter_index++] = Sound_RateSLOW;
} /* if */
} /* if */
/* Set up the filter information */
if (cvt->filter_index != 0)
{
cvt->needed = 1;
cvt->src_format = src_format;
cvt->dst_format = dst_format;
cvt->len = 0;
cvt->buf = NULL;
cvt->filters[cvt->filter_index] = NULL;
} /* if */
return(cvt->needed);
} /* Sound_BuildAudioCVT */
#endif /* !SOUND_USE_ALTCVT */
/* end of audio_convert.c ... */

View File

@@ -0,0 +1,133 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define for debug builds. */
/* #undef DEBUG */
/* Define for debug build chattering. */
#undef DEBUG_CHATTER
/* Define to 1 if you have the <assert.h> header file. */
#define HAVE_ASSERT_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> 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 <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> 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 <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> 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 <sys/types.h> does not define. */
/*#undef size_t*/

View File

@@ -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

View File

@@ -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:

View File

@@ -0,0 +1,569 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* AIFF decoder for SDL_sound
*
* [Insert something profound about the AIFF file format here.]
*
* This code was ripped from a decoder I had written for SDL_mixer, which was
* based on SDL_mixer's old AIFF music loader. (This loader was unfortunately
* completely broken, but it was still useful because all the pieces were
* still there, so to speak.)
*
* When rewriting it for SDL_sound, I changed its structure to be more like
* the WAV loader Ryan wrote. Had they not both been part of the same project
* it would have been embarrassing how similar they are.
*
* It is not the most feature-complete AIFF loader the world has ever seen.
* For instance, it only makes a token attempt at implementing the AIFF-C
* standard; basically the parts of it that I can easily understand and test.
* It's a start, though.
*
* Please see the file COPYING in the source's root directory.
*
* This file was written by Torbjörn Andersson. (d91tan@Update.UU.SE)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_AIFF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf);
static int AIFF_init(void);
static void AIFF_quit(void);
static int AIFF_open(Sound_Sample *sample, const char *ext);
static void AIFF_close(Sound_Sample *sample);
static Uint32 AIFF_read(Sound_Sample *sample);
static int AIFF_rewind(Sound_Sample *sample);
static int AIFF_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_aiff[] = { "AIFF", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_AIFF =
{
{
extensions_aiff,
"Audio Interchange File Format",
"Torbjörn Andersson <d91tan@Update.UU.SE>",
"http://www.icculus.org/SDL_sound/"
},
AIFF_init, /* init() method */
AIFF_quit, /* quit() method */
AIFF_open, /* open() method */
AIFF_close, /* close() method */
AIFF_read, /* read() method */
AIFF_rewind, /* rewind() method */
AIFF_seek /* seek() method */
};
/*****************************************************************************
* aiff_t is what we store in our internal->decoder_private field... *
*****************************************************************************/
typedef struct S_AIFF_FMT_T
{
Uint32 type;
Uint32 total_bytes;
Uint32 data_starting_offset;
void (*free)(struct S_AIFF_FMT_T *fmt);
Uint32 (*read_sample)(Sound_Sample *sample);
int (*rewind_sample)(Sound_Sample *sample);
int (*seek_sample)(Sound_Sample *sample, Uint32 ms);
#if 0
/*
this is ripped from wav.c as ann example of format-specific data.
please replace with something more appropriate when the need arises.
*/
union
{
struct
{
Uint16 cbSize;
Uint16 wSamplesPerBlock;
Uint16 wNumCoef;
ADPCMCOEFSET *aCoeff;
} adpcm;
/* put other format-specific data here... */
} fmt;
#endif
} fmt_t;
typedef struct
{
fmt_t fmt;
Sint32 bytesLeft;
} aiff_t;
/* Chunk management code... */
#define formID 0x4D524F46 /* "FORM", in ascii. */
#define aiffID 0x46464941 /* "AIFF", in ascii. */
#define aifcID 0x43464941 /* "AIFC", in ascii. */
#define ssndID 0x444E5353 /* "SSND", in ascii. */
/*****************************************************************************
* The COMM chunk... *
*****************************************************************************/
#define commID 0x4D4D4F43 /* "COMM", in ascii. */
/* format/compression types... */
#define noneID 0x454E4F4E /* "NONE", in ascii. */
typedef struct
{
Uint32 ckID;
Uint32 ckDataSize;
Uint16 numChannels;
Uint32 numSampleFrames;
Uint16 sampleSize;
Uint32 sampleRate;
/*
* We don't handle AIFF-C compressed audio yet, but for those
* interested the allowed compression types are supposed to be
*
* compressionType compressionName meaning
* ---------------------------------------------------------------
* 'NONE' "not compressed" uncompressed, that is,
* straight digitized samples
* 'ACE2' "ACE 2-to-1" 2-to-1 IIGS ACE (Audio
* Compression / Expansion)
* 'ACE8' "ACE 8-to-3" 8-to-3 IIGS ACE (Audio
* Compression / Expansion)
* 'MAC3' "MACE 3-to-1" 3-to-1 Macintosh Audio
* Compression / Expansion
* 'MAC6' "MACE 6-to-1" 6-to-1 Macintosh Audio
* Compression / Expansion
*
* A pstring is a "Pascal-style string", that is, "one byte followed
* by test bytes followed when needed by one pad byte. The total
* number of bytes in a pstring must be even. The pad byte is
* included when the number of text bytes is even, so the total of
* text bytes + one count byte + one pad byte will be even. This pad
* byte is not reflected in the count."
*
* As for how these compression algorithms work, your guess is as
* good as mine.
*/
Uint32 compressionType;
#if 0
pstring compressionName;
#endif
} comm_t;
/*
* Read in a comm_t from disk. This makes this process safe regardless of
* the processor's byte order or how the comm_t structure is packed.
*/
static int read_comm_chunk(SDL_RWops *rw, comm_t *comm)
{
Uint8 sampleRate[10];
/* skip reading the chunk ID, since it was already read at this point... */
comm->ckID = commID;
if (SDL_RWread(rw, &comm->ckDataSize, sizeof (comm->ckDataSize), 1) != 1)
return(0);
comm->ckDataSize = SDL_SwapBE32(comm->ckDataSize);
if (SDL_RWread(rw, &comm->numChannels, sizeof (comm->numChannels), 1) != 1)
return(0);
comm->numChannels = SDL_SwapBE16(comm->numChannels);
if (SDL_RWread(rw, &comm->numSampleFrames,
sizeof (comm->numSampleFrames), 1) != 1)
return(0);
comm->numSampleFrames = SDL_SwapBE32(comm->numSampleFrames);
if (SDL_RWread(rw, &comm->sampleSize, sizeof (comm->sampleSize), 1) != 1)
return(0);
comm->sampleSize = SDL_SwapBE16(comm->sampleSize);
if (SDL_RWread(rw, sampleRate, sizeof (sampleRate), 1) != 1)
return(0);
comm->sampleRate = SANE_to_Uint32(sampleRate);
if (comm->ckDataSize > sizeof(comm->numChannels)
+ sizeof(comm->numSampleFrames)
+ sizeof(comm->sampleSize)
+ sizeof(sampleRate))
{
if (SDL_RWread(rw, &comm->compressionType,
sizeof (comm->compressionType), 1) != 1)
return(0);
comm->compressionType = SDL_SwapBE32(comm->compressionType);
} /* if */
else
{
comm->compressionType = noneID;
} /* else */
return(1);
} /* read_comm_chunk */
/*****************************************************************************
* The SSND chunk... *
*****************************************************************************/
typedef struct
{
Uint32 ckID;
Uint32 ckDataSize;
Uint32 offset;
Uint32 blockSize;
/*
* Then, comm->numSampleFrames sample frames. (It's better to get the
* length from numSampleFrames than from ckDataSize.)
*/
} ssnd_t;
static int read_ssnd_chunk(SDL_RWops *rw, ssnd_t *ssnd)
{
/* skip reading the chunk ID, since it was already read at this point... */
ssnd->ckID = ssndID;
if (SDL_RWread(rw, &ssnd->ckDataSize, sizeof (ssnd->ckDataSize), 1) != 1)
return(0);
ssnd->ckDataSize = SDL_SwapBE32(ssnd->ckDataSize);
if (SDL_RWread(rw, &ssnd->offset, sizeof (ssnd->offset), 1) != 1)
return(0);
ssnd->offset = SDL_SwapBE32(ssnd->offset);
if (SDL_RWread(rw, &ssnd->blockSize, sizeof (ssnd->blockSize), 1) != 1)
return(0);
ssnd->blockSize = SDL_SwapBE32(ssnd->blockSize);
/* Leave the SDL_RWops position indicator at the start of the samples */
if (SDL_RWseek(rw, (int) ssnd->offset, SEEK_CUR) == -1)
return(0);
return(1);
} /* read_ssnd_chunk */
/*****************************************************************************
* Normal, uncompressed aiff handler... *
*****************************************************************************/
static Uint32 read_sample_fmt_normal(Sound_Sample *sample)
{
Uint32 retval;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
aiff_t *a = (aiff_t *) internal->decoder_private;
Uint32 max = (internal->buffer_size < (Uint32) a->bytesLeft) ?
internal->buffer_size : (Uint32) a->bytesLeft;
assert(max > 0);
/*
* We don't actually do any decoding, so we read the AIFF data
* directly into the internal buffer...
*/
retval = SDL_RWread(internal->rw, internal->buffer, 1, max);
a->bytesLeft -= retval;
/* Make sure the read went smoothly... */
if ((retval == 0) || (a->bytesLeft == 0))
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else if (retval == -1)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
/* (next call this EAGAIN may turn into an EOF or error.) */
else if (retval < internal->buffer_size)
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
return(retval);
} /* read_sample_fmt_normal */
static int rewind_sample_fmt_normal(Sound_Sample *sample)
{
/* no-op. */
return(1);
} /* rewind_sample_fmt_normal */
static int seek_sample_fmt_normal(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
aiff_t *a = (aiff_t *) internal->decoder_private;
fmt_t *fmt = &a->fmt;
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
int pos = (int) (fmt->data_starting_offset + offset);
int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
a->bytesLeft = fmt->total_bytes - offset;
return(1); /* success. */
} /* seek_sample_fmt_normal */
static void free_fmt_normal(fmt_t *fmt)
{
/* it's a no-op. */
} /* free_fmt_normal */
static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt)
{
/* (don't need to read more from the RWops...) */
fmt->free = free_fmt_normal;
fmt->read_sample = read_sample_fmt_normal;
fmt->rewind_sample = rewind_sample_fmt_normal;
fmt->seek_sample = seek_sample_fmt_normal;
return(1);
} /* read_fmt_normal */
/*****************************************************************************
* Everything else... *
*****************************************************************************/
static int AIFF_init(void)
{
return(1); /* always succeeds. */
} /* AIFF_init */
static void AIFF_quit(void)
{
/* it's a no-op. */
} /* AIFF_quit */
/*
* Sample rate is encoded as an "80 bit IEEE Standard 754 floating point
* number (Standard Apple Numeric Environment [SANE] data type Extended)".
* Whose bright idea was that?
*
* This function was adapted from libsndfile, and while I do know a little
* bit about the IEEE floating point standard I don't pretend to fully
* understand this.
*/
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
{
/* Is the frequency outside of what we can represent with Uint32? */
if ( (sanebuf[0] & 0x80)
|| (sanebuf[0] <= 0x3F)
|| (sanebuf[0] > 0x40)
|| (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) )
return 0;
return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
} /* SANE_to_Uint32 */
static int find_chunk(SDL_RWops *rw, Uint32 id)
{
Sint32 siz = 0;
Uint32 _id = 0;
while (1)
{
BAIL_IF_MACRO(SDL_RWread(rw, &_id, sizeof (_id), 1) != 1, NULL, 0);
if (SDL_SwapLE32(_id) == id)
return(1);
BAIL_IF_MACRO(SDL_RWread(rw, &siz, sizeof (siz), 1) != 1, NULL, 0);
siz = SDL_SwapBE32(siz);
assert(siz > 0);
BAIL_IF_MACRO(SDL_RWseek(rw, siz, SEEK_CUR) == -1, NULL, 0);
} /* while */
return(0); /* shouldn't hit this, but just in case... */
} /* find_chunk */
static int read_fmt(SDL_RWops *rw, comm_t *c, fmt_t *fmt)
{
fmt->type = c->compressionType;
/* if it's in this switch statement, we support the format. */
switch (fmt->type)
{
case noneID:
SNDDBG(("AIFF: Appears to be uncompressed audio.\n"));
return(read_fmt_normal(rw, fmt));
/* add other types here. */
default:
SNDDBG(("AIFF: Format %lu is unknown.\n",
(unsigned int) fmt->type));
BAIL_MACRO("AIFF: Unsupported format", 0);
} /* switch */
assert(0); /* shouldn't hit this point. */
return(0);
} /* read_fmt */
static int AIFF_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *rw = internal->rw;
Uint32 chunk_id;
int bytes_per_sample;
long pos;
comm_t c;
ssnd_t s;
aiff_t *a;
BAIL_IF_MACRO(SDL_ReadLE32(rw) != formID, "AIFF: Not a FORM file.", 0);
SDL_ReadBE32(rw); /* throw the length away; we don't need it. */
chunk_id = SDL_ReadLE32(rw);
BAIL_IF_MACRO(chunk_id != aiffID && chunk_id != aifcID,
"AIFF: Not an AIFF or AIFC file.", 0);
/* Chunks may appear in any order, so we establish base camp here. */
pos = SDL_RWtell(rw);
BAIL_IF_MACRO(!find_chunk(rw, commID), "AIFF: No common chunk.", 0);
BAIL_IF_MACRO(!read_comm_chunk(rw, &c),
"AIFF: Can't read common chunk.", 0);
sample->actual.channels = (Uint8) c.numChannels;
sample->actual.rate = c.sampleRate;
if (c.sampleSize <= 8)
{
sample->actual.format = AUDIO_S8;
bytes_per_sample = c.numChannels;
} /* if */
else if (c.sampleSize <= 16)
{
sample->actual.format = AUDIO_S16MSB;
bytes_per_sample = 2 * c.numChannels;
} /* if */
else
{
BAIL_MACRO("AIFF: Unsupported sample size.", 0);
} /* else */
BAIL_IF_MACRO(c.sampleRate == 0, "AIFF: Unsupported sample rate.", 0);
a = (aiff_t *) malloc(sizeof(aiff_t));
BAIL_IF_MACRO(a == NULL, ERR_OUT_OF_MEMORY, 0);
if (!read_fmt(rw, &c, &(a->fmt)))
{
free(a);
return(0);
} /* if */
SDL_RWseek(rw, pos, SEEK_SET); /* if the seek fails, let it go... */
if (!find_chunk(rw, ssndID))
{
free(a);
BAIL_MACRO("AIFF: No sound data chunk.", 0);
} /* if */
if (!read_ssnd_chunk(rw, &s))
{
free(a);
BAIL_MACRO("AIFF: Can't read sound data chunk.", 0);
} /* if */
a->fmt.total_bytes = a->bytesLeft = bytes_per_sample * c.numSampleFrames;
a->fmt.data_starting_offset = SDL_RWtell(rw);
internal->decoder_private = (void *) a;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
SNDDBG(("AIFF: Accepting data stream.\n"));
return(1); /* we'll handle this data. */
} /* AIFF_open */
static void AIFF_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
aiff_t *a = (aiff_t *) internal->decoder_private;
a->fmt.free(&(a->fmt));
free(a);
} /* AIFF_close */
static Uint32 AIFF_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
aiff_t *a = (aiff_t *) internal->decoder_private;
return(a->fmt.read_sample(sample));
} /* AIFF_read */
static int AIFF_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
aiff_t *a = (aiff_t *) internal->decoder_private;
fmt_t *fmt = &a->fmt;
int rc = SDL_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET);
BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0);
a->bytesLeft = fmt->total_bytes;
return(fmt->rewind_sample(sample));
} /* AIFF_rewind */
static int AIFF_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
aiff_t *a = (aiff_t *) internal->decoder_private;
return(a->fmt.seek_sample(sample, ms));
} /* AIFF_seek */
#endif /* SOUND_SUPPORTS_AIFF */
/* end of aiff.c ... */

View File

@@ -0,0 +1,376 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Sun/NeXT .au decoder for SDL_sound.
* Formats supported: 8 and 16 bit linear PCM, 8 bit µ-law.
* Files without valid header are assumed to be 8 bit µ-law, 8kHz, mono.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Mattias Engdegård. (f91-men@nada.kth.se)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_AU
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int AU_init(void);
static void AU_quit(void);
static int AU_open(Sound_Sample *sample, const char *ext);
static void AU_close(Sound_Sample *sample);
static Uint32 AU_read(Sound_Sample *sample);
static int AU_rewind(Sound_Sample *sample);
static int AU_seek(Sound_Sample *sample, Uint32 ms);
/*
* Sometimes the extension ".snd" is used for these files (mostly on the NeXT),
* and the magic number comes from this. However it may clash with other
* formats and is somewhat of an anachronism, so only .au is used here.
*/
static const char *extensions_au[] = { "AU", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_AU =
{
{
extensions_au,
"Sun/NeXT audio file format",
"Mattias Engdegård <f91-men@nada.kth.se>",
"http://www.icculus.org/SDL_sound/"
},
AU_init, /* init() method */
AU_quit, /* quit() method */
AU_open, /* open() method */
AU_close, /* close() method */
AU_read, /* read() method */
AU_rewind, /* rewind() method */
AU_seek /* seek() method */
};
/* no init/deinit needed */
static int AU_init(void)
{
return(1);
} /* AU_init */
static void AU_quit(void)
{
/* no-op. */
} /* AU_quit */
struct au_file_hdr
{
Uint32 magic;
Uint32 hdr_size;
Uint32 data_size;
Uint32 encoding;
Uint32 sample_rate;
Uint32 channels;
};
#define HDR_SIZE 24
enum
{
AU_ENC_ULAW_8 = 1, /* 8-bit ISDN µ-law */
AU_ENC_LINEAR_8 = 2, /* 8-bit linear PCM */
AU_ENC_LINEAR_16 = 3, /* 16-bit linear PCM */
/* the rest are unsupported (I have never seen them in the wild) */
AU_ENC_LINEAR_24 = 4, /* 24-bit linear PCM */
AU_ENC_LINEAR_32 = 5, /* 32-bit linear PCM */
AU_ENC_FLOAT = 6, /* 32-bit IEEE floating point */
AU_ENC_DOUBLE = 7, /* 64-bit IEEE floating point */
/* more Sun formats, not supported either */
AU_ENC_ADPCM_G721 = 23,
AU_ENC_ADPCM_G722 = 24,
AU_ENC_ADPCM_G723_3 = 25,
AU_ENC_ADPCM_G723_5 = 26,
AU_ENC_ALAW_8 = 27
};
struct audec
{
Uint32 total;
Uint32 remaining;
Uint32 start_offset;
int encoding;
};
/*
* Read in the AU header from disk. This makes this process safe
* regardless of the processor's byte order or how the au_file_hdr
* structure is packed.
*/
static int read_au_header(SDL_RWops *rw, struct au_file_hdr *hdr)
{
if (SDL_RWread(rw, &hdr->magic, sizeof (hdr->magic), 1) != 1)
return(0);
hdr->magic = SDL_SwapBE32(hdr->magic);
if (SDL_RWread(rw, &hdr->hdr_size, sizeof (hdr->hdr_size), 1) != 1)
return(0);
hdr->hdr_size = SDL_SwapBE32(hdr->hdr_size);
if (SDL_RWread(rw, &hdr->data_size, sizeof (hdr->data_size), 1) != 1)
return(0);
hdr->data_size = SDL_SwapBE32(hdr->data_size);
if (SDL_RWread(rw, &hdr->encoding, sizeof (hdr->encoding), 1) != 1)
return(0);
hdr->encoding = SDL_SwapBE32(hdr->encoding);
if (SDL_RWread(rw, &hdr->sample_rate, sizeof (hdr->sample_rate), 1) != 1)
return(0);
hdr->sample_rate = SDL_SwapBE32(hdr->sample_rate);
if (SDL_RWread(rw, &hdr->channels, sizeof (hdr->channels), 1) != 1)
return(0);
hdr->channels = SDL_SwapBE32(hdr->channels);
return(1);
} /* read_au_header */
#define AU_MAGIC 0x2E736E64 /* ".snd", in ASCII (bigendian number) */
static int AU_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = sample->opaque;
SDL_RWops *rw = internal->rw;
int skip, hsize, i;
struct au_file_hdr hdr;
struct audec *dec;
char c;
/* read_au_header() will do byte order swapping. */
BAIL_IF_MACRO(!read_au_header(rw, &hdr), "AU: bad header", 0);
dec = malloc(sizeof *dec);
BAIL_IF_MACRO(dec == NULL, ERR_OUT_OF_MEMORY, 0);
internal->decoder_private = dec;
if (hdr.magic == AU_MAGIC)
{
/* valid magic */
dec->encoding = hdr.encoding;
switch(dec->encoding)
{
case AU_ENC_ULAW_8:
/* Convert 8-bit µ-law to 16-bit linear on the fly. This is
slightly wasteful if the audio driver must convert them
back, but µ-law only devices are rare (mostly _old_ Suns) */
sample->actual.format = AUDIO_S16SYS;
break;
case AU_ENC_LINEAR_8:
sample->actual.format = AUDIO_S8;
break;
case AU_ENC_LINEAR_16:
sample->actual.format = AUDIO_S16MSB;
break;
default:
free(dec);
BAIL_MACRO("AU: Unsupported .au encoding", 0);
} /* switch */
sample->actual.rate = hdr.sample_rate;
sample->actual.channels = hdr.channels;
dec->remaining = hdr.data_size;
hsize = hdr.hdr_size;
/* skip remaining part of header (input may be unseekable) */
for (i = HDR_SIZE; i < hsize; i++)
{
if (SDL_RWread(rw, &c, 1, 1) != 1)
{
free(dec);
BAIL_MACRO(ERR_IO_ERROR, 0);
} /* if */
} /* for */
} /* if */
else if (__Sound_strcasecmp(ext, "au") == 0)
{
/*
* A number of files in the wild have the .au extension but no valid
* header; these are traditionally assumed to be 8kHz µ-law. Handle
* them here only if the extension is recognized.
*/
SNDDBG(("AU: Invalid header, assuming raw 8kHz µ-law.\n"));
/* if seeking fails, we lose 24 samples. big deal */
SDL_RWseek(rw, -HDR_SIZE, SEEK_CUR);
dec->encoding = AU_ENC_ULAW_8;
dec->remaining = (Uint32)-1; /* no limit */
sample->actual.format = AUDIO_S16SYS;
sample->actual.rate = 8000;
sample->actual.channels = 1;
} /* else if */
else
{
free(dec);
BAIL_MACRO("AU: Not an .AU stream.", 0);
} /* else */
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
dec->total = dec->remaining;
dec->start_offset = SDL_RWtell(rw);
SNDDBG(("AU: Accepting data stream.\n"));
return(1);
} /* AU_open */
static void AU_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = sample->opaque;
free(internal->decoder_private);
} /* AU_close */
/* table to convert from µ-law encoding to signed 16-bit samples,
generated by a throwaway perl script */
static Sint16 ulaw_to_linear[256] = {
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
-11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-876, -844, -812, -780, -748, -716, -684, -652,
-620, -588, -556, -524, -492, -460, -428, -396,
-372, -356, -340, -324, -308, -292, -276, -260,
-244, -228, -212, -196, -180, -164, -148, -132,
-120, -112, -104, -96, -88, -80, -72, -64,
-56, -48, -40, -32, -24, -16, -8, 0,
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
876, 844, 812, 780, 748, 716, 684, 652,
620, 588, 556, 524, 492, 460, 428, 396,
372, 356, 340, 324, 308, 292, 276, 260,
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0
};
static Uint32 AU_read(Sound_Sample *sample)
{
int ret;
Sound_SampleInternal *internal = sample->opaque;
struct audec *dec = internal->decoder_private;
int maxlen;
Uint8 *buf;
maxlen = internal->buffer_size;
buf = internal->buffer;
if (dec->encoding == AU_ENC_ULAW_8)
{
/* We read µ-law samples into the second half of the buffer, so
we can expand them to 16-bit samples afterwards */
maxlen >>= 1;
buf += maxlen;
} /* if */
if (maxlen > dec->remaining)
maxlen = dec->remaining;
ret = SDL_RWread(internal->rw, buf, 1, maxlen);
if (ret == 0)
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else if (ret == -1)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
else
{
dec->remaining -= ret;
if (ret < maxlen)
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
if (dec->encoding == AU_ENC_ULAW_8)
{
int i;
Sint16 *dst = internal->buffer;
for (i = 0; i < ret; i++)
dst[i] = ulaw_to_linear[buf[i]];
ret <<= 1; /* return twice as much as read */
} /* if */
} /* else */
return(ret);
} /* AU_read */
static int AU_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
struct audec *dec = (struct audec *) internal->decoder_private;
int rc = SDL_RWseek(internal->rw, dec->start_offset, SEEK_SET);
BAIL_IF_MACRO(rc != dec->start_offset, ERR_IO_ERROR, 0);
dec->remaining = dec->total;
return(1);
} /* AU_rewind */
static int AU_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
struct audec *dec = (struct audec *) internal->decoder_private;
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
int rc;
int pos;
if (dec->encoding == AU_ENC_ULAW_8)
offset >>= 1; /* halve the byte offset for compression. */
pos = (int) (dec->start_offset + offset);
rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
dec->remaining = dec->total - offset;
return(1);
} /* AU_seek */
#endif /* SOUND_SUPPORTS_AU */

View File

@@ -0,0 +1,566 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* FLAC decoder for SDL_sound.
*
* This driver handles FLAC audio, that is to say the Free Lossless Audio
* Codec. It depends on libFLAC for decoding, which can be grabbed from:
* http://flac.sourceforge.net
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Torbjörn Andersson. (d91tan@Update.UU.SE)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_FLAC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include <FLAC/export.h>
/* FLAC 1.1.3 has FLAC_API_VERSION_CURRENT == 8 */
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
#define LEGACY_FLAC
#else
#undef LEGACY_FLAC
#endif
#ifdef LEGACY_FLAC
#include <FLAC/seekable_stream_decoder.h>
#define D_END_OF_STREAM FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM
#define d_new() FLAC__seekable_stream_decoder_new()
#define d_init(x) FLAC__seekable_stream_decoder_init(x)
#define d_process_metadata(x) FLAC__seekable_stream_decoder_process_until_end_of_metadata(x)
#define d_process_one_frame(x) FLAC__seekable_stream_decoder_process_single(x)
#define d_get_state(x) FLAC__seekable_stream_decoder_get_state(x)
#define d_finish(x) FLAC__seekable_stream_decoder_finish(x)
#define d_delete(x) FLAC__seekable_stream_decoder_delete(x)
#define d_set_read_callback(x, y) FLAC__seekable_stream_decoder_set_read_callback(x, y)
#define d_set_write_callback(x, y) FLAC__seekable_stream_decoder_set_write_callback(x, y)
#define d_set_metadata_callback(x, y) FLAC__seekable_stream_decoder_set_metadata_callback(x, y)
#define d_set_error_callback(x, y) FLAC__seekable_stream_decoder_set_error_callback(x, y)
#define d_set_client_data(x, y) FLAC__seekable_stream_decoder_set_client_data(x, y)
typedef FLAC__SeekableStreamDecoder decoder_t;
typedef FLAC__SeekableStreamDecoderReadStatus d_read_status_t;
#define D_SEEK_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK
#define D_SEEK_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
#define D_TELL_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK
#define D_TELL_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
#define D_LENGTH_STATUS_OK FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK
#define D_LENGTH_STATUS_ERROR FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
#define d_set_seek_callback(x, y) FLAC__seekable_stream_decoder_set_seek_callback(x, y)
#define d_set_tell_callback(x, y) FLAC__seekable_stream_decoder_set_tell_callback(x, y)
#define d_set_length_callback(x, y) FLAC__seekable_stream_decoder_set_length_callback(x, y)
#define d_set_eof_callback(x, y) FLAC__seekable_stream_decoder_set_eof_callback(x, y)
#define d_seek_absolute(x, y) FLAC__seekable_stream_decoder_seek_absolute(x, y)
typedef FLAC__SeekableStreamDecoderSeekStatus d_seek_status_t;
typedef FLAC__SeekableStreamDecoderTellStatus d_tell_status_t;
typedef FLAC__SeekableStreamDecoderLengthStatus d_length_status_t;
#else
#include <FLAC/stream_decoder.h>
#define D_END_OF_STREAM FLAC__STREAM_DECODER_END_OF_STREAM
#define d_new() FLAC__stream_decoder_new()
#define d_process_metadata(x) FLAC__stream_decoder_process_until_end_of_metadata(x)
#define d_process_one_frame(x) FLAC__stream_decoder_process_single(x)
#define d_get_state(x) FLAC__stream_decoder_get_state(x)
#define d_finish(x) FLAC__stream_decoder_finish(x)
#define d_delete(x) FLAC__stream_decoder_delete(x)
typedef FLAC__StreamDecoder decoder_t;
typedef FLAC__StreamDecoderReadStatus d_read_status_t;
#define D_SEEK_STATUS_OK FLAC__STREAM_DECODER_SEEK_STATUS_OK
#define D_SEEK_STATUS_ERROR FLAC__STREAM_DECODER_SEEK_STATUS_ERROR
#define D_TELL_STATUS_OK FLAC__STREAM_DECODER_TELL_STATUS_OK
#define D_TELL_STATUS_ERROR FLAC__STREAM_DECODER_TELL_STATUS_ERROR
#define D_LENGTH_STATUS_OK FLAC__STREAM_DECODER_LENGTH_STATUS_OK
#define D_LENGTH_STATUS_ERROR FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR
#define d_seek_absolute(x, y) FLAC__stream_decoder_seek_absolute(x, y)
typedef FLAC__StreamDecoderSeekStatus d_seek_status_t;
typedef FLAC__StreamDecoderTellStatus d_tell_status_t;
typedef FLAC__StreamDecoderLengthStatus d_length_status_t;
#endif
#define D_WRITE_CONTINUE FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
#define D_READ_END_OF_STREAM FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
#define D_READ_ABORT FLAC__STREAM_DECODER_READ_STATUS_ABORT
#define D_READ_CONTINUE FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
#define d_error_status_string FLAC__StreamDecoderErrorStatusString
typedef FLAC__StreamDecoderErrorStatus d_error_status_t;
typedef FLAC__StreamMetadata d_metadata_t;
typedef FLAC__StreamDecoderWriteStatus d_write_status_t;
static int FLAC_init(void);
static void FLAC_quit(void);
static int FLAC_open(Sound_Sample *sample, const char *ext);
static void FLAC_close(Sound_Sample *sample);
static Uint32 FLAC_read(Sound_Sample *sample);
static int FLAC_rewind(Sound_Sample *sample);
static int FLAC_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_flac[] = { "FLAC", "FLA", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC =
{
{
extensions_flac,
"Free Lossless Audio Codec",
"Torbjörn Andersson <d91tan@Update.UU.SE>",
"http://flac.sourceforge.net/"
},
FLAC_init, /* init() method */
FLAC_quit, /* quit() method */
FLAC_open, /* open() method */
FLAC_close, /* close() method */
FLAC_read, /* read() method */
FLAC_rewind, /* rewind() method */
FLAC_seek /* seek() method */
};
/* This is what we store in our internal->decoder_private field. */
typedef struct
{
decoder_t *decoder;
SDL_RWops *rw;
Sound_Sample *sample;
Uint32 frame_size;
Uint8 is_flac;
Uint32 stream_length;
} flac_t;
static void free_flac(flac_t *f)
{
d_finish(f->decoder);
d_delete(f->decoder);
free(f);
} /* free_flac */
#ifdef LEGACY_FLAC
static d_read_status_t read_callback(
const decoder_t *decoder, FLAC__byte buffer[],
unsigned int *bytes, void *client_data)
#else
static d_read_status_t read_callback(
const decoder_t *decoder, FLAC__byte buffer[],
size_t *bytes, void *client_data)
#endif
{
flac_t *f = (flac_t *) client_data;
Uint32 retval;
retval = SDL_RWread(f->rw, (Uint8 *) buffer, 1, *bytes);
if (retval == 0)
{
*bytes = 0;
f->sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(D_READ_END_OF_STREAM);
} /* if */
if (retval == -1)
{
*bytes = 0;
f->sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(D_READ_ABORT);
} /* if */
if (retval < *bytes)
{
*bytes = retval;
f->sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
} /* if */
return(D_READ_CONTINUE);
} /* read_callback */
static d_write_status_t write_callback(
const decoder_t *decoder, const FLAC__Frame *frame,
const FLAC__int32 * const buffer[],
void *client_data)
{
flac_t *f = (flac_t *) client_data;
Uint32 i, j;
Uint32 sample;
Uint8 *dst;
f->frame_size = frame->header.channels * frame->header.blocksize
* frame->header.bits_per_sample / 8;
if (f->frame_size > f->sample->buffer_size)
Sound_SetBufferSize(f->sample, f->frame_size);
dst = f->sample->buffer;
/* If the sample is neither exactly 8-bit nor 16-bit, it will have to
* be converted. Unfortunately the buffer is read-only, so we either
* have to check for each sample, or make a copy of the buffer. I'm
* not sure which way is best, so I've arbitrarily picked the former.
*/
if (f->sample->actual.format == AUDIO_S8)
{
for (i = 0; i < frame->header.blocksize; i++)
for (j = 0; j < frame->header.channels; j++)
{
sample = buffer[j][i];
if (frame->header.bits_per_sample < 8)
sample <<= (8 - frame->header.bits_per_sample);
*dst++ = sample & 0x00ff;
} /* for */
} /* if */
else
{
for (i = 0; i < frame->header.blocksize; i++)
for (j = 0; j < frame->header.channels; j++)
{
sample = buffer[j][i];
if (frame->header.bits_per_sample < 16)
sample <<= (16 - frame->header.bits_per_sample);
else if (frame->header.bits_per_sample > 16)
sample >>= (frame->header.bits_per_sample - 16);
*dst++ = (sample & 0xff00) >> 8;
*dst++ = sample & 0x00ff;
} /* for */
} /* else */
return(D_WRITE_CONTINUE);
} /* write_callback */
static void metadata_callback(
const decoder_t *decoder,
const d_metadata_t *metadata,
void *client_data)
{
flac_t *f = (flac_t *) client_data;
SNDDBG(("FLAC: Metadata callback.\n"));
/* There are several kinds of metadata, but STREAMINFO is the only
* one that always has to be there.
*/
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
{
SNDDBG(("FLAC: Metadata is streaminfo.\n"));
f->is_flac = 1;
f->sample->actual.channels = metadata->data.stream_info.channels;
f->sample->actual.rate = metadata->data.stream_info.sample_rate;
if (metadata->data.stream_info.bits_per_sample > 8)
f->sample->actual.format = AUDIO_S16MSB;
else
f->sample->actual.format = AUDIO_S8;
} /* if */
} /* metadata_callback */
static void error_callback(
const decoder_t *decoder,
d_error_status_t status,
void *client_data)
{
flac_t *f = (flac_t *) client_data;
__Sound_SetError(d_error_status_string[status]);
f->sample->flags |= SOUND_SAMPLEFLAG_ERROR;
} /* error_callback */
static d_seek_status_t seek_callback(
const decoder_t *decoder,
FLAC__uint64 absolute_byte_offset,
void *client_data)
{
flac_t *f = (flac_t *) client_data;
if (SDL_RWseek(f->rw, absolute_byte_offset, SEEK_SET) >= 0)
{
return(D_SEEK_STATUS_OK);
} /* if */
return(D_SEEK_STATUS_ERROR);
} /* seek_callback*/
static d_tell_status_t tell_callback(
const decoder_t *decoder,
FLAC__uint64 *absolute_byte_offset,
void *client_data)
{
flac_t *f = (flac_t *) client_data;
int pos;
pos = SDL_RWtell(f->rw);
if (pos < 0)
{
return(D_TELL_STATUS_ERROR);
} /* if */
*absolute_byte_offset = pos;
return(D_TELL_STATUS_OK);
} /* tell_callback */
static d_length_status_t length_callback(
const decoder_t *decoder,
FLAC__uint64 *stream_length,
void *client_data)
{
flac_t *f = (flac_t *) client_data;
if (f->sample->flags & SOUND_SAMPLEFLAG_CANSEEK)
{
*stream_length = f->stream_length;
return(D_LENGTH_STATUS_OK);
} /* if */
return(D_LENGTH_STATUS_ERROR);
} /* length_callback */
static FLAC__bool eof_callback(
const decoder_t *decoder,
void *client_data)
{
flac_t *f = (flac_t *) client_data;
int pos;
/* Maybe we could check for SOUND_SAMPLEFLAG_EOF here instead? */
pos = SDL_RWtell(f->rw);
if (pos >= 0 && pos >= f->stream_length)
{
return(true);
} /* if */
return(false);
} /* eof_callback */
static int FLAC_init(void)
{
return(1); /* always succeeds. */
} /* FLAC_init */
static void FLAC_quit(void)
{
/* it's a no-op. */
} /* FLAC_quit */
#define FLAC_MAGIC 0x43614C66 /* "fLaC" in ASCII. */
static int FLAC_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *rw = internal->rw;
decoder_t *decoder;
flac_t *f;
int i;
int has_extension = 0;
Uint32 pos;
/*
* If the extension is "flac", we'll believe that this is really meant
* to be a FLAC stream, and will try to grok it from existing metadata.
* metadata searching can be a very expensive operation, however, so
* unless the user swears that it is a FLAC stream through the extension,
* we decide what to do based on the existance of a 32-bit magic number.
*/
for (i = 0; extensions_flac[i] != NULL; i++)
{
if (__Sound_strcasecmp(ext, extensions_flac[i]) == 0)
{
has_extension = 1;
break;
} /* if */
} /* for */
if (!has_extension)
{
int rc;
Uint32 flac_magic = SDL_ReadLE32(rw);
BAIL_IF_MACRO(flac_magic != FLAC_MAGIC, "FLAC: Not a FLAC stream.", 0);
/* move back over magic number for metadata scan... */
rc = SDL_RWseek(internal->rw, -sizeof (flac_magic), SEEK_CUR);
BAIL_IF_MACRO(rc < 0, ERR_IO_ERROR, 0);
} /* if */
f = (flac_t *) malloc(sizeof (flac_t));
BAIL_IF_MACRO(f == NULL, ERR_OUT_OF_MEMORY, 0);
decoder = d_new();
if (decoder == NULL)
{
free(f);
BAIL_MACRO(ERR_OUT_OF_MEMORY, 0);
} /* if */
#ifdef LEGACY_FLAC
d_set_read_callback(decoder, read_callback);
d_set_write_callback(decoder, write_callback);
d_set_metadata_callback(decoder, metadata_callback);
d_set_error_callback(decoder, error_callback);
d_set_seek_callback(decoder, seek_callback);
d_set_tell_callback(decoder, tell_callback);
d_set_length_callback(decoder, length_callback);
d_set_eof_callback(decoder, eof_callback);
d_set_client_data(decoder, f);
#endif
f->rw = internal->rw;
f->sample = sample;
f->decoder = decoder;
f->sample->actual.format = 0;
f->is_flac = 0 /* !!! FIXME: should be "has_extension", not "0". */;
internal->decoder_private = f;
/* really should check the init return value here: */
#ifdef LEGACY_FLAC
d_init(decoder);
#else
FLAC__stream_decoder_init_stream(decoder, read_callback, seek_callback,
tell_callback, length_callback,
eof_callback, write_callback,
metadata_callback, error_callback, f);
#endif
sample->flags = SOUND_SAMPLEFLAG_NONE;
pos = SDL_RWtell(f->rw);
if (SDL_RWseek(f->rw, 0, SEEK_END) > 0)
{
f->stream_length = SDL_RWtell(f->rw);
if (SDL_RWseek(f->rw, pos, SEEK_SET) == -1)
{
free_flac(f);
BAIL_MACRO(ERR_IO_ERROR, 0);
} /* if */
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
} /* if */
/*
* If we are not sure this is a FLAC stream, check for the STREAMINFO
* metadata block. If not, we'd have to peek at the first audio frame
* and get the sound format from there, but that is not yet
* implemented.
*/
if (!f->is_flac)
{
d_process_metadata(decoder);
/* Still not FLAC? Give up. */
if (!f->is_flac)
{
free_flac(f);
BAIL_MACRO("FLAC: No metadata found. Not a FLAC stream?", 0);
} /* if */
} /* if */
SNDDBG(("FLAC: Accepting data stream.\n"));
return(1);
} /* FLAC_open */
static void FLAC_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
flac_t *f = (flac_t *) internal->decoder_private;
free_flac(f);
} /* FLAC_close */
static Uint32 FLAC_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
flac_t *f = (flac_t *) internal->decoder_private;
Uint32 len;
if (!d_process_one_frame(f->decoder))
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
BAIL_MACRO("FLAC: Couldn't decode frame.", 0);
} /* if */
if (d_get_state(f->decoder) == D_END_OF_STREAM)
{
sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(0);
} /* if */
/* An error may have been signalled through the error callback. */
if (sample->flags & SOUND_SAMPLEFLAG_ERROR)
return(0);
return(f->frame_size);
} /* FLAC_read */
static int FLAC_rewind(Sound_Sample *sample)
{
return FLAC_seek(sample, 0);
} /* FLAC_rewind */
static int FLAC_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
flac_t *f = (flac_t *) internal->decoder_private;
d_seek_absolute(f->decoder, (ms * sample->actual.rate) / 1000);
return(1);
} /* FLAC_seek */
#endif /* SOUND_SUPPORTS_FLAC */
/* end of flac.c ... */

View File

@@ -0,0 +1,175 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* MIDI decoder for SDL_sound.
*
* This driver handles MIDI data through a stripped-down version of TiMidity.
* See the documentation in the timidity subdirectory.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Torbjörn Andersson. (d91tan@Update.UU.SE)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_MIDI
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
static int MIDI_init(void);
static void MIDI_quit(void);
static int MIDI_open(Sound_Sample *sample, const char *ext);
static void MIDI_close(Sound_Sample *sample);
static Uint32 MIDI_read(Sound_Sample *sample);
static int MIDI_rewind(Sound_Sample *sample);
static int MIDI_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_midi[] = { "MIDI", "MID", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_MIDI =
{
{
extensions_midi,
"MIDI decoder, using a subset of TiMidity",
"Torbjörn Andersson <d91tan@Update.UU.SE>",
"http://www.icculus.org/SDL_sound/"
},
MIDI_init, /* init() method */
MIDI_quit, /* quit() method */
MIDI_open, /* open() method */
MIDI_close, /* close() method */
MIDI_read, /* read() method */
MIDI_rewind, /* rewind() method */
MIDI_seek /* seek() method */
};
static int MIDI_init(void)
{
BAIL_IF_MACRO(Timidity_Init() < 0, "MIDI: Could not initialise", 0);
return(1);
} /* MIDI_init */
static void MIDI_quit(void)
{
Timidity_Exit();
} /* MIDI_quit */
static int MIDI_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *rw = internal->rw;
SDL_AudioSpec spec;
MidiSong *song;
spec.channels = 2;
spec.format = AUDIO_S16SYS;
spec.freq = 44100;
spec.samples = 4096;
song = Timidity_LoadSong(rw, &spec);
BAIL_IF_MACRO(song == NULL, "MIDI: Not a MIDI file.", 0);
Timidity_SetVolume(song, 100);
Timidity_Start(song);
SNDDBG(("MIDI: Accepting data stream.\n"));
internal->decoder_private = (void *) song;
sample->actual.channels = 2;
sample->actual.rate = 44100;
sample->actual.format = AUDIO_S16SYS;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
return(1); /* we'll handle this data. */
} /* MIDI_open */
static void MIDI_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MidiSong *song = (MidiSong *) internal->decoder_private;
Timidity_FreeSong(song);
} /* MIDI_close */
static Uint32 MIDI_read(Sound_Sample *sample)
{
Uint32 retval;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MidiSong *song = (MidiSong *) internal->decoder_private;
retval = Timidity_PlaySome(song, internal->buffer, internal->buffer_size);
/* Make sure the read went smoothly... */
if (retval == 0)
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else if (retval == -1)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
/* (next call this EAGAIN may turn into an EOF or error.) */
else if (retval < internal->buffer_size)
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
return(retval);
} /* MIDI_read */
static int MIDI_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MidiSong *song = (MidiSong *) internal->decoder_private;
Timidity_Start(song);
return(1);
} /* MIDI_rewind */
static int MIDI_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MidiSong *song = (MidiSong *) internal->decoder_private;
Timidity_Seek(song, ms);
return(1);
} /* MIDI_seek */
#endif /* SOUND_SUPPORTS_MIDI */
/* end of midi.c ... */

View File

@@ -0,0 +1,344 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Module player for SDL_sound. This driver handles anything MikMod does, and
* is based on SDL_mixer.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Torbjörn Andersson (d91tan@Update.UU.SE)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_MIKMOD
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "mikmod.h"
static int MIKMOD_init(void);
static void MIKMOD_quit(void);
static int MIKMOD_open(Sound_Sample *sample, const char *ext);
static void MIKMOD_close(Sound_Sample *sample);
static Uint32 MIKMOD_read(Sound_Sample *sample);
static int MIKMOD_rewind(Sound_Sample *sample);
static int MIKMOD_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_mikmod[] =
{
"669", /* Composer 669 */
"AMF", /* DMP Advanced Module Format */
"DSM", /* DSIK internal format */
"FAR", /* Farandole module */
"GDM", /* General DigiMusic module */
"IMF", /* Imago Orpheus module */
"IT", /* Impulse tracker */
"M15", /* 15 instrument MOD / Ultimate Sound Tracker (old M15 format) */
"MED", /* Amiga MED module */
"MOD", /* Generic MOD (Protracker, StarTracker, FastTracker, etc) */
"MTM", /* MTM module */
"OKT", /* Oktalyzer module */
"S3M", /* Screamtracker module */
"STM", /* Screamtracker 2 module */
"STX", /* STMIK 0.2 module */
"ULT", /* Ultratracker module */
"UNI", /* UNIMOD - libmikmod's and APlayer's internal module format */
"XM", /* Fasttracker module */
NULL
};
const Sound_DecoderFunctions __Sound_DecoderFunctions_MIKMOD =
{
{
extensions_mikmod,
"Play modules through MikMod",
"Torbjörn Andersson <d91tan@Update.UU.SE>",
"http://mikmod.raphnet.net/"
},
MIKMOD_init, /* init() method */
MIKMOD_quit, /* quit() method */
MIKMOD_open, /* open() method */
MIKMOD_close, /* close() method */
MIKMOD_read, /* read() method */
MIKMOD_rewind, /* rewind() method */
MIKMOD_seek /* seek() method */
};
/* Make MikMod read from a RWops... */
typedef struct MRWOPSREADER {
MREADER core;
Sound_Sample *sample;
int end;
} MRWOPSREADER;
static BOOL _mm_RWopsReader_eof(MREADER *reader)
{
MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
Sound_Sample *sample = rwops_reader->sample;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
int pos = SDL_RWtell(internal->rw);
if (rwops_reader->end == pos)
return(1);
return(0);
} /* _mm_RWopsReader_eof */
static BOOL _mm_RWopsReader_read(MREADER *reader, void *ptr, size_t size)
{
MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
Sound_Sample *sample = rwops_reader->sample;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
return(SDL_RWread(internal->rw, ptr, size, 1));
} /* _mm_RWopsReader_Read */
static int _mm_RWopsReader_get(MREADER *reader)
{
char buf;
MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
Sound_Sample *sample = rwops_reader->sample;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
if (SDL_RWread(internal->rw, &buf, 1, 1) != 1)
return(EOF);
return((int) buf);
} /* _mm_RWopsReader_get */
static BOOL _mm_RWopsReader_seek(MREADER *reader, long offset, int whence)
{
MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
Sound_Sample *sample = rwops_reader->sample;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
return(SDL_RWseek(internal->rw, offset, whence));
} /* _mm_RWopsReader_seek */
static long _mm_RWopsReader_tell(MREADER *reader)
{
MRWOPSREADER *rwops_reader = (MRWOPSREADER *) reader;
Sound_Sample *sample = rwops_reader->sample;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
return(SDL_RWtell(internal->rw));
} /* _mm_RWopsReader_tell */
static MREADER *_mm_new_rwops_reader(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MRWOPSREADER *reader = (MRWOPSREADER *) malloc(sizeof (MRWOPSREADER));
if (reader != NULL)
{
int failed_seek = 1;
int here;
reader->core.Eof = _mm_RWopsReader_eof;
reader->core.Read = _mm_RWopsReader_read;
reader->core.Get = _mm_RWopsReader_get;
reader->core.Seek = _mm_RWopsReader_seek;
reader->core.Tell = _mm_RWopsReader_tell;
reader->sample = sample;
/* RWops does not explicitly support an eof check, so we shall find
the end manually - this requires seek support for the RWop */
here = SDL_RWtell(internal->rw);
if (here != -1)
{
reader->end = SDL_RWseek(internal->rw, 0, SEEK_END);
if (reader->end != -1)
{
/* Move back */
if (SDL_RWseek(internal->rw, here, SEEK_SET) != -1)
failed_seek = 0;
} /* if */
} /* if */
if (failed_seek)
{
free(reader);
reader = NULL;
} /* if */
} /* if */
return((MREADER *) reader);
} /* _mm_new_rwops_reader */
static void _mm_delete_rwops_reader(MREADER *reader)
{
/* SDL_sound will delete the RWops and sample at a higher level... */
if (reader != NULL)
free(reader);
} /* _mm_delete_rwops_reader */
static int MIKMOD_init(void)
{
MikMod_RegisterDriver(&drv_nos);
/* Quick and dirty hack to prevent an infinite loop problem
* found when using SDL_mixer and SDL_sound together and
* both have MikMod compiled in. So, check to see if
* MikMod has already been registered first before calling
* RegisterAllLoaders()
*/
if(MikMod_InfoLoader() == NULL)
{
MikMod_RegisterAllLoaders();
}
/*
* Both DMODE_SOFT_MUSIC and DMODE_16BITS should be set by default,
* so this is just for clarity. I haven't experimented with any of
* the other flags. There are a few which are said to give better
* sound quality.
*/
md_mode |= (DMODE_SOFT_MUSIC | DMODE_16BITS);
md_mixfreq = 0;
md_reverb = 1;
BAIL_IF_MACRO(MikMod_Init(""), MikMod_strerror(MikMod_errno), 0);
return(1); /* success. */
} /* MIKMOD_init */
static void MIKMOD_quit(void)
{
MikMod_Exit();
md_mixfreq = 0;
} /* MIKMOD_quit */
static int MIKMOD_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MREADER *reader;
MODULE *module;
reader = _mm_new_rwops_reader(sample);
BAIL_IF_MACRO(reader == NULL, ERR_OUT_OF_MEMORY, 0);
module = Player_LoadGeneric(reader, 64, 0);
_mm_delete_rwops_reader(reader);
BAIL_IF_MACRO(module == NULL, "MIKMOD: Not a module file.", 0);
module->extspd = 1;
module->panflag = 1;
module->wrap = 0;
module->loop = 0;
if (md_mixfreq == 0)
md_mixfreq = (!sample->desired.rate) ? 44100 : sample->desired.rate;
sample->actual.channels = 2;
sample->actual.rate = md_mixfreq;
sample->actual.format = AUDIO_S16SYS;
internal->decoder_private = (void *) module;
Player_Start(module);
Player_SetPosition(0);
sample->flags = SOUND_SAMPLEFLAG_NONE;
SNDDBG(("MIKMOD: Name: %s\n", module->songname));
SNDDBG(("MIKMOD: Type: %s\n", module->modtype));
SNDDBG(("MIKMOD: Accepting data stream\n"));
return(1); /* we'll handle this data. */
} /* MIKMOD_open */
static void MIKMOD_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MODULE *module = (MODULE *) internal->decoder_private;
Player_Free(module);
} /* MIKMOD_close */
static Uint32 MIKMOD_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MODULE *module = (MODULE *) internal->decoder_private;
/* Switch to the current module, stopping any previous one. */
Player_Start(module);
if (!Player_Active())
{
sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(0);
} /* if */
return((Uint32) VC_WriteBytes(internal->buffer, internal->buffer_size));
} /* MIKMOD_read */
static int MIKMOD_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MODULE *module = (MODULE *) internal->decoder_private;
Player_Start(module);
Player_SetPosition(0);
return(1);
} /* MIKMOD_rewind */
static int MIKMOD_seek(Sound_Sample *sample, Uint32 ms)
{
#if 0
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
MODULE *module = (MODULE *) internal->decoder_private;
/*
* Heaven may know what the argument to Player_SetPosition() is.
* I, however, haven't the faintest idea.
*/
Player_Start(module);
Player_SetPosition(ms);
return(1);
#else
BAIL_MACRO("MIKMOD: Seeking not implemented", 0);
#endif
} /* MIKMOD_seek */
#endif /* SOUND_SUPPORTS_MIKMOD */
/* end of mikmod.c ... */

View File

@@ -0,0 +1,340 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Module player for SDL_sound. This driver handles anything that ModPlug does.
*
* ModPlug can be found at http://sourceforge.net/projects/modplug-xmms
*
* An unofficial version of modplug with all C++ dependencies removed is also
* available: http://freecraft.net/snapshots/
* (Look for something like "libmodplug-johns-*.tar.gz")
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Torbjörn Andersson (d91tan@Update.UU.SE)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_MODPLUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#if SOUND_MODPLUG_IN_OWN_PATH
#include "libmodplug/modplug.h"
#else
#include "modplug.h"
#endif
static int MODPLUG_init(void);
static void MODPLUG_quit(void);
static int MODPLUG_open(Sound_Sample *sample, const char *ext);
static void MODPLUG_close(Sound_Sample *sample);
static Uint32 MODPLUG_read(Sound_Sample *sample);
static int MODPLUG_rewind(Sound_Sample *sample);
static int MODPLUG_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_modplug[] =
{
/* The XMMS plugin is apparently able to load compressed modules as
* well, but libmodplug does not handle this.
*/
"669", /* Composer 669 / UNIS 669 module */
"AMF", /* ASYLUM Music Format / Advanced Music Format(DSM) */
"AMS", /* AMS module */
"DBM", /* DigiBooster Pro Module */
"DMF", /* DMF DELUSION DIGITAL MUSIC FILEFORMAT (X-Tracker) */
"DSM", /* DSIK Internal Format module */
"FAR", /* Farandole module */
"IT", /* Impulse Tracker IT file */
"MDL", /* DigiTracker module */
#if 0
"J2B", /* Not implemented? What is it anyway? */
#endif
"MED", /* OctaMed MED file */
"MOD", /* ProTracker / NoiseTracker MOD/NST file */
"MT2", /* MadTracker 2.0 */
"MTM", /* MTM file */
"OKT", /* Oktalyzer module */
"PTM", /* PTM PolyTracker module */
"PSM", /* PSM module */
"S3M", /* ScreamTracker file */
"STM", /* ST 2.xx */
"ULT",
"UMX",
"XM", /* FastTracker II */
NULL
};
const Sound_DecoderFunctions __Sound_DecoderFunctions_MODPLUG =
{
{
extensions_modplug,
"Play modules through ModPlug",
"Torbjörn Andersson <d91tan@Update.UU.SE>",
"http://modplug-xmms.sourceforge.net/"
},
MODPLUG_init, /* init() method */
MODPLUG_quit, /* quit() method */
MODPLUG_open, /* open() method */
MODPLUG_close, /* close() method */
MODPLUG_read, /* read() method */
MODPLUG_rewind, /* rewind() method */
MODPLUG_seek /* seek() method */
};
static ModPlug_Settings settings;
static Sound_AudioInfo current_audioinfo;
static unsigned int total_mods_decoding = 0;
static SDL_mutex *modplug_mutex = NULL;
static int MODPLUG_init(void)
{
assert(modplug_mutex == NULL);
/*
* The settings will require some experimenting. I've borrowed some
* of them from the XMMS ModPlug plugin.
*/
settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING;
#ifndef _WIN32_WCE
settings.mFlags |= MODPLUG_ENABLE_NOISE_REDUCTION |
MODPLUG_ENABLE_REVERB |
MODPLUG_ENABLE_MEGABASS |
MODPLUG_ENABLE_SURROUND;
settings.mReverbDepth = 30;
settings.mReverbDelay = 100;
settings.mBassAmount = 40;
settings.mBassRange = 30;
settings.mSurroundDepth = 20;
settings.mSurroundDelay = 20;
#endif
settings.mChannels = 2;
settings.mBits = 16;
settings.mFrequency = 44100;
settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
settings.mLoopCount = 0;
current_audioinfo.channels = 2;
current_audioinfo.rate = 44100;
current_audioinfo.format = AUDIO_S16SYS;
total_mods_decoding = 0;
modplug_mutex = SDL_CreateMutex();
ModPlug_SetSettings(&settings);
return(1); /* success. */
} /* MODPLUG_init */
static void MODPLUG_quit(void)
{
assert(total_mods_decoding == 0);
if (modplug_mutex != NULL)
{
SDL_DestroyMutex(modplug_mutex);
modplug_mutex = NULL;
} /* if */
} /* MODPLUG_quit */
/*
* Most MOD files I've seen have tended to be a few hundred KB, even if some
* of them were much smaller than that.
*/
#define CHUNK_SIZE 65536
static int MODPLUG_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
ModPlugFile *module;
Uint8 *data;
size_t size;
Uint32 retval;
int has_extension = 0;
int i;
/*
* Apparently ModPlug's loaders are too forgiving. They gladly accept
* streams that they shouldn't. For now, rely on file extension instead.
*/
for (i = 0; extensions_modplug[i] != NULL; i++)
{
if (__Sound_strcasecmp(ext, extensions_modplug[i]) == 0)
{
has_extension = 1;
break;
} /* if */
} /* for */
if (!has_extension)
{
SNDDBG(("MODPLUG: Unrecognized file type: %s\n", ext));
BAIL_MACRO("MODPLUG: Not a module file.", 0);
} /* if */
/*
* ModPlug needs the entire stream in one big chunk. I don't like it,
* but I don't think there's any way around it.
*/
data = (Uint8 *) malloc(CHUNK_SIZE);
BAIL_IF_MACRO(data == NULL, ERR_OUT_OF_MEMORY, 0);
size = 0;
do
{
retval = SDL_RWread(internal->rw, &data[size], 1, CHUNK_SIZE);
size += retval;
if (retval == CHUNK_SIZE)
{
data = (Uint8 *) realloc(data, size + CHUNK_SIZE);
BAIL_IF_MACRO(data == NULL, ERR_OUT_OF_MEMORY, 0);
} /* if */
} while (retval > 0);
/*
* It's only safe to change these settings when there're
* no other mods being decoded...
*/
if (modplug_mutex != NULL)
SDL_LockMutex(modplug_mutex);
if (total_mods_decoding > 0)
{
/* other mods decoding: use the same settings they are. */
memcpy(&sample->actual, &current_audioinfo, sizeof (Sound_AudioInfo));
} /* if */
else
{
/* no other mods decoding: define the new ModPlug output settings. */
memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo));
if (sample->actual.rate == 0)
sample->actual.rate = 44100;
if (sample->actual.channels == 0)
sample->actual.channels = 2;
if (sample->actual.format == 0)
sample->actual.format = AUDIO_S16SYS;
memcpy(&current_audioinfo, &sample->actual, sizeof (Sound_AudioInfo));
settings.mChannels=sample->actual.channels;
settings.mFrequency=sample->actual.rate;
settings.mBits = sample->actual.format & 0xFF;
ModPlug_SetSettings(&settings);
} /* else */
/*
* The buffer may be a bit too large, but that doesn't matter. I think
* it's safe to free it as soon as ModPlug_Load() is finished anyway.
*/
module = ModPlug_Load((void *) data, size);
free(data);
if (module == NULL)
{
if (modplug_mutex != NULL)
SDL_UnlockMutex(modplug_mutex);
BAIL_MACRO("MODPLUG: Not a module file.", 0);
} /* if */
total_mods_decoding++;
if (modplug_mutex != NULL)
SDL_UnlockMutex(modplug_mutex);
SNDDBG(("MODPLUG: [%d ms] %s\n",
ModPlug_GetLength(module), ModPlug_GetName(module)));
internal->decoder_private = (void *) module;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
SNDDBG(("MODPLUG: Accepting data stream\n"));
return(1); /* we'll handle this data. */
} /* MODPLUG_open */
static void MODPLUG_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
if (modplug_mutex != NULL)
SDL_LockMutex(modplug_mutex);
total_mods_decoding--;
if (modplug_mutex != NULL)
SDL_UnlockMutex(modplug_mutex);
ModPlug_Unload(module);
} /* MODPLUG_close */
static Uint32 MODPLUG_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
int retval;
retval = ModPlug_Read(module, internal->buffer, internal->buffer_size);
if (retval == 0)
sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(retval);
} /* MODPLUG_read */
static int MODPLUG_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
ModPlug_Seek(module, 0);
return(1);
} /* MODPLUG_rewind */
static int MODPLUG_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
ModPlugFile *module = (ModPlugFile *) internal->decoder_private;
/* Assume that this will work. */
ModPlug_Seek(module, ms);
return(1);
} /* MODPLUG_seek */
#endif /* SOUND_SUPPORTS_MODPLUG */
/* end of modplug.c ... */

View File

@@ -0,0 +1,298 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* MPGLIB decoder for SDL_sound. This is a very lightweight MP3 decoder,
* which is included with the SDL_sound source, so that it doesn't rely on
* unnecessary external libraries.
*
* The SMPEG decoder plays back more forms of MPEGs, and may behave better or
* worse under various conditions. mpglib is (apparently) more efficient than
* SMPEG, and, again, doesn't need an external library. You should test both
* decoders and use what you find works best for you.
*
* mpglib is an LGPL'd portion of mpg123, which can be found in its original
* form at: http://www.mpg123.de/
*
* Please see the file COPYING in the source's root directory. The included
* source code for mpglib falls under the LGPL, which is the same license as
* SDL_sound (so you can consider it a single work).
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_MPGLIB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mpglib/mpg123_sdlsound.h"
#include "mpglib/mpglib_sdlsound.h"
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int MPGLIB_init(void);
static void MPGLIB_quit(void);
static int MPGLIB_open(Sound_Sample *sample, const char *ext);
static void MPGLIB_close(Sound_Sample *sample);
static Uint32 MPGLIB_read(Sound_Sample *sample);
static int MPGLIB_rewind(Sound_Sample *sample);
static int MPGLIB_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_mpglib[] = { "MP3", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_MPGLIB =
{
{
extensions_mpglib,
"MP3 decoding via internal mpglib",
"Ryan C. Gordon <icculus@icculus.org>",
"http://www.icculus.org/SDL_sound/"
},
MPGLIB_init, /* init() method */
MPGLIB_quit, /* quit() method */
MPGLIB_open, /* open() method */
MPGLIB_close, /* close() method */
MPGLIB_read, /* read() method */
MPGLIB_rewind, /* rewind() method */
MPGLIB_seek /* seek() method */
};
/* this is what we store in our internal->decoder_private field... */
typedef struct
{
struct mpstr mp;
Uint8 inbuf[16384];
Uint8 outbuf[8192];
int outleft;
int outpos;
} mpglib_t;
static int MPGLIB_init(void)
{
return(1); /* always succeeds. */
} /* MPGLIB_init */
static void MPGLIB_quit(void)
{
/* it's a no-op. */
} /* MPGLIB_quit */
static int MPGLIB_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
mpglib_t *mpg = NULL;
int rc;
/*
* If I understand things correctly, MP3 files don't really have any
* magic header we can check for. The MP3 player is expected to just
* pick the first thing that looks like a valid frame and start
* playing from there.
*
* So here's what we do: If the caller insists that this is really
* MP3 we'll take his word for it. Otherwise, use the same test as
* SDL_mixer does and check if the stream starts with something that
* looks like a frame.
*
* A frame begins with 11 bits of frame sync (all bits must be set),
* followed by a two-bit MPEG Audio version ID:
*
* 00 - MPEG Version 2.5 (later extension of MPEG 2)
* 01 - reserved
* 10 - MPEG Version 2 (ISO/IEC 13818-3)
* 11 - MPEG Version 1 (ISO/IEC 11172-3)
*
* Apparently we don't handle MPEG Version 2.5.
*/
if (__Sound_strcasecmp(ext, "MP3") != 0)
{
Uint8 mp3_magic[2];
if (SDL_RWread(internal->rw, mp3_magic, sizeof (mp3_magic), 1) != 1)
BAIL_MACRO("MPGLIB: Could not read MP3 magic.", 0);
if (mp3_magic[0] != 0xFF || (mp3_magic[1] & 0xF0) != 0xF0)
BAIL_MACRO("MPGLIB: Not an MP3 stream.", 0);
/* If the seek fails, we'll probably miss a frame, but oh well. */
SDL_RWseek(internal->rw, -sizeof (mp3_magic), SEEK_CUR);
} /* if */
mpg = (mpglib_t *) malloc(sizeof (mpglib_t));
BAIL_IF_MACRO(mpg == NULL, ERR_OUT_OF_MEMORY, 0);
memset(mpg, '\0', sizeof (mpglib_t));
InitMP3(&mpg->mp);
rc = SDL_RWread(internal->rw, mpg->inbuf, 1, sizeof (mpg->inbuf));
if (rc <= 0)
{
free(mpg);
BAIL_MACRO("MPGLIB: Failed to read any data at all", 0);
} /* if */
if (decodeMP3(&mpg->mp, mpg->inbuf, rc,
mpg->outbuf, sizeof (mpg->outbuf),
&mpg->outleft) == MP3_ERR)
{
free(mpg);
BAIL_MACRO("MPGLIB: Not an MP3 stream?", 0);
} /* if */
SNDDBG(("MPGLIB: Accepting data stream.\n"));
internal->decoder_private = mpg;
sample->actual.rate = mpglib_freqs[mpg->mp.fr.sampling_frequency];
sample->actual.channels = mpg->mp.fr.stereo;
sample->actual.format = AUDIO_S16SYS;
sample->flags = SOUND_SAMPLEFLAG_NONE;
return(1); /* we'll handle this data. */
} /* MPGLIB_open */
static void MPGLIB_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
mpglib_t *mpg = ((mpglib_t *) internal->decoder_private);
ExitMP3(&mpg->mp);
free(mpg);
} /* MPGLIB_close */
static Uint32 MPGLIB_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
mpglib_t *mpg = ((mpglib_t *) internal->decoder_private);
Uint32 bw = 0;
int rc;
while (bw < internal->buffer_size)
{
if (mpg->outleft > 0)
{
size_t cpysize = internal->buffer_size - bw;
if (cpysize > mpg->outleft)
cpysize = mpg->outleft;
memcpy(((Uint8 *) internal->buffer) + bw,
mpg->outbuf + mpg->outpos, cpysize);
bw += cpysize;
mpg->outpos += cpysize;
mpg->outleft -= cpysize;
continue;
} /* if */
/* need to decode more from the MP3 stream... */
mpg->outpos = 0;
rc = decodeMP3(&mpg->mp, NULL, 0, mpg->outbuf,
sizeof (mpg->outbuf), &mpg->outleft);
if (rc == MP3_ERR)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(bw);
} /* if */
else if (rc == MP3_NEED_MORE)
{
rc = SDL_RWread(internal->rw, mpg->inbuf, 1, sizeof (mpg->inbuf));
if (rc == -1)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(bw);
} /* if */
else if (rc == 0)
{
sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(bw);
} /* else if */
/* make sure there isn't an ID3 tag. */
/*
* !!! FIXME: This can fail under the following circumstances:
* First, if there's the sequence "TAG" 128 bytes from the end
* of a read that isn't the EOF. This is unlikely.
* Second, if the TAG sequence is split between two reads (ie,
* the last byte of a read is 'T', and the next read is the
* final 127 bytes of the stream, being the rest of the ID3 tag).
* While this is more likely, it's still not very likely at all.
* Still, something SHOULD be done about this.
* ID3v2 tags are more complex, too, not to mention LYRICS tags,
* etc, which aren't handled, either. Hey, this IS meant to be
* a lightweight decoder. Use SMPEG if you need an all-purpose
* decoder. mpglib really assumes you control all your assets.
*/
if (rc >= 128)
{
Uint8 *ptr = &mpg->inbuf[rc - 128];
if ((ptr[0] == 'T') && (ptr[1] == 'A') && (ptr[2] == 'G'))
rc -= 128; /* disregard it. */
} /* if */
rc = decodeMP3(&mpg->mp, mpg->inbuf, rc,
mpg->outbuf, sizeof (mpg->outbuf),
&mpg->outleft);
if (rc == MP3_ERR)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(bw);
} /* if */
} /* else if */
} /* while */
return(bw);
} /* MPGLIB_read */
static int MPGLIB_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
mpglib_t *mpg = ((mpglib_t *) internal->decoder_private);
BAIL_IF_MACRO(SDL_RWseek(internal->rw, 0, SEEK_SET) != 0, ERR_IO_ERROR, 0);
/* this is just resetting some fields in a structure; it's very fast. */
ExitMP3(&mpg->mp);
InitMP3(&mpg->mp);
mpg->outpos = mpg->outleft = 0;
return(1);
} /* MPGLIB_rewind */
static int MPGLIB_seek(Sound_Sample *sample, Uint32 ms)
{
BAIL_MACRO("MPGLIB: Seeking not implemented", 0);
} /* MPGLIB_seek */
#endif /* SOUND_SUPPORTS_MPGLIB */
/* end of mpglib.c ... */

View File

@@ -0,0 +1,4 @@
14/Oct/1999:
- VBR fix
- Layer2 and Layer1 added

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -0,0 +1,153 @@
/*
* Mpeg Layer-1,2,3 audio decoder
* ------------------------------
* copyright (c) 1995,1996,1997 by Michael Hipp, All rights reserved.
* See also 'README'
*
* slighlty optimized for machines without autoincrement/decrement.
* The performance is highly compiler dependend. Maybe
* the decode.c version for 'normal' processor may be faster
* even for Intel processors.
*/
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "mpg123_sdlsound.h"
#include "mpglib_sdlsound.h"
/* old WRITE_SAMPLE */
#define WRITE_SAMPLE(samples,sum,clip) \
if( (sum) > 32767.0) { *(samples) = 0x7fff; (clip)++; } \
else if( (sum) < -32768.0) { *(samples) = -0x8000; (clip)++; } \
else { *(samples) = sum; }
int synth_1to1_mono(real *bandPtr,unsigned char *samples,
int *pnt, struct mpstr *mp)
{
short samples_tmp[64];
short *tmp1 = samples_tmp;
int i,ret;
int pnt1 = 0;
ret = synth_1to1(bandPtr,0,(unsigned char *) samples_tmp,&pnt1,mp);
samples += *pnt;
for(i=0;i<32;i++) {
*( (short *) samples) = *tmp1;
samples += 2;
tmp1 += 2;
}
*pnt += 64;
return ret;
}
int synth_1to1(real *bandPtr,int channel,unsigned char *out,
int *pnt, struct mpstr *mp)
{
static const int step = 2;
int bo;
short *samples = (short *) (out + *pnt);
real *b0,(*buf)[0x110];
int clip = 0;
int bo1;
bo = mp->synth_bo;
if(!channel) {
bo--;
bo &= 0xf;
buf = mp->synth_buffs[0];
}
else {
samples++;
buf = mp->synth_buffs[1];
}
if(bo & 0x1) {
b0 = buf[0];
bo1 = bo;
dct64(buf[1]+((bo+1)&0xf),buf[0]+bo,bandPtr);
}
else {
b0 = buf[1];
bo1 = bo+1;
dct64(buf[0]+bo,buf[1]+bo+1,bandPtr);
}
mp->synth_bo = bo;
{
register int j;
real *window = decwin + 16 - bo1;
for (j=16;j;j--,b0+=0x10,window+=0x20,samples+=step)
{
real sum;
sum = window[0x0] * b0[0x0];
sum -= window[0x1] * b0[0x1];
sum += window[0x2] * b0[0x2];
sum -= window[0x3] * b0[0x3];
sum += window[0x4] * b0[0x4];
sum -= window[0x5] * b0[0x5];
sum += window[0x6] * b0[0x6];
sum -= window[0x7] * b0[0x7];
sum += window[0x8] * b0[0x8];
sum -= window[0x9] * b0[0x9];
sum += window[0xA] * b0[0xA];
sum -= window[0xB] * b0[0xB];
sum += window[0xC] * b0[0xC];
sum -= window[0xD] * b0[0xD];
sum += window[0xE] * b0[0xE];
sum -= window[0xF] * b0[0xF];
WRITE_SAMPLE(samples,sum,clip);
}
{
real sum;
sum = window[0x0] * b0[0x0];
sum += window[0x2] * b0[0x2];
sum += window[0x4] * b0[0x4];
sum += window[0x6] * b0[0x6];
sum += window[0x8] * b0[0x8];
sum += window[0xA] * b0[0xA];
sum += window[0xC] * b0[0xC];
sum += window[0xE] * b0[0xE];
WRITE_SAMPLE(samples,sum,clip);
b0-=0x10,window-=0x20,samples+=step;
}
window += bo1<<1;
for (j=15;j;j--,b0-=0x10,window-=0x20,samples+=step)
{
real sum;
sum = -window[-0x1] * b0[0x0];
sum -= window[-0x2] * b0[0x1];
sum -= window[-0x3] * b0[0x2];
sum -= window[-0x4] * b0[0x3];
sum -= window[-0x5] * b0[0x4];
sum -= window[-0x6] * b0[0x5];
sum -= window[-0x7] * b0[0x6];
sum -= window[-0x8] * b0[0x7];
sum -= window[-0x9] * b0[0x8];
sum -= window[-0xA] * b0[0x9];
sum -= window[-0xB] * b0[0xA];
sum -= window[-0xC] * b0[0xB];
sum -= window[-0xD] * b0[0xC];
sum -= window[-0xE] * b0[0xD];
sum -= window[-0xF] * b0[0xE];
sum -= window[-0x0] * b0[0xF];
WRITE_SAMPLE(samples,sum,clip);
}
}
*pnt += 128;
return clip;
}

View File

@@ -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 }
};

View File

@@ -0,0 +1,243 @@
#include <stdlib.h>
#include <stdio.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "mpg123_sdlsound.h"
#include "mpglib_sdlsound.h"
BOOL InitMP3(struct mpstr *mp)
{
static int init = 0;
memset(mp,0,sizeof(struct mpstr));
mp->framesize = 0;
mp->fsizeold = -1;
mp->bsize = 0;
mp->head = mp->tail = NULL;
mp->fr.single = -1;
mp->bsnum = 0;
mp->synth_bo = 1;
if(!init) {
init = 1;
make_decode_tables(32767);
init_layer2();
init_layer3(SBLIMIT);
}
return !0;
}
void ExitMP3(struct mpstr *mp)
{
struct buf *b,*bn;
b = mp->tail;
while(b) {
free(b->pnt);
bn = b->next;
free(b);
b = bn;
}
}
static struct buf *addbuf(struct mpstr *mp,char *buf,int size)
{
struct buf *nbuf;
nbuf = malloc( sizeof(struct buf) );
BAIL_IF_MACRO(!nbuf, ERR_OUT_OF_MEMORY, NULL);
nbuf->pnt = malloc(size);
if(!nbuf->pnt) {
free(nbuf);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
}
nbuf->size = size;
memcpy(nbuf->pnt,buf,size);
nbuf->next = NULL;
nbuf->prev = mp->head;
nbuf->pos = 0;
if(!mp->tail) {
mp->tail = nbuf;
}
else {
mp->head->next = nbuf;
}
mp->head = nbuf;
mp->bsize += size;
return nbuf;
}
static void remove_buf(struct mpstr *mp)
{
struct buf *buf = mp->tail;
mp->tail = buf->next;
if(mp->tail)
mp->tail->prev = NULL;
else {
mp->tail = mp->head = NULL;
}
free(buf->pnt);
free(buf);
}
static int read_buf_byte(struct mpstr *mp, unsigned long *retval)
{
int pos;
pos = mp->tail->pos;
while(pos >= mp->tail->size) {
remove_buf(mp);
pos = mp->tail->pos;
if(!mp->tail) {
BAIL_MACRO("MPGLIB: Short read in read_buf_byte()!", 0);
}
}
if (retval != NULL)
*retval = mp->tail->pnt[pos];
mp->bsize--;
mp->tail->pos++;
return 1;
}
static int read_head(struct mpstr *mp)
{
unsigned long val;
unsigned long head;
if (!read_buf_byte(mp, &val))
return 0;
head = val << 8;
if (!read_buf_byte(mp, &val))
return 0;
head |= val;
head <<= 8;
if (!read_buf_byte(mp, &val))
return 0;
head |= val;
head <<= 8;
if (!read_buf_byte(mp, &val))
return 0;
head |= val;
mp->header = head;
return 1;
}
int decodeMP3(struct mpstr *mp,char *in,int isize,char *out,
int osize,int *done)
{
int len;
BAIL_IF_MACRO(osize < 4608, "MPGLIB: Output buffer too small", MP3_ERR);
if(in) {
if(addbuf(mp,in,isize) == NULL) {
return MP3_ERR;
}
}
/* First decode header */
if(mp->framesize == 0) {
if(mp->bsize < 4) {
return MP3_NEED_MORE;
}
if (!read_head(mp))
return MP3_ERR;
if (!decode_header(&mp->fr,mp->header))
return MP3_ERR;
mp->framesize = mp->fr.framesize;
}
if(mp->fr.framesize > mp->bsize)
return MP3_NEED_MORE;
wordpointer = mp->bsspace[mp->bsnum] + 512;
mp->bsnum = (mp->bsnum + 1) & 0x1;
bitindex = 0;
len = 0;
while(len < mp->framesize) {
int nlen;
int blen = mp->tail->size - mp->tail->pos;
if( (mp->framesize - len) <= blen) {
nlen = mp->framesize-len;
}
else {
nlen = blen;
}
memcpy(wordpointer+len,mp->tail->pnt+mp->tail->pos,nlen);
len += nlen;
mp->tail->pos += nlen;
mp->bsize -= nlen;
if(mp->tail->pos == mp->tail->size) {
remove_buf(mp);
}
}
*done = 0;
if(mp->fr.error_protection)
getbits(16);
switch(mp->fr.lay) {
case 1:
do_layer1(&mp->fr,(unsigned char *) out,done,mp);
break;
case 2:
do_layer2(&mp->fr,(unsigned char *) out,done,mp);
break;
case 3:
do_layer3(&mp->fr,(unsigned char *) out,done,mp);
break;
}
mp->fsizeold = mp->framesize;
mp->framesize = 0;
return MP3_OK;
}
int set_pointer(long backstep, struct mpstr *mp)
{
unsigned char *bsbufold;
if(mp->fsizeold < 0 && backstep > 0) {
char err[128];
snprintf(err, sizeof (err), "MPGLIB: Can't step back! %ld!", backstep);
BAIL_MACRO(err, MP3_ERR);
}
bsbufold = mp->bsspace[mp->bsnum] + 512;
wordpointer -= backstep;
if (backstep)
memcpy(wordpointer,bsbufold+mp->fsizeold-backstep,backstep);
bitindex = 0;
return MP3_OK;
}

View File

@@ -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} };

View File

@@ -0,0 +1,148 @@
/*
* Mpeg Layer-1 audio decoder
* --------------------------
* copyright (c) 1995 by Michael Hipp, All rights reserved. See also 'README'
* near unoptimzed ...
*
* may have a few bugs after last optimization ...
*
*/
#include "mpg123_sdlsound.h"
void I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT],struct frame *fr)
{
unsigned int *ba=balloc;
unsigned int *sca = (unsigned int *) scale_index;
if(fr->stereo) {
int i;
int jsbound = fr->jsbound;
for (i=0;i<jsbound;i++) {
*ba++ = getbits(4);
*ba++ = getbits(4);
}
for (i=jsbound;i<SBLIMIT;i++)
*ba++ = getbits(4);
ba = balloc;
for (i=0;i<jsbound;i++) {
if ((*ba++))
*sca++ = getbits(6);
if ((*ba++))
*sca++ = getbits(6);
}
for (i=jsbound;i<SBLIMIT;i++)
if ((*ba++)) {
*sca++ = getbits(6);
*sca++ = getbits(6);
}
}
else {
int i;
for (i=0;i<SBLIMIT;i++)
*ba++ = getbits(4);
ba = balloc;
for (i=0;i<SBLIMIT;i++)
if ((*ba++))
*sca++ = getbits(6);
}
}
void I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT],
unsigned int scale_index[2][SBLIMIT],struct frame *fr)
{
int i,n;
int smpb[2*SBLIMIT]; /* values: 0-65535 */
int *sample;
register unsigned int *ba;
register unsigned int *sca = (unsigned int *) scale_index;
if(fr->stereo) {
int jsbound = fr->jsbound;
register real *f0 = fraction[0];
register real *f1 = fraction[1];
ba = balloc;
for (sample=smpb,i=0;i<jsbound;i++) {
if ((n = *ba++))
*sample++ = getbits(n+1);
if ((n = *ba++))
*sample++ = getbits(n+1);
}
for (i=jsbound;i<SBLIMIT;i++)
if ((n = *ba++))
*sample++ = getbits(n+1);
ba = balloc;
for (sample=smpb,i=0;i<jsbound;i++) {
if((n=*ba++))
*f0++ = (real) ( ((-1)<<n) + (*sample++) + 1) * muls[n+1][*sca++];
else
*f0++ = 0.0;
if((n=*ba++))
*f1++ = (real) ( ((-1)<<n) + (*sample++) + 1) * muls[n+1][*sca++];
else
*f1++ = 0.0;
}
for (i=jsbound;i<SBLIMIT;i++) {
if ((n=*ba++)) {
real samp = ( ((-1)<<n) + (*sample++) + 1);
*f0++ = samp * muls[n+1][*sca++];
*f1++ = samp * muls[n+1][*sca++];
}
else
*f0++ = *f1++ = 0.0;
}
}
else {
register real *f0 = fraction[0];
ba = balloc;
for (sample=smpb,i=0;i<SBLIMIT;i++)
if ((n = *ba++))
*sample++ = getbits(n+1);
ba = balloc;
for (sample=smpb,i=0;i<SBLIMIT;i++) {
if((n=*ba++))
*f0++ = (real) ( ((-1)<<n) + (*sample++) + 1) * muls[n+1][*sca++];
else
*f0++ = 0.0;
}
}
}
int do_layer1(struct frame *fr,unsigned char *pcm_sample,
int *pcm_point,struct mpstr *mp)
{
int clip=0;
int i,stereo = fr->stereo;
unsigned int balloc[2*SBLIMIT];
unsigned int scale_index[2][SBLIMIT];
real fraction[2][SBLIMIT];
int single = fr->single;
fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ? (fr->mode_ext<<2)+4 : 32;
if(stereo == 1 || single == 3)
single = 0;
I_step_one(balloc,scale_index,fr);
for (i=0;i<SCALE_BLOCK;i++)
{
I_step_two(fraction,balloc,scale_index,fr);
if(single >= 0) {
clip += synth_1to1_mono( (real*)fraction[single],pcm_sample,pcm_point,mp);
}
else {
int p1 = *pcm_point;
clip += synth_1to1( (real*)fraction[0],0,pcm_sample,&p1,mp);
clip += synth_1to1( (real*)fraction[1],1,pcm_sample,pcm_point,mp);
}
}
return clip;
}

View File

@@ -0,0 +1,289 @@
/*
* Mpeg Layer-2 audio decoder
* --------------------------
* copyright (c) 1995 by Michael Hipp, All rights reserved. See also 'README'
*
*/
#include "mpg123_sdlsound.h"
#include "l2tables.h"
static int grp_3tab[32 * 3] = { 0, }; /* used: 27 */
static int grp_5tab[128 * 3] = { 0, }; /* used: 125 */
static int grp_9tab[1024 * 3] = { 0, }; /* used: 729 */
real muls[27][64]; /* also used by layer 1 */
void init_layer2(void)
{
static double mulmul[27] = {
0.0 , -2.0/3.0 , 2.0/3.0 ,
2.0/7.0 , 2.0/15.0 , 2.0/31.0, 2.0/63.0 , 2.0/127.0 , 2.0/255.0 ,
2.0/511.0 , 2.0/1023.0 , 2.0/2047.0 , 2.0/4095.0 , 2.0/8191.0 ,
2.0/16383.0 , 2.0/32767.0 , 2.0/65535.0 ,
-4.0/5.0 , -2.0/5.0 , 2.0/5.0, 4.0/5.0 ,
-8.0/9.0 , -4.0/9.0 , -2.0/9.0 , 2.0/9.0 , 4.0/9.0 , 8.0/9.0 };
static int base[3][9] = {
{ 1 , 0, 2 , } ,
{ 17, 18, 0 , 19, 20 , } ,
{ 21, 1, 22, 23, 0, 24, 25, 2, 26 } };
int i,j,k,l,len;
real *table;
static int tablen[3] = { 3 , 5 , 9 };
static int *itable,*tables[3] = { grp_3tab , grp_5tab , grp_9tab };
for(i=0;i<3;i++)
{
itable = tables[i];
len = tablen[i];
for(j=0;j<len;j++)
for(k=0;k<len;k++)
for(l=0;l<len;l++)
{
*itable++ = base[i][l];
*itable++ = base[i][k];
*itable++ = base[i][j];
}
}
for(k=0;k<27;k++)
{
double m=mulmul[k];
table = muls[k];
for(j=3,i=0;i<63;i++,j--)
*table++ = m * pow(2.0,(double) j / 3.0);
*table++ = 0.0;
}
}
void II_step_one(unsigned int *bit_alloc,int *scale,struct frame *fr)
{
int stereo = fr->stereo-1;
int sblimit = fr->II_sblimit;
int jsbound = fr->jsbound;
int sblimit2 = fr->II_sblimit<<stereo;
struct al_table *alloc1 = fr->alloc;
int i;
static unsigned int scfsi_buf[64];
unsigned int *scfsi,*bita;
int sc,step;
bita = bit_alloc;
if(stereo)
{
for (i=jsbound;i;i--,alloc1+=(1<<step))
{
*bita++ = (char) getbits(step=alloc1->bits);
*bita++ = (char) getbits(step);
}
for (i=sblimit-jsbound;i;i--,alloc1+=(1<<step))
{
bita[0] = (char) getbits(step=alloc1->bits);
bita[1] = bita[0];
bita+=2;
}
bita = bit_alloc;
scfsi=scfsi_buf;
for (i=sblimit2;i;i--)
if (*bita++)
*scfsi++ = (char) getbits_fast(2);
}
else /* mono */
{
for (i=sblimit;i;i--,alloc1+=(1<<step))
*bita++ = (char) getbits(step=alloc1->bits);
bita = bit_alloc;
scfsi=scfsi_buf;
for (i=sblimit;i;i--)
if (*bita++)
*scfsi++ = (char) getbits_fast(2);
}
bita = bit_alloc;
scfsi=scfsi_buf;
for (i=sblimit2;i;i--)
if (*bita++)
switch (*scfsi++)
{
case 0:
*scale++ = getbits_fast(6);
*scale++ = getbits_fast(6);
*scale++ = getbits_fast(6);
break;
case 1 :
*scale++ = sc = getbits_fast(6);
*scale++ = sc;
*scale++ = getbits_fast(6);
break;
case 2:
*scale++ = sc = getbits_fast(6);
*scale++ = sc;
*scale++ = sc;
break;
default: /* case 3 */
*scale++ = getbits_fast(6);
*scale++ = sc = getbits_fast(6);
*scale++ = sc;
break;
}
}
void II_step_two(unsigned int *bit_alloc,real fraction[2][4][SBLIMIT],int *scale,struct frame *fr,int x1)
{
int i,j,k,ba;
int stereo = fr->stereo;
int sblimit = fr->II_sblimit;
int jsbound = fr->jsbound;
struct al_table *alloc2,*alloc1 = fr->alloc;
unsigned int *bita=bit_alloc;
int d1,step;
for (i=0;i<jsbound;i++,alloc1+=(1<<step))
{
step = alloc1->bits;
for (j=0;j<stereo;j++)
{
if ( (ba=*bita++) )
{
k=(alloc2 = alloc1+ba)->bits;
if( (d1=alloc2->d) < 0)
{
real cm=muls[k][scale[x1]];
fraction[j][0][i] = ((real) ((int)getbits(k) + d1)) * cm;
fraction[j][1][i] = ((real) ((int)getbits(k) + d1)) * cm;
fraction[j][2][i] = ((real) ((int)getbits(k) + d1)) * cm;
}
else
{
static int *table[] = { 0,0,0,grp_3tab,0,grp_5tab,0,0,0,grp_9tab };
unsigned int idx,*tab,m=scale[x1];
idx = (unsigned int) getbits(k);
tab = (unsigned int *) (table[d1] + idx + idx + idx);
fraction[j][0][i] = muls[*tab++][m];
fraction[j][1][i] = muls[*tab++][m];
fraction[j][2][i] = muls[*tab][m];
}
scale+=3;
}
else
fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
}
}
for (i=jsbound;i<sblimit;i++,alloc1+=(1<<step))
{
step = alloc1->bits;
bita++; /* channel 1 and channel 2 bitalloc are the same */
if ( (ba=*bita++) )
{
k=(alloc2 = alloc1+ba)->bits;
if( (d1=alloc2->d) < 0)
{
real cm;
cm=muls[k][scale[x1+3]];
fraction[1][0][i] = (fraction[0][0][i] = (real) ((int)getbits(k) + d1) ) * cm;
fraction[1][1][i] = (fraction[0][1][i] = (real) ((int)getbits(k) + d1) ) * cm;
fraction[1][2][i] = (fraction[0][2][i] = (real) ((int)getbits(k) + d1) ) * cm;
cm=muls[k][scale[x1]];
fraction[0][0][i] *= cm; fraction[0][1][i] *= cm; fraction[0][2][i] *= cm;
}
else
{
static int *table[] = { 0,0,0,grp_3tab,0,grp_5tab,0,0,0,grp_9tab };
unsigned int idx,*tab,m1,m2;
m1 = scale[x1]; m2 = scale[x1+3];
idx = (unsigned int) getbits(k);
tab = (unsigned int *) (table[d1] + idx + idx + idx);
fraction[0][0][i] = muls[*tab][m1]; fraction[1][0][i] = muls[*tab++][m2];
fraction[0][1][i] = muls[*tab][m1]; fraction[1][1][i] = muls[*tab++][m2];
fraction[0][2][i] = muls[*tab][m1]; fraction[1][2][i] = muls[*tab][m2];
}
scale+=6;
}
else {
fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] =
fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0;
}
/*
should we use individual scalefac for channel 2 or
is the current way the right one , where we just copy channel 1 to
channel 2 ??
The current 'strange' thing is, that we throw away the scalefac
values for the second channel ...!!
-> changed .. now we use the scalefac values of channel one !!
*/
}
for(i=sblimit;i<SBLIMIT;i++)
for (j=0;j<stereo;j++)
fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0;
}
static void II_select_table(struct frame *fr)
{
static int translate[3][2][16] =
{ { { 0,2,2,2,2,2,2,0,0,0,1,1,1,1,1,0 } ,
{ 0,2,2,0,0,0,1,1,1,1,1,1,1,1,1,0 } } ,
{ { 0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0 } ,
{ 0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0 } } ,
{ { 0,3,3,3,3,3,3,0,0,0,1,1,1,1,1,0 } ,
{ 0,3,3,0,0,0,1,1,1,1,1,1,1,1,1,0 } } };
int table,sblim;
static struct al_table *tables[5] =
{ alloc_0, alloc_1, alloc_2, alloc_3 , alloc_4 };
static int sblims[5] = { 27 , 30 , 8, 12 , 30 };
if(fr->lsf)
table = 4;
else
table = translate[fr->sampling_frequency][2-fr->stereo][fr->bitrate_index];
sblim = sblims[table];
fr->alloc = tables[table];
fr->II_sblimit = sblim;
}
int do_layer2(struct frame *fr,unsigned char *pcm_sample,
int *pcm_point,struct mpstr *mp)
{
int clip=0;
int i,j;
int stereo = fr->stereo;
real fraction[2][4][SBLIMIT]; /* pick_table clears unused subbands */
unsigned int bit_alloc[64];
int scale[192];
int single = fr->single;
II_select_table(fr);
fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ?
(fr->mode_ext<<2)+4 : fr->II_sblimit;
if(stereo == 1 || single == 3)
single = 0;
II_step_one(bit_alloc, scale, fr);
for (i=0;i<SCALE_BLOCK;i++)
{
II_step_two(bit_alloc,fraction,scale,fr,i>>2);
for (j=0;j<3;j++) {
if(single >= 0) {
clip += synth_1to1_mono(fraction[0][j],pcm_sample,pcm_point,mp);
}
else {
int p1 = *pcm_point;
clip += synth_1to1(fraction[0][j],0,pcm_sample,&p1,mp);
clip += synth_1to1(fraction[1][j],1,pcm_sample,pcm_point,mp);
}
}
}
return clip;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
#include <stdio.h>
#include <string.h>
#if !defined(WIN32) && !defined(macintosh) && !defined(_WIN32_WCE)
#include <unistd.h>
#endif
#include <math.h>
#if defined(_WIN32)
# undef WIN32
# define WIN32
#endif
#if defined(WIN32) || defined(macintosh) || defined(_WIN32_WCE)
# define M_PI 3.14159265358979323846
# define M_SQRT2 1.41421356237309504880
# define REAL_IS_FLOAT
# define NEW_DCT9
# define random rand
# define srandom srand
#endif
#ifdef REAL_IS_FLOAT
# define real float
#elif defined(REAL_IS_LONG_DOUBLE)
# define real long double
#else
# define real double
#endif
#ifdef __GNUC__
#define INLINE inline
#elif ((defined _MSC_VER) || (defined __inline__))
#define INLINE __inline__
#else
#define INLINE
#endif
/* AUDIOBUFSIZE = n*64 with n=1,2,3 ... */
#define AUDIOBUFSIZE 16384
#ifndef FALSE
#define FALSE 0
#endif
#ifndef FALSE
#define TRUE 1
#endif
#define SBLIMIT 32
#define SSLIMIT 18
#define SCALE_BLOCK 12
#define MPG_MD_STEREO 0
#define MPG_MD_JOINT_STEREO 1
#define MPG_MD_DUAL_CHANNEL 2
#define MPG_MD_MONO 3
#define MAXFRAMESIZE 1792
/* Pre Shift fo 16 to 8 bit converter table */
#define AUSHIFT (3)
struct frame {
int stereo;
int jsbound;
int single;
int lsf;
int mpeg25;
int header_change;
int lay;
int error_protection;
int bitrate_index;
int sampling_frequency;
int padding;
int extension;
int mode;
int mode_ext;
int copyright;
int original;
int emphasis;
int framesize; /* computed framesize */
/* layer2 stuff */
int II_sblimit;
void *alloc;
};
struct parameter {
int quiet; /* shut up! */
int tryresync; /* resync stream after error */
int verbose; /* verbose level */
int checkrange;
};
struct mpstr; /* forward declaration. */
extern unsigned int get1bit(void);
extern unsigned int getbits(int);
extern unsigned int getbits_fast(int);
extern int set_pointer(long,struct mpstr *);
extern unsigned char *wordpointer;
extern int bitindex;
extern void make_decode_tables(long scaleval);
extern int do_layer3(struct frame *fr,unsigned char *,int *,struct mpstr *);
extern int do_layer2(struct frame *fr,unsigned char *,int *,struct mpstr *);
extern int do_layer1(struct frame *fr,unsigned char *,int *,struct mpstr *);
extern int decode_header(struct frame *fr,unsigned long newhead);
struct gr_info_s {
int scfsi;
unsigned part2_3_length;
unsigned big_values;
unsigned scalefac_compress;
unsigned block_type;
unsigned mixed_block_flag;
unsigned table_select[3];
unsigned subblock_gain[3];
unsigned maxband[3];
unsigned maxbandl;
unsigned maxb;
unsigned region1start;
unsigned region2start;
unsigned preflag;
unsigned scalefac_scale;
unsigned count1table_select;
real *full_gain[3];
real *pow2gain;
};
struct III_sideinfo
{
unsigned main_data_begin;
unsigned private_bits;
struct {
struct gr_info_s gr[2];
} ch[2];
};
extern int synth_1to1 (real *,int,unsigned char *,int *,struct mpstr *);
extern int synth_1to1_8bit (real *,int,unsigned char *,int *);
extern int synth_1to1_mono (real *,unsigned char *,int *,struct mpstr *);
extern int synth_1to1_mono2stereo (real *,unsigned char *,int *);
extern int synth_1to1_8bit_mono (real *,unsigned char *,int *);
extern int synth_1to1_8bit_mono2stereo (real *,unsigned char *,int *);
extern int synth_2to1 (real *,int,unsigned char *,int *);
extern int synth_2to1_8bit (real *,int,unsigned char *,int *);
extern int synth_2to1_mono (real *,unsigned char *,int *);
extern int synth_2to1_mono2stereo (real *,unsigned char *,int *);
extern int synth_2to1_8bit_mono (real *,unsigned char *,int *);
extern int synth_2to1_8bit_mono2stereo (real *,unsigned char *,int *);
extern int synth_4to1 (real *,int,unsigned char *,int *);
extern int synth_4to1_8bit (real *,int,unsigned char *,int *);
extern int synth_4to1_mono (real *,unsigned char *,int *);
extern int synth_4to1_mono2stereo (real *,unsigned char *,int *);
extern int synth_4to1_8bit_mono (real *,unsigned char *,int *);
extern int synth_4to1_8bit_mono2stereo (real *,unsigned char *,int *);
extern int synth_ntom (real *,int,unsigned char *,int *);
extern int synth_ntom_8bit (real *,int,unsigned char *,int *);
extern int synth_ntom_mono (real *,unsigned char *,int *);
extern int synth_ntom_mono2stereo (real *,unsigned char *,int *);
extern int synth_ntom_8bit_mono (real *,unsigned char *,int *);
extern int synth_ntom_8bit_mono2stereo (real *,unsigned char *,int *);
extern void rewindNbits(int bits);
extern int hsstell(void);
extern int get_songlen(struct frame *fr,int no);
extern void init_layer3(int);
extern void init_layer2(void);
extern void make_decode_tables(long scale);
extern void make_conv16to8_table(int);
extern void dct64(real *,real *,real *);
extern void synth_ntom_set_step(long,long);
extern unsigned char *conv16to8;
extern long mpglib_freqs[9];
extern real muls[27][64];
extern real decwin[512+32];
extern real *pnts[5];
extern struct parameter param;

View File

@@ -0,0 +1,243 @@
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <ctype.h>
#include <stdlib.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "mpg123_sdlsound.h"
struct parameter param = { 1 , 1 , 0 , 0 };
int tabsel_123[2][3][16] = {
{ {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
{0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
{0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
{ {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
};
long mpglib_freqs[9] = { 44100, 48000, 32000,
22050, 24000, 16000 ,
11025 , 12000 , 8000 };
int bitindex;
unsigned char *wordpointer;
unsigned char *pcm_sample;
int pcm_point = 0;
#define HDRCMPMASK 0xfffffd00
#if 0
int head_check(unsigned long head)
{
if( (head & 0xffe00000) != 0xffe00000)
return FALSE;
if(!((head>>17)&3))
return FALSE;
if( ((head>>12)&0xf) == 0xf)
return FALSE;
if( ((head>>10)&0x3) == 0x3 )
return FALSE;
return TRUE;
}
#endif
/*
* the code a header and write the information
* into the frame structure
*/
int decode_header(struct frame *fr,unsigned long newhead)
{
if( newhead & (1<<20) ) {
fr->lsf = (newhead & (1<<19)) ? 0x0 : 0x1;
fr->mpeg25 = 0;
}
else {
fr->lsf = 1;
fr->mpeg25 = 1;
}
fr->lay = 4-((newhead>>17)&3);
if( ((newhead>>10)&0x3) == 0x3) {
BAIL_MACRO("MPGLIB: Corrupted header", 0);
}
if(fr->mpeg25) {
fr->sampling_frequency = 6 + ((newhead>>10)&0x3);
}
else
fr->sampling_frequency = ((newhead>>10)&0x3) + (fr->lsf*3);
fr->error_protection = ((newhead>>16)&0x1)^0x1;
if(fr->mpeg25) /* allow Bitrate change for 2.5 ... */
fr->bitrate_index = ((newhead>>12)&0xf);
fr->bitrate_index = ((newhead>>12)&0xf);
fr->padding = ((newhead>>9)&0x1);
fr->extension = ((newhead>>8)&0x1);
fr->mode = ((newhead>>6)&0x3);
fr->mode_ext = ((newhead>>4)&0x3);
fr->copyright = ((newhead>>3)&0x1);
fr->original = ((newhead>>2)&0x1);
fr->emphasis = newhead & 0x3;
fr->stereo = (fr->mode == MPG_MD_MONO) ? 1 : 2;
if(!fr->bitrate_index)
{
BAIL_MACRO("MPGLIB: Free format not supported.", 0);
}
switch(fr->lay)
{
case 1:
#ifdef LAYER1
#if 0
fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ?
(fr->mode_ext<<2)+4 : 32;
#endif
fr->framesize = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
fr->framesize /= mpglib_freqs[fr->sampling_frequency];
fr->framesize = ((fr->framesize+fr->padding)<<2)-4;
#else
__Sound_SetError("MPGLIB: Not supported!");
#endif
break;
case 2:
#ifdef LAYER2
#if 0
fr->jsbound = (fr->mode == MPG_MD_JOINT_STEREO) ?
(fr->mode_ext<<2)+4 : fr->II_sblimit;
#endif
fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
fr->framesize /= mpglib_freqs[fr->sampling_frequency];
fr->framesize += fr->padding - 4;
#else
__Sound_SetError("MPGLIB: Not supported!");
#endif
break;
case 3:
#if 0
fr->do_layer = do_layer3;
if(fr->lsf)
ssize = (fr->stereo == 1) ? 9 : 17;
else
ssize = (fr->stereo == 1) ? 17 : 32;
#endif
#if 0
if(fr->error_protection)
ssize += 2;
#endif
fr->framesize = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
fr->framesize /= mpglib_freqs[fr->sampling_frequency]<<(fr->lsf);
fr->framesize = fr->framesize + fr->padding - 4;
break;
default:
BAIL_MACRO("MPGLIB: Unknown layer type.", 0);
}
return 1;
}
#if 0
void print_header(struct frame *fr)
{
static char *modes[4] = { "Stereo", "Joint-Stereo", "Dual-Channel", "Single-Channel" };
static char *layers[4] = { "Unknown" , "I", "II", "III" };
fprintf(stderr,"MPEG %s, Layer: %s, Freq: %ld, mode: %s, modext: %d, BPF : %d\n",
fr->mpeg25 ? "2.5" : (fr->lsf ? "2.0" : "1.0"),
layers[fr->lay],mpglib_freqs[fr->sampling_frequency],
modes[fr->mode],fr->mode_ext,fr->framesize+4);
fprintf(stderr,"Channels: %d, copyright: %s, original: %s, CRC: %s, emphasis: %d.\n",
fr->stereo,fr->copyright?"Yes":"No",
fr->original?"Yes":"No",fr->error_protection?"Yes":"No",
fr->emphasis);
fprintf(stderr,"Bitrate: %d Kbits/s, Extension value: %d\n",
tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index],fr->extension);
}
void print_header_compact(struct frame *fr)
{
static char *modes[4] = { "stereo", "joint-stereo", "dual-channel", "mono" };
static char *layers[4] = { "Unknown" , "I", "II", "III" };
fprintf(stderr,"MPEG %s layer %s, %d kbit/s, %ld Hz %s\n",
fr->mpeg25 ? "2.5" : (fr->lsf ? "2.0" : "1.0"),
layers[fr->lay],
tabsel_123[fr->lsf][fr->lay-1][fr->bitrate_index],
mpglib_freqs[fr->sampling_frequency], modes[fr->mode]);
}
#endif
unsigned int getbits(int number_of_bits)
{
unsigned long rval;
if(!number_of_bits)
return 0;
{
rval = wordpointer[0];
rval <<= 8;
rval |= wordpointer[1];
rval <<= 8;
rval |= wordpointer[2];
rval <<= bitindex;
rval &= 0xffffff;
bitindex += number_of_bits;
rval >>= (24-number_of_bits);
wordpointer += (bitindex>>3);
bitindex &= 7;
}
return rval;
}
unsigned int getbits_fast(int number_of_bits)
{
unsigned long rval;
{
rval = wordpointer[0];
rval <<= 8;
rval |= wordpointer[1];
rval <<= bitindex;
rval &= 0xffff;
bitindex += number_of_bits;
rval >>= (16-number_of_bits);
wordpointer += (bitindex>>3);
bitindex &= 7;
}
return rval;
}
unsigned int get1bit(void)
{
unsigned char rval;
rval = *wordpointer << bitindex;
bitindex++;
wordpointer += (bitindex>>3);
bitindex &= 7;
return rval>>7;
}

View File

@@ -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

View File

@@ -0,0 +1,80 @@
#include <stdlib.h>
#include "mpg123_sdlsound.h"
real decwin[512+32];
static real cos64[16],cos32[8],cos16[4],cos8[2],cos4[1];
real *pnts[] = { cos64,cos32,cos16,cos8,cos4 };
#if 0
static unsigned char *conv16to8_buf = NULL;
unsigned char *conv16to8;
#endif
static long intwinbase[] = {
0, -1, -1, -1, -1, -1, -1, -2, -2, -2,
-2, -3, -3, -4, -4, -5, -5, -6, -7, -7,
-8, -9, -10, -11, -13, -14, -16, -17, -19, -21,
-24, -26, -29, -31, -35, -38, -41, -45, -49, -53,
-58, -63, -68, -73, -79, -85, -91, -97, -104, -111,
-117, -125, -132, -139, -147, -154, -161, -169, -176, -183,
-190, -196, -202, -208, -213, -218, -222, -225, -227, -228,
-228, -227, -224, -221, -215, -208, -200, -189, -177, -163,
-146, -127, -106, -83, -57, -29, 2, 36, 72, 111,
153, 197, 244, 294, 347, 401, 459, 519, 581, 645,
711, 779, 848, 919, 991, 1064, 1137, 1210, 1283, 1356,
1428, 1498, 1567, 1634, 1698, 1759, 1817, 1870, 1919, 1962,
2001, 2032, 2057, 2075, 2085, 2087, 2080, 2063, 2037, 2000,
1952, 1893, 1822, 1739, 1644, 1535, 1414, 1280, 1131, 970,
794, 605, 402, 185, -45, -288, -545, -814, -1095, -1388,
-1692, -2006, -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
-5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, -7910, -8209,
-8491, -8755, -8998, -9219, -9416, -9585, -9727, -9838, -9916, -9959,
-9966, -9935, -9863, -9750, -9592, -9389, -9139, -8840, -8492, -8092,
-7640, -7134, -6574, -5959, -5288, -4561, -3776, -2935, -2037, -1082,
-70, 998, 2122, 3300, 4533, 5818, 7154, 8540, 9975, 11455,
12980, 14548, 16155, 17799, 19478, 21189, 22929, 24694, 26482, 28289,
30112, 31947, 33791, 35640, 37489, 39336, 41176, 43006, 44821, 46617,
48390, 50137, 51853, 53534, 55178, 56778, 58333, 59838, 61289, 62684,
64019, 65290, 66494, 67629, 68692, 69679, 70590, 71420, 72169, 72835,
73415, 73908, 74313, 74630, 74856, 74992, 75038 };
void make_decode_tables(long scaleval)
{
int i,j,k,kr,divv;
real *table,*costab;
for(i=0;i<5;i++)
{
kr=0x10>>i; divv=0x40>>i;
costab = pnts[i];
for(k=0;k<kr;k++)
costab[k] = 1.0 / (2.0 * cos(M_PI * ((double) k * 2.0 + 1.0) / (double) divv));
}
table = decwin;
scaleval = -scaleval;
for(i=0,j=0;i<256;i++,j++,table+=32)
{
if(table < decwin+512+16)
table[16] = table[0] = (double) intwinbase[j] / 65536.0 * (double) scaleval;
if(i % 32 == 31)
table -= 1023;
if(i % 64 == 63)
scaleval = - scaleval;
}
for( /* i=256 */ ;i<512;i++,j--,table+=32)
{
if(table < decwin+512+16)
table[16] = table[0] = (double) intwinbase[j] / 65536.0 * (double) scaleval;
if(i % 32 == 31)
table -= 1023;
if(i % 64 == 63)
scaleval = - scaleval;
}
}

View File

@@ -0,0 +1,375 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Ogg Vorbis decoder for SDL_sound.
*
* This driver handles .OGG audio files, and depends on libvorbisfile to
* do the actual decoding work. libvorbisfile is part of libvorbis, which
* is part of the Ogg Vorbis project.
*
* Ogg Vorbis: http://www.xiph.org/ogg/vorbis/
* vorbisfile documentation: http://www.xiph.org/ogg/vorbis/doc/vorbisfile/
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_OGG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
static int OGG_init(void);
static void OGG_quit(void);
static int OGG_open(Sound_Sample *sample, const char *ext);
static void OGG_close(Sound_Sample *sample);
static Uint32 OGG_read(Sound_Sample *sample);
static int OGG_rewind(Sound_Sample *sample);
static int OGG_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_ogg[] = { "OGG", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG =
{
{
extensions_ogg,
"Ogg Vorbis audio through VorbisFile",
"Ryan C. Gordon <icculus@icculus.org>",
"http://www.icculus.org/SDL_sound/"
},
OGG_init, /* init() method */
OGG_quit, /* quit() method */
OGG_open, /* open() method */
OGG_close, /* close() method */
OGG_read, /* read() method */
OGG_rewind, /* rewind() method */
OGG_seek /* seek() method */
};
static int OGG_init(void)
{
return(1); /* always succeeds. */
} /* OGG_init */
static void OGG_quit(void)
{
/* it's a no-op. */
} /* OGG_quit */
/*
* These are callbacks from vorbisfile that let them read data from
* a RWops...
*/
static size_t RWops_ogg_read(void *ptr, size_t size, size_t nmemb, void *datasource)
{
return((size_t) SDL_RWread((SDL_RWops *) datasource, ptr, size, nmemb));
} /* RWops_ogg_read */
static int RWops_ogg_seek(void *datasource, ogg_int64_t offset, int whence)
{
return(SDL_RWseek((SDL_RWops *) datasource, offset, whence));
} /* RWops_ogg_seek */
static int RWops_ogg_close(void *datasource)
{
/* do nothing; SDL_sound will delete the RWops at a higher level. */
return(0); /* this is success in fclose(), so I guess that's okay. */
} /* RWops_ogg_close */
static long RWops_ogg_tell(void *datasource)
{
return((long) SDL_RWtell((SDL_RWops *) datasource));
} /* RWops_ogg_tell */
static const ov_callbacks RWops_ogg_callbacks =
{
RWops_ogg_read,
RWops_ogg_seek,
RWops_ogg_close,
RWops_ogg_tell
};
/* Return a human readable version of an VorbisFile error code... */
#if (defined DEBUG_CHATTER)
static const char *ogg_error(int errnum)
{
switch(errnum)
{
case OV_EREAD:
return("i/o error");
case OV_ENOTVORBIS:
return("not a vorbis file");
case OV_EVERSION:
return("Vorbis version mismatch");
case OV_EBADHEADER:
return("invalid Vorbis bitstream header");
case OV_EFAULT:
return("internal logic fault in Vorbis library");
} /* switch */
return("unknown error");
} /* ogg_error */
#endif
static __inline__ void output_ogg_comments(OggVorbis_File *vf)
{
#if (defined DEBUG_CHATTER)
int i;
vorbis_comment *vc = ov_comment(vf, -1);
if (vc == NULL)
return;
SNDDBG(("OGG: vendor == [%s].\n", vc->vendor));
for (i = 0; i < vc->comments; i++)
{
SNDDBG(("OGG: user comment [%s].\n", vc->user_comments[i]));
} /* for */
#endif
} /* output_ogg_comments */
static int OGG_open(Sound_Sample *sample, const char *ext)
{
int rc;
OggVorbis_File *vf;
vorbis_info *info;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vf = (OggVorbis_File *) malloc(sizeof (OggVorbis_File));
BAIL_IF_MACRO(vf == NULL, ERR_OUT_OF_MEMORY, 0);
rc = ov_open_callbacks(internal->rw, vf, NULL, 0, RWops_ogg_callbacks);
if (rc != 0)
{
SNDDBG(("OGG: can't grok data. reason: [%s].\n", ogg_error(rc)));
free(vf);
BAIL_MACRO("OGG: Not valid Ogg Vorbis data.", 0);
} /* if */
info = ov_info(vf, -1);
if (info == NULL)
{
ov_clear(vf);
free(vf);
BAIL_MACRO("OGG: failed to retrieve bitstream info", 0);
} /* if */
SNDDBG(("OGG: Accepting data stream.\n"));
output_ogg_comments(vf);
SNDDBG(("OGG: bitstream version == (%d).\n", info->version));
SNDDBG(("OGG: bitstream channels == (%d).\n", info->channels));
SNDDBG(("OGG: bitstream sampling rate == (%ld).\n", info->rate));
SNDDBG(("OGG: seekable == {%s}.\n", ov_seekable(vf) ? "TRUE" : "FALSE"));
SNDDBG(("OGG: number of logical bitstreams == (%ld).\n", ov_streams(vf)));
SNDDBG(("OGG: serial number == (%ld).\n", ov_serialnumber(vf, -1)));
SNDDBG(("OGG: total seconds of sample == (%f).\n", ov_time_total(vf, -1)));
internal->decoder_private = vf;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
sample->actual.rate = (Uint32) info->rate;
sample->actual.channels = (Uint8) info->channels;
/*
* Since we might have more than one logical bitstream in the OGG file,
* and these bitstreams may be in different formats, we might be
* converting two or three times: once in vorbisfile, once again in
* SDL_sound, and perhaps a third time to get it to the sound device's
* format. That's wickedly inefficient.
*
* To combat this a little, if the user specified a desired format, we
* claim that to be the "actual" format of the collection of logical
* bitstreams. This means that VorbisFile will do a conversion as
* necessary, and SDL_sound will not. If the user didn't specify a
* desired format, then we pretend the "actual" format is something that
* OGG files are apparently commonly encoded in.
*/
sample->actual.format = (sample->desired.format == 0) ?
AUDIO_S16LSB : sample->desired.format;
return(1);
} /* OGG_open */
static void OGG_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
ov_clear(vf);
free(vf);
} /* OGG_close */
/* Note: According to the Vorbis documentation:
* "ov_read() will decode at most one vorbis packet per invocation,
* so the value returned will generally be less than length."
* Due to this, for buffer sizes like 16384, SDL_Sound was always getting
* an underfilled buffer and always setting the EAGAIN flag.
* Since the SDL_Sound API implies that the entire buffer
* should be filled unless EOF, additional code has been added
* to this function to call ov_read() until the buffer is filled.
* However, there may still be some corner cases where the buffer
* cannot be entirely filled. So be aware.
*/
static Uint32 OGG_read(Sound_Sample *sample)
{
int rc;
int bitstream;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
rc = ov_read(vf, internal->buffer, internal->buffer_size,
((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */
((sample->actual.format & 0xFF) / 8), /* bytes per sample point */
((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */
&bitstream);
/* Make sure the read went smoothly... */
if (rc == 0)
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else if (rc < 0)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
/* If the buffer isn't filled, keep trying to fill it
* until no more data can be grabbed */
else if ((Uint32) rc < internal->buffer_size)
{
/* Creating a pointer to the buffer that denotes where to start
* writing new data. */
Uint8* buffer_start_point = NULL;
int total_bytes_read = rc;
int bytes_remaining = internal->buffer_size - rc;
/* Keep grabbing data until something prevents
* us from getting more. (Could be EOF,
* packets are too large to fit in remaining
* space, or an error.)
*/
while( (rc > 0) && (bytes_remaining > 0) )
{
/* Set buffer pointer to end of last write */
/* All the messiness is to get rid of the warning for
* dereferencing a void*
*/
buffer_start_point = &(((Uint8*)internal->buffer)[total_bytes_read]);
rc = ov_read(vf, buffer_start_point, bytes_remaining,
((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */
((sample->actual.format & 0xFF) / 8), /* bytes per sample point */
((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */
&bitstream);
/* Make sure rc > 0 because we don't accidently want
* to change the counters if there was an error
*/
if(rc > 0)
{
total_bytes_read += rc;
bytes_remaining = bytes_remaining - rc;
}
}
/* I think the minimum read size is 2, though I'm
* not sure about this. (I've hit cases where I
* couldn't read less than 4.) What I don't want to do is
* accidently claim we hit EOF when the reason rc == 0
* is because the requested amount of data was smaller
* than the minimum packet size.
* For now, I will be conservative
* and not set the EOF flag, and let the next call to
* this function figure it out.
* I think the ERROR flag is safe to set because
* it looks like OGG simply returns 0 if the
* read size is too small.
* And in most cases for sensible buffer sizes,
* this fix will fill the buffer,
* so we can set the EAGAIN flag without worrying
* that it will always be set.
*/
if(rc < 0)
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
}
else if(rc == 0)
{
/* Do nothing for now until there is a better solution */
/* sample->flags |= SOUND_SAMPLEFLAG_EOF; */
}
/* Test for a buffer underrun. It should occur less frequently
* now, but it still may happen and not necessarily mean
* anything useful. */
if ((Uint32) total_bytes_read < internal->buffer_size)
{
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
}
/* change rc to the total bytes read so function
* can return the correct value.
*/
rc = total_bytes_read;
}
return((Uint32) rc);
} /* OGG_read */
static int OGG_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
BAIL_IF_MACRO(ov_raw_seek(vf, 0) < 0, ERR_IO_ERROR, 0);
return(1);
} /* OGG_rewind */
static int OGG_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private;
double timepos = (((double) ms) / 1000.0);
BAIL_IF_MACRO(ov_time_seek(vf, timepos) < 0, ERR_IO_ERROR, 0);
return(1);
} /* OGG_seek */
#endif /* SOUND_SUPPORTS_OGG */
/* end of ogg.c ... */

View File

@@ -0,0 +1,591 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* QuickTime decoder for sound formats that QuickTime supports.
* April 28, 2002
*
* This driver handles .mov files with a sound track. In
* theory, it could handle any format that QuickTime supports.
* In practice, it may only handle a select few of these formats.
*
* It seems able to play back AIFF and other standard Mac formats.
* Rewinding is not supported yet.
*
* The routine QT_create_data_ref() needs to be
* tweaked to support different media types.
* This code was originally written to get MP3 support,
* as it turns out, this isn't possible using this method.
*
* The only way to get streaming MP3 support through QuickTime,
* and hence support for SDL_RWops, is to write
* a DataHandler component, which suddenly gets much more difficult :-(
*
* This file was written by Darrell Walisser (walisser@mac.com)
* Portions have been borrowed from the "MP3Player" sample code,
* courtesy of Apple.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_QUICKTIME
#ifdef macintosh
typedef long int32_t;
# define OPAQUE_UPP_TYPES 0
# include <QuickTime.h>
#else
# include <QuickTime/QuickTime.h>
# include <Carbon/Carbon.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int QT_init(void);
static void QT_quit(void);
static int QT_open(Sound_Sample *sample, const char *ext);
static void QT_close(Sound_Sample *sample);
static Uint32 QT_read(Sound_Sample *sample);
static int QT_rewind(Sound_Sample *sample);
static int QT_seek(Sound_Sample *sample, Uint32 ms);
#define QT_MAX_INPUT_BUFFER (32*1024) /* Maximum size of internal buffer (internal->buffer_size) */
static const char *extensions_quicktime[] = { "mov", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime =
{
{
extensions_quicktime,
"QuickTime format",
"Darrell Walisser <dwaliss1@purdue.edu>",
"http://www.icculus.org/SDL_sound/"
},
QT_init, /* init() method */
QT_quit, /* quit() method */
QT_open, /* open() method */
QT_close, /* close() method */
QT_read, /* read() method */
QT_rewind, /* rewind() method */
QT_seek /* seek() method */
};
typedef struct {
ExtendedSoundComponentData compData;
Handle hSource; /* source media buffer */
Media sourceMedia; /* sound media identifier */
TimeValue getMediaAtThisTime;
TimeValue sourceDuration;
Boolean isThereMoreSource;
UInt32 maxBufferSize;
} SCFillBufferData, *SCFillBufferDataPtr;
typedef struct {
Movie movie;
Track track;
Media media;
AudioFormatAtomPtr atom;
SoundComponentData source_format;
SoundComponentData dest_format;
SoundConverter converter;
SCFillBufferData buffer_data;
SoundConverterFillBufferDataUPP fill_buffer_proc;
} qt_t;
/*
* This procedure creates a description of the raw data
* read from SDL_RWops so that QuickTime can identify
* the codec it needs to use to decompress it.
*/
static Handle QT_create_data_ref (const char *file_extension) {
Handle tmp_handle, data_ref;
StringPtr file_name = "\p"; /* empty since we don't know the file name! */
OSType file_type;
StringPtr mime_type;
long atoms[3];
/*
if (__Sound_strcasecmp (file_extension, "mp3")==0) {
file_type = 'MPEG';
mime_type = "\pvideo/mpeg";
}
else {
return NULL;
}
*/
if (__Sound_strcasecmp (file_extension, "mov") == 0) {
file_type = 'MooV';
mime_type = "\pvideo/quicktime";
}
else {
return NULL;
}
tmp_handle = NewHandle(0);
assert (tmp_handle != NULL);
assert (noErr == PtrToHand (&tmp_handle, &data_ref, sizeof(Handle)));
assert (noErr == PtrAndHand (file_name, data_ref, file_name[0]+1));
atoms[0] = EndianU32_NtoB (sizeof(long) * 3);
atoms[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType);
atoms[2] = EndianU32_NtoB (file_type);
assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*3));
atoms[0] = EndianU32_NtoB (sizeof(long)*2 + mime_type[0]+1);
atoms[1] = EndianU32_NtoB (kDataRefExtensionMIMEType);
assert (noErr == PtrAndHand (atoms, data_ref, sizeof(long)*2));
assert (noErr == PtrAndHand (mime_type, data_ref, mime_type[0]+1));
return data_ref;
}
/*
* This procedure is a hook for QuickTime to grab data from the
* SDL_RWOps data structure when it needs it
*/
static pascal OSErr QT_get_movie_data_proc (long offset, long size,
void *data, void *user_data)
{
SDL_RWops* rw = (SDL_RWops*)user_data;
OSErr error;
if (offset == SDL_RWseek (rw, offset, SEEK_SET)) {
if (size == SDL_RWread (rw, data, 1, size)) {
error = noErr;
}
else {
error = notEnoughDataErr;
}
}
else {
error = fileOffsetTooBigErr;
}
return (error);
}
/* * ----------------------------
* SoundConverterFillBufferDataProc
*
* the callback routine that provides the source data for conversion -
* it provides data by setting outData to a pointer to a properly
* filled out ExtendedSoundComponentData structure
*/
static pascal Boolean QT_sound_converter_fill_buffer_data_proc (SoundComponentDataPtr *outData, void *inRefCon)
{
SCFillBufferDataPtr pFillData = (SCFillBufferDataPtr)inRefCon;
OSErr err = noErr;
/* if after getting the last chunk of data the total time is over
* the duration, we're done
*/
if (pFillData->getMediaAtThisTime >= pFillData->sourceDuration) {
pFillData->isThereMoreSource = false;
pFillData->compData.desc.buffer = NULL;
pFillData->compData.desc.sampleCount = 0;
pFillData->compData.bufferSize = 0;
}
if (pFillData->isThereMoreSource) {
long sourceBytesReturned;
long numberOfSamples;
TimeValue sourceReturnedTime, durationPerSample;
HUnlock(pFillData->hSource);
err = GetMediaSample
(pFillData->sourceMedia,/* specifies the media for this operation */
pFillData->hSource, /* function returns the sample data into this handle */
pFillData->maxBufferSize, /* maximum number of bytes of sample data to be returned */
&sourceBytesReturned, /* the number of bytes of sample data returned */
pFillData->getMediaAtThisTime,/* starting time of the sample to
be retrieved (must be in
Media's TimeScale) */
&sourceReturnedTime,/* indicates the actual time of the returned sample data */
&durationPerSample, /* duration of each sample in the media */
NULL, /* sample description corresponding to the returned sample data (NULL to ignore) */
NULL, /* index value to the sample description that corresponds
to the returned sample data (NULL to ignore) */
0, /* maximum number of samples to be returned (0 to use a
value that is appropriate for the media) */
&numberOfSamples, /* number of samples it actually returned */
NULL); /* flags that describe the sample (NULL to ignore) */
HLock(pFillData->hSource);
if ((noErr != err) || (sourceBytesReturned == 0)) {
pFillData->isThereMoreSource = false;
pFillData->compData.desc.buffer = NULL;
pFillData->compData.desc.sampleCount = 0;
if ((err != noErr) && (sourceBytesReturned > 0))
DebugStr("\pGetMediaSample - Failed in FillBufferDataProc");
}
pFillData->getMediaAtThisTime = sourceReturnedTime + (durationPerSample * numberOfSamples);
pFillData->compData.bufferSize = sourceBytesReturned;
}
/* set outData to a properly filled out ExtendedSoundComponentData struct */
*outData = (SoundComponentDataPtr)&pFillData->compData;
return (pFillData->isThereMoreSource);
}
static int QT_init_internal () {
OSErr error;
error = EnterMovies(); /* initialize the movie toolbox */
return (error == noErr);
}
static void QT_quit_internal () {
ExitMovies();
}
static qt_t* QT_open_internal (Sound_Sample *sample, const char *extension)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
qt_t *instance;
OSErr error;
Movie movie;
Track sound_track;
Media sound_track_media;
AudioFormatAtomPtr source_sound_decomp_atom;
SoundDescriptionV1Handle source_sound_description;
Handle source_sound_description_extension;
Size source_sound_description_extension_size;
Handle data_ref;
data_ref = QT_create_data_ref (extension);
/* create a movie that will read data using SDL_RWops */
error = NewMovieFromUserProc
(&movie,
0,
NULL,
NewGetMovieUPP(QT_get_movie_data_proc),
(void*) internal->rw,
data_ref,
'hndl');
if (error != noErr) {
return NULL;
}
/* get the first sound track of the movie; other tracks will be ignored */
sound_track = GetMovieIndTrackType (movie, 1, SoundMediaType, movieTrackMediaType);
if (sound_track == NULL) {
/* movie needs a sound track! */
return NULL;
}
/* get and return the sound track media */
sound_track_media = GetTrackMedia (sound_track);
if (sound_track_media == NULL) {
return NULL;
}
/* create a description of the source sound so we can convert it later */
source_sound_description = (SoundDescriptionV1Handle)NewHandle(0);
assert (source_sound_description != NULL); /* out of memory */
GetMediaSampleDescription (sound_track_media, 1,
(SampleDescriptionHandle)source_sound_description);
error = GetMoviesError();
if (error != noErr) {
return NULL;
}
source_sound_description_extension = NewHandle(0);
assert (source_sound_description_extension != NULL); /* out of memory */
error = GetSoundDescriptionExtension ((SoundDescriptionHandle) source_sound_description,
&source_sound_description_extension,
siDecompressionParams);
if (error == noErr) {
/* copy extension to atom format description if we have an extension */
source_sound_description_extension_size =
GetHandleSize (source_sound_description_extension);
HLock (source_sound_description_extension);
source_sound_decomp_atom = (AudioFormatAtom*)
NewPtr (source_sound_description_extension_size);
assert (source_sound_decomp_atom != NULL); /* out of memory */
BlockMoveData (*source_sound_description_extension,
source_sound_decomp_atom,
source_sound_description_extension_size);
HUnlock (source_sound_description_extension);
}
else {
source_sound_decomp_atom = NULL;
}
instance = (qt_t*) malloc (sizeof(*instance));
assert (instance != NULL); /* out of memory */
instance->movie = movie;
instance->track = sound_track;
instance->media = sound_track_media;
instance->atom = source_sound_decomp_atom;
instance->source_format.flags = 0;
instance->source_format.format = (*source_sound_description)->desc.dataFormat;
instance->source_format.numChannels = (*source_sound_description)->desc.numChannels;
instance->source_format.sampleSize = (*source_sound_description)->desc.sampleSize;
instance->source_format.sampleRate = (*source_sound_description)->desc.sampleRate;
instance->source_format.sampleCount = 0;
instance->source_format.buffer = NULL;
instance->source_format.reserved = 0;
instance->dest_format.flags = 0;
instance->dest_format.format = kSoundNotCompressed;
instance->dest_format.numChannels = (*source_sound_description)->desc.numChannels;
instance->dest_format.sampleSize = (*source_sound_description)->desc.sampleSize;
instance->dest_format.sampleRate = (*source_sound_description)->desc.sampleRate;
instance->dest_format.sampleCount = 0;
instance->dest_format.buffer = NULL;
instance->dest_format.reserved = 0;
sample->actual.channels = (*source_sound_description)->desc.numChannels;
sample->actual.rate = (*source_sound_description)->desc.sampleRate >> 16;
if ((*source_sound_description)->desc.sampleSize == 16) {
sample->actual.format = AUDIO_S16SYS;
}
else if ((*source_sound_description)->desc.sampleSize == 8) {
sample->actual.format = AUDIO_U8;
}
else {
/* 24-bit or others... (which SDL can't handle) */
return NULL;
}
DisposeHandle (source_sound_description_extension);
DisposeHandle ((Handle)source_sound_description);
/* This next code sets up the SoundConverter component */
error = SoundConverterOpen (&instance->source_format, &instance->dest_format,
&instance->converter);
if (error != noErr) {
return NULL;
}
error = SoundConverterSetInfo (instance->converter, siDecompressionParams,
instance->atom);
if (error == siUnknownInfoType) {
/* ignore */
}
else if (error != noErr) {
/* reall error */
return NULL;
}
error = SoundConverterBeginConversion (instance->converter);
if (error != noErr) {
return NULL;
}
instance->buffer_data.sourceMedia = instance->media;
instance->buffer_data.getMediaAtThisTime = 0;
instance->buffer_data.sourceDuration = GetMediaDuration(instance->media);
instance->buffer_data.isThereMoreSource = true;
instance->buffer_data.maxBufferSize = QT_MAX_INPUT_BUFFER;
/* allocate source media buffer */
instance->buffer_data.hSource = NewHandle((long)instance->buffer_data.maxBufferSize);
assert (instance->buffer_data.hSource != NULL); /* out of memory */
instance->buffer_data.compData.desc = instance->source_format;
instance->buffer_data.compData.desc.buffer = (Byte *)*instance->buffer_data.hSource;
instance->buffer_data.compData.desc.flags = kExtendedSoundData;
instance->buffer_data.compData.recordSize = sizeof(ExtendedSoundComponentData);
instance->buffer_data.compData.extendedFlags =
kExtendedSoundSampleCountNotValid | kExtendedSoundBufferSizeValid;
instance->buffer_data.compData.bufferSize = 0;
instance->fill_buffer_proc =
NewSoundConverterFillBufferDataUPP (QT_sound_converter_fill_buffer_data_proc);
return (instance);
} /* QT_open_internal */
static void QT_close_internal (qt_t *instance)
{
} /* QT_close_internal */
static Uint32 QT_read_internal(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
qt_t *instance = (qt_t*) internal->decoder_private;
long output_bytes, output_frames, output_flags;
OSErr error;
error = SoundConverterFillBuffer
(instance->converter, /* a sound converter */
instance->fill_buffer_proc, /* the callback UPP */
&instance->buffer_data, /* refCon passed to FillDataProc */
internal->buffer, /* the decompressed data 'play' buffer */
internal->buffer_size, /* size of the 'play' buffer */
&output_bytes, /* number of output bytes */
&output_frames, /* number of output frames */
&output_flags); /* fillbuffer retured advisor flags */
if (output_flags & kSoundConverterHasLeftOverData) {
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
}
else {
sample->flags |= SOUND_SAMPLEFLAG_EOF;
}
if (error != noErr) {
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
}
return (output_bytes);
} /* QT_read_internal */
static int QT_rewind_internal (Sound_Sample *sample)
{
return 0;
} /* QT_rewind_internal */
static int QT_init(void)
{
return (QT_init_internal());
} /* QT_init */
static void QT_quit(void)
{
QT_quit_internal();
} /* QT_quit */
static int QT_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
qt_t *instance;
instance = QT_open_internal(sample, ext);
internal->decoder_private = (void*)instance;
return(instance != NULL);
} /* QT_open */
static void QT_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
qt_t *instance = (qt_t *) internal->decoder_private;
QT_close_internal (instance);
free (instance);
} /* QT_close */
static Uint32 QT_read(Sound_Sample *sample)
{
return(QT_read_internal(sample));
} /* QT_read */
static int QT_rewind(Sound_Sample *sample)
{
return(QT_rewind_internal(sample));
} /* QT_rewind */
static int QT_seek(Sound_Sample *sample, Uint32 ms)
{
BAIL_MACRO("QUICKTIME: Seeking not implemented", 0);
} /* QT_seek */
#endif /* SOUND_SUPPORTS_QUICKTIME */
/* end of quicktime.c ... */

View File

@@ -0,0 +1,184 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* RAW decoder for SDL_sound. This is as simple as it gets.
*
* This driver handles raw audio data. You must, regardless of where the
* data is actually coming from, specify the string "RAW" in the extension
* parameter of Sound_NewSample() (or, alternately, open a file with the
* extension ".raw" in Sound_NewSampleFromFile()). The string is checked
* case-insensitive. We need this check, because raw data, being raw, has
* no headers or magic number we can use to determine if we should handle a
* given file, so we needed some way to have this "decoder" discriminate.
*
* When calling Sound_NewSample*(), you must also specify a "desired"
* audio format. The "actual" format will always match what you specify, so
* there will be no conversion overhead, but these routines need to know how
* to treat the bits, since it's all random garbage otherwise.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_RAW
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int RAW_init(void);
static void RAW_quit(void);
static int RAW_open(Sound_Sample *sample, const char *ext);
static void RAW_close(Sound_Sample *sample);
static Uint32 RAW_read(Sound_Sample *sample);
static int RAW_rewind(Sound_Sample *sample);
static int RAW_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_raw[] = { "RAW", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW =
{
{
extensions_raw,
"Raw audio",
"Ryan C. Gordon <icculus@icculus.org>",
"http://www.icculus.org/SDL_sound/"
},
RAW_init, /* init() method */
RAW_quit, /* quit() method */
RAW_open, /* open() method */
RAW_close, /* close() method */
RAW_read, /* read() method */
RAW_rewind, /* rewind() method */
RAW_seek /* seek() method */
};
static int RAW_init(void)
{
return(1); /* always succeeds. */
} /* RAW_init */
static void RAW_quit(void)
{
/* it's a no-op. */
} /* RAW_quit */
static int RAW_open(Sound_Sample *sample, const char *ext)
{
/*
* We check this explicitly, since we have no other way to
* determine whether we should handle this data or not.
*/
if (__Sound_strcasecmp(ext, "RAW") != 0)
BAIL_MACRO("RAW: extension isn't explicitly \"RAW\".", 0);
/*
* You must also specify a desired format, so we know how to
* treat the bits that are otherwise binary garbage.
*/
if ( (sample->desired.channels < 1) ||
(sample->desired.channels > 2) ||
(sample->desired.rate == 0) ||
(sample->desired.format == 0) )
{
BAIL_MACRO("RAW: invalid desired format.", 0);
} /* if */
SNDDBG(("RAW: Accepting data stream.\n"));
/*
* We never convert raw samples; what you ask for is what you get.
*/
memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo));
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
return(1); /* we'll handle this data. */
} /* RAW_open */
static void RAW_close(Sound_Sample *sample)
{
/* we don't allocate anything that we need to free. That's easy, eh? */
} /* RAW_close */
static Uint32 RAW_read(Sound_Sample *sample)
{
Uint32 retval;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
/*
* We don't actually do any decoding, so we read the raw data
* directly into the internal buffer...
*/
retval = SDL_RWread(internal->rw, internal->buffer,
1, internal->buffer_size);
/* Make sure the read went smoothly... */
if (retval == 0)
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else if (retval == -1)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
/* (next call this EAGAIN may turn into an EOF or error.) */
else if (retval < internal->buffer_size)
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
return(retval);
} /* RAW_read */
static int RAW_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
BAIL_IF_MACRO(SDL_RWseek(internal->rw, 0, SEEK_SET) != 0, ERR_IO_ERROR, 0);
return(1);
} /* RAW_rewind */
static int RAW_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
int pos = (int) __Sound_convertMsToBytePos(&sample->actual, ms);
int err = (SDL_RWseek(internal->rw, pos, SEEK_SET) != pos);
BAIL_IF_MACRO(err, ERR_IO_ERROR, 0);
return(1);
} /* RAW_seek */
#endif /* SOUND_SUPPORTS_RAW */
/* end of raw.c ... */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* MPEG-1 Layer 3, or simply, "MP3", decoder for SDL_sound.
*
* This driver handles all those highly compressed songs you stole through
* Napster. :) It depends on the SMPEG library for decoding, which can
* be grabbed from: http://www.lokigames.com/development/smpeg.php3
*
* This should also be able to extract the audio stream from an MPEG movie.
*
* There is an alternative MP3 decoder available, called "mpglib", which
* doesn't depend on external libraries (the decoder itself is part of
* SDL_sound), and may be more efficient, but less flexible than SMPEG. YMMV.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_SMPEG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "smpeg.h"
#include "extra_rwops.h"
static int _SMPEG_init(void);
static void _SMPEG_quit(void);
static int _SMPEG_open(Sound_Sample *sample, const char *ext);
static void _SMPEG_close(Sound_Sample *sample);
static Uint32 _SMPEG_read(Sound_Sample *sample);
static int _SMPEG_rewind(Sound_Sample *sample);
static int _SMPEG_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_smpeg[] = { "MP3", "MPEG", "MPG", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_SMPEG =
{
{
extensions_smpeg,
"MPEG-1 Layer 3 audio through SMPEG",
"Ryan C. Gordon <icculus@icculus.org>",
"http://icculus.org/smpeg/"
},
_SMPEG_init, /* init() method */
_SMPEG_quit, /* quit() method */
_SMPEG_open, /* open() method */
_SMPEG_close, /* close() method */
_SMPEG_read, /* read() method */
_SMPEG_rewind, /* rewind() method */
_SMPEG_seek /* seek() method */
};
static int _SMPEG_init(void)
{
return(1); /* always succeeds. */
} /* _SMPEG_init */
static void _SMPEG_quit(void)
{
/* it's a no-op. */
} /* _SMPEG_quit */
static __inline__ void output_version(void)
{
static int first_time = 1;
if (first_time)
{
SMPEG_version v;
SMPEG_VERSION(&v);
SNDDBG(("SMPEG: Compiled against SMPEG v%d.%d.%d.\n",
v.major, v.minor, v.patch));
first_time = 0;
} /* if */
} /* output_version */
static int _SMPEG_open(Sound_Sample *sample, const char *ext)
{
SMPEG *smpeg;
SMPEG_Info smpeg_info;
SDL_AudioSpec spec;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *refCounter;
const char *err = NULL;
output_version();
/*
* If I understand things correctly, MP3 files don't really have any
* magic header we can check for. The MP3 player is expected to just
* pick the first thing that looks like a valid frame and start
* playing from there.
*
* So here's what we do: If the caller insists that this is really
* MP3 we'll take his word for it. Otherwise, use the same test as
* SDL_mixer does and check if the stream starts with something that
* looks like a frame.
*
* A frame begins with 11 bits of frame sync (all bits must be set),
* followed by a two-bit MPEG Audio version ID:
*
* 00 - MPEG Version 2.5 (later extension of MPEG 2)
* 01 - reserved
* 10 - MPEG Version 2 (ISO/IEC 13818-3)
* 11 - MPEG Version 1 (ISO/IEC 11172-3)
*
* Apparently we don't handle MPEG Version 2.5.
*/
if (__Sound_strcasecmp(ext, "MP3") != 0)
{
Uint8 mp3_magic[2];
if (SDL_RWread(internal->rw, mp3_magic, sizeof (mp3_magic), 1) != 1)
BAIL_MACRO("SMPEG: Could not read MP3 magic.", 0);
if (mp3_magic[0] != 0xFF || (mp3_magic[1] & 0xF0) != 0xF0)
BAIL_MACRO("SMPEG: Not an MP3 stream.", 0);
/* If the seek fails, we'll probably miss a frame, but oh well */
SDL_RWseek(internal->rw, -sizeof (mp3_magic), SEEK_CUR);
} /* if */
refCounter = RWops_RWRefCounter_new(internal->rw);
if (refCounter == NULL)
{
SNDDBG(("SMPEG: Failed to create reference counting RWops.\n"));
return(0);
} /* if */
/* replace original RWops. This is safe. Honest. :) */
internal->rw = refCounter;
/*
* increment the refcount, since SMPEG will nuke the RWops if it can't
* accept the contained data...
*/
RWops_RWRefCounter_addRef(refCounter);
smpeg = SMPEG_new_rwops(refCounter, &smpeg_info, 0);
err = SMPEG_error(smpeg);
if (err != NULL)
{
__Sound_SetError(err); /* make a copy before SMPEG_delete()... */
SMPEG_delete(smpeg);
return(0);
} /* if */
if (!smpeg_info.has_audio)
{
SMPEG_delete(smpeg);
BAIL_MACRO("SMPEG: No audio stream found in data.", 0);
} /* if */
SNDDBG(("SMPEG: Accepting data stream.\n"));
SNDDBG(("SMPEG: has_audio == {%s}.\n", smpeg_info.has_audio ? "TRUE" : "FALSE"));
SNDDBG(("SMPEG: has_video == {%s}.\n", smpeg_info.has_video ? "TRUE" : "FALSE"));
SNDDBG(("SMPEG: width == (%d).\n", smpeg_info.width));
SNDDBG(("SMPEG: height == (%d).\n", smpeg_info.height));
SNDDBG(("SMPEG: current_frame == (%d).\n", smpeg_info.current_frame));
SNDDBG(("SMPEG: current_fps == (%f).\n", smpeg_info.current_fps));
SNDDBG(("SMPEG: audio_string == [%s].\n", smpeg_info.audio_string));
SNDDBG(("SMPEG: audio_current_frame == (%d).\n", smpeg_info.audio_current_frame));
SNDDBG(("SMPEG: current_offset == (%d).\n", smpeg_info.current_offset));
SNDDBG(("SMPEG: total_size == (%d).\n", smpeg_info.total_size));
SNDDBG(("SMPEG: current_time == (%f).\n", smpeg_info.current_time));
SNDDBG(("SMPEG: total_time == (%f).\n", smpeg_info.total_time));
SMPEG_enablevideo(smpeg, 0);
SMPEG_enableaudio(smpeg, 1);
SMPEG_loop(smpeg, 0);
SMPEG_wantedSpec(smpeg, &spec);
/*
* One of the MP3s I tried wouldn't work unless I added this line
* to tell SMPEG that yes, it may have the spec it wants.
*/
SMPEG_actualSpec(smpeg, &spec);
sample->actual.format = spec.format;
sample->actual.rate = spec.freq;
sample->actual.channels = spec.channels;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
internal->decoder_private = smpeg;
SMPEG_play(smpeg);
return(1);
} /* _SMPEG_open */
static void _SMPEG_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SMPEG_delete((SMPEG *) internal->decoder_private);
} /* _SMPEG_close */
static Uint32 _SMPEG_read(Sound_Sample *sample)
{
Uint32 retval;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SMPEG *smpeg = (SMPEG *) internal->decoder_private;
/*
* We have to clear the buffer because apparently SMPEG_playAudio()
* will mix the decoded audio with whatever's already in it. Nasty.
*/
memset(internal->buffer, '\0', internal->buffer_size);
retval = SMPEG_playAudio(smpeg, internal->buffer, internal->buffer_size);
if (retval < internal->buffer_size)
{
char *errMsg = SMPEG_error(smpeg);
if (errMsg == NULL)
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else
{
__Sound_SetError(errMsg);
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
} /* else */
} /* if */
return(retval);
} /* _SMPEG_read */
static int _SMPEG_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SMPEG *smpeg = (SMPEG *) internal->decoder_private;
SMPEGstatus status;
/*
* SMPEG_rewind() really means "stop and rewind", so we may have to
* restart it afterwards.
*/
status = SMPEG_status(smpeg);
SMPEG_rewind(smpeg);
/* EW: I think SMPEG_play() has an independent and unrelated meaning
* to the flag, "SMPEG_PLAYING". This is why the SMPEG_play() call
* is done in the open() function even though the file is not yet
* technically playing. I believe SMPEG_play() must always be active
* because this seems to be what's causing the:
* "Can't rewind after the file has finished playing once" problem,
* because always recalling it here seems to make the problem go away.
*/
/*
if (status == SMPEG_PLAYING)
SMPEG_play(smpeg);
*/
SMPEG_play(smpeg);
return(1);
} /* _SMPEG_rewind */
static int _SMPEG_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SMPEG *smpeg = (SMPEG *) internal->decoder_private;
SMPEGstatus status;
/*
* SMPEG_rewind() really means "stop and rewind", so we may have to
* restart it afterwards.
*/
status = SMPEG_status(smpeg);
SMPEG_rewind(smpeg);
SMPEG_skip(smpeg, ((float) ms) / 1000.0);
if (status == SMPEG_PLAYING)
SMPEG_play(smpeg);
return(1);
} /* _SMPEG_seek */
#endif /* SOUND_SUPPORTS_SMPEG */
/* end of smpeg.c ... */

View File

@@ -0,0 +1,436 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Speex decoder for SDL_sound.
*
* This driver handles Speex audio data. Speex is a codec for speech that is
* meant to be transmitted over narrowband network connections. Epic Games
* estimates that their VoIP solution, built on top of Speex, uses around
* 500 bytes per second or less to transmit relatively good sounding speech.
*
* This decoder processes the .spx files that the speexenc program produces.
*
* Speex isn't meant for general audio compression. Something like Ogg Vorbis
* will give better results in that case.
*
* Further Speex information can be found at http://www.speex.org/
*
* This code is based on speexdec.c (see the Speex website).
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_SPEEX
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ogg/ogg.h>
#include <speex/speex.h>
#include <speex/speex_header.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int SPEEX_init(void);
static void SPEEX_quit(void);
static int SPEEX_open(Sound_Sample *sample, const char *ext);
static void SPEEX_close(Sound_Sample *sample);
static Uint32 SPEEX_read(Sound_Sample *sample);
static int SPEEX_rewind(Sound_Sample *sample);
static int SPEEX_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_speex[] = { "spx", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_SPEEX =
{
{
extensions_speex,
"SPEEX speech compression format",
"Ryan C. Gordon <icculus@icculus.org>",
"http://www.icculus.org/SDL_sound/"
},
SPEEX_init, /* init() method */
SPEEX_quit, /* quit() method */
SPEEX_open, /* open() method */
SPEEX_close, /* close() method */
SPEEX_read, /* read() method */
SPEEX_rewind, /* rewind() method */
SPEEX_seek /* seek() method */
};
#define SPEEX_USE_PERCEPTUAL_ENHANCER 1
#define SPEEX_MAGIC 0x5367674F /* "OggS" in ASCII (littleendian) */
#define SPEEX_OGG_BUFSIZE 200
/* this is what we store in our internal->decoder_private field... */
typedef struct
{
ogg_sync_state oy;
ogg_page og;
ogg_packet op;
ogg_stream_state os;
void *state;
SpeexBits bits;
int header_count;
int frame_size;
int nframes;
int frames_avail;
float *decode_buf;
int decode_total;
int decode_pos;
int have_ogg_packet;
} speex_t;
static int SPEEX_init(void)
{
return(1); /* no-op. */
} /* SPEEX_init */
static void SPEEX_quit(void)
{
/* no-op. */
} /* SPEEX_quit */
static int process_header(speex_t *speex, Sound_Sample *sample)
{
SpeexMode *mode;
SpeexHeader *hptr;
SpeexHeader header;
int enh_enabled = SPEEX_USE_PERCEPTUAL_ENHANCER;
int tmp;
hptr = speex_packet_to_header((char*) speex->op.packet, speex->op.bytes);
BAIL_IF_MACRO(!hptr, "SPEEX: Cannot read header", 0);
memcpy(&header, hptr, sizeof (SpeexHeader)); /* move to stack. */
free(hptr); /* lame that this forces you to malloc... */
BAIL_IF_MACRO(header.mode >= SPEEX_NB_MODES, "SPEEX: Unknown mode", 0);
BAIL_IF_MACRO(header.mode < 0, "SPEEX: Unknown mode", 0);
mode = speex_mode_list[header.mode];
BAIL_IF_MACRO(header.speex_version_id > 1, "SPEEX: Unknown version", 0);
BAIL_IF_MACRO(mode->bitstream_version < header.mode_bitstream_version,
"SPEEX: Unsupported bitstream version", 0);
BAIL_IF_MACRO(mode->bitstream_version > header.mode_bitstream_version,
"SPEEX: Unsupported bitstream version", 0);
speex->state = speex_decoder_init(mode);
BAIL_IF_MACRO(!speex->state, "SPEEX: Decoder initialization error", 0);
speex_decoder_ctl(speex->state, SPEEX_SET_ENH, &enh_enabled);
speex_decoder_ctl(speex->state, SPEEX_GET_FRAME_SIZE, &speex->frame_size);
speex->decode_buf = (float *) malloc(speex->frame_size * sizeof (float));
BAIL_IF_MACRO(!speex->decode_buf, ERR_OUT_OF_MEMORY, 0);
speex->nframes = header.frames_per_packet;
if (!speex->nframes)
speex->nframes = 1;
/* !!! FIXME: Write converters to match desired format.
!!! FIXME: We have to convert from Float32 anyhow. */
/* !!! FIXME: Is it a performance hit to alter sampling rate?
!!! FIXME: If not, try to match desired rate. */
/* !!! FIXME: We force mono output, but speexdec.c has code for stereo.
!!! FIXME: Use that if sample->desired.channels == 2? */
tmp = header.rate;
speex_decoder_ctl(speex->state, SPEEX_SET_SAMPLING_RATE, &tmp);
speex_decoder_ctl(speex->state, SPEEX_GET_SAMPLING_RATE, &tmp);
sample->actual.rate = tmp;
sample->actual.channels = 1;
sample->actual.format = AUDIO_S16SYS;
SNDDBG(("SPEEX: %dHz, mono, %svbr, %s mode.\n",
(int) sample->actual.rate,
header.vbr ? "" : "not ",
mode->modeName));
/* plus 2: one for this header, one for the comment header. */
speex->header_count = header.extra_headers + 2;
return(1);
} /* process_header */
/* !!! FIXME: this code sucks. */
static int SPEEX_open(Sound_Sample *sample, const char *ext)
{
int set_error_str = 1;
int bitstream_initialized = 0;
Uint8 *buffer = NULL;
int packet_count = 0;
speex_t *speex = NULL;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *rw = internal->rw;
Uint32 magic;
/* Quick rejection. */
/*
* !!! FIXME: If (ext) is .spx, ignore bad magic number and assume
* !!! FIXME: this is a corrupted file...try to sync up further in
* !!! FIXME: stream. But for general purposes we can't read the
* !!! FIXME: whole RWops here in case it's not a Speex file at all.
*/
magic = SDL_ReadLE32(rw); /* make sure this is an ogg stream. */
BAIL_IF_MACRO(magic != SPEEX_MAGIC, "SPEEX: Not a complete ogg stream", 0);
BAIL_IF_MACRO(SDL_RWseek(rw, -4, SEEK_CUR) < 0, ERR_IO_ERROR, 0);
speex = (speex_t *) malloc(sizeof (speex_t));
BAIL_IF_MACRO(speex == NULL, ERR_OUT_OF_MEMORY, 0);
memset(speex, '\0', sizeof (speex_t));
speex_bits_init(&speex->bits);
if (ogg_sync_init(&speex->oy) != 0) goto speex_open_failed;
while (1)
{
int rc;
Uint8 *buffer = (Uint8*)ogg_sync_buffer(&speex->oy, SPEEX_OGG_BUFSIZE);
if (buffer == NULL) goto speex_open_failed;
rc = SDL_RWread(rw, buffer, 1, SPEEX_OGG_BUFSIZE);
if (rc <= 0) goto speex_open_failed;
if (ogg_sync_wrote(&speex->oy, rc) != 0) goto speex_open_failed;
while (ogg_sync_pageout(&speex->oy, &speex->og) == 1)
{
if (!bitstream_initialized)
{
if (ogg_stream_init(&speex->os, ogg_page_serialno(&speex->og)))
goto speex_open_failed;
bitstream_initialized = 1;
} /* if */
if (ogg_stream_pagein(&speex->os, &speex->og) != 0)
goto speex_open_failed;
while (ogg_stream_packetout(&speex->os, &speex->op) == 1)
{
if (speex->op.e_o_s)
goto speex_open_failed; /* end of stream already?! */
packet_count++;
if (packet_count == 1) /* need speex header. */
{
if (!process_header(speex, sample))
{
set_error_str = 0; /* process_header will set error string. */
goto speex_open_failed;
} /* if */
} /* if */
if (packet_count > speex->header_count)
{
/* if you made it here, you're ready to get a waveform. */
SNDDBG(("SPEEX: Accepting data stream.\n"));
/* sample->actual is configured in process_header()... */
speex->have_ogg_packet = 1;
sample->flags = SOUND_SAMPLEFLAG_NONE;
internal->decoder_private = speex;
return(1); /* we'll handle this data. */
} /* if */
} /* while */
} /* while */
} /* while */
assert(0); /* shouldn't hit this point. */
speex_open_failed:
if (speex != NULL)
{
if (speex->state != NULL)
speex_decoder_destroy(speex->state);
if (bitstream_initialized)
ogg_stream_clear(&speex->os);
speex_bits_destroy(&speex->bits);
ogg_sync_clear(&speex->oy);
free(speex->decode_buf);
free(speex);
} /* if */
if (set_error_str)
BAIL_MACRO("SPEEX: decoding error", 0);
return(0);
} /* SPEEX_open */
static void SPEEX_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
speex_t *speex = (speex_t *) internal->decoder_private;
speex_decoder_destroy(speex->state);
ogg_stream_clear(&speex->os);
speex_bits_destroy(&speex->bits);
ogg_sync_clear(&speex->oy);
free(speex->decode_buf);
free(speex);
} /* SPEEX_close */
static Uint32 copy_from_decoded(speex_t *speex,
Sound_SampleInternal *internal,
Uint32 _cpypos)
{
/*
* !!! FIXME: Obviously, this all needs to change if we allow for
* !!! FIXME: more than mono, S16SYS data.
*/
Uint32 cpypos = _cpypos >> 1;
Sint16 *dst = ((Sint16 *) internal->buffer) + cpypos;
Sint16 *max;
Uint32 maxoutput = (internal->buffer_size >> 1) - cpypos;
Uint32 maxavail = speex->decode_total - speex->decode_pos;
float *src = speex->decode_buf + speex->decode_pos;
if (maxavail < maxoutput)
maxoutput = maxavail;
speex->decode_pos += maxoutput;
cpypos += maxoutput;
for (max = dst + maxoutput; dst < max; dst++, src++)
{
/* !!! FIXME: This screams for vectorization. */
register float f = *src;
if (f > 32000.0f) /* eh, speexdec.c clamps like this, too. */
f = 32000.0f;
else if (f < -32000.0f)
f = -32000.0f;
*dst = (Sint16) (0.5f + f);
} /* for */
return(cpypos << 1);
} /* copy_from_decoded */
/* !!! FIXME: this code sucks. */
static Uint32 SPEEX_read(Sound_Sample *sample)
{
Uint32 retval = 0;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
speex_t *speex = (speex_t *) internal->decoder_private;
SDL_RWops *rw = internal->rw;
Uint8 *buffer;
int rc;
while (1)
{
/* see if there's some already-decoded leftovers... */
if (speex->decode_total != speex->decode_pos)
{
retval = copy_from_decoded(speex, internal, retval);
if (retval >= internal->buffer_size)
return(retval); /* whee. */
} /* if */
/* okay, decoded buffer is spent. What else do we have? */
speex->decode_total = speex->decode_pos = 0;
if (speex->frames_avail) /* have more frames to decode? */
{
rc = speex_decode(speex->state, &speex->bits, speex->decode_buf);
if (rc < 0) goto speex_read_failed;
if (speex_bits_remaining(&speex->bits) < 0) goto speex_read_failed;
speex->frames_avail--;
speex->decode_total = speex->frame_size;
continue; /* go fill the output buffer... */
} /* if */
/* need to get more speex frames from available ogg packets... */
if (speex->have_ogg_packet)
{
speex_bits_read_from(&speex->bits,
(char *) speex->op.packet,
speex->op.bytes);
speex->frames_avail += speex->nframes;
if (ogg_stream_packetout(&speex->os, &speex->op) <= 0)
speex->have_ogg_packet = 0;
continue; /* go decode these frames. */
} /* if */
/* need to get more ogg packets from bitstream... */
if (speex->op.e_o_s) /* okay, we're really spent. */
{
sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(retval);
} /* if */
while ((!speex->op.e_o_s) && (!speex->have_ogg_packet))
{
buffer = (Uint8 *) ogg_sync_buffer(&speex->oy, SPEEX_OGG_BUFSIZE);
if (buffer == NULL) goto speex_read_failed;
rc = SDL_RWread(rw, buffer, 1, SPEEX_OGG_BUFSIZE);
if (rc <= 0) goto speex_read_failed;
if (ogg_sync_wrote(&speex->oy, rc) != 0) goto speex_read_failed;
/* got complete ogg page? */
if (ogg_sync_pageout(&speex->oy, &speex->og) == 1)
{
if (ogg_stream_pagein(&speex->os, &speex->og) != 0)
goto speex_read_failed;
/* got complete ogg packet? */
if (ogg_stream_packetout(&speex->os, &speex->op) == 1)
speex->have_ogg_packet = 1;
} /* if */
} /* while */
} /* while */
assert(0); /* never hit this. Either return or goto speex_read_failed */
speex_read_failed:
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
/* !!! FIXME: "i/o error" is better in some situations. */
BAIL_MACRO("SPEEX: Decoding error", retval);
} /* SPEEX_read */
static int SPEEX_rewind(Sound_Sample *sample)
{
/* !!! FIXME */ return(0);
} /* SPEEX_rewind */
static int SPEEX_seek(Sound_Sample *sample, Uint32 ms)
{
/* !!! FIXME */ return(0);
} /* SPEEX_seek */
#endif /* SOUND_SUPPORTS_SPEEX */
/* end of speex.c ... */

View File

@@ -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()

View File

@@ -0,0 +1,519 @@
Please note that the included source from Timidity, the MIDI decoder, is also
licensed under the following terms (GNU LGPL), but can also be used
separately under the GNU GPL, or the Perl Artistic License. Those licensing
terms are not reprinted here, but can be found on the web easily.
If you want to use SDL_sound under a closed-source license, please contact
Ryan (icculus@icculus.org), and we can discuss an alternate license for
money to be distributed between the contributors to this work, but I'd
encourage you to abide by the LGPL, since the usual concern is whether you
can use this library without releasing your own source code (you can).
-------------------
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -0,0 +1,100 @@
---------------------------*-indented-text-*------------------------------
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
--------------------------------------------------------------------------
Frequently Asked Questions with answers:
--------------------------------------------------------------------------
Q: What is it?
A: Where? Well Chris, TiMidity is a software-only synthesizer, MIDI
renderer, MIDI to WAVE converter, realtime MIDI player for UNIX machines,
even (I've heard) a Netscape helper application. It takes a MIDI file
and writes a WAVE or raw PCM data or plays it on your digital audio
device. It sounds much more realistic than FM synthesis, but you need a
~100Mhz processor to listen to 32kHz stereo music in the background while
you work. 11kHz mono can be played on a low-end 486, and, to some, it
still sounds better than FM.
--------------------------------------------------------------------------
Q: I don't have a GUS, can I use TiMidity?
A: Yes. That's the point. You don't need a Gravis Ultrasound to use
TiMidity, you just need GUS-compatible patches, which are freely
available on the Internet. See below for pointers.
--------------------------------------------------------------------------
Q: I have a GUS, can I use TiMidity?
A: The DOS port doesn't have GUS support, and TiMidity won't be taking
advantage of the board's internal synthesizer under other operating
systems either. So it kind of defeats the purpose. But you can use it.
--------------------------------------------------------------------------
Q: I tried playing a MIDI file I got off the Net but all I got was a
dozen warnings saying "No instrument mapped to tone bank 0, program
xx - this instrument will not be heard". What's wrong?
A: The General MIDI standard specifies 128 melodic instruments and
some sixty percussion sounds. If you wish to play arbitrary General
MIDI files, you'll need to get more patch files.
There's a program called Midia for SGI's, which also plays MIDI
files and has a lot more bells and whistles than TiMidity. It uses
GUS-compatible patches, too -- so you can get the 8 MB set at
ftp://archive.cs.umbc.edu/pub/midia for pretty good GM compatibility.
There are also many excellent patches on the Ultrasound FTP sites.
I can recommend Dustin McCartney's collections gsdrum*.zip and
wow*.zip in the "[.../]sound/patches/files" directory. The huge
ProPats series (pp3-*.zip) contains good patches as well. General
MIDI files can also be found on these sites.
This site list is from the GUS FAQ:
> FTP Sites Archive Directories
> --------- -------------------
> Main N.American Site: archive.orst.edu pub/packages/gravis
> wuarchive.wustl.edu systems/ibmpc/ultrasound
> Main Asian Site: nctuccca.edu.tw PC/ultrasound
> Main European Site: src.doc.ic.ac.uk packages/ultrasound
> Main Australian Site: ftp.mpx.com.au /ultrasound/general
> /ultrasound/submit
> South African Site: ftp.sun.ac.za /pub/packages/ultrasound
> Submissions: archive.epas.utoronto.ca pub/pc/ultrasound/submit
> Newly Validated Files: archive.epas.utoronto.ca pub/pc/ultrasound
>
> Mirrors: garbo.uwasa.fi mirror/ultrasound
> ftp.st.nepean.uws.edu.au pc/ultrasound
> ftp.luth.se pub/msdos/ultrasound
--------------------------------------------------------------------------
Q: Some files have awful clicks and pops.
A: Find out which patch is responsible for the clicking (try "timidity
-P<patch> <midi/test-decay|midi/test-panning>". Add "strip=tail" in
the config file after its name. If this doesn't fix it, mail me the
patch.
--------------------------------------------------------------------------
Q: I'm playing Fantasie Impromptu in the background. When I run Netscape,
the sound gets choppy and it takes ten minutes to load. What can I do?
A: Here are some things to try:
- Use a lower sampling rate.
- Use mono output. This can improve performance by 10-30%.
(Using 8-bit instead of 16-bit output makes no difference.)
- Use a smaller number of simultaneous voices.
- Make sure you compiled with FAST_DECAY enabled in options.h
- Recompile with an Intel-optimized gcc for a 5-15%
performance increase.
--------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -0,0 +1,61 @@
[This version of timidity has been stripped for simplicity in porting to SDL,
and then even further for SDL_sound]
---------------------------------*-text-*---------------------------------
From http://www.cgs.fi/~tt/discontinued.html :
If you'd like to continue hacking on TiMidity, feel free. I'm
hereby extending the TiMidity license agreement: you can now
select the most convenient license for your needs from (1) the
GNU GPL, (2) the GNU LGPL, or (3) the Perl Artistic License.
--------------------------------------------------------------------------
This is the README file for TiMidity v0.2i
TiMidity is a MIDI to WAVE converter that uses Gravis
Ultrasound(*)-compatible patch files to generate digital audio data
from General MIDI files. The audio data can be played through any
sound device or stored on disk. On a fast machine, music can be
played in real time. TiMidity runs under Linux, FreeBSD, HP-UX, SunOS, and
Win32, and porting to other systems with gcc should be easy.
TiMidity Features:
* 32 or more dynamically allocated fully independent voices
* Compatibility with GUS patch files
* Output to 16- or 8-bit PCM or uLaw audio device, file, or
stdout at any sampling rate
* Optional interactive mode with real-time status display
under ncurses and SLang terminal control libraries. Also
a user friendly motif interface since version 0.2h
* Support for transparent loading of compressed MIDI files and
patch files
* Support for the following MIDI events:
- Program change
- Key pressure
- Channel main volume
- Tempo
- Panning
- Damper pedal (Sustain)
- Pitch wheel
- Pitch wheel sensitivity
- Change drum set
* The GNU General Public License can, as always, be found in the file
"../COPYING".
* TiMidity requires sampled instruments (patches) to play MIDI files. You
should get the file "timidity-lib-0.1.tar.gz" and unpack it in the same
directory where you unpacked the source code archive. You'll want more
patches later -- read the file "FAQ" for pointers.
* Timidity is no longer supported, but can be found by searching the web.
Tuukka Toivonen <toivonen@clinet.fi>
[(*) Any Registered Trademarks used anywhere in the documentation or
source code for TiMidity are acknowledged as belonging to their
respective owners.]

View File

@@ -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?

View File

@@ -0,0 +1,137 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
common.c
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "options.h"
#include "common.h"
/* The paths in this list will be tried whenever we're reading a file */
static PathList *pathlist = NULL; /* This is a linked list */
/* This is meant to find and open files for reading */
SDL_RWops *open_file(char *name)
{
SDL_RWops *rw;
if (!name || !(*name))
{
SNDDBG(("Attempted to open nameless file.\n"));
return 0;
}
/* First try the given name */
SNDDBG(("Trying to open %s\n", name));
if ((rw = SDL_RWFromFile(name, "rb")))
return rw;
if (name[0] != PATH_SEP)
{
char current_filename[1024];
PathList *plp = pathlist;
int l;
while (plp) /* Try along the path then */
{
*current_filename = 0;
l = strlen(plp->path);
if(l)
{
strcpy(current_filename, plp->path);
if(current_filename[l - 1] != PATH_SEP)
{
current_filename[l] = PATH_SEP;
current_filename[l + 1] = '\0';
}
}
strcat(current_filename, name);
SNDDBG(("Trying to open %s\n", current_filename));
if ((rw = SDL_RWFromFile(current_filename, "rb")))
return rw;
plp = plp->next;
}
}
/* Nothing could be opened. */
SNDDBG(("Could not open %s\n", name));
return 0;
}
/* This'll allocate memory or die. */
void *safe_malloc(size_t count)
{
void *p;
p = malloc(count);
if (p == NULL)
SNDDBG(("Sorry. Couldn't malloc %d bytes.\n", count));
return p;
}
/* This adds a directory to the path list */
void add_to_pathlist(char *s)
{
PathList *plp = safe_malloc(sizeof(PathList));
if (plp == NULL)
return;
plp->path = safe_malloc(strlen(s) + 1);
if (plp->path == NULL)
{
free(plp);
return;
}
strcpy(plp->path, s);
plp->next = pathlist;
pathlist = plp;
}
void free_pathlist(void)
{
PathList *plp = pathlist;
PathList *next;
while (plp)
{
next = plp->next;
free(plp->path);
free(plp);
plp = next;
}
pathlist = NULL;
}

View File

@@ -0,0 +1,32 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
common.h
*/
typedef struct {
char *path;
void *next;
} PathList;
extern SDL_RWops *open_file(char *name);
extern void add_to_pathlist(char *s);
extern void *safe_malloc(size_t count);
extern void free_pathlist(void);

View File

@@ -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 */

View File

@@ -0,0 +1,130 @@
/*
dls2.h
Description:
Interface defines and structures for the DLS2 extensions of DLS.
Written by Microsoft 1998. Released for public use.
*/
#ifndef _INC_DLS2
#define _INC_DLS2
/*
FOURCC's used in the DLS2 file, in addition to DLS1 chunks
*/
#define FOURCC_RGN2 mmioFOURCC('r','g','n','2')
#define FOURCC_LAR2 mmioFOURCC('l','a','r','2')
#define FOURCC_ART2 mmioFOURCC('a','r','t','2')
#define FOURCC_CDL mmioFOURCC('c','d','l',' ')
#define FOURCC_DLID mmioFOURCC('d','l','i','d')
/*
Articulation connection graph definitions. These are in addition to
the definitions in the DLS1 header.
*/
/* Generic Sources (in addition to DLS1 sources. */
#define CONN_SRC_POLYPRESSURE 0x0007 /* Polyphonic Pressure */
#define CONN_SRC_CHANNELPRESSURE 0x0008 /* Channel Pressure */
#define CONN_SRC_VIBRATO 0x0009 /* Vibrato LFO */
#define CONN_SRC_MONOPRESSURE 0x000a /* MIDI Mono pressure */
/* Midi Controllers */
#define CONN_SRC_CC91 0x00db /* Reverb Send */
#define CONN_SRC_CC93 0x00dd /* Chorus Send */
/* Generic Destinations */
#define CONN_DST_GAIN 0x0001 /* Same as CONN_DST_ ATTENUATION, but more appropriate terminology. */
#define CONN_DST_KEYNUMBER 0x0005 /* Key Number Generator */
/* Audio Channel Output Destinations */
#define CONN_DST_LEFT 0x0010 /* Left Channel Send */
#define CONN_DST_RIGHT 0x0011 /* Right Channel Send */
#define CONN_DST_CENTER 0x0012 /* Center Channel Send */
#define CONN_DST_LEFTREAR 0x0013 /* Left Rear Channel Send */
#define CONN_DST_RIGHTREAR 0x0014 /* Right Rear Channel Send */
#define CONN_DST_LFE_CHANNEL 0x0015 /* LFE Channel Send */
#define CONN_DST_CHORUS 0x0080 /* Chorus Send */
#define CONN_DST_REVERB 0x0081 /* Reverb Send */
/* Vibrato LFO Destinations */
#define CONN_DST_VIB_FREQUENCY 0x0114 /* Vibrato Frequency */
#define CONN_DST_VIB_STARTDELAY 0x0115 /* Vibrato Start Delay */
/* EG1 Destinations */
#define CONN_DST_EG1_DELAYTIME 0x020B /* EG1 Delay Time */
#define CONN_DST_EG1_HOLDTIME 0x020C /* EG1 Hold Time */
#define CONN_DST_EG1_SHUTDOWNTIME 0x020D /* EG1 Shutdown Time */
/* EG2 Destinations */
#define CONN_DST_EG2_DELAYTIME 0x030F /* EG2 Delay Time */
#define CONN_DST_EG2_HOLDTIME 0x0310 /* EG2 Hold Time */
/* Filter Destinations */
#define CONN_DST_FILTER_CUTOFF 0x0500 /* Filter Cutoff Frequency */
#define CONN_DST_FILTER_Q 0x0501 /* Filter Resonance */
/* Transforms */
#define CONN_TRN_CONVEX 0x0002 /* Convex Transform */
#define CONN_TRN_SWITCH 0x0003 /* Switch Transform */
/* Conditional chunk operators */
#define DLS_CDL_AND 0x0001 /* X = X & Y */
#define DLS_CDL_OR 0x0002 /* X = X | Y */
#define DLS_CDL_XOR 0x0003 /* X = X ^ Y */
#define DLS_CDL_ADD 0x0004 /* X = X + Y */
#define DLS_CDL_SUBTRACT 0x0005 /* X = X - Y */
#define DLS_CDL_MULTIPLY 0x0006 /* X = X * Y */
#define DLS_CDL_DIVIDE 0x0007 /* X = X / Y */
#define DLS_CDL_LOGICAL_AND 0x0008 /* X = X && Y */
#define DLS_CDL_LOGICAL_OR 0x0009 /* X = X || Y */
#define DLS_CDL_LT 0x000A /* X = (X < Y) */
#define DLS_CDL_LE 0x000B /* X = (X <= Y) */
#define DLS_CDL_GT 0x000C /* X = (X > Y) */
#define DLS_CDL_GE 0x000D /* X = (X >= Y) */
#define DLS_CDL_EQ 0x000E /* X = (X == Y) */
#define DLS_CDL_NOT 0x000F /* X = !X */
#define DLS_CDL_CONST 0x0010 /* 32-bit constant */
#define DLS_CDL_QUERY 0x0011 /* 32-bit value returned from query */
#define DLS_CDL_QUERYSUPPORTED 0x0012 /* Test to see if query is supported by synth */
/*
Loop and release
*/
#define WLOOP_TYPE_RELEASE 1
/*
WaveLink chunk <wlnk-ck>
*/
#define F_WAVELINK_MULTICHANNEL 0x0002
/*
DLSID queries for <cdl-ck>
*/
DEFINE_GUID(DLSID_GMInHardware, 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(DLSID_GSInHardware, 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(DLSID_XGInHardware, 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(DLSID_SupportsDLS1, 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(DLSID_SupportsDLS2, 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6);
DEFINE_GUID(DLSID_SampleMemorySize, 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12);
DEFINE_GUID(DLSID_ManufacturersID, 0xb03e1181, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
DEFINE_GUID(DLSID_ProductID, 0xb03e1182, 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
DEFINE_GUID(DLSID_SamplePlaybackRate, 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8);
#endif /* _INC_DLS2 */

View File

@@ -0,0 +1,623 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
instrum.c
Code to load and unload GUS-compatible instrument patches.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
#include "options.h"
#include "common.h"
#include "instrum.h"
#include "instrum_dls.h"
#include "resample.h"
#include "tables.h"
static void free_instrument(Instrument *ip)
{
Sample *sp;
int i;
if (!ip) return;
for (i=0; i<ip->samples; i++)
{
sp=&(ip->sample[i]);
free(sp->data);
}
free(ip->sample);
free(ip);
}
static void free_bank(MidiSong *song, int dr, int b)
{
int i;
ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]);
for (i=0; i<128; i++)
if (bank->instrument[i])
{
/* Not that this could ever happen, of course */
if (bank->instrument[i] != MAGIC_LOAD_INSTRUMENT)
free_instrument(bank->instrument[i]);
bank->instrument[i]=0;
}
}
static Sint32 convert_envelope_rate(MidiSong *song, Uint8 rate)
{
Sint32 r;
r = 3 - ((rate >> 6) & 0x3);
r *= 3;
r = (Sint32) (rate & 0x3f) << r; /* 6.9 fixed point */
/* 15.15 fixed point. */
r = ((r * 44100) / song->rate) * song->control_ratio;
#ifdef FAST_DECAY
return r << 10;
#else
return r << 9;
#endif
}
static Sint32 convert_envelope_offset(Uint8 offset)
{
/* This is not too good... Can anyone tell me what these values mean?
Are they GUS-style "exponential" volumes? And what does that mean? */
/* 15.15 fixed point */
return offset << (7+15);
}
static Sint32 convert_tremolo_sweep(MidiSong *song, Uint8 sweep)
{
if (!sweep)
return 0;
return
((song->control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
(song->rate * sweep);
}
static Sint32 convert_vibrato_sweep(MidiSong *song, Uint8 sweep,
Sint32 vib_control_ratio)
{
if (!sweep)
return 0;
return
(Sint32) (FSCALE((double) (vib_control_ratio) * SWEEP_TUNING, SWEEP_SHIFT)
/ (double)(song->rate * sweep));
/* this was overflowing with seashore.pat
((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
(song->rate * sweep); */
}
static Sint32 convert_tremolo_rate(MidiSong *song, Uint8 rate)
{
return
((SINE_CYCLE_LENGTH * song->control_ratio * rate) << RATE_SHIFT) /
(TREMOLO_RATE_TUNING * song->rate);
}
static Sint32 convert_vibrato_rate(MidiSong *song, Uint8 rate)
{
/* Return a suitable vibrato_control_ratio value */
return
(VIBRATO_RATE_TUNING * song->rate) /
(rate * 2 * VIBRATO_SAMPLE_INCREMENTS);
}
static void reverse_data(Sint16 *sp, Sint32 ls, Sint32 le)
{
Sint16 s, *ep=sp+le;
sp+=ls;
le-=ls;
le/=2;
while (le--)
{
s=*sp;
*sp++=*ep;
*ep--=s;
}
}
/*
If panning or note_to_use != -1, it will be used for all samples,
instead of the sample-specific values in the instrument file.
For note_to_use, any value <0 or >127 will be forced to 0.
For other parameters, 1 means yes, 0 means no, other values are
undefined.
TODO: do reverse loops right */
static Instrument *load_instrument(MidiSong *song, char *name, int percussion,
int panning, int amp, int note_to_use,
int strip_loop, int strip_envelope,
int strip_tail)
{
Instrument *ip;
Sample *sp;
SDL_RWops *rw;
char tmp[1024];
int i,j,noluck=0;
static char *patch_ext[] = PATCH_EXT_LIST;
if (!name) return 0;
/* Open patch file */
if ((rw=open_file(name)) == NULL)
{
noluck=1;
/* Try with various extensions */
for (i=0; patch_ext[i]; i++)
{
if (strlen(name)+strlen(patch_ext[i])<1024)
{
strcpy(tmp, name);
strcat(tmp, patch_ext[i]);
if ((rw=open_file(tmp)) != NULL)
{
noluck=0;
break;
}
}
}
}
if (noluck)
{
SNDDBG(("Instrument `%s' can't be found.\n", name));
return 0;
}
SNDDBG(("Loading instrument %s\n", tmp));
/* Read some headers and do cursory sanity checks. There are loads
of magic offsets. This could be rewritten... */
if ((239 != SDL_RWread(rw, tmp, 1, 239)) ||
(memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
differences are */
{
SNDDBG(("%s: not an instrument\n", name));
return 0;
}
if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers,
0 means 1 */
{
SNDDBG(("Can't handle patches with %d instruments\n", tmp[82]));
return 0;
}
if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
{
SNDDBG(("Can't handle instruments with %d layers\n", tmp[151]));
return 0;
}
ip=safe_malloc(sizeof(Instrument));
ip->samples = tmp[198];
ip->sample = safe_malloc(sizeof(Sample) * ip->samples);
for (i=0; i<ip->samples; i++)
{
Uint8 fractions;
Sint32 tmplong;
Uint16 tmpshort;
Uint8 tmpchar;
#define READ_CHAR(thing) \
if (1 != SDL_RWread(rw, &tmpchar, 1, 1)) goto fail; \
thing = tmpchar;
#define READ_SHORT(thing) \
if (1 != SDL_RWread(rw, &tmpshort, 2, 1)) goto fail; \
thing = SDL_SwapLE16(tmpshort);
#define READ_LONG(thing) \
if (1 != SDL_RWread(rw, &tmplong, 4, 1)) goto fail; \
thing = SDL_SwapLE32(tmplong);
SDL_RWseek(rw, 7, SEEK_CUR); /* Skip the wave name */
if (1 != SDL_RWread(rw, &fractions, 1, 1))
{
fail:
SNDDBG(("Error reading sample %d\n", i));
for (j=0; j<i; j++)
free(ip->sample[j].data);
free(ip->sample);
free(ip);
return 0;
}
sp=&(ip->sample[i]);
READ_LONG(sp->data_length);
READ_LONG(sp->loop_start);
READ_LONG(sp->loop_end);
READ_SHORT(sp->sample_rate);
READ_LONG(sp->low_freq);
READ_LONG(sp->high_freq);
READ_LONG(sp->root_freq);
sp->low_vel = 0;
sp->high_vel = 127;
SDL_RWseek(rw, 2, SEEK_CUR); /* Why have a "root frequency" and then
* "tuning"?? */
READ_CHAR(tmp[0]);
if (panning==-1)
sp->panning = (tmp[0] * 8 + 4) & 0x7f;
else
sp->panning=(Uint8)(panning & 0x7F);
/* envelope, tremolo, and vibrato */
if (18 != SDL_RWread(rw, tmp, 1, 18)) goto fail;
if (!tmp[13] || !tmp[14])
{
sp->tremolo_sweep_increment=
sp->tremolo_phase_increment=sp->tremolo_depth=0;
SNDDBG((" * no tremolo\n"));
}
else
{
sp->tremolo_sweep_increment=convert_tremolo_sweep(song, tmp[12]);
sp->tremolo_phase_increment=convert_tremolo_rate(song, tmp[13]);
sp->tremolo_depth=tmp[14];
SNDDBG((" * tremolo: sweep %d, phase %d, depth %d\n",
sp->tremolo_sweep_increment, sp->tremolo_phase_increment,
sp->tremolo_depth));
}
if (!tmp[16] || !tmp[17])
{
sp->vibrato_sweep_increment=
sp->vibrato_control_ratio=sp->vibrato_depth=0;
SNDDBG((" * no vibrato\n"));
}
else
{
sp->vibrato_control_ratio=convert_vibrato_rate(song, tmp[16]);
sp->vibrato_sweep_increment=
convert_vibrato_sweep(song, tmp[15], sp->vibrato_control_ratio);
sp->vibrato_depth=tmp[17];
SNDDBG((" * vibrato: sweep %d, ctl %d, depth %d\n",
sp->vibrato_sweep_increment, sp->vibrato_control_ratio,
sp->vibrato_depth));
}
READ_CHAR(sp->modes);
SDL_RWseek(rw, 40, SEEK_CUR); /* skip the useless scale frequency, scale
factor (what's it mean?), and reserved
space */
/* Mark this as a fixed-pitch instrument if such a deed is desired. */
if (note_to_use!=-1)
sp->note_to_use=(Uint8)(note_to_use);
else
sp->note_to_use=0;
/* seashore.pat in the Midia patch set has no Sustain. I don't
understand why, and fixing it by adding the Sustain flag to
all looped patches probably breaks something else. We do it
anyway. */
if (sp->modes & MODES_LOOPING)
sp->modes |= MODES_SUSTAIN;
/* Strip any loops and envelopes we're permitted to */
if ((strip_loop==1) &&
(sp->modes & (MODES_SUSTAIN | MODES_LOOPING |
MODES_PINGPONG | MODES_REVERSE)))
{
SNDDBG((" - Removing loop and/or sustain\n"));
sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING |
MODES_PINGPONG | MODES_REVERSE);
}
if (strip_envelope==1)
{
if (sp->modes & MODES_ENVELOPE)
SNDDBG((" - Removing envelope\n"));
sp->modes &= ~MODES_ENVELOPE;
}
else if (strip_envelope != 0)
{
/* Have to make a guess. */
if (!(sp->modes & (MODES_LOOPING | MODES_PINGPONG | MODES_REVERSE)))
{
/* No loop? Then what's there to sustain? No envelope needed
either... */
sp->modes &= ~(MODES_SUSTAIN|MODES_ENVELOPE);
SNDDBG((" - No loop, removing sustain and envelope\n"));
}
else if (!memcmp(tmp, "??????", 6) || tmp[11] >= 100)
{
/* Envelope rates all maxed out? Envelope end at a high "offset"?
That's a weird envelope. Take it out. */
sp->modes &= ~MODES_ENVELOPE;
SNDDBG((" - Weirdness, removing envelope\n"));
}
else if (!(sp->modes & MODES_SUSTAIN))
{
/* No sustain? Then no envelope. I don't know if this is
justified, but patches without sustain usually don't need the
envelope either... at least the Gravis ones. They're mostly
drums. I think. */
sp->modes &= ~MODES_ENVELOPE;
SNDDBG((" - No sustain, removing envelope\n"));
}
}
for (j=0; j<6; j++)
{
sp->envelope_rate[j]=
convert_envelope_rate(song, tmp[j]);
sp->envelope_offset[j]=
convert_envelope_offset(tmp[6+j]);
}
/* Then read the sample data */
sp->data = safe_malloc(sp->data_length);
if (1 != SDL_RWread(rw, sp->data, sp->data_length, 1))
goto fail;
if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
{
Sint32 i=sp->data_length;
Uint8 *cp=(Uint8 *)(sp->data);
Uint16 *tmp,*new;
tmp=new=safe_malloc(sp->data_length*2);
while (i--)
*tmp++ = (Uint16)(*cp++) << 8;
cp=(Uint8 *)(sp->data);
sp->data = (sample_t *)new;
free(cp);
sp->data_length *= 2;
sp->loop_start *= 2;
sp->loop_end *= 2;
}
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
else
/* convert to machine byte order */
{
Sint32 i=sp->data_length/2;
Sint16 *tmp=(Sint16 *)sp->data,s;
while (i--)
{
s=SDL_SwapLE16(*tmp);
*tmp++=s;
}
}
#endif
if (sp->modes & MODES_UNSIGNED) /* convert to signed data */
{
Sint32 i=sp->data_length/2;
Sint16 *tmp=(Sint16 *)sp->data;
while (i--)
*tmp++ ^= 0x8000;
}
/* Reverse reverse loops and pass them off as normal loops */
if (sp->modes & MODES_REVERSE)
{
Sint32 t;
/* The GUS apparently plays reverse loops by reversing the
whole sample. We do the same because the GUS does not SUCK. */
SNDDBG(("Reverse loop in %s\n", name));
reverse_data((Sint16 *)sp->data, 0, sp->data_length/2);
t=sp->loop_start;
sp->loop_start=sp->data_length - sp->loop_end;
sp->loop_end=sp->data_length - t;
sp->modes &= ~MODES_REVERSE;
sp->modes |= MODES_LOOPING; /* just in case */
}
#ifdef ADJUST_SAMPLE_VOLUMES
if (amp!=-1)
sp->volume=(float)((amp) / 100.0);
else
{
/* Try to determine a volume scaling factor for the sample.
This is a very crude adjustment, but things sound more
balanced with it. Still, this should be a runtime option. */
Sint32 i=sp->data_length/2;
Sint16 maxamp=0,a;
Sint16 *tmp=(Sint16 *)sp->data;
while (i--)
{
a=*tmp++;
if (a<0) a=-a;
if (a>maxamp)
maxamp=a;
}
sp->volume=(float)(32768.0 / maxamp);
SNDDBG((" * volume comp: %f\n", sp->volume));
}
#else
if (amp!=-1)
sp->volume=(double)(amp) / 100.0;
else
sp->volume=1.0;
#endif
sp->data_length /= 2; /* These are in bytes. Convert into samples. */
sp->loop_start /= 2;
sp->loop_end /= 2;
/* Then fractional samples */
sp->data_length <<= FRACTION_BITS;
sp->loop_start <<= FRACTION_BITS;
sp->loop_end <<= FRACTION_BITS;
/* Adjust for fractional loop points. This is a guess. Does anyone
know what "fractions" really stands for? */
sp->loop_start |=
(fractions & 0x0F) << (FRACTION_BITS-4);
sp->loop_end |=
((fractions>>4) & 0x0F) << (FRACTION_BITS-4);
/* If this instrument will always be played on the same note,
and it's not looped, we can resample it now. */
if (sp->note_to_use && !(sp->modes & MODES_LOOPING))
pre_resample(song, sp);
if (strip_tail==1)
{
/* Let's not really, just say we did. */
SNDDBG((" - Stripping tail\n"));
sp->data_length = sp->loop_end;
}
}
SDL_RWclose(rw);
return ip;
}
static int fill_bank(MidiSong *song, int dr, int b)
{
int i, errors=0;
ToneBank *bank=((dr) ? song->drumset[b] : song->tonebank[b]);
if (!bank)
{
SNDDBG(("Huh. Tried to load instruments in non-existent %s %d\n",
(dr) ? "drumset" : "tone bank", b));
return 0;
}
for (i=0; i<128; i++)
{
if (bank->instrument[i]==MAGIC_LOAD_INSTRUMENT)
{
bank->instrument[i]=load_instrument_dls(song, dr, b, i);
if (bank->instrument[i])
{
continue;
}
if (!(bank->tone[i].name))
{
SNDDBG(("No instrument mapped to %s %d, program %d%s\n",
(dr)? "drum set" : "tone bank", b, i,
(b!=0) ? "" : " - this instrument will not be heard"));
if (b!=0)
{
/* Mark the corresponding instrument in the default
bank / drumset for loading (if it isn't already) */
if (!dr)
{
if (!(song->tonebank[0]->instrument[i]))
song->tonebank[0]->instrument[i] =
MAGIC_LOAD_INSTRUMENT;
}
else
{
if (!(song->drumset[0]->instrument[i]))
song->drumset[0]->instrument[i] =
MAGIC_LOAD_INSTRUMENT;
}
}
bank->instrument[i] = 0;
errors++;
}
else if (!(bank->instrument[i] =
load_instrument(song,
bank->tone[i].name,
(dr) ? 1 : 0,
bank->tone[i].pan,
bank->tone[i].amp,
(bank->tone[i].note!=-1) ?
bank->tone[i].note :
((dr) ? i : -1),
(bank->tone[i].strip_loop!=-1) ?
bank->tone[i].strip_loop :
((dr) ? 1 : -1),
(bank->tone[i].strip_envelope != -1) ?
bank->tone[i].strip_envelope :
((dr) ? 1 : -1),
bank->tone[i].strip_tail )))
{
SNDDBG(("Couldn't load instrument %s (%s %d, program %d)\n",
bank->tone[i].name,
(dr)? "drum set" : "tone bank", b, i));
errors++;
}
}
}
return errors;
}
int load_missing_instruments(MidiSong *song)
{
int i=128,errors=0;
while (i--)
{
if (song->tonebank[i])
errors+=fill_bank(song,0,i);
if (song->drumset[i])
errors+=fill_bank(song,1,i);
}
return errors;
}
void free_instruments(MidiSong *song)
{
int i=128;
while(i--)
{
if (song->tonebank[i])
free_bank(song, 0, i);
if (song->drumset[i])
free_bank(song, 1, i);
}
}
int set_default_instrument(MidiSong *song, char *name)
{
Instrument *ip;
if (!(ip=load_instrument(song, name, 0, -1, -1, -1, 0, 0, 0)))
return -1;
song->default_instrument = ip;
song->default_program = SPECIAL_PROGRAM;
return 0;
}

View File

@@ -0,0 +1,41 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
instrum.h
*/
/* Bits in modes: */
#define MODES_16BIT (1<<0)
#define MODES_UNSIGNED (1<<1)
#define MODES_LOOPING (1<<2)
#define MODES_PINGPONG (1<<3)
#define MODES_REVERSE (1<<4)
#define MODES_SUSTAIN (1<<5)
#define MODES_ENVELOPE (1<<6)
/* A hack to delay instrument loading until after reading the
entire MIDI file. */
#define MAGIC_LOAD_INSTRUMENT ((Instrument *) (-1))
#define SPECIAL_PROGRAM -1
extern int load_missing_instruments(MidiSong *song);
extern void free_instruments(MidiSong *song);
extern int set_default_instrument(MidiSong *song, char *name);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
instrum.h
*/
extern Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument);

View File

@@ -0,0 +1,573 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
Suddenly, you realize that this program is free software; you get
an overwhelming urge to redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received another copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
I bet they'll be amazed.
mix.c */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
#include "options.h"
#include "instrum.h"
#include "playmidi.h"
#include "output.h"
#include "tables.h"
#include "resample.h"
#include "mix.h"
/* Returns 1 if envelope runs out */
int recompute_envelope(MidiSong *song, int v)
{
int stage;
stage = song->voice[v].envelope_stage;
if (stage>5)
{
/* Envelope ran out. */
song->voice[v].status = VOICE_FREE;
return 1;
}
if (song->voice[v].sample->modes & MODES_ENVELOPE)
{
if (song->voice[v].status==VOICE_ON || song->voice[v].status==VOICE_SUSTAINED)
{
if (stage>2)
{
/* Freeze envelope until note turns off. Trumpets want this. */
song->voice[v].envelope_increment=0;
return 0;
}
}
}
song->voice[v].envelope_stage=stage+1;
if (song->voice[v].envelope_volume==song->voice[v].sample->envelope_offset[stage])
return recompute_envelope(song, v);
song->voice[v].envelope_target = song->voice[v].sample->envelope_offset[stage];
song->voice[v].envelope_increment = song->voice[v].sample->envelope_rate[stage];
if (song->voice[v].envelope_target < song->voice[v].envelope_volume)
song->voice[v].envelope_increment = -song->voice[v].envelope_increment;
return 0;
}
void apply_envelope_to_amp(MidiSong *song, int v)
{
float lamp = song->voice[v].left_amp, ramp;
Sint32 la,ra;
if (song->voice[v].panned == PANNED_MYSTERY)
{
ramp = song->voice[v].right_amp;
if (song->voice[v].tremolo_phase_increment)
{
lamp *= song->voice[v].tremolo_volume;
ramp *= song->voice[v].tremolo_volume;
}
if (song->voice[v].sample->modes & MODES_ENVELOPE)
{
lamp *= (float)vol_table[song->voice[v].envelope_volume>>23];
ramp *= (float)vol_table[song->voice[v].envelope_volume>>23];
}
la = (Sint32)FSCALE(lamp,AMP_BITS);
if (la>MAX_AMP_VALUE)
la=MAX_AMP_VALUE;
ra = (Sint32)FSCALE(ramp,AMP_BITS);
if (ra>MAX_AMP_VALUE)
ra=MAX_AMP_VALUE;
song->voice[v].left_mix = la;
song->voice[v].right_mix = ra;
}
else
{
if (song->voice[v].tremolo_phase_increment)
lamp *= song->voice[v].tremolo_volume;
if (song->voice[v].sample->modes & MODES_ENVELOPE)
lamp *= (float)vol_table[song->voice[v].envelope_volume>>23];
la = (Sint32)FSCALE(lamp,AMP_BITS);
if (la>MAX_AMP_VALUE)
la=MAX_AMP_VALUE;
song->voice[v].left_mix = la;
}
}
static int update_envelope(MidiSong *song, int v)
{
song->voice[v].envelope_volume += song->voice[v].envelope_increment;
/* Why is there no ^^ operator?? */
if (((song->voice[v].envelope_increment < 0) &&
(song->voice[v].envelope_volume <= song->voice[v].envelope_target)) ||
((song->voice[v].envelope_increment > 0) &&
(song->voice[v].envelope_volume >= song->voice[v].envelope_target)))
{
song->voice[v].envelope_volume = song->voice[v].envelope_target;
if (recompute_envelope(song, v))
return 1;
}
return 0;
}
static void update_tremolo(MidiSong *song, int v)
{
Sint32 depth = song->voice[v].sample->tremolo_depth << 7;
if (song->voice[v].tremolo_sweep)
{
/* Update sweep position */
song->voice[v].tremolo_sweep_position += song->voice[v].tremolo_sweep;
if (song->voice[v].tremolo_sweep_position >= (1 << SWEEP_SHIFT))
song->voice[v].tremolo_sweep=0; /* Swept to max amplitude */
else
{
/* Need to adjust depth */
depth *= song->voice[v].tremolo_sweep_position;
depth >>= SWEEP_SHIFT;
}
}
song->voice[v].tremolo_phase += song->voice[v].tremolo_phase_increment;
/* if (song->voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<<RATE_SHIFT))
song->voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<<RATE_SHIFT; */
song->voice[v].tremolo_volume = (float)
(1.0 - FSCALENEG((sine(song->voice[v].tremolo_phase >> RATE_SHIFT) + 1.0)
* depth * TREMOLO_AMPLITUDE_TUNING,
17));
/* I'm not sure about the +1.0 there -- it makes tremoloed voices'
volumes on average the lower the higher the tremolo amplitude. */
}
/* Returns 1 if the note died */
static int update_signal(MidiSong *song, int v)
{
if (song->voice[v].envelope_increment && update_envelope(song, v))
return 1;
if (song->voice[v].tremolo_phase_increment)
update_tremolo(song, v);
apply_envelope_to_amp(song, v);
return 0;
}
#define MIXATION(a) *lp++ += (a)*s;
static void mix_mystery_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
int count)
{
Voice *vp = song->voice + v;
final_volume_t
left=vp->left_mix,
right=vp->right_mix;
int cc;
sample_t s;
if (!(cc = vp->control_counter))
{
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
right = vp->right_mix;
}
while (count)
if (cc < count)
{
count -= cc;
while (cc--)
{
s = *sp++;
MIXATION(left);
MIXATION(right);
}
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
right = vp->right_mix;
}
else
{
vp->control_counter = cc - count;
while (count--)
{
s = *sp++;
MIXATION(left);
MIXATION(right);
}
return;
}
}
static void mix_center_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
int count)
{
Voice *vp = song->voice + v;
final_volume_t
left=vp->left_mix;
int cc;
sample_t s;
if (!(cc = vp->control_counter))
{
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
}
while (count)
if (cc < count)
{
count -= cc;
while (cc--)
{
s = *sp++;
MIXATION(left);
MIXATION(left);
}
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
}
else
{
vp->control_counter = cc - count;
while (count--)
{
s = *sp++;
MIXATION(left);
MIXATION(left);
}
return;
}
}
static void mix_single_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
int count)
{
Voice *vp = song->voice + v;
final_volume_t
left=vp->left_mix;
int cc;
sample_t s;
if (!(cc = vp->control_counter))
{
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
}
while (count)
if (cc < count)
{
count -= cc;
while (cc--)
{
s = *sp++;
MIXATION(left);
lp++;
}
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
}
else
{
vp->control_counter = cc - count;
while (count--)
{
s = *sp++;
MIXATION(left);
lp++;
}
return;
}
}
static void mix_mono_signal(MidiSong *song, sample_t *sp, Sint32 *lp, int v,
int count)
{
Voice *vp = song->voice + v;
final_volume_t
left=vp->left_mix;
int cc;
sample_t s;
if (!(cc = vp->control_counter))
{
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
}
while (count)
if (cc < count)
{
count -= cc;
while (cc--)
{
s = *sp++;
MIXATION(left);
}
cc = song->control_ratio;
if (update_signal(song, v))
return; /* Envelope ran out */
left = vp->left_mix;
}
else
{
vp->control_counter = cc - count;
while (count--)
{
s = *sp++;
MIXATION(left);
}
return;
}
}
static void mix_mystery(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
{
final_volume_t
left = song->voice[v].left_mix,
right = song->voice[v].right_mix;
sample_t s;
while (count--)
{
s = *sp++;
MIXATION(left);
MIXATION(right);
}
}
static void mix_center(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
{
final_volume_t
left = song->voice[v].left_mix;
sample_t s;
while (count--)
{
s = *sp++;
MIXATION(left);
MIXATION(left);
}
}
static void mix_single(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
{
final_volume_t
left = song->voice[v].left_mix;
sample_t s;
while (count--)
{
s = *sp++;
MIXATION(left);
lp++;
}
}
static void mix_mono(MidiSong *song, sample_t *sp, Sint32 *lp, int v, int count)
{
final_volume_t
left = song->voice[v].left_mix;
sample_t s;
while (count--)
{
s = *sp++;
MIXATION(left);
}
}
/* Ramp a note out in c samples */
static void ramp_out(MidiSong *song, sample_t *sp, Sint32 *lp, int v, Sint32 c)
{
/* should be final_volume_t, but Uint8 gives trouble. */
Sint32 left, right, li, ri;
sample_t s=0; /* silly warning about uninitialized s */
/* Fix by James Caldwell */
if ( c == 0 ) c = 1;
left=song->voice[v].left_mix;
li=-(left/c);
if (!li) li=-1;
/* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */
if (!(song->encoding & PE_MONO))
{
if (song->voice[v].panned==PANNED_MYSTERY)
{
right=song->voice[v].right_mix;
ri=-(right/c);
while (c--)
{
left += li;
if (left<0)
left=0;
right += ri;
if (right<0)
right=0;
s=*sp++;
MIXATION(left);
MIXATION(right);
}
}
else if (song->voice[v].panned==PANNED_CENTER)
{
while (c--)
{
left += li;
if (left<0)
return;
s=*sp++;
MIXATION(left);
MIXATION(left);
}
}
else if (song->voice[v].panned==PANNED_LEFT)
{
while (c--)
{
left += li;
if (left<0)
return;
s=*sp++;
MIXATION(left);
lp++;
}
}
else if (song->voice[v].panned==PANNED_RIGHT)
{
while (c--)
{
left += li;
if (left<0)
return;
s=*sp++;
lp++;
MIXATION(left);
}
}
}
else
{
/* Mono output. */
while (c--)
{
left += li;
if (left<0)
return;
s=*sp++;
MIXATION(left);
}
}
}
/**************** interface function ******************/
void mix_voice(MidiSong *song, Sint32 *buf, int v, Sint32 c)
{
Voice *vp = song->voice + v;
sample_t *sp;
if (vp->status==VOICE_DIE)
{
if (c>=MAX_DIE_TIME)
c=MAX_DIE_TIME;
sp=resample_voice(song, v, &c);
ramp_out(song, sp, buf, v, c);
vp->status=VOICE_FREE;
}
else
{
sp=resample_voice(song, v, &c);
if (song->encoding & PE_MONO)
{
/* Mono output. */
if (vp->envelope_increment || vp->tremolo_phase_increment)
mix_mono_signal(song, sp, buf, v, c);
else
mix_mono(song, sp, buf, v, c);
}
else
{
if (vp->panned == PANNED_MYSTERY)
{
if (vp->envelope_increment || vp->tremolo_phase_increment)
mix_mystery_signal(song, sp, buf, v, c);
else
mix_mystery(song, sp, buf, v, c);
}
else if (vp->panned == PANNED_CENTER)
{
if (vp->envelope_increment || vp->tremolo_phase_increment)
mix_center_signal(song, sp, buf, v, c);
else
mix_center(song, sp, buf, v, c);
}
else
{
/* It's either full left or full right. In either case,
every other sample is 0. Just get the offset right: */
if (vp->panned == PANNED_RIGHT) buf++;
if (vp->envelope_increment || vp->tremolo_phase_increment)
mix_single_signal(song, sp, buf, v, c);
else
mix_single(song, sp, buf, v, c);
}
}
}
}

View File

@@ -0,0 +1,27 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
In case you haven't heard, this program is free software;
you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
mix.h
*/
extern void mix_voice(MidiSong *song, Sint32 *buf, int v, Sint32 c);
extern int recompute_envelope(MidiSong *song, int v);
extern void apply_envelope_to_amp(MidiSong *song, int v);

View File

@@ -0,0 +1,113 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* When a patch file can't be opened, one of these extensions is
appended to the filename and the open is tried again.
*/
#define PATCH_EXT_LIST { ".pat", 0 }
/* Acoustic Grand Piano seems to be the usual default instrument. */
#define DEFAULT_PROGRAM 0
/* 9 here is MIDI channel 10, which is the standard percussion channel.
Some files (notably C:\WINDOWS\CANYON.MID) think that 16 is one too.
On the other hand, some files know that 16 is not a drum channel and
try to play music on it. This is now a runtime option, so this isn't
a critical choice anymore. */
#define DEFAULT_DRUMCHANNELS ((1<<9) | (1<<15))
/* In percent. */
#define DEFAULT_AMPLIFICATION 70
/* Default polyphony */
#define DEFAULT_VOICES 32
/* 1000 here will give a control ratio of 22:1 with 22 kHz output.
Higher CONTROLS_PER_SECOND values allow more accurate rendering
of envelopes and tremolo. The cost is CPU time. */
#define CONTROLS_PER_SECOND 1000
/* Make envelopes twice as fast. Saves ~20% CPU time (notes decay
faster) and sounds more like a GUS. There is now a command line
option to toggle this as well. */
#define FAST_DECAY
/* How many bits to use for the fractional part of sample positions.
This affects tonal accuracy. The entire position counter must fit
in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of
a sample is 1048576 samples (2 megabytes in memory). The GUS gets
by with just 9 bits and a little help from its friends...
"The GUS does not SUCK!!!" -- a happy user :) */
#define FRACTION_BITS 12
/* For some reason the sample volume is always set to maximum in all
patch files. Define this for a crude adjustment that may help
equalize instrument volumes. */
#define ADJUST_SAMPLE_VOLUMES
/* The number of samples to use for ramping out a dying note. Affects
click removal. */
#define MAX_DIE_TIME 20
/**************************************************************************/
/* Anything below this shouldn't need to be changed unless you're porting
to a new machine with other than 32-bit, big-endian words. */
/**************************************************************************/
/* change FRACTION_BITS above, not these */
#define INTEGER_MASK (0xFFFFFFFF << FRACTION_BITS)
#define FRACTION_MASK (~ INTEGER_MASK)
/* This is enforced by some computations that must fit in an int */
#define MAX_CONTROL_RATIO 255
#define MAX_AMPLIFICATION 800
/* The TiMidity configuration file */
#define CONFIG_FILE "timidity.cfg"
/* These affect general volume */
#define GUARD_BITS 3
#define AMP_BITS (15-GUARD_BITS)
#define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1)
#define FSCALE(a,b) (float)((a) * (double)(1<<(b)))
#define FSCALENEG(a,b) (float)((a) * (1.0L / (double)(1<<(b))))
/* Vibrato and tremolo Choices of the Day */
#define SWEEP_TUNING 38
#define VIBRATO_AMPLITUDE_TUNING 1.0L
#define VIBRATO_RATE_TUNING 38
#define TREMOLO_AMPLITUDE_TUNING 1.0L
#define TREMOLO_RATE_TUNING 38
#define SWEEP_SHIFT 16
#define RATE_SHIFT 5
#ifndef PI
#define PI 3.14159265358979323846
#endif
/* The path separator (D.M.) */
#ifdef WIN32
# define PATH_SEP '\\'
#else
# define PATH_SEP '/'
#endif

View File

@@ -0,0 +1,116 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
output.c
Audio output (to file / device) functions.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "options.h"
#include "output.h"
/*****************************************************************/
/* Some functions to convert signed 32-bit data to other formats */
void s32tos8(void *dp, Sint32 *lp, Sint32 c)
{
Sint8 *cp=(Sint8 *)(dp);
Sint32 l;
while (c--)
{
l=(*lp++)>>(32-8-GUARD_BITS);
if (l>127) l=127;
else if (l<-128) l=-128;
*cp++ = (Sint8) (l);
}
}
void s32tou8(void *dp, Sint32 *lp, Sint32 c)
{
Uint8 *cp=(Uint8 *)(dp);
Sint32 l;
while (c--)
{
l=(*lp++)>>(32-8-GUARD_BITS);
if (l>127) l=127;
else if (l<-128) l=-128;
*cp++ = 0x80 ^ ((Uint8) l);
}
}
void s32tos16(void *dp, Sint32 *lp, Sint32 c)
{
Sint16 *sp=(Sint16 *)(dp);
Sint32 l;
while (c--)
{
l=(*lp++)>>(32-16-GUARD_BITS);
if (l > 32767) l=32767;
else if (l<-32768) l=-32768;
*sp++ = (Sint16)(l);
}
}
void s32tou16(void *dp, Sint32 *lp, Sint32 c)
{
Uint16 *sp=(Uint16 *)(dp);
Sint32 l;
while (c--)
{
l=(*lp++)>>(32-16-GUARD_BITS);
if (l > 32767) l=32767;
else if (l<-32768) l=-32768;
*sp++ = 0x8000 ^ (Uint16)(l);
}
}
void s32tos16x(void *dp, Sint32 *lp, Sint32 c)
{
Sint16 *sp=(Sint16 *)(dp);
Sint32 l;
while (c--)
{
l=(*lp++)>>(32-16-GUARD_BITS);
if (l > 32767) l=32767;
else if (l<-32768) l=-32768;
*sp++ = SDL_Swap16((Sint16)(l));
}
}
void s32tou16x(void *dp, Sint32 *lp, Sint32 c)
{
Uint16 *sp=(Uint16 *)(dp);
Sint32 l;
while (c--)
{
l=(*lp++)>>(32-16-GUARD_BITS);
if (l > 32767) l=32767;
else if (l<-32768) l=-32768;
*sp++ = SDL_Swap16(0x8000 ^ (Uint16)(l));
}
}

View File

@@ -0,0 +1,56 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
output.h
*/
/* Data format encoding bits */
#define PE_MONO 0x01 /* versus stereo */
#define PE_SIGNED 0x02 /* versus unsigned */
#define PE_16BIT 0x04 /* versus 8-bit */
/* Conversion functions -- These overwrite the Sint32 data in *lp with
data in another format */
/* 8-bit signed and unsigned*/
extern void s32tos8(void *dp, Sint32 *lp, Sint32 c);
extern void s32tou8(void *dp, Sint32 *lp, Sint32 c);
/* 16-bit */
extern void s32tos16(void *dp, Sint32 *lp, Sint32 c);
extern void s32tou16(void *dp, Sint32 *lp, Sint32 c);
/* byte-exchanged 16-bit */
extern void s32tos16x(void *dp, Sint32 *lp, Sint32 c);
extern void s32tou16x(void *dp, Sint32 *lp, Sint32 c);
/* little-endian and big-endian specific */
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define s32tou16l s32tou16
#define s32tou16b s32tou16x
#define s32tos16l s32tos16
#define s32tos16b s32tos16x
#else
#define s32tou16l s32tou16x
#define s32tou16b s32tou16
#define s32tos16l s32tos16x
#define s32tos16b s32tos16
#endif

View File

@@ -0,0 +1,806 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
playmidi.c -- random stuff in need of rearrangement
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
#include "options.h"
#include "instrum.h"
#include "playmidi.h"
#include "output.h"
#include "mix.h"
#include "tables.h"
static void adjust_amplification(MidiSong *song)
{
song->master_volume = (float)(song->amplification) / (float)100.0;
}
static void reset_voices(MidiSong *song)
{
int i;
for (i=0; i<MAX_VOICES; i++)
song->voice[i].status=VOICE_FREE;
}
/* Process the Reset All Controllers event */
static void reset_controllers(MidiSong *song, int c)
{
song->channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */
song->channel[c].expression=127; /* SCC-1 does this. */
song->channel[c].sustain=0;
song->channel[c].pitchbend=0x2000;
song->channel[c].pitchfactor=0; /* to be computed */
}
static void reset_midi(MidiSong *song)
{
int i;
for (i=0; i<16; i++)
{
reset_controllers(song, i);
/* The rest of these are unaffected by the Reset All Controllers event */
song->channel[i].program=song->default_program;
song->channel[i].panning=NO_PANNING;
song->channel[i].pitchsens=2;
song->channel[i].bank=0; /* tone bank or drum set */
}
reset_voices(song);
}
static void select_sample(MidiSong *song, int v, Instrument *ip, int vel)
{
Sint32 f, cdiff, diff;
int s,i;
Sample *sp, *closest;
s=ip->samples;
sp=ip->sample;
if (s==1)
{
song->voice[v].sample=sp;
return;
}
f=song->voice[v].orig_frequency;
for (i=0; i<s; i++)
{
if (sp->low_vel <= vel && sp->high_vel >= vel &&
sp->low_freq <= f && sp->high_freq >= f)
{
song->voice[v].sample=sp;
return;
}
sp++;
}
/*
No suitable sample found! We'll select the sample whose root
frequency is closest to the one we want. (Actually we should
probably convert the low, high, and root frequencies to MIDI note
values and compare those.) */
cdiff=0x7FFFFFFF;
closest=sp=ip->sample;
for(i=0; i<s; i++)
{
diff=sp->root_freq - f;
if (diff<0) diff=-diff;
if (diff<cdiff)
{
cdiff=diff;
closest=sp;
}
sp++;
}
song->voice[v].sample=closest;
return;
}
static void recompute_freq(MidiSong *song, int v)
{
int
sign=(song->voice[v].sample_increment < 0), /* for bidirectional loops */
pb=song->channel[song->voice[v].channel].pitchbend;
double a;
if (!song->voice[v].sample->sample_rate)
return;
if (song->voice[v].vibrato_control_ratio)
{
/* This instrument has vibrato. Invalidate any precomputed
sample_increments. */
int i=VIBRATO_SAMPLE_INCREMENTS;
while (i--)
song->voice[v].vibrato_sample_increment[i]=0;
}
if (pb==0x2000 || pb<0 || pb>0x3FFF)
song->voice[v].frequency = song->voice[v].orig_frequency;
else
{
pb-=0x2000;
if (!(song->channel[song->voice[v].channel].pitchfactor))
{
/* Damn. Somebody bent the pitch. */
Sint32 i=pb*song->channel[song->voice[v].channel].pitchsens;
if (pb<0)
i=-i;
song->channel[song->voice[v].channel].pitchfactor=
(float)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]);
}
if (pb>0)
song->voice[v].frequency=
(Sint32)(song->channel[song->voice[v].channel].pitchfactor *
(double)(song->voice[v].orig_frequency));
else
song->voice[v].frequency=
(Sint32)((double)(song->voice[v].orig_frequency) /
song->channel[song->voice[v].channel].pitchfactor);
}
a = FSCALE(((double)(song->voice[v].sample->sample_rate) *
(double)(song->voice[v].frequency)) /
((double)(song->voice[v].sample->root_freq) *
(double)(song->rate)),
FRACTION_BITS);
if (sign)
a = -a; /* need to preserve the loop direction */
song->voice[v].sample_increment = (Sint32)(a);
}
static void recompute_amp(MidiSong *song, int v)
{
Sint32 tempamp;
/* TODO: use fscale */
tempamp= (song->voice[v].velocity *
song->channel[song->voice[v].channel].volume *
song->channel[song->voice[v].channel].expression); /* 21 bits */
if (!(song->encoding & PE_MONO))
{
if (song->voice[v].panning > 60 && song->voice[v].panning < 68)
{
song->voice[v].panned=PANNED_CENTER;
song->voice[v].left_amp=
FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
21);
}
else if (song->voice[v].panning<5)
{
song->voice[v].panned = PANNED_LEFT;
song->voice[v].left_amp=
FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
20);
}
else if (song->voice[v].panning>123)
{
song->voice[v].panned = PANNED_RIGHT;
song->voice[v].left_amp= /* left_amp will be used */
FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
20);
}
else
{
song->voice[v].panned = PANNED_MYSTERY;
song->voice[v].left_amp=
FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
27);
song->voice[v].right_amp = song->voice[v].left_amp * (song->voice[v].panning);
song->voice[v].left_amp *= (float)(127 - song->voice[v].panning);
}
}
else
{
song->voice[v].panned = PANNED_CENTER;
song->voice[v].left_amp=
FSCALENEG((double)(tempamp) * song->voice[v].sample->volume * song->master_volume,
21);
}
}
static void start_note(MidiSong *song, MidiEvent *e, int i)
{
Instrument *ip;
int j;
if (ISDRUMCHANNEL(song, e->channel))
{
if (!(ip=song->drumset[song->channel[e->channel].bank]->instrument[e->a]))
{
if (!(ip=song->drumset[0]->instrument[e->a]))
return; /* No instrument? Then we can't play. */
}
if (ip->samples != 1)
{
SNDDBG(("Strange: percussion instrument with %d samples!",
ip->samples));
}
if (ip->sample->note_to_use) /* Do we have a fixed pitch? */
song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
else
song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
/* drums are supposed to have only one sample */
song->voice[i].sample = ip->sample;
}
else
{
if (song->channel[e->channel].program == SPECIAL_PROGRAM)
ip=song->default_instrument;
else if (!(ip=song->tonebank[song->channel[e->channel].bank]->
instrument[song->channel[e->channel].program]))
{
if (!(ip=song->tonebank[0]->instrument[song->channel[e->channel].program]))
return; /* No instrument? Then we can't play. */
}
if (ip->sample->note_to_use) /* Fixed-pitch instrument? */
song->voice[i].orig_frequency = freq_table[(int)(ip->sample->note_to_use)];
else
song->voice[i].orig_frequency = freq_table[e->a & 0x7F];
select_sample(song, i, ip, e->b);
}
song->voice[i].status = VOICE_ON;
song->voice[i].channel = e->channel;
song->voice[i].note = e->a;
song->voice[i].velocity = e->b;
song->voice[i].sample_offset = 0;
song->voice[i].sample_increment = 0; /* make sure it isn't negative */
song->voice[i].tremolo_phase = 0;
song->voice[i].tremolo_phase_increment = song->voice[i].sample->tremolo_phase_increment;
song->voice[i].tremolo_sweep = song->voice[i].sample->tremolo_sweep_increment;
song->voice[i].tremolo_sweep_position = 0;
song->voice[i].vibrato_sweep = song->voice[i].sample->vibrato_sweep_increment;
song->voice[i].vibrato_sweep_position = 0;
song->voice[i].vibrato_control_ratio = song->voice[i].sample->vibrato_control_ratio;
song->voice[i].vibrato_control_counter = song->voice[i].vibrato_phase = 0;
for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)
song->voice[i].vibrato_sample_increment[j] = 0;
if (song->channel[e->channel].panning != NO_PANNING)
song->voice[i].panning = song->channel[e->channel].panning;
else
song->voice[i].panning = song->voice[i].sample->panning;
recompute_freq(song, i);
recompute_amp(song, i);
if (song->voice[i].sample->modes & MODES_ENVELOPE)
{
/* Ramp up from 0 */
song->voice[i].envelope_stage = 0;
song->voice[i].envelope_volume = 0;
song->voice[i].control_counter = 0;
recompute_envelope(song, i);
apply_envelope_to_amp(song, i);
}
else
{
song->voice[i].envelope_increment = 0;
apply_envelope_to_amp(song, i);
}
}
static void kill_note(MidiSong *song, int i)
{
song->voice[i].status = VOICE_DIE;
}
/* Only one instance of a note can be playing on a single channel. */
static void note_on(MidiSong *song)
{
int i = song->voices, lowest=-1;
Sint32 lv=0x7FFFFFFF, v;
MidiEvent *e = song->current_event;
while (i--)
{
if (song->voice[i].status == VOICE_FREE)
lowest=i; /* Can't get a lower volume than silence */
else if (song->voice[i].channel==e->channel &&
(song->voice[i].note==e->a || song->channel[song->voice[i].channel].mono))
kill_note(song, i);
}
if (lowest != -1)
{
/* Found a free voice. */
start_note(song,e,lowest);
return;
}
/* Look for the decaying note with the lowest volume */
i = song->voices;
while (i--)
{
if ((song->voice[i].status != VOICE_ON) &&
(song->voice[i].status != VOICE_DIE))
{
v = song->voice[i].left_mix;
if ((song->voice[i].panned == PANNED_MYSTERY)
&& (song->voice[i].right_mix > v))
v = song->voice[i].right_mix;
if (v<lv)
{
lv=v;
lowest=i;
}
}
}
if (lowest != -1)
{
/* This can still cause a click, but if we had a free voice to
spare for ramping down this note, we wouldn't need to kill it
in the first place... Still, this needs to be fixed. Perhaps
we could use a reserve of voices to play dying notes only. */
song->cut_notes++;
song->voice[lowest].status=VOICE_FREE;
start_note(song,e,lowest);
}
else
song->lost_notes++;
}
static void finish_note(MidiSong *song, int i)
{
if (song->voice[i].sample->modes & MODES_ENVELOPE)
{
/* We need to get the envelope out of Sustain stage */
song->voice[i].envelope_stage = 3;
song->voice[i].status = VOICE_OFF;
recompute_envelope(song, i);
apply_envelope_to_amp(song, i);
}
else
{
/* Set status to OFF so resample_voice() will let this voice out
of its loop, if any. In any case, this voice dies when it
hits the end of its data (ofs>=data_length). */
song->voice[i].status = VOICE_OFF;
}
}
static void note_off(MidiSong *song)
{
int i = song->voices;
MidiEvent *e = song->current_event;
while (i--)
if (song->voice[i].status == VOICE_ON &&
song->voice[i].channel == e->channel &&
song->voice[i].note == e->a)
{
if (song->channel[e->channel].sustain)
{
song->voice[i].status = VOICE_SUSTAINED;
}
else
finish_note(song, i);
return;
}
}
/* Process the All Notes Off event */
static void all_notes_off(MidiSong *song)
{
int i = song->voices;
int c = song->current_event->channel;
SNDDBG(("All notes off on channel %d", c));
while (i--)
if (song->voice[i].status == VOICE_ON &&
song->voice[i].channel == c)
{
if (song->channel[c].sustain)
song->voice[i].status = VOICE_SUSTAINED;
else
finish_note(song, i);
}
}
/* Process the All Sounds Off event */
static void all_sounds_off(MidiSong *song)
{
int i = song->voices;
int c = song->current_event->channel;
while (i--)
if (song->voice[i].channel == c &&
song->voice[i].status != VOICE_FREE &&
song->voice[i].status != VOICE_DIE)
{
kill_note(song, i);
}
}
static void adjust_pressure(MidiSong *song)
{
MidiEvent *e = song->current_event;
int i = song->voices;
while (i--)
if (song->voice[i].status == VOICE_ON &&
song->voice[i].channel == e->channel &&
song->voice[i].note == e->a)
{
song->voice[i].velocity = e->b;
recompute_amp(song, i);
apply_envelope_to_amp(song, i);
return;
}
}
static void drop_sustain(MidiSong *song)
{
int i = song->voices;
int c = song->current_event->channel;
while (i--)
if (song->voice[i].status == VOICE_SUSTAINED && song->voice[i].channel == c)
finish_note(song, i);
}
static void adjust_pitchbend(MidiSong *song)
{
int c = song->current_event->channel;
int i = song->voices;
while (i--)
if (song->voice[i].status != VOICE_FREE && song->voice[i].channel == c)
{
recompute_freq(song, i);
}
}
static void adjust_volume(MidiSong *song)
{
int c = song->current_event->channel;
int i = song->voices;
while (i--)
if (song->voice[i].channel == c &&
(song->voice[i].status==VOICE_ON || song->voice[i].status==VOICE_SUSTAINED))
{
recompute_amp(song, i);
apply_envelope_to_amp(song, i);
}
}
static void seek_forward(MidiSong *song, Sint32 until_time)
{
reset_voices(song);
while (song->current_event->time < until_time)
{
switch(song->current_event->type)
{
/* All notes stay off. Just handle the parameter changes. */
case ME_PITCH_SENS:
song->channel[song->current_event->channel].pitchsens =
song->current_event->a;
song->channel[song->current_event->channel].pitchfactor = 0;
break;
case ME_PITCHWHEEL:
song->channel[song->current_event->channel].pitchbend =
song->current_event->a + song->current_event->b * 128;
song->channel[song->current_event->channel].pitchfactor = 0;
break;
case ME_MAINVOLUME:
song->channel[song->current_event->channel].volume =
song->current_event->a;
break;
case ME_PAN:
song->channel[song->current_event->channel].panning =
song->current_event->a;
break;
case ME_EXPRESSION:
song->channel[song->current_event->channel].expression =
song->current_event->a;
break;
case ME_PROGRAM:
if (ISDRUMCHANNEL(song, song->current_event->channel))
/* Change drum set */
song->channel[song->current_event->channel].bank =
song->current_event->a;
else
song->channel[song->current_event->channel].program =
song->current_event->a;
break;
case ME_SUSTAIN:
song->channel[song->current_event->channel].sustain =
song->current_event->a;
break;
case ME_RESET_CONTROLLERS:
reset_controllers(song, song->current_event->channel);
break;
case ME_TONE_BANK:
song->channel[song->current_event->channel].bank =
song->current_event->a;
break;
case ME_EOT:
song->current_sample = song->current_event->time;
return;
}
song->current_event++;
}
/*song->current_sample=song->current_event->time;*/
if (song->current_event != song->events)
song->current_event--;
song->current_sample=until_time;
}
static void skip_to(MidiSong *song, Sint32 until_time)
{
if (song->current_sample > until_time)
song->current_sample = 0;
reset_midi(song);
song->buffered_count = 0;
song->buffer_pointer = song->common_buffer;
song->current_event = song->events;
if (until_time)
seek_forward(song, until_time);
}
static void do_compute_data(MidiSong *song, Sint32 count)
{
int i;
memset(song->buffer_pointer, 0,
(song->encoding & PE_MONO) ? (count * 4) : (count * 8));
for (i = 0; i < song->voices; i++)
{
if(song->voice[i].status != VOICE_FREE)
mix_voice(song, song->buffer_pointer, i, count);
}
song->current_sample += count;
}
/* count=0 means flush remaining buffered data to output device, then
flush the device itself */
static void compute_data(MidiSong *song, void *stream, Sint32 count)
{
int channels;
if ( song->encoding & PE_MONO )
channels = 1;
else
channels = 2;
if (!count)
{
if (song->buffered_count)
song->write(stream, song->common_buffer, channels * song->buffered_count);
song->buffer_pointer = song->common_buffer;
song->buffered_count = 0;
return;
}
while ((count + song->buffered_count) >= song->buffer_size)
{
do_compute_data(song, song->buffer_size - song->buffered_count);
count -= song->buffer_size - song->buffered_count;
song->write(stream, song->common_buffer, channels * song->buffer_size);
song->buffer_pointer = song->common_buffer;
song->buffered_count = 0;
}
if (count>0)
{
do_compute_data(song, count);
song->buffered_count += count;
song->buffer_pointer += (song->encoding & PE_MONO) ? count : count*2;
}
}
void Timidity_Start(MidiSong *song)
{
song->playing = 1;
adjust_amplification(song);
skip_to(song, 0);
}
void Timidity_Seek(MidiSong *song, Uint32 ms)
{
skip_to(song, (ms * song->rate) / 1000);
}
int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len)
{
Sint32 start_sample, end_sample, samples;
int bytes_per_sample;
if (!song->playing)
return 0;
bytes_per_sample =
((song->encoding & PE_MONO) ? 1 : 2)
* ((song->encoding & PE_16BIT) ? 2 : 1);
samples = len / bytes_per_sample;
start_sample = song->current_sample;
end_sample = song->current_sample+samples;
while ( song->current_sample < end_sample ) {
/* Handle all events that should happen at this time */
while (song->current_event->time <= song->current_sample) {
switch(song->current_event->type) {
/* Effects affecting a single note */
case ME_NOTEON:
if (!(song->current_event->b)) /* Velocity 0? */
note_off(song);
else
note_on(song);
break;
case ME_NOTEOFF:
note_off(song);
break;
case ME_KEYPRESSURE:
adjust_pressure(song);
break;
/* Effects affecting a single channel */
case ME_PITCH_SENS:
song->channel[song->current_event->channel].pitchsens =
song->current_event->a;
song->channel[song->current_event->channel].pitchfactor = 0;
break;
case ME_PITCHWHEEL:
song->channel[song->current_event->channel].pitchbend =
song->current_event->a + song->current_event->b * 128;
song->channel[song->current_event->channel].pitchfactor = 0;
/* Adjust pitch for notes already playing */
adjust_pitchbend(song);
break;
case ME_MAINVOLUME:
song->channel[song->current_event->channel].volume =
song->current_event->a;
adjust_volume(song);
break;
case ME_PAN:
song->channel[song->current_event->channel].panning =
song->current_event->a;
break;
case ME_EXPRESSION:
song->channel[song->current_event->channel].expression =
song->current_event->a;
adjust_volume(song);
break;
case ME_PROGRAM:
if (ISDRUMCHANNEL(song, song->current_event->channel)) {
/* Change drum set */
song->channel[song->current_event->channel].bank =
song->current_event->a;
}
else
song->channel[song->current_event->channel].program =
song->current_event->a;
break;
case ME_SUSTAIN:
song->channel[song->current_event->channel].sustain =
song->current_event->a;
if (!song->current_event->a)
drop_sustain(song);
break;
case ME_RESET_CONTROLLERS:
reset_controllers(song, song->current_event->channel);
break;
case ME_ALL_NOTES_OFF:
all_notes_off(song);
break;
case ME_ALL_SOUNDS_OFF:
all_sounds_off(song);
break;
case ME_TONE_BANK:
song->channel[song->current_event->channel].bank =
song->current_event->a;
break;
case ME_EOT:
/* Give the last notes a couple of seconds to decay */
SNDDBG(("Playing time: ~%d seconds\n",
song->current_sample/song->rate+2));
SNDDBG(("Notes cut: %d\n", song->cut_notes));
SNDDBG(("Notes lost totally: %d\n", song->lost_notes));
song->playing = 0;
return (song->current_sample - start_sample) * bytes_per_sample;
}
song->current_event++;
}
if (song->current_event->time > end_sample)
compute_data(song, stream, end_sample-song->current_sample);
else
compute_data(song, stream, song->current_event->time-song->current_sample);
}
return samples * bytes_per_sample;
}
void Timidity_SetVolume(MidiSong *song, int volume)
{
int i;
if (volume > MAX_AMPLIFICATION)
song->amplification = MAX_AMPLIFICATION;
else
if (volume < 0)
song->amplification = 0;
else
song->amplification = volume;
adjust_amplification(song);
for (i = 0; i < song->voices; i++)
if (song->voice[i].status != VOICE_FREE)
{
recompute_amp(song, i);
apply_envelope_to_amp(song, i);
}
}

View File

@@ -0,0 +1,64 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
playmidi.h
*/
/* Midi events */
#define ME_NONE 0
#define ME_NOTEON 1
#define ME_NOTEOFF 2
#define ME_KEYPRESSURE 3
#define ME_MAINVOLUME 4
#define ME_PAN 5
#define ME_SUSTAIN 6
#define ME_EXPRESSION 7
#define ME_PITCHWHEEL 8
#define ME_PROGRAM 9
#define ME_TEMPO 10
#define ME_PITCH_SENS 11
#define ME_ALL_SOUNDS_OFF 12
#define ME_RESET_CONTROLLERS 13
#define ME_ALL_NOTES_OFF 14
#define ME_TONE_BANK 15
#define ME_LYRIC 16
#define ME_EOT 99
/* Causes the instrument's default panning to be used. */
#define NO_PANNING -1
/* Voice status options: */
#define VOICE_FREE 0
#define VOICE_ON 1
#define VOICE_SUSTAINED 2
#define VOICE_OFF 3
#define VOICE_DIE 4
/* Voice panned options: */
#define PANNED_MYSTERY 0
#define PANNED_LEFT 1
#define PANNED_RIGHT 2
#define PANNED_CENTER 3
/* Anything but PANNED_MYSTERY only uses the left volume */
#define ISDRUMCHANNEL(s, c) (((s)->drumchannels & (1<<(c))))

View File

@@ -0,0 +1,584 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
/* Computes how many (fractional) samples one MIDI delta-time unit contains */
static void compute_sample_increment(MidiSong *song, Sint32 tempo,
Sint32 divisions)
{
double a;
a = (double) (tempo) * (double) (song->rate) * (65536.0/1000000.0) /
(double)(divisions);
song->sample_correction = (Sint32)(a) & 0xFFFF;
song->sample_increment = (Sint32)(a) >> 16;
SNDDBG(("Samples per delta-t: %d (correction %d)",
song->sample_increment, song->sample_correction));
}
/* Read variable-length number (7 bits per byte, MSB first) */
static Sint32 getvl(SDL_RWops *rw)
{
Sint32 l=0;
Uint8 c;
for (;;)
{
SDL_RWread(rw, &c, 1, 1);
l += (c & 0x7f);
if (!(c & 0x80)) return l;
l<<=7;
}
}
/* Print a string from the file, followed by a newline. Any non-ASCII
or unprintable characters will be converted to periods. */
static int dumpstring(SDL_RWops *rw, Sint32 len, char *label)
{
signed char *s=safe_malloc(len+1);
if (len != (Sint32) SDL_RWread(rw, s, 1, len))
{
free(s);
return -1;
}
s[len]='\0';
while (len--)
{
if (s[len]<32)
s[len]='.';
}
SNDDBG(("%s%s", label, s));
free(s);
return 0;
}
#define MIDIEVENT(at,t,ch,pa,pb) \
new=safe_malloc(sizeof(MidiEventList)); \
new->event.time=at; new->event.type=t; new->event.channel=ch; \
new->event.a=pa; new->event.b=pb; new->next=0;\
return new;
#define MAGIC_EOT ((MidiEventList *)(-1))
/* Read a MIDI event, returning a freshly allocated element that can
be linked to the event list */
static MidiEventList *read_midi_event(MidiSong *song)
{
static Uint8 laststatus, lastchan;
static Uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */
Uint8 me, type, a,b,c;
Sint32 len;
MidiEventList *new;
for (;;)
{
song->at += getvl(song->rw);
if (SDL_RWread(song->rw, &me, 1, 1) != 1)
{
SNDDBG(("read_midi_event: SDL_RWread() failure\n"));
return 0;
}
if(me==0xF0 || me == 0xF7) /* SysEx event */
{
len=getvl(song->rw);
SDL_RWseek(song->rw, len, SEEK_CUR);
}
else if(me==0xFF) /* Meta event */
{
SDL_RWread(song->rw, &type, 1, 1);
len=getvl(song->rw);
if (type>0 && type<16)
{
static char *label[]={
"Text event: ", "Text: ", "Copyright: ", "Track name: ",
"Instrument: ", "Lyric: ", "Marker: ", "Cue point: "};
dumpstring(song->rw, len, label[(type>7) ? 0 : type]);
}
else
switch(type)
{
case 0x2F: /* End of Track */
return MAGIC_EOT;
case 0x51: /* Tempo */
SDL_RWread(song->rw, &a, 1, 1);
SDL_RWread(song->rw, &b, 1, 1);
SDL_RWread(song->rw, &c, 1, 1);
MIDIEVENT(song->at, ME_TEMPO, c, a, b);
default:
SNDDBG(("(Meta event type 0x%02x, length %d)\n", type, len));
SDL_RWseek(song->rw, len, SEEK_CUR);
break;
}
}
else
{
a=me;
if (a & 0x80) /* status byte */
{
lastchan=a & 0x0F;
laststatus=(a>>4) & 0x07;
SDL_RWread(song->rw, &a, 1, 1);
a &= 0x7F;
}
switch(laststatus)
{
case 0: /* Note off */
SDL_RWread(song->rw, &b, 1, 1);
b &= 0x7F;
MIDIEVENT(song->at, ME_NOTEOFF, lastchan, a,b);
case 1: /* Note on */
SDL_RWread(song->rw, &b, 1, 1);
b &= 0x7F;
MIDIEVENT(song->at, ME_NOTEON, lastchan, a,b);
case 2: /* Key Pressure */
SDL_RWread(song->rw, &b, 1, 1);
b &= 0x7F;
MIDIEVENT(song->at, ME_KEYPRESSURE, lastchan, a, b);
case 3: /* Control change */
SDL_RWread(song->rw, &b, 1, 1);
b &= 0x7F;
{
int control=255;
switch(a)
{
case 7: control=ME_MAINVOLUME; break;
case 10: control=ME_PAN; break;
case 11: control=ME_EXPRESSION; break;
case 64: control=ME_SUSTAIN; break;
case 120: control=ME_ALL_SOUNDS_OFF; break;
case 121: control=ME_RESET_CONTROLLERS; break;
case 123: control=ME_ALL_NOTES_OFF; break;
/* These should be the SCC-1 tone bank switch
commands. I don't know why there are two, or
why the latter only allows switching to bank 0.
Also, some MIDI files use 0 as some sort of
continuous controller. This will cause lots of
warnings about undefined tone banks. */
case 0: control=ME_TONE_BANK; break;
case 32:
if (b!=0)
SNDDBG(("(Strange: tone bank change 0x20%02x)\n", b));
else
control=ME_TONE_BANK;
break;
case 100: nrpn=0; rpn_msb[lastchan]=b; break;
case 101: nrpn=0; rpn_lsb[lastchan]=b; break;
case 99: nrpn=1; rpn_msb[lastchan]=b; break;
case 98: nrpn=1; rpn_lsb[lastchan]=b; break;
case 6:
if (nrpn)
{
SNDDBG(("(Data entry (MSB) for NRPN %02x,%02x: %d)\n",
rpn_msb[lastchan], rpn_lsb[lastchan], b));
break;
}
switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan])
{
case 0x0000: /* Pitch bend sensitivity */
control=ME_PITCH_SENS;
break;
case 0x7F7F: /* RPN reset */
/* reset pitch bend sensitivity to 2 */
MIDIEVENT(song->at, ME_PITCH_SENS, lastchan, 2, 0);
default:
SNDDBG(("(Data entry (MSB) for RPN %02x,%02x: %d)\n",
rpn_msb[lastchan], rpn_lsb[lastchan], b));
break;
}
break;
default:
SNDDBG(("(Control %d: %d)\n", a, b));
break;
}
if (control != 255)
{
MIDIEVENT(song->at, control, lastchan, b, 0);
}
}
break;
case 4: /* Program change */
a &= 0x7f;
MIDIEVENT(song->at, ME_PROGRAM, lastchan, a, 0);
case 5: /* Channel pressure - NOT IMPLEMENTED */
break;
case 6: /* Pitch wheel */
SDL_RWread(song->rw, &b, 1, 1);
b &= 0x7F;
MIDIEVENT(song->at, ME_PITCHWHEEL, lastchan, a, b);
default:
SNDDBG(("*** Can't happen: status 0x%02X, channel 0x%02X\n",
laststatus, lastchan));
break;
}
}
}
return new;
}
#undef MIDIEVENT
/* Read a midi track into the linked list, either merging with any previous
tracks or appending to them. */
static int read_track(MidiSong *song, int append)
{
MidiEventList *meep;
MidiEventList *next, *new;
Sint32 len;
char tmp[4];
meep = song->evlist;
if (append && meep)
{
/* find the last event in the list */
for (; meep->next; meep=meep->next)
;
song->at = meep->event.time;
}
else
song->at=0;
/* Check the formalities */
if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1)
{
SNDDBG(("Can't read track header.\n"));
return -1;
}
len=SDL_SwapBE32(len);
if (memcmp(tmp, "MTrk", 4))
{
SNDDBG(("Corrupt MIDI file.\n"));
return -2;
}
for (;;)
{
if (!(new=read_midi_event(song))) /* Some kind of error */
return -2;
if (new==MAGIC_EOT) /* End-of-track Hack. */
{
return 0;
}
next=meep->next;
while (next && (next->event.time < new->event.time))
{
meep=next;
next=meep->next;
}
new->next=next;
meep->next=new;
song->event_count++; /* Count the event. (About one?) */
meep=new;
}
}
/* Free the linked event list from memory. */
static void free_midi_list(MidiSong *song)
{
MidiEventList *meep, *next;
if (!(meep = song->evlist)) return;
while (meep)
{
next=meep->next;
free(meep);
meep=next;
}
song->evlist=0;
}
/* Allocate an array of MidiEvents and fill it from the linked list of
events, marking used instruments for loading. Convert event times to
samples: handle tempo changes. Strip unnecessary events from the list.
Free the linked list. */
static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp,
Sint32 *samplesp)
{
MidiEvent *groomed_list, *lp;
MidiEventList *meep;
Sint32 i, our_event_count, tempo, skip_this_event, new_value;
Sint32 sample_cum, samples_to_do, at, st, dt, counting_time;
int current_bank[16], current_set[16], current_program[16];
/* Or should each bank have its own current program? */
for (i=0; i<16; i++)
{
current_bank[i]=0;
current_set[i]=0;
current_program[i]=song->default_program;
}
tempo=500000;
compute_sample_increment(song, tempo, divisions);
/* This may allocate a bit more than we need */
groomed_list=lp=safe_malloc(sizeof(MidiEvent) * (song->event_count+1));
meep=song->evlist;
our_event_count=0;
st=at=sample_cum=0;
counting_time=2; /* We strip any silence before the first NOTE ON. */
for (i = 0; i < song->event_count; i++)
{
skip_this_event=0;
if (meep->event.type==ME_TEMPO)
{
tempo=
meep->event.channel + meep->event.b * 256 + meep->event.a * 65536;
compute_sample_increment(song, tempo, divisions);
skip_this_event=1;
}
else switch (meep->event.type)
{
case ME_PROGRAM:
if (ISDRUMCHANNEL(song, meep->event.channel))
{
if (song->drumset[meep->event.a]) /* Is this a defined drumset? */
new_value=meep->event.a;
else
{
SNDDBG(("Drum set %d is undefined\n", meep->event.a));
new_value=meep->event.a=0;
}
if (current_set[meep->event.channel] != new_value)
current_set[meep->event.channel]=new_value;
else
skip_this_event=1;
}
else
{
new_value=meep->event.a;
if ((current_program[meep->event.channel] != SPECIAL_PROGRAM)
&& (current_program[meep->event.channel] != new_value))
current_program[meep->event.channel] = new_value;
else
skip_this_event=1;
}
break;
case ME_NOTEON:
if (counting_time)
counting_time=1;
if (ISDRUMCHANNEL(song, meep->event.channel))
{
/* Mark this instrument to be loaded */
if (!(song->drumset[current_set[meep->event.channel]]
->instrument[meep->event.a]))
song->drumset[current_set[meep->event.channel]]
->instrument[meep->event.a] = MAGIC_LOAD_INSTRUMENT;
}
else
{
if (current_program[meep->event.channel]==SPECIAL_PROGRAM)
break;
/* Mark this instrument to be loaded */
if (!(song->tonebank[current_bank[meep->event.channel]]
->instrument[current_program[meep->event.channel]]))
song->tonebank[current_bank[meep->event.channel]]
->instrument[current_program[meep->event.channel]] =
MAGIC_LOAD_INSTRUMENT;
}
break;
case ME_TONE_BANK:
if (ISDRUMCHANNEL(song, meep->event.channel))
{
skip_this_event=1;
break;
}
if (song->tonebank[meep->event.a]) /* Is this a defined tone bank? */
new_value=meep->event.a;
else
{
SNDDBG(("Tone bank %d is undefined\n", meep->event.a));
new_value=meep->event.a=0;
}
if (current_bank[meep->event.channel]!=new_value)
current_bank[meep->event.channel]=new_value;
else
skip_this_event=1;
break;
}
/* Recompute time in samples*/
if ((dt=meep->event.time - at) && !counting_time)
{
samples_to_do = song->sample_increment * dt;
sample_cum += song->sample_correction * dt;
if (sample_cum & 0xFFFF0000)
{
samples_to_do += ((sample_cum >> 16) & 0xFFFF);
sample_cum &= 0x0000FFFF;
}
st += samples_to_do;
}
else if (counting_time==1) counting_time=0;
if (!skip_this_event)
{
/* Add the event to the list */
*lp=meep->event;
lp->time=st;
lp++;
our_event_count++;
}
at=meep->event.time;
meep=meep->next;
}
/* Add an End-of-Track event */
lp->time=st;
lp->type=ME_EOT;
our_event_count++;
free_midi_list(song);
*eventsp=our_event_count;
*samplesp=st;
return groomed_list;
}
MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp)
{
Sint32 len, divisions;
Sint16 format, tracks, divisions_tmp;
int i;
char tmp[4];
song->event_count=0;
song->at=0;
song->evlist=0;
if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1)
{
SNDDBG(("Not a MIDI file!\n"));
return 0;
}
len=SDL_SwapBE32(len);
if (memcmp(tmp, "MThd", 4) || len < 6)
{
SNDDBG(("Not a MIDI file!\n"));
return 0;
}
SDL_RWread(song->rw, &format, 2, 1);
SDL_RWread(song->rw, &tracks, 2, 1);
SDL_RWread(song->rw, &divisions_tmp, 2, 1);
format=SDL_SwapBE16(format);
tracks=SDL_SwapBE16(tracks);
divisions_tmp=SDL_SwapBE16(divisions_tmp);
if (divisions_tmp<0)
{
/* SMPTE time -- totally untested. Got a MIDI file that uses this? */
divisions=
(Sint32)(-(divisions_tmp/256)) * (Sint32)(divisions_tmp & 0xFF);
}
else divisions=(Sint32)(divisions_tmp);
if (len > 6)
{
SNDDBG(("MIDI file header size %u bytes", len));
SDL_RWseek(song->rw, len-6, SEEK_CUR); /* skip the excess */
}
if (format<0 || format >2)
{
SNDDBG(("Unknown MIDI file format %d\n", format));
return 0;
}
SNDDBG(("Format: %d Tracks: %d Divisions: %d\n",
format, tracks, divisions));
/* Put a do-nothing event first in the list for easier processing */
song->evlist=safe_malloc(sizeof(MidiEventList));
song->evlist->event.time=0;
song->evlist->event.type=ME_NONE;
song->evlist->next=0;
song->event_count++;
switch(format)
{
case 0:
if (read_track(song, 0))
{
free_midi_list(song);
return 0;
}
break;
case 1:
for (i=0; i<tracks; i++)
if (read_track(song, 0))
{
free_midi_list(song);
return 0;
}
break;
case 2: /* We simply play the tracks sequentially */
for (i=0; i<tracks; i++)
if (read_track(song, 1))
{
free_midi_list(song);
return 0;
}
break;
}
return groom_list(song, divisions, count, sp);
}

View File

@@ -0,0 +1,24 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
readmidi.h
*/
extern MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp);

View File

@@ -0,0 +1,612 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
resample.c
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
#include "options.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "tables.h"
#include "resample.h"
/*************** resampling with fixed increment *****************/
static sample_t *rs_plain(MidiSong *song, int v, Sint32 *countptr)
{
/* Play sample until end, then free the voice. */
sample_t v1, v2;
Voice
*vp=&(song->voice[v]);
sample_t
*dest=song->resample_buffer,
*src=vp->sample->data;
Sint32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->data_length,
count=*countptr;
Sint32 i;
if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
/* Precalc how many times we should go through the loop.
NOTE: Assumes that incr > 0 and that ofs <= le */
i = (le - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
while (i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
if (ofs >= le)
{
if (ofs == le)
*dest++ = src[ofs >> FRACTION_BITS];
vp->status=VOICE_FREE;
*countptr-=count+1;
}
vp->sample_offset=ofs; /* Update offset */
return song->resample_buffer;
}
static sample_t *rs_loop(MidiSong *song, Voice *vp, Sint32 count)
{
/* Play sample until end-of-loop, skip back and continue. */
sample_t v1, v2;
Sint32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ll=le - vp->sample->loop_start;
sample_t
*dest=song->resample_buffer,
*src=vp->sample->data;
Sint32 i;
while (count)
{
if (ofs >= le)
/* NOTE: Assumes that ll > incr and that incr > 0. */
ofs -= ll;
/* Precalc how many times we should go through the loop */
i = (le - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
while (i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
}
vp->sample_offset=ofs; /* Update offset */
return song->resample_buffer;
}
static sample_t *rs_bidir(MidiSong *song, Voice *vp, Sint32 count)
{
sample_t v1, v2;
Sint32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ls=vp->sample->loop_start;
sample_t
*dest=song->resample_buffer,
*src=vp->sample->data;
Sint32
le2 = le<<1,
ls2 = ls<<1,
i;
/* Play normally until inside the loop region */
if (ofs <= ls)
{
/* NOTE: Assumes that incr > 0, which is NOT always the case
when doing bidirectional looping. I have yet to see a case
where both ofs <= ls AND incr < 0, however. */
i = (ls - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
while (i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
}
/* Then do the bidirectional looping */
while(count)
{
/* Precalc how many times we should go through the loop */
i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
while (i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
if (ofs>=le)
{
/* fold the overshoot back in */
ofs = le2 - ofs;
incr *= -1;
}
else if (ofs <= ls)
{
ofs = ls2 - ofs;
incr *= -1;
}
}
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return song->resample_buffer;
}
/*********************** vibrato versions ***************************/
/* We only need to compute one half of the vibrato sine cycle */
static int vib_phase_to_inc_ptr(int phase)
{
if (phase < VIBRATO_SAMPLE_INCREMENTS/2)
return VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
else if (phase >= 3*VIBRATO_SAMPLE_INCREMENTS/2)
return 5*VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
else
return phase-VIBRATO_SAMPLE_INCREMENTS/2;
}
static Sint32 update_vibrato(MidiSong *song, Voice *vp, int sign)
{
Sint32 depth;
int phase, pb;
double a;
if (vp->vibrato_phase++ >= 2*VIBRATO_SAMPLE_INCREMENTS-1)
vp->vibrato_phase=0;
phase=vib_phase_to_inc_ptr(vp->vibrato_phase);
if (vp->vibrato_sample_increment[phase])
{
if (sign)
return -vp->vibrato_sample_increment[phase];
else
return vp->vibrato_sample_increment[phase];
}
/* Need to compute this sample increment. */
depth=vp->sample->vibrato_depth<<7;
if (vp->vibrato_sweep)
{
/* Need to update sweep */
vp->vibrato_sweep_position += vp->vibrato_sweep;
if (vp->vibrato_sweep_position >= (1<<SWEEP_SHIFT))
vp->vibrato_sweep=0;
else
{
/* Adjust depth */
depth *= vp->vibrato_sweep_position;
depth >>= SWEEP_SHIFT;
}
}
a = FSCALE(((double)(vp->sample->sample_rate) *
(double)(vp->frequency)) /
((double)(vp->sample->root_freq) *
(double)(song->rate)),
FRACTION_BITS);
pb=(int)((sine(vp->vibrato_phase *
(SINE_CYCLE_LENGTH/(2*VIBRATO_SAMPLE_INCREMENTS)))
* (double)(depth) * VIBRATO_AMPLITUDE_TUNING));
if (pb<0)
{
pb=-pb;
a /= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
}
else
a *= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
/* If the sweep's over, we can store the newly computed sample_increment */
if (!vp->vibrato_sweep)
vp->vibrato_sample_increment[phase]=(Sint32) a;
if (sign)
a = -a; /* need to preserve the loop direction */
return (Sint32) a;
}
static sample_t *rs_vib_plain(MidiSong *song, int v, Sint32 *countptr)
{
/* Play sample until end, then free the voice. */
sample_t v1, v2;
Voice *vp=&(song->voice[v]);
sample_t
*dest=song->resample_buffer,
*src=vp->sample->data;
Sint32
le=vp->sample->data_length,
ofs=vp->sample_offset,
incr=vp->sample_increment,
count=*countptr;
int
cc=vp->vibrato_control_counter;
/* This has never been tested */
if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
while (count--)
{
if (!cc--)
{
cc=vp->vibrato_control_ratio;
incr=update_vibrato(song, vp, 0);
}
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
if (ofs >= le)
{
if (ofs == le)
*dest++ = src[ofs >> FRACTION_BITS];
vp->status=VOICE_FREE;
*countptr-=count+1;
break;
}
}
vp->vibrato_control_counter=cc;
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return song->resample_buffer;
}
static sample_t *rs_vib_loop(MidiSong *song, Voice *vp, Sint32 count)
{
/* Play sample until end-of-loop, skip back and continue. */
sample_t v1, v2;
Sint32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ll=le - vp->sample->loop_start;
sample_t
*dest=song->resample_buffer,
*src=vp->sample->data;
int
cc=vp->vibrato_control_counter;
Sint32 i;
int
vibflag=0;
while (count)
{
/* Hopefully the loop is longer than an increment */
if(ofs >= le)
ofs -= ll;
/* Precalc how many times to go through the loop, taking
the vibrato control ratio into account this time. */
i = (le - ofs) / incr + 1;
if(i > count) i = count;
if(i > cc)
{
i = cc;
vibflag = 1;
}
else cc -= i;
count -= i;
while(i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
if(vibflag)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(song, vp, 0);
vibflag = 0;
}
}
vp->vibrato_control_counter=cc;
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return song->resample_buffer;
}
static sample_t *rs_vib_bidir(MidiSong *song, Voice *vp, Sint32 count)
{
sample_t v1, v2;
Sint32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ls=vp->sample->loop_start;
sample_t
*dest=song->resample_buffer,
*src=vp->sample->data;
int
cc=vp->vibrato_control_counter;
Sint32
le2=le<<1,
ls2=ls<<1,
i;
int
vibflag = 0;
/* Play normally until inside the loop region */
while (count && (ofs <= ls))
{
i = (ls - ofs) / incr + 1;
if (i > count) i = count;
if (i > cc)
{
i = cc;
vibflag = 1;
}
else cc -= i;
count -= i;
while (i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
if (vibflag)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(song, vp, 0);
vibflag = 0;
}
}
/* Then do the bidirectional looping */
while (count)
{
/* Precalc how many times we should go through the loop */
i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
if(i > count) i = count;
if(i > cc)
{
i = cc;
vibflag = 1;
}
else cc -= i;
count -= i;
while (i--)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS)+1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
ofs += incr;
}
if (vibflag)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(song, vp, (incr < 0));
vibflag = 0;
}
if (ofs >= le)
{
/* fold the overshoot back in */
ofs = le2 - ofs;
incr *= -1;
}
else if (ofs <= ls)
{
ofs = ls2 - ofs;
incr *= -1;
}
}
vp->vibrato_control_counter=cc;
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return song->resample_buffer;
}
sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr)
{
Sint32 ofs;
Uint8 modes;
Voice *vp=&(song->voice[v]);
if (!(vp->sample->sample_rate))
{
/* Pre-resampled data -- just update the offset and check if
we're out of data. */
ofs=vp->sample_offset >> FRACTION_BITS; /* Kind of silly to use
FRACTION_BITS here... */
if (*countptr >= (vp->sample->data_length>>FRACTION_BITS) - ofs)
{
/* Note finished. Free the voice. */
vp->status = VOICE_FREE;
/* Let the caller know how much data we had left */
*countptr = (vp->sample->data_length>>FRACTION_BITS) - ofs;
}
else
vp->sample_offset += *countptr << FRACTION_BITS;
return vp->sample->data+ofs;
}
/* Need to resample. Use the proper function. */
modes=vp->sample->modes;
if (vp->vibrato_control_ratio)
{
if ((modes & MODES_LOOPING) &&
((modes & MODES_ENVELOPE) ||
(vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
{
if (modes & MODES_PINGPONG)
return rs_vib_bidir(song, vp, *countptr);
else
return rs_vib_loop(song, vp, *countptr);
}
else
return rs_vib_plain(song, v, countptr);
}
else
{
if ((modes & MODES_LOOPING) &&
((modes & MODES_ENVELOPE) ||
(vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
{
if (modes & MODES_PINGPONG)
return rs_bidir(song, vp, *countptr);
else
return rs_loop(song, vp, *countptr);
}
else
return rs_plain(song, v, countptr);
}
}
void pre_resample(MidiSong *song, Sample *sp)
{
double a, xdiff;
Sint32 incr, ofs, newlen, count;
Sint16 *newdata, *dest, *src = (Sint16 *) sp->data;
Sint16 v1, v2, v3, v4, *vptr;
#ifdef DEBUG_CHATTER
static const char note_name[12][3] =
{
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
};
#endif
SNDDBG((" * pre-resampling for note %d (%s%d)\n",
sp->note_to_use,
note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12));
a = ((double) (sp->sample_rate) * freq_table[(int) (sp->note_to_use)]) /
((double) (sp->root_freq) * song->rate);
newlen = (Sint32)(sp->data_length / a);
dest = newdata = safe_malloc(newlen >> (FRACTION_BITS - 1));
count = (newlen >> FRACTION_BITS) - 1;
ofs = incr = (sp->data_length - (1 << FRACTION_BITS)) / count;
if (--count)
*dest++ = src[0];
/* Since we're pre-processing and this doesn't have to be done in
real-time, we go ahead and do the full sliding cubic interpolation. */
while (--count)
{
vptr = src + (ofs >> FRACTION_BITS);
/*
* Electric Fence to the rescue: Accessing *(vptr - 1) is not a
* good thing to do when vptr <= src. (TiMidity++ has a similar
* safe-guard here.)
*/
v1 = (vptr == src) ? *vptr : *(vptr - 1);
v2 = *vptr;
v3 = *(vptr + 1);
v4 = *(vptr + 2);
xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS);
*dest++ = (Sint16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 +
xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4))));
ofs += incr;
}
if (ofs & FRACTION_MASK)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS) + 1];
*dest++ = v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS);
}
else
*dest++ = src[ofs >> FRACTION_BITS];
sp->data_length = newlen;
sp->loop_start = (Sint32)(sp->loop_start / a);
sp->loop_end = (Sint32)(sp->loop_end / a);
free(sp->data);
sp->data = (sample_t *) newdata;
sp->sample_rate = 0;
}

View File

@@ -0,0 +1,24 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
resample.h
*/
extern sample_t *resample_voice(MidiSong *song, int v, Sint32 *countptr);
extern void pre_resample(MidiSong *song, Sample *sp);

View File

@@ -0,0 +1,218 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "tables.h"
const Sint32 freq_table[128]=
{
8176, 8662, 9177, 9723,
10301, 10913, 11562, 12250,
12978, 13750, 14568, 15434,
16352, 17324, 18354, 19445,
20602, 21827, 23125, 24500,
25957, 27500, 29135, 30868,
32703, 34648, 36708, 38891,
41203, 43654, 46249, 48999,
51913, 55000, 58270, 61735,
65406, 69296, 73416, 77782,
82407, 87307, 92499, 97999,
103826, 110000, 116541, 123471,
130813, 138591, 146832, 155563,
164814, 174614, 184997, 195998,
207652, 220000, 233082, 246942,
261626, 277183, 293665, 311127,
329628, 349228, 369994, 391995,
415305, 440000, 466164, 493883,
523251, 554365, 587330, 622254,
659255, 698456, 739989, 783991,
830609, 880000, 932328, 987767,
1046502, 1108731, 1174659, 1244508,
1318510, 1396913, 1479978, 1567982,
1661219, 1760000, 1864655, 1975533,
2093005, 2217461, 2349318, 2489016,
2637020, 2793826, 2959955, 3135963,
3322438, 3520000, 3729310, 3951066,
4186009, 4434922, 4698636, 4978032,
5274041, 5587652, 5919911, 6271927,
6644875, 7040000, 7458620, 7902133,
8372018, 8869844, 9397273, 9956063,
10548082, 11175303, 11839822, 12543854
};
/* v=2.^((x/127-1) * 6) */
const double vol_table[128] =
{
0.015625, 0.016145143728351113, 0.016682602624583379, 0.017237953096759438,
0.017811790741104401, 0.01840473098076444, 0.019017409725829021, 0.019650484055324921,
0.020304632921913132, 0.020980557880044631, 0.021678983838355849, 0.02240065983711079,
0.023146359851523596, 0.023916883621822989, 0.024713057510949051, 0.025535735390801884,
0.026385799557992876, 0.027264161680080529, 0.028171763773305786, 0.029109579212875332,
0.030078613776876421, 0.031079906724942836, 0.032114531912828696, 0.033183598944085631,
0.034288254360078256, 0.035429682869614412, 0.036609108619508737, 0.037827796507442342,
0.039087053538526394, 0.040388230227024875, 0.041732722044739302, 0.043121970917609151,
0.044557466772132896, 0.046040749133268132, 0.047573408775524545, 0.049157089429020417,
0.050793489542332405, 0.05248436410402918, 0.054231526524842463, 0.056036850582493913,
0.057902272431264008, 0.059829792678457581, 0.061821478529993396, 0.063879466007418645,
0.066005962238725971, 0.068203247825430205, 0.070473679288442961, 0.072819691595368496,
0.075243800771931268, 0.077748606600335793, 0.080336795407452768, 0.083011142945821612,
0.085774517370559328, 0.088629882315368294, 0.091580300070941839, 0.094628934869176312,
0.097779056276712184, 0.10103404270144323, 0.1043973850157546, 0.1078726903003755,
0.11146368571286204, 0.11517422248485852, 0.11900828005242428, 0.12296997032385605,
0.12706354208958254, 0.13129338557886089, 0.13566403716816194, 0.14018018424629392,
0.14484667024148207, 0.14966849981579558, 0.15465084423249356, 0.15979904690204472,
0.16511862911277009, 0.17061529595225433, 0.17629494242587571, 0.18216365977901747,
0.18822774202974024, 0.19449369271892172, 0.20096823188510385, 0.20765830327152621,
0.21457108177307616, 0.22171398113114205, 0.2290946618846218, 0.23672103958561411,
0.2446012932886038, 0.25274387432224471, 0.26115751535314891, 0.26985123975140174,
0.27883437126784744, 0.28811654403352405, 0.29770771289197112, 0.30761816407549192,
0.31785852623682015, 0.32843978184802081, 0.33937327897885317, 0.3506707434672246,
0.36234429149478936, 0.37440644258117928, 0.38687013301080181, 0.39974872970660535,
0.41305604456569134, 0.42680634927214656, 0.44101439060298442, 0.45569540624360722,
0.47086514112975281, 0.48653986433345225, 0.50273638651110641, 0.51947207793239625,
0.53676488710936021, 0.55463336004561792, 0.57309666012638816, 0.59217458867062556,
0.61188760616732485, 0.63225685421876243, 0.65330417821421161, 0.67505215075844849,
0.69752409588017272, 0.72074411404630734, 0.74473710800900605, 0.76952880951308478,
0.79514580689252357, 0.82161557358563286, 0.84896649759946774, 0.87722791195508854,
0.90643012614631979, 0.93660445864574493, 0.96778327049280244, 1
};
const double bend_fine[256] = {
1, 1.0002256593050698, 1.0004513695322617, 1.0006771306930664,
1.0009029427989777, 1.0011288058614922, 1.0013547198921082, 1.0015806849023274,
1.0018067009036538, 1.002032767907594, 1.0022588859256572, 1.0024850549693551,
1.0027112750502025, 1.0029375461797159, 1.0031638683694153, 1.0033902416308227,
1.0036166659754628, 1.0038431414148634, 1.0040696679605541, 1.0042962456240678,
1.0045228744169397, 1.0047495543507072, 1.0049762854369111, 1.0052030676870944,
1.0054299011128027, 1.0056567857255843, 1.00588372153699, 1.006110708558573,
1.0063377468018897, 1.0065648362784985, 1.0067919769999607, 1.0070191689778405,
1.0072464122237039, 1.0074737067491204, 1.0077010525656616, 1.0079284496849015,
1.0081558981184175, 1.008383397877789, 1.008610948974598, 1.0088385514204294,
1.0090662052268706, 1.0092939104055114, 1.0095216669679448, 1.0097494749257656,
1.009977334290572, 1.0102052450739643, 1.0104332072875455, 1.0106612209429215,
1.0108892860517005, 1.0111174026254934, 1.0113455706759138, 1.0115737902145781,
1.0118020612531047, 1.0120303838031153, 1.0122587578762337, 1.012487183484087,
1.0127156606383041, 1.0129441893505169, 1.0131727696323602, 1.0134014014954713,
1.0136300849514894, 1.0138588200120575, 1.0140876066888203, 1.0143164449934257,
1.0145453349375237, 1.0147742765327674, 1.0150032697908125, 1.0152323147233171,
1.015461411341942, 1.0156905596583505, 1.0159197596842091, 1.0161490114311862,
1.0163783149109531, 1.0166076701351838, 1.0168370771155553, 1.0170665358637463,
1.0172960463914391, 1.0175256087103179, 1.0177552228320703, 1.0179848887683858,
1.0182146065309567, 1.0184443761314785, 1.0186741975816487, 1.0189040708931674,
1.0191339960777379, 1.0193639731470658, 1.0195940021128593, 1.0198240829868295,
1.0200542157806898, 1.0202844005061564, 1.0205146371749483, 1.0207449257987866,
1.0209752663893958, 1.0212056589585028, 1.0214361035178368, 1.0216666000791297,
1.0218971486541166, 1.0221277492545349, 1.0223584018921241, 1.0225891065786274,
1.0228198633257899, 1.0230506721453596, 1.023281533049087, 1.0235124460487257,
1.0237434111560313, 1.0239744283827625, 1.0242054977406807, 1.0244366192415495,
1.0246677928971357, 1.0248990187192082, 1.025130296719539, 1.0253616269099028,
1.0255930093020766, 1.0258244439078401, 1.0260559307389761, 1.0262874698072693,
1.0265190611245079, 1.0267507047024822, 1.0269824005529853, 1.027214148687813,
1.0274459491187637, 1.0276778018576387, 1.0279097069162415, 1.0281416643063788,
1.0283736740398595, 1.0286057361284953, 1.0288378505841009, 1.0290700174184932,
1.0293022366434921, 1.0295345082709197, 1.0297668323126017, 1.0299992087803651,
1.030231637686041, 1.0304641190414621, 1.0306966528584645, 1.0309292391488862,
1.0311618779245688, 1.0313945691973556, 1.0316273129790936, 1.0318601092816313,
1.0320929581168212, 1.0323258594965172, 1.0325588134325767, 1.0327918199368598,
1.0330248790212284, 1.0332579906975481, 1.0334911549776868, 1.033724371873515,
1.0339576413969056, 1.0341909635597348, 1.0344243383738811, 1.0346577658512259,
1.034891246003653, 1.0351247788430489, 1.0353583643813031, 1.0355920026303078,
1.0358256936019572, 1.0360594373081489, 1.0362932337607829, 1.0365270829717617,
1.0367609849529913, 1.0369949397163791, 1.0372289472738365, 1.0374630076372766,
1.0376971208186156, 1.0379312868297725, 1.0381655056826686, 1.0383997773892284,
1.0386341019613787, 1.0388684794110492, 1.0391029097501721, 1.0393373929906822,
1.0395719291445176, 1.0398065182236185, 1.0400411602399278, 1.0402758552053915,
1.0405106031319582, 1.0407454040315787, 1.0409802579162071, 1.0412151647977996,
1.0414501246883161, 1.0416851375997183, 1.0419202035439705, 1.0421553225330404,
1.042390494578898, 1.042625719693516, 1.0428609978888699, 1.043096329176938,
1.0433317135697009, 1.0435671510791424, 1.0438026417172486, 1.0440381854960086,
1.0442737824274138, 1.044509432523459, 1.044745135796141, 1.0449808922574599,
1.0452167019194181, 1.0454525647940205, 1.0456884808932754, 1.0459244502291931,
1.0461604728137874, 1.0463965486590741, 1.046632677777072, 1.0468688601798024,
1.0471050958792898, 1.047341384887561, 1.0475777272166455, 1.047814122878576,
1.048050571885387, 1.0482870742491166, 1.0485236299818055, 1.0487602390954964,
1.0489969016022356, 1.0492336175140715, 1.0494703868430555, 1.0497072096012419,
1.0499440858006872, 1.0501810154534512, 1.050417998571596, 1.0506550351671864,
1.0508921252522903, 1.0511292688389782, 1.0513664659393229, 1.0516037165654004,
1.0518410207292894, 1.0520783784430709, 1.0523157897188296, 1.0525532545686513,
1.0527907730046264, 1.0530283450388465, 1.0532659706834067, 1.0535036499504049,
1.0537413828519411, 1.0539791694001188, 1.0542170096070436, 1.0544549034848243,
1.0546928510455722, 1.0549308523014012, 1.0551689072644284, 1.0554070159467728,
1.0556451783605572, 1.0558833945179062, 1.0561216644309479, 1.0563599881118126,
1.0565983655726334, 1.0568367968255465, 1.0570752818826903, 1.0573138207562065,
1.057552413458239, 1.0577910600009348, 1.0580297603964437, 1.058268514656918,
1.0585073227945128, 1.0587461848213857, 1.058985100749698, 1.0592240705916123
};
const double bend_coarse[128] = {
1, 1.0594630943592953, 1.122462048309373, 1.189207115002721,
1.2599210498948732, 1.3348398541700344, 1.4142135623730951, 1.4983070768766815,
1.5874010519681994, 1.681792830507429, 1.7817974362806785, 1.8877486253633868,
2, 2.1189261887185906, 2.244924096618746, 2.3784142300054421,
2.5198420997897464, 2.6696797083400687, 2.8284271247461903, 2.996614153753363,
3.1748021039363992, 3.363585661014858, 3.5635948725613571, 3.7754972507267741,
4, 4.2378523774371812, 4.4898481932374912, 4.7568284600108841,
5.0396841995794928, 5.3393594166801366, 5.6568542494923806, 5.993228307506727,
6.3496042078727974, 6.727171322029716, 7.1271897451227151, 7.5509945014535473,
8, 8.4757047548743625, 8.9796963864749824, 9.5136569200217682,
10.079368399158986, 10.678718833360273, 11.313708498984761, 11.986456615013454,
12.699208415745595, 13.454342644059432, 14.25437949024543, 15.101989002907095,
16, 16.951409509748721, 17.959392772949972, 19.027313840043536,
20.158736798317967, 21.357437666720553, 22.627416997969522, 23.972913230026901,
25.398416831491197, 26.908685288118864, 28.508758980490853, 30.203978005814196,
32, 33.902819019497443, 35.918785545899944, 38.054627680087073,
40.317473596635935, 42.714875333441107, 45.254833995939045, 47.945826460053802,
50.796833662982394, 53.817370576237728, 57.017517960981706, 60.407956011628393,
64, 67.805638038994886, 71.837571091799887, 76.109255360174146,
80.63494719327187, 85.429750666882214, 90.509667991878089, 95.891652920107603,
101.59366732596479, 107.63474115247546, 114.03503592196341, 120.81591202325679,
128, 135.61127607798977, 143.67514218359977, 152.21851072034829,
161.26989438654374, 170.85950133376443, 181.01933598375618, 191.78330584021521,
203.18733465192958, 215.26948230495091, 228.07007184392683, 241.63182404651357,
256, 271.22255215597971, 287.35028436719938, 304.43702144069658,
322.53978877308765, 341.71900266752868, 362.03867196751236, 383.56661168043064,
406.37466930385892, 430.53896460990183, 456.14014368785394, 483.26364809302686,
512, 542.44510431195943, 574.70056873439876, 608.87404288139317,
645.0795775461753, 683.43800533505737, 724.07734393502471, 767.13322336086128,
812.74933860771785, 861.07792921980365, 912.28028737570787, 966.52729618605372,
1024, 1084.8902086239189, 1149.4011374687975, 1217.7480857627863,
1290.1591550923506, 1366.8760106701147, 1448.1546878700494, 1534.2664467217226
};

View File

@@ -0,0 +1,30 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
tables.h
*/
#include <math.h>
#define sine(x) (sin((2*PI/1024.0) * (x)))
#define SINE_CYCLE_LENGTH 1024
extern const Sint32 freq_table[];
extern const double vol_table[];
extern const double bend_fine[];
extern const double bend_coarse[];

View File

@@ -0,0 +1,105 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* Program to test the TiMidity core, without having to worry about decoder
* and/or playsound bugs. It's not meant to be robust or user-friendly.
*/
#include <stdio.h>
#include <stdlib.h>
#include "SDL.h"
#include "timidity.h"
int done_flag = 0;
MidiSong *song;
static void audio_callback(void *userdata, Uint8 *stream, int len)
{
if (Timidity_PlaySome(song, stream, len) == 0)
done_flag = 1;
}
int main(int argc, char *argv[])
{
SDL_AudioSpec audio;
SDL_RWops *rw;
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
return 1;
}
atexit(SDL_Quit);
if (argc != 2)
{
fprintf(stderr, "Usage: %s midifile\n", argv[0]);
return 1;
}
audio.freq = 44100;
audio.format = AUDIO_S16SYS;
audio.channels = 2;
audio.samples = 4096;
audio.callback = audio_callback;
if (SDL_OpenAudio(&audio, NULL) < 0)
{
fprintf(stderr, "Couldn't open audio device. %s\n", SDL_GetError());
return 1;
}
if (Timidity_Init() < 0)
{
fprintf(stderr, "Could not initialise TiMidity.\n");
return 1;
}
rw = SDL_RWFromFile(argv[1], "rb");
if (rw == NULL)
{
fprintf(stderr, "Could not create RWops from MIDI file.\n");
return 1;
}
song = Timidity_LoadSong(rw, &audio);
SDL_RWclose(rw);
if (song == NULL)
{
fprintf(stderr, "Could not open MIDI file.\n");
return 1;
}
Timidity_SetVolume(song, 100);
Timidity_Start(song);
SDL_PauseAudio(0);
while (!done_flag)
{
SDL_Delay(10);
}
SDL_PauseAudio(1);
Timidity_FreeSong(song);
Timidity_Exit();
return 0;
}

View File

@@ -0,0 +1,602 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
#include "timidity.h"
#include "options.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "tables.h"
ToneBank *master_tonebank[128], *master_drumset[128];
static char def_instr_name[256] = "";
#define MAXWORDS 10
/* Quick-and-dirty fgets() replacement. */
static char *RWgets(SDL_RWops *rw, char *s, int size)
{
int num_read = 0;
int newline = 0;
while (num_read < size && !newline)
{
if (SDL_RWread(rw, &s[num_read], 1, 1) != 1)
break;
/* Unlike fgets(), don't store newline. Under Windows/DOS we'll
* probably get an extra blank line for every line that's being
* read, but that should be ok.
*/
if (s[num_read] == '\n' || s[num_read] == '\r')
{
s[num_read] = '\0';
newline = 1;
}
num_read++;
}
s[num_read] = '\0';
return (num_read != 0) ? s : NULL;
}
static int read_config_file(char *name)
{
SDL_RWops *rw;
char tmp[1024], *w[MAXWORDS], *cp;
ToneBank *bank=0;
int i, j, k, line=0, words;
static int rcf_count=0;
if (rcf_count>50)
{
SNDDBG(("Probable source loop in configuration files\n"));
return (-1);
}
if (!(rw=open_file(name)))
return -1;
while (RWgets(rw, tmp, sizeof(tmp)))
{
line++;
w[words=0]=strtok(tmp, " \t\240");
if (!w[0]) continue;
/* Originally the TiMidity++ extensions were prefixed like this */
if (strcmp(w[0], "#extension") == 0)
words = -1;
else if (*w[0] == '#')
continue;
while (w[words] && *w[words] != '#' && (words < MAXWORDS))
w[++words]=strtok(0," \t\240");
/*
* TiMidity++ adds a number of extensions to the config file format.
* Many of them are completely irrelevant to SDL_sound, but at least
* we shouldn't choke on them.
*
* Unfortunately the documentation for these extensions is often quite
* vague, gramatically strange or completely absent.
*/
if (
!strcmp(w[0], "comm") /* "comm" program second */
|| !strcmp(w[0], "HTTPproxy") /* "HTTPproxy" hostname:port */
|| !strcmp(w[0], "FTPproxy") /* "FTPproxy" hostname:port */
|| !strcmp(w[0], "mailaddr") /* "mailaddr" your-mail-address */
|| !strcmp(w[0], "opt") /* "opt" timidity-options */
)
{
/*
* + "comm" sets some kind of comment -- the documentation is too
* vague for me to understand at this time.
* + "HTTPproxy", "FTPproxy" and "mailaddr" are for reading data
* over a network, rather than from the file system.
* + "opt" specifies default options for TiMidity++.
*
* These are all quite useless for our version of TiMidity, so
* they can safely remain no-ops.
*/
} else if (!strcmp(w[0], "timeout")) /* "timeout" program second */
{
/*
* Specifies a timeout value of the program. A number of seconds
* before TiMidity kills the note. This may be useful to implement
* later, but I don't see any urgent need for it.
*/
SNDDBG(("FIXME: Implement \"timeout\" in TiMidity config.\n"));
} else if (!strcmp(w[0], "copydrumset") /* "copydrumset" drumset */
|| !strcmp(w[0], "copybank")) /* "copybank" bank */
{
/*
* Copies all the settings of the specified drumset or bank to
* the current drumset or bank. May be useful later, but not a
* high priority.
*/
SNDDBG(("FIXME: Implement \"%s\" in TiMidity config.\n", w[0]));
} else if (!strcmp(w[0], "undef")) /* "undef" progno */
{
/*
* Undefines the tone "progno" of the current tone bank (or
* drum set?). Not a high priority.
*/
SNDDBG(("FIXME: Implement \"undef\" in TiMidity config.\n"));
} else if (!strcmp(w[0], "altassign")) /* "altassign" prog1 prog2 ... */
{
/*
* Sets the alternate assign for drum set. Whatever that's
* supposed to mean.
*/
SNDDBG(("FIXME: Implement \"altassign\" in TiMidity config.\n"));
} else if (!strcmp(w[0], "soundfont")
|| !strcmp(w[0], "font"))
{
/*
* I can't find any documentation for these, but I guess they're
* an alternative way of loading/unloading instruments.
*
* "soundfont" sf_file "remove"
* "soundfont" sf_file ["order=" order] ["cutoff=" cutoff]
* ["reso=" reso] ["amp=" amp]
* "font" "exclude" bank preset keynote
* "font" "order" order bank preset keynote
*/
SNDDBG(("FIXME: Implmement \"%s\" in TiMidity config.\n", w[0]));
} else if (!strcmp(w[0], "progbase"))
{
/*
* The documentation for this makes absolutely no sense to me, but
* apparently it sets some sort of base offset for tone numbers.
* Why anyone would want to do this is beyond me.
*/
SNDDBG(("FIXME: Implement \"progbase\" in TiMidity config.\n"));
} else if (!strcmp(w[0], "map")) /* "map" name set1 elem1 set2 elem2 */
{
/*
* This extension is the one we will need to implement, as it is
* used by the "eawpats". Unfortunately I cannot find any
* documentation whatsoever for it, but it looks like it's used
* for remapping one instrument to another somehow.
*/
SNDDBG(("FIXME: Implement \"map\" in TiMidity config.\n"));
}
/* Standard TiMidity config */
else if (!strcmp(w[0], "dir"))
{
if (words < 2)
{
SNDDBG(("%s: line %d: No directory given\n", name, line));
return -2;
}
for (i=1; i<words; i++)
add_to_pathlist(w[i]);
}
else if (!strcmp(w[0], "source"))
{
if (words < 2)
{
SNDDBG(("%s: line %d: No file name given\n", name, line));
return -2;
}
for (i=1; i<words; i++)
{
rcf_count++;
read_config_file(w[i]);
rcf_count--;
}
}
else if (!strcmp(w[0], "default"))
{
if (words != 2)
{
SNDDBG(("%s: line %d: Must specify exactly one patch name\n",
name, line));
return -2;
}
strncpy(def_instr_name, w[1], 255);
def_instr_name[255]='\0';
}
else if (!strcmp(w[0], "drumset"))
{
if (words < 2)
{
SNDDBG(("%s: line %d: No drum set number given\n", name, line));
return -2;
}
i=atoi(w[1]);
if (i<0 || i>127)
{
SNDDBG(("%s: line %d: Drum set must be between 0 and 127\n",
name, line));
return -2;
}
if (!master_drumset[i])
{
master_drumset[i] = safe_malloc(sizeof(ToneBank));
memset(master_drumset[i], 0, sizeof(ToneBank));
master_drumset[i]->tone = safe_malloc(128 * sizeof(ToneBankElement));
memset(master_drumset[i]->tone, 0, 128 * sizeof(ToneBankElement));
}
bank=master_drumset[i];
}
else if (!strcmp(w[0], "bank"))
{
if (words < 2)
{
SNDDBG(("%s: line %d: No bank number given\n", name, line));
return -2;
}
i=atoi(w[1]);
if (i<0 || i>127)
{
SNDDBG(("%s: line %d: Tone bank must be between 0 and 127\n",
name, line));
return -2;
}
if (!master_tonebank[i])
{
master_tonebank[i] = safe_malloc(sizeof(ToneBank));
memset(master_tonebank[i], 0, sizeof(ToneBank));
master_tonebank[i]->tone = safe_malloc(128 * sizeof(ToneBankElement));
memset(master_tonebank[i]->tone, 0, 128 * sizeof(ToneBankElement));
}
bank=master_tonebank[i];
}
else
{
if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
{
SNDDBG(("%s: line %d: syntax error\n", name, line));
return -2;
}
i=atoi(w[0]);
if (i<0 || i>127)
{
SNDDBG(("%s: line %d: Program must be between 0 and 127\n",
name, line));
return -2;
}
if (!bank)
{
SNDDBG(("%s: line %d: Must specify tone bank or drum set before assignment\n",
name, line));
return -2;
}
if (bank->tone[i].name)
free(bank->tone[i].name);
strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]);
bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
bank->tone[i].strip_tail=-1;
for (j=2; j<words; j++)
{
if (!(cp=strchr(w[j], '=')))
{
SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j]));
return -2;
}
*cp++=0;
if (!strcmp(w[j], "amp"))
{
k=atoi(cp);
if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
{
SNDDBG(("%s: line %d: amplification must be between 0 and %d\n",
name, line, MAX_AMPLIFICATION));
return -2;
}
bank->tone[i].amp=k;
}
else if (!strcmp(w[j], "note"))
{
k=atoi(cp);
if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
{
SNDDBG(("%s: line %d: note must be between 0 and 127\n",
name, line));
return -2;
}
bank->tone[i].note=k;
}
else if (!strcmp(w[j], "pan"))
{
if (!strcmp(cp, "center"))
k=64;
else if (!strcmp(cp, "left"))
k=0;
else if (!strcmp(cp, "right"))
k=127;
else
k=((atoi(cp)+100) * 100) / 157;
if ((k<0 || k>127) || (k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
{
SNDDBG(("%s: line %d: panning must be left, right, center, or between -100 and 100\n",
name, line));
return -2;
}
bank->tone[i].pan=k;
}
else if (!strcmp(w[j], "keep"))
{
if (!strcmp(cp, "env"))
bank->tone[i].strip_envelope=0;
else if (!strcmp(cp, "loop"))
bank->tone[i].strip_loop=0;
else
{
SNDDBG(("%s: line %d: keep must be env or loop\n", name, line));
return -2;
}
}
else if (!strcmp(w[j], "strip"))
{
if (!strcmp(cp, "env"))
bank->tone[i].strip_envelope=1;
else if (!strcmp(cp, "loop"))
bank->tone[i].strip_loop=1;
else if (!strcmp(cp, "tail"))
bank->tone[i].strip_tail=1;
else
{
SNDDBG(("%s: line %d: strip must be env, loop, or tail\n",
name, line));
return -2;
}
}
else
{
SNDDBG(("%s: line %d: bad patch option %s\n", name, line, w[j]));
return -2;
}
}
}
}
SDL_RWclose(rw);
return 0;
}
int Timidity_Init_NoConfig()
{
/* Allocate memory for the standard tonebank and drumset */
master_tonebank[0] = safe_malloc(sizeof(ToneBank));
memset(master_tonebank[0], 0, sizeof(ToneBank));
master_tonebank[0]->tone = safe_malloc(128 * sizeof(ToneBankElement));
memset(master_tonebank[0]->tone, 0, 128 * sizeof(ToneBankElement));
master_drumset[0] = safe_malloc(sizeof(ToneBank));
memset(master_drumset[0], 0, sizeof(ToneBank));
master_drumset[0]->tone = safe_malloc(128 * sizeof(ToneBankElement));
memset(master_drumset[0]->tone, 0, 128 * sizeof(ToneBankElement));
return 0;
}
int Timidity_Init()
{
/* !!! FIXME: This may be ugly, but slightly less so than requiring the
* default search path to have only one element. I think.
*
* We only need to include the likely locations for the config
* file itself since that file should contain any other directory
* that needs to be added to the search path.
*/
#ifdef WIN32
add_to_pathlist("\\TIMIDITY");
#else
add_to_pathlist("/usr/local/lib/timidity");
add_to_pathlist("/etc");
#endif
Timidity_Init_NoConfig();
return read_config_file(CONFIG_FILE);
}
MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio)
{
MidiSong *song;
Sint32 events;
int i;
if (rw == NULL)
return NULL;
/* Allocate memory for the song */
song = (MidiSong *)safe_malloc(sizeof(*song));
memset(song, 0, sizeof(*song));
song->patches = patches;
for (i = 0; i < 128; i++)
{
if (master_tonebank[i])
{
song->tonebank[i] = safe_malloc(sizeof(ToneBank));
memset(song->tonebank[i], 0, sizeof(ToneBank));
song->tonebank[i]->tone = master_tonebank[i]->tone;
}
if (master_drumset[i])
{
song->drumset[i] = safe_malloc(sizeof(ToneBank));
memset(song->drumset[i], 0, sizeof(ToneBank));
song->drumset[i]->tone = master_drumset[i]->tone;
}
}
song->amplification = DEFAULT_AMPLIFICATION;
song->voices = DEFAULT_VOICES;
song->drumchannels = DEFAULT_DRUMCHANNELS;
song->rw = rw;
song->rate = audio->freq;
song->encoding = 0;
if ((audio->format & 0xFF) == 16)
song->encoding |= PE_16BIT;
if (audio->format & 0x8000)
song->encoding |= PE_SIGNED;
if (audio->channels == 1)
song->encoding |= PE_MONO;
switch (audio->format) {
case AUDIO_S8:
song->write = s32tos8;
break;
case AUDIO_U8:
song->write = s32tou8;
break;
case AUDIO_S16LSB:
song->write = s32tos16l;
break;
case AUDIO_S16MSB:
song->write = s32tos16b;
break;
case AUDIO_U16LSB:
song->write = s32tou16l;
break;
default:
SNDDBG(("Unsupported audio format"));
song->write = s32tou16l;
break;
}
song->buffer_size = audio->samples;
song->resample_buffer = safe_malloc(audio->samples * sizeof(sample_t));
song->common_buffer = safe_malloc(audio->samples * 2 * sizeof(Sint32));
song->control_ratio = audio->freq / CONTROLS_PER_SECOND;
if (song->control_ratio < 1)
song->control_ratio = 1;
else if (song->control_ratio > MAX_CONTROL_RATIO)
song->control_ratio = MAX_CONTROL_RATIO;
song->lost_notes = 0;
song->cut_notes = 0;
song->events = read_midi_file(song, &events, &song->samples);
/* The RWops can safely be closed at this point, but let's make that the
* responsibility of the caller.
*/
/* Make sure everything is okay */
if (!song->events) {
free(song);
return(NULL);
}
song->default_instrument = 0;
song->default_program = DEFAULT_PROGRAM;
if (*def_instr_name)
set_default_instrument(song, def_instr_name);
load_missing_instruments(song);
return(song);
}
MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio)
{
return Timidity_LoadDLSSong(rw, NULL, audio);
}
void Timidity_FreeSong(MidiSong *song)
{
int i;
free_instruments(song);
for (i = 0; i < 128; i++)
{
if (song->tonebank[i])
free(song->tonebank[i]);
if (song->drumset[i])
free(song->drumset[i]);
}
free(song->common_buffer);
free(song->resample_buffer);
free(song->events);
free(song);
}
void Timidity_Exit(void)
{
int i, j;
for (i = 0; i < 128; i++)
{
if (master_tonebank[i])
{
ToneBankElement *e = master_tonebank[i]->tone;
if (e != NULL)
{
for (j = 0; j < 128; j++)
{
if (e[j].name != NULL)
free(e[j].name);
}
free(e);
}
free(master_tonebank[i]);
}
if (master_drumset[i])
{
ToneBankElement *e = master_drumset[i]->tone;
if (e != NULL)
{
for (j = 0; j < 128; j++)
{
if (e[j].name != NULL)
free(e[j].name);
}
free(e);
}
free(master_drumset[i]);
}
}
free_pathlist();
}

View File

@@ -0,0 +1,176 @@
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef TIMIDITY_H
#define TIMIDITY_H
#ifdef __cplusplus
extern "C" {
#endif
typedef Sint16 sample_t;
typedef Sint32 final_volume_t;
#define VIBRATO_SAMPLE_INCREMENTS 32
/* Maximum polyphony. */
#define MAX_VOICES 48
typedef struct {
Sint32
loop_start, loop_end, data_length,
sample_rate, low_vel, high_vel, low_freq, high_freq, root_freq;
Sint32
envelope_rate[6], envelope_offset[6];
float
volume;
sample_t *data;
Sint32
tremolo_sweep_increment, tremolo_phase_increment,
vibrato_sweep_increment, vibrato_control_ratio;
Uint8
tremolo_depth, vibrato_depth,
modes;
Sint8
panning, note_to_use;
} Sample;
typedef struct {
int
bank, program, volume, sustain, panning, pitchbend, expression,
mono, /* one note only on this channel -- not implemented yet */
pitchsens;
/* chorus, reverb... Coming soon to a 300-MHz, eight-way superscalar
processor near you */
float
pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
} Channel;
typedef struct {
Uint8
status, channel, note, velocity;
Sample *sample;
Sint32
orig_frequency, frequency,
sample_offset, sample_increment,
envelope_volume, envelope_target, envelope_increment,
tremolo_sweep, tremolo_sweep_position,
tremolo_phase, tremolo_phase_increment,
vibrato_sweep, vibrato_sweep_position;
final_volume_t left_mix, right_mix;
float
left_amp, right_amp, tremolo_volume;
Sint32
vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS];
int
vibrato_phase, vibrato_control_ratio, vibrato_control_counter,
envelope_stage, control_counter, panning, panned;
} Voice;
typedef struct {
int samples;
Sample *sample;
} Instrument;
/* Shared data */
typedef struct {
char *name;
int note, amp, pan, strip_loop, strip_envelope, strip_tail;
} ToneBankElement;
typedef struct {
ToneBankElement *tone;
Instrument *instrument[128];
} ToneBank;
typedef struct {
Sint32 time;
Uint8 channel, type, a, b;
} MidiEvent;
typedef struct {
MidiEvent event;
void *next;
} MidiEventList;
struct _DLS_Data;
typedef struct _DLS_Data DLS_Patches;
typedef struct {
int playing;
SDL_RWops *rw;
Sint32 rate;
Sint32 encoding;
float master_volume;
Sint32 amplification;
DLS_Patches *patches;
ToneBank *tonebank[128];
ToneBank *drumset[128];
Instrument *default_instrument;
int default_program;
void (*write)(void *dp, Sint32 *lp, Sint32 c);
int buffer_size;
sample_t *resample_buffer;
Sint32 *common_buffer;
Sint32 *buffer_pointer;
/* These would both fit into 32 bits, but they are often added in
large multiples, so it's simpler to have two roomy ints */
/* samples per MIDI delta-t */
Sint32 sample_increment;
Sint32 sample_correction;
Channel channel[16];
Voice voice[MAX_VOICES];
int voices;
Sint32 drumchannels;
Sint32 buffered_count;
Sint32 control_ratio;
Sint32 lost_notes;
Sint32 cut_notes;
Sint32 samples;
MidiEvent *events;
MidiEvent *current_event;
MidiEventList *evlist;
Sint32 current_sample;
Sint32 event_count;
Sint32 at;
} MidiSong;
/* Some of these are not defined in timidity.c but are here for convenience */
extern int Timidity_Init(void);
extern int Timidity_Init_NoConfig(void);
extern void Timidity_SetVolume(MidiSong *song, int volume);
extern int Timidity_PlaySome(MidiSong *song, void *stream, Sint32 len);
extern DLS_Patches *Timidity_LoadDLS(SDL_RWops *rw);
extern void Timidity_FreeDLS(DLS_Patches *patches);
extern MidiSong *Timidity_LoadDLSSong(SDL_RWops *rw, DLS_Patches *patches, SDL_AudioSpec *audio);
extern MidiSong *Timidity_LoadSong(SDL_RWops *rw, SDL_AudioSpec *audio);
extern void Timidity_Start(MidiSong *song);
extern void Timidity_Seek(MidiSong *song, Uint32 ms);
extern void Timidity_FreeSong(MidiSong *song);
extern void Timidity_Exit(void);
#ifdef __cplusplus
}
#endif
#endif /* TIMIDITY_H */

View File

@@ -0,0 +1,569 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* VOC decoder for SDL_sound.
*
* This driver handles Creative Labs VOC audio data...this is a legacy format,
* but there's some game ports that could make use of such a decoder. Plus,
* VOC is fairly straightforward to decode, so this is a more complex, but
* still palatable example of an SDL_sound decoder. Y'know, in case the
* RAW decoder didn't do it for you. :)
*
* This code was ripped from a decoder I had written for SDL_mixer, which was
* largely ripped from sox v12.17.1's voc.c.
*
* SDL_mixer: http://www.libsdl.org/projects/SDL_mixer/
* sox: http://www.freshmeat.net/projects/sox/
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_VOC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int VOC_init(void);
static void VOC_quit(void);
static int VOC_open(Sound_Sample *sample, const char *ext);
static void VOC_close(Sound_Sample *sample);
static Uint32 VOC_read(Sound_Sample *sample);
static int VOC_rewind(Sound_Sample *sample);
static int VOC_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_voc[] = { "VOC", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC =
{
{
extensions_voc,
"Creative Labs Voice format",
"Ryan C. Gordon <icculus@icculus.org>",
"http://www.icculus.org/SDL_sound/"
},
VOC_init, /* init() method */
VOC_quit, /* quit() method */
VOC_open, /* open() method */
VOC_close, /* close() method */
VOC_read, /* read() method */
VOC_rewind, /* rewind() method */
VOC_seek /* seek() method */
};
/* Private data for VOC file */
typedef struct vocstuff {
Uint32 rest; /* bytes remaining in current block */
Uint32 rate; /* rate code (byte) of this chunk */
int silent; /* sound or silence? */
Uint32 srate; /* rate code (byte) of silence */
Uint32 blockseek; /* start of current output block */
Uint32 samples; /* number of samples output */
Uint32 size; /* word length of data */
Uint8 channels; /* number of sound channels */
int extended; /* Has an extended block been read? */
Uint32 bufpos; /* byte position in internal->buffer. */
Uint32 start_pos; /* offset to seek to in stream when rewinding. */
int error; /* error condition (as opposed to EOF). */
} vs_t;
/* Size field */
/* SJB: note that the 1st 3 are sometimes used as sizeof(type) */
#define ST_SIZE_BYTE 1
#define ST_SIZE_8BIT 1
#define ST_SIZE_WORD 2
#define ST_SIZE_16BIT 2
#define ST_SIZE_DWORD 4
#define ST_SIZE_32BIT 4
#define ST_SIZE_FLOAT 5
#define ST_SIZE_DOUBLE 6
#define ST_SIZE_IEEE 7 /* IEEE 80-bit floats. */
/* Style field */
#define ST_ENCODING_UNSIGNED 1 /* unsigned linear: Sound Blaster */
#define ST_ENCODING_SIGN2 2 /* signed linear 2's comp: Mac */
#define ST_ENCODING_ULAW 3 /* U-law signed logs: US telephony, SPARC */
#define ST_ENCODING_ALAW 4 /* A-law signed logs: non-US telephony */
#define ST_ENCODING_ADPCM 5 /* Compressed PCM */
#define ST_ENCODING_IMA_ADPCM 6 /* Compressed PCM */
#define ST_ENCODING_GSM 7 /* GSM 6.10 33-byte frame lossy compression */
#define VOC_TERM 0
#define VOC_DATA 1
#define VOC_CONT 2
#define VOC_SILENCE 3
#define VOC_MARKER 4
#define VOC_TEXT 5
#define VOC_LOOP 6
#define VOC_LOOPEND 7
#define VOC_EXTENDED 8
#define VOC_DATA_16 9
static int VOC_init(void)
{
return(1); /* always succeeds. */
} /* VOC_init */
static void VOC_quit(void)
{
/* it's a no-op. */
} /* VOC_quit */
static __inline__ int voc_readbytes(SDL_RWops *src, vs_t *v, void *p, int size)
{
if (SDL_RWread(src, p, size, 1) != 1)
{
v->error = 1;
BAIL_MACRO("VOC: i/o error", 0);
} /* if */
return(1);
} /* voc_readbytes */
static __inline__ int voc_check_header(SDL_RWops *src)
{
/* VOC magic header */
Uint8 signature[20]; /* "Creative Voice File\032" */
Uint16 datablockofs;
vs_t v; /* dummy struct for voc_readbytes */
if (!voc_readbytes(src, &v, signature, sizeof (signature)))
return(0);
if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0)
{
BAIL_MACRO("VOC: Wrong signature; not a VOC file.", 0);
} /* if */
/* get the offset where the first datablock is located */
if (!voc_readbytes(src, &v, &datablockofs, sizeof (Uint16)))
return(0);
datablockofs = SDL_SwapLE16(datablockofs);
if (SDL_RWseek(src, datablockofs, SEEK_SET) != datablockofs)
{
BAIL_MACRO("VOC: Failed to seek to data block.", 0);
} /* if */
return(1); /* success! */
} /* voc_check_header */
/* Read next block header, save info, leave position at start of data */
static int voc_get_block(Sound_Sample *sample, vs_t *v)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *src = internal->rw;
Uint8 bits24[3];
Uint8 uc, block;
Uint32 sblen;
Uint16 new_rate_short;
Uint32 new_rate_long;
Uint8 trash[6];
Uint16 period;
int i;
v->silent = 0;
while (v->rest == 0)
{
if (SDL_RWread(src, &block, sizeof (block), 1) != 1)
return 1; /* assume that's the end of the file. */
if (block == VOC_TERM)
return 1;
if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1)
return 1; /* assume that's the end of the file. */
/* Size is an 24-bit value. Ugh. */
sblen = ( (bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16) );
switch(block)
{
case VOC_DATA:
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
return 0;
/* When DATA block preceeded by an EXTENDED */
/* block, the DATA blocks rate value is invalid */
if (!v->extended)
{
BAIL_IF_MACRO(uc == 0, "VOC: Sample rate is zero?", 0);
if ((v->rate != -1) && (uc != v->rate))
BAIL_MACRO("VOC sample rate codes differ", 0);
v->rate = uc;
v->channels = 1;
sample->actual.rate = 1000000.0/(256 - v->rate);
sample->actual.channels = 1;
} /* if */
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
return(0);
BAIL_IF_MACRO(uc != 0, "VOC: only supports 8-bit data", 0);
v->extended = 0;
v->rest = sblen - 2;
v->size = ST_SIZE_BYTE;
return 1;
case VOC_DATA_16:
if (!voc_readbytes(src, v, &new_rate_long, sizeof (Uint32)))
return 0;
new_rate_long = SDL_SwapLE32(new_rate_long);
BAIL_IF_MACRO(!new_rate_long, "VOC: Sample rate is zero?", 0);
if ((v->rate != -1) && (new_rate_long != v->rate))
BAIL_MACRO("VOC: sample rate codes differ", 0);
v->rate = new_rate_long;
sample->actual.rate = new_rate_long;
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
return 0;
switch (uc)
{
case 8: v->size = ST_SIZE_BYTE; break;
case 16: v->size = ST_SIZE_WORD; break;
default:
BAIL_MACRO("VOC: unknown data size", 0);
} /* switch */
if (!voc_readbytes(src, v, &v->channels, sizeof (Uint8)))
return 0;
if (!voc_readbytes(src, v, trash, sizeof (Uint8) * 6))
return 0;
v->rest = sblen - 12;
return 1;
case VOC_CONT:
v->rest = sblen;
return 1;
case VOC_SILENCE:
if (!voc_readbytes(src, v, &period, sizeof (period)))
return 0;
period = SDL_SwapLE16(period);
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
return 0;
BAIL_IF_MACRO(uc == 0, "VOC: silence sample rate is zero", 0);
/*
* Some silence-packed files have gratuitously
* different sample rate codes in silence.
* Adjust period.
*/
if ((v->rate != -1) && (uc != v->rate))
period = (period * (256 - uc))/(256 - v->rate);
else
v->rate = uc;
v->rest = period;
v->silent = 1;
return 1;
case VOC_LOOP:
case VOC_LOOPEND:
for(i = 0; i < sblen; i++) /* skip repeat loops. */
{
if (!voc_readbytes(src, v, trash, sizeof (Uint8)))
return 0;
} /* for */
break;
case VOC_EXTENDED:
/* An Extended block is followed by a data block */
/* Set this byte so we know to use the rate */
/* value from the extended block and not the */
/* data block. */
v->extended = 1;
if (!voc_readbytes(src, v, &new_rate_short, sizeof (Uint16)))
return 0;
new_rate_short = SDL_SwapLE16(new_rate_short);
BAIL_IF_MACRO(!new_rate_short, "VOC: sample rate is zero", 0);
if ((v->rate != -1) && (new_rate_short != v->rate))
BAIL_MACRO("VOC: sample rate codes differ", 0);
v->rate = new_rate_short;
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
return 0;
BAIL_IF_MACRO(uc != 0, "VOC: only supports 8-bit data", 0);
if (!voc_readbytes(src, v, &uc, sizeof (uc)))
return 0;
if (uc)
sample->actual.channels = 2; /* Stereo */
/* Needed number of channels before finishing
compute for rate */
sample->actual.rate =
(256000000L/(65536L - v->rate)) / sample->actual.channels;
/* An extended block must be followed by a data */
/* block to be valid so loop back to top so it */
/* can be grabed. */
continue;
case VOC_MARKER:
if (!voc_readbytes(src, v, trash, sizeof (Uint8) * 2))
return 0;
/* Falling! Falling! */
default: /* text block or other krapola. */
for(i = 0; i < sblen; i++) /* skip repeat loops. */
{
if (!voc_readbytes(src, v, trash, sizeof (Uint8)))
return 0;
} /* for */
if (block == VOC_TEXT)
continue; /* get next block */
} /* switch */
} /* while */
return 1;
} /* voc_get_block */
static int voc_read_waveform(Sound_Sample *sample, int fill_buf, Uint32 max)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *src = internal->rw;
vs_t *v = (vs_t *) internal->decoder_private;
int done = 0;
Uint8 silence = 0x80;
Uint8 *buf = internal->buffer;
if (v->rest == 0)
{
if (!voc_get_block(sample, v))
return 0;
} /* if */
if (v->rest == 0)
return 0;
max = (v->rest < max) ? v->rest : max;
if (v->silent)
{
if (v->size == ST_SIZE_WORD)
silence = 0x00;
/* Fill in silence */
if (fill_buf)
memset(buf + v->bufpos, silence, max);
done = max;
v->rest -= done;
} /* if */
else
{
if (fill_buf)
{
done = SDL_RWread(src, buf + v->bufpos, 1, max);
if (done < max)
{
__Sound_SetError("VOC: i/o error");
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
} /* if */
} /* if */
else
{
int cur, rc;
cur = SDL_RWtell(src);
if (cur >= 0)
{
rc = SDL_RWseek(src, max, SEEK_CUR);
if (rc >= 0)
done = rc - cur;
else
{
__Sound_SetError("VOC: seek error");
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
} /* else */
} /* if */
} /* else */
v->rest -= done;
v->bufpos += done;
} /* else */
return(done);
} /* voc_read_waveform */
static int VOC_open(Sound_Sample *sample, const char *ext)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = NULL;
if (!voc_check_header(internal->rw))
return(0);
v = (vs_t *) malloc(sizeof (vs_t));
BAIL_IF_MACRO(v == NULL, ERR_OUT_OF_MEMORY, 0);
memset(v, '\0', sizeof (vs_t));
v->start_pos = SDL_RWtell(internal->rw);
v->rate = -1;
if (!voc_get_block(sample, v))
{
free(v);
return(0);
} /* if */
if (v->rate == -1)
{
free(v);
BAIL_MACRO("VOC: data had no sound!", 0);
} /* if */
SNDDBG(("VOC: Accepting data stream.\n"));
sample->actual.format = (v->size == ST_SIZE_WORD) ? AUDIO_S16LSB:AUDIO_U8;
sample->actual.channels = v->channels;
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
internal->decoder_private = v;
return(1);
} /* VOC_open */
static void VOC_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
free(internal->decoder_private);
} /* VOC_close */
static Uint32 VOC_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = (vs_t *) internal->decoder_private;
v->bufpos = 0;
while (v->bufpos < internal->buffer_size)
{
Uint32 rc = voc_read_waveform(sample, 1, internal->buffer_size);
if (rc == 0)
{
sample->flags |= (v->error) ?
SOUND_SAMPLEFLAG_ERROR :
SOUND_SAMPLEFLAG_EOF;
break;
} /* if */
if (!voc_get_block(sample, v))
{
sample->flags |= (v->error) ?
SOUND_SAMPLEFLAG_ERROR :
SOUND_SAMPLEFLAG_EOF;
break;
} /* if */
} /* while */
return(v->bufpos);
} /* VOC_read */
static int VOC_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = (vs_t *) internal->decoder_private;
int rc = SDL_RWseek(internal->rw, v->start_pos, SEEK_SET);
BAIL_IF_MACRO(rc != v->start_pos, ERR_IO_ERROR, 0);
v->rest = 0;
return(1);
} /* VOC_rewind */
static int VOC_seek(Sound_Sample *sample, Uint32 ms)
{
/*
* VOCs don't lend themselves well to seeking, since you have to
* parse each section, which is an arbitrary size. The best we can do
* is rewind, set a flag saying not to write the waveforms to a buffer,
* and decode to the point that we want. Ugh. Fortunately, there's
* really no such thing as a large VOC, due to the era and hardware that
* spawned them, so even though this is inefficient, this is still a
* relatively fast operation in most cases.
*/
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
vs_t *v = (vs_t *) internal->decoder_private;
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
int origpos = SDL_RWtell(internal->rw);
int origrest = v->rest;
BAIL_IF_MACRO(!VOC_rewind(sample), NULL, 0);
v->bufpos = 0;
while (offset > 0)
{
Uint32 rc = voc_read_waveform(sample, 0, offset);
if ( (rc == 0) || (!voc_get_block(sample, v)) )
{
SDL_RWseek(internal->rw, origpos, SEEK_SET);
v->rest = origrest;
return(0);
} /* if */
offset -= rc;
} /* while */
return(1);
} /* VOC_seek */
#endif /* SOUND_SUPPORTS_VOC */
/* end of voc.c ... */

View File

@@ -0,0 +1,800 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* WAV decoder for SDL_sound.
*
* This driver handles Microsoft .WAVs, in as many of the thousands of
* variations as we can.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef SOUND_SUPPORTS_WAV
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_sound.h"
#define __SDL_SOUND_INTERNAL__
#include "SDL_sound_internal.h"
static int WAV_init(void);
static void WAV_quit(void);
static int WAV_open(Sound_Sample *sample, const char *ext);
static void WAV_close(Sound_Sample *sample);
static Uint32 WAV_read(Sound_Sample *sample);
static int WAV_rewind(Sound_Sample *sample);
static int WAV_seek(Sound_Sample *sample, Uint32 ms);
static const char *extensions_wav[] = { "WAV", NULL };
const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV =
{
{
extensions_wav,
"Microsoft WAVE audio format",
"Ryan C. Gordon <icculus@icculus.org>",
"http://www.icculus.org/SDL_sound/"
},
WAV_init, /* init() method */
WAV_quit, /* quit() method */
WAV_open, /* open() method */
WAV_close, /* close() method */
WAV_read, /* read() method */
WAV_rewind, /* rewind() method */
WAV_seek /* seek() method */
};
/* Better than SDL_ReadLE16, since you can detect i/o errors... */
static __inline__ int read_le16(SDL_RWops *rw, Uint16 *ui16)
{
int rc = SDL_RWread(rw, ui16, sizeof (Uint16), 1);
BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
*ui16 = SDL_SwapLE16(*ui16);
return(1);
} /* read_le16 */
/* Better than SDL_ReadLE32, since you can detect i/o errors... */
static __inline__ int read_le32(SDL_RWops *rw, Uint32 *ui32)
{
int rc = SDL_RWread(rw, ui32, sizeof (Uint32), 1);
BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
*ui32 = SDL_SwapLE32(*ui32);
return(1);
} /* read_le32 */
/* This is just cleaner on the caller's end... */
static __inline__ int read_uint8(SDL_RWops *rw, Uint8 *ui8)
{
int rc = SDL_RWread(rw, ui8, sizeof (Uint8), 1);
BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0);
return(1);
} /* read_uint8 */
/* Chunk management code... */
#define riffID 0x46464952 /* "RIFF", in ascii. */
#define waveID 0x45564157 /* "WAVE", in ascii. */
#define factID 0x74636166 /* "fact", in ascii. */
/*****************************************************************************
* The FORMAT chunk... *
*****************************************************************************/
#define fmtID 0x20746D66 /* "fmt ", in ascii. */
#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */
#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */
typedef struct
{
Sint16 iCoef1;
Sint16 iCoef2;
} ADPCMCOEFSET;
typedef struct
{
Uint8 bPredictor;
Uint16 iDelta;
Sint16 iSamp1;
Sint16 iSamp2;
} ADPCMBLOCKHEADER;
typedef struct S_WAV_FMT_T
{
Uint32 chunkID;
Sint32 chunkSize;
Sint16 wFormatTag;
Uint16 wChannels;
Uint32 dwSamplesPerSec;
Uint32 dwAvgBytesPerSec;
Uint16 wBlockAlign;
Uint16 wBitsPerSample;
Uint32 next_chunk_offset;
Uint32 sample_frame_size;
Uint32 data_starting_offset;
Uint32 total_bytes;
void (*free)(struct S_WAV_FMT_T *fmt);
Uint32 (*read_sample)(Sound_Sample *sample);
int (*rewind_sample)(Sound_Sample *sample);
int (*seek_sample)(Sound_Sample *sample, Uint32 ms);
union
{
struct
{
Uint16 cbSize;
Uint16 wSamplesPerBlock;
Uint16 wNumCoef;
ADPCMCOEFSET *aCoef;
ADPCMBLOCKHEADER *blockheaders;
Uint32 samples_left_in_block;
int nibble_state;
Sint8 nibble;
} adpcm;
/* put other format-specific data here... */
} fmt;
} fmt_t;
/*
* Read in a fmt_t from disk. This makes this process safe regardless of
* the processor's byte order or how the fmt_t structure is packed.
* Note that the union "fmt" is not read in here; that is handled as
* needed in the read_fmt_* functions.
*/
static int read_fmt_chunk(SDL_RWops *rw, fmt_t *fmt)
{
/* skip reading the chunk ID, since it was already read at this point... */
fmt->chunkID = fmtID;
BAIL_IF_MACRO(!read_le32(rw, &fmt->chunkSize), NULL, 0);
BAIL_IF_MACRO(fmt->chunkSize < 16, "WAV: Invalid chunk size", 0);
fmt->next_chunk_offset = SDL_RWtell(rw) + fmt->chunkSize;
BAIL_IF_MACRO(!read_le16(rw, &fmt->wFormatTag), NULL, 0);
BAIL_IF_MACRO(!read_le16(rw, &fmt->wChannels), NULL, 0);
BAIL_IF_MACRO(!read_le32(rw, &fmt->dwSamplesPerSec), NULL, 0);
BAIL_IF_MACRO(!read_le32(rw, &fmt->dwAvgBytesPerSec), NULL, 0);
BAIL_IF_MACRO(!read_le16(rw, &fmt->wBlockAlign), NULL, 0);
BAIL_IF_MACRO(!read_le16(rw, &fmt->wBitsPerSample), NULL, 0);
return(1);
} /* read_fmt_chunk */
/*****************************************************************************
* The DATA chunk... *
*****************************************************************************/
#define dataID 0x61746164 /* "data", in ascii. */
typedef struct
{
Uint32 chunkID;
Sint32 chunkSize;
/* Then, (chunkSize) bytes of waveform data... */
} data_t;
/*
* Read in a data_t from disk. This makes this process safe regardless of
* the processor's byte order or how the fmt_t structure is packed.
*/
static int read_data_chunk(SDL_RWops *rw, data_t *data)
{
/* skip reading the chunk ID, since it was already read at this point... */
data->chunkID = dataID;
BAIL_IF_MACRO(!read_le32(rw, &data->chunkSize), NULL, 0);
return(1);
} /* read_data_chunk */
/*****************************************************************************
* this is what we store in our internal->decoder_private field... *
*****************************************************************************/
typedef struct
{
fmt_t *fmt;
Sint32 bytesLeft;
} wav_t;
/*****************************************************************************
* Normal, uncompressed waveform handler... *
*****************************************************************************/
/*
* Sound_Decode() lands here for uncompressed WAVs...
*/
static Uint32 read_sample_fmt_normal(Sound_Sample *sample)
{
Uint32 retval;
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
Uint32 max = (internal->buffer_size < (Uint32) w->bytesLeft) ?
internal->buffer_size : (Uint32) w->bytesLeft;
assert(max > 0);
/*
* We don't actually do any decoding, so we read the wav data
* directly into the internal buffer...
*/
retval = SDL_RWread(internal->rw, internal->buffer, 1, max);
w->bytesLeft -= retval;
/* Make sure the read went smoothly... */
if ((retval == 0) || (w->bytesLeft == 0))
sample->flags |= SOUND_SAMPLEFLAG_EOF;
else if (retval == -1)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
/* (next call this EAGAIN may turn into an EOF or error.) */
else if (retval < internal->buffer_size)
sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
return(retval);
} /* read_sample_fmt_normal */
static int seek_sample_fmt_normal(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
fmt_t *fmt = w->fmt;
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
int pos = (int) (fmt->data_starting_offset + offset);
int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
w->bytesLeft = fmt->total_bytes - offset;
return(1); /* success. */
} /* seek_sample_fmt_normal */
static int rewind_sample_fmt_normal(Sound_Sample *sample)
{
/* no-op. */
return(1);
} /* rewind_sample_fmt_normal */
static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt)
{
/* (don't need to read more from the RWops...) */
fmt->free = NULL;
fmt->read_sample = read_sample_fmt_normal;
fmt->rewind_sample = rewind_sample_fmt_normal;
fmt->seek_sample = seek_sample_fmt_normal;
return(1);
} /* read_fmt_normal */
/*****************************************************************************
* ADPCM compression handler... *
*****************************************************************************/
#define FIXED_POINT_COEF_BASE 256
#define FIXED_POINT_ADAPTION_BASE 256
#define SMALLEST_ADPCM_DELTA 16
static __inline__ int read_adpcm_block_headers(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *rw = internal->rw;
wav_t *w = (wav_t *) internal->decoder_private;
fmt_t *fmt = w->fmt;
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
int i;
int max = fmt->wChannels;
if (w->bytesLeft < fmt->wBlockAlign)
{
sample->flags |= SOUND_SAMPLEFLAG_EOF;
return(0);
} /* if */
w->bytesLeft -= fmt->wBlockAlign;
for (i = 0; i < max; i++)
BAIL_IF_MACRO(!read_uint8(rw, &headers[i].bPredictor), NULL, 0);
for (i = 0; i < max; i++)
BAIL_IF_MACRO(!read_le16(rw, &headers[i].iDelta), NULL, 0);
for (i = 0; i < max; i++)
BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp1), NULL, 0);
for (i = 0; i < max; i++)
BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp2), NULL, 0);
fmt->fmt.adpcm.samples_left_in_block = fmt->fmt.adpcm.wSamplesPerBlock;
fmt->fmt.adpcm.nibble_state = 0;
return(1);
} /* read_adpcm_block_headers */
static __inline__ void do_adpcm_nibble(Uint8 nib,
ADPCMBLOCKHEADER *header,
Sint32 lPredSamp)
{
static const Sint32 max_audioval = ((1<<(16-1))-1);
static const Sint32 min_audioval = -(1<<(16-1));
static const Sint32 AdaptionTable[] =
{
230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
};
Sint32 lNewSamp;
Sint32 delta;
if (nib & 0x08)
lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10));
else
lNewSamp = lPredSamp + (header->iDelta * nib);
/* clamp value... */
if (lNewSamp < min_audioval)
lNewSamp = min_audioval;
else if (lNewSamp > max_audioval)
lNewSamp = max_audioval;
delta = ((Sint32) header->iDelta * AdaptionTable[nib]) /
FIXED_POINT_ADAPTION_BASE;
if (delta < SMALLEST_ADPCM_DELTA)
delta = SMALLEST_ADPCM_DELTA;
header->iDelta = delta;
header->iSamp2 = header->iSamp1;
header->iSamp1 = lNewSamp;
} /* do_adpcm_nibble */
static __inline__ int decode_adpcm_sample_frame(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
fmt_t *fmt = w->fmt;
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
SDL_RWops *rw = internal->rw;
int i;
int max = fmt->wChannels;
Sint32 delta;
Uint8 nib = fmt->fmt.adpcm.nibble;
for (i = 0; i < max; i++)
{
Uint8 byte;
Sint16 iCoef1 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef1;
Sint16 iCoef2 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef2;
Sint32 lPredSamp = ((headers[i].iSamp1 * iCoef1) +
(headers[i].iSamp2 * iCoef2)) /
FIXED_POINT_COEF_BASE;
if (fmt->fmt.adpcm.nibble_state == 0)
{
BAIL_IF_MACRO(!read_uint8(rw, &nib), NULL, 0);
fmt->fmt.adpcm.nibble_state = 1;
do_adpcm_nibble(nib >> 4, &headers[i], lPredSamp);
} /* if */
else
{
fmt->fmt.adpcm.nibble_state = 0;
do_adpcm_nibble(nib & 0x0F, &headers[i], lPredSamp);
} /* else */
} /* for */
fmt->fmt.adpcm.nibble = nib;
return(1);
} /* decode_adpcm_sample_frame */
static __inline__ void put_adpcm_sample_frame1(void *_buf, fmt_t *fmt)
{
Uint16 *buf = (Uint16 *) _buf;
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
int i;
for (i = 0; i < fmt->wChannels; i++)
*(buf++) = headers[i].iSamp1;
} /* put_adpcm_sample_frame1 */
static __inline__ void put_adpcm_sample_frame2(void *_buf, fmt_t *fmt)
{
Uint16 *buf = (Uint16 *) _buf;
ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders;
int i;
for (i = 0; i < fmt->wChannels; i++)
*(buf++) = headers[i].iSamp2;
} /* put_adpcm_sample_frame2 */
/*
* Sound_Decode() lands here for ADPCM-encoded WAVs...
*/
static Uint32 read_sample_fmt_adpcm(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
fmt_t *fmt = w->fmt;
Uint32 bw = 0;
while (bw < internal->buffer_size)
{
/* write ongoing sample frame before reading more data... */
switch (fmt->fmt.adpcm.samples_left_in_block)
{
case 0: /* need to read a new block... */
if (!read_adpcm_block_headers(sample))
{
if ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0)
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(bw);
} /* if */
/* only write first sample frame for now. */
put_adpcm_sample_frame2((Uint8 *) internal->buffer + bw, fmt);
fmt->fmt.adpcm.samples_left_in_block--;
bw += fmt->sample_frame_size;
break;
case 1: /* output last sample frame of block... */
put_adpcm_sample_frame1((Uint8 *) internal->buffer + bw, fmt);
fmt->fmt.adpcm.samples_left_in_block--;
bw += fmt->sample_frame_size;
break;
default: /* output latest sample frame and read a new one... */
put_adpcm_sample_frame1((Uint8 *) internal->buffer + bw, fmt);
fmt->fmt.adpcm.samples_left_in_block--;
bw += fmt->sample_frame_size;
if (!decode_adpcm_sample_frame(sample))
{
sample->flags |= SOUND_SAMPLEFLAG_ERROR;
return(bw);
} /* if */
} /* switch */
} /* while */
return(bw);
} /* read_sample_fmt_adpcm */
/*
* Sound_FreeSample() lands here for ADPCM-encoded WAVs...
*/
static void free_fmt_adpcm(fmt_t *fmt)
{
if (fmt->fmt.adpcm.aCoef != NULL)
free(fmt->fmt.adpcm.aCoef);
if (fmt->fmt.adpcm.blockheaders != NULL)
free(fmt->fmt.adpcm.blockheaders);
} /* free_fmt_adpcm */
static int rewind_sample_fmt_adpcm(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
w->fmt->fmt.adpcm.samples_left_in_block = 0;
return(1);
} /* rewind_sample_fmt_adpcm */
static int seek_sample_fmt_adpcm(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
fmt_t *fmt = w->fmt;
Uint32 origsampsleft = fmt->fmt.adpcm.samples_left_in_block;
int origpos = SDL_RWtell(internal->rw);
int offset = __Sound_convertMsToBytePos(&sample->actual, ms);
int bpb = (fmt->fmt.adpcm.wSamplesPerBlock * fmt->sample_frame_size);
int skipsize = (offset / bpb) * fmt->wBlockAlign;
int pos = skipsize + fmt->data_starting_offset;
int rc = SDL_RWseek(internal->rw, pos, SEEK_SET);
BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0);
/* The offset we need is in this block, so we need to decode to there. */
skipsize += (offset % bpb);
rc = (offset % bpb); /* bytes into this block we need to decode */
if (!read_adpcm_block_headers(sample))
{
SDL_RWseek(internal->rw, origpos, SEEK_SET); /* try to make sane. */
return(0);
} /* if */
/* first sample frame of block is a freebie. :) */
fmt->fmt.adpcm.samples_left_in_block--;
rc -= fmt->sample_frame_size;
while (rc > 0)
{
if (!decode_adpcm_sample_frame(sample))
{
SDL_RWseek(internal->rw, origpos, SEEK_SET);
fmt->fmt.adpcm.samples_left_in_block = origsampsleft;
return(0);
} /* if */
fmt->fmt.adpcm.samples_left_in_block--;
rc -= fmt->sample_frame_size;
} /* while */
w->bytesLeft = fmt->total_bytes - skipsize;
return(1); /* success. */
} /* seek_sample_fmt_adpcm */
/*
* Read in the adpcm-specific info from disk. This makes this process
* safe regardless of the processor's byte order or how the fmt_t
* structure is packed.
*/
static int read_fmt_adpcm(SDL_RWops *rw, fmt_t *fmt)
{
size_t i;
memset(&fmt->fmt.adpcm, '\0', sizeof (fmt->fmt.adpcm));
fmt->free = free_fmt_adpcm;
fmt->read_sample = read_sample_fmt_adpcm;
fmt->rewind_sample = rewind_sample_fmt_adpcm;
fmt->seek_sample = seek_sample_fmt_adpcm;
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.cbSize), NULL, 0);
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wSamplesPerBlock), NULL, 0);
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wNumCoef), NULL, 0);
/* fmt->free() is always called, so these malloc()s will be cleaned up. */
i = sizeof (ADPCMCOEFSET) * fmt->fmt.adpcm.wNumCoef;
fmt->fmt.adpcm.aCoef = (ADPCMCOEFSET *) malloc(i);
BAIL_IF_MACRO(fmt->fmt.adpcm.aCoef == NULL, ERR_OUT_OF_MEMORY, 0);
for (i = 0; i < fmt->fmt.adpcm.wNumCoef; i++)
{
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef1), NULL, 0);
BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef2), NULL, 0);
} /* for */
i = sizeof (ADPCMBLOCKHEADER) * fmt->wChannels;
fmt->fmt.adpcm.blockheaders = (ADPCMBLOCKHEADER *) malloc(i);
BAIL_IF_MACRO(fmt->fmt.adpcm.blockheaders == NULL, ERR_OUT_OF_MEMORY, 0);
return(1);
} /* read_fmt_adpcm */
/*****************************************************************************
* Everything else... *
*****************************************************************************/
static int WAV_init(void)
{
return(1); /* always succeeds. */
} /* WAV_init */
static void WAV_quit(void)
{
/* it's a no-op. */
} /* WAV_quit */
static int read_fmt(SDL_RWops *rw, fmt_t *fmt)
{
/* if it's in this switch statement, we support the format. */
switch (fmt->wFormatTag)
{
case FMT_NORMAL:
SNDDBG(("WAV: Appears to be uncompressed audio.\n"));
return(read_fmt_normal(rw, fmt));
case FMT_ADPCM:
SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n"));
return(read_fmt_adpcm(rw, fmt));
/* add other types here. */
default:
SNDDBG(("WAV: Format 0x%X is unknown.\n",
(unsigned int) fmt->wFormatTag));
BAIL_MACRO("WAV: Unsupported format", 0);
} /* switch */
assert(0); /* shouldn't hit this point. */
return(0);
} /* read_fmt */
/*
* Locate a specific chunk in the WAVE file by ID...
*/
static int find_chunk(SDL_RWops *rw, Uint32 id)
{
Sint32 siz = 0;
Uint32 _id = 0;
Uint32 pos = SDL_RWtell(rw);
while (1)
{
BAIL_IF_MACRO(!read_le32(rw, &_id), NULL, 0);
if (_id == id)
return(1);
/* skip ahead and see what next chunk is... */
BAIL_IF_MACRO(!read_le32(rw, &siz), NULL, 0);
assert(siz >= 0);
pos += (sizeof (Uint32) * 2) + siz;
if (siz > 0)
BAIL_IF_MACRO(SDL_RWseek(rw, pos, SEEK_SET) != pos, NULL, 0);
} /* while */
return(0); /* shouldn't hit this, but just in case... */
} /* find_chunk */
static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
SDL_RWops *rw = internal->rw;
data_t d;
wav_t *w;
Uint32 pos;
BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0);
SDL_ReadLE32(rw); /* throw the length away; we get this info later. */
BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0);
BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0);
BAIL_IF_MACRO(!read_fmt_chunk(rw, fmt), "WAV: Can't read format chunk.", 0);
sample->actual.channels = (Uint8) fmt->wChannels;
sample->actual.rate = fmt->dwSamplesPerSec;
if ((fmt->wBitsPerSample == 4) /*|| (fmt->wBitsPerSample == 0) */ )
sample->actual.format = AUDIO_S16SYS;
else if (fmt->wBitsPerSample == 8)
sample->actual.format = AUDIO_U8;
else if (fmt->wBitsPerSample == 16)
sample->actual.format = AUDIO_S16LSB;
else
{
SNDDBG(("WAV: %d bits per sample!?\n", (int) fmt->wBitsPerSample));
BAIL_MACRO("WAV: Unsupported sample size.", 0);
} /* else */
BAIL_IF_MACRO(!read_fmt(rw, fmt), NULL, 0);
SDL_RWseek(rw, fmt->next_chunk_offset, SEEK_SET);
BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0);
BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0);
w = (wav_t *) malloc(sizeof(wav_t));
BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0);
w->fmt = fmt;
fmt->total_bytes = w->bytesLeft = d.chunkSize;
fmt->data_starting_offset = SDL_RWtell(rw);
fmt->sample_frame_size = ( ((sample->actual.format & 0xFF) / 8) *
sample->actual.channels );
internal->decoder_private = (void *) w;
sample->flags = SOUND_SAMPLEFLAG_NONE;
if (fmt->seek_sample != NULL)
sample->flags |= SOUND_SAMPLEFLAG_CANSEEK;
SNDDBG(("WAV: Accepting data stream.\n"));
return(1); /* we'll handle this data. */
} /* WAV_open_internal */
static int WAV_open(Sound_Sample *sample, const char *ext)
{
int rc;
fmt_t *fmt = (fmt_t *) malloc(sizeof (fmt_t));
BAIL_IF_MACRO(fmt == NULL, ERR_OUT_OF_MEMORY, 0);
memset(fmt, '\0', sizeof (fmt_t));
rc = WAV_open_internal(sample, ext, fmt);
if (!rc)
{
if (fmt->free != NULL)
fmt->free(fmt);
free(fmt);
} /* if */
return(rc);
} /* WAV_open */
static void WAV_close(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
if (w->fmt->free != NULL)
w->fmt->free(w->fmt);
free(w->fmt);
free(w);
} /* WAV_close */
static Uint32 WAV_read(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
return(w->fmt->read_sample(sample));
} /* WAV_read */
static int WAV_rewind(Sound_Sample *sample)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
fmt_t *fmt = w->fmt;
int rc = SDL_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET);
BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0);
w->bytesLeft = fmt->total_bytes;
return(fmt->rewind_sample(sample));
} /* WAV_rewind */
static int WAV_seek(Sound_Sample *sample, Uint32 ms)
{
Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
wav_t *w = (wav_t *) internal->decoder_private;
return(w->fmt->seek_sample(sample, ms));
} /* WAV_seek */
#endif /* SOUND_SUPPORTS_WAV */
/* end of wav.c ... */

View File

@@ -0,0 +1,135 @@
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Some extra RWops that are needed or are just handy to have.
*
* Please see the file COPYING in the source's root directory.
*
* This file written by Ryan C. Gordon. (icculus@icculus.org)
*/
#include <stdio.h>
#include <stdlib.h>
#include "SDL.h"
/*
* The Reference Counter RWops...
*/
typedef struct
{
SDL_RWops *rw; /* The actual RWops we're refcounting... */
int refcount; /* The refcount; starts at 1. If goes to 0, delete. */
} RWRefCounterData;
/* Just pass through to the actual SDL_RWops's method... */
static int refcounter_seek(SDL_RWops *rw, int offset, int whence)
{
RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
return(data->rw->seek(data->rw, offset, whence));
} /* refcounter_seek */
/* Just pass through to the actual SDL_RWops's method... */
static int refcounter_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
{
RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
return(data->rw->read(data->rw, ptr, size, maxnum));
} /* refcounter_read */
/* Just pass through to the actual SDL_RWops's method... */
static int refcounter_write(SDL_RWops *rw, const void *ptr, int size, int num)
{
RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
return(data->rw->write(data->rw, ptr, size, num));
} /* refcounter_write */
/*
* Decrement the reference count. If there are no more references, pass
* through to the actual SDL_RWops's method, and then clean ourselves up.
*/
static int refcounter_close(SDL_RWops *rw)
{
int retval = 0;
RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
data->refcount--;
if (data->refcount <= 0)
{
retval = data->rw->close(data->rw);
free(data);
SDL_FreeRW(rw);
} /* if */
return(retval);
} /* refcounter_close */
void RWops_RWRefCounter_addRef(SDL_RWops *rw)
{
RWRefCounterData *data = (RWRefCounterData *) rw->hidden.unknown.data1;
data->refcount++;
} /* RWops_RWRefCounter_addRef */
SDL_RWops *RWops_RWRefCounter_new(SDL_RWops *rw)
{
SDL_RWops *retval = NULL;
if (rw == NULL)
{
SDL_SetError("NULL argument to RWops_RWRefCounter_new().");
return(NULL);
} /* if */
retval = SDL_AllocRW();
if (retval != NULL)
{
RWRefCounterData *data;
data = (RWRefCounterData *) malloc(sizeof (RWRefCounterData));
if (data == NULL)
{
SDL_SetError("Out of memory.");
SDL_FreeRW(retval);
retval = NULL;
} /* if */
else
{
data->rw = rw;
data->refcount = 1;
retval->hidden.unknown.data1 = data;
retval->seek = refcounter_seek;
retval->read = refcounter_read;
retval->write = refcounter_write;
retval->close = refcounter_close;
} /* else */
} /* if */
return(retval);
} /* RWops_RWRefCounter_new */
/* end of extra_rwops.c ... */

View File

@@ -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 ... */

View File

@@ -0,0 +1,674 @@
/** \file SDL_sound.h */
/*
* SDL_sound -- An abstract sound format decoding API.
* Copyright (C) 2001 Ryan C. Gordon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* \mainpage SDL_sound
*
* The latest version of SDL_sound can be found at:
* http://icculus.org/SDL_sound/
*
* The basic gist of SDL_sound is that you use an SDL_RWops to get sound data
* into this library, and SDL_sound will take that data, in one of several
* popular formats, and decode it into raw waveform data in the format of
* your choice. This gives you a nice abstraction for getting sound into your
* game or application; just feed it to SDL_sound, and it will handle
* decoding and converting, so you can just pass it to your SDL audio
* callback (or whatever). Since it gets data from an SDL_RWops, you can get
* the initial sound data from any number of sources: file, memory buffer,
* network connection, etc.
*
* As the name implies, this library depends on SDL: Simple Directmedia Layer,
* which is a powerful, free, and cross-platform multimedia library. It can
* be found at http://www.libsdl.org/
*
* Support is in place or planned for the following sound formats:
* - .WAV (Microsoft WAVfile RIFF data, internal.)
* - .VOC (Creative Labs' Voice format, internal.)
* - .MP3 (MPEG-1 Layer 3 support, via the SMPEG and mpglib libraries.)
* - .MID (MIDI music converted to Waveform data, internal.)
* - .MOD (MOD files, via MikMod and ModPlug.)
* - .OGG (Ogg files, via Ogg Vorbis libraries.)
* - .SPX (Speex files, via libspeex.)
* - .SHN (Shorten files, internal.)
* - .RAW (Raw sound data in any format, internal.)
* - .AU (Sun's Audio format, internal.)
* - .AIFF (Audio Interchange format, internal.)
* - .FLAC (Lossless audio compression, via libFLAC.)
*
* (...and more to come...)
*
* Please see the file COPYING in the source's root directory.
*
* \author Ryan C. Gordon (icculus@icculus.org)
* \author many others, please see CREDITS in the source's root directory.
*/
#ifndef _INCLUDE_SDL_SOUND_H_
#define _INCLUDE_SDL_SOUND_H_
#include "SDL.h"
#include "SDL_endian.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef DOXYGEN_SHOULD_IGNORE_THIS
#ifndef SDLCALL /* may not be defined with older SDL releases. */
#define SDLCALL
#endif
#ifdef SDL_SOUND_DLL_EXPORTS
# define SNDDECLSPEC __declspec(dllexport)
#else
# define SNDDECLSPEC
#endif
#define SOUND_VER_MAJOR 1
#define SOUND_VER_MINOR 0
#define SOUND_VER_PATCH 3
#endif
/**
* \enum Sound_SampleFlags
* \brief Flags that are used in a Sound_Sample to show various states.
*
* To use:
* \code
* if (sample->flags & SOUND_SAMPLEFLAG_ERROR) { dosomething(); }
* \endcode
*
* \sa Sound_SampleNew
* \sa Sound_SampleNewFromFile
* \sa Sound_SampleDecode
* \sa Sound_SampleDecodeAll
* \sa Sound_SampleSeek
*/
typedef enum
{
SOUND_SAMPLEFLAG_NONE = 0, /**< No special attributes. */
/* these are set at sample creation time... */
SOUND_SAMPLEFLAG_CANSEEK = 1, /**< Sample can seek to arbitrary points. */
/* these are set during decoding... */
SOUND_SAMPLEFLAG_EOF = 1 << 29, /**< End of input stream. */
SOUND_SAMPLEFLAG_ERROR = 1 << 30, /**< Unrecoverable error. */
SOUND_SAMPLEFLAG_EAGAIN = 1 << 31 /**< Function would block, or temp error. */
} Sound_SampleFlags;
/**
* \struct Sound_AudioInfo
* \brief Information about an existing sample's format.
*
* These are the basics of a decoded sample's data structure: data format
* (see AUDIO_U8 and friends in SDL_audio.h), number of channels, and sample
* rate. If you need more explanation than that, you should stop developing
* sound code right now.
*
* \sa Sound_SampleNew
* \sa Sound_SampleNewFromFile
*/
typedef struct
{
Uint16 format; /**< Equivalent of SDL_AudioSpec.format. */
Uint8 channels; /**< Number of sound channels. 1 == mono, 2 == stereo. */
Uint32 rate; /**< Sample rate; frequency of sample points per second. */
} Sound_AudioInfo;
/**
* \struct Sound_DecoderInfo
* \brief Information about available soudn decoders.
*
* Each decoder sets up one of these structs, which can be retrieved via
* the Sound_AvailableDecoders() function. EVERY FIELD IN THIS IS READ-ONLY.
*
* The extensions field is a NULL-terminated list of ASCIZ strings. You
* should read it like this:
*
* \code
* const char **ext;
* for (ext = info->extensions; *ext != NULL; ext++) {
* printf(" File extension \"%s\"\n", *ext);
* }
* \endcode
*
* \sa Sound_AvailableDecoders
*/
typedef struct
{
const char **extensions; /**< File extensions, list ends with NULL. */
const char *description; /**< Human readable description of decoder. */
const char *author; /**< "Name Of Author \<email@emailhost.dom\>" */
const char *url; /**< URL specific to this decoder. */
} Sound_DecoderInfo;
/**
* \struct Sound_Sample
* \brief Represents sound data in the process of being decoded.
*
* The Sound_Sample structure is the heart of SDL_sound. This holds
* information about a source of sound data as it is being decoded.
* EVERY FIELD IN THIS IS READ-ONLY. Please use the API functions to
* change them.
*/
typedef struct
{
void *opaque; /**< Internal use only. Don't touch. */
const Sound_DecoderInfo *decoder; /**< Decoder used for this sample. */
Sound_AudioInfo desired; /**< Desired audio format for conversion. */
Sound_AudioInfo actual; /**< Actual audio format of sample. */
void *buffer; /**< Decoded sound data lands in here. */
Uint32 buffer_size; /**< Current size of (buffer), in bytes (Uint8). */
Sound_SampleFlags flags; /**< Flags relating to this sample. */
} Sound_Sample;
/**
* \struct Sound_Version
* \brief Information the version of SDL_sound in use.
*
* Represents the library's version as three levels: major revision
* (increments with massive changes, additions, and enhancements),
* minor revision (increments with backwards-compatible changes to the
* major revision), and patchlevel (increments with fixes to the minor
* revision).
*
* \sa SOUND_VERSION
* \sa Sound_GetLinkedVersion
*/
typedef struct
{
int major; /**< major revision */
int minor; /**< minor revision */
int patch; /**< patchlevel */
} Sound_Version;
/* functions and macros... */
/**
* \def SOUND_VERSION(x)
* \brief Macro to determine SDL_sound version program was compiled against.
*
* This macro fills in a Sound_Version structure with the version of the
* library you compiled against. This is determined by what header the
* compiler uses. Note that if you dynamically linked the library, you might
* have a slightly newer or older version at runtime. That version can be
* determined with Sound_GetLinkedVersion(), which, unlike SOUND_VERSION,
* is not a macro.
*
* \param x A pointer to a Sound_Version struct to initialize.
*
* \sa Sound_Version
* \sa Sound_GetLinkedVersion
*/
#define SOUND_VERSION(x) \
{ \
(x)->major = SOUND_VER_MAJOR; \
(x)->minor = SOUND_VER_MINOR; \
(x)->patch = SOUND_VER_PATCH; \
}
/**
* \fn void Sound_GetLinkedVersion(Sound_Version *ver)
* \brief Get the version of SDL_sound that is linked against your program.
*
* If you are using a shared library (DLL) version of SDL_sound, then it is
* possible that it will be different than the version you compiled against.
*
* This is a real function; the macro SOUND_VERSION tells you what version
* of SDL_sound you compiled against:
*
* \code
* Sound_Version compiled;
* Sound_Version linked;
*
* SOUND_VERSION(&compiled);
* Sound_GetLinkedVersion(&linked);
* printf("We compiled against SDL_sound version %d.%d.%d ...\n",
* compiled.major, compiled.minor, compiled.patch);
* printf("But we linked against SDL_sound version %d.%d.%d.\n",
* linked.major, linked.minor, linked.patch);
* \endcode
*
* This function may be called safely at any time, even before Sound_Init().
*
* \param ver Sound_Version structure to fill with shared library's version.
*
* \sa Sound_Version
* \sa SOUND_VERSION
*/
SNDDECLSPEC void SDLCALL Sound_GetLinkedVersion(Sound_Version *ver);
/**
* \fn Sound_Init(void)
* \brief Initialize SDL_sound.
*
* This must be called before any other SDL_sound function (except perhaps
* Sound_GetLinkedVersion()). You should call SDL_Init() before calling this.
* Sound_Init() will attempt to call SDL_Init(SDL_INIT_AUDIO), just in case.
* This is a safe behaviour, but it may not configure SDL to your liking by
* itself.
*
* \return nonzero on success, zero on error. Specifics of the
* error can be gleaned from Sound_GetError().
*
* \sa Sound_Quit
*/
SNDDECLSPEC int SDLCALL Sound_Init(void);
/**
* \fn Sound_Quit(void)
* \brief Shutdown SDL_sound.
*
* This closes any SDL_RWops that were being used as sound sources, and frees
* any resources in use by SDL_sound.
*
* All Sound_Sample pointers you had prior to this call are INVALIDATED.
*
* Once successfully deinitialized, Sound_Init() can be called again to
* restart the subsystem. All default API states are restored at this
* point.
*
* You should call this BEFORE SDL_Quit(). This will NOT call SDL_Quit()
* for you!
*
* \return nonzero on success, zero on error. Specifics of the error
* can be gleaned from Sound_GetError(). If failure, state of
* SDL_sound is undefined, and probably badly screwed up.
*
* \sa Sound_Init
*/
SNDDECLSPEC int SDLCALL Sound_Quit(void);
/**
* \fn const Sound_DecoderInfo **Sound_AvailableDecoders(void)
* \brief Get a list of sound formats supported by this version of SDL_sound.
*
* This is for informational purposes only. Note that the extension listed is
* merely convention: if we list "MP3", you can open an MPEG-1 Layer 3 audio
* file with an extension of "XYZ", if you like. The file extensions are
* informational, and only required as a hint to choosing the correct
* decoder, since the sound data may not be coming from a file at all, thanks
* to the abstraction that an SDL_RWops provides.
*
* The returned value is an array of pointers to Sound_DecoderInfo structures,
* with a NULL entry to signify the end of the list:
*
* \code
* Sound_DecoderInfo **i;
*
* for (i = Sound_AvailableDecoders(); *i != NULL; i++)
* {
* printf("Supported sound format: [%s], which is [%s].\n",
* i->extension, i->description);
* // ...and other fields...
* }
* \endcode
*
* The return values are pointers to static internal memory, and should
* be considered READ ONLY, and never freed.
*
* \return READ ONLY Null-terminated array of READ ONLY structures.
*
* \sa Sound_DecoderInfo
*/
SNDDECLSPEC const Sound_DecoderInfo ** SDLCALL Sound_AvailableDecoders(void);
/**
* \fn const char *Sound_GetError(void)
* \brief Get the last SDL_sound error message as a null-terminated string.
*
* This will be NULL if there's been no error since the last call to this
* function. The pointer returned by this call points to an internal buffer,
* and should not be deallocated. Each thread has a unique error state
* associated with it, but each time a new error message is set, it will
* overwrite the previous one associated with that thread. It is safe to call
* this function at anytime, even before Sound_Init().
*
* \return READ ONLY string of last error message.
*
* \sa Sound_ClearError
*/
SNDDECLSPEC const char * SDLCALL Sound_GetError(void);
/**
* \fn void Sound_ClearError(void)
* \brief Clear the current error message.
*
* The next call to Sound_GetError() after Sound_ClearError() will return NULL.
*
* \sa Sound_GetError
*/
SNDDECLSPEC void SDLCALL Sound_ClearError(void);
/**
* \fn Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, Sound_AudioInfo *desired, Uint32 bufferSize)
* \brief Start decoding a new sound sample.
*
* The data is read via an SDL_RWops structure (see SDL_rwops.h in the SDL
* include directory), so it may be coming from memory, disk, network stream,
* etc. The (ext) parameter is merely a hint to determining the correct
* decoder; if you specify, for example, "mp3" for an extension, and one of
* the decoders lists that as a handled extension, then that decoder is given
* first shot at trying to claim the data for decoding. If none of the
* extensions match (or the extension is NULL), then every decoder examines
* the data to determine if it can handle it, until one accepts it. In such a
* case your SDL_RWops will need to be capable of rewinding to the start of
* the stream.
*
* If no decoders can handle the data, a NULL value is returned, and a human
* readable error message can be fetched from Sound_GetError().
*
* Optionally, a desired audio format can be specified. If the incoming data
* is in a different format, SDL_sound will convert it to the desired format
* on the fly. Note that this can be an expensive operation, so it may be
* wise to convert data before you need to play it back, if possible, or
* make sure your data is initially in the format that you need it in.
* If you don't want to convert the data, you can specify NULL for a desired
* format. The incoming format of the data, preconversion, can be found
* in the Sound_Sample structure.
*
* Note that the raw sound data "decoder" needs you to specify both the
* extension "RAW" and a "desired" format, or it will refuse to handle
* the data. This is to prevent it from catching all formats unsupported
* by the other decoders.
*
* Finally, specify an initial buffer size; this is the number of bytes that
* will be allocated to store each read from the sound buffer. The more you
* can safely allocate, the more decoding can be done in one block, but the
* more resources you have to use up, and the longer each decoding call will
* take. Note that different data formats require more or less space to
* store. This buffer can be resized via Sound_SetBufferSize() ...
*
* The buffer size specified must be a multiple of the size of a single
* sample point. So, if you want 16-bit, stereo samples, then your sample
* point size is (2 channels * 16 bits), or 32 bits per sample, which is four
* bytes. In such a case, you could specify 128 or 132 bytes for a buffer,
* but not 129, 130, or 131 (although in reality, you'll want to specify a
* MUCH larger buffer).
*
* When you are done with this Sound_Sample pointer, you can dispose of it
* via Sound_FreeSample().
*
* You do not have to keep a reference to (rw) around. If this function
* suceeds, it stores (rw) internally (and disposes of it during the call
* to Sound_FreeSample()). If this function fails, it will dispose of the
* SDL_RWops for you.
*
* \param rw SDL_RWops with sound data.
* \param ext File extension normally associated with a data format.
* Can usually be NULL.
* \param desired Format to convert sound data into. Can usually be NULL,
* if you don't need conversion.
* \param bufferSize Size, in bytes, to allocate for the decoding buffer.
* \return Sound_Sample pointer, which is used as a handle to several other
* SDL_sound APIs. NULL on error. If error, use
* Sound_GetError() to see what went wrong.
*
* \sa Sound_NewSampleFromFile
* \sa Sound_SetBufferSize
* \sa Sound_Decode
* \sa Sound_DecodeAll
* \sa Sound_Seek
* \sa Sound_Rewind
* \sa Sound_FreeSample
*/
SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSample(SDL_RWops *rw,
const char *ext,
Sound_AudioInfo *desired,
Uint32 bufferSize);
/**
* \fn Sound_Sample *Sound_NewSampleFromFile(const char *filename, Sound_AudioInfo *desired, Uint32 bufferSize)
* \brief Start decoding a new sound sample from a file on disk.
*
* This is identical to Sound_NewSample(), but it creates an SDL_RWops for you
* from the file located in (filename). Note that (filename) is specified in
* platform-dependent notation. ("C:\\music\\mysong.mp3" on windows, and
* "/home/icculus/music/mysong.mp3" or whatever on Unix, etc.)
* Sound_NewSample()'s "ext" parameter is gleaned from the contents of
* (filename).
*
* \param filename file containing sound data.
* \param desired Format to convert sound data into. Can usually be NULL,
* if you don't need conversion.
* \param bufferSize size, in bytes, of initial read buffer.
* \return Sound_Sample pointer, which is used as a handle to several other
* SDL_sound APIs. NULL on error. If error, use
* Sound_GetError() to see what went wrong.
*
* \sa Sound_NewSample
* \sa Sound_SetBufferSize
* \sa Sound_Decode
* \sa Sound_DecodeAll
* \sa Sound_Seek
* \sa Sound_Rewind
* \sa Sound_FreeSample
*/
SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSampleFromFile(const char *fname,
Sound_AudioInfo *desired,
Uint32 bufferSize);
/**
* \fn void Sound_FreeSample(Sound_Sample *sample)
* \brief Dispose of a Sound_Sample.
*
* This will also close/dispose of the SDL_RWops that was used at creation
* time, so there's no need to keep a reference to that around.
* The Sound_Sample pointer is invalid after this call, and will almost
* certainly result in a crash if you attempt to keep using it.
*
* \param sample The Sound_Sample to delete.
*
* \sa Sound_NewSample
* \sa Sound_NewSampleFromFile
*/
SNDDECLSPEC void SDLCALL Sound_FreeSample(Sound_Sample *sample);
/**
* \fn int Sound_SetBufferSize(Sound_Sample *sample, Uint32 new_size)
* \brief Change the current buffer size for a sample.
*
* If the buffer size could be changed, then the sample->buffer and
* sample->buffer_size fields will reflect that. If they could not be
* changed, then your original sample state is preserved. If the buffer is
* shrinking, the data at the end of buffer is truncated. If the buffer is
* growing, the contents of the new space at the end is undefined until you
* decode more into it or initialize it yourself.
*
* The buffer size specified must be a multiple of the size of a single
* sample point. So, if you want 16-bit, stereo samples, then your sample
* point size is (2 channels * 16 bits), or 32 bits per sample, which is four
* bytes. In such a case, you could specify 128 or 132 bytes for a buffer,
* but not 129, 130, or 131 (although in reality, you'll want to specify a
* MUCH larger buffer).
*
* \param sample The Sound_Sample whose buffer to modify.
* \param new_size The desired size, in bytes, of the new buffer.
* \return non-zero if buffer size changed, zero on failure.
*
* \sa Sound_Decode
* \sa Sound_DecodeAll
*/
SNDDECLSPEC int SDLCALL Sound_SetBufferSize(Sound_Sample *sample,
Uint32 new_size);
/**
* \fn Uint32 Sound_Decode(Sound_Sample *sample)
* \brief Decode more of the sound data in a Sound_Sample.
*
* It will decode at most sample->buffer_size bytes into sample->buffer in the
* desired format, and return the number of decoded bytes.
* If sample->buffer_size bytes could not be decoded, then please refer to
* sample->flags to determine if this was an end-of-stream or error condition.
*
* \param sample Do more decoding to this Sound_Sample.
* \return number of bytes decoded into sample->buffer. If it is less than
* sample->buffer_size, then you should check sample->flags to see
* what the current state of the sample is (EOF, error, read again).
*
* \sa Sound_DecodeAll
* \sa Sound_SetBufferSize
* \sa Sound_Seek
* \sa Sound_Rewind
*/
SNDDECLSPEC Uint32 SDLCALL Sound_Decode(Sound_Sample *sample);
/**
* \fn Uint32 Sound_DecodeAll(Sound_Sample *sample)
* \brief Decode the remainder of the sound data in a Sound_Sample.
*
* This will dynamically allocate memory for the ENTIRE remaining sample.
* sample->buffer_size and sample->buffer will be updated to reflect the
* new buffer. Please refer to sample->flags to determine if the decoding
* finished due to an End-of-stream or error condition.
*
* Be aware that sound data can take a large amount of memory, and that
* this function may block for quite awhile while processing. Also note
* that a streaming source (for example, from a SDL_RWops that is getting
* fed from an Internet radio feed that doesn't end) may fill all available
* memory before giving up...be sure to use this on finite sound sources
* only!
*
* When decoding the sample in its entirety, the work is done one buffer at a
* time. That is, sound is decoded in sample->buffer_size blocks, and
* appended to a continually-growing buffer until the decoding completes.
* That means that this function will need enough RAM to hold approximately
* sample->buffer_size bytes plus the complete decoded sample at most. The
* larger your buffer size, the less overhead this function needs, but beware
* the possibility of paging to disk. Best to make this user-configurable if
* the sample isn't specific and small.
*
* \param sample Do all decoding for this Sound_Sample.
* \return number of bytes decoded into sample->buffer. You should check
* sample->flags to see what the current state of the sample is
* (EOF, error, read again).
*
* \sa Sound_Decode
* \sa Sound_SetBufferSize
*/
SNDDECLSPEC Uint32 SDLCALL Sound_DecodeAll(Sound_Sample *sample);
/**
* \fn int Sound_Rewind(Sound_Sample *sample)
* \brief Rewind a sample to the start.
*
* Restart a sample at the start of its waveform data, as if newly
* created with Sound_NewSample(). If successful, the next call to
* Sound_Decode[All]() will give audio data from the earliest point
* in the stream.
*
* Beware that this function will fail if the SDL_RWops that feeds the
* decoder can not be rewound via it's seek method, but this can
* theoretically be avoided by wrapping it in some sort of buffering
* SDL_RWops.
*
* This function should ONLY fail if the RWops is not seekable, or
* SDL_sound is not initialized. Both can be controlled by the application,
* and thus, it is up to the developer's paranoia to dictate whether this
* function's return value need be checked at all.
*
* If this function fails, the state of the sample is undefined, but it
* is still safe to call Sound_FreeSample() to dispose of it.
*
* On success, ERROR, EOF, and EAGAIN are cleared from sample->flags. The
* ERROR flag is set on error.
*
* \param sample The Sound_Sample to rewind.
* \return nonzero on success, zero on error. Specifics of the
* error can be gleaned from Sound_GetError().
*
* \sa Sound_Seek
*/
SNDDECLSPEC int SDLCALL Sound_Rewind(Sound_Sample *sample);
/**
* \fn int Sound_Seek(Sound_Sample *sample, Uint32 ms)
* \brief Seek to a different point in a sample.
*
* Reposition a sample's stream. If successful, the next call to
* Sound_Decode[All]() will give audio data from the offset you
* specified.
*
* The offset is specified in milliseconds from the start of the
* sample.
*
* Beware that this function can fail for several reasons. If the
* SDL_RWops that feeds the decoder can not seek, this call will almost
* certainly fail, but this can theoretically be avoided by wrapping it
* in some sort of buffering SDL_RWops. Some decoders can never seek,
* others can only seek with certain files. The decoders will set a flag
* in the sample at creation time to help you determine this.
*
* You should check sample->flags & SOUND_SAMPLEFLAG_CANSEEK
* before attempting. Sound_Seek() reports failure immediately if this
* flag isn't set. This function can still fail for other reasons if the
* flag is set.
*
* This function can be emulated in the application with Sound_Rewind()
* and predecoding a specific amount of the sample, but this can be
* extremely inefficient. Sound_Seek() accelerates the seek on a
* with decoder-specific code.
*
* If this function fails, the sample should continue to function as if
* this call was never made. If there was an unrecoverable error,
* sample->flags & SOUND_SAMPLEFLAG_ERROR will be set, which you regular
* decoding loop can pick up.
*
* On success, ERROR, EOF, and EAGAIN are cleared from sample->flags.
*
* \param sample The Sound_Sample to seek.
* \param ms The new position, in milliseconds from start of sample.
* \return nonzero on success, zero on error. Specifics of the
* error can be gleaned from Sound_GetError().
*
* \sa Sound_Rewind
*/
SNDDECLSPEC int SDLCALL Sound_Seek(Sound_Sample *sample, Uint32 ms);
#ifdef __cplusplus
}
#endif
#endif /* !defined _INCLUDE_SDL_SOUND_H_ */
/* end of SDL_sound.h ... */