1
0
Fork 0
forked from len0rd/rockbox

Port of Duke Nukem 3D

This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL
for Rockbox.

Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
This commit is contained in:
Franklin Wei 2017-01-21 15:18:31 -05:00
parent 01c6dcf6c7
commit a855d62025
994 changed files with 336924 additions and 15 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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[];

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -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[]);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
/*
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 {
MidiEvent event;
void *next;
} MidiEventList;
extern int32 quietchannels;
extern MidiEvent *read_midi_file(SDL_RWops *mrw, int32 *count, int32 *sp);
extern char midi_name[FILENAME_MAX+1];

View file

@ -0,0 +1,730 @@
/*
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"
#ifdef LINEAR_INTERPOLATION
# if defined(LOOKUP_HACK) && defined(LOOKUP_INTERPOLATION)
# define RESAMPLATION \
v1=src[ofs>>FRACTION_BITS];\
v2=src[(ofs>>FRACTION_BITS)+1];\
*dest++ = (resample_t)(v1 + (iplookup[(((v2-v1)<<5) & 0x03FE0) | \
((ofs & FRACTION_MASK) >> (FRACTION_BITS-5))]));
# else
# define RESAMPLATION \
v1=src[ofs>>FRACTION_BITS];\
v2=src[(ofs>>FRACTION_BITS)+1];\
*dest++ = (resample_t)(v1 + (((v2-v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
# endif
# define INTERPVARS sample_t v1, v2
#else
/* Earplugs recommended for maximum listening enjoyment */
# define RESAMPLATION *dest++ = src[ofs>>FRACTION_BITS];
# define INTERPVARS
#endif
#define FINALINTERP if (ofs == le) *dest++=src[ofs>>FRACTION_BITS];
/* So it isn't interpolation. At least it's final. */
extern resample_t *resample_buffer;
/*************** resampling with fixed increment *****************/
static resample_t *rs_plain(int v, int32 *countptr)
{
/* Play sample until end, then free the voice. */
INTERPVARS;
Voice
*vp=&voice[v];
resample_t
*dest=resample_buffer;
sample_t
*src=vp->sample->data;
int32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->data_length,
count=*countptr;
#ifdef PRECALC_LOOPS
int32 i, j;
if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
/* Precalc how many times we should go through the loop.
NOTE: Assumes that incr > 0 and that ofs <= le */
i = (le - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
for(j = 0; j < i; j++)
{
RESAMPLATION;
ofs += incr;
}
if (ofs >= le)
{
FINALINTERP;
vp->status=VOICE_FREE;
ctl->note(v);
*countptr-=count+1;
}
#else /* PRECALC_LOOPS */
while (count--)
{
RESAMPLATION;
ofs += incr;
if (ofs >= le)
{
FINALINTERP;
vp->status=VOICE_FREE;
ctl->note(v);
*countptr-=count+1;
break;
}
}
#endif /* PRECALC_LOOPS */
vp->sample_offset=ofs; /* Update offset */
return resample_buffer;
}
static resample_t *rs_loop(Voice *vp, int32 count)
{
/* Play sample until end-of-loop, skip back and continue. */
INTERPVARS;
int32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ll=le - vp->sample->loop_start;
resample_t
*dest=resample_buffer;
sample_t
*src=vp->sample->data;
#ifdef PRECALC_LOOPS
int32 i;
if (ofs < 0 || le < 0) return resample_buffer;
while (count)
{
if (ofs >= le)
/* NOTE: Assumes that ll > incr and that incr > 0. */
ofs -= ll;
/* Precalc how many times we should go through the loop */
i = (le - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
if (i > 0)
while (i--)
{
RESAMPLATION;
ofs += incr;
}
}
#else
while (count--)
{
RESAMPLATION;
ofs += incr;
if (ofs>=le)
ofs -= ll; /* Hopefully the loop is longer than an increment. */
}
#endif
vp->sample_offset=ofs; /* Update offset */
return resample_buffer;
}
static resample_t *rs_bidir(Voice *vp, int32 count)
{
INTERPVARS;
int32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ls=vp->sample->loop_start;
resample_t
*dest=resample_buffer;
sample_t
*src=vp->sample->data;
#ifdef PRECALC_LOOPS
int32
le2 = le<<1,
ls2 = ls<<1,
i;
/* Play normally until inside the loop region */
if (ofs <= ls)
{
/* NOTE: Assumes that incr > 0, which is NOT always the case
when doing bidirectional looping. I have yet to see a case
where both ofs <= ls AND incr < 0, however. */
i = (ls - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
while (i--)
{
RESAMPLATION;
ofs += incr;
}
}
/* Then do the bidirectional looping */
while(count)
{
/* Precalc how many times we should go through the loop */
i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
if (i > count)
{
i = count;
count = 0;
}
else count -= i;
while (i--)
{
RESAMPLATION;
ofs += incr;
}
if (ofs>=le)
{
/* fold the overshoot back in */
ofs = le2 - ofs;
incr *= -1;
}
else if (ofs <= ls)
{
ofs = ls2 - ofs;
incr *= -1;
}
}
#else /* PRECALC_LOOPS */
/* Play normally until inside the loop region */
if (ofs < ls)
{
while (count--)
{
RESAMPLATION;
ofs += incr;
if (ofs>=ls)
break;
}
}
/* Then do the bidirectional looping */
if (count>0)
while (count--)
{
RESAMPLATION;
ofs += incr;
if (ofs>=le)
{
/* fold the overshoot back in */
ofs = le - (ofs - le);
incr = -incr;
}
else if (ofs <= ls)
{
ofs = ls + (ls - ofs);
incr = -incr;
}
}
#endif /* PRECALC_LOOPS */
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return resample_buffer;
}
/*********************** vibrato versions ***************************/
/* We only need to compute one half of the vibrato sine cycle */
static int vib_phase_to_inc_ptr(int phase)
{
if (phase < VIBRATO_SAMPLE_INCREMENTS/2)
return VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
else if (phase >= 3*VIBRATO_SAMPLE_INCREMENTS/2)
return 5*VIBRATO_SAMPLE_INCREMENTS/2-1-phase;
else
return phase-VIBRATO_SAMPLE_INCREMENTS/2;
}
static int32 update_vibrato(Voice *vp, int sign)
{
int32 depth;
int phase, pb;
double a;
if (vp->vibrato_phase++ >= 2*VIBRATO_SAMPLE_INCREMENTS-1)
vp->vibrato_phase=0;
phase=vib_phase_to_inc_ptr(vp->vibrato_phase);
if (vp->vibrato_sample_increment[phase])
{
if (sign)
return -vp->vibrato_sample_increment[phase];
else
return vp->vibrato_sample_increment[phase];
}
/* Need to compute this sample increment. */
depth=vp->sample->vibrato_depth<<7;
if (vp->vibrato_sweep)
{
/* Need to update sweep */
vp->vibrato_sweep_position += vp->vibrato_sweep;
if (vp->vibrato_sweep_position >= (1<<SWEEP_SHIFT))
vp->vibrato_sweep=0;
else
{
/* Adjust depth */
depth *= vp->vibrato_sweep_position;
depth >>= SWEEP_SHIFT;
}
}
a = FSCALE(((double)(vp->sample->sample_rate) *
(double)(vp->frequency)) /
((double)(vp->sample->root_freq) *
(double)(play_mode->rate)),
FRACTION_BITS);
pb=(int)((sine(vp->vibrato_phase *
(SINE_CYCLE_LENGTH/(2*VIBRATO_SAMPLE_INCREMENTS)))
* (double)(depth) * VIBRATO_AMPLITUDE_TUNING));
if (pb<0)
{
pb=-pb;
a /= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
}
else
a *= bend_fine[(pb>>5) & 0xFF] * bend_coarse[pb>>13];
/* If the sweep's over, we can store the newly computed sample_increment */
if (!vp->vibrato_sweep)
vp->vibrato_sample_increment[phase]=(int32) a;
if (sign)
a = -a; /* need to preserve the loop direction */
return (int32) a;
}
static resample_t *rs_vib_plain(int v, int32 *countptr)
{
/* Play sample until end, then free the voice. */
INTERPVARS;
Voice *vp=&voice[v];
resample_t
*dest=resample_buffer;
sample_t
*src=vp->sample->data;
int32
le=vp->sample->data_length,
ofs=vp->sample_offset,
incr=vp->sample_increment,
count=*countptr;
int
cc=vp->vibrato_control_counter;
/* This has never been tested */
if (incr<0) incr = -incr; /* In case we're coming out of a bidir loop */
while (count--)
{
if (!cc--)
{
cc=vp->vibrato_control_ratio;
incr=update_vibrato(vp, 0);
}
RESAMPLATION;
ofs += incr;
if (ofs >= le)
{
FINALINTERP;
vp->status=VOICE_FREE;
ctl->note(v);
*countptr-=count+1;
break;
}
}
vp->vibrato_control_counter=cc;
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return resample_buffer;
}
static resample_t *rs_vib_loop(Voice *vp, int32 count)
{
/* Play sample until end-of-loop, skip back and continue. */
INTERPVARS;
int32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ll=le - vp->sample->loop_start;
resample_t
*dest=resample_buffer;
sample_t
*src=vp->sample->data;
int
cc=vp->vibrato_control_counter;
#ifdef PRECALC_LOOPS
int32 i;
int
vibflag=0;
while (count)
{
/* Hopefully the loop is longer than an increment */
if(ofs >= le)
ofs -= ll;
/* Precalc how many times to go through the loop, taking
the vibrato control ratio into account this time. */
i = (le - ofs) / incr + 1;
if(i > count) i = count;
if(i > cc)
{
i = cc;
vibflag = 1;
}
else cc -= i;
count -= i;
while(i--)
{
RESAMPLATION;
ofs += incr;
}
if(vibflag)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, 0);
vibflag = 0;
}
}
#else /* PRECALC_LOOPS */
while (count--)
{
if (!cc--)
{
cc=vp->vibrato_control_ratio;
incr=update_vibrato(vp, 0);
}
RESAMPLATION;
ofs += incr;
if (ofs>=le)
ofs -= ll; /* Hopefully the loop is longer than an increment. */
}
#endif /* PRECALC_LOOPS */
vp->vibrato_control_counter=cc;
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return resample_buffer;
}
static resample_t *rs_vib_bidir(Voice *vp, int32 count)
{
INTERPVARS;
int32
ofs=vp->sample_offset,
incr=vp->sample_increment,
le=vp->sample->loop_end,
ls=vp->sample->loop_start;
resample_t
*dest=resample_buffer;
sample_t
*src=vp->sample->data;
int
cc=vp->vibrato_control_counter;
#ifdef PRECALC_LOOPS
int32
le2=le<<1,
ls2=ls<<1,
i;
int
vibflag = 0;
/* Play normally until inside the loop region */
while (count && (ofs <= ls))
{
i = (ls - ofs) / incr + 1;
if (i > count) i = count;
if (i > cc)
{
i = cc;
vibflag = 1;
}
else cc -= i;
count -= i;
while (i--)
{
RESAMPLATION;
ofs += incr;
}
if (vibflag)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, 0);
vibflag = 0;
}
}
/* Then do the bidirectional looping */
while (count)
{
/* Precalc how many times we should go through the loop */
i = ((incr > 0 ? le : ls) - ofs) / incr + 1;
if(i > count) i = count;
if(i > cc)
{
i = cc;
vibflag = 1;
}
else cc -= i;
count -= i;
while (i--)
{
RESAMPLATION;
ofs += incr;
}
if (vibflag)
{
cc = vp->vibrato_control_ratio;
incr = update_vibrato(vp, (incr < 0));
vibflag = 0;
}
if (ofs >= le)
{
/* fold the overshoot back in */
ofs = le2 - ofs;
incr *= -1;
}
else if (ofs <= ls)
{
ofs = ls2 - ofs;
incr *= -1;
}
}
#else /* PRECALC_LOOPS */
/* Play normally until inside the loop region */
if (ofs < ls)
{
while (count--)
{
if (!cc--)
{
cc=vp->vibrato_control_ratio;
incr=update_vibrato(vp, 0);
}
RESAMPLATION;
ofs += incr;
if (ofs>=ls)
break;
}
}
/* Then do the bidirectional looping */
if (count>0)
while (count--)
{
if (!cc--)
{
cc=vp->vibrato_control_ratio;
incr=update_vibrato(vp, (incr < 0));
}
RESAMPLATION;
ofs += incr;
if (ofs>=le)
{
/* fold the overshoot back in */
ofs = le - (ofs - le);
incr = -incr;
}
else if (ofs <= ls)
{
ofs = ls + (ls - ofs);
incr = -incr;
}
}
#endif /* PRECALC_LOOPS */
vp->vibrato_control_counter=cc;
vp->sample_increment=incr;
vp->sample_offset=ofs; /* Update offset */
return resample_buffer;
}
resample_t *resample_voice(int v, int32 *countptr)
{
int32 ofs;
uint8 modes;
Voice *vp=&voice[v];
if (!(vp->sample->sample_rate))
{
/* Pre-resampled data -- just update the offset and check if
we're out of data. */
ofs=vp->sample_offset >> FRACTION_BITS; /* Kind of silly to use
FRACTION_BITS here... */
if (*countptr >= (vp->sample->data_length>>FRACTION_BITS) - ofs)
{
/* Note finished. Free the voice. */
vp->status = VOICE_FREE;
ctl->note(v);
/* Let the caller know how much data we had left */
*countptr = (vp->sample->data_length>>FRACTION_BITS) - ofs;
}
else
vp->sample_offset += *countptr << FRACTION_BITS;
return (resample_t *)vp->sample->data+ofs;
}
/* Need to resample. Use the proper function. */
modes=vp->sample->modes;
if (vp->vibrato_control_ratio)
{
if ((modes & MODES_LOOPING) &&
((modes & MODES_ENVELOPE) ||
(vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
{
if (modes & MODES_PINGPONG)
return rs_vib_bidir(vp, *countptr);
else
return rs_vib_loop(vp, *countptr);
}
else
return rs_vib_plain(v, countptr);
}
else
{
if ((modes & MODES_LOOPING) &&
((modes & MODES_ENVELOPE) ||
(vp->status==VOICE_ON || vp->status==VOICE_SUSTAINED)))
{
if (modes & MODES_PINGPONG)
return rs_bidir(vp, *countptr);
else
return rs_loop(vp, *countptr);
}
else
return rs_plain(v, countptr);
}
}
void pre_resample(Sample * sp)
{
double a, xdiff;
int32 incr, ofs, newlen, count;
int16 *src = (int16 *) sp->data;
resample_t *newdata, *dest;
int16 v1, v2, v3, v4, *vptr;
static const char note_name[12][3] =
{
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
};
ctl->cmsg(CMSG_INFO, VERB_NOISY, " * pre-resampling for note %d (%s%d)",
sp->note_to_use,
note_name[sp->note_to_use % 12], (sp->note_to_use & 0x7F) / 12);
a = ((double) (sp->sample_rate) * freq_table[(int) (sp->note_to_use)]) /
((double) (sp->root_freq) * play_mode->rate);
if (a <= 0) return;
newlen = (int32)(sp->data_length / a);
if (newlen < 0 || (newlen >> FRACTION_BITS) > MAX_SAMPLE_SIZE) return;
dest = newdata = safe_malloc(newlen >> (FRACTION_BITS - 1));
count = (newlen >> FRACTION_BITS) - 1;
ofs = incr = (sp->data_length - (1 << FRACTION_BITS)) / count;
if (--count)
*dest++ = src[0];
/* Since we're pre-processing and this doesn't have to be done in
real-time, we go ahead and do the full sliding cubic interpolation. */
while (--count)
{
vptr = src + (ofs >> FRACTION_BITS);
v1 = (vptr == src) ? *vptr : *(vptr - 1);
v2 = *vptr;
v3 = *(vptr + 1);
v4 = *(vptr + 2);
xdiff = FSCALENEG(ofs & FRACTION_MASK, FRACTION_BITS);
*dest++ = (int16)(v2 + (xdiff / 6.0) * (-2 * v1 - 3 * v2 + 6 * v3 - v4 +
xdiff * (3 * (v1 - 2 * v2 + v3) + xdiff * (-v1 + 3 * (v2 - v3) + v4))));
ofs += incr;
}
if (ofs & FRACTION_MASK)
{
v1 = src[ofs >> FRACTION_BITS];
v2 = src[(ofs >> FRACTION_BITS) + 1];
*dest++ = (resample_t)(v1 + (((v2 - v1) * (ofs & FRACTION_MASK)) >> FRACTION_BITS));
}
else
*dest++ = src[ofs >> FRACTION_BITS];
sp->data_length = newlen;
sp->loop_start = (int32)(sp->loop_start / a);
sp->loop_end = (int32)(sp->loop_end / a);
free(sp->data);
sp->data = (sample_t *) newdata;
sp->sample_rate = 0;
}

View file

@ -0,0 +1,10 @@
/*
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 resample_t *resample_voice(int v, int32 *countptr);
extern void pre_resample(Sample *sp);

View file

@ -0,0 +1,19 @@
/*
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"
/* export the playback mode */
#define dpm sdl_play_mode
PlayMode dpm = {
DEFAULT_RATE, PE_16BIT|PE_SIGNED,
"SDL audio"
};

View file

@ -0,0 +1,136 @@
/*
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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "config.h"
#include "common.h"
#include "output.h"
#include "ctrlmode.h"
#include "instrum.h"
#include "playmidi.h"
static void ctl_refresh(void);
static void ctl_total_time(int tt);
static void ctl_master_volume(int mv);
static void ctl_file_name(char *name);
static void ctl_current_time(int ct);
static void ctl_note(int v);
static void ctl_program(int ch, int val);
static void ctl_volume(int channel, int val);
static void ctl_expression(int channel, int val);
static void ctl_panning(int channel, int val);
static void ctl_sustain(int channel, int val);
static void ctl_pitch_bend(int channel, int val);
static void ctl_reset(void);
static int ctl_open(int using_stdin, int using_stdout);
static void ctl_close(void);
static int ctl_read(int32 *valp);
static int cmsg(int type, int verbosity_level, char *fmt, ...);
/**********************************/
/* export the interface functions */
#define ctl sdl_control_mode
ControlMode ctl=
{
"SDL interface", 's',
1,0,0,
ctl_open,NULL, ctl_close, ctl_read, cmsg,
ctl_refresh, ctl_reset, ctl_file_name, ctl_total_time, ctl_current_time,
ctl_note,
ctl_master_volume, ctl_program, ctl_volume,
ctl_expression, ctl_panning, ctl_sustain, ctl_pitch_bend
};
static int ctl_open(int using_stdin, int using_stdout)
{
ctl.opened=1;
return 0;
}
static void ctl_close(void)
{
ctl.opened=0;
}
static int ctl_read(int32 *valp)
{
return RC_NONE;
}
static int cmsg(int type, int verbosity_level, char *fmt, ...)
{
#ifdef GREGS_DEBUG
va_list ap;
int flag_newline = 1;
if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
ctl.verbosity<verbosity_level-1)
return 0;
if (*fmt == '~')
{
flag_newline = 0;
fmt++;
}
va_start(ap, fmt);
if (!ctl.opened)
{
vfprintf(stderr, fmt, ap);
if (flag_newline) fprintf(stderr, "\n");
}
else
{
vfprintf(stderr, fmt, ap);
if (flag_newline) fprintf(stderr, "\n");
}
va_end(ap);
if (!flag_newline) fflush(stderr);
return 0;
#else
va_list ap;
if ((type==CMSG_TEXT || type==CMSG_INFO || type==CMSG_WARNING) &&
ctl.verbosity<verbosity_level)
return 0;
va_start(ap, fmt);
char buf[128];
vsnprintf(buf, 128, fmt, ap);
puts(buf);
SDL_vsnprintf(timidity_error, TIMIDITY_ERROR_SIZE, fmt, ap);
va_end(ap);
return 0;
#endif
}
static void ctl_refresh(void) { }
static void ctl_total_time(int tt) {}
static void ctl_master_volume(int mv) {}
static void ctl_file_name(char *name) {}
static void ctl_current_time(int ct) {}
static void ctl_note(int v) {}
static void ctl_program(int ch, int val) {}
static void ctl_volume(int channel, int val) {}
static void ctl_expression(int channel, int val) {}
static void ctl_panning(int channel, int val) {}
static void ctl_sustain(int channel, int val) {}
static void ctl_pitch_bend(int channel, int val) {}
static void ctl_reset(void) {}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
/*
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.
*/
#ifdef LOOKUP_SINE
extern FLOAT_T sine(int x);
#else
#define sine(x) (sin((2*PI/1024.0) * (x)))
#endif
#define SINE_CYCLE_LENGTH 1024
extern int32 freq_table[];
extern double vol_table[];
extern double expr_table[];
extern double bend_fine[];
extern double bend_coarse[];
extern uint8 *_l2u; /* 13-bit PCM to 8-bit u-law */
extern uint8 _l2u_[]; /* used in LOOKUP_HACK */
#ifdef LOOKUP_HACK
extern int16 _u2l[];
extern int32 *mixup;
#ifdef LOOKUP_INTERPOLATION
extern int8 *iplookup;
#endif
#endif
extern void init_tables(void);
#define XMAPMAX 800
extern int xmap[XMAPMAX][5];

View file

@ -0,0 +1,359 @@
/*
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.h"
#include "config.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include "output.h"
#include "ctrlmode.h"
#include "timidity.h"
#include "tables.h"
void (*s32tobuf)(void *dp, int32 *lp, int32 c);
int free_instruments_afterwards=0;
static char def_instr_name[256]="";
int AUDIO_BUFFER_SIZE;
resample_t *resample_buffer=NULL;
int32 *common_buffer=NULL;
int num_ochannels;
#define MAXWORDS 10
static int read_config_file(const char *name)
{
FILE *fp;
char tmp[PATH_MAX], *w[MAXWORDS], *cp;
ToneBank *bank=0;
int i, j, k, line=0, words;
static int rcf_count=0;
if (rcf_count>50)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"Probable source loop in configuration files");
return (-1);
}
if (!(fp=open_file(name, 1, OF_VERBOSE)))
return -1;
while (fgets(tmp, sizeof(tmp), fp))
{
line++;
w[words=0]=strtok(tmp, " \t\r\n\240");
if (!w[0] || (*w[0]=='#')) continue;
while (w[words] && (words < MAXWORDS))
{
w[++words]=strtok(0," \t\r\n\240");
if (w[words] && w[words][0]=='#') break;
}
if (!strcmp(w[0], "map")) continue;
if (!strcmp(w[0], "dir"))
{
if (words < 2)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: No directory given\n", name, line);
return -2;
}
for (i=1; i<words; i++)
add_to_pathlist(w[i]);
}
else if (!strcmp(w[0], "source"))
{
if (words < 2)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: No file name given\n", name, line);
return -2;
}
for (i=1; i<words; i++)
{
rcf_count++;
read_config_file(w[i]);
rcf_count--;
}
}
else if (!strcmp(w[0], "default"))
{
if (words != 2)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: Must specify exactly one patch name\n",
name, line);
return -2;
}
strncpy(def_instr_name, w[1], 255);
def_instr_name[255]='\0';
}
else if (!strcmp(w[0], "drumset"))
{
if (words < 2)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: No drum set number given\n",
name, line);
return -2;
}
i=atoi(w[1]);
if (i<0 || i>127)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: Drum set must be between 0 and 127\n",
name, line);
return -2;
}
if (!drumset[i])
{
drumset[i]=safe_malloc(sizeof(ToneBank));
memset(drumset[i], 0, sizeof(ToneBank));
}
bank=drumset[i];
}
else if (!strcmp(w[0], "bank"))
{
if (words < 2)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: No bank number given\n",
name, line);
return -2;
}
i=atoi(w[1]);
if (i<0 || i>127)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: Tone bank must be between 0 and 127\n",
name, line);
return -2;
}
if (!tonebank[i])
{
tonebank[i]=safe_malloc(sizeof(ToneBank));
memset(tonebank[i], 0, sizeof(ToneBank));
}
bank=tonebank[i];
}
else {
if ((words < 2) || (*w[0] < '0' || *w[0] > '9'))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: syntax error\n", name, line);
return -2;
}
i=atoi(w[0]);
if (i<0 || i>127)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: Program must be between 0 and 127\n",
name, line);
return -2;
}
if (!bank)
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: Must specify tone bank or drum set "
"before assignment\n",
name, line);
return -2;
}
if (bank->tone[i].name)
free(bank->tone[i].name);
strcpy((bank->tone[i].name=safe_malloc(strlen(w[1])+1)),w[1]);
bank->tone[i].note=bank->tone[i].amp=bank->tone[i].pan=
bank->tone[i].strip_loop=bank->tone[i].strip_envelope=
bank->tone[i].strip_tail=-1;
for (j=2; j<words; j++)
{
if (!(cp=strchr(w[j], '=')))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n",
name, line, w[j]);
return -2;
}
*cp++=0;
if (!strcmp(w[j], "amp"))
{
k=atoi(cp);
if ((k<0 || k>MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: amplification must be between "
"0 and %d\n", name, line, MAX_AMPLIFICATION);
return -2;
}
bank->tone[i].amp=k;
}
else if (!strcmp(w[j], "note"))
{
k=atoi(cp);
if ((k<0 || k>127) || (*cp < '0' || *cp > '9'))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: note must be between 0 and 127\n",
name, line);
return -2;
}
bank->tone[i].note=k;
}
else if (!strcmp(w[j], "pan"))
{
if (!strcmp(cp, "center"))
k=64;
else if (!strcmp(cp, "left"))
k=0;
else if (!strcmp(cp, "right"))
k=127;
else
k=((atoi(cp)+100) * 100) / 157;
if ((k<0 || k>127) ||
(k==0 && *cp!='-' && (*cp < '0' || *cp > '9')))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: panning must be left, right, "
"center, or between -100 and 100\n",
name, line);
return -2;
}
bank->tone[i].pan=k;
}
else if (!strcmp(w[j], "keep"))
{
if (!strcmp(cp, "env"))
bank->tone[i].strip_envelope=0;
else if (!strcmp(cp, "loop"))
bank->tone[i].strip_loop=0;
else
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: keep must be env or loop\n", name, line);
return -2;
}
}
else if (!strcmp(w[j], "strip"))
{
if (!strcmp(cp, "env"))
bank->tone[i].strip_envelope=1;
else if (!strcmp(cp, "loop"))
bank->tone[i].strip_loop=1;
else if (!strcmp(cp, "tail"))
bank->tone[i].strip_tail=1;
else
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
"%s: line %d: strip must be env, loop, or tail\n",
name, line);
return -2;
}
}
else
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: line %d: bad patch option %s\n",
name, line, w[j]);
return -2;
}
}
}
}
if (ferror(fp))
{
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't read from %s\n", name);
close_file(fp);
return -2;
}
close_file(fp);
return 0;
}
int Timidity_Init(int rate, int format, int channels, int samples)
{
const char *env = getenv("TIMIDITY_CFG");
if (!env || read_config_file(env)<0) {
if (read_config_file(CONFIG_FILE)<0) {
if (read_config_file(CONFIG_FILE_ETC)<0) {
return(-1);
}
}
}
if (channels < 1 || channels == 3 || channels == 5 || channels > 6) return(-1);
num_ochannels = channels;
/* Set play mode parameters */
play_mode->rate = rate;
play_mode->encoding = 0;
if ( (format&0xFF) == 16 ) {
play_mode->encoding |= PE_16BIT;
}
if ( (format&0x8000) ) {
play_mode->encoding |= PE_SIGNED;
}
if ( channels == 1 ) {
play_mode->encoding |= PE_MONO;
}
switch (format) {
case AUDIO_S8:
s32tobuf = s32tos8;
break;
case AUDIO_U8:
s32tobuf = s32tou8;
break;
case AUDIO_S16LSB:
s32tobuf = s32tos16l;
break;
case AUDIO_S16MSB:
s32tobuf = s32tos16b;
break;
case AUDIO_U16LSB:
s32tobuf = s32tou16l;
break;
case AUDIO_U16MSB:
s32tobuf = s32tou16b;
break;
default:
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Unsupported audio format");
return(-1);
}
AUDIO_BUFFER_SIZE = samples;
/* Allocate memory for mixing (WARNING: Memory leak!) */
resample_buffer = safe_malloc(AUDIO_BUFFER_SIZE*sizeof(resample_t)+100);
common_buffer = safe_malloc(AUDIO_BUFFER_SIZE*num_ochannels*sizeof(int32));
init_tables();
if (ctl->open(0, 0)) {
ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Couldn't open %s\n", ctl->id_name);
return(-1);
}
if (!control_ratio) {
control_ratio = play_mode->rate / CONTROLS_PER_SECOND;
if(control_ratio<1)
control_ratio=1;
else if (control_ratio > MAX_CONTROL_RATIO)
control_ratio=MAX_CONTROL_RATIO;
}
if (*def_instr_name)
set_default_instrument(def_instr_name);
return(0);
}
char timidity_error[TIMIDITY_ERROR_SIZE] = "";
const char *Timidity_Error(void)
{
return(timidity_error);
}

View file

@ -0,0 +1,20 @@
/*
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 _MidiSong MidiSong;
extern int Timidity_Init(int rate, int format, int channels, int samples);
extern const char *Timidity_Error(void);
extern void Timidity_SetVolume(int volume);
extern int Timidity_PlaySome(void *stream, int samples);
extern MidiSong *Timidity_LoadSong_RW(SDL_RWops *rw, int freerw);
extern void Timidity_Start(MidiSong *song);
extern int Timidity_Active(void);
extern void Timidity_Stop(void);
extern void Timidity_FreeSong(MidiSong *song);
extern void Timidity_Close(void);

View file

@ -0,0 +1,521 @@
/*
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$ */
/* This file supports streaming WAV files, without volume adjustment */
#include "SDL_audio.h"
#include "SDL_mutex.h"
#include "SDL_rwops.h"
#include "SDL_endian.h"
#include "SDL_mixer.h"
#include "wavestream.h"
/*
Taken with permission from SDL_wave.h, part of the SDL library,
available at: http://www.libsdl.org/
and placed under the same license as this mixer library.
*/
/* WAVE files are little-endian */
/*******************************************/
/* Define values for Microsoft WAVE format */
/*******************************************/
#define RIFF 0x46464952 /* "RIFF" */
#define WAVE 0x45564157 /* "WAVE" */
#define FACT 0x74636166 /* "fact" */
#define LIST 0x5453494c /* "LIST" */
#define FMT 0x20746D66 /* "fmt " */
#define DATA 0x61746164 /* "data" */
#define PCM_CODE 1
#define ADPCM_CODE 2
#define WAVE_MONO 1
#define WAVE_STEREO 2
/* Normally, these three chunks come consecutively in a WAVE file */
typedef struct WaveFMT {
/* Not saved in the chunk we read:
Uint32 FMTchunk;
Uint32 fmtlen;
*/
Uint16 encoding;
Uint16 channels; /* 1 = mono, 2 = stereo */
Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
Uint32 byterate; /* Average bytes per second */
Uint16 blockalign; /* Bytes per sample block */
Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
} WaveFMT;
/* The general chunk found in the WAVE file */
typedef struct Chunk {
Uint32 magic;
Uint32 length;
Uint8 *data; /* Data includes magic and length */
} Chunk;
/*********************************************/
/* Define values for AIFF (IFF audio) format */
/*********************************************/
#define FORM 0x4d524f46 /* "FORM" */
#define AIFF 0x46464941 /* "AIFF" */
#define SSND 0x444e5353 /* "SSND" */
#define COMM 0x4d4d4f43 /* "COMM" */
/* Currently we only support a single stream at a time */
static WAVStream *music = NULL;
/* This is the format of the audio mixer data */
static SDL_AudioSpec mixer;
static int wavestream_volume = MIX_MAX_VOLUME;
/* Function to load the WAV/AIFF stream */
static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
long *start, long *stop);
static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
long *start, long *stop);
/* Initialize the WAVStream player, with the given mixer settings
This function returns 0, or -1 if there was an error.
*/
int WAVStream_Init(SDL_AudioSpec *mixerfmt)
{
mixer = *mixerfmt;
return(0);
}
void WAVStream_SetVolume(int volume)
{
wavestream_volume = volume;
}
/* Load a WAV stream from the given RWops object */
WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw)
{
WAVStream *wave;
SDL_AudioSpec wavespec;
if ( ! mixer.format ) {
Mix_SetError("WAV music output not started");
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
wave = (WAVStream *)SDL_malloc(sizeof *wave);
if ( wave ) {
memset(wave, 0, (sizeof *wave));
wave->freerw = freerw;
if ( strcmp(magic, "RIFF") == 0 ) {
wave->rw = LoadWAVStream(rw, &wavespec,
&wave->start, &wave->stop);
} else
if ( strcmp(magic, "FORM") == 0 ) {
wave->rw = LoadAIFFStream(rw, &wavespec,
&wave->start, &wave->stop);
} else {
Mix_SetError("Unknown WAVE format");
}
if ( wave->rw == NULL ) {
SDL_free(wave);
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
SDL_BuildAudioCVT(&wave->cvt,
wavespec.format, wavespec.channels, wavespec.freq,
mixer.format, mixer.channels, mixer.freq);
} else {
SDL_OutOfMemory();
if ( freerw ) {
SDL_RWclose(rw);
}
return(NULL);
}
return(wave);
}
/* Start playback of a given WAV stream */
void WAVStream_Start(WAVStream *wave)
{
SDL_RWseek (wave->rw, wave->start, RW_SEEK_SET);
music = wave;
}
/* Play some of a stream previously started with WAVStream_Start() */
int WAVStream_PlaySome(Uint8 *stream, int len)
{
long pos;
int left = 0;
if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) {
if ( music->cvt.needed ) {
int original_len;
original_len=(int)((double)len/music->cvt.len_ratio);
if ( music->cvt.len != original_len ) {
int worksize;
if ( music->cvt.buf != NULL ) {
SDL_free(music->cvt.buf);
}
worksize = original_len*music->cvt.len_mult;
music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
if ( music->cvt.buf == NULL ) {
return 0;
}
music->cvt.len = original_len;
}
if ( (music->stop - pos) < original_len ) {
left = (original_len - (music->stop - pos));
original_len -= left;
left = (int)((double)left*music->cvt.len_ratio);
}
original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len);
/* At least at the time of writing, SDL_ConvertAudio()
does byte-order swapping starting at the end of the
buffer. Thus, if we are reading 16-bit samples, we
had better make damn sure that we get an even
number of bytes, or we'll get garbage.
*/
if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
original_len--;
}
music->cvt.len = original_len;
SDL_ConvertAudio(&music->cvt);
SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
} else {
Uint8 *data;
if ( (music->stop - pos) < len ) {
left = (len - (music->stop - pos));
len -= left;
}
data = SDL_stack_alloc(Uint8, len);
if (data)
{
SDL_RWread(music->rw, data, len, 1);
SDL_MixAudio(stream, data, len, wavestream_volume);
SDL_stack_free(data);
}
}
}
return left;
}
/* Stop playback of a stream previously started with WAVStream_Start() */
void WAVStream_Stop(void)
{
music = NULL;
}
/* Close the given WAV stream */
void WAVStream_FreeSong(WAVStream *wave)
{
if ( wave ) {
/* Clean up associated data */
if ( wave->cvt.buf ) {
SDL_free(wave->cvt.buf);
}
if ( wave->freerw ) {
SDL_RWclose(wave->rw);
}
SDL_free(wave);
}
}
/* Return non-zero if a stream is currently playing */
int WAVStream_Active(void)
{
int active;
active = 0;
if ( music && (SDL_RWtell(music->rw) < music->stop) ) {
active = 1;
}
return(active);
}
static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
{
chunk->magic = SDL_ReadLE32(src);
chunk->length = SDL_ReadLE32(src);
if ( read_data ) {
chunk->data = (Uint8 *)SDL_malloc(chunk->length);
if ( chunk->data == NULL ) {
Mix_SetError("Out of memory");
return(-1);
}
if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
Mix_SetError("Couldn't read chunk");
SDL_free(chunk->data);
return(-1);
}
} else {
SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
}
return(chunk->length);
}
static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
long *start, long *stop)
{
int was_error;
Chunk chunk;
int lenread;
/* WAV magic header */
Uint32 RIFFchunk;
Uint32 wavelen;
Uint32 WAVEmagic;
/* FMT chunk */
WaveFMT *format = NULL;
was_error = 0;
/* Check the magic header */
RIFFchunk = SDL_ReadLE32(src);
wavelen = SDL_ReadLE32(src);
WAVEmagic = SDL_ReadLE32(src);
if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
Mix_SetError("Unrecognized file type (not WAVE)");
was_error = 1;
goto done;
}
/* Read the audio data format chunk */
chunk.data = NULL;
do {
/* FIXME! Add this logic to SDL_LoadWAV_RW() */
if ( chunk.data ) {
SDL_free(chunk.data);
}
lenread = ReadChunk(src, &chunk, 1);
if ( lenread < 0 ) {
was_error = 1;
goto done;
}
} while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
/* Decode the audio data format */
format = (WaveFMT *)chunk.data;
if ( chunk.magic != FMT ) {
SDL_free(chunk.data);
Mix_SetError("Complex WAVE files not supported");
was_error = 1;
goto done;
}
switch (SDL_SwapLE16(format->encoding)) {
case PCM_CODE:
/* We can understand this */
break;
default:
Mix_SetError("Unknown WAVE data format");
was_error = 1;
goto done;
}
memset(spec, 0, (sizeof *spec));
spec->freq = SDL_SwapLE32(format->frequency);
switch (SDL_SwapLE16(format->bitspersample)) {
case 8:
spec->format = AUDIO_U8;
break;
case 16:
spec->format = AUDIO_S16;
break;
default:
Mix_SetError("Unknown PCM data format");
was_error = 1;
goto done;
}
spec->channels = (Uint8) SDL_SwapLE16(format->channels);
spec->samples = 4096; /* Good default buffer size */
/* Set the file offset to the DATA chunk data */
chunk.data = NULL;
do {
*start = SDL_RWtell(src) + 2*sizeof(Uint32);
lenread = ReadChunk(src, &chunk, 0);
if ( lenread < 0 ) {
was_error = 1;
goto done;
}
} while ( chunk.magic != DATA );
*stop = SDL_RWtell(src);
done:
if ( format != NULL ) {
SDL_free(format);
}
if ( was_error ) {
return NULL;
}
return(src);
}
/* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
* I don't pretend to fully understand it.
*/
static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
{
/* Negative number? */
if (sanebuf[0] & 0x80)
return 0;
/* Less than 1? */
if (sanebuf[0] <= 0x3F)
return 1;
/* Way too big? */
if (sanebuf[0] > 0x40)
return 0x4000000;
/* Still too big? */
if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
return 800000000;
return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
}
static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
long *start, long *stop)
{
int was_error;
int found_SSND;
int found_COMM;
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;
was_error = 0;
/* Check the magic header */
FORMchunk = SDL_ReadLE32(src);
chunk_length = SDL_ReadBE32(src);
AIFFmagic = SDL_ReadLE32(src);
if ( (FORMchunk != FORM) || (AIFFmagic != AIFF) ) {
Mix_SetError("Unrecognized file type (not AIFF)");
was_error = 1;
goto done;
}
/* From what I understand of the specification, chunks may appear in
* any order, and we should just ignore unknown ones.
*
* TODO: Better sanity-checking. E.g. what happens if the AIFF file
* contains compressed sound data?
*/
found_SSND = 0;
found_COMM = 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;
/* Read the audio data format chunk */
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);
break;
default:
break;
}
} while ((!found_SSND || !found_COMM)
&& SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
if (!found_SSND) {
Mix_SetError("Bad AIFF file (no SSND chunk)");
was_error = 1;
goto done;
}
if (!found_COMM) {
Mix_SetError("Bad AIFF file (no COMM chunk)");
was_error = 1;
goto done;
}
*stop = *start + channels * numsamples * (samplesize / 8);
/* 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:
Mix_SetError("Unknown samplesize in data format");
was_error = 1;
goto done;
}
spec->channels = (Uint8) channels;
spec->samples = 4096; /* Good default buffer size */
done:
if ( was_error ) {
return NULL;
}
return(src);
}

View file

@ -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$ */
/* This file supports streaming WAV files, without volume adjustment */
#include <stdio.h>
typedef struct {
SDL_RWops *rw;
SDL_bool freerw;
long start;
long stop;
SDL_AudioCVT cvt;
} WAVStream;
/* Initialize the WAVStream player, with the given mixer settings
This function returns 0, or -1 if there was an error.
*/
extern int WAVStream_Init(SDL_AudioSpec *mixer);
/* Unimplemented */
extern void WAVStream_SetVolume(int volume);
/* Load a WAV stream from an SDL_RWops object */
extern WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic, int freerw);
/* Start playback of a given WAV stream */
extern void WAVStream_Start(WAVStream *wave);
/* Play some of a stream previously started with WAVStream_Start() */
extern int WAVStream_PlaySome(Uint8 *stream, int len);
/* Stop playback of a stream previously started with WAVStream_Start() */
extern void WAVStream_Stop(void);
/* Close the given WAV stream */
extern void WAVStream_FreeSong(WAVStream *wave);
/* Return non-zero if a stream is currently playing */
extern int WAVStream_Active(void);