summaryrefslogtreecommitdiffstats
path: root/apps/plugins/sdl/SDL_mixer
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2017-01-21 15:18:31 -0500
committerFranklin Wei <git@fwei.tk>2017-12-23 21:01:26 -0500
commita855d6202536ff28e5aae4f22a0f31d8f5b325d0 (patch)
tree8c75f224dd64ed360505afa8843d016b0d75000b /apps/plugins/sdl/SDL_mixer
parent01c6dcf6c7b9bb1ad2fa0450f99bacc5f3d3e04b (diff)
downloadrockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.tar.gz
rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.zip
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
Diffstat (limited to 'apps/plugins/sdl/SDL_mixer')
-rw-r--r--apps/plugins/sdl/SDL_mixer/CHANGES348
-rw-r--r--apps/plugins/sdl/SDL_mixer/COPYING20
-rw-r--r--apps/plugins/sdl/SDL_mixer/Makefile.in133
-rw-r--r--apps/plugins/sdl/SDL_mixer/README43
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_flac.c177
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_flac.h66
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.c87
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.h57
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_mod.c275
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_mod.h62
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_mp3.c171
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_mp3.h47
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_ogg.c131
-rw-r--r--apps/plugins/sdl/SDL_mixer/dynamic_ogg.h53
-rw-r--r--apps/plugins/sdl/SDL_mixer/effect_position.c1615
-rw-r--r--apps/plugins/sdl/SDL_mixer/effect_stereoreverse.c117
-rw-r--r--apps/plugins/sdl/SDL_mixer/effects_internal.c121
-rw-r--r--apps/plugins/sdl/SDL_mixer/effects_internal.h60
-rw-r--r--apps/plugins/sdl/SDL_mixer/fluidsynth.c219
-rw-r--r--apps/plugins/sdl/SDL_mixer/fluidsynth.h51
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_aiff.c247
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_aiff.h31
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_flac.c338
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_flac.h31
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_ogg.c159
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_ogg.h31
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_voc.c458
-rw-r--r--apps/plugins/sdl/SDL_mixer/load_voc.h36
-rw-r--r--apps/plugins/sdl/SDL_mixer/mixer.c1484
-rw-r--r--apps/plugins/sdl/SDL_mixer/music.c1599
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_cmd.c241
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_cmd.h62
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_flac.c593
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_flac.h90
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_mad.c325
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_mad.h72
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_mod.c346
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_mod.h62
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_modplug.c239
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_modplug.h42
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_ogg.c230
-rw-r--r--apps/plugins/sdl/SDL_mixer/music_ogg.h75
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi.h38
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.c409
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.h63
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi_haiku.cpp281
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi_mac.c644
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi_macosx.c322
-rw-r--r--apps/plugins/sdl/SDL_mixer/native_midi/native_midi_win32.c312
-rw-r--r--apps/plugins/sdl/SDL_mixer/playmus.c234
-rw-r--r--apps/plugins/sdl/SDL_mixer/playwave.c497
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/COPYING127
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/FAQ112
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/README57
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/common.c238
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/common.h39
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/config.h229
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.c26
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.h74
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/filter.c187
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/filter.h23
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/instrum.c1018
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/instrum.h168
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/mix.c847
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/mix.h11
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/output.c122
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/output.h60
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/playmidi.c1746
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/playmidi.h160
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/readmidi.c1065
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/readmidi.h18
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/resample.c730
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/resample.h10
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/sdl_a.c19
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/sdl_c.c136
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/tables.c1111
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/tables.h35
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/timidity.c359
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/timidity.h20
-rw-r--r--apps/plugins/sdl/SDL_mixer/wavestream.c521
-rw-r--r--apps/plugins/sdl/SDL_mixer/wavestream.h60
81 files changed, 22772 insertions, 0 deletions
diff --git a/apps/plugins/sdl/SDL_mixer/CHANGES b/apps/plugins/sdl/SDL_mixer/CHANGES
new file mode 100644
index 0000000000..9eb53f3733
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/CHANGES
@@ -0,0 +1,348 @@
+1.2.12:
+Sam Lantinga - Sat Jan 14 22:00:29 2012 -0500
+ * Fixed seek offset with SMPEG (was relative, should be absolute)
+Sam Lantinga - Fri Jan 13 03:04:27 EST 2012
+ * Fixed memory crash loading Ogg Vorbis files on Windows
+Sam Lantinga - Thu Jan 05 22:51:54 2012 -0500
+ * Added an Xcode project for iOS
+Nikos Chantziaras - 2012-01-02 17:37:36 PST
+ * Added Mix_LoadMUSType_RW() so you can tell SDL_mixer what type the music is
+Sam Lantinga - Sun Jan 01 16:45:58 2012 -0500
+ * Fixed looping native MIDI on Mac OS X and Windows
+Sam Lantinga - Sun Jan 01 01:00:51 2012 -0500
+ * Added /usr/local/share/timidity to the timidity data path
+Sam Lantinga - Sat Dec 31 21:26:46 2011 -0500
+ * Fixed timidity loading of some MIDI files
+Sam Lantinga - Sat Dec 31 19:11:59 EST 2011
+ * Fixed dropping audio in the FLAC audio decoding
+Sam Lantinga - Sat Dec 31 18:32:05 EST 2011
+ * Fixed memory leak in SDL_LoadMUS()
+Sam Lantinga - Sat Dec 31 10:22:05 EST 2011
+ * Removed GPL native MIDI code for new licensing
+Sam Lantinga - Sat Dec 31 10:22:05 EST 2011
+ * SDL_mixer is now under the zlib license
+Manuel Montezelo - 2011-12-28 11:42:44 PST
+ * Fixed drums playing on MIDI channel 16 with timidity
+Ryan C. Gordon - Wed Jun 15 03:41:31 2011 -0400
+ * The music-finished hook can start a track immediately
+James Le Cuirot - Mon Mar 21 16:54:11 PDT 2011
+ * Added support for FluidSynth
+Egor Suvorov - Tue Jan 18 11:06:47 PST 2011
+ * Added support for native MIDI on Haiku
+Sam Lantinga - Tue Jan 11 01:29:19 2011 -0800
+ * Added Android.mk to build on the Android platform
+Jon Atkins - Sat Nov 14 13:00:18 PST 2009
+ * Added support for libmodplug (disabled by default)
+
+1.2.11:
+Sam Lantinga - Sat Nov 14 12:38:01 PST 2009
+ * Fixed initialization error and crashes if MikMod library isn't available
+Sam Lantinga - Sat Nov 14 11:22:14 PST 2009
+ * Fixed bug loading multiple music files
+
+1.2.10:
+Sam Lantinga - Sun Nov 8 08:34:48 PST 2009
+ * Added Mix_Init()/Mix_Quit() to prevent constantly loading and unloading DLLs
+Mike Frysinger - 2009-11-05 09:11:43 PST
+ * Check for fork/vfork on any platform, don't just assume it on UNIX
+Jon Atkins - Thu Nov 5 00:02:50 2009 UTC
+ * Fixed export of Mix_GetNumChunkDecoders() and Mix_GetNumMusicDecoders()
+C.W. Betts - 2009-11-02 00:16:21 PST
+ * Use newer MIDI API on Mac OS X 10.5+
+
+1.2.9:
+Ryan Gordon - Sun Oct 18 11:42:31 PDT 2009
+ * Updated native MIDI support on Mac OS X for 10.6
+Ryan Gordon - Sun Oct 11 05:29:55 2009 UTC
+ * Reset channel volumes after a fade out interrupts a fade in.
+Ryan Gordon - Sun Oct 11 02:59:12 2009 UTC
+ * Fixed crash race condition with position audio functions
+Ryan Gordon - Sat Oct 10 17:05:45 2009 UTC
+ * Fixed stereo panning in 8-bit mode
+Sam Lantinga - Sat Oct 10 11:07:15 2009 UTC
+ * Added /usr/share/timidity to the default timidity.cfg locations
+Sam Lantinga - Sat Oct 3 13:33:36 PDT 2009
+ * MOD support uses libmikmod and is dynamically loaded by default
+ * A patched version of libmikmod is included in libmikmod-3.1.12.zip
+ * The libmikmod patches fix security issues CVE-2007-6720 and CVE-2009-0179.
+Sam Lantinga - Sat Oct 3 02:49:41 PDT 2009
+ * Added TIMIDITY_CFG environment variable to fully locate timidity.cfg
+Sam Lantinga - Fri Oct 2 07:15:35 PDT 2009
+ * Implemented seamless looping for music playback
+Forrest Voight - 2009-06-13 20:31:38 PDT
+ * ID3 files are now recognized as MP3 format
+Steven Noonan - 2008-05-13 13:31:36 PDT
+ * Fixed native MIDI crash on 64-bit Windows
+Ryan Gordon - Fri Jun 5 16:07:08 2009 UTC
+ * Added decoder enumeration API:
+ Mix_GetNumChunkDecoders(), Mix_GetChunkDecoder(),
+ Mix_GetNumMusicDecoders(), Mix_GetMusicDecoder()
+Austen Dicken - Tue Feb 26 23:28:27 PST 2008
+ * Added support for FLAC audio both as chunks and streaming
+Tilman Sauerbeck - Tue Feb 26 03:44:47 PST 2008
+ * Added support for streaming WAV files with Mix_LoadMUS_RW()
+Ryan Gordon - Mon Feb 4 17:10:08 UTC 2008
+ * Fixed crash caused by not resetting position_channels
+
+1.2.8:
+Sam Lantinga - Wed Jul 18 09:45:54 PDT 2007
+ * Improved detection of Ogg Vorbis and Tremor libraries
+Ryan Gordon - Sun Jul 15 12:03:54 EDT 2007
+ * Fixed memory leaks in Effects API.
+David Rose - Sat Jul 14 22:16:09 PDT 2007
+ * Added support for MP3 playback with libmad (for GPL projects only!)
+Sam Lantinga - Sat Jul 14 21:39:30 PDT 2007
+ * Fixed the final loop of audio samples of a certain size
+Sam Lantinga - Sat Jul 14 21:05:09 PDT 2007
+ * Fixed opening Ogg Vorbis files using different C runtimes on Windows
+Philippe Simons - Sat Jul 14 20:33:17 PDT 2007
+ * Added support for Ogg Vorbis playback with Tremor (an integer decoder)
+Sam Lantinga - Sat Jul 14 07:02:09 PDT 2007
+ * Fixed memory corruption in timidity resampling code
+Ryan Gordon - Tue Jul 3 10:44:29 2007 UTC
+ * Fixed building SDL_mixer with SDL 1.3 pre-release
+Ryan Gordon - Tue Feb 13 08:11:54 2007 UTC
+ * Fixed compiling both timidity and native midi in the same build
+Hans de Goede - Sun Aug 20 23:25:46 2006 UTC
+ * Added volume control to playmus
+Jonathan Atkins - Thu Aug 10 15:06:40 2006 UTC
+ * Fixed linking with system libmikmod
+David Ergo - Fri Jun 23 09:07:19 2006 UTC
+ * Corrected no-op conditions in SetDistance(), SetPanning() and SetPosition()
+ * Fixed copy/paste errors in channel amplitudes
+
+1.2.7:
+Sam Lantinga - Fri May 12 00:04:32 PDT 2006
+ * Added support for dynamically loading SMPEG library
+Sam Lantinga - Thu May 11 22:22:43 PDT 2006
+ * Added support for dynamically loading Ogg Vorbis library
+Sam Lantinga - Sun Apr 30 09:01:44 PDT 2006
+ * Removed automake dependency, to allow Universal binaries on Mac OS X
+ * Added gcc-fat.sh for generating Universal binaries on Mac OS X
+Sam Lantinga - Sun Apr 30 01:48:40 PDT 2006
+ * Updated libtool support to version 1.5.22
+Patrice Mandin - Sat Jul 16 16:43:24 UTC 2005
+ * Use SDL_RWops also for native midi mac and win32
+Patrice Mandin - Sat Jul 9 14:40:09 UTC 2005
+ * Use SDL_RWops also for native midi gpl (todo: mac and win32)
+Ryan C. Gordon - Sat Jul 9 01:54:03 EDT 2005
+ * Tweaked Mix_Chunk's definition to make predeclaration easier.
+Patrice Mandin - Mon Jul 4 19:45:40 UTC 2005
+ * Search timidity.cfg also in /etc
+ * Fix memory leaks in timidity player
+ * Use also SDL_RWops to read midifiles for timidity
+Ryan C. Gordon - Mon Jun 13 18:18:12 EDT 2005
+ * Patch from Eric Wing to fix native midi compiling on MacOS/x86.
+Sam Lantinga - Wed Dec 22 17:14:32 PST 2004
+ * Disabled support for the system version of libmikmod by default
+Sam Lantinga - Tue Dec 21 09:51:29 PST 2004
+ * Fixed building mikmod support on UNIX
+ * Always build SDL_RWops music support
+ * Added SDL_RWops support for reading MP3 files
+
+1.2.6:
+Jonathan Atkins - Wed, 15 Sep 2004 23:26:42 -0500
+ * Added support for using the system version of libmikmod
+Martin_Storsjö - Sun, 22 Aug 2004 02:21:14 +0300 (EEST)
+ * Added SDL_RWops support for reading Ogg Vorbis files
+Greg Lee - Wed, 14 Jul 2004 05:13:14 -1000
+ * Added 4 and 6 channel surround sound output support
+ * Added support for RMID format MIDI files
+ * Improved timidity support (reverb, chorus, Roland & Yamaha sysex dumps, etc.)
+Sam Lantinga - Wed Nov 19 00:23:44 PST 2003
+ * Updated libtool support for new mingw32 DLL build process
+Ryan C. Gordon - Sun Nov 9 23:34:47 EST 2003
+ * Patch from Steven Fuller to fix positioning effect on bigendian systems.
+Laurent Ganter - Mon, 6 Oct 2003 11:51:33 +0200
+ * Fixed bug with MIDI volume in native Windows playback
+Andre Leiradella - Fri, 30 May 2003 16:12:03 -0300
+ * Added SDL_RWops support for reading MOD files
+Kyle Davenport - Sat, 19 Apr 2003 17:13:31 -0500
+ * Added .la files to the development RPM, fixing RPM build on RedHat 8
+
+1.2.5:
+Darrell Walisser - Tue Mar 4 09:24:01 PST 2003
+ * Worked around MacOS X deadlock between CoreAudio and QuickTime
+Darrell Walisser - Fri, 14 Feb 2003 20:56:08 -0500
+ * Fixed crash in native midi code with files with more than 32 tracks
+Marc Le Douarain - Sat, 15 Feb 2003 14:46:41 +0100
+ * Added 8SVX format support to the AIFF loader
+Sam Lantinga Wed Feb 12 21:03:57 PST 2003
+ * Fixed volume control on WAVE music chunks
+Ben Nason - Mon, 10 Feb 2003 11:50:27 -0800
+ * Fixed volume control on MOD music chunks
+Patrice Mandin - Fri, 31 Jan 2003 15:17:30 +0100
+ * Added support for the Atari platform
+Ryan C. Gordon - Fri Dec 27 10:14:07 EST 2002
+ * Patch from Steven Fuller to fix panning effect with 8-bit sounds.
+Ryan C. Gordon - Thu Jan 2 12:31:48 EST 2003
+ * Patch from guy on 3DRealms forums to fix native win32 midi volume.
+Ryan C. Gordon - Wed Oct 30 07:12:06 EST 2002
+ * Small, looping music samples should now be able to fade out correctly.
+Sam Lantinga - Sun Oct 20 20:52:24 PDT 2002
+ * Added shared library support for MacOS X
+Pete Shinners - Wed Oct 16 17:10:08 EDT 2002
+ * Correctly report an error when using an unknown filetype
+Vaclav Slavik - Sun Sep 8 18:57:38 PDT 2002
+ * Added support for loading Ogg Vorbis samples as an audio chunk
+Martin Storsjö - Tue Jul 16 10:38:12 PDT 2002
+ * Fixed to start playing another sample immediately when one finishes
+Martin Storsjö - Tue May 28 13:08:29 PDT 2002
+ * Fixed a volume bug when calling Mix_HaltChannel() on unused channel
+Xavier Wielemans - Wed Jun 12 14:28:14 EDT 2002
+ * Fixed volume reset bug at end of channel fade.
+Ryan C. Gordon - Wed Jun 26 16:30:59 EDT 2002
+ * Mix_LoadMUS() will now accept an MP3 by file extension, instead of relying
+ entirely on the magic number.
+
+1.2.4:
+Sam Lantinga - Mon May 20 09:11:22 PDT 2002
+ * Updated the CodeWarrior project files
+Sam Lantinga - Sun May 19 13:46:29 PDT 2002
+ * Added a function to query the music format: Mix_GetMusicType()
+Sam Lantinga - Sat May 18 12:45:16 PDT 2002
+ * Added a function to load audio data from memory: Mix_QuickLoad_RAW()
+Sam Lantinga - Thu May 16 11:26:46 PDT 2002
+ * Cleaned up threading issues in the music playback code
+Ryan Gordon - Thu May 2 21:08:48 PDT 2002
+ * Fixed deadlock introduced in the last release
+
+1.2.3:
+Sam Lantinga - Sat Apr 13 07:49:47 PDT 2002
+ * Updated autogen.sh for new versions of automake
+ * Specify the SDL API calling convention (C by default)
+Ryan Gordon - Sat Apr 13 07:33:37 PDT 2002
+ * Fixed recursive audio lock in the mixing function
+jean-julien Filatriau - Sat Mar 23 18:05:37 PST 2002
+ * Fixed setting invalid volume when querying mixer and music volumes
+Guillaume Cottenceau - Wed Feb 13 15:43:20 PST 2002
+ * Implemented Ogg Vorbis stream rewinding
+Peter Kutak - Wed Feb 13 10:26:57 PST 2002
+ * Added native midi support on Linux, using GPL code
+ --enable-music-native-midi-gpl
+Pete Shinners - Mon Jan 14 11:31:26 PST 2002
+ * Added seek support for MP3 files
+Ryan Gordon - Mon Jan 14 11:30:44 PST 2002
+ * Sample "finished" callbacks are now always called when a sample is stopped.
+
+1.2.2:
+Guillaume Cottenceau - Wed Dec 19 08:59:05 PST 2001
+ * Added an API for seeking in music files (implemented for MOD and Ogg music)
+ Mix_FadeInMusicPos(), Mix_SetMusicPosition()
+ * Exposed the mikmod synchro value for music synchronization
+ Mix_SetSynchroValue(), Mix_GetSynchroValue()
+
+1.2.1:
+Yi-Huang Han - Wed Oct 24 21:55:47 PDT 2001
+ * Fixed MOD music volume when looping
+David Hedbor - Thu Oct 18 10:01:41 PDT 2001
+ * Stop implicit looping, set fade out and other flags on MOD files
+Sam Lantinga - Tue Oct 16 11:17:12 PDT 2001
+ * The music file type is now determined by extension as well as magic
+Ryan C. Gordon - Tue Sep 11 12:05:54 PDT 2001
+ * Reworked playwave.c to make it more useful as a mixer testbed
+ * Added a realtime sound effect API to SDL_mixer.h
+ * Added the following standard sound effects:
+ panning, distance attenuation, basic positional audio, stereo reversal
+ * Added API for mixer versioning: Mix_Linked_Version() and MIX_VERSION()
+Sam Lantinga - Tue Sep 11 11:48:53 PDT 2001
+ * Updated MikMod code to version 3.1.9a
+Torbjörn Andersson - Tue Sep 11 11:22:29 PDT 2001
+ * Added support for loading AIFF audio chunks
+Max Horn - Tue Sep 4 20:38:11 PDT 2001
+ * Added native MIDI music support on MacOS and MacOS X
+Florian Schulze - Sun Aug 19 14:55:37 PDT 2001
+ * Added native MIDI music support on Windows
+Sam Lantinga - Sun Aug 19 02:20:55 PDT 2001
+ * Added Project Builder projects for building MacOS X framework
+Darrell Walisser - Sun Aug 19 00:47:22 PDT 2001
+ * Fixed compilation problems with mikmod under MacOS X
+Torbjörn Andersson - Sun, 19 Aug 2001 16:03:30
+ * Fixed AIFF music playing support
+Sam Lantinga - Sat Aug 18 04:14:13 PDT 2001
+ * Fixed building Ogg Vorbis support on Windows
+Ryan C. Gordon - Thu, 7 Jun 2001 13:15:51
+ * Added Mix_ChannelFinished() and Mix_GetChunk()
+Ryan C. Gordon - Tue, 5 Jun 2001 11:01:51
+ * Added VOC sound file support
+Guillaume Cottenceau - Thu May 10 11:17:55 PDT 2001
+ * Fixed crashes when API used with audio not initialized
+Paul Jenner - Sat, 14 Apr 2001 09:20:38 -0700 (PDT)
+ * Added support for building RPM directly from tar archive
+
+1.2.0:
+Sam Lantinga - Wed Apr 4 12:42:20 PDT 2001
+ * Synchronized release version with SDL 1.2.0
+
+1.1.1:
+John Hall - Tue Jan 2 13:46:54 PST 2001
+ * Added support to playmus for track switching with Ctrl-C
+ * Added support to playmus for multiple command line files
+
+1.1.0:
+Sam Lantinga - Wed Nov 29 20:47:13 PST 2000
+ * Package specifically for SDL 1.1 (no real reason API-wise, but for clarity)
+
+1.0.7:
+Sam Lantinga - Tue Nov 7 10:22:09 PST 2000
+ * Fixed hang in mikmod re-initialization
+Stephane Peter - Oct 17 13:07:32 PST 2000
+ * Fixed music fading
+Ray Kelm - Fri, 04 Aug 2000 20:58:00 -0400
+ * Added support for cross-compiling Windows DLL from Linux
+
+1.0.6:
+Sam Lantinga - Sun Jul 2 14:16:44 PDT 2000
+ * Added support for the Ogg Vorbis music format: http://www.vorbis.org/
+Darrell Walisser - Wed Jun 28 11:59:40 PDT 2000
+ * Added Codewarrior projects for MacOS
+Sam Lantinga - Mon Jun 26 12:01:11 PDT 2000
+ * Fixed symbol aliasing problem with "channel"
+Matt - Wed, 12 Apr 2000 15:36:13 -0700
+ * Added SDL_RWops support for mikmod loading (not hooked into music.c yet)
+
+1.0.5:
+Paul Furber - Fri Mar 3 14:58:50 PST 2000
+ * Fixed MP3 detection with compilers that use signed char datatypes
+
+1.0.4:
+Sam Lantinga - Thu Feb 10 19:42:03 PST 2000
+ * Ported the base mixer and mikmod libraries to MacOS
+Markus Oberhumer - Wed Feb 2 13:16:17 PST 2000
+ * Fixed problem with short looping sounds
+Sam Lantinga - Tue Feb 1 13:25:44 PST 2000
+ * Added Visual C++ project file
+Markus Oberhumer - Tue Feb 1 13:23:11 PST 2000
+ * Cleaned up code for compiling with Visual C++
+ * Don't hang in Mix_HaltMusic() if the music is paused
+Sam Lantinga - Fri Jan 28 08:54:56 PST 2000
+ * Fixed looping WAVE chunks that are not aligned on sample boundaries
+
+1.0.3:
+Sam Lantinga - Mon Jan 17 19:48:09 PST 2000
+ * Changed the name of the library from "mixer" to "SDL_mixer"
+ * Instead of including "mixer.h", include "SDL_mixer.h",
+ * Instead of linking with libmixer.a, link with libSDL_mixer.a
+
+1.0.2:
+Sam Lantinga - Fri Jan 14 11:06:56 PST 2000
+ * Made the CHANGELOG entries Y2K compliant. :)
+MFX - Updated the mikmod support to MikMod 3.1.8
+MFX - Added Mix_HookMusicFinished() API function
+
+1.0.1:
+SOL - Added a post-mixing callback
+SP - A few music-related bugfixes
+
+1.0.0:
+SOL - Added autoconf support
+SP - Added MP3 support using SMPEG
+SP - Added fading in/out of music and samples
+SP - Added dynamic allocation of channels
+SP - Added channel grouping functions
+SP - Added expiration delay for samples
+
+Initial Key:
+SOL - Sam Lantinga (hercules@lokigames.com)
+SP - Stephane Peter (megastep@lokigames.com)
+MFX - Markus Oberhumer (markus.oberhumer@jk.uni-linz.ac.at)
diff --git a/apps/plugins/sdl/SDL_mixer/COPYING b/apps/plugins/sdl/SDL_mixer/COPYING
new file mode 100644
index 0000000000..dce4d178b1
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/COPYING
@@ -0,0 +1,20 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
diff --git a/apps/plugins/sdl/SDL_mixer/Makefile.in b/apps/plugins/sdl/SDL_mixer/Makefile.in
new file mode 100644
index 0000000000..3d10565c6d
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/Makefile.in
@@ -0,0 +1,133 @@
+# Makefile to build and install the SDL_mixer library
+
+top_builddir = .
+srcdir = @srcdir@
+objects = build
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = $(DESTDIR)@bindir@
+libdir = $(DESTDIR)@libdir@
+includedir = $(DESTDIR)@includedir@
+datarootdir = $(DESTDIR)@datarootdir@
+datadir = @datadir@
+mandir = @mandir@
+auxdir = @ac_aux_dir@
+distpath = $(srcdir)/..
+distdir = SDL_mixer-@VERSION@
+distfile = $(distdir).tar.gz
+
+@SET_MAKE@
+EXE = @EXE@
+SHELL = @SHELL@
+CC = @CC@
+CXX = g++
+CFLAGS = @BUILD_CFLAGS@
+EXTRA_CFLAGS = @EXTRA_CFLAGS@
+LDFLAGS = @BUILD_LDFLAGS@
+EXTRA_LDFLAGS = @EXTRA_LDFLAGS@
+LIBTOOL = @LIBTOOL@
+INSTALL = @INSTALL@
+AR = @AR@
+RANLIB = @RANLIB@
+WINDRES = @WINDRES@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_LIBS = @SDL_LIBS@
+
+TARGET = libSDL_mixer.la
+OBJECTS = @OBJECTS@
+VERSION_OBJECTS = @VERSION_OBJECTS@
+PLAYWAVE_OBJECTS = @PLAYWAVE_OBJECTS@
+PLAYMUS_OBJECTS = @PLAYMUS_OBJECTS@
+
+DIST = Android.mk CHANGES COPYING CWProjects.sea.bin MPWmake.sea.bin Makefile.in SDL_mixer.pc.in README SDL_mixer.h SDL_mixer.qpg.in SDL_mixer.spec SDL_mixer.spec.in VisualC Watcom-OS2.zip Xcode Xcode-iOS acinclude autogen.sh build-scripts configure configure.in dynamic_flac.c dynamic_flac.h dynamic_fluidsynth.c dynamic_fluidsynth.h dynamic_mod.c dynamic_mod.h dynamic_mp3.c dynamic_mp3.h dynamic_ogg.c dynamic_ogg.h effect_position.c effect_stereoreverse.c effects_internal.c effects_internal.h fluidsynth.c fluidsynth.h gcc-fat.sh libmikmod-3.1.12.zip load_aiff.c load_aiff.h load_flac.c load_flac.h load_ogg.c load_ogg.h load_voc.c load_voc.h mixer.c music.c music_cmd.c music_cmd.h music_flac.c music_flac.h music_mad.c music_mad.h music_mod.c music_mod.h music_modplug.c music_modplug.h music_ogg.c music_ogg.h native_midi playmus.c playwave.c timidity wavestream.c wavestream.h version.rc
+
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+LT_LDFLAGS = -no-undefined -rpath $(libdir) -release $(LT_RELEASE) -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+all: $(srcdir)/configure Makefile $(objects) $(objects)/$(TARGET) $(objects)/playwave$(EXE) $(objects)/playmus$(EXE)
+
+$(srcdir)/configure: $(srcdir)/configure.in
+ @echo "Warning, configure.in is out of date"
+ #(cd $(srcdir) && sh autogen.sh && sh configure)
+ @sleep 3
+
+Makefile: $(srcdir)/Makefile.in
+ $(SHELL) config.status $@
+
+$(objects):
+ $(SHELL) $(auxdir)/mkinstalldirs $@
+
+.PHONY: all install install-hdrs install-lib install-bin uninstall uninstall-hdrs uninstall-lib uninstall-bin clean distclean dist
+
+$(objects)/$(TARGET): $(OBJECTS) $(VERSION_OBJECTS)
+ $(LIBTOOL) --mode=link $(CC) -o $@ $(OBJECTS) $(VERSION_OBJECTS) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LT_LDFLAGS)
+
+$(objects)/playwave$(EXE): $(objects)/playwave.lo $(objects)/$(TARGET)
+ $(LIBTOOL) --mode=link $(CC) -o $@ $(objects)/playwave.lo $(SDL_CFLAGS) $(SDL_LIBS) $(objects)/$(TARGET)
+
+$(objects)/playmus$(EXE): $(objects)/playmus.lo $(objects)/$(TARGET)
+ $(LIBTOOL) --mode=link $(CC) -o $@ $(objects)/playmus.lo $(SDL_CFLAGS) $(SDL_LIBS) $(objects)/$(TARGET)
+
+install: all install-hdrs install-lib #install-bin
+install-hdrs:
+ $(SHELL) $(auxdir)/mkinstalldirs $(includedir)/SDL
+ for src in $(srcdir)/SDL_mixer.h; do \
+ file=`echo $$src | sed -e 's|^.*/||'`; \
+ $(INSTALL) -m 644 $$src $(includedir)/SDL/$$file; \
+ done
+ $(SHELL) $(auxdir)/mkinstalldirs $(libdir)/pkgconfig
+ $(INSTALL) -m 644 SDL_mixer.pc $(libdir)/pkgconfig/
+install-lib: $(objects) $(objects)/$(TARGET)
+ $(SHELL) $(auxdir)/mkinstalldirs $(libdir)
+ $(LIBTOOL) --mode=install $(INSTALL) $(objects)/$(TARGET) $(libdir)/$(TARGET)
+install-bin:
+ $(SHELL) $(auxdir)/mkinstalldirs $(bindir)
+ $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(objects)/playwave$(EXE) $(bindir)/playwave$(EXE)
+ $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(objects)/playmus$(EXE) $(bindir)/playmus$(EXE)
+
+uninstall: uninstall-hdrs uninstall-lib uninstall-bin
+uninstall-hdrs:
+ for src in $(srcdir)/SDL_mixer.h; do \
+ file=`echo $$src | sed -e 's|^.*/||'`; \
+ rm -f $(includedir)/SDL/$$file; \
+ done
+ -rmdir $(includedir)/SDL
+ rm -f $(libdir)/pkgconfig/SDL_mixer.pc
+ -rmdir $(libdir)/pkgconfig
+uninstall-lib:
+ $(LIBTOOL) --mode=uninstall rm -f $(libdir)/$(TARGET)
+uninstall-bin:
+ rm -f $(bindir)/playwave$(EXE)
+ rm -f $(bindir)/playmus$(EXE)
+
+clean:
+ rm -rf $(objects)
+
+distclean: clean
+ rm -f Makefile
+ rm -f SDL_mixer.qpg
+ rm -f config.status config.cache config.log libtool
+ rm -f SDL_mixer.pc
+ rm -rf $(srcdir)/autom4te*
+ find $(srcdir) \( \
+ -name '*~' -o \
+ -name '*.bak' -o \
+ -name '*.old' -o \
+ -name '*.rej' -o \
+ -name '*.orig' -o \
+ -name '.#*' \) \
+ -exec rm -f {} \;
+
+dist $(distfile):
+ $(SHELL) $(auxdir)/mkinstalldirs $(distdir)
+ tar cf - $(DIST) | (cd $(distdir); tar xf -)
+ rm -rf `find $(distdir) -name .svn`
+ rm -f `find $(distdir) -name '.#*'`
+ tar cvf - $(distdir) | gzip --best >$(distfile)
+ rm -rf $(distdir)
+
+rpm: $(distfile)
+ rpmbuild -ta $?
diff --git a/apps/plugins/sdl/SDL_mixer/README b/apps/plugins/sdl/SDL_mixer/README
new file mode 100644
index 0000000000..b17cfe6840
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/README
@@ -0,0 +1,43 @@
+
+SDL_mixer 1.2
+
+The latest version of this library is available from:
+http://www.libsdl.org/projects/SDL_mixer/
+
+Due to popular demand, here is a simple multi-channel audio mixer.
+It supports 8 channels of 16 bit stereo audio, plus a single channel
+of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3
+libraries.
+
+See the header file SDL_mixer.h and the examples playwave.c and playmus.c
+for documentation on this mixer library.
+
+The mixer can currently load Microsoft WAVE files and Creative Labs VOC
+files as audio samples, and can load MIDI files via Timidity and the
+following music formats via MikMod: .MOD .S3M .IT .XM. It can load
+Ogg Vorbis streams as music if built with Ogg Vorbis or Tremor libraries,
+and finally it can load MP3 music using the SMPEG or libmad libraries.
+
+Tremor decoding is disabled by default; you can enable it by passing
+ --enable-music-ogg-tremor
+to configure, or by defining OGG_MUSIC and OGG_USE_TREMOR.
+
+libmad decoding is disabled by default; you can enable it by passing
+ --enable-music-mp3-mad
+to configure, or by defining MP3_MAD_MUSIC
+vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+WARNING: The license for libmad is GPL, which means that in order to
+ use it your application must also be GPL!
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The process of mixing MIDI files to wave output is very CPU intensive,
+so if playing regular WAVE files sound great, but playing MIDI files
+sound choppy, try using 8-bit audio, mono audio, or lower frequencies.
+
+To play MIDI files, you'll need to get a complete set of GUS patches
+from:
+http://www.libsdl.org/projects/mixer/timidity/timidity.tar.gz
+and unpack them in /usr/local/lib under UNIX, and C:\ under Win32.
+
+This library is under the zlib license, see the file "COPYING" for details.
+
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_flac.c b/apps/plugins/sdl/SDL_mixer/dynamic_flac.c
new file mode 100644
index 0000000000..59421fddea
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_flac.c
@@ -0,0 +1,177 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Implementation of the dynamic loading functionality for libFLAC.
+ ~ Austen Dicken (admin@cvpcs.org)
+*/
+
+#ifdef FLAC_MUSIC
+
+#include "SDL_loadso.h"
+
+#include "dynamic_flac.h"
+
+flac_loader flac = {
+ 0, NULL
+};
+
+#ifdef FLAC_DYNAMIC
+int Mix_InitFLAC()
+{
+ if ( flac.loaded == 0 ) {
+ flac.handle = SDL_LoadObject(FLAC_DYNAMIC);
+ if ( flac.handle == NULL ) {
+ return -1;
+ }
+ flac.FLAC__stream_decoder_new =
+ (FLAC__StreamDecoder *(*)())
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_new");
+ if ( flac.FLAC__stream_decoder_new == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_delete =
+ (void (*)(FLAC__StreamDecoder *))
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_delete");
+ if ( flac.FLAC__stream_decoder_delete == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_init_stream =
+ (FLAC__StreamDecoderInitStatus (*)(
+ FLAC__StreamDecoder *,
+ FLAC__StreamDecoderReadCallback,
+ FLAC__StreamDecoderSeekCallback,
+ FLAC__StreamDecoderTellCallback,
+ FLAC__StreamDecoderLengthCallback,
+ FLAC__StreamDecoderEofCallback,
+ FLAC__StreamDecoderWriteCallback,
+ FLAC__StreamDecoderMetadataCallback,
+ FLAC__StreamDecoderErrorCallback,
+ void *))
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_init_stream");
+ if ( flac.FLAC__stream_decoder_init_stream == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_finish =
+ (FLAC__bool (*)(FLAC__StreamDecoder *))
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_finish");
+ if ( flac.FLAC__stream_decoder_finish == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_flush =
+ (FLAC__bool (*)(FLAC__StreamDecoder *))
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_flush");
+ if ( flac.FLAC__stream_decoder_flush == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_process_single =
+ (FLAC__bool (*)(FLAC__StreamDecoder *))
+ SDL_LoadFunction(flac.handle,
+ "FLAC__stream_decoder_process_single");
+ if ( flac.FLAC__stream_decoder_process_single == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_process_until_end_of_metadata =
+ (FLAC__bool (*)(FLAC__StreamDecoder *))
+ SDL_LoadFunction(flac.handle,
+ "FLAC__stream_decoder_process_until_end_of_metadata");
+ if ( flac.FLAC__stream_decoder_process_until_end_of_metadata == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_process_until_end_of_stream =
+ (FLAC__bool (*)(FLAC__StreamDecoder *))
+ SDL_LoadFunction(flac.handle,
+ "FLAC__stream_decoder_process_until_end_of_stream");
+ if ( flac.FLAC__stream_decoder_process_until_end_of_stream == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_seek_absolute =
+ (FLAC__bool (*)(FLAC__StreamDecoder *, FLAC__uint64))
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_seek_absolute");
+ if ( flac.FLAC__stream_decoder_seek_absolute == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ flac.FLAC__stream_decoder_get_state =
+ (FLAC__StreamDecoderState (*)(const FLAC__StreamDecoder *decoder))
+ SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_get_state");
+ if ( flac.FLAC__stream_decoder_get_state == NULL ) {
+ SDL_UnloadObject(flac.handle);
+ return -1;
+ }
+ }
+ ++flac.loaded;
+
+ return 0;
+}
+void Mix_QuitFLAC()
+{
+ if ( flac.loaded == 0 ) {
+ return;
+ }
+ if ( flac.loaded == 1 ) {
+ SDL_UnloadObject(flac.handle);
+ }
+ --flac.loaded;
+}
+#else
+int Mix_InitFLAC()
+{
+ if ( flac.loaded == 0 ) {
+ flac.FLAC__stream_decoder_new = FLAC__stream_decoder_new;
+ flac.FLAC__stream_decoder_delete = FLAC__stream_decoder_delete;
+ flac.FLAC__stream_decoder_init_stream =
+ FLAC__stream_decoder_init_stream;
+ flac.FLAC__stream_decoder_finish = FLAC__stream_decoder_finish;
+ flac.FLAC__stream_decoder_flush = FLAC__stream_decoder_flush;
+ flac.FLAC__stream_decoder_process_single =
+ FLAC__stream_decoder_process_single;
+ flac.FLAC__stream_decoder_process_until_end_of_metadata =
+ FLAC__stream_decoder_process_until_end_of_metadata;
+ flac.FLAC__stream_decoder_process_until_end_of_stream =
+ FLAC__stream_decoder_process_until_end_of_stream;
+ flac.FLAC__stream_decoder_seek_absolute =
+ FLAC__stream_decoder_seek_absolute;
+ flac.FLAC__stream_decoder_get_state =
+ FLAC__stream_decoder_get_state;
+ }
+ ++flac.loaded;
+
+ return 0;
+}
+void Mix_QuitFLAC()
+{
+ if ( flac.loaded == 0 ) {
+ return;
+ }
+ if ( flac.loaded == 1 ) {
+ }
+ --flac.loaded;
+}
+#endif /* FLAC_DYNAMIC */
+
+#endif /* FLAC_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_flac.h b/apps/plugins/sdl/SDL_mixer/dynamic_flac.h
new file mode 100644
index 0000000000..e2dd3f7540
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_flac.h
@@ -0,0 +1,66 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ The following file defines all of the functions/objects used to dynamically
+ link to the libFLAC library.
+ ~ Austen Dicken (admin@cvpcs.org)
+*/
+
+#ifdef FLAC_MUSIC
+
+#include <FLAC/stream_decoder.h>
+
+typedef struct {
+ int loaded;
+ void *handle;
+ FLAC__StreamDecoder *(*FLAC__stream_decoder_new)();
+ void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder);
+ FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data);
+ FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder);
+ FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder);
+ FLAC__bool (*FLAC__stream_decoder_process_single)(
+ FLAC__StreamDecoder *decoder);
+ FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)(
+ FLAC__StreamDecoder *decoder);
+ FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)(
+ FLAC__StreamDecoder *decoder);
+ FLAC__bool (*FLAC__stream_decoder_seek_absolute)(
+ FLAC__StreamDecoder *decoder,
+ FLAC__uint64 sample);
+ FLAC__StreamDecoderState (*FLAC__stream_decoder_get_state)(
+ const FLAC__StreamDecoder *decoder);
+} flac_loader;
+
+extern flac_loader flac;
+
+#endif /* FLAC_MUSIC */
+
+extern int Mix_InitFLAC();
+extern void Mix_QuitFLAC();
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.c b/apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.c
new file mode 100644
index 0000000000..73c687fb7b
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.c
@@ -0,0 +1,87 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ James Le Cuirot
+ chewi@aura-online.co.uk
+*/
+
+#ifdef USE_FLUIDSYNTH_MIDI
+
+#include "SDL_loadso.h"
+#include "dynamic_fluidsynth.h"
+
+fluidsynth_loader fluidsynth = {
+ 0, NULL
+};
+
+#ifdef FLUIDSYNTH_DYNAMIC
+#define FLUIDSYNTH_LOADER(FUNC, SIG) \
+ fluidsynth.FUNC = (SIG) SDL_LoadFunction(fluidsynth.handle, #FUNC); \
+ if (fluidsynth.FUNC == NULL) { SDL_UnloadObject(fluidsynth.handle); return -1; }
+#else
+#define FLUIDSYNTH_LOADER(FUNC, SIG) \
+ fluidsynth.FUNC = FUNC;
+#endif
+
+int Mix_InitFluidSynth()
+{
+ if ( fluidsynth.loaded == 0 ) {
+#ifdef FLUIDSYNTH_DYNAMIC
+ fluidsynth.handle = SDL_LoadObject(FLUIDSYNTH_DYNAMIC);
+ if ( fluidsynth.handle == NULL ) return -1;
+#endif
+
+ FLUIDSYNTH_LOADER(delete_fluid_player, int (*)(fluid_player_t*));
+ FLUIDSYNTH_LOADER(delete_fluid_settings, void (*)(fluid_settings_t*));
+ FLUIDSYNTH_LOADER(delete_fluid_synth, int (*)(fluid_synth_t*));
+ FLUIDSYNTH_LOADER(fluid_player_add, int (*)(fluid_player_t*, const char*));
+ FLUIDSYNTH_LOADER(fluid_player_add_mem, int (*)(fluid_player_t*, const void*, size_t));
+ FLUIDSYNTH_LOADER(fluid_player_get_status, int (*)(fluid_player_t*));
+ FLUIDSYNTH_LOADER(fluid_player_play, int (*)(fluid_player_t*));
+ FLUIDSYNTH_LOADER(fluid_player_set_loop, int (*)(fluid_player_t*, int));
+ FLUIDSYNTH_LOADER(fluid_player_stop, int (*)(fluid_player_t*));
+ FLUIDSYNTH_LOADER(fluid_settings_setnum, int (*)(fluid_settings_t*, const char*, double));
+ FLUIDSYNTH_LOADER(fluid_synth_get_settings, fluid_settings_t* (*)(fluid_synth_t*));
+ FLUIDSYNTH_LOADER(fluid_synth_set_gain, void (*)(fluid_synth_t*, float));
+ FLUIDSYNTH_LOADER(fluid_synth_sfload, int(*)(fluid_synth_t*, const char*, int));
+ FLUIDSYNTH_LOADER(fluid_synth_write_s16, int(*)(fluid_synth_t*, int, void*, int, int, void*, int, int));
+ FLUIDSYNTH_LOADER(new_fluid_player, fluid_player_t* (*)(fluid_synth_t*));
+ FLUIDSYNTH_LOADER(new_fluid_settings, fluid_settings_t* (*)(void));
+ FLUIDSYNTH_LOADER(new_fluid_synth, fluid_synth_t* (*)(fluid_settings_t*));
+ }
+ ++fluidsynth.loaded;
+
+ return 0;
+}
+
+void Mix_QuitFluidSynth()
+{
+ if ( fluidsynth.loaded == 0 ) {
+ return;
+ }
+ if ( fluidsynth.loaded == 1 ) {
+#ifdef FLUIDSYNTH_DYNAMIC
+ SDL_UnloadObject(fluidsynth.handle);
+#endif
+ }
+ --fluidsynth.loaded;
+}
+
+#endif /* USE_FLUIDSYNTH_MIDI */
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.h b/apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.h
new file mode 100644
index 0000000000..5d25232a22
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_fluidsynth.h
@@ -0,0 +1,57 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ James Le Cuirot
+ chewi@aura-online.co.uk
+*/
+
+#ifdef USE_FLUIDSYNTH_MIDI
+
+#include <fluidsynth.h>
+
+typedef struct {
+ int loaded;
+ void *handle;
+
+ int (*delete_fluid_player)(fluid_player_t*);
+ void (*delete_fluid_settings)(fluid_settings_t*);
+ int (*delete_fluid_synth)(fluid_synth_t*);
+ int (*fluid_player_add)(fluid_player_t*, const char*);
+ int (*fluid_player_add_mem)(fluid_player_t*, const void*, size_t);
+ int (*fluid_player_get_status)(fluid_player_t*);
+ int (*fluid_player_play)(fluid_player_t*);
+ int (*fluid_player_set_loop)(fluid_player_t*, int);
+ int (*fluid_player_stop)(fluid_player_t*);
+ int (*fluid_settings_setnum)(fluid_settings_t*, const char*, double);
+ fluid_settings_t* (*fluid_synth_get_settings)(fluid_synth_t*);
+ void (*fluid_synth_set_gain)(fluid_synth_t*, float);
+ int (*fluid_synth_sfload)(fluid_synth_t*, const char*, int);
+ int (*fluid_synth_write_s16)(fluid_synth_t*, int, void*, int, int, void*, int, int);
+ fluid_player_t* (*new_fluid_player)(fluid_synth_t*);
+ fluid_settings_t* (*new_fluid_settings)(void);
+ fluid_synth_t* (*new_fluid_synth)(fluid_settings_t*);
+} fluidsynth_loader;
+
+extern fluidsynth_loader fluidsynth;
+
+#endif /* USE_FLUIDSYNTH_MIDI */
+
+extern int Mix_InitFluidSynth();
+extern void Mix_QuitFluidSynth();
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_mod.c b/apps/plugins/sdl/SDL_mixer/dynamic_mod.c
new file mode 100644
index 0000000000..7e3cd0af11
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_mod.c
@@ -0,0 +1,275 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef MOD_MUSIC
+
+#include "SDL_loadso.h"
+
+#include "dynamic_mod.h"
+
+mikmod_loader mikmod = {
+ 0, NULL
+};
+
+#ifdef MOD_DYNAMIC
+int Mix_InitMOD()
+{
+ if ( mikmod.loaded == 0 ) {
+ mikmod.handle = SDL_LoadObject(MOD_DYNAMIC);
+ if ( mikmod.handle == NULL ) {
+ return -1;
+ }
+ mikmod.MikMod_Exit =
+ (void (*)(void))
+ SDL_LoadFunction(mikmod.handle, "MikMod_Exit");
+ if ( mikmod.MikMod_Exit == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_InfoDriver =
+ (CHAR* (*)(void))
+ SDL_LoadFunction(mikmod.handle, "MikMod_InfoDriver");
+ if ( mikmod.MikMod_InfoDriver == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_InfoLoader =
+ (CHAR* (*)(void))
+ SDL_LoadFunction(mikmod.handle, "MikMod_InfoLoader");
+ if ( mikmod.MikMod_InfoLoader == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_Init =
+ (BOOL (*)(CHAR*))
+ SDL_LoadFunction(mikmod.handle, "MikMod_Init");
+ if ( mikmod.MikMod_Init == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_RegisterAllLoaders =
+ (void (*)(void))
+ SDL_LoadFunction(mikmod.handle, "MikMod_RegisterAllLoaders");
+ if ( mikmod.MikMod_RegisterAllLoaders == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_RegisterDriver =
+ (void (*)(struct MDRIVER*))
+ SDL_LoadFunction(mikmod.handle, "MikMod_RegisterDriver");
+ if ( mikmod.MikMod_RegisterDriver == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_errno =
+ (int*)
+ SDL_LoadFunction(mikmod.handle, "MikMod_errno");
+ if ( mikmod.MikMod_errno == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.MikMod_strerror =
+ (char* (*)(int))
+ SDL_LoadFunction(mikmod.handle, "MikMod_strerror");
+ if ( mikmod.MikMod_strerror == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_Active =
+ (BOOL (*)(void))
+ SDL_LoadFunction(mikmod.handle, "Player_Active");
+ if ( mikmod.Player_Active == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_Free =
+ (void (*)(MODULE*))
+ SDL_LoadFunction(mikmod.handle, "Player_Free");
+ if ( mikmod.Player_Free == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_LoadGeneric =
+ (MODULE* (*)(MREADER*,int,BOOL))
+ SDL_LoadFunction(mikmod.handle, "Player_LoadGeneric");
+ if ( mikmod.Player_LoadGeneric == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_SetPosition =
+ (void (*)(UWORD))
+ SDL_LoadFunction(mikmod.handle, "Player_SetPosition");
+ if ( mikmod.Player_SetPosition == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_SetVolume =
+ (void (*)(SWORD))
+ SDL_LoadFunction(mikmod.handle, "Player_SetVolume");
+ if ( mikmod.Player_SetVolume == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_Start =
+ (void (*)(MODULE*))
+ SDL_LoadFunction(mikmod.handle, "Player_Start");
+ if ( mikmod.Player_Start == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.Player_Stop =
+ (void (*)(void))
+ SDL_LoadFunction(mikmod.handle, "Player_Stop");
+ if ( mikmod.Player_Stop == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.VC_WriteBytes =
+ (ULONG (*)(SBYTE*,ULONG))
+ SDL_LoadFunction(mikmod.handle, "VC_WriteBytes");
+ if ( mikmod.VC_WriteBytes == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.drv_nos =
+ (MDRIVER*)
+ SDL_LoadFunction(mikmod.handle, "drv_nos");
+ if ( mikmod.drv_nos == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_device =
+ (UWORD*)
+ SDL_LoadFunction(mikmod.handle, "md_device");
+ if ( mikmod.md_device == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_mixfreq =
+ (UWORD*)
+ SDL_LoadFunction(mikmod.handle, "md_mixfreq");
+ if ( mikmod.md_mixfreq == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_mode =
+ (UWORD*)
+ SDL_LoadFunction(mikmod.handle, "md_mode");
+ if ( mikmod.md_mode == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_musicvolume =
+ (UBYTE*)
+ SDL_LoadFunction(mikmod.handle, "md_musicvolume");
+ if ( mikmod.md_musicvolume == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_pansep =
+ (UBYTE*)
+ SDL_LoadFunction(mikmod.handle, "md_pansep");
+ if ( mikmod.md_pansep == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_reverb =
+ (UBYTE*)
+ SDL_LoadFunction(mikmod.handle, "md_reverb");
+ if ( mikmod.md_reverb == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_sndfxvolume =
+ (UBYTE*)
+ SDL_LoadFunction(mikmod.handle, "md_sndfxvolume");
+ if ( mikmod.md_sndfxvolume == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ mikmod.md_volume =
+ (UBYTE*)
+ SDL_LoadFunction(mikmod.handle, "md_volume");
+ if ( mikmod.md_volume == NULL ) {
+ SDL_UnloadObject(mikmod.handle);
+ return -1;
+ }
+ }
+ ++mikmod.loaded;
+
+ return 0;
+}
+void Mix_QuitMOD()
+{
+ if ( mikmod.loaded == 0 ) {
+ return;
+ }
+ if ( mikmod.loaded == 1 ) {
+ SDL_UnloadObject(mikmod.handle);
+ }
+ --mikmod.loaded;
+}
+#else
+int Mix_InitMOD()
+{
+ if ( mikmod.loaded == 0 ) {
+ mikmod.MikMod_Exit = MikMod_Exit;
+ mikmod.MikMod_InfoDriver = MikMod_InfoDriver;
+ mikmod.MikMod_InfoLoader = MikMod_InfoLoader;
+ mikmod.MikMod_Init = MikMod_Init;
+ mikmod.MikMod_RegisterAllLoaders = MikMod_RegisterAllLoaders;
+ mikmod.MikMod_RegisterDriver = MikMod_RegisterDriver;
+ mikmod.MikMod_errno = &MikMod_errno;
+ mikmod.MikMod_strerror = MikMod_strerror;
+ mikmod.Player_Active = Player_Active;
+ mikmod.Player_Free = Player_Free;
+ mikmod.Player_LoadGeneric = Player_LoadGeneric;
+ mikmod.Player_SetPosition = Player_SetPosition;
+ mikmod.Player_SetVolume = Player_SetVolume;
+ mikmod.Player_Start = Player_Start;
+ mikmod.Player_Stop = Player_Stop;
+ mikmod.VC_WriteBytes = VC_WriteBytes;
+ mikmod.drv_nos = &drv_nos;
+ mikmod.md_device = &md_device;
+ mikmod.md_mixfreq = &md_mixfreq;
+ mikmod.md_mode = &md_mode;
+ mikmod.md_musicvolume = &md_musicvolume;
+ mikmod.md_pansep = &md_pansep;
+ mikmod.md_reverb = &md_reverb;
+ mikmod.md_sndfxvolume = &md_sndfxvolume;
+ mikmod.md_volume = &md_volume;
+ }
+ ++mikmod.loaded;
+
+ return 0;
+}
+void Mix_QuitMOD()
+{
+ if ( mikmod.loaded == 0 ) {
+ return;
+ }
+ if ( mikmod.loaded == 1 ) {
+ }
+ --mikmod.loaded;
+}
+#endif /* MOD_DYNAMIC */
+
+#endif /* MOD_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_mod.h b/apps/plugins/sdl/SDL_mixer/dynamic_mod.h
new file mode 100644
index 0000000000..3561b151db
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_mod.h
@@ -0,0 +1,62 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef MOD_MUSIC
+
+#include "mikmod.h"
+
+typedef struct {
+ int loaded;
+ void *handle;
+
+ void (*MikMod_Exit)(void);
+ CHAR* (*MikMod_InfoDriver)(void);
+ CHAR* (*MikMod_InfoLoader)(void);
+ BOOL (*MikMod_Init)(CHAR*);
+ void (*MikMod_RegisterAllLoaders)(void);
+ void (*MikMod_RegisterDriver)(struct MDRIVER*);
+ int* MikMod_errno;
+ char* (*MikMod_strerror)(int);
+ BOOL (*Player_Active)(void);
+ void (*Player_Free)(MODULE*);
+ MODULE* (*Player_LoadGeneric)(MREADER*,int,BOOL);
+ void (*Player_SetPosition)(UWORD);
+ void (*Player_SetVolume)(SWORD);
+ void (*Player_Start)(MODULE*);
+ void (*Player_Stop)(void);
+ ULONG (*VC_WriteBytes)(SBYTE*,ULONG);
+ struct MDRIVER* drv_nos;
+ UWORD* md_device;
+ UWORD* md_mixfreq;
+ UWORD* md_mode;
+ UBYTE* md_musicvolume;
+ UBYTE* md_pansep;
+ UBYTE* md_reverb;
+ UBYTE* md_sndfxvolume;
+ UBYTE* md_volume;
+} mikmod_loader;
+
+extern mikmod_loader mikmod;
+
+#endif /* MOD_MUSIC */
+
+extern int Mix_InitMOD();
+extern void Mix_QuitMOD();
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_mp3.c b/apps/plugins/sdl/SDL_mixer/dynamic_mp3.c
new file mode 100644
index 0000000000..83a3e309fc
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_mp3.c
@@ -0,0 +1,171 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef MP3_MUSIC
+
+#include "SDL_loadso.h"
+
+#include "dynamic_mp3.h"
+
+smpeg_loader smpeg = {
+ 0, NULL
+};
+
+#ifdef MP3_DYNAMIC
+int Mix_InitMP3()
+{
+ if ( smpeg.loaded == 0 ) {
+ smpeg.handle = SDL_LoadObject(MP3_DYNAMIC);
+ if ( smpeg.handle == NULL ) {
+ return -1;
+ }
+ smpeg.SMPEG_actualSpec =
+ (void (*)( SMPEG *, SDL_AudioSpec * ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_actualSpec");
+ if ( smpeg.SMPEG_actualSpec == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_delete =
+ (void (*)( SMPEG* ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_delete");
+ if ( smpeg.SMPEG_delete == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_enableaudio =
+ (void (*)( SMPEG*, int ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_enableaudio");
+ if ( smpeg.SMPEG_enableaudio == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_enablevideo =
+ (void (*)( SMPEG*, int ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_enablevideo");
+ if ( smpeg.SMPEG_enablevideo == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_new_rwops =
+ (SMPEG* (*)(SDL_RWops *, SMPEG_Info*, int))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_new_rwops");
+ if ( smpeg.SMPEG_new_rwops == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_play =
+ (void (*)( SMPEG* ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_play");
+ if ( smpeg.SMPEG_play == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_playAudio =
+ (int (*)( SMPEG *, Uint8 *, int ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_playAudio");
+ if ( smpeg.SMPEG_playAudio == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_rewind =
+ (void (*)( SMPEG* ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_rewind");
+ if ( smpeg.SMPEG_rewind == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_setvolume =
+ (void (*)( SMPEG*, int ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_setvolume");
+ if ( smpeg.SMPEG_setvolume == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_skip =
+ (void (*)( SMPEG*, float ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_skip");
+ if ( smpeg.SMPEG_skip == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_status =
+ (SMPEGstatus (*)( SMPEG* ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_status");
+ if ( smpeg.SMPEG_status == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ smpeg.SMPEG_stop =
+ (void (*)( SMPEG* ))
+ SDL_LoadFunction(smpeg.handle, "SMPEG_stop");
+ if ( smpeg.SMPEG_stop == NULL ) {
+ SDL_UnloadObject(smpeg.handle);
+ return -1;
+ }
+ }
+ ++smpeg.loaded;
+
+ return 0;
+}
+void Mix_QuitMP3()
+{
+ if ( smpeg.loaded == 0 ) {
+ return;
+ }
+ if ( smpeg.loaded == 1 ) {
+ SDL_UnloadObject(smpeg.handle);
+ }
+ --smpeg.loaded;
+}
+#else
+int Mix_InitMP3()
+{
+ if ( smpeg.loaded == 0 ) {
+ smpeg.SMPEG_actualSpec = SMPEG_actualSpec;
+ smpeg.SMPEG_delete = SMPEG_delete;
+ smpeg.SMPEG_enableaudio = SMPEG_enableaudio;
+ smpeg.SMPEG_enablevideo = SMPEG_enablevideo;
+ smpeg.SMPEG_new_rwops = SMPEG_new_rwops;
+ smpeg.SMPEG_play = SMPEG_play;
+ smpeg.SMPEG_playAudio = SMPEG_playAudio;
+ smpeg.SMPEG_rewind = SMPEG_rewind;
+ smpeg.SMPEG_setvolume = SMPEG_setvolume;
+ smpeg.SMPEG_skip = SMPEG_skip;
+ smpeg.SMPEG_status = SMPEG_status;
+ smpeg.SMPEG_stop = SMPEG_stop;
+ }
+ ++smpeg.loaded;
+
+ return 0;
+}
+void Mix_QuitMP3()
+{
+ if ( smpeg.loaded == 0 ) {
+ return;
+ }
+ if ( smpeg.loaded == 1 ) {
+ }
+ --smpeg.loaded;
+}
+#endif /* MP3_DYNAMIC */
+
+#endif /* MP3_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_mp3.h b/apps/plugins/sdl/SDL_mixer/dynamic_mp3.h
new file mode 100644
index 0000000000..03cbbbf9cf
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_mp3.h
@@ -0,0 +1,47 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef MP3_MUSIC
+#include "smpeg.h"
+
+typedef struct {
+ int loaded;
+ void *handle;
+ void (*SMPEG_actualSpec)( SMPEG *mpeg, SDL_AudioSpec *spec );
+ void (*SMPEG_delete)( SMPEG* mpeg );
+ void (*SMPEG_enableaudio)( SMPEG* mpeg, int enable );
+ void (*SMPEG_enablevideo)( SMPEG* mpeg, int enable );
+ SMPEG* (*SMPEG_new_rwops)(SDL_RWops *src, SMPEG_Info* info, int sdl_audio);
+ void (*SMPEG_play)( SMPEG* mpeg );
+ int (*SMPEG_playAudio)( SMPEG *mpeg, Uint8 *stream, int len );
+ void (*SMPEG_rewind)( SMPEG* mpeg );
+ void (*SMPEG_setvolume)( SMPEG* mpeg, int volume );
+ void (*SMPEG_skip)( SMPEG* mpeg, float seconds );
+ SMPEGstatus (*SMPEG_status)( SMPEG* mpeg );
+ void (*SMPEG_stop)( SMPEG* mpeg );
+} smpeg_loader;
+
+extern smpeg_loader smpeg;
+
+#endif /* MUSIC_MP3 */
+
+extern int Mix_InitMP3();
+extern void Mix_QuitMP3();
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_ogg.c b/apps/plugins/sdl/SDL_mixer/dynamic_ogg.c
new file mode 100644
index 0000000000..345a8c866f
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_ogg.c
@@ -0,0 +1,131 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef OGG_MUSIC
+
+#include "SDL_loadso.h"
+
+#include "dynamic_ogg.h"
+
+vorbis_loader vorbis = {
+ 0, NULL
+};
+
+#ifdef OGG_DYNAMIC
+int Mix_InitOgg()
+{
+ if ( vorbis.loaded == 0 ) {
+ vorbis.handle = SDL_LoadObject(OGG_DYNAMIC);
+ if ( vorbis.handle == NULL ) {
+ return -1;
+ }
+ vorbis.ov_clear =
+ (int (*)(OggVorbis_File *))
+ SDL_LoadFunction(vorbis.handle, "ov_clear");
+ if ( vorbis.ov_clear == NULL ) {
+ SDL_UnloadObject(vorbis.handle);
+ return -1;
+ }
+ vorbis.ov_info =
+ (vorbis_info *(*)(OggVorbis_File *,int))
+ SDL_LoadFunction(vorbis.handle, "ov_info");
+ if ( vorbis.ov_info == NULL ) {
+ SDL_UnloadObject(vorbis.handle);
+ return -1;
+ }
+ vorbis.ov_open_callbacks =
+ (int (*)(void *, OggVorbis_File *, char *, long, ov_callbacks))
+ SDL_LoadFunction(vorbis.handle, "ov_open_callbacks");
+ if ( vorbis.ov_open_callbacks == NULL ) {
+ SDL_UnloadObject(vorbis.handle);
+ return -1;
+ }
+ vorbis.ov_pcm_total =
+ (ogg_int64_t (*)(OggVorbis_File *,int))
+ SDL_LoadFunction(vorbis.handle, "ov_pcm_total");
+ if ( vorbis.ov_pcm_total == NULL ) {
+ SDL_UnloadObject(vorbis.handle);
+ return -1;
+ }
+ vorbis.ov_read =
+#ifdef OGG_USE_TREMOR
+ (long (*)(OggVorbis_File *,char *,int,int *))
+#else
+ (long (*)(OggVorbis_File *,char *,int,int,int,int,int *))
+#endif
+ SDL_LoadFunction(vorbis.handle, "ov_read");
+ if ( vorbis.ov_read == NULL ) {
+ SDL_UnloadObject(vorbis.handle);
+ return -1;
+ }
+ vorbis.ov_time_seek =
+#ifdef OGG_USE_TREMOR
+ (long (*)(OggVorbis_File *,ogg_int64_t))
+#else
+ (int (*)(OggVorbis_File *,double))
+#endif
+ SDL_LoadFunction(vorbis.handle, "ov_time_seek");
+ if ( vorbis.ov_time_seek == NULL ) {
+ SDL_UnloadObject(vorbis.handle);
+ return -1;
+ }
+ }
+ ++vorbis.loaded;
+
+ return 0;
+}
+void Mix_QuitOgg()
+{
+ if ( vorbis.loaded == 0 ) {
+ return;
+ }
+ if ( vorbis.loaded == 1 ) {
+ SDL_UnloadObject(vorbis.handle);
+ }
+ --vorbis.loaded;
+}
+#else
+int Mix_InitOgg()
+{
+ if ( vorbis.loaded == 0 ) {
+ vorbis.ov_clear = ov_clear;
+ vorbis.ov_info = ov_info;
+ vorbis.ov_open_callbacks = ov_open_callbacks;
+ vorbis.ov_pcm_total = ov_pcm_total;
+ vorbis.ov_read = ov_read;
+ vorbis.ov_time_seek = ov_time_seek;
+ }
+ ++vorbis.loaded;
+
+ return 0;
+}
+void Mix_QuitOgg()
+{
+ if ( vorbis.loaded == 0 ) {
+ return;
+ }
+ if ( vorbis.loaded == 1 ) {
+ }
+ --vorbis.loaded;
+}
+#endif /* OGG_DYNAMIC */
+
+#endif /* OGG_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/dynamic_ogg.h b/apps/plugins/sdl/SDL_mixer/dynamic_ogg.h
new file mode 100644
index 0000000000..822458d49e
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/dynamic_ogg.h
@@ -0,0 +1,53 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef OGG_MUSIC
+#ifdef OGG_USE_TREMOR
+#include <tremor/ivorbisfile.h>
+#else
+#include <vorbis/vorbisfile.h>
+#endif
+
+typedef struct {
+ int loaded;
+ void *handle;
+ int (*ov_clear)(OggVorbis_File *vf);
+ vorbis_info *(*ov_info)(OggVorbis_File *vf,int link);
+ int (*ov_open_callbacks)(void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks);
+ ogg_int64_t (*ov_pcm_total)(OggVorbis_File *vf,int i);
+#ifdef OGG_USE_TREMOR
+ long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int *bitstream);
+#else
+ long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int bigendianp,int word,int sgned,int *bitstream);
+#endif
+#ifdef OGG_USE_TREMOR
+ int (*ov_time_seek)(OggVorbis_File *vf,ogg_int64_t pos);
+#else
+ int (*ov_time_seek)(OggVorbis_File *vf,double pos);
+#endif
+} vorbis_loader;
+
+extern vorbis_loader vorbis;
+
+#endif /* OGG_MUSIC */
+
+extern int Mix_InitOgg();
+extern void Mix_QuitOgg();
diff --git a/apps/plugins/sdl/SDL_mixer/effect_position.c b/apps/plugins/sdl/SDL_mixer/effect_position.c
new file mode 100644
index 0000000000..e0b467b12f
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/effect_position.c
@@ -0,0 +1,1615 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This file by Ryan C. Gordon (icculus@icculus.org)
+
+ These are some internally supported special effects that use SDL_mixer's
+ effect callback API. They are meant for speed over quality. :)
+*/
+
+/* $Id$ */
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+#include "SDL_endian.h"
+
+#define __MIX_INTERNAL_EFFECT__
+#include "effects_internal.h"
+
+/* profile code:
+ #include <sys/time.h>
+ #include <unistd.h>
+ struct timeval tv1;
+ struct timeval tv2;
+
+ gettimeofday(&tv1, NULL);
+
+ ... do your thing here ...
+
+ gettimeofday(&tv2, NULL);
+ printf("%ld\n", tv2.tv_usec - tv1.tv_usec);
+*/
+
+
+/*
+ * Positional effects...panning, distance attenuation, etc.
+ */
+
+typedef struct _Eff_positionargs
+{
+ volatile float left_f;
+ volatile float right_f;
+ volatile Uint8 left_u8;
+ volatile Uint8 right_u8;
+ volatile float left_rear_f;
+ volatile float right_rear_f;
+ volatile float center_f;
+ volatile float lfe_f;
+ volatile Uint8 left_rear_u8;
+ volatile Uint8 right_rear_u8;
+ volatile Uint8 center_u8;
+ volatile Uint8 lfe_u8;
+ volatile float distance_f;
+ volatile Uint8 distance_u8;
+ volatile Sint16 room_angle;
+ volatile int in_use;
+ volatile int channels;
+} position_args;
+
+static position_args **pos_args_array = NULL;
+static position_args *pos_args_global = NULL;
+static int position_channels = 0;
+
+void _Eff_PositionDeinit(void)
+{
+ int i;
+ for (i = 0; i < position_channels; i++) {
+ SDL_free(pos_args_array[i]);
+ }
+
+ position_channels = 0;
+
+ SDL_free(pos_args_global);
+ pos_args_global = NULL;
+ SDL_free(pos_args_array);
+ pos_args_array = NULL;
+}
+
+
+/* This just frees up the callback-specific data. */
+static void _Eff_PositionDone(int channel, void *udata)
+{
+ if (channel < 0) {
+ if (pos_args_global != NULL) {
+ SDL_free(pos_args_global);
+ pos_args_global = NULL;
+ }
+ }
+
+ else if (pos_args_array[channel] != NULL) {
+ SDL_free(pos_args_array[channel]);
+ pos_args_array[channel] = NULL;
+ }
+}
+
+
+static void _Eff_position_u8(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint8 *ptr = (Uint8 *) stream;
+ int i;
+
+ /*
+ * if there's only a mono channnel (the only way we wouldn't have
+ * a len divisible by 2 here), then left_f and right_f are always
+ * 1.0, and are therefore throwaways.
+ */
+ if (len % sizeof (Uint16) != 0) {
+ *ptr = (Uint8) (((float) *ptr) * args->distance_f);
+ ptr++;
+ len--;
+ }
+
+ if (args->room_angle == 180)
+ for (i = 0; i < len; i += sizeof (Uint8) * 2) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else for (i = 0; i < len; i += sizeof (Uint8) * 2) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ }
+}
+static void _Eff_position_u8_c4(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint8 *ptr = (Uint8 *) stream;
+ int i;
+
+ /*
+ * if there's only a mono channnel (the only way we wouldn't have
+ * a len divisible by 2 here), then left_f and right_f are always
+ * 1.0, and are therefore throwaways.
+ */
+ if (len % sizeof (Uint16) != 0) {
+ *ptr = (Uint8) (((float) *ptr) * args->distance_f);
+ ptr++;
+ len--;
+ }
+
+ if (args->room_angle == 0)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else if (args->room_angle == 90)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else if (args->room_angle == 180)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else if (args->room_angle == 270)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ }
+}
+
+
+static void _Eff_position_u8_c6(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint8 *ptr = (Uint8 *) stream;
+ int i;
+
+ /*
+ * if there's only a mono channnel (the only way we wouldn't have
+ * a len divisible by 2 here), then left_f and right_f are always
+ * 1.0, and are therefore throwaways.
+ */
+ if (len % sizeof (Uint16) != 0) {
+ *ptr = (Uint8) (((float) *ptr) * args->distance_f);
+ ptr++;
+ len--;
+ }
+
+ if (args->room_angle == 0)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->center_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->lfe_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else if (args->room_angle == 90)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f/2) + 128)
+ + (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f/2) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->lfe_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else if (args->room_angle == 180)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f/2) + 128)
+ + (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f/2) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->lfe_f) * args->distance_f) + 128);
+ ptr++;
+ }
+ else if (args->room_angle == 270)
+ for (i = 0; i < len; i += sizeof (Uint8) * 6) {
+ /* must adjust the sample so that 0 is the center */
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_rear_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->right_f) * args->distance_f) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_f) * args->distance_f/2) + 128)
+ + (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->left_rear_f) * args->distance_f/2) + 128);
+ ptr++;
+ *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128))
+ * args->lfe_f) * args->distance_f) + 128);
+ ptr++;
+ }
+}
+
+
+/*
+ * This one runs about 10.1 times faster than the non-table version, with
+ * no loss in quality. It does, however, require 64k of memory for the
+ * lookup table. Also, this will only update position information once per
+ * call; the non-table version always checks the arguments for each sample,
+ * in case the user has called Mix_SetPanning() or whatnot again while this
+ * callback is running.
+ */
+static void _Eff_position_table_u8(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint8 *ptr = (Uint8 *) stream;
+ Uint32 *p;
+ int i;
+ Uint8 *l = ((Uint8 *) _Eff_volume_table) + (256 * args->left_u8);
+ Uint8 *r = ((Uint8 *) _Eff_volume_table) + (256 * args->right_u8);
+ Uint8 *d = ((Uint8 *) _Eff_volume_table) + (256 * args->distance_u8);
+
+ if (args->room_angle == 180) {
+ Uint8 *temp = l;
+ l = r;
+ r = temp;
+ }
+ /*
+ * if there's only a mono channnel, then l[] and r[] are always
+ * volume 255, and are therefore throwaways. Still, we have to
+ * be sure not to overrun the audio buffer...
+ */
+ while (len % sizeof (Uint32) != 0) {
+ *ptr = d[l[*ptr]];
+ ptr++;
+ if (args->channels > 1) {
+ *ptr = d[r[*ptr]];
+ ptr++;
+ }
+ len -= args->channels;
+ }
+
+ p = (Uint32 *) ptr;
+
+ for (i = 0; i < len; i += sizeof (Uint32)) {
+#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+ *p = (d[l[(*p & 0xFF000000) >> 24]] << 24) |
+ (d[r[(*p & 0x00FF0000) >> 16]] << 16) |
+ (d[l[(*p & 0x0000FF00) >> 8]] << 8) |
+ (d[r[(*p & 0x000000FF) ]] ) ;
+#else
+ *p = (d[r[(*p & 0xFF000000) >> 24]] << 24) |
+ (d[l[(*p & 0x00FF0000) >> 16]] << 16) |
+ (d[r[(*p & 0x0000FF00) >> 8]] << 8) |
+ (d[l[(*p & 0x000000FF) ]] ) ;
+#endif
+ ++p;
+ }
+}
+
+
+static void _Eff_position_s8(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint8 *ptr = (Sint8 *) stream;
+ int i;
+
+ /*
+ * if there's only a mono channnel (the only way we wouldn't have
+ * a len divisible by 2 here), then left_f and right_f are always
+ * 1.0, and are therefore throwaways.
+ */
+ if (len % sizeof (Sint16) != 0) {
+ *ptr = (Sint8) (((float) *ptr) * args->distance_f);
+ ptr++;
+ len--;
+ }
+
+ if (args->room_angle == 180)
+ for (i = 0; i < len; i += sizeof (Sint8) * 2) {
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f);
+ ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f);
+ ptr++;
+ }
+ else
+ for (i = 0; i < len; i += sizeof (Sint8) * 2) {
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f);
+ ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f);
+ ptr++;
+ }
+}
+static void _Eff_position_s8_c4(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint8 *ptr = (Sint8 *) stream;
+ int i;
+
+ /*
+ * if there's only a mono channnel (the only way we wouldn't have
+ * a len divisible by 2 here), then left_f and right_f are always
+ * 1.0, and are therefore throwaways.
+ */
+ if (len % sizeof (Sint16) != 0) {
+ *ptr = (Sint8) (((float) *ptr) * args->distance_f);
+ ptr++;
+ len--;
+ }
+
+ for (i = 0; i < len; i += sizeof (Sint8) * 4) {
+ switch (args->room_angle) {
+ case 0:
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ break;
+ case 90:
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ break;
+ case 180:
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ break;
+ case 270:
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ break;
+ }
+ }
+}
+static void _Eff_position_s8_c6(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint8 *ptr = (Sint8 *) stream;
+ int i;
+
+ /*
+ * if there's only a mono channnel (the only way we wouldn't have
+ * a len divisible by 2 here), then left_f and right_f are always
+ * 1.0, and are therefore throwaways.
+ */
+ if (len % sizeof (Sint16) != 0) {
+ *ptr = (Sint8) (((float) *ptr) * args->distance_f);
+ ptr++;
+ len--;
+ }
+
+ for (i = 0; i < len; i += sizeof (Sint8) * 6) {
+ switch (args->room_angle) {
+ case 0:
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->center_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
+ break;
+ case 90:
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f / 2)
+ + (Sint8)((((float) *ptr) * args->right_f) * args->distance_f / 2); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
+ break;
+ case 180:
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f / 2)
+ + (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f / 2); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
+ break;
+ case 270:
+ *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f / 2)
+ + (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f / 2); ptr++;
+ *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++;
+ break;
+ }
+ }
+}
+
+
+/*
+ * This one runs about 10.1 times faster than the non-table version, with
+ * no loss in quality. It does, however, require 64k of memory for the
+ * lookup table. Also, this will only update position information once per
+ * call; the non-table version always checks the arguments for each sample,
+ * in case the user has called Mix_SetPanning() or whatnot again while this
+ * callback is running.
+ */
+static void _Eff_position_table_s8(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint8 *ptr = (Sint8 *) stream;
+ Uint32 *p;
+ int i;
+ Sint8 *l = ((Sint8 *) _Eff_volume_table) + (256 * args->left_u8);
+ Sint8 *r = ((Sint8 *) _Eff_volume_table) + (256 * args->right_u8);
+ Sint8 *d = ((Sint8 *) _Eff_volume_table) + (256 * args->distance_u8);
+
+ if (args->room_angle == 180) {
+ Sint8 *temp = l;
+ l = r;
+ r = temp;
+ }
+
+
+ while (len % sizeof (Uint32) != 0) {
+ *ptr = d[l[*ptr]];
+ ptr++;
+ if (args->channels > 1) {
+ *ptr = d[r[*ptr]];
+ ptr++;
+ }
+ len -= args->channels;
+ }
+
+ p = (Uint32 *) ptr;
+
+ for (i = 0; i < len; i += sizeof (Uint32)) {
+#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+ *p = (d[l[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) |
+ (d[r[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) |
+ (d[l[((Sint16)(Sint8)((*p & 0x0000FF00) >> 8))+128]] << 8) |
+ (d[r[((Sint16)(Sint8)((*p & 0x000000FF) ))+128]] ) ;
+#else
+ *p = (d[r[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) |
+ (d[l[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) |
+ (d[r[((Sint16)(Sint8)((*p & 0x0000FF00) >> 8))+128]] << 8) |
+ (d[l[((Sint16)(Sint8)((*p & 0x000000FF) ))+128]] ) ;
+#endif
+ ++p;
+ }
+
+
+}
+
+
+/* !!! FIXME : Optimize the code for 16-bit samples? */
+
+static void _Eff_position_u16lsb(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint16 *ptr = (Uint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Uint16) * 2) {
+ Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768);
+ Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768);
+
+ Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
+ * args->distance_f) + 32768);
+ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
+ * args->distance_f) + 32768);
+
+ if (args->room_angle == 180) {
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ }
+ else {
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ }
+ }
+}
+static void _Eff_position_u16lsb_c4(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint16 *ptr = (Uint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Uint16) * 4) {
+ Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768);
+ Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768);
+ Sint16 samplr = (Sint16) (SDL_SwapLE16(*(ptr+2)) - 32768);
+ Sint16 samprr = (Sint16) (SDL_SwapLE16(*(ptr+3)) - 32768);
+
+ Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
+ * args->distance_f) + 32768);
+ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
+ * args->distance_f) + 32768);
+ Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
+ * args->distance_f) + 32768);
+ Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
+ * args->distance_f) + 32768);
+
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ break;
+ case 90:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ break;
+ case 180:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ break;
+ case 270:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ break;
+ }
+ }
+}
+static void _Eff_position_u16lsb_c6(int chan, void *stream, int len, void *udata)
+{
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint16 *ptr = (Uint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Uint16) * 6) {
+ Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768);
+ Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768);
+ Sint16 samplr = (Sint16) (SDL_SwapLE16(*(ptr+2)) - 32768);
+ Sint16 samprr = (Sint16) (SDL_SwapLE16(*(ptr+3)) - 32768);
+ Sint16 sampce = (Sint16) (SDL_SwapLE16(*(ptr+4)) - 32768);
+ Sint16 sampwf = (Sint16) (SDL_SwapLE16(*(ptr+5)) - 32768);
+
+ Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
+ * args->distance_f) + 32768);
+ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
+ * args->distance_f) + 32768);
+ Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
+ * args->distance_f) + 32768);
+ Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
+ * args->distance_f) + 32768);
+ Uint16 swapce = (Uint16) ((Sint16) (((float) sampce * args->center_f)
+ * args->distance_f) + 32768);
+ Uint16 swapwf = (Uint16) ((Sint16) (((float) sampwf * args->lfe_f)
+ * args->distance_f) + 32768);
+
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapce);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
+ break;
+ case 90:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr)/2 + (Uint16) SDL_SwapLE16(swaprr)/2;
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
+ break;
+ case 180:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr)/2 + (Uint16) SDL_SwapLE16(swaplr)/2;
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
+ break;
+ case 270:
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapl)/2 + (Uint16) SDL_SwapLE16(swaplr)/2;
+ *(ptr++) = (Uint16) SDL_SwapLE16(swapwf);
+ break;
+ }
+ }
+}
+
+static void _Eff_position_s16lsb(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 2 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint16 *ptr = (Sint16 *) stream;
+ int i;
+
+#if 0
+ if (len % (sizeof(Sint16) * 2)) {
+ fprintf(stderr,"Not an even number of frames! len=%d\n", len);
+ return;
+ }
+#endif
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 2) {
+ Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) *
+ args->left_f) * args->distance_f);
+ Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
+ args->right_f) * args->distance_f);
+ if (args->room_angle == 180) {
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ }
+ else {
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ }
+ }
+}
+static void _Eff_position_s16lsb_c4(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 4 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint16 *ptr = (Sint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 4) {
+ Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) *
+ args->left_f) * args->distance_f);
+ Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
+ args->right_f) * args->distance_f);
+ Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
+ args->left_rear_f) * args->distance_f);
+ Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+2))) *
+ args->right_rear_f) * args->distance_f);
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ break;
+ case 90:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ break;
+ case 180:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ break;
+ case 270:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ break;
+ }
+ }
+}
+
+static void _Eff_position_s16lsb_c6(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 6 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint16 *ptr = (Sint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 6) {
+ Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) *
+ args->left_f) * args->distance_f);
+ Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) *
+ args->right_f) * args->distance_f);
+ Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+2))) *
+ args->left_rear_f) * args->distance_f);
+ Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+3))) *
+ args->right_rear_f) * args->distance_f);
+ Sint16 swapce = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+4))) *
+ args->center_f) * args->distance_f);
+ Sint16 swapwf = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+5))) *
+ args->lfe_f) * args->distance_f);
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapce);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
+ break;
+ case 90:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr)/2 + (Sint16) SDL_SwapLE16(swaprr)/2;
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
+ break;
+ case 180:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr)/2 + (Sint16) SDL_SwapLE16(swaplr)/2;
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
+ break;
+ case 270:
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapl)/2 + (Sint16) SDL_SwapLE16(swaplr)/2;
+ *(ptr++) = (Sint16) SDL_SwapLE16(swapwf);
+ break;
+ }
+ }
+}
+
+static void _Eff_position_u16msb(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 2 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint16 *ptr = (Uint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 2) {
+ Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768);
+ Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768);
+
+ Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
+ * args->distance_f) + 32768);
+ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
+ * args->distance_f) + 32768);
+
+ if (args->room_angle == 180) {
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ }
+ else {
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ }
+ }
+}
+static void _Eff_position_u16msb_c4(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 4 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint16 *ptr = (Uint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 4) {
+ Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768);
+ Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768);
+ Sint16 samplr = (Sint16) (SDL_SwapBE16(*(ptr+2)) - 32768);
+ Sint16 samprr = (Sint16) (SDL_SwapBE16(*(ptr+3)) - 32768);
+
+ Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
+ * args->distance_f) + 32768);
+ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
+ * args->distance_f) + 32768);
+ Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
+ * args->distance_f) + 32768);
+ Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
+ * args->distance_f) + 32768);
+
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ break;
+ case 90:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ break;
+ case 180:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ break;
+ case 270:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ break;
+ }
+ }
+}
+static void _Eff_position_u16msb_c6(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 6 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Uint16 *ptr = (Uint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 6) {
+ Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768);
+ Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768);
+ Sint16 samplr = (Sint16) (SDL_SwapBE16(*(ptr+2)) - 32768);
+ Sint16 samprr = (Sint16) (SDL_SwapBE16(*(ptr+3)) - 32768);
+ Sint16 sampce = (Sint16) (SDL_SwapBE16(*(ptr+4)) - 32768);
+ Sint16 sampwf = (Sint16) (SDL_SwapBE16(*(ptr+5)) - 32768);
+
+ Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f)
+ * args->distance_f) + 32768);
+ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f)
+ * args->distance_f) + 32768);
+ Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f)
+ * args->distance_f) + 32768);
+ Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f)
+ * args->distance_f) + 32768);
+ Uint16 swapce = (Uint16) ((Sint16) (((float) sampce * args->center_f)
+ * args->distance_f) + 32768);
+ Uint16 swapwf = (Uint16) ((Sint16) (((float) sampwf * args->lfe_f)
+ * args->distance_f) + 32768);
+
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapce);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
+ break;
+ case 90:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr)/2 + (Uint16) SDL_SwapBE16(swaprr)/2;
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
+ break;
+ case 180:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr)/2 + (Uint16) SDL_SwapBE16(swaplr)/2;
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
+ break;
+ case 270:
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapl)/2 + (Uint16) SDL_SwapBE16(swaplr)/2;
+ *(ptr++) = (Uint16) SDL_SwapBE16(swapwf);
+ break;
+ }
+ }
+}
+
+static void _Eff_position_s16msb(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 2 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint16 *ptr = (Sint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 2) {
+ Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) *
+ args->left_f) * args->distance_f);
+ Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) *
+ args->right_f) * args->distance_f);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ }
+}
+static void _Eff_position_s16msb_c4(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 4 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint16 *ptr = (Sint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 4) {
+ Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) *
+ args->left_f) * args->distance_f);
+ Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) *
+ args->right_f) * args->distance_f);
+ Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+2))) *
+ args->left_rear_f) * args->distance_f);
+ Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+3))) *
+ args->right_rear_f) * args->distance_f);
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ break;
+ case 90:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ break;
+ case 180:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ break;
+ case 270:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ break;
+ }
+ }
+}
+static void _Eff_position_s16msb_c6(int chan, void *stream, int len, void *udata)
+{
+ /* 16 signed bits (lsb) * 6 channels. */
+ volatile position_args *args = (volatile position_args *) udata;
+ Sint16 *ptr = (Sint16 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Sint16) * 6) {
+ Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) *
+ args->left_f) * args->distance_f);
+ Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) *
+ args->right_f) * args->distance_f);
+ Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+2))) *
+ args->left_rear_f) * args->distance_f);
+ Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+3))) *
+ args->right_rear_f) * args->distance_f);
+ Sint16 swapce = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+4))) *
+ args->center_f) * args->distance_f);
+ Sint16 swapwf = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+5))) *
+ args->lfe_f) * args->distance_f);
+
+ switch (args->room_angle) {
+ case 0:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapce);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
+ break;
+ case 90:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr)/2 + (Sint16) SDL_SwapBE16(swaprr)/2;
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
+ break;
+ case 180:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr)/2 + (Sint16) SDL_SwapBE16(swaplr)/2;
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
+ break;
+ case 270:
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaplr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swaprr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapr);
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapl)/2 + (Sint16) SDL_SwapBE16(swaplr)/2;
+ *(ptr++) = (Sint16) SDL_SwapBE16(swapwf);
+ break;
+ }
+ }
+}
+
+static void init_position_args(position_args *args)
+{
+ memset(args, '\0', sizeof (position_args));
+ args->in_use = 0;
+ args->room_angle = 0;
+ args->left_u8 = args->right_u8 = args->distance_u8 = 255;
+ args->left_f = args->right_f = args->distance_f = 1.0f;
+ args->left_rear_u8 = args->right_rear_u8 = args->center_u8 = args->lfe_u8 = 255;
+ args->left_rear_f = args->right_rear_f = args->center_f = args->lfe_f = 1.0f;
+ Mix_QuerySpec(NULL, NULL, (int *) &args->channels);
+}
+
+
+static position_args *get_position_arg(int channel)
+{
+ void *rc;
+ int i;
+
+ if (channel < 0) {
+ if (pos_args_global == NULL) {
+ pos_args_global = SDL_malloc(sizeof (position_args));
+ if (pos_args_global == NULL) {
+ Mix_SetError("Out of memory");
+ return(NULL);
+ }
+ init_position_args(pos_args_global);
+ }
+
+ return(pos_args_global);
+ }
+
+ if (channel >= position_channels) {
+ rc = SDL_realloc(pos_args_array, (channel + 1) * sizeof (position_args *));
+ if (rc == NULL) {
+ Mix_SetError("Out of memory");
+ return(NULL);
+ }
+ pos_args_array = (position_args **) rc;
+ for (i = position_channels; i <= channel; i++) {
+ pos_args_array[i] = NULL;
+ }
+ position_channels = channel + 1;
+ }
+
+ if (pos_args_array[channel] == NULL) {
+ pos_args_array[channel] = (position_args *)SDL_malloc(sizeof(position_args));
+ if (pos_args_array[channel] == NULL) {
+ Mix_SetError("Out of memory");
+ return(NULL);
+ }
+ init_position_args(pos_args_array[channel]);
+ }
+
+ return(pos_args_array[channel]);
+}
+
+
+static Mix_EffectFunc_t get_position_effect_func(Uint16 format, int channels)
+{
+ Mix_EffectFunc_t f = NULL;
+
+ switch (format) {
+ case AUDIO_U8:
+ switch (channels) {
+ case 1:
+ case 2:
+ f = (_Eff_build_volume_table_u8()) ? _Eff_position_table_u8 :
+ _Eff_position_u8;
+ break;
+ case 4:
+ f = _Eff_position_u8_c4;
+ break;
+ case 6:
+ f = _Eff_position_u8_c6;
+ break;
+ }
+ break;
+
+ case AUDIO_S8:
+ switch (channels) {
+ case 1:
+ case 2:
+ f = (_Eff_build_volume_table_s8()) ? _Eff_position_table_s8 :
+ _Eff_position_s8;
+ break;
+ case 4:
+ f = _Eff_position_s8_c4;
+ break;
+ case 6:
+ f = _Eff_position_s8_c6;
+ break;
+ }
+ break;
+
+ case AUDIO_U16LSB:
+ switch (channels) {
+ case 1:
+ case 2:
+ f = _Eff_position_u16lsb;
+ break;
+ case 4:
+ f = _Eff_position_u16lsb_c4;
+ break;
+ case 6:
+ f = _Eff_position_u16lsb_c6;
+ break;
+ }
+ break;
+
+ case AUDIO_S16LSB:
+ switch (channels) {
+ case 1:
+ case 2:
+ f = _Eff_position_s16lsb;
+ break;
+ case 4:
+ f = _Eff_position_s16lsb_c4;
+ break;
+ case 6:
+ f = _Eff_position_s16lsb_c6;
+ break;
+ }
+ break;
+
+ case AUDIO_U16MSB:
+ switch (channels) {
+ case 1:
+ case 2:
+ f = _Eff_position_u16msb;
+ break;
+ case 4:
+ f = _Eff_position_u16msb_c4;
+ break;
+ case 6:
+ f = _Eff_position_u16msb_c6;
+ break;
+ }
+ break;
+
+ case AUDIO_S16MSB:
+ switch (channels) {
+ case 1:
+ case 2:
+ f = _Eff_position_s16msb;
+ break;
+ case 4:
+ f = _Eff_position_s16msb_c4;
+ break;
+ case 6:
+ f = _Eff_position_s16msb_c6;
+ break;
+ }
+ break;
+
+ default:
+ Mix_SetError("Unsupported audio format");
+ }
+
+ return(f);
+}
+
+static Uint8 speaker_amplitude[6];
+
+static void set_amplitudes(int channels, int angle, int room_angle)
+{
+ int left = 255, right = 255;
+ int left_rear = 255, right_rear = 255, center = 255;
+
+ angle = SDL_abs(angle) % 360; /* make angle between 0 and 359. */
+
+ if (channels == 2)
+ {
+ /*
+ * We only attenuate by position if the angle falls on the far side
+ * of center; That is, an angle that's due north would not attenuate
+ * either channel. Due west attenuates the right channel to 0.0, and
+ * due east attenuates the left channel to 0.0. Slightly east of
+ * center attenuates the left channel a little, and the right channel
+ * not at all. I think of this as occlusion by one's own head. :)
+ *
+ * ...so, we split our angle circle into four quadrants...
+ */
+ if (angle < 90) {
+ left = 255 - ((int) (255.0f * (((float) angle) / 89.0f)));
+ } else if (angle < 180) {
+ left = (int) (255.0f * (((float) (angle - 90)) / 89.0f));
+ } else if (angle < 270) {
+ right = 255 - ((int) (255.0f * (((float) (angle - 180)) / 89.0f)));
+ } else {
+ right = (int) (255.0f * (((float) (angle - 270)) / 89.0f));
+ }
+ }
+
+ if (channels == 4 || channels == 6)
+ {
+ /*
+ * An angle that's due north does not attenuate the center channel.
+ * An angle in the first quadrant, 0-90, does not attenuate the RF.
+ *
+ * ...so, we split our angle circle into 8 ...
+ *
+ * CE
+ * 0
+ * LF | RF
+ * |
+ * 270<-------|----------->90
+ * |
+ * LR | RR
+ * 180
+ *
+ */
+ if (angle < 45) {
+ left = ((int) (255.0f * (((float) (180 - angle)) / 179.0f)));
+ left_rear = 255 - ((int) (255.0f * (((float) (angle + 45)) / 89.0f)));
+ right_rear = 255 - ((int) (255.0f * (((float) (90 - angle)) / 179.0f)));
+ } else if (angle < 90) {
+ center = ((int) (255.0f * (((float) (225 - angle)) / 179.0f)));
+ left = ((int) (255.0f * (((float) (180 - angle)) / 179.0f)));
+ left_rear = 255 - ((int) (255.0f * (((float) (135 - angle)) / 89.0f)));
+ right_rear = ((int) (255.0f * (((float) (90 + angle)) / 179.0f)));
+ } else if (angle < 135) {
+ center = ((int) (255.0f * (((float) (225 - angle)) / 179.0f)));
+ left = 255 - ((int) (255.0f * (((float) (angle - 45)) / 89.0f)));
+ right = ((int) (255.0f * (((float) (270 - angle)) / 179.0f)));
+ left_rear = ((int) (255.0f * (((float) (angle)) / 179.0f)));
+ } else if (angle < 180) {
+ center = 255 - ((int) (255.0f * (((float) (angle - 90)) / 89.0f)));
+ left = 255 - ((int) (255.0f * (((float) (225 - angle)) / 89.0f)));
+ right = ((int) (255.0f * (((float) (270 - angle)) / 179.0f)));
+ left_rear = ((int) (255.0f * (((float) (angle)) / 179.0f)));
+ } else if (angle < 225) {
+ center = 255 - ((int) (255.0f * (((float) (270 - angle)) / 89.0f)));
+ left = ((int) (255.0f * (((float) (angle - 90)) / 179.0f)));
+ right = 255 - ((int) (255.0f * (((float) (angle - 135)) / 89.0f)));
+ right_rear = ((int) (255.0f * (((float) (360 - angle)) / 179.0f)));
+ } else if (angle < 270) {
+ center = ((int) (255.0f * (((float) (angle - 135)) / 179.0f)));
+ left = ((int) (255.0f * (((float) (angle - 90)) / 179.0f)));
+ right = 255 - ((int) (255.0f * (((float) (315 - angle)) / 89.0f)));
+ right_rear = ((int) (255.0f * (((float) (360 - angle)) / 179.0f)));
+ } else if (angle < 315) {
+ center = ((int) (255.0f * (((float) (angle - 135)) / 179.0f)));
+ right = ((int) (255.0f * (((float) (angle - 180)) / 179.0f)));
+ left_rear = ((int) (255.0f * (((float) (450 - angle)) / 179.0f)));
+ right_rear = 255 - ((int) (255.0f * (((float) (angle - 225)) / 89.0f)));
+ } else {
+ right = ((int) (255.0f * (((float) (angle - 180)) / 179.0f)));
+ left_rear = ((int) (255.0f * (((float) (450 - angle)) / 179.0f)));
+ right_rear = 255 - ((int) (255.0f * (((float) (405 - angle)) / 89.0f)));
+ }
+ }
+
+ if (left < 0) left = 0; if (left > 255) left = 255;
+ if (right < 0) right = 0; if (right > 255) right = 255;
+ if (left_rear < 0) left_rear = 0; if (left_rear > 255) left_rear = 255;
+ if (right_rear < 0) right_rear = 0; if (right_rear > 255) right_rear = 255;
+ if (center < 0) center = 0; if (center > 255) center = 255;
+
+ if (room_angle == 90) {
+ speaker_amplitude[0] = (Uint8)left_rear;
+ speaker_amplitude[1] = (Uint8)left;
+ speaker_amplitude[2] = (Uint8)right_rear;
+ speaker_amplitude[3] = (Uint8)right;
+ }
+ else if (room_angle == 180) {
+ if (channels == 2) {
+ speaker_amplitude[0] = (Uint8)right;
+ speaker_amplitude[1] = (Uint8)left;
+ }
+ else {
+ speaker_amplitude[0] = (Uint8)right_rear;
+ speaker_amplitude[1] = (Uint8)left_rear;
+ speaker_amplitude[2] = (Uint8)right;
+ speaker_amplitude[3] = (Uint8)left;
+ }
+ }
+ else if (room_angle == 270) {
+ speaker_amplitude[0] = (Uint8)right;
+ speaker_amplitude[1] = (Uint8)right_rear;
+ speaker_amplitude[2] = (Uint8)left;
+ speaker_amplitude[3] = (Uint8)left_rear;
+ }
+ else {
+ speaker_amplitude[0] = (Uint8)left;
+ speaker_amplitude[1] = (Uint8)right;
+ speaker_amplitude[2] = (Uint8)left_rear;
+ speaker_amplitude[3] = (Uint8)right_rear;
+ }
+ speaker_amplitude[4] = (Uint8)center;
+ speaker_amplitude[5] = 255;
+}
+
+int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance);
+
+int Mix_SetPanning(int channel, Uint8 left, Uint8 right)
+{
+ Mix_EffectFunc_t f = NULL;
+ int channels;
+ Uint16 format;
+ position_args *args = NULL;
+ int retval = 1;
+
+ Mix_QuerySpec(NULL, &format, &channels);
+
+ if (channels != 2 && channels != 4 && channels != 6) /* it's a no-op; we call that successful. */
+ return(1);
+
+ if (channels > 2) {
+ /* left = right = 255 => angle = 0, to unregister effect as when channels = 2 */
+ /* left = 255 => angle = -90; left = 0 => angle = +89 */
+ int angle = 0;
+ if ((left != 255) || (right != 255)) {
+ angle = (int)left;
+ angle = 127 - angle;
+ angle = -angle;
+ angle = angle * 90 / 128; /* Make it larger for more effect? */
+ }
+ return( Mix_SetPosition(channel, angle, 0) );
+ }
+
+ f = get_position_effect_func(format, channels);
+ if (f == NULL)
+ return(0);
+
+ SDL_LockAudio();
+ args = get_position_arg(channel);
+ if (!args) {
+ SDL_UnlockAudio();
+ return(0);
+ }
+
+ /* it's a no-op; unregister the effect, if it's registered. */
+ if ((args->distance_u8 == 255) && (left == 255) && (right == 255)) {
+ if (args->in_use) {
+ retval = _Mix_UnregisterEffect_locked(channel, f);
+ SDL_UnlockAudio();
+ return(retval);
+ } else {
+ SDL_UnlockAudio();
+ return(1);
+ }
+ }
+
+ args->left_u8 = left;
+ args->left_f = ((float) left) / 255.0f;
+ args->right_u8 = right;
+ args->right_f = ((float) right) / 255.0f;
+ args->room_angle = 0;
+
+ if (!args->in_use) {
+ args->in_use = 1;
+ retval=_Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void*)args);
+ }
+
+ SDL_UnlockAudio();
+ return(retval);
+}
+
+
+int Mix_SetDistance(int channel, Uint8 distance)
+{
+ Mix_EffectFunc_t f = NULL;
+ Uint16 format;
+ position_args *args = NULL;
+ int channels;
+ int retval = 1;
+
+ Mix_QuerySpec(NULL, &format, &channels);
+ f = get_position_effect_func(format, channels);
+ if (f == NULL)
+ return(0);
+
+ SDL_LockAudio();
+ args = get_position_arg(channel);
+ if (!args) {
+ SDL_UnlockAudio();
+ return(0);
+ }
+
+ distance = 255 - distance; /* flip it to our scale. */
+
+ /* it's a no-op; unregister the effect, if it's registered. */
+ if ((distance == 255) && (args->left_u8 == 255) && (args->right_u8 == 255)) {
+ if (args->in_use) {
+ retval = _Mix_UnregisterEffect_locked(channel, f);
+ SDL_UnlockAudio();
+ return(retval);
+ } else {
+ SDL_UnlockAudio();
+ return(1);
+ }
+ }
+
+ args->distance_u8 = distance;
+ args->distance_f = ((float) distance) / 255.0f;
+ if (!args->in_use) {
+ args->in_use = 1;
+ retval = _Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void *) args);
+ }
+
+ SDL_UnlockAudio();
+ return(retval);
+}
+
+
+int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance)
+{
+ Mix_EffectFunc_t f = NULL;
+ Uint16 format;
+ int channels;
+ position_args *args = NULL;
+ Sint16 room_angle = 0;
+ int retval = 1;
+
+ Mix_QuerySpec(NULL, &format, &channels);
+ f = get_position_effect_func(format, channels);
+ if (f == NULL)
+ return(0);
+
+ angle = SDL_abs(angle) % 360; /* make angle between 0 and 359. */
+
+ SDL_LockAudio();
+ args = get_position_arg(channel);
+ if (!args) {
+ SDL_UnlockAudio();
+ return(0);
+ }
+
+ /* it's a no-op; unregister the effect, if it's registered. */
+ if ((!distance) && (!angle)) {
+ if (args->in_use) {
+ retval = _Mix_UnregisterEffect_locked(channel, f);
+ SDL_UnlockAudio();
+ return(retval);
+ } else {
+ SDL_UnlockAudio();
+ return(1);
+ }
+ }
+
+ if (channels == 2)
+ {
+ if (angle > 180)
+ room_angle = 180; /* exchange left and right channels */
+ else room_angle = 0;
+ }
+
+ if (channels == 4 || channels == 6)
+ {
+ if (angle > 315) room_angle = 0;
+ else if (angle > 225) room_angle = 270;
+ else if (angle > 135) room_angle = 180;
+ else if (angle > 45) room_angle = 90;
+ else room_angle = 0;
+ }
+
+
+ distance = 255 - distance; /* flip it to scale Mix_SetDistance() uses. */
+
+ set_amplitudes(channels, angle, room_angle);
+
+ args->left_u8 = speaker_amplitude[0];
+ args->left_f = ((float) speaker_amplitude[0]) / 255.0f;
+ args->right_u8 = speaker_amplitude[1];
+ args->right_f = ((float) speaker_amplitude[1]) / 255.0f;
+ args->left_rear_u8 = speaker_amplitude[2];
+ args->left_rear_f = ((float) speaker_amplitude[2]) / 255.0f;
+ args->right_rear_u8 = speaker_amplitude[3];
+ args->right_rear_f = ((float) speaker_amplitude[3]) / 255.0f;
+ args->center_u8 = speaker_amplitude[4];
+ args->center_f = ((float) speaker_amplitude[4]) / 255.0f;
+ args->lfe_u8 = speaker_amplitude[5];
+ args->lfe_f = ((float) speaker_amplitude[5]) / 255.0f;
+ args->distance_u8 = distance;
+ args->distance_f = ((float) distance) / 255.0f;
+ args->room_angle = room_angle;
+ if (!args->in_use) {
+ args->in_use = 1;
+ retval = _Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void *) args);
+ }
+
+ SDL_UnlockAudio();
+ return(retval);
+}
+
+
+/* end of effects_position.c ... */
+
diff --git a/apps/plugins/sdl/SDL_mixer/effect_stereoreverse.c b/apps/plugins/sdl/SDL_mixer/effect_stereoreverse.c
new file mode 100644
index 0000000000..47a8bf67f1
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/effect_stereoreverse.c
@@ -0,0 +1,117 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This file by Ryan C. Gordon (icculus@icculus.org)
+
+ These are some internally supported special effects that use SDL_mixer's
+ effect callback API. They are meant for speed over quality. :)
+*/
+
+/* $Id$ */
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+#define __MIX_INTERNAL_EFFECT__
+#include "effects_internal.h"
+
+/* profile code:
+ #include <sys/time.h>
+ #include <unistd.h>
+ struct timeval tv1;
+ struct timeval tv2;
+
+ gettimeofday(&tv1, NULL);
+
+ ... do your thing here ...
+
+ gettimeofday(&tv2, NULL);
+ printf("%ld\n", tv2.tv_usec - tv1.tv_usec);
+*/
+
+
+
+/*
+ * Stereo reversal effect...this one's pretty straightforward...
+ */
+
+static void _Eff_reversestereo16(int chan, void *stream, int len, void *udata)
+{
+ /* 16 bits * 2 channels. */
+ Uint32 *ptr = (Uint32 *) stream;
+ int i;
+
+ for (i = 0; i < len; i += sizeof (Uint32), ptr++) {
+ *ptr = (((*ptr) & 0xFFFF0000) >> 16) | (((*ptr) & 0x0000FFFF) << 16);
+ }
+}
+
+
+static void _Eff_reversestereo8(int chan, void *stream, int len, void *udata)
+{
+ /* 8 bits * 2 channels. */
+ Uint32 *ptr = (Uint32 *) stream;
+ int i;
+
+ /* get the last two bytes if len is not divisible by four... */
+ if (len % sizeof (Uint32) != 0) {
+ Uint16 *p = (Uint16 *) (((Uint8 *) stream) + (len - 2));
+ *p = (Uint16)((((*p) & 0xFF00) >> 8) | (((*ptr) & 0x00FF) << 8));
+ len -= 2;
+ }
+
+ for (i = 0; i < len; i += sizeof (Uint32), ptr++) {
+ *ptr = (((*ptr) & 0x0000FF00) >> 8) | (((*ptr) & 0x000000FF) << 8) |
+ (((*ptr) & 0xFF000000) >> 8) | (((*ptr) & 0x00FF0000) << 8);
+ }
+}
+
+
+int Mix_SetReverseStereo(int channel, int flip)
+{
+ Mix_EffectFunc_t f = NULL;
+ int channels;
+ Uint16 format;
+
+ Mix_QuerySpec(NULL, &format, &channels);
+
+ if (channels == 2) {
+ if ((format & 0xFF) == 16)
+ f = _Eff_reversestereo16;
+ else if ((format & 0xFF) == 8)
+ f = _Eff_reversestereo8;
+ else {
+ Mix_SetError("Unsupported audio format");
+ return(0);
+ }
+
+ if (!flip) {
+ return(Mix_UnregisterEffect(channel, f));
+ } else {
+ return(Mix_RegisterEffect(channel, f, NULL, NULL));
+ }
+ }
+
+ return(1);
+}
+
+
+/* end of effect_stereoreverse.c ... */
+
diff --git a/apps/plugins/sdl/SDL_mixer/effects_internal.c b/apps/plugins/sdl/SDL_mixer/effects_internal.c
new file mode 100644
index 0000000000..353a15b91e
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/effects_internal.c
@@ -0,0 +1,121 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This file by Ryan C. Gordon (icculus@icculus.org)
+
+ These are some helper functions for the internal mixer special effects.
+*/
+
+/* $Id$ */
+
+
+ /* ------ These are used internally only. Don't touch. ------ */
+
+
+#include "SDL_mixer.h"
+
+#define __MIX_INTERNAL_EFFECT__
+#include "effects_internal.h"
+
+/* Should we favor speed over memory usage and/or quality of output? */
+int _Mix_effects_max_speed = 0;
+
+
+void _Mix_InitEffects(void)
+{
+ _Mix_effects_max_speed = (SDL_getenv(MIX_EFFECTSMAXSPEED) != NULL);
+}
+
+void _Mix_DeinitEffects(void)
+{
+ _Eff_PositionDeinit();
+}
+
+
+void *_Eff_volume_table = NULL;
+
+
+/* Build the volume table for Uint8-format samples.
+ *
+ * Each column of the table is a possible sample, while each row of the
+ * table is a volume. Volume is a Uint8, where 0 is silence and 255 is full
+ * volume. So _Eff_volume_table[128][mysample] would be the value of
+ * mysample, at half volume.
+ */
+void *_Eff_build_volume_table_u8(void)
+{
+ int volume;
+ int sample;
+ Uint8 *rc;
+
+ if (!_Mix_effects_max_speed) {
+ return(NULL);
+ }
+
+ if (!_Eff_volume_table) {
+ rc = SDL_malloc(256 * 256);
+ if (rc) {
+ _Eff_volume_table = (void *) rc;
+ for (volume = 0; volume < 256; volume++) {
+ for (sample = -128; sample < 128; sample ++) {
+ *rc = (Uint8)(((float) sample) * ((float) volume / 255.0))
+ + 128;
+ rc++;
+ }
+ }
+ }
+ }
+
+ return(_Eff_volume_table);
+}
+
+
+/* Build the volume table for Sint8-format samples.
+ *
+ * Each column of the table is a possible sample, while each row of the
+ * table is a volume. Volume is a Uint8, where 0 is silence and 255 is full
+ * volume. So _Eff_volume_table[128][mysample+128] would be the value of
+ * mysample, at half volume.
+ */
+void *_Eff_build_volume_table_s8(void)
+{
+ int volume;
+ int sample;
+ Sint8 *rc;
+
+ if (!_Eff_volume_table) {
+ rc = SDL_malloc(256 * 256);
+ if (rc) {
+ _Eff_volume_table = (void *) rc;
+ for (volume = 0; volume < 256; volume++) {
+ for (sample = -128; sample < 128; sample ++) {
+ *rc = (Sint8)(((float) sample) * ((float) volume / 255.0));
+ rc++;
+ }
+ }
+ }
+ }
+
+ return(_Eff_volume_table);
+}
+
+
+/* end of effects.c ... */
+
diff --git a/apps/plugins/sdl/SDL_mixer/effects_internal.h b/apps/plugins/sdl/SDL_mixer/effects_internal.h
new file mode 100644
index 0000000000..12b4b3b2da
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/effects_internal.h
@@ -0,0 +1,60 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#ifndef _INCLUDE_EFFECTS_INTERNAL_H_
+#define _INCLUDE_EFFECTS_INTERNAL_H_
+
+#ifndef __MIX_INTERNAL_EFFECT__
+#error You should not include this file or use these functions.
+#endif
+
+#include "SDL_mixer.h"
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int _Mix_effects_max_speed;
+extern void *_Eff_volume_table;
+void *_Eff_build_volume_table_u8(void);
+void *_Eff_build_volume_table_s8(void);
+
+void _Mix_InitEffects(void);
+void _Mix_DeinitEffects(void);
+void _Eff_PositionDeinit(void);
+
+int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
+ Mix_EffectDone_t d, void *arg);
+int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f);
+int _Mix_UnregisterAllEffects_locked(int channel);
+
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/apps/plugins/sdl/SDL_mixer/fluidsynth.c b/apps/plugins/sdl/SDL_mixer/fluidsynth.c
new file mode 100644
index 0000000000..d680576542
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/fluidsynth.c
@@ -0,0 +1,219 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ James Le Cuirot
+ chewi@aura-online.co.uk
+*/
+
+#ifdef USE_FLUIDSYNTH_MIDI
+
+#include "SDL_mixer.h"
+#include "fluidsynth.h"
+
+static Uint16 format;
+static Uint8 channels;
+static int freq;
+
+int fluidsynth_check_soundfont(const char *path, void *data)
+{
+ FILE *file = fopen(path, "r");
+
+ if (file) {
+ fclose(file);
+ return 1;
+ } else {
+ Mix_SetError("Failed to access the SoundFont %s", path);
+ return 0;
+ }
+}
+
+int fluidsynth_load_soundfont(const char *path, void *data)
+{
+ /* If this fails, it's too late to try Timidity so pray that at least one works. */
+ fluidsynth.fluid_synth_sfload((fluid_synth_t*) data, path, 1);
+ return 1;
+}
+
+int fluidsynth_init(SDL_AudioSpec *mixer)
+{
+ if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL))
+ return -1;
+
+ format = mixer->format;
+ channels = mixer->channels;
+ freq = mixer->freq;
+
+ return 0;
+}
+
+static FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
+{
+ FluidSynthMidiSong *song;
+ fluid_settings_t *settings = NULL;
+
+ if (!Mix_Init(MIX_INIT_FLUIDSYNTH)) {
+ return NULL;
+ }
+
+ if ((song = SDL_malloc(sizeof(FluidSynthMidiSong)))) {
+ memset(song, 0, sizeof(FluidSynthMidiSong));
+
+ if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
+ if ((settings = fluidsynth.new_fluid_settings())) {
+ fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
+
+ if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
+ if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
+ if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
+ if (function(song, data)) return song;
+ fluidsynth.delete_fluid_player(song->player);
+ } else {
+ Mix_SetError("Failed to create FluidSynth player");
+ }
+ }
+ fluidsynth.delete_fluid_synth(song->synth);
+ } else {
+ Mix_SetError("Failed to create FluidSynth synthesizer");
+ }
+ fluidsynth.delete_fluid_settings(settings);
+ } else {
+ Mix_SetError("Failed to create FluidSynth settings");
+ }
+ } else {
+ Mix_SetError("Failed to set up audio conversion");
+ }
+ SDL_free(song);
+ } else {
+ Mix_SetError("Insufficient memory for song");
+ }
+ return NULL;
+}
+
+static int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
+{
+ off_t offset;
+ size_t size;
+ char *buffer;
+ SDL_RWops *rw = (SDL_RWops*) data;
+
+ offset = SDL_RWtell(rw);
+ SDL_RWseek(rw, 0, RW_SEEK_END);
+ size = SDL_RWtell(rw) - offset;
+ SDL_RWseek(rw, offset, RW_SEEK_SET);
+
+ if ((buffer = (char*) SDL_malloc(size))) {
+ if(SDL_RWread(rw, buffer, size, 1) == 1) {
+ if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
+ return 1;
+ } else {
+ Mix_SetError("FluidSynth failed to load in-memory song");
+ }
+ } else {
+ Mix_SetError("Failed to read in-memory song");
+ }
+ SDL_free(buffer);
+ } else {
+ Mix_SetError("Insufficient memory for song");
+ }
+ return 0;
+}
+
+FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw)
+{
+ FluidSynthMidiSong *song;
+
+ song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return song;
+}
+
+void fluidsynth_freesong(FluidSynthMidiSong *song)
+{
+ if (!song) return;
+ fluidsynth.delete_fluid_player(song->player);
+ fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
+ fluidsynth.delete_fluid_synth(song->synth);
+ SDL_free(song);
+}
+
+void fluidsynth_start(FluidSynthMidiSong *song)
+{
+ fluidsynth.fluid_player_set_loop(song->player, 1);
+ fluidsynth.fluid_player_play(song->player);
+}
+
+void fluidsynth_stop(FluidSynthMidiSong *song)
+{
+ fluidsynth.fluid_player_stop(song->player);
+}
+
+int fluidsynth_active(FluidSynthMidiSong *song)
+{
+ return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? 1 : 0;
+}
+
+void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume)
+{
+ /* FluidSynth's default is 0.2. Make 0.8 the maximum. */
+ fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 0.00625));
+}
+
+int fluidsynth_playsome(FluidSynthMidiSong *song, void *dest, int dest_len)
+{
+ int result = -1;
+ int frames = dest_len / channels / ((format & 0xFF) / 8);
+ int src_len = frames * 4; /* 16-bit stereo */
+ void *src = dest;
+
+ if (dest_len < src_len) {
+ if (!(src = SDL_malloc(src_len))) {
+ Mix_SetError("Insufficient memory for audio conversion");
+ return result;
+ }
+ }
+
+ if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
+ Mix_SetError("Error generating FluidSynth audio");
+ goto finish;
+ }
+
+ song->convert.buf = src;
+ song->convert.len = src_len;
+
+ if (SDL_ConvertAudio(&song->convert) < 0) {
+ Mix_SetError("Error during audio conversion");
+ goto finish;
+ }
+
+ if (src != dest)
+ memcpy(dest, src, dest_len);
+
+ result = 0;
+
+finish:
+ if (src != dest)
+ SDL_free(src);
+
+ return result;
+}
+
+#endif /* USE_FLUIDSYNTH_MIDI */
diff --git a/apps/plugins/sdl/SDL_mixer/fluidsynth.h b/apps/plugins/sdl/SDL_mixer/fluidsynth.h
new file mode 100644
index 0000000000..47538bbc2b
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/fluidsynth.h
@@ -0,0 +1,51 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ James Le Cuirot
+ chewi@aura-online.co.uk
+*/
+
+#ifndef _FLUIDSYNTH_H_
+#define _FLUIDSYNTH_H_
+
+#ifdef USE_FLUIDSYNTH_MIDI
+
+#include "dynamic_fluidsynth.h"
+#include <SDL_rwops.h>
+#include <SDL_audio.h>
+
+typedef struct {
+ SDL_AudioCVT convert;
+ fluid_synth_t *synth;
+ fluid_player_t* player;
+} FluidSynthMidiSong;
+
+int fluidsynth_init(SDL_AudioSpec *mixer);
+FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw);
+void fluidsynth_freesong(FluidSynthMidiSong *song);
+void fluidsynth_start(FluidSynthMidiSong *song);
+void fluidsynth_stop(FluidSynthMidiSong *song);
+int fluidsynth_active(FluidSynthMidiSong *song);
+void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume);
+int fluidsynth_playsome(FluidSynthMidiSong *song, void *stream, int len);
+
+#endif /* USE_FLUIDSYNTH_MIDI */
+
+#endif /* _FLUIDSYNTH_H_ */
diff --git a/apps/plugins/sdl/SDL_mixer/load_aiff.c b/apps/plugins/sdl/SDL_mixer/load_aiff.c
new file mode 100644
index 0000000000..ac71e425ff
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_aiff.c
@@ -0,0 +1,247 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode an AIFF file into a waveform.
+ It's pretty straightforward once you get going. The only
+ externally-callable function is Mix_LoadAIFF_RW(), which is meant to
+ act as identically to SDL_LoadWAV_RW() as possible.
+
+ This file by Torbjörn Andersson (torbjorn.andersson@eurotime.se)
+ 8SVX file support added by Marc Le Douarain (mavati@club-internet.fr)
+ in december 2002.
+*/
+
+/* $Id$ */
+
+#include "SDL_endian.h"
+#include "SDL_mixer.h"
+#include "load_aiff.h"
+
+/*********************************************/
+/* Define values for AIFF (IFF audio) format */
+/*********************************************/
+#define FORM 0x4d524f46 /* "FORM" */
+
+#define AIFF 0x46464941 /* "AIFF" */
+#define SSND 0x444e5353 /* "SSND" */
+#define COMM 0x4d4d4f43 /* "COMM" */
+
+#define _8SVX 0x58565338 /* "8SVX" */
+#define VHDR 0x52444856 /* "VHDR" */
+#define BODY 0x59444F42 /* "BODY" */
+
+/* This function was taken from libsndfile. I don't pretend to fully
+ * understand it.
+ */
+
+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]);
+}
+
+/* This function is based on SDL_LoadWAV_RW(). */
+
+SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+ int was_error;
+ int found_SSND;
+ int found_COMM;
+ int found_VHDR;
+ int found_BODY;
+ long start = 0;
+
+ Uint32 chunk_type;
+ Uint32 chunk_length;
+ long next_chunk;
+
+ /* AIFF magic header */
+ Uint32 FORMchunk;
+ Uint32 AIFFmagic;
+
+ /* SSND chunk */
+ Uint32 offset;
+ Uint32 blocksize;
+
+ /* COMM format chunk */
+ Uint16 channels = 0;
+ Uint32 numsamples = 0;
+ Uint16 samplesize = 0;
+ Uint8 sane_freq[10];
+ Uint32 frequency = 0;
+
+ /* Make sure we are passed a valid data source */
+ was_error = 0;
+ if ( src == NULL ) {
+ was_error = 1;
+ goto done;
+ }
+
+ FORMchunk = SDL_ReadLE32(src);
+ chunk_length = SDL_ReadBE32(src);
+ if ( chunk_length == AIFF ) { /* The FORMchunk has already been read */
+ AIFFmagic = chunk_length;
+ chunk_length = FORMchunk;
+ FORMchunk = FORM;
+ } else {
+ AIFFmagic = SDL_ReadLE32(src);
+ }
+ if ( (FORMchunk != FORM) || ( (AIFFmagic != AIFF) && (AIFFmagic != _8SVX) ) ) {
+ SDL_SetError("Unrecognized file type (not AIFF nor 8SVX)");
+ was_error = 1;
+ goto done;
+ }
+
+ /* TODO: Better santity-checking. */
+
+ found_SSND = 0;
+ found_COMM = 0;
+ found_VHDR = 0;
+ found_BODY = 0;
+
+ do {
+ chunk_type = SDL_ReadLE32(src);
+ chunk_length = SDL_ReadBE32(src);
+ next_chunk = SDL_RWtell(src) + chunk_length;
+ /* Paranoia to avoid infinite loops */
+ if (chunk_length == 0)
+ break;
+
+ switch (chunk_type) {
+ case SSND:
+ found_SSND = 1;
+ offset = SDL_ReadBE32(src);
+ blocksize = SDL_ReadBE32(src);
+ start = SDL_RWtell(src) + offset;
+ break;
+
+ case COMM:
+ found_COMM = 1;
+ channels = SDL_ReadBE16(src);
+ numsamples = SDL_ReadBE32(src);
+ samplesize = SDL_ReadBE16(src);
+ SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
+ frequency = SANE_to_Uint32(sane_freq);
+ if (frequency == 0) {
+ SDL_SetError("Bad AIFF sample frequency");
+ was_error = 1;
+ goto done;
+ }
+ break;
+
+ case VHDR:
+ found_VHDR = 1;
+ SDL_ReadBE32(src);
+ SDL_ReadBE32(src);
+ SDL_ReadBE32(src);
+ frequency = SDL_ReadBE16(src);
+ channels = 1;
+ samplesize = 8;
+ break;
+
+ case BODY:
+ found_BODY = 1;
+ numsamples = chunk_length;
+ start = SDL_RWtell(src);
+ break;
+
+ default:
+ break;
+ }
+ /* a 0 pad byte can be stored for any odd-length chunk */
+ if (chunk_length&1)
+ next_chunk++;
+ } while ( ( ( (AIFFmagic == AIFF) && ( !found_SSND || !found_COMM ) )
+ || ( (AIFFmagic == _8SVX ) && ( !found_VHDR || !found_BODY ) ) )
+ && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != 1 );
+
+ if ( (AIFFmagic == AIFF) && !found_SSND ) {
+ SDL_SetError("Bad AIFF (no SSND chunk)");
+ was_error = 1;
+ goto done;
+ }
+
+ if ( (AIFFmagic == AIFF) && !found_COMM ) {
+ SDL_SetError("Bad AIFF (no COMM chunk)");
+ was_error = 1;
+ goto done;
+ }
+
+ if ( (AIFFmagic == _8SVX) && !found_VHDR ) {
+ SDL_SetError("Bad 8SVX (no VHDR chunk)");
+ was_error = 1;
+ goto done;
+ }
+
+ if ( (AIFFmagic == _8SVX) && !found_BODY ) {
+ SDL_SetError("Bad 8SVX (no BODY chunk)");
+ was_error = 1;
+ goto done;
+ }
+
+ /* Decode the audio data format */
+ memset(spec, 0, sizeof(*spec));
+ spec->freq = frequency;
+ switch (samplesize) {
+ case 8:
+ spec->format = AUDIO_S8;
+ break;
+ case 16:
+ spec->format = AUDIO_S16MSB;
+ break;
+ default:
+ SDL_SetError("Unsupported AIFF samplesize");
+ was_error = 1;
+ goto done;
+ }
+ spec->channels = (Uint8) channels;
+ spec->samples = 4096; /* Good default buffer size */
+
+ *audio_len = channels * numsamples * (samplesize / 8);
+ *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
+ if ( *audio_buf == NULL ) {
+ SDL_SetError("Out of memory");
+ return(NULL);
+ }
+ SDL_RWseek(src, start, RW_SEEK_SET);
+ if ( SDL_RWread(src, *audio_buf, *audio_len, 1) != 1 ) {
+ SDL_SetError("Unable to read audio data");
+ return(NULL);
+ }
+
+ /* Don't return a buffer that isn't a multiple of samplesize */
+ *audio_len &= ~((samplesize / 8) - 1);
+
+done:
+ if ( freesrc && src ) {
+ SDL_RWclose(src);
+ }
+ if ( was_error ) {
+ spec = NULL;
+ }
+ return(spec);
+}
+
diff --git a/apps/plugins/sdl/SDL_mixer/load_aiff.h b/apps/plugins/sdl/SDL_mixer/load_aiff.h
new file mode 100644
index 0000000000..ed55d36440
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_aiff.h
@@ -0,0 +1,31 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2009 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
+
+ This is the source needed to decode an AIFF file into a waveform.
+ It's pretty straightforward once you get going. The only
+ externally-callable function is Mix_LoadAIFF_RW(), which is meant to
+ act as identically to SDL_LoadWAV_RW() as possible.
+
+ This file by Torbjörn Andersson (torbjorn.andersson@eurotime.se)
+*/
+
+/* $Id$ */
+
+/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
diff --git a/apps/plugins/sdl/SDL_mixer/load_flac.c b/apps/plugins/sdl/SDL_mixer/load_flac.c
new file mode 100644
index 0000000000..151de63f6f
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_flac.c
@@ -0,0 +1,338 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode a FLAC into a waveform.
+ ~ Austen Dicken (admin@cvpcs.org).
+*/
+
+#ifdef FLAC_MUSIC
+
+#include "SDL_mutex.h"
+#include "SDL_endian.h"
+#include "SDL_timer.h"
+
+#include "SDL_mixer.h"
+#include "dynamic_flac.h"
+#include "load_flac.h"
+
+#include <FLAC/stream_decoder.h>
+
+typedef struct {
+ SDL_RWops* sdl_src;
+ SDL_AudioSpec* sdl_spec;
+ Uint8** sdl_audio_buf;
+ Uint32* sdl_audio_len;
+ int sdl_audio_read;
+ FLAC__uint64 flac_total_samples;
+ unsigned flac_bps;
+} FLAC_SDL_Data;
+
+static FLAC__StreamDecoderReadStatus flac_read_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__byte buffer[],
+ size_t *bytes,
+ void *client_data)
+{
+ // make sure there is something to be reading
+ if (*bytes > 0) {
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+
+ *bytes = SDL_RWread (data->sdl_src, buffer, sizeof (FLAC__byte),
+ *bytes);
+
+ if(*bytes < 0) { // error in read
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+ else if(*bytes == 0) { // no data was read (EOF)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+ else { // data was read, continue
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ }
+ else {
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+}
+
+static FLAC__StreamDecoderSeekStatus flac_seek_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__uint64 absolute_byte_offset,
+ void *client_data)
+{
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+
+ if (SDL_RWseek (data->sdl_src, absolute_byte_offset, RW_SEEK_SET) < 0) {
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+ else {
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ }
+}
+
+static FLAC__StreamDecoderTellStatus flac_tell_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__uint64 *absolute_byte_offset,
+ void *client_data)
+{
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+
+ int pos = SDL_RWtell (data->sdl_src);
+
+ if (pos < 0) {
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+ else {
+ *absolute_byte_offset = (FLAC__uint64)pos;
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+}
+
+static FLAC__StreamDecoderLengthStatus flac_length_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__uint64 *stream_length,
+ void *client_data)
+{
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+
+ int pos = SDL_RWtell (data->sdl_src);
+ int length = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
+
+ if (SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET) != pos || length < 0) {
+ /* there was an error attempting to return the stream to the original
+ * position, or the length was invalid. */
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ }
+ else {
+ *stream_length = (FLAC__uint64)length;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ }
+}
+
+static FLAC__bool flac_eof_load_cb(const FLAC__StreamDecoder *decoder,
+ void *client_data)
+{
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+
+ int pos = SDL_RWtell (data->sdl_src);
+ int end = SDL_RWseek (data->sdl_src, 0, RW_SEEK_END);
+
+ // was the original position equal to the end (a.k.a. the seek didn't move)?
+ if (pos == end) {
+ // must be EOF
+ return true;
+ }
+ else {
+ // not EOF, return to the original position
+ SDL_RWseek (data->sdl_src, pos, RW_SEEK_SET);
+
+ return false;
+ }
+}
+
+static FLAC__StreamDecoderWriteStatus flac_write_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 *const buffer[],
+ void *client_data)
+{
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+ size_t i;
+ Uint8 *buf;
+
+ if (data->flac_total_samples == 0) {
+ SDL_SetError ("Given FLAC file does not specify its sample count.");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if (data->sdl_spec->channels != 2 || data->flac_bps != 16) {
+ SDL_SetError ("Current FLAC support is only for 16 bit Stereo files.");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ // check if it is the first audio frame so we can initialize the output
+ // buffer
+ if (frame->header.number.sample_number == 0) {
+ *(data->sdl_audio_len) = data->sdl_spec->size;
+ data->sdl_audio_read = 0;
+ *(data->sdl_audio_buf) = SDL_malloc (*(data->sdl_audio_len));
+
+ if (*(data->sdl_audio_buf) == NULL) {
+ SDL_SetError
+ ("Unable to allocate memory to store the FLAC stream.");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ }
+
+ buf = *(data->sdl_audio_buf);
+
+ for (i = 0; i < frame->header.blocksize; i++) {
+ FLAC__int16 i16;
+ FLAC__uint16 ui16;
+
+ i16 = (FLAC__int16)buffer[0][i];
+ ui16 = (FLAC__uint16)i16;
+
+ *(buf + (data->sdl_audio_read++)) = (char)(ui16);
+ *(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
+
+ i16 = (FLAC__int16)buffer[1][i];
+ ui16 = (FLAC__uint16)i16;
+
+ *(buf + (data->sdl_audio_read++)) = (char)(ui16);
+ *(buf + (data->sdl_audio_read++)) = (char)(ui16 >> 8);
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void flac_metadata_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data)
+{
+ FLAC_SDL_Data *data = (FLAC_SDL_Data *)client_data;
+ FLAC__uint64 total_samples;
+ unsigned bps;
+
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ // save the metadata right now for use later on
+ *(data->sdl_audio_buf) = NULL;
+ *(data->sdl_audio_len) = 0;
+ memset (data->sdl_spec, '\0', sizeof (SDL_AudioSpec));
+
+ data->sdl_spec->format = AUDIO_S16;
+ data->sdl_spec->freq = (int)(metadata->data.stream_info.sample_rate);
+ data->sdl_spec->channels = (Uint8)(metadata->data.stream_info.channels);
+ data->sdl_spec->samples = 8192; /* buffer size */
+
+ total_samples = metadata->data.stream_info.total_samples;
+ bps = metadata->data.stream_info.bits_per_sample;
+
+ data->sdl_spec->size = total_samples * data->sdl_spec->channels *
+ (bps / 8);
+ data->flac_total_samples = total_samples;
+ data->flac_bps = bps;
+ }
+}
+
+static void flac_error_load_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data)
+{
+ // print an SDL error based on the error status
+ switch (status) {
+ case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+ SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+ SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+ SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
+ SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
+ break;
+ default:
+ SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
+ break;
+ }
+}
+
+/* don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+ FLAC__StreamDecoder *decoder = 0;
+ FLAC__StreamDecoderInitStatus init_status;
+ int was_error = 1;
+ int was_init = 0;
+ Uint32 samplesize;
+
+ // create the client data passing information
+ FLAC_SDL_Data* client_data;
+ client_data = (FLAC_SDL_Data *)SDL_malloc (sizeof (FLAC_SDL_Data));
+
+ if ((!src) || (!audio_buf) || (!audio_len)) /* sanity checks. */
+ goto done;
+
+ if (!Mix_Init(MIX_INIT_FLAC))
+ goto done;
+
+ if ((decoder = flac.FLAC__stream_decoder_new ()) == NULL) {
+ SDL_SetError ("Unable to allocate FLAC decoder.");
+ goto done;
+ }
+
+ init_status = flac.FLAC__stream_decoder_init_stream (decoder,
+ flac_read_load_cb, flac_seek_load_cb,
+ flac_tell_load_cb, flac_length_load_cb,
+ flac_eof_load_cb, flac_write_load_cb,
+ flac_metadata_load_cb, flac_error_load_cb,
+ client_data);
+
+ if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ SDL_SetError ("Unable to initialize FLAC stream decoder.");
+ goto done;
+ }
+
+ was_init = 1;
+
+ client_data->sdl_src = src;
+ client_data->sdl_spec = spec;
+ client_data->sdl_audio_buf = audio_buf;
+ client_data->sdl_audio_len = audio_len;
+
+ if (!flac.FLAC__stream_decoder_process_until_end_of_stream (decoder)) {
+ SDL_SetError ("Unable to process FLAC file.");
+ goto done;
+ }
+
+ was_error = 0;
+
+ /* Don't return a buffer that isn't a multiple of samplesize */
+ samplesize = ((spec->format & 0xFF) / 8) * spec->channels;
+ *audio_len &= ~(samplesize - 1);
+
+done:
+ if (was_init && decoder) {
+ flac.FLAC__stream_decoder_finish (decoder);
+ }
+
+ if (decoder) {
+ flac.FLAC__stream_decoder_delete (decoder);
+ }
+
+ if (src) {
+ if (freesrc)
+ SDL_RWclose (src);
+ else
+ SDL_RWseek (src, 0, RW_SEEK_SET);
+ }
+
+ if (was_error)
+ spec = NULL;
+
+ return spec;
+}
+
+#endif // FLAC_MUSIC
diff --git a/apps/plugins/sdl/SDL_mixer/load_flac.h b/apps/plugins/sdl/SDL_mixer/load_flac.h
new file mode 100644
index 0000000000..63fcd4bcd0
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_flac.h
@@ -0,0 +1,31 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode a FLAC into a waveform.
+ ~ Austen Dicken (admin@cvpcs.org).
+*/
+
+/* $Id: $ */
+
+#ifdef FLAC_MUSIC
+/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/load_ogg.c b/apps/plugins/sdl/SDL_mixer/load_ogg.c
new file mode 100644
index 0000000000..829bbdbe8b
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_ogg.c
@@ -0,0 +1,159 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode an Ogg Vorbis into a waveform.
+ This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
+*/
+
+/* $Id$ */
+
+#ifdef OGG_MUSIC
+
+#include "SDL_mutex.h"
+#include "SDL_endian.h"
+#include "SDL_timer.h"
+
+#include "SDL_mixer.h"
+#include "dynamic_ogg.h"
+#include "load_ogg.h"
+
+static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+ return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
+}
+
+static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
+{
+ return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
+}
+
+static int sdl_close_func_freesrc(void *datasource)
+{
+ return SDL_RWclose((SDL_RWops*)datasource);
+}
+
+static int sdl_close_func_nofreesrc(void *datasource)
+{
+ return SDL_RWseek((SDL_RWops*)datasource, 0, RW_SEEK_SET);
+}
+
+static long sdl_tell_func(void *datasource)
+{
+ return SDL_RWtell((SDL_RWops*)datasource);
+}
+
+
+/* don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+ OggVorbis_File vf;
+ ov_callbacks callbacks;
+ vorbis_info *info;
+ Uint8 *buf;
+ int bitstream = -1;
+ long samplesize;
+ long samples;
+ int read, to_read;
+ int must_close = 1;
+ int was_error = 1;
+
+ if ( (!src) || (!audio_buf) || (!audio_len) ) /* sanity checks. */
+ goto done;
+
+ if ( !Mix_Init(MIX_INIT_OGG) )
+ goto done;
+
+ callbacks.read_func = sdl_read_func;
+ callbacks.seek_func = sdl_seek_func;
+ callbacks.tell_func = sdl_tell_func;
+ callbacks.close_func = freesrc ?
+ sdl_close_func_freesrc : sdl_close_func_nofreesrc;
+
+ if (vorbis.ov_open_callbacks(src, &vf, NULL, 0, callbacks) != 0)
+ {
+ SDL_SetError("OGG bitstream is not valid Vorbis stream!");
+ goto done;
+ }
+
+ must_close = 0;
+
+ info = vorbis.ov_info(&vf, -1);
+
+ *audio_buf = NULL;
+ *audio_len = 0;
+ memset(spec, '\0', sizeof (SDL_AudioSpec));
+
+ spec->format = AUDIO_S16;
+ spec->channels = info->channels;
+ spec->freq = info->rate;
+ spec->samples = 4096; /* buffer size */
+
+ samples = (long)vorbis.ov_pcm_total(&vf, -1);
+
+ *audio_len = spec->size = samples * spec->channels * 2;
+ *audio_buf = SDL_malloc(*audio_len);
+ if (*audio_buf == NULL)
+ goto done;
+
+ buf = *audio_buf;
+ to_read = *audio_len;
+#ifdef OGG_USE_TREMOR
+ for (read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream);
+ read > 0;
+ read = vorbis.ov_read(&vf, (char *)buf, to_read, &bitstream))
+#else
+ for (read = vorbis.ov_read(&vf, (char *)buf, to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &bitstream);
+ read > 0;
+ read = vorbis.ov_read(&vf, (char *)buf, to_read, 0, 2, 1, &bitstream))
+#endif
+ {
+ if (read == OV_HOLE || read == OV_EBADLINK)
+ break; /* error */
+
+ to_read -= read;
+ buf += read;
+ }
+
+ vorbis.ov_clear(&vf);
+ was_error = 0;
+
+ /* Don't return a buffer that isn't a multiple of samplesize */
+ samplesize = ((spec->format & 0xFF)/8)*spec->channels;
+ *audio_len &= ~(samplesize-1);
+
+done:
+ if (src && must_close)
+ {
+ if (freesrc)
+ SDL_RWclose(src);
+ else
+ SDL_RWseek(src, 0, RW_SEEK_SET);
+ }
+
+ if ( was_error )
+ spec = NULL;
+
+ return(spec);
+} /* Mix_LoadOGG_RW */
+
+/* end of load_ogg.c ... */
+
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/load_ogg.h b/apps/plugins/sdl/SDL_mixer/load_ogg.h
new file mode 100644
index 0000000000..e63b04f7b3
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_ogg.h
@@ -0,0 +1,31 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode an Ogg Vorbis into a waveform.
+ This file by Vaclav Slavik (vaclav.slavik@matfyz.cz).
+*/
+
+/* $Id$ */
+
+#ifdef OGG_MUSIC
+/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/load_voc.c b/apps/plugins/sdl/SDL_mixer/load_voc.c
new file mode 100644
index 0000000000..2e7798e222
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_voc.c
@@ -0,0 +1,458 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode a Creative Labs VOC file into a
+ waveform. It's pretty straightforward once you get going. The only
+ externally-callable function is Mix_LoadVOC_RW(), which is meant to
+ act as identically to SDL_LoadWAV_RW() as possible.
+
+ This file by Ryan C. Gordon (icculus@icculus.org).
+
+ Heavily borrowed from sox v12.17.1's voc.c.
+ (http://www.freshmeat.net/projects/sox/)
+*/
+
+/* $Id$ */
+
+#include "SDL_mutex.h"
+#include "SDL_endian.h"
+#include "SDL_timer.h"
+
+#include "SDL_mixer.h"
+#include "load_voc.h"
+
+/* 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 has_extended; /* Has an extended block been read? */
+} 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_check_header(SDL_RWops *src)
+{
+ /* VOC magic header */
+ Uint8 signature[20]; /* "Creative Voice File\032" */
+ Uint16 datablockofs;
+
+ SDL_RWseek(src, 0, RW_SEEK_SET);
+
+ if (SDL_RWread(src, signature, sizeof (signature), 1) != 1)
+ return(0);
+
+ if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0) {
+ SDL_SetError("Unrecognized file type (not VOC)");
+ return(0);
+ }
+
+ /* get the offset where the first datablock is located */
+ if (SDL_RWread(src, &datablockofs, sizeof (Uint16), 1) != 1)
+ return(0);
+
+ datablockofs = SDL_SwapLE16(datablockofs);
+
+ if (SDL_RWseek(src, datablockofs, RW_SEEK_SET) != datablockofs)
+ return(0);
+
+ return(1); /* success! */
+} /* voc_check_header */
+
+
+/* Read next block header, save info, leave position at start of data */
+static int voc_get_block(SDL_RWops *src, vs_t *v, SDL_AudioSpec *spec)
+{
+ Uint8 bits24[3];
+ Uint8 uc, block;
+ Uint32 sblen;
+ Uint16 new_rate_short;
+ Uint32 new_rate_long;
+ Uint8 trash[6];
+ Uint16 period;
+ unsigned 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 (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
+ return 0;
+
+ /* When DATA block preceeded by an EXTENDED */
+ /* block, the DATA blocks rate value is invalid */
+ if (!v->has_extended)
+ {
+ if (uc == 0)
+ {
+ SDL_SetError("VOC Sample rate is zero?");
+ return 0;
+ }
+
+ if ((v->rate != -1) && (uc != v->rate))
+ {
+ SDL_SetError("VOC sample rate codes differ");
+ return 0;
+ }
+
+ v->rate = uc;
+ spec->freq = (Uint16)(1000000.0/(256 - v->rate));
+ v->channels = 1;
+ }
+
+ if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
+ return 0;
+
+ if (uc != 0)
+ {
+ SDL_SetError("VOC decoder only interprets 8-bit data");
+ return 0;
+ }
+
+ v->has_extended = 0;
+ v->rest = sblen - 2;
+ v->size = ST_SIZE_BYTE;
+ return 1;
+
+ case VOC_DATA_16:
+ if (SDL_RWread(src, &new_rate_long, sizeof (new_rate_long), 1) != 1)
+ return 0;
+ new_rate_long = SDL_SwapLE32(new_rate_long);
+ if (new_rate_long == 0)
+ {
+ SDL_SetError("VOC Sample rate is zero?");
+ return 0;
+ }
+ if ((v->rate != -1) && (new_rate_long != v->rate))
+ {
+ SDL_SetError("VOC sample rate codes differ");
+ return 0;
+ }
+ v->rate = new_rate_long;
+ spec->freq = new_rate_long;
+
+ if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
+ return 0;
+
+ switch (uc)
+ {
+ case 8: v->size = ST_SIZE_BYTE; break;
+ case 16: v->size = ST_SIZE_WORD; break;
+ default:
+ SDL_SetError("VOC with unknown data size");
+ return 0;
+ }
+
+ if (SDL_RWread(src, &v->channels, sizeof (Uint8), 1) != 1)
+ return 0;
+
+ if (SDL_RWread(src, trash, sizeof (Uint8), 6) != 6)
+ return 0;
+
+ v->rest = sblen - 12;
+ return 1;
+
+ case VOC_CONT:
+ v->rest = sblen;
+ return 1;
+
+ case VOC_SILENCE:
+ if (SDL_RWread(src, &period, sizeof (period), 1) != 1)
+ return 0;
+ period = SDL_SwapLE16(period);
+
+ if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
+ return 0;
+ if (uc == 0)
+ {
+ SDL_SetError("VOC silence sample rate is zero");
+ return 0;
+ }
+
+ /*
+ * Some silence-packed files have gratuitously
+ * different sample rate codes in silence.
+ * Adjust period.
+ */
+ if ((v->rate != -1) && (uc != v->rate))
+ period = (Uint16)((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 (SDL_RWread(src, trash, sizeof (Uint8), 1) != 1)
+ return 0;
+ }
+ 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->has_extended = 1;
+ if (SDL_RWread(src, &new_rate_short, sizeof (new_rate_short), 1) != 1)
+ return 0;
+ new_rate_short = SDL_SwapLE16(new_rate_short);
+ if (new_rate_short == 0)
+ {
+ SDL_SetError("VOC sample rate is zero");
+ return 0;
+ }
+ if ((v->rate != -1) && (new_rate_short != v->rate))
+ {
+ SDL_SetError("VOC sample rate codes differ");
+ return 0;
+ }
+ v->rate = new_rate_short;
+
+ if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
+ return 0;
+
+ if (uc != 0)
+ {
+ SDL_SetError("VOC decoder only interprets 8-bit data");
+ return 0;
+ }
+
+ if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1)
+ return 0;
+
+ if (uc)
+ spec->channels = 2; /* Stereo */
+ /* Needed number of channels before finishing
+ compute for rate */
+ spec->freq = (256000000L/(65536L - v->rate))/spec->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 (SDL_RWread(src, trash, sizeof (Uint8), 2) != 2)
+ return 0;
+
+ /* Falling! Falling! */
+
+ default: /* text block or other krapola. */
+ for(i = 0; i < sblen; i++)
+ {
+ if (SDL_RWread(src, &trash, sizeof (Uint8), 1) != 1)
+ return 0;
+ }
+
+ if (block == VOC_TEXT)
+ continue; /* get next block */
+ }
+ }
+
+ return 1;
+}
+
+
+static int voc_read(SDL_RWops *src, vs_t *v, Uint8 *buf, SDL_AudioSpec *spec)
+{
+ int done = 0;
+ Uint8 silence = 0x80;
+
+ if (v->rest == 0)
+ {
+ if (!voc_get_block(src, v, spec))
+ return 0;
+ }
+
+ if (v->rest == 0)
+ return 0;
+
+ if (v->silent)
+ {
+ if (v->size == ST_SIZE_WORD)
+ silence = 0x00;
+
+ /* Fill in silence */
+ memset(buf, silence, v->rest);
+ done = v->rest;
+ v->rest = 0;
+ }
+
+ else
+ {
+ done = SDL_RWread(src, buf, 1, v->rest);
+ v->rest -= done;
+ if (v->size == ST_SIZE_WORD)
+ {
+ #if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+ Uint16 *samples = (Uint16 *)buf;
+ for (; v->rest > 0; v->rest -= 2)
+ {
+ *samples = SDL_SwapLE16(*samples);
+ samples++;
+ }
+ #endif
+ done >>= 1;
+ }
+ }
+
+ return done;
+} /* voc_read */
+
+
+/* don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+ vs_t v;
+ int was_error = 1;
+ int samplesize;
+ Uint8 *fillptr;
+ void *ptr;
+
+ if ( (!src) || (!audio_buf) || (!audio_len) ) /* sanity checks. */
+ goto done;
+
+ if ( !voc_check_header(src) )
+ goto done;
+
+ v.rate = -1;
+ v.rest = 0;
+ v.has_extended = 0;
+ *audio_buf = NULL;
+ *audio_len = 0;
+ memset(spec, '\0', sizeof (SDL_AudioSpec));
+
+ if (!voc_get_block(src, &v, spec))
+ goto done;
+
+ if (v.rate == -1)
+ {
+ SDL_SetError("VOC data had no sound!");
+ goto done;
+ }
+
+ spec->format = ((v.size == ST_SIZE_WORD) ? AUDIO_S16 : AUDIO_U8);
+ if (spec->channels == 0)
+ spec->channels = v.channels;
+
+ *audio_len = v.rest;
+ *audio_buf = SDL_malloc(v.rest);
+ if (*audio_buf == NULL)
+ goto done;
+
+ fillptr = *audio_buf;
+
+ while (voc_read(src, &v, fillptr, spec) > 0)
+ {
+ if (!voc_get_block(src, &v, spec))
+ goto done;
+
+ *audio_len += v.rest;
+ ptr = SDL_realloc(*audio_buf, *audio_len);
+ if (ptr == NULL)
+ {
+ SDL_free(*audio_buf);
+ *audio_buf = NULL;
+ *audio_len = 0;
+ goto done;
+ }
+
+ *audio_buf = ptr;
+ fillptr = ((Uint8 *) ptr) + (*audio_len - v.rest);
+ }
+
+ spec->samples = (Uint16)(*audio_len / v.size);
+
+ was_error = 0; /* success, baby! */
+
+ /* Don't return a buffer that isn't a multiple of samplesize */
+ samplesize = ((spec->format & 0xFF)/8)*spec->channels;
+ *audio_len &= ~(samplesize-1);
+
+done:
+ if (src)
+ {
+ if (freesrc)
+ SDL_RWclose(src);
+ else
+ SDL_RWseek(src, 0, RW_SEEK_SET);
+ }
+
+ if ( was_error )
+ spec = NULL;
+
+ return(spec);
+} /* Mix_LoadVOC_RW */
+
+/* end of load_voc.c ... */
diff --git a/apps/plugins/sdl/SDL_mixer/load_voc.h b/apps/plugins/sdl/SDL_mixer/load_voc.h
new file mode 100644
index 0000000000..20ae23ca40
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/load_voc.h
@@ -0,0 +1,36 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This is the source needed to decode a Creative Labs VOC file into a
+ waveform. It's pretty straightforward once you get going. The only
+ externally-callable function is Mix_LoadVOC_RW(), which is meant to
+ act as identically to SDL_LoadWAV_RW() as possible.
+
+ This file by Ryan C. Gordon (icculus@icculus.org).
+
+ Heavily borrowed from sox v12.17.1's voc.c.
+ (http://www.freshmeat.net/projects/sox/)
+*/
+
+/* $Id$ */
+
+/* Don't call this directly; use Mix_LoadWAV_RW() for now. */
+SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc,
+ SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len);
diff --git a/apps/plugins/sdl/SDL_mixer/mixer.c b/apps/plugins/sdl/SDL_mixer/mixer.c
new file mode 100644
index 0000000000..a24a0e7c1d
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/mixer.c
@@ -0,0 +1,1484 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#include "SDL_mutex.h"
+#include "SDL_endian.h"
+#include "SDL_timer.h"
+
+#include "SDL_mixer.h"
+#include "load_aiff.h"
+#include "load_voc.h"
+#include "load_ogg.h"
+#include "load_flac.h"
+#include "dynamic_flac.h"
+#include "dynamic_mod.h"
+#include "dynamic_mp3.h"
+#include "dynamic_ogg.h"
+
+#define __MIX_INTERNAL_EFFECT__
+#include "effects_internal.h"
+
+/* Magic numbers for various audio file formats */
+#define RIFF 0x46464952 /* "RIFF" */
+#define WAVE 0x45564157 /* "WAVE" */
+#define FORM 0x4d524f46 /* "FORM" */
+#define OGGS 0x5367674f /* "OggS" */
+#define CREA 0x61657243 /* "Crea" */
+#define FLAC 0x43614C66 /* "fLaC" */
+
+static int audio_opened = 0;
+static SDL_AudioSpec mixer;
+
+typedef struct _Mix_effectinfo
+{
+ Mix_EffectFunc_t callback;
+ Mix_EffectDone_t done_callback;
+ void *udata;
+ struct _Mix_effectinfo *next;
+} effect_info;
+
+static struct _Mix_Channel {
+ Mix_Chunk *chunk;
+ int playing;
+ int paused;
+ Uint8 *samples;
+ int volume;
+ int looping;
+ int tag;
+ Uint32 expire;
+ Uint32 start_time;
+ Mix_Fading fading;
+ int fade_volume;
+ int fade_volume_reset;
+ Uint32 fade_length;
+ Uint32 ticks_fade;
+ effect_info *effects;
+} *mix_channel = NULL;
+
+static effect_info *posteffects = NULL;
+
+static int num_channels;
+static int reserved_channels = 0;
+
+
+/* Support for hooking into the mixer callback system */
+static void (*mix_postmix)(void *udata, Uint8 *stream, int len) = NULL;
+static void *mix_postmix_data = NULL;
+
+/* rcg07062001 callback to alert when channels are done playing. */
+static void (*channel_done_callback)(int channel) = NULL;
+
+/* Music function declarations */
+extern int open_music(SDL_AudioSpec *mixer);
+extern void close_music(void);
+
+/* Support for user defined music functions, plus the default one */
+extern int volatile music_active;
+extern void music_mixer(void *udata, Uint8 *stream, int len);
+static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer;
+static void *music_data = NULL;
+
+/* rcg06042009 report available decoders at runtime. */
+static const char **chunk_decoders = NULL;
+static int num_decoders = 0;
+
+/* Semicolon-separated SoundFont paths */
+#ifdef MID_MUSIC
+extern char* soundfont_paths;
+#endif
+
+int Mix_GetNumChunkDecoders(void)
+{
+ return(num_decoders);
+}
+
+const char *Mix_GetChunkDecoder(int index)
+{
+ if ((index < 0) || (index >= num_decoders)) {
+ return NULL;
+ }
+ return(chunk_decoders[index]);
+}
+
+static void add_chunk_decoder(const char *decoder)
+{
+ void *ptr = SDL_realloc(chunk_decoders, (num_decoders + 1) * sizeof (const char **));
+ if (ptr == NULL) {
+ return; /* oh well, go on without it. */
+ }
+ chunk_decoders = (const char **) ptr;
+ chunk_decoders[num_decoders++] = decoder;
+}
+
+/* rcg06192001 get linked library's version. */
+const SDL_version *Mix_Linked_Version(void)
+{
+ static SDL_version linked_version;
+ SDL_MIXER_VERSION(&linked_version);
+ return(&linked_version);
+}
+
+static int initialized = 0;
+
+int Mix_Init(int flags)
+{
+ int result = 0;
+
+ if (flags & MIX_INIT_FLUIDSYNTH) {
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ((initialized & MIX_INIT_FLUIDSYNTH) || Mix_InitFluidSynth() == 0) {
+ result |= MIX_INIT_FLUIDSYNTH;
+ }
+#else
+ Mix_SetError("Mixer not built with FluidSynth support");
+#endif
+ }
+ if (flags & MIX_INIT_FLAC) {
+#ifdef FLAC_MUSIC
+ if ((initialized & MIX_INIT_FLAC) || Mix_InitFLAC() == 0) {
+ result |= MIX_INIT_FLAC;
+ }
+#else
+ Mix_SetError("Mixer not built with FLAC support");
+#endif
+ }
+ if (flags & MIX_INIT_MOD) {
+#ifdef MOD_MUSIC
+ if ((initialized & MIX_INIT_MOD) || Mix_InitMOD() == 0) {
+ result |= MIX_INIT_MOD;
+ }
+#else
+ Mix_SetError("Mixer not built with MOD support");
+#endif
+ }
+ if (flags & MIX_INIT_MP3) {
+#ifdef MP3_MUSIC
+ if ((initialized & MIX_INIT_MP3) || Mix_InitMP3() == 0) {
+ result |= MIX_INIT_MP3;
+ }
+#else
+ Mix_SetError("Mixer not built with MP3 support");
+#endif
+ }
+ if (flags & MIX_INIT_OGG) {
+#ifdef OGG_MUSIC
+ if ((initialized & MIX_INIT_OGG) || Mix_InitOgg() == 0) {
+ result |= MIX_INIT_OGG;
+ }
+#else
+ Mix_SetError("Mixer not built with Ogg Vorbis support");
+#endif
+ }
+ initialized |= result;
+
+ return (result);
+}
+
+void Mix_Quit()
+{
+#ifdef USE_FLUIDSYNTH_MIDI
+ if (initialized & MIX_INIT_FLUIDSYNTH) {
+ Mix_QuitFluidSynth();
+ }
+#endif
+#ifdef FLAC_MUSIC
+ if (initialized & MIX_INIT_FLAC) {
+ Mix_QuitFLAC();
+ }
+#endif
+#ifdef MOD_MUSIC
+ if (initialized & MIX_INIT_MOD) {
+ Mix_QuitMOD();
+ }
+#endif
+#ifdef MP3_MUSIC
+ if (initialized & MIX_INIT_MP3) {
+ Mix_QuitMP3();
+ }
+#endif
+#ifdef OGG_MUSIC
+ if (initialized & MIX_INIT_OGG) {
+ Mix_QuitOgg();
+ }
+#endif
+#ifdef MID_MUSIC
+ if (soundfont_paths) {
+ SDL_free(soundfont_paths);
+ }
+#endif
+ initialized = 0;
+}
+
+static int _Mix_remove_all_effects(int channel, effect_info **e);
+
+/*
+ * rcg06122001 Cleanup effect callbacks.
+ * MAKE SURE SDL_LockAudio() is called before this (or you're in the
+ * audio callback).
+ */
+static void _Mix_channel_done_playing(int channel)
+{
+ if (channel_done_callback) {
+ channel_done_callback(channel);
+ }
+
+ /*
+ * Call internal function directly, to avoid locking audio from
+ * inside audio callback.
+ */
+ _Mix_remove_all_effects(channel, &mix_channel[channel].effects);
+}
+
+
+static void *Mix_DoEffects(int chan, void *snd, int len)
+{
+ int posteffect = (chan == MIX_CHANNEL_POST);
+ effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects);
+ void *buf = snd;
+
+ if (e != NULL) { /* are there any registered effects? */
+ /* if this is the postmix, we can just overwrite the original. */
+ if (!posteffect) {
+ buf = SDL_malloc(len);
+ if (buf == NULL) {
+ return(snd);
+ }
+ memcpy(buf, snd, len);
+ }
+
+ for (; e != NULL; e = e->next) {
+ if (e->callback != NULL) {
+ e->callback(chan, buf, len, e->udata);
+ }
+ }
+ }
+
+ /* be sure to SDL_free() the return value if != snd ... */
+ return(buf);
+}
+
+
+/* Mixing function */
+static void mix_channels(void *udata, Uint8 *stream, int len)
+{
+ Uint8 *mix_input;
+ int i, mixable, volume = SDL_MIX_MAXVOLUME;
+ Uint32 sdl_ticks;
+
+#if SDL_VERSION_ATLEAST(1, 3, 0)
+ /* Need to initialize the stream in SDL 1.3+ */
+ memset(stream, mixer.silence, len);
+#endif
+
+ /* Mix the music (must be done before the channels are added) */
+ if ( music_active || (mix_music != music_mixer) ) {
+ mix_music(music_data, stream, len);
+ }
+
+ /* Mix any playing channels... */
+ sdl_ticks = SDL_GetTicks();
+ for ( i=0; i<num_channels; ++i ) {
+ if( ! mix_channel[i].paused ) {
+ if ( mix_channel[i].expire > 0 && mix_channel[i].expire < sdl_ticks ) {
+ /* Expiration delay for that channel is reached */
+ mix_channel[i].playing = 0;
+ mix_channel[i].looping = 0;
+ mix_channel[i].fading = MIX_NO_FADING;
+ mix_channel[i].expire = 0;
+ _Mix_channel_done_playing(i);
+ } else if ( mix_channel[i].fading != MIX_NO_FADING ) {
+ Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade;
+ if( ticks > mix_channel[i].fade_length ) {
+ Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */
+ if( mix_channel[i].fading == MIX_FADING_OUT ) {
+ mix_channel[i].playing = 0;
+ mix_channel[i].looping = 0;
+ mix_channel[i].expire = 0;
+ _Mix_channel_done_playing(i);
+ }
+ mix_channel[i].fading = MIX_NO_FADING;
+ } else {
+ if( mix_channel[i].fading == MIX_FADING_OUT ) {
+ Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks))
+ / mix_channel[i].fade_length );
+ } else {
+ Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length );
+ }
+ }
+ }
+ if ( mix_channel[i].playing > 0 ) {
+ int index = 0;
+ int remaining = len;
+ while (mix_channel[i].playing > 0 && index < len) {
+ remaining = len - index;
+ volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME;
+ mixable = mix_channel[i].playing;
+ if ( mixable > remaining ) {
+ mixable = remaining;
+ }
+
+ mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable);
+ SDL_MixAudio(stream+index,mix_input,mixable,volume);
+ if (mix_input != mix_channel[i].samples)
+ SDL_free(mix_input);
+
+ mix_channel[i].samples += mixable;
+ mix_channel[i].playing -= mixable;
+ index += mixable;
+
+ /* rcg06072001 Alert app if channel is done playing. */
+ if (!mix_channel[i].playing && !mix_channel[i].looping) {
+ _Mix_channel_done_playing(i);
+ }
+ }
+
+ /* If looping the sample and we are at its end, make sure
+ we will still return a full buffer */
+ while ( mix_channel[i].looping && index < len ) {
+ int alen = mix_channel[i].chunk->alen;
+ remaining = len - index;
+ if (remaining > alen) {
+ remaining = alen;
+ }
+
+ mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining);
+ SDL_MixAudio(stream+index, mix_input, remaining, volume);
+ if (mix_input != mix_channel[i].chunk->abuf)
+ SDL_free(mix_input);
+
+ --mix_channel[i].looping;
+ mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining;
+ mix_channel[i].playing = mix_channel[i].chunk->alen - remaining;
+ index += remaining;
+ }
+ if ( ! mix_channel[i].playing && mix_channel[i].looping ) {
+ --mix_channel[i].looping;
+ mix_channel[i].samples = mix_channel[i].chunk->abuf;
+ mix_channel[i].playing = mix_channel[i].chunk->alen;
+ }
+ }
+ }
+ }
+
+ /* rcg06122001 run posteffects... */
+ Mix_DoEffects(MIX_CHANNEL_POST, stream, len);
+
+ if ( mix_postmix ) {
+ mix_postmix(mix_postmix_data, stream, len);
+ }
+}
+
+#if 0
+static void PrintFormat(char *title, SDL_AudioSpec *fmt)
+{
+ printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF),
+ (fmt->format&0x8000) ? "signed" : "unsigned",
+ (fmt->channels > 2) ? "surround" :
+ (fmt->channels > 1) ? "stereo" : "mono", fmt->freq);
+}
+#endif
+
+
+/* Open the mixer with a certain desired audio format */
+int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize)
+{
+ int i;
+ SDL_AudioSpec desired;
+
+ /* If the mixer is already opened, increment open count */
+ if ( audio_opened ) {
+ if ( format == mixer.format && nchannels == mixer.channels ) {
+ ++audio_opened;
+ return(0);
+ }
+ while ( audio_opened ) {
+ Mix_CloseAudio();
+ }
+ }
+
+ /* Set the desired format and frequency */
+ desired.freq = frequency;
+ desired.format = format;
+ desired.channels = nchannels;
+ desired.samples = chunksize;
+ desired.callback = mix_channels;
+ desired.userdata = NULL;
+
+ /* Accept nearly any audio format */
+ if ( SDL_OpenAudio(&desired, &mixer) < 0 ) {
+ return(-1);
+ }
+#if 0
+ PrintFormat("Audio device", &mixer);
+#endif
+
+ /* Initialize the music players */
+ if ( open_music(&mixer) < 0 ) {
+ SDL_CloseAudio();
+ return(-1);
+ }
+
+ num_channels = MIX_CHANNELS;
+ mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel));
+
+ /* Clear out the audio channels */
+ for ( i=0; i<num_channels; ++i ) {
+ mix_channel[i].chunk = NULL;
+ mix_channel[i].playing = 0;
+ mix_channel[i].looping = 0;
+ mix_channel[i].volume = SDL_MIX_MAXVOLUME;
+ mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
+ mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
+ mix_channel[i].fading = MIX_NO_FADING;
+ mix_channel[i].tag = -1;
+ mix_channel[i].expire = 0;
+ mix_channel[i].effects = NULL;
+ mix_channel[i].paused = 0;
+ }
+ Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
+
+ _Mix_InitEffects();
+
+ /* This list is (currently) decided at build time. */
+ add_chunk_decoder("WAVE");
+ add_chunk_decoder("AIFF");
+ add_chunk_decoder("VOC");
+#ifdef OGG_MUSIC
+ add_chunk_decoder("OGG");
+#endif
+#ifdef FLAC_MUSIC
+ add_chunk_decoder("FLAC");
+#endif
+
+ audio_opened = 1;
+ SDL_PauseAudio(0);
+ return(0);
+}
+
+/* Dynamically change the number of channels managed by the mixer.
+ If decreasing the number of channels, the upper channels are
+ stopped.
+ */
+int Mix_AllocateChannels(int numchans)
+{
+ if ( numchans<0 || numchans==num_channels )
+ return(num_channels);
+
+ if ( numchans < num_channels ) {
+ /* Stop the affected channels */
+ int i;
+ for(i=numchans; i < num_channels; i++) {
+ Mix_UnregisterAllEffects(i);
+ Mix_HaltChannel(i);
+ }
+ }
+ SDL_LockAudio();
+ mix_channel = (struct _Mix_Channel *) SDL_realloc(mix_channel, numchans * sizeof(struct _Mix_Channel));
+ if ( numchans > num_channels ) {
+ /* Initialize the new channels */
+ int i;
+ for(i=num_channels; i < numchans; i++) {
+ mix_channel[i].chunk = NULL;
+ mix_channel[i].playing = 0;
+ mix_channel[i].looping = 0;
+ mix_channel[i].volume = SDL_MIX_MAXVOLUME;
+ mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME;
+ mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME;
+ mix_channel[i].fading = MIX_NO_FADING;
+ mix_channel[i].tag = -1;
+ mix_channel[i].expire = 0;
+ mix_channel[i].effects = NULL;
+ mix_channel[i].paused = 0;
+ }
+ }
+ num_channels = numchans;
+ SDL_UnlockAudio();
+ return(num_channels);
+}
+
+/* Return the actual mixer parameters */
+int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
+{
+ if ( audio_opened ) {
+ if ( frequency ) {
+ *frequency = mixer.freq;
+ }
+ if ( format ) {
+ *format = mixer.format;
+ }
+ if ( channels ) {
+ *channels = mixer.channels;
+ }
+ }
+ return(audio_opened);
+}
+
+
+/*
+ * !!! FIXME: Ideally, we want a Mix_LoadSample_RW(), which will handle the
+ * generic setup, then call the correct file format loader.
+ */
+
+/* Load a wave file */
+Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
+{
+ Uint32 magic;
+ Mix_Chunk *chunk;
+ SDL_AudioSpec wavespec, *loaded;
+ SDL_AudioCVT wavecvt;
+ int samplesize;
+
+ /* rcg06012001 Make sure src is valid */
+ if ( ! src ) {
+ SDL_SetError("Mix_LoadWAV_RW with NULL src");
+ return(NULL);
+ }
+
+ /* Make sure audio has been opened */
+ if ( ! audio_opened ) {
+ SDL_SetError("Audio device hasn't been opened");
+ if ( freesrc && src ) {
+ SDL_RWclose(src);
+ }
+ return(NULL);
+ }
+
+ /* Allocate the chunk memory */
+ chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
+ if ( chunk == NULL ) {
+ SDL_SetError("Out of memory");
+ if ( freesrc ) {
+ SDL_RWclose(src);
+ }
+ return(NULL);
+ }
+
+ /* Find out what kind of audio file this is */
+ magic = SDL_ReadLE32(src);
+ /* Seek backwards for compatibility with older loaders */
+ SDL_RWseek(src, -(int)sizeof(Uint32), RW_SEEK_CUR);
+
+ switch (magic) {
+ case WAVE:
+ case RIFF:
+ loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec,
+ (Uint8 **)&chunk->abuf, &chunk->alen);
+ break;
+ case FORM:
+ loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec,
+ (Uint8 **)&chunk->abuf, &chunk->alen);
+ break;
+#ifdef OGG_MUSIC
+ case OGGS:
+ loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec,
+ (Uint8 **)&chunk->abuf, &chunk->alen);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case FLAC:
+ loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec,
+ (Uint8 **)&chunk->abuf, &chunk->alen);
+ break;
+#endif
+ case CREA:
+ loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec,
+ (Uint8 **)&chunk->abuf, &chunk->alen);
+ break;
+ default:
+ SDL_SetError("Unrecognized sound file type");
+ return(0);
+ }
+ if ( !loaded ) {
+ SDL_free(chunk);
+ if ( freesrc ) {
+ SDL_RWclose(src);
+ }
+ return(NULL);
+ }
+
+#if 0
+ PrintFormat("Audio device", &mixer);
+ PrintFormat("-- Wave file", &wavespec);
+#endif
+
+ /* Build the audio converter and create conversion buffers */
+ if ( wavespec.format != mixer.format ||
+ wavespec.channels != mixer.channels ||
+ wavespec.freq != mixer.freq ) {
+ if ( SDL_BuildAudioCVT(&wavecvt,
+ wavespec.format, wavespec.channels, wavespec.freq,
+ mixer.format, mixer.channels, mixer.freq) < 0 ) {
+ SDL_free(chunk->abuf);
+ SDL_free(chunk);
+ return(NULL);
+ }
+ samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels;
+ wavecvt.len = chunk->alen & ~(samplesize-1);
+ wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult);
+ if ( wavecvt.buf == NULL ) {
+ SDL_SetError("Out of memory");
+ SDL_free(chunk->abuf);
+ SDL_free(chunk);
+ return(NULL);
+ }
+ memcpy(wavecvt.buf, chunk->abuf, chunk->alen);
+ SDL_free(chunk->abuf);
+
+ /* Run the audio converter */
+ if ( SDL_ConvertAudio(&wavecvt) < 0 ) {
+ SDL_free(wavecvt.buf);
+ SDL_free(chunk);
+ return(NULL);
+ }
+
+ chunk->abuf = wavecvt.buf;
+ chunk->alen = wavecvt.len_cvt;
+ }
+
+ chunk->allocated = 1;
+ chunk->volume = MIX_MAX_VOLUME;
+
+ return(chunk);
+}
+
+/* Load a wave file of the mixer format from a memory buffer */
+Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem)
+{
+ Mix_Chunk *chunk;
+ Uint8 magic[4];
+
+ /* Make sure audio has been opened */
+ if ( ! audio_opened ) {
+ SDL_SetError("Audio device hasn't been opened");
+ return(NULL);
+ }
+
+ /* Allocate the chunk memory */
+ chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk));
+ if ( chunk == NULL ) {
+ SDL_SetError("Out of memory");
+ return(NULL);
+ }
+
+ /* Essentially just skip to the audio data (no error checking - fast) */
+ chunk->allocated = 0;
+ mem += 12; /* WAV header */
+ do {
+ memcpy(magic, mem, 4);
+ mem += 4;
+ chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0]));
+ mem += 4;
+ chunk->abuf = mem;
+ mem += chunk->alen;
+ } while ( memcmp(magic, "data", 4) != 0 );
+ chunk->volume = MIX_MAX_VOLUME;
+
+ return(chunk);
+}
+
+/* Load raw audio data of the mixer format from a memory buffer */
+Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len)
+{
+ Mix_Chunk *chunk;
+
+ /* Make sure audio has been opened */
+ if ( ! audio_opened ) {
+ SDL_SetError("Audio device hasn't been opened");
+ return(NULL);
+ }
+
+ /* Allocate the chunk memory */
+ chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk));
+ if ( chunk == NULL ) {
+ SDL_SetError("Out of memory");
+ return(NULL);
+ }
+
+ /* Essentially just point at the audio data (no error checking - fast) */
+ chunk->allocated = 0;
+ chunk->alen = len;
+ chunk->abuf = mem;
+ chunk->volume = MIX_MAX_VOLUME;
+
+ return(chunk);
+}
+
+/* Free an audio chunk previously loaded */
+void Mix_FreeChunk(Mix_Chunk *chunk)
+{
+ int i;
+
+ /* Caution -- if the chunk is playing, the mixer will crash */
+ if ( chunk ) {
+ /* Guarantee that this chunk isn't playing */
+ SDL_LockAudio();
+ if ( mix_channel ) {
+ for ( i=0; i<num_channels; ++i ) {
+ if ( chunk == mix_channel[i].chunk ) {
+ mix_channel[i].playing = 0;
+ mix_channel[i].looping = 0;
+ }
+ }
+ }
+ SDL_UnlockAudio();
+ /* Actually free the chunk */
+ if ( chunk->allocated ) {
+ SDL_free(chunk->abuf);
+ }
+ SDL_free(chunk);
+ }
+}
+
+/* Set a function that is called after all mixing is performed.
+ This can be used to provide real-time visual display of the audio stream
+ or add a custom mixer filter for the stream data.
+*/
+void Mix_SetPostMix(void (*mix_func)
+ (void *udata, Uint8 *stream, int len), void *arg)
+{
+ SDL_LockAudio();
+ mix_postmix_data = arg;
+ mix_postmix = mix_func;
+ SDL_UnlockAudio();
+}
+
+/* Add your own music player or mixer function.
+ If 'mix_func' is NULL, the default music player is re-enabled.
+ */
+void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len),
+ void *arg)
+{
+ SDL_LockAudio();
+ if ( mix_func != NULL ) {
+ music_data = arg;
+ mix_music = mix_func;
+ } else {
+ music_data = NULL;
+ mix_music = music_mixer;
+ }
+ SDL_UnlockAudio();
+}
+
+void *Mix_GetMusicHookData(void)
+{
+ return(music_data);
+}
+
+void Mix_ChannelFinished(void (*channel_finished)(int channel))
+{
+ SDL_LockAudio();
+ channel_done_callback = channel_finished;
+ SDL_UnlockAudio();
+}
+
+
+/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
+ them dynamically to the next sample if requested with a -1 value below.
+ Returns the number of reserved channels.
+ */
+int Mix_ReserveChannels(int num)
+{
+ if (num > num_channels)
+ num = num_channels;
+ reserved_channels = num;
+ return num;
+}
+
+static int checkchunkintegral(Mix_Chunk *chunk)
+{
+ int frame_width = 1;
+
+ if ((mixer.format & 0xFF) == 16) frame_width = 2;
+ frame_width *= mixer.channels;
+ while (chunk->alen % frame_width) chunk->alen--;
+ return chunk->alen;
+}
+
+/* Play an audio chunk on a specific channel.
+ If the specified channel is -1, play on the first free channel.
+ 'ticks' is the number of milliseconds at most to play the sample, or -1
+ if there is no limit.
+ Returns which channel was used to play the sound.
+*/
+int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
+{
+ int i;
+
+ /* Don't play null pointers :-) */
+ if ( chunk == NULL ) {
+ Mix_SetError("Tried to play a NULL chunk");
+ return(-1);
+ }
+ if ( !checkchunkintegral(chunk)) {
+ Mix_SetError("Tried to play a chunk with a bad frame");
+ return(-1);
+ }
+
+ /* Lock the mixer while modifying the playing channels */
+ SDL_LockAudio();
+ {
+ /* If which is -1, play on the first free channel */
+ if ( which == -1 ) {
+ for ( i=reserved_channels; i<num_channels; ++i ) {
+ if ( mix_channel[i].playing <= 0 )
+ break;
+ }
+ if ( i == num_channels ) {
+ Mix_SetError("No free channels available");
+ which = -1;
+ } else {
+ which = i;
+ }
+ }
+
+ /* Queue up the audio data for this channel */
+ if ( which >= 0 && which < num_channels ) {
+ Uint32 sdl_ticks = SDL_GetTicks();
+ if (Mix_Playing(which))
+ _Mix_channel_done_playing(which);
+ mix_channel[which].samples = chunk->abuf;
+ mix_channel[which].playing = chunk->alen;
+ mix_channel[which].looping = loops;
+ mix_channel[which].chunk = chunk;
+ mix_channel[which].paused = 0;
+ mix_channel[which].fading = MIX_NO_FADING;
+ mix_channel[which].start_time = sdl_ticks;
+ mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0;
+ }
+ }
+ SDL_UnlockAudio();
+
+ /* Return the channel on which the sound is being played */
+ return(which);
+}
+
+/* Change the expiration delay for a channel */
+int Mix_ExpireChannel(int which, int ticks)
+{
+ int status = 0;
+
+ if ( which == -1 ) {
+ int i;
+ for ( i=0; i < num_channels; ++ i ) {
+ status += Mix_ExpireChannel(i, ticks);
+ }
+ } else if ( which < num_channels ) {
+ SDL_LockAudio();
+ mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0;
+ SDL_UnlockAudio();
+ ++ status;
+ }
+ return(status);
+}
+
+/* Fade in a sound on a channel, over ms milliseconds */
+int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
+{
+ int i;
+
+ /* Don't play null pointers :-) */
+ if ( chunk == NULL ) {
+ return(-1);
+ }
+ if ( !checkchunkintegral(chunk)) {
+ Mix_SetError("Tried to play a chunk with a bad frame");
+ return(-1);
+ }
+
+ /* Lock the mixer while modifying the playing channels */
+ SDL_LockAudio();
+ {
+ /* If which is -1, play on the first free channel */
+ if ( which == -1 ) {
+ for ( i=reserved_channels; i<num_channels; ++i ) {
+ if ( mix_channel[i].playing <= 0 )
+ break;
+ }
+ if ( i == num_channels ) {
+ which = -1;
+ } else {
+ which = i;
+ }
+ }
+
+ /* Queue up the audio data for this channel */
+ if ( which >= 0 && which < num_channels ) {
+ Uint32 sdl_ticks = SDL_GetTicks();
+ if (Mix_Playing(which))
+ _Mix_channel_done_playing(which);
+ mix_channel[which].samples = chunk->abuf;
+ mix_channel[which].playing = chunk->alen;
+ mix_channel[which].looping = loops;
+ mix_channel[which].chunk = chunk;
+ mix_channel[which].paused = 0;
+ mix_channel[which].fading = MIX_FADING_IN;
+ mix_channel[which].fade_volume = mix_channel[which].volume;
+ mix_channel[which].fade_volume_reset = mix_channel[which].volume;
+ mix_channel[which].volume = 0;
+ mix_channel[which].fade_length = (Uint32)ms;
+ mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks;
+ mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0;
+ }
+ }
+ SDL_UnlockAudio();
+
+ /* Return the channel on which the sound is being played */
+ return(which);
+}
+
+/* Set volume of a particular channel */
+int Mix_Volume(int which, int volume)
+{
+ int i;
+ int prev_volume = 0;
+
+ if ( which == -1 ) {
+ for ( i=0; i<num_channels; ++i ) {
+ prev_volume += Mix_Volume(i, volume);
+ }
+ prev_volume /= num_channels;
+ } else if ( which < num_channels ) {
+ prev_volume = mix_channel[which].volume;
+ if ( volume >= 0 ) {
+ if ( volume > SDL_MIX_MAXVOLUME ) {
+ volume = SDL_MIX_MAXVOLUME;
+ }
+ mix_channel[which].volume = volume;
+ }
+ }
+ return(prev_volume);
+}
+/* Set volume of a particular chunk */
+int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
+{
+ int prev_volume;
+
+ prev_volume = chunk->volume;
+ if ( volume >= 0 ) {
+ if ( volume > MIX_MAX_VOLUME ) {
+ volume = MIX_MAX_VOLUME;
+ }
+ chunk->volume = volume;
+ }
+ return(prev_volume);
+}
+
+/* Halt playing of a particular channel */
+int Mix_HaltChannel(int which)
+{
+ int i;
+
+ if ( which == -1 ) {
+ for ( i=0; i<num_channels; ++i ) {
+ Mix_HaltChannel(i);
+ }
+ } else if ( which < num_channels ) {
+ SDL_LockAudio();
+ if (mix_channel[which].playing) {
+ _Mix_channel_done_playing(which);
+ mix_channel[which].playing = 0;
+ mix_channel[which].looping = 0;
+ }
+ mix_channel[which].expire = 0;
+ if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */
+ mix_channel[which].volume = mix_channel[which].fade_volume_reset;
+ mix_channel[which].fading = MIX_NO_FADING;
+ SDL_UnlockAudio();
+ }
+ return(0);
+}
+
+/* Halt playing of a particular group of channels */
+int Mix_HaltGroup(int tag)
+{
+ int i;
+
+ for ( i=0; i<num_channels; ++i ) {
+ if( mix_channel[i].tag == tag ) {
+ Mix_HaltChannel(i);
+ }
+ }
+ return(0);
+}
+
+/* Fade out a channel and then stop it automatically */
+int Mix_FadeOutChannel(int which, int ms)
+{
+ int status;
+
+ status = 0;
+ if ( audio_opened ) {
+ if ( which == -1 ) {
+ int i;
+
+ for ( i=0; i<num_channels; ++i ) {
+ status += Mix_FadeOutChannel(i, ms);
+ }
+ } else if ( which < num_channels ) {
+ SDL_LockAudio();
+ if ( mix_channel[which].playing &&
+ (mix_channel[which].volume > 0) &&
+ (mix_channel[which].fading != MIX_FADING_OUT) ) {
+ mix_channel[which].fade_volume = mix_channel[which].volume;
+ mix_channel[which].fading = MIX_FADING_OUT;
+ mix_channel[which].fade_length = ms;
+ mix_channel[which].ticks_fade = SDL_GetTicks();
+
+ /* only change fade_volume_reset if we're not fading. */
+ if (mix_channel[which].fading == MIX_NO_FADING) {
+ mix_channel[which].fade_volume_reset = mix_channel[which].volume;
+ }
+ ++status;
+ }
+ SDL_UnlockAudio();
+ }
+ }
+ return(status);
+}
+
+/* Halt playing of a particular group of channels */
+int Mix_FadeOutGroup(int tag, int ms)
+{
+ int i;
+ int status = 0;
+ for ( i=0; i<num_channels; ++i ) {
+ if( mix_channel[i].tag == tag ) {
+ status += Mix_FadeOutChannel(i,ms);
+ }
+ }
+ return(status);
+}
+
+Mix_Fading Mix_FadingChannel(int which)
+{
+ if ( which < 0 || which >= num_channels ) {
+ return MIX_NO_FADING;
+ }
+ return mix_channel[which].fading;
+}
+
+/* Check the status of a specific channel.
+ If the specified mix_channel is -1, check all mix channels.
+*/
+int Mix_Playing(int which)
+{
+ int status;
+
+ status = 0;
+ if ( which == -1 ) {
+ int i;
+
+ for ( i=0; i<num_channels; ++i ) {
+ if ((mix_channel[i].playing > 0) ||
+ (mix_channel[i].looping > 0))
+ {
+ ++status;
+ }
+ }
+ } else if ( which < num_channels ) {
+ if ( (mix_channel[which].playing > 0) ||
+ (mix_channel[which].looping > 0) )
+ {
+ ++status;
+ }
+ }
+ return(status);
+}
+
+/* rcg06072001 Get the chunk associated with a channel. */
+Mix_Chunk *Mix_GetChunk(int channel)
+{
+ Mix_Chunk *retval = NULL;
+
+ if ((channel >= 0) && (channel < num_channels)) {
+ retval = mix_channel[channel].chunk;
+ }
+
+ return(retval);
+}
+
+/* Close the mixer, halting all playing audio */
+void Mix_CloseAudio(void)
+{
+ int i;
+
+ if ( audio_opened ) {
+ if ( audio_opened == 1 ) {
+ for (i = 0; i < num_channels; i++) {
+ Mix_UnregisterAllEffects(i);
+ }
+ Mix_UnregisterAllEffects(MIX_CHANNEL_POST);
+ close_music();
+ Mix_HaltChannel(-1);
+ _Mix_DeinitEffects();
+ SDL_CloseAudio();
+ SDL_free(mix_channel);
+ mix_channel = NULL;
+
+ /* rcg06042009 report available decoders at runtime. */
+ SDL_free(chunk_decoders);
+ chunk_decoders = NULL;
+ num_decoders = 0;
+ }
+ --audio_opened;
+ }
+}
+
+/* Pause a particular channel (or all) */
+void Mix_Pause(int which)
+{
+ Uint32 sdl_ticks = SDL_GetTicks();
+ if ( which == -1 ) {
+ int i;
+
+ for ( i=0; i<num_channels; ++i ) {
+ if ( mix_channel[i].playing > 0 ) {
+ mix_channel[i].paused = sdl_ticks;
+ }
+ }
+ } else if ( which < num_channels ) {
+ if ( mix_channel[which].playing > 0 ) {
+ mix_channel[which].paused = sdl_ticks;
+ }
+ }
+}
+
+/* Resume a paused channel */
+void Mix_Resume(int which)
+{
+ Uint32 sdl_ticks = SDL_GetTicks();
+
+ SDL_LockAudio();
+ if ( which == -1 ) {
+ int i;
+
+ for ( i=0; i<num_channels; ++i ) {
+ if ( mix_channel[i].playing > 0 ) {
+ if(mix_channel[i].expire > 0)
+ mix_channel[i].expire += sdl_ticks - mix_channel[i].paused;
+ mix_channel[i].paused = 0;
+ }
+ }
+ } else if ( which < num_channels ) {
+ if ( mix_channel[which].playing > 0 ) {
+ if(mix_channel[which].expire > 0)
+ mix_channel[which].expire += sdl_ticks - mix_channel[which].paused;
+ mix_channel[which].paused = 0;
+ }
+ }
+ SDL_UnlockAudio();
+}
+
+int Mix_Paused(int which)
+{
+ if ( which < 0 ) {
+ int status = 0;
+ int i;
+ for( i=0; i < num_channels; ++i ) {
+ if ( mix_channel[i].paused ) {
+ ++ status;
+ }
+ }
+ return(status);
+ } else if ( which < num_channels ) {
+ return(mix_channel[which].paused != 0);
+ } else {
+ return(0);
+ }
+}
+
+/* Change the group of a channel */
+int Mix_GroupChannel(int which, int tag)
+{
+ if ( which < 0 || which > num_channels )
+ return(0);
+
+ SDL_LockAudio();
+ mix_channel[which].tag = tag;
+ SDL_UnlockAudio();
+ return(1);
+}
+
+/* Assign several consecutive channels to a group */
+int Mix_GroupChannels(int from, int to, int tag)
+{
+ int status = 0;
+ for( ; from <= to; ++ from ) {
+ status += Mix_GroupChannel(from, tag);
+ }
+ return(status);
+}
+
+/* Finds the first available channel in a group of channels */
+int Mix_GroupAvailable(int tag)
+{
+ int i;
+ for( i=0; i < num_channels; i ++ ) {
+ if ( ((tag == -1) || (tag == mix_channel[i].tag)) &&
+ (mix_channel[i].playing <= 0) )
+ return i;
+ }
+ return(-1);
+}
+
+int Mix_GroupCount(int tag)
+{
+ int count = 0;
+ int i;
+ for( i=0; i < num_channels; i ++ ) {
+ if ( mix_channel[i].tag==tag || tag==-1 )
+ ++ count;
+ }
+ return(count);
+}
+
+/* Finds the "oldest" sample playing in a group of channels */
+int Mix_GroupOldest(int tag)
+{
+ int chan = -1;
+ Uint32 mintime = SDL_GetTicks();
+ int i;
+ for( i=0; i < num_channels; i ++ ) {
+ if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
+ && mix_channel[i].start_time <= mintime ) {
+ mintime = mix_channel[i].start_time;
+ chan = i;
+ }
+ }
+ return(chan);
+}
+
+/* Finds the "most recent" (i.e. last) sample playing in a group of channels */
+int Mix_GroupNewer(int tag)
+{
+ int chan = -1;
+ Uint32 maxtime = 0;
+ int i;
+ for( i=0; i < num_channels; i ++ ) {
+ if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0
+ && mix_channel[i].start_time >= maxtime ) {
+ maxtime = mix_channel[i].start_time;
+ chan = i;
+ }
+ }
+ return(chan);
+}
+
+
+
+/*
+ * rcg06122001 The special effects exportable API.
+ * Please see effect_*.c for internally-implemented effects, such
+ * as Mix_SetPanning().
+ */
+
+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
+static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f,
+ Mix_EffectDone_t d, void *arg)
+{
+ effect_info *new_e;
+
+ if (!e) {
+ Mix_SetError("Internal error");
+ return(0);
+ }
+
+ if (f == NULL) {
+ Mix_SetError("NULL effect callback");
+ return(0);
+ }
+
+ new_e = SDL_malloc(sizeof (effect_info));
+ if (new_e == NULL) {
+ Mix_SetError("Out of memory");
+ return(0);
+ }
+
+ new_e->callback = f;
+ new_e->done_callback = d;
+ new_e->udata = arg;
+ new_e->next = NULL;
+
+ /* add new effect to end of linked list... */
+ if (*e == NULL) {
+ *e = new_e;
+ } else {
+ effect_info *cur = *e;
+ while (1) {
+ if (cur->next == NULL) {
+ cur->next = new_e;
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+
+ return(1);
+}
+
+
+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
+static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f)
+{
+ effect_info *cur;
+ effect_info *prev = NULL;
+ effect_info *next = NULL;
+
+ if (!e) {
+ Mix_SetError("Internal error");
+ return(0);
+ }
+
+ for (cur = *e; cur != NULL; cur = cur->next) {
+ if (cur->callback == f) {
+ next = cur->next;
+ if (cur->done_callback != NULL) {
+ cur->done_callback(channel, cur->udata);
+ }
+ SDL_free(cur);
+
+ if (prev == NULL) { /* removing first item of list? */
+ *e = next;
+ } else {
+ prev->next = next;
+ }
+ return(1);
+ }
+ prev = cur;
+ }
+
+ Mix_SetError("No such effect registered");
+ return(0);
+}
+
+
+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
+static int _Mix_remove_all_effects(int channel, effect_info **e)
+{
+ effect_info *cur;
+ effect_info *next;
+
+ if (!e) {
+ Mix_SetError("Internal error");
+ return(0);
+ }
+
+ for (cur = *e; cur != NULL; cur = next) {
+ next = cur->next;
+ if (cur->done_callback != NULL) {
+ cur->done_callback(channel, cur->udata);
+ }
+ SDL_free(cur);
+ }
+ *e = NULL;
+
+ return(1);
+}
+
+
+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
+int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f,
+ Mix_EffectDone_t d, void *arg)
+{
+ effect_info **e = NULL;
+
+ if (channel == MIX_CHANNEL_POST) {
+ e = &posteffects;
+ } else {
+ if ((channel < 0) || (channel >= num_channels)) {
+ Mix_SetError("Invalid channel number");
+ return(0);
+ }
+ e = &mix_channel[channel].effects;
+ }
+
+ return _Mix_register_effect(e, f, d, arg);
+}
+
+int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f,
+ Mix_EffectDone_t d, void *arg)
+{
+ int retval;
+ SDL_LockAudio();
+ retval = _Mix_RegisterEffect_locked(channel, f, d, arg);
+ SDL_UnlockAudio();
+ return retval;
+}
+
+
+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
+int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f)
+{
+ effect_info **e = NULL;
+
+ if (channel == MIX_CHANNEL_POST) {
+ e = &posteffects;
+ } else {
+ if ((channel < 0) || (channel >= num_channels)) {
+ Mix_SetError("Invalid channel number");
+ return(0);
+ }
+ e = &mix_channel[channel].effects;
+ }
+
+ return _Mix_remove_effect(channel, e, f);
+}
+
+int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f)
+{
+ int retval;
+ SDL_LockAudio();
+ retval = _Mix_UnregisterEffect_locked(channel, f);
+ SDL_UnlockAudio();
+ return(retval);
+}
+
+/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */
+int _Mix_UnregisterAllEffects_locked(int channel)
+{
+ effect_info **e = NULL;
+
+ if (channel == MIX_CHANNEL_POST) {
+ e = &posteffects;
+ } else {
+ if ((channel < 0) || (channel >= num_channels)) {
+ Mix_SetError("Invalid channel number");
+ return(0);
+ }
+ e = &mix_channel[channel].effects;
+ }
+
+ return _Mix_remove_all_effects(channel, e);
+}
+
+int Mix_UnregisterAllEffects(int channel)
+{
+ int retval;
+ SDL_LockAudio();
+ retval = _Mix_UnregisterAllEffects_locked(channel);
+ SDL_UnlockAudio();
+ return(retval);
+}
+
+/* end of mixer.c ... */
+
diff --git a/apps/plugins/sdl/SDL_mixer/music.c b/apps/plugins/sdl/SDL_mixer/music.c
new file mode 100644
index 0000000000..ab41327394
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music.c
@@ -0,0 +1,1599 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#include <ctype.h>
+#include "SDL_endian.h"
+#include "SDL_audio.h"
+#include "SDL_timer.h"
+
+#include "SDL_mixer.h"
+
+#ifdef CMD_MUSIC
+#include "music_cmd.h"
+#endif
+#ifdef WAV_MUSIC
+#include "wavestream.h"
+#endif
+#ifdef MODPLUG_MUSIC
+#include "music_modplug.h"
+#endif
+#ifdef MOD_MUSIC
+#include "music_mod.h"
+#endif
+#ifdef MID_MUSIC
+# ifdef USE_TIMIDITY_MIDI
+# include "timidity/timidity.h"
+# endif
+# ifdef USE_FLUIDSYNTH_MIDI
+# include "fluidsynth.h"
+# endif
+# ifdef USE_NATIVE_MIDI
+# include "native_midi.h"
+# endif
+#endif
+#ifdef OGG_MUSIC
+#include "music_ogg.h"
+#endif
+#ifdef MP3_MUSIC
+#include "dynamic_mp3.h"
+#endif
+#ifdef MP3_MAD_MUSIC
+#include "music_mad.h"
+#endif
+#ifdef FLAC_MUSIC
+#include "music_flac.h"
+#endif
+
+#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
+static SDL_AudioSpec used_mixer;
+#endif
+
+
+int volatile music_active = 1;
+static int volatile music_stopped = 0;
+static int music_loops = 0;
+static char *music_cmd = NULL;
+static Mix_Music * volatile music_playing = NULL;
+static int music_volume = MIX_MAX_VOLUME;
+
+struct _Mix_Music {
+ Mix_MusicType type;
+ union {
+#ifdef CMD_MUSIC
+ MusicCMD *cmd;
+#endif
+#ifdef WAV_MUSIC
+ WAVStream *wave;
+#endif
+#ifdef MODPLUG_MUSIC
+ modplug_data *modplug;
+#endif
+#ifdef MOD_MUSIC
+ struct MODULE *module;
+#endif
+#ifdef MID_MUSIC
+#ifdef USE_TIMIDITY_MIDI
+ MidiSong *midi;
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ FluidSynthMidiSong *fluidsynthmidi;
+#endif
+#ifdef USE_NATIVE_MIDI
+ NativeMidiSong *nativemidi;
+#endif
+#endif
+#ifdef OGG_MUSIC
+ OGG_music *ogg;
+#endif
+#ifdef MP3_MUSIC
+ SMPEG *mp3;
+#endif
+#ifdef MP3_MAD_MUSIC
+ mad_data *mp3_mad;
+#endif
+#ifdef FLAC_MUSIC
+ FLAC_music *flac;
+#endif
+ } data;
+ Mix_Fading fading;
+ int fade_step;
+ int fade_steps;
+ int error;
+};
+#ifdef MID_MUSIC
+#ifdef USE_TIMIDITY_MIDI
+static int timidity_ok;
+static int samplesize;
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+static int fluidsynth_ok;
+#endif
+#ifdef USE_NATIVE_MIDI
+static int native_midi_ok;
+#endif
+#endif
+
+/* Used to calculate fading steps */
+static int ms_per_step;
+
+/* rcg06042009 report available decoders at runtime. */
+static const char **music_decoders = NULL;
+static int num_decoders = 0;
+
+/* Semicolon-separated SoundFont paths */
+#ifdef MID_MUSIC
+char* soundfont_paths = NULL;
+#endif
+
+int Mix_GetNumMusicDecoders(void)
+{
+ return(num_decoders);
+}
+
+const char *Mix_GetMusicDecoder(int index)
+{
+ if ((index < 0) || (index >= num_decoders)) {
+ return NULL;
+ }
+ return(music_decoders[index]);
+}
+
+static void add_music_decoder(const char *decoder)
+{
+ void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
+ if (ptr == NULL) {
+ return; /* oh well, go on without it. */
+ }
+ music_decoders = (const char **) ptr;
+ music_decoders[num_decoders++] = decoder;
+}
+
+/* Local low-level functions prototypes */
+static void music_internal_initialize_volume(void);
+static void music_internal_volume(int volume);
+static int music_internal_play(Mix_Music *music, double position);
+static int music_internal_position(double position);
+static int music_internal_playing();
+static void music_internal_halt(void);
+
+
+/* Support for hooking when the music has finished */
+static void (*music_finished_hook)(void) = NULL;
+
+void Mix_HookMusicFinished(void (*music_finished)(void))
+{
+ SDL_LockAudio();
+ music_finished_hook = music_finished;
+ SDL_UnlockAudio();
+}
+
+
+/* If music isn't playing, halt it if no looping is required, restart it */
+/* otherwhise. NOP if the music is playing */
+static int music_halt_or_loop (void)
+{
+ /* Restart music if it has to loop */
+
+ if (!music_internal_playing())
+ {
+#ifdef USE_NATIVE_MIDI
+ /* Native MIDI handles looping internally */
+ if (music_playing->type == MUS_MID && native_midi_ok) {
+ music_loops = 0;
+ }
+#endif
+
+ /* Restart music if it has to loop at a high level */
+ if (music_loops)
+ {
+ Mix_Fading current_fade;
+ --music_loops;
+ current_fade = music_playing->fading;
+ music_internal_play(music_playing, 0.0);
+ music_playing->fading = current_fade;
+ }
+ else
+ {
+ music_internal_halt();
+ if (music_finished_hook)
+ music_finished_hook();
+
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+
+/* Mixing function */
+void music_mixer(void *udata, Uint8 *stream, int len)
+{
+ //printf("music_mixer() called!\n");
+ int left = 0;
+
+ if ( music_playing && music_active ) {
+ /* Handle fading */
+ if ( music_playing->fading != MIX_NO_FADING ) {
+ if ( music_playing->fade_step++ < music_playing->fade_steps ) {
+ int volume;
+ int fade_step = music_playing->fade_step;
+ int fade_steps = music_playing->fade_steps;
+
+ if ( music_playing->fading == MIX_FADING_OUT ) {
+ volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
+ } else { /* Fading in */
+ volume = (music_volume * fade_step) / fade_steps;
+ }
+ music_internal_volume(volume);
+ } else {
+ if ( music_playing->fading == MIX_FADING_OUT ) {
+ music_internal_halt();
+ if ( music_finished_hook ) {
+ music_finished_hook();
+ }
+ return;
+ }
+ music_playing->fading = MIX_NO_FADING;
+ }
+ }
+
+ music_halt_or_loop();
+ if (!music_internal_playing())
+ return;
+
+ switch (music_playing->type) {
+#ifdef CMD_MUSIC
+ case MUS_CMD:
+ /* The playing is done externally */
+ break;
+#endif
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ left = WAVStream_PlaySome(stream, len);
+ break;
+#endif
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ left = modplug_playAudio(music_playing->data.modplug, stream, len);
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ left = MOD_playAudio(music_playing->data.module, stream, len);
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ /* Native midi is handled asynchronously */
+ goto skip;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_ok ) {
+ fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
+ goto skip;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ int samples = len / samplesize;
+ Timidity_PlaySome(stream, samples);
+ goto skip;
+ }
+#endif
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+
+ left = OGG_playAudio(music_playing->data.ogg, stream, len);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ left = FLAC_playAudio(music_playing->data.flac, stream, len);
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
+ break;
+#endif
+ default:
+ /* Unknown music type?? */
+ break;
+ }
+ }
+
+
+skip:
+ /* Handle seamless music looping */
+ if (left > 0 && left < len) {
+ music_halt_or_loop();
+ if (music_internal_playing())
+ music_mixer(udata, stream+(len-left), left);
+ }
+ //printf("sample 0: %d %d", stream[0], stream[1]);
+}
+
+/* Initialize the music players with a certain desired audio format */
+int open_music(SDL_AudioSpec *mixer)
+{
+#ifdef WAV_MUSIC
+ if ( WAVStream_Init(mixer) == 0 ) {
+ add_music_decoder("WAVE");
+ }
+#endif
+#ifdef MODPLUG_MUSIC
+ if ( modplug_init(mixer) == 0 ) {
+ add_music_decoder("MODPLUG");
+ }
+#endif
+#ifdef MOD_MUSIC
+ if ( MOD_init(mixer) == 0 ) {
+ add_music_decoder("MIKMOD");
+ }
+#endif
+#ifdef MID_MUSIC
+#ifdef USE_TIMIDITY_MIDI
+ samplesize = mixer->size / mixer->samples;
+ if ( Timidity_Init(mixer->freq, mixer->format,
+ mixer->channels, mixer->samples) == 0 ) {
+ timidity_ok = 1;
+ add_music_decoder("TIMIDITY");
+ } else {
+ timidity_ok = 0;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_init(mixer) == 0 ) {
+ fluidsynth_ok = 1;
+ add_music_decoder("FLUIDSYNTH");
+ } else {
+ fluidsynth_ok = 0;
+ }
+#endif
+#ifdef USE_NATIVE_MIDI
+#ifdef USE_FLUIDSYNTH_MIDI
+ native_midi_ok = !fluidsynth_ok;
+ if ( native_midi_ok )
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ native_midi_ok = !timidity_ok;
+ if ( !native_midi_ok ) {
+ native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
+ }
+ if ( native_midi_ok )
+#endif
+ native_midi_ok = native_midi_detect();
+ if ( native_midi_ok )
+ add_music_decoder("NATIVEMIDI");
+#endif
+#endif
+#ifdef OGG_MUSIC
+ if ( OGG_init(mixer) == 0 ) {
+ add_music_decoder("OGG");
+ }
+#endif
+#ifdef FLAC_MUSIC
+ if ( FLAC_init(mixer) == 0 ) {
+ add_music_decoder("FLAC");
+ }
+#endif
+#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
+ /* Keep a copy of the mixer */
+ used_mixer = *mixer;
+ add_music_decoder("MP3");
+#endif
+
+ music_playing = NULL;
+ music_stopped = 0;
+ Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
+
+ /* Calculate the number of ms for each callback */
+ ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
+
+ return(0);
+}
+
+/* Portable case-insensitive string compare function */
+int MIX_string_equals(const char *str1, const char *str2)
+{
+ while ( *str1 && *str2 ) {
+ if ( toupper((unsigned char)*str1) !=
+ toupper((unsigned char)*str2) )
+ break;
+ ++str1;
+ ++str2;
+ }
+ return (!*str1 && !*str2);
+}
+
+static int detect_mp3(Uint8 *magic)
+{
+ if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
+ return 1;
+ }
+
+ /* Detection code lifted from SMPEG */
+ if(((magic[0] & 0xff) != 0xff) || // No sync bits
+ ((magic[1] & 0xf0) != 0xf0) || //
+ ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
+ ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
+ ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
+ ((magic[1] & 0x06) == 0x00)) { // Layer is 4
+ return(0);
+ }
+ return 1;
+}
+
+/* MUS_MOD can't be auto-detected. If no other format was detected, MOD is
+ * assumed and MUS_MOD will be returned, meaning that the format might not
+ * actually be MOD-based.
+ *
+ * Returns MUS_NONE in case of errors. */
+static Mix_MusicType detect_music_type(SDL_RWops *rw)
+{
+ Uint8 magic[5];
+ Uint8 moremagic[9];
+
+ int start = SDL_RWtell(rw);
+ if (SDL_RWread(rw, magic, 1, 4) != 4 || SDL_RWread(rw, moremagic, 1, 8) != 8 ) {
+ Mix_SetError("Couldn't read from RWops");
+ return MUS_NONE;
+ }
+ SDL_RWseek(rw, start, RW_SEEK_SET);
+ magic[4]='\0';
+ moremagic[8] = '\0';
+
+ /* WAVE files have the magic four bytes "RIFF"
+ AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
+ if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
+ (strcmp((char *)magic, "FORM") == 0)) {
+ return MUS_WAV;
+ }
+
+ /* Ogg Vorbis files have the magic four bytes "OggS" */
+ if (strcmp((char *)magic, "OggS") == 0) {
+ return MUS_OGG;
+ }
+
+ /* FLAC files have the magic four bytes "fLaC" */
+ if (strcmp((char *)magic, "fLaC") == 0) {
+ return MUS_FLAC;
+ }
+
+ /* MIDI files have the magic four bytes "MThd" */
+ if (strcmp((char *)magic, "MThd") == 0) {
+ return MUS_MID;
+ }
+
+ if (detect_mp3(magic)) {
+ return MUS_MP3;
+ }
+
+ /* Assume MOD format.
+ *
+ * Apparently there is no way to check if the file is really a MOD,
+ * or there are too many formats supported by MikMod/ModPlug, or
+ * MikMod/ModPlug does this check by itself. */
+ return MUS_MOD;
+}
+
+/* Load a music file */
+Mix_Music *Mix_LoadMUS(const char *file)
+{
+ SDL_RWops *rw;
+ Mix_Music *music;
+ Mix_MusicType type;
+ char *ext = strrchr(file, '.');
+
+#ifdef CMD_MUSIC
+ if ( music_cmd ) {
+ /* Allocate memory for the music structure */
+ music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
+ if ( music == NULL ) {
+ Mix_SetError("Out of memory");
+ return(NULL);
+ }
+ music->error = 0;
+ music->type = MUS_CMD;
+ music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
+ if ( music->data.cmd == NULL ) {
+ SDL_free(music);
+ music == NULL;
+ }
+ return music;
+ }
+#endif
+
+ rw = SDL_RWFromFile(file, "rb");
+ if ( rw == NULL ) {
+ Mix_SetError("Couldn't open '%s'", file);
+ return NULL;
+ }
+
+ /* Use the extension as a first guess on the file type */
+ type = MUS_NONE;
+ ext = strrchr(file, '.');
+ /* No need to guard these with #ifdef *_MUSIC stuff,
+ * since we simply call Mix_LoadMUSType_RW() later */
+ if ( ext ) {
+ ++ext; /* skip the dot in the extension */
+ if ( MIX_string_equals(ext, "WAV") ) {
+ type = MUS_WAV;
+ } else if ( MIX_string_equals(ext, "MID") ||
+ MIX_string_equals(ext, "MIDI") ||
+ MIX_string_equals(ext, "KAR") ) {
+ type = MUS_MID;
+ } else if ( MIX_string_equals(ext, "OGG") ) {
+ type = MUS_OGG;
+ } else if ( MIX_string_equals(ext, "FLAC") ) {
+ type = MUS_FLAC;
+ } else if ( MIX_string_equals(ext, "MPG") ||
+ MIX_string_equals(ext, "MPEG") ||
+ MIX_string_equals(ext, "MP3") ||
+ MIX_string_equals(ext, "MAD") ) {
+ type = MUS_MP3;
+ }
+ }
+ if ( type == MUS_NONE ) {
+ type = detect_music_type(rw);
+ }
+
+ /* We need to know if a specific error occurs; if not, we'll set a
+ * generic one, so we clear the current one. */
+ Mix_SetError("");
+ music = Mix_LoadMUSType_RW(rw, type, SDL_TRUE);
+ if ( music == NULL && Mix_GetError()[0] == '\0' ) {
+ SDL_FreeRW(rw);
+ Mix_SetError("Couldn't open '%s'", file);
+ }
+ return music;
+}
+
+Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
+{
+ return Mix_LoadMUSType_RW(rw, MUS_NONE, SDL_FALSE);
+}
+
+Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc)
+{
+ Mix_Music *music;
+
+ if (!rw) {
+ Mix_SetError("RWops pointer is NULL");
+ return NULL;
+ }
+
+ /* If the caller wants auto-detection, figure out what kind of file
+ * this is. */
+ if (type == MUS_NONE) {
+ if ((type = detect_music_type(rw)) == MUS_NONE) {
+ /* Don't call Mix_SetError() here since detect_music_type()
+ * does that. */
+ return NULL;
+ }
+ }
+
+ /* Allocate memory for the music structure */
+ music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
+ if (music == NULL ) {
+ Mix_SetError("Out of memory");
+ return NULL;
+ }
+ music->error = 0;
+
+ switch (type) {
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ /* The WAVE loader needs the first 4 bytes of the header */
+ {
+ Uint8 magic[5];
+ int start = SDL_RWtell(rw);
+ if (SDL_RWread(rw, magic, 1, 4) != 4) {
+ Mix_SetError("Couldn't read from RWops");
+ return MUS_NONE;
+ }
+ SDL_RWseek(rw, start, RW_SEEK_SET);
+ magic[4] = '\0';
+ music->type = MUS_WAV;
+ music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freesrc);
+ }
+ if (music->data.wave == NULL) {
+ music->error = 1;
+ }
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ music->type = MUS_OGG;
+ music->data.ogg = OGG_new_RW(rw, freesrc);
+ if ( music->data.ogg == NULL ) {
+ music->error = 1;
+ }
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ music->type = MUS_FLAC;
+ music->data.flac = FLAC_new_RW(rw, freesrc);
+ if ( music->data.flac == NULL ) {
+ music->error = 1;
+ }
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ if ( Mix_Init(MIX_INIT_MP3) ) {
+ SMPEG_Info info;
+ music->type = MUS_MP3;
+ music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
+ if ( !info.has_audio ) {
+ Mix_SetError("MPEG file does not have any audio stream.");
+ music->error = 1;
+ } else {
+ smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
+ }
+ } else {
+ music->error = 1;
+ }
+ break;
+#elif defined(MP3_MAD_MUSIC)
+ case MUS_MP3:
+ music->type = MUS_MP3_MAD;
+ music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freesrc);
+ if (music->data.mp3_mad == 0) {
+ Mix_SetError("Could not initialize MPEG stream.");
+ music->error = 1;
+ }
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+ music->type = MUS_MID;
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ music->data.nativemidi = native_midi_loadsong_RW(rw, freesrc);
+ if ( music->data.nativemidi == NULL ) {
+ Mix_SetError("%s", native_midi_error());
+ music->error = 1;
+ }
+ break;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_ok ) {
+ music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freesrc);
+ if ( music->data.fluidsynthmidi == NULL ) {
+ music->error = 1;
+ }
+ break;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ music->data.midi = Timidity_LoadSong_RW(rw, freesrc);
+ if ( music->data.midi == NULL ) {
+ Mix_SetError("%s", Timidity_Error());
+ music->error = 1;
+ }
+ //else
+ //printf("Timidity successfully loaded song!\n");
+ } else {
+ Mix_SetError("%s", Timidity_Error());
+ music->error = 1;
+ }
+#endif
+ break;
+#endif
+#if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
+ case MUS_MOD:
+ music->error = 1;
+#ifdef MODPLUG_MUSIC
+ if ( music->error ) {
+ music->type = MUS_MODPLUG;
+ music->data.modplug = modplug_new_RW(rw, freesrc);
+ if ( music->data.modplug ) {
+ music->error = 0;
+ }
+ }
+#endif
+#ifdef MOD_MUSIC
+ if ( music->error ) {
+ music->type = MUS_MOD;
+ music->data.module = MOD_new_RW(rw, freesrc);
+ if ( music->data.module ) {
+ music->error = 0;
+ }
+ }
+#endif
+ break;
+#endif
+
+ default:
+ Mix_SetError("Unrecognized music format");
+ music->error=1;
+ } /* switch (want) */
+
+
+ if (music->error) {
+ SDL_free(music);
+ music=NULL;
+ }
+ return(music);
+}
+
+/* Free a music chunk previously loaded */
+void Mix_FreeMusic(Mix_Music *music)
+{
+ if ( music ) {
+ /* Stop the music if it's currently playing */
+ SDL_LockAudio();
+ if ( music == music_playing ) {
+ /* Wait for any fade out to finish */
+ while ( music->fading == MIX_FADING_OUT ) {
+ SDL_UnlockAudio();
+ SDL_Delay(100);
+ SDL_LockAudio();
+ }
+ if ( music == music_playing ) {
+ music_internal_halt();
+ }
+ }
+ SDL_UnlockAudio();
+ switch (music->type) {
+#ifdef CMD_MUSIC
+ case MUS_CMD:
+ MusicCMD_FreeSong(music->data.cmd);
+ break;
+#endif
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ WAVStream_FreeSong(music->data.wave);
+ break;
+#endif
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ modplug_delete(music->data.modplug);
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ MOD_delete(music->data.module);
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ native_midi_freesong(music->data.nativemidi);
+ goto skip;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_ok ) {
+ fluidsynth_freesong(music->data.fluidsynthmidi);
+ goto skip;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ Timidity_FreeSong(music->data.midi);
+ goto skip;
+ }
+#endif
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ OGG_delete(music->data.ogg);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ FLAC_delete(music->data.flac);
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ smpeg.SMPEG_delete(music->data.mp3);
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ mad_closeFile(music->data.mp3_mad);
+ break;
+#endif
+ default:
+ /* Unknown music type?? */
+ break;
+ }
+
+ skip:
+ SDL_free(music);
+ }
+}
+
+/* Find out the music format of a mixer music, or the currently playing
+ music, if 'music' is NULL.
+*/
+Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
+{
+ Mix_MusicType type = MUS_NONE;
+
+ if ( music ) {
+ type = music->type;
+ } else {
+ SDL_LockAudio();
+ if ( music_playing ) {
+ type = music_playing->type;
+ }
+ SDL_UnlockAudio();
+ }
+ return(type);
+}
+
+/* Play a music chunk. Returns 0, or -1 if there was an error.
+ */
+static int music_internal_play(Mix_Music *music, double position)
+{
+ int retval = 0;
+
+#if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
+ /* This fixes a bug with native MIDI on Mac OS X, where you
+ can't really stop and restart MIDI from the audio callback.
+ */
+ if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
+ /* Just a seek suffices to restart playing */
+ music_internal_position(position);
+ return 0;
+ }
+#endif
+
+ /* Note the music we're playing */
+ if ( music_playing ) {
+ music_internal_halt();
+ }
+ music_playing = music;
+
+ /* Set the initial volume */
+ if ( music->type != MUS_MOD ) {
+ music_internal_initialize_volume();
+ }
+
+ /* Set up for playback */
+ switch (music->type) {
+#ifdef CMD_MUSIC
+ case MUS_CMD:
+ MusicCMD_Start(music->data.cmd);
+ break;
+#endif
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ WAVStream_Start(music->data.wave);
+ break;
+#endif
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ /* can't set volume until file is loaded, so finally set it now */
+ music_internal_initialize_volume();
+ modplug_play(music->data.modplug);
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ MOD_play(music->data.module);
+ /* Player_SetVolume() does nothing before Player_Start() */
+ music_internal_initialize_volume();
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ native_midi_start(music->data.nativemidi, music_loops);
+ goto skip;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if (fluidsynth_ok ) {
+ fluidsynth_start(music->data.fluidsynthmidi);
+ goto skip;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ Timidity_Start(music->data.midi);
+ goto skip;
+ }
+#endif
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ OGG_play(music->data.ogg);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ FLAC_play(music->data.flac);
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ smpeg.SMPEG_enableaudio(music->data.mp3,1);
+ smpeg.SMPEG_enablevideo(music->data.mp3,0);
+ smpeg.SMPEG_play(music_playing->data.mp3);
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ mad_start(music->data.mp3_mad);
+ break;
+#endif
+ default:
+ Mix_SetError("Can't play unknown music type");
+ retval = -1;
+ break;
+ }
+
+skip:
+ /* Set the playback position, note any errors if an offset is used */
+ if ( retval == 0 ) {
+ if ( position > 0.0 ) {
+ if ( music_internal_position(position) < 0 ) {
+ Mix_SetError("Position not implemented for music type");
+ retval = -1;
+ }
+ } else {
+ music_internal_position(0.0);
+ }
+ }
+
+ /* If the setup failed, we're not playing any music anymore */
+ if ( retval < 0 ) {
+ music_playing = NULL;
+ }
+ return(retval);
+}
+int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
+{
+ int retval;
+
+ if ( ms_per_step == 0 ) {
+ SDL_SetError("Audio device hasn't been opened");
+ return(-1);
+ }
+
+ /* Don't play null pointers :-) */
+ if ( music == NULL ) {
+ Mix_SetError("music parameter was NULL");
+ return(-1);
+ }
+
+ /* Setup the data */
+ if ( ms ) {
+ music->fading = MIX_FADING_IN;
+ } else {
+ music->fading = MIX_NO_FADING;
+ }
+ music->fade_step = 0;
+ music->fade_steps = ms/ms_per_step;
+
+ /* Play the puppy */
+ SDL_LockAudio();
+ /* If the current music is fading out, wait for the fade to complete */
+ while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
+ SDL_UnlockAudio();
+ SDL_Delay(100);
+ SDL_LockAudio();
+ }
+ music_active = 1;
+ if (loops == 1) {
+ /* Loop is the number of times to play the audio */
+ loops = 0;
+ }
+ music_loops = loops;
+ retval = music_internal_play(music, position);
+ SDL_UnlockAudio();
+
+ return(retval);
+}
+int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
+{
+ return Mix_FadeInMusicPos(music, loops, ms, 0.0);
+}
+int Mix_PlayMusic(Mix_Music *music, int loops)
+{
+ return Mix_FadeInMusicPos(music, loops, 0, 0.0);
+}
+
+/* Set the playing music position */
+int music_internal_position(double position)
+{
+ int retval = 0;
+
+ switch (music_playing->type) {
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ modplug_jump_to_time(music_playing->data.modplug, position);
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ MOD_jump_to_time(music_playing->data.module, position);
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ OGG_jump_to_time(music_playing->data.ogg, position);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ FLAC_jump_to_time(music_playing->data.flac, position);
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ smpeg.SMPEG_rewind(music_playing->data.mp3);
+ smpeg.SMPEG_play(music_playing->data.mp3);
+ if ( position > 0.0 ) {
+ smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
+ }
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ mad_seek(music_playing->data.mp3_mad, position);
+ break;
+#endif
+ default:
+ /* TODO: Implement this for other music backends */
+ retval = -1;
+ break;
+ }
+ return(retval);
+}
+int Mix_SetMusicPosition(double position)
+{
+ int retval;
+
+ SDL_LockAudio();
+ if ( music_playing ) {
+ retval = music_internal_position(position);
+ if ( retval < 0 ) {
+ Mix_SetError("Position not implemented for music type");
+ }
+ } else {
+ Mix_SetError("Music isn't playing");
+ retval = -1;
+ }
+ SDL_UnlockAudio();
+
+ return(retval);
+}
+
+/* Set the music's initial volume */
+static void music_internal_initialize_volume(void)
+{
+ if ( music_playing->fading == MIX_FADING_IN ) {
+ music_internal_volume(0);
+ } else {
+ music_internal_volume(music_volume);
+ }
+}
+
+/* Set the music volume */
+static void music_internal_volume(int volume)
+{
+ switch (music_playing->type) {
+#ifdef CMD_MUSIC
+ case MUS_CMD:
+ MusicCMD_SetVolume(volume);
+ break;
+#endif
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ WAVStream_SetVolume(volume);
+ break;
+#endif
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ modplug_setvolume(music_playing->data.modplug, volume);
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ MOD_setvolume(music_playing->data.module, volume);
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ native_midi_setvolume(volume);
+ return;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_ok ) {
+ fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
+ return;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ Timidity_SetVolume(volume);
+ return;
+ }
+#endif
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ OGG_setvolume(music_playing->data.ogg, volume);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ FLAC_setvolume(music_playing->data.flac, volume);
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ mad_setVolume(music_playing->data.mp3_mad, volume);
+ break;
+#endif
+ default:
+ /* Unknown music type?? */
+ break;
+ }
+}
+int Mix_VolumeMusic(int volume)
+{
+ int prev_volume;
+
+ prev_volume = music_volume;
+ if ( volume < 0 ) {
+ return prev_volume;
+ }
+ if ( volume > SDL_MIX_MAXVOLUME ) {
+ volume = SDL_MIX_MAXVOLUME;
+ }
+ music_volume = volume;
+ SDL_LockAudio();
+ if ( music_playing ) {
+ music_internal_volume(music_volume);
+ }
+ SDL_UnlockAudio();
+ return(prev_volume);
+}
+
+/* Halt playing of music */
+static void music_internal_halt(void)
+{
+ switch (music_playing->type) {
+#ifdef CMD_MUSIC
+ case MUS_CMD:
+ MusicCMD_Stop(music_playing->data.cmd);
+ break;
+#endif
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ WAVStream_Stop();
+ break;
+#endif
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ modplug_stop(music_playing->data.modplug);
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ MOD_stop(music_playing->data.module);
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ native_midi_stop();
+ goto skip;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_ok ) {
+ fluidsynth_stop(music_playing->data.fluidsynthmidi);
+ goto skip;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ Timidity_Stop();
+ goto skip;
+ }
+#endif
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ OGG_stop(music_playing->data.ogg);
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ FLAC_stop(music_playing->data.flac);
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ smpeg.SMPEG_stop(music_playing->data.mp3);
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ mad_stop(music_playing->data.mp3_mad);
+ break;
+#endif
+ default:
+ /* Unknown music type?? */
+ return;
+ }
+
+skip:
+ music_playing->fading = MIX_NO_FADING;
+ music_playing = NULL;
+}
+int Mix_HaltMusic(void)
+{
+ SDL_LockAudio();
+ if ( music_playing ) {
+ music_internal_halt();
+ }
+ SDL_UnlockAudio();
+
+ return(0);
+}
+
+/* Progressively stop the music */
+int Mix_FadeOutMusic(int ms)
+{
+ int retval = 0;
+
+ if ( ms_per_step == 0 ) {
+ SDL_SetError("Audio device hasn't been opened");
+ return 0;
+ }
+
+ if (ms <= 0) { /* just halt immediately. */
+ Mix_HaltMusic();
+ return 1;
+ }
+
+ SDL_LockAudio();
+ if ( music_playing) {
+ int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
+ if ( music_playing->fading == MIX_NO_FADING ) {
+ music_playing->fade_step = 0;
+ } else {
+ int step;
+ int old_fade_steps = music_playing->fade_steps;
+ if ( music_playing->fading == MIX_FADING_OUT ) {
+ step = music_playing->fade_step;
+ } else {
+ step = old_fade_steps
+ - music_playing->fade_step + 1;
+ }
+ music_playing->fade_step = (step * fade_steps)
+ / old_fade_steps;
+ }
+ music_playing->fading = MIX_FADING_OUT;
+ music_playing->fade_steps = fade_steps;
+ retval = 1;
+ }
+ SDL_UnlockAudio();
+
+ return(retval);
+}
+
+Mix_Fading Mix_FadingMusic(void)
+{
+ Mix_Fading fading = MIX_NO_FADING;
+
+ SDL_LockAudio();
+ if ( music_playing ) {
+ fading = music_playing->fading;
+ }
+ SDL_UnlockAudio();
+
+ return(fading);
+}
+
+/* Pause/Resume the music stream */
+void Mix_PauseMusic(void)
+{
+ music_active = 0;
+}
+
+void Mix_ResumeMusic(void)
+{
+ music_active = 1;
+}
+
+void Mix_RewindMusic(void)
+{
+ Mix_SetMusicPosition(0.0);
+}
+
+int Mix_PausedMusic(void)
+{
+ return (music_active == 0);
+}
+
+/* Check the status of the music */
+static int music_internal_playing()
+{
+ int playing = 1;
+
+ if (music_playing == NULL) {
+ return 0;
+ }
+
+ switch (music_playing->type) {
+#ifdef CMD_MUSIC
+ case MUS_CMD:
+ if (!MusicCMD_Active(music_playing->data.cmd)) {
+ playing = 0;
+ }
+ break;
+#endif
+#ifdef WAV_MUSIC
+ case MUS_WAV:
+ if ( ! WAVStream_Active() ) {
+ playing = 0;
+ }
+ break;
+#endif
+#ifdef MODPLUG_MUSIC
+ case MUS_MODPLUG:
+ if ( ! modplug_playing(music_playing->data.modplug) ) {
+ playing = 0;
+ }
+ break;
+#endif
+#ifdef MOD_MUSIC
+ case MUS_MOD:
+ if ( ! MOD_playing(music_playing->data.module) ) {
+ playing = 0;
+ }
+ break;
+#endif
+#ifdef MID_MUSIC
+ case MUS_MID:
+#ifdef USE_NATIVE_MIDI
+ if ( native_midi_ok ) {
+ if ( ! native_midi_active() )
+ playing = 0;
+ goto skip;
+ }
+#endif
+#ifdef USE_FLUIDSYNTH_MIDI
+ if ( fluidsynth_ok ) {
+ if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
+ playing = 0;
+ goto skip;
+ }
+#endif
+#ifdef USE_TIMIDITY_MIDI
+ if ( timidity_ok ) {
+ if ( ! Timidity_Active() )
+ playing = 0;
+ goto skip;
+ }
+#endif
+ break;
+#endif
+#ifdef OGG_MUSIC
+ case MUS_OGG:
+ if ( ! OGG_playing(music_playing->data.ogg) ) {
+ playing = 0;
+ }
+ break;
+#endif
+#ifdef FLAC_MUSIC
+ case MUS_FLAC:
+ if ( ! FLAC_playing(music_playing->data.flac) ) {
+ playing = 0;
+ }
+ break;
+#endif
+#ifdef MP3_MUSIC
+ case MUS_MP3:
+ if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
+ playing = 0;
+ break;
+#endif
+#ifdef MP3_MAD_MUSIC
+ case MUS_MP3_MAD:
+ if (!mad_isPlaying(music_playing->data.mp3_mad)) {
+ playing = 0;
+ }
+ break;
+#endif
+ default:
+ playing = 0;
+ break;
+ }
+
+skip:
+ return(playing);
+}
+int Mix_PlayingMusic(void)
+{
+ int playing = 0;
+
+ SDL_LockAudio();
+ if ( music_playing ) {
+ playing = music_loops || music_internal_playing();
+ }
+ SDL_UnlockAudio();
+
+ return(playing);
+}
+
+/* Set the external music playback command */
+int Mix_SetMusicCMD(const char *command)
+{
+ Mix_HaltMusic();
+ if ( music_cmd ) {
+ SDL_free(music_cmd);
+ music_cmd = NULL;
+ }
+ if ( command ) {
+ music_cmd = (char *)SDL_malloc(strlen(command)+1);
+ if ( music_cmd == NULL ) {
+ return(-1);
+ }
+ strcpy(music_cmd, command);
+ }
+ return(0);
+}
+
+int Mix_SetSynchroValue(int i)
+{
+ /* Not supported by any players at this time */
+ return(-1);
+}
+
+int Mix_GetSynchroValue(void)
+{
+ /* Not supported by any players at this time */
+ return(-1);
+}
+
+
+/* Uninitialize the music players */
+void close_music(void)
+{
+ Mix_HaltMusic();
+#ifdef CMD_MUSIC
+ Mix_SetMusicCMD(NULL);
+#endif
+#ifdef MODPLUG_MUSIC
+ modplug_exit();
+#endif
+#ifdef MOD_MUSIC
+ MOD_exit();
+#endif
+#ifdef MID_MUSIC
+# ifdef USE_TIMIDITY_MIDI
+ Timidity_Close();
+# endif
+#endif
+
+ /* rcg06042009 report available decoders at runtime. */
+ SDL_free(music_decoders);
+ music_decoders = NULL;
+ num_decoders = 0;
+
+ ms_per_step = 0;
+}
+
+int Mix_SetSoundFonts(const char *paths)
+{
+#ifdef MID_MUSIC
+ if (soundfont_paths) {
+ SDL_free(soundfont_paths);
+ soundfont_paths = NULL;
+ }
+
+ if (paths) {
+ if (!(soundfont_paths = SDL_strdup(paths))) {
+ Mix_SetError("Insufficient memory to set SoundFonts");
+ return 0;
+ }
+ }
+#endif
+ return 1;
+}
+
+#ifdef MID_MUSIC
+const char* Mix_GetSoundFonts(void)
+{
+ const char* force = getenv("SDL_FORCE_SOUNDFONTS");
+
+ if (!soundfont_paths || (force && force[0] == '1')) {
+ return getenv("SDL_SOUNDFONTS");
+ } else {
+ return soundfont_paths;
+ }
+}
+
+int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
+{
+ char *context, *path, *paths;
+ const char* cpaths = Mix_GetSoundFonts();
+
+ if (!cpaths) {
+ Mix_SetError("No SoundFonts have been requested");
+ return 0;
+ }
+
+ if (!(paths = SDL_strdup(cpaths))) {
+ Mix_SetError("Insufficient memory to iterate over SoundFonts");
+ return 0;
+ }
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
+#elif defined(_WIN32)
+ for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
+#else
+ for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
+#endif
+ if (!function(path, data)) {
+ SDL_free(paths);
+ return 0;
+ }
+ }
+
+ SDL_free(paths);
+ return 1;
+}
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/music_cmd.c b/apps/plugins/sdl/SDL_mixer/music_cmd.c
new file mode 100644
index 0000000000..968794b3fb
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_cmd.c
@@ -0,0 +1,241 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+/* This file supports an external command for playing music */
+
+#ifdef CMD_MUSIC
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+
+#include "SDL_mixer.h"
+#include "music_cmd.h"
+
+/* Unimplemented */
+void MusicCMD_SetVolume(int volume)
+{
+ Mix_SetError("No way to modify external player volume");
+}
+
+/* Load a music stream from the given file */
+MusicCMD *MusicCMD_LoadSong(const char *cmd, const char *file)
+{
+ MusicCMD *music;
+
+ /* Allocate and fill the music structure */
+ music = (MusicCMD *)SDL_malloc(sizeof *music);
+ if ( music == NULL ) {
+ Mix_SetError("Out of memory");
+ return(NULL);
+ }
+ strncpy(music->file, file, (sizeof music->file)-1);
+ music->file[(sizeof music->file)-1] = '\0';
+ strncpy(music->cmd, cmd, (sizeof music->cmd)-1);
+ music->cmd[(sizeof music->cmd)-1] = '\0';
+ music->pid = 0;
+
+ /* We're done */
+ return(music);
+}
+
+/* Parse a command line buffer into arguments */
+static int ParseCommandLine(char *cmdline, char **argv)
+{
+ char *bufp;
+ int argc;
+
+ argc = 0;
+ for ( bufp = cmdline; *bufp; ) {
+ /* Skip leading whitespace */
+ while ( isspace(*bufp) ) {
+ ++bufp;
+ }
+ /* Skip over argument */
+ if ( *bufp == '"' ) {
+ ++bufp;
+ if ( *bufp ) {
+ if ( argv ) {
+ argv[argc] = bufp;
+ }
+ ++argc;
+ }
+ /* Skip over word */
+ while ( *bufp && (*bufp != '"') ) {
+ ++bufp;
+ }
+ } else {
+ if ( *bufp ) {
+ if ( argv ) {
+ argv[argc] = bufp;
+ }
+ ++argc;
+ }
+ /* Skip over word */
+ while ( *bufp && ! isspace(*bufp) ) {
+ ++bufp;
+ }
+ }
+ if ( *bufp ) {
+ if ( argv ) {
+ *bufp = '\0';
+ }
+ ++bufp;
+ }
+ }
+ if ( argv ) {
+ argv[argc] = NULL;
+ }
+ return(argc);
+}
+
+static char **parse_args(char *command, char *last_arg)
+{
+ int argc;
+ char **argv;
+
+ /* Parse the command line */
+ argc = ParseCommandLine(command, NULL);
+ if ( last_arg ) {
+ ++argc;
+ }
+ argv = (char **)SDL_malloc((argc+1)*(sizeof *argv));
+ if ( argv == NULL ) {
+ return(NULL);
+ }
+ argc = ParseCommandLine(command, argv);
+
+ /* Add last command line argument */
+ if ( last_arg ) {
+ argv[argc++] = last_arg;
+ }
+ argv[argc] = NULL;
+
+ /* We're ready! */
+ return(argv);
+}
+
+/* Start playback of a given music stream */
+void MusicCMD_Start(MusicCMD *music)
+{
+#ifdef HAVE_FORK
+ music->pid = fork();
+#else
+ music->pid = vfork();
+#endif
+ switch(music->pid) {
+ /* Failed fork() system call */
+ case -1:
+ Mix_SetError("fork() failed");
+ return;
+
+ /* Child process - executes here */
+ case 0: {
+ char command[PATH_MAX];
+ char **argv;
+
+ /* Unblock signals in case we're called from a thread */
+ {
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ }
+
+ /* Execute the command */
+ strcpy(command, music->cmd);
+ argv = parse_args(command, music->file);
+ if ( argv != NULL ) {
+ execvp(argv[0], argv);
+ }
+
+ /* exec() failed */
+ perror(argv[0]);
+ _exit(-1);
+ }
+ break;
+
+ /* Parent process - executes here */
+ default:
+ break;
+ }
+ return;
+}
+
+/* Stop playback of a stream previously started with MusicCMD_Start() */
+void MusicCMD_Stop(MusicCMD *music)
+{
+ int status;
+
+ if ( music->pid > 0 ) {
+ while ( kill(music->pid, 0) == 0 ) {
+ kill(music->pid, SIGTERM);
+ sleep(1);
+ waitpid(music->pid, &status, WNOHANG);
+ }
+ music->pid = 0;
+ }
+}
+
+/* Pause playback of a given music stream */
+void MusicCMD_Pause(MusicCMD *music)
+{
+ if ( music->pid > 0 ) {
+ kill(music->pid, SIGSTOP);
+ }
+}
+
+/* Resume playback of a given music stream */
+void MusicCMD_Resume(MusicCMD *music)
+{
+ if ( music->pid > 0 ) {
+ kill(music->pid, SIGCONT);
+ }
+}
+
+/* Close the given music stream */
+void MusicCMD_FreeSong(MusicCMD *music)
+{
+ SDL_free(music);
+}
+
+/* Return non-zero if a stream is currently playing */
+int MusicCMD_Active(MusicCMD *music)
+{
+ int status;
+ int active;
+
+ active = 0;
+ if ( music->pid > 0 ) {
+ waitpid(music->pid, &status, WNOHANG);
+ if ( kill(music->pid, 0) == 0 ) {
+ active = 1;
+ }
+ }
+ return(active);
+}
+
+#endif /* CMD_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_cmd.h b/apps/plugins/sdl/SDL_mixer/music_cmd.h
new file mode 100644
index 0000000000..10168deaa0
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_cmd.h
@@ -0,0 +1,62 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* This file supports an external command for playing music */
+
+#ifdef CMD_MUSIC
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdio.h>
+#if defined(__linux__) && defined(__arm__)
+# include <linux/limits.h>
+#endif
+typedef struct {
+ char file[PATH_MAX];
+ char cmd[PATH_MAX];
+ pid_t pid;
+} MusicCMD;
+
+/* Unimplemented */
+extern void MusicCMD_SetVolume(int volume);
+
+/* Load a music stream from the given file */
+extern MusicCMD *MusicCMD_LoadSong(const char *cmd, const char *file);
+
+/* Start playback of a given music stream */
+extern void MusicCMD_Start(MusicCMD *music);
+
+/* Stop playback of a stream previously started with MusicCMD_Start() */
+extern void MusicCMD_Stop(MusicCMD *music);
+
+/* Pause playback of a given music stream */
+extern void MusicCMD_Pause(MusicCMD *music);
+
+/* Resume playback of a given music stream */
+extern void MusicCMD_Resume(MusicCMD *music);
+
+/* Close the given music stream */
+extern void MusicCMD_FreeSong(MusicCMD *music);
+
+/* Return non-zero if a stream is currently playing */
+extern int MusicCMD_Active(MusicCMD *music);
+
+#endif /* CMD_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_flac.c b/apps/plugins/sdl/SDL_mixer/music_flac.c
new file mode 100644
index 0000000000..e2ffc573eb
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_flac.c
@@ -0,0 +1,593 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This file is used to support SDL_LoadMUS playback of FLAC files.
+ ~ Austen Dicken (admin@cvpcs.org)
+*/
+
+#ifdef FLAC_MUSIC
+
+#include "SDL_mixer.h"
+#include "dynamic_flac.h"
+#include "music_flac.h"
+
+/* This is the format of the audio mixer data */
+static SDL_AudioSpec mixer;
+
+/* Initialize the FLAC player, with the given mixer settings
+ This function returns 0, or -1 if there was an error.
+ */
+int FLAC_init(SDL_AudioSpec *mixerfmt)
+{
+ mixer = *mixerfmt;
+ return(0);
+}
+
+/* Set the volume for an FLAC stream */
+void FLAC_setvolume(FLAC_music *music, int volume)
+{
+ music->volume = volume;
+}
+
+static FLAC__StreamDecoderReadStatus flac_read_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__byte buffer[],
+ size_t *bytes,
+ void *client_data)
+{
+ FLAC_music *data = (FLAC_music*)client_data;
+
+ // make sure there is something to be reading
+ if (*bytes > 0) {
+ *bytes = SDL_RWread (data->rwops, buffer, sizeof (FLAC__byte), *bytes);
+
+ if (*bytes < 0) { // error in read
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+ else if (*bytes == 0 ) { // no data was read (EOF)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+ else { // data was read, continue
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ }
+ else {
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+}
+
+static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__uint64 absolute_byte_offset,
+ void *client_data)
+{
+ FLAC_music *data = (FLAC_music*)client_data;
+
+ if (SDL_RWseek (data->rwops, absolute_byte_offset, RW_SEEK_SET) < 0) {
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+ else {
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ }
+}
+
+static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__uint64 *absolute_byte_offset,
+ void *client_data )
+{
+ FLAC_music *data = (FLAC_music*)client_data;
+
+ int pos = SDL_RWtell (data->rwops);
+
+ if (pos < 0) {
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+ else {
+ *absolute_byte_offset = (FLAC__uint64)pos;
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+}
+
+static FLAC__StreamDecoderLengthStatus flac_length_music_cb (
+ const FLAC__StreamDecoder *decoder,
+ FLAC__uint64 *stream_length,
+ void *client_data)
+{
+ FLAC_music *data = (FLAC_music*)client_data;
+
+ int pos = SDL_RWtell (data->rwops);
+ int length = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
+
+ if (SDL_RWseek (data->rwops, pos, RW_SEEK_SET) != pos || length < 0) {
+ /* there was an error attempting to return the stream to the original
+ * position, or the length was invalid. */
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ }
+ else {
+ *stream_length = (FLAC__uint64)length;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ }
+}
+
+static FLAC__bool flac_eof_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ void *client_data )
+{
+ FLAC_music *data = (FLAC_music*)client_data;
+
+ int pos = SDL_RWtell (data->rwops);
+ int end = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
+
+ // was the original position equal to the end (a.k.a. the seek didn't move)?
+ if (pos == end) {
+ // must be EOF
+ return true;
+ }
+ else {
+ // not EOF, return to the original position
+ SDL_RWseek (data->rwops, pos, RW_SEEK_SET);
+
+ return false;
+ }
+}
+
+static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 *const buffer[],
+ void *client_data)
+{
+ FLAC_music *data = (FLAC_music *)client_data;
+ size_t i;
+
+ if (data->flac_data.total_samples == 0) {
+ SDL_SetError ("Given FLAC file does not specify its sample count.");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if (data->flac_data.channels != 2 ||
+ data->flac_data.bits_per_sample != 16) {
+ SDL_SetError("Current FLAC support is only for 16 bit Stereo files.");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ for (i = 0; i < frame->header.blocksize; i++) {
+ FLAC__int16 i16;
+ FLAC__uint16 ui16;
+
+ // make sure we still have at least two bytes that can be read (one for
+ // each channel)
+ if (data->flac_data.max_to_read >= 4) {
+ // does the data block exist?
+ if (!data->flac_data.data) {
+ data->flac_data.data_len = data->flac_data.max_to_read;
+ data->flac_data.data_read = 0;
+
+ // create it
+ data->flac_data.data =
+ (char *)SDL_malloc (data->flac_data.data_len);
+
+ if (!data->flac_data.data) {
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ }
+
+ i16 = (FLAC__int16)buffer[0][i];
+ ui16 = (FLAC__uint16)i16;
+
+ *((data->flac_data.data) + (data->flac_data.data_read++)) =
+ (char)(ui16);
+ *((data->flac_data.data) + (data->flac_data.data_read++)) =
+ (char)(ui16 >> 8);
+
+ i16 = (FLAC__int16)buffer[1][i];
+ ui16 = (FLAC__uint16)i16;
+
+ *((data->flac_data.data) + (data->flac_data.data_read++)) =
+ (char)(ui16);
+ *((data->flac_data.data) + (data->flac_data.data_read++)) =
+ (char)(ui16 >> 8);
+
+ data->flac_data.max_to_read -= 4;
+
+ if (data->flac_data.max_to_read < 4) {
+ // we need to set this so that the read halts from the
+ // FLAC_getsome function.
+ data->flac_data.max_to_read = 0;
+ }
+ }
+ else {
+ // we need to write to the overflow
+ if (!data->flac_data.overflow) {
+ data->flac_data.overflow_len =
+ 4 * (frame->header.blocksize - i);
+ data->flac_data.overflow_read = 0;
+
+ // make it big enough for the rest of the block
+ data->flac_data.overflow =
+ (char *)SDL_malloc (data->flac_data.overflow_len);
+
+ if (!data->flac_data.overflow) {
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ }
+
+ i16 = (FLAC__int16)buffer[0][i];
+ ui16 = (FLAC__uint16)i16;
+
+ *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
+ (char)(ui16);
+ *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
+ (char)(ui16 >> 8);
+
+ i16 = (FLAC__int16)buffer[1][i];
+ ui16 = (FLAC__uint16)i16;
+
+ *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
+ (char)(ui16);
+ *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
+ (char)(ui16 >> 8);
+ }
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void flac_metadata_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data)
+{
+ FLAC_music *data = (FLAC_music *)client_data;
+
+ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ data->flac_data.sample_rate = metadata->data.stream_info.sample_rate;
+ data->flac_data.channels = metadata->data.stream_info.channels;
+ data->flac_data.total_samples =
+ metadata->data.stream_info.total_samples;
+ data->flac_data.bits_per_sample =
+ metadata->data.stream_info.bits_per_sample;
+ data->flac_data.sample_size = data->flac_data.channels *
+ ((data->flac_data.bits_per_sample) / 8);
+ }
+}
+
+static void flac_error_music_cb(
+ const FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data)
+{
+ // print an SDL error based on the error status
+ switch (status) {
+ case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+ SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+ SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+ SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
+ SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
+ break;
+ default:
+ SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
+ break;
+ }
+}
+
+/* Load an FLAC stream from an SDL_RWops object */
+FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw)
+{
+ FLAC_music *music;
+ int init_stage = 0;
+ int was_error = 1;
+
+ if (!Mix_Init(MIX_INIT_FLAC)) {
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+ }
+
+ music = (FLAC_music *)SDL_malloc ( sizeof (*music));
+ if (music) {
+ /* Initialize the music structure */
+ memset (music, 0, (sizeof (*music)));
+ FLAC_stop (music);
+ FLAC_setvolume (music, MIX_MAX_VOLUME);
+ music->section = -1;
+ music->rwops = rw;
+ music->freerw = freerw;
+ music->flac_data.max_to_read = 0;
+ music->flac_data.overflow = NULL;
+ music->flac_data.overflow_len = 0;
+ music->flac_data.overflow_read = 0;
+ music->flac_data.data = NULL;
+ music->flac_data.data_len = 0;
+ music->flac_data.data_read = 0;
+
+ init_stage++; // stage 1!
+
+ music->flac_decoder = flac.FLAC__stream_decoder_new ();
+
+ if (music->flac_decoder != NULL) {
+ init_stage++; // stage 2!
+
+ if (flac.FLAC__stream_decoder_init_stream(
+ music->flac_decoder,
+ flac_read_music_cb, flac_seek_music_cb,
+ flac_tell_music_cb, flac_length_music_cb,
+ flac_eof_music_cb, flac_write_music_cb,
+ flac_metadata_music_cb, flac_error_music_cb,
+ music) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
+ init_stage++; // stage 3!
+
+ if (flac.FLAC__stream_decoder_process_until_end_of_metadata
+ (music->flac_decoder)) {
+ was_error = 0;
+ } else {
+ SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
+ }
+ } else {
+ SDL_SetError("FLAC__stream_decoder_init_stream() failed");
+ }
+ } else {
+ SDL_SetError("FLAC__stream_decoder_new() failed");
+ }
+
+ if (was_error) {
+ switch (init_stage) {
+ case 3:
+ flac.FLAC__stream_decoder_finish( music->flac_decoder );
+ case 2:
+ flac.FLAC__stream_decoder_delete( music->flac_decoder );
+ case 1:
+ case 0:
+ SDL_free(music);
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ break;
+ }
+ return NULL;
+ }
+ } else {
+ SDL_OutOfMemory();
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+ }
+
+ return music;
+}
+
+/* Start playback of a given FLAC stream */
+void FLAC_play(FLAC_music *music)
+{
+ music->playing = 1;
+}
+
+/* Return non-zero if a stream is currently playing */
+int FLAC_playing(FLAC_music *music)
+{
+ return(music->playing);
+}
+
+/* Read some FLAC stream data and convert it for output */
+static void FLAC_getsome(FLAC_music *music)
+{
+ SDL_AudioCVT *cvt;
+
+ /* GET AUDIO WAVE DATA */
+ // set the max number of characters to read
+ music->flac_data.max_to_read = 8192;
+ music->flac_data.data_len = music->flac_data.max_to_read;
+ music->flac_data.data_read = 0;
+ if (!music->flac_data.data) {
+ music->flac_data.data = (char *)SDL_malloc (music->flac_data.data_len);
+ }
+
+ // we have data to read
+ while(music->flac_data.max_to_read > 0) {
+ // first check if there is data in the overflow from before
+ if (music->flac_data.overflow) {
+ size_t overflow_len = music->flac_data.overflow_read;
+
+ if (overflow_len > music->flac_data.max_to_read) {
+ size_t overflow_extra_len = overflow_len -
+ music->flac_data.max_to_read;
+
+ memcpy (music->flac_data.data+music->flac_data.data_read,
+ music->flac_data.overflow, music->flac_data.max_to_read);
+ music->flac_data.data_read += music->flac_data.max_to_read;
+ memcpy (music->flac_data.overflow,
+ music->flac_data.overflow + music->flac_data.max_to_read,
+ overflow_extra_len);
+ music->flac_data.overflow_len = overflow_extra_len;
+ music->flac_data.overflow_read = overflow_extra_len;
+ music->flac_data.max_to_read = 0;
+ }
+ else {
+ memcpy (music->flac_data.data+music->flac_data.data_read,
+ music->flac_data.overflow, overflow_len);
+ music->flac_data.data_read += overflow_len;
+ free (music->flac_data.overflow);
+ music->flac_data.overflow = NULL;
+ music->flac_data.overflow_len = 0;
+ music->flac_data.overflow_read = 0;
+ music->flac_data.max_to_read -= overflow_len;
+ }
+ }
+ else {
+ if (!flac.FLAC__stream_decoder_process_single (
+ music->flac_decoder)) {
+ music->flac_data.max_to_read = 0;
+ }
+
+ if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
+ == FLAC__STREAM_DECODER_END_OF_STREAM) {
+ music->flac_data.max_to_read = 0;
+ }
+ }
+ }
+
+ if (music->flac_data.data_read <= 0) {
+ if (music->flac_data.data_read == 0) {
+ music->playing = 0;
+ }
+ return;
+ }
+ cvt = &music->cvt;
+ if (music->section < 0) {
+
+ SDL_BuildAudioCVT (cvt, AUDIO_S16, (Uint8)music->flac_data.channels,
+ (int)music->flac_data.sample_rate, mixer.format,
+ mixer.channels, mixer.freq);
+ if (cvt->buf) {
+ free (cvt->buf);
+ }
+ cvt->buf = (Uint8 *)SDL_malloc (music->flac_data.data_len * cvt->len_mult);
+ music->section = 0;
+ }
+ if (cvt->buf) {
+ memcpy (cvt->buf, music->flac_data.data, music->flac_data.data_read);
+ if (cvt->needed) {
+ cvt->len = music->flac_data.data_read;
+ SDL_ConvertAudio (cvt);
+ }
+ else {
+ cvt->len_cvt = music->flac_data.data_read;
+ }
+ music->len_available = music->cvt.len_cvt;
+ music->snd_available = music->cvt.buf;
+ }
+ else {
+ SDL_SetError ("Out of memory");
+ music->playing = 0;
+ }
+}
+
+/* Play some of a stream previously started with FLAC_play() */
+int FLAC_playAudio(FLAC_music *music, Uint8 *snd, int len)
+{
+ int mixable;
+
+ while ((len > 0) && music->playing) {
+ if (!music->len_available) {
+ FLAC_getsome (music);
+ }
+ mixable = len;
+ if (mixable > music->len_available) {
+ mixable = music->len_available;
+ }
+ if (music->volume == MIX_MAX_VOLUME) {
+ memcpy (snd, music->snd_available, mixable);
+ }
+ else {
+ SDL_MixAudio (snd, music->snd_available, mixable, music->volume);
+ }
+ music->len_available -= mixable;
+ music->snd_available += mixable;
+ len -= mixable;
+ snd += mixable;
+ }
+
+ return len;
+}
+
+/* Stop playback of a stream previously started with FLAC_play() */
+void FLAC_stop(FLAC_music *music)
+{
+ music->playing = 0;
+}
+
+/* Close the given FLAC_music object */
+void FLAC_delete(FLAC_music *music)
+{
+ if (music) {
+ if (music->flac_decoder) {
+ flac.FLAC__stream_decoder_finish (music->flac_decoder);
+ flac.FLAC__stream_decoder_delete (music->flac_decoder);
+ }
+
+ if (music->flac_data.data) {
+ free (music->flac_data.data);
+ }
+
+ if (music->flac_data.overflow) {
+ free (music->flac_data.overflow);
+ }
+
+ if (music->cvt.buf) {
+ free (music->cvt.buf);
+ }
+
+ if (music->freerw) {
+ SDL_RWclose(music->rwops);
+ }
+ free (music);
+ }
+}
+
+/* Jump (seek) to a given position (time is in seconds) */
+void FLAC_jump_to_time(FLAC_music *music, double time)
+{
+ if (music) {
+ if (music->flac_decoder) {
+ double seek_sample = music->flac_data.sample_rate * time;
+
+ // clear data if it has data
+ if (music->flac_data.data) {
+ free (music->flac_data.data);
+ music->flac_data.data = NULL;
+ }
+
+ // clear overflow if it has data
+ if (music->flac_data.overflow) {
+ free (music->flac_data.overflow);
+ music->flac_data.overflow = NULL;
+ }
+
+ if (!flac.FLAC__stream_decoder_seek_absolute (music->flac_decoder,
+ (FLAC__uint64)seek_sample)) {
+ if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
+ == FLAC__STREAM_DECODER_SEEK_ERROR) {
+ flac.FLAC__stream_decoder_flush (music->flac_decoder);
+ }
+
+ SDL_SetError
+ ("Seeking of FLAC stream failed: libFLAC seek failed.");
+ }
+ }
+ else {
+ SDL_SetError
+ ("Seeking of FLAC stream failed: FLAC decoder was NULL.");
+ }
+ }
+ else {
+ SDL_SetError ("Seeking of FLAC stream failed: music was NULL.");
+ }
+}
+
+#endif /* FLAC_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_flac.h b/apps/plugins/sdl/SDL_mixer/music_flac.h
new file mode 100644
index 0000000000..c87dc9ea9f
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_flac.h
@@ -0,0 +1,90 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Header to handle loading FLAC music files in SDL.
+ ~ Austen Dicken (admin@cvpcs.org)
+*/
+
+/* $Id: $ */
+
+#ifdef FLAC_MUSIC
+
+#include <FLAC/stream_decoder.h>
+
+typedef struct {
+ FLAC__uint64 sample_size;
+ unsigned sample_rate;
+ unsigned channels;
+ unsigned bits_per_sample;
+ FLAC__uint64 total_samples;
+
+ // the following are used to handle the callback nature of the writer
+ int max_to_read;
+ char *data; // pointer to beginning of data array
+ int data_len; // size of data array
+ int data_read; // amount of data array used
+ char *overflow; // pointer to beginning of overflow array
+ int overflow_len; // size of overflow array
+ int overflow_read; // amount of overflow array used
+} FLAC_Data;
+
+typedef struct {
+ int playing;
+ int volume;
+ int section;
+ FLAC__StreamDecoder *flac_decoder;
+ FLAC_Data flac_data;
+ SDL_RWops *rwops;
+ int freerw;
+ SDL_AudioCVT cvt;
+ int len_available;
+ Uint8 *snd_available;
+} FLAC_music;
+
+/* Initialize the FLAC player, with the given mixer settings
+ This function returns 0, or -1 if there was an error.
+ */
+extern int FLAC_init(SDL_AudioSpec *mixer);
+
+/* Set the volume for a FLAC stream */
+extern void FLAC_setvolume(FLAC_music *music, int volume);
+
+/* Load an FLAC stream from an SDL_RWops object */
+extern FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw);
+
+/* Start playback of a given FLAC stream */
+extern void FLAC_play(FLAC_music *music);
+
+/* Return non-zero if a stream is currently playing */
+extern int FLAC_playing(FLAC_music *music);
+
+/* Play some of a stream previously started with FLAC_play() */
+extern int FLAC_playAudio(FLAC_music *music, Uint8 *stream, int len);
+
+/* Stop playback of a stream previously started with FLAC_play() */
+extern void FLAC_stop(FLAC_music *music);
+
+/* Close the given FLAC stream */
+extern void FLAC_delete(FLAC_music *music);
+
+/* Jump (seek) to a given position (time is in seconds) */
+extern void FLAC_jump_to_time(FLAC_music *music, double time);
+
+#endif /* FLAC_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_mad.c b/apps/plugins/sdl/SDL_mixer/music_mad.c
new file mode 100644
index 0000000000..e9bedf59d4
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_mad.c
@@ -0,0 +1,325 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef MP3_MAD_MUSIC
+
+#include "music_mad.h"
+
+mad_data *
+mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw)
+{
+ mad_data *mp3_mad;
+
+ mp3_mad = (mad_data *)SDL_malloc(sizeof(mad_data));
+ if (mp3_mad) {
+ mp3_mad->rw = rw;
+ mp3_mad->freerw = freerw;
+ mad_stream_init(&mp3_mad->stream);
+ mad_frame_init(&mp3_mad->frame);
+ mad_synth_init(&mp3_mad->synth);
+ mp3_mad->frames_read = 0;
+ mad_timer_reset(&mp3_mad->next_frame_start);
+ mp3_mad->volume = MIX_MAX_VOLUME;
+ mp3_mad->status = 0;
+ mp3_mad->output_begin = 0;
+ mp3_mad->output_end = 0;
+ mp3_mad->mixer = *mixer;
+ }
+ return mp3_mad;
+}
+
+void
+mad_closeFile(mad_data *mp3_mad)
+{
+ mad_stream_finish(&mp3_mad->stream);
+ mad_frame_finish(&mp3_mad->frame);
+ mad_synth_finish(&mp3_mad->synth);
+
+ if (mp3_mad->freerw) {
+ SDL_RWclose(mp3_mad->rw);
+ }
+ SDL_free(mp3_mad);
+}
+
+/* Starts the playback. */
+void
+mad_start(mad_data *mp3_mad) {
+ mp3_mad->status |= MS_playing;
+}
+
+/* Stops the playback. */
+void
+mad_stop(mad_data *mp3_mad) {
+ mp3_mad->status &= ~MS_playing;
+}
+
+/* Returns true if the playing is engaged, false otherwise. */
+int
+mad_isPlaying(mad_data *mp3_mad) {
+ return ((mp3_mad->status & MS_playing) != 0);
+}
+
+/* Reads the next frame from the file. Returns true on success or
+ false on failure. */
+static int
+read_next_frame(mad_data *mp3_mad) {
+ if (mp3_mad->stream.buffer == NULL ||
+ mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
+ size_t read_size;
+ size_t remaining;
+ unsigned char *read_start;
+
+ /* There might be some bytes in the buffer left over from last
+ time. If so, move them down and read more bytes following
+ them. */
+ if (mp3_mad->stream.next_frame != NULL) {
+ remaining = mp3_mad->stream.bufend - mp3_mad->stream.next_frame;
+ memmove(mp3_mad->input_buffer, mp3_mad->stream.next_frame, remaining);
+ read_start = mp3_mad->input_buffer + remaining;
+ read_size = MAD_INPUT_BUFFER_SIZE - remaining;
+
+ } else {
+ read_size = MAD_INPUT_BUFFER_SIZE;
+ read_start = mp3_mad->input_buffer;
+ remaining = 0;
+ }
+
+ /* Now read additional bytes from the input file. */
+ read_size = SDL_RWread(mp3_mad->rw, read_start, 1, read_size);
+
+ if (read_size <= 0) {
+ if ((mp3_mad->status & (MS_input_eof | MS_input_error)) == 0) {
+ if (read_size == 0) {
+ mp3_mad->status |= MS_input_eof;
+ } else {
+ mp3_mad->status |= MS_input_error;
+ }
+
+ /* At the end of the file, we must stuff MAD_BUFFER_GUARD
+ number of 0 bytes. */
+ memset(read_start + read_size, 0, MAD_BUFFER_GUARD);
+ read_size += MAD_BUFFER_GUARD;
+ }
+ }
+
+ /* Now feed those bytes into the libmad stream. */
+ mad_stream_buffer(&mp3_mad->stream, mp3_mad->input_buffer,
+ read_size + remaining);
+ mp3_mad->stream.error = MAD_ERROR_NONE;
+ }
+
+ /* Now ask libmad to extract a frame from the data we just put in
+ its buffer. */
+ if (mad_frame_decode(&mp3_mad->frame, &mp3_mad->stream)) {
+ if (MAD_RECOVERABLE(mp3_mad->stream.error)) {
+ return 0;
+
+ } else if (mp3_mad->stream.error == MAD_ERROR_BUFLEN) {
+ return 0;
+
+ } else {
+ mp3_mad->status |= MS_decode_error;
+ return 0;
+ }
+ }
+
+ mp3_mad->frames_read++;
+ mad_timer_add(&mp3_mad->next_frame_start, mp3_mad->frame.header.duration);
+
+ return 1;
+}
+
+/* Scale a MAD sample to 16 bits for output. */
+static signed int
+scale(mad_fixed_t sample) {
+ /* round */
+ sample += (1L << (MAD_F_FRACBITS - 16));
+
+ /* clip */
+ if (sample >= MAD_F_ONE)
+ sample = MAD_F_ONE - 1;
+ else if (sample < -MAD_F_ONE)
+ sample = -MAD_F_ONE;
+
+ /* quantize */
+ return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
+
+/* Once the frame has been read, copies its samples into the output
+ buffer. */
+static void
+decode_frame(mad_data *mp3_mad) {
+ struct mad_pcm *pcm;
+ unsigned int nchannels, nsamples;
+ mad_fixed_t const *left_ch, *right_ch;
+ unsigned char *out;
+ int ret;
+
+ mad_synth_frame(&mp3_mad->synth, &mp3_mad->frame);
+ pcm = &mp3_mad->synth.pcm;
+ out = mp3_mad->output_buffer + mp3_mad->output_end;
+
+ if ((mp3_mad->status & MS_cvt_decoded) == 0) {
+ mp3_mad->status |= MS_cvt_decoded;
+
+ /* The first frame determines some key properties of the stream.
+ In particular, it tells us enough to set up the convert
+ structure now. */
+ SDL_BuildAudioCVT(&mp3_mad->cvt, AUDIO_S16, pcm->channels, mp3_mad->frame.header.samplerate, mp3_mad->mixer.format, mp3_mad->mixer.channels, mp3_mad->mixer.freq);
+ }
+
+ /* pcm->samplerate contains the sampling frequency */
+
+ nchannels = pcm->channels;
+ nsamples = pcm->length;
+ left_ch = pcm->samples[0];
+ right_ch = pcm->samples[1];
+
+ while (nsamples--) {
+ signed int sample;
+
+ /* output sample(s) in 16-bit signed little-endian PCM */
+
+ sample = scale(*left_ch++);
+ *out++ = ((sample >> 0) & 0xff);
+ *out++ = ((sample >> 8) & 0xff);
+
+ if (nchannels == 2) {
+ sample = scale(*right_ch++);
+ *out++ = ((sample >> 0) & 0xff);
+ *out++ = ((sample >> 8) & 0xff);
+ }
+ }
+
+ mp3_mad->output_end = out - mp3_mad->output_buffer;
+ /*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
+}
+
+int
+mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len) {
+ int bytes_remaining;
+ int num_bytes;
+ Uint8 *out;
+
+ if ((mp3_mad->status & MS_playing) == 0) {
+ /* We're not supposed to be playing, so send silence instead. */
+ memset(stream, 0, len);
+ return;
+ }
+
+ out = stream;
+ bytes_remaining = len;
+ while (bytes_remaining > 0) {
+ if (mp3_mad->output_end == mp3_mad->output_begin) {
+ /* We need to get a new frame. */
+ mp3_mad->output_begin = 0;
+ mp3_mad->output_end = 0;
+ if (!read_next_frame(mp3_mad)) {
+ if ((mp3_mad->status & MS_error_flags) != 0) {
+ /* Couldn't read a frame; either an error condition or
+ end-of-file. Stop. */
+ memset(out, 0, bytes_remaining);
+ mp3_mad->status &= ~MS_playing;
+ return bytes_remaining;
+ }
+ } else {
+ decode_frame(mp3_mad);
+
+ /* Now convert the frame data to the appropriate format for
+ output. */
+ mp3_mad->cvt.buf = mp3_mad->output_buffer;
+ mp3_mad->cvt.len = mp3_mad->output_end;
+
+ mp3_mad->output_end = (int)(mp3_mad->output_end * mp3_mad->cvt.len_ratio);
+ /*assert(mp3_mad->output_end <= MAD_OUTPUT_BUFFER_SIZE);*/
+ SDL_ConvertAudio(&mp3_mad->cvt);
+ }
+ }
+
+ num_bytes = mp3_mad->output_end - mp3_mad->output_begin;
+ if (bytes_remaining < num_bytes) {
+ num_bytes = bytes_remaining;
+ }
+
+ if (mp3_mad->volume == MIX_MAX_VOLUME) {
+ memcpy(out, mp3_mad->output_buffer + mp3_mad->output_begin, num_bytes);
+ } else {
+ SDL_MixAudio(out, mp3_mad->output_buffer + mp3_mad->output_begin,
+ num_bytes, mp3_mad->volume);
+ }
+ out += num_bytes;
+ mp3_mad->output_begin += num_bytes;
+ bytes_remaining -= num_bytes;
+ }
+ return 0;
+}
+
+void
+mad_seek(mad_data *mp3_mad, double position) {
+ mad_timer_t target;
+ int int_part;
+
+ int_part = (int)position;
+ mad_timer_set(&target, int_part,
+ (int)((position - int_part) * 1000000), 1000000);
+
+ if (mad_timer_compare(mp3_mad->next_frame_start, target) > 0) {
+ /* In order to seek backwards in a VBR file, we have to rewind and
+ start again from the beginning. This isn't necessary if the
+ file happens to be CBR, of course; in that case we could seek
+ directly to the frame we want. But I leave that little
+ optimization for the future developer who discovers she really
+ needs it. */
+ mp3_mad->frames_read = 0;
+ mad_timer_reset(&mp3_mad->next_frame_start);
+ mp3_mad->status &= ~MS_error_flags;
+ mp3_mad->output_begin = 0;
+ mp3_mad->output_end = 0;
+
+ SDL_RWseek(mp3_mad->rw, 0, RW_SEEK_SET);
+ }
+
+ /* Now we have to skip frames until we come to the right one.
+ Again, only truly necessary if the file is VBR. */
+ while (mad_timer_compare(mp3_mad->next_frame_start, target) < 0) {
+ if (!read_next_frame(mp3_mad)) {
+ if ((mp3_mad->status & MS_error_flags) != 0) {
+ /* Couldn't read a frame; either an error condition or
+ end-of-file. Stop. */
+ mp3_mad->status &= ~MS_playing;
+ return;
+ }
+ }
+ }
+
+ /* Here we are, at the beginning of the frame that contains the
+ target time. Ehh, I say that's close enough. If we wanted to,
+ we could get more precise by decoding the frame now and counting
+ the appropriate number of samples out of it. */
+}
+
+void
+mad_setVolume(mad_data *mp3_mad, int volume) {
+ mp3_mad->volume = volume;
+}
+
+
+#endif /* MP3_MAD_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_mad.h b/apps/plugins/sdl/SDL_mixer/music_mad.h
new file mode 100644
index 0000000000..af93c8df5e
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_mad.h
@@ -0,0 +1,72 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifdef MP3_MAD_MUSIC
+
+#include "mad.h"
+#include "SDL_rwops.h"
+#include "SDL_audio.h"
+#include "SDL_mixer.h"
+
+#define MAD_INPUT_BUFFER_SIZE (5*8192)
+#define MAD_OUTPUT_BUFFER_SIZE 8192
+
+enum {
+ MS_input_eof = 0x0001,
+ MS_input_error = 0x0001,
+ MS_decode_eof = 0x0002,
+ MS_decode_error = 0x0004,
+ MS_error_flags = 0x000f,
+
+ MS_playing = 0x0100,
+ MS_cvt_decoded = 0x0200,
+};
+
+typedef struct {
+ SDL_RWops *rw;
+ int freerw;
+ struct mad_stream stream;
+ struct mad_frame frame;
+ struct mad_synth synth;
+ int frames_read;
+ mad_timer_t next_frame_start;
+ int volume;
+ int status;
+ int output_begin, output_end;
+ SDL_AudioSpec mixer;
+ SDL_AudioCVT cvt;
+
+ unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
+ unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE];
+} mad_data;
+
+mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw);
+void mad_closeFile(mad_data *mp3_mad);
+
+void mad_start(mad_data *mp3_mad);
+void mad_stop(mad_data *mp3_mad);
+int mad_isPlaying(mad_data *mp3_mad);
+
+int mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len);
+void mad_seek(mad_data *mp3_mad, double position);
+void mad_setVolume(mad_data *mp3_mad, int volume);
+
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/music_mod.c b/apps/plugins/sdl/SDL_mixer/music_mod.c
new file mode 100644
index 0000000000..be17902266
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_mod.c
@@ -0,0 +1,346 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id: music_mod.c 4211 2008-12-08 00:27:32Z slouken $ */
+
+#ifdef MOD_MUSIC
+
+/* This file supports MOD tracker music streams */
+
+#include "SDL_mixer.h"
+#include "dynamic_mod.h"
+#include "music_mod.h"
+
+#include "mikmod.h"
+
+#define SDL_SURROUND
+#ifdef SDL_SURROUND
+#define MAX_OUTPUT_CHANNELS 6
+#else
+#define MAX_OUTPUT_CHANNELS 2
+#endif
+
+/* Reference for converting mikmod output to 4/6 channels */
+static int current_output_channels;
+static Uint16 current_output_format;
+
+static int music_swap8;
+static int music_swap16;
+
+/* Initialize the MOD player, with the given mixer settings
+ This function returns 0, or -1 if there was an error.
+ */
+int MOD_init(SDL_AudioSpec *mixerfmt)
+{
+ CHAR *list;
+
+ if ( !Mix_Init(MIX_INIT_MOD) ) {
+ return -1;
+ }
+
+ /* Set the MikMod music format */
+ music_swap8 = 0;
+ music_swap16 = 0;
+ switch (mixerfmt->format) {
+
+ case AUDIO_U8:
+ case AUDIO_S8: {
+ if ( mixerfmt->format == AUDIO_S8 ) {
+ music_swap8 = 1;
+ }
+ *mikmod.md_mode = 0;
+ }
+ break;
+
+ case AUDIO_S16LSB:
+ case AUDIO_S16MSB: {
+ /* See if we need to correct MikMod mixing */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+ if ( mixerfmt->format == AUDIO_S16MSB ) {
+#else
+ if ( mixerfmt->format == AUDIO_S16LSB ) {
+#endif
+ music_swap16 = 1;
+ }
+ *mikmod.md_mode = DMODE_16BITS;
+ }
+ break;
+
+ default: {
+ Mix_SetError("Unknown hardware audio format");
+ return -1;
+ }
+ }
+ current_output_channels = mixerfmt->channels;
+ current_output_format = mixerfmt->format;
+ if ( mixerfmt->channels > 1 ) {
+ if ( mixerfmt->channels > MAX_OUTPUT_CHANNELS ) {
+ Mix_SetError("Hardware uses more channels than mixerfmt");
+ return -1;
+ }
+ *mikmod.md_mode |= DMODE_STEREO;
+ }
+ *mikmod.md_mixfreq = mixerfmt->freq;
+ *mikmod.md_device = 0;
+ *mikmod.md_volume = 96;
+ *mikmod.md_musicvolume = 128;
+ *mikmod.md_sndfxvolume = 128;
+ *mikmod.md_pansep = 128;
+ *mikmod.md_reverb = 0;
+ *mikmod.md_mode |= DMODE_HQMIXER|DMODE_SOFT_MUSIC|DMODE_SURROUND;
+
+ list = mikmod.MikMod_InfoDriver();
+ if ( list )
+ free(list);
+ else
+ mikmod.MikMod_RegisterDriver(mikmod.drv_nos);
+
+ list = mikmod.MikMod_InfoLoader();
+ if ( list )
+ free(list);
+ else
+ mikmod.MikMod_RegisterAllLoaders();
+
+ if ( mikmod.MikMod_Init(NULL) ) {
+ Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Uninitialize the music players */
+void MOD_exit(void)
+{
+ if (mikmod.MikMod_Exit) {
+ mikmod.MikMod_Exit();
+ }
+}
+
+/* Set the volume for a MOD stream */
+void MOD_setvolume(MODULE *music, int volume)
+{
+ mikmod.Player_SetVolume((SWORD)volume);
+}
+
+typedef struct
+{
+ MREADER mr;
+ long offset;
+ long eof;
+ SDL_RWops *rw;
+} LMM_MREADER;
+
+BOOL LMM_Seek(struct MREADER *mr,long to,int dir)
+{
+ LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
+ if ( dir == SEEK_SET ) {
+ to += lmmmr->offset;
+ }
+ return (SDL_RWseek(lmmmr->rw, to, dir) < lmmmr->offset);
+}
+long LMM_Tell(struct MREADER *mr)
+{
+ LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
+ return SDL_RWtell(lmmmr->rw) - lmmmr->offset;
+}
+BOOL LMM_Read(struct MREADER *mr,void *buf,size_t sz)
+{
+ LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
+ return SDL_RWread(lmmmr->rw, buf, sz, 1);
+}
+int LMM_Get(struct MREADER *mr)
+{
+ unsigned char c;
+ LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
+ if ( SDL_RWread(lmmmr->rw, &c, 1, 1) ) {
+ return c;
+ }
+ return EOF;
+}
+BOOL LMM_Eof(struct MREADER *mr)
+{
+ long offset;
+ LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
+ offset = LMM_Tell(mr);
+ return offset >= lmmmr->eof;
+}
+MODULE *MikMod_LoadSongRW(SDL_RWops *rw, int maxchan)
+{
+ LMM_MREADER lmmmr = {
+ { LMM_Seek, LMM_Tell, LMM_Read, LMM_Get, LMM_Eof },
+ 0,
+ 0,
+ 0
+ };
+ lmmmr.offset = SDL_RWtell(rw);
+ SDL_RWseek(rw, 0, RW_SEEK_END);
+ lmmmr.eof = SDL_RWtell(rw);
+ SDL_RWseek(rw, lmmmr.offset, RW_SEEK_SET);
+ lmmmr.rw = rw;
+ return mikmod.Player_LoadGeneric((MREADER*)&lmmmr, maxchan, 0);
+}
+
+/* Load a MOD stream from an SDL_RWops object */
+MODULE *MOD_new_RW(SDL_RWops *rw, int freerw)
+{
+ MODULE *module;
+
+ /* Make sure the mikmod library is loaded */
+ if ( !Mix_Init(MIX_INIT_MOD) ) {
+ if ( freerw ) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+ }
+
+ module = MikMod_LoadSongRW(rw,64);
+ if (!module) {
+ Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
+ if ( freerw ) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+ }
+
+ /* Stop implicit looping, fade out and other flags. */
+ module->extspd = 1;
+ module->panflag = 1;
+ module->wrap = 0;
+ module->loop = 0;
+#if 0 /* Don't set fade out by default - unfortunately there's no real way
+to query the status of the song or set trigger actions. Hum. */
+ module->fadeout = 1;
+#endif
+
+ if ( freerw ) {
+ SDL_RWclose(rw);
+ }
+ return module;
+}
+
+/* Start playback of a given MOD stream */
+void MOD_play(MODULE *music)
+{
+ mikmod.Player_Start(music);
+}
+
+/* Return non-zero if a stream is currently playing */
+int MOD_playing(MODULE *music)
+{
+ return mikmod.Player_Active();
+}
+
+/* Play some of a stream previously started with MOD_play() */
+int MOD_playAudio(MODULE *music, Uint8 *stream, int len)
+{
+ if (current_output_channels > 2) {
+ int small_len = 2 * len / current_output_channels;
+ int i;
+ Uint8 *src, *dst;
+
+ mikmod.VC_WriteBytes((SBYTE *)stream, small_len);
+ /* and extend to len by copying channels */
+ src = stream + small_len;
+ dst = stream + len;
+
+ switch (current_output_format & 0xFF) {
+ case 8:
+ for ( i=small_len/2; i; --i ) {
+ src -= 2;
+ dst -= current_output_channels;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst[3] = src[1];
+ if (current_output_channels == 6) {
+ dst[4] = src[0];
+ dst[5] = src[1];
+ }
+ }
+ break;
+ case 16:
+ for ( i=small_len/4; i; --i ) {
+ src -= 4;
+ dst -= 2 * current_output_channels;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[0];
+ dst[5] = src[1];
+ dst[6] = src[2];
+ dst[7] = src[3];
+ if (current_output_channels == 6) {
+ dst[8] = src[0];
+ dst[9] = src[1];
+ dst[10] = src[2];
+ dst[11] = src[3];
+ }
+ }
+ break;
+ }
+ } else {
+ mikmod.VC_WriteBytes((SBYTE *)stream, len);
+ }
+ if ( music_swap8 ) {
+ Uint8 *dst;
+ int i;
+
+ dst = stream;
+ for ( i=len; i; --i ) {
+ *dst++ ^= 0x80;
+ }
+ } else
+ if ( music_swap16 ) {
+ Uint8 *dst, tmp;
+ int i;
+
+ dst = stream;
+ for ( i=(len/2); i; --i ) {
+ tmp = dst[0];
+ dst[0] = dst[1];
+ dst[1] = tmp;
+ dst += 2;
+ }
+ }
+ return 0;
+}
+
+/* Stop playback of a stream previously started with MOD_play() */
+void MOD_stop(MODULE *music)
+{
+ mikmod.Player_Stop();
+}
+
+/* Close the given MOD stream */
+void MOD_delete(MODULE *music)
+{
+ mikmod.Player_Free(music);
+}
+
+/* Jump (seek) to a given position (time is in seconds) */
+void MOD_jump_to_time(MODULE *music, double time)
+{
+ mikmod.Player_SetPosition((UWORD)time);
+}
+
+#endif /* MOD_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_mod.h b/apps/plugins/sdl/SDL_mixer/music_mod.h
new file mode 100644
index 0000000000..4328e2b2c7
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_mod.h
@@ -0,0 +1,62 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id: music_mod.h 4211 2008-12-08 00:27:32Z slouken $ */
+
+#ifdef MOD_MUSIC
+
+/* This file supports MOD tracker music streams */
+
+struct MODULE;
+
+/* Initialize the Ogg Vorbis player, with the given mixer settings
+ This function returns 0, or -1 if there was an error.
+ */
+extern int MOD_init(SDL_AudioSpec *mixer);
+
+/* Uninitialize the music players */
+extern void MOD_exit(void);
+
+/* Set the volume for a MOD stream */
+extern void MOD_setvolume(struct MODULE *music, int volume);
+
+/* Load a MOD stream from an SDL_RWops object */
+extern struct MODULE *MOD_new_RW(SDL_RWops *rw, int freerw);
+
+/* Start playback of a given MOD stream */
+extern void MOD_play(struct MODULE *music);
+
+/* Return non-zero if a stream is currently playing */
+extern int MOD_playing(struct MODULE *music);
+
+/* Play some of a stream previously started with MOD_play() */
+extern int MOD_playAudio(struct MODULE *music, Uint8 *stream, int len);
+
+/* Stop playback of a stream previously started with MOD_play() */
+extern void MOD_stop(struct MODULE *music);
+
+/* Close the given MOD stream */
+extern void MOD_delete(struct MODULE *music);
+
+/* Jump (seek) to a given position (time is in seconds) */
+extern void MOD_jump_to_time(struct MODULE *music, double time);
+
+#endif /* MOD_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_modplug.c b/apps/plugins/sdl/SDL_mixer/music_modplug.c
new file mode 100644
index 0000000000..31a7ba200f
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_modplug.c
@@ -0,0 +1,239 @@
+#ifdef MODPLUG_MUSIC
+
+#include "music_modplug.h"
+
+static int current_output_channels=0;
+static int music_swap8=0;
+static int music_swap16=0;
+static ModPlug_Settings settings;
+
+int modplug_init(SDL_AudioSpec *spec)
+{
+ ModPlug_GetSettings(&settings);
+ settings.mFlags=MODPLUG_ENABLE_OVERSAMPLING;
+ current_output_channels=spec->channels;
+ settings.mChannels=spec->channels>1?2:1;
+ settings.mBits=spec->format&0xFF;
+
+ music_swap8 = 0;
+ music_swap16 = 0;
+
+ switch(spec->format)
+ {
+ case AUDIO_U8:
+ case AUDIO_S8: {
+ if ( spec->format == AUDIO_S8 ) {
+ music_swap8 = 1;
+ }
+ settings.mBits=8;
+ }
+ break;
+
+ case AUDIO_S16LSB:
+ case AUDIO_S16MSB: {
+ /* See if we need to correct MikMod mixing */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+ if ( spec->format == AUDIO_S16MSB ) {
+#else
+ if ( spec->format == AUDIO_S16LSB ) {
+#endif
+ music_swap16 = 1;
+ }
+ settings.mBits=16;
+ }
+ break;
+
+ default: {
+ Mix_SetError("Unknown hardware audio format");
+ return -1;
+ }
+
+ }
+
+ settings.mFrequency=spec->freq; /*TODO: limit to 11025, 22050, or 44100 ? */
+ settings.mResamplingMode=MODPLUG_RESAMPLE_FIR;
+ settings.mReverbDepth=0;
+ settings.mReverbDelay=100;
+ settings.mBassAmount=0;
+ settings.mBassRange=50;
+ settings.mSurroundDepth=0;
+ settings.mSurroundDelay=10;
+ settings.mLoopCount=0;
+ ModPlug_SetSettings(&settings);
+ return 0;
+}
+
+/* Uninitialize the music players */
+void modplug_exit()
+{
+}
+
+/* Set the volume for a modplug stream */
+void modplug_setvolume(modplug_data *music, int volume)
+{
+ ModPlug_SetMasterVolume(music->file, volume*4);
+}
+
+/* Load a modplug stream from an SDL_RWops object */
+modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw)
+{
+ modplug_data *music=NULL;
+ long offset,sz;
+ char *buf=NULL;
+
+ offset = SDL_RWtell(rw);
+ SDL_RWseek(rw, 0, RW_SEEK_END);
+ sz = SDL_RWtell(rw)-offset;
+ SDL_RWseek(rw, offset, RW_SEEK_SET);
+ buf=(char*)SDL_malloc(sz);
+ if(buf)
+ {
+ if(SDL_RWread(rw, buf, sz, 1)==1)
+ {
+ music=(modplug_data*)SDL_malloc(sizeof(modplug_data));
+ if (music)
+ {
+ music->playing=0;
+ music->file=ModPlug_Load(buf,sz);
+ if(!music->file)
+ {
+ SDL_free(music);
+ music=NULL;
+ }
+ }
+ else
+ {
+ SDL_OutOfMemory();
+ }
+ }
+ SDL_free(buf);
+ }
+ else
+ {
+ SDL_OutOfMemory();
+ }
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return music;
+}
+
+/* Start playback of a given modplug stream */
+void modplug_play(modplug_data *music)
+{
+ ModPlug_Seek(music->file,0);
+ music->playing=1;
+}
+
+/* Return non-zero if a stream is currently playing */
+int modplug_playing(modplug_data *music)
+{
+ return music && music->playing;
+}
+
+/* Play some of a stream previously started with modplug_play() */
+int modplug_playAudio(modplug_data *music, Uint8 *stream, int len)
+{
+ if (current_output_channels > 2) {
+ int small_len = 2 * len / current_output_channels;
+ int i;
+ Uint8 *src, *dst;
+
+ i=ModPlug_Read(music->file, stream, small_len);
+ if(i<small_len)
+ {
+ memset(stream+i,0,small_len-i);
+ music->playing=0;
+ }
+ /* and extend to len by copying channels */
+ src = stream + small_len;
+ dst = stream + len;
+
+ switch (settings.mBits) {
+ case 8:
+ for ( i=small_len/2; i; --i ) {
+ src -= 2;
+ dst -= current_output_channels;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst[3] = src[1];
+ if (current_output_channels == 6) {
+ dst[4] = src[0];
+ dst[5] = src[1];
+ }
+ }
+ break;
+ case 16:
+ for ( i=small_len/4; i; --i ) {
+ src -= 4;
+ dst -= 2 * current_output_channels;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[0];
+ dst[5] = src[1];
+ dst[6] = src[2];
+ dst[7] = src[3];
+ if (current_output_channels == 6) {
+ dst[8] = src[0];
+ dst[9] = src[1];
+ dst[10] = src[2];
+ dst[11] = src[3];
+ }
+ }
+ break;
+ }
+ } else {
+ int i=ModPlug_Read(music->file, stream, len);
+ if(i<len)
+ {
+ memset(stream+i,0,len-i);
+ music->playing=0;
+ }
+ }
+ if ( music_swap8 ) {
+ Uint8 *dst;
+ int i;
+
+ dst = stream;
+ for ( i=len; i; --i ) {
+ *dst++ ^= 0x80;
+ }
+ } else
+ if ( music_swap16 ) {
+ Uint8 *dst, tmp;
+ int i;
+
+ dst = stream;
+ for ( i=(len/2); i; --i ) {
+ tmp = dst[0];
+ dst[0] = dst[1];
+ dst[1] = tmp;
+ dst += 2;
+ }
+ }
+ return 0;
+}
+
+/* Stop playback of a stream previously started with modplug_play() */
+void modplug_stop(modplug_data *music)
+{
+ music->playing=0;
+}
+
+/* Close the given modplug stream */
+void modplug_delete(modplug_data *music)
+{
+ ModPlug_Unload(music->file);
+ SDL_free(music);
+}
+
+/* Jump (seek) to a given position (time is in seconds) */
+void modplug_jump_to_time(modplug_data *music, double time)
+{
+ ModPlug_Seek(music->file,(int)(time*1000));
+}
+
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/music_modplug.h b/apps/plugins/sdl/SDL_mixer/music_modplug.h
new file mode 100644
index 0000000000..92cbafd094
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_modplug.h
@@ -0,0 +1,42 @@
+#ifdef MODPLUG_MUSIC
+
+#include "modplug.h"
+#include "SDL_rwops.h"
+#include "SDL_audio.h"
+#include "SDL_mixer.h"
+
+typedef struct {
+ ModPlugFile *file;
+ int playing;
+} modplug_data;
+
+int modplug_init(SDL_AudioSpec *mixer);
+
+/* Uninitialize the music players */
+void modplug_exit(void);
+
+/* Set the volume for a modplug stream */
+void modplug_setvolume(modplug_data *music, int volume);
+
+/* Load a modplug stream from an SDL_RWops object */
+modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw);
+
+/* Start playback of a given modplug stream */
+void modplug_play(modplug_data *music);
+
+/* Return non-zero if a stream is currently playing */
+int modplug_playing(modplug_data *music);
+
+/* Play some of a stream previously started with modplug_play() */
+int modplug_playAudio(modplug_data *music, Uint8 *stream, int len);
+
+/* Stop playback of a stream previously started with modplug_play() */
+void modplug_stop(modplug_data *music);
+
+/* Close the given modplug stream */
+void modplug_delete(modplug_data *music);
+
+/* Jump (seek) to a given position (time is in seconds) */
+void modplug_jump_to_time(modplug_data *music, double time);
+
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/music_ogg.c b/apps/plugins/sdl/SDL_mixer/music_ogg.c
new file mode 100644
index 0000000000..de5f9c5421
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_ogg.c
@@ -0,0 +1,230 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#ifdef OGG_MUSIC
+
+/* This file supports Ogg Vorbis music streams */
+
+#include "SDL_mixer.h"
+#include "dynamic_ogg.h"
+#include "music_ogg.h"
+
+/* This is the format of the audio mixer data */
+static SDL_AudioSpec mixer;
+
+/* Initialize the Ogg Vorbis player, with the given mixer settings
+ This function returns 0, or -1 if there was an error.
+ */
+int OGG_init(SDL_AudioSpec *mixerfmt)
+{
+ mixer = *mixerfmt;
+ return(0);
+}
+
+/* Set the volume for an OGG stream */
+void OGG_setvolume(OGG_music *music, int volume)
+{
+ music->volume = volume;
+}
+
+static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+ return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
+}
+
+static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
+{
+ return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
+}
+
+static long sdl_tell_func(void *datasource)
+{
+ return SDL_RWtell((SDL_RWops*)datasource);
+}
+
+/* Load an OGG stream from an SDL_RWops object */
+OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw)
+{
+ OGG_music *music;
+ ov_callbacks callbacks;
+
+ if ( !Mix_Init(MIX_INIT_OGG) ) {
+ if ( freerw ) {
+ SDL_RWclose(rw);
+ }
+ return(NULL);
+ }
+
+ SDL_memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.read_func = sdl_read_func;
+ callbacks.seek_func = sdl_seek_func;
+ callbacks.tell_func = sdl_tell_func;
+
+ music = (OGG_music *)SDL_malloc(sizeof *music);
+ if ( music ) {
+ /* Initialize the music structure */
+ memset(music, 0, (sizeof *music));
+ music->rw = rw;
+ music->freerw = freerw;
+ OGG_stop(music);
+ OGG_setvolume(music, MIX_MAX_VOLUME);
+ music->section = -1;
+
+ if ( vorbis.ov_open_callbacks(rw, &music->vf, NULL, 0, callbacks) < 0 ) {
+ SDL_free(music);
+ if ( freerw ) {
+ SDL_RWclose(rw);
+ }
+ SDL_SetError("Not an Ogg Vorbis audio stream");
+ return(NULL);
+ }
+ } else {
+ if ( freerw ) {
+ SDL_RWclose(rw);
+ }
+ SDL_OutOfMemory();
+ return(NULL);
+ }
+ return(music);
+}
+
+/* Start playback of a given OGG stream */
+void OGG_play(OGG_music *music)
+{
+ music->playing = 1;
+}
+
+/* Return non-zero if a stream is currently playing */
+int OGG_playing(OGG_music *music)
+{
+ return(music->playing);
+}
+
+/* Read some Ogg stream data and convert it for output */
+static void OGG_getsome(OGG_music *music)
+{
+ int section;
+ int len;
+ char data[4096];
+ SDL_AudioCVT *cvt;
+
+#ifdef OGG_USE_TREMOR
+ len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
+#else
+ len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
+#endif
+ if ( len <= 0 ) {
+ if ( len == 0 ) {
+ music->playing = 0;
+ }
+ return;
+ }
+ cvt = &music->cvt;
+ if ( section != music->section ) {
+ vorbis_info *vi;
+
+ vi = vorbis.ov_info(&music->vf, -1);
+ SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
+ mixer.format,mixer.channels,mixer.freq);
+ if ( cvt->buf ) {
+ SDL_free(cvt->buf);
+ }
+ cvt->buf = (Uint8 *)SDL_malloc(sizeof(data)*cvt->len_mult);
+ music->section = section;
+ }
+ if ( cvt->buf ) {
+ memcpy(cvt->buf, data, len);
+ if ( cvt->needed ) {
+ cvt->len = len;
+ SDL_ConvertAudio(cvt);
+ } else {
+ cvt->len_cvt = len;
+ }
+ music->len_available = music->cvt.len_cvt;
+ music->snd_available = music->cvt.buf;
+ } else {
+ SDL_SetError("Out of memory");
+ music->playing = 0;
+ }
+}
+
+/* Play some of a stream previously started with OGG_play() */
+int OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
+{
+ int mixable;
+
+ while ( (len > 0) && music->playing ) {
+ if ( ! music->len_available ) {
+ OGG_getsome(music);
+ }
+ mixable = len;
+ if ( mixable > music->len_available ) {
+ mixable = music->len_available;
+ }
+ if ( music->volume == MIX_MAX_VOLUME ) {
+ memcpy(snd, music->snd_available, mixable);
+ } else {
+ SDL_MixAudio(snd, music->snd_available, mixable,
+ music->volume);
+ }
+ music->len_available -= mixable;
+ music->snd_available += mixable;
+ len -= mixable;
+ snd += mixable;
+ }
+
+ return len;
+}
+
+/* Stop playback of a stream previously started with OGG_play() */
+void OGG_stop(OGG_music *music)
+{
+ music->playing = 0;
+}
+
+/* Close the given OGG stream */
+void OGG_delete(OGG_music *music)
+{
+ if ( music ) {
+ if ( music->cvt.buf ) {
+ SDL_free(music->cvt.buf);
+ }
+ if ( music->freerw ) {
+ SDL_RWclose(music->rw);
+ }
+ vorbis.ov_clear(&music->vf);
+ SDL_free(music);
+ }
+}
+
+/* Jump (seek) to a given position (time is in seconds) */
+void OGG_jump_to_time(OGG_music *music, double time)
+{
+#ifdef OGG_USE_TREMOR
+ vorbis.ov_time_seek( &music->vf, (ogg_int64_t)time );
+#else
+ vorbis.ov_time_seek( &music->vf, time );
+#endif
+}
+
+#endif /* OGG_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/music_ogg.h b/apps/plugins/sdl/SDL_mixer/music_ogg.h
new file mode 100644
index 0000000000..4d93a2bc62
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/music_ogg.h
@@ -0,0 +1,75 @@
+/*
+ SDL_mixer: An audio mixer library based on the SDL library
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#ifdef OGG_MUSIC
+
+/* This file supports Ogg Vorbis music streams */
+
+#ifdef OGG_USE_TREMOR
+#include <tremor/ivorbisfile.h>
+#else
+#include <vorbis/vorbisfile.h>
+#endif
+
+typedef struct {
+ SDL_RWops *rw;
+ int freerw;
+ int playing;
+ int volume;
+ OggVorbis_File vf;
+ int section;
+ SDL_AudioCVT cvt;
+ int len_available;
+ Uint8 *snd_available;
+} OGG_music;
+
+/* Initialize the Ogg Vorbis player, with the given mixer settings
+ This function returns 0, or -1 if there was an error.
+ */
+extern int OGG_init(SDL_AudioSpec *mixer);
+
+/* Set the volume for an OGG stream */
+extern void OGG_setvolume(OGG_music *music, int volume);
+
+/* Load an OGG stream from an SDL_RWops object */
+extern OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw);
+
+/* Start playback of a given OGG stream */
+extern void OGG_play(OGG_music *music);
+
+/* Return non-zero if a stream is currently playing */
+extern int OGG_playing(OGG_music *music);
+
+/* Play some of a stream previously started with OGG_play() */
+extern int OGG_playAudio(OGG_music *music, Uint8 *stream, int len);
+
+/* Stop playback of a stream previously started with OGG_play() */
+extern void OGG_stop(OGG_music *music);
+
+/* Close the given OGG stream */
+extern void OGG_delete(OGG_music *music);
+
+/* Jump (seek) to a given position (time is in seconds) */
+extern void OGG_jump_to_time(OGG_music *music, double time);
+
+#endif /* OGG_MUSIC */
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi.h b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi.h
new file mode 100644
index 0000000000..17e4769d86
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi.h
@@ -0,0 +1,38 @@
+/*
+ native_midi: Hardware Midi support for the SDL_mixer library
+ Copyright (C) 2000 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef _NATIVE_MIDI_H_
+#define _NATIVE_MIDI_H_
+
+#include <SDL_rwops.h>
+
+typedef struct _NativeMidiSong NativeMidiSong;
+
+int native_midi_detect();
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw);
+void native_midi_freesong(NativeMidiSong *song);
+void native_midi_start(NativeMidiSong *song, int loops);
+void native_midi_stop();
+int native_midi_active();
+void native_midi_setvolume(int volume);
+const char *native_midi_error(void);
+
+#endif /* _NATIVE_MIDI_H_ */
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.c b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.c
new file mode 100644
index 0000000000..12294750f8
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.c
@@ -0,0 +1,409 @@
+/*
+ native_midi: Hardware Midi support for the SDL_mixer library
+ Copyright (C) 2000,2001 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+#include "native_midi_common.h"
+
+#include "../SDL_mixer.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+
+/* The maximum number of midi tracks that we can handle
+#define MIDI_TRACKS 32 */
+
+
+/* A single midi track as read from the midi file */
+typedef struct
+{
+ Uint8 *data; /* MIDI message stream */
+ int len; /* length of the track data */
+} MIDITrack;
+
+/* A midi file, stripped down to the absolute minimum - divison & track data */
+typedef struct
+{
+ int division; /* number of pulses per quarter note (ppqn) */
+ int nTracks; /* number of tracks */
+ MIDITrack *track; /* tracks */
+} MIDIFile;
+
+
+/* Some macros that help us stay endianess-independant */
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+#define BE_SHORT(x) (x)
+#define BE_LONG(x) (x)
+#else
+#define BE_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define BE_LONG(x) ((((x)&0x0000FF)<<24) | \
+ (((x)&0x00FF00)<<8) | \
+ (((x)&0xFF0000)>>8) | \
+ (((x)>>24)&0xFF))
+#endif
+
+
+
+/* Get Variable Length Quantity */
+static int GetVLQ(MIDITrack *track, int *currentPos)
+{
+ int l = 0;
+ Uint8 c;
+ while(1)
+ {
+ c = track->data[*currentPos];
+ (*currentPos)++;
+ l += (c & 0x7f);
+ if (!(c & 0x80))
+ return l;
+ l <<= 7;
+ }
+}
+
+/* Create a single MIDIEvent */
+static MIDIEvent *CreateEvent(Uint32 time, Uint8 event, Uint8 a, Uint8 b)
+{
+ MIDIEvent *newEvent;
+
+ newEvent = calloc(1, sizeof(MIDIEvent));
+
+ if (newEvent)
+ {
+ newEvent->time = time;
+ newEvent->status = event;
+ newEvent->data[0] = a;
+ newEvent->data[1] = b;
+ }
+ else
+ Mix_SetError("Out of memory");
+
+ return newEvent;
+}
+
+/* Convert a single midi track to a list of MIDIEvents */
+static MIDIEvent *MIDITracktoStream(MIDITrack *track)
+{
+ Uint32 atime = 0;
+ Uint32 len = 0;
+ Uint8 event,type,a,b;
+ Uint8 laststatus = 0;
+ Uint8 lastchan = 0;
+ int currentPos = 0;
+ int end = 0;
+ MIDIEvent *head = CreateEvent(0,0,0,0); /* dummy event to make handling the list easier */
+ MIDIEvent *currentEvent = head;
+
+ while (!end)
+ {
+ if (currentPos >= track->len)
+ break; /* End of data stream reached */
+
+ atime += GetVLQ(track, &currentPos);
+ event = track->data[currentPos++];
+
+ /* Handle SysEx seperatly */
+ if (((event>>4) & 0x0F) == MIDI_STATUS_SYSEX)
+ {
+ if (event == 0xFF)
+ {
+ type = track->data[currentPos];
+ currentPos++;
+ switch(type)
+ {
+ case 0x2f: /* End of data marker */
+ end = 1;
+ case 0x51: /* Tempo change */
+ /*
+ a=track->data[currentPos];
+ b=track->data[currentPos+1];
+ c=track->data[currentPos+2];
+ AddEvent(song, atime, MEVT_TEMPO, c, b, a);
+ */
+ break;
+ }
+ }
+ else
+ type = 0;
+
+ len = GetVLQ(track, &currentPos);
+
+ /* Create an event and attach the extra data, if any */
+ currentEvent->next = CreateEvent(atime, event, type, 0);
+ currentEvent = currentEvent->next;
+ if (NULL == currentEvent)
+ {
+ FreeMIDIEventList(head);
+ return NULL;
+ }
+ if (len)
+ {
+ currentEvent->extraLen = len;
+ currentEvent->extraData = malloc(len);
+ memcpy(currentEvent->extraData, &(track->data[currentPos]), len);
+ currentPos += len;
+ }
+ }
+ else
+ {
+ a = event;
+ if (a & 0x80) /* It's a status byte */
+ {
+ /* Extract channel and status information */
+ lastchan = a & 0x0F;
+ laststatus = (a>>4) & 0x0F;
+
+ /* Read the next byte which should always be a data byte */
+ a = track->data[currentPos++] & 0x7F;
+ }
+ switch(laststatus)
+ {
+ case MIDI_STATUS_NOTE_OFF:
+ case MIDI_STATUS_NOTE_ON: /* Note on */
+ case MIDI_STATUS_AFTERTOUCH: /* Key Pressure */
+ case MIDI_STATUS_CONTROLLER: /* Control change */
+ case MIDI_STATUS_PITCH_WHEEL: /* Pitch wheel */
+ b = track->data[currentPos++] & 0x7F;
+ currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, b);
+ currentEvent = currentEvent->next;
+ if (NULL == currentEvent)
+ {
+ FreeMIDIEventList(head);
+ return NULL;
+ }
+ break;
+
+ case MIDI_STATUS_PROG_CHANGE: /* Program change */
+ case MIDI_STATUS_PRESSURE: /* Channel pressure */
+ a &= 0x7f;
+ currentEvent->next = CreateEvent(atime, (Uint8)((laststatus<<4)+lastchan), a, 0);
+ currentEvent = currentEvent->next;
+ if (NULL == currentEvent)
+ {
+ FreeMIDIEventList(head);
+ return NULL;
+ }
+ break;
+
+ default: /* Sysex already handled above */
+ break;
+ }
+ }
+ }
+
+ currentEvent = head->next;
+ free(head); /* release the dummy head event */
+ return currentEvent;
+}
+
+/*
+ * Convert a midi song, consisting of up to 32 tracks, to a list of MIDIEvents.
+ * To do so, first convert the tracks seperatly, then interweave the resulting
+ * MIDIEvent-Lists to one big list.
+ */
+static MIDIEvent *MIDItoStream(MIDIFile *mididata)
+{
+ MIDIEvent **track;
+ MIDIEvent *head = CreateEvent(0,0,0,0); /* dummy event to make handling the list easier */
+ MIDIEvent *currentEvent = head;
+ int trackID;
+
+ if (NULL == head)
+ return NULL;
+
+ track = (MIDIEvent**) calloc(1, sizeof(MIDIEvent*) * mididata->nTracks);
+ if (NULL == head)
+ return NULL;
+
+ /* First, convert all tracks to MIDIEvent lists */
+ for (trackID = 0; trackID < mididata->nTracks; trackID++)
+ track[trackID] = MIDITracktoStream(&mididata->track[trackID]);
+
+ /* Now, merge the lists. */
+ /* TODO */
+ while(1)
+ {
+ Uint32 lowestTime = INT_MAX;
+ int currentTrackID = -1;
+
+ /* Find the next event */
+ for (trackID = 0; trackID < mididata->nTracks; trackID++)
+ {
+ if (track[trackID] && (track[trackID]->time < lowestTime))
+ {
+ currentTrackID = trackID;
+ lowestTime = track[currentTrackID]->time;
+ }
+ }
+
+ /* Check if we processes all events */
+ if (currentTrackID == -1)
+ break;
+
+ currentEvent->next = track[currentTrackID];
+ track[currentTrackID] = track[currentTrackID]->next;
+
+ currentEvent = currentEvent->next;
+
+
+ lowestTime = 0;
+ }
+
+ /* Make sure the list is properly terminated */
+ currentEvent->next = 0;
+
+ currentEvent = head->next;
+ free(track);
+ free(head); /* release the dummy head event */
+ return currentEvent;
+}
+
+static int ReadMIDIFile(MIDIFile *mididata, SDL_RWops *rw)
+{
+ int i = 0;
+ Uint32 ID;
+ Uint32 size;
+ Uint16 format;
+ Uint16 tracks;
+ Uint16 division;
+
+ if (!mididata)
+ return 0;
+ if (!rw)
+ return 0;
+
+ /* Make sure this is really a MIDI file */
+ SDL_RWread(rw, &ID, 1, 4);
+ if (BE_LONG(ID) != 'MThd')
+ return 0;
+
+ /* Header size must be 6 */
+ SDL_RWread(rw, &size, 1, 4);
+ size = BE_LONG(size);
+ if (size != 6)
+ return 0;
+
+ /* We only support format 0 and 1, but not 2 */
+ SDL_RWread(rw, &format, 1, 2);
+ format = BE_SHORT(format);
+ if (format != 0 && format != 1)
+ return 0;
+
+ SDL_RWread(rw, &tracks, 1, 2);
+ tracks = BE_SHORT(tracks);
+ mididata->nTracks = tracks;
+
+ /* Allocate tracks */
+ mididata->track = (MIDITrack*) calloc(1, sizeof(MIDITrack) * mididata->nTracks);
+ if (NULL == mididata->track)
+ {
+ Mix_SetError("Out of memory");
+ goto bail;
+ }
+
+ /* Retrieve the PPQN value, needed for playback */
+ SDL_RWread(rw, &division, 1, 2);
+ mididata->division = BE_SHORT(division);
+
+
+ for (i=0; i<tracks; i++)
+ {
+ SDL_RWread(rw, &ID, 1, 4); /* We might want to verify this is MTrk... */
+ SDL_RWread(rw, &size, 1, 4);
+ size = BE_LONG(size);
+ mididata->track[i].len = size;
+ mididata->track[i].data = malloc(size);
+ if (NULL == mididata->track[i].data)
+ {
+ Mix_SetError("Out of memory");
+ goto bail;
+ }
+ SDL_RWread(rw, mididata->track[i].data, 1, size);
+ }
+ return 1;
+
+bail:
+ for(;i >= 0; i--)
+ {
+ if (mididata->track[i].data)
+ free(mididata->track[i].data);
+ }
+
+ return 0;
+}
+
+MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division)
+{
+ MIDIFile *mididata = NULL;
+ MIDIEvent *eventList;
+ int trackID;
+
+ mididata = calloc(1, sizeof(MIDIFile));
+ if (!mididata)
+ return NULL;
+
+ /* Open the file */
+ if ( rw != NULL )
+ {
+ /* Read in the data */
+ if ( ! ReadMIDIFile(mididata, rw))
+ {
+ free(mididata);
+ return NULL;
+ }
+ }
+ else
+ {
+ free(mididata);
+ return NULL;
+ }
+
+ if (division)
+ *division = mididata->division;
+
+ eventList = MIDItoStream(mididata);
+
+ for(trackID = 0; trackID < mididata->nTracks; trackID++)
+ {
+ if (mididata->track[trackID].data)
+ free(mididata->track[trackID].data);
+ }
+ free(mididata->track);
+ free(mididata);
+
+ return eventList;
+}
+
+void FreeMIDIEventList(MIDIEvent *head)
+{
+ MIDIEvent *cur, *next;
+
+ cur = head;
+
+ while (cur)
+ {
+ next = cur->next;
+ if (cur->extraData)
+ free (cur->extraData);
+ free (cur);
+ cur = next;
+ }
+}
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.h b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.h
new file mode 100644
index 0000000000..e0400272d8
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_common.h
@@ -0,0 +1,63 @@
+/*
+ native_midi: Hardware Midi support for the SDL_mixer library
+ Copyright (C) 2000,2001 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef _NATIVE_MIDI_COMMON_H_
+#define _NATIVE_MIDI_COMMON_H_
+
+#include "SDL.h"
+
+/* Midi Status Bytes */
+#define MIDI_STATUS_NOTE_OFF 0x8
+#define MIDI_STATUS_NOTE_ON 0x9
+#define MIDI_STATUS_AFTERTOUCH 0xA
+#define MIDI_STATUS_CONTROLLER 0xB
+#define MIDI_STATUS_PROG_CHANGE 0xC
+#define MIDI_STATUS_PRESSURE 0xD
+#define MIDI_STATUS_PITCH_WHEEL 0xE
+#define MIDI_STATUS_SYSEX 0xF
+
+/* We store the midi events in a linked list; this way it is
+ easy to shuffle the tracks together later on; and we are
+ flexible in the size of each elemnt.
+ */
+typedef struct MIDIEvent
+{
+ Uint32 time; /* Time at which this midi events occurs */
+ Uint8 status; /* Status byte */
+ Uint8 data[2]; /* 1 or 2 bytes additional data for most events */
+
+ Uint32 extraLen; /* For some SysEx events, we need additional storage */
+ Uint8 *extraData;
+
+ struct MIDIEvent *next;
+} MIDIEvent;
+
+
+/* Load a midifile to memory, converting it to a list of MIDIEvents.
+ This function returns a linked lists of MIDIEvents, 0 if an error occured.
+ */
+MIDIEvent *CreateMIDIEventList(SDL_RWops *rw, Uint16 *division);
+
+/* Release a MIDIEvent list after usage. */
+void FreeMIDIEventList(MIDIEvent *head);
+
+
+#endif /* _NATIVE_MIDI_COMMON_H_ */
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_haiku.cpp b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_haiku.cpp
new file mode 100644
index 0000000000..8de350e80a
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_haiku.cpp
@@ -0,0 +1,281 @@
+/*
+ native_midi_haiku: Native Midi support on Haiku for the SDL_mixer library
+ Copyright (C) 2010 Egor Suvorov <egor_suvorov@mail.ru>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+#ifdef __HAIKU__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <MidiStore.h>
+#include <MidiDefs.h>
+#include <MidiSynthFile.h>
+#include <algorithm>
+#include <assert.h>
+extern "C" {
+#include "native_midi.h"
+#include "native_midi_common.h"
+}
+
+bool compareMIDIEvent(const MIDIEvent &a, const MIDIEvent &b)
+{
+ return a.time < b.time;
+}
+
+class MidiEventsStore : public BMidi
+{
+ public:
+ MidiEventsStore()
+ {
+ fPlaying = false;
+ fLoops = 0;
+ }
+ virtual status_t Import(SDL_RWops *rw)
+ {
+ fEvs = CreateMIDIEventList(rw, &fDivision);
+ if (!fEvs) {
+ return B_BAD_MIDI_DATA;
+ }
+ fTotal = 0;
+ for (MIDIEvent *x = fEvs; x; x = x->next) fTotal++;
+ fPos = fTotal;
+
+ sort_events();
+ return B_OK;
+ }
+ virtual void Run()
+ {
+ fPlaying = true;
+ fPos = 0;
+ MIDIEvent *ev = fEvs;
+
+ uint32 startTime = B_NOW;
+ while (KeepRunning())
+ {
+ if (!ev) {
+ if (fLoops && fEvs) {
+ --fLoops;
+ fPos = 0;
+ ev = fEvs;
+ } else
+ break;
+ }
+ SprayEvent(ev, ev->time + startTime);
+ ev = ev->next;
+ fPos++;
+ }
+ fPos = fTotal;
+ fPlaying = false;
+ }
+ virtual ~MidiEventsStore()
+ {
+ if (!fEvs) return;
+ FreeMIDIEventList(fEvs);
+ fEvs = 0;
+ }
+
+ bool IsPlaying()
+ {
+ return fPlaying;
+ }
+
+ void SetLoops(int loops)
+ {
+ fLoops = loops;
+ }
+
+ protected:
+ MIDIEvent *fEvs;
+ Uint16 fDivision;
+
+ int fPos, fTotal;
+ int fLoops;
+ bool fPlaying;
+
+ void SprayEvent(MIDIEvent *ev, uint32 time)
+ {
+ switch (ev->status & 0xF0)
+ {
+ case B_NOTE_OFF:
+ SprayNoteOff((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
+ break;
+ case B_NOTE_ON:
+ SprayNoteOn((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
+ break;
+ case B_KEY_PRESSURE:
+ SprayKeyPressure((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
+ break;
+ case B_CONTROL_CHANGE:
+ SprayControlChange((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
+ break;
+ case B_PROGRAM_CHANGE:
+ SprayProgramChange((ev->status & 0x0F) + 1, ev->data[0], time);
+ break;
+ case B_CHANNEL_PRESSURE:
+ SprayChannelPressure((ev->status & 0x0F) + 1, ev->data[0], time);
+ break;
+ case B_PITCH_BEND:
+ SprayPitchBend((ev->status & 0x0F) + 1, ev->data[0], ev->data[1], time);
+ break;
+ case 0xF:
+ switch (ev->status)
+ {
+ case B_SYS_EX_START:
+ SpraySystemExclusive(ev->extraData, ev->extraLen, time);
+ break;
+ case B_MIDI_TIME_CODE:
+ case B_SONG_POSITION:
+ case B_SONG_SELECT:
+ case B_CABLE_MESSAGE:
+ case B_TUNE_REQUEST:
+ case B_SYS_EX_END:
+ SpraySystemCommon(ev->status, ev->data[0], ev->data[1], time);
+ break;
+ case B_TIMING_CLOCK:
+ case B_START:
+ case B_STOP:
+ case B_CONTINUE:
+ case B_ACTIVE_SENSING:
+ SpraySystemRealTime(ev->status, time);
+ break;
+ case B_SYSTEM_RESET:
+ if (ev->data[0] == 0x51 && ev->data[1] == 0x03)
+ {
+ assert(ev->extraLen == 3);
+ int val = (ev->extraData[0] << 16) | (ev->extraData[1] << 8) | ev->extraData[2];
+ int tempo = 60000000 / val;
+ SprayTempoChange(tempo, time);
+ }
+ else
+ {
+ SpraySystemRealTime(ev->status, time);
+ }
+ }
+ break;
+ }
+ }
+
+ void sort_events()
+ {
+ MIDIEvent *items = new MIDIEvent[fTotal];
+ MIDIEvent *x = fEvs;
+ for (int i = 0; i < fTotal; i++)
+ {
+ memcpy(items + i, x, sizeof(MIDIEvent));
+ x = x->next;
+ }
+ std::sort(items, items + fTotal, compareMIDIEvent);
+
+ x = fEvs;
+ for (int i = 0; i < fTotal; i++)
+ {
+ MIDIEvent *ne = x->next;
+ memcpy(x, items + i, sizeof(MIDIEvent));
+ x->next = ne;
+ x = ne;
+ }
+
+ for (x = fEvs; x && x->next; x = x->next)
+ assert(x->time <= x->next->time);
+
+ delete[] items;
+ }
+};
+
+BMidiSynth synth;
+struct _NativeMidiSong {
+ MidiEventsStore *store;
+} *currentSong = NULL;
+
+char lasterr[1024];
+
+int native_midi_detect()
+{
+ status_t res = synth.EnableInput(true, false);
+ return res == B_OK;
+}
+
+void native_midi_setvolume(int volume)
+{
+ if (volume < 0) volume = 0;
+ if (volume > 128) volume = 128;
+ synth.SetVolume(volume / 128.0);
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
+{
+ NativeMidiSong *song = new NativeMidiSong;
+ song->store = new MidiEventsStore;
+ status_t res = song->store->Import(rw);
+
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ if (res != B_OK)
+ {
+ snprintf(lasterr, sizeof lasterr, "Cannot Import() midi file: status_t=%d", res);
+ delete song->store;
+ delete song;
+ return NULL;
+ }
+ return song;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+ if (song == NULL) return;
+ song->store->Stop();
+ song->store->Disconnect(&synth);
+ if (currentSong == song)
+ {
+ currentSong = NULL;
+ }
+ delete song->store;
+ delete song; song = 0;
+}
+void native_midi_start(NativeMidiSong *song, int loops)
+{
+ native_midi_stop();
+ song->store->Connect(&synth);
+ song->store->SetLoops(loops);
+ song->store->Start();
+ currentSong = song;
+}
+void native_midi_stop()
+{
+ if (currentSong == NULL) return;
+ currentSong->store->Stop();
+ currentSong->store->Disconnect(&synth);
+ while (currentSong->store->IsPlaying())
+ usleep(1000);
+ currentSong = NULL;
+}
+int native_midi_active()
+{
+ if (currentSong == NULL) return 0;
+ return currentSong->store->IsPlaying();
+}
+
+const char* native_midi_error(void)
+{
+ return lasterr;
+}
+
+#endif /* __HAIKU__ */
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_mac.c b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_mac.c
new file mode 100644
index 0000000000..01e7877472
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_mac.c
@@ -0,0 +1,644 @@
+/*
+ native_midi_mac: Native Midi support on MacOS for the SDL_mixer library
+ Copyright (C) 2001 Max Horn <max@quendi.de>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+#include "SDL_endian.h"
+
+#if __MACOS__ /*|| __MACOSX__ */
+
+#include "native_midi.h"
+#include "native_midi_common.h"
+
+#if __MACOSX__
+#include <QuickTime/QuickTimeMusic.h>
+#else
+#include <QuickTimeMusic.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Native Midi song */
+struct _NativeMidiSong
+{
+ Uint32 *tuneSequence;
+ Uint32 *tuneHeader;
+};
+
+enum
+{
+ /* number of (32-bit) long words in a note request event */
+ kNoteRequestEventLength = ((sizeof(NoteRequest)/sizeof(long)) + 2),
+
+ /* number of (32-bit) long words in a marker event */
+ kMarkerEventLength = 1,
+
+ /* number of (32-bit) long words in a general event, minus its data */
+ kGeneralEventLength = 2
+};
+
+#define ERROR_BUF_SIZE 256
+#define BUFFER_INCREMENT 5000
+
+#define REST_IF_NECESSARY() do {\
+ int timeDiff = eventPos->time - lastEventTime; \
+ if(timeDiff) \
+ { \
+ timeDiff = (int)(timeDiff*tick); \
+ qtma_StuffRestEvent(*tunePos, timeDiff); \
+ tunePos++; \
+ lastEventTime = eventPos->time; \
+ } \
+ } while(0)
+
+
+static Uint32 *BuildTuneSequence(MIDIEvent *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int *numParts);
+static Uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts);
+
+/* The global TunePlayer instance */
+static TunePlayer gTunePlayer = NULL;
+static int gInstaceCount = 0;
+static Uint32 *gCurrentTuneSequence = NULL;
+static char gErrorBuffer[ERROR_BUF_SIZE] = "";
+
+
+/* Check whether QuickTime is available */
+int native_midi_detect()
+{
+ /* TODO */
+ return 1;
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
+{
+ NativeMidiSong *song = NULL;
+ MIDIEvent *evntlist = NULL;
+ int part_to_inst[32];
+ int part_poly_max[32];
+ int numParts = 0;
+ Uint16 ppqn;
+
+ /* Init the arrays */
+ memset(part_poly_max,0,sizeof(part_poly_max));
+ memset(part_to_inst,-1,sizeof(part_to_inst));
+
+ /* Attempt to load the midi file */
+ evntlist = CreateMIDIEventList(rw, &ppqn);
+ if (!evntlist)
+ goto bail;
+
+ /* Allocate memory for the song struct */
+ song = malloc(sizeof(NativeMidiSong));
+ if (!song)
+ goto bail;
+
+ /* Build a tune sequence from the event list */
+ song->tuneSequence = BuildTuneSequence(evntlist, ppqn, part_poly_max, part_to_inst, &numParts);
+ if(!song->tuneSequence)
+ goto bail;
+
+ /* Now build a tune header from the data we collect above, create
+ all parts as needed and assign them the correct instrument.
+ */
+ song->tuneHeader = BuildTuneHeader(part_poly_max, part_to_inst, numParts);
+ if(!song->tuneHeader)
+ goto bail;
+
+ /* Increment the instance count */
+ gInstaceCount++;
+ if (gTunePlayer == NULL)
+ gTunePlayer = OpenDefaultComponent(kTunePlayerComponentType, 0);
+
+ /* Finally, free the event list */
+ FreeMIDIEventList(evntlist);
+
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return song;
+
+bail:
+ if (evntlist)
+ FreeMIDIEventList(evntlist);
+
+ if (song)
+ {
+ if(song->tuneSequence)
+ free(song->tuneSequence);
+
+ if(song->tuneHeader)
+ DisposePtr((Ptr)song->tuneHeader);
+
+ free(song);
+ }
+
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+ if(!song || !song->tuneSequence)
+ return;
+
+ /* If this is the currently playing song, stop it now */
+ if (song->tuneSequence == gCurrentTuneSequence)
+ native_midi_stop();
+
+ /* Finally, free the data storage */
+ free(song->tuneSequence);
+ DisposePtr((Ptr)song->tuneHeader);
+ free(song);
+
+ /* Increment the instance count */
+ gInstaceCount--;
+ if ((gTunePlayer != NULL) && (gInstaceCount == 0))
+ {
+ CloseComponent(gTunePlayer);
+ gTunePlayer = NULL;
+ }
+}
+
+void native_midi_start(NativeMidiSong *song, int loops)
+{
+ UInt32 queueFlags = 0;
+ ComponentResult tpError;
+
+ assert (gTunePlayer != NULL);
+
+ /* FIXME: is this code even used anymore? */
+ assert (loops == 0);
+
+ SDL_PauseAudio(1);
+ SDL_UnlockAudio();
+
+ /* First, stop the currently playing music */
+ native_midi_stop();
+
+ /* Set up the queue flags */
+ queueFlags = kTuneStartNow;
+
+ /* Set the time scale (units per second), we want milliseconds */
+ tpError = TuneSetTimeScale(gTunePlayer, 1000);
+ if (tpError != noErr)
+ {
+ strncpy (gErrorBuffer, "MIDI error during TuneSetTimeScale", ERROR_BUF_SIZE);
+ goto done;
+ }
+
+ /* Set the header, to tell what instruments are used */
+ tpError = TuneSetHeader(gTunePlayer, (UInt32 *)song->tuneHeader);
+ if (tpError != noErr)
+ {
+ strncpy (gErrorBuffer, "MIDI error during TuneSetHeader", ERROR_BUF_SIZE);
+ goto done;
+ }
+
+ /* Have it allocate whatever resources are needed */
+ tpError = TunePreroll(gTunePlayer);
+ if (tpError != noErr)
+ {
+ strncpy (gErrorBuffer, "MIDI error during TunePreroll", ERROR_BUF_SIZE);
+ goto done;
+ }
+
+ /* We want to play at normal volume */
+ tpError = TuneSetVolume(gTunePlayer, 0x00010000);
+ if (tpError != noErr)
+ {
+ strncpy (gErrorBuffer, "MIDI error during TuneSetVolume", ERROR_BUF_SIZE);
+ goto done;
+ }
+
+ /* Finally, start playing the full song */
+ gCurrentTuneSequence = song->tuneSequence;
+ tpError = TuneQueue(gTunePlayer, (UInt32 *)song->tuneSequence, 0x00010000, 0, 0xFFFFFFFF, queueFlags, NULL, 0);
+ if (tpError != noErr)
+ {
+ strncpy (gErrorBuffer, "MIDI error during TuneQueue", ERROR_BUF_SIZE);
+ goto done;
+ }
+
+done:
+ SDL_LockAudio();
+ SDL_PauseAudio(0);
+}
+
+void native_midi_stop()
+{
+ if (gTunePlayer == NULL)
+ return;
+
+ /* Stop music */
+ TuneStop(gTunePlayer, 0);
+
+ /* Deallocate all instruments */
+ TuneUnroll(gTunePlayer);
+}
+
+int native_midi_active()
+{
+ if (gTunePlayer != NULL)
+ {
+ TuneStatus ts;
+
+ TuneGetStatus(gTunePlayer,&ts);
+ return ts.queueTime != 0;
+ }
+ else
+ return 0;
+}
+
+void native_midi_setvolume(int volume)
+{
+ if (gTunePlayer == NULL)
+ return;
+
+ /* QTMA olume may range from 0.0 to 1.0 (in 16.16 fixed point encoding) */
+ TuneSetVolume(gTunePlayer, (0x00010000 * volume)/SDL_MIX_MAXVOLUME);
+}
+
+const char *native_midi_error(void)
+{
+ return gErrorBuffer;
+}
+
+Uint32 *BuildTuneSequence(MIDIEvent *evntlist, int ppqn, int part_poly_max[32], int part_to_inst[32], int *numParts)
+{
+ int part_poly[32];
+ int channel_to_part[16];
+
+ int channel_pan[16];
+ int channel_vol[16];
+ int channel_pitch_bend[16];
+
+ int lastEventTime = 0;
+ int tempo = 500000;
+ double Ippqn = 1.0 / (1000*ppqn);
+ double tick = tempo * Ippqn;
+ MIDIEvent *eventPos = evntlist;
+ MIDIEvent *noteOffPos;
+ Uint32 *tunePos, *endPos;
+ Uint32 *tuneSequence;
+ size_t tuneSize;
+
+ /* allocate space for the tune header */
+ tuneSize = 5000;
+ tuneSequence = (Uint32 *)malloc(tuneSize * sizeof(Uint32));
+ if (tuneSequence == NULL)
+ return NULL;
+
+ /* Set starting position in our tune memory */
+ tunePos = tuneSequence;
+ endPos = tuneSequence + tuneSize;
+
+ /* Initialise the arrays */
+ memset(part_poly,0,sizeof(part_poly));
+
+ memset(channel_to_part,-1,sizeof(channel_to_part));
+ memset(channel_pan,-1,sizeof(channel_pan));
+ memset(channel_vol,-1,sizeof(channel_vol));
+ memset(channel_pitch_bend,-1,sizeof(channel_pitch_bend));
+
+ *numParts = 0;
+
+ /*
+ * Now the major work - iterate over all GM events,
+ * and turn them into QuickTime Music format.
+ * At the same time, calculate the max. polyphony for each part,
+ * and also the part->instrument mapping.
+ */
+ while(eventPos)
+ {
+ int status = (eventPos->status&0xF0)>>4;
+ int channel = eventPos->status&0x0F;
+ int part = channel_to_part[channel];
+ int velocity, pitch;
+ int value, controller;
+ int bend;
+ int newInst;
+
+ /* Check if we are running low on space... */
+ if((tunePos+16) > endPos)
+ {
+ /* Resize our data storage. */
+ Uint32 *oldTuneSequence = tuneSequence;
+
+ tuneSize += BUFFER_INCREMENT;
+ tuneSequence = (Uint32 *)realloc(tuneSequence, tuneSize * sizeof(Uint32));
+ if(oldTuneSequence != tuneSequence)
+ tunePos += tuneSequence - oldTuneSequence;
+ endPos = tuneSequence + tuneSize;
+ }
+
+ switch (status)
+ {
+ case MIDI_STATUS_NOTE_OFF:
+ assert(part>=0 && part<=31);
+
+ /* Keep track of the polyphony of the current part */
+ part_poly[part]--;
+ break;
+ case MIDI_STATUS_NOTE_ON:
+ if (part < 0)
+ {
+ /* If no part is specified yet, we default to the first instrument, which
+ is piano (or the first drum kit if we are on the drum channel)
+ */
+ int newInst;
+
+ if (channel == 9)
+ newInst = kFirstDrumkit + 1; /* the first drum kit is the "no drum" kit! */
+ else
+ newInst = kFirstGMInstrument;
+ part = channel_to_part[channel] = *numParts;
+ part_to_inst[(*numParts)++] = newInst;
+ }
+ /* TODO - add support for more than 32 parts using eXtended QTMA events */
+ assert(part<=31);
+
+ /* Decode pitch & velocity */
+ pitch = eventPos->data[0];
+ velocity = eventPos->data[1];
+
+ if (velocity == 0)
+ {
+ /* was a NOTE OFF in disguise, so we decrement the polyphony */
+ part_poly[part]--;
+ }
+ else
+ {
+ /* Keep track of the polyphony of the current part */
+ int foo = ++part_poly[part];
+ if (part_poly_max[part] < foo)
+ part_poly_max[part] = foo;
+
+ /* Now scan forward to find the matching NOTE OFF event */
+ for(noteOffPos = eventPos; noteOffPos; noteOffPos = noteOffPos->next)
+ {
+ if ((noteOffPos->status&0xF0)>>4 == MIDI_STATUS_NOTE_OFF
+ && channel == (eventPos->status&0x0F)
+ && pitch == noteOffPos->data[0])
+ break;
+ /* NOTE ON with velocity == 0 is the same as a NOTE OFF */
+ if ((noteOffPos->status&0xF0)>>4 == MIDI_STATUS_NOTE_ON
+ && channel == (eventPos->status&0x0F)
+ && pitch == noteOffPos->data[0]
+ && 0 == noteOffPos->data[1])
+ break;
+ }
+
+ /* Did we find a note off? Should always be the case, but who knows... */
+ if (noteOffPos)
+ {
+ /* We found a NOTE OFF, now calculate the note duration */
+ int duration = (int)((noteOffPos->time - eventPos->time)*tick);
+
+ REST_IF_NECESSARY();
+ /* Now we need to check if we get along with a normal Note Event, or if we need an extended one... */
+ if (duration < 2048 && pitch>=32 && pitch<=95 && velocity>=0 && velocity<=127)
+ {
+ qtma_StuffNoteEvent(*tunePos, part, pitch, velocity, duration);
+ tunePos++;
+ }
+ else
+ {
+ qtma_StuffXNoteEvent(*tunePos, *(tunePos+1), part, pitch, velocity, duration);
+ tunePos+=2;
+ }
+ }
+ }
+ break;
+ case MIDI_STATUS_AFTERTOUCH:
+ /* NYI - use kControllerAfterTouch. But how are the parameters to be mapped? */
+ break;
+ case MIDI_STATUS_CONTROLLER:
+ controller = eventPos->data[0];
+ value = eventPos->data[1];
+
+ switch(controller)
+ {
+ case 0: /* bank change - igore for now */
+ break;
+ case kControllerVolume:
+ if(channel_vol[channel] != value<<8)
+ {
+ channel_vol[channel] = value<<8;
+ if(part>=0 && part<=31)
+ {
+ REST_IF_NECESSARY();
+ qtma_StuffControlEvent(*tunePos, part, kControllerVolume, channel_vol[channel]);
+ tunePos++;
+ }
+ }
+ break;
+ case kControllerPan:
+ if(channel_pan[channel] != (value << 1) + 256)
+ {
+ channel_pan[channel] = (value << 1) + 256;
+ if(part>=0 && part<=31)
+ {
+ REST_IF_NECESSARY();
+ qtma_StuffControlEvent(*tunePos, part, kControllerPan, channel_pan[channel]);
+ tunePos++;
+ }
+ }
+ break;
+ default:
+ /* No other controllers implemented yet */;
+ break;
+ }
+
+ break;
+ case MIDI_STATUS_PROG_CHANGE:
+ /* Instrument changed */
+ newInst = eventPos->data[0];
+
+ /* Channel 9 (the 10th channel) is different, it indicates a drum kit */
+ if (channel == 9)
+ newInst += kFirstDrumkit;
+ else
+ newInst += kFirstGMInstrument;
+ /* Only if the instrument for this channel *really* changed, add a new part. */
+ if(newInst != part_to_inst[part])
+ {
+ /* TODO maybe make use of kGeneralEventPartChange here,
+ to help QT reuse note channels?
+ */
+ part = channel_to_part[channel] = *numParts;
+ part_to_inst[(*numParts)++] = newInst;
+
+ if(channel_vol[channel] >= 0)
+ {
+ REST_IF_NECESSARY();
+ qtma_StuffControlEvent(*tunePos, part, kControllerVolume, channel_vol[channel]);
+ tunePos++;
+ }
+ if(channel_pan[channel] >= 0)
+ {
+ REST_IF_NECESSARY();
+ qtma_StuffControlEvent(*tunePos, part, kControllerPan, channel_pan[channel]);
+ tunePos++;
+ }
+ if(channel_pitch_bend[channel] >= 0)
+ {
+ REST_IF_NECESSARY();
+ qtma_StuffControlEvent(*tunePos, part, kControllerPitchBend, channel_pitch_bend[channel]);
+ tunePos++;
+ }
+ }
+ break;
+ case MIDI_STATUS_PRESSURE:
+ /* NYI */
+ break;
+ case MIDI_STATUS_PITCH_WHEEL:
+ /* In the midi spec, 0x2000 = center, 0x0000 = - 2 semitones, 0x3FFF = +2 semitones
+ but for QTMA, we specify it as a 8.8 fixed point of semitones
+ TODO: detect "pitch bend range changes" & honor them!
+ */
+ bend = (eventPos->data[0] & 0x7f) | ((eventPos->data[1] & 0x7f) << 7);
+
+ /* "Center" the bend */
+ bend -= 0x2000;
+
+ /* Move it to our format: */
+ bend <<= 4;
+
+ /* If it turns out the pitch bend didn't change, stop here */
+ if(channel_pitch_bend[channel] == bend)
+ break;
+
+ channel_pitch_bend[channel] = bend;
+ if(part>=0 && part<=31)
+ {
+ /* Stuff a control event */
+ REST_IF_NECESSARY();
+ qtma_StuffControlEvent(*tunePos, part, kControllerPitchBend, bend);
+ tunePos++;
+ }
+ break;
+ case MIDI_STATUS_SYSEX:
+ if (eventPos->status == 0xFF && eventPos->data[0] == 0x51) /* Tempo change */
+ {
+ tempo = (eventPos->extraData[0] << 16) +
+ (eventPos->extraData[1] << 8) +
+ eventPos->extraData[2];
+
+ tick = tempo * Ippqn;
+ }
+ break;
+ }
+
+ /* on to the next event */
+ eventPos = eventPos->next;
+ }
+
+ /* Finally, place an end marker */
+ *tunePos = kEndMarkerValue;
+
+ return tuneSequence;
+}
+
+Uint32 *BuildTuneHeader(int part_poly_max[32], int part_to_inst[32], int numParts)
+{
+ Uint32 *myHeader;
+ Uint32 *myPos1, *myPos2; /* pointers to the head and tail long words of a music event */
+ NoteRequest *myNoteRequest;
+ NoteAllocator myNoteAllocator; /* for the NAStuffToneDescription call */
+ ComponentResult myErr = noErr;
+ int part;
+
+ myHeader = NULL;
+ myNoteAllocator = NULL;
+
+ /*
+ * Open up the Note Allocator
+ */
+ myNoteAllocator = OpenDefaultComponent(kNoteAllocatorComponentType,0);
+ if (myNoteAllocator == NULL)
+ goto bail;
+
+ /*
+ * Allocate space for the tune header
+ */
+ myHeader = (Uint32 *)
+ NewPtrClear((numParts * kNoteRequestEventLength + kMarkerEventLength) * sizeof(Uint32));
+ if (myHeader == NULL)
+ goto bail;
+
+ myPos1 = myHeader;
+
+ /*
+ * Loop over all parts
+ */
+ for(part = 0; part < numParts; ++part)
+ {
+ /*
+ * Stuff request for the instrument with the given polyphony
+ */
+ myPos2 = myPos1 + (kNoteRequestEventLength - 1); /* last longword of general event */
+ qtma_StuffGeneralEvent(*myPos1, *myPos2, part, kGeneralEventNoteRequest, kNoteRequestEventLength);
+ myNoteRequest = (NoteRequest *)(myPos1 + 1);
+ myNoteRequest->info.flags = 0;
+ /* I'm told by the Apple people that the Quicktime types were poorly designed and it was
+ * too late to change them. On little endian, the BigEndian(Short|Fixed) types are structs
+ * while on big endian they are primitive types. Furthermore, Quicktime failed to
+ * provide setter and getter functions. To get this to work, we need to case the
+ * code for the two possible situations.
+ * My assumption is that the right-side value was always expected to be BigEndian
+ * as it was written way before the Universal Binary transition. So in the little endian
+ * case, OSSwap is used.
+ */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+ myNoteRequest->info.polyphony.bigEndianValue = OSSwapHostToBigInt16(part_poly_max[part]);
+ myNoteRequest->info.typicalPolyphony.bigEndianValue = OSSwapHostToBigInt32(0x00010000);
+#else
+ myNoteRequest->info.polyphony = part_poly_max[part];
+ myNoteRequest->info.typicalPolyphony = 0x00010000;
+#endif
+ myErr = NAStuffToneDescription(myNoteAllocator,part_to_inst[part],&myNoteRequest->tone);
+ if (myErr != noErr)
+ goto bail;
+
+ /* move pointer to beginning of next event */
+ myPos1 += kNoteRequestEventLength;
+ }
+
+ *myPos1 = kEndMarkerValue; /* end of sequence marker */
+
+
+bail:
+ if(myNoteAllocator)
+ CloseComponent(myNoteAllocator);
+
+ /* if we encountered an error, dispose of the storage we allocated and return NULL */
+ if (myErr != noErr) {
+ DisposePtr((Ptr)myHeader);
+ myHeader = NULL;
+ }
+
+ return myHeader;
+}
+
+#endif /* MacOS native MIDI support */
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_macosx.c b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_macosx.c
new file mode 100644
index 0000000000..8fefbc9616
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_macosx.c
@@ -0,0 +1,322 @@
+/*
+ native_midi_macosx: Native Midi support on Mac OS X for the SDL_mixer library
+ Copyright (C) 2009 Ryan C. Gordon <icculus@icculus.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* This is Mac OS X only, using Core MIDI.
+ Mac OS 9 support via QuickTime is in native_midi_mac.c */
+
+#include "SDL_config.h"
+
+#if __MACOSX__
+
+#include <Carbon/Carbon.h>
+#include <AudioToolbox/AudioToolbox.h>
+#include <AvailabilityMacros.h>
+
+#include "../SDL_mixer.h"
+#include "SDL_endian.h"
+#include "native_midi.h"
+
+/* Native Midi song */
+struct _NativeMidiSong
+{
+ MusicPlayer player;
+ MusicSequence sequence;
+ MusicTimeStamp endTime;
+ AudioUnit audiounit;
+ int loops;
+};
+
+static NativeMidiSong *currentsong = NULL;
+static int latched_volume = MIX_MAX_VOLUME;
+
+static OSStatus
+GetSequenceLength(MusicSequence sequence, MusicTimeStamp *_sequenceLength)
+{
+ // http://lists.apple.com/archives/Coreaudio-api/2003/Jul/msg00370.html
+ // figure out sequence length
+ UInt32 ntracks, i;
+ MusicTimeStamp sequenceLength = 0;
+ OSStatus err;
+
+ err = MusicSequenceGetTrackCount(sequence, &ntracks);
+ if (err != noErr)
+ return err;
+
+ for (i = 0; i < ntracks; ++i)
+ {
+ MusicTrack track;
+ MusicTimeStamp tracklen = 0;
+ UInt32 tracklenlen = sizeof (tracklen);
+
+ err = MusicSequenceGetIndTrack(sequence, i, &track);
+ if (err != noErr)
+ return err;
+
+ err = MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
+ &tracklen, &tracklenlen);
+ if (err != noErr)
+ return err;
+
+ if (sequenceLength < tracklen)
+ sequenceLength = tracklen;
+ }
+
+ *_sequenceLength = sequenceLength;
+
+ return noErr;
+}
+
+
+/* we're looking for the sequence output audiounit. */
+static OSStatus
+GetSequenceAudioUnit(MusicSequence sequence, AudioUnit *aunit)
+{
+ AUGraph graph;
+ UInt32 nodecount, i;
+ OSStatus err;
+
+ err = MusicSequenceGetAUGraph(sequence, &graph);
+ if (err != noErr)
+ return err;
+
+ err = AUGraphGetNodeCount(graph, &nodecount);
+ if (err != noErr)
+ return err;
+
+ for (i = 0; i < nodecount; i++) {
+ AUNode node;
+
+ if (AUGraphGetIndNode(graph, i, &node) != noErr)
+ continue; /* better luck next time. */
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* this is deprecated, but works back to 10.0 */
+ {
+ struct ComponentDescription desc;
+ UInt32 classdatasize = 0;
+ void *classdata = NULL;
+ err = AUGraphGetNodeInfo(graph, node, &desc, &classdatasize,
+ &classdata, aunit);
+ if (err != noErr)
+ continue;
+ else if (desc.componentType != kAudioUnitType_Output)
+ continue;
+ else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
+ continue;
+ }
+ #else /* not deprecated, but requires 10.5 or later */
+ {
+ AudioComponentDescription desc;
+ if (AUGraphNodeInfo(graph, node, &desc, aunit) != noErr)
+ continue;
+ else if (desc.componentType != kAudioUnitType_Output)
+ continue;
+ else if (desc.componentSubType != kAudioUnitSubType_DefaultOutput)
+ continue;
+ }
+ #endif
+
+ return noErr; /* found it! */
+ }
+
+ return kAUGraphErr_NodeNotFound;
+}
+
+
+int native_midi_detect()
+{
+ return 1; /* always available. */
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
+{
+ NativeMidiSong *retval = NULL;
+ void *buf = NULL;
+ int len = 0;
+ CFDataRef data = NULL;
+
+ if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
+ goto fail;
+ len = SDL_RWtell(rw);
+ if (len < 0)
+ goto fail;
+ if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
+ goto fail;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ goto fail;
+
+ if (SDL_RWread(rw, buf, len, 1) != 1)
+ goto fail;
+
+ retval = malloc(sizeof(NativeMidiSong));
+ if (retval == NULL)
+ goto fail;
+
+ memset(retval, '\0', sizeof (*retval));
+
+ if (NewMusicPlayer(&retval->player) != noErr)
+ goto fail;
+ if (NewMusicSequence(&retval->sequence) != noErr)
+ goto fail;
+
+ data = CFDataCreate(NULL, (const UInt8 *) buf, len);
+ if (data == NULL)
+ goto fail;
+
+ free(buf);
+ buf = NULL;
+
+ #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 /* this is deprecated, but works back to 10.3 */
+ if (MusicSequenceLoadSMFDataWithFlags(retval->sequence, data, 0) != noErr)
+ goto fail;
+ #else /* not deprecated, but requires 10.5 or later */
+ if (MusicSequenceFileLoadData(retval->sequence, data, 0, 0) != noErr)
+ goto fail;
+ #endif
+
+ CFRelease(data);
+ data = NULL;
+
+ if (GetSequenceLength(retval->sequence, &retval->endTime) != noErr)
+ goto fail;
+
+ if (MusicPlayerSetSequence(retval->player, retval->sequence) != noErr)
+ goto fail;
+
+ if (freerw)
+ SDL_RWclose(rw);
+
+ return retval;
+
+fail:
+ if (retval) {
+ if (retval->sequence)
+ DisposeMusicSequence(retval->sequence);
+ if (retval->player)
+ DisposeMusicPlayer(retval->player);
+ free(retval);
+ }
+
+ if (data)
+ CFRelease(data);
+
+ if (buf)
+ free(buf);
+
+ if (freerw)
+ SDL_RWclose(rw);
+
+ return NULL;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+ if (song != NULL) {
+ if (currentsong == song)
+ currentsong = NULL;
+ MusicPlayerStop(song->player);
+ DisposeMusicSequence(song->sequence);
+ DisposeMusicPlayer(song->player);
+ free(song);
+ }
+}
+
+void native_midi_start(NativeMidiSong *song, int loops)
+{
+ int vol;
+
+ if (song == NULL)
+ return;
+
+ SDL_PauseAudio(1);
+ SDL_UnlockAudio();
+
+ if (currentsong)
+ MusicPlayerStop(currentsong->player);
+
+ currentsong = song;
+ currentsong->loops = loops;
+
+ MusicPlayerPreroll(song->player);
+ MusicPlayerSetTime(song->player, 0);
+ MusicPlayerStart(song->player);
+
+ GetSequenceAudioUnit(song->sequence, &song->audiounit);
+
+ vol = latched_volume;
+ latched_volume++; /* just make this not match. */
+ native_midi_setvolume(vol);
+
+ SDL_LockAudio();
+ SDL_PauseAudio(0);
+}
+
+void native_midi_stop()
+{
+ if (currentsong) {
+ SDL_PauseAudio(1);
+ SDL_UnlockAudio();
+ MusicPlayerStop(currentsong->player);
+ currentsong = NULL;
+ SDL_LockAudio();
+ SDL_PauseAudio(0);
+ }
+}
+
+int native_midi_active()
+{
+ MusicTimeStamp currentTime = 0;
+ if (currentsong == NULL)
+ return 0;
+
+ MusicPlayerGetTime(currentsong->player, &currentTime);
+ if ((currentTime < currentsong->endTime) ||
+ (currentTime >= kMusicTimeStamp_EndOfTrack)) {
+ return 1;
+ } else if (currentsong->loops) {
+ --currentsong->loops;
+ MusicPlayerSetTime(currentsong->player, 0);
+ return 1;
+ }
+ return 0;
+}
+
+void native_midi_setvolume(int volume)
+{
+ if (latched_volume == volume)
+ return;
+
+ latched_volume = volume;
+ if ((currentsong) && (currentsong->audiounit)) {
+ const float floatvol = ((float) volume) / ((float) MIX_MAX_VOLUME);
+ AudioUnitSetParameter(currentsong->audiounit, kHALOutputParam_Volume,
+ kAudioUnitScope_Global, 0, floatvol, 0);
+ }
+}
+
+const char *native_midi_error(void)
+{
+ return ""; /* !!! FIXME */
+}
+
+#endif /* Mac OS X native MIDI support */
+
diff --git a/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_win32.c b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_win32.c
new file mode 100644
index 0000000000..187d989ff3
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/native_midi/native_midi_win32.c
@@ -0,0 +1,312 @@
+/*
+ native_midi: Hardware Midi support for the SDL_mixer library
+ Copyright (C) 2000,2001 Florian 'Proff' Schulze <florian.proff.schulze@gmx.net>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_config.h"
+
+/* everything below is currently one very big bad hack ;) Proff */
+
+#if __WIN32__
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <windowsx.h>
+#include <mmsystem.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "native_midi.h"
+#include "native_midi_common.h"
+
+struct _NativeMidiSong {
+ int MusicLoaded;
+ int MusicPlaying;
+ int Loops;
+ int CurrentHdr;
+ MIDIHDR MidiStreamHdr[2];
+ MIDIEVENT *NewEvents;
+ Uint16 ppqn;
+ int Size;
+ int NewPos;
+};
+
+static UINT MidiDevice=MIDI_MAPPER;
+static HMIDISTRM hMidiStream;
+static NativeMidiSong *currentsong;
+
+static int BlockOut(NativeMidiSong *song)
+{
+ MMRESULT err;
+ int BlockSize;
+ MIDIHDR *hdr;
+
+ if ((song->MusicLoaded) && (song->NewEvents))
+ {
+ // proff 12/8/98: Added for safety
+ song->CurrentHdr = !song->CurrentHdr;
+ hdr = &song->MidiStreamHdr[song->CurrentHdr];
+ midiOutUnprepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR));
+ if (song->NewPos>=song->Size)
+ return 0;
+ BlockSize=(song->Size-song->NewPos);
+ if (BlockSize<=0)
+ return 0;
+ if (BlockSize>36000)
+ BlockSize=36000;
+ hdr->lpData=(void *)((unsigned char *)song->NewEvents+song->NewPos);
+ song->NewPos+=BlockSize;
+ hdr->dwBufferLength=BlockSize;
+ hdr->dwBytesRecorded=BlockSize;
+ hdr->dwFlags=0;
+ hdr->dwOffset=0;
+ err=midiOutPrepareHeader((HMIDIOUT)hMidiStream,hdr,sizeof(MIDIHDR));
+ if (err!=MMSYSERR_NOERROR)
+ return 0;
+ err=midiStreamOut(hMidiStream,hdr,sizeof(MIDIHDR));
+ return 0;
+ }
+ return 1;
+}
+
+static void MIDItoStream(NativeMidiSong *song, MIDIEvent *evntlist)
+{
+ int eventcount;
+ MIDIEvent *event;
+ MIDIEVENT *newevent;
+
+ eventcount=0;
+ event=evntlist;
+ while (event)
+ {
+ eventcount++;
+ event=event->next;
+ }
+ song->NewEvents=malloc(eventcount*3*sizeof(DWORD));
+ if (!song->NewEvents)
+ return;
+ memset(song->NewEvents,0,(eventcount*3*sizeof(DWORD)));
+
+ eventcount=0;
+ event=evntlist;
+ newevent=song->NewEvents;
+ while (event)
+ {
+ int status = (event->status&0xF0)>>4;
+ switch (status)
+ {
+ case MIDI_STATUS_NOTE_OFF:
+ case MIDI_STATUS_NOTE_ON:
+ case MIDI_STATUS_AFTERTOUCH:
+ case MIDI_STATUS_CONTROLLER:
+ case MIDI_STATUS_PROG_CHANGE:
+ case MIDI_STATUS_PRESSURE:
+ case MIDI_STATUS_PITCH_WHEEL:
+ newevent->dwDeltaTime=event->time;
+ newevent->dwEvent=(event->status|0x80)|(event->data[0]<<8)|(event->data[1]<<16)|(MEVT_SHORTMSG<<24);
+ newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
+ eventcount++;
+ break;
+
+ case MIDI_STATUS_SYSEX:
+ if (event->status == 0xFF && event->data[0] == 0x51) /* Tempo change */
+ {
+ int tempo = (event->extraData[0] << 16) |
+ (event->extraData[1] << 8) |
+ event->extraData[2];
+ newevent->dwDeltaTime=event->time;
+ newevent->dwEvent=(MEVT_TEMPO<<24) | tempo;
+ newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
+ eventcount++;
+ }
+ break;
+ }
+
+ event=event->next;
+ }
+
+ song->Size=eventcount*3*sizeof(DWORD);
+
+ {
+ int time;
+ int temptime;
+
+ song->NewPos=0;
+ time=0;
+ newevent=song->NewEvents;
+ while (song->NewPos<song->Size)
+ {
+ temptime=newevent->dwDeltaTime;
+ newevent->dwDeltaTime-=time;
+ time=temptime;
+ if ((song->NewPos+12)>=song->Size)
+ newevent->dwEvent |= MEVT_F_CALLBACK;
+ newevent=(MIDIEVENT*)((char*)newevent+(3*sizeof(DWORD)));
+ song->NewPos+=12;
+ }
+ }
+ song->NewPos=0;
+ song->MusicLoaded=1;
+}
+
+void CALLBACK MidiProc( HMIDIIN hMidi, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD_PTR dwParam1, DWORD_PTR dwParam2 )
+{
+ switch( uMsg )
+ {
+ case MOM_DONE:
+ if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr[currentsong->CurrentHdr]))
+ BlockOut(currentsong);
+ break;
+ case MOM_POSITIONCB:
+ if ((currentsong->MusicLoaded) && (dwParam1 == (DWORD_PTR)&currentsong->MidiStreamHdr[currentsong->CurrentHdr])) {
+ if (currentsong->Loops) {
+ --currentsong->Loops;
+ currentsong->NewPos=0;
+ BlockOut(currentsong);
+ } else {
+ currentsong->MusicPlaying=0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int native_midi_detect()
+{
+ MMRESULT merr;
+ HMIDISTRM MidiStream;
+
+ merr=midiStreamOpen(&MidiStream,&MidiDevice,(DWORD)1,(DWORD_PTR)MidiProc,(DWORD_PTR)0,CALLBACK_FUNCTION);
+ if (merr!=MMSYSERR_NOERROR)
+ return 0;
+ midiStreamClose(MidiStream);
+ return 1;
+}
+
+NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw, int freerw)
+{
+ NativeMidiSong *newsong;
+ MIDIEvent *evntlist = NULL;
+
+ newsong=malloc(sizeof(NativeMidiSong));
+ if (!newsong) {
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+ }
+ memset(newsong,0,sizeof(NativeMidiSong));
+
+ /* Attempt to load the midi file */
+ evntlist = CreateMIDIEventList(rw, &newsong->ppqn);
+ if (!evntlist)
+ {
+ free(newsong);
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return NULL;
+ }
+
+ MIDItoStream(newsong, evntlist);
+
+ FreeMIDIEventList(evntlist);
+
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+ return newsong;
+}
+
+void native_midi_freesong(NativeMidiSong *song)
+{
+ if (hMidiStream)
+ {
+ midiStreamStop(hMidiStream);
+ midiStreamClose(hMidiStream);
+ }
+ if (song)
+ {
+ if (song->NewEvents)
+ free(song->NewEvents);
+ free(song);
+ }
+}
+
+void native_midi_start(NativeMidiSong *song, int loops)
+{
+ MMRESULT merr;
+ MIDIPROPTIMEDIV mptd;
+
+ native_midi_stop();
+ if (!hMidiStream)
+ {
+ merr=midiStreamOpen(&hMidiStream,&MidiDevice,(DWORD)1,(DWORD_PTR)MidiProc,(DWORD_PTR)0,CALLBACK_FUNCTION);
+ if (merr!=MMSYSERR_NOERROR)
+ {
+ hMidiStream = NULL; // should I do midiStreamClose(hMidiStream) before?
+ return;
+ }
+ //midiStreamStop(hMidiStream);
+ currentsong=song;
+ currentsong->NewPos=0;
+ currentsong->MusicPlaying=1;
+ currentsong->Loops=loops;
+ mptd.cbStruct=sizeof(MIDIPROPTIMEDIV);
+ mptd.dwTimeDiv=currentsong->ppqn;
+ merr=midiStreamProperty(hMidiStream,(LPBYTE)&mptd,MIDIPROP_SET | MIDIPROP_TIMEDIV);
+ BlockOut(song);
+ merr=midiStreamRestart(hMidiStream);
+ }
+}
+
+void native_midi_stop()
+{
+ if (!hMidiStream)
+ return;
+ midiStreamStop(hMidiStream);
+ midiStreamClose(hMidiStream);
+ currentsong=NULL;
+ hMidiStream = NULL;
+}
+
+int native_midi_active()
+{
+ return currentsong->MusicPlaying;
+}
+
+void native_midi_setvolume(int volume)
+{
+ int calcVolume;
+ if (volume > 128)
+ volume = 128;
+ if (volume < 0)
+ volume = 0;
+ calcVolume = (65535 * volume / 128);
+
+ midiOutSetVolume((HMIDIOUT)hMidiStream, MAKELONG(calcVolume , calcVolume));
+}
+
+const char *native_midi_error(void)
+{
+ return "";
+}
+
+#endif /* Windows native MIDI support */
diff --git a/apps/plugins/sdl/SDL_mixer/playmus.c b/apps/plugins/sdl/SDL_mixer/playmus.c
new file mode 100644
index 0000000000..4f8bb612a1
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/playmus.c
@@ -0,0 +1,234 @@
+/*
+ PLAYMUS: A test application for the SDL mixer library.
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#ifdef unix
+#include <unistd.h>
+#endif
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+
+static int audio_open = 0;
+static Mix_Music *music = NULL;
+static int next_track = 0;
+
+void CleanUp(int exitcode)
+{
+ if( Mix_PlayingMusic() ) {
+ Mix_FadeOutMusic(1500);
+ SDL_Delay(1500);
+ }
+ if ( music ) {
+ Mix_FreeMusic(music);
+ music = NULL;
+ }
+ if ( audio_open ) {
+ Mix_CloseAudio();
+ audio_open = 0;
+ }
+ SDL_Quit();
+ exit(exitcode);
+}
+
+void Usage(char *argv0)
+{
+ fprintf(stderr, "Usage: %s [-i] [-l] [-8] [-r rate] [-c channels] [-b buffers] [-v N] [-rwops] <musicfile>\n", argv0);
+}
+
+void Menu(void)
+{
+ char buf[10];
+
+ printf("Available commands: (p)ause (r)esume (h)alt volume(v#) > ");
+ if (scanf("%s",buf) == 1) {
+ switch(buf[0]){
+ case 'p': case 'P':
+ Mix_PauseMusic();
+ break;
+ case 'r': case 'R':
+ Mix_ResumeMusic();
+ break;
+ case 'h': case 'H':
+ Mix_HaltMusic();
+ break;
+ case 'v': case 'V':
+ Mix_VolumeMusic(atoi(buf+1));
+ break;
+ }
+ }
+ printf("Music playing: %s Paused: %s\n", Mix_PlayingMusic() ? "yes" : "no",
+ Mix_PausedMusic() ? "yes" : "no");
+}
+
+#ifdef HAVE_SIGNAL_H
+
+void IntHandler(int sig)
+{
+ switch (sig) {
+ case SIGINT:
+ next_track++;
+ break;
+ }
+}
+
+#endif
+
+int main(int argc, char *argv[])
+{
+ SDL_RWops *rwfp = NULL;
+ int audio_rate;
+ Uint16 audio_format;
+ int audio_channels;
+ int audio_buffers;
+ int audio_volume = MIX_MAX_VOLUME;
+ int looping = 0;
+ int interactive = 0;
+ int rwops = 0;
+ int i;
+
+ /* Initialize variables */
+ audio_rate = 22050;
+ audio_format = AUDIO_S16;
+ audio_channels = 2;
+ audio_buffers = 4096;
+
+ /* Check command line usage */
+ for ( i=1; argv[i] && (*argv[i] == '-'); ++i ) {
+ if ( (strcmp(argv[i], "-r") == 0) && argv[i+1] ) {
+ ++i;
+ audio_rate = atoi(argv[i]);
+ } else
+ if ( strcmp(argv[i], "-m") == 0 ) {
+ audio_channels = 1;
+ } else
+ if ( (strcmp(argv[i], "-c") == 0) && argv[i+1] ) {
+ ++i;
+ audio_channels = atoi(argv[i]);
+ } else
+ if ( (strcmp(argv[i], "-b") == 0) && argv[i+1] ) {
+ ++i;
+ audio_buffers = atoi(argv[i]);
+ } else
+ if ( (strcmp(argv[i], "-v") == 0) && argv[i+1] ) {
+ ++i;
+ audio_volume = atoi(argv[i]);
+ } else
+ if ( strcmp(argv[i], "-l") == 0 ) {
+ looping = -1;
+ } else
+ if ( strcmp(argv[i], "-i") == 0 ) {
+ interactive = 1;
+ } else
+ if ( strcmp(argv[i], "-8") == 0 ) {
+ audio_format = AUDIO_U8;
+ } else
+ if ( strcmp(argv[i], "-rwops") == 0 ) {
+ rwops = 1;
+ } else {
+ Usage(argv[0]);
+ return(1);
+ }
+ }
+ if ( ! argv[i] ) {
+ Usage(argv[0]);
+ return(1);
+ }
+
+ /* Initialize the SDL library */
+ if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
+ fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
+ return(255);
+ }
+
+#ifdef HAVE_SIGNAL_H
+ signal(SIGINT, IntHandler);
+ signal(SIGTERM, CleanUp);
+#endif
+
+ /* Open the audio device */
+ if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) < 0) {
+ fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
+ return(2);
+ } else {
+ Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
+ printf("Opened audio at %d Hz %d bit %s (%s), %d bytes audio buffer\n", audio_rate,
+ (audio_format&0xFF),
+ (audio_channels > 2) ? "surround" : (audio_channels > 1) ? "stereo" : "mono",
+ (audio_format&0x1000) ? "BE" : "LE",
+ audio_buffers );
+ }
+ audio_open = 1;
+
+ /* Set the music volume */
+ Mix_VolumeMusic(audio_volume);
+
+ /* Set the external music player, if any */
+ Mix_SetMusicCMD(SDL_getenv("MUSIC_CMD"));
+
+ while (argv[i]) {
+ next_track = 0;
+
+ /* Load the requested music file */
+ if ( rwops ) {
+ rwfp = SDL_RWFromFile(argv[i], "rb");
+ music = Mix_LoadMUS_RW(rwfp);
+ } else {
+ music = Mix_LoadMUS(argv[i]);
+ }
+ if ( music == NULL ) {
+ fprintf(stderr, "Couldn't load %s: %s\n",
+ argv[i], SDL_GetError());
+ CleanUp(2);
+ }
+
+ /* Play and then exit */
+ printf("Playing %s\n", argv[i]);
+ Mix_FadeInMusic(music,looping,2000);
+ while ( !next_track && (Mix_PlayingMusic() || Mix_PausedMusic()) ) {
+ if(interactive)
+ Menu();
+ else
+ SDL_Delay(100);
+ }
+ Mix_FreeMusic(music);
+ if ( rwops ) {
+ SDL_RWclose(rwfp);
+ }
+ music = NULL;
+
+ /* If the user presses Ctrl-C more than once, exit. */
+ SDL_Delay(500);
+ if ( next_track > 1 ) break;
+
+ i++;
+ }
+ CleanUp(0);
+
+ /* Not reached, but fixes compiler warnings */
+ return 0;
+}
diff --git a/apps/plugins/sdl/SDL_mixer/playwave.c b/apps/plugins/sdl/SDL_mixer/playwave.c
new file mode 100644
index 0000000000..e53f1a93d5
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/playwave.c
@@ -0,0 +1,497 @@
+/*
+ PLAYWAVE: A test application for the SDL mixer library.
+ Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* $Id$ */
+
+#ifdef unix
+#include <unistd.h>
+#endif
+
+#include "SDL.h"
+#include "SDL_mixer.h"
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+
+/*
+ * rcg06132001 various mixer tests. Define the ones you want.
+ */
+/*#define TEST_MIX_DECODERS*/
+/*#define TEST_MIX_VERSIONS*/
+/*#define TEST_MIX_CHANNELFINISHED*/
+/*#define TEST_MIX_PANNING*/
+/*#define TEST_MIX_DISTANCE*/
+/*#define TEST_MIX_POSITION*/
+
+
+#if (defined TEST_MIX_POSITION)
+
+#if (defined TEST_MIX_PANNING)
+#error TEST_MIX_POSITION interferes with TEST_MIX_PANNING.
+#endif
+
+#if (defined TEST_MIX_DISTANCE)
+#error TEST_MIX_POSITION interferes with TEST_MIX_DISTANCE.
+#endif
+
+#endif
+
+
+/* rcg06192001 for debugging purposes. */
+static void output_test_warnings(void)
+{
+#if (defined TEST_MIX_CHANNELFINISHED)
+ fprintf(stderr, "Warning: TEST_MIX_CHANNELFINISHED is enabled in this binary...\n");
+#endif
+#if (defined TEST_MIX_PANNING)
+ fprintf(stderr, "Warning: TEST_MIX_PANNING is enabled in this binary...\n");
+#endif
+#if (defined TEST_MIX_VERSIONS)
+ fprintf(stderr, "Warning: TEST_MIX_VERSIONS is enabled in this binary...\n");
+#endif
+#if (defined TEST_MIX_DISTANCE)
+ fprintf(stderr, "Warning: TEST_MIX_DISTANCE is enabled in this binary...\n");
+#endif
+#if (defined TEST_MIX_POSITION)
+ fprintf(stderr, "Warning: TEST_MIX_POSITION is enabled in this binary...\n");
+#endif
+}
+
+
+static int audio_open = 0;
+static Mix_Chunk *wave = NULL;
+
+/* rcg06042009 Report available decoders. */
+#if (defined TEST_MIX_DECODERS)
+static void report_decoders(void)
+{
+ int i, total;
+
+ printf("Supported decoders...\n");
+ total = Mix_GetNumChunkDecoders();
+ for (i = 0; i < total; i++) {
+ fprintf(stderr, " - chunk decoder: %s\n", Mix_GetChunkDecoder(i));
+ }
+
+ total = Mix_GetNumMusicDecoders();
+ for (i = 0; i < total; i++) {
+ fprintf(stderr, " - music decoder: %s\n", Mix_GetMusicDecoder(i));
+ }
+}
+#endif
+
+/* rcg06192001 Check new Mixer version API. */
+#if (defined TEST_MIX_VERSIONS)
+static void output_versions(const char *libname, const SDL_version *compiled,
+ const SDL_version *linked)
+{
+ fprintf(stderr,
+ "This program was compiled against %s %d.%d.%d,\n"
+ " and is dynamically linked to %d.%d.%d.\n", libname,
+ compiled->major, compiled->minor, compiled->patch,
+ linked->major, linked->minor, linked->patch);
+}
+
+static void test_versions(void)
+{
+ SDL_version compiled;
+ const SDL_version *linked;
+
+ SDL_VERSION(&compiled);
+ linked = SDL_Linked_Version();
+ output_versions("SDL", &compiled, linked);
+
+ SDL_MIXER_VERSION(&compiled);
+ linked = Mix_Linked_Version();
+ output_versions("SDL_mixer", &compiled, linked);
+}
+#endif
+
+
+#ifdef TEST_MIX_CHANNELFINISHED /* rcg06072001 */
+static volatile int channel_is_done = 0;
+static void channel_complete_callback(int chan)
+{
+ Mix_Chunk *done_chunk = Mix_GetChunk(chan);
+ fprintf(stderr, "We were just alerted that Mixer channel #%d is done.\n", chan);
+ fprintf(stderr, "Channel's chunk pointer is (%p).\n", done_chunk);
+ fprintf(stderr, " Which %s correct.\n", (wave == done_chunk) ? "is" : "is NOT");
+ channel_is_done = 1;
+}
+#endif
+
+
+/* rcg06192001 abstract this out for testing purposes. */
+static int still_playing(void)
+{
+#ifdef TEST_MIX_CHANNELFINISHED
+ return(!channel_is_done);
+#else
+ return(Mix_Playing(0));
+#endif
+}
+
+
+#if (defined TEST_MIX_PANNING)
+static void do_panning_update(void)
+{
+ static Uint8 leftvol = 128;
+ static Uint8 rightvol = 128;
+ static Uint8 leftincr = -1;
+ static Uint8 rightincr = 1;
+ static int panningok = 1;
+ static Uint32 next_panning_update = 0;
+
+ if ((panningok) && (SDL_GetTicks() >= next_panning_update)) {
+ panningok = Mix_SetPanning(0, leftvol, rightvol);
+ if (!panningok) {
+ fprintf(stderr, "Mix_SetPanning(0, %d, %d) failed!\n",
+ (int) leftvol, (int) rightvol);
+ fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
+ }
+
+ if ((leftvol == 255) || (leftvol == 0)) {
+ if (leftvol == 255)
+ printf("All the way in the left speaker.\n");
+ leftincr *= -1;
+ }
+
+ if ((rightvol == 255) || (rightvol == 0)) {
+ if (rightvol == 255)
+ printf("All the way in the right speaker.\n");
+ rightincr *= -1;
+ }
+
+ leftvol += leftincr;
+ rightvol += rightincr;
+ next_panning_update = SDL_GetTicks() + 10;
+ }
+}
+#endif
+
+
+#if (defined TEST_MIX_DISTANCE)
+static void do_distance_update(void)
+{
+ static Uint8 distance = 1;
+ static Uint8 distincr = 1;
+ static int distanceok = 1;
+ static Uint32 next_distance_update = 0;
+
+ if ((distanceok) && (SDL_GetTicks() >= next_distance_update)) {
+ distanceok = Mix_SetDistance(0, distance);
+ if (!distanceok) {
+ fprintf(stderr, "Mix_SetDistance(0, %d) failed!\n", (int) distance);
+ fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
+ }
+
+ if (distance == 0) {
+ printf("Distance at nearest point.\n");
+ distincr *= -1;
+ }
+ else if (distance == 255) {
+ printf("Distance at furthest point.\n");
+ distincr *= -1;
+ }
+
+ distance += distincr;
+ next_distance_update = SDL_GetTicks() + 15;
+ }
+}
+#endif
+
+
+#if (defined TEST_MIX_POSITION)
+static void do_position_update(void)
+{
+ static Sint16 distance = 1;
+ static Sint8 distincr = 1;
+ static Uint16 angle = 0;
+ static Sint8 angleincr = 1;
+ static int positionok = 1;
+ static Uint32 next_position_update = 0;
+
+ if ((positionok) && (SDL_GetTicks() >= next_position_update)) {
+ positionok = Mix_SetPosition(0, angle, distance);
+ if (!positionok) {
+ fprintf(stderr, "Mix_SetPosition(0, %d, %d) failed!\n",
+ (int) angle, (int) distance);
+ fprintf(stderr, "Reason: [%s].\n", Mix_GetError());
+ }
+
+ if (angle == 0) {
+ printf("Due north; now rotating clockwise...\n");
+ angleincr = 1;
+ }
+
+ else if (angle == 360) {
+ printf("Due north; now rotating counter-clockwise...\n");
+ angleincr = -1;
+ }
+
+ distance += distincr;
+
+ if (distance < 0) {
+ distance = 0;
+ distincr = 3;
+ printf("Distance is very, very near. Stepping away by threes...\n");
+ } else if (distance > 255) {
+ distance = 255;
+ distincr = -3;
+ printf("Distance is very, very far. Stepping towards by threes...\n");
+ }
+
+ angle += angleincr;
+ next_position_update = SDL_GetTicks() + 30;
+ }
+}
+#endif
+
+
+static void CleanUp(int exitcode)
+{
+ if ( wave ) {
+ Mix_FreeChunk(wave);
+ wave = NULL;
+ }
+ if ( audio_open ) {
+ Mix_CloseAudio();
+ audio_open = 0;
+ }
+ SDL_Quit();
+
+ exit(exitcode);
+}
+
+
+static void Usage(char *argv0)
+{
+ fprintf(stderr, "Usage: %s [-8] [-r rate] [-c channels] [-f] [-F] [-l] [-m] <wavefile>\n", argv0);
+}
+
+
+/*
+ * rcg06182001 This is sick, but cool.
+ *
+ * Actually, it's meant to be an example of how to manipulate a voice
+ * without having to use the mixer effects API. This is more processing
+ * up front, but no extra during the mixing process. Also, in a case like
+ * this, when you need to touch the whole sample at once, it's the only
+ * option you've got. And, with the effects API, you are altering a copy of
+ * the original sample for each playback, and thus, your changes aren't
+ * permanent; here, you've got a reversed sample, and that's that until
+ * you either reverse it again, or reload it.
+ */
+static void flip_sample(Mix_Chunk *wave)
+{
+ Uint16 format;
+ int channels, i, incr;
+ Uint8 *start = wave->abuf;
+ Uint8 *end = wave->abuf + wave->alen;
+
+ Mix_QuerySpec(NULL, &format, &channels);
+ incr = (format & 0xFF) * channels;
+
+ end -= incr;
+
+ switch (incr) {
+ case 8:
+ for (i = wave->alen / 2; i >= 0; i -= 1) {
+ Uint8 tmp = *start;
+ *start = *end;
+ *end = tmp;
+ start++;
+ end--;
+ }
+ break;
+
+ case 16:
+ for (i = wave->alen / 2; i >= 0; i -= 2) {
+ Uint16 tmp = *start;
+ *((Uint16 *) start) = *((Uint16 *) end);
+ *((Uint16 *) end) = tmp;
+ start += 2;
+ end -= 2;
+ }
+ break;
+
+ case 32:
+ for (i = wave->alen / 2; i >= 0; i -= 4) {
+ Uint32 tmp = *start;
+ *((Uint32 *) start) = *((Uint32 *) end);
+ *((Uint32 *) end) = tmp;
+ start += 4;
+ end -= 4;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unhandled format in sample flipping.\n");
+ return;
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ int audio_rate;
+ Uint16 audio_format;
+ int audio_channels;
+ int loops = 0;
+ int i;
+ int reverse_stereo = 0;
+ int reverse_sample = 0;
+
+#ifdef HAVE_SETBUF
+ setbuf(stdout, NULL); /* rcg06132001 for debugging purposes. */
+ setbuf(stderr, NULL); /* rcg06192001 for debugging purposes, too. */
+#endif
+ output_test_warnings();
+
+ /* Initialize variables */
+ audio_rate = MIX_DEFAULT_FREQUENCY;
+ audio_format = MIX_DEFAULT_FORMAT;
+ audio_channels = 2;
+
+ /* Check command line usage */
+ for ( i=1; argv[i] && (*argv[i] == '-'); ++i ) {
+ if ( (strcmp(argv[i], "-r") == 0) && argv[i+1] ) {
+ ++i;
+ audio_rate = atoi(argv[i]);
+ } else
+ if ( strcmp(argv[i], "-m") == 0 ) {
+ audio_channels = 1;
+ } else
+ if ( (strcmp(argv[i], "-c") == 0) && argv[i+1] ) {
+ ++i;
+ audio_channels = atoi(argv[i]);
+ } else
+ if ( strcmp(argv[i], "-l") == 0 ) {
+ loops = -1;
+ } else
+ if ( strcmp(argv[i], "-8") == 0 ) {
+ audio_format = AUDIO_U8;
+ } else
+ if ( strcmp(argv[i], "-f") == 0 ) { /* rcg06122001 flip stereo */
+ reverse_stereo = 1;
+ } else
+ if ( strcmp(argv[i], "-F") == 0 ) { /* rcg06172001 flip sample */
+ reverse_sample = 1;
+ } else {
+ Usage(argv[0]);
+ return(1);
+ }
+ }
+ if ( ! argv[i] ) {
+ Usage(argv[0]);
+ return(1);
+ }
+
+ /* Initialize the SDL library */
+ if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
+ fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
+ return(255);
+ }
+#ifdef HAVE_SIGNAL_H
+ signal(SIGINT, CleanUp);
+ signal(SIGTERM, CleanUp);
+#endif
+
+ /* Open the audio device */
+ if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
+ fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
+ CleanUp(2);
+ } else {
+ Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
+ printf("Opened audio at %d Hz %d bit %s", audio_rate,
+ (audio_format&0xFF),
+ (audio_channels > 2) ? "surround" :
+ (audio_channels > 1) ? "stereo" : "mono");
+ if ( loops ) {
+ printf(" (looping)\n");
+ } else {
+ putchar('\n');
+ }
+ }
+ audio_open = 1;
+
+#if (defined TEST_MIX_VERSIONS)
+ test_versions();
+#endif
+
+#if (defined TEST_MIX_DECODERS)
+ report_decoders();
+#endif
+
+ /* Load the requested wave file */
+ wave = Mix_LoadWAV(argv[i]);
+ if ( wave == NULL ) {
+ fprintf(stderr, "Couldn't load %s: %s\n",
+ argv[i], SDL_GetError());
+ CleanUp(2);
+ }
+
+ if (reverse_sample) {
+ flip_sample(wave);
+ }
+
+#ifdef TEST_MIX_CHANNELFINISHED /* rcg06072001 */
+ Mix_ChannelFinished(channel_complete_callback);
+#endif
+
+ if ( (!Mix_SetReverseStereo(MIX_CHANNEL_POST, reverse_stereo)) &&
+ (reverse_stereo) )
+ {
+ printf("Failed to set up reverse stereo effect!\n");
+ printf("Reason: [%s].\n", Mix_GetError());
+ }
+
+ /* Play and then exit */
+ Mix_PlayChannel(0, wave, loops);
+
+ while (still_playing()) {
+
+#if (defined TEST_MIX_PANNING) /* rcg06132001 */
+ do_panning_update();
+#endif
+
+#if (defined TEST_MIX_DISTANCE) /* rcg06192001 */
+ do_distance_update();
+#endif
+
+#if (defined TEST_MIX_POSITION) /* rcg06202001 */
+ do_position_update();
+#endif
+
+ SDL_Delay(1);
+
+ } /* while still_playing() loop... */
+
+ CleanUp(0);
+
+ /* Not reached, but fixes compiler warnings */
+ return 0;
+}
+
+/* end of playwave.c ... */
+
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/COPYING b/apps/plugins/sdl/SDL_mixer/timidity/COPYING
new file mode 100644
index 0000000000..cdbb291069
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/COPYING
@@ -0,0 +1,127 @@
+ The "Artistic License"
+
+ Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes
+ of the Copyright Holder as specified below.
+
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ "You" is you, if you're thinking about copying or distributing
+ this Package.
+
+ "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people involved,
+ and so on. (You will not be required to justify it to the
+ Copyright Holder, but only to the computing community at large
+ as a market that must bear the fee.)
+
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder. A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or
+ an equivalent medium, or placing the modifications on a major archive
+ site such as uunet.uu.net, or by allowing the Copyright Holder to include
+ your modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict
+ with standard executables, which must also be provided, and provide
+ a separate manual page for each non-standard executable that clearly
+ documents how it differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where
+ to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of
+ the Package with your modifications.
+
+ c) give non-standard executables non-standard names, and clearly
+ document the differences in manual pages (or equivalent), together
+ with instructions on where to get the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this
+Package. You may not charge a fee for this Package itself. However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own. You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whoever generated
+them, and may be sold commercially, and may be aggregated with this
+Package. If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. C subroutines (or comparably compiled subroutines in other
+languages) supplied by you and linked into this Package in order to
+emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution. Such use shall not be
+construed as a distribution of this Package.
+
+9. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/FAQ b/apps/plugins/sdl/SDL_mixer/timidity/FAQ
new file mode 100644
index 0000000000..f1f8e237b4
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/FAQ
@@ -0,0 +1,112 @@
+---------------------------*-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 and PRECALC_LOOPS enabled
+ in config.h
+
+ - If you don't have hardware to compute sines, recompile with
+ LOOKUP_SINE enabled in config.h
+
+ - Recompile with LOOKUP_HACK enabled in config.h.
+
+ - Recompile with LINEAR_INTERPOLATION disabled in config.h.
+
+ - Recompile with DANGEROUS_RENICE enabled in config.h, and make
+ TiMidity setuid root. This will help only if you frequently play
+ music while other processes are running.
+
+ - Recompile with an Intel-optimized gcc for a 5-15%
+ performance increase.
+
+--------------------------------------------------------------------------
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/README b/apps/plugins/sdl/SDL_mixer/timidity/README
new file mode 100644
index 0000000000..e0882f3d03
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/README
@@ -0,0 +1,57 @@
+[This version of timidity has been stripped for simplicity in porting to SDL]
+---------------------------------*-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
+
+* TiMidity requires sampled instruments (patches) to play MIDI files. You
+ should get the file "timidity-lib-0.1.tar.gz" and unpack it in the same
+ directory where you unpacked the source code archive. You'll want more
+ patches later -- read the file "FAQ" for pointers.
+
+* Timidity is no longer supported, but can be found by searching the web.
+
+
+ Tuukka Toivonen <toivonen@clinet.fi>
+
+[(*) Any Registered Trademarks used anywhere in the documentation or
+source code for TiMidity are acknowledged as belonging to their
+respective owners.]
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/common.c b/apps/plugins/sdl/SDL_mixer/timidity/common.c
new file mode 100644
index 0000000000..bc284e6ccf
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/common.c
@@ -0,0 +1,238 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include "config.h"
+#include "common.h"
+#include "output.h"
+#include "ctrlmode.h"
+
+/* I guess "rb" should be right for any libc */
+#define OPEN_MODE "rb"
+
+char current_filename[PATH_MAX];
+
+static PathList *pathlist=NULL;
+
+/* Try to open a file for reading. If the filename ends in one of the
+ defined compressor extensions, pipe the file through the decompressor */
+static FILE *try_to_open(const char *name, int decompress, int noise_mode)
+{
+ FILE *fp;
+
+ fp=fopen(name, OPEN_MODE); /* First just check that the file exists */
+
+ if (!fp)
+ return 0;
+
+#ifdef DECOMPRESSOR_LIST
+ if (decompress)
+ {
+ int l,el;
+ static char *decompressor_list[] = DECOMPRESSOR_LIST, **dec;
+ const char *cp;
+ char tmp[PATH_MAX], tmp2[PATH_MAX], *cp2;
+ /* Check if it's a compressed file */
+ l=strlen(name);
+ for (dec=decompressor_list; *dec; dec+=2)
+ {
+ el=strlen(*dec);
+ if ((el>=l) || (strcmp(name+l-el, *dec)))
+ continue;
+
+ /* Yes. Close the file, open a pipe instead. */
+ fclose(fp);
+
+ /* Quote some special characters in the file name */
+ cp=name;
+ cp2=tmp2;
+ while (*cp)
+ {
+ switch(*cp)
+ {
+ case '\'':
+ case '\\':
+ case ' ':
+ case '`':
+ case '!':
+ case '"':
+ case '&':
+ case ';':
+ *cp2++='\\';
+ }
+ *cp2++=*cp++;
+ }
+ *cp2=0;
+
+ sprintf(tmp, *(dec+1), tmp2);
+ fp=popen(tmp, "r");
+ break;
+ }
+ }
+#endif
+
+ return fp;
+}
+
+/* This is meant to find and open files for reading, possibly piping
+ them through a decompressor. */
+FILE *open_file(const char *name, int decompress, int noise_mode)
+{
+ FILE *fp;
+ PathList *plp;
+ int l;
+
+ if (!name || !(*name))
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Attempted to open nameless file.");
+ return 0;
+ }
+
+ if (pathlist==NULL) {
+ /* Generate path list */
+#ifdef DEFAULT_PATH
+ add_to_pathlist(DEFAULT_PATH);
+#endif
+#ifdef DEFAULT_PATH1
+ add_to_pathlist(DEFAULT_PATH1);
+#endif
+#ifdef DEFAULT_PATH2
+ add_to_pathlist(DEFAULT_PATH2);
+#endif
+#ifdef DEFAULT_PATH3
+ add_to_pathlist(DEFAULT_PATH3);
+#endif
+ }
+
+ /* First try the given name */
+
+ strncpy(current_filename, name, PATH_MAX - 1);
+ current_filename[PATH_MAX - 1]='\0';
+
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename);
+ if ((fp=try_to_open(current_filename, decompress, noise_mode)))
+ return fp;
+
+#ifdef ENOENT
+ if (noise_mode && (errno != ENOENT))
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
+ current_filename, strerror(errno));
+ return 0;
+ }
+#endif
+
+ plp=pathlist;
+ if (name[0] != PATH_SEP)
+ 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)
+ strcat(current_filename, PATH_STRING);
+ }
+ strcat(current_filename, name);
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename);
+ if ((fp=try_to_open(current_filename, decompress, noise_mode)))
+ return fp;
+#ifdef ENOENT
+ if (noise_mode && (errno != ENOENT))
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
+ current_filename, strerror(errno));
+ return 0;
+ }
+#endif
+ plp=plp->next;
+ }
+
+ /* Nothing could be opened. */
+
+ *current_filename=0;
+
+ if (noise_mode>=2)
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", name, strerror(errno));
+
+ return 0;
+}
+
+/* This closes files opened with open_file */
+void close_file(FILE *fp)
+{
+#ifdef DECOMPRESSOR_LIST
+ if (pclose(fp)) /* Any better ideas? */
+#endif
+ fclose(fp);
+
+ strncpy(current_filename, "MIDI file", PATH_MAX - 1);
+}
+
+/* This is meant for skipping a few bytes in a file or fifo. */
+void skip(FILE *fp, size_t len)
+{
+ size_t c;
+ char tmp[PATH_MAX];
+ while (len>0)
+ {
+ c=len;
+ if (c>PATH_MAX) c=PATH_MAX;
+ len-=c;
+ if (c!=fread(tmp, 1, c, fp))
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: skip: %s",
+ current_filename, strerror(errno));
+ }
+}
+
+/* This'll allocate memory or die. */
+void *safe_malloc(size_t count)
+{
+ void *p;
+ if (count > (1<<21))
+ {
+ ctl->cmsg(CMSG_FATAL, VERB_NORMAL,
+ "Strange, I feel like allocating %d bytes. This must be a bug.",
+ count);
+ }
+ else if ((p=malloc(count)))
+ return p;
+ else
+ ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Sorry. Couldn't malloc %d bytes.", count);
+
+ ctl->close();
+ exit(10);
+ return(NULL);
+}
+
+/* This adds a directory to the path list */
+void add_to_pathlist(const char *s)
+{
+ PathList *plp=safe_malloc(sizeof(PathList));
+ strcpy((plp->path=safe_malloc(strlen(s)+1)),s);
+ plp->next=pathlist;
+ pathlist=plp;
+}
+
+/* Free memory associated to path list */
+void free_pathlist(void)
+{
+ PathList *plp, *next_plp;
+
+ plp = pathlist;
+ while (plp) {
+ if (plp->path) {
+ free(plp->path);
+ plp->path=NULL;
+ }
+ next_plp = plp->next;
+ free(plp);
+ plp = next_plp;
+ }
+ pathlist = NULL;
+}
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/common.h b/apps/plugins/sdl/SDL_mixer/timidity/common.h
new file mode 100644
index 0000000000..8d9c0ec8bc
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/common.h
@@ -0,0 +1,39 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include <limits.h>
+
+#ifndef PATH_MAX /* GNU Hurd doesn't limit path size, thus no PATH_MAX... */
+#define PATH_MAX 1024 /* ...so we'll just impose an arbitrary limit. */
+#endif
+
+extern char *program_name, current_filename[];
+
+extern FILE *msgfp;
+
+extern int num_ochannels;
+
+#define MULTICHANNEL_OUT
+#define MAX_OUT_CHANNELS 6
+
+typedef struct {
+ char *path;
+ void *next;
+} PathList;
+
+/* Noise modes for open_file */
+#define OF_SILENT 0
+#define OF_NORMAL 1
+#define OF_VERBOSE 2
+
+extern FILE *open_file(const char *name, int decompress, int noise_mode);
+extern void add_to_pathlist(const char *s);
+extern void free_pathlist(void);
+extern void close_file(FILE *fp);
+extern void skip(FILE *fp, size_t len);
+extern void *safe_malloc(size_t count);
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/config.h b/apps/plugins/sdl/SDL_mixer/timidity/config.h
new file mode 100644
index 0000000000..46f1aa95fe
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/config.h
@@ -0,0 +1,229 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+/* This is for use with the SDL library */
+#ifndef __TIMIDITY_CONFIG_H__
+#define __TIMIDITY_CONFIG_H__
+#define SDL
+#include "SDL_config.h"
+#include "SDL_endian.h"
+
+#define TIMIDITY_ERROR_SIZE 1024
+
+/* 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)
+
+/* A somewhat arbitrary frequency range. The low end of this will
+ sound terrible as no lowpass filtering is performed on most
+ instruments before resampling. */
+#define MIN_OUTPUT_RATE 4000
+#define MAX_OUTPUT_RATE 65000
+
+/* In percent. */
+/* #define DEFAULT_AMPLIFICATION 70 */
+/* #define DEFAULT_AMPLIFICATION 50 */
+#define DEFAULT_AMPLIFICATION 30
+
+/* Default sampling rate, default polyphony, and maximum polyphony.
+ All but the last can be overridden from the command line. */
+#define DEFAULT_RATE 32000
+/* #define DEFAULT_VOICES 32 */
+/* #define MAX_VOICES 48 */
+#define DEFAULT_VOICES 256
+#define MAX_VOICES 256
+#define MAXCHAN 16
+/* #define MAXCHAN 64 */
+#define MAXNOTE 128
+
+/* 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
+
+/* Strongly recommended. This option increases CPU usage by half, but
+ without it sound quality is very poor. */
+#define LINEAR_INTERPOLATION
+
+/* This is an experimental kludge that needs to be done right, but if
+ you've got an 8-bit sound card, or cheap multimedia speakers hooked
+ to your 16-bit output device, you should definitely give it a try.
+
+ Defining LOOKUP_HACK causes table lookups to be used in mixing
+ instead of multiplication. We convert the sample data to 8 bits at
+ load time and volumes to logarithmic 7-bit values before looking up
+ the product, which degrades sound quality noticeably.
+
+ Defining LOOKUP_HACK should save ~20% of CPU on an Intel machine.
+ LOOKUP_INTERPOLATION might give another ~5% */
+/* #define LOOKUP_HACK
+ #define LOOKUP_INTERPOLATION */
+
+/* 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
+
+#define MAX_SAMPLE_SIZE (1 << (32-FRACTION_BITS))
+
+typedef double FLOAT_T;
+
+/* 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
+
+/* On some machines (especially PCs without math coprocessors),
+ looking up sine values in a table will be significantly faster than
+ computing them on the fly. Uncomment this to use lookups. */
+/* #define LOOKUP_SINE */
+
+/* Shawn McHorse's resampling optimizations. These may not in fact be
+ faster on your particular machine and compiler. You'll have to run
+ a benchmark to find out. */
+#define PRECALC_LOOPS
+
+/* If calling ldexp() is faster than a floating point multiplication
+ on your machine/compiler/libm, uncomment this. It doesn't make much
+ difference either way, but hey -- it was on the TODO list, so it
+ got done. */
+/* #define USE_LDEXP */
+
+/**************************************************************************/
+/* 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_BITS (32 - FRACTION_BITS)
+#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
+
+typedef unsigned int uint32;
+typedef int int32;
+typedef unsigned short uint16;
+typedef short int16;
+typedef unsigned char uint8;
+typedef char int8;
+
+/* Instrument files are little-endian, MIDI files big-endian, so we
+ need to do some conversions. */
+
+#define XCHG_SHORT(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+# define XCHG_LONG(x) ((((x)&0xFF)<<24) | \
+ (((x)&0xFF00)<<8) | \
+ (((x)&0xFF0000)>>8) | \
+ (((x)>>24)&0xFF))
+
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define LE_SHORT(x) x
+#define LE_LONG(x) x
+#define BE_SHORT(x) XCHG_SHORT(x)
+#define BE_LONG(x) XCHG_LONG(x)
+#else
+#define BE_SHORT(x) x
+#define BE_LONG(x) x
+#define LE_SHORT(x) XCHG_SHORT(x)
+#define LE_LONG(x) XCHG_LONG(x)
+#endif
+
+#define MAX_AMPLIFICATION 800
+
+/* You could specify a complete path, e.g. "/etc/timidity.cfg", and
+ then specify the library directory in the configuration file. */
+#define CONFIG_FILE "/.rockbox/timidity/timidity.cfg"
+#define CONFIG_FILE_ETC "/.rockbox/timidity/timidity.cfg"
+
+#if defined(__WIN32__) || defined(__OS2__)
+#define DEFAULT_PATH "C:\\TIMIDITY"
+#else
+#define DEFAULT_PATH "/.rockbox/patchset"
+#define DEFAULT_PATH1 "/.rockbox/duke3d"
+#define DEFAULT_PATH2 "/.rockbox/timidity"
+#define DEFAULT_PATH3 "/.rockbox/midi"
+#endif
+
+/* These affect general volume */
+#define GUARD_BITS 3
+#define AMP_BITS (15-GUARD_BITS)
+
+#ifdef LOOKUP_HACK
+ typedef int8 sample_t;
+ typedef uint8 final_volume_t;
+# define FINAL_VOLUME(v) (~_l2u[v])
+# define MIXUP_SHIFT 5
+# define MAX_AMP_VALUE 4095
+#else
+ typedef int16 sample_t;
+ typedef int32 final_volume_t;
+# define FINAL_VOLUME(v) (v)
+# define MAX_AMP_VALUE ((1<<(AMP_BITS+1))-1)
+#endif
+
+typedef int16 resample_t;
+
+#ifdef USE_LDEXP
+# define FSCALE(a,b) ldexp((a),(b))
+# define FSCALENEG(a,b) ldexp((a),-(b))
+#else
+# define FSCALE(a,b) (float)((a) * (double)(1<<(b)))
+# define FSCALENEG(a,b) (float)((a) * (1.0L / (double)(1<<(b))))
+#endif
+
+/* 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
+
+#define VIBRATO_SAMPLE_INCREMENTS 32
+
+#ifndef PI
+ #define PI 3.14159265358979323846
+#endif
+
+/* The path separator (D.M.) */
+#if defined(__WIN32__) || defined(__OS2__)
+# define PATH_SEP '\\'
+# define PATH_STRING "\\"
+#else
+# define PATH_SEP '/'
+# define PATH_STRING "/"
+#endif
+
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.c b/apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.c
new file mode 100644
index 0000000000..facaa0b4f9
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.c
@@ -0,0 +1,26 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include "config.h"
+#include "ctrlmode.h"
+
+#ifdef SDL
+ extern ControlMode sdl_control_mode;
+# ifndef DEFAULT_CONTROL_MODE
+# define DEFAULT_CONTROL_MODE &sdl_control_mode
+# endif
+#endif
+
+ControlMode *ctl_list[]={
+#ifdef SDL
+ &sdl_control_mode,
+#endif
+ 0
+};
+
+ControlMode *ctl=DEFAULT_CONTROL_MODE;
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.h b/apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.h
new file mode 100644
index 0000000000..5a116bc63c
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/ctrlmode.h
@@ -0,0 +1,74 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+/* Return values for ControlMode.read */
+
+#define RC_ERROR -1
+#define RC_NONE 0
+#define RC_QUIT 1
+#define RC_NEXT 2
+#define RC_PREVIOUS 3 /* Restart this song at beginning, or the previous
+ song if we're less than a second into this one. */
+#define RC_FORWARD 4
+#define RC_BACK 5
+#define RC_JUMP 6
+#define RC_TOGGLE_PAUSE 7 /* Pause/continue */
+#define RC_RESTART 8 /* Restart song at beginning */
+
+#define RC_PAUSE 9 /* Really pause playing */
+#define RC_CONTINUE 10 /* Continue if paused */
+#define RC_REALLY_PREVIOUS 11 /* Really go to the previous song */
+#define RC_CHANGE_VOLUME 12
+#define RC_LOAD_FILE 13 /* Load a new midifile */
+#define RC_TUNE_END 14 /* The tune is over, play it again sam? */
+
+#define CMSG_INFO 0
+#define CMSG_WARNING 1
+#define CMSG_ERROR 2
+#define CMSG_FATAL 3
+#define CMSG_TRACE 4
+#define CMSG_TIME 5
+#define CMSG_TOTAL 6
+#define CMSG_FILE 7
+#define CMSG_TEXT 8
+
+#define VERB_NORMAL 0
+#define VERB_VERBOSE 1
+#define VERB_NOISY 2
+#define VERB_DEBUG 3
+#define VERB_DEBUG_SILLY 4
+
+typedef struct {
+ char *id_name, id_character;
+ int verbosity, trace_playing, opened;
+
+ int (*open)(int using_stdin, int using_stdout);
+ void (*pass_playing_list)(int number_of_files, char *list_of_files[]);
+ void (*close)(void);
+ int (*read)(int32 *valp);
+ int (*cmsg)(int type, int verbosity_level, char *fmt, ...);
+
+ void (*refresh)(void);
+ void (*reset)(void);
+ void (*file_name)(char *name);
+ void (*total_time)(int tt);
+ void (*current_time)(int ct);
+
+ void (*note)(int v);
+ void (*master_volume)(int mv);
+ void (*program)(int channel, int val); /* val<0 means drum set -val */
+ void (*volume)(int channel, int val);
+ void (*expression)(int channel, int val);
+ void (*panning)(int channel, int val);
+ void (*sustain)(int channel, int val);
+ void (*pitch_bend)(int channel, int val);
+
+} ControlMode;
+
+extern ControlMode *ctl_list[], *ctl;
+extern char timidity_error[];
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/filter.c b/apps/plugins/sdl/SDL_mixer/timidity/filter.c
new file mode 100644
index 0000000000..e93cc6b23c
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/filter.c
@@ -0,0 +1,187 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+
+ filter.c: written by Vincent Pagel ( pagel@loria.fr )
+
+ implements fir antialiasing filter : should help when setting sample
+ rates as low as 8Khz.
+
+ April 95
+ - first draft
+
+ 22/5/95
+ - modify "filter" so that it simulate leading and trailing 0 in the buffer
+ */
+
+#include "config.h"
+#include "common.h"
+#include "ctrlmode.h"
+#include "instrum.h"
+#include "filter.h"
+
+/* bessel function */
+static float ino(float x)
+{
+ float y, de, e, sde;
+ int i;
+
+ y = x / 2;
+ e = 1.0;
+ de = 1.0;
+ i = 1;
+ do {
+ de = de * y / (float) i;
+ sde = de * de;
+ e += sde;
+ } while (!( (e * 1.0e-08 - sde > 0) || (i++ > 25) ));
+ return(e);
+}
+
+/* Kaiser Window (symetric) */
+static void kaiser(float *w,int n,float beta)
+{
+ float xind, xi;
+ int i;
+
+ xind = (float)((2*n - 1) * (2*n - 1));
+ for (i =0; i<n ; i++)
+ {
+ xi = (float)(i + 0.5);
+ w[i] = ino((float)(beta * sqrt((double)(1. - 4 * xi * xi / xind))))
+ / ino((float)beta);
+ }
+}
+
+/*
+ * fir coef in g, cuttoff frequency in fc
+ */
+static void designfir(float *g , float fc)
+{
+ int i;
+ float xi, omega, att, beta ;
+ float w[ORDER2];
+
+ for (i =0; i < ORDER2 ;i++)
+ {
+ xi = (float) (i + 0.5);
+ omega = (float)(PI * xi);
+ g[i] = (float)(sin( (double) omega * fc) / omega);
+ }
+
+ att = 40.; /* attenuation in db */
+ beta = (float) (exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886
+ * (att - 20.96));
+ kaiser( w, ORDER2, beta);
+
+ /* Matrix product */
+ for (i =0; i < ORDER2 ; i++)
+ g[i] = g[i] * w[i];
+}
+
+/*
+ * FIR filtering -> apply the filter given by coef[] to the data buffer
+ * Note that we simulate leading and trailing 0 at the border of the
+ * data buffer
+ */
+static void filter(sample_t *result,sample_t *data, int32 length,float coef[])
+{
+ int32 sample,i,sample_window;
+ int16 peak = 0;
+ float sum;
+
+ /* Simulate leading 0 at the begining of the buffer */
+ for (sample = 0; sample < ORDER2 ; sample++ )
+ {
+ sum = 0.0;
+ sample_window= sample - ORDER2;
+
+ for (i = 0; i < ORDER ;i++)
+ sum += (float)(coef[i] *
+ ((sample_window<0)? 0.0 : data[sample_window++])) ;
+
+ /* Saturation ??? */
+ if (sum> 32767.) { sum=32767.; peak++; }
+ if (sum< -32768.) { sum=-32768; peak++; }
+ result[sample] = (sample_t) sum;
+ }
+
+ /* The core of the buffer */
+ for (sample = ORDER2; sample < length - ORDER + ORDER2 ; sample++ )
+ {
+ sum = 0.0;
+ sample_window= sample - ORDER2;
+
+ for (i = 0; i < ORDER ;i++)
+ sum += data[sample_window++] * coef[i];
+
+ /* Saturation ??? */
+ if (sum> 32767.) { sum=32767.; peak++; }
+ if (sum< -32768.) { sum=-32768; peak++; }
+ result[sample] = (sample_t) sum;
+ }
+
+ /* Simulate 0 at the end of the buffer */
+ for (sample = length - ORDER + ORDER2; sample < length ; sample++ )
+ {
+ sum = 0.0;
+ sample_window= sample - ORDER2;
+
+ for (i = 0; i < ORDER ;i++)
+ sum += (float)(coef[i] *
+ ((sample_window>=length)? 0.0 : data[sample_window++])) ;
+
+ /* Saturation ??? */
+ if (sum> 32767.) { sum=32767.; peak++; }
+ if (sum< -32768.) { sum=-32768; peak++; }
+ result[sample] = (sample_t) sum;
+ }
+
+ if (peak)
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Saturation %2.3f %%.", 100.0*peak/ (float) length);
+}
+
+/***********************************************************************/
+/* Prevent aliasing by filtering any freq above the output_rate */
+/* */
+/* I don't worry about looping point -> they will remain soft if they */
+/* were already */
+/***********************************************************************/
+void antialiasing(Sample *sp, int32 output_rate )
+{
+ sample_t *temp;
+ int i;
+ float fir_symetric[ORDER];
+ float fir_coef[ORDER2];
+ float freq_cut; /* cutoff frequency [0..1.0] FREQ_CUT/SAMP_FREQ*/
+
+
+ ctl->cmsg(CMSG_INFO, VERB_NOISY, "Antialiasing: Fsample=%iKHz",
+ sp->sample_rate);
+
+ /* No oversampling */
+ if (output_rate>=sp->sample_rate)
+ return;
+
+ freq_cut= (float) output_rate / (float) sp->sample_rate;
+ ctl->cmsg(CMSG_INFO, VERB_NOISY, "Antialiasing: cutoff=%f%%",
+ freq_cut*100.);
+
+ designfir(fir_coef,freq_cut);
+
+ /* Make the filter symetric */
+ for (i = 0 ; i<ORDER2 ;i++)
+ fir_symetric[ORDER-1 - i] = fir_symetric[i] = fir_coef[ORDER2-1 - i];
+
+ /* We apply the filter we have designed on a copy of the patch */
+ temp = safe_malloc(sp->data_length);
+ memcpy(temp,sp->data,sp->data_length);
+
+ filter(sp->data,temp,sp->data_length/sizeof(sample_t),fir_symetric);
+
+ free(temp);
+}
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/filter.h b/apps/plugins/sdl/SDL_mixer/timidity/filter.h
new file mode 100644
index 0000000000..79133377dd
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/filter.h
@@ -0,0 +1,23 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+
+ filter.h : written by Vincent Pagel ( pagel@loria.fr )
+
+ implements fir antialiasing filter : should help when setting sample
+ rates as low as 8Khz.
+
+ */
+
+/* Order of the FIR filter = 20 should be enough ! */
+#define ORDER 20
+#define ORDER2 ORDER/2
+
+#ifndef PI
+#define PI 3.14159265
+#endif
+
+extern void antialiasing(Sample *sp, int32 output_rate);
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/instrum.c b/apps/plugins/sdl/SDL_mixer/timidity/instrum.c
new file mode 100644
index 0000000000..c480ec18a1
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/instrum.c
@@ -0,0 +1,1018 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include "config.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "output.h"
+#include "ctrlmode.h"
+#include "resample.h"
+#include "tables.h"
+#include "filter.h"
+
+/* Some functions get aggravated if not even the standard banks are
+ available. */
+static ToneBank standard_tonebank, standard_drumset;
+ToneBank
+ *tonebank[MAXBANK]={&standard_tonebank},
+ *drumset[MAXBANK]={&standard_drumset};
+
+/* This is a special instrument, used for all melodic programs */
+InstrumentLayer *default_instrument=0;
+
+/* This is only used for tracks that don't specify a program */
+int default_program=DEFAULT_PROGRAM;
+
+int antialiasing_allowed=0;
+#ifdef FAST_DECAY
+int fast_decay=1;
+#else
+int fast_decay=0;
+#endif
+
+
+int current_tune_number = 0;
+int last_tune_purged = 0;
+int current_patch_memory = 0;
+int max_patch_memory = 60000000;
+
+static void purge_as_required(void);
+
+static void free_instrument(Instrument *ip)
+{
+ Sample *sp;
+ int i;
+ if (!ip) return;
+
+ if (!ip->contents)
+ for (i=0; i<ip->samples; i++)
+ {
+ sp=&(ip->sample[i]);
+ if (sp->data) free(sp->data);
+ }
+ free(ip->sample);
+
+ if (!ip->contents)
+ for (i=0; i<ip->right_samples; i++)
+ {
+ sp=&(ip->right_sample[i]);
+ if (sp->data) free(sp->data);
+ }
+ if (ip->right_sample)
+ free(ip->right_sample);
+ free(ip);
+}
+
+
+static void free_layer(InstrumentLayer *lp)
+{
+ InstrumentLayer *next;
+
+ current_patch_memory -= lp->size;
+
+ for (; lp; lp = next)
+ {
+ next = lp->next;
+ free_instrument(lp->instrument);
+ free(lp);
+ }
+}
+
+static void free_bank(int dr, int b)
+{
+ int i;
+ ToneBank *bank=((dr) ? drumset[b] : tonebank[b]);
+ for (i=0; i<MAXPROG; i++)
+ {
+ if (bank->tone[i].layer)
+ {
+ /* Not that this could ever happen, of course */
+ if (bank->tone[i].layer != MAGIC_LOAD_INSTRUMENT)
+ {
+ free_layer(bank->tone[i].layer);
+ bank->tone[i].layer=NULL;
+ bank->tone[i].last_used=-1;
+ }
+ }
+ if (bank->tone[i].name)
+ {
+ free(bank->tone[i].name);
+ bank->tone[i].name = NULL;
+ }
+ }
+}
+
+
+static void free_old_bank(int dr, int b, int how_old)
+{
+ int i;
+ ToneBank *bank=((dr) ? drumset[b] : tonebank[b]);
+ for (i=0; i<MAXPROG; i++)
+ if (bank->tone[i].layer && bank->tone[i].last_used < how_old)
+ {
+ if (bank->tone[i].layer != MAGIC_LOAD_INSTRUMENT)
+ {
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ "Unloading %s %s[%d,%d] - last used %d.",
+ (dr)? "drum" : "inst", bank->tone[i].name,
+ i, b, bank->tone[i].last_used);
+ free_layer(bank->tone[i].layer);
+ bank->tone[i].layer=NULL;
+ bank->tone[i].last_used=-1;
+ }
+ }
+}
+
+
+int32 convert_envelope_rate_attack(uint8 rate, uint8 fastness)
+{
+ int32 r;
+
+ r=3-((rate>>6) & 0x3);
+ r*=3;
+ r = (int32)(rate & 0x3f) << r; /* 6.9 fixed point */
+
+ /* 15.15 fixed point. */
+ return (((r * 44100) / play_mode->rate) * control_ratio)
+ << 10;
+}
+
+int32 convert_envelope_rate(uint8 rate)
+{
+ int32 r;
+
+ r=3-((rate>>6) & 0x3);
+ r*=3;
+ r = (int32)(rate & 0x3f) << r; /* 6.9 fixed point */
+
+ /* 15.15 fixed point. */
+ return (((r * 44100) / play_mode->rate) * control_ratio)
+ << ((fast_decay) ? 10 : 9);
+}
+
+int32 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);
+}
+
+int32 convert_tremolo_sweep(uint8 sweep)
+{
+ if (!sweep)
+ return 0;
+
+ return
+ ((control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
+ (play_mode->rate * sweep);
+}
+
+int32 convert_vibrato_sweep(uint8 sweep, int32 vib_control_ratio)
+{
+ if (!sweep)
+ return 0;
+
+ return
+ (int32) (FSCALE((double) (vib_control_ratio) * SWEEP_TUNING, SWEEP_SHIFT)
+ / (double)(play_mode->rate * sweep));
+
+ /* this was overflowing with seashore.pat
+
+ ((vib_control_ratio * SWEEP_TUNING) << SWEEP_SHIFT) /
+ (play_mode->rate * sweep); */
+}
+
+int32 convert_tremolo_rate(uint8 rate)
+{
+ return
+ ((SINE_CYCLE_LENGTH * control_ratio * rate) << RATE_SHIFT) /
+ (TREMOLO_RATE_TUNING * play_mode->rate);
+}
+
+int32 convert_vibrato_rate(uint8 rate)
+{
+ /* Return a suitable vibrato_control_ratio value */
+ return
+ (VIBRATO_RATE_TUNING * play_mode->rate) /
+ (rate * 2 * VIBRATO_SAMPLE_INCREMENTS);
+}
+
+static void reverse_data(int16 *sp, int32 ls, int32 le)
+{
+ int16 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 InstrumentLayer *load_instrument(const char *name, int font_type, int percussion,
+ int panning, int amp, int cfg_tuning, int note_to_use,
+ int strip_loop, int strip_envelope,
+ int strip_tail, int bank, int gm_num, int sf_ix)
+{
+ InstrumentLayer *lp, *lastlp, *headlp = 0;
+ Instrument *ip;
+ FILE *fp;
+ uint8 tmp[1024];
+ int i,j,noluck=0;
+#ifdef PATCH_EXT_LIST
+ static char *patch_ext[] = PATCH_EXT_LIST;
+#endif
+ int sf2flag = 0;
+ int right_samples = 0;
+ int stereo_channels = 1, stereo_layer;
+ int vlayer_list[19][4], vlayer, vlayer_count = 0;
+
+ if (!name) return 0;
+
+ /* Open patch file */
+ if ((fp=open_file(name, 1, OF_NORMAL)) == NULL)
+ {
+ noluck=1;
+#ifdef PATCH_EXT_LIST
+ /* Try with various extensions */
+ for (i=0; patch_ext[i]; i++)
+ {
+ if (strlen(name)+strlen(patch_ext[i])<PATH_MAX)
+ {
+ char path[PATH_MAX];
+ strcpy(path, name);
+ strcat(path, patch_ext[i]);
+ if ((fp=open_file(path, 1, OF_NORMAL)) != NULL)
+ {
+ noluck=0;
+ break;
+ }
+ }
+ }
+#endif
+ }
+
+ if (noluck)
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Instrument `%s' can't be found.", name);
+ fclose(fp);
+ return 0;
+ }
+
+ /*ctl->cmsg(CMSG_INFO, VERB_NOISY, "Loading instrument %s", current_filename);*/
+
+ /* Read some headers and do cursory sanity checks. There are loads
+ of magic offsets. This could be rewritten... */
+
+ if ((239 != fread(tmp, 1, 239, fp)) ||
+ (memcmp(tmp, "GF1PATCH110\0ID#000002", 22) &&
+ memcmp(tmp, "GF1PATCH100\0ID#000002", 22))) /* don't know what the
+ differences are */
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: not an instrument", name);
+ fclose(fp);
+ return 0;
+ }
+
+/* patch layout:
+ * bytes: info: starts at offset:
+ * 22 id (see above) 0
+ * 60 copyright 22
+ * 1 instruments 82
+ * 1 voices 83
+ * 1 channels 84
+ * 2 number of waveforms 85
+ * 2 master volume 87
+ * 4 datasize 89
+ * 36 reserved, but now: 93
+ * 7 "SF2EXT\0" id 93
+ * 1 right samples 100
+ * 28 reserved 101
+ * 2 instrument number 129
+ * 16 instrument name 131
+ * 4 instrument size 147
+ * 1 number of layers 151
+ * 40 reserved 152
+ * 1 layer duplicate 192
+ * 1 layer number 193
+ * 4 layer size 194
+ * 1 number of samples 198
+ * 40 reserved 199
+ * 239
+ * THEN, for each sample, see below
+ */
+
+ if (!memcmp(tmp + 93, "SF2EXT", 6))
+ {
+ sf2flag = 1;
+ vlayer_count = tmp[152];
+ }
+
+ if (tmp[82] != 1 && tmp[82] != 0) /* instruments. To some patch makers,
+ 0 means 1 */
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Can't handle patches with %d instruments", tmp[82]);
+ fclose(fp);
+ return 0;
+ }
+
+ if (tmp[151] != 1 && tmp[151] != 0) /* layers. What's a layer? */
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Can't handle instruments with %d layers", tmp[151]);
+ fclose(fp);
+ return 0;
+ }
+
+
+ if (sf2flag && vlayer_count > 0) {
+ for (i = 0; i < 9; i++)
+ for (j = 0; j < 4; j++)
+ vlayer_list[i][j] = tmp[153+i*4+j];
+ for (i = 9; i < 19; i++)
+ for (j = 0; j < 4; j++)
+ vlayer_list[i][j] = tmp[199+(i-9)*4+j];
+ }
+ else {
+ for (i = 0; i < 19; i++)
+ for (j = 0; j < 4; j++)
+ vlayer_list[i][j] = 0;
+ vlayer_list[0][0] = 0;
+ vlayer_list[0][1] = 127;
+ vlayer_list[0][2] = tmp[198];
+ vlayer_list[0][3] = 0;
+ vlayer_count = 1;
+ }
+
+ lastlp = 0;
+
+ for (vlayer = 0; vlayer < vlayer_count; vlayer++) {
+
+ lp=(InstrumentLayer *)safe_malloc(sizeof(InstrumentLayer));
+ lp->size = sizeof(InstrumentLayer);
+ lp->lo = vlayer_list[vlayer][0];
+ lp->hi = vlayer_list[vlayer][1];
+ ip=(Instrument *)safe_malloc(sizeof(Instrument));
+ lp->size += sizeof(Instrument);
+ lp->instrument = ip;
+ lp->next = 0;
+
+ if (lastlp) lastlp->next = lp;
+ else headlp = lp;
+
+ lastlp = lp;
+
+ if (sf2flag) ip->type = INST_SF2;
+ else ip->type = INST_GUS;
+ ip->samples = vlayer_list[vlayer][2];
+ ip->sample = (Sample *)safe_malloc(sizeof(Sample) * ip->samples);
+ lp->size += sizeof(Sample) * ip->samples;
+ ip->left_samples = ip->samples;
+ ip->left_sample = ip->sample;
+ right_samples = vlayer_list[vlayer][3];
+ ip->right_samples = right_samples;
+ if (right_samples)
+ {
+ ip->right_sample = (Sample *)safe_malloc(sizeof(Sample) * right_samples);
+ lp->size += sizeof(Sample) * right_samples;
+ stereo_channels = 2;
+ }
+ else ip->right_sample = 0;
+ ip->contents = 0;
+
+ ctl->cmsg(CMSG_INFO, VERB_NOISY, "%s%s[%d,%d] %s(%d-%d layer %d of %d)",
+ (percussion)? " ":"", name,
+ (percussion)? note_to_use : gm_num, bank,
+ (right_samples)? "(2) " : "",
+ lp->lo, lp->hi, vlayer+1, vlayer_count);
+
+ for (stereo_layer = 0; stereo_layer < stereo_channels; stereo_layer++)
+ {
+ int sample_count = 0;
+
+ if (stereo_layer == 0) sample_count = ip->left_samples;
+ else if (stereo_layer == 1) sample_count = ip->right_samples;
+
+ for (i=0; i < sample_count; i++)
+ {
+ uint8 fractions;
+ int32 tmplong;
+ uint16 tmpshort;
+ uint16 sample_volume = 0;
+ uint8 tmpchar;
+ Sample *sp = 0;
+ uint8 sf2delay = 0;
+
+#define READ_CHAR(thing) \
+ if (1 != fread(&tmpchar, 1, 1, fp)) { \
+ printf("error readc\n"); goto fail; } \
+ thing = tmpchar;
+#define READ_SHORT(thing) \
+ if (1 != fread(&tmpshort, 2, 1, fp)) { \
+ printf("error reads\n"); goto fail; } \
+ thing = LE_SHORT(tmpshort);
+#define READ_LONG(thing) \
+ if (1 != fread(&tmplong, 4, 1, fp)) { \
+ printf("error readl\n"); goto fail; } \
+ thing = LE_LONG(tmplong);
+
+/*
+ * 7 sample name
+ * 1 fractions
+ * 4 length
+ * 4 loop start
+ * 4 loop end
+ * 2 sample rate
+ * 4 low frequency
+ * 4 high frequency
+ * 2 finetune
+ * 1 panning
+ * 6 envelope rates |
+ * 6 envelope offsets | 18 bytes
+ * 3 tremolo sweep, rate, depth |
+ * 3 vibrato sweep, rate, depth |
+ * 1 sample mode
+ * 2 scale frequency
+ * 2 scale factor
+ * 2 sample volume (??)
+ * 34 reserved
+ * Now: 1 delay
+ * 33 reserved
+ */
+ skip(fp, 7); /* Skip the wave name */
+
+ if (1 != fread(&fractions, 1, 1, fp))
+ {
+ printf("error 1\n");
+ fail:
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Error reading sample %d", i);
+ if (stereo_layer == 1)
+ {
+ for (j=0; j<i; j++)
+ free(ip->right_sample[j].data);
+ free(ip->right_sample);
+ i = ip->left_samples;
+ }
+ for (j=0; j<i; j++)
+ free(ip->left_sample[j].data);
+ free(ip->left_sample);
+ free(ip);
+ free(lp);
+ fclose(fp);
+ return 0;
+ }
+
+ if (stereo_layer == 0) sp=&(ip->left_sample[i]);
+ else if (stereo_layer == 1) sp=&(ip->right_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);
+ skip(fp, 2); /* 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);
+
+ sp->resonance=0;
+ sp->cutoff_freq=0;
+ sp->reverberation=0;
+ sp->chorusdepth=0;
+ sp->exclusiveClass=0;
+ sp->keyToModEnvHold=0;
+ sp->keyToModEnvDecay=0;
+ sp->keyToVolEnvHold=0;
+ sp->keyToVolEnvDecay=0;
+
+ if (cfg_tuning)
+ {
+ double tune_factor = (double)(cfg_tuning)/1200.0;
+ tune_factor = pow(2.0, tune_factor);
+ sp->root_freq = (uint32)( tune_factor * (double)sp->root_freq );
+ }
+
+ /* envelope, tremolo, and vibrato */
+ if (18 != fread(tmp, 1, 18, fp)) { printf("error 2\n"); goto fail; }
+
+ if (!tmp[13] || !tmp[14])
+ {
+ sp->tremolo_sweep_increment=
+ sp->tremolo_phase_increment=sp->tremolo_depth=0;
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no tremolo");
+ }
+ else
+ {
+ sp->tremolo_sweep_increment=convert_tremolo_sweep(tmp[12]);
+ sp->tremolo_phase_increment=convert_tremolo_rate(tmp[13]);
+ sp->tremolo_depth=tmp[14];
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ " * tremolo: sweep %d, phase %d, depth %d",
+ 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;
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * no vibrato");
+ }
+ else
+ {
+ sp->vibrato_control_ratio=convert_vibrato_rate(tmp[16]);
+ sp->vibrato_sweep_increment=
+ convert_vibrato_sweep(tmp[15], sp->vibrato_control_ratio);
+ sp->vibrato_depth=tmp[17];
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ " * vibrato: sweep %d, ctl %d, depth %d",
+ sp->vibrato_sweep_increment, sp->vibrato_control_ratio,
+ sp->vibrato_depth);
+
+ }
+
+ READ_CHAR(sp->modes);
+ READ_SHORT(sp->freq_center);
+ READ_SHORT(sp->freq_scale);
+
+ if (sf2flag)
+ {
+ READ_SHORT(sample_volume);
+ READ_CHAR(sf2delay);
+ READ_CHAR(sp->exclusiveClass);
+ skip(fp, 32);
+ }
+ else
+ {
+ skip(fp, 36);
+ }
+
+ /* 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)))
+ {
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing loop and/or sustain");
+ sp->modes &=~(MODES_SUSTAIN | MODES_LOOPING |
+ MODES_PINGPONG | MODES_REVERSE);
+ }
+
+ if (strip_envelope==1)
+ {
+ if (sp->modes & MODES_ENVELOPE)
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Removing envelope");
+ 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);
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ " - No loop, removing sustain and envelope");
+ }
+ 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;
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ " - Weirdness, removing envelope");
+ }
+ 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;
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ " - No sustain, removing envelope");
+ }
+ }
+
+ sp->attenuation = 0;
+
+ for (j=ATTACK; j<DELAY; j++)
+ {
+ sp->envelope_rate[j]=
+ (j<3)? convert_envelope_rate_attack(tmp[j], 11) : convert_envelope_rate(tmp[j]);
+ sp->envelope_offset[j]=
+ convert_envelope_offset(tmp[6+j]);
+ }
+ if (sf2flag)
+ {
+ if (sf2delay > 5) sf2delay = 5;
+ sp->envelope_rate[DELAY] = (int32)( (sf2delay*play_mode->rate) / 1000 );
+ }
+ else
+ {
+ sp->envelope_rate[DELAY]=0;
+ }
+ sp->envelope_offset[DELAY]=0;
+
+ for (j=ATTACK; j<DELAY; j++)
+ {
+ sp->modulation_rate[j]=sp->envelope_rate[j];
+ sp->modulation_offset[j]=sp->envelope_offset[j];
+ }
+ sp->modulation_rate[DELAY] = sp->modulation_offset[DELAY] = 0;
+ sp->modEnvToFilterFc=0;
+ sp->modEnvToPitch=0;
+ sp->lfo_sweep_increment = 0;
+ sp->lfo_phase_increment = 0;
+ sp->modLfoToFilterFc = 0;
+ sp->vibrato_delay = 0;
+
+ /* Then read the sample data */
+ if (sp->data_length/2 > MAX_SAMPLE_SIZE)
+ {
+ printf("error 3\n");
+ goto fail;
+ }
+ sp->data = safe_malloc(sp->data_length + 1);
+ lp->size += sp->data_length + 1;
+
+ if (1 != fread(sp->data, sp->data_length, 1, fp))
+ {
+ printf("error 4\n");
+ goto fail;
+ }
+
+ if (!(sp->modes & MODES_16BIT)) /* convert to 16-bit data */
+ {
+ int32 i=sp->data_length;
+ uint8 *cp=(uint8 *)(sp->data);
+ uint16 *tmp,*newdta;
+ tmp=newdta=safe_malloc(sp->data_length*2 + 2);
+ while (i--)
+ *tmp++ = (uint16)(*cp++) << 8;
+ cp=(uint8 *)(sp->data);
+ sp->data = (sample_t *)newdta;
+ 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 */
+ {
+ int32 i=sp->data_length/2;
+ int16 *tmp=(int16 *)sp->data,s;
+ while (i--)
+ {
+ s=LE_SHORT(*tmp);
+ *tmp++=s;
+ }
+ }
+#endif
+
+ if (sp->modes & MODES_UNSIGNED) /* convert to signed data */
+ {
+ int32 i=sp->data_length/2;
+ int16 *tmp=(int16 *)sp->data;
+ while (i--)
+ *tmp++ ^= 0x8000;
+ }
+
+ /* Reverse reverse loops and pass them off as normal loops */
+ if (sp->modes & MODES_REVERSE)
+ {
+ int32 t;
+ /* The GUS apparently plays reverse loops by reversing the
+ whole sample. We do the same because the GUS does not SUCK. */
+
+ ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Reverse loop in %s", name);
+ reverse_data((int16 *)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 */
+ }
+
+ /* If necessary do some anti-aliasing filtering */
+
+ if (antialiasing_allowed)
+ antialiasing(sp,play_mode->rate);
+
+#ifdef ADJUST_SAMPLE_VOLUMES
+ if (amp!=-1)
+ sp->volume=(FLOAT_T)((amp) / 100.0);
+ else if (sf2flag)
+ sp->volume=(FLOAT_T)((sample_volume) / 255.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. */
+ uint32 i, numsamps=sp->data_length/2;
+ uint32 higher=0, highcount=0;
+ int16 maxamp=0,a;
+ int16 *tmp=(int16 *)sp->data;
+ i = numsamps;
+ while (i--)
+ {
+ a=*tmp++;
+ if (a<0) a=-a;
+ if (a>maxamp)
+ maxamp=a;
+ }
+ tmp=(int16 *)sp->data;
+ i = numsamps;
+ while (i--)
+ {
+ a=*tmp++;
+ if (a<0) a=-a;
+ if (a > 3*maxamp/4)
+ {
+ higher += a;
+ highcount++;
+ }
+ }
+ if (highcount) higher /= highcount;
+ else higher = 10000;
+ sp->volume = (32768.0 * 0.875) / (double)higher ;
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f", 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;
+ sp->data[sp->data_length] = sp->data[sp->data_length-1];
+
+ /* Then fractional samples */
+ sp->data_length <<= FRACTION_BITS;
+ sp->loop_start <<= FRACTION_BITS;
+ sp->loop_end <<= FRACTION_BITS;
+
+ /* trim off zero data at end */
+ {
+ int ls = sp->loop_start>>FRACTION_BITS;
+ int le = sp->loop_end>>FRACTION_BITS;
+ int se = sp->data_length>>FRACTION_BITS;
+ while (se > 1 && !sp->data[se-1]) se--;
+ if (le > se) le = se;
+ if (ls >= le) sp->modes &= ~MODES_LOOPING;
+ sp->loop_end = le<<FRACTION_BITS;
+ sp->data_length = se<<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(sp);
+
+#ifdef LOOKUP_HACK
+ /* Squash the 16-bit data into 8 bits. */
+ {
+ uint8 *gulp,*ulp;
+ int16 *swp;
+ int l=sp->data_length >> FRACTION_BITS;
+ gulp=ulp=safe_malloc(l+1);
+ swp=(int16 *)sp->data;
+ while(l--)
+ *ulp++ = (*swp++ >> 8) & 0xFF;
+ free(sp->data);
+ sp->data=(sample_t *)gulp;
+ }
+#endif
+
+ if (strip_tail==1)
+ {
+ /* Let's not really, just say we did. */
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, " - Stripping tail");
+ sp->data_length = sp->loop_end;
+ }
+ } /* end of sample loop */
+ } /* end of stereo layer loop */
+ } /* end of vlayer loop */
+
+
+ close_file(fp);
+ return headlp;
+}
+
+static int fill_bank(int dr, int b)
+{
+ int i, errors=0;
+ ToneBank *bank=((dr) ? drumset[b] : tonebank[b]);
+ if (!bank)
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Huh. Tried to load instruments in non-existent %s %d",
+ (dr) ? "drumset" : "tone bank", b);
+ return 0;
+ }
+ for (i=0; i<MAXPROG; i++)
+ {
+ if (bank->tone[i].layer==MAGIC_LOAD_INSTRUMENT)
+ {
+ if (!(bank->tone[i].name))
+ {
+ ctl->cmsg(CMSG_WARNING, (b!=0) ? VERB_VERBOSE : VERB_NORMAL,
+ "No instrument mapped to %s %d, program %d%s",
+ (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 (!(standard_tonebank.tone[i].layer))
+ standard_tonebank.tone[i].layer=
+ MAGIC_LOAD_INSTRUMENT;
+ }
+ else
+ {
+ if (!(standard_drumset.tone[i].layer))
+ standard_drumset.tone[i].layer=
+ MAGIC_LOAD_INSTRUMENT;
+ }
+ }
+ bank->tone[i].layer=0;
+ errors++;
+ }
+ else if (!(bank->tone[i].layer=
+ load_instrument(bank->tone[i].name,
+ bank->tone[i].font_type,
+ (dr) ? 1 : 0,
+ bank->tone[i].pan,
+ bank->tone[i].amp,
+ bank->tone[i].tuning,
+ (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,
+ b,
+ ((dr) ? i + 128 : i),
+ bank->tone[i].sf_ix
+ )))
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Couldn't load instrument %s (%s %d, program %d)",
+ bank->tone[i].name,
+ (dr)? "drum set" : "tone bank", b, i);
+ errors++;
+ }
+ else
+ { /* it's loaded now */
+ bank->tone[i].last_used = current_tune_number;
+ current_patch_memory += bank->tone[i].layer->size;
+ purge_as_required();
+ if (current_patch_memory > max_patch_memory) {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Not enough memory to load instrument %s (%s %d, program %d)",
+ bank->tone[i].name,
+ (dr)? "drum set" : "tone bank", b, i);
+ errors++;
+ free_layer(bank->tone[i].layer);
+ bank->tone[i].layer=0;
+ bank->tone[i].last_used=-1;
+ }
+#if 0
+ if (check_for_rc()) {
+ free_layer(bank->tone[i].layer);
+ bank->tone[i].layer=0;
+ bank->tone[i].last_used=-1;
+ return 0;
+ }
+#endif
+ }
+ }
+ }
+ return errors;
+}
+
+static void free_old_instruments(int how_old)
+{
+ int i=MAXBANK;
+ while(i--)
+ {
+ if (tonebank[i])
+ free_old_bank(0, i, how_old);
+ if (drumset[i])
+ free_old_bank(1, i, how_old);
+ }
+}
+
+static void purge_as_required(void)
+{
+ if (!max_patch_memory) return;
+
+ while (last_tune_purged < current_tune_number
+ && current_patch_memory > max_patch_memory)
+ {
+ last_tune_purged++;
+ free_old_instruments(last_tune_purged);
+ }
+}
+
+
+int load_missing_instruments(void)
+{
+ int i=MAXBANK,errors=0;
+ while (i--)
+ {
+ if (tonebank[i])
+ errors+=fill_bank(0,i);
+ if (drumset[i])
+ errors+=fill_bank(1,i);
+ }
+ current_tune_number++;
+ return errors;
+}
+
+void free_instruments(void)
+{
+ int i=128;
+ while(i--)
+ {
+ if (tonebank[i])
+ free_bank(0,i);
+ if (drumset[i])
+ free_bank(1,i);
+ }
+}
+
+int set_default_instrument(const char *name)
+{
+ InstrumentLayer *lp;
+/* if (!(lp=load_instrument(name, 0, -1, -1, -1, 0, 0, 0))) */
+ if (!(lp=load_instrument(name, FONT_NORMAL, 0, -1, -1, 0, -1, -1, -1, -1, 0, -1, -1)))
+ return -1;
+ if (default_instrument)
+ free_layer(default_instrument);
+ default_instrument=lp;
+ default_program=SPECIAL_PROGRAM;
+ return 0;
+}
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/instrum.h b/apps/plugins/sdl/SDL_mixer/timidity/instrum.h
new file mode 100644
index 0000000000..7ba0a99bc1
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/instrum.h
@@ -0,0 +1,168 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+
+typedef struct {
+ int32
+ loop_start, loop_end, data_length,
+ sample_rate, low_freq, high_freq, root_freq;
+ uint8
+ root_tune, fine_tune;
+ int32
+ envelope_rate[7], envelope_offset[7],
+ modulation_rate[7], modulation_offset[7];
+ FLOAT_T
+ volume, resonance,
+ modEnvToFilterFc, modEnvToPitch, modLfoToFilterFc;
+ sample_t *data;
+ int32
+ tremolo_sweep_increment, tremolo_phase_increment,
+ lfo_sweep_increment, lfo_phase_increment,
+ vibrato_sweep_increment, vibrato_control_ratio,
+ cutoff_freq;
+ uint8
+ reverberation, chorusdepth,
+ tremolo_depth, vibrato_depth,
+ modes;
+ uint8
+ attenuation, freq_center;
+ int8
+ panning, note_to_use, exclusiveClass;
+ int16
+ scale_tuning, keyToModEnvHold, keyToModEnvDecay,
+ keyToVolEnvHold, keyToVolEnvDecay;
+ int32
+ freq_scale, vibrato_delay;
+} Sample;
+
+/* 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)
+#define MODES_FAST_RELEASE (1<<7)
+
+#if 0
+typedef struct {
+ int samples;
+ Sample *sample;
+} Instrument;
+#endif
+
+#define INST_GUS 0
+#define INST_SF2 1
+
+typedef struct {
+ int type;
+ int samples;
+ Sample *sample;
+ int left_samples;
+ Sample *left_sample;
+ int right_samples;
+ Sample *right_sample;
+ unsigned char *contents;
+} Instrument;
+
+
+typedef struct _InstrumentLayer {
+ uint8 lo, hi;
+ int size;
+ Instrument *instrument;
+ struct _InstrumentLayer *next;
+} InstrumentLayer;
+
+struct cfg_type {
+ int font_code;
+ int num;
+ const char *name;
+};
+
+#define FONT_NORMAL 0
+#define FONT_FFF 1
+#define FONT_SBK 2
+#define FONT_TONESET 3
+#define FONT_DRUMSET 4
+#define FONT_PRESET 5
+
+
+typedef struct {
+ char *name;
+ InstrumentLayer *layer;
+ int font_type, sf_ix, last_used, tuning;
+ int note, amp, pan, strip_loop, strip_envelope, strip_tail;
+} ToneBankElement;
+
+#if 0
+typedef struct {
+ char *name;
+ Instrument *instrument;
+ int note, amp, pan, strip_loop, strip_envelope, strip_tail;
+} ToneBankElement;
+#endif
+/* A hack to delay instrument loading until after reading the
+ entire MIDI file. */
+#define MAGIC_LOAD_INSTRUMENT ((InstrumentLayer *)(-1))
+
+#define MAXPROG 128
+#define MAXBANK 130
+#define SFXBANK (MAXBANK-1)
+#define SFXDRUM1 (MAXBANK-2)
+#define SFXDRUM2 (MAXBANK-1)
+#define XGDRUM 1
+
+#if 0
+typedef struct {
+ ToneBankElement tone[128];
+} ToneBank;
+#endif
+
+typedef struct {
+ char *name;
+ ToneBankElement tone[MAXPROG];
+} ToneBank;
+
+
+extern char *sf_file;
+
+extern ToneBank *tonebank[], *drumset[];
+
+#if 0
+extern Instrument *default_instrument;
+#endif
+extern InstrumentLayer *default_instrument;
+extern int default_program;
+extern int antialiasing_allowed;
+extern int fast_decay;
+extern int free_instruments_afterwards;
+
+#define SPECIAL_PROGRAM -1
+
+extern int load_missing_instruments(void);
+extern void free_instruments(void);
+extern void end_soundfont(void);
+extern int set_default_instrument(const char *name);
+
+
+extern int32 convert_tremolo_sweep(uint8 sweep);
+extern int32 convert_vibrato_sweep(uint8 sweep, int32 vib_control_ratio);
+extern int32 convert_tremolo_rate(uint8 rate);
+extern int32 convert_vibrato_rate(uint8 rate);
+
+extern int init_soundfont(char *fname, int oldbank, int newbank, int level);
+extern InstrumentLayer *load_sbk_patch(const char *name, int gm_num, int bank, int percussion,
+ int panning, int amp, int note_to_use, int sf_ix);
+extern int current_tune_number;
+extern int max_patch_memory;
+extern int current_patch_memory;
+#define XMAPMAX 800
+extern int xmap[XMAPMAX][5];
+extern void pcmap(int *b, int *v, int *p, int *drums);
+
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/mix.c b/apps/plugins/sdl/SDL_mixer/timidity/mix.c
new file mode 100644
index 0000000000..79d4bfd757
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/mix.c
@@ -0,0 +1,847 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include "config.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "output.h"
+#include "ctrlmode.h"
+#include "tables.h"
+#include "resample.h"
+#include "mix.h"
+
+/* Returns 1 if envelope runs out */
+int recompute_envelope(int v)
+{
+ int stage;
+
+ stage = voice[v].envelope_stage;
+
+ if (stage>5)
+ {
+ /* Envelope ran out. */
+ int tmp=(voice[v].status == VOICE_DIE); /* Already displayed as dead */
+ voice[v].status = VOICE_FREE;
+ if(!tmp)
+ ctl->note(v);
+ return 1;
+ }
+
+ if (voice[v].sample->modes & MODES_ENVELOPE)
+ {
+ if (voice[v].status==VOICE_ON || voice[v].status==VOICE_SUSTAINED)
+ {
+ if (stage>2)
+ {
+ /* Freeze envelope until note turns off. Trumpets want this. */
+ voice[v].envelope_increment=0;
+ return 0;
+ }
+ }
+ }
+ voice[v].envelope_stage=stage+1;
+
+ if (voice[v].envelope_volume==voice[v].sample->envelope_offset[stage])
+ return recompute_envelope(v);
+ voice[v].envelope_target=voice[v].sample->envelope_offset[stage];
+ voice[v].envelope_increment = voice[v].sample->envelope_rate[stage];
+ if (voice[v].envelope_target<voice[v].envelope_volume)
+ voice[v].envelope_increment = -voice[v].envelope_increment;
+ return 0;
+}
+
+void apply_envelope_to_amp(int v)
+{
+ FLOAT_T lamp=voice[v].left_amp, ramp, lramp, rramp, ceamp, lfeamp;
+ int32 la,ra, lra, rra, cea, lfea;
+ if (voice[v].panned == PANNED_MYSTERY)
+ {
+ lramp=voice[v].lr_amp;
+ ramp=voice[v].right_amp;
+ ceamp=voice[v].ce_amp;
+ rramp=voice[v].rr_amp;
+ lfeamp=voice[v].lfe_amp;
+
+ if (voice[v].tremolo_phase_increment)
+ {
+ FLOAT_T tv = voice[v].tremolo_volume;
+ lramp *= tv;
+ lamp *= tv;
+ ceamp *= tv;
+ ramp *= tv;
+ rramp *= tv;
+ lfeamp *= tv;
+ }
+ if (voice[v].sample->modes & MODES_ENVELOPE)
+ {
+ FLOAT_T ev = (FLOAT_T)vol_table[voice[v].envelope_volume>>23];
+ lramp *= ev;
+ lamp *= ev;
+ ceamp *= ev;
+ ramp *= ev;
+ rramp *= ev;
+ lfeamp *= ev;
+ }
+
+ la = (int32)FSCALE(lamp,AMP_BITS);
+ ra = (int32)FSCALE(ramp,AMP_BITS);
+ lra = (int32)FSCALE(lramp,AMP_BITS);
+ rra = (int32)FSCALE(rramp,AMP_BITS);
+ cea = (int32)FSCALE(ceamp,AMP_BITS);
+ lfea = (int32)FSCALE(lfeamp,AMP_BITS);
+
+ if (la>MAX_AMP_VALUE) la=MAX_AMP_VALUE;
+ if (ra>MAX_AMP_VALUE) ra=MAX_AMP_VALUE;
+ if (lra>MAX_AMP_VALUE) lra=MAX_AMP_VALUE;
+ if (rra>MAX_AMP_VALUE) rra=MAX_AMP_VALUE;
+ if (cea>MAX_AMP_VALUE) cea=MAX_AMP_VALUE;
+ if (lfea>MAX_AMP_VALUE) lfea=MAX_AMP_VALUE;
+
+ voice[v].lr_mix=FINAL_VOLUME(lra);
+ voice[v].left_mix=FINAL_VOLUME(la);
+ voice[v].ce_mix=FINAL_VOLUME(cea);
+ voice[v].right_mix=FINAL_VOLUME(ra);
+ voice[v].rr_mix=FINAL_VOLUME(rra);
+ voice[v].lfe_mix=FINAL_VOLUME(lfea);
+ }
+ else
+ {
+ if (voice[v].tremolo_phase_increment)
+ lamp *= voice[v].tremolo_volume;
+ if (voice[v].sample->modes & MODES_ENVELOPE)
+ lamp *= (FLOAT_T)vol_table[voice[v].envelope_volume>>23];
+
+ la = (int32)FSCALE(lamp,AMP_BITS);
+
+ if (la>MAX_AMP_VALUE)
+ la=MAX_AMP_VALUE;
+
+ voice[v].left_mix=FINAL_VOLUME(la);
+ }
+}
+
+static int update_envelope(int v)
+{
+ voice[v].envelope_volume += voice[v].envelope_increment;
+ /* Why is there no ^^ operator?? */
+ if (((voice[v].envelope_increment < 0) &&
+ (voice[v].envelope_volume <= voice[v].envelope_target)) ||
+ ((voice[v].envelope_increment > 0) &&
+ (voice[v].envelope_volume >= voice[v].envelope_target)))
+ {
+ voice[v].envelope_volume = voice[v].envelope_target;
+ if (recompute_envelope(v))
+ return 1;
+ }
+ return 0;
+}
+
+static void update_tremolo(int v)
+{
+ int32 depth=voice[v].sample->tremolo_depth<<7;
+
+ if (voice[v].tremolo_sweep)
+ {
+ /* Update sweep position */
+
+ voice[v].tremolo_sweep_position += voice[v].tremolo_sweep;
+ if (voice[v].tremolo_sweep_position>=(1<<SWEEP_SHIFT))
+ voice[v].tremolo_sweep=0; /* Swept to max amplitude */
+ else
+ {
+ /* Need to adjust depth */
+ depth *= voice[v].tremolo_sweep_position;
+ depth >>= SWEEP_SHIFT;
+ }
+ }
+
+ voice[v].tremolo_phase += voice[v].tremolo_phase_increment;
+
+ /* if (voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<<RATE_SHIFT))
+ voice[v].tremolo_phase -= SINE_CYCLE_LENGTH<<RATE_SHIFT; */
+
+ voice[v].tremolo_volume = (FLOAT_T)
+ (1.0 - FSCALENEG((sine(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(int v)
+{
+ if (voice[v].envelope_increment && update_envelope(v))
+ return 1;
+
+ if (voice[v].tremolo_phase_increment)
+ update_tremolo(v);
+
+ apply_envelope_to_amp(v);
+ return 0;
+}
+
+#ifdef LOOKUP_HACK
+# define MIXATION(a) *lp++ += mixup[(a<<8) | (uint8)s];
+#else
+# define MIXATION(a) *lp++ += (a)*s;
+#endif
+
+#define MIXSKIP lp++
+#define MIXMAX(a,b) *lp++ += ((a>b)?a:b) * s
+#define MIXCENT(a,b) *lp++ += (a/2+b/2) * s
+#define MIXHALF(a) *lp++ += (a>>1)*s;
+
+static void mix_mystery_signal(resample_t *sp, int32 *lp, int v, int count)
+{
+ Voice *vp = voice + v;
+ final_volume_t
+ left_rear=vp->lr_mix,
+ left=vp->left_mix,
+ center=vp->ce_mix,
+ right=vp->right_mix,
+ right_rear=vp->rr_mix,
+ lfe=vp->lfe_mix;
+ int cc;
+ resample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+
+ left_rear = vp->lr_mix;
+ left = vp->left_mix;
+ center = vp->ce_mix;
+ right = vp->right_mix;
+ right_rear = vp->rr_mix;
+ lfe = vp->lfe_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(right);
+ if (num_ochannels >= 4) {
+ MIXATION(left_rear);
+ MIXATION(right_rear);
+ }
+ if (num_ochannels == 6) {
+ MIXATION(center);
+ MIXATION(lfe);
+ }
+ }
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left_rear = vp->lr_mix;
+ left = vp->left_mix;
+ center = vp->ce_mix;
+ right = vp->right_mix;
+ right_rear = vp->rr_mix;
+ lfe = vp->lfe_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(right);
+ if (num_ochannels >= 4) {
+ MIXATION(left_rear);
+ MIXATION(right_rear);
+ }
+ if (num_ochannels == 6) {
+ MIXATION(center);
+ MIXATION(lfe);
+ }
+ }
+ return;
+ }
+}
+
+static void mix_center_signal(resample_t *sp, int32 *lp, int v, int count)
+{
+ Voice *vp = voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ resample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXATION(left);
+ }
+ else if (num_ochannels == 4) {
+ MIXATION(left);
+ MIXSKIP;
+ MIXATION(left);
+ MIXSKIP;
+ }
+ else if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXATION(left);
+ }
+ else if (num_ochannels == 4) {
+ MIXATION(left);
+ MIXSKIP;
+ MIXATION(left);
+ MIXSKIP;
+ }
+ else if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+ return;
+ }
+}
+
+static void mix_single_left_signal(resample_t *sp, int32 *lp, int v, int count)
+{
+ Voice *vp = voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ resample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXSKIP;
+ }
+ if (num_ochannels >= 4) {
+ MIXHALF(left);
+ MIXSKIP;
+ MIXATION(left);
+ MIXSKIP;
+ }
+ if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ }
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXSKIP;
+ }
+ if (num_ochannels >= 4) {
+ MIXHALF(left);
+ MIXSKIP;
+ MIXATION(left);
+ MIXSKIP;
+ }
+ if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ }
+ return;
+ }
+}
+
+static void mix_single_right_signal(resample_t *sp, int32 *lp, int v, int count)
+{
+ Voice *vp = voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ resample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ if (num_ochannels >= 4) {
+ MIXSKIP;
+ MIXHALF(left);
+ MIXSKIP;
+ MIXATION(left);
+ } if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ }
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+ else
+ {
+ vp->control_counter = cc - count;
+ while (count--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ if (num_ochannels >= 4) {
+ MIXSKIP;
+ MIXHALF(left);
+ MIXSKIP;
+ MIXATION(left);
+ } if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ }
+ return;
+ }
+}
+
+static void mix_mono_signal(resample_t *sp, int32 *lp, int v, int count)
+{
+ Voice *vp = voice + v;
+ final_volume_t
+ left=vp->left_mix;
+ int cc;
+ resample_t s;
+
+ if (!(cc = vp->control_counter))
+ {
+ cc = control_ratio;
+ if (update_signal(v))
+ return; /* Envelope ran out */
+ left = vp->left_mix;
+ }
+
+ while (count)
+ if (cc < count)
+ {
+ count -= cc;
+ while (cc--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ }
+ cc = control_ratio;
+ if (update_signal(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(resample_t *sp, int32 *lp, int v, int count)
+{
+ final_volume_t
+ left_rear=voice[v].lr_mix,
+ left=voice[v].left_mix,
+ center=voice[v].ce_mix,
+ right=voice[v].right_mix,
+ right_rear=voice[v].rr_mix,
+ lfe=voice[v].lfe_mix;
+ resample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ MIXATION(right);
+ if (num_ochannels >= 4) {
+ MIXATION(left_rear);
+ MIXATION(right_rear);
+ }
+ if (num_ochannels == 6) {
+ MIXATION(center);
+ MIXATION(lfe);
+ }
+ }
+}
+
+static void mix_center(resample_t *sp, int32 *lp, int v, int count)
+{
+ final_volume_t
+ left=voice[v].left_mix;
+ resample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXATION(left);
+ }
+ else if (num_ochannels == 4) {
+ MIXATION(left);
+ MIXATION(left);
+ MIXSKIP;
+ MIXSKIP;
+ }
+ else if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+}
+
+static void mix_single_left(resample_t *sp, int32 *lp, int v, int count)
+{
+ final_volume_t
+ left=voice[v].left_mix;
+ resample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXSKIP;
+ }
+ if (num_ochannels >= 4) {
+ MIXHALF(left);
+ MIXSKIP;
+ MIXATION(left);
+ MIXSKIP;
+ }
+ if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ }
+}
+static void mix_single_right(resample_t *sp, int32 *lp, int v, int count)
+{
+ final_volume_t
+ left=voice[v].left_mix;
+ resample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ if (num_ochannels == 2) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ if (num_ochannels >= 4) {
+ MIXSKIP;
+ MIXHALF(left);
+ MIXSKIP;
+ MIXATION(left);
+ }
+ if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXATION(left);
+ }
+ }
+}
+
+static void mix_mono(resample_t *sp, int32 *lp, int v, int count)
+{
+ final_volume_t
+ left=voice[v].left_mix;
+ resample_t s;
+
+ while (count--)
+ {
+ s = *sp++;
+ MIXATION(left);
+ }
+}
+
+/* Ramp a note out in c samples */
+static void ramp_out(resample_t *sp, int32 *lp, int v, int32 c)
+{
+
+ /* should be final_volume_t, but uint8 gives trouble. */
+ int32 left_rear, left, center, right, right_rear, lfe, li, ri;
+
+ resample_t s = 0; /* silly warning about uninitialized s */
+
+ /* Fix by James Caldwell */
+ if ( c == 0 ) c = 1;
+
+ left = 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 (!(play_mode->encoding & PE_MONO))
+ {
+ if (voice[v].panned==PANNED_MYSTERY)
+ {
+ left_rear = voice[v].lr_mix;
+ center=voice[v].ce_mix;
+ right=voice[v].right_mix;
+ right_rear = voice[v].rr_mix;
+ lfe = voice[v].lfe_mix;
+
+ ri=-(right/c);
+ while (c--)
+ {
+ left_rear += li; if (left_rear<0) left_rear=0;
+ left += li; if (left<0) left=0;
+ center += li; if (center<0) center=0;
+ right += ri; if (right<0) right=0;
+ right_rear += ri; if (right_rear<0) right_rear=0;
+ lfe += li; if (lfe<0) lfe=0;
+ s=*sp++;
+ MIXATION(left);
+ MIXATION(right);
+ if (num_ochannels >= 4) {
+ MIXATION(left_rear);
+ MIXATION(right_rear);
+ }
+ if (num_ochannels == 6) {
+ MIXATION(center);
+ MIXATION(lfe);
+ }
+ }
+ }
+ else if (voice[v].panned==PANNED_CENTER)
+ {
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ if (num_ochannels == 2) {
+ MIXATION(left);
+ MIXATION(left);
+ }
+ else if (num_ochannels == 4) {
+ MIXATION(left);
+ MIXATION(left);
+ MIXSKIP;
+ MIXSKIP;
+ }
+ else if (num_ochannels == 6) {
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXSKIP;
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+ }
+ else if (voice[v].panned==PANNED_LEFT)
+ {
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ MIXATION(left);
+ MIXSKIP;
+ if (num_ochannels >= 4) {
+ MIXATION(left);
+ MIXSKIP;
+ } if (num_ochannels == 6) {
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+ }
+ else if (voice[v].panned==PANNED_RIGHT)
+ {
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ MIXSKIP;
+ MIXATION(left);
+ if (num_ochannels >= 4) {
+ MIXSKIP;
+ MIXATION(left);
+ } if (num_ochannels == 6) {
+ MIXATION(left);
+ MIXATION(left);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Mono output. */
+ while (c--)
+ {
+ left += li;
+ if (left<0)
+ return;
+ s=*sp++;
+ MIXATION(left);
+ }
+ }
+}
+
+
+/**************** interface function ******************/
+
+void mix_voice(int32 *buf, int v, int32 c)
+{
+ Voice *vp=voice+v;
+ int32 count=c;
+ resample_t *sp;
+ if (c<0) return;
+ if (vp->status==VOICE_DIE)
+ {
+ if (count>=MAX_DIE_TIME)
+ count=MAX_DIE_TIME;
+ sp=resample_voice(v, &count);
+ ramp_out(sp, buf, v, count);
+ vp->status=VOICE_FREE;
+ }
+ else
+ {
+ sp=resample_voice(v, &count);
+ if (count<0) return;
+ if (play_mode->encoding & PE_MONO)
+ {
+ /* Mono output. */
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_mono_signal(sp, buf, v, count);
+ else
+ mix_mono(sp, buf, v, count);
+ }
+ else
+ {
+ if (vp->panned == PANNED_MYSTERY)
+ {
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_mystery_signal(sp, buf, v, count);
+ else
+ mix_mystery(sp, buf, v, count);
+ }
+ else if (vp->panned == PANNED_CENTER)
+ {
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ mix_center_signal(sp, buf, v, count);
+ else
+ mix_center(sp, buf, v, count);
+ }
+ else
+ {
+ /* It's either full left or full right. In either case,
+ every other sample is 0. Just get the offset right: */
+
+ if (vp->envelope_increment || vp->tremolo_phase_increment)
+ {
+ if (vp->panned == PANNED_RIGHT)
+ mix_single_right_signal(sp, buf, v, count);
+ else mix_single_left_signal(sp, buf, v, count);
+ }
+ else
+ {
+ if (vp->panned == PANNED_RIGHT)
+ mix_single_right(sp, buf, v, count);
+ else mix_single_left(sp, buf, v, count);
+ }
+ }
+ }
+ }
+}
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/mix.h b/apps/plugins/sdl/SDL_mixer/timidity/mix.h
new file mode 100644
index 0000000000..2f582b8a6a
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/mix.h
@@ -0,0 +1,11 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+extern void mix_voice(int32 *buf, int v, int32 c);
+extern int recompute_envelope(int v);
+extern void apply_envelope_to_amp(int v);
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/output.c b/apps/plugins/sdl/SDL_mixer/timidity/output.c
new file mode 100644
index 0000000000..5dab01f2eb
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/output.c
@@ -0,0 +1,122 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include "config.h"
+#include "output.h"
+#include "tables.h"
+
+
+#ifdef SDL
+extern PlayMode sdl_play_mode;
+#define DEFAULT_PLAY_MODE &sdl_play_mode
+#endif
+
+PlayMode *play_mode_list[] = {
+#ifdef DEFAULT_PLAY_MODE
+ DEFAULT_PLAY_MODE,
+#endif
+ 0
+};
+
+#ifdef DEFAULT_PLAY_MODE
+ PlayMode *play_mode=DEFAULT_PLAY_MODE;
+#endif
+
+/*****************************************************************/
+/* Some functions to convert signed 32-bit data to other formats */
+
+void s32tos8(void *dp, int32 *lp, int32 c)
+{
+ int8 *cp=(int8 *)(dp);
+ int32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-8-GUARD_BITS);
+ if (l>127) l=127;
+ else if (l<-128) l=-128;
+ *cp++ = (int8) (l);
+ }
+}
+
+void s32tou8(void *dp, int32 *lp, int32 c)
+{
+ uint8 *cp=(uint8 *)(dp);
+ int32 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, int32 *lp, int32 c)
+{
+ int16 *sp=(int16 *)(dp);
+ int32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = (int16)(l);
+ }
+}
+
+void s32tou16(void *dp, int32 *lp, int32 c)
+{
+ uint16 *sp=(uint16 *)(dp);
+ int32 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, int32 *lp, int32 c)
+{
+ int16 *sp=(int16 *)(dp);
+ int32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = XCHG_SHORT((int16)(l));
+ }
+}
+
+void s32tou16x(void *dp, int32 *lp, int32 c)
+{
+ uint16 *sp=(uint16 *)(dp);
+ int32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-16-GUARD_BITS);
+ if (l > 32767) l=32767;
+ else if (l<-32768) l=-32768;
+ *sp++ = XCHG_SHORT(0x8000 ^ (uint16)(l));
+ }
+}
+
+void s32toulaw(void *dp, int32 *lp, int32 c)
+{
+ uint8 *up=(uint8 *)(dp);
+ int32 l;
+ while (c--)
+ {
+ l=(*lp++)>>(32-13-GUARD_BITS);
+ if (l > 4095) l=4095;
+ else if (l<-4096) l=-4096;
+ *up++ = _l2u[l];
+ }
+}
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/output.h b/apps/plugins/sdl/SDL_mixer/timidity/output.h
new file mode 100644
index 0000000000..598792dd20
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/output.h
@@ -0,0 +1,60 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+/* Data format encoding bits */
+
+#define PE_MONO 0x01 /* versus stereo */
+#define PE_SIGNED 0x02 /* versus unsigned */
+#define PE_16BIT 0x04 /* versus 8-bit */
+#define PE_ULAW 0x08 /* versus linear */
+#define PE_BYTESWAP 0x10 /* versus the other way */
+
+typedef struct {
+ int32 rate, encoding;
+ char *id_name;
+} PlayMode;
+
+extern PlayMode *play_mode_list[], *play_mode;
+extern int init_buffers(int kbytes);
+
+/* Conversion functions -- These overwrite the int32 data in *lp with
+ data in another format */
+
+/* The size of the output buffers */
+extern int AUDIO_BUFFER_SIZE;
+
+/* Actual copy function */
+extern void (*s32tobuf)(void *dp, int32 *lp, int32 c);
+
+/* 8-bit signed and unsigned*/
+extern void s32tos8(void *dp, int32 *lp, int32 c);
+extern void s32tou8(void *dp, int32 *lp, int32 c);
+
+/* 16-bit */
+extern void s32tos16(void *dp, int32 *lp, int32 c);
+extern void s32tou16(void *dp, int32 *lp, int32 c);
+
+/* byte-exchanged 16-bit */
+extern void s32tos16x(void *dp, int32 *lp, int32 c);
+extern void s32tou16x(void *dp, int32 *lp, int32 c);
+
+/* uLaw (8 bits) */
+extern void s32toulaw(void *dp, int32 *lp, int32 c);
+
+/* little-endian and big-endian specific */
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+#define s32tou16l s32tou16
+#define s32tou16b s32tou16x
+#define s32tos16l s32tos16
+#define s32tos16b s32tos16x
+#else
+#define s32tou16l s32tou16x
+#define s32tou16b s32tou16
+#define s32tos16l s32tos16x
+#define s32tos16b s32tos16
+#endif
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c
new file mode 100644
index 0000000000..84b18cf5cb
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c
@@ -0,0 +1,1746 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include <SDL_rwops.h>
+
+#include "config.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "readmidi.h"
+#include "output.h"
+#include "mix.h"
+#include "ctrlmode.h"
+#include "timidity.h"
+
+#include "tables.h"
+
+
+static int opt_expression_curve = 2;
+static int opt_volume_curve = 2;
+static int opt_stereo_surround = 0;
+
+
+Channel channel[MAXCHAN];
+Voice voice[MAX_VOICES];
+signed char drumvolume[MAXCHAN][MAXNOTE];
+signed char drumpanpot[MAXCHAN][MAXNOTE];
+signed char drumreverberation[MAXCHAN][MAXNOTE];
+signed char drumchorusdepth[MAXCHAN][MAXNOTE];
+
+int
+ voices=DEFAULT_VOICES;
+
+int32
+ control_ratio=0,
+ amplification=DEFAULT_AMPLIFICATION;
+
+FLOAT_T
+ master_volume;
+
+int32 drumchannels=DEFAULT_DRUMCHANNELS;
+int adjust_panning_immediately=0;
+
+struct _MidiSong {
+ int32 samples;
+ MidiEvent *events;
+};
+static int midi_playing = 0;
+static int32 lost_notes, cut_notes;
+static int32 *buffer_pointer;
+static int32 buffered_count;
+extern int32 *common_buffer;
+extern resample_t *resample_buffer; /* to free it on Timidity_Close */
+
+static MidiEvent *event_list, *current_event;
+static int32 sample_count, current_sample;
+
+int GM_System_On=0;
+int XG_System_On=0;
+int GS_System_On=0;
+int XG_System_reverb_type;
+int XG_System_chorus_type;
+int XG_System_variation_type;
+
+
+static void adjust_amplification(void)
+{
+ master_volume = (FLOAT_T)(amplification) / (FLOAT_T)100.0;
+ master_volume /= 2;
+}
+
+
+static void adjust_master_volume(int32 vol)
+{
+ master_volume = (double)(vol*amplification) / 1638400.0L;
+ master_volume /= 2;
+}
+
+
+static void reset_voices(void)
+{
+ int i;
+ for (i=0; i<MAX_VOICES; i++)
+ voice[i].status=VOICE_FREE;
+}
+
+/* Process the Reset All Controllers event */
+static void reset_controllers(int c)
+{
+ channel[c].volume=90; /* Some standard says, although the SCC docs say 0. */
+ channel[c].expression=127; /* SCC-1 does this. */
+ channel[c].sustain=0;
+ channel[c].pitchbend=0x2000;
+ channel[c].pitchfactor=0; /* to be computed */
+
+ channel[c].reverberation = 0;
+ channel[c].chorusdepth = 0;
+}
+
+static void redraw_controllers(int c)
+{
+ ctl->volume(c, channel[c].volume);
+ ctl->expression(c, channel[c].expression);
+ ctl->sustain(c, channel[c].sustain);
+ ctl->pitch_bend(c, channel[c].pitchbend);
+}
+
+static void reset_midi(void)
+{
+ int i;
+ for (i=0; i<MAXCHAN; i++)
+ {
+ reset_controllers(i);
+ /* The rest of these are unaffected by the Reset All Controllers event */
+ channel[i].program=default_program;
+ channel[i].panning=NO_PANNING;
+ channel[i].pitchsens=2;
+ channel[i].bank=0; /* tone bank or drum set */
+ channel[i].harmoniccontent=64,
+ channel[i].releasetime=64,
+ channel[i].attacktime=64,
+ channel[i].brightness=64,
+ channel[i].sfx=0;
+ }
+ reset_voices();
+}
+
+static void select_sample(int v, Instrument *ip)
+{
+ int32 f, cdiff, diff, midfreq;
+ int s,i;
+ Sample *sp, *closest;
+
+ s=ip->samples;
+ sp=ip->sample;
+
+ if (s==1)
+ {
+ voice[v].sample=sp;
+ return;
+ }
+
+ f=voice[v].orig_frequency;
+ /*
+ 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;
+ midfreq = (sp->low_freq + sp->high_freq) / 2;
+ for(i=0; i<s; i++)
+ {
+ diff=sp->root_freq - f;
+ /* But the root freq. can perfectly well lie outside the keyrange
+ * frequencies, so let's try:
+ */
+ /* diff=midfreq - f; */
+ if (diff<0) diff=-diff;
+ if (diff<cdiff)
+ {
+ cdiff=diff;
+ closest=sp;
+ }
+ sp++;
+ }
+ voice[v].sample=closest;
+ return;
+}
+
+
+
+static void select_stereo_samples(int v, InstrumentLayer *lp)
+{
+ Instrument *ip;
+ InstrumentLayer *nlp, *bestvel;
+ int diffvel, midvel, mindiff;
+
+/* select closest velocity */
+ bestvel = lp;
+ mindiff = 500;
+ for (nlp = lp; nlp; nlp = nlp->next) {
+ midvel = (nlp->hi + nlp->lo)/2;
+ if (!midvel) diffvel = 127;
+ else if (voice[v].velocity < nlp->lo || voice[v].velocity > nlp->hi)
+ diffvel = 200;
+ else diffvel = voice[v].velocity - midvel;
+ if (diffvel < 0) diffvel = -diffvel;
+ if (diffvel < mindiff) {
+ mindiff = diffvel;
+ bestvel = nlp;
+ }
+ }
+ ip = bestvel->instrument;
+
+ if (ip->right_sample) {
+ ip->sample = ip->right_sample;
+ ip->samples = ip->right_samples;
+ select_sample(v, ip);
+ voice[v].right_sample = voice[v].sample;
+ }
+ else voice[v].right_sample = 0;
+ ip->sample = ip->left_sample;
+ ip->samples = ip->left_samples;
+ select_sample(v, ip);
+}
+
+
+static void recompute_freq(int v)
+{
+ int
+ sign=(voice[v].sample_increment < 0), /* for bidirectional loops */
+ pb=channel[voice[v].channel].pitchbend;
+ double a;
+
+ if (!voice[v].sample->sample_rate)
+ return;
+
+ if (voice[v].vibrato_control_ratio)
+ {
+ /* This instrument has vibrato. Invalidate any precomputed
+ sample_increments. */
+
+ int i=VIBRATO_SAMPLE_INCREMENTS;
+ while (i--)
+ voice[v].vibrato_sample_increment[i]=0;
+ }
+
+ if (pb==0x2000 || pb<0 || pb>0x3FFF)
+ voice[v].frequency=voice[v].orig_frequency;
+ else
+ {
+ pb-=0x2000;
+ if (!(channel[voice[v].channel].pitchfactor))
+ {
+ /* Damn. Somebody bent the pitch. */
+ int32 i=pb*channel[voice[v].channel].pitchsens;
+ if (pb<0)
+ i=-i;
+ channel[voice[v].channel].pitchfactor=
+ (FLOAT_T)(bend_fine[(i>>5) & 0xFF] * bend_coarse[i>>13]);
+ }
+ if (pb>0)
+ voice[v].frequency=
+ (int32)(channel[voice[v].channel].pitchfactor *
+ (double)(voice[v].orig_frequency));
+ else
+ voice[v].frequency=
+ (int32)((double)(voice[v].orig_frequency) /
+ channel[voice[v].channel].pitchfactor);
+ }
+
+ a = FSCALE(((double)(voice[v].sample->sample_rate) *
+ (double)(voice[v].frequency)) /
+ ((double)(voice[v].sample->root_freq) *
+ (double)(play_mode->rate)),
+ FRACTION_BITS);
+
+ if (sign)
+ a = -a; /* need to preserve the loop direction */
+
+ voice[v].sample_increment = (int32)(a);
+}
+
+static int expr_curve[128] = {
+ 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11,
+ 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+ 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22,
+ 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31,
+ 32, 32, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 59, 60, 61, 63,
+ 64, 65, 67, 68, 70, 71, 73, 75, 76, 78, 80, 82, 83, 85, 87, 89,
+ 91, 93, 95, 97, 99, 102, 104, 106, 109, 111, 113, 116, 118, 121,
+ 124, 127
+};
+
+static int panf(int pan, int speaker, int separation)
+{
+ int val;
+ val = abs(pan - speaker);
+ val = (val * 127) / separation;
+ val = 127 - val;
+ if (val < 0) val = 0;
+ if (val > 127) val = 127;
+ return expr_curve[val];
+}
+
+
+static int vcurve[128] = {
+0,0,18,29,36,42,47,51,55,58,
+60,63,65,67,69,71,73,74,76,77,
+79,80,81,82,83,84,85,86,87,88,
+89,90,91,92,92,93,94,95,95,96,
+97,97,98,99,99,100,100,101,101,102,
+103,103,104,104,105,105,106,106,106,107,
+107,108,108,109,109,109,110,110,111,111,
+111,112,112,112,113,113,114,114,114,115,
+115,115,116,116,116,116,117,117,117,118,
+118,118,119,119,119,119,120,120,120,120,
+121,121,121,122,122,122,122,123,123,123,
+123,123,124,124,124,124,125,125,125,125,
+126,126,126,126,126,127,127,127
+};
+
+static void recompute_amp(int v)
+{
+ int32 tempamp;
+ int chan = voice[v].channel;
+ int panning = voice[v].panning;
+ int vol = channel[chan].volume;
+ int expr = channel[chan].expression;
+ int vel = vcurve[voice[v].velocity];
+ FLOAT_T curved_expression, curved_volume;
+
+ if (channel[chan].kit)
+ {
+ int note = voice[v].sample->note_to_use;
+ if (note>0 && drumvolume[chan][note]>=0) vol = drumvolume[chan][note];
+ if (note>0 && drumpanpot[chan][note]>=0) panning = drumvolume[chan][note];
+ }
+
+ if (opt_expression_curve == 2) curved_expression = 127.0 * vol_table[expr];
+ else if (opt_expression_curve == 1) curved_expression = 127.0 * expr_table[expr];
+ else curved_expression = (FLOAT_T)expr;
+
+ if (opt_volume_curve == 2) curved_volume = 127.0 * vol_table[vol];
+ else if (opt_volume_curve == 1) curved_volume = 127.0 * expr_table[vol];
+ else curved_volume = (FLOAT_T)vol;
+
+ tempamp= (int32)((FLOAT_T)vel * curved_volume * curved_expression); /* 21 bits */
+
+ /* TODO: use fscale */
+
+ if (num_ochannels > 1)
+ {
+ if (panning > 60 && panning < 68)
+ {
+ voice[v].panned=PANNED_CENTER;
+
+ if (num_ochannels == 6) voice[v].left_amp =
+ FSCALENEG((double) (tempamp) * voice[v].sample->volume *
+ master_volume, 20);
+ else voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * voice[v].sample->volume *
+ master_volume, 21);
+ }
+ else if (panning<5)
+ {
+ voice[v].panned = PANNED_LEFT;
+
+ voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * voice[v].sample->volume * master_volume,
+ 20);
+ }
+ else if (panning>123)
+ {
+ voice[v].panned = PANNED_RIGHT;
+
+ voice[v].left_amp= /* left_amp will be used */
+ FSCALENEG((double)(tempamp) * voice[v].sample->volume * master_volume,
+ 20);
+ }
+ else
+ {
+ FLOAT_T refv = (double)(tempamp) * voice[v].sample->volume * master_volume;
+ int wide_panning = 64;
+
+ if (num_ochannels == 4) wide_panning = 95;
+
+ voice[v].panned = PANNED_MYSTERY;
+ voice[v].lfe_amp = FSCALENEG(refv * 64, 27);
+
+ switch (num_ochannels)
+ {
+ case 2:
+ voice[v].lr_amp = 0;
+ voice[v].left_amp = FSCALENEG(refv * (128-panning), 27);
+ voice[v].ce_amp = 0;
+ voice[v].right_amp = FSCALENEG(refv * panning, 27);
+ voice[v].rr_amp = 0;
+ break;
+ case 4:
+ voice[v].lr_amp = FSCALENEG(refv * panf(panning, 0, wide_panning), 27);
+ voice[v].left_amp = FSCALENEG(refv * panf(panning, 32, wide_panning), 27);
+ voice[v].ce_amp = 0;
+ voice[v].right_amp = FSCALENEG(refv * panf(panning, 95, wide_panning), 27);
+ voice[v].rr_amp = FSCALENEG(refv * panf(panning, 128, wide_panning), 27);
+ break;
+ case 6:
+ voice[v].lr_amp = FSCALENEG(refv * panf(panning, 0, wide_panning), 27);
+ voice[v].left_amp = FSCALENEG(refv * panf(panning, 32, wide_panning), 27);
+ voice[v].ce_amp = FSCALENEG(refv * panf(panning, 64, wide_panning), 27);
+ voice[v].right_amp = FSCALENEG(refv * panf(panning, 95, wide_panning), 27);
+ voice[v].rr_amp = FSCALENEG(refv * panf(panning, 128, wide_panning), 27);
+ break;
+ }
+
+ }
+ }
+ else
+ {
+ voice[v].panned=PANNED_CENTER;
+
+ voice[v].left_amp=
+ FSCALENEG((double)(tempamp) * voice[v].sample->volume * master_volume,
+ 21);
+ }
+}
+
+
+#define NOT_CLONE 0
+#define STEREO_CLONE 1
+#define REVERB_CLONE 2
+#define CHORUS_CLONE 3
+
+
+/* just a variant of note_on() */
+static int vc_alloc(int j)
+{
+ int i=voices;
+
+ while (i--)
+ {
+ if (i == j) continue;
+ if (voice[i].status & VOICE_FREE) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void kill_note(int i);
+
+static void kill_others(int i)
+{
+ int j=voices;
+
+ if (!voice[i].sample->exclusiveClass) return;
+
+ while (j--)
+ {
+ if (voice[j].status & (VOICE_FREE|VOICE_OFF|VOICE_DIE)) continue;
+ if (i == j) continue;
+ if (voice[i].channel != voice[j].channel) continue;
+ if (voice[j].sample->note_to_use)
+ {
+ if (voice[j].sample->exclusiveClass != voice[i].sample->exclusiveClass) continue;
+ kill_note(j);
+ }
+ }
+}
+
+
+static void clone_voice(Instrument *ip, int v, MidiEvent *e, int clone_type, int variationbank)
+{
+ int w, played_note, chorus=0, reverb=0, milli;
+ int chan = voice[v].channel;
+
+ if (clone_type == STEREO_CLONE) {
+ if (!voice[v].right_sample && variationbank != 3) return;
+ if (variationbank == 6) return;
+ }
+
+ if (channel[chan].kit) {
+ reverb = drumreverberation[chan][voice[v].note];
+ chorus = drumchorusdepth[chan][voice[v].note];
+ }
+ else {
+ reverb = channel[chan].reverberation;
+ chorus = channel[chan].chorusdepth;
+ }
+
+ if (clone_type == REVERB_CLONE) chorus = 0;
+ else if (clone_type == CHORUS_CLONE) reverb = 0;
+ else if (clone_type == STEREO_CLONE) reverb = chorus = 0;
+
+ if (reverb > 127) reverb = 127;
+ if (chorus > 127) chorus = 127;
+
+ if (clone_type == CHORUS_CLONE) {
+ if (variationbank == 32) chorus = 30;
+ else if (variationbank == 33) chorus = 60;
+ else if (variationbank == 34) chorus = 90;
+ }
+
+ chorus /= 2; /* This is an ad hoc adjustment. */
+
+ if (!reverb && !chorus && clone_type != STEREO_CLONE) return;
+
+ if ( (w = vc_alloc(v)) < 0 ) return;
+
+ voice[w] = voice[v];
+ if (clone_type==STEREO_CLONE) voice[v].clone_voice = w;
+ voice[w].clone_voice = v;
+ voice[w].clone_type = clone_type;
+
+ voice[w].sample = voice[v].right_sample;
+ voice[w].velocity= e->b;
+
+ milli = play_mode->rate/1000;
+
+ if (clone_type == STEREO_CLONE) {
+ int left, right, leftpan, rightpan;
+ int panrequest = voice[v].panning;
+ if (variationbank == 3) {
+ voice[v].panning = 0;
+ voice[w].panning = 127;
+ }
+ else {
+ if (voice[v].sample->panning > voice[w].sample->panning) {
+ left = w;
+ right = v;
+ }
+ else {
+ left = v;
+ right = w;
+ }
+#define INSTRUMENT_SEPARATION 12
+ leftpan = panrequest - INSTRUMENT_SEPARATION / 2;
+ rightpan = leftpan + INSTRUMENT_SEPARATION;
+ if (leftpan < 0) {
+ leftpan = 0;
+ rightpan = leftpan + INSTRUMENT_SEPARATION;
+ }
+ if (rightpan > 127) {
+ rightpan = 127;
+ leftpan = rightpan - INSTRUMENT_SEPARATION;
+ }
+ voice[left].panning = leftpan;
+ voice[right].panning = rightpan;
+ voice[right].echo_delay = 20 * milli;
+ }
+ }
+
+ voice[w].volume = voice[w].sample->volume;
+
+ if (reverb) {
+ if (opt_stereo_surround) {
+ if (voice[w].panning > 64) voice[w].panning = 127;
+ else voice[w].panning = 0;
+ }
+ else {
+ if (voice[v].panning < 64) voice[w].panning = 64 + reverb/2;
+ else voice[w].panning = 64 - reverb/2;
+ }
+
+/* try 98->99 for melodic instruments ? (bit much for percussion) */
+ voice[w].volume *= vol_table[(127-reverb)/8 + 98];
+
+ voice[w].echo_delay += reverb * milli;
+ voice[w].envelope_rate[DECAY] *= 2;
+ voice[w].envelope_rate[RELEASE] /= 2;
+
+ if (XG_System_reverb_type >= 0) {
+ int subtype = XG_System_reverb_type & 0x07;
+ int rtype = XG_System_reverb_type >>3;
+ switch (rtype) {
+ case 0: /* no effect */
+ break;
+ case 1: /* hall */
+ if (subtype) voice[w].echo_delay += 100 * milli;
+ break;
+ case 2: /* room */
+ voice[w].echo_delay /= 2;
+ break;
+ case 3: /* stage */
+ voice[w].velocity = voice[v].velocity;
+ break;
+ case 4: /* plate */
+ voice[w].panning = voice[v].panning;
+ break;
+ case 16: /* white room */
+ voice[w].echo_delay = 0;
+ break;
+ case 17: /* tunnel */
+ voice[w].echo_delay *= 2;
+ voice[w].velocity /= 2;
+ break;
+ case 18: /* canyon */
+ voice[w].echo_delay *= 2;
+ break;
+ case 19: /* basement */
+ voice[w].velocity /= 2;
+ break;
+ default: break;
+ }
+ }
+ }
+ played_note = voice[w].sample->note_to_use;
+ if (!played_note) {
+ played_note = e->a & 0x7f;
+ if (variationbank == 35) played_note += 12;
+ else if (variationbank == 36) played_note -= 12;
+ else if (variationbank == 37) played_note += 7;
+ else if (variationbank == 36) played_note -= 7;
+ }
+#if 0
+ played_note = ( (played_note - voice[w].sample->freq_center) * voice[w].sample->freq_scale ) / 1024 +
+ voice[w].sample->freq_center;
+#endif
+ voice[w].note = played_note;
+ voice[w].orig_frequency = freq_table[played_note];
+
+ if (chorus) {
+ if (opt_stereo_surround) {
+ if (voice[v].panning < 64) voice[w].panning = voice[v].panning + 32;
+ else voice[w].panning = voice[v].panning - 32;
+ }
+
+ if (!voice[w].vibrato_control_ratio) {
+ voice[w].vibrato_control_ratio = 100;
+ voice[w].vibrato_depth = 6;
+ voice[w].vibrato_sweep = 74;
+ }
+ voice[w].volume *= 0.40;
+ voice[v].volume = voice[w].volume;
+ recompute_amp(v);
+ apply_envelope_to_amp(v);
+ voice[w].vibrato_sweep = chorus/2;
+ voice[w].vibrato_depth /= 2;
+ if (!voice[w].vibrato_depth) voice[w].vibrato_depth = 2;
+ voice[w].vibrato_control_ratio /= 2;
+ voice[w].echo_delay += 30 * milli;
+
+ if (XG_System_chorus_type >= 0) {
+ int subtype = XG_System_chorus_type & 0x07;
+ int chtype = 0x0f & (XG_System_chorus_type >> 3);
+ switch (chtype) {
+ case 0: /* no effect */
+ break;
+ case 1: /* chorus */
+ chorus /= 3;
+ if(channel[ voice[w].channel ].pitchbend + chorus < 0x2000)
+ voice[w].orig_frequency =
+ (uint32)( (FLOAT_T)voice[w].orig_frequency * bend_fine[chorus] );
+ else voice[w].orig_frequency =
+ (uint32)( (FLOAT_T)voice[w].orig_frequency / bend_fine[chorus] );
+ if (subtype) voice[w].vibrato_depth *= 2;
+ break;
+ case 2: /* celeste */
+ voice[w].orig_frequency += (voice[w].orig_frequency/128) * chorus;
+ break;
+ case 3: /* flanger */
+ voice[w].vibrato_control_ratio = 10;
+ voice[w].vibrato_depth = 100;
+ voice[w].vibrato_sweep = 8;
+ voice[w].echo_delay += 200 * milli;
+ break;
+ case 4: /* symphonic : cf Children of the Night /128 bad, /1024 ok */
+ voice[w].orig_frequency += (voice[w].orig_frequency/512) * chorus;
+ voice[v].orig_frequency -= (voice[v].orig_frequency/512) * chorus;
+ recompute_freq(v);
+ break;
+ case 8: /* phaser */
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ chorus /= 3;
+ if(channel[ voice[w].channel ].pitchbend + chorus < 0x2000)
+ voice[w].orig_frequency =
+ (uint32)( (FLOAT_T)voice[w].orig_frequency * bend_fine[chorus] );
+ else voice[w].orig_frequency =
+ (uint32)( (FLOAT_T)voice[w].orig_frequency / bend_fine[chorus] );
+ }
+ }
+#if 0
+ voice[w].loop_start = voice[w].sample->loop_start;
+ voice[w].loop_end = voice[w].sample->loop_end;
+#endif
+ voice[w].echo_delay_count = voice[w].echo_delay;
+ if (reverb) voice[w].echo_delay *= 2;
+
+ recompute_freq(w);
+ recompute_amp(w);
+ if (voice[w].sample->modes & MODES_ENVELOPE)
+ {
+ /* Ramp up from 0 */
+ voice[w].envelope_stage=ATTACK;
+ voice[w].modulation_stage=ATTACK;
+ voice[w].envelope_volume=0;
+ voice[w].modulation_volume=0;
+ voice[w].control_counter=0;
+ voice[w].modulation_counter=0;
+ recompute_envelope(w);
+ /*recompute_modulation(w);*/
+ }
+ else
+ {
+ voice[w].envelope_increment=0;
+ voice[w].modulation_increment=0;
+ }
+ apply_envelope_to_amp(w);
+}
+
+
+static void xremap(int *banknumpt, int *this_notept, int this_kit) {
+ int i, newmap;
+ int banknum = *banknumpt;
+ int this_note = *this_notept;
+ int newbank, newnote;
+
+ if (!this_kit) {
+ if (banknum == SFXBANK && tonebank[SFXBANK]) return;
+ if (banknum == SFXBANK && tonebank[120]) *banknumpt = 120;
+ return;
+ }
+
+ if (this_kit != 127 && this_kit != 126) return;
+
+ for (i = 0; i < XMAPMAX; i++) {
+ newmap = xmap[i][0];
+ if (!newmap) return;
+ if (this_kit == 127 && newmap != XGDRUM) continue;
+ if (this_kit == 126 && newmap != SFXDRUM1) continue;
+ if (xmap[i][1] != banknum) continue;
+ if (xmap[i][3] != this_note) continue;
+ newbank = xmap[i][2];
+ newnote = xmap[i][4];
+ if (newbank == banknum && newnote == this_note) return;
+ if (!drumset[newbank]) return;
+ if (!drumset[newbank]->tone[newnote].layer) return;
+ if (drumset[newbank]->tone[newnote].layer == MAGIC_LOAD_INSTRUMENT) return;
+ *banknumpt = newbank;
+ *this_notept = newnote;
+ return;
+ }
+}
+
+
+static void start_note(MidiEvent *e, int i)
+{
+ InstrumentLayer *lp;
+ Instrument *ip;
+ int j, banknum, ch=e->channel;
+ int played_note, drumpan=NO_PANNING;
+ int32 rt;
+ int attacktime, releasetime, decaytime, variationbank;
+ int brightness = channel[ch].brightness;
+ int harmoniccontent = channel[ch].harmoniccontent;
+ int this_note = e->a;
+ int this_velocity = e->b;
+ int drumsflag = channel[ch].kit;
+ int this_prog = channel[ch].program;
+
+ if (channel[ch].sfx) banknum=channel[ch].sfx;
+ else banknum=channel[ch].bank;
+
+ voice[i].velocity=this_velocity;
+
+ if (XG_System_On) xremap(&banknum, &this_note, drumsflag);
+ /* if (current_config_pc42b) pcmap(&banknum, &this_note, &this_prog, &drumsflag); */
+
+ if (drumsflag)
+ {
+ if (!(lp=drumset[banknum]->tone[this_note].layer))
+ {
+ if (!(lp=drumset[0]->tone[this_note].layer))
+ return; /* No instrument? Then we can't play. */
+ }
+ ip = lp->instrument;
+ if (ip->type == INST_GUS && ip->samples != 1)
+ {
+ ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
+ "Strange: percussion instrument with %d samples!", ip->samples);
+ }
+
+ if (ip->sample->note_to_use) /* Do we have a fixed pitch? */
+ {
+ voice[i].orig_frequency=freq_table[(int)(ip->sample->note_to_use)];
+ drumpan=drumpanpot[ch][(int)ip->sample->note_to_use];
+ }
+ else
+ voice[i].orig_frequency=freq_table[this_note & 0x7F];
+
+ }
+ else
+ {
+ if (channel[ch].program==SPECIAL_PROGRAM)
+ lp=default_instrument;
+ else if (!(lp=tonebank[channel[ch].bank]->
+ tone[channel[ch].program].layer))
+ {
+ if (!(lp=tonebank[0]->tone[this_prog].layer))
+ return; /* No instrument? Then we can't play. */
+ }
+ ip = lp->instrument;
+ if (ip->sample->note_to_use) /* Fixed-pitch instrument? */
+ voice[i].orig_frequency=freq_table[(int)(ip->sample->note_to_use)];
+ else
+ voice[i].orig_frequency=freq_table[this_note & 0x7F];
+ }
+
+ select_stereo_samples(i, lp);
+
+ voice[i].starttime = e->time;
+ played_note = voice[i].sample->note_to_use;
+
+ if (!played_note || !drumsflag) played_note = this_note & 0x7f;
+#if 0
+ played_note = ( (played_note - voice[i].sample->freq_center) * voice[i].sample->freq_scale ) / 1024 +
+ voice[i].sample->freq_center;
+#endif
+ voice[i].status=VOICE_ON;
+ voice[i].channel=ch;
+ voice[i].note=played_note;
+ voice[i].velocity=this_velocity;
+ voice[i].sample_offset=0;
+ voice[i].sample_increment=0; /* make sure it isn't negative */
+
+ voice[i].tremolo_phase=0;
+ voice[i].tremolo_phase_increment=voice[i].sample->tremolo_phase_increment;
+ voice[i].tremolo_sweep=voice[i].sample->tremolo_sweep_increment;
+ voice[i].tremolo_sweep_position=0;
+
+ voice[i].vibrato_sweep=voice[i].sample->vibrato_sweep_increment;
+ voice[i].vibrato_sweep_position=0;
+ voice[i].vibrato_depth=voice[i].sample->vibrato_depth;
+ voice[i].vibrato_control_ratio=voice[i].sample->vibrato_control_ratio;
+ voice[i].vibrato_control_counter=voice[i].vibrato_phase=0;
+ voice[i].vibrato_delay = voice[i].sample->vibrato_delay;
+
+ kill_others(i);
+
+ for (j=0; j<VIBRATO_SAMPLE_INCREMENTS; j++)
+ voice[i].vibrato_sample_increment[j]=0;
+
+
+ attacktime = channel[ch].attacktime;
+ releasetime = channel[ch].releasetime;
+ decaytime = 64;
+ variationbank = channel[ch].variationbank;
+
+ switch (variationbank) {
+ case 8:
+ attacktime = 64+32;
+ break;
+ case 12:
+ decaytime = 64-32;
+ break;
+ case 16:
+ brightness = 64+16;
+ break;
+ case 17:
+ brightness = 64+32;
+ break;
+ case 18:
+ brightness = 64-16;
+ break;
+ case 19:
+ brightness = 64-32;
+ break;
+ case 20:
+ harmoniccontent = 64+16;
+ break;
+#if 0
+ case 24:
+ voice[i].modEnvToFilterFc=2.0;
+ voice[i].sample->cutoff_freq = 800;
+ break;
+ case 25:
+ voice[i].modEnvToFilterFc=-2.0;
+ voice[i].sample->cutoff_freq = 800;
+ break;
+ case 27:
+ voice[i].modLfoToFilterFc=2.0;
+ voice[i].lfo_phase_increment=109;
+ voice[i].lfo_sweep=122;
+ voice[i].sample->cutoff_freq = 800;
+ break;
+ case 28:
+ voice[i].modLfoToFilterFc=-2.0;
+ voice[i].lfo_phase_increment=109;
+ voice[i].lfo_sweep=122;
+ voice[i].sample->cutoff_freq = 800;
+ break;
+#endif
+ default:
+ break;
+ }
+
+
+ for (j=ATTACK; j<MAXPOINT; j++)
+ {
+ voice[i].envelope_rate[j]=voice[i].sample->envelope_rate[j];
+ voice[i].envelope_offset[j]=voice[i].sample->envelope_offset[j];
+ }
+
+ voice[i].echo_delay=voice[i].envelope_rate[DELAY];
+ voice[i].echo_delay_count = voice[i].echo_delay;
+
+ if (attacktime!=64)
+ {
+ rt = voice[i].envelope_rate[ATTACK];
+ rt = rt + ( (64-attacktime)*rt ) / 100;
+ if (rt > 1000) voice[i].envelope_rate[ATTACK] = rt;
+ }
+ if (releasetime!=64)
+ {
+ rt = voice[i].envelope_rate[RELEASE];
+ rt = rt + ( (64-releasetime)*rt ) / 100;
+ if (rt > 1000) voice[i].envelope_rate[RELEASE] = rt;
+ }
+ if (decaytime!=64)
+ {
+ rt = voice[i].envelope_rate[DECAY];
+ rt = rt + ( (64-decaytime)*rt ) / 100;
+ if (rt > 1000) voice[i].envelope_rate[DECAY] = rt;
+ }
+
+ if (channel[ch].panning != NO_PANNING)
+ voice[i].panning=channel[ch].panning;
+ else
+ voice[i].panning=voice[i].sample->panning;
+ if (drumpan != NO_PANNING)
+ voice[i].panning=drumpan;
+
+ if (variationbank == 1) {
+ int pan = voice[i].panning;
+ int disturb = 0;
+ /* If they're close up (no reverb) and you are behind the pianist,
+ * high notes come from the right, so we'll spread piano etc. notes
+ * out horizontally according to their pitches.
+ */
+ if (this_prog < 21) {
+ int n = voice[i].velocity - 32;
+ if (n < 0) n = 0;
+ if (n > 64) n = 64;
+ pan = pan/2 + n;
+ }
+ /* For other types of instruments, the music sounds more alive if
+ * notes come from slightly different directions. However, instruments
+ * do drift around in a sometimes disconcerting way, so the following
+ * might not be such a good idea.
+ */
+ else disturb = (voice[i].velocity/32 % 8) +
+ (voice[i].note % 8); /* /16? */
+
+ if (pan < 64) pan += disturb;
+ else pan -= disturb;
+ if (pan < 0) pan = 0;
+ else if (pan > 127) pan = 127;
+ voice[i].panning = pan;
+ }
+
+ recompute_freq(i);
+ recompute_amp(i);
+ if (voice[i].sample->modes & MODES_ENVELOPE)
+ {
+ /* Ramp up from 0 */
+ voice[i].envelope_stage=ATTACK;
+ voice[i].envelope_volume=0;
+ voice[i].control_counter=0;
+ recompute_envelope(i);
+ }
+ else
+ {
+ voice[i].envelope_increment=0;
+ }
+ apply_envelope_to_amp(i);
+
+ voice[i].clone_voice = -1;
+ voice[i].clone_type = NOT_CLONE;
+
+ clone_voice(ip, i, e, STEREO_CLONE, variationbank);
+ clone_voice(ip, i, e, CHORUS_CLONE, variationbank);
+ clone_voice(ip, i, e, REVERB_CLONE, variationbank);
+
+ ctl->note(i);
+}
+
+static void kill_note(int i)
+{
+ voice[i].status=VOICE_DIE;
+ if (voice[i].clone_voice >= 0)
+ voice[ voice[i].clone_voice ].status=VOICE_DIE;
+ ctl->note(i);
+}
+
+
+/* Only one instance of a note can be playing on a single channel. */
+static void note_on(MidiEvent *e)
+{
+ int i=voices, lowest=-1;
+ int32 lv=0x7FFFFFFF, v;
+
+ while (i--)
+ {
+ if (voice[i].status == VOICE_FREE)
+ lowest=i; /* Can't get a lower volume than silence */
+ else if (voice[i].channel==e->channel &&
+ (voice[i].note==e->a || channel[voice[i].channel].mono))
+ kill_note(i);
+ }
+
+ if (lowest != -1)
+ {
+ /* Found a free voice. */
+ start_note(e,lowest);
+ return;
+ }
+
+#if 0
+ /* Look for the decaying note with the lowest volume */
+ i=voices;
+ while (i--)
+ {
+ if (voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE))
+ {
+ v=voice[i].left_mix;
+ if ((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v))
+ v=voice[i].right_mix;
+ if (v<lv)
+ {
+ lv=v;
+ lowest=i;
+ }
+ }
+ }
+#endif
+
+ /* Look for the decaying note with the lowest volume */
+ if (lowest==-1)
+ {
+ i=voices;
+ while (i--)
+ {
+ if ( (voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE)) &&
+ (!voice[i].clone_type))
+ {
+ v=voice[i].left_mix;
+ if ((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v))
+ v=voice[i].right_mix;
+ if (v<lv)
+ {
+ lv=v;
+ lowest=i;
+ }
+ }
+ }
+ }
+
+ if (lowest != -1)
+ {
+ int cl = voice[lowest].clone_voice;
+
+ /* 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. */
+
+ if (cl >= 0) {
+ if (voice[cl].clone_type==STEREO_CLONE ||
+ (!voice[cl].clone_type && voice[lowest].clone_type==STEREO_CLONE))
+ voice[cl].status=VOICE_FREE;
+ else if (voice[cl].clone_voice==lowest) voice[cl].clone_voice=-1;
+ }
+
+ cut_notes++;
+ voice[lowest].status=VOICE_FREE;
+ ctl->note(lowest);
+ start_note(e,lowest);
+ }
+ else
+ lost_notes++;
+}
+
+static void finish_note(int i)
+{
+ if (voice[i].sample->modes & MODES_ENVELOPE)
+ {
+ /* We need to get the envelope out of Sustain stage */
+ voice[i].envelope_stage=3;
+ voice[i].status=VOICE_OFF;
+ recompute_envelope(i);
+ apply_envelope_to_amp(i);
+ ctl->note(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). */
+ voice[i].status=VOICE_OFF;
+ }
+
+ { int v;
+ if ( (v=voice[i].clone_voice) >= 0)
+ {
+ voice[i].clone_voice = -1;
+ finish_note(v);
+ }
+ }
+}
+
+static void note_off(MidiEvent *e)
+{
+ int i=voices, v;
+ while (i--)
+ if (voice[i].status==VOICE_ON &&
+ voice[i].channel==e->channel &&
+ voice[i].note==e->a)
+ {
+ if (channel[e->channel].sustain)
+ {
+ voice[i].status=VOICE_SUSTAINED;
+
+ if ( (v=voice[i].clone_voice) >= 0)
+ {
+ if (voice[v].status == VOICE_ON)
+ voice[v].status=VOICE_SUSTAINED;
+ }
+
+ ctl->note(i);
+ }
+ else
+ finish_note(i);
+ return;
+ }
+}
+
+/* Process the All Notes Off event */
+static void all_notes_off(int c)
+{
+ int i=voices;
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c);
+ while (i--)
+ if (voice[i].status==VOICE_ON &&
+ voice[i].channel==c)
+ {
+ if (channel[c].sustain)
+ {
+ voice[i].status=VOICE_SUSTAINED;
+ ctl->note(i);
+ }
+ else
+ finish_note(i);
+ }
+}
+
+/* Process the All Sounds Off event */
+static void all_sounds_off(int c)
+{
+ int i=voices;
+ while (i--)
+ if (voice[i].channel==c &&
+ voice[i].status != VOICE_FREE &&
+ voice[i].status != VOICE_DIE)
+ {
+ kill_note(i);
+ }
+}
+
+static void adjust_pressure(MidiEvent *e)
+{
+ int i=voices;
+ while (i--)
+ if (voice[i].status==VOICE_ON &&
+ voice[i].channel==e->channel &&
+ voice[i].note==e->a)
+ {
+ voice[i].velocity=e->b;
+ recompute_amp(i);
+ apply_envelope_to_amp(i);
+ return;
+ }
+}
+
+static void adjust_panning(int c)
+{
+ int i=voices;
+ while (i--)
+ if ((voice[i].channel==c) &&
+ (voice[i].status==VOICE_ON || voice[i].status==VOICE_SUSTAINED))
+ {
+ if (voice[i].clone_type != NOT_CLONE) continue;
+ voice[i].panning=channel[c].panning;
+ recompute_amp(i);
+ apply_envelope_to_amp(i);
+ }
+}
+
+static void drop_sustain(int c)
+{
+ int i=voices;
+ while (i--)
+ if (voice[i].status==VOICE_SUSTAINED && voice[i].channel==c)
+ finish_note(i);
+}
+
+static void adjust_pitchbend(int c)
+{
+ int i=voices;
+ while (i--)
+ if (voice[i].status!=VOICE_FREE && voice[i].channel==c)
+ {
+ recompute_freq(i);
+ }
+}
+
+static void adjust_volume(int c)
+{
+ int i=voices;
+ while (i--)
+ if (voice[i].channel==c &&
+ (voice[i].status==VOICE_ON || voice[i].status==VOICE_SUSTAINED))
+ {
+ recompute_amp(i);
+ apply_envelope_to_amp(i);
+ }
+}
+
+static void seek_forward(int32 until_time)
+{
+ reset_voices();
+ while (current_event->time < until_time)
+ {
+ switch(current_event->type)
+ {
+ /* All notes stay off. Just handle the parameter changes. */
+
+ case ME_PITCH_SENS:
+ channel[current_event->channel].pitchsens=
+ current_event->a;
+ channel[current_event->channel].pitchfactor=0;
+ break;
+
+ case ME_PITCHWHEEL:
+ channel[current_event->channel].pitchbend=
+ current_event->a + current_event->b * 128;
+ channel[current_event->channel].pitchfactor=0;
+ break;
+
+ case ME_MAINVOLUME:
+ channel[current_event->channel].volume=current_event->a;
+ break;
+
+ case ME_MASTERVOLUME:
+ adjust_master_volume(current_event->a + (current_event->b <<7));
+ break;
+
+ case ME_PAN:
+ channel[current_event->channel].panning=current_event->a;
+ break;
+
+ case ME_EXPRESSION:
+ channel[current_event->channel].expression=current_event->a;
+ break;
+
+ case ME_PROGRAM:
+ /* if (ISDRUMCHANNEL(current_event->channel)) */
+ if (channel[current_event->channel].kit)
+ /* Change drum set */
+ channel[current_event->channel].bank=current_event->a;
+ else
+ channel[current_event->channel].program=current_event->a;
+ break;
+
+ case ME_SUSTAIN:
+ channel[current_event->channel].sustain=current_event->a;
+ break;
+
+
+ case ME_REVERBERATION:
+ channel[current_event->channel].reverberation=current_event->a;
+ break;
+
+ case ME_CHORUSDEPTH:
+ channel[current_event->channel].chorusdepth=current_event->a;
+ break;
+
+ case ME_HARMONICCONTENT:
+ channel[current_event->channel].harmoniccontent=current_event->a;
+ break;
+
+ case ME_RELEASETIME:
+ channel[current_event->channel].releasetime=current_event->a;
+ break;
+
+ case ME_ATTACKTIME:
+ channel[current_event->channel].attacktime=current_event->a;
+ break;
+
+ case ME_BRIGHTNESS:
+ channel[current_event->channel].brightness=current_event->a;
+ break;
+
+ case ME_TONE_KIT:
+ if (current_event->a==SFX_BANKTYPE)
+ {
+ channel[current_event->channel].sfx=SFXBANK;
+ channel[current_event->channel].kit=0;
+ }
+ else
+ {
+ channel[current_event->channel].sfx=0;
+ channel[current_event->channel].kit=current_event->a;
+ }
+ break;
+
+
+ case ME_RESET_CONTROLLERS:
+ reset_controllers(current_event->channel);
+ break;
+
+ case ME_TONE_BANK:
+ channel[current_event->channel].bank=current_event->a;
+ break;
+
+ case ME_EOT:
+ current_sample=current_event->time;
+ return;
+ }
+ current_event++;
+ }
+ /*current_sample=current_event->time;*/
+ if (current_event != event_list)
+ current_event--;
+ current_sample=until_time;
+}
+
+static void skip_to(int32 until_time)
+{
+ if (current_sample > until_time)
+ current_sample=0;
+
+ reset_midi();
+ buffered_count=0;
+ buffer_pointer=common_buffer;
+ current_event=event_list;
+
+ if (until_time)
+ seek_forward(until_time);
+ ctl->reset();
+}
+
+static int apply_controls(void)
+{
+ int rc, i, did_skip=0;
+ int32 val;
+ /* ASCII renditions of CD player pictograms indicate approximate effect */
+ do
+ switch(rc=ctl->read(&val))
+ {
+ case RC_QUIT: /* [] */
+ case RC_LOAD_FILE:
+ case RC_NEXT: /* >>| */
+ case RC_REALLY_PREVIOUS: /* |<< */
+ return rc;
+
+ case RC_CHANGE_VOLUME:
+ if (val>0 || amplification > -val)
+ amplification += val;
+ else
+ amplification=0;
+ if (amplification > MAX_AMPLIFICATION)
+ amplification=MAX_AMPLIFICATION;
+ adjust_amplification();
+ for (i=0; i<voices; i++)
+ if (voice[i].status != VOICE_FREE)
+ {
+ recompute_amp(i);
+ apply_envelope_to_amp(i);
+ }
+ ctl->master_volume(amplification);
+ break;
+
+ case RC_PREVIOUS: /* |<< */
+ if (current_sample < 2*play_mode->rate)
+ return RC_REALLY_PREVIOUS;
+ return RC_RESTART;
+
+ case RC_RESTART: /* |<< */
+ skip_to(0);
+ did_skip=1;
+ break;
+
+ case RC_JUMP:
+ if (val >= sample_count)
+ return RC_NEXT;
+ skip_to(val);
+ return rc;
+
+ case RC_FORWARD: /* >> */
+ if (val+current_sample >= sample_count)
+ return RC_NEXT;
+ skip_to(val+current_sample);
+ did_skip=1;
+ break;
+
+ case RC_BACK: /* << */
+ if (current_sample > val)
+ skip_to(current_sample-val);
+ else
+ skip_to(0); /* We can't seek to end of previous song. */
+ did_skip=1;
+ break;
+ }
+ while (rc!= RC_NONE);
+
+ /* Advertise the skip so that we stop computing the audio buffer */
+ if (did_skip)
+ return RC_JUMP;
+ else
+ return rc;
+}
+
+static void do_compute_data(uint32 count)
+{
+ int i;
+ if (!count) return; /* (gl) */
+ memset(buffer_pointer, 0, count * num_ochannels * 4);
+ for (i=0; i<voices; i++)
+ {
+ if(voice[i].status != VOICE_FREE)
+ {
+ //printf("mixing voice %d\n", i);
+ if (!voice[i].sample_offset && voice[i].echo_delay_count)
+ {
+ if ((uint32)voice[i].echo_delay_count >= count) voice[i].echo_delay_count -= count;
+ else
+ {
+ mix_voice(buffer_pointer+voice[i].echo_delay_count, i, count-voice[i].echo_delay_count);
+ voice[i].echo_delay_count = 0;
+ }
+ }
+ else mix_voice(buffer_pointer, i, count);
+ }
+ }
+ current_sample += count;
+}
+
+
+/* count=0 means flush remaining buffered data to output device, then
+ flush the device itself */
+static int compute_data(void *stream, int32 count)
+{
+ int rc, channels;
+
+ if ( play_mode->encoding & PE_MONO )
+ channels = 1;
+ else
+ channels = num_ochannels;
+
+ if (!count)
+ {
+ if (buffered_count)
+ s32tobuf(stream, common_buffer, channels*buffered_count);
+ buffer_pointer=common_buffer;
+ buffered_count=0;
+ return RC_NONE;
+ }
+
+ while ((count+buffered_count) >= AUDIO_BUFFER_SIZE)
+ {
+ do_compute_data(AUDIO_BUFFER_SIZE-buffered_count);
+ count -= AUDIO_BUFFER_SIZE-buffered_count;
+ s32tobuf(stream, common_buffer, channels*AUDIO_BUFFER_SIZE);
+ buffer_pointer=common_buffer;
+ buffered_count=0;
+
+ ctl->current_time(current_sample);
+ if ((rc=apply_controls())!=RC_NONE)
+ return rc;
+ }
+ if (count>0)
+ {
+ do_compute_data(count);
+ buffered_count += count;
+ buffer_pointer += count * channels;
+ }
+ return RC_NONE;
+}
+
+int Timidity_PlaySome(void *stream, int samples)
+{
+ //printf("Timidity_PlaySome()\n");
+ int rc = RC_NONE;
+ int32 end_sample;
+
+ if ( ! midi_playing ) {
+ return RC_NONE;
+ }
+ end_sample = current_sample+samples;
+ while ( current_sample < end_sample ) {
+ /* Handle all events that should happen at this time */
+ while (current_event->time <= current_sample) {
+ switch(current_event->type) {
+
+ /* Effects affecting a single note */
+
+ case ME_NOTEON:
+ current_event->a += channel[current_event->channel].transpose;
+ if (!(current_event->b)) /* Velocity 0? */
+ note_off(current_event);
+ else
+ note_on(current_event);
+ break;
+
+ case ME_NOTEOFF:
+ current_event->a += channel[current_event->channel].transpose;
+ note_off(current_event);
+ break;
+
+ case ME_KEYPRESSURE:
+ adjust_pressure(current_event);
+ break;
+
+ /* Effects affecting a single channel */
+
+ case ME_PITCH_SENS:
+ channel[current_event->channel].pitchsens=current_event->a;
+ channel[current_event->channel].pitchfactor=0;
+ break;
+
+ case ME_PITCHWHEEL:
+ channel[current_event->channel].pitchbend=
+ current_event->a + current_event->b * 128;
+ channel[current_event->channel].pitchfactor=0;
+ /* Adjust pitch for notes already playing */
+ adjust_pitchbend(current_event->channel);
+ ctl->pitch_bend(current_event->channel,
+ channel[current_event->channel].pitchbend);
+ break;
+
+ case ME_MAINVOLUME:
+ channel[current_event->channel].volume=current_event->a;
+ adjust_volume(current_event->channel);
+ ctl->volume(current_event->channel, current_event->a);
+ break;
+
+ case ME_MASTERVOLUME:
+ adjust_master_volume(current_event->a + (current_event->b <<7));
+ break;
+
+ case ME_REVERBERATION:
+ channel[current_event->channel].reverberation=current_event->a;
+ break;
+
+ case ME_CHORUSDEPTH:
+ channel[current_event->channel].chorusdepth=current_event->a;
+ break;
+
+ case ME_PAN:
+ channel[current_event->channel].panning=current_event->a;
+ if (adjust_panning_immediately)
+ adjust_panning(current_event->channel);
+ ctl->panning(current_event->channel, current_event->a);
+ break;
+
+ case ME_EXPRESSION:
+ channel[current_event->channel].expression=current_event->a;
+ adjust_volume(current_event->channel);
+ ctl->expression(current_event->channel, current_event->a);
+ break;
+
+ case ME_PROGRAM:
+ /* if (ISDRUMCHANNEL(current_event->channel)) { */
+ if (channel[current_event->channel].kit) {
+ /* Change drum set */
+ channel[current_event->channel].bank=current_event->a;
+ }
+ else
+ {
+ channel[current_event->channel].program=current_event->a;
+ }
+ ctl->program(current_event->channel, current_event->a);
+ break;
+
+ case ME_SUSTAIN:
+ channel[current_event->channel].sustain=current_event->a;
+ if (!current_event->a)
+ drop_sustain(current_event->channel);
+ ctl->sustain(current_event->channel, current_event->a);
+ break;
+
+ case ME_RESET_CONTROLLERS:
+ reset_controllers(current_event->channel);
+ redraw_controllers(current_event->channel);
+ break;
+
+ case ME_ALL_NOTES_OFF:
+ all_notes_off(current_event->channel);
+ break;
+
+ case ME_ALL_SOUNDS_OFF:
+ all_sounds_off(current_event->channel);
+ break;
+
+ case ME_HARMONICCONTENT:
+ channel[current_event->channel].harmoniccontent=current_event->a;
+ break;
+
+ case ME_RELEASETIME:
+ channel[current_event->channel].releasetime=current_event->a;
+ break;
+
+ case ME_ATTACKTIME:
+ channel[current_event->channel].attacktime=current_event->a;
+ break;
+
+ case ME_BRIGHTNESS:
+ channel[current_event->channel].brightness=current_event->a;
+ break;
+
+ case ME_TONE_BANK:
+ channel[current_event->channel].bank=current_event->a;
+ break;
+
+
+ case ME_TONE_KIT:
+ if (current_event->a==SFX_BANKTYPE)
+ {
+ channel[current_event->channel].sfx=SFXBANK;
+ channel[current_event->channel].kit=0;
+ }
+ else
+ {
+ channel[current_event->channel].sfx=0;
+ channel[current_event->channel].kit=current_event->a;
+ }
+ break;
+
+ case ME_EOT:
+ /* Give the last notes a couple of seconds to decay */
+ ctl->cmsg(CMSG_INFO, VERB_VERBOSE,
+ "Playing time: ~%d seconds", current_sample/play_mode->rate+2);
+ ctl->cmsg(CMSG_INFO, VERB_VERBOSE,
+ "Notes cut: %d", cut_notes);
+ ctl->cmsg(CMSG_INFO, VERB_VERBOSE,
+ "Notes lost totally: %d", lost_notes);
+ midi_playing = 0;
+ return RC_TUNE_END;
+ }
+ current_event++;
+ }
+ if (current_event->time > end_sample)
+ rc=compute_data(stream, end_sample-current_sample);
+ else
+ rc=compute_data(stream, current_event->time-current_sample);
+ ctl->refresh();
+ if ( (rc!=RC_NONE) && (rc!=RC_JUMP))
+ break;
+ }
+ return rc;
+}
+
+
+void Timidity_SetVolume(int volume)
+{
+ int i;
+ if (volume > MAX_AMPLIFICATION)
+ amplification=MAX_AMPLIFICATION;
+ else
+ if (volume < 0)
+ amplification=0;
+ else
+ amplification=volume;
+ adjust_amplification();
+ for (i=0; i<voices; i++)
+ if (voice[i].status != VOICE_FREE)
+ {
+ recompute_amp(i);
+ apply_envelope_to_amp(i);
+ }
+ ctl->master_volume(amplification);
+}
+
+MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw, int freerw)
+{
+ MidiSong *song;
+ int32 events;
+
+ /* Allocate memory for the song */
+ song = (MidiSong *)safe_malloc(sizeof(*song));
+ memset(song, 0, sizeof(*song));
+
+ strcpy(midi_name, "SDLrwops source");
+
+ song->events = read_midi_file(rw, &events, &song->samples);
+ if (freerw) {
+ SDL_RWclose(rw);
+ }
+
+ /* Make sure everything is okay */
+ if (!song->events) {
+ free(song);
+ song = NULL;
+ }
+ return(song);
+}
+
+void Timidity_Start(MidiSong *song)
+{
+ load_missing_instruments();
+ adjust_amplification();
+ sample_count = song->samples;
+ event_list = song->events;
+ lost_notes=cut_notes=0;
+ //printf("Timidity: playing song with %d samples\n", sample_count);
+
+ skip_to(0);
+ midi_playing = 1;
+}
+
+int Timidity_Active(void)
+{
+ return(midi_playing);
+}
+
+void Timidity_Stop(void)
+{
+ midi_playing = 0;
+}
+
+void Timidity_FreeSong(MidiSong *song)
+{
+ if (free_instruments_afterwards)
+ free_instruments();
+
+ free(song->events);
+ free(song);
+}
+
+void Timidity_Close(void)
+{
+ if (resample_buffer) {
+ free(resample_buffer);
+ resample_buffer=NULL;
+ }
+ if (common_buffer) {
+ free(common_buffer);
+ common_buffer=NULL;
+ }
+ free_instruments();
+ free_pathlist();
+}
+
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/playmidi.h b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.h
new file mode 100644
index 0000000000..2a32d7ebe2
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.h
@@ -0,0 +1,160 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+typedef struct {
+ int32 time;
+ uint8 channel, type, a, b;
+} MidiEvent;
+
+/* 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_TONE_KIT 17
+#define ME_MASTERVOLUME 18
+#define ME_CHANNEL_PRESSURE 19
+
+#define ME_HARMONICCONTENT 71
+#define ME_RELEASETIME 72
+#define ME_ATTACKTIME 73
+#define ME_BRIGHTNESS 74
+
+#define ME_REVERBERATION 91
+#define ME_CHORUSDEPTH 93
+
+#define ME_EOT 99
+
+
+#define SFX_BANKTYPE 64
+
+typedef struct {
+ int
+ bank, program, volume, sustain, panning, pitchbend, expression,
+ mono, /* one note only on this channel -- not implemented yet */
+ /* new stuff */
+ variationbank, reverberation, chorusdepth, harmoniccontent,
+ releasetime, attacktime, brightness, kit, sfx,
+ /* end new */
+ pitchsens;
+ FLOAT_T
+ pitchfactor; /* precomputed pitch bend factor to save some fdiv's */
+ char transpose;
+ char *name;
+} Channel;
+
+/* Causes the instrument's default panning to be used. */
+#define NO_PANNING -1
+/* envelope points */
+#define MAXPOINT 7
+
+typedef struct {
+ uint8
+ status, channel, note, velocity, clone_type;
+ Sample *sample;
+ Sample *left_sample;
+ Sample *right_sample;
+ int32 clone_voice;
+ int32
+ orig_frequency, frequency,
+ sample_offset, loop_start, loop_end;
+ int32
+ envelope_volume, modulation_volume;
+ int32
+ envelope_target, modulation_target;
+ int32
+ tremolo_sweep, tremolo_sweep_position, tremolo_phase,
+ lfo_sweep, lfo_sweep_position, lfo_phase,
+ vibrato_sweep, vibrato_sweep_position, vibrato_depth, vibrato_delay,
+ starttime, echo_delay_count;
+ int32
+ echo_delay,
+ sample_increment,
+ envelope_increment,
+ modulation_increment,
+ tremolo_phase_increment,
+ lfo_phase_increment;
+
+ final_volume_t left_mix, right_mix, lr_mix, rr_mix, ce_mix, lfe_mix;
+
+ FLOAT_T
+ left_amp, right_amp, lr_amp, rr_amp, ce_amp, lfe_amp,
+ volume, tremolo_volume, lfo_volume;
+ int32
+ vibrato_sample_increment[VIBRATO_SAMPLE_INCREMENTS];
+ int32
+ envelope_rate[MAXPOINT], envelope_offset[MAXPOINT];
+ int32
+ vibrato_phase, vibrato_control_ratio, vibrato_control_counter,
+ envelope_stage, modulation_stage, control_counter,
+ modulation_delay, modulation_counter, panning, panned;
+} Voice;
+
+/* 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 */
+
+/* Envelope stages: */
+#define ATTACK 0
+#define HOLD 1
+#define DECAY 2
+#define RELEASE 3
+#define RELEASEB 4
+#define RELEASEC 5
+#define DELAY 6
+
+extern Channel channel[16];
+extern Voice voice[MAX_VOICES];
+extern signed char drumvolume[MAXCHAN][MAXNOTE];
+extern signed char drumpanpot[MAXCHAN][MAXNOTE];
+extern signed char drumreverberation[MAXCHAN][MAXNOTE];
+extern signed char drumchorusdepth[MAXCHAN][MAXNOTE];
+
+extern int32 control_ratio, amp_with_poly, amplification;
+extern int32 drumchannels;
+extern int adjust_panning_immediately;
+extern int voices;
+
+#define ISDRUMCHANNEL(c) ((drumchannels & (1<<(c))))
+
+extern int GM_System_On;
+extern int XG_System_On;
+extern int GS_System_On;
+
+extern int XG_System_reverb_type;
+extern int XG_System_chorus_type;
+extern int XG_System_variation_type;
+
+extern int play_midi(MidiEvent *el, int32 events, int32 samples);
+extern int play_midi_file(const char *fn);
+extern void dumb_pass_playing_list(int number_of_files, char *list_of_files[]);
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/readmidi.c b/apps/plugins/sdl/SDL_mixer/timidity/readmidi.c
new file mode 100644
index 0000000000..afd3f9f571
--- /dev/null
+++ b/apps/plugins/sdl/SDL_mixer/timidity/readmidi.c
@@ -0,0 +1,1065 @@
+/*
+ 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 Perl Artistic License, available in COPYING.
+ */
+
+#include <SDL_rwops.h>
+
+#include "config.h"
+#include "common.h"
+#include "instrum.h"
+#include "playmidi.h"
+#include "readmidi.h"
+#include "output.h"
+#include "ctrlmode.h"
+
+int32 quietchannels=0;
+
+static int midi_port_number;
+char midi_name[FILENAME_MAX+1];
+
+static int track_info, curr_track, curr_title_track;
+static char title[128];
+
+#if MAXCHAN <= 16
+#define MERGE_CHANNEL_PORT(ch) ((int)(ch))
+#else
+#define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4))
+#endif
+
+/* to avoid some unnecessary parameter passing */
+static MidiEventList *evlist;
+static int32 event_count;
+static SDL_RWops *rw;
+static int32 at;
+
+/* These would both fit into 32 bits, but they are often added in
+ large multiples, so it's simpler to have two roomy ints */
+static int32 sample_increment, sample_correction; /*samples per MIDI delta-t*/
+
+/* Computes how many (fractional) samples one MIDI delta-time unit contains */
+static void compute_sample_increment(int32 tempo, int32 divisions)
+{
+ double a;
+ a = (double) (tempo) * (double) (play_mode->rate) * (65536.0/1000000.0) /
+ (double)(divisions);
+
+ sample_correction = (int32)(a) & 0xFFFF;
+ sample_increment = (int32)(a) >> 16;
+
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Samples per delta-t: %d (correction %d)",
+ sample_increment, sample_correction);
+}
+
+/* Read variable-length number (7 bits per byte, MSB first) */
+static int32 getvl(void)
+{
+ int32 l=0;
+ uint8 c;
+ for (;;)
+ {
+ SDL_RWread(rw,&c,1,1);
+ l += (c & 0x7f);
+ if (!(c & 0x80)) return l;
+ l<<=7;
+ }
+}
+
+
+static int sysex(uint32 len, uint8 *syschan, uint8 *sysa, uint8 *sysb, SDL_RWops *rw)
+{
+ unsigned char *s=(unsigned char *)safe_malloc(len);
+ int id, model, ch, port, adhi, adlo, cd, dta, dtb, dtc;
+ if (len != (uint32)SDL_RWread(rw, s, 1, len))
+ {
+ free(s);
+ return 0;
+ }
+ if (len<5) { free(s); return 0; }
+ if (curr_track == curr_title_track && track_info > 1) title[0] = '\0';
+ id=s[0]; port=s[1]; model=s[2]; adhi=s[3]; adlo=s[4];
+ if (id==0x7e && port==0x7f && model==0x09 && adhi==0x01)
+ {
+ ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "GM System On", len);
+ GM_System_On=1;
+ free(s);
+ return 0;
+ }
+ ch = adlo & 0x0f;
+ *syschan=(uint8)ch;
+ if (id==0x7f && len==7 && port==0x7f && model==0x04 && adhi==0x01)
+ {
+ ctl->cmsg(CMSG_TEXT, VERB_DEBUG, "Master Volume %d", s[4]+(s[5]<<7));
+ *sysa = s[4];
+ *sysb = s[5];
+ free(s);
+ return ME_MASTERVOLUME;
+ /** return s[4]+(s[5]<<7); **/
+ }
+ if (len<8) { free(s); return 0; }
+ port &=0x0f;
+ ch = (adlo & 0x0f) | ((port & 0x03) << 4);
+ *syschan=(uint8)ch;
+ cd=s[5]; dta=s[6];
+ if (len >= 8) dtb=s[7];
+ else dtb=-1;
+ if (len >= 9) dtc=s[8];
+ else dtc=-1;
+ free(s);
+ if (id==0x43 && model==0x4c)
+ {
+ if (!adhi && !adlo && cd==0x7e && !dta)
+ {
+ ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "XG System On", len);
+ XG_System_On=1;
+ #ifdef tplus
+ vol_table = xg_vol_table;
+ #endif
+ }
+ else if (adhi == 2 && adlo == 1)
+ {
+ if (dtb==8) dtb=3;
+ switch (cd)
+ {
+ case 0x00:
+ XG_System_reverb_type=(dta<<3)+dtb;
+ break;
+ case 0x20:
+ XG_System_chorus_type=((dta-64)<<3)+dtb;
+ break;
+ case 0x40:
+ XG_System_variation_type=dta;
+ break;
+ case 0x5a:
+ /* dta==0 Insertion; dta==1 System */
+ break;
+ default: break;
+ }
+ }
+ else if (adhi == 8 && cd <= 40)
+ {
+ *sysa = dta & 0x7f;
+ switch (cd)
+ {
+ case 0x01: /* bank select MSB */
+ return ME_TONE_KIT;
+ break;
+ case 0x02: /* bank select LSB */
+ return ME_TONE_BANK;
+ break;
+ case 0x03: /* program number */
+ /** MIDIEVENT(d->at, ME_PROGRAM, lastchan, a, 0); **/
+ return ME_PROGRAM;
+ break;
+ case 0x08: /* */
+ /* d->channel[adlo&0x0f].transpose = (char)(dta-64); */
+ channel[ch].transpose = (char)(dta-64);
+ ctl->cmsg(CMSG_TEXT, VERB_DEBUG, "transpose channel %d by %d",
+ (adlo&0x0f)+1, dta-64);
+ break;
+ case 0x0b: /* volume */
+ return ME_MAINVOLUME;
+ break;
+ case 0x0e: /* pan */
+ return ME_PAN;
+ break;
+ case 0x12: /* chorus send */
+ return ME_CHORUSDEPTH;
+ break;
+ case 0x13: /* reverb send */
+ return ME_REVERBERATION;
+ break;
+ case 0x14: /* variation send */
+ break;
+ case 0x18: /* filter cutoff */
+ return ME_BRIGHTNESS;
+ break;
+ case 0x19: /* filter resonance */
+ return ME_HARMONICCONTENT;
+ break;
+ default: break;
+ }
+ }
+ return 0;
+ }
+ else if (id==0x41 && model==0x42 && adhi==0x12 && adlo==0x40)
+ {
+ if (dtc<0) return 0;
+ if (!cd && dta==0x7f && !dtb && dtc==0x41)
+ {
+ ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "GS System On", len);
+ GS_System_On=1;
+ #ifdef tplus
+ vol_table = gs_vol_table;
+ #endif
+ }
+ else if (dta==0x15 && (cd&0xf0)==0x10)
+ {
+ int chan=cd&0x0f;
+ if (!chan) chan=9;
+ else if (chan<10) chan--;
+ chan = MERGE_CHANNEL_PORT(chan);
+ channel[chan].kit=dtb;
+ }
+ else if (cd==0x01) switch(dta)
+ {
+ case 0x30:
+ switch(dtb)
+ {
+ case 0: XG_System_reverb_type=16+0; break;
+ case 1: XG_System_reverb_type=16+1; break;
+ case 2: XG_System_reverb_type=16+2; break;
+ case 3: XG_System_reverb_type= 8+0; break;
+ case 4: XG_System_reverb_type= 8+1; break;
+ case 5: XG_System_reverb_type=32+0; break;
+ case 6: XG_System_reverb_type=8*17; break;
+ case 7: XG_System_reverb_type=8*18; break;
+ }
+ break;
+ case 0x38:
+ switch(dtb)
+ {
+ case 0: XG_System_chorus_type= 8+0; break;
+ case 1: XG_System_chorus_type= 8+1; break;
+ case 2: XG_System_chorus_type= 8+2; break;
+ case 3: XG_System_chorus_type= 8+4; break;
+ case 4: XG_System_chorus_type= -1; break;
+ case 5: XG_System_chorus_type= 8*3; break;
+ case 6: XG_System_chorus_type= -1; break;
+ case 7: XG_System_chorus_type= -1; break;
+ }
+ break;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+/* Print a string from the file, followed by a newline. Any non-ASCII
+ or unprintable characters will be converted to periods. */
+static int dumpstring(int32 len, const char *label)
+{
+ signed char *s=safe_malloc(len+1);
+ if (len != (int32)SDL_RWread(rw, s, 1, len))
+ {
+ free(s);
+ return -1;
+ }
+ s[len]='\0';
+ while (len--)
+ {
+ if (s[len]<32)
+ s[len]='.';
+ }
+ ctl->cmsg(CMSG_TEXT, VERB_VERBOSE, "%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(void)
+{
+ static uint8 laststatus, lastchan;
+ static uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */
+ uint8 me, type, a,b,c;
+ int32 len;
+ MidiEventList *new;
+
+ for (;;)
+ {
+ at+=getvl();
+ if (SDL_RWread(rw,&me,1,1)!=1)
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: read_midi_event: %s",
+ current_filename, strerror(errno));
+ return 0;
+ }
+
+ if(me==0xF0 || me == 0xF7) /* SysEx event */
+ {
+ int32 sret;
+ uint8 sysa=0, sysb=0, syschan=0;
+
+ len=getvl();
+ sret=sysex(len, &syschan, &sysa, &sysb, rw);
+ if (sret)
+ {
+ MIDIEVENT(at, sret, syschan, sysa, sysb);
+ }
+ }
+ else if(me==0xFF) /* Meta event */
+ {
+ SDL_RWread(rw,&type,1,1);
+ len=getvl();
+ if (type>0 && type<16)
+ {
+ static char *label[]={
+ "Text event: ", "Text: ", "Copyright: ", "Track name: ",
+ "Instrument: ", "Lyric: ", "Marker: ", "Cue point: "};
+ dumpstring(len, label[(type>7) ? 0 : type]);
+ }
+ else
+ switch(type)
+ {
+
+ case 0x21: /* MIDI port number */
+ if(len == 1)
+ {
+ SDL_RWread(rw,&midi_port_number,1,1);
+ if(midi_port_number == EOF)
+ {
+ ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
+ "Warning: \"%s\": Short midi file.",
+ midi_name);
+ return 0;
+ }
+ midi_port_number &= 0x0f;
+ if (midi_port_number)
+ ctl->cmsg(CMSG_INFO, VERB_VERBOSE,
+ "(MIDI port number %d)", midi_port_number);
+ midi_port_number &= 0x03;
+ }
+ else SDL_RWseek(rw, len, RW_SEEK_CUR);
+ break;
+
+ case 0x2F: /* End of Track */
+ return MAGIC_EOT;
+
+ case 0x51: /* Tempo */
+ SDL_RWread(rw,&a,1,1); SDL_RWread(rw,&b,1,1); SDL_RWread(rw,&c,1,1);
+ MIDIEVENT(at, ME_TEMPO, c, a, b);
+
+ default:
+ ctl->cmsg(CMSG_INFO, VERB_DEBUG,
+ "(Meta event type 0x%02x, length %ld)", type, len);
+ SDL_RWseek(rw, len, RW_SEEK_CUR);
+ break;
+ }
+ }
+ else
+ {
+ a=me;
+ if (a & 0x80) /* status byte */
+ {
+ lastchan=a & 0x0F;
+ laststatus=(a>>4) & 0x07;
+ SDL_RWread(rw,&a, 1,1);
+ a &= 0x7F;
+ }
+ switch(laststatus)
+ {
+ case 0: /* Note off */
+ SDL_RWread(rw,&b, 1,1);
+ b &= 0x7F;
+ MIDIEVENT(at, ME_NOTEOFF, lastchan, a,b);
+
+ case 1: /* Note on */
+ SDL_RWread(rw,&b, 1,1);
+ b &= 0x7F;
+ if (curr_track == curr_title_track && track_info > 1) title[0] = '\0';
+ MIDIEVENT(at, ME_NOTEON, lastchan, a,b);
+
+
+ case 2: /* Key Pressure */
+ SDL_RWread(rw,&b, 1,1);
+ b &= 0x7F;
+ MIDIEVENT(at, ME_KEYPRESSURE, lastchan, a, b);
+
+ case 3: /* Control change */
+ SDL_RWread(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 71: control=ME_HARMONICCONTENT; break;
+ case 72: control=ME_RELEASETIME; break;
+ case 73: control=ME_ATTACKTIME; break;
+ case 74: control=ME_BRIGHTNESS; break;
+ case 91: control=ME_REVERBERATION; break;
+ case 93: control=ME_CHORUSDEPTH; break;
+
+ case 120: control=ME_ALL_SOUNDS_OFF; break;
+ case 121: control=ME_RESET_CONTROLLERS; break;
+ case 123: control=ME_ALL_NOTES_OFF; break;