From 127b85086bbcac6018fa01a4c8bdabd3d773b98c Mon Sep 17 00:00:00 2001 From: turbocat Date: Tue, 23 Mar 2021 06:51:33 +0000 Subject: [PATCH] Wolfenstein 3D: - Added sound! - Added Linux makefile - Added _KOLIBRI definition - Removed not working parameters from --help in KolibriOS git-svn-id: svn://kolibrios.org@8645 a494cfbc-eb01-0410-851d-a64ba20cac60 --- contrib/games/wolf3d/Makefile | 59 +- contrib/games/wolf3d/Makefile.linux | 126 ++ contrib/games/wolf3d/SDL/SDL_audiocvt.c | 642 +++++++ contrib/games/wolf3d/SDL/SDL_mixer.c | 218 +++ contrib/games/wolf3d/SDL/SDL_sysaudio.h | 150 ++ contrib/games/wolf3d/SDL/SDL_wave.c | 591 ++++++ contrib/games/wolf3d/SDL/SDL_wave.h | 65 + contrib/games/wolf3d/SDL_mixer/SDL_mixer.h | 642 +++++++ contrib/games/wolf3d/SDL_mixer/dynamic_flac.h | 66 + .../wolf3d/SDL_mixer/dynamic_fluidsynth.h | 57 + contrib/games/wolf3d/SDL_mixer/dynamic_mod.h | 62 + contrib/games/wolf3d/SDL_mixer/dynamic_mp3.h | 47 + contrib/games/wolf3d/SDL_mixer/dynamic_ogg.h | 53 + .../games/wolf3d/SDL_mixer/effect_position.c | 1619 +++++++++++++++++ .../games/wolf3d/SDL_mixer/effects_internal.c | 124 ++ .../games/wolf3d/SDL_mixer/effects_internal.h | 60 + contrib/games/wolf3d/SDL_mixer/fluidsynth.h | 51 + contrib/games/wolf3d/SDL_mixer/load_aiff.c | 250 +++ contrib/games/wolf3d/SDL_mixer/load_aiff.h | 31 + contrib/games/wolf3d/SDL_mixer/load_flac.h | 31 + contrib/games/wolf3d/SDL_mixer/load_ogg.h | 31 + contrib/games/wolf3d/SDL_mixer/load_voc.c | 462 +++++ contrib/games/wolf3d/SDL_mixer/load_voc.h | 36 + contrib/games/wolf3d/SDL_mixer/mixer.c | 1488 +++++++++++++++ contrib/games/wolf3d/SDL_mixer/music.c | 1597 ++++++++++++++++ contrib/games/wolf3d/SDL_mixer/music_cmd.h | 62 + contrib/games/wolf3d/SDL_mixer/music_flac.h | 90 + contrib/games/wolf3d/SDL_mixer/music_mad.h | 72 + contrib/games/wolf3d/SDL_mixer/music_mod.h | 62 + .../games/wolf3d/SDL_mixer/music_modplug.h | 42 + contrib/games/wolf3d/SDL_mixer/music_ogg.h | 75 + contrib/games/wolf3d/SDL_mixer/wavestream.h | 60 + contrib/games/wolf3d/compile_flags.txt | 4 + contrib/games/wolf3d/id_sd.cpp | 1568 ++++++++++++++-- contrib/games/wolf3d/id_sd.h | 312 ++-- contrib/games/wolf3d/wl_inter.cpp | 2 +- contrib/games/wolf3d/wl_main.cpp | 14 +- 37 files changed, 10610 insertions(+), 311 deletions(-) create mode 100644 contrib/games/wolf3d/Makefile.linux create mode 100644 contrib/games/wolf3d/SDL/SDL_audiocvt.c create mode 100644 contrib/games/wolf3d/SDL/SDL_mixer.c create mode 100644 contrib/games/wolf3d/SDL/SDL_sysaudio.h create mode 100644 contrib/games/wolf3d/SDL/SDL_wave.c create mode 100644 contrib/games/wolf3d/SDL/SDL_wave.h create mode 100644 contrib/games/wolf3d/SDL_mixer/SDL_mixer.h create mode 100644 contrib/games/wolf3d/SDL_mixer/dynamic_flac.h create mode 100644 contrib/games/wolf3d/SDL_mixer/dynamic_fluidsynth.h create mode 100644 contrib/games/wolf3d/SDL_mixer/dynamic_mod.h create mode 100644 contrib/games/wolf3d/SDL_mixer/dynamic_mp3.h create mode 100644 contrib/games/wolf3d/SDL_mixer/dynamic_ogg.h create mode 100644 contrib/games/wolf3d/SDL_mixer/effect_position.c create mode 100644 contrib/games/wolf3d/SDL_mixer/effects_internal.c create mode 100644 contrib/games/wolf3d/SDL_mixer/effects_internal.h create mode 100644 contrib/games/wolf3d/SDL_mixer/fluidsynth.h create mode 100644 contrib/games/wolf3d/SDL_mixer/load_aiff.c create mode 100644 contrib/games/wolf3d/SDL_mixer/load_aiff.h create mode 100644 contrib/games/wolf3d/SDL_mixer/load_flac.h create mode 100644 contrib/games/wolf3d/SDL_mixer/load_ogg.h create mode 100644 contrib/games/wolf3d/SDL_mixer/load_voc.c create mode 100644 contrib/games/wolf3d/SDL_mixer/load_voc.h create mode 100644 contrib/games/wolf3d/SDL_mixer/mixer.c create mode 100644 contrib/games/wolf3d/SDL_mixer/music.c create mode 100644 contrib/games/wolf3d/SDL_mixer/music_cmd.h create mode 100644 contrib/games/wolf3d/SDL_mixer/music_flac.h create mode 100644 contrib/games/wolf3d/SDL_mixer/music_mad.h create mode 100644 contrib/games/wolf3d/SDL_mixer/music_mod.h create mode 100644 contrib/games/wolf3d/SDL_mixer/music_modplug.h create mode 100644 contrib/games/wolf3d/SDL_mixer/music_ogg.h create mode 100644 contrib/games/wolf3d/SDL_mixer/wavestream.h create mode 100644 contrib/games/wolf3d/compile_flags.txt diff --git a/contrib/games/wolf3d/Makefile b/contrib/games/wolf3d/Makefile index a623903852..5be015a4a0 100755 --- a/contrib/games/wolf3d/Makefile +++ b/contrib/games/wolf3d/Makefile @@ -3,21 +3,64 @@ LD = kos32-ld SDK_DIR = $(abspath ../../sdk) -CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 +CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -D_KOLIBRI LDFLAGS = -static -S -nostdlib -T $(SDK_DIR)/sources/newlib/app.lds --image-base 0 -INCLUDES = -I$(SDK_DIR)/sources/newlib/libc/include -I$(SDK_DIR)/sources/SDL-1.2.2_newlib/include -I. +INCLUDES = -I$(SDK_DIR)/sources/newlib/libc/include -I$(SDK_DIR)/sources/SDL-1.2.2_newlib/include -I. -I SDL_mixer LIBPATH = -L $(SDK_DIR)/lib -L /home/autobuild/tools/win32/mingw32/lib -OBJECTS = wl_cloudsky.o wl_debug.o id_sd.o wl_play.o id_vl.o wl_act2.o wl_floorceiling.o wl_dir3dspr.o wl_state.o wl_atmos.o id_in.o signon.o wl_parallax.o wl_agent.o sdl_winmain.o wl_inter.o wl_text.o id_pm.o wl_draw.o wl_menu.o wl_game.o wl_act1.o wl_main.o wl_shade.o id_us_1.o id_vh.o id_ca.o joystick_stub.o kolibri.o +OBJECTS += wl_cloudsky.o +OBJECTS += wl_debug.o +OBJECTS += id_sd.o +OBJECTS += wl_play.o +OBJECTS += id_vl.o +OBJECTS += wl_act2.o +OBJECTS += wl_floorceiling.o +OBJECTS += wl_dir3dspr.o +OBJECTS += wl_state.o +OBJECTS += wl_atmos.o +OBJECTS += id_in.o +OBJECTS += signon.o +OBJECTS += wl_parallax.o +OBJECTS += wl_agent.o +OBJECTS += sdl_winmain.o +OBJECTS += wl_inter.o +OBJECTS += wl_text.o +OBJECTS += id_pm.o +OBJECTS += wl_draw.o +OBJECTS += wl_menu.o +OBJECTS += wl_game.o +OBJECTS += wl_act1.o +OBJECTS += wl_main.o +OBJECTS += wl_shade.o +OBJECTS += id_us_1.o +OBJECTS += id_vh.o +OBJECTS += id_ca.o +OBJECTS += joystick_stub.o +OBJECTS += kolibri.o +OBJECTS += mame/fmopl.o -default: $(OBJECTS) - kos32-ld $(LDFLAGS) $(LIBPATH) --subsystem native -o wolf3d $(OBJECTS) -lSDLn -lsound -lstdc++ -lsupc++ -lgcc -lc.dll - objcopy wolf3d -O binary - kpack --nologo wolf3d +SDL_OBJ += SDL/SDL_wave.o +SDL_OBJ += SDL/SDL_audiocvt.o +SDL_OBJ += SDL/SDL_mixer.o + +SDL_MIX_OBJ += SDL_mixer/mixer.o +SDL_MIX_OBJ += SDL_mixer/music.o +SDL_MIX_OBJ += SDL_mixer/load_aiff.o +SDL_MIX_OBJ += SDL_mixer/load_voc.o +SDL_MIX_OBJ += SDL_mixer/effects_internal.o +SDL_MIX_OBJ += SDL_mixer/effect_position.o + +default: $(OBJECTS) $(SDL_MIX_OBJ) $(SDL_OBJ) + kos32-ld $(LDFLAGS) $(LIBPATH) --subsystem native -o bin/wolf3d $(OBJECTS) $(SDL_MIX_OBJ) $(SDL_OBJ) -lSDLn -lsound -lstdc++ -lsupc++ -lgcc -lc.dll + objcopy bin/wolf3d -O binary + kpack --nologo bin/wolf3d %.o : %.cpp $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< +%.o : %.c + $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< + clean: - rm *.o + rm *.o SDL_mixer/*.o mame/*.o SDL/*.o *.d SDL_mixer/*.d mame/*.d SDL/*.d diff --git a/contrib/games/wolf3d/Makefile.linux b/contrib/games/wolf3d/Makefile.linux new file mode 100644 index 0000000000..90f3f3c38b --- /dev/null +++ b/contrib/games/wolf3d/Makefile.linux @@ -0,0 +1,126 @@ +CONFIG ?= config.default +-include $(CONFIG) + + +BINARY ?= bin/wolf3d +PREFIX ?= /usr/local +MANPREFIX ?= $(PREFIX)/share/man/ +MANPAGE ?= man6/wolf4sdl.6 +DATADIR ?= $(PREFIX)/share/games/wolf3d/ + +INSTALL ?= install +INSTALL_PROGRAM ?= $(INSTALL) -m 555 -s +INSTALL_MAN ?= $(INSTALL) -m 444 +INSTALL_DATA ?= $(INSTALL) -m 444 + + +SDL_CONFIG ?= sdl-config +CFLAGS_SDL ?= $(shell $(SDL_CONFIG) --cflags) +LDFLAGS_SDL ?= $(shell $(SDL_CONFIG) --libs) + + +CFLAGS += $(CFLAGS_SDL) + +#CFLAGS += -Wall +#CFLAGS += -W +CFLAGS += -Wpointer-arith +CFLAGS += -Wreturn-type +CFLAGS += -Wwrite-strings +CFLAGS += -Wcast-align + +ifdef DATADIR + CFLAGS += -DDATADIR=\"$(DATADIR)\" +endif + +CCFLAGS += $(CFLAGS) +CCFLAGS += -std=gnu99 +CCFLAGS += -Werror-implicit-function-declaration +CCFLAGS += -Wimplicit-int +CCFLAGS += -Wsequence-point + +CXXFLAGS += $(CFLAGS) + +LDFLAGS += $(LDFLAGS_SDL) + +SRCS := +SRCS += mame/fmopl.cpp +SRCS += id_ca.cpp +SRCS += id_in.cpp +SRCS += id_pm.cpp +SRCS += id_sd.cpp +SRCS += id_us_1.cpp +SRCS += id_vh.cpp +SRCS += id_vl.cpp +SRCS += signon.cpp +SRCS += wl_act1.cpp +SRCS += wl_act2.cpp +SRCS += wl_agent.cpp +SRCS += wl_atmos.cpp +SRCS += wl_cloudsky.cpp +SRCS += wl_debug.cpp +SRCS += wl_draw.cpp +SRCS += wl_floorceiling.cpp +SRCS += wl_game.cpp +SRCS += wl_inter.cpp +SRCS += wl_main.cpp +SRCS += wl_menu.cpp +SRCS += wl_parallax.cpp +SRCS += wl_play.cpp +SRCS += wl_state.cpp +SRCS += wl_text.cpp + +SRCS += SDL_mixer/mixer.c +SRCS += SDL_mixer/music.c +SRCS += SDL_mixer/load_aiff.c +SRCS += SDL_mixer/load_voc.c +SRCS += SDL_mixer/effects_internal.c +SRCS += SDL_mixer/effect_position.c + + +DEPS = $(filter %.d, $(SRCS:.c=.d) $(SRCS:.cpp=.d)) +OBJS = $(filter %.o, $(SRCS:.c=.o) $(SRCS:.cpp=.o)) + +.SUFFIXES: +.SUFFIXES: .c .cpp .d .o + +Q ?= @ + +all: $(BINARY) + +ifndef NO_DEPS +depend: $(DEPS) + +ifeq ($(findstring $(MAKECMDGOALS), clean depend Data),) +-include $(DEPS) +endif +endif + +$(BINARY): $(OBJS) + @echo '===> LD $@' + $(Q)$(CXX) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $@ + +.c.o: + @echo '===> CC $<' + $(Q)$(CC) $(CCFLAGS) -c $< -o $@ + +.cpp.o: + @echo '===> CXX $<' + $(Q)$(CXX) $(CXXFLAGS) -c $< -o $@ + +.c.d: + @echo '===> DEP $<' + $(Q)$(CC) $(CCFLAGS) -MM $< | sed 's#^$(@F:%.d=%.o):#$@ $(@:%.d=%.o):#' > $@ + +.cpp.d: + @echo '===> DEP $<' + $(Q)$(CXX) $(CXXFLAGS) -MM $< | sed 's#^$(@F:%.d=%.o):#$@ $(@:%.d=%.o):#' > $@ + +clean distclean: + @echo '===> CLEAN' + $(Q)rm -fr $(DEPS) $(OBJS) $(BINARY) + +install: $(BINARY) + @echo '===> INSTALL' + $(Q)$(INSTALL) -d $(PREFIX)/bin + $(Q)$(INSTALL_PROGRAM) $(BINARY) $(PREFIX)/bin + $(Q)$(INSTALL_MAN) $(MANPAGE) $(MANPREFIX)/man6 diff --git a/contrib/games/wolf3d/SDL/SDL_audiocvt.c b/contrib/games/wolf3d/SDL/SDL_audiocvt.c new file mode 100644 index 0000000000..e9a82ce6c6 --- /dev/null +++ b/contrib/games/wolf3d/SDL/SDL_audiocvt.c @@ -0,0 +1,642 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id: SDL_audiocvt.c,v 1.2 2001/04/26 16:50:17 hercules Exp $"; +#endif + +/* Functions for audio drivers to perform runtime conversion of audio format */ + +#include + +#include "SDL_error.h" +#include "SDL_audio.h" + + +/* Effectively mix right and left channels into a single channel */ +void SDL_ConvertMono(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Sint32 sample; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting to mono\n"); +#endif + switch (format&0x8018) { + + case AUDIO_U8: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + for ( i=cvt->len_cvt/2; i; --i ) { + sample = src[0] + src[1]; + if ( sample > 255 ) { + *dst = 255; + } else { + *dst = sample; + } + src += 2; + dst += 1; + } + } + break; + + case AUDIO_S8: { + Sint8 *src, *dst; + + src = (Sint8 *)cvt->buf; + dst = (Sint8 *)cvt->buf; + for ( i=cvt->len_cvt/2; i; --i ) { + sample = src[0] + src[1]; + if ( sample > 127 ) { + *dst = 127; + } else + if ( sample < -128 ) { + *dst = -128; + } else { + *dst = sample; + } + src += 2; + dst += 1; + } + } + break; + + case AUDIO_U16: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/4; i; --i ) { + sample = (Uint16)((src[0]<<8)|src[1])+ + (Uint16)((src[2]<<8)|src[3]); + if ( sample > 65535 ) { + dst[0] = 0xFF; + dst[1] = 0xFF; + } else { + dst[1] = (sample&0xFF); + sample >>= 8; + dst[0] = (sample&0xFF); + } + src += 4; + dst += 2; + } + } else { + for ( i=cvt->len_cvt/4; i; --i ) { + sample = (Uint16)((src[1]<<8)|src[0])+ + (Uint16)((src[3]<<8)|src[2]); + if ( sample > 65535 ) { + dst[0] = 0xFF; + dst[1] = 0xFF; + } else { + dst[0] = (sample&0xFF); + sample >>= 8; + dst[1] = (sample&0xFF); + } + src += 4; + dst += 2; + } + } + } + break; + + case AUDIO_S16: { + Uint8 *src, *dst; + + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) == 0x1000 ) { + for ( i=cvt->len_cvt/4; i; --i ) { + sample = (Sint16)((src[0]<<8)|src[1])+ + (Sint16)((src[2]<<8)|src[3]); + if ( sample > 32767 ) { + dst[0] = 0x7F; + dst[1] = 0xFF; + } else + if ( sample < -32768 ) { + dst[0] = 0x80; + dst[1] = 0x00; + } else { + dst[1] = (sample&0xFF); + sample >>= 8; + dst[0] = (sample&0xFF); + } + src += 4; + dst += 2; + } + } else { + for ( i=cvt->len_cvt/4; i; --i ) { + sample = (Sint16)((src[1]<<8)|src[0])+ + (Sint16)((src[3]<<8)|src[2]); + if ( sample > 32767 ) { + dst[1] = 0x7F; + dst[0] = 0xFF; + } else + if ( sample < -32768 ) { + dst[1] = 0x80; + dst[0] = 0x00; + } else { + dst[0] = (sample&0xFF); + sample >>= 8; + dst[1] = (sample&0xFF); + } + src += 4; + dst += 2; + } + } + } + break; + } + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + + +/* Duplicate a mono channel to both stereo channels */ +void SDL_ConvertStereo(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting to stereo\n"); +#endif + if ( (format & 0xFF) == 16 ) { + Uint16 *src, *dst; + + src = (Uint16 *)(cvt->buf+cvt->len_cvt); + dst = (Uint16 *)(cvt->buf+cvt->len_cvt*2); + for ( i=cvt->len_cvt/2; i; --i ) { + dst -= 2; + src -= 1; + dst[0] = src[0]; + dst[1] = src[0]; + } + } else { + Uint8 *src, *dst; + + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + for ( i=cvt->len_cvt; i; --i ) { + dst -= 2; + src -= 1; + dst[0] = src[0]; + dst[1] = src[0]; + } + } + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Convert 8-bit to 16-bit - LSB */ +void SDL_Convert16LSB(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting to 16-bit LSB\n"); +#endif + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + for ( i=cvt->len_cvt; i; --i ) { + src -= 1; + dst -= 2; + dst[1] = *src; + dst[0] = 0; + } + format = ((format & ~0x0008) | AUDIO_U16LSB); + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} +/* Convert 8-bit to 16-bit - MSB */ +void SDL_Convert16MSB(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting to 16-bit MSB\n"); +#endif + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + for ( i=cvt->len_cvt; i; --i ) { + src -= 1; + dst -= 2; + dst[0] = *src; + dst[1] = 0; + } + format = ((format & ~0x0008) | AUDIO_U16MSB); + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Convert 16-bit to 8-bit */ +void SDL_Convert8(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting to 8-bit\n"); +#endif + src = cvt->buf; + dst = cvt->buf; + if ( (format & 0x1000) != 0x1000 ) { /* Little endian */ + ++src; + } + for ( i=cvt->len_cvt/2; i; --i ) { + *dst = *src; + src += 2; + dst += 1; + } + format = ((format & ~0x9010) | AUDIO_U8); + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Toggle signed/unsigned */ +void SDL_ConvertSign(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *data; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio signedness\n"); +#endif + data = cvt->buf; + if ( (format & 0xFF) == 16 ) { + if ( (format & 0x1000) != 0x1000 ) { /* Little endian */ + ++data; + } + for ( i=cvt->len_cvt/2; i; --i ) { + *data ^= 0x80; + data += 2; + } + } else { + for ( i=cvt->len_cvt; i; --i ) { + *data++ ^= 0x80; + } + } + format = (format ^ 0x8000); + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Toggle endianness */ +void SDL_ConvertEndian(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *data, tmp; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio endianness\n"); +#endif + data = cvt->buf; + for ( i=cvt->len_cvt/2; i; --i ) { + tmp = data[0]; + data[0] = data[1]; + data[1] = tmp; + data += 2; + } + format = (format ^ 0x1000); + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Convert rate up by multiple of 2 */ +void SDL_RateMUL2(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate * 2\n"); +#endif + src = cvt->buf+cvt->len_cvt; + dst = cvt->buf+cvt->len_cvt*2; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt; i; --i ) { + src -= 1; + dst -= 2; + dst[0] = src[0]; + dst[1] = src[0]; + } + break; + case 16: + for ( i=cvt->len_cvt/2; i; --i ) { + src -= 2; + dst -= 4; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[0]; + dst[3] = src[1]; + } + break; + } + cvt->len_cvt *= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Convert rate down by multiple of 2 */ +void SDL_RateDIV2(SDL_AudioCVT *cvt, Uint16 format) +{ + int i; + Uint8 *src, *dst; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate / 2\n"); +#endif + src = cvt->buf; + dst = cvt->buf; + switch (format & 0xFF) { + case 8: + for ( i=cvt->len_cvt/2; i; --i ) { + dst[0] = src[0]; + src += 2; + dst += 1; + } + break; + case 16: + for ( i=cvt->len_cvt/4; i; --i ) { + dst[0] = src[0]; + dst[1] = src[1]; + src += 4; + dst += 2; + } + break; + } + cvt->len_cvt /= 2; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +/* Very slow rate conversion routine */ +void SDL_RateSLOW(SDL_AudioCVT *cvt, Uint16 format) +{ + double ipos; + int i, clen; + +#ifdef DEBUG_CONVERT + fprintf(stderr, "Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr); +#endif + clen = (int)((double)cvt->len_cvt / cvt->rate_incr); + if ( cvt->rate_incr > 1.0 ) { + switch (format & 0xFF) { + case 8: { + Uint8 *output; + + output = cvt->buf; + ipos = 0.0; + for ( i=clen; i; --i ) { + *output = cvt->buf[(int)ipos]; + ipos += cvt->rate_incr; + output += 1; + } + } + break; + + case 16: { + Uint16 *output; + + clen &= ~1; + output = (Uint16 *)cvt->buf; + ipos = 0.0; + for ( i=clen/2; i; --i ) { + *output=((Uint16 *)cvt->buf)[(int)ipos]; + ipos += cvt->rate_incr; + output += 1; + } + } + break; + } + } else { + switch (format & 0xFF) { + case 8: { + Uint8 *output; + + output = cvt->buf+clen; + ipos = (double)cvt->len_cvt; + for ( i=clen; i; --i ) { + ipos -= cvt->rate_incr; + output -= 1; + *output = cvt->buf[(int)ipos]; + } + } + break; + + case 16: { + Uint16 *output; + + clen &= ~1; + output = (Uint16 *)(cvt->buf+clen); + ipos = (double)cvt->len_cvt/2; + for ( i=clen/2; i; --i ) { + ipos -= cvt->rate_incr; + output -= 1; + *output=((Uint16 *)cvt->buf)[(int)ipos]; + } + } + break; + } + } + cvt->len_cvt = clen; + if ( cvt->filters[++cvt->filter_index] ) { + cvt->filters[cvt->filter_index](cvt, format); + } +} + +int SDL_ConvertAudio(SDL_AudioCVT *cvt) +{ + /* Make sure there's data to convert */ + if ( cvt->buf == NULL ) { + SDL_SetError("No buffer allocated for conversion"); + return(-1); + } + /* Return okay if no conversion is necessary */ + cvt->len_cvt = cvt->len; + if ( cvt->filters[0] == NULL ) { + return(0); + } + + /* Set up the conversion and go! */ + cvt->filter_index = 0; + cvt->filters[0](cvt, cvt->src_format); + return(0); +} + +/* Creates a set of audio filters to convert from one format to another. + Returns -1 if the format conversion is not supported, or 1 if the + audio filter is set up. +*/ + +int SDL_BuildAudioCVT(SDL_AudioCVT *cvt, + Uint16 src_format, Uint8 src_channels, int src_rate, + Uint16 dst_format, Uint8 dst_channels, int dst_rate) +{ + /* Start off with no conversion necessary */ + cvt->needed = 0; + cvt->filter_index = 0; + cvt->filters[0] = NULL; + cvt->len_mult = 1; + cvt->len_ratio = 1.0; + + /* First filter: Endian conversion from src to dst */ + if ( (src_format & 0x1000) != (dst_format & 0x1000) + && ((src_format & 0xff) != 8) ) { + cvt->filters[cvt->filter_index++] = SDL_ConvertEndian; + } + + /* Second filter: Sign conversion -- signed/unsigned */ + if ( (src_format & 0x8000) != (dst_format & 0x8000) ) { + cvt->filters[cvt->filter_index++] = SDL_ConvertSign; + } + + /* Next filter: Convert 16 bit <--> 8 bit PCM */ + if ( (src_format & 0xFF) != (dst_format & 0xFF) ) { + switch (dst_format&0x10FF) { + case AUDIO_U8: + cvt->filters[cvt->filter_index++] = + SDL_Convert8; + cvt->len_ratio /= 2; + break; + case AUDIO_U16LSB: + cvt->filters[cvt->filter_index++] = + SDL_Convert16LSB; + cvt->len_mult *= 2; + cvt->len_ratio *= 2; + break; + case AUDIO_U16MSB: + cvt->filters[cvt->filter_index++] = + SDL_Convert16MSB; + cvt->len_mult *= 2; + cvt->len_ratio *= 2; + break; + } + } + + /* Last filter: Mono/Stereo conversion */ + if ( src_channels != dst_channels ) { + while ( (src_channels*2) <= dst_channels ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertStereo; + cvt->len_mult *= 2; + src_channels *= 2; + cvt->len_ratio *= 2; + } + /* This assumes that 4 channel audio is in the format: + Left {front/back} + Right {front/back} + so converting to L/R stereo works properly. + */ + while ( ((src_channels%2) == 0) && + ((src_channels/2) >= dst_channels) ) { + cvt->filters[cvt->filter_index++] = + SDL_ConvertMono; + src_channels /= 2; + cvt->len_ratio /= 2; + } + if ( src_channels != dst_channels ) { + /* Uh oh.. */; + } + } + + /* Do rate conversion */ + cvt->rate_incr = 0.0; + if ( (src_rate/100) != (dst_rate/100) ) { + Uint32 hi_rate, lo_rate; + int len_mult; + double len_ratio; + void (*rate_cvt)(SDL_AudioCVT *cvt, Uint16 format); + + if ( src_rate > dst_rate ) { + hi_rate = src_rate; + lo_rate = dst_rate; + rate_cvt = SDL_RateDIV2; + len_mult = 1; + len_ratio = 0.5; + } else { + hi_rate = dst_rate; + lo_rate = src_rate; + rate_cvt = SDL_RateMUL2; + len_mult = 2; + len_ratio = 2.0; + } + /* If hi_rate = lo_rate*2^x then conversion is easy */ + while ( ((lo_rate*2)/100) <= (hi_rate/100) ) { + cvt->filters[cvt->filter_index++] = rate_cvt; + cvt->len_mult *= len_mult; + lo_rate *= 2; + cvt->len_ratio *= len_ratio; + } + /* We may need a slow conversion here to finish up */ + if ( (lo_rate/100) != (hi_rate/100) ) { +#if 1 + /* The problem with this is that if the input buffer is + say 1K, and the conversion rate is say 1.1, then the + output buffer is 1.1K, which may not be an acceptable + buffer size for the audio driver (not a power of 2) + */ + /* For now, punt and hope the rate distortion isn't great. + */ +#else + if ( src_rate < dst_rate ) { + cvt->rate_incr = (double)lo_rate/hi_rate; + cvt->len_mult *= 2; + cvt->len_ratio /= cvt->rate_incr; + } else { + cvt->rate_incr = (double)hi_rate/lo_rate; + cvt->len_ratio *= cvt->rate_incr; + } + cvt->filters[cvt->filter_index++] = SDL_RateSLOW; +#endif + } + } + + /* Set up the filter information */ + if ( cvt->filter_index != 0 ) { + cvt->needed = 1; + cvt->src_format = src_format; + cvt->dst_format = dst_format; + cvt->len = 0; + cvt->buf = NULL; + cvt->filters[cvt->filter_index] = NULL; + } + return(cvt->needed); +} diff --git a/contrib/games/wolf3d/SDL/SDL_mixer.c b/contrib/games/wolf3d/SDL/SDL_mixer.c new file mode 100644 index 0000000000..03cf713587 --- /dev/null +++ b/contrib/games/wolf3d/SDL/SDL_mixer.c @@ -0,0 +1,218 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id: SDL_mixer.c,v 1.2 2001/04/26 16:50:17 hercules Exp $"; +#endif + +/* This provides the default mixing callback for the SDL audio routines */ + +#include +#include +#include + +#include "SDL_audio.h" +#include "SDL_mutex.h" +#include "SDL_timer.h" +#include "SDL_sysaudio.h" + +SDL_AudioDevice *current_audio = NULL; + +/* This table is used to add two sound values together and pin + * the value to avoid overflow. (used with permission from ARDI) + * Changed to use 0xFE instead of 0xFF for better sound quality. + */ +static const Uint8 mix8[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, + 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, + 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, + 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, + 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, + 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, + 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, + 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, + 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, + 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE +}; + +/* The volume ranges from 0 - 128 */ +#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME) +#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128) + +void SDL_MixAudio (Uint8 *dst, const Uint8 *src, Uint32 len, int volume) +{ + Uint16 format; + + if ( volume == 0 ) { + return; + } + /* Mix the user-level audio format */ + if ( current_audio ) { + if ( current_audio->convert.needed ) { + format = current_audio->convert.src_format; + } else { + format = current_audio->spec.format; + } + } else { + format = AUDIO_S16; + } + format = AUDIO_S16; + switch (format) { + + case AUDIO_U8: { + Uint8 src_sample; + + while ( len-- ) { + src_sample = *src; + ADJUST_VOLUME_U8(src_sample, volume); + *dst = mix8[*dst+src_sample]; + ++dst; + ++src; + } + } + break; + + case AUDIO_S8: { + Sint8 *dst8, *src8; + Sint8 src_sample; + int dst_sample; + const int max_audioval = ((1<<(8-1))-1); + const int min_audioval = -(1<<(8-1)); + + src8 = (Sint8 *)src; + dst8 = (Sint8 *)dst; + while ( len-- ) { + src_sample = *src8; + ADJUST_VOLUME(src_sample, volume); + dst_sample = *dst8 + src_sample; + if ( dst_sample > max_audioval ) { + *dst8 = max_audioval; + } else + if ( dst_sample < min_audioval ) { + *dst8 = min_audioval; + } else { + *dst8 = dst_sample; + } + ++dst8; + ++src8; + } + } + break; + + case AUDIO_S16LSB: { + Sint16 src1, src2; + int dst_sample; + const int max_audioval = ((1<<(16-1))-1); + const int min_audioval = -(1<<(16-1)); + + len /= 2; + while ( len-- ) { + src1 = ((src[1])<<8|src[0]); + ADJUST_VOLUME(src1, volume); + src2 = ((dst[1])<<8|dst[0]); + src += 2; + dst_sample = src1+src2; + if ( dst_sample > max_audioval ) { + dst_sample = max_audioval; + } else + if ( dst_sample < min_audioval ) { + dst_sample = min_audioval; + } + dst[0] = dst_sample&0xFF; + dst_sample >>= 8; + dst[1] = dst_sample&0xFF; + dst += 2; + } + } + break; + + case AUDIO_S16MSB: { + Sint16 src1, src2; + int dst_sample; + const int max_audioval = ((1<<(16-1))-1); + const int min_audioval = -(1<<(16-1)); + + len /= 2; + while ( len-- ) { + src1 = ((src[0])<<8|src[1]); + ADJUST_VOLUME(src1, volume); + src2 = ((dst[0])<<8|dst[1]); + src += 2; + dst_sample = src1+src2; + if ( dst_sample > max_audioval ) { + dst_sample = max_audioval; + } else + if ( dst_sample < min_audioval ) { + dst_sample = min_audioval; + } + dst[1] = dst_sample&0xFF; + dst_sample >>= 8; + dst[0] = dst_sample&0xFF; + dst += 2; + } + } + break; + + default: /* If this happens... FIXME! */ + SDL_SetError("SDL_MixAudio(): unknown audio format"); + return; + } +} diff --git a/contrib/games/wolf3d/SDL/SDL_sysaudio.h b/contrib/games/wolf3d/SDL/SDL_sysaudio.h new file mode 100644 index 0000000000..074ba3e5d3 --- /dev/null +++ b/contrib/games/wolf3d/SDL/SDL_sysaudio.h @@ -0,0 +1,150 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id: SDL_sysaudio.h,v 1.8 2001/07/23 02:58:42 slouken Exp $"; +#endif + +#ifndef _SDL_sysaudio_h +#define _SDL_sysaudio_h + +#include "SDL_mutex.h" +#include "SDL_thread.h" + +/* The SDL audio driver */ +typedef struct SDL_AudioDevice SDL_AudioDevice; + +/* Define the SDL audio driver structure */ +#define _THIS SDL_AudioDevice *_this +#ifndef _STATUS +#define _STATUS SDL_status *status +#endif +struct SDL_AudioDevice { + /* * * */ + /* The name of this audio driver */ + const char *name; + + /* * * */ + /* The description of this audio driver */ + const char *desc; + + /* * * */ + /* Public driver functions */ + int (*OpenAudio)(_THIS, SDL_AudioSpec *spec); + void (*ThreadInit)(_THIS); /* Called by audio thread at start */ + void (*WaitAudio)(_THIS); + void (*PlayAudio)(_THIS); + Uint8 *(*GetAudioBuf)(_THIS); + void (*WaitDone)(_THIS); + void (*CloseAudio)(_THIS); + + /* * * */ + /* Data common to all devices */ + + /* The current audio specification (shared with audio thread) */ + SDL_AudioSpec spec; + + /* An audio conversion block for audio format emulation */ + SDL_AudioCVT convert; + + /* Current state flags */ + int enabled; + int paused; + int opened; + + /* Fake audio buffer for when the audio hardware is busy */ + Uint8 *fake_stream; + + /* A semaphore for locking the mixing buffers */ + SDL_mutex *mixer_lock; + + /* A thread to feed the audio device */ + SDL_Thread *thread; + Uint32 threadid; + + /* * * */ + /* Data private to this driver */ + struct SDL_PrivateAudioData *hidden; + + /* * * */ + /* The function used to dispose of this structure */ + void (*free)(_THIS); +}; +#undef _THIS + +typedef struct AudioBootStrap { + const char *name; + const char *desc; + int (*available)(void); + SDL_AudioDevice *(*create)(int devindex); +} AudioBootStrap; + +#ifdef OPENBSD_AUDIO_SUPPORT +extern AudioBootStrap OPENBSD_AUDIO_bootstrap; +#endif +#ifdef OSS_SUPPORT +extern AudioBootStrap DSP_bootstrap; +extern AudioBootStrap DMA_bootstrap; +#endif +#ifdef ALSA_SUPPORT +extern AudioBootStrap ALSA_bootstrap; +#endif +#if (defined(unix) && !defined(__CYGWIN32__)) && \ + !defined(OSS_SUPPORT) && !defined(ALSA_SUPPORT) +extern AudioBootStrap AUDIO_bootstrap; +#endif +#ifdef ARTSC_SUPPORT +extern AudioBootStrap ARTSC_bootstrap; +#endif +#ifdef ESD_SUPPORT +extern AudioBootStrap ESD_bootstrap; +#endif +#ifdef NAS_SUPPORT +extern AudioBootStrap NAS_bootstrap; +#endif +#ifdef ENABLE_DIRECTX +extern AudioBootStrap DSOUND_bootstrap; +#endif +#ifdef ENABLE_WINDIB +extern AudioBootStrap WAVEOUT_bootstrap; +#endif +#ifdef _AIX +extern AudioBootStrap Paud_bootstrap; +#endif +#ifdef __BEOS__ +extern AudioBootStrap BAUDIO_bootstrap; +#endif +#if defined(macintosh) || TARGET_API_MAC_CARBON +extern AudioBootStrap SNDMGR_bootstrap; +#endif +#ifdef ENABLE_AHI +extern AudioBootStrap AHI_bootstrap; +#endif +#ifdef DISKAUD_SUPPORT +extern AudioBootStrap DISKAUD_bootstrap; +#endif + +/* This is the current audio device */ +extern SDL_AudioDevice *current_audio; + +#endif /* _SDL_sysaudio_h */ diff --git a/contrib/games/wolf3d/SDL/SDL_wave.c b/contrib/games/wolf3d/SDL/SDL_wave.c new file mode 100644 index 0000000000..237ec15087 --- /dev/null +++ b/contrib/games/wolf3d/SDL/SDL_wave.c @@ -0,0 +1,591 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id: SDL_wave.c,v 1.2 2001/04/26 16:50:17 hercules Exp $"; +#endif + +#ifndef DISABLE_FILE + +/* Microsoft WAVE file loading routines */ + +#include +#include + +#include "SDL_error.h" +#include "SDL_audio.h" +#include "SDL_wave.h" +#include "SDL_endian.h" + +#ifndef NELEMS +#define NELEMS(array) ((sizeof array)/(sizeof array[0])) +#endif + +static int ReadChunk(SDL_RWops *src, Chunk *chunk); + +struct MS_ADPCM_decodestate { + Uint8 hPredictor; + Uint16 iDelta; + Sint16 iSamp1; + Sint16 iSamp2; +}; +static struct MS_ADPCM_decoder { + WaveFMT wavefmt; + Uint16 wSamplesPerBlock; + Uint16 wNumCoef; + Sint16 aCoeff[7][2]; + /* * * */ + struct MS_ADPCM_decodestate state[2]; +} MS_ADPCM_state; + +static int InitMS_ADPCM(WaveFMT *format) +{ + Uint8 *rogue_feel; + Uint16 extra_info; + int i; + + /* Set the rogue pointer to the MS_ADPCM specific data */ + MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); + MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); + MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); + MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); + MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); + MS_ADPCM_state.wavefmt.bitspersample = + SDL_SwapLE16(format->bitspersample); + rogue_feel = (Uint8 *)format+sizeof(*format); + if ( sizeof(*format) == 16 ) { + extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]); + rogue_feel += sizeof(Uint16); + } + MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); + rogue_feel += sizeof(Uint16); + MS_ADPCM_state.wNumCoef = ((rogue_feel[1]<<8)|rogue_feel[0]); + rogue_feel += sizeof(Uint16); + if ( MS_ADPCM_state.wNumCoef != 7 ) { + SDL_SetError("Unknown set of MS_ADPCM coefficients"); + return(-1); + } + for ( i=0; iiSamp1 * coeff[0]) + + (state->iSamp2 * coeff[1]))/256; + if ( nybble & 0x08 ) { + new_sample += state->iDelta * (nybble-0x10); + } else { + new_sample += state->iDelta * nybble; + } + if ( new_sample < min_audioval ) { + new_sample = min_audioval; + } else + if ( new_sample > max_audioval ) { + new_sample = max_audioval; + } + delta = ((Sint32)state->iDelta * adaptive[nybble])/256; + if ( delta < 16 ) { + delta = 16; + } + state->iDelta = delta; + state->iSamp2 = state->iSamp1; + state->iSamp1 = new_sample; + return(new_sample); +} + +static int MS_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) +{ + struct MS_ADPCM_decodestate *state[2]; + Uint8 *freeable, *encoded, *decoded; + Sint32 encoded_len, samplesleft; + Sint8 nybble, stereo; + Sint16 *coeff[2]; + Sint32 new_sample; + + /* Allocate the proper sized output buffer */ + encoded_len = *audio_len; + encoded = *audio_buf; + freeable = *audio_buf; + *audio_len = (encoded_len/MS_ADPCM_state.wavefmt.blockalign) * + MS_ADPCM_state.wSamplesPerBlock* + MS_ADPCM_state.wavefmt.channels*sizeof(Sint16); + *audio_buf = (Uint8 *)malloc(*audio_len); + if ( *audio_buf == NULL ) { + SDL_Error(SDL_ENOMEM); + return(-1); + } + decoded = *audio_buf; + + /* Get ready... Go! */ + stereo = (MS_ADPCM_state.wavefmt.channels == 2); + state[0] = &MS_ADPCM_state.state[0]; + state[1] = &MS_ADPCM_state.state[stereo]; + while ( encoded_len >= MS_ADPCM_state.wavefmt.blockalign ) { + /* Grab the initial information for this block */ + state[0]->hPredictor = *encoded++; + if ( stereo ) { + state[1]->hPredictor = *encoded++; + } + state[0]->iDelta = ((encoded[1]<<8)|encoded[0]); + encoded += sizeof(Sint16); + if ( stereo ) { + state[1]->iDelta = ((encoded[1]<<8)|encoded[0]); + encoded += sizeof(Sint16); + } + state[0]->iSamp1 = ((encoded[1]<<8)|encoded[0]); + encoded += sizeof(Sint16); + if ( stereo ) { + state[1]->iSamp1 = ((encoded[1]<<8)|encoded[0]); + encoded += sizeof(Sint16); + } + state[0]->iSamp2 = ((encoded[1]<<8)|encoded[0]); + encoded += sizeof(Sint16); + if ( stereo ) { + state[1]->iSamp2 = ((encoded[1]<<8)|encoded[0]); + encoded += sizeof(Sint16); + } + coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor]; + coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor]; + + /* Store the two initial samples we start with */ + decoded[0] = state[0]->iSamp2&0xFF; + decoded[1] = state[0]->iSamp2>>8; + decoded += 2; + if ( stereo ) { + decoded[0] = state[1]->iSamp2&0xFF; + decoded[1] = state[1]->iSamp2>>8; + decoded += 2; + } + decoded[0] = state[0]->iSamp1&0xFF; + decoded[1] = state[0]->iSamp1>>8; + decoded += 2; + if ( stereo ) { + decoded[0] = state[1]->iSamp1&0xFF; + decoded[1] = state[1]->iSamp1>>8; + decoded += 2; + } + + /* Decode and store the other samples in this block */ + samplesleft = (MS_ADPCM_state.wSamplesPerBlock-2)* + MS_ADPCM_state.wavefmt.channels; + while ( samplesleft > 0 ) { + nybble = (*encoded)>>4; + new_sample = MS_ADPCM_nibble(state[0],nybble,coeff[0]); + decoded[0] = new_sample&0xFF; + new_sample >>= 8; + decoded[1] = new_sample&0xFF; + decoded += 2; + + nybble = (*encoded)&0x0F; + new_sample = MS_ADPCM_nibble(state[1],nybble,coeff[1]); + decoded[0] = new_sample&0xFF; + new_sample >>= 8; + decoded[1] = new_sample&0xFF; + decoded += 2; + + ++encoded; + samplesleft -= 2; + } + encoded_len -= MS_ADPCM_state.wavefmt.blockalign; + } + free(freeable); + return(0); +} + +struct IMA_ADPCM_decodestate { + Sint32 sample; + Sint8 index; +}; +static struct IMA_ADPCM_decoder { + WaveFMT wavefmt; + Uint16 wSamplesPerBlock; + /* * * */ + struct IMA_ADPCM_decodestate state[2]; +} IMA_ADPCM_state; + +static int InitIMA_ADPCM(WaveFMT *format) +{ + Uint8 *rogue_feel; + Uint16 extra_info; + + /* Set the rogue pointer to the IMA_ADPCM specific data */ + IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); + IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); + IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); + IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); + IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); + IMA_ADPCM_state.wavefmt.bitspersample = + SDL_SwapLE16(format->bitspersample); + rogue_feel = (Uint8 *)format+sizeof(*format); + if ( sizeof(*format) == 16 ) { + extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]); + rogue_feel += sizeof(Uint16); + } + IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); + return(0); +} + +static Sint32 IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state,Uint8 nybble) +{ + const Sint32 max_audioval = ((1<<(16-1))-1); + const Sint32 min_audioval = -(1<<(16-1)); + const int index_table[16] = { + -1, -1, -1, -1, + 2, 4, 6, 8, + -1, -1, -1, -1, + 2, 4, 6, 8 + }; + const Sint32 step_table[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, + 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, + 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, + 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, + 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, + 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, + 22385, 24623, 27086, 29794, 32767 + }; + Sint32 delta, step; + + /* Compute difference and new sample value */ + step = step_table[state->index]; + delta = step >> 3; + if ( nybble & 0x04 ) delta += step; + if ( nybble & 0x02 ) delta += (step >> 1); + if ( nybble & 0x01 ) delta += (step >> 2); + if ( nybble & 0x08 ) delta = -delta; + state->sample += delta; + + /* Update index value */ + state->index += index_table[nybble]; + if ( state->index > 88 ) { + state->index = 88; + } else + if ( state->index < 0 ) { + state->index = 0; + } + + /* Clamp output sample */ + if ( state->sample > max_audioval ) { + state->sample = max_audioval; + } else + if ( state->sample < min_audioval ) { + state->sample = min_audioval; + } + return(state->sample); +} + +/* Fill the decode buffer with a channel block of data (8 samples) */ +static void Fill_IMA_ADPCM_block(Uint8 *decoded, Uint8 *encoded, + int channel, int numchannels, struct IMA_ADPCM_decodestate *state) +{ + int i; + Sint8 nybble; + Sint32 new_sample; + + decoded += (channel * 2); + for ( i=0; i<4; ++i ) { + nybble = (*encoded)&0x0F; + new_sample = IMA_ADPCM_nibble(state, nybble); + decoded[0] = new_sample&0xFF; + new_sample >>= 8; + decoded[1] = new_sample&0xFF; + decoded += 2 * numchannels; + + nybble = (*encoded)>>4; + new_sample = IMA_ADPCM_nibble(state, nybble); + decoded[0] = new_sample&0xFF; + new_sample >>= 8; + decoded[1] = new_sample&0xFF; + decoded += 2 * numchannels; + + ++encoded; + } +} + +static int IMA_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) +{ + struct IMA_ADPCM_decodestate *state; + Uint8 *freeable, *encoded, *decoded; + Sint32 encoded_len, samplesleft; + int c, channels; + + /* Check to make sure we have enough variables in the state array */ + channels = IMA_ADPCM_state.wavefmt.channels; + if ( channels > NELEMS(IMA_ADPCM_state.state) ) { + SDL_SetError("IMA ADPCM decoder can only handle %d channels", + NELEMS(IMA_ADPCM_state.state)); + return(-1); + } + state = IMA_ADPCM_state.state; + + /* Allocate the proper sized output buffer */ + encoded_len = *audio_len; + encoded = *audio_buf; + freeable = *audio_buf; + *audio_len = (encoded_len/IMA_ADPCM_state.wavefmt.blockalign) * + IMA_ADPCM_state.wSamplesPerBlock* + IMA_ADPCM_state.wavefmt.channels*sizeof(Sint16); + *audio_buf = (Uint8 *)malloc(*audio_len); + if ( *audio_buf == NULL ) { + SDL_Error(SDL_ENOMEM); + return(-1); + } + decoded = *audio_buf; + + /* Get ready... Go! */ + while ( encoded_len >= IMA_ADPCM_state.wavefmt.blockalign ) { + /* Grab the initial information for this block */ + for ( c=0; c>8; + decoded += 2; + } + + /* Decode and store the other samples in this block */ + samplesleft = (IMA_ADPCM_state.wSamplesPerBlock-1)*channels; + while ( samplesleft > 0 ) { + for ( c=0; cencoding)) { + case PCM_CODE: + /* We can understand this */ + break; + case MS_ADPCM_CODE: + /* Try to understand this */ + if ( InitMS_ADPCM(format) < 0 ) { + was_error = 1; + goto done; + } + MS_ADPCM_encoded = 1; + break; + case IMA_ADPCM_CODE: + /* Try to understand this */ + if ( InitIMA_ADPCM(format) < 0 ) { + was_error = 1; + goto done; + } + IMA_ADPCM_encoded = 1; + break; + default: + SDL_SetError("Unknown WAVE data format: 0x%.4x", + SDL_SwapLE16(format->encoding)); + was_error = 1; + goto done; + } + memset(spec, 0, (sizeof *spec)); + spec->freq = SDL_SwapLE32(format->frequency); + switch (SDL_SwapLE16(format->bitspersample)) { + case 4: + if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) { + spec->format = AUDIO_S16; + } else { + was_error = 1; + } + break; + case 8: + spec->format = AUDIO_U8; + break; + case 16: + spec->format = AUDIO_S16; + break; + default: + was_error = 1; + break; + } + if ( was_error ) { + SDL_SetError("Unknown %d-bit PCM data format", + SDL_SwapLE16(format->bitspersample)); + goto done; + } + spec->channels = (Uint8)SDL_SwapLE16(format->channels); + spec->samples = 4096; /* Good default buffer size */ + + /* Read the audio data chunk */ + *audio_buf = NULL; + do { + if ( *audio_buf != NULL ) { + free(*audio_buf); + } + lenread = ReadChunk(src, &chunk); + if ( lenread < 0 ) { + was_error = 1; + goto done; + } + *audio_len = lenread; + *audio_buf = chunk.data; + } while ( chunk.magic != DATA ); + + if ( MS_ADPCM_encoded ) { + if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) { + was_error = 1; + goto done; + } + } + if ( IMA_ADPCM_encoded ) { + if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) { + was_error = 1; + goto done; + } + } + + /* 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 ( format != NULL ) { + free(format); + } + if ( freesrc && src ) { + SDL_RWclose(src); + } + if ( was_error ) { + spec = NULL; + } + return(spec); +} + +/* Since the WAV memory is allocated in the shared library, it must also + be freed here. (Necessary under Win32, VC++) + */ +void SDL_FreeWAV(Uint8 *audio_buf) +{ + if ( audio_buf != NULL ) { + free(audio_buf); + } +} + +static int ReadChunk(SDL_RWops *src, Chunk *chunk) +{ + chunk->magic = SDL_ReadLE32(src); + chunk->length = SDL_ReadLE32(src); + chunk->data = (Uint8 *)malloc(chunk->length); + if ( chunk->data == NULL ) { + SDL_Error(SDL_ENOMEM); + return(-1); + } + if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { + SDL_Error(SDL_EFREAD); + free(chunk->data); + return(-1); + } + return(chunk->length); +} + +#endif /* ENABLE_FILE */ diff --git a/contrib/games/wolf3d/SDL/SDL_wave.h b/contrib/games/wolf3d/SDL/SDL_wave.h new file mode 100644 index 0000000000..7f0247e3c2 --- /dev/null +++ b/contrib/games/wolf3d/SDL/SDL_wave.h @@ -0,0 +1,65 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id: SDL_wave.h,v 1.2 2001/04/26 16:50:17 hercules Exp $"; +#endif + +/* 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 0x0001 +#define MS_ADPCM_CODE 0x0002 +#define IMA_ADPCM_CODE 0x0011 +#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; + diff --git a/contrib/games/wolf3d/SDL_mixer/SDL_mixer.h b/contrib/games/wolf3d/SDL_mixer/SDL_mixer.h new file mode 100644 index 0000000000..5980dfa2c7 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/SDL_mixer.h @@ -0,0 +1,642 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 _SDL_MIXER_H +#define _SDL_MIXER_H + +#include "SDL_types.h" +#include "SDL_rwops.h" +#include "SDL_audio.h" +#include "SDL_endian.h" +#include "SDL_version.h" +#include "begin_code.h" + +#define SDLCALL +#define RW_SEEK_SET SEEK_SET +#define SDL_free free +#define SDL_malloc malloc +#define SDL_realloc realloc +#define SDL_calloc calloc +#define SDL_abs abs + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL +*/ +#define SDL_MIXER_MAJOR_VERSION 1 +#define SDL_MIXER_MINOR_VERSION 2 +#define SDL_MIXER_PATCHLEVEL 12 + +/* This macro can be used to fill a version structure with the compile-time + * version of the SDL_mixer library. + */ +#define SDL_MIXER_VERSION(X) \ +{ \ + (X)->major = SDL_MIXER_MAJOR_VERSION; \ + (X)->minor = SDL_MIXER_MINOR_VERSION; \ + (X)->patch = SDL_MIXER_PATCHLEVEL; \ +} + +/* Backwards compatibility */ +#define MIX_MAJOR_VERSION SDL_MIXER_MAJOR_VERSION +#define MIX_MINOR_VERSION SDL_MIXER_MINOR_VERSION +#define MIX_PATCHLEVEL SDL_MIXER_PATCHLEVEL +#define MIX_VERSION(X) SDL_MIXER_VERSION(X) + +/* This function gets the version of the dynamically linked SDL_mixer library. + it should NOT be used to fill a version structure, instead you should + use the SDL_MIXER_VERSION() macro. + */ +extern DECLSPEC const SDL_version * SDLCALL Mix_Linked_Version(void); + +typedef enum +{ + MIX_INIT_FLAC = 0x00000001, + MIX_INIT_MOD = 0x00000002, + MIX_INIT_MP3 = 0x00000004, + MIX_INIT_OGG = 0x00000008, + MIX_INIT_FLUIDSYNTH = 0x00000010 +} MIX_InitFlags; + +/* Loads dynamic libraries and prepares them for use. Flags should be + one or more flags from MIX_InitFlags OR'd together. + It returns the flags successfully initialized, or 0 on failure. + */ +extern DECLSPEC int SDLCALL Mix_Init(int flags); + +/* Unloads libraries loaded with Mix_Init */ +extern DECLSPEC void SDLCALL Mix_Quit(void); + + +/* The default mixer has 8 simultaneous mixing channels */ +#ifndef MIX_CHANNELS +#define MIX_CHANNELS 8 +#endif + +/* Good default values for a PC soundcard */ +#define MIX_DEFAULT_FREQUENCY 22050 +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#define MIX_DEFAULT_FORMAT AUDIO_S16LSB +#else +#define MIX_DEFAULT_FORMAT AUDIO_S16MSB +#endif +#define MIX_DEFAULT_CHANNELS 2 +#define MIX_MAX_VOLUME 128 /* Volume of a chunk */ + +/* The internal format for an audio chunk */ +typedef struct Mix_Chunk { + int allocated; + Uint8 *abuf; + Uint32 alen; + Uint8 volume; /* Per-sample volume, 0-128 */ +} Mix_Chunk; + +/* The different fading types supported */ +typedef enum { + MIX_NO_FADING, + MIX_FADING_OUT, + MIX_FADING_IN +} Mix_Fading; + +typedef enum { + MUS_NONE, + MUS_CMD, + MUS_WAV, + MUS_MOD, + MUS_MID, + MUS_OGG, + MUS_MP3, + MUS_MP3_MAD, + MUS_FLAC, + MUS_MODPLUG +} Mix_MusicType; + +/* The internal format for a music chunk interpreted via mikmod */ +typedef struct _Mix_Music Mix_Music; + +/* Open the mixer with a certain audio format */ +extern DECLSPEC int SDLCALL Mix_OpenAudio(int frequency, Uint16 format, int channels, + int chunksize); + +/* Dynamically change the number of channels managed by the mixer. + If decreasing the number of channels, the upper channels are + stopped. + This function returns the new number of allocated channels. + */ +extern DECLSPEC int SDLCALL Mix_AllocateChannels(int numchans); + +/* Find out what the actual audio device parameters are. + This function returns 1 if the audio has been opened, 0 otherwise. + */ +extern DECLSPEC int SDLCALL Mix_QuerySpec(int *frequency,Uint16 *format,int *channels); + +/* Load a wave file or a music (.mod .s3m .it .xm) file */ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_LoadWAV_RW(SDL_RWops *src, int freesrc); +#define Mix_LoadWAV(file) Mix_LoadWAV_RW(SDL_RWFromFile(file, "rb"), 1) +extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUS(const char *file); + +/* Load a music file from an SDL_RWop object (Ogg and MikMod specific currently) + Matt Campbell (matt@campbellhome.dhs.org) April 2000 */ +extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUS_RW(SDL_RWops *rw); + +/* Load a music file from an SDL_RWop object assuming a specific format */ +extern DECLSPEC Mix_Music * SDLCALL Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc); + +/* Load a wave file of the mixer format from a memory buffer */ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_QuickLoad_WAV(Uint8 *mem); + +/* Load raw audio data of the mixer format from a memory buffer */ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len); + +/* Free an audio chunk previously loaded */ +extern DECLSPEC void SDLCALL Mix_FreeChunk(Mix_Chunk *chunk); +extern DECLSPEC void SDLCALL Mix_FreeMusic(Mix_Music *music); + +/* Get a list of chunk/music decoders that this build of SDL_mixer provides. + This list can change between builds AND runs of the program, if external + libraries that add functionality become available. + You must successfully call Mix_OpenAudio() before calling these functions. + This API is only available in SDL_mixer 1.2.9 and later. + + // usage... + int i; + const int total = Mix_GetNumChunkDecoders(); + for (i = 0; i < total; i++) + printf("Supported chunk decoder: [%s]\n", Mix_GetChunkDecoder(i)); + + Appearing in this list doesn't promise your specific audio file will + decode...but it's handy to know if you have, say, a functioning Timidity + install. + + These return values are static, read-only data; do not modify or free it. + The pointers remain valid until you call Mix_CloseAudio(). +*/ +extern DECLSPEC int SDLCALL Mix_GetNumChunkDecoders(void); +extern DECLSPEC const char * SDLCALL Mix_GetChunkDecoder(int index); +extern DECLSPEC int SDLCALL Mix_GetNumMusicDecoders(void); +extern DECLSPEC const char * SDLCALL Mix_GetMusicDecoder(int index); + +/* Find out the music format of a mixer music, or the currently playing + music, if 'music' is NULL. +*/ +extern DECLSPEC Mix_MusicType SDLCALL Mix_GetMusicType(const Mix_Music *music); + +/* Set a function that is called after all mixing is performed. + This can be used to provide real-time visual display of the audio stream + or add a custom mixer filter for the stream data. +*/ +extern DECLSPEC void SDLCALL Mix_SetPostMix(void (*mix_func) + (void *udata, Uint8 *stream, int len), void *arg); + +/* Add your own music player or additional mixer function. + If 'mix_func' is NULL, the default music player is re-enabled. + */ +extern DECLSPEC void SDLCALL Mix_HookMusic(void (*mix_func) + (void *udata, Uint8 *stream, int len), void *arg); + +/* Add your own callback when the music has finished playing. + This callback is only called if the music finishes naturally. + */ +extern DECLSPEC void SDLCALL Mix_HookMusicFinished(void (*music_finished)(void)); + +/* Get a pointer to the user data for the current music hook */ +extern DECLSPEC void * SDLCALL Mix_GetMusicHookData(void); + +/* + * Add your own callback when a channel has finished playing. NULL + * to disable callback. The callback may be called from the mixer's audio + * callback or it could be called as a result of Mix_HaltChannel(), etc. + * do not call SDL_LockAudio() from this callback; you will either be + * inside the audio callback, or SDL_mixer will explicitly lock the audio + * before calling your callback. + */ +extern DECLSPEC void SDLCALL Mix_ChannelFinished(void (*channel_finished)(int channel)); + + +/* Special Effects API by ryan c. gordon. (icculus@icculus.org) */ + +#define MIX_CHANNEL_POST -2 + +/* This is the format of a special effect callback: + * + * myeffect(int chan, void *stream, int len, void *udata); + * + * (chan) is the channel number that your effect is affecting. (stream) is + * the buffer of data to work upon. (len) is the size of (stream), and + * (udata) is a user-defined bit of data, which you pass as the last arg of + * Mix_RegisterEffect(), and is passed back unmolested to your callback. + * Your effect changes the contents of (stream) based on whatever parameters + * are significant, or just leaves it be, if you prefer. You can do whatever + * you like to the buffer, though, and it will continue in its changed state + * down the mixing pipeline, through any other effect functions, then finally + * to be mixed with the rest of the channels and music for the final output + * stream. + * + * DO NOT EVER call SDL_LockAudio() from your callback function! + */ +typedef void (*Mix_EffectFunc_t)(int chan, void *stream, int len, void *udata); + +/* + * This is a callback that signifies that a channel has finished all its + * loops and has completed playback. This gets called if the buffer + * plays out normally, or if you call Mix_HaltChannel(), implicitly stop + * a channel via Mix_AllocateChannels(), or unregister a callback while + * it's still playing. + * + * DO NOT EVER call SDL_LockAudio() from your callback function! + */ +typedef void (*Mix_EffectDone_t)(int chan, void *udata); + + +/* Register a special effect function. At mixing time, the channel data is + * copied into a buffer and passed through each registered effect function. + * After it passes through all the functions, it is mixed into the final + * output stream. The copy to buffer is performed once, then each effect + * function performs on the output of the previous effect. Understand that + * this extra copy to a buffer is not performed if there are no effects + * registered for a given chunk, which saves CPU cycles, and any given + * effect will be extra cycles, too, so it is crucial that your code run + * fast. Also note that the data that your function is given is in the + * format of the sound device, and not the format you gave to Mix_OpenAudio(), + * although they may in reality be the same. This is an unfortunate but + * necessary speed concern. Use Mix_QuerySpec() to determine if you can + * handle the data before you register your effect, and take appropriate + * actions. + * You may also specify a callback (Mix_EffectDone_t) that is called when + * the channel finishes playing. This gives you a more fine-grained control + * than Mix_ChannelFinished(), in case you need to free effect-specific + * resources, etc. If you don't need this, you can specify NULL. + * You may set the callbacks before or after calling Mix_PlayChannel(). + * Things like Mix_SetPanning() are just internal special effect functions, + * so if you are using that, you've already incurred the overhead of a copy + * to a separate buffer, and that these effects will be in the queue with + * any functions you've registered. The list of registered effects for a + * channel is reset when a chunk finishes playing, so you need to explicitly + * set them with each call to Mix_PlayChannel*(). + * You may also register a special effect function that is to be run after + * final mixing occurs. The rules for these callbacks are identical to those + * in Mix_RegisterEffect, but they are run after all the channels and the + * music have been mixed into a single stream, whereas channel-specific + * effects run on a given channel before any other mixing occurs. These + * global effect callbacks are call "posteffects". Posteffects only have + * their Mix_EffectDone_t function called when they are unregistered (since + * the main output stream is never "done" in the same sense as a channel). + * You must unregister them manually when you've had enough. Your callback + * will be told that the channel being mixed is (MIX_CHANNEL_POST) if the + * processing is considered a posteffect. + * + * After all these effects have finished processing, the callback registered + * through Mix_SetPostMix() runs, and then the stream goes to the audio + * device. + * + * DO NOT EVER call SDL_LockAudio() from your callback function! + * + * returns zero if error (no such channel), nonzero if added. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_RegisterEffect(int chan, Mix_EffectFunc_t f, + Mix_EffectDone_t d, void *arg); + + +/* You may not need to call this explicitly, unless you need to stop an + * effect from processing in the middle of a chunk's playback. + * Posteffects are never implicitly unregistered as they are for channels, + * but they may be explicitly unregistered through this function by + * specifying MIX_CHANNEL_POST for a channel. + * returns zero if error (no such channel or effect), nonzero if removed. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f); + + +/* You may not need to call this explicitly, unless you need to stop all + * effects from processing in the middle of a chunk's playback. Note that + * this will also shut off some internal effect processing, since + * Mix_SetPanning() and others may use this API under the hood. This is + * called internally when a channel completes playback. + * Posteffects are never implicitly unregistered as they are for channels, + * but they may be explicitly unregistered through this function by + * specifying MIX_CHANNEL_POST for a channel. + * returns zero if error (no such channel), nonzero if all effects removed. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_UnregisterAllEffects(int channel); + + +#define MIX_EFFECTSMAXSPEED "MIX_EFFECTSMAXSPEED" + +/* + * These are the internally-defined mixing effects. They use the same API that + * effects defined in the application use, but are provided here as a + * convenience. Some effects can reduce their quality or use more memory in + * the name of speed; to enable this, make sure the environment variable + * MIX_EFFECTSMAXSPEED (see above) is defined before you call + * Mix_OpenAudio(). + */ + + +/* Set the panning of a channel. The left and right channels are specified + * as integers between 0 and 255, quietest to loudest, respectively. + * + * Technically, this is just individual volume control for a sample with + * two (stereo) channels, so it can be used for more than just panning. + * If you want real panning, call it like this: + * + * Mix_SetPanning(channel, left, 255 - left); + * + * ...which isn't so hard. + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the panning will be done to the final mixed stream before passing it on + * to the audio device. + * + * This uses the Mix_RegisterEffect() API internally, and returns without + * registering the effect function if the audio device is not configured + * for stereo output. Setting both (left) and (right) to 255 causes this + * effect to be unregistered, since that is the data's normal state. + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if panning effect enabled. Note that an audio device in mono + * mode is a no-op, but this call will return successful in that case. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetPanning(int channel, Uint8 left, Uint8 right); + + +/* Set the position of a channel. (angle) is an integer from 0 to 360, that + * specifies the location of the sound in relation to the listener. (angle) + * will be reduced as neccesary (540 becomes 180 degrees, -100 becomes 260). + * Angle 0 is due north, and rotates clockwise as the value increases. + * For efficiency, the precision of this effect may be limited (angles 1 + * through 7 might all produce the same effect, 8 through 15 are equal, etc). + * (distance) is an integer between 0 and 255 that specifies the space + * between the sound and the listener. The larger the number, the further + * away the sound is. Using 255 does not guarantee that the channel will be + * culled from the mixing process or be completely silent. For efficiency, + * the precision of this effect may be limited (distance 0 through 5 might + * all produce the same effect, 6 through 10 are equal, etc). Setting (angle) + * and (distance) to 0 unregisters this effect, since the data would be + * unchanged. + * + * If you need more precise positional audio, consider using OpenAL for + * spatialized effects instead of SDL_mixer. This is only meant to be a + * basic effect for simple "3D" games. + * + * If the audio device is configured for mono output, then you won't get + * any effectiveness from the angle; however, distance attenuation on the + * channel will still occur. While this effect will function with stereo + * voices, it makes more sense to use voices with only one channel of sound, + * so when they are mixed through this effect, the positioning will sound + * correct. You can convert them to mono through SDL before giving them to + * the mixer in the first place if you like. + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the positioning will be done to the final mixed stream before passing it + * on to the audio device. + * + * This is a convenience wrapper over Mix_SetDistance() and Mix_SetPanning(). + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if position effect is enabled. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetPosition(int channel, Sint16 angle, Uint8 distance); + + +/* Set the "distance" of a channel. (distance) is an integer from 0 to 255 + * that specifies the location of the sound in relation to the listener. + * Distance 0 is overlapping the listener, and 255 is as far away as possible + * A distance of 255 does not guarantee silence; in such a case, you might + * want to try changing the chunk's volume, or just cull the sample from the + * mixing process with Mix_HaltChannel(). + * For efficiency, the precision of this effect may be limited (distances 1 + * through 7 might all produce the same effect, 8 through 15 are equal, etc). + * (distance) is an integer between 0 and 255 that specifies the space + * between the sound and the listener. The larger the number, the further + * away the sound is. + * Setting (distance) to 0 unregisters this effect, since the data would be + * unchanged. + * If you need more precise positional audio, consider using OpenAL for + * spatialized effects instead of SDL_mixer. This is only meant to be a + * basic effect for simple "3D" games. + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the distance attenuation will be done to the final mixed stream before + * passing it on to the audio device. + * + * This uses the Mix_RegisterEffect() API internally. + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if position effect is enabled. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetDistance(int channel, Uint8 distance); + + +/* + * !!! FIXME : Haven't implemented, since the effect goes past the + * end of the sound buffer. Will have to think about this. + * --ryan. + */ +#if 0 +/* Causes an echo effect to be mixed into a sound. (echo) is the amount + * of echo to mix. 0 is no echo, 255 is infinite (and probably not + * what you want). + * + * Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and + * the reverbing will be done to the final mixed stream before passing it on + * to the audio device. + * + * This uses the Mix_RegisterEffect() API internally. If you specify an echo + * of zero, the effect is unregistered, as the data is already in that state. + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if reversing effect is enabled. + * Error messages can be retrieved from Mix_GetError(). + */ +extern no_parse_DECLSPEC int SDLCALL Mix_SetReverb(int channel, Uint8 echo); +#endif + +/* Causes a channel to reverse its stereo. This is handy if the user has his + * speakers hooked up backwards, or you would like to have a minor bit of + * psychedelia in your sound code. :) Calling this function with (flip) + * set to non-zero reverses the chunks's usual channels. If (flip) is zero, + * the effect is unregistered. + * + * This uses the Mix_RegisterEffect() API internally, and thus is probably + * more CPU intensive than having the user just plug in his speakers + * correctly. Mix_SetReverseStereo() returns without registering the effect + * function if the audio device is not configured for stereo output. + * + * If you specify MIX_CHANNEL_POST for (channel), then this the effect is used + * on the final mixed stream before sending it on to the audio device (a + * posteffect). + * + * returns zero if error (no such channel or Mix_RegisterEffect() fails), + * nonzero if reversing effect is enabled. Note that an audio device in mono + * mode is a no-op, but this call will return successful in that case. + * Error messages can be retrieved from Mix_GetError(). + */ +extern DECLSPEC int SDLCALL Mix_SetReverseStereo(int channel, int flip); + +/* end of effects API. --ryan. */ + + +/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate + them dynamically to the next sample if requested with a -1 value below. + Returns the number of reserved channels. + */ +extern DECLSPEC int SDLCALL Mix_ReserveChannels(int num); + +/* Channel grouping functions */ + +/* Attach a tag to a channel. A tag can be assigned to several mixer + channels, to form groups of channels. + If 'tag' is -1, the tag is removed (actually -1 is the tag used to + represent the group of all the channels). + Returns true if everything was OK. + */ +extern DECLSPEC int SDLCALL Mix_GroupChannel(int which, int tag); +/* Assign several consecutive channels to a group */ +extern DECLSPEC int SDLCALL Mix_GroupChannels(int from, int to, int tag); +/* Finds the first available channel in a group of channels, + returning -1 if none are available. + */ +extern DECLSPEC int SDLCALL Mix_GroupAvailable(int tag); +/* Returns the number of channels in a group. This is also a subtle + way to get the total number of channels when 'tag' is -1 + */ +extern DECLSPEC int SDLCALL Mix_GroupCount(int tag); +/* Finds the "oldest" sample playing in a group of channels */ +extern DECLSPEC int SDLCALL Mix_GroupOldest(int tag); +/* Finds the "most recent" (i.e. last) sample playing in a group of channels */ +extern DECLSPEC int SDLCALL Mix_GroupNewer(int tag); + +/* Play an audio chunk on a specific channel. + If the specified channel is -1, play on the first free channel. + If 'loops' is greater than zero, loop the sound that many times. + If 'loops' is -1, loop inifinitely (~65000 times). + Returns which channel was used to play the sound. +*/ +#define Mix_PlayChannel(channel,chunk,loops) Mix_PlayChannelTimed(channel,chunk,loops,-1) +/* The same as above, but the sound is played at most 'ticks' milliseconds */ +extern DECLSPEC int SDLCALL Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks); +extern DECLSPEC int SDLCALL Mix_PlayMusic(Mix_Music *music, int loops); + +/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */ +extern DECLSPEC int SDLCALL Mix_FadeInMusic(Mix_Music *music, int loops, int ms); +extern DECLSPEC int SDLCALL Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position); +#define Mix_FadeInChannel(channel,chunk,loops,ms) Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1) +extern DECLSPEC int SDLCALL Mix_FadeInChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ms, int ticks); + +/* Set the volume in the range of 0-128 of a specific channel or chunk. + If the specified channel is -1, set volume for all channels. + Returns the original volume. + If the specified volume is -1, just return the current volume. +*/ +extern DECLSPEC int SDLCALL Mix_Volume(int channel, int volume); +extern DECLSPEC int SDLCALL Mix_VolumeChunk(Mix_Chunk *chunk, int volume); +extern DECLSPEC int SDLCALL Mix_VolumeMusic(int volume); + +/* Halt playing of a particular channel */ +extern DECLSPEC int SDLCALL Mix_HaltChannel(int channel); +extern DECLSPEC int SDLCALL Mix_HaltGroup(int tag); +extern DECLSPEC int SDLCALL Mix_HaltMusic(void); + +/* Change the expiration delay for a particular channel. + The sample will stop playing after the 'ticks' milliseconds have elapsed, + or remove the expiration if 'ticks' is -1 +*/ +extern DECLSPEC int SDLCALL Mix_ExpireChannel(int channel, int ticks); + +/* Halt a channel, fading it out progressively till it's silent + The ms parameter indicates the number of milliseconds the fading + will take. + */ +extern DECLSPEC int SDLCALL Mix_FadeOutChannel(int which, int ms); +extern DECLSPEC int SDLCALL Mix_FadeOutGroup(int tag, int ms); +extern DECLSPEC int SDLCALL Mix_FadeOutMusic(int ms); + +/* Query the fading status of a channel */ +extern DECLSPEC Mix_Fading SDLCALL Mix_FadingMusic(void); +extern DECLSPEC Mix_Fading SDLCALL Mix_FadingChannel(int which); + +/* Pause/Resume a particular channel */ +extern DECLSPEC void SDLCALL Mix_Pause(int channel); +extern DECLSPEC void SDLCALL Mix_Resume(int channel); +extern DECLSPEC int SDLCALL Mix_Paused(int channel); + +/* Pause/Resume the music stream */ +extern DECLSPEC void SDLCALL Mix_PauseMusic(void); +extern DECLSPEC void SDLCALL Mix_ResumeMusic(void); +extern DECLSPEC void SDLCALL Mix_RewindMusic(void); +extern DECLSPEC int SDLCALL Mix_PausedMusic(void); + +/* Set the current position in the music stream. + This returns 0 if successful, or -1 if it failed or isn't implemented. + This function is only implemented for MOD music formats (set pattern + order number) and for OGG, FLAC, MP3_MAD, and MODPLUG music (set + position in seconds), at the moment. +*/ +extern DECLSPEC int SDLCALL Mix_SetMusicPosition(double position); + +/* Check the status of a specific channel. + If the specified channel is -1, check all channels. +*/ +extern DECLSPEC int SDLCALL Mix_Playing(int channel); +extern DECLSPEC int SDLCALL Mix_PlayingMusic(void); + +/* Stop music and set external music playback command */ +extern DECLSPEC int SDLCALL Mix_SetMusicCMD(const char *command); + +/* Synchro value is set by MikMod from modules while playing */ +extern DECLSPEC int SDLCALL Mix_SetSynchroValue(int value); +extern DECLSPEC int SDLCALL Mix_GetSynchroValue(void); + +/* Set/Get/Iterate SoundFonts paths to use by supported MIDI backends */ +extern DECLSPEC int SDLCALL Mix_SetSoundFonts(const char *paths); +extern DECLSPEC const char* SDLCALL Mix_GetSoundFonts(void); +extern DECLSPEC int SDLCALL Mix_EachSoundFont(int (*function)(const char*, void*), void *data); + +/* Get the Mix_Chunk currently associated with a mixer channel + Returns NULL if it's an invalid channel, or there's no chunk associated. +*/ +extern DECLSPEC Mix_Chunk * SDLCALL Mix_GetChunk(int channel); + +/* Close the mixer, halting all playing audio */ +extern DECLSPEC void SDLCALL Mix_CloseAudio(void); + +/* We'll use SDL for reporting errors */ +#define Mix_SetError SDL_SetError +#define Mix_GetError SDL_GetError + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* _SDL_MIXER_H */ diff --git a/contrib/games/wolf3d/SDL_mixer/dynamic_flac.h b/contrib/games/wolf3d/SDL_mixer/dynamic_flac.h new file mode 100644 index 0000000000..e2dd3f7540 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/dynamic_flac.h @@ -0,0 +1,66 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 + +typedef struct { + int loaded; + void *handle; + FLAC__StreamDecoder *(*FLAC__stream_decoder_new)(); + void (*FLAC__stream_decoder_delete)(FLAC__StreamDecoder *decoder); + FLAC__StreamDecoderInitStatus (*FLAC__stream_decoder_init_stream)( + FLAC__StreamDecoder *decoder, + FLAC__StreamDecoderReadCallback read_callback, + FLAC__StreamDecoderSeekCallback seek_callback, + FLAC__StreamDecoderTellCallback tell_callback, + FLAC__StreamDecoderLengthCallback length_callback, + FLAC__StreamDecoderEofCallback eof_callback, + FLAC__StreamDecoderWriteCallback write_callback, + FLAC__StreamDecoderMetadataCallback metadata_callback, + FLAC__StreamDecoderErrorCallback error_callback, + void *client_data); + FLAC__bool (*FLAC__stream_decoder_finish)(FLAC__StreamDecoder *decoder); + FLAC__bool (*FLAC__stream_decoder_flush)(FLAC__StreamDecoder *decoder); + FLAC__bool (*FLAC__stream_decoder_process_single)( + FLAC__StreamDecoder *decoder); + FLAC__bool (*FLAC__stream_decoder_process_until_end_of_metadata)( + FLAC__StreamDecoder *decoder); + FLAC__bool (*FLAC__stream_decoder_process_until_end_of_stream)( + FLAC__StreamDecoder *decoder); + FLAC__bool (*FLAC__stream_decoder_seek_absolute)( + FLAC__StreamDecoder *decoder, + FLAC__uint64 sample); + FLAC__StreamDecoderState (*FLAC__stream_decoder_get_state)( + const FLAC__StreamDecoder *decoder); +} flac_loader; + +extern flac_loader flac; + +#endif /* FLAC_MUSIC */ + +extern int Mix_InitFLAC(); +extern void Mix_QuitFLAC(); diff --git a/contrib/games/wolf3d/SDL_mixer/dynamic_fluidsynth.h b/contrib/games/wolf3d/SDL_mixer/dynamic_fluidsynth.h new file mode 100644 index 0000000000..5d25232a22 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/dynamic_fluidsynth.h @@ -0,0 +1,57 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 + +typedef struct { + int loaded; + void *handle; + + int (*delete_fluid_player)(fluid_player_t*); + void (*delete_fluid_settings)(fluid_settings_t*); + int (*delete_fluid_synth)(fluid_synth_t*); + int (*fluid_player_add)(fluid_player_t*, const char*); + int (*fluid_player_add_mem)(fluid_player_t*, const void*, size_t); + int (*fluid_player_get_status)(fluid_player_t*); + int (*fluid_player_play)(fluid_player_t*); + int (*fluid_player_set_loop)(fluid_player_t*, int); + int (*fluid_player_stop)(fluid_player_t*); + int (*fluid_settings_setnum)(fluid_settings_t*, const char*, double); + fluid_settings_t* (*fluid_synth_get_settings)(fluid_synth_t*); + void (*fluid_synth_set_gain)(fluid_synth_t*, float); + int (*fluid_synth_sfload)(fluid_synth_t*, const char*, int); + int (*fluid_synth_write_s16)(fluid_synth_t*, int, void*, int, int, void*, int, int); + fluid_player_t* (*new_fluid_player)(fluid_synth_t*); + fluid_settings_t* (*new_fluid_settings)(void); + fluid_synth_t* (*new_fluid_synth)(fluid_settings_t*); +} fluidsynth_loader; + +extern fluidsynth_loader fluidsynth; + +#endif /* USE_FLUIDSYNTH_MIDI */ + +extern int Mix_InitFluidSynth(); +extern void Mix_QuitFluidSynth(); diff --git a/contrib/games/wolf3d/SDL_mixer/dynamic_mod.h b/contrib/games/wolf3d/SDL_mixer/dynamic_mod.h new file mode 100644 index 0000000000..3561b151db --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/dynamic_mod.h @@ -0,0 +1,62 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifdef MOD_MUSIC + +#include "mikmod.h" + +typedef struct { + int loaded; + void *handle; + + void (*MikMod_Exit)(void); + CHAR* (*MikMod_InfoDriver)(void); + CHAR* (*MikMod_InfoLoader)(void); + BOOL (*MikMod_Init)(CHAR*); + void (*MikMod_RegisterAllLoaders)(void); + void (*MikMod_RegisterDriver)(struct MDRIVER*); + int* MikMod_errno; + char* (*MikMod_strerror)(int); + BOOL (*Player_Active)(void); + void (*Player_Free)(MODULE*); + MODULE* (*Player_LoadGeneric)(MREADER*,int,BOOL); + void (*Player_SetPosition)(UWORD); + void (*Player_SetVolume)(SWORD); + void (*Player_Start)(MODULE*); + void (*Player_Stop)(void); + ULONG (*VC_WriteBytes)(SBYTE*,ULONG); + struct MDRIVER* drv_nos; + UWORD* md_device; + UWORD* md_mixfreq; + UWORD* md_mode; + UBYTE* md_musicvolume; + UBYTE* md_pansep; + UBYTE* md_reverb; + UBYTE* md_sndfxvolume; + UBYTE* md_volume; +} mikmod_loader; + +extern mikmod_loader mikmod; + +#endif /* MOD_MUSIC */ + +extern int Mix_InitMOD(); +extern void Mix_QuitMOD(); diff --git a/contrib/games/wolf3d/SDL_mixer/dynamic_mp3.h b/contrib/games/wolf3d/SDL_mixer/dynamic_mp3.h new file mode 100644 index 0000000000..03cbbbf9cf --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/dynamic_mp3.h @@ -0,0 +1,47 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifdef MP3_MUSIC +#include "smpeg.h" + +typedef struct { + int loaded; + void *handle; + void (*SMPEG_actualSpec)( SMPEG *mpeg, SDL_AudioSpec *spec ); + void (*SMPEG_delete)( SMPEG* mpeg ); + void (*SMPEG_enableaudio)( SMPEG* mpeg, int enable ); + void (*SMPEG_enablevideo)( SMPEG* mpeg, int enable ); + SMPEG* (*SMPEG_new_rwops)(SDL_RWops *src, SMPEG_Info* info, int sdl_audio); + void (*SMPEG_play)( SMPEG* mpeg ); + int (*SMPEG_playAudio)( SMPEG *mpeg, Uint8 *stream, int len ); + void (*SMPEG_rewind)( SMPEG* mpeg ); + void (*SMPEG_setvolume)( SMPEG* mpeg, int volume ); + void (*SMPEG_skip)( SMPEG* mpeg, float seconds ); + SMPEGstatus (*SMPEG_status)( SMPEG* mpeg ); + void (*SMPEG_stop)( SMPEG* mpeg ); +} smpeg_loader; + +extern smpeg_loader smpeg; + +#endif /* MUSIC_MP3 */ + +extern int Mix_InitMP3(); +extern void Mix_QuitMP3(); diff --git a/contrib/games/wolf3d/SDL_mixer/dynamic_ogg.h b/contrib/games/wolf3d/SDL_mixer/dynamic_ogg.h new file mode 100644 index 0000000000..822458d49e --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/dynamic_ogg.h @@ -0,0 +1,53 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#else +#include +#endif + +typedef struct { + int loaded; + void *handle; + int (*ov_clear)(OggVorbis_File *vf); + vorbis_info *(*ov_info)(OggVorbis_File *vf,int link); + int (*ov_open_callbacks)(void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks); + ogg_int64_t (*ov_pcm_total)(OggVorbis_File *vf,int i); +#ifdef OGG_USE_TREMOR + long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int *bitstream); +#else + long (*ov_read)(OggVorbis_File *vf,char *buffer,int length, int bigendianp,int word,int sgned,int *bitstream); +#endif +#ifdef OGG_USE_TREMOR + int (*ov_time_seek)(OggVorbis_File *vf,ogg_int64_t pos); +#else + int (*ov_time_seek)(OggVorbis_File *vf,double pos); +#endif +} vorbis_loader; + +extern vorbis_loader vorbis; + +#endif /* OGG_MUSIC */ + +extern int Mix_InitOgg(); +extern void Mix_QuitOgg(); diff --git a/contrib/games/wolf3d/SDL_mixer/effect_position.c b/contrib/games/wolf3d/SDL_mixer/effect_position.c new file mode 100644 index 0000000000..f7208776ce --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/effect_position.c @@ -0,0 +1,1619 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#include +#include + +#include "SDL.h" +#include "SDL_mixer.h" +#include "SDL_endian.h" + +#define __MIX_INTERNAL_EFFECT__ +#include "effects_internal.h" + +/* profile code: + #include + #include + struct timeval tv1; + struct timeval tv2; + + gettimeofday(&tv1, NULL); + + ... do your thing here ... + + gettimeofday(&tv2, NULL); + printf("%ld\n", tv2.tv_usec - tv1.tv_usec); +*/ + + +/* + * Positional effects...panning, distance attenuation, etc. + */ + +typedef struct _Eff_positionargs +{ + volatile float left_f; + volatile float right_f; + volatile Uint8 left_u8; + volatile Uint8 right_u8; + volatile float left_rear_f; + volatile float right_rear_f; + volatile float center_f; + volatile float lfe_f; + volatile Uint8 left_rear_u8; + volatile Uint8 right_rear_u8; + volatile Uint8 center_u8; + volatile Uint8 lfe_u8; + volatile float distance_f; + volatile Uint8 distance_u8; + volatile Sint16 room_angle; + volatile int in_use; + volatile int channels; +} position_args; + +static position_args **pos_args_array = NULL; +static position_args *pos_args_global = NULL; +static int position_channels = 0; + +void _Eff_PositionDeinit(void) +{ + int i; + for (i = 0; i < position_channels; i++) { + SDL_free(pos_args_array[i]); + } + + position_channels = 0; + + SDL_free(pos_args_global); + pos_args_global = NULL; + SDL_free(pos_args_array); + pos_args_array = NULL; +} + + +/* This just frees up the callback-specific data. */ +static void _Eff_PositionDone(int channel, void *udata) +{ + if (channel < 0) { + if (pos_args_global != NULL) { + SDL_free(pos_args_global); + pos_args_global = NULL; + } + } + + else if (pos_args_array[channel] != NULL) { + SDL_free(pos_args_array[channel]); + pos_args_array[channel] = NULL; + } +} + + +static void _Eff_position_u8(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint8 *ptr = (Uint8 *) stream; + int i; + + /* + * if there's only a mono channnel (the only way we wouldn't have + * a len divisible by 2 here), then left_f and right_f are always + * 1.0, and are therefore throwaways. + */ + if (len % sizeof (Uint16) != 0) { + *ptr = (Uint8) (((float) *ptr) * args->distance_f); + ptr++; + len--; + } + + if (args->room_angle == 180) + for (i = 0; i < len; i += sizeof (Uint8) * 2) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + } + else for (i = 0; i < len; i += sizeof (Uint8) * 2) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + } +} +static void _Eff_position_u8_c4(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint8 *ptr = (Uint8 *) stream; + int i; + + /* + * if there's only a mono channnel (the only way we wouldn't have + * a len divisible by 2 here), then left_f and right_f are always + * 1.0, and are therefore throwaways. + */ + if (len % sizeof (Uint16) != 0) { + *ptr = (Uint8) (((float) *ptr) * args->distance_f); + ptr++; + len--; + } + + if (args->room_angle == 0) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + } + else if (args->room_angle == 90) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + } + else if (args->room_angle == 180) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + } + else if (args->room_angle == 270) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + } +} + + +static void _Eff_position_u8_c6(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint8 *ptr = (Uint8 *) stream; + int i; + + /* + * if there's only a mono channnel (the only way we wouldn't have + * a len divisible by 2 here), then left_f and right_f are always + * 1.0, and are therefore throwaways. + */ + if (len % sizeof (Uint16) != 0) { + *ptr = (Uint8) (((float) *ptr) * args->distance_f); + ptr++; + len--; + } + + if (args->room_angle == 0) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->center_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->lfe_f) * args->distance_f) + 128); + ptr++; + } + else if (args->room_angle == 90) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f/2) + 128) + + (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f/2) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->lfe_f) * args->distance_f) + 128); + ptr++; + } + else if (args->room_angle == 180) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f/2) + 128) + + (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f/2) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->lfe_f) * args->distance_f) + 128); + ptr++; + } + else if (args->room_angle == 270) + for (i = 0; i < len; i += sizeof (Uint8) * 6) { + /* must adjust the sample so that 0 is the center */ + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_rear_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->right_f) * args->distance_f) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_f) * args->distance_f/2) + 128) + + (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->left_rear_f) * args->distance_f/2) + 128); + ptr++; + *ptr = (Uint8) ((Sint8) ((((float) (Sint8) (*ptr - 128)) + * args->lfe_f) * args->distance_f) + 128); + ptr++; + } +} + + +/* + * This one runs about 10.1 times faster than the non-table version, with + * no loss in quality. It does, however, require 64k of memory for the + * lookup table. Also, this will only update position information once per + * call; the non-table version always checks the arguments for each sample, + * in case the user has called Mix_SetPanning() or whatnot again while this + * callback is running. + */ +static void _Eff_position_table_u8(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint8 *ptr = (Uint8 *) stream; + Uint32 *p; + int i; + Uint8 *l = ((Uint8 *) _Eff_volume_table) + (256 * args->left_u8); + Uint8 *r = ((Uint8 *) _Eff_volume_table) + (256 * args->right_u8); + Uint8 *d = ((Uint8 *) _Eff_volume_table) + (256 * args->distance_u8); + + if (args->room_angle == 180) { + Uint8 *temp = l; + l = r; + r = temp; + } + /* + * if there's only a mono channnel, then l[] and r[] are always + * volume 255, and are therefore throwaways. Still, we have to + * be sure not to overrun the audio buffer... + */ + while (len % sizeof (Uint32) != 0) { + *ptr = d[l[*ptr]]; + ptr++; + if (args->channels > 1) { + *ptr = d[r[*ptr]]; + ptr++; + } + len -= args->channels; + } + + p = (Uint32 *) ptr; + + for (i = 0; i < len; i += sizeof (Uint32)) { +#if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + *p = (d[l[(*p & 0xFF000000) >> 24]] << 24) | + (d[r[(*p & 0x00FF0000) >> 16]] << 16) | + (d[l[(*p & 0x0000FF00) >> 8]] << 8) | + (d[r[(*p & 0x000000FF) ]] ) ; +#else + *p = (d[r[(*p & 0xFF000000) >> 24]] << 24) | + (d[l[(*p & 0x00FF0000) >> 16]] << 16) | + (d[r[(*p & 0x0000FF00) >> 8]] << 8) | + (d[l[(*p & 0x000000FF) ]] ) ; +#endif + ++p; + } +} + + +static void _Eff_position_s8(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Sint8 *ptr = (Sint8 *) stream; + int i; + + /* + * if there's only a mono channnel (the only way we wouldn't have + * a len divisible by 2 here), then left_f and right_f are always + * 1.0, and are therefore throwaways. + */ + if (len % sizeof (Sint16) != 0) { + *ptr = (Sint8) (((float) *ptr) * args->distance_f); + ptr++; + len--; + } + + if (args->room_angle == 180) + for (i = 0; i < len; i += sizeof (Sint8) * 2) { + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); + ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); + ptr++; + } + else + for (i = 0; i < len; i += sizeof (Sint8) * 2) { + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); + ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); + ptr++; + } +} +static void _Eff_position_s8_c4(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Sint8 *ptr = (Sint8 *) stream; + int i; + + /* + * if there's only a mono channnel (the only way we wouldn't have + * a len divisible by 2 here), then left_f and right_f are always + * 1.0, and are therefore throwaways. + */ + if (len % sizeof (Sint16) != 0) { + *ptr = (Sint8) (((float) *ptr) * args->distance_f); + ptr++; + len--; + } + + for (i = 0; i < len; i += sizeof (Sint8) * 4) { + switch (args->room_angle) { + case 0: + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + break; + case 90: + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + break; + case 180: + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + break; + case 270: + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + break; + } + } +} +static void _Eff_position_s8_c6(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Sint8 *ptr = (Sint8 *) stream; + int i; + + /* + * if there's only a mono channnel (the only way we wouldn't have + * a len divisible by 2 here), then left_f and right_f are always + * 1.0, and are therefore throwaways. + */ + if (len % sizeof (Sint16) != 0) { + *ptr = (Sint8) (((float) *ptr) * args->distance_f); + ptr++; + len--; + } + + for (i = 0; i < len; i += sizeof (Sint8) * 6) { + switch (args->room_angle) { + case 0: + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->center_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++; + break; + case 90: + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f / 2) + + (Sint8)((((float) *ptr) * args->right_f) * args->distance_f / 2); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++; + break; + case 180: + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f / 2) + + (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f / 2); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++; + break; + case 270: + *ptr = (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_rear_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->right_f) * args->distance_f); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->left_f) * args->distance_f / 2) + + (Sint8)((((float) *ptr) * args->left_rear_f) * args->distance_f / 2); ptr++; + *ptr = (Sint8)((((float) *ptr) * args->lfe_f) * args->distance_f); ptr++; + break; + } + } +} + + +/* + * This one runs about 10.1 times faster than the non-table version, with + * no loss in quality. It does, however, require 64k of memory for the + * lookup table. Also, this will only update position information once per + * call; the non-table version always checks the arguments for each sample, + * in case the user has called Mix_SetPanning() or whatnot again while this + * callback is running. + */ +static void _Eff_position_table_s8(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Sint8 *ptr = (Sint8 *) stream; + Uint32 *p; + int i; + Sint8 *l = ((Sint8 *) _Eff_volume_table) + (256 * args->left_u8); + Sint8 *r = ((Sint8 *) _Eff_volume_table) + (256 * args->right_u8); + Sint8 *d = ((Sint8 *) _Eff_volume_table) + (256 * args->distance_u8); + + if (args->room_angle == 180) { + Sint8 *temp = l; + l = r; + r = temp; + } + + + while (len % sizeof (Uint32) != 0) { + *ptr = d[l[*ptr]]; + ptr++; + if (args->channels > 1) { + *ptr = d[r[*ptr]]; + ptr++; + } + len -= args->channels; + } + + p = (Uint32 *) ptr; + + for (i = 0; i < len; i += sizeof (Uint32)) { +#if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + *p = (d[l[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) | + (d[r[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) | + (d[l[((Sint16)(Sint8)((*p & 0x0000FF00) >> 8))+128]] << 8) | + (d[r[((Sint16)(Sint8)((*p & 0x000000FF) ))+128]] ) ; +#else + *p = (d[r[((Sint16)(Sint8)((*p & 0xFF000000) >> 24))+128]] << 24) | + (d[l[((Sint16)(Sint8)((*p & 0x00FF0000) >> 16))+128]] << 16) | + (d[r[((Sint16)(Sint8)((*p & 0x0000FF00) >> 8))+128]] << 8) | + (d[l[((Sint16)(Sint8)((*p & 0x000000FF) ))+128]] ) ; +#endif + ++p; + } + + +} + + +/* !!! FIXME : Optimize the code for 16-bit samples? */ + +static void _Eff_position_u16lsb(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint16 *ptr = (Uint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Uint16) * 2) { + Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768); + Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768); + + Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f) + * args->distance_f) + 32768); + Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) + * args->distance_f) + 32768); + + if (args->room_angle == 180) { + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + } + else { + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + } + } +} +static void _Eff_position_u16lsb_c4(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint16 *ptr = (Uint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Uint16) * 4) { + Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768); + Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768); + Sint16 samplr = (Sint16) (SDL_SwapLE16(*(ptr+2)) - 32768); + Sint16 samprr = (Sint16) (SDL_SwapLE16(*(ptr+3)) - 32768); + + Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f) + * args->distance_f) + 32768); + Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) + * args->distance_f) + 32768); + Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f) + * args->distance_f) + 32768); + Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f) + * args->distance_f) + 32768); + + switch (args->room_angle) { + case 0: + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + break; + case 90: + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + break; + case 180: + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + break; + case 270: + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + break; + } + } +} +static void _Eff_position_u16lsb_c6(int chan, void *stream, int len, void *udata) +{ + volatile position_args *args = (volatile position_args *) udata; + Uint16 *ptr = (Uint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Uint16) * 6) { + Sint16 sampl = (Sint16) (SDL_SwapLE16(*(ptr+0)) - 32768); + Sint16 sampr = (Sint16) (SDL_SwapLE16(*(ptr+1)) - 32768); + Sint16 samplr = (Sint16) (SDL_SwapLE16(*(ptr+2)) - 32768); + Sint16 samprr = (Sint16) (SDL_SwapLE16(*(ptr+3)) - 32768); + Sint16 sampce = (Sint16) (SDL_SwapLE16(*(ptr+4)) - 32768); + Sint16 sampwf = (Sint16) (SDL_SwapLE16(*(ptr+5)) - 32768); + + Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f) + * args->distance_f) + 32768); + Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) + * args->distance_f) + 32768); + Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f) + * args->distance_f) + 32768); + Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f) + * args->distance_f) + 32768); + Uint16 swapce = (Uint16) ((Sint16) (((float) sampce * args->center_f) + * args->distance_f) + 32768); + Uint16 swapwf = (Uint16) ((Sint16) (((float) sampwf * args->lfe_f) + * args->distance_f) + 32768); + + switch (args->room_angle) { + case 0: + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapce); + *(ptr++) = (Uint16) SDL_SwapLE16(swapwf); + break; + case 90: + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr)/2 + (Uint16) SDL_SwapLE16(swaprr)/2; + *(ptr++) = (Uint16) SDL_SwapLE16(swapwf); + break; + case 180: + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr)/2 + (Uint16) SDL_SwapLE16(swaplr)/2; + *(ptr++) = (Uint16) SDL_SwapLE16(swapwf); + break; + case 270: + *(ptr++) = (Uint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl)/2 + (Uint16) SDL_SwapLE16(swaplr)/2; + *(ptr++) = (Uint16) SDL_SwapLE16(swapwf); + break; + } + } +} + +static void _Eff_position_s16lsb(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 2 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Sint16 *ptr = (Sint16 *) stream; + int i; + +#if 0 + if (len % (sizeof(Sint16) * 2)) { + fprintf(stderr,"Not an even number of frames! len=%d\n", len); + return; + } +#endif + + for (i = 0; i < len; i += sizeof (Sint16) * 2) { + Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) * + args->left_f) * args->distance_f); + Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) * + args->right_f) * args->distance_f); + if (args->room_angle == 180) { + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + } + else { + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + } + } +} +static void _Eff_position_s16lsb_c4(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 4 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Sint16 *ptr = (Sint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 4) { + Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) * + args->left_f) * args->distance_f); + Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) * + args->right_f) * args->distance_f); + Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) * + args->left_rear_f) * args->distance_f); + Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+2))) * + args->right_rear_f) * args->distance_f); + switch (args->room_angle) { + case 0: + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + break; + case 90: + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + break; + case 180: + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + break; + case 270: + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + break; + } + } +} + +static void _Eff_position_s16lsb_c6(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 6 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Sint16 *ptr = (Sint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 6) { + Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+0))) * + args->left_f) * args->distance_f); + Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+1))) * + args->right_f) * args->distance_f); + Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+2))) * + args->left_rear_f) * args->distance_f); + Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+3))) * + args->right_rear_f) * args->distance_f); + Sint16 swapce = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+4))) * + args->center_f) * args->distance_f); + Sint16 swapwf = (Sint16) ((((float) (Sint16) SDL_SwapLE16(*(ptr+5))) * + args->lfe_f) * args->distance_f); + switch (args->room_angle) { + case 0: + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapce); + *(ptr++) = (Sint16) SDL_SwapLE16(swapwf); + break; + case 90: + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr)/2 + (Sint16) SDL_SwapLE16(swaprr)/2; + *(ptr++) = (Sint16) SDL_SwapLE16(swapwf); + break; + case 180: + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr)/2 + (Sint16) SDL_SwapLE16(swaplr)/2; + *(ptr++) = (Sint16) SDL_SwapLE16(swapwf); + break; + case 270: + *(ptr++) = (Sint16) SDL_SwapLE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl); + *(ptr++) = (Sint16) SDL_SwapLE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapr); + *(ptr++) = (Sint16) SDL_SwapLE16(swapl)/2 + (Sint16) SDL_SwapLE16(swaplr)/2; + *(ptr++) = (Sint16) SDL_SwapLE16(swapwf); + break; + } + } +} + +static void _Eff_position_u16msb(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 2 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Uint16 *ptr = (Uint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 2) { + Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768); + Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768); + + Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f) + * args->distance_f) + 32768); + Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) + * args->distance_f) + 32768); + + if (args->room_angle == 180) { + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + } + else { + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + } + } +} +static void _Eff_position_u16msb_c4(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 4 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Uint16 *ptr = (Uint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 4) { + Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768); + Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768); + Sint16 samplr = (Sint16) (SDL_SwapBE16(*(ptr+2)) - 32768); + Sint16 samprr = (Sint16) (SDL_SwapBE16(*(ptr+3)) - 32768); + + Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f) + * args->distance_f) + 32768); + Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) + * args->distance_f) + 32768); + Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f) + * args->distance_f) + 32768); + Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f) + * args->distance_f) + 32768); + + switch (args->room_angle) { + case 0: + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + break; + case 90: + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + break; + case 180: + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + break; + case 270: + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + break; + } + } +} +static void _Eff_position_u16msb_c6(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 6 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Uint16 *ptr = (Uint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 6) { + Sint16 sampl = (Sint16) (SDL_SwapBE16(*(ptr+0)) - 32768); + Sint16 sampr = (Sint16) (SDL_SwapBE16(*(ptr+1)) - 32768); + Sint16 samplr = (Sint16) (SDL_SwapBE16(*(ptr+2)) - 32768); + Sint16 samprr = (Sint16) (SDL_SwapBE16(*(ptr+3)) - 32768); + Sint16 sampce = (Sint16) (SDL_SwapBE16(*(ptr+4)) - 32768); + Sint16 sampwf = (Sint16) (SDL_SwapBE16(*(ptr+5)) - 32768); + + Uint16 swapl = (Uint16) ((Sint16) (((float) sampl * args->left_f) + * args->distance_f) + 32768); + Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) + * args->distance_f) + 32768); + Uint16 swaplr = (Uint16) ((Sint16) (((float) samplr * args->left_rear_f) + * args->distance_f) + 32768); + Uint16 swaprr = (Uint16) ((Sint16) (((float) samprr * args->right_rear_f) + * args->distance_f) + 32768); + Uint16 swapce = (Uint16) ((Sint16) (((float) sampce * args->center_f) + * args->distance_f) + 32768); + Uint16 swapwf = (Uint16) ((Sint16) (((float) sampwf * args->lfe_f) + * args->distance_f) + 32768); + + switch (args->room_angle) { + case 0: + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapce); + *(ptr++) = (Uint16) SDL_SwapBE16(swapwf); + break; + case 90: + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr)/2 + (Uint16) SDL_SwapBE16(swaprr)/2; + *(ptr++) = (Uint16) SDL_SwapBE16(swapwf); + break; + case 180: + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr)/2 + (Uint16) SDL_SwapBE16(swaplr)/2; + *(ptr++) = (Uint16) SDL_SwapBE16(swapwf); + break; + case 270: + *(ptr++) = (Uint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl); + *(ptr++) = (Uint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapr); + *(ptr++) = (Uint16) SDL_SwapBE16(swapl)/2 + (Uint16) SDL_SwapBE16(swaplr)/2; + *(ptr++) = (Uint16) SDL_SwapBE16(swapwf); + break; + } + } +} + +static void _Eff_position_s16msb(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 2 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Sint16 *ptr = (Sint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 2) { + Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) * + args->left_f) * args->distance_f); + Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) * + args->right_f) * args->distance_f); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + } +} +static void _Eff_position_s16msb_c4(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 4 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Sint16 *ptr = (Sint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 4) { + Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) * + args->left_f) * args->distance_f); + Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) * + args->right_f) * args->distance_f); + Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+2))) * + args->left_rear_f) * args->distance_f); + Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+3))) * + args->right_rear_f) * args->distance_f); + switch (args->room_angle) { + case 0: + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + break; + case 90: + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + break; + case 180: + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + break; + case 270: + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + break; + } + } +} +static void _Eff_position_s16msb_c6(int chan, void *stream, int len, void *udata) +{ + /* 16 signed bits (lsb) * 6 channels. */ + volatile position_args *args = (volatile position_args *) udata; + Sint16 *ptr = (Sint16 *) stream; + int i; + + for (i = 0; i < len; i += sizeof (Sint16) * 6) { + Sint16 swapl = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+0))) * + args->left_f) * args->distance_f); + Sint16 swapr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+1))) * + args->right_f) * args->distance_f); + Sint16 swaplr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+2))) * + args->left_rear_f) * args->distance_f); + Sint16 swaprr = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+3))) * + args->right_rear_f) * args->distance_f); + Sint16 swapce = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+4))) * + args->center_f) * args->distance_f); + Sint16 swapwf = (Sint16) ((((float) (Sint16) SDL_SwapBE16(*(ptr+5))) * + args->lfe_f) * args->distance_f); + + switch (args->room_angle) { + case 0: + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapce); + *(ptr++) = (Sint16) SDL_SwapBE16(swapwf); + break; + case 90: + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr)/2 + (Sint16) SDL_SwapBE16(swaprr)/2; + *(ptr++) = (Sint16) SDL_SwapBE16(swapwf); + break; + case 180: + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr)/2 + (Sint16) SDL_SwapBE16(swaplr)/2; + *(ptr++) = (Sint16) SDL_SwapBE16(swapwf); + break; + case 270: + *(ptr++) = (Sint16) SDL_SwapBE16(swaplr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl); + *(ptr++) = (Sint16) SDL_SwapBE16(swaprr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapr); + *(ptr++) = (Sint16) SDL_SwapBE16(swapl)/2 + (Sint16) SDL_SwapBE16(swaplr)/2; + *(ptr++) = (Sint16) SDL_SwapBE16(swapwf); + break; + } + } +} + +static void init_position_args(position_args *args) +{ + memset(args, '\0', sizeof (position_args)); + args->in_use = 0; + args->room_angle = 0; + args->left_u8 = args->right_u8 = args->distance_u8 = 255; + args->left_f = args->right_f = args->distance_f = 1.0f; + args->left_rear_u8 = args->right_rear_u8 = args->center_u8 = args->lfe_u8 = 255; + args->left_rear_f = args->right_rear_f = args->center_f = args->lfe_f = 1.0f; + Mix_QuerySpec(NULL, NULL, (int *) &args->channels); +} + + +static position_args *get_position_arg(int channel) +{ + void *rc; + int i; + + if (channel < 0) { + if (pos_args_global == NULL) { + pos_args_global = SDL_malloc(sizeof (position_args)); + if (pos_args_global == NULL) { + Mix_SetError("Out of memory"); + return(NULL); + } + init_position_args(pos_args_global); + } + + return(pos_args_global); + } + + if (channel >= position_channels) { + rc = SDL_realloc(pos_args_array, (channel + 1) * sizeof (position_args *)); + if (rc == NULL) { + Mix_SetError("Out of memory"); + return(NULL); + } + pos_args_array = (position_args **) rc; + for (i = position_channels; i <= channel; i++) { + pos_args_array[i] = NULL; + } + position_channels = channel + 1; + } + + if (pos_args_array[channel] == NULL) { + pos_args_array[channel] = (position_args *)SDL_malloc(sizeof(position_args)); + if (pos_args_array[channel] == NULL) { + Mix_SetError("Out of memory"); + return(NULL); + } + init_position_args(pos_args_array[channel]); + } + + return(pos_args_array[channel]); +} + + +static Mix_EffectFunc_t get_position_effect_func(Uint16 format, int channels) +{ + Mix_EffectFunc_t f = NULL; + + switch (format) { + case AUDIO_U8: + switch (channels) { + case 1: + case 2: + f = (_Eff_build_volume_table_u8()) ? _Eff_position_table_u8 : + _Eff_position_u8; + break; + case 4: + f = _Eff_position_u8_c4; + break; + case 6: + f = _Eff_position_u8_c6; + break; + } + break; + + case AUDIO_S8: + switch (channels) { + case 1: + case 2: + f = (_Eff_build_volume_table_s8()) ? _Eff_position_table_s8 : + _Eff_position_s8; + break; + case 4: + f = _Eff_position_s8_c4; + break; + case 6: + f = _Eff_position_s8_c6; + break; + } + break; + + case AUDIO_U16LSB: + switch (channels) { + case 1: + case 2: + f = _Eff_position_u16lsb; + break; + case 4: + f = _Eff_position_u16lsb_c4; + break; + case 6: + f = _Eff_position_u16lsb_c6; + break; + } + break; + + case AUDIO_S16LSB: + switch (channels) { + case 1: + case 2: + f = _Eff_position_s16lsb; + break; + case 4: + f = _Eff_position_s16lsb_c4; + break; + case 6: + f = _Eff_position_s16lsb_c6; + break; + } + break; + + case AUDIO_U16MSB: + switch (channels) { + case 1: + case 2: + f = _Eff_position_u16msb; + break; + case 4: + f = _Eff_position_u16msb_c4; + break; + case 6: + f = _Eff_position_u16msb_c6; + break; + } + break; + + case AUDIO_S16MSB: + switch (channels) { + case 1: + case 2: + f = _Eff_position_s16msb; + break; + case 4: + f = _Eff_position_s16msb_c4; + break; + case 6: + f = _Eff_position_s16msb_c6; + break; + } + break; + + default: + Mix_SetError("Unsupported audio format"); + } + + return(f); +} + +static Uint8 speaker_amplitude[6]; + +static void set_amplitudes(int channels, int angle, int room_angle) +{ + int left = 255, right = 255; + int left_rear = 255, right_rear = 255, center = 255; + + angle = SDL_abs(angle) % 360; /* make angle between 0 and 359. */ + + if (channels == 2) + { + /* + * We only attenuate by position if the angle falls on the far side + * of center; That is, an angle that's due north would not attenuate + * either channel. Due west attenuates the right channel to 0.0, and + * due east attenuates the left channel to 0.0. Slightly east of + * center attenuates the left channel a little, and the right channel + * not at all. I think of this as occlusion by one's own head. :) + * + * ...so, we split our angle circle into four quadrants... + */ + if (angle < 90) { + left = 255 - ((int) (255.0f * (((float) angle) / 89.0f))); + } else if (angle < 180) { + left = (int) (255.0f * (((float) (angle - 90)) / 89.0f)); + } else if (angle < 270) { + right = 255 - ((int) (255.0f * (((float) (angle - 180)) / 89.0f))); + } else { + right = (int) (255.0f * (((float) (angle - 270)) / 89.0f)); + } + } + + if (channels == 4 || channels == 6) + { + /* + * An angle that's due north does not attenuate the center channel. + * An angle in the first quadrant, 0-90, does not attenuate the RF. + * + * ...so, we split our angle circle into 8 ... + * + * CE + * 0 + * LF | RF + * | + * 270<-------|----------->90 + * | + * LR | RR + * 180 + * + */ + if (angle < 45) { + left = ((int) (255.0f * (((float) (180 - angle)) / 179.0f))); + left_rear = 255 - ((int) (255.0f * (((float) (angle + 45)) / 89.0f))); + right_rear = 255 - ((int) (255.0f * (((float) (90 - angle)) / 179.0f))); + } else if (angle < 90) { + center = ((int) (255.0f * (((float) (225 - angle)) / 179.0f))); + left = ((int) (255.0f * (((float) (180 - angle)) / 179.0f))); + left_rear = 255 - ((int) (255.0f * (((float) (135 - angle)) / 89.0f))); + right_rear = ((int) (255.0f * (((float) (90 + angle)) / 179.0f))); + } else if (angle < 135) { + center = ((int) (255.0f * (((float) (225 - angle)) / 179.0f))); + left = 255 - ((int) (255.0f * (((float) (angle - 45)) / 89.0f))); + right = ((int) (255.0f * (((float) (270 - angle)) / 179.0f))); + left_rear = ((int) (255.0f * (((float) (angle)) / 179.0f))); + } else if (angle < 180) { + center = 255 - ((int) (255.0f * (((float) (angle - 90)) / 89.0f))); + left = 255 - ((int) (255.0f * (((float) (225 - angle)) / 89.0f))); + right = ((int) (255.0f * (((float) (270 - angle)) / 179.0f))); + left_rear = ((int) (255.0f * (((float) (angle)) / 179.0f))); + } else if (angle < 225) { + center = 255 - ((int) (255.0f * (((float) (270 - angle)) / 89.0f))); + left = ((int) (255.0f * (((float) (angle - 90)) / 179.0f))); + right = 255 - ((int) (255.0f * (((float) (angle - 135)) / 89.0f))); + right_rear = ((int) (255.0f * (((float) (360 - angle)) / 179.0f))); + } else if (angle < 270) { + center = ((int) (255.0f * (((float) (angle - 135)) / 179.0f))); + left = ((int) (255.0f * (((float) (angle - 90)) / 179.0f))); + right = 255 - ((int) (255.0f * (((float) (315 - angle)) / 89.0f))); + right_rear = ((int) (255.0f * (((float) (360 - angle)) / 179.0f))); + } else if (angle < 315) { + center = ((int) (255.0f * (((float) (angle - 135)) / 179.0f))); + right = ((int) (255.0f * (((float) (angle - 180)) / 179.0f))); + left_rear = ((int) (255.0f * (((float) (450 - angle)) / 179.0f))); + right_rear = 255 - ((int) (255.0f * (((float) (angle - 225)) / 89.0f))); + } else { + right = ((int) (255.0f * (((float) (angle - 180)) / 179.0f))); + left_rear = ((int) (255.0f * (((float) (450 - angle)) / 179.0f))); + right_rear = 255 - ((int) (255.0f * (((float) (405 - angle)) / 89.0f))); + } + } + + if (left < 0) left = 0; if (left > 255) left = 255; + if (right < 0) right = 0; if (right > 255) right = 255; + if (left_rear < 0) left_rear = 0; if (left_rear > 255) left_rear = 255; + if (right_rear < 0) right_rear = 0; if (right_rear > 255) right_rear = 255; + if (center < 0) center = 0; if (center > 255) center = 255; + + if (room_angle == 90) { + speaker_amplitude[0] = (Uint8)left_rear; + speaker_amplitude[1] = (Uint8)left; + speaker_amplitude[2] = (Uint8)right_rear; + speaker_amplitude[3] = (Uint8)right; + } + else if (room_angle == 180) { + if (channels == 2) { + speaker_amplitude[0] = (Uint8)right; + speaker_amplitude[1] = (Uint8)left; + } + else { + speaker_amplitude[0] = (Uint8)right_rear; + speaker_amplitude[1] = (Uint8)left_rear; + speaker_amplitude[2] = (Uint8)right; + speaker_amplitude[3] = (Uint8)left; + } + } + else if (room_angle == 270) { + speaker_amplitude[0] = (Uint8)right; + speaker_amplitude[1] = (Uint8)right_rear; + speaker_amplitude[2] = (Uint8)left; + speaker_amplitude[3] = (Uint8)left_rear; + } + else { + speaker_amplitude[0] = (Uint8)left; + speaker_amplitude[1] = (Uint8)right; + speaker_amplitude[2] = (Uint8)left_rear; + speaker_amplitude[3] = (Uint8)right_rear; + } + speaker_amplitude[4] = (Uint8)center; + speaker_amplitude[5] = 255; +} + +int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance); + +int Mix_SetPanning(int channel, Uint8 left, Uint8 right) +{ + Mix_EffectFunc_t f = NULL; + int channels; + Uint16 format; + position_args *args = NULL; + int retval = 1; + + Mix_QuerySpec(NULL, &format, &channels); + + if (channels != 2 && channels != 4 && channels != 6) /* it's a no-op; we call that successful. */ + return(1); + + if (channels > 2) { + /* left = right = 255 => angle = 0, to unregister effect as when channels = 2 */ + /* left = 255 => angle = -90; left = 0 => angle = +89 */ + int angle = 0; + if ((left != 255) || (right != 255)) { + angle = (int)left; + angle = 127 - angle; + angle = -angle; + angle = angle * 90 / 128; /* Make it larger for more effect? */ + } + return( Mix_SetPosition(channel, angle, 0) ); + } + + f = get_position_effect_func(format, channels); + if (f == NULL) + return(0); + + SDL_LockAudio(); + args = get_position_arg(channel); + if (!args) { + SDL_UnlockAudio(); + return(0); + } + + /* it's a no-op; unregister the effect, if it's registered. */ + if ((args->distance_u8 == 255) && (left == 255) && (right == 255)) { + if (args->in_use) { + retval = _Mix_UnregisterEffect_locked(channel, f); + SDL_UnlockAudio(); + return(retval); + } else { + SDL_UnlockAudio(); + return(1); + } + } + + args->left_u8 = left; + args->left_f = ((float) left) / 255.0f; + args->right_u8 = right; + args->right_f = ((float) right) / 255.0f; + args->room_angle = 0; + + if (!args->in_use) { + args->in_use = 1; + retval=_Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void*)args); + } + + SDL_UnlockAudio(); + return(retval); +} + + +int Mix_SetDistance(int channel, Uint8 distance) +{ + Mix_EffectFunc_t f = NULL; + Uint16 format; + position_args *args = NULL; + int channels; + int retval = 1; + + Mix_QuerySpec(NULL, &format, &channels); + f = get_position_effect_func(format, channels); + if (f == NULL) + return(0); + + SDL_LockAudio(); + args = get_position_arg(channel); + if (!args) { + SDL_UnlockAudio(); + return(0); + } + + distance = 255 - distance; /* flip it to our scale. */ + + /* it's a no-op; unregister the effect, if it's registered. */ + if ((distance == 255) && (args->left_u8 == 255) && (args->right_u8 == 255)) { + if (args->in_use) { + retval = _Mix_UnregisterEffect_locked(channel, f); + SDL_UnlockAudio(); + return(retval); + } else { + SDL_UnlockAudio(); + return(1); + } + } + + args->distance_u8 = distance; + args->distance_f = ((float) distance) / 255.0f; + if (!args->in_use) { + args->in_use = 1; + retval = _Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void *) args); + } + + SDL_UnlockAudio(); + return(retval); +} + + +int Mix_SetPosition(int channel, Sint16 angle, Uint8 distance) +{ + Mix_EffectFunc_t f = NULL; + Uint16 format; + int channels; + position_args *args = NULL; + Sint16 room_angle = 0; + int retval = 1; + + Mix_QuerySpec(NULL, &format, &channels); + f = get_position_effect_func(format, channels); + if (f == NULL) + return(0); + + angle = SDL_abs(angle) % 360; /* make angle between 0 and 359. */ + + SDL_LockAudio(); + args = get_position_arg(channel); + if (!args) { + SDL_UnlockAudio(); + return(0); + } + + /* it's a no-op; unregister the effect, if it's registered. */ + if ((!distance) && (!angle)) { + if (args->in_use) { + retval = _Mix_UnregisterEffect_locked(channel, f); + SDL_UnlockAudio(); + return(retval); + } else { + SDL_UnlockAudio(); + return(1); + } + } + + if (channels == 2) + { + if (angle > 180) + room_angle = 180; /* exchange left and right channels */ + else room_angle = 0; + } + + if (channels == 4 || channels == 6) + { + if (angle > 315) room_angle = 0; + else if (angle > 225) room_angle = 270; + else if (angle > 135) room_angle = 180; + else if (angle > 45) room_angle = 90; + else room_angle = 0; + } + + + distance = 255 - distance; /* flip it to scale Mix_SetDistance() uses. */ + + set_amplitudes(channels, angle, room_angle); + + args->left_u8 = speaker_amplitude[0]; + args->left_f = ((float) speaker_amplitude[0]) / 255.0f; + args->right_u8 = speaker_amplitude[1]; + args->right_f = ((float) speaker_amplitude[1]) / 255.0f; + args->left_rear_u8 = speaker_amplitude[2]; + args->left_rear_f = ((float) speaker_amplitude[2]) / 255.0f; + args->right_rear_u8 = speaker_amplitude[3]; + args->right_rear_f = ((float) speaker_amplitude[3]) / 255.0f; + args->center_u8 = speaker_amplitude[4]; + args->center_f = ((float) speaker_amplitude[4]) / 255.0f; + args->lfe_u8 = speaker_amplitude[5]; + args->lfe_f = ((float) speaker_amplitude[5]) / 255.0f; + args->distance_u8 = distance; + args->distance_f = ((float) distance) / 255.0f; + args->room_angle = room_angle; + if (!args->in_use) { + args->in_use = 1; + retval = _Mix_RegisterEffect_locked(channel, f, _Eff_PositionDone, (void *) args); + } + + SDL_UnlockAudio(); + return(retval); +} + + +/* end of effects_position.c ... */ + diff --git a/contrib/games/wolf3d/SDL_mixer/effects_internal.c b/contrib/games/wolf3d/SDL_mixer/effects_internal.c new file mode 100644 index 0000000000..c73e5ddf56 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/effects_internal.c @@ -0,0 +1,124 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#include +#include "SDL_mixer.h" + +#define __MIX_INTERNAL_EFFECT__ +#include "effects_internal.h" + +/* Should we favor speed over memory usage and/or quality of output? */ +int _Mix_effects_max_speed = 0; + + +void _Mix_InitEffects(void) +{ + _Mix_effects_max_speed = (SDL_getenv(MIX_EFFECTSMAXSPEED) != NULL); +} + +void _Mix_DeinitEffects(void) +{ + _Eff_PositionDeinit(); +} + + +void *_Eff_volume_table = NULL; + + +/* Build the volume table for Uint8-format samples. + * + * Each column of the table is a possible sample, while each row of the + * table is a volume. Volume is a Uint8, where 0 is silence and 255 is full + * volume. So _Eff_volume_table[128][mysample] would be the value of + * mysample, at half volume. + */ +void *_Eff_build_volume_table_u8(void) +{ + int volume; + int sample; + Uint8 *rc; + + if (!_Mix_effects_max_speed) { + return(NULL); + } + + if (!_Eff_volume_table) { + rc = SDL_malloc(256 * 256); + if (rc) { + _Eff_volume_table = (void *) rc; + for (volume = 0; volume < 256; volume++) { + for (sample = -128; sample < 128; sample ++) { + *rc = (Uint8)(((float) sample) * ((float) volume / 255.0)) + + 128; + rc++; + } + } + } + } + + return(_Eff_volume_table); +} + + +/* Build the volume table for Sint8-format samples. + * + * Each column of the table is a possible sample, while each row of the + * table is a volume. Volume is a Uint8, where 0 is silence and 255 is full + * volume. So _Eff_volume_table[128][mysample+128] would be the value of + * mysample, at half volume. + */ +void *_Eff_build_volume_table_s8(void) +{ + int volume; + int sample; + Sint8 *rc; + + if (!_Eff_volume_table) { + rc = SDL_malloc(256 * 256); + if (rc) { + _Eff_volume_table = (void *) rc; + for (volume = 0; volume < 256; volume++) { + for (sample = -128; sample < 128; sample ++) { + *rc = (Sint8)(((float) sample) * ((float) volume / 255.0)); + rc++; + } + } + } + } + + return(_Eff_volume_table); +} + + +/* end of effects.c ... */ + diff --git a/contrib/games/wolf3d/SDL_mixer/effects_internal.h b/contrib/games/wolf3d/SDL_mixer/effects_internal.h new file mode 100644 index 0000000000..12b4b3b2da --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/effects_internal.h @@ -0,0 +1,60 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* $Id$ */ + +#ifndef _INCLUDE_EFFECTS_INTERNAL_H_ +#define _INCLUDE_EFFECTS_INTERNAL_H_ + +#ifndef __MIX_INTERNAL_EFFECT__ +#error You should not include this file or use these functions. +#endif + +#include "SDL_mixer.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +extern int _Mix_effects_max_speed; +extern void *_Eff_volume_table; +void *_Eff_build_volume_table_u8(void); +void *_Eff_build_volume_table_s8(void); + +void _Mix_InitEffects(void); +void _Mix_DeinitEffects(void); +void _Eff_PositionDeinit(void); + +int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f, + Mix_EffectDone_t d, void *arg); +int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f); +int _Mix_UnregisterAllEffects_locked(int channel); + + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/contrib/games/wolf3d/SDL_mixer/fluidsynth.h b/contrib/games/wolf3d/SDL_mixer/fluidsynth.h new file mode 100644 index 0000000000..47538bbc2b --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/fluidsynth.h @@ -0,0 +1,51 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#include + +typedef struct { + SDL_AudioCVT convert; + fluid_synth_t *synth; + fluid_player_t* player; +} FluidSynthMidiSong; + +int fluidsynth_init(SDL_AudioSpec *mixer); +FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw); +void fluidsynth_freesong(FluidSynthMidiSong *song); +void fluidsynth_start(FluidSynthMidiSong *song); +void fluidsynth_stop(FluidSynthMidiSong *song); +int fluidsynth_active(FluidSynthMidiSong *song); +void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume); +int fluidsynth_playsome(FluidSynthMidiSong *song, void *stream, int len); + +#endif /* USE_FLUIDSYNTH_MIDI */ + +#endif /* _FLUIDSYNTH_H_ */ diff --git a/contrib/games/wolf3d/SDL_mixer/load_aiff.c b/contrib/games/wolf3d/SDL_mixer/load_aiff.c new file mode 100644 index 0000000000..b56537e94e --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/load_aiff.c @@ -0,0 +1,250 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#include + +#include "SDL_endian.h" +#include "SDL_mixer.h" +#include "load_aiff.h" + +/*********************************************/ +/* Define values for AIFF (IFF audio) format */ +/*********************************************/ +#define FORM 0x4d524f46 /* "FORM" */ + +#define AIFF 0x46464941 /* "AIFF" */ +#define SSND 0x444e5353 /* "SSND" */ +#define COMM 0x4d4d4f43 /* "COMM" */ + +#define _8SVX 0x58565338 /* "8SVX" */ +#define VHDR 0x52444856 /* "VHDR" */ +#define BODY 0x59444F42 /* "BODY" */ + +/* This function was taken from libsndfile. I don't pretend to fully + * understand it. + */ + +static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) +{ + /* Is the frequency outside of what we can represent with Uint32? */ + if ( (sanebuf[0] & 0x80) || (sanebuf[0] <= 0x3F) || (sanebuf[0] > 0x40) + || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) ) + return 0; + + return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) + | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); +} + +/* This function is based on SDL_LoadWAV_RW(). */ + +SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc, + SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) +{ + int was_error; + int found_SSND; + int found_COMM; + int found_VHDR; + int found_BODY; + long start = 0; + + Uint32 chunk_type; + Uint32 chunk_length; + long next_chunk; + + /* AIFF magic header */ + Uint32 FORMchunk; + Uint32 AIFFmagic; + + /* SSND chunk */ + Uint32 offset; + Uint32 blocksize; + + /* COMM format chunk */ + Uint16 channels = 0; + Uint32 numsamples = 0; + Uint16 samplesize = 0; + Uint8 sane_freq[10]; + Uint32 frequency = 0; + + /* Make sure we are passed a valid data source */ + was_error = 0; + if ( src == NULL ) { + was_error = 1; + goto done; + } + + FORMchunk = SDL_ReadLE32(src); + chunk_length = SDL_ReadBE32(src); + if ( chunk_length == AIFF ) { /* The FORMchunk has already been read */ + AIFFmagic = chunk_length; + chunk_length = FORMchunk; + FORMchunk = FORM; + } else { + AIFFmagic = SDL_ReadLE32(src); + } + if ( (FORMchunk != FORM) || ( (AIFFmagic != AIFF) && (AIFFmagic != _8SVX) ) ) { + SDL_SetError("Unrecognized file type (not AIFF nor 8SVX)"); + was_error = 1; + goto done; + } + + /* TODO: Better santity-checking. */ + + found_SSND = 0; + found_COMM = 0; + found_VHDR = 0; + found_BODY = 0; + + do { + chunk_type = SDL_ReadLE32(src); + chunk_length = SDL_ReadBE32(src); + next_chunk = SDL_RWtell(src) + chunk_length; + /* Paranoia to avoid infinite loops */ + if (chunk_length == 0) + break; + + switch (chunk_type) { + case SSND: + found_SSND = 1; + offset = SDL_ReadBE32(src); + blocksize = SDL_ReadBE32(src); + start = SDL_RWtell(src) + offset; + break; + + case COMM: + found_COMM = 1; + channels = SDL_ReadBE16(src); + numsamples = SDL_ReadBE32(src); + samplesize = SDL_ReadBE16(src); + SDL_RWread(src, sane_freq, sizeof(sane_freq), 1); + frequency = SANE_to_Uint32(sane_freq); + if (frequency == 0) { + SDL_SetError("Bad AIFF sample frequency"); + was_error = 1; + goto done; + } + break; + + case VHDR: + found_VHDR = 1; + SDL_ReadBE32(src); + SDL_ReadBE32(src); + SDL_ReadBE32(src); + frequency = SDL_ReadBE16(src); + channels = 1; + samplesize = 8; + break; + + case BODY: + found_BODY = 1; + numsamples = chunk_length; + start = SDL_RWtell(src); + break; + + default: + break; + } + /* a 0 pad byte can be stored for any odd-length chunk */ + if (chunk_length&1) + next_chunk++; + } while ( ( ( (AIFFmagic == AIFF) && ( !found_SSND || !found_COMM ) ) + || ( (AIFFmagic == _8SVX ) && ( !found_VHDR || !found_BODY ) ) ) + && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != 1 ); + + if ( (AIFFmagic == AIFF) && !found_SSND ) { + SDL_SetError("Bad AIFF (no SSND chunk)"); + was_error = 1; + goto done; + } + + if ( (AIFFmagic == AIFF) && !found_COMM ) { + SDL_SetError("Bad AIFF (no COMM chunk)"); + was_error = 1; + goto done; + } + + if ( (AIFFmagic == _8SVX) && !found_VHDR ) { + SDL_SetError("Bad 8SVX (no VHDR chunk)"); + was_error = 1; + goto done; + } + + if ( (AIFFmagic == _8SVX) && !found_BODY ) { + SDL_SetError("Bad 8SVX (no BODY chunk)"); + was_error = 1; + goto done; + } + + /* Decode the audio data format */ + memset(spec, 0, sizeof(*spec)); + spec->freq = frequency; + switch (samplesize) { + case 8: + spec->format = AUDIO_S8; + break; + case 16: + spec->format = AUDIO_S16MSB; + break; + default: + SDL_SetError("Unsupported AIFF samplesize"); + was_error = 1; + goto done; + } + spec->channels = (Uint8) channels; + spec->samples = 4096; /* Good default buffer size */ + + *audio_len = channels * numsamples * (samplesize / 8); + *audio_buf = (Uint8 *)SDL_malloc(*audio_len); + if ( *audio_buf == NULL ) { + SDL_SetError("Out of memory"); + return(NULL); + } + SDL_RWseek(src, start, RW_SEEK_SET); + if ( SDL_RWread(src, *audio_buf, *audio_len, 1) != 1 ) { + SDL_SetError("Unable to read audio data"); + return(NULL); + } + + /* Don't return a buffer that isn't a multiple of samplesize */ + *audio_len &= ~((samplesize / 8) - 1); + +done: + if ( freesrc && src ) { + SDL_RWclose(src); + } + if ( was_error ) { + spec = NULL; + } + return(spec); +} + diff --git a/contrib/games/wolf3d/SDL_mixer/load_aiff.h b/contrib/games/wolf3d/SDL_mixer/load_aiff.h new file mode 100644 index 0000000000..ed55d36440 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/load_aiff.h @@ -0,0 +1,31 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + This is the source needed to decode an AIFF file into a waveform. + It's pretty straightforward once you get going. The only + externally-callable function is Mix_LoadAIFF_RW(), which is meant to + act as identically to SDL_LoadWAV_RW() as possible. + + This file by Torbjörn Andersson (torbjorn.andersson@eurotime.se) +*/ + +/* $Id$ */ + +/* Don't call this directly; use Mix_LoadWAV_RW() for now. */ +SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc, + SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len); diff --git a/contrib/games/wolf3d/SDL_mixer/load_flac.h b/contrib/games/wolf3d/SDL_mixer/load_flac.h new file mode 100644 index 0000000000..63fcd4bcd0 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/load_flac.h @@ -0,0 +1,31 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + This is the source needed to decode a FLAC into a waveform. + ~ Austen Dicken (admin@cvpcs.org). +*/ + +/* $Id: $ */ + +#ifdef FLAC_MUSIC +/* Don't call this directly; use Mix_LoadWAV_RW() for now. */ +SDL_AudioSpec *Mix_LoadFLAC_RW (SDL_RWops *src, int freesrc, + SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len); +#endif diff --git a/contrib/games/wolf3d/SDL_mixer/load_ogg.h b/contrib/games/wolf3d/SDL_mixer/load_ogg.h new file mode 100644 index 0000000000..e63b04f7b3 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/load_ogg.h @@ -0,0 +1,31 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + This is the source needed to decode an Ogg Vorbis into a waveform. + This file by Vaclav Slavik (vaclav.slavik@matfyz.cz). +*/ + +/* $Id$ */ + +#ifdef OGG_MUSIC +/* Don't call this directly; use Mix_LoadWAV_RW() for now. */ +SDL_AudioSpec *Mix_LoadOGG_RW (SDL_RWops *src, int freesrc, + SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len); +#endif diff --git a/contrib/games/wolf3d/SDL_mixer/load_voc.c b/contrib/games/wolf3d/SDL_mixer/load_voc.c new file mode 100644 index 0000000000..ba489fc472 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/load_voc.c @@ -0,0 +1,462 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#include +#include + +#include "SDL_mutex.h" +#include "SDL_endian.h" +#include "SDL_timer.h" + +#include "SDL_mixer.h" +#include "load_voc.h" + +/* Private data for VOC file */ +typedef struct vocstuff { + Uint32 rest; /* bytes remaining in current block */ + Uint32 rate; /* rate code (byte) of this chunk */ + int silent; /* sound or silence? */ + Uint32 srate; /* rate code (byte) of silence */ + Uint32 blockseek; /* start of current output block */ + Uint32 samples; /* number of samples output */ + Uint32 size; /* word length of data */ + Uint8 channels; /* number of sound channels */ + int has_extended; /* Has an extended block been read? */ +} vs_t; + +/* Size field */ +/* SJB: note that the 1st 3 are sometimes used as sizeof(type) */ +#define ST_SIZE_BYTE 1 +#define ST_SIZE_8BIT 1 +#define ST_SIZE_WORD 2 +#define ST_SIZE_16BIT 2 +#define ST_SIZE_DWORD 4 +#define ST_SIZE_32BIT 4 +#define ST_SIZE_FLOAT 5 +#define ST_SIZE_DOUBLE 6 +#define ST_SIZE_IEEE 7 /* IEEE 80-bit floats. */ + +/* Style field */ +#define ST_ENCODING_UNSIGNED 1 /* unsigned linear: Sound Blaster */ +#define ST_ENCODING_SIGN2 2 /* signed linear 2's comp: Mac */ +#define ST_ENCODING_ULAW 3 /* U-law signed logs: US telephony, SPARC */ +#define ST_ENCODING_ALAW 4 /* A-law signed logs: non-US telephony */ +#define ST_ENCODING_ADPCM 5 /* Compressed PCM */ +#define ST_ENCODING_IMA_ADPCM 6 /* Compressed PCM */ +#define ST_ENCODING_GSM 7 /* GSM 6.10 33-byte frame lossy compression */ + +#define VOC_TERM 0 +#define VOC_DATA 1 +#define VOC_CONT 2 +#define VOC_SILENCE 3 +#define VOC_MARKER 4 +#define VOC_TEXT 5 +#define VOC_LOOP 6 +#define VOC_LOOPEND 7 +#define VOC_EXTENDED 8 +#define VOC_DATA_16 9 + + +static int voc_check_header(SDL_RWops *src) +{ + /* VOC magic header */ + Uint8 signature[20]; /* "Creative Voice File\032" */ + Uint16 datablockofs; + + SDL_RWseek(src, 0, RW_SEEK_SET); + + if (SDL_RWread(src, signature, sizeof (signature), 1) != 1) + return(0); + + if (memcmp(signature, "Creative Voice File\032", sizeof (signature)) != 0) { + SDL_SetError("Unrecognized file type (not VOC)"); + return(0); + } + + /* get the offset where the first datablock is located */ + if (SDL_RWread(src, &datablockofs, sizeof (Uint16), 1) != 1) + return(0); + + datablockofs = SDL_SwapLE16(datablockofs); + + if (SDL_RWseek(src, datablockofs, RW_SEEK_SET) != datablockofs) + return(0); + + return(1); /* success! */ +} /* voc_check_header */ + + +/* Read next block header, save info, leave position at start of data */ +static int voc_get_block(SDL_RWops *src, vs_t *v, SDL_AudioSpec *spec) +{ + Uint8 bits24[3]; + Uint8 uc, block; + Uint32 sblen; + Uint16 new_rate_short; + Uint32 new_rate_long; + Uint8 trash[6]; + Uint16 period; + unsigned int i; + + v->silent = 0; + while (v->rest == 0) + { + if (SDL_RWread(src, &block, sizeof (block), 1) != 1) + return 1; /* assume that's the end of the file. */ + + if (block == VOC_TERM) + return 1; + + if (SDL_RWread(src, bits24, sizeof (bits24), 1) != 1) + return 1; /* assume that's the end of the file. */ + + /* Size is an 24-bit value. Ugh. */ + sblen = ( (bits24[0]) | (bits24[1] << 8) | (bits24[2] << 16) ); + + switch(block) + { + case VOC_DATA: + if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1) + return 0; + + /* When DATA block preceeded by an EXTENDED */ + /* block, the DATA blocks rate value is invalid */ + if (!v->has_extended) + { + if (uc == 0) + { + SDL_SetError("VOC Sample rate is zero?"); + return 0; + } + + if ((v->rate != -1) && (uc != v->rate)) + { + SDL_SetError("VOC sample rate codes differ"); + return 0; + } + + v->rate = uc; + spec->freq = (Uint16)(1000000.0/(256 - v->rate)); + v->channels = 1; + } + + if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1) + return 0; + + if (uc != 0) + { + SDL_SetError("VOC decoder only interprets 8-bit data"); + return 0; + } + + v->has_extended = 0; + v->rest = sblen - 2; + v->size = ST_SIZE_BYTE; + return 1; + + case VOC_DATA_16: + if (SDL_RWread(src, &new_rate_long, sizeof (new_rate_long), 1) != 1) + return 0; + new_rate_long = SDL_SwapLE32(new_rate_long); + if (new_rate_long == 0) + { + SDL_SetError("VOC Sample rate is zero?"); + return 0; + } + if ((v->rate != -1) && (new_rate_long != v->rate)) + { + SDL_SetError("VOC sample rate codes differ"); + return 0; + } + v->rate = new_rate_long; + spec->freq = new_rate_long; + + if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1) + return 0; + + switch (uc) + { + case 8: v->size = ST_SIZE_BYTE; break; + case 16: v->size = ST_SIZE_WORD; break; + default: + SDL_SetError("VOC with unknown data size"); + return 0; + } + + if (SDL_RWread(src, &v->channels, sizeof (Uint8), 1) != 1) + return 0; + + if (SDL_RWread(src, trash, sizeof (Uint8), 6) != 6) + return 0; + + v->rest = sblen - 12; + return 1; + + case VOC_CONT: + v->rest = sblen; + return 1; + + case VOC_SILENCE: + if (SDL_RWread(src, &period, sizeof (period), 1) != 1) + return 0; + period = SDL_SwapLE16(period); + + if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1) + return 0; + if (uc == 0) + { + SDL_SetError("VOC silence sample rate is zero"); + return 0; + } + + /* + * Some silence-packed files have gratuitously + * different sample rate codes in silence. + * Adjust period. + */ + if ((v->rate != -1) && (uc != v->rate)) + period = (Uint16)((period * (256 - uc))/(256 - v->rate)); + else + v->rate = uc; + v->rest = period; + v->silent = 1; + return 1; + + case VOC_LOOP: + case VOC_LOOPEND: + for(i = 0; i < sblen; i++) /* skip repeat loops. */ + { + if (SDL_RWread(src, trash, sizeof (Uint8), 1) != 1) + return 0; + } + break; + + case VOC_EXTENDED: + /* An Extended block is followed by a data block */ + /* Set this byte so we know to use the rate */ + /* value from the extended block and not the */ + /* data block. */ + v->has_extended = 1; + if (SDL_RWread(src, &new_rate_short, sizeof (new_rate_short), 1) != 1) + return 0; + new_rate_short = SDL_SwapLE16(new_rate_short); + if (new_rate_short == 0) + { + SDL_SetError("VOC sample rate is zero"); + return 0; + } + if ((v->rate != -1) && (new_rate_short != v->rate)) + { + SDL_SetError("VOC sample rate codes differ"); + return 0; + } + v->rate = new_rate_short; + + if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1) + return 0; + + if (uc != 0) + { + SDL_SetError("VOC decoder only interprets 8-bit data"); + return 0; + } + + if (SDL_RWread(src, &uc, sizeof (uc), 1) != 1) + return 0; + + if (uc) + spec->channels = 2; /* Stereo */ + /* Needed number of channels before finishing + compute for rate */ + spec->freq = (256000000L/(65536L - v->rate))/spec->channels; + /* An extended block must be followed by a data */ + /* block to be valid so loop back to top so it */ + /* can be grabed. */ + continue; + + case VOC_MARKER: + if (SDL_RWread(src, trash, sizeof (Uint8), 2) != 2) + return 0; + + /* Falling! Falling! */ + + default: /* text block or other krapola. */ + for(i = 0; i < sblen; i++) + { + if (SDL_RWread(src, &trash, sizeof (Uint8), 1) != 1) + return 0; + } + + if (block == VOC_TEXT) + continue; /* get next block */ + } + } + + return 1; +} + + +static int voc_read(SDL_RWops *src, vs_t *v, Uint8 *buf, SDL_AudioSpec *spec) +{ + int done = 0; + Uint8 silence = 0x80; + + if (v->rest == 0) + { + if (!voc_get_block(src, v, spec)) + return 0; + } + + if (v->rest == 0) + return 0; + + if (v->silent) + { + if (v->size == ST_SIZE_WORD) + silence = 0x00; + + /* Fill in silence */ + memset(buf, silence, v->rest); + done = v->rest; + v->rest = 0; + } + + else + { + done = SDL_RWread(src, buf, 1, v->rest); + v->rest -= done; + if (v->size == ST_SIZE_WORD) + { + #if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + Uint16 *samples = (Uint16 *)buf; + for (; v->rest > 0; v->rest -= 2) + { + *samples = SDL_SwapLE16(*samples); + samples++; + } + #endif + done >>= 1; + } + } + + return done; +} /* voc_read */ + + +/* don't call this directly; use Mix_LoadWAV_RW() for now. */ +SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc, + SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) +{ + vs_t v; + int was_error = 1; + int samplesize; + Uint8 *fillptr; + void *ptr; + + if ( (!src) || (!audio_buf) || (!audio_len) ) /* sanity checks. */ + goto done; + + if ( !voc_check_header(src) ) + goto done; + + v.rate = -1; + v.rest = 0; + v.has_extended = 0; + *audio_buf = NULL; + *audio_len = 0; + memset(spec, '\0', sizeof (SDL_AudioSpec)); + + if (!voc_get_block(src, &v, spec)) + goto done; + + if (v.rate == -1) + { + SDL_SetError("VOC data had no sound!"); + goto done; + } + + spec->format = ((v.size == ST_SIZE_WORD) ? AUDIO_S16 : AUDIO_U8); + if (spec->channels == 0) + spec->channels = v.channels; + + *audio_len = v.rest; + *audio_buf = SDL_malloc(v.rest); + if (*audio_buf == NULL) + goto done; + + fillptr = *audio_buf; + + while (voc_read(src, &v, fillptr, spec) > 0) + { + if (!voc_get_block(src, &v, spec)) + goto done; + + *audio_len += v.rest; + ptr = SDL_realloc(*audio_buf, *audio_len); + if (ptr == NULL) + { + SDL_free(*audio_buf); + *audio_buf = NULL; + *audio_len = 0; + goto done; + } + + *audio_buf = ptr; + fillptr = ((Uint8 *) ptr) + (*audio_len - v.rest); + } + + spec->samples = (Uint16)(*audio_len / v.size); + + was_error = 0; /* success, baby! */ + + /* Don't return a buffer that isn't a multiple of samplesize */ + samplesize = ((spec->format & 0xFF)/8)*spec->channels; + *audio_len &= ~(samplesize-1); + +done: + if (src) + { + if (freesrc) + SDL_RWclose(src); + else + SDL_RWseek(src, 0, RW_SEEK_SET); + } + + if ( was_error ) + spec = NULL; + + return(spec); +} /* Mix_LoadVOC_RW */ + +/* end of load_voc.c ... */ diff --git a/contrib/games/wolf3d/SDL_mixer/load_voc.h b/contrib/games/wolf3d/SDL_mixer/load_voc.h new file mode 100644 index 0000000000..20ae23ca40 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/load_voc.h @@ -0,0 +1,36 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + This is the source needed to decode a Creative Labs VOC file into a + waveform. It's pretty straightforward once you get going. The only + externally-callable function is Mix_LoadVOC_RW(), which is meant to + act as identically to SDL_LoadWAV_RW() as possible. + + This file by Ryan C. Gordon (icculus@icculus.org). + + Heavily borrowed from sox v12.17.1's voc.c. + (http://www.freshmeat.net/projects/sox/) +*/ + +/* $Id$ */ + +/* Don't call this directly; use Mix_LoadWAV_RW() for now. */ +SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, int freesrc, + SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len); diff --git a/contrib/games/wolf3d/SDL_mixer/mixer.c b/contrib/games/wolf3d/SDL_mixer/mixer.c new file mode 100644 index 0000000000..3a35023c32 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/mixer.c @@ -0,0 +1,1488 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* $Id$ */ + +#include +#include +#include + +#include "SDL_mutex.h" +#include "SDL_endian.h" +#include "SDL_timer.h" + +#include "SDL_mixer.h" +#include "load_aiff.h" +#include "load_voc.h" +#include "load_ogg.h" +#include "load_flac.h" +#include "dynamic_flac.h" +#include "dynamic_mod.h" +#include "dynamic_mp3.h" +#include "dynamic_ogg.h" + +#define __MIX_INTERNAL_EFFECT__ +#include "effects_internal.h" + +/* Magic numbers for various audio file formats */ +#define RIFF 0x46464952 /* "RIFF" */ +#define WAVE 0x45564157 /* "WAVE" */ +#define FORM 0x4d524f46 /* "FORM" */ +#define OGGS 0x5367674f /* "OggS" */ +#define CREA 0x61657243 /* "Crea" */ +#define FLAC 0x43614C66 /* "fLaC" */ + +static int audio_opened = 0; +static SDL_AudioSpec mixer; + +typedef struct _Mix_effectinfo +{ + Mix_EffectFunc_t callback; + Mix_EffectDone_t done_callback; + void *udata; + struct _Mix_effectinfo *next; +} effect_info; + +static struct _Mix_Channel { + Mix_Chunk *chunk; + int playing; + int paused; + Uint8 *samples; + int volume; + int looping; + int tag; + Uint32 expire; + Uint32 start_time; + Mix_Fading fading; + int fade_volume; + int fade_volume_reset; + Uint32 fade_length; + Uint32 ticks_fade; + effect_info *effects; +} *mix_channel = NULL; + +static effect_info *posteffects = NULL; + +static int num_channels; +static int reserved_channels = 0; + + +/* Support for hooking into the mixer callback system */ +static void (*mix_postmix)(void *udata, Uint8 *stream, int len) = NULL; +static void *mix_postmix_data = NULL; + +/* rcg07062001 callback to alert when channels are done playing. */ +static void (*channel_done_callback)(int channel) = NULL; + +/* Music function declarations */ +extern int open_music(SDL_AudioSpec *mixer); +extern void close_music(void); + +/* Support for user defined music functions, plus the default one */ +extern int volatile music_active; +extern void music_mixer(void *udata, Uint8 *stream, int len); +static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer; +static void *music_data = NULL; + +/* rcg06042009 report available decoders at runtime. */ +static const char **chunk_decoders = NULL; +static int num_decoders = 0; + +/* Semicolon-separated SoundFont paths */ +#ifdef MID_MUSIC +extern char* soundfont_paths; +#endif + +int Mix_GetNumChunkDecoders(void) +{ + return(num_decoders); +} + +const char *Mix_GetChunkDecoder(int index) +{ + if ((index < 0) || (index >= num_decoders)) { + return NULL; + } + return(chunk_decoders[index]); +} + +static void add_chunk_decoder(const char *decoder) +{ + void *ptr = SDL_realloc(chunk_decoders, (num_decoders + 1) * sizeof (const char **)); + if (ptr == NULL) { + return; /* oh well, go on without it. */ + } + chunk_decoders = (const char **) ptr; + chunk_decoders[num_decoders++] = decoder; +} + +/* rcg06192001 get linked library's version. */ +const SDL_version *Mix_Linked_Version(void) +{ + static SDL_version linked_version; + SDL_MIXER_VERSION(&linked_version); + return(&linked_version); +} + +static int initialized = 0; + +int Mix_Init(int flags) +{ + int result = 0; + + if (flags & MIX_INIT_FLUIDSYNTH) { +#ifdef USE_FLUIDSYNTH_MIDI + if ((initialized & MIX_INIT_FLUIDSYNTH) || Mix_InitFluidSynth() == 0) { + result |= MIX_INIT_FLUIDSYNTH; + } +#else + Mix_SetError("Mixer not built with FluidSynth support"); +#endif + } + if (flags & MIX_INIT_FLAC) { +#ifdef FLAC_MUSIC + if ((initialized & MIX_INIT_FLAC) || Mix_InitFLAC() == 0) { + result |= MIX_INIT_FLAC; + } +#else + Mix_SetError("Mixer not built with FLAC support"); +#endif + } + if (flags & MIX_INIT_MOD) { +#ifdef MOD_MUSIC + if ((initialized & MIX_INIT_MOD) || Mix_InitMOD() == 0) { + result |= MIX_INIT_MOD; + } +#else + Mix_SetError("Mixer not built with MOD support"); +#endif + } + if (flags & MIX_INIT_MP3) { +#ifdef MP3_MUSIC + if ((initialized & MIX_INIT_MP3) || Mix_InitMP3() == 0) { + result |= MIX_INIT_MP3; + } +#else + Mix_SetError("Mixer not built with MP3 support"); +#endif + } + if (flags & MIX_INIT_OGG) { +#ifdef OGG_MUSIC + if ((initialized & MIX_INIT_OGG) || Mix_InitOgg() == 0) { + result |= MIX_INIT_OGG; + } +#else + Mix_SetError("Mixer not built with Ogg Vorbis support"); +#endif + } + initialized |= result; + + return (result); +} + +void Mix_Quit() +{ +#ifdef USE_FLUIDSYNTH_MIDI + if (initialized & MIX_INIT_FLUIDSYNTH) { + Mix_QuitFluidSynth(); + } +#endif +#ifdef FLAC_MUSIC + if (initialized & MIX_INIT_FLAC) { + Mix_QuitFLAC(); + } +#endif +#ifdef MOD_MUSIC + if (initialized & MIX_INIT_MOD) { + Mix_QuitMOD(); + } +#endif +#ifdef MP3_MUSIC + if (initialized & MIX_INIT_MP3) { + Mix_QuitMP3(); + } +#endif +#ifdef OGG_MUSIC + if (initialized & MIX_INIT_OGG) { + Mix_QuitOgg(); + } +#endif +#ifdef MID_MUSIC + if (soundfont_paths) { + SDL_free(soundfont_paths); + } +#endif + initialized = 0; +} + +static int _Mix_remove_all_effects(int channel, effect_info **e); + +/* + * rcg06122001 Cleanup effect callbacks. + * MAKE SURE SDL_LockAudio() is called before this (or you're in the + * audio callback). + */ +static void _Mix_channel_done_playing(int channel) +{ + if (channel_done_callback) { + channel_done_callback(channel); + } + + /* + * Call internal function directly, to avoid locking audio from + * inside audio callback. + */ + _Mix_remove_all_effects(channel, &mix_channel[channel].effects); +} + + +static void *Mix_DoEffects(int chan, void *snd, int len) +{ + int posteffect = (chan == MIX_CHANNEL_POST); + effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects); + void *buf = snd; + + if (e != NULL) { /* are there any registered effects? */ + /* if this is the postmix, we can just overwrite the original. */ + if (!posteffect) { + buf = SDL_malloc(len); + if (buf == NULL) { + return(snd); + } + memcpy(buf, snd, len); + } + + for (; e != NULL; e = e->next) { + if (e->callback != NULL) { + e->callback(chan, buf, len, e->udata); + } + } + } + + /* be sure to SDL_free() the return value if != snd ... */ + return(buf); +} + + +/* Mixing function */ +static void mix_channels(void *udata, Uint8 *stream, int len) +{ + Uint8 *mix_input; + int i, mixable, volume = SDL_MIX_MAXVOLUME; + Uint32 sdl_ticks; + +#if SDL_VERSION_ATLEAST(1, 3, 0) + /* Need to initialize the stream in SDL 1.3+ */ + memset(stream, mixer.silence, len); +#endif + + /* Mix the music (must be done before the channels are added) */ + if ( music_active || (mix_music != music_mixer) ) { + mix_music(music_data, stream, len); + } + + /* Mix any playing channels... */ + sdl_ticks = SDL_GetTicks(); + for ( i=0; i 0 && mix_channel[i].expire < sdl_ticks ) { + /* Expiration delay for that channel is reached */ + mix_channel[i].playing = 0; + mix_channel[i].looping = 0; + mix_channel[i].fading = MIX_NO_FADING; + mix_channel[i].expire = 0; + _Mix_channel_done_playing(i); + } else if ( mix_channel[i].fading != MIX_NO_FADING ) { + Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade; + if( ticks > mix_channel[i].fade_length ) { + Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */ + if( mix_channel[i].fading == MIX_FADING_OUT ) { + mix_channel[i].playing = 0; + mix_channel[i].looping = 0; + mix_channel[i].expire = 0; + _Mix_channel_done_playing(i); + } + mix_channel[i].fading = MIX_NO_FADING; + } else { + if( mix_channel[i].fading == MIX_FADING_OUT ) { + Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks)) + / mix_channel[i].fade_length ); + } else { + Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length ); + } + } + } + if ( mix_channel[i].playing > 0 ) { + int index = 0; + int remaining = len; + while (mix_channel[i].playing > 0 && index < len) { + remaining = len - index; + volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME; + mixable = mix_channel[i].playing; + if ( mixable > remaining ) { + mixable = remaining; + } + + mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable); + SDL_MixAudio(stream+index,mix_input,mixable,volume); + if (mix_input != mix_channel[i].samples) + SDL_free(mix_input); + + mix_channel[i].samples += mixable; + mix_channel[i].playing -= mixable; + index += mixable; + + /* rcg06072001 Alert app if channel is done playing. */ + if (!mix_channel[i].playing && !mix_channel[i].looping) { + _Mix_channel_done_playing(i); + } + } + + /* If looping the sample and we are at its end, make sure + we will still return a full buffer */ + while ( mix_channel[i].looping && index < len ) { + int alen = mix_channel[i].chunk->alen; + remaining = len - index; + if (remaining > alen) { + remaining = alen; + } + + mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining); + SDL_MixAudio(stream+index, mix_input, remaining, volume); + if (mix_input != mix_channel[i].chunk->abuf) + SDL_free(mix_input); + + --mix_channel[i].looping; + mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining; + mix_channel[i].playing = mix_channel[i].chunk->alen - remaining; + index += remaining; + } + if ( ! mix_channel[i].playing && mix_channel[i].looping ) { + --mix_channel[i].looping; + mix_channel[i].samples = mix_channel[i].chunk->abuf; + mix_channel[i].playing = mix_channel[i].chunk->alen; + } + } + } + } + + /* rcg06122001 run posteffects... */ + Mix_DoEffects(MIX_CHANNEL_POST, stream, len); + + if ( mix_postmix ) { + mix_postmix(mix_postmix_data, stream, len); + } +} + +#if 0 +static void PrintFormat(char *title, SDL_AudioSpec *fmt) +{ + printf("%s: %d bit %s audio (%s) at %u Hz\n", title, (fmt->format&0xFF), + (fmt->format&0x8000) ? "signed" : "unsigned", + (fmt->channels > 2) ? "surround" : + (fmt->channels > 1) ? "stereo" : "mono", fmt->freq); +} +#endif + + +/* Open the mixer with a certain desired audio format */ +int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize) +{ + int i; + SDL_AudioSpec desired; + + /* If the mixer is already opened, increment open count */ + if ( audio_opened ) { + if ( format == mixer.format && nchannels == mixer.channels ) { + ++audio_opened; + return(0); + } + while ( audio_opened ) { + Mix_CloseAudio(); + } + } + + /* Set the desired format and frequency */ + desired.freq = frequency; + desired.format = format; + desired.channels = nchannels; + desired.samples = chunksize; + desired.callback = mix_channels; + desired.userdata = NULL; + + /* Accept nearly any audio format */ + if ( SDL_OpenAudio(&desired, &mixer) < 0 ) { + return(-1); + } +#if 0 + PrintFormat("Audio device", &mixer); +#endif + + /* Initialize the music players */ + if ( open_music(&mixer) < 0 ) { + SDL_CloseAudio(); + return(-1); + } + + num_channels = MIX_CHANNELS; + mix_channel = (struct _Mix_Channel *) SDL_malloc(num_channels * sizeof(struct _Mix_Channel)); + + /* Clear out the audio channels */ + for ( i=0; i num_channels ) { + /* Initialize the new channels */ + int i; + for(i=num_channels; i < numchans; i++) { + mix_channel[i].chunk = NULL; + mix_channel[i].playing = 0; + mix_channel[i].looping = 0; + mix_channel[i].volume = SDL_MIX_MAXVOLUME; + mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME; + mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME; + mix_channel[i].fading = MIX_NO_FADING; + mix_channel[i].tag = -1; + mix_channel[i].expire = 0; + mix_channel[i].effects = NULL; + mix_channel[i].paused = 0; + } + } + num_channels = numchans; + SDL_UnlockAudio(); + return(num_channels); +} + +/* Return the actual mixer parameters */ +int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels) +{ + if ( audio_opened ) { + if ( frequency ) { + *frequency = mixer.freq; + } + if ( format ) { + *format = mixer.format; + } + if ( channels ) { + *channels = mixer.channels; + } + } + return(audio_opened); +} + + +/* + * !!! FIXME: Ideally, we want a Mix_LoadSample_RW(), which will handle the + * generic setup, then call the correct file format loader. + */ + +/* Load a wave file */ +Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc) +{ + Uint32 magic; + Mix_Chunk *chunk; + SDL_AudioSpec wavespec, *loaded; + SDL_AudioCVT wavecvt; + int samplesize; + + /* rcg06012001 Make sure src is valid */ + if ( ! src ) { + SDL_SetError("Mix_LoadWAV_RW with NULL src"); + return(NULL); + } + + /* Make sure audio has been opened */ + if ( ! audio_opened ) { + SDL_SetError("Audio device hasn't been opened"); + if ( freesrc && src ) { + SDL_RWclose(src); + } + return(NULL); + } + + /* Allocate the chunk memory */ + chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk)); + if ( chunk == NULL ) { + SDL_SetError("Out of memory"); + if ( freesrc ) { + SDL_RWclose(src); + } + return(NULL); + } + + /* Find out what kind of audio file this is */ + magic = SDL_ReadLE32(src); + /* Seek backwards for compatibility with older loaders */ + SDL_RWseek(src, -(int)sizeof(Uint32), SEEK_CUR); + + switch (magic) { + case WAVE: + case RIFF: + loaded = SDL_LoadWAV_RW(src, freesrc, &wavespec, + (Uint8 **)&chunk->abuf, &chunk->alen); + break; + case FORM: + loaded = Mix_LoadAIFF_RW(src, freesrc, &wavespec, + (Uint8 **)&chunk->abuf, &chunk->alen); + break; +#ifdef OGG_MUSIC + case OGGS: + loaded = Mix_LoadOGG_RW(src, freesrc, &wavespec, + (Uint8 **)&chunk->abuf, &chunk->alen); + break; +#endif +#ifdef FLAC_MUSIC + case FLAC: + loaded = Mix_LoadFLAC_RW(src, freesrc, &wavespec, + (Uint8 **)&chunk->abuf, &chunk->alen); + break; +#endif + case CREA: + loaded = Mix_LoadVOC_RW(src, freesrc, &wavespec, + (Uint8 **)&chunk->abuf, &chunk->alen); + break; + default: + SDL_SetError("Unrecognized sound file type"); + return(0); + } + if ( !loaded ) { + SDL_free(chunk); + if ( freesrc ) { + SDL_RWclose(src); + } + return(NULL); + } + +#if 0 + PrintFormat("Audio device", &mixer); + PrintFormat("-- Wave file", &wavespec); +#endif + + /* Build the audio converter and create conversion buffers */ + if ( wavespec.format != mixer.format || + wavespec.channels != mixer.channels || + wavespec.freq != mixer.freq ) { + if ( SDL_BuildAudioCVT(&wavecvt, + wavespec.format, wavespec.channels, wavespec.freq, + mixer.format, mixer.channels, mixer.freq) < 0 ) { + SDL_free(chunk->abuf); + SDL_free(chunk); + return(NULL); + } + samplesize = ((wavespec.format & 0xFF)/8)*wavespec.channels; + wavecvt.len = chunk->alen & ~(samplesize-1); + wavecvt.buf = (Uint8 *)SDL_calloc(1, wavecvt.len*wavecvt.len_mult); + if ( wavecvt.buf == NULL ) { + SDL_SetError("Out of memory"); + SDL_free(chunk->abuf); + SDL_free(chunk); + return(NULL); + } + memcpy(wavecvt.buf, chunk->abuf, chunk->alen); + SDL_free(chunk->abuf); + + /* Run the audio converter */ + if ( SDL_ConvertAudio(&wavecvt) < 0 ) { + SDL_free(wavecvt.buf); + SDL_free(chunk); + return(NULL); + } + + chunk->abuf = wavecvt.buf; + chunk->alen = wavecvt.len_cvt; + } + + chunk->allocated = 1; + chunk->volume = MIX_MAX_VOLUME; + + return(chunk); +} + +/* Load a wave file of the mixer format from a memory buffer */ +Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem) +{ + Mix_Chunk *chunk; + Uint8 magic[4]; + + /* Make sure audio has been opened */ + if ( ! audio_opened ) { + SDL_SetError("Audio device hasn't been opened"); + return(NULL); + } + + /* Allocate the chunk memory */ + chunk = (Mix_Chunk *)SDL_calloc(1,sizeof(Mix_Chunk)); + if ( chunk == NULL ) { + SDL_SetError("Out of memory"); + return(NULL); + } + + /* Essentially just skip to the audio data (no error checking - fast) */ + chunk->allocated = 0; + mem += 12; /* WAV header */ + do { + memcpy(magic, mem, 4); + mem += 4; + chunk->alen = ((mem[3]<<24)|(mem[2]<<16)|(mem[1]<<8)|(mem[0])); + mem += 4; + chunk->abuf = mem; + mem += chunk->alen; + } while ( memcmp(magic, "data", 4) != 0 ); + chunk->volume = MIX_MAX_VOLUME; + + return(chunk); +} + +/* Load raw audio data of the mixer format from a memory buffer */ +Mix_Chunk *Mix_QuickLoad_RAW(Uint8 *mem, Uint32 len) +{ + Mix_Chunk *chunk; + + /* Make sure audio has been opened */ + if ( ! audio_opened ) { + SDL_SetError("Audio device hasn't been opened"); + return(NULL); + } + + /* Allocate the chunk memory */ + chunk = (Mix_Chunk *)SDL_malloc(sizeof(Mix_Chunk)); + if ( chunk == NULL ) { + SDL_SetError("Out of memory"); + return(NULL); + } + + /* Essentially just point at the audio data (no error checking - fast) */ + chunk->allocated = 0; + chunk->alen = len; + chunk->abuf = mem; + chunk->volume = MIX_MAX_VOLUME; + + return(chunk); +} + +/* Free an audio chunk previously loaded */ +void Mix_FreeChunk(Mix_Chunk *chunk) +{ + int i; + + /* Caution -- if the chunk is playing, the mixer will crash */ + if ( chunk ) { + /* Guarantee that this chunk isn't playing */ + SDL_LockAudio(); + if ( mix_channel ) { + for ( i=0; iallocated ) { + SDL_free(chunk->abuf); + } + SDL_free(chunk); + } +} + +/* Set a function that is called after all mixing is performed. + This can be used to provide real-time visual display of the audio stream + or add a custom mixer filter for the stream data. +*/ +void Mix_SetPostMix(void (*mix_func) + (void *udata, Uint8 *stream, int len), void *arg) +{ + SDL_LockAudio(); + mix_postmix_data = arg; + mix_postmix = mix_func; + SDL_UnlockAudio(); +} + +/* Add your own music player or mixer function. + If 'mix_func' is NULL, the default music player is re-enabled. + */ +void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len), + void *arg) +{ + SDL_LockAudio(); + if ( mix_func != NULL ) { + music_data = arg; + mix_music = mix_func; + } else { + music_data = NULL; + mix_music = music_mixer; + } + SDL_UnlockAudio(); +} + +void *Mix_GetMusicHookData(void) +{ + return(music_data); +} + +void Mix_ChannelFinished(void (*channel_finished)(int channel)) +{ + SDL_LockAudio(); + channel_done_callback = channel_finished; + SDL_UnlockAudio(); +} + + +/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate + them dynamically to the next sample if requested with a -1 value below. + Returns the number of reserved channels. + */ +int Mix_ReserveChannels(int num) +{ + if (num > num_channels) + num = num_channels; + reserved_channels = num; + return num; +} + +static int checkchunkintegral(Mix_Chunk *chunk) +{ + int frame_width = 1; + + if ((mixer.format & 0xFF) == 16) frame_width = 2; + frame_width *= mixer.channels; + while (chunk->alen % frame_width) chunk->alen--; + return chunk->alen; +} + +/* Play an audio chunk on a specific channel. + If the specified channel is -1, play on the first free channel. + 'ticks' is the number of milliseconds at most to play the sample, or -1 + if there is no limit. + Returns which channel was used to play the sound. +*/ +int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks) +{ + int i; + + /* Don't play null pointers :-) */ + if ( chunk == NULL ) { + Mix_SetError("Tried to play a NULL chunk"); + return(-1); + } + if ( !checkchunkintegral(chunk)) { + Mix_SetError("Tried to play a chunk with a bad frame"); + return(-1); + } + + /* Lock the mixer while modifying the playing channels */ + SDL_LockAudio(); + { + /* If which is -1, play on the first free channel */ + if ( which == -1 ) { + for ( i=reserved_channels; i= 0 && which < num_channels ) { + Uint32 sdl_ticks = SDL_GetTicks(); + if (Mix_Playing(which)) + _Mix_channel_done_playing(which); + mix_channel[which].samples = chunk->abuf; + mix_channel[which].playing = chunk->alen; + mix_channel[which].looping = loops; + mix_channel[which].chunk = chunk; + mix_channel[which].paused = 0; + mix_channel[which].fading = MIX_NO_FADING; + mix_channel[which].start_time = sdl_ticks; + mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0; + } + } + SDL_UnlockAudio(); + + /* Return the channel on which the sound is being played */ + return(which); +} + +/* Change the expiration delay for a channel */ +int Mix_ExpireChannel(int which, int ticks) +{ + int status = 0; + + if ( which == -1 ) { + int i; + for ( i=0; i < num_channels; ++ i ) { + status += Mix_ExpireChannel(i, ticks); + } + } else if ( which < num_channels ) { + SDL_LockAudio(); + mix_channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : 0; + SDL_UnlockAudio(); + ++ status; + } + return(status); +} + +/* Fade in a sound on a channel, over ms milliseconds */ +int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks) +{ + int i; + + /* Don't play null pointers :-) */ + if ( chunk == NULL ) { + return(-1); + } + if ( !checkchunkintegral(chunk)) { + Mix_SetError("Tried to play a chunk with a bad frame"); + return(-1); + } + + /* Lock the mixer while modifying the playing channels */ + SDL_LockAudio(); + { + /* If which is -1, play on the first free channel */ + if ( which == -1 ) { + for ( i=reserved_channels; i= 0 && which < num_channels ) { + Uint32 sdl_ticks = SDL_GetTicks(); + if (Mix_Playing(which)) + _Mix_channel_done_playing(which); + mix_channel[which].samples = chunk->abuf; + mix_channel[which].playing = chunk->alen; + mix_channel[which].looping = loops; + mix_channel[which].chunk = chunk; + mix_channel[which].paused = 0; + mix_channel[which].fading = MIX_FADING_IN; + mix_channel[which].fade_volume = mix_channel[which].volume; + mix_channel[which].fade_volume_reset = mix_channel[which].volume; + mix_channel[which].volume = 0; + mix_channel[which].fade_length = (Uint32)ms; + mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks; + mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0; + } + } + SDL_UnlockAudio(); + + /* Return the channel on which the sound is being played */ + return(which); +} + +/* Set volume of a particular channel */ +int Mix_Volume(int which, int volume) +{ + int i; + int prev_volume = 0; + + if ( which == -1 ) { + for ( i=0; i= 0 ) { + if ( volume > SDL_MIX_MAXVOLUME ) { + volume = SDL_MIX_MAXVOLUME; + } + mix_channel[which].volume = volume; + } + } + return(prev_volume); +} +/* Set volume of a particular chunk */ +int Mix_VolumeChunk(Mix_Chunk *chunk, int volume) +{ + int prev_volume; + + prev_volume = chunk->volume; + if ( volume >= 0 ) { + if ( volume > MIX_MAX_VOLUME ) { + volume = MIX_MAX_VOLUME; + } + chunk->volume = volume; + } + return(prev_volume); +} + +/* Halt playing of a particular channel */ +int Mix_HaltChannel(int which) +{ + int i; + + if ( which == -1 ) { + for ( i=0; i 0) && + (mix_channel[which].fading != MIX_FADING_OUT) ) { + mix_channel[which].fade_volume = mix_channel[which].volume; + mix_channel[which].fading = MIX_FADING_OUT; + mix_channel[which].fade_length = ms; + mix_channel[which].ticks_fade = SDL_GetTicks(); + + /* only change fade_volume_reset if we're not fading. */ + if (mix_channel[which].fading == MIX_NO_FADING) { + mix_channel[which].fade_volume_reset = mix_channel[which].volume; + } + ++status; + } + SDL_UnlockAudio(); + } + } + return(status); +} + +/* Halt playing of a particular group of channels */ +int Mix_FadeOutGroup(int tag, int ms) +{ + int i; + int status = 0; + for ( i=0; i= num_channels ) { + return MIX_NO_FADING; + } + return mix_channel[which].fading; +} + +/* Check the status of a specific channel. + If the specified mix_channel is -1, check all mix channels. +*/ +int Mix_Playing(int which) +{ + int status; + + status = 0; + if ( which == -1 ) { + int i; + + for ( i=0; i 0) || + (mix_channel[i].looping > 0)) + { + ++status; + } + } + } else if ( which < num_channels ) { + if ( (mix_channel[which].playing > 0) || + (mix_channel[which].looping > 0) ) + { + ++status; + } + } + return(status); +} + +/* rcg06072001 Get the chunk associated with a channel. */ +Mix_Chunk *Mix_GetChunk(int channel) +{ + Mix_Chunk *retval = NULL; + + if ((channel >= 0) && (channel < num_channels)) { + retval = mix_channel[channel].chunk; + } + + return(retval); +} + +/* Close the mixer, halting all playing audio */ +void Mix_CloseAudio(void) +{ + int i; + + if ( audio_opened ) { + if ( audio_opened == 1 ) { + for (i = 0; i < num_channels; i++) { + Mix_UnregisterAllEffects(i); + } + Mix_UnregisterAllEffects(MIX_CHANNEL_POST); + close_music(); + Mix_HaltChannel(-1); + _Mix_DeinitEffects(); + SDL_CloseAudio(); + SDL_free(mix_channel); + mix_channel = NULL; + + /* rcg06042009 report available decoders at runtime. */ + SDL_free(chunk_decoders); + chunk_decoders = NULL; + num_decoders = 0; + } + --audio_opened; + } +} + +/* Pause a particular channel (or all) */ +void Mix_Pause(int which) +{ + Uint32 sdl_ticks = SDL_GetTicks(); + if ( which == -1 ) { + int i; + + for ( i=0; i 0 ) { + mix_channel[i].paused = sdl_ticks; + } + } + } else if ( which < num_channels ) { + if ( mix_channel[which].playing > 0 ) { + mix_channel[which].paused = sdl_ticks; + } + } +} + +/* Resume a paused channel */ +void Mix_Resume(int which) +{ + Uint32 sdl_ticks = SDL_GetTicks(); + + SDL_LockAudio(); + if ( which == -1 ) { + int i; + + for ( i=0; i 0 ) { + if(mix_channel[i].expire > 0) + mix_channel[i].expire += sdl_ticks - mix_channel[i].paused; + mix_channel[i].paused = 0; + } + } + } else if ( which < num_channels ) { + if ( mix_channel[which].playing > 0 ) { + if(mix_channel[which].expire > 0) + mix_channel[which].expire += sdl_ticks - mix_channel[which].paused; + mix_channel[which].paused = 0; + } + } + SDL_UnlockAudio(); +} + +int Mix_Paused(int which) +{ + if ( which < 0 ) { + int status = 0; + int i; + for( i=0; i < num_channels; ++i ) { + if ( mix_channel[i].paused ) { + ++ status; + } + } + return(status); + } else if ( which < num_channels ) { + return(mix_channel[which].paused != 0); + } else { + return(0); + } +} + +/* Change the group of a channel */ +int Mix_GroupChannel(int which, int tag) +{ + if ( which < 0 || which > num_channels ) + return(0); + + SDL_LockAudio(); + mix_channel[which].tag = tag; + SDL_UnlockAudio(); + return(1); +} + +/* Assign several consecutive channels to a group */ +int Mix_GroupChannels(int from, int to, int tag) +{ + int status = 0; + for( ; from <= to; ++ from ) { + status += Mix_GroupChannel(from, tag); + } + return(status); +} + +/* Finds the first available channel in a group of channels */ +int Mix_GroupAvailable(int tag) +{ + int i; + for( i=0; i < num_channels; i ++ ) { + if ( ((tag == -1) || (tag == mix_channel[i].tag)) && + (mix_channel[i].playing <= 0) ) + return i; + } + return(-1); +} + +int Mix_GroupCount(int tag) +{ + int count = 0; + int i; + for( i=0; i < num_channels; i ++ ) { + if ( mix_channel[i].tag==tag || tag==-1 ) + ++ count; + } + return(count); +} + +/* Finds the "oldest" sample playing in a group of channels */ +int Mix_GroupOldest(int tag) +{ + int chan = -1; + Uint32 mintime = SDL_GetTicks(); + int i; + for( i=0; i < num_channels; i ++ ) { + if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0 + && mix_channel[i].start_time <= mintime ) { + mintime = mix_channel[i].start_time; + chan = i; + } + } + return(chan); +} + +/* Finds the "most recent" (i.e. last) sample playing in a group of channels */ +int Mix_GroupNewer(int tag) +{ + int chan = -1; + Uint32 maxtime = 0; + int i; + for( i=0; i < num_channels; i ++ ) { + if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0 + && mix_channel[i].start_time >= maxtime ) { + maxtime = mix_channel[i].start_time; + chan = i; + } + } + return(chan); +} + + + +/* + * rcg06122001 The special effects exportable API. + * Please see effect_*.c for internally-implemented effects, such + * as Mix_SetPanning(). + */ + +/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */ +static int _Mix_register_effect(effect_info **e, Mix_EffectFunc_t f, + Mix_EffectDone_t d, void *arg) +{ + effect_info *new_e; + + if (!e) { + Mix_SetError("Internal error"); + return(0); + } + + if (f == NULL) { + Mix_SetError("NULL effect callback"); + return(0); + } + + new_e = SDL_malloc(sizeof (effect_info)); + if (new_e == NULL) { + Mix_SetError("Out of memory"); + return(0); + } + + new_e->callback = f; + new_e->done_callback = d; + new_e->udata = arg; + new_e->next = NULL; + + /* add new effect to end of linked list... */ + if (*e == NULL) { + *e = new_e; + } else { + effect_info *cur = *e; + while (1) { + if (cur->next == NULL) { + cur->next = new_e; + break; + } + cur = cur->next; + } + } + + return(1); +} + + +/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */ +static int _Mix_remove_effect(int channel, effect_info **e, Mix_EffectFunc_t f) +{ + effect_info *cur; + effect_info *prev = NULL; + effect_info *next = NULL; + + if (!e) { + Mix_SetError("Internal error"); + return(0); + } + + for (cur = *e; cur != NULL; cur = cur->next) { + if (cur->callback == f) { + next = cur->next; + if (cur->done_callback != NULL) { + cur->done_callback(channel, cur->udata); + } + SDL_free(cur); + + if (prev == NULL) { /* removing first item of list? */ + *e = next; + } else { + prev->next = next; + } + return(1); + } + prev = cur; + } + + Mix_SetError("No such effect registered"); + return(0); +} + + +/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */ +static int _Mix_remove_all_effects(int channel, effect_info **e) +{ + effect_info *cur; + effect_info *next; + + if (!e) { + Mix_SetError("Internal error"); + return(0); + } + + for (cur = *e; cur != NULL; cur = next) { + next = cur->next; + if (cur->done_callback != NULL) { + cur->done_callback(channel, cur->udata); + } + SDL_free(cur); + } + *e = NULL; + + return(1); +} + + +/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */ +int _Mix_RegisterEffect_locked(int channel, Mix_EffectFunc_t f, + Mix_EffectDone_t d, void *arg) +{ + effect_info **e = NULL; + + if (channel == MIX_CHANNEL_POST) { + e = &posteffects; + } else { + if ((channel < 0) || (channel >= num_channels)) { + Mix_SetError("Invalid channel number"); + return(0); + } + e = &mix_channel[channel].effects; + } + + return _Mix_register_effect(e, f, d, arg); +} + +int Mix_RegisterEffect(int channel, Mix_EffectFunc_t f, + Mix_EffectDone_t d, void *arg) +{ + int retval; + SDL_LockAudio(); + retval = _Mix_RegisterEffect_locked(channel, f, d, arg); + SDL_UnlockAudio(); + return retval; +} + + +/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */ +int _Mix_UnregisterEffect_locked(int channel, Mix_EffectFunc_t f) +{ + effect_info **e = NULL; + + if (channel == MIX_CHANNEL_POST) { + e = &posteffects; + } else { + if ((channel < 0) || (channel >= num_channels)) { + Mix_SetError("Invalid channel number"); + return(0); + } + e = &mix_channel[channel].effects; + } + + return _Mix_remove_effect(channel, e, f); +} + +int Mix_UnregisterEffect(int channel, Mix_EffectFunc_t f) +{ + int retval; + SDL_LockAudio(); + retval = _Mix_UnregisterEffect_locked(channel, f); + SDL_UnlockAudio(); + return(retval); +} + +/* MAKE SURE you hold the audio lock (SDL_LockAudio()) before calling this! */ +int _Mix_UnregisterAllEffects_locked(int channel) +{ + effect_info **e = NULL; + + if (channel == MIX_CHANNEL_POST) { + e = &posteffects; + } else { + if ((channel < 0) || (channel >= num_channels)) { + Mix_SetError("Invalid channel number"); + return(0); + } + e = &mix_channel[channel].effects; + } + + return _Mix_remove_all_effects(channel, e); +} + +int Mix_UnregisterAllEffects(int channel) +{ + int retval; + SDL_LockAudio(); + retval = _Mix_UnregisterAllEffects_locked(channel); + SDL_UnlockAudio(); + return(retval); +} + +/* end of mixer.c ... */ + diff --git a/contrib/games/wolf3d/SDL_mixer/music.c b/contrib/games/wolf3d/SDL_mixer/music.c new file mode 100644 index 0000000000..b8622ea532 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music.c @@ -0,0 +1,1597 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* $Id$ */ + +#include +#include +#include +#include +#include "SDL_endian.h" +#include "SDL_audio.h" +#include "SDL_timer.h" + +#include "SDL_mixer.h" + +#ifdef CMD_MUSIC +#include "music_cmd.h" +#endif +#ifdef WAV_MUSIC +#include "wavestream.h" +#endif +#ifdef MODPLUG_MUSIC +#include "music_modplug.h" +#endif +#ifdef MOD_MUSIC +#include "music_mod.h" +#endif +#ifdef MID_MUSIC +# ifdef USE_TIMIDITY_MIDI +# include "timidity.h" +# endif +# ifdef USE_FLUIDSYNTH_MIDI +# include "fluidsynth.h" +# endif +# ifdef USE_NATIVE_MIDI +# include "native_midi.h" +# endif +#endif +#ifdef OGG_MUSIC +#include "music_ogg.h" +#endif +#ifdef MP3_MUSIC +#include "dynamic_mp3.h" +#endif +#ifdef MP3_MAD_MUSIC +#include "music_mad.h" +#endif +#ifdef FLAC_MUSIC +#include "music_flac.h" +#endif + +#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC) +static SDL_AudioSpec used_mixer; +#endif + + +int volatile music_active = 1; +static int volatile music_stopped = 0; +static int music_loops = 0; +static char *music_cmd = NULL; +static Mix_Music * volatile music_playing = NULL; +static int music_volume = MIX_MAX_VOLUME; + +struct _Mix_Music { + Mix_MusicType type; + union { +#ifdef CMD_MUSIC + MusicCMD *cmd; +#endif +#ifdef WAV_MUSIC + WAVStream *wave; +#endif +#ifdef MODPLUG_MUSIC + modplug_data *modplug; +#endif +#ifdef MOD_MUSIC + struct MODULE *module; +#endif +#ifdef MID_MUSIC +#ifdef USE_TIMIDITY_MIDI + MidiSong *midi; +#endif +#ifdef USE_FLUIDSYNTH_MIDI + FluidSynthMidiSong *fluidsynthmidi; +#endif +#ifdef USE_NATIVE_MIDI + NativeMidiSong *nativemidi; +#endif +#endif +#ifdef OGG_MUSIC + OGG_music *ogg; +#endif +#ifdef MP3_MUSIC + SMPEG *mp3; +#endif +#ifdef MP3_MAD_MUSIC + mad_data *mp3_mad; +#endif +#ifdef FLAC_MUSIC + FLAC_music *flac; +#endif + } data; + Mix_Fading fading; + int fade_step; + int fade_steps; + int error; +}; +#ifdef MID_MUSIC +#ifdef USE_TIMIDITY_MIDI +static int timidity_ok; +static int samplesize; +#endif +#ifdef USE_FLUIDSYNTH_MIDI +static int fluidsynth_ok; +#endif +#ifdef USE_NATIVE_MIDI +static int native_midi_ok; +#endif +#endif + +/* Used to calculate fading steps */ +static int ms_per_step; + +/* rcg06042009 report available decoders at runtime. */ +static const char **music_decoders = NULL; +static int num_decoders = 0; + +/* Semicolon-separated SoundFont paths */ +#ifdef MID_MUSIC +char* soundfont_paths = NULL; +#endif + +int Mix_GetNumMusicDecoders(void) +{ + return(num_decoders); +} + +const char *Mix_GetMusicDecoder(int index) +{ + if ((index < 0) || (index >= num_decoders)) { + return NULL; + } + return(music_decoders[index]); +} + +static void add_music_decoder(const char *decoder) +{ + void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **)); + if (ptr == NULL) { + return; /* oh well, go on without it. */ + } + music_decoders = (const char **) ptr; + music_decoders[num_decoders++] = decoder; +} + +/* Local low-level functions prototypes */ +static void music_internal_initialize_volume(void); +static void music_internal_volume(int volume); +static int music_internal_play(Mix_Music *music, double position); +static int music_internal_position(double position); +static int music_internal_playing(); +static void music_internal_halt(void); + + +/* Support for hooking when the music has finished */ +static void (*music_finished_hook)(void) = NULL; + +void Mix_HookMusicFinished(void (*music_finished)(void)) +{ + SDL_LockAudio(); + music_finished_hook = music_finished; + SDL_UnlockAudio(); +} + + +/* If music isn't playing, halt it if no looping is required, restart it */ +/* otherwhise. NOP if the music is playing */ +static int music_halt_or_loop (void) +{ + /* Restart music if it has to loop */ + + if (!music_internal_playing()) + { +#ifdef USE_NATIVE_MIDI + /* Native MIDI handles looping internally */ + if (music_playing->type == MUS_MID && native_midi_ok) { + music_loops = 0; + } +#endif + + /* Restart music if it has to loop at a high level */ + if (music_loops) + { + Mix_Fading current_fade; + --music_loops; + current_fade = music_playing->fading; + music_internal_play(music_playing, 0.0); + music_playing->fading = current_fade; + } + else + { + music_internal_halt(); + if (music_finished_hook) + music_finished_hook(); + + return 0; + } + } + + return 1; +} + + + +/* Mixing function */ +void music_mixer(void *udata, Uint8 *stream, int len) +{ + int left = 0; + + if ( music_playing && music_active ) { + /* Handle fading */ + if ( music_playing->fading != MIX_NO_FADING ) { + if ( music_playing->fade_step++ < music_playing->fade_steps ) { + int volume; + int fade_step = music_playing->fade_step; + int fade_steps = music_playing->fade_steps; + + if ( music_playing->fading == MIX_FADING_OUT ) { + volume = (music_volume * (fade_steps-fade_step)) / fade_steps; + } else { /* Fading in */ + volume = (music_volume * fade_step) / fade_steps; + } + music_internal_volume(volume); + } else { + if ( music_playing->fading == MIX_FADING_OUT ) { + music_internal_halt(); + if ( music_finished_hook ) { + music_finished_hook(); + } + return; + } + music_playing->fading = MIX_NO_FADING; + } + } + + music_halt_or_loop(); + if (!music_internal_playing()) + return; + + switch (music_playing->type) { +#ifdef CMD_MUSIC + case MUS_CMD: + /* The playing is done externally */ + break; +#endif +#ifdef WAV_MUSIC + case MUS_WAV: + left = WAVStream_PlaySome(stream, len); + break; +#endif +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + left = modplug_playAudio(music_playing->data.modplug, stream, len); + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + left = MOD_playAudio(music_playing->data.module, stream, len); + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + /* Native midi is handled asynchronously */ + goto skip; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_ok ) { + fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len); + goto skip; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + int samples = len / samplesize; + Timidity_PlaySome(stream, samples); + goto skip; + } +#endif + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + + left = OGG_playAudio(music_playing->data.ogg, stream, len); + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + left = FLAC_playAudio(music_playing->data.flac, stream, len); + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len)); + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + left = mad_getSamples(music_playing->data.mp3_mad, stream, len); + break; +#endif + default: + /* Unknown music type?? */ + break; + } + } + +skip: + /* Handle seamless music looping */ + if (left > 0 && left < len) { + music_halt_or_loop(); + if (music_internal_playing()) + music_mixer(udata, stream+(len-left), left); + } +} + +/* Initialize the music players with a certain desired audio format */ +int open_music(SDL_AudioSpec *mixer) +{ +#ifdef WAV_MUSIC + if ( WAVStream_Init(mixer) == 0 ) { + add_music_decoder("WAVE"); + } +#endif +#ifdef MODPLUG_MUSIC + if ( modplug_init(mixer) == 0 ) { + add_music_decoder("MODPLUG"); + } +#endif +#ifdef MOD_MUSIC + if ( MOD_init(mixer) == 0 ) { + add_music_decoder("MIKMOD"); + } +#endif +#ifdef MID_MUSIC +#ifdef USE_TIMIDITY_MIDI + samplesize = mixer->size / mixer->samples; + if ( Timidity_Init(mixer->freq, mixer->format, + mixer->channels, mixer->samples) == 0 ) { + timidity_ok = 1; + add_music_decoder("TIMIDITY"); + } else { + timidity_ok = 0; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_init(mixer) == 0 ) { + fluidsynth_ok = 1; + add_music_decoder("FLUIDSYNTH"); + } else { + fluidsynth_ok = 0; + } +#endif +#ifdef USE_NATIVE_MIDI +#ifdef USE_FLUIDSYNTH_MIDI + native_midi_ok = !fluidsynth_ok; + if ( native_midi_ok ) +#endif +#ifdef USE_TIMIDITY_MIDI + native_midi_ok = !timidity_ok; + if ( !native_midi_ok ) { + native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL); + } + if ( native_midi_ok ) +#endif + native_midi_ok = native_midi_detect(); + if ( native_midi_ok ) + add_music_decoder("NATIVEMIDI"); +#endif +#endif +#ifdef OGG_MUSIC + if ( OGG_init(mixer) == 0 ) { + add_music_decoder("OGG"); + } +#endif +#ifdef FLAC_MUSIC + if ( FLAC_init(mixer) == 0 ) { + add_music_decoder("FLAC"); + } +#endif +#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC) + /* Keep a copy of the mixer */ + used_mixer = *mixer; + add_music_decoder("MP3"); +#endif + + music_playing = NULL; + music_stopped = 0; + Mix_VolumeMusic(SDL_MIX_MAXVOLUME); + + /* Calculate the number of ms for each callback */ + ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq); + + return(0); +} + +/* Portable case-insensitive string compare function */ +int MIX_string_equals(const char *str1, const char *str2) +{ + while ( *str1 && *str2 ) { + if ( toupper((unsigned char)*str1) != + toupper((unsigned char)*str2) ) + break; + ++str1; + ++str2; + } + return (!*str1 && !*str2); +} + +static int detect_mp3(Uint8 *magic) +{ + if ( strncmp((char *)magic, "ID3", 3) == 0 ) { + return 1; + } + + /* Detection code lifted from SMPEG */ + if(((magic[0] & 0xff) != 0xff) || // No sync bits + ((magic[1] & 0xf0) != 0xf0) || // + ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0 + ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15 + ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3 + ((magic[1] & 0x06) == 0x00)) { // Layer is 4 + return(0); + } + return 1; +} + +/* MUS_MOD can't be auto-detected. If no other format was detected, MOD is + * assumed and MUS_MOD will be returned, meaning that the format might not + * actually be MOD-based. + * + * Returns MUS_NONE in case of errors. */ +static Mix_MusicType detect_music_type(SDL_RWops *rw) +{ + Uint8 magic[5]; + Uint8 moremagic[9]; + + int start = SDL_RWtell(rw); + if (SDL_RWread(rw, magic, 1, 4) != 4 || SDL_RWread(rw, moremagic, 1, 8) != 8 ) { + Mix_SetError("Couldn't read from RWops"); + return MUS_NONE; + } + SDL_RWseek(rw, start, RW_SEEK_SET); + magic[4]='\0'; + moremagic[8] = '\0'; + + /* WAVE files have the magic four bytes "RIFF" + AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */ + if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) || + (strcmp((char *)magic, "FORM") == 0)) { + return MUS_WAV; + } + + /* Ogg Vorbis files have the magic four bytes "OggS" */ + if (strcmp((char *)magic, "OggS") == 0) { + return MUS_OGG; + } + + /* FLAC files have the magic four bytes "fLaC" */ + if (strcmp((char *)magic, "fLaC") == 0) { + return MUS_FLAC; + } + + /* MIDI files have the magic four bytes "MThd" */ + if (strcmp((char *)magic, "MThd") == 0) { + return MUS_MID; + } + + if (detect_mp3(magic)) { + return MUS_MP3; + } + + /* Assume MOD format. + * + * Apparently there is no way to check if the file is really a MOD, + * or there are too many formats supported by MikMod/ModPlug, or + * MikMod/ModPlug does this check by itself. */ + return MUS_MOD; +} + +/* Load a music file */ +Mix_Music *Mix_LoadMUS(const char *file) +{ + SDL_RWops *rw; + Mix_Music *music; + Mix_MusicType type; + char *ext = strrchr(file, '.'); + +#ifdef CMD_MUSIC + if ( music_cmd ) { + /* Allocate memory for the music structure */ + music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music)); + if ( music == NULL ) { + Mix_SetError("Out of memory"); + return(NULL); + } + music->error = 0; + music->type = MUS_CMD; + music->data.cmd = MusicCMD_LoadSong(music_cmd, file); + if ( music->data.cmd == NULL ) { + SDL_free(music); + music == NULL; + } + return music; + } +#endif + + rw = SDL_RWFromFile(file, "rb"); + if ( rw == NULL ) { + Mix_SetError("Couldn't open '%s'", file); + return NULL; + } + + /* Use the extension as a first guess on the file type */ + type = MUS_NONE; + ext = strrchr(file, '.'); + /* No need to guard these with #ifdef *_MUSIC stuff, + * since we simply call Mix_LoadMUSType_RW() later */ + if ( ext ) { + ++ext; /* skip the dot in the extension */ + if ( MIX_string_equals(ext, "WAV") ) { + type = MUS_WAV; + } else if ( MIX_string_equals(ext, "MID") || + MIX_string_equals(ext, "MIDI") || + MIX_string_equals(ext, "KAR") ) { + type = MUS_MID; + } else if ( MIX_string_equals(ext, "OGG") ) { + type = MUS_OGG; + } else if ( MIX_string_equals(ext, "FLAC") ) { + type = MUS_FLAC; + } else if ( MIX_string_equals(ext, "MPG") || + MIX_string_equals(ext, "MPEG") || + MIX_string_equals(ext, "MP3") || + MIX_string_equals(ext, "MAD") ) { + type = MUS_MP3; + } + } + if ( type == MUS_NONE ) { + type = detect_music_type(rw); + } + + /* We need to know if a specific error occurs; if not, we'll set a + * generic one, so we clear the current one. */ + Mix_SetError(""); + music = Mix_LoadMUSType_RW(rw, type, SDL_TRUE); + if ( music == NULL && Mix_GetError()[0] == '\0' ) { + SDL_FreeRW(rw); + Mix_SetError("Couldn't open '%s'", file); + } + return music; +} + +Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) +{ + return Mix_LoadMUSType_RW(rw, MUS_NONE, SDL_FALSE); +} + +Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc) +{ + Mix_Music *music; + + if (!rw) { + Mix_SetError("RWops pointer is NULL"); + return NULL; + } + + /* If the caller wants auto-detection, figure out what kind of file + * this is. */ + if (type == MUS_NONE) { + if ((type = detect_music_type(rw)) == MUS_NONE) { + /* Don't call Mix_SetError() here since detect_music_type() + * does that. */ + return NULL; + } + } + + /* Allocate memory for the music structure */ + music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music)); + if (music == NULL ) { + Mix_SetError("Out of memory"); + return NULL; + } + music->error = 0; + + switch (type) { +#ifdef WAV_MUSIC + case MUS_WAV: + /* The WAVE loader needs the first 4 bytes of the header */ + { + Uint8 magic[5]; + int start = SDL_RWtell(rw); + if (SDL_RWread(rw, magic, 1, 4) != 4) { + Mix_SetError("Couldn't read from RWops"); + return MUS_NONE; + } + SDL_RWseek(rw, start, RW_SEEK_SET); + magic[4] = '\0'; + music->type = MUS_WAV; + music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freesrc); + } + if (music->data.wave == NULL) { + music->error = 1; + } + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + music->type = MUS_OGG; + music->data.ogg = OGG_new_RW(rw, freesrc); + if ( music->data.ogg == NULL ) { + music->error = 1; + } + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + music->type = MUS_FLAC; + music->data.flac = FLAC_new_RW(rw, freesrc); + if ( music->data.flac == NULL ) { + music->error = 1; + } + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + if ( Mix_Init(MIX_INIT_MP3) ) { + SMPEG_Info info; + music->type = MUS_MP3; + music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0); + if ( !info.has_audio ) { + Mix_SetError("MPEG file does not have any audio stream."); + music->error = 1; + } else { + smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer); + } + } else { + music->error = 1; + } + break; +#elif defined(MP3_MAD_MUSIC) + case MUS_MP3: + music->type = MUS_MP3_MAD; + music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freesrc); + if (music->data.mp3_mad == 0) { + Mix_SetError("Could not initialize MPEG stream."); + music->error = 1; + } + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: + music->type = MUS_MID; +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + music->data.nativemidi = native_midi_loadsong_RW(rw, freesrc); + if ( music->data.nativemidi == NULL ) { + Mix_SetError("%s", native_midi_error()); + music->error = 1; + } + break; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_ok ) { + music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freesrc); + if ( music->data.fluidsynthmidi == NULL ) { + music->error = 1; + } + break; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + music->data.midi = Timidity_LoadSong_RW(rw, freesrc); + if ( music->data.midi == NULL ) { + Mix_SetError("%s", Timidity_Error()); + music->error = 1; + } + } else { + Mix_SetError("%s", Timidity_Error()); + music->error = 1; + } +#endif + break; +#endif +#if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC) + case MUS_MOD: + music->error = 1; +#ifdef MODPLUG_MUSIC + if ( music->error ) { + music->type = MUS_MODPLUG; + music->data.modplug = modplug_new_RW(rw, freesrc); + if ( music->data.modplug ) { + music->error = 0; + } + } +#endif +#ifdef MOD_MUSIC + if ( music->error ) { + music->type = MUS_MOD; + music->data.module = MOD_new_RW(rw, freesrc); + if ( music->data.module ) { + music->error = 0; + } + } +#endif + break; +#endif + + default: + Mix_SetError("Unrecognized music format"); + music->error=1; + } /* switch (want) */ + + + if (music->error) { + SDL_free(music); + music=NULL; + } + return(music); +} + +/* Free a music chunk previously loaded */ +void Mix_FreeMusic(Mix_Music *music) +{ + if ( music ) { + /* Stop the music if it's currently playing */ + SDL_LockAudio(); + if ( music == music_playing ) { + /* Wait for any fade out to finish */ + while ( music->fading == MIX_FADING_OUT ) { + SDL_UnlockAudio(); + SDL_Delay(100); + SDL_LockAudio(); + } + if ( music == music_playing ) { + music_internal_halt(); + } + } + SDL_UnlockAudio(); + switch (music->type) { +#ifdef CMD_MUSIC + case MUS_CMD: + MusicCMD_FreeSong(music->data.cmd); + break; +#endif +#ifdef WAV_MUSIC + case MUS_WAV: + WAVStream_FreeSong(music->data.wave); + break; +#endif +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + modplug_delete(music->data.modplug); + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + MOD_delete(music->data.module); + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + native_midi_freesong(music->data.nativemidi); + goto skip; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_ok ) { + fluidsynth_freesong(music->data.fluidsynthmidi); + goto skip; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + Timidity_FreeSong(music->data.midi); + goto skip; + } +#endif + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_delete(music->data.ogg); + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + FLAC_delete(music->data.flac); + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + smpeg.SMPEG_delete(music->data.mp3); + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + mad_closeFile(music->data.mp3_mad); + break; +#endif + default: + /* Unknown music type?? */ + break; + } + + skip: + SDL_free(music); + } +} + +/* Find out the music format of a mixer music, or the currently playing + music, if 'music' is NULL. +*/ +Mix_MusicType Mix_GetMusicType(const Mix_Music *music) +{ + Mix_MusicType type = MUS_NONE; + + if ( music ) { + type = music->type; + } else { + SDL_LockAudio(); + if ( music_playing ) { + type = music_playing->type; + } + SDL_UnlockAudio(); + } + return(type); +} + +/* Play a music chunk. Returns 0, or -1 if there was an error. + */ +static int music_internal_play(Mix_Music *music, double position) +{ + int retval = 0; + +#if defined(__MACOSX__) && defined(USE_NATIVE_MIDI) + /* This fixes a bug with native MIDI on Mac OS X, where you + can't really stop and restart MIDI from the audio callback. + */ + if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) { + /* Just a seek suffices to restart playing */ + music_internal_position(position); + return 0; + } +#endif + + /* Note the music we're playing */ + if ( music_playing ) { + music_internal_halt(); + } + music_playing = music; + + /* Set the initial volume */ + if ( music->type != MUS_MOD ) { + music_internal_initialize_volume(); + } + + /* Set up for playback */ + switch (music->type) { +#ifdef CMD_MUSIC + case MUS_CMD: + MusicCMD_Start(music->data.cmd); + break; +#endif +#ifdef WAV_MUSIC + case MUS_WAV: + WAVStream_Start(music->data.wave); + break; +#endif +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + /* can't set volume until file is loaded, so finally set it now */ + music_internal_initialize_volume(); + modplug_play(music->data.modplug); + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + MOD_play(music->data.module); + /* Player_SetVolume() does nothing before Player_Start() */ + music_internal_initialize_volume(); + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + native_midi_start(music->data.nativemidi, music_loops); + goto skip; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if (fluidsynth_ok ) { + fluidsynth_start(music->data.fluidsynthmidi); + goto skip; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + Timidity_Start(music->data.midi); + goto skip; + } +#endif + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_play(music->data.ogg); + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + FLAC_play(music->data.flac); + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + smpeg.SMPEG_enableaudio(music->data.mp3,1); + smpeg.SMPEG_enablevideo(music->data.mp3,0); + smpeg.SMPEG_play(music_playing->data.mp3); + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + mad_start(music->data.mp3_mad); + break; +#endif + default: + Mix_SetError("Can't play unknown music type"); + retval = -1; + break; + } + +skip: + /* Set the playback position, note any errors if an offset is used */ + if ( retval == 0 ) { + if ( position > 0.0 ) { + if ( music_internal_position(position) < 0 ) { + Mix_SetError("Position not implemented for music type"); + retval = -1; + } + } else { + music_internal_position(0.0); + } + } + + /* If the setup failed, we're not playing any music anymore */ + if ( retval < 0 ) { + music_playing = NULL; + } + return(retval); +} +int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position) +{ + int retval; + + if ( ms_per_step == 0 ) { + SDL_SetError("Audio device hasn't been opened"); + return(-1); + } + + /* Don't play null pointers :-) */ + if ( music == NULL ) { + Mix_SetError("music parameter was NULL"); + return(-1); + } + + /* Setup the data */ + if ( ms ) { + music->fading = MIX_FADING_IN; + } else { + music->fading = MIX_NO_FADING; + } + music->fade_step = 0; + music->fade_steps = ms/ms_per_step; + + /* Play the puppy */ + SDL_LockAudio(); + /* If the current music is fading out, wait for the fade to complete */ + while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) { + SDL_UnlockAudio(); + SDL_Delay(100); + SDL_LockAudio(); + } + music_active = 1; + if (loops == 1) { + /* Loop is the number of times to play the audio */ + loops = 0; + } + music_loops = loops; + retval = music_internal_play(music, position); + SDL_UnlockAudio(); + + return(retval); +} +int Mix_FadeInMusic(Mix_Music *music, int loops, int ms) +{ + return Mix_FadeInMusicPos(music, loops, ms, 0.0); +} +int Mix_PlayMusic(Mix_Music *music, int loops) +{ + return Mix_FadeInMusicPos(music, loops, 0, 0.0); +} + +/* Set the playing music position */ +int music_internal_position(double position) +{ + int retval = 0; + + switch (music_playing->type) { +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + modplug_jump_to_time(music_playing->data.modplug, position); + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + MOD_jump_to_time(music_playing->data.module, position); + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_jump_to_time(music_playing->data.ogg, position); + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + FLAC_jump_to_time(music_playing->data.flac, position); + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + smpeg.SMPEG_rewind(music_playing->data.mp3); + smpeg.SMPEG_play(music_playing->data.mp3); + if ( position > 0.0 ) { + smpeg.SMPEG_skip(music_playing->data.mp3, (float)position); + } + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + mad_seek(music_playing->data.mp3_mad, position); + break; +#endif + default: + /* TODO: Implement this for other music backends */ + retval = -1; + break; + } + return(retval); +} +int Mix_SetMusicPosition(double position) +{ + int retval; + + SDL_LockAudio(); + if ( music_playing ) { + retval = music_internal_position(position); + if ( retval < 0 ) { + Mix_SetError("Position not implemented for music type"); + } + } else { + Mix_SetError("Music isn't playing"); + retval = -1; + } + SDL_UnlockAudio(); + + return(retval); +} + +/* Set the music's initial volume */ +static void music_internal_initialize_volume(void) +{ + if ( music_playing->fading == MIX_FADING_IN ) { + music_internal_volume(0); + } else { + music_internal_volume(music_volume); + } +} + +/* Set the music volume */ +static void music_internal_volume(int volume) +{ + switch (music_playing->type) { +#ifdef CMD_MUSIC + case MUS_CMD: + MusicCMD_SetVolume(volume); + break; +#endif +#ifdef WAV_MUSIC + case MUS_WAV: + WAVStream_SetVolume(volume); + break; +#endif +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + modplug_setvolume(music_playing->data.modplug, volume); + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + MOD_setvolume(music_playing->data.module, volume); + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + native_midi_setvolume(volume); + return; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_ok ) { + fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume); + return; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + Timidity_SetVolume(volume); + return; + } +#endif + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_setvolume(music_playing->data.ogg, volume); + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + FLAC_setvolume(music_playing->data.flac, volume); + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0)); + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + mad_setVolume(music_playing->data.mp3_mad, volume); + break; +#endif + default: + /* Unknown music type?? */ + break; + } +} +int Mix_VolumeMusic(int volume) +{ + int prev_volume; + + prev_volume = music_volume; + if ( volume < 0 ) { + return prev_volume; + } + if ( volume > SDL_MIX_MAXVOLUME ) { + volume = SDL_MIX_MAXVOLUME; + } + music_volume = volume; + SDL_LockAudio(); + if ( music_playing ) { + music_internal_volume(music_volume); + } + SDL_UnlockAudio(); + return(prev_volume); +} + +/* Halt playing of music */ +static void music_internal_halt(void) +{ + switch (music_playing->type) { +#ifdef CMD_MUSIC + case MUS_CMD: + MusicCMD_Stop(music_playing->data.cmd); + break; +#endif +#ifdef WAV_MUSIC + case MUS_WAV: + WAVStream_Stop(); + break; +#endif +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + modplug_stop(music_playing->data.modplug); + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + MOD_stop(music_playing->data.module); + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + native_midi_stop(); + goto skip; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_ok ) { + fluidsynth_stop(music_playing->data.fluidsynthmidi); + goto skip; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + Timidity_Stop(); + goto skip; + } +#endif + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_stop(music_playing->data.ogg); + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + FLAC_stop(music_playing->data.flac); + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + smpeg.SMPEG_stop(music_playing->data.mp3); + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + mad_stop(music_playing->data.mp3_mad); + break; +#endif + default: + /* Unknown music type?? */ + return; + } + +skip: + music_playing->fading = MIX_NO_FADING; + music_playing = NULL; +} +int Mix_HaltMusic(void) +{ + SDL_LockAudio(); + if ( music_playing ) { + music_internal_halt(); + } + SDL_UnlockAudio(); + + return(0); +} + +/* Progressively stop the music */ +int Mix_FadeOutMusic(int ms) +{ + int retval = 0; + + if ( ms_per_step == 0 ) { + SDL_SetError("Audio device hasn't been opened"); + return 0; + } + + if (ms <= 0) { /* just halt immediately. */ + Mix_HaltMusic(); + return 1; + } + + SDL_LockAudio(); + if ( music_playing) { + int fade_steps = (ms + ms_per_step - 1)/ms_per_step; + if ( music_playing->fading == MIX_NO_FADING ) { + music_playing->fade_step = 0; + } else { + int step; + int old_fade_steps = music_playing->fade_steps; + if ( music_playing->fading == MIX_FADING_OUT ) { + step = music_playing->fade_step; + } else { + step = old_fade_steps + - music_playing->fade_step + 1; + } + music_playing->fade_step = (step * fade_steps) + / old_fade_steps; + } + music_playing->fading = MIX_FADING_OUT; + music_playing->fade_steps = fade_steps; + retval = 1; + } + SDL_UnlockAudio(); + + return(retval); +} + +Mix_Fading Mix_FadingMusic(void) +{ + Mix_Fading fading = MIX_NO_FADING; + + SDL_LockAudio(); + if ( music_playing ) { + fading = music_playing->fading; + } + SDL_UnlockAudio(); + + return(fading); +} + +/* Pause/Resume the music stream */ +void Mix_PauseMusic(void) +{ + music_active = 0; +} + +void Mix_ResumeMusic(void) +{ + music_active = 1; +} + +void Mix_RewindMusic(void) +{ + Mix_SetMusicPosition(0.0); +} + +int Mix_PausedMusic(void) +{ + return (music_active == 0); +} + +/* Check the status of the music */ +static int music_internal_playing() +{ + int playing = 1; + + if (music_playing == NULL) { + return 0; + } + + switch (music_playing->type) { +#ifdef CMD_MUSIC + case MUS_CMD: + if (!MusicCMD_Active(music_playing->data.cmd)) { + playing = 0; + } + break; +#endif +#ifdef WAV_MUSIC + case MUS_WAV: + if ( ! WAVStream_Active() ) { + playing = 0; + } + break; +#endif +#ifdef MODPLUG_MUSIC + case MUS_MODPLUG: + if ( ! modplug_playing(music_playing->data.modplug) ) { + playing = 0; + } + break; +#endif +#ifdef MOD_MUSIC + case MUS_MOD: + if ( ! MOD_playing(music_playing->data.module) ) { + playing = 0; + } + break; +#endif +#ifdef MID_MUSIC + case MUS_MID: +#ifdef USE_NATIVE_MIDI + if ( native_midi_ok ) { + if ( ! native_midi_active() ) + playing = 0; + goto skip; + } +#endif +#ifdef USE_FLUIDSYNTH_MIDI + if ( fluidsynth_ok ) { + if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) ) + playing = 0; + goto skip; + } +#endif +#ifdef USE_TIMIDITY_MIDI + if ( timidity_ok ) { + if ( ! Timidity_Active() ) + playing = 0; + goto skip; + } +#endif + break; +#endif +#ifdef OGG_MUSIC + case MUS_OGG: + if ( ! OGG_playing(music_playing->data.ogg) ) { + playing = 0; + } + break; +#endif +#ifdef FLAC_MUSIC + case MUS_FLAC: + if ( ! FLAC_playing(music_playing->data.flac) ) { + playing = 0; + } + break; +#endif +#ifdef MP3_MUSIC + case MUS_MP3: + if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING ) + playing = 0; + break; +#endif +#ifdef MP3_MAD_MUSIC + case MUS_MP3_MAD: + if (!mad_isPlaying(music_playing->data.mp3_mad)) { + playing = 0; + } + break; +#endif + default: + playing = 0; + break; + } + +skip: + return(playing); +} +int Mix_PlayingMusic(void) +{ + int playing = 0; + + SDL_LockAudio(); + if ( music_playing ) { + playing = music_loops || music_internal_playing(); + } + SDL_UnlockAudio(); + + return(playing); +} + +/* Set the external music playback command */ +int Mix_SetMusicCMD(const char *command) +{ + Mix_HaltMusic(); + if ( music_cmd ) { + SDL_free(music_cmd); + music_cmd = NULL; + } + if ( command ) { + music_cmd = (char *)SDL_malloc(strlen(command)+1); + if ( music_cmd == NULL ) { + return(-1); + } + strcpy(music_cmd, command); + } + return(0); +} + +int Mix_SetSynchroValue(int i) +{ + /* Not supported by any players at this time */ + return(-1); +} + +int Mix_GetSynchroValue(void) +{ + /* Not supported by any players at this time */ + return(-1); +} + + +/* Uninitialize the music players */ +void close_music(void) +{ + Mix_HaltMusic(); +#ifdef CMD_MUSIC + Mix_SetMusicCMD(NULL); +#endif +#ifdef MODPLUG_MUSIC + modplug_exit(); +#endif +#ifdef MOD_MUSIC + MOD_exit(); +#endif +#ifdef MID_MUSIC +# ifdef USE_TIMIDITY_MIDI + Timidity_Close(); +# endif +#endif + + /* rcg06042009 report available decoders at runtime. */ + SDL_free(music_decoders); + music_decoders = NULL; + num_decoders = 0; + + ms_per_step = 0; +} + +int Mix_SetSoundFonts(const char *paths) +{ +#ifdef MID_MUSIC + if (soundfont_paths) { + SDL_free(soundfont_paths); + soundfont_paths = NULL; + } + + if (paths) { + if (!(soundfont_paths = SDL_strdup(paths))) { + Mix_SetError("Insufficient memory to set SoundFonts"); + return 0; + } + } +#endif + return 1; +} + +#ifdef MID_MUSIC +const char* Mix_GetSoundFonts(void) +{ + const char* force = getenv("SDL_FORCE_SOUNDFONTS"); + + if (!soundfont_paths || (force && force[0] == '1')) { + return getenv("SDL_SOUNDFONTS"); + } else { + return soundfont_paths; + } +} + +int Mix_EachSoundFont(int (*function)(const char*, void*), void *data) +{ + char *context, *path, *paths; + const char* cpaths = Mix_GetSoundFonts(); + + if (!cpaths) { + Mix_SetError("No SoundFonts have been requested"); + return 0; + } + + if (!(paths = SDL_strdup(cpaths))) { + Mix_SetError("Insufficient memory to iterate over SoundFonts"); + return 0; + } + +#if defined(__MINGW32__) || defined(__MINGW64__) + for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) { +#elif defined(_WIN32) + for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) { +#else + for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) { +#endif + if (!function(path, data)) { + SDL_free(paths); + return 0; + } + } + + SDL_free(paths); + return 1; +} +#endif diff --git a/contrib/games/wolf3d/SDL_mixer/music_cmd.h b/contrib/games/wolf3d/SDL_mixer/music_cmd.h new file mode 100644 index 0000000000..10168deaa0 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music_cmd.h @@ -0,0 +1,62 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#include +#include +#if defined(__linux__) && defined(__arm__) +# include +#endif +typedef struct { + char file[PATH_MAX]; + char cmd[PATH_MAX]; + pid_t pid; +} MusicCMD; + +/* Unimplemented */ +extern void MusicCMD_SetVolume(int volume); + +/* Load a music stream from the given file */ +extern MusicCMD *MusicCMD_LoadSong(const char *cmd, const char *file); + +/* Start playback of a given music stream */ +extern void MusicCMD_Start(MusicCMD *music); + +/* Stop playback of a stream previously started with MusicCMD_Start() */ +extern void MusicCMD_Stop(MusicCMD *music); + +/* Pause playback of a given music stream */ +extern void MusicCMD_Pause(MusicCMD *music); + +/* Resume playback of a given music stream */ +extern void MusicCMD_Resume(MusicCMD *music); + +/* Close the given music stream */ +extern void MusicCMD_FreeSong(MusicCMD *music); + +/* Return non-zero if a stream is currently playing */ +extern int MusicCMD_Active(MusicCMD *music); + +#endif /* CMD_MUSIC */ diff --git a/contrib/games/wolf3d/SDL_mixer/music_flac.h b/contrib/games/wolf3d/SDL_mixer/music_flac.h new file mode 100644 index 0000000000..c87dc9ea9f --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music_flac.h @@ -0,0 +1,90 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 + +typedef struct { + FLAC__uint64 sample_size; + unsigned sample_rate; + unsigned channels; + unsigned bits_per_sample; + FLAC__uint64 total_samples; + + // the following are used to handle the callback nature of the writer + int max_to_read; + char *data; // pointer to beginning of data array + int data_len; // size of data array + int data_read; // amount of data array used + char *overflow; // pointer to beginning of overflow array + int overflow_len; // size of overflow array + int overflow_read; // amount of overflow array used +} FLAC_Data; + +typedef struct { + int playing; + int volume; + int section; + FLAC__StreamDecoder *flac_decoder; + FLAC_Data flac_data; + SDL_RWops *rwops; + int freerw; + SDL_AudioCVT cvt; + int len_available; + Uint8 *snd_available; +} FLAC_music; + +/* Initialize the FLAC player, with the given mixer settings + This function returns 0, or -1 if there was an error. + */ +extern int FLAC_init(SDL_AudioSpec *mixer); + +/* Set the volume for a FLAC stream */ +extern void FLAC_setvolume(FLAC_music *music, int volume); + +/* Load an FLAC stream from an SDL_RWops object */ +extern FLAC_music *FLAC_new_RW(SDL_RWops *rw, int freerw); + +/* Start playback of a given FLAC stream */ +extern void FLAC_play(FLAC_music *music); + +/* Return non-zero if a stream is currently playing */ +extern int FLAC_playing(FLAC_music *music); + +/* Play some of a stream previously started with FLAC_play() */ +extern int FLAC_playAudio(FLAC_music *music, Uint8 *stream, int len); + +/* Stop playback of a stream previously started with FLAC_play() */ +extern void FLAC_stop(FLAC_music *music); + +/* Close the given FLAC stream */ +extern void FLAC_delete(FLAC_music *music); + +/* Jump (seek) to a given position (time is in seconds) */ +extern void FLAC_jump_to_time(FLAC_music *music, double time); + +#endif /* FLAC_MUSIC */ diff --git a/contrib/games/wolf3d/SDL_mixer/music_mad.h b/contrib/games/wolf3d/SDL_mixer/music_mad.h new file mode 100644 index 0000000000..af93c8df5e --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music_mad.h @@ -0,0 +1,72 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifdef MP3_MAD_MUSIC + +#include "mad.h" +#include "SDL_rwops.h" +#include "SDL_audio.h" +#include "SDL_mixer.h" + +#define MAD_INPUT_BUFFER_SIZE (5*8192) +#define MAD_OUTPUT_BUFFER_SIZE 8192 + +enum { + MS_input_eof = 0x0001, + MS_input_error = 0x0001, + MS_decode_eof = 0x0002, + MS_decode_error = 0x0004, + MS_error_flags = 0x000f, + + MS_playing = 0x0100, + MS_cvt_decoded = 0x0200, +}; + +typedef struct { + SDL_RWops *rw; + int freerw; + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + int frames_read; + mad_timer_t next_frame_start; + int volume; + int status; + int output_begin, output_end; + SDL_AudioSpec mixer; + SDL_AudioCVT cvt; + + unsigned char input_buffer[MAD_INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD]; + unsigned char output_buffer[MAD_OUTPUT_BUFFER_SIZE]; +} mad_data; + +mad_data *mad_openFileRW(SDL_RWops *rw, SDL_AudioSpec *mixer, int freerw); +void mad_closeFile(mad_data *mp3_mad); + +void mad_start(mad_data *mp3_mad); +void mad_stop(mad_data *mp3_mad); +int mad_isPlaying(mad_data *mp3_mad); + +int mad_getSamples(mad_data *mp3_mad, Uint8 *stream, int len); +void mad_seek(mad_data *mp3_mad, double position); +void mad_setVolume(mad_data *mp3_mad, int volume); + +#endif diff --git a/contrib/games/wolf3d/SDL_mixer/music_mod.h b/contrib/games/wolf3d/SDL_mixer/music_mod.h new file mode 100644 index 0000000000..4328e2b2c7 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music_mod.h @@ -0,0 +1,62 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* $Id: music_mod.h 4211 2008-12-08 00:27:32Z slouken $ */ + +#ifdef MOD_MUSIC + +/* This file supports MOD tracker music streams */ + +struct MODULE; + +/* Initialize the Ogg Vorbis player, with the given mixer settings + This function returns 0, or -1 if there was an error. + */ +extern int MOD_init(SDL_AudioSpec *mixer); + +/* Uninitialize the music players */ +extern void MOD_exit(void); + +/* Set the volume for a MOD stream */ +extern void MOD_setvolume(struct MODULE *music, int volume); + +/* Load a MOD stream from an SDL_RWops object */ +extern struct MODULE *MOD_new_RW(SDL_RWops *rw, int freerw); + +/* Start playback of a given MOD stream */ +extern void MOD_play(struct MODULE *music); + +/* Return non-zero if a stream is currently playing */ +extern int MOD_playing(struct MODULE *music); + +/* Play some of a stream previously started with MOD_play() */ +extern int MOD_playAudio(struct MODULE *music, Uint8 *stream, int len); + +/* Stop playback of a stream previously started with MOD_play() */ +extern void MOD_stop(struct MODULE *music); + +/* Close the given MOD stream */ +extern void MOD_delete(struct MODULE *music); + +/* Jump (seek) to a given position (time is in seconds) */ +extern void MOD_jump_to_time(struct MODULE *music, double time); + +#endif /* MOD_MUSIC */ diff --git a/contrib/games/wolf3d/SDL_mixer/music_modplug.h b/contrib/games/wolf3d/SDL_mixer/music_modplug.h new file mode 100644 index 0000000000..92cbafd094 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music_modplug.h @@ -0,0 +1,42 @@ +#ifdef MODPLUG_MUSIC + +#include "modplug.h" +#include "SDL_rwops.h" +#include "SDL_audio.h" +#include "SDL_mixer.h" + +typedef struct { + ModPlugFile *file; + int playing; +} modplug_data; + +int modplug_init(SDL_AudioSpec *mixer); + +/* Uninitialize the music players */ +void modplug_exit(void); + +/* Set the volume for a modplug stream */ +void modplug_setvolume(modplug_data *music, int volume); + +/* Load a modplug stream from an SDL_RWops object */ +modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw); + +/* Start playback of a given modplug stream */ +void modplug_play(modplug_data *music); + +/* Return non-zero if a stream is currently playing */ +int modplug_playing(modplug_data *music); + +/* Play some of a stream previously started with modplug_play() */ +int modplug_playAudio(modplug_data *music, Uint8 *stream, int len); + +/* Stop playback of a stream previously started with modplug_play() */ +void modplug_stop(modplug_data *music); + +/* Close the given modplug stream */ +void modplug_delete(modplug_data *music); + +/* Jump (seek) to a given position (time is in seconds) */ +void modplug_jump_to_time(modplug_data *music, double time); + +#endif diff --git a/contrib/games/wolf3d/SDL_mixer/music_ogg.h b/contrib/games/wolf3d/SDL_mixer/music_ogg.h new file mode 100644 index 0000000000..4d93a2bc62 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/music_ogg.h @@ -0,0 +1,75 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 +#else +#include +#endif + +typedef struct { + SDL_RWops *rw; + int freerw; + int playing; + int volume; + OggVorbis_File vf; + int section; + SDL_AudioCVT cvt; + int len_available; + Uint8 *snd_available; +} OGG_music; + +/* Initialize the Ogg Vorbis player, with the given mixer settings + This function returns 0, or -1 if there was an error. + */ +extern int OGG_init(SDL_AudioSpec *mixer); + +/* Set the volume for an OGG stream */ +extern void OGG_setvolume(OGG_music *music, int volume); + +/* Load an OGG stream from an SDL_RWops object */ +extern OGG_music *OGG_new_RW(SDL_RWops *rw, int freerw); + +/* Start playback of a given OGG stream */ +extern void OGG_play(OGG_music *music); + +/* Return non-zero if a stream is currently playing */ +extern int OGG_playing(OGG_music *music); + +/* Play some of a stream previously started with OGG_play() */ +extern int OGG_playAudio(OGG_music *music, Uint8 *stream, int len); + +/* Stop playback of a stream previously started with OGG_play() */ +extern void OGG_stop(OGG_music *music); + +/* Close the given OGG stream */ +extern void OGG_delete(OGG_music *music); + +/* Jump (seek) to a given position (time is in seconds) */ +extern void OGG_jump_to_time(OGG_music *music, double time); + +#endif /* OGG_MUSIC */ diff --git a/contrib/games/wolf3d/SDL_mixer/wavestream.h b/contrib/games/wolf3d/SDL_mixer/wavestream.h new file mode 100644 index 0000000000..9d119dc152 --- /dev/null +++ b/contrib/games/wolf3d/SDL_mixer/wavestream.h @@ -0,0 +1,60 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2012 Sam Lantinga + + 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 + +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); diff --git a/contrib/games/wolf3d/compile_flags.txt b/contrib/games/wolf3d/compile_flags.txt new file mode 100644 index 0000000000..16ee2f742c --- /dev/null +++ b/contrib/games/wolf3d/compile_flags.txt @@ -0,0 +1,4 @@ +-I +../../sdk/sources/SDL-1.2.2_newlib/include +../../sdk/sources/newlib/libc/include +. diff --git a/contrib/games/wolf3d/id_sd.cpp b/contrib/games/wolf3d/id_sd.cpp index ddef520dfc..606d9ed110 100755 --- a/contrib/games/wolf3d/id_sd.cpp +++ b/contrib/games/wolf3d/id_sd.cpp @@ -1,144 +1,1424 @@ -// -// ID Engine -// ID_SD.c - Sound Manager for Wolfenstein 3D -// v1.2 -// By Jason Blochowiak -// - -// -// This module handles dealing with generating sound on the appropriate -// hardware -// -// Depends on: User Mgr (for parm checking) -// -// Globals: -// For User Mgr: -// SoundBlasterPresent - SoundBlaster card present? -// AdLibPresent - AdLib card present? -// SoundMode - What device is used for sound effects -// (Use SM_SetSoundMode() to set) -// MusicMode - What device is used for music -// (Use SM_SetMusicMode() to set) -// DigiMode - What device is used for digitized sound effects -// (Use SM_SetDigiDevice() to set) -// -// For Cache Mgr: -// NeedsDigitized - load digitized sounds? -// NeedsMusic - load music? -// - -/// ///////////// /// -/// In Kolibrios - stub - -#include "wl_def.h" -//#include -#if defined(GP2X_940) -#include "gp2x/fmopl.h" -#else -#ifdef USE_GPL -#include "dosbox/dbopl.h" -#else -#include "mame/fmopl.h" -#endif -#endif - -#define ORIGSAMPLERATE 7042 - -typedef struct -{ - char RIFF[4]; - longword filelenminus8; - char WAVE[4]; - char fmt_[4]; - longword formatlen; - word val0x0001; - word channels; - longword samplerate; - longword bytespersec; - word bytespersample; - word bitspersample; -} headchunk; - -typedef struct -{ - char chunkid[4]; - longword chunklength; -} wavechunk; - -typedef struct -{ - uint32_t startpage; - uint32_t length; -} digiinfo; - -// Global variables - boolean AdLibPresent, - SoundBlasterPresent,SBProPresent, - SoundPositioned; - SDMode SoundMode; - SMMode MusicMode; - SDSMode DigiMode; -static byte **SoundTable; - int DigiMap[LASTSOUND]; - int DigiChannel[STARTMUSIC - STARTDIGISOUNDS]; - -// Internal variables -static boolean SD_Started; -static boolean nextsoundpos; -static soundnames SoundNumber; -static soundnames DigiNumber; -static word SoundPriority; -static word DigiPriority; -static int LeftPosition; -static int RightPosition; - - word NumDigi; -static digiinfo *DigiList; -static boolean DigiPlaying; - -// PC Sound variables -static volatile byte pcLastSample; -static byte * volatile pcSound; -static longword pcLengthLeft; - -// AdLib variables -static byte * volatile alSound; -static byte alBlock; -static longword alLengthLeft; -static longword alTimeCount; -static Instrument alZeroInst; - -// Sequencer variables -static volatile boolean sqActive; -static word *sqHack; -static word *sqHackPtr; -static int sqHackLen; -static int sqHackSeqLen; -static longword sqHackTime; - -// STUB -void SD_Startup(void){}; -void SD_Shutdown(void){}; - -int SD_GetChannelForDigi(int which){}; -void SD_PositionSound(int leftvol,int rightvol){}; -boolean SD_PlaySound(soundnames sound){}; -void SD_SetPosition(int channel, int leftvol,int rightvol){}; -void SD_StopSound(void){}; - void SD_WaitSoundDone(void){}; - -void SD_StartMusic(int chunk){}; -void SD_ContinueMusic(int chunk, int startoffs){}; -void SD_MusicOn(void){}; - void SD_FadeOutMusic(void){}; -int SD_MusicOff(void){}; - -boolean SD_MusicPlaying(void){}; -boolean SD_SetSoundMode(SDMode mode){}; -boolean SD_SetMusicMode(SMMode mode){}; -word SD_SoundPlaying(void){}; - -void SD_SetDigiDevice(SDSMode){}; -void SD_PrepareSound(int which){}; -int SD_PlayDigitized(word which,int leftpos,int rightpos){}; -void SD_StopDigitized(void){}; +// +// ID Engine +// ID_SD.c - Sound Manager for Wolfenstein 3D +// v1.2 +// By Jason Blochowiak +// + +// +// This module handles dealing with generating sound on the appropriate +// hardware +// +// Depends on: User Mgr (for parm checking) +// +// Globals: +// For User Mgr: +// SoundBlasterPresent - SoundBlaster card present? +// AdLibPresent - AdLib card present? +// SoundMode - What device is used for sound effects +// (Use SM_SetSoundMode() to set) +// MusicMode - What device is used for music +// (Use SM_SetMusicMode() to set) +// DigiMode - What device is used for digitized sound effects +// (Use SM_SetDigiDevice() to set) +// +// For Cache Mgr: +// NeedsDigitized - load digitized sounds? +// NeedsMusic - load music? +// + +#include "wl_def.h" +#include "SDL_mixer/SDL_mixer.h" +#if defined(GP2X_940) +#include "gp2x/fmopl.h" +#else +#include "mame/fmopl.h" +#endif + +#pragma hdrstop + +#define ORIGSAMPLERATE 7042 + +typedef struct +{ + char RIFF[4]; + longword filelenminus8; + char WAVE[4]; + char fmt_[4]; + longword formatlen; + word val0x0001; + word channels; + longword samplerate; + longword bytespersec; + word bytespersample; + word bitspersample; +} headchunk; + +typedef struct +{ + char chunkid[4]; + longword chunklength; +} wavechunk; + +typedef struct +{ + uint32_t startpage; + uint32_t length; +} digiinfo; + +static Mix_Chunk *SoundChunks[ STARTMUSIC - STARTDIGISOUNDS]; +static byte *SoundBuffers[STARTMUSIC - STARTDIGISOUNDS]; + +globalsoundpos channelSoundPos[MIX_CHANNELS]; + +// Global variables + boolean AdLibPresent, + SoundBlasterPresent,SBProPresent, + SoundPositioned; + SDMode SoundMode; + SMMode MusicMode; + SDSMode DigiMode; +static byte **SoundTable; + int DigiMap[LASTSOUND]; + int DigiChannel[STARTMUSIC - STARTDIGISOUNDS]; + +// Internal variables +static boolean SD_Started; +static boolean nextsoundpos; +static soundnames SoundNumber; +static soundnames DigiNumber; +static word SoundPriority; +static word DigiPriority; +static int LeftPosition; +static int RightPosition; + + word NumDigi; +static digiinfo *DigiList; +static boolean DigiPlaying; + +// PC Sound variables +static volatile byte pcLastSample; +static byte * volatile pcSound; +static longword pcLengthLeft; + +// AdLib variables +static byte * volatile alSound; +static byte alBlock; +static longword alLengthLeft; +static longword alTimeCount; +static Instrument alZeroInst; + +// Sequencer variables +static volatile boolean sqActive; +static word *sqHack; +static word *sqHackPtr; +static int sqHackLen; +static int sqHackSeqLen; +static longword sqHackTime; + + +static void SDL_SoundFinished(void) +{ + SoundNumber = (soundnames)0; + SoundPriority = 0; +} + + +#ifdef NOTYET + +void SDL_turnOnPCSpeaker(word timerval); +#pragma aux SDL_turnOnPCSpeaker = \ + "mov al,0b6h" \ + "out 43h,al" \ + "mov al,bl" \ + "out 42h,al" \ + "mov al,bh" \ + "out 42h,al" \ + "in al,61h" \ + "or al,3" \ + "out 61h,al" \ + parm [bx] \ + modify exact [al] + +void SDL_turnOffPCSpeaker(); +#pragma aux SDL_turnOffPCSpeaker = \ + "in al,61h" \ + "and al,0fch" \ + "out 61h,al" \ + modify exact [al] + +void SDL_setPCSpeaker(byte val); +#pragma aux SDL_setPCSpeaker = \ + "in al,61h" \ + "and al,0fch" \ + "or al,ah" \ + "out 61h,al" \ + parm [ah] \ + modify exact [al] + +void inline SDL_DoFX() +{ + if(pcSound) + { + if(*pcSound!=pcLastSample) + { + pcLastSample=*pcSound; + + if(pcLastSample) + SDL_turnOnPCSpeaker(pcLastSample*60); + else + SDL_turnOffPCSpeaker(); + } + pcSound++; + pcLengthLeft--; + if(!pcLengthLeft) + { + pcSound=0; + SoundNumber=(soundnames)0; + SoundPriority=0; + SDL_turnOffPCSpeaker(); + } + } + + // [adlib sound stuff removed...] +} + +static void SDL_DigitizedDoneInIRQ(void); + +void inline SDL_DoFast() +{ + count_fx++; + if(count_fx>=5) + { + count_fx=0; + + SDL_DoFX(); + + count_time++; + if(count_time>=2) + { + TimeCount++; + count_time=0; + } + } + + // [adlib music and soundsource stuff removed...] + + TimerCount+=TimerDivisor; + if(*((word *)&TimerCount+1)) + { + *((word *)&TimerCount+1)=0; + t0OldService(); + } + else + { + outp(0x20,0x20); + } +} + +// Timer 0 ISR for 7000Hz interrupts +void __interrupt SDL_t0ExtremeAsmService(void) +{ + if(pcindicate) + { + if(pcSound) + { + SDL_setPCSpeaker(((*pcSound++)&0x80)>>6); + pcLengthLeft--; + if(!pcLengthLeft) + { + pcSound=0; + SDL_turnOffPCSpeaker(); + SDL_DigitizedDoneInIRQ(); + } + } + } + extreme++; + if(extreme>=10) + { + extreme=0; + SDL_DoFast(); + } + else + outp(0x20,0x20); +} + +// Timer 0 ISR for 700Hz interrupts +void __interrupt SDL_t0FastAsmService(void) +{ + SDL_DoFast(); +} + +// Timer 0 ISR for 140Hz interrupts +void __interrupt SDL_t0SlowAsmService(void) +{ + count_time++; + if(count_time>=2) + { + TimeCount++; + count_time=0; + } + + SDL_DoFX(); + + TimerCount+=TimerDivisor; + if(*((word *)&TimerCount+1)) + { + *((word *)&TimerCount+1)=0; + t0OldService(); + } + else + outp(0x20,0x20); +} + +void SDL_IndicatePC(boolean ind) +{ + pcindicate=ind; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SetTimer0() - Sets system timer 0 to the specified speed +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_SetTimer0(word speed) +{ +#ifndef TPROF // If using Borland's profiling, don't screw with the timer +// _asm pushfd + _asm cli + + outp(0x43,0x36); // Change timer 0 + outp(0x40,(byte)speed); + outp(0x40,speed >> 8); + // Kludge to handle special case for digitized PC sounds + if (TimerDivisor == (1192030 / (TickBase * 100))) + TimerDivisor = (1192030 / (TickBase * 10)); + else + TimerDivisor = speed; + +// _asm popfd + _asm sti +#else + TimerDivisor = 0x10000; +#endif +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of +// interrupts generated by system timer 0 per second +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_SetIntsPerSec(word ints) +{ + TimerRate = ints; + SDL_SetTimer0(1192030 / ints); +} + +static void +SDL_SetTimerSpeed(void) +{ + word rate; + void (_interrupt *isr)(void); + + if ((DigiMode == sds_PC) && DigiPlaying) + { + rate = TickBase * 100; + isr = SDL_t0ExtremeAsmService; + } + else if ((MusicMode == smm_AdLib) || ((DigiMode == sds_SoundSource) && DigiPlaying) ) + { + rate = TickBase * 10; + isr = SDL_t0FastAsmService; + } + else + { + rate = TickBase * 2; + isr = SDL_t0SlowAsmService; + } + + if (rate != TimerRate) + { + _dos_setvect(8,isr); + SDL_SetIntsPerSec(rate); + TimerRate = rate; + } +} + +// +// PC Sound code +// + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCPlaySample() - Plays the specified sample on the PC speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCPlaySample(byte *data,longword len,boolean inIRQ) +{ + if(!inIRQ) + { +// _asm pushfd + _asm cli + } + + SDL_IndicatePC(true); + + pcLengthLeft = len; + pcSound = (volatile byte *)data; + + if(!inIRQ) + { +// _asm popfd + _asm sti + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCStopSample() - Stops a sample playing on the PC speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCStopSampleInIRQ(void) +{ + pcSound = 0; + + SDL_IndicatePC(false); + + _asm in al,0x61 // Turn the speaker off + _asm and al,0xfd // ~2 + _asm out 0x61,al +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCPlaySound() - Plays the specified sound on the PC speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCPlaySound(PCSound *sound) +{ +// _asm pushfd + _asm cli + + pcLastSample = -1; + pcLengthLeft = sound->common.length; + pcSound = sound->data; + +// _asm popfd + _asm sti +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_PCStopSound() - Stops the current sound playing on the PC Speaker +// +/////////////////////////////////////////////////////////////////////////// +#ifdef _MUSE_ +void +#else +static void +#endif +SDL_PCStopSound(void) +{ +// _asm pushfd + _asm cli + + pcSound = 0; + + _asm in al,0x61 // Turn the speaker off + _asm and al,0xfd // ~2 + _asm out 0x61,al + +// _asm popfd + _asm sti +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutPC() - Turns off the pc speaker +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutPC(void) +{ +// _asm pushfd + _asm cli + + pcSound = 0; + + _asm in al,0x61 // Turn the speaker & gate off + _asm and al,0xfc // ~3 + _asm out 0x61,al + +// _asm popfd + _asm sti +} + +#endif + +void +SD_StopDigitized(void) +{ + DigiPlaying = false; + DigiNumber = (soundnames) 0; + DigiPriority = 0; + SoundPositioned = false; + if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) + SDL_SoundFinished(); + + switch (DigiMode) + { + case sds_PC: +// SDL_PCStopSampleInIRQ(); + break; + case sds_SoundBlaster: +// SDL_SBStopSampleInIRQ(); + Mix_HaltChannel(-1); + break; + } +} + +int SD_GetChannelForDigi(int which) +{ + if(DigiChannel[which] != -1) return DigiChannel[which]; + + int channel = Mix_GroupAvailable(1); + if(channel == -1) channel = Mix_GroupOldest(1); + if(channel == -1) // All sounds stopped in the meantime? + return Mix_GroupAvailable(1); + return channel; +} + +void SD_SetPosition(int channel, int leftpos, int rightpos) +{ + if((leftpos < 0) || (leftpos > 15) || (rightpos < 0) || (rightpos > 15) + || ((leftpos == 15) && (rightpos == 15))) + Quit("SD_SetPosition: Illegal position"); + + switch (DigiMode) + { + case sds_SoundBlaster: +// SDL_PositionSBP(leftpos,rightpos); + Mix_SetPanning(channel, ((15 - leftpos) << 4) + 15, + ((15 - rightpos) << 4) + 15); + break; + } +} + +Sint16 GetSample(float csample, byte *samples, int size) +{ + float s0=0, s1=0, s2=0; + int cursample = (int) csample; + float sf = csample - (float) cursample; + + if(cursample-1 >= 0) s0 = (float) (samples[cursample-1] - 128); + s1 = (float) (samples[cursample] - 128); + if(cursample+1 < size) s2 = (float) (samples[cursample+1] - 128); + + float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2; + int32_t intval = (int32_t) (val * 256); + if(intval < -32768) intval = -32768; + else if(intval > 32767) intval = 32767; + return (Sint16) intval; +} + +void SD_PrepareSound(int which) +{ + if(DigiList == NULL) + Quit("SD_PrepareSound(%i): DigiList not initialized!\n", which); + + int page = DigiList[which].startpage; + int size = DigiList[which].length; + + byte *origsamples = PM_GetSound(page); + if(origsamples + size >= PM_GetEnd()) + Quit("SD_PrepareSound(%i): Sound reaches out of page file!\n", which); + + int destsamples = (int) ((float) size * (float) param_samplerate + / (float) ORIGSAMPLERATE); + + byte *wavebuffer = (byte *) malloc(sizeof(headchunk) + sizeof(wavechunk) + + destsamples * 2); // dest are 16-bit samples + if(wavebuffer == NULL) + Quit("Unable to allocate wave buffer for sound %i!\n", which); + + headchunk head = {{'R','I','F','F'}, 0, {'W','A','V','E'}, + {'f','m','t',' '}, 0x10, 0x0001, 1, param_samplerate, param_samplerate*2, 2, 16}; + wavechunk dhead = {{'d', 'a', 't', 'a'}, destsamples*2}; + head.filelenminus8 = sizeof(head) + destsamples*2; // (sizeof(dhead)-8 = 0) + memcpy(wavebuffer, &head, sizeof(head)); + memcpy(wavebuffer+sizeof(head), &dhead, sizeof(dhead)); + + // alignment is correct, as wavebuffer comes from malloc + // and sizeof(headchunk) % 4 == 0 and sizeof(wavechunk) % 4 == 0 + Sint16 *newsamples = (Sint16 *)(void *) (wavebuffer + sizeof(headchunk) + + sizeof(wavechunk)); + float cursample = 0.F; + float samplestep = (float) ORIGSAMPLERATE / (float) param_samplerate; + for(int i=0; i= NumDigi) + Quit("SD_PlayDigitized: bad sound number %i", which); + + int channel = SD_GetChannelForDigi(which); + SD_SetPosition(channel, leftpos,rightpos); + + DigiPlaying = true; + + Mix_Chunk *sample = SoundChunks[which]; + if(sample == NULL) + { + printf("SoundChunks[%i] is NULL!\n", which); + return 0; + } + + if(Mix_PlayChannel(channel, sample, 0) == -1) + { + printf("Unable to play sound: %s\n", Mix_GetError()); + return 0; + } + + return channel; +} + +void SD_ChannelFinished(int channel) +{ + channelSoundPos[channel].valid = 0; +} + +void +SD_SetDigiDevice(SDSMode mode) +{ + boolean devicenotpresent; + + if (mode == DigiMode) + return; + + SD_StopDigitized(); + + devicenotpresent = false; + switch (mode) + { + case sds_SoundBlaster: + if (!SoundBlasterPresent) + devicenotpresent = true; + break; + } + + if (!devicenotpresent) + { + DigiMode = mode; + +#ifdef NOTYET + SDL_SetTimerSpeed(); +#endif + } +} + +void +SDL_SetupDigi(void) +{ + // Correct padding enforced by PM_Startup() + word *soundInfoPage = (word *) (void *) PM_GetPage(ChunksInFile-1); + NumDigi = (word) PM_GetPageSize(ChunksInFile - 1) / 4; + + DigiList = (digiinfo *) malloc(NumDigi * sizeof(digiinfo)); + int i; + for(i = 0; i < NumDigi; i++) + { + // Calculate the size of the digi from the sizes of the pages between + // the start page and the start page of the next sound + + DigiList[i].startpage = soundInfoPage[i * 2]; + if((int) DigiList[i].startpage >= ChunksInFile - 1) + { + NumDigi = i; + break; + } + + int lastPage; + if(i < NumDigi - 1) + { + lastPage = soundInfoPage[i * 2 + 2]; + if(lastPage == 0 || lastPage + PMSoundStart > ChunksInFile - 1) lastPage = ChunksInFile - 1; + else lastPage += PMSoundStart; + } + else lastPage = ChunksInFile - 1; + + int size = 0; + for(int page = PMSoundStart + DigiList[i].startpage; page < lastPage; page++) + size += PM_GetPageSize(page); + + // Don't include padding of sound info page, if padding was added + if(lastPage == ChunksInFile - 1 && PMSoundInfoPagePadded) size--; + + // Patch lower 16-bit of size with size from sound info page. + // The original VSWAP contains padding which is included in the page size, + // but not included in the 16-bit size. So we use the more precise value. + if((size & 0xffff0000) != 0 && (size & 0xffff) < soundInfoPage[i * 2 + 1]) + size -= 0x10000; + size = (size & 0xffff0000) | soundInfoPage[i * 2 + 1]; + + DigiList[i].length = size; + } + + for(i = 0; i < LASTSOUND; i++) + { + DigiMap[i] = -1; + DigiChannel[i] = -1; + } +} + +// AdLib Code + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALStopSound() - Turns off any sound effects playing through the +// AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ALStopSound(void) +{ + alSound = 0; + alOut(alFreqH + 0, 0); +} + +static void +SDL_AlSetFXInst(Instrument *inst) +{ + byte c,m; + + m = 0; // modulator cell for channel 0 + c = 3; // carrier cell for channel 0 + alOut(m + alChar,inst->mChar); + alOut(m + alScale,inst->mScale); + alOut(m + alAttack,inst->mAttack); + alOut(m + alSus,inst->mSus); + alOut(m + alWave,inst->mWave); + alOut(c + alChar,inst->cChar); + alOut(c + alScale,inst->cScale); + alOut(c + alAttack,inst->cAttack); + alOut(c + alSus,inst->cSus); + alOut(c + alWave,inst->cWave); + + // Note: Switch commenting on these lines for old MUSE compatibility +// alOutInIRQ(alFeedCon,inst->nConn); + alOut(alFeedCon,0); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ALPlaySound() - Plays the specified sound on the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ALPlaySound(AdLibSound *sound) +{ + Instrument *inst; + byte *data; + + SDL_ALStopSound(); + + alLengthLeft = sound->common.length; + data = sound->data; + alBlock = ((sound->block & 7) << 2) | 0x20; + inst = &sound->inst; + + if (!(inst->mSus | inst->cSus)) + { + Quit("SDL_ALPlaySound() - Bad instrument"); + } + + SDL_AlSetFXInst(inst); + alSound = (byte *)data; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutAL() - Shuts down the AdLib card for sound effects +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutAL(void) +{ + alSound = 0; + alOut(alEffects,0); + alOut(alFreqH + 0,0); + SDL_AlSetFXInst(&alZeroInst); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CleanAL() - Totally shuts down the AdLib card +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_CleanAL(void) +{ + int i; + + alOut(alEffects,0); + for (i = 1; i < 0xf5; i++) + alOut(i, 0); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartAL() - Starts up the AdLib card for sound effects +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartAL(void) +{ + alOut(alEffects, 0); + SDL_AlSetFXInst(&alZeroInst); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster +// emulating an AdLib) present +// +/////////////////////////////////////////////////////////////////////////// +static boolean +SDL_DetectAdLib(void) +{ + for (int i = 1; i <= 0xf5; i++) // Zero all the registers + alOut(i, 0); + + alOut(1, 0x20); // Set WSE=1 +// alOut(8, 0); // Set CSM=0 & SEL=0 + + return true; +} + +//////////////////////////////////////////////////////////////////////////// +// +// SDL_ShutDevice() - turns off whatever device was being used for sound fx +// +//////////////////////////////////////////////////////////////////////////// +static void +SDL_ShutDevice(void) +{ + switch (SoundMode) + { + case sdm_PC: +// SDL_ShutPC(); + break; + case sdm_AdLib: + SDL_ShutAL(); + break; + } + SoundMode = sdm_Off; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_CleanDevice() - totally shuts down all sound devices +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_CleanDevice(void) +{ + if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib)) + SDL_CleanAL(); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SDL_StartDevice() - turns on whatever device is to be used for sound fx +// +/////////////////////////////////////////////////////////////////////////// +static void +SDL_StartDevice(void) +{ + switch (SoundMode) + { + case sdm_AdLib: + SDL_StartAL(); + break; + } + SoundNumber = (soundnames) 0; + SoundPriority = 0; +} + +// Public routines + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SetSoundMode() - Sets which sound hardware to use for sound effects +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_SetSoundMode(SDMode mode) +{ + boolean result = false; + word tableoffset; + + SD_StopSound(); + + if ((mode == sdm_AdLib) && !AdLibPresent) + mode = sdm_PC; + + switch (mode) + { + case sdm_Off: + tableoffset = STARTADLIBSOUNDS; + result = true; + break; + case sdm_PC: + tableoffset = STARTPCSOUNDS; + result = true; + break; + case sdm_AdLib: + tableoffset = STARTADLIBSOUNDS; + if (AdLibPresent) + result = true; + break; + default: + Quit("SD_SetSoundMode: Invalid sound mode %i", mode); + return false; + } + SoundTable = &audiosegs[tableoffset]; + + if (result && (mode != SoundMode)) + { + SDL_ShutDevice(); + SoundMode = mode; + SDL_StartDevice(); + } + + return(result); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SetMusicMode() - sets the device to use for background music +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_SetMusicMode(SMMode mode) +{ + boolean result = false; + + SD_FadeOutMusic(); + while (SD_MusicPlaying()) + SDL_Delay(5); + + switch (mode) + { + case smm_Off: + result = true; + break; + case smm_AdLib: + if (AdLibPresent) + result = true; + break; + } + + if (result) + MusicMode = mode; + +// SDL_SetTimerSpeed(); + + return(result); +} + +int numreadysamples = 0; +byte *curAlSound = 0; +byte *curAlSoundPtr = 0; +longword curAlLengthLeft = 0; +int soundTimeCounter = 5; +int samplesPerMusicTick; + +void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len) +{ + int stereolen = len>>1; + int sampleslen = stereolen>>1; + INT16 *stream16 = (INT16 *) (void *) stream; // expect correct alignment + + while(1) + { + if(numreadysamples) + { + if(numreadysamples alTimeCount) break; + sqHackTime = alTimeCount + *(sqHackPtr+1); + alOut(*(byte *) sqHackPtr, *(((byte *) sqHackPtr)+1)); + sqHackPtr += 2; + sqHackLen -= 4; + } + while(sqHackLen>0); + alTimeCount++; + if(!sqHackLen) + { + sqHackPtr = sqHack; + sqHackLen = sqHackSeqLen; + sqHackTime = 0; + alTimeCount = 0; + } + } + numreadysamples = samplesPerMusicTick; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_Startup() - starts up the Sound Mgr +// Detects all additional sound hardware and installs my ISR +// +/////////////////////////////////////////////////////////////////////////// +void +SD_Startup(void) +{ + int i; + + if (SD_Started) + return; + + if(Mix_OpenAudio(param_samplerate, AUDIO_S16, 2, param_audiobuffer)) + { + printf("Unable to open audio: %s\n", Mix_GetError()); + return; + } + + Mix_ReserveChannels(2); // reserve player and boss weapon channels + Mix_GroupChannels(2, MIX_CHANNELS-1, 1); // group remaining channels + + // Init music + + samplesPerMusicTick = param_samplerate / 700; // SDL_t0FastAsmService played at 700Hz + + if(YM3812Init(1,3579545,param_samplerate)) + { + printf("Unable to create virtual OPL!!\n"); + } + + for(i=1;i<0xf6;i++) + YM3812Write(0,i,0); + + YM3812Write(0,1,0x20); // Set WSE=1 +// YM3812Write(0,8,0); // Set CSM=0 & SEL=0 // already set in for statement + + Mix_HookMusic(SDL_IMFMusicPlayer, 0); + Mix_ChannelFinished(SD_ChannelFinished); + AdLibPresent = true; + SoundBlasterPresent = true; + + alTimeCount = 0; + + SD_SetSoundMode(sdm_Off); + SD_SetMusicMode(smm_Off); + + SDL_SetupDigi(); + + SD_Started = true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_Shutdown() - shuts down the Sound Mgr +// Removes sound ISR and turns off whatever sound hardware was active +// +/////////////////////////////////////////////////////////////////////////// +void +SD_Shutdown(void) +{ + if (!SD_Started) + return; + + SD_MusicOff(); + SD_StopSound(); + + for(int i = 0; i < STARTMUSIC - STARTDIGISOUNDS; i++) + { + if(SoundChunks[i]) Mix_FreeChunk(SoundChunks[i]); + if(SoundBuffers[i]) free(SoundBuffers[i]); + } + + free(DigiList); + + SD_Started = false; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_PositionSound() - Sets up a stereo imaging location for the next +// sound to be played. Each channel ranges from 0 to 15. +// +/////////////////////////////////////////////////////////////////////////// +void +SD_PositionSound(int leftvol,int rightvol) +{ + LeftPosition = leftvol; + RightPosition = rightvol; + nextsoundpos = true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_PlaySound() - plays the specified sound on the appropriate hardware +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_PlaySound(soundnames sound) +{ + boolean ispos; + SoundCommon *s; + int lp,rp; + + lp = LeftPosition; + rp = RightPosition; + LeftPosition = 0; + RightPosition = 0; + + ispos = nextsoundpos; + nextsoundpos = false; + + if (sound == -1 || (DigiMode == sds_Off && SoundMode == sdm_Off)) + return 0; + + s = (SoundCommon *) SoundTable[sound]; + + if ((SoundMode != sdm_Off) && !s) + Quit("SD_PlaySound() - Uncached sound"); + + if ((DigiMode != sds_Off) && (DigiMap[sound] != -1)) + { + if ((DigiMode == sds_PC) && (SoundMode == sdm_PC)) + { +#ifdef NOTYET + if (s->priority < SoundPriority) + return 0; + + SDL_PCStopSound(); + + SD_PlayDigitized(DigiMap[sound],lp,rp); + SoundPositioned = ispos; + SoundNumber = sound; + SoundPriority = s->priority; +#else + return 0; +#endif + } + else + { +#ifdef NOTYET + if (s->priority < DigiPriority) + return(false); +#endif + + int channel = SD_PlayDigitized(DigiMap[sound], lp, rp); + SoundPositioned = ispos; + DigiNumber = sound; + DigiPriority = s->priority; + return channel + 1; + } + + return(true); + } + + if (SoundMode == sdm_Off) + return 0; + + if (!s->length) + Quit("SD_PlaySound() - Zero length sound"); + if (s->priority < SoundPriority) + return 0; + + switch (SoundMode) + { + case sdm_PC: +// SDL_PCPlaySound((PCSound *)s); + break; + case sdm_AdLib: + SDL_ALPlaySound((AdLibSound *)s); + break; + } + + SoundNumber = sound; + SoundPriority = s->priority; + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_SoundPlaying() - returns the sound number that's playing, or 0 if +// no sound is playing +// +/////////////////////////////////////////////////////////////////////////// + +word +SD_SoundPlaying(void) +{ + boolean result = false; + + switch (SoundMode) + { + case sdm_PC: + result = pcSound? true : false; + break; + case sdm_AdLib: + result = alSound? true : false; + break; + } + + if (result) + return(SoundNumber); + else + return(false); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_StopSound() - if a sound is playing, stops it +// +/////////////////////////////////////////////////////////////////////////// +void +SD_StopSound(void) +{ + if (DigiPlaying) + SD_StopDigitized(); + + switch (SoundMode) + { + case sdm_PC: +// SDL_PCStopSound(); + break; + case sdm_AdLib: + SDL_ALStopSound(); + break; + } + + SoundPositioned = false; + + SDL_SoundFinished(); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_WaitSoundDone() - waits until the current sound is done playing +// +/////////////////////////////////////////////////////////////////////////// +void +SD_WaitSoundDone(void) +{ + while (SD_SoundPlaying()) + SDL_Delay(5); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicOn() - turns on the sequencer +// +/////////////////////////////////////////////////////////////////////////// +void +SD_MusicOn(void) +{ + sqActive = true; +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicOff() - turns off the sequencer and any playing notes +// returns the last music offset for music continue +// +/////////////////////////////////////////////////////////////////////////// +int +SD_MusicOff(void) +{ + word i; + + sqActive = false; + switch (MusicMode) + { + case smm_AdLib: + alOut(alEffects, 0); + for (i = 0;i < sqMaxTracks;i++) + alOut(alFreqH + i + 1, 0); + break; + } + + return (int) (sqHackPtr-sqHack); +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_StartMusic() - starts playing the music pointed to +// +/////////////////////////////////////////////////////////////////////////// +void +SD_StartMusic(int chunk) +{ + SD_MusicOff(); + + if (MusicMode == smm_AdLib) + { + int32_t chunkLen = CA_CacheAudioChunk(chunk); + sqHack = (word *)(void *) audiosegs[chunk]; // alignment is correct + if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen; + else sqHackLen = sqHackSeqLen = *sqHack++; + sqHackPtr = sqHack; + sqHackTime = 0; + alTimeCount = 0; + SD_MusicOn(); + } +} + +void +SD_ContinueMusic(int chunk, int startoffs) +{ + SD_MusicOff(); + + if (MusicMode == smm_AdLib) + { + int32_t chunkLen = CA_CacheAudioChunk(chunk); + sqHack = (word *)(void *) audiosegs[chunk]; // alignment is correct + if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen; + else sqHackLen = sqHackSeqLen = *sqHack++; + sqHackPtr = sqHack; + + if(startoffs >= sqHackLen) + { + Quit("SD_StartMusic: Illegal startoffs provided!"); + } + + // fast forward to correct position + // (needed to reconstruct the instruments) + + for(int i = 0; i < startoffs; i += 2) + { + byte reg = *(byte *)sqHackPtr; + byte val = *(((byte *)sqHackPtr) + 1); + if(reg >= 0xb1 && reg <= 0xb8) val &= 0xdf; // disable play note flag + else if(reg == 0xbd) val &= 0xe0; // disable drum flags + + alOut(reg,val); + sqHackPtr += 2; + sqHackLen -= 4; + } + sqHackTime = 0; + alTimeCount = 0; + + SD_MusicOn(); + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying() +// to see if the fadeout is complete +// +/////////////////////////////////////////////////////////////////////////// +void +SD_FadeOutMusic(void) +{ + switch (MusicMode) + { + case smm_AdLib: + // DEBUG - quick hack to turn the music off + SD_MusicOff(); + break; + } +} + +/////////////////////////////////////////////////////////////////////////// +// +// SD_MusicPlaying() - returns true if music is currently playing, false if +// not +// +/////////////////////////////////////////////////////////////////////////// +boolean +SD_MusicPlaying(void) +{ + boolean result; + + switch (MusicMode) + { + case smm_AdLib: + result = sqActive; + break; + default: + result = false; + break; + } + + return(result); +} diff --git a/contrib/games/wolf3d/id_sd.h b/contrib/games/wolf3d/id_sd.h index b55e7db7ee..540dc74ff5 100755 --- a/contrib/games/wolf3d/id_sd.h +++ b/contrib/games/wolf3d/id_sd.h @@ -1,156 +1,156 @@ -// -// ID Engine -// ID_SD.h - Sound Manager Header -// Version for Wolfenstein -// By Jason Blochowiak -// - -#ifndef __ID_SD__ -#define __ID_SD__ - -#define alOut(n,b) YM3812Write(oplChip, n, b) - -#define TickBase 70 // 70Hz per tick - used as a base for timer 0 - -typedef enum -{ - sdm_Off, - sdm_PC,sdm_AdLib, -} SDMode; - -typedef enum -{ - smm_Off,smm_AdLib -} SMMode; - -typedef enum -{ - sds_Off,sds_PC,sds_SoundBlaster -} SDSMode; - -typedef struct -{ - longword length; - word priority; -} SoundCommon; - -#define ORIG_SOUNDCOMMON_SIZE 6 - -// PC Sound stuff -#define pcTimer 0x42 -#define pcTAccess 0x43 -#define pcSpeaker 0x61 - -#define pcSpkBits 3 - -typedef struct -{ - SoundCommon common; - byte data[1]; -} PCSound; - -// Register addresses -// Operator stuff -#define alChar 0x20 -#define alScale 0x40 -#define alAttack 0x60 -#define alSus 0x80 -#define alWave 0xe0 -// Channel stuff -#define alFreqL 0xa0 -#define alFreqH 0xb0 -#define alFeedCon 0xc0 -// Global stuff -#define alEffects 0xbd - -typedef struct -{ - byte mChar,cChar, - mScale,cScale, - mAttack,cAttack, - mSus,cSus, - mWave,cWave, - nConn, - - // These are only for Muse - these bytes are really unused - voice, - mode; - byte unused[3]; -} Instrument; - -#define ORIG_INSTRUMENT_SIZE 16 - -typedef struct -{ - SoundCommon common; - Instrument inst; - byte block; - byte data[1]; -} AdLibSound; - -#define ORIG_ADLIBSOUND_SIZE (ORIG_SOUNDCOMMON_SIZE + ORIG_INSTRUMENT_SIZE + 2) - -// -// Sequencing stuff -// -#define sqMaxTracks 10 - -typedef struct -{ - word length; - word values[1]; -} MusicGroup; - -typedef struct -{ - int valid; - fixed globalsoundx, globalsoundy; -} globalsoundpos; - -extern int channelSoundPos[]; - -// Global variables -extern boolean AdLibPresent, - SoundBlasterPresent, - SoundPositioned; -extern SDMode SoundMode; -extern SDSMode DigiMode; -extern SMMode MusicMode; -extern int DigiMap[]; -extern int DigiChannel[]; - -#define GetTimeCount() ((SDL_GetTicks()*7)/100) - -inline void Delay(int wolfticks) -{ - if(wolfticks>0) SDL_Delay(wolfticks * 100 / 7); -} - -// Function prototypes -extern void SD_Startup(void), - SD_Shutdown(void); - -extern int SD_GetChannelForDigi(int which); -extern void SD_PositionSound(int leftvol,int rightvol); -extern boolean SD_PlaySound(soundnames sound); -extern void SD_SetPosition(int channel, int leftvol,int rightvol); -extern void SD_StopSound(void), - SD_WaitSoundDone(void); - -extern void SD_StartMusic(int chunk); -extern void SD_ContinueMusic(int chunk, int startoffs); -extern void SD_MusicOn(void), - SD_FadeOutMusic(void); -extern int SD_MusicOff(void); - -extern boolean SD_MusicPlaying(void); -extern boolean SD_SetSoundMode(SDMode mode); -extern boolean SD_SetMusicMode(SMMode mode); -extern word SD_SoundPlaying(void); - -extern void SD_SetDigiDevice(SDSMode); -extern void SD_PrepareSound(int which); -extern int SD_PlayDigitized(word which,int leftpos,int rightpos); -extern void SD_StopDigitized(void); - -#endif +// +// ID Engine +// ID_SD.h - Sound Manager Header +// Version for Wolfenstein +// By Jason Blochowiak +// + +#ifndef __ID_SD__ +#define __ID_SD__ + +#define alOut(n,b) YM3812Write(0, n, b) + +#define TickBase 70 // 70Hz per tick - used as a base for timer 0 + +typedef enum +{ + sdm_Off, + sdm_PC,sdm_AdLib, +} SDMode; + +typedef enum +{ + smm_Off,smm_AdLib +} SMMode; + +typedef enum +{ + sds_Off,sds_PC,sds_SoundBlaster +} SDSMode; + +typedef struct +{ + longword length; + word priority; +} SoundCommon; + +#define ORIG_SOUNDCOMMON_SIZE 6 + +// PC Sound stuff +#define pcTimer 0x42 +#define pcTAccess 0x43 +#define pcSpeaker 0x61 + +#define pcSpkBits 3 + +typedef struct +{ + SoundCommon common; + byte data[1]; +} PCSound; + +// Register addresses +// Operator stuff +#define alChar 0x20 +#define alScale 0x40 +#define alAttack 0x60 +#define alSus 0x80 +#define alWave 0xe0 +// Channel stuff +#define alFreqL 0xa0 +#define alFreqH 0xb0 +#define alFeedCon 0xc0 +// Global stuff +#define alEffects 0xbd + +typedef struct +{ + byte mChar,cChar, + mScale,cScale, + mAttack,cAttack, + mSus,cSus, + mWave,cWave, + nConn, + + // These are only for Muse - these bytes are really unused + voice, + mode; + byte unused[3]; +} Instrument; + +#define ORIG_INSTRUMENT_SIZE 16 + +typedef struct +{ + SoundCommon common; + Instrument inst; + byte block; + byte data[1]; +} AdLibSound; + +#define ORIG_ADLIBSOUND_SIZE (ORIG_SOUNDCOMMON_SIZE + ORIG_INSTRUMENT_SIZE + 2) + +// +// Sequencing stuff +// +#define sqMaxTracks 10 + +typedef struct +{ + word length; + word values[1]; +} MusicGroup; + +typedef struct +{ + int valid; + fixed globalsoundx, globalsoundy; +} globalsoundpos; + +extern globalsoundpos channelSoundPos[]; + +// Global variables +extern boolean AdLibPresent, + SoundBlasterPresent, + SoundPositioned; +extern SDMode SoundMode; +extern SDSMode DigiMode; +extern SMMode MusicMode; +extern int DigiMap[]; +extern int DigiChannel[]; + +#define GetTimeCount() ((SDL_GetTicks()*7)/100) + +inline void Delay(int wolfticks) +{ + if(wolfticks>0) SDL_Delay(wolfticks * 100 / 7); +} + +// Function prototypes +extern void SD_Startup(void), + SD_Shutdown(void); + +extern int SD_GetChannelForDigi(int which); +extern void SD_PositionSound(int leftvol,int rightvol); +extern boolean SD_PlaySound(soundnames sound); +extern void SD_SetPosition(int channel, int leftvol,int rightvol); +extern void SD_StopSound(void), + SD_WaitSoundDone(void); + +extern void SD_StartMusic(int chunk); +extern void SD_ContinueMusic(int chunk, int startoffs); +extern void SD_MusicOn(void), + SD_FadeOutMusic(void); +extern int SD_MusicOff(void); + +extern boolean SD_MusicPlaying(void); +extern boolean SD_SetSoundMode(SDMode mode); +extern boolean SD_SetMusicMode(SMMode mode); +extern word SD_SoundPlaying(void); + +extern void SD_SetDigiDevice(SDSMode); +extern void SD_PrepareSound(int which); +extern int SD_PlayDigitized(word which,int leftpos,int rightpos); +extern void SD_StopDigitized(void); + +#endif diff --git a/contrib/games/wolf3d/wl_inter.cpp b/contrib/games/wolf3d/wl_inter.cpp index 113c55c79d..5c66555865 100755 --- a/contrib/games/wolf3d/wl_inter.cpp +++ b/contrib/games/wolf3d/wl_inter.cpp @@ -2,7 +2,7 @@ #include "wl_def.h" #pragma hdrstop - +#define itoa ltoa LRstruct LevelRatios[LRpack]; int32_t lastBreathTime = 0; diff --git a/contrib/games/wolf3d/wl_main.cpp b/contrib/games/wolf3d/wl_main.cpp index 114eca6c57..efff1c0338 100755 --- a/contrib/games/wolf3d/wl_main.cpp +++ b/contrib/games/wolf3d/wl_main.cpp @@ -1210,11 +1210,12 @@ static void InitGame() #if defined _WIN32 putenv("SDL_VIDEODRIVER=directx"); #endif - if(SDL_Init(SDL_INIT_VIDEO /*| SDL_INIT_AUDIO | SDL_INIT_JOYSTICK*/) < 0) + if(SDL_Init(SDL_INIT_VIDEO) < 0) { printf("Unable to init SDL: %s\n", SDL_GetError()); exit(1); } + SDL_AudioInit(NULL); atexit(SDL_Quit); int numJoysticks = SDL_NumJoysticks(); @@ -1232,8 +1233,10 @@ static void InitGame() #endif SignonScreen (); +#ifdef _KOLIBRI kolibri_set_win_center(); - +#endif + #if defined _WIN32 if(!fullscreen) { @@ -1886,6 +1889,9 @@ void CheckParameters(int argc, char *argv[]) printf( "Wolf4SDL v1.7 ($Revision$)\n" "Ported by Chaos-Software (http://www.chaos-software.de.vu)\n" + #ifdef _KOLIBRI + "Ported for KolibriOS by 'turbocat2001' and 'maxcodehack'\n" + #endif "Original Wolfenstein 3D by id Software\n\n" "Usage: Wolf4SDL [options]\n" "Options:\n" @@ -1896,8 +1902,10 @@ void CheckParameters(int argc, char *argv[]) " --normal Sets the difficulty to normal for tedlevel\n" " --hard Sets the difficulty to hard for tedlevel\n" " --nowait Skips intro screens\n" + #ifndef _KOLIBRI " --windowed[-mouse] Starts the game in a window [and grabs mouse]\n" " --res Sets the screen resolution\n" + #endif " (must be multiple of 320x200 or 320x240)\n" " --resf Sets any screen resolution >= 320x200\n" " (which may result in graphic errors)\n" @@ -1907,9 +1915,11 @@ void CheckParameters(int argc, char *argv[]) " --nodblbuf Don't use SDL's double buffering\n" " --extravbls Sets a delay after each frame, which may help to\n" " reduce flickering (unit is currently 8 ms, default: 0)\n" + #ifndef _KOLIBRI " --joystick Use the index-th joystick if available\n" " (-1 to disable joystick, default: 0)\n" " --joystickhat Enables movement with the given coolie hat\n" + #endif " --samplerate Sets the sound sample rate (given in Hz, default: %i)\n" " --audiobuffer Sets the size of the audio buffer (-> sound latency)\n" " (given in bytes, default: 2048 / (44100 / samplerate))\n"