From 75033fb4fe38db118113ac1b225f8a03fb6b2575 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 27 Dec 1999 19:24:50 +0000 Subject: [PATCH] FXJ - Updated the mikmod support to MikMod 3.1.8 FXJ - Added Mix_HookMusicFinished() API function --- CHANGES | 6 +- Makefile.am | 16 +- Makefile.in | 79 +- README | 5 +- aclocal.m4 | 4 +- configure | 113 +- configure.in | 4 +- mikmod/Makefile.am | 15 +- mikmod/Makefile.in | 28 +- mikmod/README | 16 +- mikmod/drv_nos.c | 212 +- mikmod/drv_sdl.c | 13 +- mikmod/load_it.c | 1766 ++++++++------- mikmod/load_mod.c | 591 ++--- mikmod/load_s3m.c | 809 ++++--- mikmod/load_xm.c | 1324 ++++++------ mikmod/mdreg.c | 55 +- mikmod/mdriver.c | 1142 ++++++---- mikmod/mikmod.h | 977 ++++++--- mikmod/mloader.c | 759 ++++--- mikmod/mlreg.c | 74 +- mikmod/mmalloc.c | 94 +- mikmod/mmerror.c | 260 ++- mikmod/mmio.c | 535 ++--- mikmod/mplayer.c | 4902 ++++++++++++++++++++++-------------------- mikmod/munitrk.c | 464 ++-- mikmod/npertab.c | 57 +- mikmod/sloader.c | 782 ++++--- mikmod/virtch.c | 1940 ++++++----------- mixer.c | 11 +- mixer.h | 225 ++ music.c | 55 +- timidity/Makefile.in | 9 +- wavestream.c | 8 +- 34 files changed, 9203 insertions(+), 8147 deletions(-) create mode 100644 mixer.h diff --git a/CHANGES b/CHANGES index 95aa1306..48461fdd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,8 @@ +1.0.2: +FXJ - Updated the mikmod support to MikMod 3.1.8 +FXJ - Added Mix_HookMusicFinished() API function + 1.0.1: SOL - Added a post-mixing callback SP - A few music-related bugfixes @@ -14,4 +18,4 @@ SP - Added expiration delay for samples Initial Key: SOL - Sam Lantinga (hercules@lokigames.com) SP - Stephane Peter (megastep@lokigames.com) - +FXJ - Markus Oberhumer (markus.oberhumer@jk.uni-linz.ac.at) diff --git a/Makefile.am b/Makefile.am index 4903c3c2..db8db5d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,15 +1,15 @@ # Makefile.am for the SDL sample mixer library and players -lib_LTLIBRARIES = libmixer.la +lib_LTLIBRARIES = libSDLmixer.la SUBDIRS = @MUSIC_SUBDIRS@ DIST_SUBIDRS = mikmod timidity -libmixerincludedir = $(includedir) -libmixerinclude_HEADERS = \ +libSDLmixerincludedir = $(includedir) +libSDLmixerinclude_HEADERS = \ mixer.h -libmixer_la_SOURCES = \ +libSDLmixer_la_SOURCES = \ mixer.c \ music.c \ music_cmd.c \ @@ -29,12 +29,12 @@ else TIMIDITY_LIB = endif -libmixer_la_LDFLAGS = \ +libSDLmixer_la_LDFLAGS = \ -release $(LT_RELEASE) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -libmixer_la_LIBADD = $(MIKMOD_LIB) $(TIMIDITY_LIB) +libSDLmixer_la_LIBADD = $(MIKMOD_LIB) $(TIMIDITY_LIB) bin_PROGRAMS = playwave playmus -playwave_LDADD = libmixer.la -playmus_LDADD = libmixer.la +playwave_LDADD = libSDLmixer.la +playmus_LDADD = libSDLmixer.la diff --git a/Makefile.in b/Makefile.in index 531404d2..beda423e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am +# Makefile.in generated automatically by automake 1.4a from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation @@ -48,9 +48,10 @@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = transform = @program_transform_name@ NORMAL_INSTALL = : @@ -87,30 +88,30 @@ SDL_CONFIG = @SDL_CONFIG@ SDL_LIBS = @SDL_LIBS@ VERSION = @VERSION@ -lib_LTLIBRARIES = libmixer.la +lib_LTLIBRARIES = libSDLmixer.la SUBDIRS = @MUSIC_SUBDIRS@ DIST_SUBIDRS = mikmod timidity -libmixerincludedir = $(includedir) -libmixerinclude_HEADERS = mixer.h +libSDLmixerincludedir = $(includedir) +libSDLmixerinclude_HEADERS = mixer.h -libmixer_la_SOURCES = mixer.c music.c music_cmd.c music_cmd.h wave.h wavestream.c wavestream.h +libSDLmixer_la_SOURCES = mixer.c music.c music_cmd.c music_cmd.h wave.h wavestream.c wavestream.h @USE_MIKMOD_TRUE@MIKMOD_LIB = mikmod/libmikmod.la @USE_MIKMOD_FALSE@MIKMOD_LIB = @USE_TIMIDITY_TRUE@TIMIDITY_LIB = timidity/libtimidity.la @USE_TIMIDITY_FALSE@TIMIDITY_LIB = -libmixer_la_LDFLAGS = -release $(LT_RELEASE) -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) +libSDLmixer_la_LDFLAGS = -release $(LT_RELEASE) -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -libmixer_la_LIBADD = $(MIKMOD_LIB) $(TIMIDITY_LIB) +libSDLmixer_la_LIBADD = $(MIKMOD_LIB) $(TIMIDITY_LIB) bin_PROGRAMS = playwave playmus -playwave_LDADD = libmixer.la -playmus_LDADD = libmixer.la +playwave_LDADD = libSDLmixer.la +playmus_LDADD = libSDLmixer.la ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = @@ -121,31 +122,31 @@ DEFS = @DEFS@ -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -@USE_TIMIDITY_FALSE@@USE_MIKMOD_FALSE@libmixer_la_DEPENDENCIES = -@USE_TIMIDITY_TRUE@@USE_MIKMOD_TRUE@libmixer_la_DEPENDENCIES = \ +@USE_TIMIDITY_FALSE@@USE_MIKMOD_FALSE@libSDLmixer_la_DEPENDENCIES = +@USE_TIMIDITY_TRUE@@USE_MIKMOD_TRUE@libSDLmixer_la_DEPENDENCIES = \ @USE_TIMIDITY_TRUE@@USE_MIKMOD_TRUE@mikmod/libmikmod.la \ @USE_TIMIDITY_TRUE@@USE_MIKMOD_TRUE@timidity/libtimidity.la -@USE_TIMIDITY_TRUE@@USE_MIKMOD_FALSE@libmixer_la_DEPENDENCIES = \ +@USE_TIMIDITY_TRUE@@USE_MIKMOD_FALSE@libSDLmixer_la_DEPENDENCIES = \ @USE_TIMIDITY_TRUE@@USE_MIKMOD_FALSE@timidity/libtimidity.la -@USE_TIMIDITY_FALSE@@USE_MIKMOD_TRUE@libmixer_la_DEPENDENCIES = \ +@USE_TIMIDITY_FALSE@@USE_MIKMOD_TRUE@libSDLmixer_la_DEPENDENCIES = \ @USE_TIMIDITY_FALSE@@USE_MIKMOD_TRUE@mikmod/libmikmod.la -libmixer_la_OBJECTS = mixer.lo music.lo music_cmd.lo wavestream.lo +libSDLmixer_la_OBJECTS = mixer.lo music.lo music_cmd.lo wavestream.lo PROGRAMS = $(bin_PROGRAMS) playwave_SOURCES = playwave.c playwave_OBJECTS = playwave.o -playwave_DEPENDENCIES = libmixer.la +playwave_DEPENDENCIES = libSDLmixer.la playwave_LDFLAGS = playmus_SOURCES = playmus.c playmus_OBJECTS = playmus.o -playmus_DEPENDENCIES = libmixer.la +playmus_DEPENDENCIES = libSDLmixer.la playmus_LDFLAGS = CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ -HEADERS = $(libmixerinclude_HEADERS) +HEADERS = $(libSDLmixerinclude_HEADERS) DIST_COMMON = README COPYING Makefile.am Makefile.in acinclude.m4 \ aclocal.m4 config.guess config.sub configure configure.in install-sh \ @@ -158,8 +159,8 @@ TAR = gtar GZIP_ENV = --best DEP_FILES = .deps/mixer.P .deps/music.P .deps/music_cmd.P \ .deps/playmus.P .deps/playwave.P .deps/wavestream.P -SOURCES = $(libmixer_la_SOURCES) playwave.c playmus.c -OBJECTS = $(libmixer_la_OBJECTS) playwave.o playmus.o +SOURCES = $(libSDLmixer_la_SOURCES) playwave.c playmus.c +OBJECTS = $(libSDLmixer_la_OBJECTS) playwave.o playmus.o all: all-redirect .SUFFIXES: @@ -236,8 +237,8 @@ distclean-libtool: maintainer-clean-libtool: -libmixer.la: $(libmixer_la_OBJECTS) $(libmixer_la_DEPENDENCIES) - $(LINK) -rpath $(libdir) $(libmixer_la_LDFLAGS) $(libmixer_la_OBJECTS) $(libmixer_la_LIBADD) $(LIBS) +libSDLmixer.la: $(libSDLmixer_la_OBJECTS) $(libSDLmixer_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libSDLmixer_la_LDFLAGS) $(libSDLmixer_la_OBJECTS) $(libSDLmixer_la_LIBADD) $(LIBS) mostlyclean-binPROGRAMS: @@ -253,8 +254,8 @@ install-binPROGRAMS: $(bin_PROGRAMS) $(mkinstalldirs) $(DESTDIR)$(bindir) @list='$(bin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ - echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ - $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ else :; fi; \ done @@ -272,19 +273,19 @@ playmus: $(playmus_OBJECTS) $(playmus_DEPENDENCIES) @rm -f playmus $(LINK) $(playmus_LDFLAGS) $(playmus_OBJECTS) $(playmus_LDADD) $(LIBS) -install-libmixerincludeHEADERS: $(libmixerinclude_HEADERS) +install-libSDLmixerincludeHEADERS: $(libSDLmixerinclude_HEADERS) @$(NORMAL_INSTALL) - $(mkinstalldirs) $(DESTDIR)$(libmixerincludedir) - @list='$(libmixerinclude_HEADERS)'; for p in $$list; do \ + $(mkinstalldirs) $(DESTDIR)$(libSDLmixerincludedir) + @list='$(libSDLmixerinclude_HEADERS)'; for p in $$list; do \ if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ - echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(libmixerincludedir)/$$p"; \ - $(INSTALL_DATA) $$d$$p $(DESTDIR)$(libmixerincludedir)/$$p; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(libSDLmixerincludedir)/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(libSDLmixerincludedir)/$$p; \ done -uninstall-libmixerincludeHEADERS: +uninstall-libSDLmixerincludeHEADERS: @$(NORMAL_UNINSTALL) - list='$(libmixerinclude_HEADERS)'; for p in $$list; do \ - rm -f $(DESTDIR)$(libmixerincludedir)/$$p; \ + list='$(libSDLmixerinclude_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(libSDLmixerincludedir)/$$p; \ done # This directory's subdirectories are mostly independent; you can cd @@ -422,7 +423,7 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$/$$file $(distdir)/$$file; \ + cp -pr $$d/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ @@ -482,23 +483,23 @@ installcheck: installcheck-recursive install-exec-am: install-libLTLIBRARIES install-binPROGRAMS install-exec: install-exec-recursive -install-data-am: install-libmixerincludeHEADERS +install-data-am: install-libSDLmixerincludeHEADERS install-data: install-data-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-recursive uninstall-am: uninstall-libLTLIBRARIES uninstall-binPROGRAMS \ - uninstall-libmixerincludeHEADERS + uninstall-libSDLmixerincludeHEADERS uninstall: uninstall-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) all-redirect: all-recursive install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install installdirs: installdirs-recursive installdirs-am: $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(bindir) \ - $(DESTDIR)$(libmixerincludedir) + $(DESTDIR)$(libSDLmixerincludedir) mostlyclean-generic: @@ -548,8 +549,8 @@ distclean-compile clean-compile maintainer-clean-compile \ mostlyclean-libtool distclean-libtool clean-libtool \ maintainer-clean-libtool mostlyclean-binPROGRAMS distclean-binPROGRAMS \ clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \ -install-binPROGRAMS uninstall-libmixerincludeHEADERS \ -install-libmixerincludeHEADERS install-data-recursive \ +install-binPROGRAMS uninstall-libSDLmixerincludeHEADERS \ +install-libSDLmixerincludeHEADERS install-data-recursive \ uninstall-data-recursive install-exec-recursive \ uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ all-recursive check-recursive installcheck-recursive info-recursive \ diff --git a/README b/README index 43d714aa..d25e2599 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ It supports 4 channels of 16 bit stereo audio, plus a single channel of music, mixed by the popular MikMod MOD, Timidity MIDI and SMPEG MP3 libraries. -See the header file mixer.h and the examples playwave.c and playmus.c +See the header file SDL_mixer.h and the examples playwave.c and playmus.c for documentation on this mixer library. The mixer can currently load Microsoft WAVE files as audio samples @@ -19,7 +19,8 @@ so if playing regular WAVE files sound great, but playing MIDI files sound choppy, try using 8-bit audio, mono audio, or lower frequencies. To play MIDI files, you'll need to get a complete set of GUS patches -from: http://www.devolution.com/~slouken/SDL/timidity/timidity.tar.gz +from: +http://www.devolution.com/~slouken/SDL/projectx/mixer/timidity/timidity.tar.gz and unpack them in /usr/local/lib under UNIX, and C:\ under Win32. You may add panning, reverb, echo, whatever, but if you do, please diff --git a/aclocal.m4 b/aclocal.m4 index dbf8fc07..c8491685 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -dnl aclocal.m4 generated automatically by aclocal 1.4 +dnl aclocal.m4 generated automatically by aclocal 1.4a dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation @@ -627,6 +627,8 @@ dnl AM_INIT_AUTOMAKE(package,version, [no-define]) AC_DEFUN(AM_INIT_AUTOMAKE, [AC_REQUIRE([AC_PROG_INSTALL]) +dnl We require 2.13 because we rely on SHELL being computed by configure. +AC_PREREQ([2.13]) PACKAGE=[$1] AC_SUBST(PACKAGE) VERSION=[$2] diff --git a/configure b/configure index e81fa51a..717988d7 100755 --- a/configure +++ b/configure @@ -561,9 +561,9 @@ fi MAJOR_VERSION=1 MINOR_VERSION=0 -MICRO_VERSION=1 +MICRO_VERSION=2 INTERFACE_AGE=0 -BINARY_AGE=1 +BINARY_AGE=2 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION @@ -752,6 +752,7 @@ else fi + PACKAGE=mixer VERSION=$VERSION @@ -771,7 +772,7 @@ EOF missing_dir=`cd $ac_aux_dir && pwd` echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:775: checking for working aclocal" >&5 +echo "configure:776: checking for working aclocal" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -784,7 +785,7 @@ else fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:788: checking for working autoconf" >&5 +echo "configure:789: checking for working autoconf" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -797,7 +798,7 @@ else fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:801: checking for working automake" >&5 +echo "configure:802: checking for working automake" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -810,7 +811,7 @@ else fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:814: checking for working autoheader" >&5 +echo "configure:815: checking for working autoheader" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -823,7 +824,7 @@ else fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:827: checking for working makeinfo" >&5 +echo "configure:828: checking for working makeinfo" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -839,7 +840,7 @@ fi echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:843: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:844: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -868,7 +869,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:872: checking for $ac_word" >&5 +echo "configure:873: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -898,7 +899,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:902: checking for $ac_word" >&5 +echo "configure:903: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -949,7 +950,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:953: checking for $ac_word" >&5 +echo "configure:954: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -981,7 +982,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:985: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:986: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -992,12 +993,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 996 "configure" +#line 997 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:1001: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1002: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -1023,12 +1024,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1027: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:1028: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1032: checking whether we are using GNU C" >&5 +echo "configure:1033: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1037,7 +1038,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1041: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1042: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1056,7 +1057,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1060: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1061: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1164,7 +1165,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:1168: checking host system type" >&5 +echo "configure:1169: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -1185,7 +1186,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:1189: checking build system type" >&5 +echo "configure:1190: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -1214,7 +1215,7 @@ ac_prog=ld if test "$ac_cv_prog_gcc" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 -echo "configure:1218: checking for ld used by GCC" >&5 +echo "configure:1219: checking for ld used by GCC" >&5 case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw @@ -1244,10 +1245,10 @@ echo "configure:1218: checking for ld used by GCC" >&5 esac elif test "$with_gnu_ld" = yes; then echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 -echo "configure:1248: checking for GNU ld" >&5 +echo "configure:1249: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 -echo "configure:1251: checking for non-GNU ld" >&5 +echo "configure:1252: checking for non-GNU ld" >&5 fi if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1283,7 +1284,7 @@ fi test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 -echo "configure:1287: checking if the linker ($LD) is GNU ld" >&5 +echo "configure:1288: checking if the linker ($LD) is GNU ld" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1299,7 +1300,7 @@ echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6 echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 -echo "configure:1303: checking for BSD-compatible nm" >&5 +echo "configure:1304: checking for BSD-compatible nm" >&5 if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1336,7 +1337,7 @@ echo "$ac_t""$NM" 1>&6 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:1340: checking whether ln -s works" >&5 +echo "configure:1341: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1366,7 +1367,7 @@ fi # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1370: checking for $ac_word" >&5 +echo "configure:1371: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1398,7 +1399,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1402: checking for $ac_word" >&5 +echo "configure:1403: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1465,8 +1466,8 @@ test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" case "$host" in *-*-irix6*) # Find out which ABI we are using. - echo '#line 1469 "configure"' > conftest.$ac_ext - if { (eval echo configure:1470: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + echo '#line 1470 "configure"' > conftest.$ac_ext + if { (eval echo configure:1471: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then case "`/usr/bin/file conftest.o`" in *32-bit*) LD="${LD-ld} -32" @@ -1487,19 +1488,19 @@ case "$host" in SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6 -echo "configure:1491: checking whether the C compiler needs -belf" >&5 +echo "configure:1492: checking whether the C compiler needs -belf" >&5 if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1504: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_cc_needs_belf=yes else @@ -1522,7 +1523,7 @@ echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6 # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1526: checking for $ac_word" >&5 +echo "configure:1527: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1554,7 +1555,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1558: checking for $ac_word" >&5 +echo "configure:1559: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1589,7 +1590,7 @@ fi # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1593: checking for $ac_word" >&5 +echo "configure:1594: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1621,7 +1622,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1625: checking for $ac_word" >&5 +echo "configure:1626: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1656,7 +1657,7 @@ fi # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1660: checking for $ac_word" >&5 +echo "configure:1661: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_OBJDUMP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1688,7 +1689,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1692: checking for $ac_word" >&5 +echo "configure:1693: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_OBJDUMP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1724,19 +1725,19 @@ fi # recent cygwin and mingw systems supply a stub DllMain which the user # can override, but on older systems we have to supply one echo $ac_n "checking if libtool should supply DllMain function""... $ac_c" 1>&6 -echo "configure:1728: checking if libtool should supply DllMain function" >&5 +echo "configure:1729: checking if libtool should supply DllMain function" >&5 if eval "test \"`echo '$''{'lt_cv_need_dllmain'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1741: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_need_dllmain=yes else @@ -1761,19 +1762,19 @@ echo "$ac_t""$lt_cv_need_dllmain" 1>&6 SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -mdll" echo $ac_n "checking how to link DLLs""... $ac_c" 1>&6 -echo "configure:1765: checking how to link DLLs" >&5 +echo "configure:1766: checking how to link DLLs" >&5 if eval "test \"`echo '$''{'lt_cv_cc_dll_switch'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_cc_dll_switch=-mdll else @@ -1883,7 +1884,7 @@ exec 5>>./config.log # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1887: checking for a BSD compatible install" >&5 +echo "configure:1888: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1937,7 +1938,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking target system type""... $ac_c" 1>&6 -echo "configure:1941: checking target system type" >&5 +echo "configure:1942: checking target system type" >&5 target_alias=$target case "$target_alias" in @@ -2002,7 +2003,7 @@ fi # Extract the first word of "sdl-config", so it can be a program name with args. set dummy sdl-config; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2006: checking for $ac_word" >&5 +echo "configure:2007: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_SDL_CONFIG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2037,7 +2038,7 @@ fi min_sdl_version=$SDL_VERSION echo $ac_n "checking for SDL - version >= $min_sdl_version""... $ac_c" 1>&6 -echo "configure:2041: checking for SDL - version >= $min_sdl_version" >&5 +echo "configure:2042: checking for SDL - version >= $min_sdl_version" >&5 no_sdl="" if test "$SDL_CONFIG" = "no" ; then no_sdl=yes @@ -2061,7 +2062,7 @@ echo "configure:2041: checking for SDL - version >= $min_sdl_version" >&5 echo $ac_n "cross compiling; assumed OK... $ac_c" else cat > conftest.$ac_ext < @@ -2119,7 +2120,7 @@ int main () EOF -if { (eval echo configure:2123: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2124: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -2153,7 +2154,7 @@ fi CFLAGS="$CFLAGS $SDL_CFLAGS" LIBS="$LIBS $SDL_LIBS" cat > conftest.$ac_ext < @@ -2163,7 +2164,7 @@ int main() { return 0; ; return 0; } EOF -if { (eval echo configure:2167: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2168: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding SDL or finding the wrong" @@ -2256,10 +2257,10 @@ fi if test x$enable_music_mp3 = xyes; then echo $ac_n "checking for SMPEG headers and libraries""... $ac_c" 1>&6 -echo "configure:2260: checking for SMPEG headers and libraries" >&5 +echo "configure:2261: checking for SMPEG headers and libraries" >&5 have_smpeg=no cat > conftest.$ac_ext < @@ -2269,7 +2270,7 @@ int main() { ; return 0; } EOF -if { (eval echo configure:2273: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2274: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* have_smpeg=yes diff --git a/configure.in b/configure.in index 9cae5a54..8035d6fd 100644 --- a/configure.in +++ b/configure.in @@ -13,9 +13,9 @@ dnl Set various version strings - taken gratefully from the GTk sources MAJOR_VERSION=1 MINOR_VERSION=0 -MICRO_VERSION=1 +MICRO_VERSION=2 INTERFACE_AGE=0 -BINARY_AGE=1 +BINARY_AGE=2 VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION AC_SUBST(MAJOR_VERSION) diff --git a/mikmod/Makefile.am b/mikmod/Makefile.am index 4c26c4a9..a8367cdd 100644 --- a/mikmod/Makefile.am +++ b/mikmod/Makefile.am @@ -10,20 +10,23 @@ libmikmod_la_SOURCES = \ load_xm.c \ mdreg.c \ mdriver.c \ + mdulaw.c \ mikmod.h \ + mikmod_build.h \ + mikmod_internals.h \ mloader.c \ mlreg.c \ + mlutil.c \ mmalloc.c \ mmerror.c \ mmio.c \ - mmio.h \ mplayer.c \ munitrk.c \ + mwav.c \ npertab.c \ - ptform.h \ - s3m_it.c \ sloader.c \ - tdefs.h \ - virtch.c + virtch.c \ + virtch2.c \ + virtch_common.c -EXTRA_DIST = README license.txt +EXTRA_DIST = AUTHORS COPYING.LESSER README diff --git a/mikmod/Makefile.in b/mikmod/Makefile.in index 52f79aa7..769e835f 100644 --- a/mikmod/Makefile.in +++ b/mikmod/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am +# Makefile.in generated automatically by automake 1.4a from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation @@ -46,9 +46,10 @@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = transform = @program_transform_name@ NORMAL_INSTALL = : @@ -87,10 +88,10 @@ VERSION = @VERSION@ noinst_LTLIBRARIES = libmikmod.la -libmikmod_la_SOURCES = drv_nos.c drv_sdl.c load_it.c load_mod.c load_s3m.c load_xm.c mdreg.c mdriver.c mikmod.h mloader.c mlreg.c mmalloc.c mmerror.c mmio.c mmio.h mplayer.c munitrk.c npertab.c ptform.h s3m_it.c sloader.c tdefs.h virtch.c +libmikmod_la_SOURCES = drv_nos.c drv_sdl.c load_it.c load_mod.c load_s3m.c load_xm.c mdreg.c mdriver.c mdulaw.c mikmod.h mikmod_build.h mikmod_internals.h mloader.c mlreg.c mlutil.c mmalloc.c mmerror.c mmio.c mplayer.c munitrk.c mwav.c npertab.c sloader.c virtch.c virtch2.c virtch_common.c -EXTRA_DIST = README license.txt +EXTRA_DIST = AUTHORS COPYING.LESSER README mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_CLEAN_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) @@ -103,15 +104,15 @@ LIBS = @LIBS@ libmikmod_la_LDFLAGS = libmikmod_la_LIBADD = libmikmod_la_OBJECTS = drv_nos.lo drv_sdl.lo load_it.lo load_mod.lo \ -load_s3m.lo load_xm.lo mdreg.lo mdriver.lo mloader.lo mlreg.lo \ -mmalloc.lo mmerror.lo mmio.lo mplayer.lo munitrk.lo npertab.lo \ -s3m_it.lo sloader.lo virtch.lo +load_s3m.lo load_xm.lo mdreg.lo mdriver.lo mdulaw.lo mloader.lo \ +mlreg.lo mlutil.lo mmalloc.lo mmerror.lo mmio.lo mplayer.lo munitrk.lo \ +mwav.lo npertab.lo sloader.lo virtch.lo virtch2.lo virtch_common.lo CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ -DIST_COMMON = README Makefile.am Makefile.in +DIST_COMMON = README AUTHORS Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) @@ -120,9 +121,10 @@ TAR = gtar GZIP_ENV = --best DEP_FILES = .deps/drv_nos.P .deps/drv_sdl.P .deps/load_it.P \ .deps/load_mod.P .deps/load_s3m.P .deps/load_xm.P .deps/mdreg.P \ -.deps/mdriver.P .deps/mloader.P .deps/mlreg.P .deps/mmalloc.P \ -.deps/mmerror.P .deps/mmio.P .deps/mplayer.P .deps/munitrk.P \ -.deps/npertab.P .deps/s3m_it.P .deps/sloader.P .deps/virtch.P +.deps/mdriver.P .deps/mdulaw.P .deps/mloader.P .deps/mlreg.P \ +.deps/mlutil.P .deps/mmalloc.P .deps/mmerror.P .deps/mmio.P \ +.deps/mplayer.P .deps/munitrk.P .deps/mwav.P .deps/npertab.P \ +.deps/sloader.P .deps/virtch.P .deps/virtch2.P .deps/virtch_common.P SOURCES = $(libmikmod_la_SOURCES) OBJECTS = $(libmikmod_la_OBJECTS) @@ -223,7 +225,7 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$/$$file $(distdir)/$$file; \ + cp -pr $$d/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ @@ -284,7 +286,7 @@ uninstall: uninstall-am all-am: Makefile $(LTLIBRARIES) all-redirect: all-am install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install installdirs: diff --git a/mikmod/README b/mikmod/README index 9510152a..b7b169a3 100644 --- a/mikmod/README +++ b/mikmod/README @@ -1,14 +1,14 @@ - --> MikMod Sound Libraries Version 3.0 - -> Release Notes - August 20th, 1997 + --> MikMod Sound Libraries Version 3.1.8 + --> libmikmod 3.1.8 was released on 10/25/1999. --- -This version of the library is based on the official UNIX MikMod version 3.0, -found at: http://freenet.tlh.fl.us/~amstpi/mikmod.html +-- +This version of the library is based on the official UNIX MikMod +library version 3.1.8, found at: http://mikmod.darkorb.net/ -It has been stripped down for inclusion with Simple DirectMedia Layer, +It has been stripped down for inclusion with Simple DirectMedia Layer, but the missing drivers and file loaders can be plugged right in from -the MikMod 3.03 archive. +the MikMod 3.1.8 archive. -See license.txt for copying information +See COPYING.LESSER for copying information -- diff --git a/mikmod/drv_nos.c b/mikmod/drv_nos.c index 6cf8f30f..fdaebb66 100644 --- a/mikmod/drv_nos.c +++ b/mikmod/drv_nos.c @@ -1,161 +1,107 @@ -/* - -Name: -DRV_NOS.C - -Description: -Mikmod driver for no output on any soundcard, monitor, keyboard, or whatever :) +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ -Portability: -All systems - All compilers +/*============================================================================== -*/ + $Id$ -#include "mikmod.h" + Driver for no output +==============================================================================*/ -static BOOL NS_IsThere(void) -{ - return 1; -} +/* + Written by Jean-Paul Mikkers -static SWORD NS_SampleLoad(SAMPLOAD *s, int type) -{ - return 0; -} +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -static void NS_SampleUnload(SWORD h) -{ -} +#ifdef HAVE_UNISTD_H +#include +#endif +#include "mikmod_internals.h" -static ULONG NS_SampleSpace(int type) -{ - return 0; -} +#define ZEROLEN 32768 +static SBYTE *zerobuf=NULL; -static ULONG NS_SampleLength(int type, SAMPLE *s) +static BOOL NS_IsThere(void) { - return s->length; + return 1; } - static BOOL NS_Init(void) { - return 0; + zerobuf=(SBYTE*)_mm_malloc(ZEROLEN); + return VC_Init(); } - static void NS_Exit(void) { + VC_Exit(); + _mm_free(zerobuf); } - -static BOOL NS_Reset(void) -{ - return 0; -} - - -static BOOL NS_PlayStart(void) -{ - return 0; -} - - -static void NS_PlayStop(void) -{ -} - - static void NS_Update(void) { -} - - -static BOOL NS_SetNumVoices(void) -{ - return 0; -} - - -static void NS_VoiceSetVolume(UBYTE voice,UWORD vol) -{ -} - - -static void NS_VoiceSetFrequency(UBYTE voice,ULONG frq) -{ -} - - -static void NS_VoiceSetPanning(UBYTE voice,ULONG pan) -{ -} - - -static void NS_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags) -{ -} - - -static void NS_VoiceStop(UBYTE voice) -{ -} - - -static BOOL NS_VoiceStopped(UBYTE voice) -{ - return 0; -} - - -static void NS_VoiceReleaseSustain(UBYTE voice) -{ -} - - -static SLONG NS_VoiceGetPosition(UBYTE voice) -{ - return 0; -} - - -static ULONG NS_VoiceRealVolume(UBYTE voice) -{ - return 0; -} - - - -MDRIVER drv_nos = -{ NULL, - "No Sound", - "Nosound Driver v2.0 - (c) Creative Silence", - 255,255, - NS_IsThere, - NS_SampleLoad, - NS_SampleUnload, - NS_SampleSpace, - NS_SampleLength, - NS_Init, - NS_Exit, - NS_Reset, - NS_SetNumVoices, - NS_PlayStart, - NS_PlayStop, - NS_Update, - NS_VoiceSetVolume, - NS_VoiceSetFrequency, - NS_VoiceSetPanning, - NS_VoicePlay, - NS_VoiceStop, - NS_VoiceStopped, - NS_VoiceReleaseSustain, - NS_VoiceGetPosition, - NS_VoiceRealVolume + if (zerobuf) + VC_WriteBytes(zerobuf,ZEROLEN); +} + +MDRIVER drv_nos={ + NULL, + "No Sound", + "Nosound Driver v3.0", + 255,255, + "nosound", + + NULL, + NS_IsThere, + VC_SampleLoad, + VC_SampleUnload, + VC_SampleSpace, + VC_SampleLength, + NS_Init, + NS_Exit, + NULL, + VC_SetNumVoices, + VC_PlayStart, + VC_PlayStop, + NS_Update, + NULL, + VC_VoiceSetVolume, + VC_VoiceGetVolume, + VC_VoiceSetFrequency, + VC_VoiceGetFrequency, + VC_VoiceSetPanning, + VC_VoiceGetPanning, + VC_VoicePlay, + VC_VoiceStop, + VC_VoiceStopped, + VC_VoiceGetPosition, + VC_VoiceRealVolume }; + +/* ex:set ts=4: */ diff --git a/mikmod/drv_sdl.c b/mikmod/drv_sdl.c index 77851e97..155e1a5b 100644 --- a/mikmod/drv_sdl.c +++ b/mikmod/drv_sdl.c @@ -8,7 +8,8 @@ Mikmod driver for output using the Simple DirectMedia Layer */ -#include "mikmod.h" + +#include "mikmod_internals.h" static BOOL SDRV_IsThere(void) @@ -45,8 +46,11 @@ static BOOL SDRV_Reset(void) MDRIVER drv_sdl = { NULL, "SDL", - "MikMod Simple DirectMedia Layer driver v1.0", + "MikMod Simple DirectMedia Layer driver v1.1", 0,255, + "SDL", + + NULL, SDRV_IsThere, VC_SampleLoad, VC_SampleUnload, @@ -59,13 +63,16 @@ MDRIVER drv_sdl = VC_PlayStart, VC_PlayStop, SDRV_Update, + NULL, /* FIXME: Pause */ VC_VoiceSetVolume, + VC_VoiceGetVolume, VC_VoiceSetFrequency, + VC_VoiceGetFrequency, VC_VoiceSetPanning, + VC_VoiceGetPanning, VC_VoicePlay, VC_VoiceStop, VC_VoiceStopped, - VC_VoiceReleaseSustain, VC_VoiceGetPosition, VC_VoiceRealVolume }; diff --git a/mikmod/load_it.c b/mikmod/load_it.c index 7403bb52..2b938c0b 100644 --- a/mikmod/load_it.c +++ b/mikmod/load_it.c @@ -1,857 +1,1011 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ - Name: LOAD_IT.C +/*============================================================================== - Description: - ImpulseTracker (IT) module loader + $Id$ - Portability: - All systems - all compilers (hopefully) + Impulse tracker (IT) module loader - Copyright 1997 by Jake Stine and Divine Entertainment +==============================================================================*/ - If this module is found to not be portable to any particular platform, - please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for - more information on contacting the author). -*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include #include -#include "mikmod.h" - -/************************************************************************** -**************************************************************************/ - -typedef struct ITNOTE -{ UBYTE note,ins,volpan,cmd,inf; -} ITNOTE; -UBYTE *IT_ConvertTrack(ITNOTE *tr,UWORD numrows); - - -/* Raw IT header struct: */ - -typedef struct ITHEADER -{ CHAR songname[26]; - UBYTE blank01[2]; - UWORD ordnum; - UWORD insnum; - UWORD smpnum; - UWORD patnum; - UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */ - UWORD cmwt; /* Compatable with tracker ver > than val. */ - UWORD flags; - UWORD special; /* bit 0 set = song message attached */ - UBYTE globvol; - UBYTE mixvol; /* mixing volume [ignored] */ - UBYTE initspeed; - UBYTE inittempo; - UBYTE pansep; /* panning separation between channels */ - UBYTE zerobyte; - UWORD msglength; - ULONG msgoffset; - UBYTE blank02[4]; - - UBYTE pantable[64]; - UBYTE voltable[64]; +#include "mikmod_internals.h" + +/*========== Module structure */ + +/* header */ +typedef struct ITHEADER { + CHAR songname[26]; + UBYTE blank01[2]; + UWORD ordnum; + UWORD insnum; + UWORD smpnum; + UWORD patnum; + UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */ + UWORD cmwt; /* Compatible with tracker ver > than val. */ + UWORD flags; + UWORD special; /* bit 0 set = song message attached */ + UBYTE globvol; + UBYTE mixvol; /* mixing volume [ignored] */ + UBYTE initspeed; + UBYTE inittempo; + UBYTE pansep; /* panning separation between channels */ + UBYTE zerobyte; + UWORD msglength; + ULONG msgoffset; + UBYTE blank02[4]; + UBYTE pantable[64]; + UBYTE voltable[64]; } ITHEADER; - -/* Raw IT sampleinfo struct: */ - -typedef struct ITSAMPLE -{ CHAR filename[12]; - UBYTE zerobyte; - UBYTE globvol; - UBYTE flag; - UBYTE volume; - UBYTE panning; - CHAR sampname[28]; - UWORD convert; /* sample conversion flag */ - ULONG length; - ULONG loopbeg; - ULONG loopend; - ULONG c5spd; - ULONG susbegin; - ULONG susend; - ULONG sampoffset; - UBYTE vibspeed; - UBYTE vibdepth; - UBYTE vibrate; - UBYTE vibwave; /* 0 = sine; 1 = rampdown; 2 = square; 3 = random (speed ignored) */ - - UBYTE noteindex; /* for converting c5spd to finetune */ +/* sample information */ +typedef struct ITSAMPLE { + CHAR filename[12]; + UBYTE zerobyte; + UBYTE globvol; + UBYTE flag; + UBYTE volume; + UBYTE panning; + CHAR sampname[28]; + UWORD convert; /* sample conversion flag */ + ULONG length; + ULONG loopbeg; + ULONG loopend; + ULONG c5spd; + ULONG susbegin; + ULONG susend; + ULONG sampoffset; + UBYTE vibspeed; + UBYTE vibdepth; + UBYTE vibrate; + UBYTE vibwave; /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */ } ITSAMPLE; +/* instrument information */ + +#define ITENVCNT 25 +#define ITNOTECNT 120 +typedef struct ITINSTHEADER { + ULONG size; /* (dword) Instrument size */ + CHAR filename[12]; /* (char) Instrument filename */ + UBYTE zerobyte; /* (byte) Instrument type (always 0) */ + UBYTE volflg; + UBYTE volpts; + UBYTE volbeg; /* (byte) Volume loop start (node) */ + UBYTE volend; /* (byte) Volume loop end (node) */ + UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */ + UBYTE volsusend; /* (byte) Volume Sustain end (node) */ + UBYTE panflg; + UBYTE panpts; + UBYTE panbeg; /* (byte) channel loop start (node) */ + UBYTE panend; /* (byte) channel loop end (node) */ + UBYTE pansusbeg; /* (byte) channel sustain begin (node) */ + UBYTE pansusend; /* (byte) channel Sustain end (node) */ + UBYTE pitflg; + UBYTE pitpts; + UBYTE pitbeg; /* (byte) pitch loop start (node) */ + UBYTE pitend; /* (byte) pitch loop end (node) */ + UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */ + UBYTE pitsusend; /* (byte) pitch Sustain end (node) */ + UWORD blank; + UBYTE globvol; + UBYTE chanpan; + UWORD fadeout; /* Envelope end / NNA volume fadeout */ + UBYTE dnc; /* Duplicate note check */ + UBYTE dca; /* Duplicate check action */ + UBYTE dct; /* Duplicate check type */ + UBYTE nna; /* New Note Action [0,1,2,3] */ + UWORD trkvers; /* tracker version used to save [files only] */ + UBYTE ppsep; /* Pitch-pan Separation */ + UBYTE ppcenter; /* Pitch-pan Center */ + UBYTE rvolvar; /* random volume varations */ + UBYTE rpanvar; /* random panning varations */ + UWORD numsmp; /* Number of samples in instrument [files only] */ + CHAR name[26]; /* Instrument name */ + UBYTE blank01[6]; + UWORD samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */ + UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ + UBYTE oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */ + UBYTE volnode[ITENVCNT]; /* amplitude of volume nodes */ + UWORD voltick[ITENVCNT]; /* tick value of volume nodes */ + SBYTE pannode[ITENVCNT]; /* panenv - node points */ + UWORD pantick[ITENVCNT]; /* tick value of panning nodes */ + SBYTE pitnode[ITENVCNT]; /* pitchenv - node points */ + UWORD pittick[ITENVCNT]; /* tick value of pitch nodes */ +} ITINSTHEADER; + +/* unpacked note */ + +typedef struct ITNOTE { + UBYTE note,ins,volpan,cmd,inf; +} ITNOTE; -typedef struct ITINSTHEADER -{ ULONG size; /* (dword) Instrument size */ - CHAR filename[12]; /* (char) Instrument filename */ - UBYTE zerobyte; /* (byte) Instrument type (always 0) */ - UBYTE volflg; - UBYTE volpts; - UBYTE volbeg; /* (byte) Volume loop start (node) */ - UBYTE volend; /* (byte) Volume loop end (node) */ - UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */ - UBYTE volsusend; /* (byte) Volume Sustain end (node) */ - UBYTE panflg; - UBYTE panpts; - UBYTE panbeg; /* (byte) channel loop start (node) */ - UBYTE panend; /* (byte) channel loop end (node) */ - UBYTE pansusbeg; /* (byte) cahnnel sustain begin (node) */ - UBYTE pansusend; /* (byte) channel Sustain end (node) */ - UBYTE pitflg; - UBYTE pitpts; - UBYTE pitbeg; /* (byte) pitch loop start (node) */ - UBYTE pitend; /* (byte) pitch loop end (node) */ - UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */ - UBYTE pitsusend; /* (byte) pitch Sustain end (node) */ - UWORD blank; - UBYTE globvol; - UBYTE chanpan; - UWORD fadeout; /* Envelope end / NNA volume fadeout */ - UBYTE dnc; /* Duplicate note check */ - UBYTE dca; /* Duplicate check action */ - UBYTE dct; /* Duplicate check type */ - UBYTE nna; /* New Note Action [0,1,2,3] */ - UWORD trkvers; /* tracker version used to save [in files only] */ - UBYTE ppsep; /* Pitch-pan Separation */ - UBYTE ppcenter; /* Pitch-pan Center */ - UBYTE rvolvar; /* random volume varations */ - UBYTE rpanvar; /* random panning varations */ - UWORD numsmp; /* Number of samples in instrument [in files only] */ - CHAR name[26]; /* Instrument name */ - UBYTE blank01[6]; - UWORD samptable[120]; /* sample for each note [note / samp pairs] */ - - UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ - UBYTE oldvoltick[25]; /* volume tick position (IT 1.x stuff) */ - UBYTE volnode[25]; /* aplitude of volume nodes */ - UWORD voltick[25]; /* tick value of volume nodes */ - SBYTE pannode[25]; /* panenv - node points */ - UWORD pantick[25]; /* tick value of panning nodes */ - SBYTE pitnode[25]; /* pitchenv - node points */ - UWORD pittick[25]; /* tick value of pitch nodes */ -} ITINSTHEADER; - - -/************************************************************************** -**************************************************************************/ - -extern SBYTE remap[64]; /* for removing empty channels */ -extern UBYTE *poslookup; /* S3M/IT fix - removing blank patterns needs a */ - /* lookup table to fix position-jump commands */ -static ULONG *paraptr = NULL; /* parapointer array (see IT docs) */ -static ITHEADER *mh = NULL; -static ITNOTE *itpat = NULL; /* allocate to space for one full pattern */ -static UBYTE *mask = NULL; /* arrays allocated to 64 elements and used for */ -static ITNOTE *last = NULL; /* uncompressing IT's pattern information */ -static int numtrk = 0; -static int old_effect; /* if set, use S3M old-effects stuffs */ -static int *noteindex; - -CHAR IT_Version[] = "ImpulseTracker x.xx"; +/*========== Loader data */ + +static ULONG *paraptr=NULL; /* parapointer array (see IT docs) */ +static ITHEADER *mh=NULL; +static ITNOTE *itpat=NULL; /* allocate to space for one full pattern */ +static UBYTE *mask=NULL; /* arrays allocated to 64 elements and used for */ +static ITNOTE *last=NULL; /* uncompressing IT's pattern information */ +static int numtrk=0; +static int old_effect; /* if set, use S3M old-effects stuffs */ + +static CHAR* IT_Version[]={ + "ImpulseTracker . ", + "Compressed ImpulseTracker . ", + "ImpulseTracker 2.14p3", + "Compressed ImpulseTracker 2.14p3", + "ImpulseTracker 2.14p4", + "Compressed ImpulseTracker 2.14p4", +}; +/* table for porta-to-note command within volume/panning column */ +static UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255}; + +/*========== Loader code */ BOOL IT_Test(void) { - UBYTE id[4]; - - if(!_mm_read_UBYTES(id,4,modfp)) return 0; - if(!memcmp(id,"IMPM",4)) return 1; - return 0; + UBYTE id[4]; + + if(!_mm_read_UBYTES(id,4,modreader)) return 0; + if(!memcmp(id,"IMPM",4)) return 1; + return 0; } BOOL IT_Init(void) { - if((mh=(ITHEADER *)_mm_calloc(1,sizeof(ITHEADER)))==NULL) return 0; - if((poslookup=(UBYTE *)_mm_malloc(256*sizeof(UBYTE)))==NULL) return 0; - if((itpat=(ITNOTE *)_mm_malloc(200*64*sizeof(ITNOTE)))==NULL) return 0; - if((mask=(UBYTE *)_mm_malloc(64*sizeof(UBYTE)))==NULL) return 0; - if((last=(ITNOTE *)_mm_malloc(64*sizeof(ITNOTE)))==NULL) return 0; - - return 1; + if(!(mh=(ITHEADER*)_mm_malloc(sizeof(ITHEADER)))) return 0; + if(!(poslookup=(UBYTE*)_mm_malloc(256*sizeof(UBYTE)))) return 0; + if(!(itpat=(ITNOTE*)_mm_malloc(200*64*sizeof(ITNOTE)))) return 0; + if(!(mask=(UBYTE*)_mm_malloc(64*sizeof(UBYTE)))) return 0; + if(!(last=(ITNOTE*)_mm_malloc(64*sizeof(ITNOTE)))) return 0; + + return 1; } void IT_Cleanup(void) { - if(mh!=NULL) free(mh); - if(poslookup!=NULL) free(poslookup); - if(itpat!=NULL) free(itpat); - if(mask!=NULL) free(mask); - if(last!=NULL) free(last); - if(paraptr!=NULL) free(paraptr); - if(noteindex!=NULL) free(noteindex); - - mh = NULL; - poslookup = NULL; - itpat = NULL; - mask = NULL; - last = NULL; - paraptr = NULL; - noteindex = NULL; + FreeLinear(); + + _mm_free(mh); + _mm_free(poslookup); + _mm_free(itpat); + _mm_free(mask); + _mm_free(last); + _mm_free(paraptr); + _mm_free(origpositions); } +/* Because so many IT files have 64 channels as the set number used, but really + only use far less (usually from 8 to 24 still), I had to make this function, + which determines the number of channels that are actually USED by a pattern. -BOOL IT_GetNumChannels(UWORD patrows) + NOTE: You must first seek to the file location of the pattern before calling + this procedure. -/* Because so many IT files have 64 channels as the set number used, but really */ -/* only use far less (usually 8 to 12 still), I had to make this function, */ -/* which determines the number of channels that are actually USED by a pattern. */ -/* */ -/* For every channel that's used, it sets the appropriate array entry of the */ -/* global varialbe 'isused' */ -/* */ -/* NOTE: You must first seek to the file location of the pattern before calling */ -/* this procedure. */ -/* Returns 1 on error */ + Returns 1 on error +*/ +static BOOL IT_GetNumChannels(UWORD patrows) { - int row=0,flag,ch; - - do - { flag = _mm_read_UBYTE(modfp); - if(flag == EOF) - { _mm_errno = MMERR_LOADING_PATTERN; - return 1; - } - - if(flag == 0) - { row++; - } else - { ch = (flag-1) & 63; - remap[ch] = 0; - if(flag & 128) mask[ch] = _mm_read_UBYTE(modfp); - if(mask[ch] & 1) _mm_read_UBYTE(modfp); - if(mask[ch] & 2) _mm_read_UBYTE(modfp); - if(mask[ch] & 4) _mm_read_UBYTE(modfp); - if(mask[ch] & 8) { _mm_read_UBYTE(modfp); _mm_read_UBYTE(modfp); } - } - } while(row < patrows); - - return 0; + int row=0,flag,ch; + + do { + if((flag=_mm_read_UBYTE(modreader))==EOF) { + _mm_errno=MMERR_LOADING_PATTERN; + return 1; + } + if(!flag) + row++; + else { + ch=(flag-1)&63; + remap[ch]=0; + if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader); + if(mask[ch]&1) _mm_read_UBYTE(modreader); + if(mask[ch]&2) _mm_read_UBYTE(modreader); + if(mask[ch]&4) _mm_read_UBYTE(modreader); + if(mask[ch]&8) { _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); } + } + } while(rownote = n->note = _mm_read_UBYTE(modfp)) == 255) - { l->note = n->note = 253; } - if(mask[ch] & 2) l->ins = n->ins = _mm_read_UBYTE(modfp); - if(mask[ch] & 4) l->volpan = n->volpan = _mm_read_UBYTE(modfp); - if(mask[ch] & 8) { l->cmd = n->cmd = _mm_read_UBYTE(modfp); - l->inf = n->inf = _mm_read_UBYTE(modfp); } - if(mask[ch] & 16) n->note = l->note; - if(mask[ch] & 32) n->ins = l->ins; - if(mask[ch] & 64) n->volpan = l->volpan; - if(mask[ch] & 128) { n->cmd = l->cmd; - n->inf = l->inf; } - } - } while(row < patrows); - - for(blah=0; blah=65) && (volpan<=74)) /* fine volume slide up (65-74) */ - { UniVolEffect(VOL_VOLSLIDE,0x0f + ((volpan-65)<<4)); - } else if((volpan>=75) && (volpan<=84)) /* fine volume slide down (75-84) */ - { UniVolEffect(VOL_VOLSLIDE,0xf0 + (volpan-75)); - } else if((volpan>=85) && (volpan<=94)) /* volume slide up (85-94) */ - { UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4)); - } else if((volpan>=95) && (volpan<=104)) /* volume slide down (95-104) */ - { UniVolEffect(VOL_VOLSLIDE,(volpan-95)); - } else if((volpan>=105) && (volpan<=114)) /* pitch slide up (105-114) */ - { UniVolEffect(VOL_PITCHSLIDEDN,((volpan-105)<<4)); - } else if((volpan>=115) && (volpan<=124)) /* pitch slide down (115-124) */ - { UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115)); - } else if((volpan>=128) && (volpan<=192)) - { UniVolEffect(VOL_PANNING,((volpan-128) == 64) ? 255 : ((volpan-128) << 2)); - } else if((volpan>=193) && (volpan<=202)) /* portamento to note */ - { UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]); - } else if((volpan>=203) && (volpan<=212)) /* vibrato */ - { UniVolEffect(VOL_VIBRATO,(volpan-203)); - } - - S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,old_effect); - - UniNewline(); - } - return UniDup(); + int row=0,flag,ch,blah; + ITNOTE *itt=itpat,dummy,*n,*l; + + memset(itt,255,200*64*sizeof(ITNOTE)); + + do { + if((flag=_mm_read_UBYTE(modreader))==EOF) { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + if(!flag) { + itt=&itt[of.numchn]; + row++; + } else { + ch=remap[(flag-1)&63]; + if(ch!=-1) { + n=&itt[ch]; + l=&last[ch]; + } else + n=l=&dummy; + + if(flag&128) mask[ch]=_mm_read_UBYTE(modreader); + if(mask[ch]&1) + /* convert IT note off to internal note off */ + if((l->note=n->note=_mm_read_UBYTE(modreader))==255) + l->note=n->note=253; + if(mask[ch]&2) + l->ins=n->ins=_mm_read_UBYTE(modreader); + if(mask[ch]&4) + l->volpan=n->volpan=_mm_read_UBYTE(modreader); + if(mask[ch]&8) { + l->cmd=n->cmd=_mm_read_UBYTE(modreader); + l->inf=n->inf=_mm_read_UBYTE(modreader); + } + if(mask[ch]&16) + n->note=l->note; + if(mask[ch]&32) + n->ins=l->ins; + if(mask[ch]&64) + n->volpan=l->volpan; + if(mask[ch]&128) { + n->cmd=l->cmd; + n->inf=l->inf; + } + } + } while(row= c5spd) break; - ctmp = tmp; - note++; - } while(1); - - if(tmp != c5spd) - { if((tmp-c5spd) < (c5spd-ctmp)) - while(tmp>c5spd) tmp = getfrequency(of.flags,getlinearperiod(note,--finetune)); - else - { note--; - while(ctmpsongname,26,modfp); - _mm_read_UBYTES(mh->blank01,2,modfp); - mh->ordnum =_mm_read_I_UWORD(modfp); - mh->insnum =_mm_read_I_UWORD(modfp); - mh->smpnum =_mm_read_I_UWORD(modfp); - mh->patnum =_mm_read_I_UWORD(modfp); - mh->cwt =_mm_read_I_UWORD(modfp); - mh->cmwt =_mm_read_I_UWORD(modfp); - mh->flags =_mm_read_I_UWORD(modfp); - mh->special =_mm_read_I_UWORD(modfp); - - mh->globvol =_mm_read_UBYTE(modfp); - mh->mixvol =_mm_read_UBYTE(modfp); - mh->initspeed =_mm_read_UBYTE(modfp); - mh->inittempo =_mm_read_UBYTE(modfp); - mh->pansep =_mm_read_UBYTE(modfp); - mh->zerobyte =_mm_read_UBYTE(modfp); - mh->msglength =_mm_read_I_UWORD(modfp); - mh->msgoffset =_mm_read_I_ULONG(modfp); - _mm_read_UBYTES(mh->blank02,4,modfp); - _mm_read_UBYTES(mh->pantable,64,modfp); - _mm_read_UBYTES(mh->voltable,64,modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - /* set module variables */ - - of.modtype = strdup(IT_Version); - of.modtype[15] = (mh->cwt >> 8) + 0x30; - of.modtype[17] = ((mh->cwt >> 4) & 0xf) + 0x30; - of.modtype[18] = ((mh->cwt) & 0xf) + 0x30; - of.songname = DupStr(mh->songname,26); /* make a cstr of songname */ - of.reppos = 0; - of.numpat = mh->patnum; - of.numins = mh->insnum; - of.numsmp = mh->smpnum; - of.initspeed = mh->initspeed; - of.inittempo = mh->inittempo; - of.initvolume = mh->globvol; - - old_effect = 0; - if(mh->flags & 8) { of.flags |= (UF_XMPERIODS | UF_LINEAR); old_effect |= 2; } - if((mh->cwt >= 0x106) && (mh->flags & 16)) old_effect |= 1; - - /* set panning positions */ - for(t=0; t<64; t++) - { if(mh->pantable[t] < 64) of.panning[t] = mh->pantable[t] << 2; - else if(mh->pantable[t]==64) of.panning[t] = 255; - else if(mh->pantable[t]==100) of.panning[t] = PAN_SURROUND; - } - - /* set channel volumes */ - memcpy(of.chanvol,mh->voltable,64); - - /* read the order data */ - if(!AllocPositions(mh->ordnum)) return 0; - - for(t=0; tordnum; t++) - of.positions[t] = _mm_read_UBYTE(modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - of.numpos = 0; - for(t=0; tordnum; t++) - { of.positions[of.numpos] = of.positions[t]; - poslookup[t] = of.numpos; /* bug fix for FREAKY S3Ms / ITs */ - if(of.positions[t]<254) of.numpos++; - } - - if((paraptr=(ULONG *)_mm_malloc((mh->insnum+mh->smpnum+of.numpat)*sizeof(ULONG))) == NULL) return 0; - - /* read the instrument, sample, and pattern parapointers */ - _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modfp); - - /* now is a good time to check if the header was too short :) */ - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - /* Check for and load song comment */ - if(mh->special & 1) - { _mm_fseek(modfp,(long)(mh->msgoffset),SEEK_SET); - if(!ReadComment(mh->msglength)) return 0; - } - - if(!(mh->flags & 4)) of.numins = of.numsmp; - if(!AllocSamples()) return 0; - - if((noteindex=(int *)_mm_malloc(mh->smpnum*sizeof(int)))==NULL) return 0; - - q = of.samples; - - /* Load all samples (they're used either way) */ - for(t=0; tsmpnum; t++) - { ITSAMPLE s; - - /* seek to sample position */ - _mm_fseek(modfp,(long)(paraptr[mh->insnum+t] + 4),SEEK_SET); - - /* and load sample info */ - _mm_read_string(s.filename,12,modfp); - s.zerobyte = _mm_read_UBYTE(modfp); - s.globvol = _mm_read_UBYTE(modfp); - s.flag = _mm_read_UBYTE(modfp); - s.volume = _mm_read_UBYTE(modfp); - _mm_read_string(s.sampname,26,modfp); - s.convert = _mm_read_UBYTE(modfp); - s.panning = _mm_read_UBYTE(modfp); - s.length = _mm_read_I_ULONG(modfp); - s.loopbeg = _mm_read_I_ULONG(modfp); - s.loopend = _mm_read_I_ULONG(modfp); - s.c5spd = _mm_read_I_ULONG(modfp); - s.susbegin = _mm_read_I_ULONG(modfp); - s.susend = _mm_read_I_ULONG(modfp); - s.sampoffset = _mm_read_I_ULONG(modfp); - s.vibspeed = _mm_read_UBYTE(modfp); - s.vibdepth = _mm_read_UBYTE(modfp); - s.vibrate = _mm_read_UBYTE(modfp); - s.vibwave = _mm_read_UBYTE(modfp); - - - /* Generate an error if c5spd is > 512k, or samplelength > 256 megs */ - /* (nothing would EVER be that high) */ - - if(feof(modfp) || (s.c5spd > 0x7ffffL) || (s.length > 0xfffffffUL) || - (s.loopbeg > 0xfffffffUL) || (s.loopend > 0xfffffffUL)) - { _mm_errno = MMERR_LOADING_SAMPLEINFO; - return 0; - } - - q->samplename = DupStr(s.sampname,26); - - q->speed = s.c5spd / 2; - q->panning = ((s.panning & 127)==64) ? 255 : (s.panning & 127) << 2; - q->length = s.length; - q->loopstart = s.loopbeg; - q->loopend = s.loopend; - q->volume = s.volume; - q->globvol = s.globvol; - q->seekpos = s.sampoffset; - - /* =================================== */ - /* Convert speed to XM linear finetune */ - - if(of.flags & UF_LINEAR) - q->speed = cvt_c5spd_to_finetune(s.c5spd, t); - - if(s.panning & 128) q->flags |= SF_OWNPAN; - - if(s.vibrate) - { q->vibflags |= AV_IT; - q->vibtype = s.vibwave; - q->vibsweep = s.vibrate * 2; - q->vibdepth = s.vibdepth; - q->vibrate = s.vibspeed; - } - - if(s.flag & 2) q->flags |= SF_16BITS; - if(s.flag & 16) q->flags |= SF_LOOP; - if(s.flag & 64) q->flags |= SF_BIDI; - - if(mh->cwt >= 0x200) - { if(s.convert & 1) q->flags |= SF_SIGNED; - if(s.convert & 4) q->flags |= SF_DELTA; - } - - q++; - } - - /* Load instruments if instrument mode flag enabled */ - - if(mh->flags & 4) - { if(!AllocInstruments()) return 0; - d = of.instruments; - of.flags |= UF_NNA | UF_INST; - - for(t=0; tinsnum; t++) - { ITINSTHEADER ih; - - /* seek to instrument position */ - _mm_fseek(modfp,paraptr[t]+4,SEEK_SET); - - /* and load instrument info */ - _mm_read_string(ih.filename,12,modfp); - ih.zerobyte = _mm_read_UBYTE(modfp); - if(mh->cwt < 0x200) /* load IT 1.xx inst header */ - { ih.volflg = _mm_read_UBYTE(modfp); - ih.volbeg = _mm_read_UBYTE(modfp); - ih.volend = _mm_read_UBYTE(modfp); - ih.volsusbeg = _mm_read_UBYTE(modfp); - ih.volsusend = _mm_read_UBYTE(modfp); - _mm_read_I_UWORD(modfp); - ih.fadeout = _mm_read_I_UWORD(modfp); - ih.nna = _mm_read_UBYTE(modfp); - ih.dnc = _mm_read_UBYTE(modfp); - } else /* Read IT200+ header */ - { ih.nna = _mm_read_UBYTE(modfp); - ih.dct = _mm_read_UBYTE(modfp); - ih.dca = _mm_read_UBYTE(modfp); - ih.fadeout = _mm_read_I_UWORD(modfp); - ih.ppsep = _mm_read_UBYTE(modfp); - ih.ppcenter = _mm_read_UBYTE(modfp); - ih.globvol = _mm_read_UBYTE(modfp); - ih.chanpan = _mm_read_UBYTE(modfp); - ih.rvolvar = _mm_read_UBYTE(modfp); - ih.rpanvar = _mm_read_UBYTE(modfp); - } - - ih.trkvers = _mm_read_I_UWORD(modfp); - ih.numsmp = _mm_read_UBYTE(modfp); - _mm_read_UBYTE(modfp); - _mm_read_string(ih.name,26,modfp); - _mm_read_UBYTES(ih.blank01,6,modfp); - _mm_read_I_UWORDS(ih.samptable,120,modfp); - if(mh->cwt < 0x200) /* load IT 1xx volume envelope */ - { _mm_read_UBYTES(ih.volenv,200,modfp); - for(lp=0; lp<25; lp++) - { ih.oldvoltick[lp] = _mm_read_UBYTE(modfp); - ih.volnode[lp] = _mm_read_UBYTE(modfp); - } - } else /* load IT 2xx vol & chanpan & pitch envs */ - { ih.volflg = _mm_read_UBYTE(modfp); - ih.volpts = _mm_read_UBYTE(modfp); - ih.volbeg = _mm_read_UBYTE(modfp); - ih.volend = _mm_read_UBYTE(modfp); - ih.volsusbeg = _mm_read_UBYTE(modfp); - ih.volsusend = _mm_read_UBYTE(modfp); - for(lp=0; lp<25; lp++) - { ih.volnode[lp] = _mm_read_UBYTE(modfp); - ih.voltick[lp] = _mm_read_I_UWORD(modfp); - } - _mm_read_UBYTE(modfp); - - ih.panflg = _mm_read_UBYTE(modfp); - ih.panpts = _mm_read_UBYTE(modfp); - ih.panbeg = _mm_read_UBYTE(modfp); - ih.panend = _mm_read_UBYTE(modfp); - ih.pansusbeg = _mm_read_UBYTE(modfp); - ih.pansusend = _mm_read_UBYTE(modfp); - for(lp=0; lp<25; lp++) - { ih.pannode[lp] = _mm_read_SBYTE(modfp); - ih.pantick[lp] = _mm_read_I_UWORD(modfp); - } - _mm_read_UBYTE(modfp); - - ih.pitflg = _mm_read_UBYTE(modfp); - ih.pitpts = _mm_read_UBYTE(modfp); - ih.pitbeg = _mm_read_UBYTE(modfp); - ih.pitend = _mm_read_UBYTE(modfp); - ih.pitsusbeg = _mm_read_UBYTE(modfp); - ih.pitsusend = _mm_read_UBYTE(modfp); - for(lp=0; lp<25; lp++) - { ih.pitnode[lp] = _mm_read_SBYTE(modfp); - ih.pittick[lp] = _mm_read_I_UWORD(modfp); - } - _mm_read_UBYTE(modfp); - } - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_SAMPLEINFO; - return 0; - } - - d->volflg |= EF_VOLENV; - d->insname = DupStr(ih.name,26); - d->nnatype = ih.nna; - - if(mh->cwt < 0x200) - { d->volfade = ih.fadeout << 6; - if(ih.dnc) - { d->dct = DCT_NOTE; - d->dca = DCA_CUT; - } - - if(ih.volflg & 1) d->volflg |= EF_ON; - if(ih.volflg & 2) d->volflg |= EF_LOOP; - if(ih.volflg & 4) d->volflg |= EF_SUSTAIN; - - /* XM conversion of IT envelope Array */ - - d->volbeg = ih.volbeg; - d->volend = ih.volend; - d->volsusbeg = ih.volsusbeg; - d->volsusend = ih.volsusend; - - if(ih.volflg & 1) - { for(u=0; u<25; u++) - if(ih.oldvoltick[d->volpts] != 0xff) - { d->volenv[d->volpts].val = (ih.volnode[d->volpts] << 2); - d->volenv[d->volpts].pos = ih.oldvoltick[d->volpts]; - d->volpts++; - } else break; - } - } else - { d->panning = ((ih.chanpan&127) == 64) ? 255 : (ih.chanpan&127)<<2; - if(!(ih.chanpan & 128)) d->flags |= IF_OWNPAN; - - if(!(ih.ppsep & 128)) - { d->pitpansep = ih.ppsep << 2; - d->pitpancenter= ih.ppcenter; - d->flags |= IF_PITCHPAN; - } - d->globvol = ih.globvol >> 1; - d->volfade = ih.fadeout << 5; - d->dct = ih.dct; - d->dca = ih.dca; - - if(mh->cwt >= 0x204) - { d->rvolvar = ih.rvolvar; - d->rpanvar = ih.rpanvar; - } - - if(ih.volflg & 1) d->volflg |= EF_ON; - if(ih.volflg & 2) d->volflg |= EF_LOOP; - if(ih.volflg & 4) d->volflg |= EF_SUSTAIN; - - if(ih.panflg & 1) d->panflg |= EF_ON; - if(ih.panflg & 2) d->panflg |= EF_LOOP; - if(ih.panflg & 4) d->panflg |= EF_SUSTAIN; - - if(ih.pitflg & 1) d->pitflg |= EF_ON; - if(ih.pitflg & 2) d->pitflg |= EF_LOOP; - if(ih.pitflg & 4) d->pitflg |= EF_SUSTAIN; - - d->volpts = ih.volpts; - d->volbeg = ih.volbeg; - d->volend = ih.volend; - d->volsusbeg = ih.volsusbeg; - d->volsusend = ih.volsusend; - - for(u=0; uvolenv[u].val = (ih.volnode[u] << 2); - d->volenv[u].pos = ih.voltick[u]; - } - - d->panpts = ih.panpts; - d->panbeg = ih.panbeg; - d->panend = ih.panend; - d->pansusbeg = ih.pansusbeg; - d->pansusend = ih.pansusend; - - for(u=0; upanenv[u].val = (ih.pannode[u]+32) << 2; - d->panenv[u].pos = ih.pantick[u]; - } - - d->pitpts = ih.pitpts; - d->pitbeg = ih.pitbeg; - d->pitend = ih.pitend; - d->pitsusbeg = ih.pitsusbeg; - d->pitsusend = ih.pitsusend; - - for(u=0; upitenv[u].val = (ih.pitnode[u]+32); - d->pitenv[u].pos = ih.pittick[u]; - } - } - - if(of.flags & UF_LINEAR) - { for(u=0; u<120; u++) - { d->samplenote[u] = (ih.samptable[u] & 255); - d->samplenumber[u] = (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 255; - if(d->samplenumber[u]!=255) - d->samplenote[u] += noteindex[d->samplenumber[u]]; - } - } else - { for(u=0; u<120; u++) - { d->samplenote[u] = (ih.samptable[u] & 255); - d->samplenumber[u] = (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 255; - } - } - - d++; - } - } else if(of.flags & UF_LINEAR) - { if(!AllocInstruments()) return 0; - d = of.instruments; - of.flags |= UF_INST; - - for(t=0; tsmpnum; t++, d++) - { for(u=0; u<120; u++) - d->samplenote[u] += noteindex[d->samplenumber[u]]; - } - } - - - /* Figure out how many channels this blasted song actually uses (what */ - /* ever happened to common courtesy of storing this simple value */ - /* somewhere in the damn module, eh!?) */ - - of.numchn = 0; - memset(remap,-1,64*sizeof(UBYTE)); - - for(t=0; tinsnum+mh->smpnum+t] != 0) /* No parapointer = pattern of 64 rows, EMPTY */ - { _mm_fseek(modfp,(((long)paraptr[mh->insnum+mh->smpnum+t])),SEEK_SET); - packlen = _mm_read_I_UWORD(modfp); - packlen = _mm_read_I_UWORD(modfp); /* read pattern length (# of rows) */ - _mm_read_I_ULONG(modfp); - if(IT_GetNumChannels(packlen)) return 0; - } - } - - /* give each of them a different number */ - for(t=0; t<64; t++) - { if(remap[t]==0) - { remap[t] = of.numchn; - of.numchn++; - } - } - - of.numtrk = of.numpat*of.numchn; - - - if(!AllocPatterns()) return 0; - if(!AllocTracks()) return 0; - - for(t=0; tinsnum+mh->smpnum+t] == 0) /* No parapointer = pattern of 64 rows, EMPTY */ - { of.pattrows[t] = 64; - for(u=0; uinsnum+mh->smpnum+t])),SEEK_SET); - packlen = _mm_read_I_UWORD(modfp); - of.pattrows[t] = _mm_read_I_UWORD(modfp); - _mm_read_I_ULONG(modfp); - - if(!IT_ReadPattern(of.pattrows[t])) return 0; - } - } - - return 1; + int i; + + memset(filtermacros,0,sizeof(filtermacros)); + memset(filtersettings,0,sizeof(filtersettings)); + + if (modreader) { /* information is embedded in file */ + UWORD dat; + CHAR midiline[33]; + + dat=_mm_read_I_UWORD(modreader); + _mm_fseek(modreader,8*dat+0x120,SEEK_CUR); + + /* read midi macros */ + for(i=0;i<16;i++) { + LoadMidiString(modreader,midiline); + if((!strncmp(midiline,"F0F00",5))&& + ((midiline[5]=='0')||(midiline[5]=='1'))) + filtermacros[i]=(midiline[5]-'0')|0x80; + } + + /* read standalone filters */ + for(i=0x80;i<0x100;i++) { + LoadMidiString(modreader,midiline); + if((!strncmp(midiline,"F0F00",5))&& + ((midiline[5]=='0')||(midiline[5]=='1'))) { + filtersettings[i].filter=(midiline[5]-'0')|0x80; + dat=(midiline[6])?(midiline[6]-'0'):0; + if(midiline[7])dat=(dat<<4)|(midiline[7]-'0'); + filtersettings[i].inf=dat; + } + } + } else { /* use default information */ + filtermacros[0]=FILT_CUT; + for(i=0x80;i<0x90;i++) { + filtersettings[i].filter=FILT_RESONANT; + filtersettings[i].inf=(i&0x7f)<<3; + } + } + activemacro=0; + for(i=0;i<0x80;i++) { + filtersettings[i].filter=filtermacros[0]; + filtersettings[i].inf=i; + } } +BOOL IT_Load(BOOL curious) +{ + int t,u,lp; + INSTRUMENT *d; + SAMPLE *q; + BOOL compressed=0; + + numtrk=0; + filters=0; + + /* try to read module header */ + _mm_read_I_ULONG(modreader); /* kill the 4 byte header */ + _mm_read_string(mh->songname,26,modreader); + _mm_read_UBYTES(mh->blank01,2,modreader); + mh->ordnum =_mm_read_I_UWORD(modreader); + mh->insnum =_mm_read_I_UWORD(modreader); + mh->smpnum =_mm_read_I_UWORD(modreader); + mh->patnum =_mm_read_I_UWORD(modreader); + mh->cwt =_mm_read_I_UWORD(modreader); + mh->cmwt =_mm_read_I_UWORD(modreader); + mh->flags =_mm_read_I_UWORD(modreader); + mh->special =_mm_read_I_UWORD(modreader); + mh->globvol =_mm_read_UBYTE(modreader); + mh->mixvol =_mm_read_UBYTE(modreader); + mh->initspeed =_mm_read_UBYTE(modreader); + mh->inittempo =_mm_read_UBYTE(modreader); + mh->pansep =_mm_read_UBYTE(modreader); + mh->zerobyte =_mm_read_UBYTE(modreader); + mh->msglength =_mm_read_I_UWORD(modreader); + mh->msgoffset =_mm_read_I_ULONG(modreader); + _mm_read_UBYTES(mh->blank02,4,modreader); + _mm_read_UBYTES(mh->pantable,64,modreader); + _mm_read_UBYTES(mh->voltable,64,modreader); + + if(_mm_eof(modreader)) { + _mm_errno=MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr(mh->songname,26,0); /* make a cstr of songname */ + of.reppos = 0; + of.numpat = mh->patnum; + of.numins = mh->insnum; + of.numsmp = mh->smpnum; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->globvol; + of.flags |= UF_BGSLIDES|UF_ARPMEM; + + if(mh->songname[25]) { + of.numvoices=1+mh->songname[25]; +#ifdef MIKMOD_DEBUG + fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices); +#endif + } + + /* set the module type */ + /* 2.17 : IT 2.14p4 */ + /* 2.16 : IT 2.14p3 with resonant filters */ + /* 2.15 : IT 2.14p3 (improved compression) */ + if((mh->cwt<=0x219)&&(mh->cwt>=0x217)) + of.modtype=strdup(IT_Version[mh->cmwt<0x214?4:5]); + else if (mh->cwt>=0x215) + of.modtype=strdup(IT_Version[mh->cmwt<0x214?2:3]); + else { + of.modtype = strdup(IT_Version[mh->cmwt<0x214?0:1]); + of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0'; + of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0'; + of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0'; + } + + if(mh->flags&8) + of.flags|=(UF_XMPERIODS | UF_LINEAR); + + if((mh->cwt>=0x106)&&(mh->flags&16)) + old_effect=1; + else + old_effect=0; + + /* set panning positions */ + for(t=0;t<64;t++) { + mh->pantable[t]&=0x7f; + if(mh->pantable[t]<64) + of.panning[t]=mh->pantable[t]<<2; + else if(mh->pantable[t]==64) + of.panning[t]=255; + else if(mh->pantable[t]==100) + of.panning[t]=PAN_SURROUND; + else if(mh->pantable[t]==127) + of.panning[t]=PAN_CENTER; + else { + _mm_errno=MMERR_LOADING_HEADER; + return 0; + } + } + + /* set channel volumes */ + memcpy(of.chanvol,mh->voltable,64); + + /* read the order data */ + if(!AllocPositions(mh->ordnum)) return 0; + if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0; + + for(t=0;tordnum;t++) { + origpositions[t]=_mm_read_UBYTE(modreader); + if((origpositions[t]>mh->patnum)&&(origpositions[t]<254)) + origpositions[t]=255; + } + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + poslookupcnt=mh->ordnum; + S3MIT_CreateOrders(curious); + + if(!(paraptr=(ULONG*)_mm_malloc((mh->insnum+mh->smpnum+of.numpat)* + sizeof(ULONG)))) return 0; + + /* read the instrument, sample, and pattern parapointers */ + _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* Check for and load midi information for resonant filters */ + if(mh->cmwt>=0x216) { + if(mh->special&8) { + IT_LoadMidiConfiguration(modreader); + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + } else + IT_LoadMidiConfiguration(NULL); + filters=1; + } + + /* Check for and load song comment */ + if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) { + _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET); + if(!ReadComment(mh->msglength)) return 0; + } + + if(!(mh->flags&4)) of.numins=of.numsmp; + if(!AllocSamples()) return 0; + + if(!AllocLinear()) return 0; + + /* Load all samples */ + q = of.samples; + for(t=0;tsmpnum;t++) { + ITSAMPLE s; + + /* seek to sample position */ + _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET); + + /* load sample info */ + _mm_read_string(s.filename,12,modreader); + s.zerobyte = _mm_read_UBYTE(modreader); + s.globvol = _mm_read_UBYTE(modreader); + s.flag = _mm_read_UBYTE(modreader); + s.volume = _mm_read_UBYTE(modreader); + _mm_read_string(s.sampname,26,modreader); + s.convert = _mm_read_UBYTE(modreader); + s.panning = _mm_read_UBYTE(modreader); + s.length = _mm_read_I_ULONG(modreader); + s.loopbeg = _mm_read_I_ULONG(modreader); + s.loopend = _mm_read_I_ULONG(modreader); + s.c5spd = _mm_read_I_ULONG(modreader); + s.susbegin = _mm_read_I_ULONG(modreader); + s.susend = _mm_read_I_ULONG(modreader); + s.sampoffset = _mm_read_I_ULONG(modreader); + s.vibspeed = _mm_read_UBYTE(modreader); + s.vibdepth = _mm_read_UBYTE(modreader); + s.vibrate = _mm_read_UBYTE(modreader); + s.vibwave = _mm_read_UBYTE(modreader); + + /* Generate an error if c5spd is > 512k, or samplelength > 256 megs + (nothing would EVER be that high) */ + + if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)|| + (s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL)) { + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr(s.sampname,26,0); + q->speed = s.c5spd / 2; + q->panning = ((s.panning&127)==64)?255:(s.panning&127)<<2; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = s.loopend; + q->volume = s.volume; + q->globvol = s.globvol; + q->seekpos = s.sampoffset; + + /* Convert speed to XM linear finetune */ + if(of.flags&UF_LINEAR) + q->speed=speed_to_finetune(s.c5spd,t); + + if(s.panning&128) q->flags|=SF_OWNPAN; + + if(s.vibrate) { + q->vibflags |= AV_IT; + q->vibtype = s.vibwave; + q->vibsweep = s.vibrate * 2; + q->vibdepth = s.vibdepth; + q->vibrate = s.vibspeed; + } + + if(s.flag&2) q->flags|=SF_16BITS; + if((s.flag&8)&&(mh->cwt>=0x214)) { + q->flags|=SF_ITPACKED; + compressed=1; + } + if(s.flag&16) q->flags|=SF_LOOP; + if(s.flag&64) q->flags|=SF_BIDI; + + if(mh->cwt>=0x200) { + if(s.convert&1) q->flags|=SF_SIGNED; + if(s.convert&4) q->flags|=SF_DELTA; + } + + q++; + } + + /* Load instruments if instrument mode flag enabled */ + if(mh->flags&4) { + if(!AllocInstruments()) return 0; + d=of.instruments; + of.flags|=UF_NNA|UF_INST; + + for(t=0;tinsnum;t++) { + ITINSTHEADER ih; + + /* seek to instrument position */ + _mm_fseek(modreader,paraptr[t]+4,SEEK_SET); + + /* load instrument info */ + _mm_read_string(ih.filename,12,modreader); + ih.zerobyte = _mm_read_UBYTE(modreader); + if(mh->cwt<0x200) { + /* load IT 1.xx inst header */ + ih.volflg = _mm_read_UBYTE(modreader); + ih.volbeg = _mm_read_UBYTE(modreader); + ih.volend = _mm_read_UBYTE(modreader); + ih.volsusbeg = _mm_read_UBYTE(modreader); + ih.volsusend = _mm_read_UBYTE(modreader); + _mm_read_I_UWORD(modreader); + ih.fadeout = _mm_read_I_UWORD(modreader); + ih.nna = _mm_read_UBYTE(modreader); + ih.dnc = _mm_read_UBYTE(modreader); + } else { + /* Read IT200+ header */ + ih.nna = _mm_read_UBYTE(modreader); + ih.dct = _mm_read_UBYTE(modreader); + ih.dca = _mm_read_UBYTE(modreader); + ih.fadeout = _mm_read_I_UWORD(modreader); + ih.ppsep = _mm_read_UBYTE(modreader); + ih.ppcenter = _mm_read_UBYTE(modreader); + ih.globvol = _mm_read_UBYTE(modreader); + ih.chanpan = _mm_read_UBYTE(modreader); + ih.rvolvar = _mm_read_UBYTE(modreader); + ih.rpanvar = _mm_read_UBYTE(modreader); + } + + ih.trkvers = _mm_read_I_UWORD(modreader); + ih.numsmp = _mm_read_UBYTE(modreader); + _mm_read_UBYTE(modreader); + _mm_read_string(ih.name,26,modreader); + _mm_read_UBYTES(ih.blank01,6,modreader); + _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader); + if(mh->cwt<0x200) { + /* load IT 1xx volume envelope */ + _mm_read_UBYTES(ih.volenv,200,modreader); + for(lp=0;lpvolflg|=EF_VOLENV; + d->insname = DupStr(ih.name,26,0); + d->nnatype = ih.nna; + + if(mh->cwt<0x200) { + d->volfade=ih.fadeout<< 6; + if(ih.dnc) { + d->dct=DCT_NOTE; + d->dca=DCA_CUT; + } + + if(ih.volflg&1) d->volflg|=EF_ON; + if(ih.volflg&2) d->volflg|=EF_LOOP; + if(ih.volflg&4) d->volflg|=EF_SUSTAIN; + + /* XM conversion of IT envelope Array */ + d->volbeg = ih.volbeg; + d->volend = ih.volend; + d->volsusbeg = ih.volsusbeg; + d->volsusend = ih.volsusend; + + if(ih.volflg&1) { + for(u=0;uvolpts]!=0xff) { + d->volenv[d->volpts].val=(ih.volnode[d->volpts]<<2); + d->volenv[d->volpts].pos=ih.oldvoltick[d->volpts]; + d->volpts++; + } else + break; + } + } else { + d->panning=((ih.chanpan&127)==64)?255:(ih.chanpan&127)<<2; + if(!(ih.chanpan&128)) d->flags|=IF_OWNPAN; + + if(!(ih.ppsep & 128)) { + d->pitpansep=ih.ppsep<<2; + d->pitpancenter=ih.ppcenter; + d->flags|=IF_PITCHPAN; + } + d->globvol=ih.globvol>>1; + d->volfade=ih.fadeout<<5; + d->dct =ih.dct; + d->dca =ih.dca; + + if(mh->cwt>=0x204) { + d->rvolvar = ih.rvolvar; + d->rpanvar = ih.rpanvar; + } + +#ifdef __STDC__ +#define IT_ProcessEnvelope(name) \ + if(ih.##name##flg&1) d->##name##flg|=EF_ON; \ + if(ih.##name##flg&2) d->##name##flg|=EF_LOOP; \ + if(ih.##name##flg&4) d->##name##flg|=EF_SUSTAIN; \ + d->##name##pts=ih.##name##pts; \ + d->##name##beg=ih.##name##beg; \ + d->##name##end=ih.##name##end; \ + d->##name##susbeg=ih.##name##susbeg; \ + d->##name##susend=ih.##name##susend; \ + \ + for(u=0;u##name##env[u].pos=ih.##name##tick[u]; \ + \ + if((d->##name##flg&EF_ON)&&(d->##name##pts<2)) \ + d->##name##flg&=~EF_ON; +#else +#define IT_ProcessEnvelope(name) \ + if(ih./**/name/**/flg&1) d->/**/name/**/flg|=EF_ON; \ + if(ih./**/name/**/flg&2) d->/**/name/**/flg|=EF_LOOP; \ + if(ih./**/name/**/flg&4) d->/**/name/**/flg|=EF_SUSTAIN; \ + d->/**/name/**/pts=ih./**/name/**/pts; \ + d->/**/name/**/beg=ih./**/name/**/beg; \ + d->/**/name/**/end=ih./**/name/**/end; \ + d->/**/name/**/susbeg=ih./**/name/**/susbeg; \ + d->/**/name/**/susend=ih./**/name/**/susend; \ + \ + for(u=0;u/**/name/**/env[u].pos=ih./**/name/**/tick[u]; \ + \ + if((d->/**/name/**/flg&EF_ON)&&(d->/**/name/**/pts<2)) \ + d->/**/name/**/flg&=~EF_ON; +#endif + + IT_ProcessEnvelope(vol); + for(u=0;uvolenv[u].val=(ih.volnode[u]<<2); + + IT_ProcessEnvelope(pan); + for(u=0;upanenv[u].val= + ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2; + + IT_ProcessEnvelope(pit); + for(u=0;upitenv[u].val=ih.pitnode[u]+32; +#undef IT_ProcessEnvelope + + if(ih.pitflg&0x80) { + /* filter envelopes not supported yet */ + d->pitflg&=~EF_ON; + ih.pitpts=ih.pitbeg=ih.pitend=0; +#ifdef MIKMOD_DEBUG + { + static int warn=0; + + if(!warn) + fputs("\rFilter envelopes not supported yet\n",stderr); + warn=1; + } +#endif + } + + d->volpts = ih.volpts; + d->volbeg = ih.volbeg; + d->volend = ih.volend; + d->volsusbeg = ih.volsusbeg; + d->volsusend = ih.volsusend; + + for(u=0;uvolenv[u].val=(ih.volnode[u]<<2); + d->volenv[u].pos=ih.voltick[u]; + } + + d->panpts = ih.panpts; + d->panbeg = ih.panbeg; + d->panend = ih.panend; + d->pansusbeg = ih.pansusbeg; + d->pansusend = ih.pansusend; + + for(u=0;upanenv[u].val=ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2; + d->panenv[u].pos=ih.pantick[u]; + } + + d->pitpts =ih.pitpts; + d->pitbeg =ih.pitbeg; + d->pitend =ih.pitend; + d->pitsusbeg=ih.pitsusbeg; + d->pitsusend=ih.pitsusend; + + for(u=0;upitenv[u].val=ih.pitnode[u]+32; + d->pitenv[u].pos=ih.pittick[u]; + } + } + + for(u=0;usamplenote[u]=(ih.samptable[u]&255); + d->samplenumber[u]= + (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff; + if(d->samplenumber[u]>=of.numsmp) + d->samplenote[u]=255; + else if (of.flags&UF_LINEAR) { + int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; + d->samplenote[u]=(note<0)?0:(note>255?255:note); + } + } + + d++; + } + } else if(of.flags & UF_LINEAR) { + if(!AllocInstruments()) return 0; + d=of.instruments; + of.flags|=UF_INST; + + for(t=0;tsmpnum;t++,d++) + for(u=0;usamplenumber[u]>=of.numsmp) + d->samplenote[u]=255; + else { + int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]]; + d->samplenote[u]=(note<0)?0:(note>255?255:note); + } + } + } + + /* Figure out how many channels this song actually uses */ + of.numchn=0; + memset(remap,-1,64*sizeof(UBYTE)); + for(t=0;tinsnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */ + _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET); + _mm_read_I_UWORD(modreader); + /* read pattern length (# of rows) + Impulse Tracker never creates patterns with less than 32 rows, + but some other trackers do, so we only check for more than 256 + rows */ + packlen=_mm_read_I_UWORD(modreader); + if(packlen>256) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + _mm_read_I_ULONG(modreader); + if(IT_GetNumChannels(packlen)) return 0; + } + } + + /* give each of them a different number */ + for(t=0;t<64;t++) + if(!remap[t]) + remap[t]=of.numchn++; + + of.numtrk = of.numpat*of.numchn; + if(of.numvoices) + if (of.numvoicesinsnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */ + of.pattrows[t]=64; + for(u=0;uinsnum+mh->smpnum+t]),SEEK_SET); + packlen=_mm_read_I_UWORD(modreader); + of.pattrows[t]=_mm_read_I_UWORD(modreader); + _mm_read_I_ULONG(modreader); + if(!IT_ReadPattern(of.pattrows[t])) return 0; + } + } + + return 1; +} CHAR *IT_LoadTitle(void) { - CHAR s[26]; - - _mm_fseek(modfp,4,SEEK_SET); - if(!fread(s,26,1,modfp)) return NULL; - - return(DupStr(s,26)); -} + CHAR s[26]; + _mm_fseek(modreader,4,SEEK_SET); + if(!_mm_read_UBYTES(s,26,modreader)) return NULL; -MLOADER load_it = -{ NULL, - "IT", - "Portable IT loader v0.2", - IT_Init, - IT_Test, - IT_Load, - IT_Cleanup, + return(DupStr(s,26,0)); +} - IT_LoadTitle +/*========== Loader information */ + +MLOADER load_it={ + NULL, + "IT", + "IT (Impulse Tracker)", + IT_Init, + IT_Test, + IT_Load, + IT_Cleanup, + IT_LoadTitle }; +/* ex:set ts=4: */ diff --git a/mikmod/load_mod.c b/mikmod/load_mod.c index 856b123a..f0dfa962 100644 --- a/mikmod/load_mod.c +++ b/mikmod/load_mod.c @@ -1,140 +1,146 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ - Name: LOAD_MOD.C +/*============================================================================== - Description: - Generic MOD loader (Protracker, StarTracker, FastTracker, etc) + $Id$ - Portability: - All systems - all compilers (hopefully) + Generic MOD loader (Protracker, StarTracker, FastTracker, etc) - If this module is found to not be portable to any particular platform, - please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for - more information on contacting the author). +==============================================================================*/ -*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include -#include "mikmod.h" -/************************************************************************* -*************************************************************************/ +#include "mikmod_internals.h" +/*========== Module structure */ -typedef struct MSAMPINFO /* sample header as it appears in a module */ -{ CHAR samplename[22]; - UWORD length; - UBYTE finetune; - UBYTE volume; - UWORD reppos; - UWORD replen; +typedef struct MSAMPINFO { + CHAR samplename[23]; /* 22 in module, 23 in memory */ + UWORD length; + UBYTE finetune; + UBYTE volume; + UWORD reppos; + UWORD replen; } MSAMPINFO; - -typedef struct MODULEHEADER /* verbatim module header */ -{ CHAR songname[20]; /* the songname.. */ - MSAMPINFO samples[31]; /* all sampleinfo */ - UBYTE songlength; /* number of patterns used */ - UBYTE magic1; /* should be 127 */ - UBYTE positions[128]; /* which pattern to play at pos */ - UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */ +typedef struct MODULEHEADER { + CHAR songname[21]; /* the songname.. 20 in module, 21 in memory */ + MSAMPINFO samples[31]; /* all sampleinfo */ + UBYTE songlength; /* number of patterns used */ + UBYTE magic1; /* should be 127 */ + UBYTE positions[128]; /* which pattern to play at pos */ + UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */ } MODULEHEADER; -#define MODULEHEADERSIZE 1084 - - -typedef struct MODTYPE /* struct to identify type of module */ -{ CHAR id[5]; - UBYTE channels; - CHAR *name; +typedef struct MODTYPE { + CHAR id[5]; + UBYTE channels; + CHAR *name; } MODTYPE; - -typedef struct MODNOTE -{ UBYTE a,b,c,d; +typedef struct MODNOTE { + UBYTE a,b,c,d; } MODNOTE; +/*========== Loader variables */ + +#define MODULEHEADERSIZE 1084 -/************************************************************************* -*************************************************************************/ - - -CHAR protracker[] = "Protracker"; -CHAR startracker[] = "Startracker"; -CHAR fasttracker[] = "Fasttracker"; -CHAR ins15tracker[] = "15-instrument"; -CHAR oktalyzer[] = "Oktalyzer"; -CHAR taketracker[] = "TakeTracker"; - - -MODTYPE modtypes[] = -{ "M.K.",4,protracker, /* protracker 4 channel */ - "M!K!",4,protracker, /* protracker 4 channel */ - "FLT4",4,startracker, /* startracker 4 channel */ - "2CHN",2,fasttracker, /* fasttracker 2 channel */ - "4CHN",4,fasttracker, /* fasttracker 4 channel */ - "6CHN",6,fasttracker, /* fasttracker 6 channel */ - "8CHN",8,fasttracker, /* fasttracker 8 channel */ - "10CH",10,fasttracker, /* fasttracker 10 channel */ - "12CH",12,fasttracker, /* fasttracker 12 channel */ - "14CH",14,fasttracker, /* fasttracker 14 channel */ - "16CH",16,fasttracker, /* fasttracker 16 channel */ - "18CH",18,fasttracker, /* fasttracker 18 channel */ - "20CH",20,fasttracker, /* fasttracker 20 channel */ - "22CH",22,fasttracker, /* fasttracker 22 channel */ - "24CH",24,fasttracker, /* fasttracker 24 channel */ - "26CH",26,fasttracker, /* fasttracker 26 channel */ - "28CH",28,fasttracker, /* fasttracker 28 channel */ - "30CH",30,fasttracker, /* fasttracker 30 channel */ - "32CH",32,fasttracker, /* fasttracker 32 channel */ - "CD81",8,oktalyzer, /* atari oktalyzer 8 channel */ - "OKTA",8,oktalyzer, /* atari oktalyzer 8 channel */ - "16CN",16,taketracker, /* taketracker 16 channel */ - "32CN",32,taketracker, /* taketracker 32 channel */ - " ",4,ins15tracker /* 15-instrument 4 channel */ +static CHAR protracker[] = "Protracker"; +static CHAR startracker[] = "Startracker"; +static CHAR fasttracker[] = "Fasttracker"; +static CHAR ins15tracker[] = "15-instrument"; +static CHAR oktalyzer[] = "Oktalyzer"; +static CHAR taketracker[] = "TakeTracker"; +static CHAR orpheus[] = "Imago Orpheus (MOD format)"; + +#define MODTYPE_COUNT 24 +static MODTYPE modtypes[MODTYPE_COUNT+1]={ + {"M.K.", 4, protracker}, /* protracker 4 channel */ + {"M!K!", 4, protracker}, /* protracker 4 channel */ + {"FLT4", 4, startracker}, /* startracker 4 channel */ + {"2CHN", 2, fasttracker}, /* fasttracker 2 channel */ + {"4CHN", 4, fasttracker}, /* fasttracker 4 channel */ + {"6CHN", 6, fasttracker}, /* fasttracker 6 channel */ + {"8CHN", 8, fasttracker}, /* fasttracker 8 channel */ + {"10CH",10, fasttracker}, /* fasttracker 10 channel */ + {"12CH",12, fasttracker}, /* fasttracker 12 channel */ + {"14CH",14, fasttracker}, /* fasttracker 14 channel */ + {"15CH",15, fasttracker}, /* fasttracker 15 channel */ + {"16CH",16, fasttracker}, /* fasttracker 16 channel */ + {"18CH",18, fasttracker}, /* fasttracker 18 channel */ + {"20CH",20, fasttracker}, /* fasttracker 20 channel */ + {"22CH",22, fasttracker}, /* fasttracker 22 channel */ + {"24CH",24, fasttracker}, /* fasttracker 24 channel */ + {"26CH",26, fasttracker}, /* fasttracker 26 channel */ + {"28CH",28, fasttracker}, /* fasttracker 28 channel */ + {"30CH",30, fasttracker}, /* fasttracker 30 channel */ + {"32CH",32, fasttracker}, /* fasttracker 32 channel */ + {"CD81", 8, oktalyzer}, /* atari oktalyzer 8 channel */ + {"OKTA", 8, oktalyzer}, /* atari oktalyzer 8 channel */ + {"16CN",16, taketracker}, /* taketracker 16 channel */ + {"32CN",32, taketracker}, /* taketracker 32 channel */ + {" ", 4,ins15tracker} /* 15-instrument 4 channel */ }; -static MODULEHEADER *mh = NULL; /* raw as-is module header */ +static MODULEHEADER *mh = NULL; static MODNOTE *patbuf = NULL; static int modtype = 0; -BOOL MOD_Test(void) -{ - UBYTE id[4]; +/*========== Loader code */ - _mm_fseek(modfp,MODULEHEADERSIZE-4,SEEK_SET); - if(!fread(id,4,1,modfp)) return 0; +static BOOL MOD_Test(void) +{ + UBYTE id[4]; - /* find out which ID string */ + _mm_fseek(modreader,MODULEHEADERSIZE-4,SEEK_SET); + if(!_mm_read_UBYTES(id,4,modreader)) return 0; - for(modtype=0; modtype<23; modtype++) - if(!memcmp(id,modtypes[modtype].id,4)) return 1; + /* find out which ID string */ + for(modtype=0;modtypea&0x10)|(n->c>>4); - period = (((UWORD)n->a&0xf)<<8)+n->b; - effect = n->c&0xf; - effdat = n->d; - - /* Convert the period to a note number */ - - note=0; - if(period!=0) - { for(note=0; note<60; note++) - if(period >= npertab[note]) break; - note++; - if(note==61) note = 0; - } - - if(instrument!=0) UniInstrument(instrument-1); - if(note!=0) UniNote(note+23); - - /* Convert pattern jump from Dec to Hex */ - if(effect == 0xd) - effdat = (((effdat&0xf0)>>4)*10)+(effdat&0xf); - - UniPTEffect(effect,effdat); + UBYTE instrument,effect,effdat,note; + UWORD period; + UBYTE lastnote=0; + + /* extract the various information from the 4 bytes that make up a note */ + instrument = (n->a&0x10)|(n->c>>4); + period = (((UWORD)n->a&0xf)<<8)+n->b; + effect = n->c&0xf; + effdat = n->d; + + /* Convert the period to a note number */ + note=0; + if(period) { + for(note=0;note<7*OCTAVE;note++) + if(period>=npertab[note]) break; + if(note==7*OCTAVE) note=0; + else note++; + } + + if(instrument) { + /* if instrument does not exist, note cut */ + if((instrument>31)||(!mh->samples[instrument-1].length)) { + UniPTEffect(0xc,0); + if(effect==0xc) effect=effdat=0; + } else { + /* Protracker handling */ + if(modtype<=2) { + /* if we had a note, then change instrument... */ + if(note) + UniInstrument(instrument-1); + /* ...otherwise, only adjust volume... */ + else { + /* ...unless an effect was specified, which forces a new + note to be played */ + if(effect||effdat) { + UniInstrument(instrument-1); + note=lastnote; + } else + UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f); + } + } else { + /* Fasttracker handling */ + UniInstrument(instrument-1); + if(!note) note=lastnote; + } + } + } + if(note) { + UniNote(note+2*OCTAVE-1); + lastnote=note; + } + + /* Convert pattern jump from Dec to Hex */ + if(effect==0xd) + effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf); + + /* Volume slide, up has priority */ + if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0)) + effdat&=0xf0; + + UniPTEffect(effect,effdat); } - -UBYTE *ConvertTrack(MODNOTE *n) +static UBYTE* ConvertTrack(MODNOTE* n) { - int t; - - UniReset(); - for(t=0;t<64;t++) - { ConvertNote(n); - UniNewline(); - n+=of.numchn; - } - return UniDup(); + int t; + + UniReset(); + for(t=0;t<64;t++) { + ConvertNote(n); + UniNewline(); + n+=of.numchn; + } + return UniDup(); } - -BOOL ML_LoadPatterns(void) -/* Loads all patterns of a modfile and converts them into the */ -/* 3 byte format. */ +/* Loads all patterns of a modfile and converts them into the 3 byte format. */ +static BOOL ML_LoadPatterns(void) { - int t,s,tracks = 0; - - if(!AllocPatterns()) return 0; - if(!AllocTracks()) return 0; - - /* Allocate temporary buffer for loading */ - /* and converting the patterns */ - - if(!(patbuf=(MODNOTE *)_mm_calloc(64U*of.numchn,sizeof(MODNOTE)))) return 0; - - for(t=0; tsongname,20,modfp); - - for(t=0; t<31; t++) - { s = &mh->samples[t]; - _mm_read_string(s->samplename,22,modfp); - s->length =_mm_read_M_UWORD(modfp); - s->finetune =_mm_read_UBYTE(modfp); - s->volume =_mm_read_UBYTE(modfp); - s->reppos =_mm_read_M_UWORD(modfp); - s->replen =_mm_read_M_UWORD(modfp); - } - - mh->songlength =_mm_read_UBYTE(modfp); - mh->magic1 =_mm_read_UBYTE(modfp); - - _mm_read_UBYTES(mh->positions,128,modfp); - _mm_read_UBYTES(mh->magic2,4,modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - /* set module variables */ - - of.initspeed = 6; - of.inittempo = 125; - of.numchn = modtypes[modtype].channels; /* get number of channels */ - of.modtype = strdup(modtypes[modtype].name); /* get ascii type of mod */ - of.songname = DupStr(mh->songname,20); /* make a cstr of songname */ - of.numpos = mh->songlength; /* copy the songlength */ - - if(!AllocPositions(of.numpos)) return 0; - for(t=0; tpositions[t]; - - /* Count the number of patterns */ - - of.numpat = 0; - - for(t=0; t of.numpat) - of.numpat = of.positions[t]; - } - of.numpat++; - of.numtrk = of.numpat*of.numchn; - - /* Finally, init the sampleinfo structures */ - of.numins = of.numsmp = 31; - - if(!AllocSamples()) return 0; - - s = mh->samples; /* init source pointer */ - q = of.samples; - - for(t=0; tsamplename = DupStr(s->samplename, 22); - - /* init the sampleinfo variables and */ - /* convert the size pointers to longword format */ - - q->speed = finetune[s->finetune & 0xf]; - q->volume = s->volume; - q->loopstart = (ULONG)s->reppos << 1; - q->loopend = q->loopstart + ((ULONG)s->replen << 1); - q->length = (ULONG)s->length << 1; - - q->flags = SF_SIGNED; - if(s->replen > 1) q->flags |= SF_LOOP; - - /* fix replen if repend > length */ - if(q->loopend > q->length) q->loopend = q->length; - - s++; /* point to next source sampleinfo */ - q++; - } - - if(!ML_LoadPatterns()) return 0; - return 1; + int t,scan; + SAMPLE *q; + MSAMPINFO *s; + BOOL is_orpheus=0; + + /* try to read module header */ + _mm_read_string((CHAR*)mh->songname,20,modreader); + mh->songname[20]=0; /* just in case */ + + for(t=0;t<31;t++) { + s=&mh->samples[t]; + _mm_read_string(s->samplename,22,modreader); + s->samplename[22]=0; /* just in case */ + s->length =_mm_read_M_UWORD(modreader); + s->finetune =_mm_read_UBYTE(modreader); + s->volume =_mm_read_UBYTE(modreader); + s->reppos =_mm_read_M_UWORD(modreader); + s->replen =_mm_read_M_UWORD(modreader); + } + + mh->songlength =_mm_read_UBYTE(modreader); + mh->magic1 =_mm_read_UBYTE(modreader); + _mm_read_UBYTES(mh->positions,128,modreader); + _mm_read_UBYTES(mh->magic2,4,modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = 6; + of.inittempo = 125; + of.numchn = modtypes[modtype].channels; + of.songname = DupStr(mh->songname,21,1); + of.numpos = mh->songlength; + of.reppos = 0; + + /* Count the number of patterns */ + of.numpat = 0; + for(t=0;tpositions[t]>of.numpat) + of.numpat=mh->positions[t]; + /* since some old modules embed extra patterns, we have to check the + whole list to get the samples' file offsets right - however we can find + garbage here, so check carefully */ + scan=1; + for(t=of.numpos;t<128;t++) + if(mh->positions[t]>=0x80) scan=0; + if (scan) + for(t=of.numpos;t<128;t++) { + if(mh->positions[t]>of.numpat) + of.numpat=mh->positions[t]; + if((curious)&&(mh->positions[t])) of.numpos=t+1; + } + of.numpat++; + of.numtrk = of.numpat*of.numchn; + + if(!AllocPositions(of.numpos)) return 0; + for(t=0;tpositions[t]; + + /* Finally, init the sampleinfo structures */ + of.numins=of.numsmp=31; + if(!AllocSamples()) return 0; + s = mh->samples; + q = of.samples; + for(t=0;tsamplename = DupStr(s->samplename,23,1); + /* init the sampleinfo variables and convert the size pointers */ + q->speed = finetune[s->finetune & 0xf]; + q->volume = s->volume&0x7f; + q->loopstart = (ULONG)s->reppos << 1; + q->loopend = q->loopstart + ((ULONG)s->replen << 1); + q->length = (ULONG)s->length << 1; + q->flags = SF_SIGNED; + /* Imago Orpheus creates MODs with 16 bit samples, check */ + if((modtypes[modtype].name==fasttracker)&&(s->volume&0x80)) { + q->flags|=SF_16BITS; + is_orpheus=1; + } + + if(s->replen>1) q->flags |= SF_LOOP; + /* fix replen if repend > length */ + if(q->loopend>q->length) q->loopend=q->length; + + s++; + q++; + } + + if(is_orpheus) + of.modtype=strdup(orpheus); + else + of.modtype=strdup(modtypes[modtype].name); + + if(!ML_LoadPatterns()) return 0; + return 1; } - -CHAR *MOD_LoadTitle(void) +static CHAR *MOD_LoadTitle(void) { - CHAR s[20]; + CHAR s[21]; - _mm_fseek(modfp,0,SEEK_SET); - if(!fread(s,20,1,modfp)) return NULL; - - return(DupStr(s,20)); -} + _mm_fseek(modreader,0,SEEK_SET); + if(!_mm_read_UBYTES(s,20,modreader)) return NULL; + s[20]=0; /* just in case */ + return(DupStr(s,21,1)); +} -MLOADER load_mod = -{ NULL, - "Standard module", - "Portable MOD loader v0.11", - MOD_Init, - MOD_Test, - MOD_Load, - MOD_Cleanup, - MOD_LoadTitle +/*========== Loader information */ + +MLOADER load_mod={ + NULL, + "Standard module", + "MOD (31 instrument)", + MOD_Init, + MOD_Test, + MOD_Load, + MOD_Cleanup, + MOD_LoadTitle }; +/* ex:set ts=4: */ diff --git a/mikmod/load_s3m.c b/mikmod/load_s3m.c index 28b7432b..0c562b82 100644 --- a/mikmod/load_s3m.c +++ b/mikmod/load_s3m.c @@ -1,466 +1,449 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ - Name: LOAD_S3M.C +/*============================================================================== - Description: - Screamtracker (S3M) module loader + $Id$ - Portability: - All systems - all compilers (hopefully) + Screamtracker (S3M) module loader - If this module is found to not be portable to any particular platform, - please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for - more information on contacting the author). +==============================================================================*/ -*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include -#include "mikmod.h" - -/************************************************************************** -**************************************************************************/ - -typedef struct S3MNOTE -{ UBYTE note,ins,vol,cmd,inf; -} S3MNOTE; -typedef S3MNOTE S3MTRACK[64]; - - -/* Raw S3M header struct: */ - -typedef struct S3MHEADER -{ CHAR songname[28]; - UBYTE t1a; - UBYTE type; - UBYTE unused1[2]; - UWORD ordnum; - UWORD insnum; - UWORD patnum; - UWORD flags; - UWORD tracker; - UWORD fileformat; - CHAR scrm[4]; - UBYTE mastervol; - UBYTE initspeed; - UBYTE inittempo; - UBYTE mastermult; - UBYTE ultraclick; - UBYTE pantable; - UBYTE unused2[8]; - UWORD special; - UBYTE channels[32]; +#include "mikmod_internals.h" + +/*========== Module structure */ + +/* header */ +typedef struct S3MHEADER { + CHAR songname[28]; + UBYTE t1a; + UBYTE type; + UBYTE unused1[2]; + UWORD ordnum; + UWORD insnum; + UWORD patnum; + UWORD flags; + UWORD tracker; + UWORD fileformat; + CHAR scrm[4]; + UBYTE mastervol; + UBYTE initspeed; + UBYTE inittempo; + UBYTE mastermult; + UBYTE ultraclick; + UBYTE pantable; + UBYTE unused2[8]; + UWORD special; + UBYTE channels[32]; } S3MHEADER; - -/* Raw S3M sampleinfo struct: */ - -typedef struct S3MSAMPLE -{ UBYTE type; - CHAR filename[12]; - UBYTE memsegh; - UWORD memsegl; - ULONG length; - ULONG loopbeg; - ULONG loopend; - UBYTE volume; - UBYTE dsk; - UBYTE pack; - UBYTE flags; - ULONG c2spd; - UBYTE unused[12]; - CHAR sampname[28]; - CHAR scrs[4]; +/* sample information */ +typedef struct S3MSAMPLE { + UBYTE type; + CHAR filename[12]; + UBYTE memsegh; + UWORD memsegl; + ULONG length; + ULONG loopbeg; + ULONG loopend; + UBYTE volume; + UBYTE dsk; + UBYTE pack; + UBYTE flags; + ULONG c2spd; + UBYTE unused[12]; + CHAR sampname[28]; + CHAR scrs[4]; } S3MSAMPLE; -/************************************************************************** -**************************************************************************/ - +typedef struct S3MNOTE { + UBYTE note,ins,vol,cmd,inf; +} S3MNOTE; -extern UBYTE *poslookup; /* S3M/IT fix - removing blank patterns needs a */ - /* lookup table to fix position-jump commands */ -extern SBYTE remap[64]; /* for removing empty channels */ +/*========== Loader variables */ static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */ static S3MHEADER *mh = NULL; static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */ -CHAR S3M_Version[] = "Screamtracker 3.xx"; +/* tracker identifiers */ +#define NUMTRACKERS 4 +static CHAR* S3M_Version[] = { + "Screamtracker x.xx", + "Imago Orpheus x.xx (S3M format)", + "Impulse Tracker x.xx (S3M format)", + "Unknown tracker x.xx (S3M format)", + "Impulse Tracker 2.14p3 (S3M format)", + "Impulse Tracker 2.14p4 (S3M format)" +}; +/* version number position in above array */ +static int numeric[NUMTRACKERS]={14,14,16,16}; + +/*========== Loader code */ BOOL S3M_Test(void) { - UBYTE id[4]; - - _mm_fseek(modfp,0x2c,SEEK_SET); - if(!_mm_read_UBYTES(id,4,modfp)) return 0; - if(!memcmp(id,"SCRM",4)) return 1; - return 0; + UBYTE id[4]; + + _mm_fseek(modreader,0x2c,SEEK_SET); + if(!_mm_read_UBYTES(id,4,modreader)) return 0; + if(!memcmp(id,"SCRM",4)) return 1; + return 0; } BOOL S3M_Init(void) { - if(!(s3mbuf = (S3MNOTE *)_mm_malloc(16*64*sizeof(S3MNOTE)))) return 0; - if(!(mh = (S3MHEADER *)_mm_calloc(1,sizeof(S3MHEADER)))) return 0; - if(!(poslookup = (UBYTE *)_mm_malloc(sizeof(UBYTE)*128))) return 0; + if(!(s3mbuf=(S3MNOTE*)_mm_malloc(32*64*sizeof(S3MNOTE)))) return 0; + if(!(mh=(S3MHEADER*)_mm_malloc(sizeof(S3MHEADER)))) return 0; + if(!(poslookup=(UBYTE*)_mm_malloc(sizeof(UBYTE)*256))) return 0; + memset(poslookup,-1,256); - return 1; + return 1; } void S3M_Cleanup(void) { - if(s3mbuf!=NULL) free(s3mbuf); - if(paraptr!=NULL) free(paraptr); - if(poslookup!=NULL) free(poslookup); - if(mh!=NULL) free(mh); - - paraptr = NULL; - s3mbuf = NULL; - poslookup = NULL; - mh = NULL; + _mm_free(s3mbuf); + _mm_free(paraptr); + _mm_free(poslookup); + _mm_free(mh); + _mm_free(origpositions); } +/* Because so many s3m files have 16 channels as the set number used, but really + only use far less (usually 8 to 12 still), I had to make this function, which + determines the number of channels that are actually USED by a pattern. -BOOL S3M_GetNumChannels(void) + For every channel that's used, it sets the appropriate array entry of the + global variable 'remap' -/* Because so many s3m files have 16 channels as the set number used, but really */ -/* only use far less (usually 8 to 12 still), I had to make this function, */ -/* which determines the number of channels that are actually USED by a pattern. */ -/* */ -/* For every channel that's used, it sets the appropriate array entry of the */ -/* global varialbe 'isused' */ -/* */ -/* NOTE: You must first seek to the file location of the pattern before calling */ -/* this procedure. */ -/* Returns 1 on fail. */ + NOTE: You must first seek to the file location of the pattern before calling + this procedure. + Returns 1 on fail. */ +static BOOL S3M_GetNumChannels(void) { - int row=0,flag,ch; - - while(row<64) - { flag = _mm_read_UBYTE(modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_PATTERN; - return 1; - } - - if(flag) - { ch = flag&31; - if(mh->channels[ch] < 16) remap[ch] = 0; - - if(flag&32) - { _mm_read_UBYTE(modfp); - _mm_read_UBYTE(modfp); - } - - if(flag&64) - _mm_read_UBYTE(modfp); - - if(flag&128) - { _mm_read_UBYTE(modfp); - _mm_read_UBYTE(modfp); - } - } else row++; - } - - return 0; -} - + int row=0,flag,ch; + + while(row<64) { + flag=_mm_read_UBYTE(modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_PATTERN; + return 1; + } + + if(flag) { + ch=flag&31; + if(mh->channels[ch]<32) remap[ch] = 0; + if(flag&32) {_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);} + if(flag&64) _mm_read_UBYTE(modreader); + if(flag&128){_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);} + } else row++; + } + return 0; +} -BOOL S3M_ReadPattern(void) +static BOOL S3M_ReadPattern(void) { - int row=0,flag,ch; - S3MNOTE *n; - S3MNOTE dummy; - - /* clear pattern data */ - memset(s3mbuf,255,16*64*sizeof(S3MNOTE)); - - while(row<64) - { flag = _mm_read_UBYTE(modfp); - - if(flag==EOF) - { _mm_errno = MMERR_LOADING_PATTERN; - return 0; - } - - if(flag) - { ch = remap[flag&31]; - - if(ch != -1) - n = &s3mbuf[(64U*ch)+row]; - else - n = &dummy; - - if(flag&32) - { n->note = _mm_read_UBYTE(modfp); - n->ins = _mm_read_UBYTE(modfp); - } - - if(flag&64) - n->vol = _mm_read_UBYTE(modfp); - - if(flag&128) - { n->cmd = _mm_read_UBYTE(modfp); - n->inf = _mm_read_UBYTE(modfp); - } - } else row++; - } - return 1; + int row=0,flag,ch; + S3MNOTE *n,dummy; + + /* clear pattern data */ + memset(s3mbuf,255,32*64*sizeof(S3MNOTE)); + + while(row<64) { + flag=_mm_read_UBYTE(modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if(flag) { + ch=remap[flag&31]; + + if(ch!=-1) + n=&s3mbuf[(64U*ch)+row]; + else + n=&dummy; + + if(flag&32) { + n->note=_mm_read_UBYTE(modreader); + n->ins=_mm_read_UBYTE(modreader); + } + if(flag&64) + n->vol=_mm_read_UBYTE(modreader); + if(flag&128) { + n->cmd=_mm_read_UBYTE(modreader); + n->inf=_mm_read_UBYTE(modreader); + } + } else row++; + } + return 1; } - -void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, BOOL oldeffect); - -UBYTE *S3M_ConvertTrack(S3MNOTE *tr) +static UBYTE* S3M_ConvertTrack(S3MNOTE* tr) { - int t; - - UBYTE note,ins,vol; - - UniReset(); - for(t=0; t<64; t++) - { - note = tr[t].note; - ins = tr[t].ins; - vol = tr[t].vol; - - - if(ins!=0 && ins!=255) UniInstrument(ins-1); - if(note!=255) - { if(note==254) UniPTEffect(0xc,0); /* <- note off command */ - else UniNote(((note>>4)*12)+(note&0xf)); /* <- normal note */ - } - - if(vol<255) - UniPTEffect(0xc,vol); - - S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,1); - UniNewline(); - } - - return UniDup(); + int t; + + UniReset(); + for(t=0;t<64;t++) { + UBYTE note,ins,vol; + + note=tr[t].note; + ins=tr[t].ins; + vol=tr[t].vol; + + if((ins)&&(ins!=255)) UniInstrument(ins-1); + if(note!=255) { + if(note==254) { + UniPTEffect(0xc,0); /* note cut command */ + vol=255; + } else + UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */ + } + if(vol<255) UniPTEffect(0xc,vol); + + S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,1); + UniNewline(); + } + return UniDup(); } - -BOOL S3M_Load(void) +BOOL S3M_Load(BOOL curious) { - int t,u,track = 0; - SAMPLE *q; - UBYTE pan[32]; - - /* try to read module header */ - - _mm_read_string(mh->songname,28,modfp); - mh->t1a =_mm_read_UBYTE(modfp); - mh->type =_mm_read_UBYTE(modfp); - _mm_read_UBYTES(mh->unused1,2,modfp); - mh->ordnum =_mm_read_I_UWORD(modfp); - mh->insnum =_mm_read_I_UWORD(modfp); - mh->patnum =_mm_read_I_UWORD(modfp); - mh->flags =_mm_read_I_UWORD(modfp); - mh->tracker =_mm_read_I_UWORD(modfp); - mh->fileformat =_mm_read_I_UWORD(modfp); - _mm_read_string(mh->scrm,4,modfp); - - mh->mastervol =_mm_read_UBYTE(modfp); - mh->initspeed =_mm_read_UBYTE(modfp); - mh->inittempo =_mm_read_UBYTE(modfp); - mh->mastermult =_mm_read_UBYTE(modfp); - mh->ultraclick =_mm_read_UBYTE(modfp); - mh->pantable =_mm_read_UBYTE(modfp); - _mm_read_UBYTES(mh->unused2,8,modfp); - mh->special =_mm_read_I_UWORD(modfp); - _mm_read_UBYTES(mh->channels,32,modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - /* set module variables */ - - of.modtype = strdup(S3M_Version); - of.modtype[14] = ((mh->tracker >> 8) &0xf) + 0x30; - of.modtype[16] = ((mh->tracker >> 4)&0xf) + 0x30; - of.modtype[17] = ((mh->tracker)&0xf) + 0x30; - of.songname = DupStr(mh->songname,28); - of.numpat = mh->patnum; - of.reppos = 0; - of.numins = of.numsmp = mh->insnum; - of.initspeed = mh->initspeed; - of.inittempo = mh->inittempo; - of.initvolume = mh->mastervol<<1; - - /* read the order data */ - if(!AllocPositions(mh->ordnum)) return 0; - for(t=0; tordnum; t++) - of.positions[t] = _mm_read_UBYTE(modfp); - - of.numpos = 0; - for(t=0; tordnum; t++) - { of.positions[of.numpos] = of.positions[t]; - poslookup[t] = of.numpos; /* bug fix for FREAKY S3Ms */ - if(of.positions[t]<254) of.numpos++; - } - - if((paraptr=(UWORD *)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD)))==NULL) return 0; - - /* read the instrument+pattern parapointers */ - _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modfp); - - - if(mh->pantable==252) - { /* read the panning table (ST 3.2 addition. See below for further */ - /* portions of channel panning [past reampper]). */ - _mm_read_UBYTES(pan,32,modfp); - } - - - /* now is a good time to check if the header was too short :) */ - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - - /* ============================================== */ - /* Load those darned Samples! (no insts in ST3) */ - - if(!AllocSamples()) return 0; - - q = of.samples; - - for(t=0; tsamplename = DupStr(s.sampname,28); - q->speed = s.c2spd; - q->length = s.length; - q->loopstart = s.loopbeg; - q->loopend = s.loopend; - q->volume = s.volume; - q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4; - - if(s.flags&1) q->flags |= SF_LOOP; - if(s.flags&4) q->flags |= SF_16BITS; - if(mh->fileformat==1) q->flags |= SF_SIGNED; - - /* DON'T load sample if it doesn't have the SCRS tag */ - if(memcmp(s.scrs,"SCRS",4)!=0) q->length = 0; - - q++; - } - - /* ==================================== */ - /* Determine the number of channels actually used. (what ever happened */ - /* to the concept of a single "numchn" variable, eh?! */ - - of.numchn = 0; - memset(remap,-1,32*sizeof(UBYTE)); - - for(t=0; tchannels[t]<16) && (remap[t]!=-1)) - { if(mh->channels[t]<8) - of.panning[remap[t]] = 0x20; /* 0x30 = std s3m val */ - else - of.panning[remap[t]] = 0xd0; /* 0xc0 = std s3m val */ - } - } - - if(mh->pantable==252) - { /* set panning positions according to panning table (new for st3.2) */ - for(t=0; t<32; t++) - { if((pan[t]&0x20) && (mh->channels[t]<16) && (remap[t]!=-1)) - of.panning[remap[t]] = (pan[t]&0xf)<<4; - } - } - - - /* ============================== */ - /* Load the pattern info now! */ - - of.numtrk = of.numpat*of.numchn; - if(!AllocTracks()) return 0; - if(!AllocPatterns()) return 0; - - for(t=0; tsongname,28,modreader); + mh->t1a =_mm_read_UBYTE(modreader); + mh->type =_mm_read_UBYTE(modreader); + _mm_read_UBYTES(mh->unused1,2,modreader); + mh->ordnum =_mm_read_I_UWORD(modreader); + mh->insnum =_mm_read_I_UWORD(modreader); + mh->patnum =_mm_read_I_UWORD(modreader); + mh->flags =_mm_read_I_UWORD(modreader); + mh->tracker =_mm_read_I_UWORD(modreader); + mh->fileformat =_mm_read_I_UWORD(modreader); + _mm_read_string(mh->scrm,4,modreader); + mh->mastervol =_mm_read_UBYTE(modreader); + mh->initspeed =_mm_read_UBYTE(modreader); + mh->inittempo =_mm_read_UBYTE(modreader); + mh->mastermult =_mm_read_UBYTE(modreader); + mh->ultraclick =_mm_read_UBYTE(modreader); + mh->pantable =_mm_read_UBYTE(modreader); + _mm_read_UBYTES(mh->unused2,8,modreader); + mh->special =_mm_read_I_UWORD(modreader); + _mm_read_UBYTES(mh->channels,32,modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.songname = DupStr(mh->songname,28,0); + of.numpat = mh->patnum; + of.reppos = 0; + of.numins = of.numsmp = mh->insnum; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->mastervol<<1; + of.flags |= UF_ARPMEM; + if((mh->tracker==0x1300)||(mh->flags&64)) + of.flags|=UF_S3MSLIDES; + + /* read the order data */ + if(!AllocPositions(mh->ordnum)) return 0; + if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0; + + for(t=0;tordnum;t++) { + origpositions[t]=_mm_read_UBYTE(modreader); + if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254)) + origpositions[t]=255/*mh->patnum-1*/; + } + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + poslookupcnt=mh->ordnum; + S3MIT_CreateOrders(curious); + + if(!(paraptr=(UWORD*)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD)))) + return 0; + + /* read the instrument+pattern parapointers */ + _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader); + + if(mh->pantable==252) { + /* read the panning table (ST 3.2 addition. See below for further + portions of channel panning [past reampper]). */ + _mm_read_UBYTES(pan,32,modreader); + } + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* load samples */ + if(!AllocSamples()) return 0; + q = of.samples; + for(t=0;tsamplename = DupStr(s.sampname,28,0); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopbeg>s.length?s.length:s.loopbeg; + q->loopend = s.loopend>s.length?s.length:s.loopend; + q->volume = s.volume; + q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4; + + if(s.flags&1) q->flags |= SF_LOOP; + if(s.flags&4) q->flags |= SF_16BITS; + if(mh->fileformat==1) q->flags |= SF_SIGNED; + + /* don't load sample if it doesn't have the SCRS tag */ + if(memcmp(s.scrs,"SCRS",4)) q->length = 0; + + q++; + } + + /* determine the number of channels actually used. */ + of.numchn = 0; + memset(remap,-1,32*sizeof(UBYTE)); + for(t=0;ttracker>>12; + if((!t)||(t>3)) + t=NUMTRACKERS-1; /* unknown tracker */ + else { + if(mh->tracker>=0x3217) + t=NUMTRACKERS+1; /* IT 2.14p4 */ + else if(mh->tracker>=0x3216) + t=NUMTRACKERS; /* IT 2.14p3 */ + else t--; + } + of.modtype = strdup(S3M_Version[t]); + if(ttracker>>8) &0xf)+'0'; + of.modtype[numeric[t]+2] = ((mh->tracker>>4)&0xf)+'0'; + of.modtype[numeric[t]+3] = ((mh->tracker)&0xf)+'0'; + } + + /* build the remap array */ + for(t=0;t<32;t++) + if(!remap[t]) + remap[t]=of.numchn++; + + /* set panning positions after building remap chart! */ + for(t=0;t<32;t++) + if((mh->channels[t]<32)&&(remap[t]!=-1)) { + if(mh->channels[t]<8) + of.panning[remap[t]]=0x20; /* 0x30 = std s3m val */ + else + of.panning[remap[t]]=0xd0; /* 0xc0 = std s3m val */ + } + if(mh->pantable==252) + /* set panning positions according to panning table (new for st3.2) */ + for(t=0;t<32;t++) + if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1)) + of.panning[remap[t]]=(pan[t]&0xf)<<4; + + /* load pattern info */ + of.numtrk=of.numpat*of.numchn; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + for(t=0;t -#include "mikmod.h" - -/************************************************************************** -**************************************************************************/ - - -typedef struct XMHEADER -{ CHAR id[17]; /* ID text: 'Extended module: ' */ - CHAR songname[21]; /* Module name, padded with zeroes and 0x1a at the end */ - CHAR trackername[20]; /* Tracker name */ - UWORD version; /* (word) Version number, hi-byte major and low-byte minor */ - ULONG headersize; /* Header size */ - UWORD songlength; /* (word) Song length (in patten order table) */ - UWORD restart; /* (word) Restart position */ - UWORD numchn; /* (word) Number of channels (2,4,6,8,10,...,32) */ - UWORD numpat; /* (word) Number of patterns (max 256) */ - UWORD numins; /* (word) Number of instruments (max 128) */ - UWORD flags; /* (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table */ - UWORD tempo; /* (word) Default tempo */ - UWORD bpm; /* (word) Default BPM */ - UBYTE orders[256]; /* (byte) Pattern order table */ -} XMHEADER; +#include "mikmod_internals.h" + +/*========== Module structure */ + +typedef struct XMHEADER { + CHAR id[17]; /* ID text: 'Extended module: ' */ + CHAR songname[21]; /* Module name */ + CHAR trackername[20]; /* Tracker name */ + UWORD version; /* Version number */ + ULONG headersize; /* Header size */ + UWORD songlength; /* Song length (in patten order table) */ + UWORD restart; /* Restart position */ + UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */ + UWORD numpat; /* Number of patterns (max 256) */ + UWORD numins; /* Number of instruments (max 128) */ + UWORD flags; + UWORD tempo; /* Default tempo */ + UWORD bpm; /* Default BPM */ + UBYTE orders[256]; /* Pattern order table */ +} XMHEADER; -typedef struct XMINSTHEADER -{ ULONG size; /* (dword) Instrument size */ - CHAR name[22]; /* (char) Instrument name */ - UBYTE type; /* (byte) Instrument type (always 0) */ - UWORD numsmp; /* (word) Number of samples in instrument */ - ULONG ssize; /* */ +typedef struct XMINSTHEADER { + ULONG size; /* Instrument size */ + CHAR name[22]; /* Instrument name */ + UBYTE type; /* Instrument type (always 0) */ + UWORD numsmp; /* Number of samples in instrument */ + ULONG ssize; } XMINSTHEADER; - -typedef struct XMPATCHHEADER -{ UBYTE what[96]; /* (byte) Sample number for all notes */ - UWORD volenv[24]; /* (byte) Points for volume envelope */ - UWORD panenv[24]; /* (byte) Points for panning envelope */ - UBYTE volpts; /* (byte) Number of volume points */ - UBYTE panpts; /* (byte) Number of panning points */ - UBYTE volsus; /* (byte) Volume sustain point */ - UBYTE volbeg; /* (byte) Volume loop start point */ - UBYTE volend; /* (byte) Volume loop end point */ - UBYTE pansus; /* (byte) Panning sustain point */ - UBYTE panbeg; /* (byte) Panning loop start point */ - UBYTE panend; /* (byte) Panning loop end point */ - UBYTE volflg; /* (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop */ - UBYTE panflg; /* (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop */ - UBYTE vibflg; /* (byte) Vibrato type */ - UBYTE vibsweep; /* (byte) Vibrato sweep */ - UBYTE vibdepth; /* (byte) Vibrato depth */ - UBYTE vibrate; /* (byte) Vibrato rate */ - UWORD volfade; /* (word) Volume fadeout */ - UWORD reserved[11]; /* (word) Reserved */ +#define XMENVCNT (12*2) +#define XMNOTECNT (8*OCTAVE) +typedef struct XMPATCHHEADER { + UBYTE what[XMNOTECNT]; /* Sample number for all notes */ + UWORD volenv[XMENVCNT]; /* Points for volume envelope */ + UWORD panenv[XMENVCNT]; /* Points for panning envelope */ + UBYTE volpts; /* Number of volume points */ + UBYTE panpts; /* Number of panning points */ + UBYTE volsus; /* Volume sustain point */ + UBYTE volbeg; /* Volume loop start point */ + UBYTE volend; /* Volume loop end point */ + UBYTE pansus; /* Panning sustain point */ + UBYTE panbeg; /* Panning loop start point */ + UBYTE panend; /* Panning loop end point */ + UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */ + UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */ + UBYTE vibflg; /* Vibrato type */ + UBYTE vibsweep; /* Vibrato sweep */ + UBYTE vibdepth; /* Vibrato depth */ + UBYTE vibrate; /* Vibrato rate */ + UWORD volfade; /* Volume fadeout */ } XMPATCHHEADER; - -typedef struct XMWAVHEADER -{ ULONG length; /* (dword) Sample length */ - ULONG loopstart; /* (dword) Sample loop start */ - ULONG looplength; /* (dword) Sample loop length */ - UBYTE volume; /* (byte) Volume */ - SBYTE finetune; /* (byte) Finetune (signed byte -128..+127) */ - UBYTE type; /* (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop, */ - /* 2 = Ping-pong loop; */ - /* 4: 16-bit sampledata */ - UBYTE panning; /* (byte) Panning (0-255) */ - SBYTE relnote; /* (byte) Relative note number (signed byte) */ - UBYTE reserved; /* (byte) Reserved */ - CHAR samplename[22]; /* (char) Sample name */ - - UBYTE vibtype; /* (byte) Vibrato type */ - UBYTE vibsweep; /* (byte) Vibrato sweep */ - UBYTE vibdepth; /* (byte) Vibrato depth */ - UBYTE vibrate; /* (byte) Vibrato rate */ +typedef struct XMWAVHEADER { + ULONG length; /* Sample length */ + ULONG loopstart; /* Sample loop start */ + ULONG looplength; /* Sample loop length */ + UBYTE volume; /* Volume */ + SBYTE finetune; /* Finetune (signed byte -128..+127) */ + UBYTE type; /* Loop type */ + UBYTE panning; /* Panning (0-255) */ + SBYTE relnote; /* Relative note number (signed byte) */ + UBYTE reserved; + CHAR samplename[22]; /* Sample name */ + UBYTE vibtype; /* Vibrato type */ + UBYTE vibsweep; /* Vibrato sweep */ + UBYTE vibdepth; /* Vibrato depth */ + UBYTE vibrate; /* Vibrato rate */ } XMWAVHEADER; - -typedef struct XMPATHEADE -{ ULONG size; /* (dword) Pattern header length */ - UBYTE packing; /* (byte) Packing type (always 0) */ - UWORD numrows; /* (word) Number of rows in pattern (1..256) */ - UWORD packsize; /* (word) Packed patterndata size */ +typedef struct XMPATHEADER { + ULONG size; /* Pattern header length */ + UBYTE packing; /* Packing type (always 0) */ + UWORD numrows; /* Number of rows in pattern (1..256) */ + SWORD packsize; /* Packed patterndata size */ } XMPATHEADER; -typedef struct MTMNOTE -{ UBYTE a,b,c; -} MTMNOTE; +typedef struct XMNOTE { + UBYTE note,ins,vol,eff,dat; +} XMNOTE; +/*========== Loader variables */ -typedef struct XMNOTE -{ UBYTE note,ins,vol,eff,dat; -}XMNOTE; +static XMNOTE *xmpat=NULL; +static XMHEADER *mh=NULL; -/************************************************************************** -**************************************************************************/ +/* increment unit for sample array reallocation */ +#define XM_SMPINCR 64 +static ULONG *nextwav=NULL; +static XMWAVHEADER *wh=NULL,*s=NULL; -static XMNOTE *xmpat = NULL; -static XMHEADER *mh = NULL; +/*========== Loader code */ BOOL XM_Test(void) { - UBYTE id[17]; - - if(!_mm_read_UBYTES(id,17,modfp)) return 0; - if(!memcmp(id,"Extended Module: ",17)) return 1; - return 0; -} + UBYTE id[38]; + if(!_mm_read_UBYTES(id,38,modreader)) return 0; + if(memcmp(id,"Extended Module: ",17)) return 0; + if(id[37]==0x1a) return 1; + return 0; +} BOOL XM_Init(void) { - if(!(mh=(XMHEADER *)_mm_calloc(1,sizeof(XMHEADER)))) return 0; - return 1; + if(!(mh=(XMHEADER *)_mm_malloc(sizeof(XMHEADER)))) return 0; + return 1; } - void XM_Cleanup(void) { - if(mh!=NULL) free(mh); - mh = NULL; + _mm_free(mh); } - -void XM_ReadNote(XMNOTE *n) +static int XM_ReadNote(XMNOTE* n) { - UBYTE cmp; - - memset(n,0,sizeof(XMNOTE)); - - cmp = _mm_read_UBYTE(modfp); - - if(cmp&0x80) - { if(cmp&1) n->note = _mm_read_UBYTE(modfp); - if(cmp&2) n->ins = _mm_read_UBYTE(modfp); - if(cmp&4) n->vol = _mm_read_UBYTE(modfp); - if(cmp&8) n->eff = _mm_read_UBYTE(modfp); - if(cmp&16) n->dat = _mm_read_UBYTE(modfp); - } - else - { n->note = cmp; - n->ins = _mm_read_UBYTE(modfp); - n->vol = _mm_read_UBYTE(modfp); - n->eff = _mm_read_UBYTE(modfp); - n->dat = _mm_read_UBYTE(modfp); - } + UBYTE cmp,result=1; + + memset(n,0,sizeof(XMNOTE)); + cmp=_mm_read_UBYTE(modreader); + + if(cmp&0x80) { + if(cmp&1) { result++;n->note = _mm_read_UBYTE(modreader); } + if(cmp&2) { result++;n->ins = _mm_read_UBYTE(modreader); } + if(cmp&4) { result++;n->vol = _mm_read_UBYTE(modreader); } + if(cmp&8) { result++;n->eff = _mm_read_UBYTE(modreader); } + if(cmp&16) { result++;n->dat = _mm_read_UBYTE(modreader); } + } else { + n->note = cmp; + n->ins = _mm_read_UBYTE(modreader); + n->vol = _mm_read_UBYTE(modreader); + n->eff = _mm_read_UBYTE(modreader); + n->dat = _mm_read_UBYTE(modreader); + result += 4; + } + return result; } - -UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows) +static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows) { - int t; - UBYTE note,ins,vol,eff,dat; - - UniReset(); - - for(t=0; tnote; - ins = xmtrack->ins; - vol = xmtrack->vol; - eff = xmtrack->eff; - dat = xmtrack->dat; - - if(note!=0) - { if(note==97) - { UniWrite(UNI_KEYFADE); - UniWrite(0); - } else - UniNote(note-1); - } - - if(ins!=0) UniInstrument(ins-1); - - switch(vol>>4) - { - case 0x6: /* volslide down */ - if(vol&0xf) - { UniWrite(UNI_XMEFFECTA); - UniWrite(vol&0xf); - } - break; - - case 0x7: /* volslide up */ - if(vol&0xf) - { UniWrite(UNI_XMEFFECTA); - UniWrite(vol<<4); - } - break; - - /* volume-row fine volume slide is compatible with protracker */ - /* EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as */ - /* opposed to 'take the last sliding value'. */ - - case 0x8: /* finevol down */ - UniPTEffect(0xe,0xb0 | (vol&0xf)); - break; - - case 0x9: /* finevol up */ - UniPTEffect(0xe,0xa0 | (vol&0xf)); - break; - - case 0xa: /* set vibrato speed */ - UniPTEffect(0x4,vol<<4); - break; - - case 0xb: /* vibrato */ - UniPTEffect(0x4,vol&0xf); - break; - - case 0xc: /* set panning */ - UniPTEffect(0x8,vol<<4); - break; - - case 0xd: /* panning slide left */ - /* only slide when data nibble not zero: */ - - if(vol&0xf) - { UniWrite(UNI_XMEFFECTP); - UniWrite(vol&0xf); - } - break; - - case 0xe: /* panning slide right */ - /* only slide when data nibble not zero: */ - - if(vol&0xf) - { UniWrite(UNI_XMEFFECTP); - UniWrite(vol<<4); - } - break; - - case 0xf: /* tone porta */ - UniPTEffect(0x3,vol<<4); - break; - - default: - if(vol>=0x10 && vol<=0x50) - UniPTEffect(0xc,vol-0x10); - } - - switch(eff) - { - case 0x4: /* Effect 4: Vibrato */ - UniWrite(UNI_XMEFFECT4); - UniWrite(dat); - break; - - case 0xa: - UniWrite(UNI_XMEFFECTA); - UniWrite(dat); - break; - - case 0xe: - switch(dat>>4) - { case 0x1: /* XM fine porta up */ - UniWrite(UNI_XMEFFECTE1); - UniWrite(dat&0xf); - break; - - case 0x2: /* XM fine porta down */ - UniWrite(UNI_XMEFFECTE2); - UniWrite(dat&0xf); - break; - - case 0xa: /* XM fine volume up */ - UniWrite(UNI_XMEFFECTEA); - UniWrite(dat&0xf); - break; - - case 0xb: /* XM fine volume down */ - UniWrite(UNI_XMEFFECTEB); - UniWrite(dat&0xf); - break; - - default: - UniPTEffect(0x0e,dat); - } - break; - - case 'G'-55: /* G - set global volume */ - if(dat>64) dat = 64; - UniWrite(UNI_XMEFFECTG); - UniWrite(dat); - break; - - case 'H'-55: /* H - global volume slide */ - UniWrite(UNI_XMEFFECTH); - UniWrite(dat); - break; - - case 'K'-55: /* K - keyOff and KeyFade */ - UniWrite(UNI_KEYFADE); - UniWrite(dat); - break; - - case 'L'-55: /* L - set envelope position */ - UniWrite(UNI_XMEFFECTL); - UniWrite(dat); - break; - - case 'P'-55: /* P - panning slide */ - UniWrite(UNI_XMEFFECTP); - UniWrite(dat); - break; - - case 'R'-55: /* R - multi retrig note */ - UniWrite(UNI_S3MEFFECTQ); - UniWrite(dat); - break; - - case 'T'-55: /* T - Tremor !! (== S3M effect I) */ - UniWrite(UNI_S3MEFFECTI); - UniWrite(dat); - break; - - case 'X'-55: - if((dat>>4) == 1) /* X1 - Extra Fine Porta up */ - { UniWrite(UNI_XMEFFECTX1); - UniWrite(dat & 0xf); - } else if((dat>>4) == 2) /* X2 - Extra Fine Porta down */ - { UniWrite(UNI_XMEFFECTX2); - UniWrite(dat & 0xf); - } - break; - - default: - if(eff <= 0xf) - { /* Convert pattern jump from Dec to Hex */ - if(eff == 0xd) - dat = (((dat&0xf0)>>4)*10)+(dat&0xf); - UniPTEffect(eff,dat); - } - break; - } - - UniNewline(); - xmtrack++; - } - return UniDup(); + int t; + UBYTE note,ins,vol,eff,dat; + + UniReset(); + for(t=0;tnote; + ins = xmtrack->ins; + vol = xmtrack->vol; + eff = xmtrack->eff; + dat = xmtrack->dat; + + if(note) { + if(note>XMNOTECNT) + UniEffect(UNI_KEYFADE,0); + else + UniNote(note-1); + } + if(ins) UniInstrument(ins-1); + + switch(vol>>4) { + case 0x6: /* volslide down */ + if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf); + break; + case 0x7: /* volslide up */ + if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4); + break; + + /* volume-row fine volume slide is compatible with protracker + EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as + opposed to 'take the last sliding value'. */ + case 0x8: /* finevol down */ + UniPTEffect(0xe,0xb0|(vol&0xf)); + break; + case 0x9: /* finevol up */ + UniPTEffect(0xe,0xa0|(vol&0xf)); + break; + case 0xa: /* set vibrato speed */ + UniPTEffect(0x4,vol<<4); + break; + case 0xb: /* vibrato */ + UniPTEffect(0x4,vol&0xf); + break; + case 0xc: /* set panning */ + UniPTEffect(0x8,vol<<4); + break; + case 0xd: /* panning slide left (only slide when data not zero) */ + if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf); + break; + case 0xe: /* panning slide right (only slide when data not zero) */ + if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4); + break; + case 0xf: /* tone porta */ + UniPTEffect(0x3,vol<<4); + break; + default: + if((vol>=0x10)&&(vol<=0x50)) + UniPTEffect(0xc,vol-0x10); + } + + switch(eff) { + case 0x4: + UniEffect(UNI_XMEFFECT4,dat); + break; + case 0xa: + UniEffect(UNI_XMEFFECTA,dat); + break; + case 0xe: /* Extended effects */ + switch(dat>>4) { + case 0x1: /* XM fine porta up */ + UniEffect(UNI_XMEFFECTE1,dat&0xf); + break; + case 0x2: /* XM fine porta down */ + UniEffect(UNI_XMEFFECTE2,dat&0xf); + break; + case 0xa: /* XM fine volume up */ + UniEffect(UNI_XMEFFECTEA,dat&0xf); + break; + case 0xb: /* XM fine volume down */ + UniEffect(UNI_XMEFFECTEB,dat&0xf); + break; + default: + UniPTEffect(eff,dat); + } + break; + case 'G'-55: /* G - set global volume */ + UniEffect(UNI_XMEFFECTG,dat>64?64:dat); + break; + case 'H'-55: /* H - global volume slide */ + UniEffect(UNI_XMEFFECTH,dat); + break; + case 'K'-55: /* K - keyOff and KeyFade */ + UniEffect(UNI_KEYFADE,dat); + break; + case 'L'-55: /* L - set envelope position */ + UniEffect(UNI_XMEFFECTL,dat); + break; + case 'P'-55: /* P - panning slide */ + UniEffect(UNI_XMEFFECTP,dat); + break; + case 'R'-55: /* R - multi retrig note */ + UniEffect(UNI_S3MEFFECTQ,dat); + break; + case 'T'-55: /* T - Tremor */ + UniEffect(UNI_S3MEFFECTI,dat); + break; + case 'X'-55: + switch(dat>>4) { + case 1: /* X1 - Extra Fine Porta up */ + UniEffect(UNI_XMEFFECTX1,dat&0xf); + break; + case 2: /* X2 - Extra Fine Porta down */ + UniEffect(UNI_XMEFFECTX2,dat&0xf); + break; + } + break; + default: + if(eff<=0xf) { + /* the pattern jump destination is written in decimal, + but it seems some poor tracker software writes them + in hexadecimal... (sigh) */ + if (eff==0xd) + /* don't change anything if we're sure it's in hexa */ + if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9)) + /* otherwise, convert from dec to hex */ + dat=(((dat&0xf0)>>4)*10)+(dat&0xf); + UniPTEffect(eff,dat); + } + break; + } + UniNewline(); + xmtrack++; + } + return UniDup(); } - - -BOOL XM_Load(void) +static BOOL LoadPatterns(BOOL dummypat) { - INSTRUMENT *d; - SAMPLE *q; - XMWAVHEADER *wh,*s; - int t,u,v,p,numtrk; - long next; - ULONG nextwav[256]; - BOOL dummypat=0; - - /* try to read module header */ - - _mm_read_string(mh->id,17,modfp); - _mm_read_string(mh->songname,21,modfp); - _mm_read_string(mh->trackername,20,modfp); - mh->version =_mm_read_I_UWORD(modfp); - mh->headersize =_mm_read_I_ULONG(modfp); - mh->songlength =_mm_read_I_UWORD(modfp); - mh->restart =_mm_read_I_UWORD(modfp); - mh->numchn =_mm_read_I_UWORD(modfp); - mh->numpat =_mm_read_I_UWORD(modfp); - mh->numins =_mm_read_I_UWORD(modfp); - mh->flags =_mm_read_I_UWORD(modfp); - mh->tempo =_mm_read_I_UWORD(modfp); - mh->bpm =_mm_read_I_UWORD(modfp); - _mm_read_UBYTES(mh->orders,256,modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_HEADER; - return 0; - } - - /* set module variables */ - of.initspeed = mh->tempo; - of.inittempo = mh->bpm; - of.modtype = DupStr(mh->trackername,20); - of.numchn = mh->numchn; - of.numpat = mh->numpat; - of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */ - of.songname = DupStr(mh->songname,20); /* make a cstr of songname */ - of.numpos = mh->songlength; /* copy the songlength */ - of.reppos = mh->restart; - of.numins = mh->numins; - of.flags |= UF_XMPERIODS | UF_INST; - if(mh->flags&1) of.flags |= UF_LINEAR; - - memset(of.chanvol,64,of.numchn); /* store channel volumes */ - - if(!AllocPositions(of.numpos+3)) return 0; - for(t=0; torders[t]; - -/* - WHY THIS CODE HERE?? I CAN'T REMEMBER! - - Well, I do know why, mikmak! Seems that FT2 doesn't always count blank - patterns AT ALL if they are at the END of the song. So, we have to check - for any patter numbers in the order list greater than the number of pat- - terns total. If one or more is found, we set it equal to the pattern total - and make a dummy pattern to accomidate for the discrepency! -*/ - - for(t=0; t of.numpat) - { of.positions[t] = of.numpat; - dummypat = 1; - } - } - - if(dummypat) { of.numpat++; of.numtrk+=of.numchn; } - - if(!AllocTracks()) return 0; - if(!AllocPatterns()) return 0; - - numtrk = 0; - for(t=0; tnumpat; t++) - { XMPATHEADER ph; - - ph.size =_mm_read_I_ULONG(modfp); - ph.packing =_mm_read_UBYTE(modfp); - ph.numrows =_mm_read_I_UWORD(modfp); - ph.packsize =_mm_read_I_UWORD(modfp); - - of.pattrows[t] = ph.numrows; - - /* Gr8.. when packsize is 0, don't try to load a pattern.. it's empty. */ - /* This bug was discovered thanks to Khyron's module.. */ - - if(!(xmpat=(XMNOTE *)_mm_calloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0; - - if(ph.packsize>0) - { for(u=0; usamplenumber,255,120); - - /* read instrument header */ - - headend = _mm_ftell(modfp); - ih.size = _mm_read_I_ULONG(modfp); - headend += ih.size; - _mm_read_string(ih.name, 22, modfp); - ih.type = _mm_read_UBYTE(modfp); - ih.numsmp = _mm_read_I_UWORD(modfp); - d->insname = DupStr(ih.name,22); - - if(ih.size > 29) - { ih.ssize = _mm_read_I_ULONG(modfp); - if(ih.numsmp > 0) - { XMPATCHHEADER pth; - - _mm_read_UBYTES (pth.what, 96, modfp); - _mm_read_I_UWORDS (pth.volenv, 24, modfp); - _mm_read_I_UWORDS (pth.panenv, 24, modfp); - pth.volpts = _mm_read_UBYTE(modfp); - pth.panpts = _mm_read_UBYTE(modfp); - pth.volsus = _mm_read_UBYTE(modfp); - pth.volbeg = _mm_read_UBYTE(modfp); - pth.volend = _mm_read_UBYTE(modfp); - pth.pansus = _mm_read_UBYTE(modfp); - pth.panbeg = _mm_read_UBYTE(modfp); - pth.panend = _mm_read_UBYTE(modfp); - pth.volflg = _mm_read_UBYTE(modfp); - pth.panflg = _mm_read_UBYTE(modfp); - pth.vibflg = _mm_read_UBYTE(modfp); - pth.vibsweep = _mm_read_UBYTE(modfp); - pth.vibdepth = _mm_read_UBYTE(modfp); - pth.vibrate = _mm_read_UBYTE(modfp); - pth.volfade = _mm_read_I_UWORD(modfp); - - /* read the remainder of the header */ - for(u=headend-_mm_ftell(modfp); u; u--) _mm_read_UBYTE(modfp); - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_SAMPLEINFO; - return 0; - } - - for(u=0; u<96; u++) - d->samplenumber[u] = pth.what[u] + of.numsmp; - - d->volfade = pth.volfade; - - memcpy(d->volenv,pth.volenv,24); - if(pth.volflg & 1) d->volflg |= EF_ON; - if(pth.volflg & 2) d->volflg |= EF_SUSTAIN; - if(pth.volflg & 4) d->volflg |= EF_LOOP; - d->volsusbeg = d->volsusend = pth.volsus; - d->volbeg = pth.volbeg; - d->volend = pth.volend; - d->volpts = pth.volpts; - - /* scale volume envelope: */ - - for(p=0; p<12; p++) - d->volenv[p].val <<= 2; - - if((d->volflg & EF_ON) && (d->volpts < 2)) - d->volflg &= ~EF_ON; - - memcpy(d->panenv,pth.panenv,24); - d->panflg = pth.panflg; - d->pansusbeg = d->pansusend = pth.pansus; - d->panbeg = pth.panbeg; - d->panend = pth.panend; - d->panpts = pth.panpts; - - /* scale panning envelope: */ - - for(p=0; p<12; p++) - d->panenv[p].val <<= 2; - if((d->panflg & EF_ON) && (d->panpts < 2)) - d->panflg &= ~EF_ON; - - next = 0; - - /* Samples are stored outside the instrument struct now, so we have */ - /* to load them all into a temp area, count the of.numsmp along the */ - /* way and then do an AllocSamples() and move everything over */ - - for(u=0; ulength =_mm_read_I_ULONG (modfp); - s->loopstart =_mm_read_I_ULONG (modfp); - s->looplength =_mm_read_I_ULONG (modfp); - s->volume =_mm_read_UBYTE (modfp); - s->finetune =_mm_read_SBYTE (modfp); - s->type =_mm_read_UBYTE (modfp); - s->panning =_mm_read_UBYTE (modfp); - s->relnote =_mm_read_SBYTE (modfp); - s->vibtype = pth.vibflg; - s->vibsweep = pth.vibsweep; - s->vibdepth = pth.vibdepth*4; - s->vibrate = pth.vibrate; - - s->reserved =_mm_read_UBYTE (modfp); - _mm_read_string(s->samplename, 22, modfp); - - nextwav[of.numsmp+u] = next; - next += s->length; - - if(feof(modfp)) - { _mm_errno = MMERR_LOADING_SAMPLEINFO; - return 0; - } - } - - for(u=0; usamplename = DupStr(s->samplename,22); - q->length = s->length; - q->loopstart = s->loopstart; - q->loopend = s->loopstart+s->looplength; - q->volume = s->volume; - q->speed = s->finetune+128; - q->panning = s->panning; - q->seekpos = nextwav[u]; - q->vibtype = s->vibtype; - q->vibsweep = s->vibsweep; - q->vibdepth = s->vibdepth; - q->vibrate = s->vibrate; - - if(s->type & 0x10) - { q->length >>= 1; - q->loopstart >>= 1; - q->loopend >>= 1; - } - - q->flags|=SF_OWNPAN; - if(s->type&0x3) q->flags|=SF_LOOP; - if(s->type&0x2) q->flags|=SF_BIDI; - - if(s->type&0x10) q->flags|=SF_16BITS; - q->flags|=SF_DELTA; - q->flags|=SF_SIGNED; - } - - d = of.instruments; - s = wh; - for(u=0; usamplenumber[t]].relnote / 12) > ) - { s[d->samplenumber[t]].relnote -= 12; - of.samples[d->samplenumber[t]].speed <<= 1; - } - */ - for(t=0; t<96; t++) - d->samplenote[t] = (d->samplenumber[t]==of.numsmp) ? 255 : (t+s[d->samplenumber[t]].relnote); - } - - free(wh); - return 1; + int t,u,v,numtrk; + + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + numtrk=0; + for(t=0;tnumpat;t++) { + XMPATHEADER ph; + + ph.size =_mm_read_I_ULONG(modreader); + if (ph.size<(mh->version==0x0102?8:9)) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + ph.packing =_mm_read_UBYTE(modreader); + if(ph.packing) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + if(mh->version==0x0102) + ph.numrows =_mm_read_UBYTE(modreader)+1; + else + ph.numrows =_mm_read_I_UWORD(modreader); + ph.packsize =_mm_read_I_UWORD(modreader); + + ph.size-=(mh->version==0x0102?8:9); + if(ph.size) + _mm_fseek(modreader,ph.size,SEEK_CUR); + + of.pattrows[t]=ph.numrows; + + if(ph.numrows) { + if(!(xmpat=(XMNOTE*)_mm_calloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) + return 0; + + /* when packsize is 0, don't try to load a pattern.. it's empty. */ + if(ph.packsize) + for(u=0;usamplenumber,0xff,INSTNOTES*sizeof(UWORD)); + + /* read instrument header */ + headend = _mm_ftell(modreader); + ih.size = _mm_read_I_ULONG(modreader); + headend += ih.size; + _mm_read_string(ih.name, 22, modreader); + ih.type = _mm_read_UBYTE(modreader); + ih.numsmp = _mm_read_I_UWORD(modreader); + + d->insname = DupStr(ih.name,22,1); + + if((SWORD)ih.size>29) { + ih.ssize = _mm_read_I_ULONG(modreader); + if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) { + XMPATCHHEADER pth; + int p; + + _mm_read_UBYTES (pth.what,XMNOTECNT,modreader); + _mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader); + _mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader); + pth.volpts = _mm_read_UBYTE(modreader); + pth.panpts = _mm_read_UBYTE(modreader); + pth.volsus = _mm_read_UBYTE(modreader); + pth.volbeg = _mm_read_UBYTE(modreader); + pth.volend = _mm_read_UBYTE(modreader); + pth.pansus = _mm_read_UBYTE(modreader); + pth.panbeg = _mm_read_UBYTE(modreader); + pth.panend = _mm_read_UBYTE(modreader); + pth.volflg = _mm_read_UBYTE(modreader); + pth.panflg = _mm_read_UBYTE(modreader); + pth.vibflg = _mm_read_UBYTE(modreader); + pth.vibsweep = _mm_read_UBYTE(modreader); + pth.vibdepth = _mm_read_UBYTE(modreader); + pth.vibrate = _mm_read_UBYTE(modreader); + pth.volfade = _mm_read_I_UWORD(modreader); + + /* read the remainder of the header + (2 bytes for 1.03, 22 for 1.04) */ + for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader); + + /* #@!$&% fix for K_OSPACE.XM */ + if(pth.volpts==32) pth.volpts=XMENVCNT/2; + + if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) { + if(nextwav) { free(nextwav);nextwav=NULL; } + if(wh) { free(wh);wh=NULL; } + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + for(u=0;usamplenumber[u]=pth.what[u]+of.numsmp; + d->volfade = pth.volfade; + +#ifdef __STDC__ +#define XM_ProcessEnvelope(name) \ + memcpy(d->##name##env,pth.##name##env,XMENVCNT); \ + if (pth.##name##flg&1) d->##name##flg|=EF_ON; \ + if (pth.##name##flg&2) d->##name##flg|=EF_SUSTAIN; \ + if (pth.##name##flg&4) d->##name##flg|=EF_LOOP; \ + d->##name##susbeg=d->##name##susend=pth.##name##sus; \ + d->##name##beg=pth.##name##beg; \ + d->##name##end=pth.##name##end; \ + d->##name##pts=pth.##name##pts; \ + \ + /* scale envelope */ \ + for (p=0;p##name##env[p].val<<=2; \ + \ + if ((d->##name##flg&EF_ON)&&(d->##name##pts<2)) \ + d->##name##flg&=~EF_ON; +#else +#define XM_ProcessEnvelope(name) \ + memcpy(d->/**/name/**/env,pth./**/name/**/env,XMENVCNT); \ + if (pth./**/name/**/flg&1) d->/**/name/**/flg|=EF_ON; \ + if (pth./**/name/**/flg&2) d->/**/name/**/flg|=EF_SUSTAIN; \ + if (pth./**/name/**/flg&4) d->/**/name/**/flg|=EF_LOOP; \ + d->/**/name/**/susbeg=d->/**/name/**/susend= \ + pth./**/name/**/sus; \ + d->/**/name/**/beg=pth./**/name/**/beg; \ + d->/**/name/**/end=pth./**/name/**/end; \ + d->/**/name/**/pts=pth./**/name/**/pts; \ + \ + /* scale envelope */ \ + for (p=0;p/**/name/**/env[p].val<<=2; \ + \ + if ((d->/**/name/**/flg&EF_ON)&&(d->/**/name/**/pts<2)) \ + d->/**/name/**/flg&=~EF_ON; +#endif + + XM_ProcessEnvelope(vol); + XM_ProcessEnvelope(pan); +#undef XM_ProcessEnvelope + + /* Samples are stored outside the instrument struct now, so we + have to load them all into a temp area, count the of.numsmp + along the way and then do an AllocSamples() and move + everything over */ + if(mh->version>0x0103) next = 0; + for(u=0;ulength =_mm_read_I_ULONG (modreader); + s->loopstart =_mm_read_I_ULONG (modreader); + s->looplength =_mm_read_I_ULONG (modreader); + s->volume =_mm_read_UBYTE (modreader); + s->finetune =_mm_read_SBYTE (modreader); + s->type =_mm_read_UBYTE (modreader); + s->panning =_mm_read_UBYTE (modreader); + s->relnote =_mm_read_SBYTE (modreader); + s->vibtype = pth.vibflg; + s->vibsweep = pth.vibsweep; + s->vibdepth = pth.vibdepth*4; + s->vibrate = pth.vibrate; + s->reserved =_mm_read_UBYTE (modreader); + _mm_read_string(s->samplename, 22, modreader); + + nextwav[of.numsmp+u]=next; + next+=s->length; + + if(_mm_eof(modreader)) { + free(nextwav);free(wh); + nextwav=NULL;wh=NULL; + _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + + if(mh->version>0x0103) { + for(u=0;uid,17,modreader); + _mm_read_string(mh->songname,21,modreader); + _mm_read_string(mh->trackername,20,modreader); + mh->version =_mm_read_I_UWORD(modreader); + if((mh->version<0x102)||(mh->version>0x104)) { + _mm_errno=MMERR_NOT_A_MODULE; + return 0; + } + mh->headersize =_mm_read_I_ULONG(modreader); + mh->songlength =_mm_read_I_UWORD(modreader); + mh->restart =_mm_read_I_UWORD(modreader); + mh->numchn =_mm_read_I_UWORD(modreader); + mh->numpat =_mm_read_I_UWORD(modreader); + mh->numins =_mm_read_I_UWORD(modreader); + mh->flags =_mm_read_I_UWORD(modreader); + mh->tempo =_mm_read_I_UWORD(modreader); + mh->bpm =_mm_read_I_UWORD(modreader); + if(!mh->bpm) { + _mm_errno=MMERR_NOT_A_MODULE; + return 0; + } + _mm_read_UBYTES(mh->orders,256,modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = mh->tempo; + of.inittempo = mh->bpm; + strncpy(tracker,mh->trackername,20);tracker[20]=0; + for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0; + + /* some modules have the tracker name empty */ + if (!tracker[0]) + strcpy(tracker,"Unknown tracker"); + +#ifdef HAVE_SNPRINTF + snprintf(modtype,60,"%s (XM format %d.%02d)", + tracker,mh->version>>8,mh->version&0xff); +#else + sprintf(modtype,"%s (XM format %d.%02d)", + tracker,mh->version>>8,mh->version&0xff); +#endif + of.modtype = strdup(modtype); + of.numchn = mh->numchn; + of.numpat = mh->numpat; + of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */ + of.songname = DupStr(mh->songname,20,1); + of.numpos = mh->songlength; /* copy the songlength */ + of.reppos = mh->restartsonglength?mh->restart:0; + of.numins = mh->numins; + of.flags |= UF_XMPERIODS|UF_INST|UF_BGSLIDES|UF_NOWRAP|UF_FT2QUIRKS; + if(mh->flags&1) of.flags |= UF_LINEAR; + + memset(of.chanvol,64,of.numchn); /* store channel volumes */ + + if(!AllocPositions(of.numpos+1)) return 0; + for(t=0;torders[t]; + + /* We have to check for any pattern numbers in the order list greater than + the number of patterns total. If one or more is found, we set it equal to + the pattern total and make a dummy pattern to workaround the problem */ + for(t=0;t=of.numpat) { + of.positions[t]=of.numpat; + dummypat=1; + } + } + if(dummypat) { + of.numpat++;of.numtrk+=of.numchn; + } + + if(mh->version<0x0104) { + if(!LoadInstruments()) return 0; + if(!LoadPatterns(dummypat)) return 0; + for(t=0;tsamplename = DupStr(s->samplename,22,1); + q->length = s->length; + q->loopstart = s->loopstart; + q->loopend = s->loopstart+s->looplength; + q->volume = s->volume; + q->speed = s->finetune+128; + q->panning = s->panning; + q->seekpos = nextwav[u]; + q->vibtype = s->vibtype; + q->vibsweep = s->vibsweep; + q->vibdepth = s->vibdepth; + q->vibrate = s->vibrate; + + if(s->type & 0x10) { + q->length >>= 1; + q->loopstart >>= 1; + q->loopend >>= 1; + } + + q->flags|=SF_OWNPAN; + if(s->type&0x3) q->flags|=SF_LOOP; + if(s->type&0x2) q->flags|=SF_BIDI; + if(s->type&0x10) q->flags|=SF_16BITS; + q->flags|=SF_DELTA|SF_SIGNED; + } + + d=of.instruments; + s=wh; + for(u=0;usamplenumber[t]>=of.numsmp) + d->samplenote[t]=255; + else { + int note=t+s[d->samplenumber[t]].relnote; + d->samplenote[t]=(note<0)?0:note; + } + } + + free(wh);free(nextwav); + wh=NULL;nextwav=NULL; + return 1; +} CHAR *XM_LoadTitle(void) { - CHAR s[21]; - - _mm_fseek(modfp,17,SEEK_SET); - if(!fread(s,21,1,modfp)) return NULL; - - return(DupStr(s,21)); -} + CHAR s[21]; + _mm_fseek(modreader,17,SEEK_SET); + if(!_mm_read_UBYTES(s,21,modreader)) return NULL; + return(DupStr(s,21,1)); +} -MLOADER load_xm = -{ NULL, - "XM", - "Portable XM loader v0.5", - XM_Init, - XM_Test, - XM_Load, - XM_Cleanup, - XM_LoadTitle +/*========== Loader information */ + +MLOADER load_xm={ + NULL, + "XM", + "XM (FastTracker 2)", + XM_Init, + XM_Test, + XM_Load, + XM_Cleanup, + XM_LoadTitle }; + +/* ex:set ts=4: */ diff --git a/mikmod/mdreg.c b/mikmod/mdreg.c index ef01d60f..bbd01349 100644 --- a/mikmod/mdreg.c +++ b/mikmod/mdreg.c @@ -1,31 +1,50 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ - Name: MDREG.C +/*============================================================================== - Description: - A single routine for registering all drivers in MikMod for the current - platform. + $Id$ - Portability: - DOS, WIN95, OS2, SunOS, Solaris, - Linux, HPUX, AIX, SGI, Alpha + Routine for registering all drivers in libmikmod for the current platform. - Anything not listed above is assumed to not be supported by this procedure! +==============================================================================*/ - All Others: n +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif - - all compilers! +#include "mikmod_internals.h" -*/ +MIKMODAPI extern struct MDRIVER drv_sdl; /* Simple Direct Media */ -#include "mikmod.h" +void _mm_registeralldrivers(void) +{ + _mm_registerdriver(&drv_sdl); + _mm_registerdriver(&drv_nos); +} void MikMod_RegisterAllDrivers(void) { - - MikMod_RegisterDriver(drv_sdl); - MikMod_RegisterDriver(drv_nos); - + MUTEX_LOCK(lists); + _mm_registeralldrivers(); + MUTEX_UNLOCK(lists); } - +/* ex:set ts=4: */ diff --git a/mikmod/mdriver.c b/mikmod/mdriver.c index 42afa329..11496fbc 100644 --- a/mikmod/mdriver.c +++ b/mikmod/mdriver.c @@ -1,557 +1,907 @@ -/* - -Name: MDRIVER.C - -Description: -These routines are used to access the available soundcard drivers. - -Portability: -All systems - all compilers - +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ -#include "mikmod.h" +/*============================================================================== -MDRIVER *firstdriver = NULL, *md_driver = &drv_nos; -extern UNIMOD *pf; /* <- this modfile is being played */ + $Id$ -UWORD md_device = 0; -UWORD md_mixfreq = 44100; -UWORD md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND; -UWORD md_dmabufsize = 50; -UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */ + These routines are used to access the available soundcard drivers. -UBYTE md_reverb = 6; /* Reverb */ +==============================================================================*/ -UBYTE md_volume = 96; /* Global sound volume (0-128) */ -UBYTE md_musicvolume = 128; /* volume of song */ -UBYTE md_sndfxvolume = 128; /* volume of sound effects */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -UBYTE md_bpm = 125; +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef unix +#include +#include +#endif -/* Do not modify the numchn variables yourself! use MD_SetVoices() */ - -UBYTE md_numchn = 0, md_sngchn = 0, md_sfxchn = 0; -UBYTE md_hardchn = 0, md_softchn = 0; +#include "mikmod_internals.h" +#include +#ifdef HAVE_STRINGS_H +#include +#endif -void (*md_player)(void) = Player_HandleTick; -static BOOL isplaying = 0, initialized = 0; -static UBYTE *sfxinfo; -static int sfxpool; +static MDRIVER *firstdriver=NULL; + MDRIVER *md_driver=NULL; +extern MODULE *pf; /* modfile being played */ -static SAMPLE **md_sample = NULL; + UWORD md_device = 0; + UWORD md_mixfreq = 44100; + UWORD md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND + |DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX; + UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */ + UBYTE md_reverb = 6; /* Reverb */ + UBYTE md_volume = 128; /* Global sound volume (0-128) */ + UBYTE md_musicvolume = 128; /* volume of song */ + UBYTE md_sndfxvolume = 128; /* volume of sound effects */ + UWORD md_bpm = 125; -/* Backup variables. This way, the end programmer can fiddle with the */ -/* main globals without mikmod blowing up. */ - -static UWORD idevice, imixfreq, imode, idmabufsize; +/* Do not modify the numchn variables yourself! use MD_SetVoices() */ + UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0; + UBYTE md_hardchn=0,md_softchn=0; + void (*md_player)(void) = Player_HandleTick; +static BOOL isplaying=0, initialized = 0; +static UBYTE *sfxinfo; +static int sfxpool; -static void LimitHardVoices(int limit) +static SAMPLE **md_sample = NULL; -/* Limits the number of hardware voices to the specified amount. */ -/* This function should only be used by the low-level drivers. */ +/* Previous driver in use */ +static UWORD idevice; +/* Limits the number of hardware voices to the specified amount. + This function should only be used by the low-level drivers. */ +static void LimitHardVoices(int limit) { - int t = 0; - - if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit; - if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit; - - if(!(md_mode & DMODE_SOFT_SNDFX)) - md_hardchn = md_sfxchn; - else - md_hardchn = 0; - - if(!(md_mode & DMODE_SOFT_MUSIC)) - md_hardchn += md_sngchn; - - while(md_hardchn > limit) - { - if(++t & 1) - if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--; - else - if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--; - - if(!(md_mode & DMODE_SOFT_SNDFX)) - md_hardchn = md_sfxchn; - else - md_hardchn = 0; - - if(!(md_mode & DMODE_SOFT_MUSIC)) - md_hardchn += md_sngchn; - } - - md_numchn = md_hardchn + md_softchn; + int t=0; + + if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit; + if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit; + + if (!(md_mode & DMODE_SOFT_SNDFX)) + md_hardchn=md_sfxchn; + else + md_hardchn=0; + + if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn; + + while (md_hardchn>limit) { + if (++t & 1) { + if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--; + } else { + if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--; + } + + if (!(md_mode & DMODE_SOFT_SNDFX)) + md_hardchn=md_sfxchn; + else + md_hardchn=0; + + if (!(md_mode & DMODE_SOFT_MUSIC)) + md_hardchn+=md_sngchn; + } + md_numchn=md_hardchn+md_softchn; } - -static void LimitSoftVoices(int limit) - -/* Limits the number of hardware voices to the specified amount. */ -/* This function should only be used by the low-level drivers. */ - +/* Limits the number of hardware voices to the specified amount. + This function should only be used by the low-level drivers. */ +static void LimitSoftVoices(int limit) { - int t = 0; - - if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit; - if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit; - - if(md_mode & DMODE_SOFT_SNDFX) - md_softchn = md_sfxchn; - else - md_softchn = 0; - - if(md_mode & DMODE_SOFT_MUSIC) - md_softchn += md_sngchn; - - while(md_softchn > limit) - { - if(++t & 1) - if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--; - else - if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--; - - if(!(md_mode & DMODE_SOFT_SNDFX)) - md_softchn = md_sfxchn; - else - md_softchn = 0; - - if(!(md_mode & DMODE_SOFT_MUSIC)) - md_softchn += md_sngchn; - } - - md_numchn = md_hardchn + md_softchn; + int t=0; + + if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit; + if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit; + + if (md_mode & DMODE_SOFT_SNDFX) + md_softchn=md_sfxchn; + else + md_softchn=0; + + if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn; + + while (md_softchn>limit) { + if (++t & 1) { + if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--; + } else { + if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--; + } + + if (!(md_mode & DMODE_SOFT_SNDFX)) + md_softchn=md_sfxchn; + else + md_softchn=0; + + if (!(md_mode & DMODE_SOFT_MUSIC)) + md_softchn+=md_sngchn; + } + md_numchn=md_hardchn+md_softchn; } - -/* Note: 'type' indicates whether the returned value should be for music */ -/* or for sound effects. */ - +/* Note: 'type' indicates whether the returned value should be for music or for + sound effects. */ ULONG MD_SampleSpace(int type) { - if(type==MD_MUSIC) - type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE; - else if(type==MD_SNDFX) - type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE; + if(type==MD_MUSIC) + type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; + else if(type==MD_SNDFX) + type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; - return md_driver->FreeSampleSpace(type); + return md_driver->FreeSampleSpace(type); } - -ULONG MD_SampleLength(int type, SAMPLE *s) +ULONG MD_SampleLength(int type,SAMPLE* s) { - if(type==MD_MUSIC) - type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE; - else if(type==MD_SNDFX) - type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE; + if(type==MD_MUSIC) + type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; + else + if(type==MD_SNDFX) + type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; - return md_driver->RealSampleLength(type, s); + return md_driver->RealSampleLength(type,s); } +CHAR* MikMod_InfoDriver(void) +{ + int t,len=0; + MDRIVER *l; + CHAR *list=NULL; + + MUTEX_LOCK(lists); + /* compute size of buffer */ + for(l=firstdriver;l;l=l->next) len+=4+(l->next?1:0)+strlen(l->Version); + + if(len) + if((list=_mm_malloc(len*sizeof(CHAR)))) { + list[0]=0; + /* list all registered device drivers : */ + for(t=1,l=firstdriver;l;l=l->next,t++) + sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",list,t,l->Version); + } + MUTEX_UNLOCK(lists); + return list; +} -UWORD MD_SetDMA(int secs) - -/* Converts the given number of 1/10th seconds into the number of bytes of */ -/* audio that a sample # 1/10th seconds long would require at the current md_* */ -/* settings. */ - +void _mm_registerdriver(struct MDRIVER* drv) { - ULONG result; + MDRIVER *cruise = firstdriver; - result = (md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) * - ((md_mode & DMODE_16BITS) ? 2 : 1) * secs) * 10; + if(cruise) { + while(cruise->next) cruise=cruise->next; + cruise->next=drv; + } else + firstdriver = drv; +} - if(result > 32000) result = 32000; - return(md_dmabufsize = (result & ~3)); /* round it off to an 8 byte boundry */ +void MikMod_RegisterDriver(struct MDRIVER* drv) +{ + /* if we try to register an invalid driver, or an already registered driver, + ignore this attempt */ + if ((!drv)||(drv->next)) + return; + + MUTEX_LOCK(lists); + _mm_registerdriver(drv); + MUTEX_UNLOCK(lists); } +int MikMod_DriverFromAlias(CHAR *alias) +{ + int rank=1; + MDRIVER *cruise; + + MUTEX_LOCK(lists); + cruise=firstdriver; + while(cruise) { + if (!(strcasecmp(alias,cruise->Alias))) break; + cruise=cruise->next;rank++; + } + if(!cruise) rank=0; + MUTEX_UNLOCK(lists); + + return rank; +} -void MD_InfoDriver(void) +SWORD MD_SampleLoad(SAMPLOAD* s, int type) { - int t; - MDRIVER *l; + SWORD result; - /* list all registered devicedrivers: */ - for(t=1,l=firstdriver; l!=NULL; l=l->next, t++) - printf("%d. %s\n",t,l->Version); + if(type==MD_MUSIC) + type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; + else if(type==MD_SNDFX) + type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; + + SL_Init(s); + result=md_driver->SampleLoad(s,type); + SL_Exit(s); + + return result; } +void MD_SampleUnload(SWORD handle) +{ + md_driver->SampleUnload(handle); +} -void MD_RegisterDriver(MDRIVER *drv) +MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player) { - MDRIVER *cruise = firstdriver; + MikMod_player_t result; - if(cruise!=NULL) - { while(cruise->next!=NULL) cruise = cruise->next; - cruise->next = drv; - } else - firstdriver = drv; + MUTEX_LOCK(vars); + result=md_player; + md_player=player; + MUTEX_UNLOCK(vars); + + return result; } +void MikMod_Update(void) +{ + MUTEX_LOCK(vars); + if(isplaying) { + if((!pf)||(!pf->forbid)) + md_driver->Update(); + else { + if (md_driver->Pause) + md_driver->Pause(); + } + } + MUTEX_UNLOCK(vars); +} -SWORD MD_SampleLoad(SAMPLOAD *s, int type, FILE *fp) -/* type - sample type .. MD_MUSIC or MD_SNDFX */ +void Voice_SetVolume_internal(SBYTE voice,UWORD vol) { - SWORD result; + ULONG tmp; - if(type==MD_MUSIC) - type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE; - else if(type==MD_SNDFX) - type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE; + if((voice<0)||(voice>=md_numchn)) return; - SL_Init(s); - result = md_driver->SampleLoad(s, type); - SL_Exit(s); + /* range checks */ + if(md_musicvolume>128) md_musicvolume=128; + if(md_sndfxvolume>128) md_sndfxvolume=128; + if(md_volume>128) md_volume=128; - return result; + tmp=(ULONG)vol*(ULONG)md_volume* + ((voiceVoiceSetVolume(voice,tmp/16384UL); } - -void MD_SampleUnLoad(SWORD handle) +void Voice_SetVolume(SBYTE voice,UWORD vol) { - md_driver->SampleUnLoad(handle); + MUTEX_LOCK(vars); + Voice_SetVolume_internal(voice,vol); + MUTEX_UNLOCK(vars); } - -void MD_SetBPM(UBYTE bpm) +UWORD Voice_GetVolume(SBYTE voice) { - md_bpm = bpm; -} + UWORD result=0; + MUTEX_LOCK(vars); + if((voice>=0)&&(voiceVoiceGetVolume(voice); + MUTEX_UNLOCK(vars); -void MikMod_RegisterPlayer(void (*player)(void)) -{ - md_player = player; + return result; } - -void MikMod_Update(void) +void Voice_SetFrequency_internal(SBYTE voice,ULONG frq) { - if(isplaying && !(pf->forbid)) md_driver->Update(); + if((voice<0)||(voice>=md_numchn)) return; + if((md_sample[voice])&&(md_sample[voice]->divfactor)) + frq/=md_sample[voice]->divfactor; + md_driver->VoiceSetFrequency(voice,frq); } +void Voice_SetFrequency(SBYTE voice,ULONG frq) +{ + MUTEX_LOCK(vars); + Voice_SetFrequency_internal(voice,frq); + MUTEX_UNLOCK(vars); +} -void Voice_SetVolume(int voice, UWORD vol) +ULONG Voice_GetFrequency(SBYTE voice) { - ULONG tmp; + ULONG result=0; - if((voice<0) || (voice>=md_numchn)) return; - tmp = (ULONG)vol * (ULONG)md_volume * ((voice < md_sngchn) ? (ULONG)md_musicvolume : (ULONG)md_sndfxvolume); - md_driver->VoiceSetVolume(voice,tmp/16384UL); -} + MUTEX_LOCK(vars); + if((voice>=0)&&(voiceVoiceGetFrequency(voice); + MUTEX_UNLOCK(vars); + return result; +} -void Voice_SetFrequency(int voice, ULONG frq) +void Voice_SetPanning_internal(SBYTE voice,ULONG pan) { - if((voice < 0) || (voice >= md_numchn)) return; - if(md_sample[voice]!=NULL && md_sample[voice]->divfactor!=0) frq/=md_sample[voice]->divfactor; - md_driver->VoiceSetFrequency(voice, frq); + if((voice<0)||(voice>=md_numchn)) return; + if(pan!=PAN_SURROUND) { + if(md_pansep>128) md_pansep=128; + if(md_mode & DMODE_REVERSE) pan=255-pan; + pan = (((SWORD)(pan-128)*md_pansep)/128)+128; + } + md_driver->VoiceSetPanning(voice, pan); } - -void Voice_SetPanning(int voice, ULONG pan) +void Voice_SetPanning(SBYTE voice,ULONG pan) { - if((voice < 0) || (voice >= md_numchn)) return; - if(pan!=PAN_SURROUND) - { if(md_mode & DMODE_REVERSE) pan = 255-pan; - pan = (((SWORD)(pan-128)*md_pansep) / 128)+128; - } - md_driver->VoiceSetPanning(voice, pan); +#ifdef MIKMOD_DEBUG + if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255))) + fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan); +#endif + + MUTEX_LOCK(vars); + Voice_SetPanning_internal(voice,pan); + MUTEX_UNLOCK(vars); } +ULONG Voice_GetPanning(SBYTE voice) +{ + ULONG result=PAN_CENTER; + + MUTEX_LOCK(vars); + if((voice>=0)&&(voiceVoiceGetPanning(voice); + MUTEX_UNLOCK(vars); + + return result; +} -void Voice_Play(int voice, SAMPLE *s, ULONG start) +void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start) { - ULONG repend; - - if((voice < 0) || (voice >= md_numchn) || (start >= s->length)) return; + ULONG repend; - md_sample[voice] = s; - repend = s->loopend; + if((voice<0)||(voice>=md_numchn)) return; - if(s->flags&SF_LOOP) - if(repend > s->length) repend = s->length; /* repend can't be bigger than size */ + md_sample[voice]=s; + repend=s->loopend; - md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags); -} + if(s->flags&SF_LOOP) + /* repend can't be bigger than size */ + if(repend>s->length) repend=s->length; + md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags); +} -void Voice_Stop(int voice) +void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start) { - if((voice < 0) || (voice >= md_numchn)) return; - if(voice >= md_sngchn) - { /* It is a sound effects channel, so flag the voice as non-critical! */ - sfxinfo[voice-md_sngchn] = 0; - } + if(start>s->length) return; - md_driver->VoiceStop(voice); + MUTEX_LOCK(vars); + Voice_Play_internal(voice,s,start); + MUTEX_UNLOCK(vars); } - -BOOL Voice_Stopped(int voice) +void Voice_Stop_internal(SBYTE voice) { - if((voice < 0) || (voice >= md_numchn)) return 0; - return(md_driver->VoiceStopped(voice)); + if((voice<0)||(voice>=md_numchn)) return; + if(voice>=md_sngchn) + /* It is a sound effects channel, so flag the voice as non-critical! */ + sfxinfo[voice-md_sngchn]=0; + md_driver->VoiceStop(voice); } - -SLONG Voice_GetPosition(int voice) +void Voice_Stop(SBYTE voice) { - if((voice < 0) || (voice >= md_numchn)) return 0; - return(md_driver->VoiceGetPosition(voice)); + MUTEX_LOCK(vars); + Voice_Stop_internal(voice); + MUTEX_UNLOCK(vars); } - -ULONG Voice_RealVolume(int voice) +BOOL Voice_Stopped_internal(SBYTE voice) { - if((voice < 0) || (voice >= md_numchn)) return 0; - return(md_driver->VoiceRealVolume(voice)); + if((voice<0)||(voice>=md_numchn)) return 0; + return(md_driver->VoiceStopped(voice)); } - -/* ================================ */ -/* Functions prefixed with MikMod */ -/* ================================ */ - -BOOL MikMod_Init(void) +BOOL Voice_Stopped(SBYTE voice) { - UWORD t; - - _mm_critical = 1; + BOOL result; - /* if md_device==0, try to find a device number */ + MUTEX_LOCK(vars); + result=Voice_Stopped_internal(voice); + MUTEX_UNLOCK(vars); - if(md_device==0) - { for(t=1,md_driver=firstdriver; md_driver!=NULL; md_driver=md_driver->next, t++) - { if(md_driver->IsPresent()) break; - } + return result; +} - if(md_driver==NULL) - { _mm_errno = MMERR_DETECTING_DEVICE; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - md_driver = &drv_nos; - return 1; - } +SLONG Voice_GetPosition(SBYTE voice) +{ + SLONG result=0; - md_device = t; - } else - { /* if n>0 use that driver */ - for(t=1,md_driver=firstdriver; (md_driver!=NULL) && (t!=md_device); md_driver=md_driver->next, t++); + MUTEX_LOCK(vars); + if((voice>=0)&&(voiceVoiceGetPosition(voice)); + MUTEX_UNLOCK(vars); - if(md_driver==NULL) - { _mm_errno = MMERR_INVALID_DEVICE; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - md_driver = &drv_nos; - return 1; - } - - if(!md_driver->IsPresent()) - { _mm_errno = MMERR_DETECTING_DEVICE; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - md_driver = &drv_nos; - return 1; - } - } + return result; +} - if(md_driver->Init()) - { MikMod_Exit(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } +ULONG Voice_RealVolume(SBYTE voice) +{ + ULONG result=0; - idevice = md_device; imode = md_mode; - imixfreq = md_mixfreq; idmabufsize = md_dmabufsize; - initialized = 1; - _mm_critical = 0; + MUTEX_LOCK(vars); + if((voice>=0)&&(voiceVoiceRealVolume(voice)); + MUTEX_UNLOCK(vars); - return 0; + return result; } +static BOOL _mm_init(CHAR *cmdline) +{ + UWORD t; + + _mm_critical = 1; + + /* if md_device==0, try to find a device number */ + if(!md_device) { + cmdline=NULL; + + for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++) + if(md_driver->IsPresent()) break; + + if(!md_driver) { + _mm_errno = MMERR_DETECTING_DEVICE; + if(_mm_errorhandler) _mm_errorhandler(); + md_driver = &drv_nos; + return 1; + } + + md_device = t; + } else { + /* if n>0, use that driver */ + for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next,t++); + + if(!md_driver) { + _mm_errno = MMERR_INVALID_DEVICE; + if(_mm_errorhandler) _mm_errorhandler(); + md_driver = &drv_nos; + return 1; + } + + /* arguments here might be necessary for the presence check to succeed */ + if(cmdline&&(md_driver->CommandLine)) + md_driver->CommandLine(cmdline); + + if(!md_driver->IsPresent()) { + _mm_errno = MMERR_DETECTING_DEVICE; + if(_mm_errorhandler) _mm_errorhandler(); + md_driver = &drv_nos; + return 1; + } + } + + if(md_driver->Init()) { + md_driver->Exit(); + MikMod_Exit_internal(); + if(_mm_errorhandler) _mm_errorhandler(); + return 1; + } + + initialized=1; + _mm_critical=0; + + return 0; +} -void MikMod_Exit(void) +BOOL MikMod_Init(CHAR *cmdline) { - MikMod_DisableOutput(); - md_driver->Exit(); - md_numchn = md_sfxchn = md_sngchn = 0; - md_driver = &drv_nos; - initialized = 0; + BOOL result; + + MUTEX_LOCK(vars); + MUTEX_LOCK(lists); + result=_mm_init(cmdline); + MUTEX_UNLOCK(lists); + MUTEX_UNLOCK(vars); + + return result; } +void MikMod_Exit_internal(void) +{ + MikMod_DisableOutput_internal(); + md_driver->Exit(); + md_numchn = md_sfxchn = md_sngchn = 0; + md_driver = &drv_nos; -BOOL MikMod_Reset(void) + if(sfxinfo) free(sfxinfo); + if(md_sample) free(md_sample); + md_sample = NULL; + sfxinfo = NULL; -/* Reset the driver using the new global variable settings. */ -/* If the driver has not been initialized, it will be now. */ + initialized = 0; +} +void MikMod_Exit(void) { - if(!initialized) return MikMod_Init(); - if((md_driver->Reset == NULL) || (md_device != idevice)) - { /* md_driver->Reset was NULL, or md_device was changed, */ - /* so do a full reset of the driver. */ + MUTEX_LOCK(vars); + MUTEX_LOCK(lists); + MikMod_Exit_internal(); + MUTEX_UNLOCK(lists); + MUTEX_UNLOCK(vars); +} - if(isplaying) md_driver->PlayStop(); - md_driver->Exit(); - if(MikMod_Init()) - { MikMod_Exit(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } - if(isplaying) md_driver->PlayStart(); - } else - { if(md_driver->Reset()) - { MikMod_Exit(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } - } - - return 0; +/* Reset the driver using the new global variable settings. + If the driver has not been initialized, it will be now. */ +static BOOL _mm_reset(CHAR *cmdline) +{ + if(!initialized) return _mm_init(cmdline); + + if((!md_driver->Reset)||(md_device != idevice)) { + /* md_driver->Reset was NULL, or md_device was changed, so do a full + reset of the driver. */ + if(isplaying) md_driver->PlayStop(); + md_driver->Exit(); + if(_mm_init(cmdline)) { + MikMod_Exit_internal(); + if(_mm_errno) + if(_mm_errorhandler) _mm_errorhandler(); + return 1; + } + if(isplaying) md_driver->PlayStart(); + } else { + if(md_driver->Reset()) { + MikMod_Exit_internal(); + if(_mm_errno) + if(_mm_errorhandler) _mm_errorhandler(); + return 1; + } + } + return 0; } +BOOL MikMod_Reset(CHAR *cmdline) +{ + BOOL result; + + MUTEX_LOCK(vars); + MUTEX_LOCK(lists); + result=_mm_reset(cmdline); + MUTEX_UNLOCK(lists); + MUTEX_UNLOCK(vars); -BOOL MikMod_SetNumVoices(int music, int sfx) + return result; +} /* If either parameter is -1, the current set value will be retained. */ +BOOL MikMod_SetNumVoices_internal(int music, int sfx) +{ + BOOL resume = 0; + int t, oldchn = 0; + + if((!music)&&(!sfx)) return 1; + _mm_critical = 1; + if(isplaying) { + MikMod_DisableOutput_internal(); + oldchn = md_numchn; + resume = 1; + } + + if(sfxinfo) free(sfxinfo); + if(md_sample) free(md_sample); + md_sample = NULL; + sfxinfo = NULL; + + if(music!=-1) md_sngchn = music; + if(sfx!=-1) md_sfxchn = sfx; + md_numchn = md_sngchn + md_sfxchn; + + LimitHardVoices(md_driver->HardVoiceLimit); + LimitSoftVoices(md_driver->SoftVoiceLimit); + + if(md_driver->SetNumVoices()) { + MikMod_Exit_internal(); + if(_mm_errno) + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0; + return 1; + } + + if(md_sngchn+md_sfxchn) + md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*)); + if(md_sfxchn) + sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE)); + + /* make sure the player doesn't start with garbage */ + for(t=oldchn;tPlayStart()) return 1; + isplaying = 1; + } + _mm_critical = 0; + return 0; +} - if(sfxinfo!=NULL) free(sfxinfo); - if(md_sample!=NULL) free(md_sample); - md_sample = NULL; - sfxinfo = NULL; +BOOL MikMod_EnableOutput(void) +{ + BOOL result; - /*md_softchn = md_hardchn = 0; + MUTEX_LOCK(vars); + result=MikMod_EnableOutput_internal(); + MUTEX_UNLOCK(vars); - if(md_mode & DMODE_SOFT_SNDFX) - md_softchn = sfx; else md_hardchn = sfx; + return result; +} - if(md_mode & DMODE_SOFT_MUSIC) - md_softchn += music; else md_hardchn += music; - */ +void MikMod_DisableOutput_internal(void) +{ + if(isplaying && md_driver) { + isplaying = 0; + md_driver->PlayStop(); + } +} - if(music != -1) md_sngchn = music; - if(sfx != -1) md_sfxchn = sfx; +void MikMod_DisableOutput(void) +{ + MUTEX_LOCK(vars); + MikMod_DisableOutput_internal(); + MUTEX_UNLOCK(vars); +} - md_numchn = md_sngchn + md_sfxchn; +BOOL MikMod_Active_internal(void) +{ + return isplaying; +} - LimitHardVoices(md_driver->HardVoiceLimit); - LimitSoftVoices(md_driver->SoftVoiceLimit); +BOOL MikMod_Active(void) +{ + BOOL result; - if(md_driver->SetNumVoices()) - { MikMod_Exit(); - md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } + MUTEX_LOCK(vars); + result=MikMod_Active_internal(); + MUTEX_UNLOCK(vars); - if(md_sngchn || md_sfxchn) - md_sample = (SAMPLE **)_mm_calloc(md_sngchn+md_sfxchn, sizeof(SAMPLE *)); - if(md_sfxchn) - sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn, sizeof(UBYTE)); + return result; +} - /* make sure the player doesn't start with garbage */ - for(t=oldchn; tvolume>64) s->volume = 64; + + /* check the first location after sfxpool */ + do { + if(sfxinfo[sfxpool]&SFX_CRITICAL) { + if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) { + sfxinfo[sfxpool]=flags; + Voice_Play_internal(c,s,start); + md_driver->VoiceSetVolume(c,s->volume<<2); + Voice_SetPanning_internal(c,s->panning); + md_driver->VoiceSetFrequency(c,s->speed); + sfxpool++; + if(sfxpool>=md_sfxchn) sfxpool=0; + return c; + } + } else { + sfxinfo[sfxpool]=flags; + Voice_Play_internal(c=sfxpool+md_sngchn,s,start); + md_driver->VoiceSetVolume(c,s->volume<<2); + Voice_SetPanning_internal(c,s->panning); + md_driver->VoiceSetFrequency(c,s->speed); + sfxpool++; + if(sfxpool>=md_sfxchn) sfxpool=0; + return c; + } + + sfxpool++; + if(sfxpool>=md_sfxchn) sfxpool = 0; + } while(sfxpool!=orig); + + return -1; +} - if(resume) MikMod_EnableOutput(); - _mm_critical = 0; +SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags) +{ + SBYTE result; - return 0; -} + MUTEX_LOCK(vars); + result=Sample_Play_internal(s,start,flags); + MUTEX_UNLOCK(vars); + return result; +} -BOOL MikMod_EnableOutput(void) +long MikMod_GetVersion(void) { - /* safety valve, prevents entering */ - /* playstart twice: */ - - _mm_critical = 1; - if(!isplaying) - { if(md_driver->PlayStart()) return 1; - isplaying = 1; - } - _mm_critical = 0; - return 0; + return LIBMIKMOD_VERSION; } +/*========== MT-safe stuff */ + +#ifdef HAVE_PTHREAD +#define INIT_MUTEX(name) \ + pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER +#elif defined(__OS2__)||defined(__EMX__) +#define INIT_MUTEX(name) \ + HMTX _mm_mutex_##name +#elif defined(WIN32) +#define INIT_MUTEX(name) \ + HANDLE _mm_mutex_##name +#else +#define INIT_MUTEX(name) +#endif + +INIT_MUTEX(vars); +INIT_MUTEX(lists); + +BOOL MikMod_InitThreads(void) +{ + static int firstcall=1; + static int result=0; + + if (firstcall) { + firstcall=0; +#ifdef HAVE_PTHREAD + result=1; +#elif defined(__OS2__)||defined(__EMX__) + if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) || + DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) { + _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL; + result=0; + } else + result=1; +#elif defined(WIN32) + if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))|| + (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)")))) + result=0; + else + result=1; +#endif + } + return result; +} -void MikMod_DisableOutput(void) +void MikMod_Unlock(void) { - /* safety valve, prevents calling playStop when playstart */ - /* hasn't been called: */ + MUTEX_UNLOCK(lists); + MUTEX_UNLOCK(vars); +} - if(isplaying && md_driver!=NULL) - { isplaying = 0; - md_driver->PlayStop(); - } +void MikMod_Lock(void) +{ + MUTEX_LOCK(vars); + MUTEX_LOCK(lists); } +/*========== Parameter extraction helper */ -BOOL MikMod_Active(void) +CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,BOOL implicit) { - return isplaying; + CHAR *ret=NULL; + + if(cmdline) { + CHAR *buf=strstr(cmdline,atomname); + + if((buf)&&((buf==cmdline)||(*(buf-1)==','))) { + CHAR *ptr=buf+strlen(atomname); + + if(*ptr=='=') { + for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++); + ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR)); + if(ret) + strncpy(ret,buf,ptr-buf); + } else if((*ptr==',')||(!*ptr)) { + if(implicit) { + ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR)); + if(ret) + strncpy(ret,buf,ptr-buf); + } + } + } + } + return ret; } +#ifdef unix -int MikMod_PlaySample(SAMPLE *s, ULONG start, UBYTE flags) +#include -/* Plays a sound effects sample. Picks a voice from the number of voices */ -/* allocated for use as sound effects (loops through voices, skipping all */ -/* active criticals). */ -/* */ -/* Returns the voice that the sound is being played on. */ +/*========== Posix helper functions */ +/* Check if the file is a regular or nonexistant file (or a link to a such a + file), and that, should the calling program be setuid, the access rights are + reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise. + The goal is to prevent a setuid root libmikmod application from overriding + files like /etc/passwd with digital sound... */ +BOOL MD_Access(CHAR *filename) { - int orig = sfxpool; /* for cases where all channels are critical */ - int c; - - if(md_sfxchn==0) return -1; - if(s->volume > 64) s->volume = 64; - - /* check the first location after sfxpool */ - do - { if(sfxinfo[sfxpool] & SFX_CRITICAL) - { if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) - { sfxinfo[sfxpool] = flags; - Voice_Play(c, s, start); - md_driver->VoiceSetVolume(c,s->volume<<2); - md_driver->VoiceSetPanning(c,s->panning); - md_driver->VoiceSetFrequency(c,s->speed); - sfxpool++; - if(sfxpool >= md_sfxchn) sfxpool = 0; - return c; - } - } else - { sfxinfo[sfxpool] = flags; - Voice_Play(c=sfxpool+md_sngchn, s, start); - md_driver->VoiceSetVolume(c,s->volume<<2); - md_driver->VoiceSetPanning(c,s->panning); - md_driver->VoiceSetFrequency(c,s->speed); - sfxpool++; - if(sfxpool >= md_sfxchn) sfxpool = 0; - return c; - } - - sfxpool++; - if(sfxpool >= md_sfxchn) sfxpool = 0; - } while(sfxpool!=orig); + struct stat buf; + + if(!stat(filename,&buf)) { + /* not a regular file ? */ + if(!S_ISREG(buf.st_mode)) return 0; + /* more than one hard link to the file ? */ + if(buf.st_nlink>1) return 0; + /* check access rights with the real user and group id */ + if(getuid()==buf.st_uid) { + if(!(buf.st_mode&S_IWUSR)) return 0; + } else if(getgid()==buf.st_gid) { + if(!(buf.st_mode&S_IWGRP)) return 0; + } else + if(!(buf.st_mode&S_IWOTH)) return 0; + } + + return 1; +} - return -1; +/* Drop all root privileges we might have */ +BOOL MD_DropPrivileges(void) +{ + if(!geteuid()) { + if(getuid()) { + /* we are setuid root -> drop setuid to become the real user */ + if(setuid(getuid())) return 1; + } else { + /* we are run as root -> drop all and become user 'nobody' */ + struct passwd *nobody; + int uid; + + if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */ + uid=nobody->pw_uid; + if (!uid) /* user 'nobody' has root privileges ? weird... */ + return 1; + if (setuid(uid)) return 1; + } + } + return 0; } +#endif + +/* ex:set ts=4: */ diff --git a/mikmod/mikmod.h b/mikmod/mikmod.h index 26d7eab5..d5621883 100644 --- a/mikmod/mikmod.h +++ b/mikmod/mikmod.h @@ -1,394 +1,699 @@ -#ifndef _MIKMOD_H -#define _MIKMOD_H +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. -#include "mmio.h" + 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. -#ifdef __cplusplus -extern "C" { -#endif + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ -#define MUTE_EXCLUSIVE 32000 -#define MUTE_INCLUSIVE 32001 +/*============================================================================== -#define PAN_LEFT 0 -#define PAN_CENTER 128 -#define PAN_RIGHT 255 -#define PAN_SURROUND 512 /* panning value for Dolby Surround */ + $Id$ + MikMod sound library include file -#define MikMod_RegisterDriver(x) MD_RegisterDriver(&x) -#define MikMod_RegisterLoader(x) ML_RegisterLoader(&x) -#define MikMod_RegisterErrorHandler(x) _mm_RegisterErrorHandler(x) +==============================================================================*/ +#ifndef _MIKMOD_H_ +#define _MIKMOD_H_ -/* The following #define macros are for retaining API compatiability */ -/* with the beta version of MikMod 3.0, and are TEMPORARY! They WILL */ -/* be removed in the future! */ +#include +#include -#define MD_RegisterPlayer(x) MikMod_RegisterPlayer(x) -#define MD_Init MikMod_Init -#define MD_Exit MikMod_Exit -#define MD_Update MikMod_Update -#define ML_Free(x) MikMod_FreeSong(x) -#define MD_SetNumChannels(x,y) MikMod_SetNumVoices(x,y) -#define MD_SetNumVoices(x,y) MikMod_SetNumVoices(x,y) -#define MD_PlayStart MikMod_EnableOutput -#define MD_PlayStop MikMod_DisableOutput +#ifdef __cplusplus +extern "C" { +#endif -#define MD_VoiceSetVolume(x,y) Voice_SetVolume(x,y) -#define MD_VoiceSetFrequency(x,y) Voice_SetFrequency(x,y) -#define MD_VoiceSetPanning(x,y) Voice_SetPanning(x,y) -#define MD_VoicePlay(x,y,z) Voice_Play(x,y,z) -#define MD_VoiceStop(x) Voice_Stop(x) -#define MD_VoiceReleaseSustain(x) Voice_ReleaseSustain(x) -#define MD_VoiceStopped(x) Voice_Stopped(x) -#define MD_VoiceGetPosition(x) Voice_GetPosition(x) -#define MD_VoiceRealVolume(x) Voice_RealVolume(x) +/* + * ========== Compiler magic for shared libraries + */ +#ifdef WIN32 +#ifdef DLL_EXPORTS +#define MIKMODAPI __declspec(dllexport) +#else +#define MIKMODAPI __declspec(dllimport) +#endif +#else +#define MIKMODAPI +#endif -#define SFX_CRITICAL 1 +/* + * ========== Library version + */ +#define LIBMIKMOD_VERSION_MAJOR 3 +#define LIBMIKMOD_VERSION_MINOR 1 +#define LIBMIKMOD_REVISION 8 -/************************************************************************** -****** mikmod types: ****************************************************** -**************************************************************************/ +#define LIBMIKMOD_VERSION \ + ((LIBMIKMOD_VERSION_MAJOR<<16)| \ + (LIBMIKMOD_VERSION_MINOR<< 8)| \ + (LIBMIKMOD_REVISION)) -/* Sample format [loading and in-memory] flags: */ -#define SF_16BITS 1 -#define SF_SIGNED 2 -#define SF_STEREO 4 -#define SF_DELTA 8 -#define SF_BIG_ENDIAN 16 +MIKMODAPI extern long MikMod_GetVersion(void); -/* General Playback flags */ +/* + * ========== Platform independent-type definitions + */ -#define SF_LOOP 32 -#define SF_BIDI 64 -#define SF_SUSTAIN 128 -#define SF_REVERSE 256 +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif -/* Module-only Playback Flags */ +#if defined(__OS2__)||defined(__EMX__) +#define INCL_DOSSEMAPHORES +#include +#else +typedef char CHAR; +#endif -#define SF_OWNPAN 512 -#define SF_UST_LOOP 1024 +/*@DOES_NOT_HAVE_SIGNED@*/ + +#if defined(__alpha) +/* 64 bit architectures */ + +typedef signed char SBYTE; /* 1 byte, signed */ +typedef unsigned char UBYTE; /* 1 byte, unsigned */ +typedef signed short SWORD; /* 2 bytes, signed */ +typedef unsigned short UWORD; /* 2 bytes, unsigned */ +typedef signed int SLONG; /* 4 bytes, signed */ +typedef unsigned int ULONG; /* 4 bytes, unsigned */ +typedef int BOOL; /* 0=false, <>0 true */ + +#else +/* 32 bit architectures */ + +typedef signed char SBYTE; /* 1 byte, signed */ +typedef unsigned char UBYTE; /* 1 byte, unsigned */ +typedef signed short SWORD; /* 2 bytes, signed */ +typedef unsigned short UWORD; /* 2 bytes, unsigned */ +typedef signed long SLONG; /* 4 bytes, signed */ +#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32) +typedef unsigned long ULONG; /* 4 bytes, unsigned */ +typedef int BOOL; /* 0=false, <>0 true */ +#endif +#endif +/* + * ========== Error codes + */ + +enum { + MMERR_OPENING_FILE = 1, + MMERR_OUT_OF_MEMORY, + MMERR_DYNAMIC_LINKING, + + MMERR_SAMPLE_TOO_BIG, + MMERR_OUT_OF_HANDLES, + MMERR_UNKNOWN_WAVE_TYPE, + + MMERR_LOADING_PATTERN, + MMERR_LOADING_TRACK, + MMERR_LOADING_HEADER, + MMERR_LOADING_SAMPLEINFO, + MMERR_NOT_A_MODULE, + MMERR_NOT_A_STREAM, + MMERR_MED_SYNTHSAMPLES, + MMERR_ITPACK_INVALID_DATA, + + MMERR_DETECTING_DEVICE, + MMERR_INVALID_DEVICE, + MMERR_INITIALIZING_MIXER, + MMERR_OPENING_AUDIO, + MMERR_8BIT_ONLY, + MMERR_16BIT_ONLY, + MMERR_STEREO_ONLY, + MMERR_ULAW, + MMERR_NON_BLOCK, + + MMERR_AF_AUDIO_PORT, + + MMERR_AIX_CONFIG_INIT, + MMERR_AIX_CONFIG_CONTROL, + MMERR_AIX_CONFIG_START, + + MMERR_GUS_SETTINGS, + MMERR_GUS_RESET, + MMERR_GUS_TIMER, + + MMERR_HP_SETSAMPLESIZE, + MMERR_HP_SETSPEED, + MMERR_HP_CHANNELS, + MMERR_HP_AUDIO_OUTPUT, + MMERR_HP_AUDIO_DESC, + MMERR_HP_BUFFERSIZE, + + MMERR_OSS_SETFRAGMENT, + MMERR_OSS_SETSAMPLESIZE, + MMERR_OSS_SETSTEREO, + MMERR_OSS_SETSPEED, + + MMERR_SGI_SPEED, + MMERR_SGI_16BIT, + MMERR_SGI_8BIT, + MMERR_SGI_STEREO, + MMERR_SGI_MONO, + + MMERR_SUN_INIT, + + MMERR_OS2_MIXSETUP, + MMERR_OS2_SEMAPHORE, + MMERR_OS2_TIMER, + MMERR_OS2_THREAD, + + MMERR_DS_PRIORITY, + MMERR_DS_BUFFER, + MMERR_DS_FORMAT, + MMERR_DS_NOTIFY, + MMERR_DS_EVENT, + MMERR_DS_THREAD, + MMERR_DS_UPDATE, + + MMERR_WINMM_HANDLE, + MMERR_WINMM_ALLOCATED, + MMERR_WINMM_DEVICEID, + MMERR_WINMM_FORMAT, + MMERR_WINMM_UNKNOWN, + + MMERR_MAC_SPEED, + MMERR_MAC_START, + + MMERR_MAX +}; -typedef struct SAMPLE -{ ULONG speed; /* Base playing speed/frequency of note (Middle C in player) */ - UBYTE volume; /* volume 0-64 */ - UWORD panning; /* panning (0-255 or PAN_SURROUND) */ - ULONG length; /* length of sample (in samples!) */ - ULONG loopstart; /* repeat position (relative to start, in samples) */ - ULONG loopend; /* repeat end */ - ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */ - ULONG susend; /* sustain loop end / Yet! */ +/* + * ========== Error handling + */ - UWORD flags; /* sample format in memory */ +typedef void (MikMod_handler)(void); +typedef MikMod_handler *MikMod_handler_t; -/* Variables used by the module player only! (ignored for sound effects) */ +MIKMODAPI extern int MikMod_errno; +MIKMODAPI extern BOOL MikMod_critical; +MIKMODAPI extern char *MikMod_strerror(int); - UBYTE globvol; /* global volume */ - UBYTE vibflags; /* autovibrato flag stuffs */ - UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */ - UBYTE vibsweep; - UBYTE vibdepth; - UBYTE vibrate; +MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t); - CHAR *samplename; /* name of the sample */ +/* + * ========== Library initialization and core functions + */ -/* Values used internally only (not saved in disk formats) */ +struct MDRIVER; - UWORD avibpos; /* autovibrato pos [player use] */ - UBYTE divfactor; /* for sample scaling (maintains proper period slides) */ - ULONG seekpos; /* seek position in file */ - SWORD handle; /* sample handle used by individual drivers */ -} SAMPLE; +MIKMODAPI extern void MikMod_RegisterAllDrivers(void); +MIKMODAPI extern CHAR* MikMod_InfoDriver(void); +MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*); +MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*); +MIKMODAPI extern BOOL MikMod_Init(CHAR*); +MIKMODAPI extern void MikMod_Exit(void); +MIKMODAPI extern BOOL MikMod_Reset(CHAR*); +MIKMODAPI extern BOOL MikMod_SetNumVoices(int,int); +MIKMODAPI extern BOOL MikMod_Active(void); +MIKMODAPI extern BOOL MikMod_EnableOutput(void); +MIKMODAPI extern void MikMod_DisableOutput(void); +MIKMODAPI extern void MikMod_Update(void); -/* --> Struct : SAMPLOAD */ -/* This is a handle of sorts attached to any sample registered with */ -/* SL_RegisterSample. Generally, this only need be used or changed by the */ -/* loaders and drivers of mikmod. */ +MIKMODAPI extern BOOL MikMod_InitThreads(void); +MIKMODAPI extern void MikMod_Lock(void); +MIKMODAPI extern void MikMod_Unlock(void); -typedef struct SAMPLOAD -{ struct SAMPLOAD *next; +/* + * ========== Reader, Writer + */ - ULONG length; /* length of sample (in samples!) */ - ULONG loopstart; /* repeat position (relative to start, in samples) */ - ULONG loopend; /* repeat end */ +typedef struct MREADER { + BOOL (*Seek)(struct MREADER*,long,int); + long (*Tell)(struct MREADER*); + BOOL (*Read)(struct MREADER*,void*,size_t); + int (*Get)(struct MREADER*); + BOOL (*Eof)(struct MREADER*); +} MREADER; - UWORD infmt, outfmt; - int scalefactor; - SAMPLE *sample; - FILE *fp; -} SAMPLOAD; +typedef struct MWRITER { + BOOL (*Seek)(struct MWRITER*,long,int); + long (*Tell)(struct MWRITER*); + BOOL (*Write)(struct MWRITER*,void*,size_t); + BOOL (*Put)(struct MWRITER*,int); +} MWRITER; -extern void SL_HalveSample(SAMPLOAD *s); -extern void SL_Sample8to16(SAMPLOAD *s); -extern void SL_Sample16to8(SAMPLOAD *s); -extern void SL_SampleSigned(SAMPLOAD *s); -extern void SL_SampleUnsigned(SAMPLOAD *s); -extern BOOL SL_LoadSamples(void); /* Returns 1 on error! */ -extern SAMPLOAD *SL_RegisterSample(SAMPLE *s, int type, FILE *fp); /* Returns 1 on error! */ -extern void SL_Load(void *buffer, SAMPLOAD *smp, int length); -extern BOOL SL_Init(SAMPLOAD *s); -extern void SL_Exit(SAMPLOAD *s); +/* + * ========== Samples + */ +/* Sample playback should not be interrupted */ +#define SFX_CRITICAL 1 -/************************************************************************** -****** Wavload stuff: ***************************************************** -**************************************************************************/ +/* Sample format [loading and in-memory] flags: */ +#define SF_16BITS 0x0001 +#define SF_STEREO 0x0002 +#define SF_SIGNED 0x0004 +#define SF_BIG_ENDIAN 0x0008 +#define SF_DELTA 0x0010 +#define SF_ITPACKED 0x0020 -SAMPLE *WAV_LoadFP(FILE *fp); -SAMPLE *WAV_LoadFN(CHAR *filename); -void WAV_Free(SAMPLE *si); +#define SF_FORMATMASK 0x003F +/* General Playback flags */ -#include "ptform.h" +#define SF_LOOP 0x0100 +#define SF_BIDI 0x0200 +#define SF_REVERSE 0x0400 +#define SF_SUSTAIN 0x0800 +#define SF_PLAYBACKMASK 0x0C00 -/************************************************************************** -****** Driver stuff: ****************************************************** -**************************************************************************/ +/* Module-only Playback Flags */ -/* max. number of handles a driver has to provide. (not strict) */ +#define SF_OWNPAN 0x1000 +#define SF_UST_LOOP 0x2000 + +#define SF_EXTRAPLAYBACKMASK 0x3000 + +/* Panning constants */ +#define PAN_LEFT 0 +#define PAN_CENTER 128 +#define PAN_RIGHT 255 +#define PAN_SURROUND 512 /* panning value for Dolby Surround */ + +typedef struct SAMPLE { + SWORD panning; /* panning (0-255 or PAN_SURROUND) */ + ULONG speed; /* Base playing speed/frequency of note */ + UBYTE volume; /* volume 0-64 */ + UWORD inflags; /* sample format on disk */ + UWORD flags; /* sample format in memory */ + ULONG length; /* length of sample (in samples!) */ + ULONG loopstart; /* repeat position (relative to start, in samples) */ + ULONG loopend; /* repeat end */ + ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */ + ULONG susend; /* sustain loop end / Yet! */ + + /* Variables used by the module player only! (ignored for sound effects) */ + UBYTE globvol; /* global volume */ + UBYTE vibflags; /* autovibrato flag stuffs */ + UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */ + UBYTE vibsweep; + UBYTE vibdepth; + UBYTE vibrate; + CHAR* samplename; /* name of the sample */ + + /* Values used internally only */ + UWORD avibpos; /* autovibrato pos [player use] */ + UBYTE divfactor; /* for sample scaling, maintains proper period slides */ + ULONG seekpos; /* seek position in file */ + SWORD handle; /* sample handle used by individual drivers */ +} SAMPLE; -#define MAXSAMPLEHANDLES 384 +/* Sample functions */ + +MIKMODAPI extern SAMPLE *Sample_Load(CHAR*); +MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*); +MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*); +MIKMODAPI extern void Sample_Free(SAMPLE*); +MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE); + +MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD); +MIKMODAPI extern UWORD Voice_GetVolume(SBYTE); +MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG); +MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE); +MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG); +MIKMODAPI extern ULONG Voice_GetPanning(SBYTE); +MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG); +MIKMODAPI extern void Voice_Stop(SBYTE); +MIKMODAPI extern BOOL Voice_Stopped(SBYTE); +MIKMODAPI extern SLONG Voice_GetPosition(SBYTE); +MIKMODAPI extern ULONG Voice_RealVolume(SBYTE); + +/* + * ========== Internal module representation (UniMod) + */ + +/* + Instrument definition - for information only, the only field which may be + of use in user programs is the name field +*/ + +/* Instrument note count */ +#define INSTNOTES 120 + +/* Envelope point */ +typedef struct ENVPT { + SWORD pos; + SWORD val; +} ENVPT; + +/* Envelope point count */ +#define ENVPOINTS 32 + +/* Instrument structure */ +typedef struct INSTRUMENT { + CHAR* insname; + + UBYTE flags; + UWORD samplenumber[INSTNOTES]; + UBYTE samplenote[INSTNOTES]; + + UBYTE nnatype; + UBYTE dca; /* duplicate check action */ + UBYTE dct; /* duplicate check type */ + UBYTE globvol; + UWORD volfade; + SWORD panning; /* instrument-based panning var */ + + UBYTE pitpansep; /* pitch pan separation (0 to 255) */ + UBYTE pitpancenter; /* pitch pan center (0 to 119) */ + UBYTE rvolvar; /* random volume varations (0 - 100%) */ + UBYTE rpanvar; /* random panning varations (0 - 100%) */ + + /* volume envelope */ + UBYTE volflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE volpts; + UBYTE volsusbeg; + UBYTE volsusend; + UBYTE volbeg; + UBYTE volend; + ENVPT volenv[ENVPOINTS]; + /* panning envelope */ + UBYTE panflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE panpts; + UBYTE pansusbeg; + UBYTE pansusend; + UBYTE panbeg; + UBYTE panend; + ENVPT panenv[ENVPOINTS]; + /* pitch envelope */ + UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE pitpts; + UBYTE pitsusbeg; + UBYTE pitsusend; + UBYTE pitbeg; + UBYTE pitend; + ENVPT pitenv[ENVPOINTS]; +} INSTRUMENT; + +struct MP_CONTROL; +struct MP_VOICE; + +/* Module flags */ +#define UF_XMPERIODS 0x0001 /* XM periods / finetuning */ +#define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */ +#define UF_INST 0x0004 /* Instruments are used */ +#define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather than numchn */ +#define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */ +#define UF_BGSLIDES 0x0020 /* continue volume slides in the background */ +#define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */ +#define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern brk semantics */ +#define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */ +#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */ + +typedef struct MODULE { + /* general module information */ + CHAR* songname; /* name of the song */ + CHAR* modtype; /* string type of module loaded */ + CHAR* comment; /* module comments */ + + UWORD flags; /* See module flags above */ + UBYTE numchn; /* number of module channels */ + UBYTE numvoices; /* max # voices used for full NNA playback */ + UWORD numpos; /* number of positions in this song */ + UWORD numpat; /* number of patterns in this song */ + UWORD numins; /* number of instruments */ + UWORD numsmp; /* number of samples */ +struct INSTRUMENT* instruments; /* all instruments */ +struct SAMPLE* samples; /* all samples */ + UBYTE realchn; /* real number of channels used */ + UBYTE totalchn; /* total number of channels used (incl NNAs) */ + + /* playback settings */ + UWORD reppos; /* restart position */ + UBYTE initspeed; /* initial song speed */ + UWORD inittempo; /* initial song tempo */ + UBYTE initvolume; /* initial global volume (0 - 128) */ + UWORD panning[64]; /* 64 panning positions */ + UBYTE chanvol[64]; /* 64 channel positions */ + UWORD bpm; /* current beats-per-minute speed */ + UWORD sngspd; /* current song speed */ + SWORD volume; /* song volume (0-128) (or user volume) */ + + BOOL extspd; /* extended speed flag (default enabled) */ + BOOL panflag; /* panning flag (default enabled) */ + BOOL wrap; /* wrap module ? (default disabled) */ + BOOL loop; /* allow module to loop ? (default enabled) */ + BOOL fadeout; /* volume fade out during last pattern */ + + UWORD patpos; /* current row number */ + SWORD sngpos; /* current song position */ + ULONG sngtime; /* current song time in 2^-10 seconds */ + + SWORD relspd; /* relative speed factor */ + + /* internal module representation */ + UWORD numtrk; /* number of tracks */ + UBYTE** tracks; /* array of numtrk pointers to tracks */ + UWORD* patterns; /* array of Patterns */ + UWORD* pattrows; /* array of number of rows for each pattern */ + UWORD* positions; /* all positions */ + + BOOL forbid; /* if true, no player update! */ + UWORD numrow; /* number of rows on current pattern */ + UWORD vbtick; /* tick counter (counts from 0 to sngspd) */ + UWORD sngremainder;/* used for song time computation */ + +struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */ +struct MP_VOICE* voice; /* Audio Voice information (size md_numchn) */ + + UBYTE globalslide; /* global volume slide rate */ + UBYTE pat_repcrazy;/* module has just looped to position -1 */ + UWORD patbrk; /* position where to start a new pattern */ + UBYTE patdly; /* patterndelay counter (command memory) */ + UBYTE patdly2; /* patterndelay counter (real one) */ + SWORD posjmp; /* flag to indicate a jump is needed... */ +} MODULE; + +/* + * ========== Module loaders + */ + +struct MLOADER; + +MIKMODAPI extern CHAR* MikMod_InfoLoader(void); +MIKMODAPI extern void MikMod_RegisterAllLoaders(void); +MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*); + +MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */ +MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */ +MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */ +MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */ +MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */ +MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */ +MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */ +MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */ +MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */ +MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */ +MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */ +MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */ +MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */ +MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */ +MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */ +MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */ +MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */ + +/* + * ========== Module player + */ + +MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL); +MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL); +MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL); +MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*); +MIKMODAPI extern void Player_Free(MODULE*); +MIKMODAPI extern void Player_Start(MODULE*); +MIKMODAPI extern BOOL Player_Active(void); +MIKMODAPI extern void Player_Stop(void); +MIKMODAPI extern void Player_TogglePause(void); +MIKMODAPI extern BOOL Player_Paused(void); +MIKMODAPI extern void Player_NextPosition(void); +MIKMODAPI extern void Player_PrevPosition(void); +MIKMODAPI extern void Player_SetPosition(UWORD); +MIKMODAPI extern BOOL Player_Muted(UBYTE); +MIKMODAPI extern void Player_SetVolume(SWORD); +MIKMODAPI extern MODULE* Player_GetModule(void); +MIKMODAPI extern void Player_SetSpeed(UWORD); +MIKMODAPI extern void Player_SetTempo(UWORD); +MIKMODAPI extern void Player_Unmute(SLONG,...); +MIKMODAPI extern void Player_Mute(SLONG,...); +MIKMODAPI extern void Player_ToggleMute(SLONG,...); +MIKMODAPI extern int Player_GetChannelVoice(UBYTE); +MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE); + +typedef void (MikMod_player)(void); +typedef MikMod_player *MikMod_player_t; + +MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t); +#define MUTE_EXCLUSIVE 32000 +#define MUTE_INCLUSIVE 32001 -enum -{ MD_MUSIC = 0, - MD_SNDFX -}; +/* + * ========== Drivers + */ -enum -{ MD_HARDWARE = 0, - MD_SOFTWARE +enum { + MD_MUSIC = 0, + MD_SNDFX }; +enum { + MD_HARDWARE = 0, + MD_SOFTWARE +}; -/* possible mixing mode bits: */ -/* -------------------------- */ -/* These take effect only after MikMod_Init or MikMod_Reset. */ - -#define DMODE_16BITS 1 /* enable 16 bit output */ -#define DMODE_SURROUND 2 /* enable Dolby surround sound (not yet supported) */ -#define DMODE_SOFT_SNDFX 4 /* Process sound effects via software mixer (not yet supported) */ -#define DMODE_SOFT_MUSIC 8 /* Process music via software mixer (not yet supported) */ - -/* These take effect immidiately. */ - -#define DMODE_STEREO 16 /* enable stereo output */ -#define DMODE_REVERSE 32 /* reverse stereo */ -#define DMODE_INTERP 64 /* enable interpolation (not yet supported) */ - - -/* driver structure: */ - -typedef struct MDRIVER -{ struct MDRIVER *next; - CHAR *Name; - CHAR *Version; - UBYTE HardVoiceLimit, /* Limit of hardware mixer voices for this driver */ - SoftVoiceLimit; /* Limit of software mixer voices for this driver */ - - BOOL (*IsPresent) (void); - SWORD (*SampleLoad) (SAMPLOAD *s, int type); - void (*SampleUnLoad) (SWORD handle); - ULONG (*FreeSampleSpace) (int type); - ULONG (*RealSampleLength) (int type, SAMPLE *s); - BOOL (*Init) (void); - void (*Exit) (void); - BOOL (*Reset) (void); - BOOL (*SetNumVoices) (void); - BOOL (*PlayStart) (void); - void (*PlayStop) (void); - void (*Update) (void); - void (*VoiceSetVolume) (UBYTE voice, UWORD vol); - void (*VoiceSetFrequency) (UBYTE voice, ULONG frq); - void (*VoiceSetPanning) (UBYTE voice, ULONG pan); - void (*VoicePlay) (UBYTE voice, SWORD handle, ULONG start, ULONG size, ULONG reppos, ULONG repend, UWORD flags); - void (*VoiceStop) (UBYTE voice); - BOOL (*VoiceStopped) (UBYTE voice); - void (*VoiceReleaseSustain)(UBYTE voice); - SLONG (*VoiceGetPosition) (UBYTE voice); - ULONG (*VoiceRealVolume) (UBYTE voice); - - BOOL (*StreamInit) (ULONG speed, UWORD flags); - void (*StreamExit) (void); - void (*StreamSetSpeed) (ULONG speed); - SLONG (*StreamGetPosition) (void); - void (*StreamLoadFP) (FILE *fp); +/* Mixing flags */ + +/* These ones take effect only after MikMod_Init or MikMod_Reset */ +#define DMODE_16BITS 0x0001 /* enable 16 bit output */ +#define DMODE_STEREO 0x0002 /* enable stereo output */ +#define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */ +#define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */ +#define DMODE_HQMIXER 0x0010 /* Use high-quality (slower) software mixer */ +/* These take effect immediately. */ +#define DMODE_SURROUND 0x0100 /* enable surround sound */ +#define DMODE_INTERP 0x0200 /* enable interpolation */ +#define DMODE_REVERSE 0x0400 /* reverse stereo */ + +struct SAMPLOAD; +typedef struct MDRIVER { +struct MDRIVER* next; + CHAR* Name; + CHAR* Version; + + UBYTE HardVoiceLimit; /* Limit of hardware mixer voices */ + UBYTE SoftVoiceLimit; /* Limit of software mixer voices */ + + CHAR* Alias; + + void (*CommandLine) (CHAR*); + BOOL (*IsPresent) (void); + SWORD (*SampleLoad) (struct SAMPLOAD*,int); + void (*SampleUnload) (SWORD); + ULONG (*FreeSampleSpace) (int); + ULONG (*RealSampleLength) (int,struct SAMPLE*); + BOOL (*Init) (void); + void (*Exit) (void); + BOOL (*Reset) (void); + BOOL (*SetNumVoices) (void); + BOOL (*PlayStart) (void); + void (*PlayStop) (void); + void (*Update) (void); + void (*Pause) (void); + void (*VoiceSetVolume) (UBYTE,UWORD); + UWORD (*VoiceGetVolume) (UBYTE); + void (*VoiceSetFrequency)(UBYTE,ULONG); + ULONG (*VoiceGetFrequency)(UBYTE); + void (*VoiceSetPanning) (UBYTE,ULONG); + ULONG (*VoiceGetPanning) (UBYTE); + void (*VoicePlay) (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); + void (*VoiceStop) (UBYTE); + BOOL (*VoiceStopped) (UBYTE); + SLONG (*VoiceGetPosition) (UBYTE); + ULONG (*VoiceRealVolume) (UBYTE); } MDRIVER; - -/* These variables can be changed at ANY time and results */ -/* will be immidiate: */ - -extern UBYTE md_bpm; /* current song / hardware BPM rate */ -extern UBYTE md_volume; /* Global sound volume (0-128) */ -extern UBYTE md_musicvolume; /* volume of song */ -extern UBYTE md_sndfxvolume; /* volume of sound effects */ -extern UBYTE md_reverb; /* 0 = none; 15 = chaos */ -extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */ - - -/* The variables below can be changed at any time, but changes will */ -/* not be implimented until MikMod_Reset is called. A call to */ -/* MikMod_Reset may result in a skip or pop in audio (depending on */ -/* the soundcard driver and the settings changed). */ - -extern UWORD md_device; /* Device. 0 = autodetect, other # depend on driver register order. */ -extern UWORD md_mixfreq; /* mixing frequency. Valid 5000 -> 44100 */ -extern UWORD md_dmabufsize; /* DMA buffer size. Valid 512 -> 32000 */ -extern UWORD md_mode; /* Mode. See DMODE_? flags above */ - - -/* Variables below can be changed via MD_SetNumVoices at any time. */ -/* However, a call to MD_SetNumVoicess while the driver */ -/* is active will cause the sound to skip slightly. */ - -extern UBYTE md_numchn, /* number of song + sound effects voices */ - md_sngchn, /* number of song voices */ - md_sfxchn, /* number of sound effects voices */ - md_hardchn, /* number of hardware mixed voices */ - md_softchn; /* number of software mixed voices */ - - -/* Following variables should not be changed! */ -extern MDRIVER *md_driver; /* Current driver in use. See MDRIVER struct */ - /* above for structure info contents. */ - -/* This is for use by the hardware drivers only. It points to the */ -/* registered tickhandler function. */ -extern void (*md_player)(void); - - -/* main driver prototypes: */ - -extern void MikMod_RegisterAllDrivers(void); -extern void MikMod_RegisterAllLoaders(void); - -extern BOOL MikMod_Init(void); -extern void MikMod_Exit(void); -extern BOOL MikMod_Reset(void); -extern int MikMod_PlaySample(SAMPLE *s, ULONG start, UBYTE flags); -extern BOOL MikMod_SetNumVoices(int music, int sndfx); -extern BOOL MikMod_Active(void); -extern BOOL MikMod_EnableOutput(void); -extern void MikMod_DisableOutput(void); -extern void MikMod_RegisterPlayer(void (*plr)(void)); -extern void MikMod_Update(void); - -extern void Voice_SetVolume(int voice, UWORD ivol); -extern void Voice_SetFrequency(int voice, ULONG frq); -extern void Voice_SetPanning(int voice, ULONG pan); -extern void Voice_Play(int voice,SAMPLE *s, ULONG start); -extern void Voice_Stop(int voice); -extern void Voice_ReleaseSustain(int voice); -extern BOOL Voice_Stopped(int voice); -extern SLONG Voice_GetPosition(int voice); -extern ULONG Voice_RealVolume(int voice); - -extern void MD_InfoDriver(void); -extern void MD_RegisterDriver(MDRIVER *drv); -extern SWORD MD_SampleLoad(SAMPLOAD *s, int type, FILE *fp); -extern void MD_SampleUnLoad(SWORD handle); -extern void MD_SetBPM(UBYTE bpm); -extern ULONG MD_SampleSpace(int type); -extern ULONG MD_SampleLength(int type, SAMPLE *s); - -/* Declare external drivers: */ - -extern MDRIVER drv_sdl; /* Simple DirectMedia Layer driver */ -extern MDRIVER drv_nos; /* nosound driver */ - - -/************************************************************************** -****** Streaming Audio stuff: ********************************************* -**************************************************************************/ - - -typedef struct MSTREAM -{ struct MSTREAM *next; - CHAR *type; - CHAR *version; - BOOL (*Init)(void); - BOOL (*Test)(void); - BOOL (*Load)(void); - void (*Cleanup)(void); -} MSTREAM; - - -extern int stream_bufsize; -extern FILE *stream_fp; -extern SLONG stream_seekpos; -extern SLONG stream_reppos; - - -/************************************************************************** -****** Virtual channel stuff: ********************************************* -**************************************************************************/ - -extern BOOL VC_Init(void); -extern void VC_Exit(void); -extern BOOL VC_SetNumVoices(void); -extern ULONG VC_SampleSpace(int type); -extern ULONG VC_SampleLength(int type, SAMPLE *s); - -extern BOOL VC_PlayStart(void); -extern void VC_PlayStop(void); - -/* extern SWORD VC_SampleLoad(SAMPLOAD *sload, int type, FILE *fp); */ -extern SWORD VC_SampleLoad(SAMPLOAD *sload, int type); -extern void VC_SampleUnload(SWORD handle); - -extern void VC_WriteSamples(SBYTE *buf,ULONG todo); -extern ULONG VC_WriteBytes(SBYTE *buf,ULONG todo); -extern void VC_SilenceBytes(SBYTE *buf,ULONG todo); - -extern void VC_VoiceSetVolume(UBYTE voice, UWORD vol); -extern void VC_VoiceSetFrequency(UBYTE voice, ULONG frq); -extern void VC_VoiceSetPanning(UBYTE voice, ULONG pan); -extern void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags); - -extern void VC_VoiceStop(UBYTE voice); -extern BOOL VC_VoiceStopped(UBYTE voice); -extern void VC_VoiceReleaseSustain(UBYTE voice); -extern SLONG VC_VoiceGetPosition(UBYTE voice); -extern ULONG VC_VoiceRealVolume(UBYTE voice); - - -extern BOOL VC2_Init(void); -extern void VC2_Exit(void); -extern BOOL VC2_SetNumVoices(void); -extern ULONG VC2_SampleSpace(int type); -extern ULONG VC2_SampleLength(int type, SAMPLE *s); - -extern BOOL VC2_PlayStart(void); -extern void VC2_PlayStop(void); - -extern SWORD VC2_SampleLoad(SAMPLOAD *sload, int type, FILE *fp); -extern void VC2_SampleUnload(SWORD handle); - -extern void VC2_WriteSamples(SBYTE *buf,ULONG todo); -extern ULONG VC2_WriteBytes(SBYTE *buf,ULONG todo); -extern void VC2_SilenceBytes(SBYTE *buf,ULONG todo); - -extern void VC2_VoiceSetVolume(UBYTE voice, UWORD vol); -extern void VC2_VoiceSetFrequency(UBYTE voice, ULONG frq); -extern void VC2_VoiceSetPanning(UBYTE voice, ULONG pan); -extern void VC2_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags); - -extern void VC2_VoiceStop(UBYTE voice); -extern BOOL VC2_VoiceStopped(UBYTE voice); -extern void VC2_VoiceReleaseSustain(UBYTE voice); -extern SLONG VC2_VoiceGetPosition(UBYTE voice); +/* These variables can be changed at ANY time and results will be immediate */ +MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */ +MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */ +MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */ +MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */ +MIKMODAPI extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */ + +/* The variables below can be changed at any time, but changes will not be + implemented until MikMod_Reset is called. A call to MikMod_Reset may result + in a skip or pop in audio (depending on the soundcard driver and the settings + changed). */ +MIKMODAPI extern UWORD md_device; /* device */ +MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */ +MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */ + +/* The following variable should not be changed! */ +MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */ + +/* Known drivers list */ + +MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */ +MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */ +MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */ +MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */ +MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */ + +MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */ + +MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */ +MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */ +MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */ +MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */ +MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */ +MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */ +MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */ +MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */ + +MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */ +MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */ + +MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */ +MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */ + +MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */ + +/*========== Virtual channel mixer interface (for user-supplied drivers only) */ + +MIKMODAPI extern BOOL VC_Init(void); +MIKMODAPI extern void VC_Exit(void); +MIKMODAPI extern BOOL VC_SetNumVoices(void); +MIKMODAPI extern ULONG VC_SampleSpace(int); +MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*); + +MIKMODAPI extern BOOL VC_PlayStart(void); +MIKMODAPI extern void VC_PlayStop(void); + +MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int); +MIKMODAPI extern void VC_SampleUnload(SWORD); + +MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG); +MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG); + +MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD); +MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE); +MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG); +MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE); +MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG); +MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE); +MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD); + +MIKMODAPI extern void VC_VoiceStop(UBYTE); +MIKMODAPI extern BOOL VC_VoiceStopped(UBYTE); +MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE); +MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE); #ifdef __cplusplus } #endif #endif + +/* ex:set ts=4: */ diff --git a/mikmod/mloader.c b/mikmod/mloader.c index 36ebc3df..cc3b24f5 100644 --- a/mikmod/mloader.c +++ b/mikmod/mloader.c @@ -1,399 +1,528 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ -Name: MLOADER.C +/*============================================================================== -Description: - These routines are used to access the available module loaders + $Id$ -Portability: - All systems - all compilers + These routines are used to access the available module loaders -*/ +==============================================================================*/ -#include -#include "mikmod.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_MEMORY_H +#include +#endif -FILE *modfp; -UNIMOD of; +#include "mikmod_internals.h" -static MLOADER *firstloader = NULL; +#include -UWORD finetune[16] = -{ 8363, 8413, 8463, 8529, 8581, 8651, 8723, 8757, - 7895, 7941, 7985, 8046, 8107, 8169, 8232, 8280 -}; + MREADER *modreader; + MODULE of; +static MLOADER *firstloader=NULL; -void ML_InfoLoader(void) -{ - int t; - MLOADER *l; - - /* list all registered devicedrivers: */ +UWORD finetune[16]={ + 8363,8413,8463,8529,8581,8651,8723,8757, + 7895,7941,7985,8046,8107,8169,8232,8280 +}; - for(t=1,l=firstloader; l!=NULL; l=l->next, t++) - printf("%d. %s\n",t,l->version); +CHAR* MikMod_InfoLoader(void) +{ + int len=0; + MLOADER *l; + CHAR *list=NULL; + + MUTEX_LOCK(lists); + /* compute size of buffer */ + for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version); + + if(len) + if((list=_mm_malloc(len*sizeof(CHAR)))) { + list[0]=0; + /* list all registered module loders */ + for(l=firstloader;l;l=l->next) + sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version); + } + MUTEX_UNLOCK(lists); + return list; } - -void ML_RegisterLoader(MLOADER *ldr) +void _mm_registerloader(MLOADER* ldr) { - MLOADER *cruise = firstloader; + MLOADER *cruise=firstloader; - if(cruise!=NULL) - { while(cruise->next!=NULL) cruise = cruise->next; - cruise->next = ldr; - } else - firstloader = ldr; + if(cruise) { + while(cruise->next) cruise = cruise->next; + cruise->next=ldr; + } else + firstloader=ldr; } +void MikMod_RegisterLoader(struct MLOADER* ldr) +{ + /* if we try to register an invalid loader, or an already registered loader, + ignore this attempt */ + if ((!ldr)||(ldr->next)) + return; + + MUTEX_LOCK(lists); + _mm_registerloader(ldr); + MUTEX_UNLOCK(lists); +} BOOL ReadComment(UWORD len) { - /*int t; */ - - if(len) - { if(!(of.comment=(CHAR *)_mm_malloc(len+1))) return 0; - fread(of.comment,len,1,modfp); - of.comment[len] = 0; - } - return 1; + if(len) { + int i; + + if(!(of.comment=(CHAR*)_mm_malloc(len+1))) return 0; + _mm_read_UBYTES(of.comment,len,modreader); + + /* translate IT linefeeds */ + for(i=0;i=0)&&(line[i]==' ');i--) line[i]=0; + for(i=0;ilines) { + if(!(of.comment=(CHAR*)_mm_malloc(total+1))) { + free(storage); + free(tempcomment); + return 0; + } + + /* convert message */ + for(line=tempcomment,t=0;tlength) SL_RegisterSample(s,MD_MUSIC,modfp); + for(u=of.numsmp,s=of.samples;u;u--,s++) + if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader); - return 1; + return 1; } - -CHAR *DupStr(CHAR *s, UWORD len) -/* Creates a CSTR out of a character buffer of 'len' bytes, but strips */ -/* any terminating non-printing characters like 0, spaces etc. */ +/* Creates a CSTR out of a character buffer of 'len' bytes, but strips any + terminating non-printing characters like 0, spaces etc. */ +CHAR *DupStr(CHAR* s,UWORD len,BOOL strict) { - UWORD t; - CHAR *d = NULL; - - /* Scan for first printing char in buffer [includes high ascii up to 254] */ - while(len) - { if(s[len-1] > 0x20) break; - len--; - } - - /* When the buffer wasn't completely empty, allocate */ - /* a cstring and copy the buffer into that string, except */ - /* for any control-chars */ - -#ifdef __GNUC__ - if(len<16) len = 16; -#endif - - if((d=(CHAR *)_mm_malloc(len+1)) != NULL) - { for(t=0; t0x20) break; + len--; + } + + /* Scan forward for possible NULL character */ + if(strict) { + for(t=0;thandle>=0) - MD_SampleUnLoad(s->handle); - if(s->samplename!=NULL) free(s->samplename); + if(s->handle>=0) + MD_SampleUnload(s->handle); + if(s->samplename) free(s->samplename); } - static void ML_XFreeInstrument(INSTRUMENT *i) { - if(i->insname!=NULL) free(i->insname); + if(i->insname) free(i->insname); } - -static void ML_FreeEx(UNIMOD *mf) +static void ML_FreeEx(MODULE *mf) { - UWORD t; - - if(mf->songname!=NULL) free(mf->songname); - if(mf->composer!=NULL) free(mf->composer); - if(mf->comment!=NULL) free(mf->comment); - - if(mf->modtype!=NULL) free(mf->modtype); - if(mf->positions!=NULL) free(mf->positions); - if(mf->patterns!=NULL) free(mf->patterns); - if(mf->pattrows!=NULL) free(mf->pattrows); - - if(mf->tracks!=NULL) - { for(t=0; tnumtrk; t++) - if(mf->tracks[t]!=NULL) free(mf->tracks[t]); - free(mf->tracks); - } - - if(mf->instruments != NULL) - { for(t=0; tnumins; t++) - ML_XFreeInstrument(&mf->instruments[t]); - free(mf->instruments); - } - - if(mf->samples != NULL) - { for(t=0; tnumsmp; t++) - if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]); - free(mf->samples); - } - - memset(mf,0,sizeof(UNIMOD)); + UWORD t; + + if(mf->songname) free(mf->songname); + if(mf->comment) free(mf->comment); + + if(mf->modtype) free(mf->modtype); + if(mf->positions) free(mf->positions); + if(mf->patterns) free(mf->patterns); + if(mf->pattrows) free(mf->pattrows); + + if(mf->tracks) { + for(t=0;tnumtrk;t++) + if(mf->tracks[t]) free(mf->tracks[t]); + free(mf->tracks); + } + if(mf->instruments) { + for(t=0;tnumins;t++) + ML_XFreeInstrument(&mf->instruments[t]); + free(mf->instruments); + } + if(mf->samples) { + for(t=0;tnumsmp;t++) + if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]); + free(mf->samples); + } + memset(mf,0,sizeof(MODULE)); + if(mf!=&of) free(mf); } - -static UNIMOD *ML_AllocUniMod(void) +static MODULE *ML_AllocUniMod(void) { - UNIMOD *mf; - - if((mf=_mm_calloc(1,sizeof(UNIMOD))) == NULL) return NULL; - return mf; -} - - -/****************************************** - - Next are the user-callable functions - -******************************************/ + MODULE *mf; + return (mf=_mm_malloc(sizeof(MODULE))); +} -void MikMod_FreeSong(UNIMOD *mf) +void Player_Free_internal(MODULE *mf) { - if(mf!=NULL) - { Player_Exit(mf); - ML_FreeEx(mf); - } + if(mf) { + Player_Exit_internal(mf); + ML_FreeEx(mf); + } } - -CHAR *MikMod_LoadSongTitle(CHAR *filename) +void Player_Free(MODULE *mf) { - MLOADER *l; - CHAR *retval; - FILE *fp; - - if((fp = _mm_fopen(filename,"rb"))==NULL) return NULL; - - _mm_errno = 0; - _mm_critical = 0; - _mm_iobase_setcur(modfp); - - /* Try to find a loader that recognizes the module */ - - for(l=firstloader; l!=NULL; l=l->next) - { _mm_rewind(modfp); - if(l->Test()) break; - } + MUTEX_LOCK(vars); + Player_Free_internal(mf); + MUTEX_UNLOCK(vars); +} - if(l==NULL) - { _mm_errno = MMERR_NOT_A_MODULE; - _mm_iobase_revert(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } +static CHAR* Player_LoadTitle_internal(MREADER *reader) +{ + MLOADER *l; + + modreader=reader; + _mm_errno = 0; + _mm_critical = 0; + _mm_iobase_setcur(modreader); + + /* Try to find a loader that recognizes the module */ + for(l=firstloader;l;l=l->next) { + _mm_rewind(modreader); + if(l->Test()) break; + } + + if(!l) { + _mm_errno = MMERR_NOT_A_MODULE; + if(_mm_errorhandler) _mm_errorhandler(); + return NULL; + } + + return l->LoadTitle(); +} - retval = l->LoadTitle(); +CHAR* Player_LoadTitle(CHAR* filename) +{ + CHAR* result=NULL; + FILE* fp; + MREADER* reader; + + if((fp=_mm_fopen(filename,"rb"))) { + if((reader=_mm_new_file_reader(fp))) { + MUTEX_LOCK(lists); + result=Player_LoadTitle_internal(reader); + MUTEX_UNLOCK(lists); + _mm_delete_file_reader(reader); + } + fclose(fp); + } + return result; +} - fclose(fp); - return(retval); +/* Loads a module given an reader */ +MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious) +{ + int t; + MLOADER *l; + BOOL ok; + MODULE *mf; + + modreader = reader; + _mm_errno = 0; + _mm_critical = 0; + _mm_iobase_setcur(modreader); + + /* Try to find a loader that recognizes the module */ + for(l=firstloader;l;l=l->next) { + _mm_rewind(modreader); + if(l->Test()) break; + } + + if(!l) { + _mm_errno = MMERR_NOT_A_MODULE; + if(_mm_errorhandler) _mm_errorhandler(); + _mm_rewind(modreader);_mm_iobase_revert(); + return NULL; + } + + /* init unitrk routines */ + if(!UniInit()) { + if(_mm_errorhandler) _mm_errorhandler(); + _mm_rewind(modreader);_mm_iobase_revert(); + return NULL; + } + + /* load the song using the song's loader variable */ + memset(&of,0,sizeof(MODULE)); + of.initvolume = 128; + + /* init panning array */ + for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0; + for(t=0; t<64; t++) of.chanvol[t] = 64; + + /* init module loader and load the header / patterns */ + if(l->Init()) { + _mm_rewind(modreader); + ok = l->Load(curious); + } else + ok = 0; + + /* free loader and unitrk allocations */ + l->Cleanup(); + UniCleanup(); + + if(!ok) { + ML_FreeEx(&of); + if(_mm_errorhandler) _mm_errorhandler(); + _mm_rewind(modreader);_mm_iobase_revert(); + return NULL; + } + + if(!ML_LoadSamples()) { + ML_FreeEx(&of); + if(_mm_errorhandler) _mm_errorhandler(); + _mm_rewind(modreader);_mm_iobase_revert(); + return NULL; + } + + if(!(mf=ML_AllocUniMod())) { + ML_FreeEx(&of); + _mm_rewind(modreader);_mm_iobase_revert(); + if(_mm_errorhandler) _mm_errorhandler(); + return NULL; + } + + /* Copy the static MODULE contents into the dynamic MODULE struct. */ + memcpy(mf,&of,sizeof(MODULE)); + _mm_iobase_revert(); + + if(maxchan>0) { + if(!(mf->flags&UF_NNA)&&(mf->numchnnumchn; + else + if((mf->numvoices)&&(mf->numvoicesnumvoices; + + if(maxchannumchn) mf->flags |= UF_NNA; + + if(MikMod_SetNumVoices_internal(maxchan,-1)) { + Player_Free(mf); + return NULL; + } + } + if(SL_LoadSamples()) { + Player_Free_internal(mf); + return NULL; + } + if(Player_Init(mf)) { + Player_Free_internal(mf); + mf=NULL; + } + return mf; } +MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious) +{ + MODULE* result; -UNIMOD *MikMod_LoadSongFP(FILE *fp, int maxchan) + MUTEX_LOCK(vars); + MUTEX_LOCK(lists); + result=Player_LoadGeneric_internal(reader,maxchan,curious); + MUTEX_UNLOCK(lists); + MUTEX_UNLOCK(vars); -/* Loads a module given a file pointer. */ -/* File is loaded from the current file seek position. */ + return result; +} +/* Loads a module given a file pointer. + File is loaded from the current file seek position. */ +MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious) { - int t; - MLOADER *l; - BOOL ok; - UNIMOD *mf; - - modfp = fp; - _mm_errno = 0; - _mm_critical = 0; - - _mm_iobase_setcur(modfp); - - /* Try to find a loader that recognizes the module */ - - for(l=firstloader; l!=NULL; l=l->next) - { _mm_rewind(modfp); - if(l->Test()) break; - } - - if(l==NULL) - { _mm_errno = MMERR_NOT_A_MODULE; - _mm_iobase_revert(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } - - /* init unitrk routines */ - if(!UniInit()) - { if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } - - /* load the song using the song's loader variable */ - memset(&of,0,sizeof(UNIMOD)); - of.initvolume = 128; - - /* init panning array */ - for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0; - for(t=0; t<64; t++) of.chanvol[t] = 64; - - /* init module loader and load the header / patterns */ - if(l->Init()) - { _mm_rewind(modfp); - ok = l->Load(); - } else ok = 0; - - /* free loader and unitrk allocations */ - l->Cleanup(); - UniCleanup(); - - if(!ok) - { ML_FreeEx(&of); - _mm_iobase_revert(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } - - if(!ML_LoadSamples()) - { ML_FreeEx(&of); - _mm_iobase_revert(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } - - if((mf=ML_AllocUniMod()) == NULL) - { ML_FreeEx(&of); - _mm_iobase_revert(); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } - - /* Copy the static UNIMOD contents into the dynamic UNIMOD struct. */ - memcpy(mf,&of,sizeof(UNIMOD)); - - _mm_iobase_revert(); - - if(maxchan > 0) - { if(!(mf->flags & UF_NNA) && (mf->numchn < maxchan)) - maxchan = mf->numchn; - else if((mf->numvoices!=0) && mf->numvoices < maxchan) - maxchan = mf->numvoices; - - if(maxchan < mf->numchn) mf->flags |= UF_NNA; - - if(MikMod_SetNumVoices(maxchan,-1)) - { MikMod_FreeSong(mf); - return NULL; - } - } - - return mf; + MODULE* result=NULL; + struct MREADER* reader=_mm_new_file_reader (fp); + + if (reader) { + result=Player_LoadGeneric(reader,maxchan,curious); + _mm_delete_file_reader(reader); + } + return result; } - -UNIMOD *MikMod_LoadSong(CHAR *filename, int maxchan) - -/* Open a module via it's filename. The loader will initialize the specified */ -/* song-player 'player'. */ - +/* Open a module via its filename. The loader will initialize the specified + song-player 'player'. */ +MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious) { - FILE *fp; - UNIMOD *mf; - - if((fp = _mm_fopen(filename,"rb"))==NULL) return NULL; - if((mf = MikMod_LoadSongFP(fp, maxchan)) != NULL) - { if(SL_LoadSamples() || Player_Init(mf)) - { MikMod_FreeSong(mf); - mf = NULL; - } - } - - fclose(fp); - return mf; + FILE *fp; + MODULE *mf=NULL; + + if((fp=_mm_fopen(filename,"rb"))) { + mf=Player_LoadFP(fp,maxchan,curious); + fclose(fp); + } + return mf; } +/* ex:set ts=4: */ diff --git a/mikmod/mlreg.c b/mikmod/mlreg.c index 265fe134..b31192fe 100644 --- a/mikmod/mlreg.c +++ b/mikmod/mlreg.c @@ -1,22 +1,70 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. - Name: MLREG.C + 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. - Description: - A single routine for registering all loaders in MikMod for the current - platform. - - Portability: - All systems - all compilers + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ -#include "mikmod.h" +/*============================================================================== + + $Id$ + + Routine for registering all loaders in libmikmod for the current platform. + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mikmod_internals.h" + +void MikMod_RegisterAllLoaders_internal(void) +{ +#if 1 + _mm_registerloader(&load_it); + _mm_registerloader(&load_mod); + _mm_registerloader(&load_s3m); + _mm_registerloader(&load_xm); +#else + _mm_registerloader(&load_669); + _mm_registerloader(&load_amf); + _mm_registerloader(&load_dsm); + _mm_registerloader(&load_far); + _mm_registerloader(&load_gdm); + _mm_registerloader(&load_it); + _mm_registerloader(&load_imf); + _mm_registerloader(&load_mod); + _mm_registerloader(&load_med); + _mm_registerloader(&load_mtm); + _mm_registerloader(&load_s3m); + _mm_registerloader(&load_stm); + _mm_registerloader(&load_stx); + _mm_registerloader(&load_ult); + _mm_registerloader(&load_uni); + _mm_registerloader(&load_xm); + + _mm_registerloader(&load_m15); +#endif +} void MikMod_RegisterAllLoaders(void) { - MikMod_RegisterLoader(load_it); - MikMod_RegisterLoader(load_xm); - MikMod_RegisterLoader(load_s3m); - MikMod_RegisterLoader(load_mod); + MUTEX_LOCK(lists); + MikMod_RegisterAllLoaders_internal(); + MUTEX_UNLOCK(lists); } +/* ex:set ts=4: */ diff --git a/mikmod/mmalloc.c b/mikmod/mmalloc.c index 270a00b8..b25c8388 100644 --- a/mikmod/mmalloc.c +++ b/mikmod/mmalloc.c @@ -1,63 +1,59 @@ -/* - --> The MMIO Portable Memory Management functions - -> Divine Entertainment GameDev Libraries - - Copyright © 1997 by Jake Stine and Divine Entertainment - +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ -#include -#include "mmio.h" +/*============================================================================== + $Id$ -/* Same as malloc, but sets error variable _mm_error when it failed */ -void *_mm_malloc(size_t size) -{ - void *d; + Dynamic memory routines - if((d=malloc(size))==NULL) - { _mm_errno = MMERR_OUT_OF_MEMORY; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - } +==============================================================================*/ - return d; -} +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "mikmod_internals.h" -/* Same as calloc, but sets error variable _mm_error when it failed */ -void *_mm_calloc(size_t nitems, size_t size) +/* Same as malloc, but sets error variable _mm_error when fails */ +void* _mm_malloc(size_t size) { - void *d; - - if((d=calloc(nitems,size))==NULL) - { _mm_errno = MMERR_OUT_OF_MEMORY; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - } - - return d; -} + void *d; + if(!(d=calloc(1,size))) { + _mm_errno = MMERR_OUT_OF_MEMORY; + if(_mm_errorhandler) _mm_errorhandler(); + } + return d; +} -#ifndef __WATCOMC__ -#ifndef __GNUC__ -#ifndef __BEOS__ -#ifndef _SGI_SOURCE -/* Same as Watcom's strdup function - allocates memory for a string */ -/* and makes a copy of it. Ruturns NULL if failed. */ -CHAR *strdup(CHAR *src) +/* Same as calloc, but sets error variable _mm_error when fails */ +void* _mm_calloc(size_t nitems,size_t size) { - CHAR *buf; + void *d; - if((buf = (CHAR *)_mm_malloc(strlen(src)+1)) == NULL) - { _mm_errno = MMERR_OUT_OF_MEMORY; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return NULL; - } - - strcpy(buf,src); - return buf; + if(!(d=calloc(nitems,size))) { + _mm_errno = MMERR_OUT_OF_MEMORY; + if(_mm_errorhandler) _mm_errorhandler(); + } + return d; } -#endif -#endif -#endif -#endif + +/* ex:set ts=4: */ diff --git a/mikmod/mmerror.c b/mikmod/mmerror.c index 6090bc2c..98747774 100644 --- a/mikmod/mmerror.c +++ b/mikmod/mmerror.c @@ -1,103 +1,197 @@ -/* - --> The MM_Error Portable Error Handling Functions - -> Divine Entertainment GameDev Libraries +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ - File: MMERROR.C +/*============================================================================== - Description: - Error handling functions for use with the DivEnt MMIO and MikMod - libraries. Register an error handler with _mm_RegisterErrorHandler() - and you're all set. + $Id$ - NOTES: + Error handling functions. + Register an error handler with _mm_RegisterErrorHandler() and you're all set. - - the global variables _mm_error, _mm_errno, and _mm_critical are - set before the error handler in called. See below for the values - of these variables. +==============================================================================*/ --------------------------- +/* + The global variables _mm_errno, and _mm_critical are set before the error + handler in called. See below for the values of these variables. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -#include "mmio.h" +#include "mikmod_internals.h" -CHAR *_mm_errmsg[] = +CHAR *_mm_errmsg[MMERR_MAX+1] = { - "", - -/* Generic MikMod Errors [referenced by _mm_error] */ -/* ----------------------------------------------- */ - - "Cannot open requested file", - "Out of memory", - "Unexpected end of file", - "Cannot write to file - Disk full", - -/* Specific Misceallenous Errors: */ - - "Sample load failed - Out of memory", - "Sample load failed - Out of sample handles", - "Could not allocate page-contiguous dma-buffer", - "Unknown wave file or sample type", - "Unknown streaming audio type", - -/* Specific Module Loader [MLOADER.C] errors: */ - - "Failure loading module pattern", - "Failure loading module track", - "Failure loading module header", - "Failure loading sampleinfo", - "Unknown module format", - -/* Specific Driver [MDRIVER.C / drivers] errors: */ - - "None of the supported sound-devices were detected", - "Device number out of range", - "Software mixer failure - Out of memory", - -#ifdef SUN -#elif defined(SOLARIS) -#elif defined(__alpha) - "Cannot find suitable audio port!" -#elif defined(OSS) - #ifdef ULTRA - #endif -#elif defined(__hpux) - "Unable to open /dev/audio", - "Unable to set non-blocking mode for /dev/audio", - "Unable to select 16bit-linear sample format", - "Could not select requested sample-rate", - "Could not select requested number of channels", - "Unable to select audio output", - "Unable to get audio description", - "Unable to get gain values", - "Unable to set gain values", - "Could not set transmission buffer size" -#elif defined(AIX) - "Could not open AIX audio device", - "Configuration (init) of AIX audio device failed", - "Configuration (control) of AIX audio device failed", - "Configuration (start) of AIX audio device failed", - "Unable to set non-blocking mode for /dev/audio", -#elif defined(SGI) -#elif defined(__OS2__) -#elif defined(__WIN32__) -#else - "The requested soundcard was not found", - "Could not open a High-DMA channel" -#endif +/* No error */ + + "No error", + +/* Generic errors */ + + "Could not open requested file", + "Out of memory", + "Dynamic linking failed", + +/* Sample errors */ + + "Out of memory to load sample", + "Out of sample handles to load sample", + "Sample format not recognized", + +/* Module errors */ + + "Failure loading module pattern", + "Failure loading module track", + "Failure loading module header", + "Failure loading sampleinfo", + "Module format not recognized", + "Module sample format not recognized", + "Synthsounds not supported in MED files", + "Compressed sample is invalid", + +/* Driver errors: */ + + "Sound device not detected", + "Device number out of range", + "Software mixer failure", + "Could not open sound device", + "This driver supports 8 bit linear output only", + "This driver supports 16 bit linear output only", + "This driver supports stereo output only", + "This driver supports uLaw output (8 bit mono, 8 kHz) only", + "Unable to set non-blocking mode for audio device", + +/* AudioFile driver errors */ + + "Cannot find suitable AudioFile audio port", + +/* AIX driver errors */ + + "Configuration (init step) of audio device failed", + "Configuration (control step) of audio device failed", + "Configuration (start step) of audio device failed", + +/* ALSA driver errors */ + +/* EsounD driver errors */ + +/* Ultrasound driver errors */ + + "Ultrasound driver only works in 16 bit stereo 44 KHz", + "Ultrasound card could not be reset", + "Could not start Ultrasound timer", + +/* HP driver errors */ + + "Unable to select 16bit-linear sample format", + "Could not select requested sample-rate", + "Could not select requested number of channels", + "Unable to select audio output", + "Unable to get audio description", + "Could not set transmission buffer size", + +/* Open Sound System driver errors */ + + "Could not set fragment size", + "Could not set sample size", + "Could not set mono/stereo setting", + "Could not set sample rate", + +/* SGI driver errors */ + + "Unsupported sample rate", + "Hardware does not support 16 bit sound", + "Hardware does not support 8 bit sound", + "Hardware does not support stereo sound", + "Hardware does not support mono sound", + +/* Sun driver errors */ + + "Sound device initialization failed", + +/* OS/2 drivers errors */ + + "Could not set mixing parameters", + "Could not create playback semaphores", + "Could not create playback timer", + "Could not create playback thread", + +/* DirectSound driver errors */ + + "Could not set playback priority", + "Could not create playback buffers", + "Could not set playback format", + "Could not register callback", + "Could not register event", + "Could not create playback thread", + "Could not initialize playback thread", + +/* Windows Multimedia API driver errors */ + + "Invalid device handle", + "The resource is already allocated", + "Invalid device identifier", + "Unsupported output format", + "Unknown error", + +/* Macintosh driver errors */ + + "Unsupported sample rate", + "Could not start playback", + +/* Invalid error */ + + "Invalid error code" }; +char *MikMod_strerror(int code) +{ + if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX+1; + return _mm_errmsg[code]; +} -void (*_mm_errorhandler)(void) = NULL; -int _mm_errno = 0; -BOOL _mm_critical = 0; +/* User installed error callback */ +MikMod_handler_t _mm_errorhandler = NULL; +int _mm_errno = 0; +BOOL _mm_critical = 0; +MikMod_handler_t _mm_registererrorhandler(MikMod_handler_t proc) +{ + MikMod_handler_t oldproc=_mm_errorhandler; + + _mm_errorhandler = proc; + return oldproc; +} -void _mm_RegisterErrorHandler(void (*proc)(void)) +MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t proc) { - _mm_errorhandler = proc; + MikMod_handler_t result; + + MUTEX_LOCK(vars); + result=_mm_registererrorhandler(proc); + MUTEX_UNLOCK(vars); + + return result; } +/* ex:set ts=4: */ diff --git a/mikmod/mmio.c b/mikmod/mmio.c index a67309d3..1695f2cc 100644 --- a/mikmod/mmio.c +++ b/mikmod/mmio.c @@ -1,457 +1,360 @@ -/* - --> The MMIO Portable Input/Output functions - -> Divine Entertainment GameDev Libraries - - File: MMIO.C - - Description: - Miscellaneous I/O routines.. used to solve some portability issues - (like big/little endian machines and word alignment in structures ) - Also includes mikmod's ingenious error handling variable. +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. - Portability: - All systems - all compilers + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Library General Public License for more details. - ----------------------------------- - The way this module works - By Jake Stine [Air Richter] + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ - - _mm_fopen and _mm_copyfile will call the errorhandler [see mmerror.c] in - addition to setting _mm_errno on exit. +/*============================================================================== - - _mm_iobase is for internal use. It is used by ML_LoadFP() to ensure that it - works properly with wad files. + $Id$ - - _mm_read_I_UWORD and _mm_read_M_UWORD have distinct differences: - the first is for reading data written by a little endian (intel) machine, - and the second is for reading big endian (Mac, RISC, Alpha) machine data. + Portable file I/O routines - - _mm_write functions work the same as the _mm_read functions. +==============================================================================*/ - - _mm_read_string is for reading binary strings. It is basically the same - as an fread of bytes. -*/ - -#include -#include "mmio.h" -#include +/* -#define COPY_BUFSIZE 1024 + The way this module works: -static long _mm_iobase = 0, - temp_iobase = 0; + - _mm_fopen will call the errorhandler [see mmerror.c] in addition to + setting _mm_errno on exit. + - _mm_iobase is for internal use. It is used by Player_LoadFP to + ensure that it works properly with wad files. + - _mm_read_I_* and _mm_read_M_* differ : the first is for reading data + written by a little endian (intel) machine, and the second is for reading + big endian (Mac, RISC, Alpha) machine data. + - _mm_write functions work the same as the _mm_read functions. + - _mm_read_string is for reading binary strings. It is basically the same + as an fread of bytes. -UBYTE _mm_cpybuf[COPY_BUFSIZE]; +*/ +/* FIXME + the _mm_iobase variable ought to be MREADER-specific. It will eventually + become a private field of the MREADER structure, but this will require a + soname version bump. -void StringWrite(CHAR *s, FILE *fp) -/* Specialized file output procedure. Writes a UWORD length and then a */ -/* string of the specified length (no NULL terminator) afterward. */ -{ - int slen; + In the meantime, the drawback is that if you use the xxx_LoadFP functions, + you can't have several MREADER objects with different iobase values. +*/ - if(s==NULL) - { _mm_write_I_UWORD(0,fp); - } else - { _mm_write_I_UWORD(slen = strlen(s),fp); - _mm_write_UBYTES(s,slen,fp); - } -} +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -CHAR *StringRead(FILE *fp) -/* Reads strings written out by StringWrite above: a UWORD length followed */ -/* by length characters. A NULL is added to the string after loading. */ -{ - CHAR *s; - UWORD len; +#include +#include - len = _mm_read_I_UWORD(fp); - if(len==0) - { s = _mm_calloc(16, sizeof(CHAR)); - } else - { if((s = (CHAR *)_mm_malloc(len+1)) == NULL) return NULL; - _mm_read_UBYTES(s,len,fp); - s[len] = 0; - } +#include "mikmod_internals.h" - return s; -} +#define COPY_BUFSIZE 1024 +static long _mm_iobase=0,temp_iobase=0; -FILE *_mm_fopen(CHAR *fname, CHAR *attrib) +FILE* _mm_fopen(CHAR* fname,CHAR* attrib) { - FILE *fp; + FILE *fp; - if((fp=fopen(fname,attrib)) == NULL) - { _mm_errno = _mm_errno = MMERR_OPENING_FILE; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - } - return fp; + if(!(fp=fopen(fname,attrib))) { + _mm_errno = MMERR_OPENING_FILE; + if(_mm_errorhandler) _mm_errorhandler(); + } + return fp; } - -int _mm_fseek(FILE *stream, long offset, int whence) +BOOL _mm_FileExists(CHAR* fname) { - return fseek(stream,(whence==SEEK_SET) ? offset+_mm_iobase : offset, whence); -} + FILE *fp; + if(!(fp=fopen(fname,"r"))) return 0; + fclose(fp); -long _mm_ftell(FILE *stream) -{ - return ftell(stream)-_mm_iobase; + return 1; } - -BOOL _mm_FileExists(CHAR *fname) +/* Sets the current file-position as the new _mm_iobase */ +void _mm_iobase_setcur(MREADER* reader) { - FILE *fp; - - if((fp=fopen(fname,"r")) == NULL) return 0; - fclose(fp); - - return 1; + temp_iobase=_mm_iobase; /* store old value in case of revert */ + _mm_iobase=reader->Tell(reader); } - -long _mm_flength(FILE *stream) +/* Reverts to the last known _mm_iobase value. */ +void _mm_iobase_revert(void) { - long tmp,tmp2; - - tmp = ftell(stream); - fseek(stream,0,SEEK_END); - tmp2 = ftell(stream); - fseek(stream,tmp,SEEK_SET); - return tmp2-tmp; + _mm_iobase=temp_iobase; } +/*========== File Reader */ -long _mm_iobase_get(void) -{ - return _mm_iobase; -} - +typedef struct MFILEREADER { + MREADER core; + FILE* file; +} MFILEREADER; -void _mm_iobase_set(long iobase) +static BOOL _mm_FileReader_Eof(MREADER* reader) { - temp_iobase = _mm_iobase; /* store old value in case of revert */ - _mm_iobase = iobase; + return feof(((MFILEREADER*)reader)->file); } - -/* Sets the current file-position as the new _mm_iobase */ -void _mm_iobase_setcur(FILE *fp) +static BOOL _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size) { - temp_iobase = _mm_iobase; /* store old value in case of revert */ - _mm_iobase = ftell(fp); + return fread(ptr,size,1,((MFILEREADER*)reader)->file); } - -/* Reverts to the last known _mm_iobase value. */ -void _mm_iobase_revert(void) +static int _mm_FileReader_Get(MREADER* reader) { - _mm_iobase = temp_iobase; + return fgetc(((MFILEREADER*)reader)->file); } - -/* Procedure: _mm_copyfile */ -/* Copies a given number of bytes from the source file to the destination */ -/* file. Returns 1 on error, and calls the _mm_errnohandler, if registered. */ -BOOL _mm_copyfile(FILE *fpi, FILE *fpo, ULONG len) +static BOOL _mm_FileReader_Seek(MREADER* reader,long offset,int whence) { - ULONG todo; - - while(len) - { todo = (len > COPY_BUFSIZE) ? COPY_BUFSIZE : len; - if(!fread(_mm_cpybuf, todo, 1, fpi)) - { _mm_errno = _mm_errno = MMERR_END_OF_FILE; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } - if(!fwrite(_mm_cpybuf, todo, 1, fpo)) - { _mm_errno = _mm_errno = MMERR_DISK_FULL; - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } - len -= todo; - } - - return 0; + return fseek(((MFILEREADER*)reader)->file, + (whence==SEEK_SET)?offset+_mm_iobase:offset,whence); } - -void _mm_write_string(CHAR *data, FILE *fp) +static long _mm_FileReader_Tell(MREADER* reader) { - if(data!=NULL) - _mm_write_UBYTES(data, strlen(data), fp); + return ftell(((MFILEREADER*)reader)->file)-_mm_iobase; } - -void _mm_fputs(FILE *fp, CHAR *data) +MREADER *_mm_new_file_reader(FILE* fp) { - if(data != NULL) - _mm_write_UBYTES(data, strlen(data), fp); - -#ifndef __UNIX__ - _mm_write_UBYTE(13,fp); -#endif - _mm_write_UBYTE(10,fp); + MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER)); + if (reader) { + reader->core.Eof =&_mm_FileReader_Eof; + reader->core.Read=&_mm_FileReader_Read; + reader->core.Get =&_mm_FileReader_Get; + reader->core.Seek=&_mm_FileReader_Seek; + reader->core.Tell=&_mm_FileReader_Tell; + reader->file=fp; + } + return (MREADER*)reader; } - - -#if 0 -/* These have accompanying #define's in mmio.h */ - -void _mm_write_SBYTE(SBYTE data, FILE *fp) +void _mm_delete_file_reader (MREADER* reader) { - fputc(data,fp); + if(reader) free(reader); } -void _mm_write_UBYTE(UBYTE data,FILE *fp) -{ - fputc(data,fp); -} -#endif - - -#ifdef MM_BIG_ENDIAN +/*========== File Writer */ -/* --> Big Endian Write Functions */ +typedef struct MFILEWRITER { + MWRITER core; + FILE* file; +} MFILEWRITER; -void _mm_write_M_UWORD(UWORD data,FILE *fp) +static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence) { - _mm_write_UBYTE(data&0xff,fp); - _mm_write_UBYTE(data>>8,fp); + return fseek(((MFILEWRITER*)writer)->file,offset,whence); } - -void _mm_write_I_UWORD(UWORD data,FILE *fp) +static long _mm_FileWriter_Tell(MWRITER* writer) { - _mm_write_UBYTE(data>>8,fp); - _mm_write_UBYTE(data&0xff,fp); + return ftell(((MFILEWRITER*)writer)->file); } - -void _mm_write_M_ULONG(ULONG data,FILE *fp) +static BOOL _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size) { - _mm_write_M_UWORD(data&0xffff,fp); - _mm_write_M_UWORD(data>>16,fp); + return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size); } - -void _mm_write_I_ULONG(ULONG data,FILE *fp) +static BOOL _mm_FileWriter_Put(MWRITER* writer,int value) { - _mm_write_I_UWORD(data>>16,fp); - _mm_write_I_UWORD(data&0xffff,fp); + return fputc(value,((MFILEWRITER*)writer)->file); } -#else - -/* --> Little Endian Write Functions */ - -void _mm_write_M_UWORD(UWORD data,FILE *fp) +MWRITER *_mm_new_file_writer(FILE* fp) { - _mm_write_UBYTE(data>>8,fp); - _mm_write_UBYTE(data&0xff,fp); + MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER)); + if (writer) { + writer->core.Seek =&_mm_FileWriter_Seek; + writer->core.Tell =&_mm_FileWriter_Tell; + writer->core.Write=&_mm_FileWriter_Write; + writer->core.Put =&_mm_FileWriter_Put; + writer->file=fp; + } + return (MWRITER*) writer; } - -void _mm_write_I_UWORD(UWORD data,FILE *fp) +void _mm_delete_file_writer (MWRITER* writer) { - _mm_write_UBYTE(data&0xff,fp); - _mm_write_UBYTE(data>>8,fp); + if(writer) free (writer); } +/*========== Write functions */ -void _mm_write_M_ULONG(ULONG data,FILE *fp) +void _mm_write_string(CHAR* data,MWRITER* writer) { - _mm_write_M_UWORD(data>>16,fp); - _mm_write_M_UWORD(data&0xffff,fp); + if(data) + _mm_write_UBYTES(data,strlen(data),writer); } - -void _mm_write_I_ULONG(ULONG data,FILE *fp) +void _mm_write_M_UWORD(UWORD data,MWRITER* writer) { - _mm_write_I_UWORD(data&0xffff,fp); - _mm_write_I_UWORD(data>>16,fp); + _mm_write_UBYTE(data>>8,writer); + _mm_write_UBYTE(data&0xff,writer); } -#endif - - -void _mm_write_M_SWORD(SWORD data,FILE *fp) +void _mm_write_I_UWORD(UWORD data,MWRITER* writer) { - _mm_write_M_UWORD((UWORD)data,fp); + _mm_write_UBYTE(data&0xff,writer); + _mm_write_UBYTE(data>>8,writer); } - -void _mm_write_I_SWORD(SWORD data,FILE *fp) +void _mm_write_M_ULONG(ULONG data,MWRITER* writer) { - _mm_write_I_UWORD((UWORD)data,fp); + _mm_write_M_UWORD(data>>16,writer); + _mm_write_M_UWORD(data&0xffff,writer); } - -void _mm_write_M_SLONG(SLONG data,FILE *fp) +void _mm_write_I_ULONG(ULONG data,MWRITER* writer) { - _mm_write_M_ULONG((ULONG)data,fp); + _mm_write_I_UWORD(data&0xffff,writer); + _mm_write_I_UWORD(data>>16,writer); } - -void _mm_write_I_SLONG(SLONG data,FILE *fp) +void _mm_write_M_SWORD(SWORD data,MWRITER* writer) { - _mm_write_I_ULONG((ULONG)data,fp); + _mm_write_M_UWORD((UWORD)data,writer); } - -#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name, type) \ -void \ -_mm_write_##type_name##S (type *buffer, int number, FILE *fp) \ -{ \ - while(number>0) \ - { _mm_write_##type_name(*(buffer++),fp); \ - number--; \ - } \ -} - -/*DEFINE_MULTIPLE_WRITE_FUNCTION (SBYTE, SBYTE) */ -/*DEFINE_MULTIPLE_WRITE_FUNCTION (UBYTE, UBYTE) */ - -DEFINE_MULTIPLE_WRITE_FUNCTION (M_SWORD, SWORD) -DEFINE_MULTIPLE_WRITE_FUNCTION (M_UWORD, UWORD) -DEFINE_MULTIPLE_WRITE_FUNCTION (I_SWORD, SWORD) -DEFINE_MULTIPLE_WRITE_FUNCTION (I_UWORD, UWORD) - -DEFINE_MULTIPLE_WRITE_FUNCTION (M_SLONG, SLONG) -DEFINE_MULTIPLE_WRITE_FUNCTION (M_ULONG, ULONG) -DEFINE_MULTIPLE_WRITE_FUNCTION (I_SLONG, SLONG) -DEFINE_MULTIPLE_WRITE_FUNCTION (I_ULONG, ULONG) - - -/********** -SBYTE _mm_read_SBYTE(FILE *fp) +void _mm_write_I_SWORD(SWORD data,MWRITER* writer) { - return(fgetc(fp)); + _mm_write_I_UWORD((UWORD)data,writer); } -UBYTE _mm_read_UBYTE(FILE *fp) +void _mm_write_M_SLONG(SLONG data,MWRITER* writer) { - return(fgetc(fp)); + _mm_write_M_ULONG((ULONG)data,writer); } -**********/ - -#ifdef MM_BIG_ENDIAN - -UWORD _mm_read_I_UWORD(FILE *fp) +void _mm_write_I_SLONG(SLONG data,MWRITER* writer) { - UWORD result=((UWORD)_mm_read_UBYTE(fp))<<8; - result|=_mm_read_UBYTE(fp); - return result; + _mm_write_I_ULONG((ULONG)data,writer); } -UWORD _mm_read_M_UWORD(FILE *fp) -{ - UWORD result=_mm_read_UBYTE(fp); - result|=((UWORD)_mm_read_UBYTE(fp))<<8; - return result; +#ifdef __STDC__ +#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \ +void _mm_write_##type_name##S (type *buffer,int number,MWRITER* writer) \ +{ \ + while(number-->0) \ + _mm_write_##type_name(*(buffer++),writer); \ } - -ULONG _mm_read_I_ULONG(FILE *fp) -{ - ULONG result=((ULONG)_mm_read_M_UWORD(fp))<<16; - result|=_mm_read_M_UWORD(fp); - return result; +#else +#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \ +void _mm_write_/**/type_name/**/S (type *buffer,int number,MWRITER* writer) \ +{ \ + while(number-->0) \ + _mm_write_/**/type_name(*(buffer++),writer); \ } +#endif -ULONG _mm_read_M_ULONG(FILE *fp) -{ - ULONG result=_mm_read_I_UWORD(fp); - result|=((ULONG)_mm_read_I_UWORD(fp))<<16; - return result; -} +DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD) +DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD) +DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD) +DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD) -#else +DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG) +DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG) +DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG) +DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG) + +/*========== Read functions */ -UWORD _mm_read_M_UWORD(FILE *fp) +int _mm_read_string(CHAR* buffer,int number,MREADER* reader) { - UWORD result=((UWORD)_mm_read_UBYTE(fp))<<8; - result|=_mm_read_UBYTE(fp); - return result; + return reader->Read(reader,buffer,number); } -UWORD _mm_read_I_UWORD(FILE *fp) +UWORD _mm_read_M_UWORD(MREADER* reader) { - UWORD result=_mm_read_UBYTE(fp); - result|=((UWORD)_mm_read_UBYTE(fp))<<8; - return result; + UWORD result=((UWORD)_mm_read_UBYTE(reader))<<8; + result|=_mm_read_UBYTE(reader); + return result; } -ULONG _mm_read_M_ULONG(FILE *fp) +UWORD _mm_read_I_UWORD(MREADER* reader) { - ULONG result=((ULONG)_mm_read_M_UWORD(fp))<<16; - result|=_mm_read_M_UWORD(fp); - return result; + UWORD result=_mm_read_UBYTE(reader); + result|=((UWORD)_mm_read_UBYTE(reader))<<8; + return result; } -ULONG _mm_read_I_ULONG(FILE *fp) +ULONG _mm_read_M_ULONG(MREADER* reader) { - ULONG result=_mm_read_I_UWORD(fp); - result|=((ULONG)_mm_read_I_UWORD(fp))<<16; - return result; + ULONG result=((ULONG)_mm_read_M_UWORD(reader))<<16; + result|=_mm_read_M_UWORD(reader); + return result; } -#endif - -SWORD _mm_read_M_SWORD(FILE *fp) +ULONG _mm_read_I_ULONG(MREADER* reader) { - return((SWORD)_mm_read_M_UWORD(fp)); + ULONG result=_mm_read_I_UWORD(reader); + result|=((ULONG)_mm_read_I_UWORD(reader))<<16; + return result; } -SWORD _mm_read_I_SWORD(FILE *fp) +SWORD _mm_read_M_SWORD(MREADER* reader) { - return((SWORD)_mm_read_I_UWORD(fp)); + return((SWORD)_mm_read_M_UWORD(reader)); } -SLONG _mm_read_M_SLONG(FILE *fp) +SWORD _mm_read_I_SWORD(MREADER* reader) { - return((SLONG)_mm_read_M_ULONG(fp)); + return((SWORD)_mm_read_I_UWORD(reader)); } -SLONG _mm_read_I_SLONG(FILE *fp) +SLONG _mm_read_M_SLONG(MREADER* reader) { - return((SLONG)_mm_read_I_ULONG(fp)); + return((SLONG)_mm_read_M_ULONG(reader)); } - -int _mm_read_string(CHAR *buffer, int number, FILE *fp) +SLONG _mm_read_I_SLONG(MREADER* reader) { - fread(buffer,1,number,fp); - return !feof(fp); + return((SLONG)_mm_read_I_ULONG(reader)); } - - -#define DEFINE_MULTIPLE_READ_FUNCTION(type_name, type) \ -int \ -_mm_read_##type_name##S (type *buffer, int number, FILE *fp) \ -{ \ - while(number>0) \ - { *(buffer++)=_mm_read_##type_name(fp); \ - number--; \ - } \ - return !feof(fp); \ +#ifdef __STDC__ +#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \ +int _mm_read_##type_name##S (type *buffer,int number,MREADER* reader) \ +{ \ + while(number-->0) \ + *(buffer++)=_mm_read_##type_name(reader); \ + return !reader->Eof(reader); \ } +#else +#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \ +int _mm_read_/**/type_name/**/S (type *buffer,int number,MREADER* reader) \ +{ \ + while(number-->0) \ + *(buffer++)=_mm_read_/**/type_name(reader); \ + return !reader->Eof(reader); \ +} +#endif -/*DEFINE_MULTIPLE_READ_FUNCTION (SBYTE, SBYTE) */ -/*DEFINE_MULTIPLE_READ_FUNCTION (UBYTE, UBYTE) */ - -DEFINE_MULTIPLE_READ_FUNCTION (M_SWORD, SWORD) -DEFINE_MULTIPLE_READ_FUNCTION (M_UWORD, UWORD) -DEFINE_MULTIPLE_READ_FUNCTION (I_SWORD, SWORD) -DEFINE_MULTIPLE_READ_FUNCTION (I_UWORD, UWORD) +DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD) +DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD) +DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD) +DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD) -DEFINE_MULTIPLE_READ_FUNCTION (M_SLONG, SLONG) -DEFINE_MULTIPLE_READ_FUNCTION (M_ULONG, ULONG) -DEFINE_MULTIPLE_READ_FUNCTION (I_SLONG, SLONG) -DEFINE_MULTIPLE_READ_FUNCTION (I_ULONG, ULONG) +DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG) +DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG) +DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG) +DEFINE_MULTIPLE_READ_FUNCTION(I_ULONG,ULONG) +/* ex:set ts=4: */ diff --git a/mikmod/mplayer.c b/mikmod/mplayer.c index 053a156e..424d9d74 100644 --- a/mikmod/mplayer.c +++ b/mikmod/mplayer.c @@ -1,2762 +1,2900 @@ -/* - --> The Protracker Player Driver - -> Part of the SPLAYER pack for MikMod 3.0 - - The protracker driver supports all base Protracker 3.x commands and fea- - tures. +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ -#include -#include -#include "mikmod.h" +/*============================================================================== + $Id$ -static void DoNNAEffects(UBYTE dat); + The Protracker Player Driver -/* Set forbid to 1 when you want to modify any of the pf->sngpos, pf->patpos etc. */ -/* variables and clear it when you're done. This prevents getting strange */ -/* results due to intermediate interrupts. */ + The protracker driver supports all base Protracker 3.x commands and features. -UNIMOD *pf; /* <- this modfile is being played */ -static SWORD mp_channel; /* channel it's working on */ -static MP_CONTROL *a; /* current AUDTMP it's working on */ -static int isfirst; +==============================================================================*/ -static MP_VOICE aout_dummy; +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -UWORD mytab[12] = -{ 1712*16, 1616*16, 1524*16, 1440*16, 1356*16, 1280*16, - 1208*16, 1140*16, 1076*16, 1016*16, 960*16, 907*16 +#include +#include +#ifdef SUNOS +extern long int random(void); +#endif +#ifdef SRANDOM_IN_MATH_H +#include +#else +#include +#endif + +#include "mikmod_internals.h" + +/* Set forbid to 1 when you want to modify any of the pf->sngpos, pf->patpos etc + variables and clear it when you're done. This prevents getting strange + results due to intermediate interrupts. */ + + MODULE *pf=NULL; /* modfile being played */ +static SWORD mp_channel; /* channel we're working on */ +static MP_CONTROL *a; /* current AUDTMP we're working on */ +static int explicitslides; + +static UWORD oldperiods[OCTAVE*2]={ + 1712*16,1664*16,1616*16,1570*16,1524*16,1480*16, + 1438*16,1396*16,1356*16,1318*16,1280*16,1244*16, + 1208*16,1174*16,1140*16,1108*16,1076*16,1046*16, + 1016*16, 988*16, 960*16, 932*16, 906*16, 880*16 }; - -UBYTE VibratoTable[32] = -{ 0,24,49,74,97,120,141,161, - 180,197,212,224,235,244,250,253, - 255,253,250,244,235,224,212,197, - 180,161,141,120,97,74,49,24 +static UBYTE VibratoTable[32]={ + 0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253, + 255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24 }; - -UBYTE avibtab[128] = -{ 0,1,3,4,6,7,9,10,12,14,15,17,18,20,21,23, - 24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44, - 45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58, - 59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63, - 64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59, - 59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46, - 45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25, - 24,23,21,20,18,17,15,14,12,10,9,7,6,4,3,1 +static UBYTE avibtab[128]={ + 0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23, + 24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44, + 45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58, + 59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63, + 64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59, + 59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46, + 45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25, + 24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1 }; - -/* ** Triton's linear periods to frequency translation table (for */ -/* ** Fast Tracker 2 [XM] modules): */ - -ULONG lintab[768] = -{ 535232,534749,534266,533784,533303,532822,532341,531861, - 531381,530902,530423,529944,529466,528988,528511,528034, - 527558,527082,526607,526131,525657,525183,524709,524236, - 523763,523290,522818,522346,521875,521404,520934,520464, - 519994,519525,519057,518588,518121,517653,517186,516720, - 516253,515788,515322,514858,514393,513929,513465,513002, - 512539,512077,511615,511154,510692,510232,509771,509312, - 508852,508393,507934,507476,507018,506561,506104,505647, - 505191,504735,504280,503825,503371,502917,502463,502010, - 501557,501104,500652,500201,499749,499298,498848,498398, - 497948,497499,497050,496602,496154,495706,495259,494812, - 494366,493920,493474,493029,492585,492140,491696,491253, - 490809,490367,489924,489482,489041,488600,488159,487718, - 487278,486839,486400,485961,485522,485084,484647,484210, - 483773,483336,482900,482465,482029,481595,481160,480726, - 480292,479859,479426,478994,478562,478130,477699,477268, - 476837,476407,475977,475548,475119,474690,474262,473834, - 473407,472979,472553,472126,471701,471275,470850,470425, - 470001,469577,469153,468730,468307,467884,467462,467041, - 466619,466198,465778,465358,464938,464518,464099,463681, - 463262,462844,462427,462010,461593,461177,460760,460345, - 459930,459515,459100,458686,458272,457859,457446,457033, - 456621,456209,455797,455386,454975,454565,454155,453745, - 453336,452927,452518,452110,451702,451294,450887,450481, - 450074,449668,449262,448857,448452,448048,447644,447240, - 446836,446433,446030,445628,445226,444824,444423,444022, - 443622,443221,442821,442422,442023,441624,441226,440828, - 440430,440033,439636,439239,438843,438447,438051,437656, - 437261,436867,436473,436079,435686,435293,434900,434508, - 434116,433724,433333,432942,432551,432161,431771,431382, - 430992,430604,430215,429827,429439,429052,428665,428278, - 427892,427506,427120,426735,426350,425965,425581,425197, - 424813,424430,424047,423665,423283,422901,422519,422138, - 421757,421377,420997,420617,420237,419858,419479,419101, - 418723,418345,417968,417591,417214,416838,416462,416086, - 415711,415336,414961,414586,414212,413839,413465,413092, - 412720,412347,411975,411604,411232,410862,410491,410121, - 409751,409381,409012,408643,408274,407906,407538,407170, - 406803,406436,406069,405703,405337,404971,404606,404241, - 403876,403512,403148,402784,402421,402058,401695,401333, - 400970,400609,400247,399886,399525,399165,398805,398445, - 398086,397727,397368,397009,396651,396293,395936,395579, - 395222,394865,394509,394153,393798,393442,393087,392733, - 392378,392024,391671,391317,390964,390612,390259,389907, - 389556,389204,388853,388502,388152,387802,387452,387102, - 386753,386404,386056,385707,385359,385012,384664,384317, - 383971,383624,383278,382932,382587,382242,381897,381552, - 381208,380864,380521,380177,379834,379492,379149,378807, - - 378466,378124,377783,377442,377102,376762,376422,376082, - 375743,375404,375065,374727,374389,374051,373714,373377, - 373040,372703,372367,372031,371695,371360,371025,370690, - 370356,370022,369688,369355,369021,368688,368356,368023, - 367691,367360,367028,366697,366366,366036,365706,365376, - 365046,364717,364388,364059,363731,363403,363075,362747, - 362420,362093,361766,361440,361114,360788,360463,360137, - 359813,359488,359164,358840,358516,358193,357869,357547, - 357224,356902,356580,356258,355937,355616,355295,354974, - 354654,354334,354014,353695,353376,353057,352739,352420, - 352103,351785,351468,351150,350834,350517,350201,349885, - 349569,349254,348939,348624,348310,347995,347682,347368, - 347055,346741,346429,346116,345804,345492,345180,344869, - 344558,344247,343936,343626,343316,343006,342697,342388, - 342079,341770,341462,341154,340846,340539,340231,339924, - 339618,339311,339005,338700,338394,338089,337784,337479, - 337175,336870,336566,336263,335959,335656,335354,335051, - 334749,334447,334145,333844,333542,333242,332941,332641, - 332341,332041,331741,331442,331143,330844,330546,330247, - 329950,329652,329355,329057,328761,328464,328168,327872, - 327576,327280,326985,326690,326395,326101,325807,325513, - 325219,324926,324633,324340,324047,323755,323463,323171, - 322879,322588,322297,322006,321716,321426,321136,320846, - 320557,320267,319978,319690,319401,319113,318825,318538, - 318250,317963,317676,317390,317103,316817,316532,316246, - 315961,315676,315391,315106,314822,314538,314254,313971, - 313688,313405,313122,312839,312557,312275,311994,311712, - 311431,311150,310869,310589,310309,310029,309749,309470, - 309190,308911,308633,308354,308076,307798,307521,307243, - 306966,306689,306412,306136,305860,305584,305308,305033, - 304758,304483,304208,303934,303659,303385,303112,302838, - 302565,302292,302019,301747,301475,301203,300931,300660, - 300388,300117,299847,299576,299306,299036,298766,298497, - 298227,297958,297689,297421,297153,296884,296617,296349, - 296082,295815,295548,295281,295015,294749,294483,294217, - 293952,293686,293421,293157,292892,292628,292364,292100, - 291837,291574,291311,291048,290785,290523,290261,289999, - 289737,289476,289215,288954,288693,288433,288173,287913, - 287653,287393,287134,286875,286616,286358,286099,285841, - 285583,285326,285068,284811,284554,284298,284041,283785, - 283529,283273,283017,282762,282507,282252,281998,281743, - 281489,281235,280981,280728,280475,280222,279969,279716, - 279464,279212,278960,278708,278457,278206,277955,277704, - 277453,277203,276953,276703,276453,276204,275955,275706, - 275457,275209,274960,274712,274465,274217,273970,273722, - 273476,273229,272982,272736,272490,272244,271999,271753, - 271508,271263,271018,270774,270530,270286,270042,269798, - 269555,269312,269069,268826,268583,268341,268099,267857 +/* Triton's linear periods to frequency translation table (for XM modules) */ +static ULONG lintab[768]={ + 535232,534749,534266,533784,533303,532822,532341,531861, + 531381,530902,530423,529944,529466,528988,528511,528034, + 527558,527082,526607,526131,525657,525183,524709,524236, + 523763,523290,522818,522346,521875,521404,520934,520464, + 519994,519525,519057,518588,518121,517653,517186,516720, + 516253,515788,515322,514858,514393,513929,513465,513002, + 512539,512077,511615,511154,510692,510232,509771,509312, + 508852,508393,507934,507476,507018,506561,506104,505647, + 505191,504735,504280,503825,503371,502917,502463,502010, + 501557,501104,500652,500201,499749,499298,498848,498398, + 497948,497499,497050,496602,496154,495706,495259,494812, + 494366,493920,493474,493029,492585,492140,491696,491253, + 490809,490367,489924,489482,489041,488600,488159,487718, + 487278,486839,486400,485961,485522,485084,484647,484210, + 483773,483336,482900,482465,482029,481595,481160,480726, + 480292,479859,479426,478994,478562,478130,477699,477268, + 476837,476407,475977,475548,475119,474690,474262,473834, + 473407,472979,472553,472126,471701,471275,470850,470425, + 470001,469577,469153,468730,468307,467884,467462,467041, + 466619,466198,465778,465358,464938,464518,464099,463681, + 463262,462844,462427,462010,461593,461177,460760,460345, + 459930,459515,459100,458686,458272,457859,457446,457033, + 456621,456209,455797,455386,454975,454565,454155,453745, + 453336,452927,452518,452110,451702,451294,450887,450481, + 450074,449668,449262,448857,448452,448048,447644,447240, + 446836,446433,446030,445628,445226,444824,444423,444022, + 443622,443221,442821,442422,442023,441624,441226,440828, + 440430,440033,439636,439239,438843,438447,438051,437656, + 437261,436867,436473,436079,435686,435293,434900,434508, + 434116,433724,433333,432942,432551,432161,431771,431382, + 430992,430604,430215,429827,429439,429052,428665,428278, + 427892,427506,427120,426735,426350,425965,425581,425197, + 424813,424430,424047,423665,423283,422901,422519,422138, + 421757,421377,420997,420617,420237,419858,419479,419101, + 418723,418345,417968,417591,417214,416838,416462,416086, + 415711,415336,414961,414586,414212,413839,413465,413092, + 412720,412347,411975,411604,411232,410862,410491,410121, + 409751,409381,409012,408643,408274,407906,407538,407170, + 406803,406436,406069,405703,405337,404971,404606,404241, + 403876,403512,403148,402784,402421,402058,401695,401333, + 400970,400609,400247,399886,399525,399165,398805,398445, + 398086,397727,397368,397009,396651,396293,395936,395579, + 395222,394865,394509,394153,393798,393442,393087,392733, + 392378,392024,391671,391317,390964,390612,390259,389907, + 389556,389204,388853,388502,388152,387802,387452,387102, + 386753,386404,386056,385707,385359,385012,384664,384317, + 383971,383624,383278,382932,382587,382242,381897,381552, + 381208,380864,380521,380177,379834,379492,379149,378807, + 378466,378124,377783,377442,377102,376762,376422,376082, + 375743,375404,375065,374727,374389,374051,373714,373377, + 373040,372703,372367,372031,371695,371360,371025,370690, + 370356,370022,369688,369355,369021,368688,368356,368023, + 367691,367360,367028,366697,366366,366036,365706,365376, + 365046,364717,364388,364059,363731,363403,363075,362747, + 362420,362093,361766,361440,361114,360788,360463,360137, + 359813,359488,359164,358840,358516,358193,357869,357547, + 357224,356902,356580,356258,355937,355616,355295,354974, + 354654,354334,354014,353695,353376,353057,352739,352420, + 352103,351785,351468,351150,350834,350517,350201,349885, + 349569,349254,348939,348624,348310,347995,347682,347368, + 347055,346741,346429,346116,345804,345492,345180,344869, + 344558,344247,343936,343626,343316,343006,342697,342388, + 342079,341770,341462,341154,340846,340539,340231,339924, + 339618,339311,339005,338700,338394,338089,337784,337479, + 337175,336870,336566,336263,335959,335656,335354,335051, + 334749,334447,334145,333844,333542,333242,332941,332641, + 332341,332041,331741,331442,331143,330844,330546,330247, + 329950,329652,329355,329057,328761,328464,328168,327872, + 327576,327280,326985,326690,326395,326101,325807,325513, + 325219,324926,324633,324340,324047,323755,323463,323171, + 322879,322588,322297,322006,321716,321426,321136,320846, + 320557,320267,319978,319690,319401,319113,318825,318538, + 318250,317963,317676,317390,317103,316817,316532,316246, + 315961,315676,315391,315106,314822,314538,314254,313971, + 313688,313405,313122,312839,312557,312275,311994,311712, + 311431,311150,310869,310589,310309,310029,309749,309470, + 309190,308911,308633,308354,308076,307798,307521,307243, + 306966,306689,306412,306136,305860,305584,305308,305033, + 304758,304483,304208,303934,303659,303385,303112,302838, + 302565,302292,302019,301747,301475,301203,300931,300660, + 300388,300117,299847,299576,299306,299036,298766,298497, + 298227,297958,297689,297421,297153,296884,296617,296349, + 296082,295815,295548,295281,295015,294749,294483,294217, + 293952,293686,293421,293157,292892,292628,292364,292100, + 291837,291574,291311,291048,290785,290523,290261,289999, + 289737,289476,289215,288954,288693,288433,288173,287913, + 287653,287393,287134,286875,286616,286358,286099,285841, + 285583,285326,285068,284811,284554,284298,284041,283785, + 283529,283273,283017,282762,282507,282252,281998,281743, + 281489,281235,280981,280728,280475,280222,279969,279716, + 279464,279212,278960,278708,278457,278206,277955,277704, + 277453,277203,276953,276703,276453,276204,275955,275706, + 275457,275209,274960,274712,274465,274217,273970,273722, + 273476,273229,272982,272736,272490,272244,271999,271753, + 271508,271263,271018,270774,270530,270286,270042,269798, + 269555,269312,269069,268826,268583,268341,268099,267857 }; - #define LOGFAC 2*16 - -UWORD logtab[104] = -{ LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862, - LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814, - LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768, - LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725, - LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684, - LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646, - LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610, - LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575, - LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543, - LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513, - LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484, - LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457, - LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431 +static UWORD logtab[104]={ + LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887, + LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862, + LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838, + LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814, + LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791, + LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768, + LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746, + LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725, + LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704, + LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684, + LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665, + LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646, + LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628, + LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610, + LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592, + LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575, + LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559, + LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543, + LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528, + LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513, + LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498, + LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484, + LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470, + LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457, + LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443, + LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431 }; -SBYTE PanbrelloTable[256] = -{ 0,2,3,5,6,8,9,11,12,14,16,17,19,20,22,23, - 24,26,27,29,30,32,33,34,36,37,38,39,41,42,43,44, - 45,46,47,48,49,50,51,52,53,54,55,56,56,57,58,59, - 59,60,60,61,61,62,62,62,63,63,63,64,64,64,64,64, - 64,64,64,64,64,64,63,63,63,62,62,62,61,61,60,60, - 59,59,58,57,56,56,55,54,53,52,51,50,49,48,47,46, - 45,44,43,42,41,39,38,37,36,34,33,32,30,29,27,26, - 24,23,22,20,19,17,16,14,12,11,9,8,6,5,3,2, - 0,-2,-3,-5,-6,-8,-9,-11,-12,-14,-16,-17,-19,-20,-22,-23, - -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, - -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, - -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, - -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, - -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, - -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, - -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,-9,-8,-6,-5,-3,-2 +static SBYTE PanbrelloTable[256]={ + 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23, + 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, + 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, + 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, + 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26, + 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2, + 0,- 2,- 3,- 5,- 6,- 8,- 9,-11,-12,-14,-16,-17,-19,-20,-22,-23, + -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, + -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, + -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, + -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, + -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, + -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, + -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,- 9,- 8,- 6,- 5,- 3,- 2 }; - -/* New Note Action Scoring System: - --------------------------------- - 1) total-volume (fadevol, chanvol, volume) is the main scorer. - 2) a looping sample is a bonus x2 - 3) a forground channel is a bonus x4 - 4) an active envelope with keyoff is a handicap -x2 -*/ -static int MP_FindEmptyChannel(int curchan) /* returns mp_control index of free channel */ +/* returns a random value between 0 and ceil-1, ceil must be a power of two */ +static int getrandom(int ceil) { - MP_VOICE *a; - ULONG t,k,tvol,p,pp; - - /*for(t=md_sngchn; t; t--, audpool++) - { if(audpool == md_sngchn) audpool = 0; - if(!(pf->voice[audpool].kick) && Voice_Stopped(audpool)) - { audpool++; - return audpool-1; - } - }*/ - - for(t=0; tvoice[t].kick) && Voice_Stopped(t)) - { return t; - } - } +#ifdef HAVE_SRANDOM + return random()&(ceil-1); +#else + return (rand()*ceil)/(RAND_MAX+1.0); +#endif +} - tvol = 0xffffffUL; t = 0; p = 0; a = pf->voice; - for(k=0; kkick) - { pp = a->totalvol << ((a->s->flags & SF_LOOP) ? 1 : 0); - if((a->master!=NULL) && (a==a->master->slave)) - pp <<= 2; +/* New Note Action Scoring System : + -------------------------------- +1) total-volume (fadevol, chanvol, volume) is the main scorer. +2) a looping sample is a bonus x2 +3) a foreground channel is a bonus x4 +4) an active envelope with keyoff is a handicap -x2 */ +static int MP_FindEmptyChannel(void) +{ + MP_VOICE *a; + ULONG t,k,tvol,pp; - /*if(a->volflg & EF_ON) - { if(a->volflg & (EF_SUSTAIN | EF_LOOP)) - { if(a->keyoff & KEY_OFF) - { pp >>= 1; - if(a->venv.env[a->venv.end].val < 32) pp>>=1; - } else - pp <<= 1; - } else pp <<= 1; - }*/ + for (t=0;tvoice[t].kick==KICK_ABSENT)||(pf->voice[t].kick==KICK_ENV))&& + Voice_Stopped_internal(t)) + return t; - if(pp < tvol) - { tvol = pp; - t = k; - } - } - } + tvol=0xffffffUL;t=0;a=pf->voice; + for (k=0;kkick==KICK_ABSENT)||(a->kick==KICK_ENV)) { + pp=a->totalvol<<((a->s->flags&SF_LOOP)?1:0); + if ((a->master)&&(a==a->master->slave)) + pp<<=2; - if(tvol>8000*7) return -1; /*mp_channel; */ + if (pp8000*7) return -1; + return t; } - -static SWORD Interpolate(SWORD p, SWORD p1, SWORD p2, SWORD v1, SWORD v2) +static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2) { - SWORD dp,dv,di; - - if(p1==p2) return v1; - - dv = v2-v1; - dp = p2-p1; - di = p-p1; - - return v1 + ((SLONG)(di*dv) / dp); + if ((p1==p2)||(p==p1)) return v1; + return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1)); } - -UWORD getlinearperiod(UBYTE note, ULONG fine) +UWORD getlinearperiod(UWORD note,ULONG fine) { - return((10L*12*16*4)-((ULONG)note*16*4)-(fine/2)+64); -} + UWORD t; + t=(20L*OCTAVE+2-note)*32L-(fine>>1); + return t; +} -static UWORD getlogperiod(UBYTE note,ULONG fine) +static UWORD getlogperiod(UWORD note,ULONG fine) { - UBYTE n,o; - UWORD p1,p2; - ULONG i; + UWORD n,o; + UWORD p1,p2; + ULONG i; - n = note%12; - o = note/12; - i = (n<<3) + (fine>>4); /* n*8 + fine/16 */ + n=note%(2*OCTAVE); + o=note/(2*OCTAVE); + i=(n<<2)+(fine>>4); /* n*8 + fine/16 */ - p1 = logtab[i]; - p2 = logtab[i+1]; + p1=logtab[i]; + p2=logtab[i+1]; - return(Interpolate(fine/16,0,15,p1,p2)>>o); + return (Interpolate(fine>>4,0,15,p1,p2)>>o); } - -static UWORD getoldperiod(UBYTE note, ULONG speed) +static UWORD getoldperiod(UWORD note,ULONG speed) { - UBYTE n, o; - ULONG period; + UWORD n,o; - if(!speed) return 4242; /* <- prevent divide overflow.. (42 eheh) */ + if (!speed) { +#ifdef MIKMOD_DEBUG + fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note); +#endif + return 4242; /* <- prevent divide overflow.. (42 hehe) */ + } - n = note % 12; - o = note / 12; - period = ((8363l*(ULONG)mytab[n]) >> o ) / speed; - return period; + n=note%(2*OCTAVE); + o=note/(2*OCTAVE); + return ((8363L*(ULONG)oldperiods[n])>>o)/speed; } - -static UWORD GetPeriod(UBYTE note, ULONG speed) +static UWORD GetPeriod(UWORD note,ULONG speed) { - if(pf->flags & UF_XMPERIODS) - return (pf->flags & UF_LINEAR) ? getlinearperiod(note,speed) : getlogperiod(note,speed); + if (pf->flags & UF_XMPERIODS) + return (pf->flags&UF_LINEAR)?getlinearperiod(note,speed):getlogperiod(note,speed); - return getoldperiod(note,speed); + return getoldperiod(note,speed); } - -static SWORD InterpolateEnv(SWORD p, ENVPT *a, ENVPT *b) +static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b) { - return(Interpolate(p,a->pos,b->pos,a->val,b->val)); + return (Interpolate(p,a->pos,b->pos,a->val,b->val)); } - -static SWORD DoPan(SWORD envpan, SWORD pan) +static SWORD DoPan(SWORD envpan,SWORD pan) { - return(pan + (((envpan-128)*(128-abs(pan-128)))/128)); -} + int newpan; + newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128); -static void StartEnvelope(ENVPR *t, UBYTE flg, UBYTE pts, UBYTE susbeg, UBYTE susend, UBYTE beg, UBYTE end, ENVPT *p, UBYTE keyoff) -{ - t->flg = flg; - t->pts = pts; - t->susbeg = susbeg; - t->susend = susend; - t->beg = beg; - t->end = end; - t->env = p; - t->p = 0; - t->a = 0; - t->b = ((t->flg & EF_SUSTAIN) && !(keyoff & KEY_OFF)) ? 0 : 1; + return (newpanPAN_RIGHT?PAN_RIGHT:newpan); } +static void StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff) +{ + t->flg=flg; + t->pts=pts; + t->susbeg=susbeg; + t->susend=susend; + t->beg=beg; + t->end=end; + t->env=p; + t->p=0; + t->a=0; + t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1; -static SWORD ProcessEnvelope(ENVPR *t, SWORD v, UBYTE keyoff) - -/* This procedure processes all envelope types, include volume, pitch, and */ -/* panning. Envelopes are defined by a set of points, each with a magnitude */ -/* [relating either to volume, panniong position, or pitch modifier] and a */ -/* tick position. */ -/* */ -/* Envelopes work in the following manner: */ -/* */ -/* (a) Each tick the envelope is moved a point further in its progression. */ -/* 1. For an accurate progression, magnitudes between two envelope points */ -/* are interpolated. */ -/* */ -/* (b) When progression reaches a defined point on the envelope, values */ -/* are shifted to interpolate between this point and the next, */ -/* and checks for loops or envelope end are done. */ -/* */ -/* Misc: */ -/* Sustain loops are loops that are only active as long as the keyoff */ -/* flag is clear. When a volume envelope terminates, so does the current */ -/* fadeout. */ + /* Imago Orpheus sometimes stores an extra initial point in the envelope */ + if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) { + t->a++;t->b++; + } -{ - if(t->flg & EF_ON) - { UBYTE a, b; /* actual points in the envelope */ - UWORD p; /* the 'tick counter' - real point being played */ + if (t->b>=t->pts) t->b=t->pts-1; +} - a = t->a; - b = t->b; - p = t->p; +/* This procedure processes all envelope types, include volume, pitch, and + panning. Envelopes are defined by a set of points, each with a magnitude + [relating either to volume, panning position, or pitch modifier] and a tick + position. - /* compute the current envelope value between points a and b */ + Envelopes work in the following manner: - if(a == b) - v = t->env[a].val; - else - v = InterpolateEnv(p, &t->env[a], &t->env[b]); + (a) Each tick the envelope is moved a point further in its progression. For + an accurate progression, magnitudes between two envelope points are + interpolated. - p++; + (b) When progression reaches a defined point on the envelope, values are + shifted to interpolate between this point and the next, and checks for + loops or envelope end are done. - /* pointer reached point b? */ + Misc: + Sustain loops are loops that are only active as long as the keyoff flag is + clear. When a volume envelope terminates, so does the current fadeout. */ +static SWORD ProcessEnvelope(ENVPR *t,SWORD v,UBYTE keyoff) +{ + if (t->flg & EF_ON) { + UBYTE a,b; /* actual points in the envelope */ + UWORD p; /* the 'tick counter' - real point being played */ - if(p >= t->env[b].pos) - { a = b++; /* shift points a and b */ + a=t->a; + b=t->b; + p=t->p; - /* Check for loops, sustain loops, or end of envelope. */ - - if((t->flg & EF_SUSTAIN) && !(keyoff & KEY_OFF) && (b > t->susend)) - { a = t->susbeg; - if(t->susbeg == t->susend) b = a; else b = a + 1; - p = t->env[a].pos; - } else if((t->flg & EF_LOOP) && (b > t->end)) - { a = t->beg; - if(t->beg == t->end) b = a; else b = a + 1; - p = t->env[a].pos; - } else - { if(b >= t->pts) - { if((t->flg & EF_VOLENV) && (mp_channel != -1)) - { pf->voice[mp_channel].keyoff |= KEY_FADE; - if(v==0) - pf->voice[mp_channel].fadevol = 0; - } - b--; p--; - } - } - } - t->a = a; - t->b = b; - t->p = p; - } - return v; -} + /* if sustain loop on one point (XM type), don't move and don't + interpolate when the point is reached */ + if ((t->flg & EF_SUSTAIN)&&(t->susbeg==t->susend)&& + (!(keyoff&KEY_OFF))&&(p==t->env[t->susbeg].pos)) + v=t->env[t->susbeg].val; + else { + /* compute the current envelope value between points a and b */ + if (a==b) + v=t->env[a].val; + else + v=InterpolateEnv(p,&t->env[a],&t->env[b]); + p++; + /* pointer reached point b? */ + if (p>=t->env[b].pos) { + a=b++; /* shift points a and b */ -ULONG getfrequency(UBYTE flags, ULONG period) + /* Check for loops, sustain loops, or end of envelope. */ + if ((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF))&&(b>t->susend)) { + a=t->susbeg; + b=(t->susbeg==t->susend)?a:a+1; + p=t->env[a].pos; + } else + if ((t->flg & EF_LOOP)&&(b>t->end)) { + a=t->beg; + b=(t->beg==t->end)?a:a+1; + p=t->env[a].pos; + } else { + if (b>=t->pts) { + if ((t->flg & EF_VOLENV)&&(mp_channel!=-1)) { + pf->voice[mp_channel].keyoff|=KEY_FADE; + if (!v) + pf->voice[mp_channel].fadevol=0; + } + b--;p--; + } + } + } + t->a=a; + t->b=b; + t->p=p; + } + } + return v; +} /* XM linear period to frequency conversion */ - +ULONG getfrequency(UBYTE flags,ULONG period) { - ULONG result; - - if(flags & UF_LINEAR) - result = lintab[period % 768] >> (period / 768); - else - result = (8363L*1712L) / period; - - return result; + if (flags & UF_LINEAR) + return lintab[period%768]>>(period/768); + else + return (8363L*1712L)/(period?period:1); } +/*========== Protracker effects */ static void DoEEffects(UBYTE dat) { - UBYTE nib; - - nib = dat & 0xf; - - switch(dat>>4) - { case 0x0: /* filter toggle, not supported */ - break; - - case 0x1: /* fineslide up */ - if(!pf->vbtick) a->tmpperiod-=(nib<<2); - break; - - case 0x2: /* fineslide dn */ - if(!pf->vbtick) a->tmpperiod+=(nib<<2); - break; - - case 0x3: /* glissando ctrl */ - a->glissando = nib; - break; - - case 0x4: /* set vibrato waveform */ - a->wavecontrol &= 0xf0; - a->wavecontrol |= nib; - break; - - case 0x5: /* set finetune */ -/* a->speed=finetune[nib]; */ -/* a->tmpperiod=GetPeriod(a->note,pf->samples[a->sample].transpose,a->speed); */ - break; - - case 0x6: /* set patternloop */ - if(pf->vbtick) break; - /* hmm.. this one is a real kludge. But now it */ - /* works */ - if(nib) /* set reppos or repcnt ? */ - { /* set repcnt, so check if repcnt already is set, */ - /* which means we are already looping */ - - if(pf->pat_repcnt > 0) - pf->pat_repcnt--; /* already looping, decrease counter */ - else - pf->pat_repcnt = nib; /* not yet looping, so set repcnt */ - - if(pf->pat_repcnt) /* jump to reppos if repcnt>0 */ - pf->patpos = pf->pat_reppos; - } else - { pf->pat_reppos = pf->patpos-1; /* set reppos */ - } - break; - - - case 0x7: /* set tremolo waveform */ - a->wavecontrol &= 0x0f; - a->wavecontrol |= nib << 4; - break; - - case 0x8: /* set panning */ - if(pf->panflag) - { if(nib<=8) nib*=16; else nib*=17; - a->panning = nib; - pf->panning[mp_channel] = nib; - } - break; - - case 0x9: /* retrig note */ - /* only retrigger if */ - /* data nibble > 0 */ - - if(nib > 0) - { if(a->retrig==0) - { /* when retrig counter reaches 0, */ - /* reset counter and restart the sample */ - a->kick = 1; - a->retrig = nib; - } - a->retrig--; /* countdown */ - } - break; - - case 0xa: /* fine volume slide up */ - if(pf->vbtick) break; - - a->tmpvolume += nib; - if(a->tmpvolume > 64) a->tmpvolume = 64; - break; - - case 0xb: /* fine volume slide dn */ - if(pf->vbtick) break; - - a->tmpvolume -= nib; - if(a->tmpvolume < 0) a->tmpvolume = 0; - break; - - case 0xc: /* cut note */ - /* When pf->vbtick reaches the cut-note value, */ - /* turn the volume to zero ( Just like */ - /* on the amiga) */ - if(pf->vbtick>=nib) - a->tmpvolume = 0; /* just turn the volume down */ - break; - - case 0xd: /* note delay */ - /* delay the start of the */ - /* sample until pf->vbtick==nib */ - if(pf->vbtick==nib) - { /*a->kick = 1; */ - a->notedelay = 0; - } else if(pf->vbtick==0) - { /*a->kick = 0; */ - a->notedelay = 1; - } - break; - - case 0xe: /* pattern delay */ - if(pf->vbtick) break; - if(!pf->patdly2) pf->patdly = nib+1; /* only once (when pf->vbtick=0) */ - break; - - case 0xf: /* invert loop, not supported */ - break; - } + UBYTE nib=dat&0xf; + + switch (dat>>4) { + case 0x0: /* hardware filter toggle, not supported */ + break; + case 0x1: /* fineslide up */ + if (a->period) + if (!pf->vbtick) a->tmpperiod-=(nib<<2); + break; + case 0x2: /* fineslide dn */ + if (a->period) + if (!pf->vbtick) a->tmpperiod+=(nib<<2); + break; + case 0x3: /* glissando ctrl */ + a->glissando=nib; + break; + case 0x4: /* set vibrato waveform */ + a->wavecontrol&=0xf0; + a->wavecontrol|=nib; + break; + case 0x5: /* set finetune */ + if (a->period) { + if (pf->flags&UF_XMPERIODS) + a->speed=nib+128; + else + a->speed=finetune[nib]; + a->tmpperiod=GetPeriod((UWORD)a->note<<1,a->speed); + } + break; + case 0x6: /* set patternloop */ + if (pf->vbtick) break; + if (nib) { /* set reppos or repcnt ? */ + /* set repcnt, so check if repcnt already is set, which means we + are already looping */ + if (a->pat_repcnt) + a->pat_repcnt--; /* already looping, decrease counter */ + else { +#if 0 + /* this would make walker.xm, shipped with Xsoundtracker, + play correctly, but it's better to remain compatible + with FT2 */ + if ((!(pf->flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE)) +#endif + a->pat_repcnt=nib; /* not yet looping, so set repcnt */ + } + + if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */ + if (a->pat_reppos==POS_NONE) + a->pat_reppos=pf->patpos-1; + if (a->pat_reppos==-1) { + pf->pat_repcrazy=1; + pf->patpos=0; + } else + pf->patpos=a->pat_reppos; + } else a->pat_reppos=POS_NONE; + } else + a->pat_reppos=pf->patpos-1; /* set reppos - can be (-1) */ + break; + case 0x7: /* set tremolo waveform */ + a->wavecontrol&=0x0f; + a->wavecontrol|=nib<<4; + break; + case 0x8: /* set panning */ + if (pf->panflag) { + if (nib<=8) nib<<=4; + else nib*=17; + a->panning=pf->panning[mp_channel]=nib; + } + break; + case 0x9: /* retrig note */ + /* only retrigger if data nibble > 0 */ + if (nib) { + if (!a->retrig) { + /* when retrig counter reaches 0, reset counter and restart + the sample */ + if (a->period) a->kick=KICK_NOTE; + a->retrig=nib; + } + a->retrig--; /* countdown */ + } + break; + case 0xa: /* fine volume slide up */ + if (pf->vbtick) break; + a->tmpvolume+=nib; + if (a->tmpvolume>64) a->tmpvolume=64; + break; + case 0xb: /* fine volume slide dn */ + if (pf->vbtick) break; + a->tmpvolume-=nib; + if (a->tmpvolume<0) a->tmpvolume=0; + break; + case 0xc: /* cut note */ + /* When pf->vbtick reaches the cut-note value, turn the volume to + zero ( Just like on the amiga) */ + if (pf->vbtick>=nib) + a->tmpvolume=0; /* just turn the volume down */ + break; + case 0xd: /* note delay */ + /* delay the start of the sample until pf->vbtick==nib */ + if (!pf->vbtick) + a->notedelay=nib; + else if (a->notedelay) + a->notedelay--; + break; + case 0xe: /* pattern delay */ + if (pf->vbtick) break; + if (!pf->patdly2) pf->patdly=nib+1; /* only once, when vbtick=0 */ + break; + case 0xf: /* invert loop, not supported */ + break; + } } - static void DoVibrato(void) { - UBYTE q; - UWORD temp; - - q = (a->vibpos>>2)&0x1f; + UBYTE q; + UWORD temp=0; - switch(a->wavecontrol&3) - { case 0: /* sine */ - temp = VibratoTable[q]; - break; + q=(a->vibpos>>2)&0x1f; - case 1: /* ramp down */ - q<<=3; - if(a->vibpos<0) q = 255-q; - temp = q; - break; + switch (a->wavecontrol&3) { + case 0: /* sine */ + temp=VibratoTable[q]; + break; + case 1: /* ramp down */ + q<<=3; + if (a->vibpos<0) q=255-q; + temp=q; + break; + case 2: /* square wave */ + temp=255; + break; + case 3: /* random wave */ + temp=getrandom(256); + break; + } - case 2: /* square wave */ - temp = 255; - break; + temp*=a->vibdepth; + temp>>=7;temp<<=2; - case 3: /* Evil random wave */ - temp = rand() & 255; - break; - } + if (a->vibpos>=0) + a->period=a->tmpperiod+temp; + else + a->period=a->tmpperiod-temp; - temp*=a->vibdepth; - temp>>=7; - temp<<=2; - - if(a->vibpos>=0) - a->period = a->tmpperiod+temp; - else - a->period = a->tmpperiod-temp; - - if(pf->vbtick) a->vibpos+=a->vibspd; /* do not update when pf->vbtick==0 */ + if (pf->vbtick) a->vibpos+=a->vibspd; } - static void DoTremolo(void) { - UBYTE q; - UWORD temp; - - q = (a->trmpos>>2) & 0x1f; - - switch((a->wavecontrol>>4) & 3) - { case 0: /* sine */ - temp = VibratoTable[q]; - break; - - case 1: /* ramp down */ - q<<=3; - if(a->trmpos<0) q = 255-q; - temp = q; - break; - - case 2: /* square wave */ - temp = 255; - break; - - case 3: /* Evil random wave */ - temp = rand() & 255; - break; - } - - temp *= a->trmdepth; - temp >>= 6; - - if(a->trmpos >= 0) - { a->volume = a->tmpvolume + temp; - if(a->volume > 64) a->volume = 64; - } else - { a->volume = a->tmpvolume - temp; - if(a->volume < 0) a->volume = 0; - } - - if(pf->vbtick) a->trmpos+=a->trmspd; /* do not update when pf->vbtick==0 */ + UBYTE q; + UWORD temp=0; + + q=(a->trmpos>>2)&0x1f; + + switch ((a->wavecontrol>>4)&3) { + case 0: /* sine */ + temp=VibratoTable[q]; + break; + case 1: /* ramp down */ + q<<=3; + if (a->trmpos<0) q=255-q; + temp=q; + break; + case 2: /* square wave */ + temp=255; + break; + case 3: /* random wave */ + temp=getrandom(256); + break; + } + temp*=a->trmdepth; + temp>>=6; + + if (a->trmpos>=0) { + a->volume=a->tmpvolume+temp; + if (a->volume>64) a->volume=64; + } else { + a->volume=a->tmpvolume-temp; + if (a->volume<0) a->volume=0; + } + + if (pf->vbtick) a->trmpos+=a->trmspd; } - static void DoVolSlide(UBYTE dat) { - if(!pf->vbtick) return; /* do not update when pf->vbtick==0 */ + if (!pf->vbtick) return; - a->tmpvolume += dat >> 4; /* volume slide */ - a->tmpvolume -= dat & 0xf; - if(a->tmpvolume < 0) a->tmpvolume = 0; - if(a->tmpvolume > 64) a->tmpvolume = 64; + if (dat&0xf) { + a->tmpvolume-=(dat&0x0f); + if (a->tmpvolume<0) a->tmpvolume=0; + } else { + a->tmpvolume+=(dat>>4); + if (a->tmpvolume>64) a->tmpvolume=64; + } } - static void DoToneSlide(void) { - int dist; - - if(a->period==0) return; - - if(!pf->vbtick) - { a->tmpperiod = a->period; - return; - } + if (pf->vbtick) { + int dist; - /* We have to slide a->period towards a->wantedperiod, so */ - /* compute the difference between those two values */ + /* We have to slide a->period towards a->wantedperiod, so compute the + difference between those two values */ + dist=a->period-a->wantedperiod; - dist = a->period-a->wantedperiod; - - if( dist==0 || a->portspeed>abs(dist) ) /* if they are equal or if portamentospeed is too big */ - a->period = a->wantedperiod; /* make tmpperiod equal tperiod */ - else if(dist>0) /* dist>0 ? */ - a->period-=a->portspeed; /* then slide up */ - else - a->period+=a->portspeed; /* dist<0 -> slide down */ - - a->tmpperiod = a->period; + /* if they are equal or if portamentospeed is too big ...*/ + if ((!dist)||a->portspeed>abs(dist)) + /* ...make tmpperiod equal tperiod */ + a->tmpperiod=a->period=a->wantedperiod; + else if (dist>0) { + a->tmpperiod-=a->portspeed; + a->period-=a->portspeed; /* dist>0, slide up */ + } else { + a->tmpperiod+=a->portspeed; + a->period+=a->portspeed; /* dist<0, slide down */ + } + } else + a->tmpperiod=a->period; } - -static void DoPTEffect0(UBYTE dat) +static void DoArpeggio(UBYTE dat) { - UBYTE note; + UBYTE note=a->note; - note = a->note; - - if(dat!=0) - { switch(pf->vbtick%3) - { case 1: - note+=(dat>>4); break; - case 2: - note+=(dat&0xf); break; - } - a->period = GetPeriod(note,a->speed); - a->ownper = 1; - } + if (dat) { + switch (pf->vbtick%3) { + case 1: + note+=(dat>>4); break; + case 2: + note+=(dat&0xf); break; + } + a->period=GetPeriod((UWORD)note<<1,a->speed); + a->ownper=1; + } } - -/* ----------------------------------------- */ -/* --> ScreamTreacker 3 Specific Effects <-- */ -/* ----------------------------------------- */ +/*========== Scream Tracker effects */ static void DoS3MVolSlide(UBYTE inf) { - UBYTE lo, hi; + UBYTE lo, hi; - if(inf) a->s3mvolslide = inf; + explicitslides=1; - inf = a->s3mvolslide; - lo = inf & 0xf; - hi = inf >> 4; + if (inf) a->s3mvolslide=inf; + else inf=a->s3mvolslide; - if(hi==0) a->tmpvolume -= lo; - else if(lo==0) a->tmpvolume += hi; - else if(hi==0xf) - { if(!pf->vbtick) a->tmpvolume -= lo; - } else if(lo==0xf) - { if(!pf->vbtick) a->tmpvolume += hi; - } - if(a->tmpvolume < 0) a->tmpvolume = 0; - if(a->tmpvolume > 64) a->tmpvolume = 64; -} + lo=inf&0xf; + hi=inf>>4; + if (!lo) { + if ((pf->vbtick)||(pf->flags&UF_S3MSLIDES)) a->tmpvolume+=hi; + } else + if (!hi) { + if ((pf->vbtick)||(pf->flags&UF_S3MSLIDES)) a->tmpvolume-=lo; + } else + if (lo==0xf) { + if (!pf->vbtick) a->tmpvolume+=(hi?hi:0xf); + } else + if (hi==0xf) { + if (!pf->vbtick) a->tmpvolume-=(lo?lo:0xf); + } else + return; + + if (a->tmpvolume<0) a->tmpvolume=0; + else if (a->tmpvolume>64) a->tmpvolume=64; +} static void DoS3MSlideDn(UBYTE inf) { - UBYTE hi,lo; + UBYTE hi,lo; - if(inf!=0) a->slidespeed = inf; - else inf = a->slidespeed; + if (inf) a->slidespeed=inf; + else inf=a->slidespeed; - hi = inf>>4; - lo = inf&0xf; + hi=inf>>4; + lo=inf&0xf; - if(hi==0xf) - { if(!pf->vbtick) a->tmpperiod+=(UWORD)lo<<2; - } else if(hi==0xe) - { if(!pf->vbtick) a->tmpperiod+=lo; - } else - { if(pf->vbtick) a->tmpperiod+=(UWORD)inf<<2; - } + if (hi==0xf) { + if (!pf->vbtick) a->tmpperiod+=(UWORD)lo<<2; + } else + if (hi==0xe) { + if (!pf->vbtick) a->tmpperiod+=lo; + } else { + if (pf->vbtick) a->tmpperiod+=(UWORD)inf<<2; + } } - static void DoS3MSlideUp(UBYTE inf) { - UBYTE hi,lo; + UBYTE hi,lo; - if(inf!=0) a->slidespeed = inf; - else inf = a->slidespeed; + if (inf) a->slidespeed=inf; + else inf=a->slidespeed; - hi = inf>>4; - lo = inf&0xf; + hi=inf>>4; + lo=inf&0xf; - if(hi==0xf) - { if(!pf->vbtick) a->tmpperiod-=(UWORD)lo<<2; - } else if(hi==0xe) - { if(!pf->vbtick) a->tmpperiod-=lo; - } else - { if(pf->vbtick) a->tmpperiod-=(UWORD)inf<<2; - } + if (hi==0xf) { + if (!pf->vbtick) a->tmpperiod-=(UWORD)lo<<2; + } else + if (hi==0xe) { + if (!pf->vbtick) a->tmpperiod-=lo; + } else { + if (pf->vbtick) a->tmpperiod-=(UWORD)inf<<2; + } } - static void DoS3MTremor(UBYTE inf) { - UBYTE on,off; - - if(inf!=0) a->s3mtronof = inf; - else inf = a->s3mtronof; + UBYTE on,off; - if(!pf->vbtick) return; + if (inf) + a->s3mtronof=inf; + else { + inf=a->s3mtronof; + if (!inf) return; + } - on = (inf>>4)+1; - off = (inf&0xf)+1; + if (!pf->vbtick) return; - a->s3mtremor %= (on+off); - a->volume = (a->s3mtremor < on ) ? a->tmpvolume : 0; - a->s3mtremor++; + on=(inf>>4)+1; + off=(inf&0xf)+1; + a->s3mtremor%=(on+off); + a->volume=(a->s3mtremortmpvolume:0; + a->s3mtremor++; } - static void DoS3MRetrig(UBYTE inf) { - UBYTE hi,lo; - - hi = inf >> 4; - lo = inf & 0xf; - - if(inf) - { a->s3mrtgslide = hi; - a->s3mrtgspeed = lo; - } - - /* only retrigger if */ - /* lo nibble > 0 */ - - if(a->s3mrtgspeed > 0) - { if(a->retrig == 0) - { /* when retrig counter reaches 0, */ - /* reset counter and restart the sample */ - - if(!a->kick) a->kick = 2; - a->retrig = a->s3mrtgspeed; - - if(pf->vbtick) /* don't slide on first retrig */ - { switch(a->s3mrtgslide) - { case 1: - case 2: - case 3: - case 4: - case 5: - a->tmpvolume-=(1<<(a->s3mrtgslide-1)); - break; - - case 6: - a->tmpvolume = (2*a->tmpvolume)/3; - break; - - case 7: - a->tmpvolume = a->tmpvolume>>1; - break; - - case 9: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - a->tmpvolume+=(1<<(a->s3mrtgslide-9)); - break; - - case 0xe: - a->tmpvolume=(3*a->tmpvolume)/2; - break; - - case 0xf: - a->tmpvolume=a->tmpvolume<<1; - break; - } - if(a->tmpvolume<0) a->tmpvolume = 0; - if(a->tmpvolume>64) a->tmpvolume = 64; - } - } - a->retrig--; /* countdown */ - } + if (inf) { + a->s3mrtgslide=inf>>4; + a->s3mrtgspeed=inf&0xf; + } + + /* only retrigger if low nibble > 0 */ + if ( a->s3mrtgspeed>0) { + if (!a->retrig) { + /* when retrig counter reaches 0, reset counter and restart the + sample */ + if (a->kick!=KICK_NOTE) a->kick=KICK_KEYOFF; + a->retrig=a->s3mrtgspeed; + + if ((pf->vbtick)||(pf->flags&UF_S3MSLIDES)) { + switch (a->s3mrtgslide) { + case 1: + case 2: + case 3: + case 4: + case 5: + a->tmpvolume-=(1<<(a->s3mrtgslide-1)); + break; + case 6: + a->tmpvolume=(2*a->tmpvolume)/3; + break; + case 7: + a->tmpvolume>>=1; + break; + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + a->tmpvolume+=(1<<(a->s3mrtgslide-9)); + break; + case 0xe: + a->tmpvolume=(3*a->tmpvolume)>>1; + break; + case 0xf: + a->tmpvolume=a->tmpvolume<<1; + break; + } + if (a->tmpvolume<0) a->tmpvolume=0; + else if (a->tmpvolume>64) a->tmpvolume=64; + } + } + a->retrig--; /* countdown */ + } } - static void DoS3MSpeed(UBYTE speed) { - if(pf->vbtick || pf->patdly2) return; + if (pf->vbtick||pf->patdly2) return; - if(speed) - { pf->sngspd = speed; - pf->vbtick = 0; - } + if (speed>128) speed-=128; + if (speed) { + pf->sngspd=speed; + pf->vbtick=0; + } } - static void DoS3MTempo(UBYTE tempo) { - if(pf->vbtick || pf->patdly2) return; - pf->bpm = tempo; -} + if (pf->vbtick||pf->patdly2) return; + pf->bpm=(tempo<32)?32:tempo; +} static void DoS3MFineVibrato(void) { - UBYTE q; - UWORD temp; - - q = (a->vibpos>>2)&0x1f; - - switch(a->wavecontrol&3) - { case 0: /* sine */ - temp=VibratoTable[q]; - break; + UBYTE q; + UWORD temp=0; - case 1: /* ramp down */ - q<<=3; - if(a->vibpos<0) q=255-q; - temp=q; - break; + q=(a->vibpos>>2)&0x1f; - case 2: /* square wave */ - temp=255; - break; + switch (a->wavecontrol&3) { + case 0: /* sine */ + temp=VibratoTable[q]; + break; + case 1: /* ramp down */ + q<<=3; + if (a->vibpos<0) q=255-q; + temp=q; + break; + case 2: /* square wave */ + temp=255; + break; + case 3: /* random */ + temp=getrandom(256); + break; + } - case 3: /* evil random */ - temp = rand() & 255; /* (range 0 to 255) */ - } + temp*=a->vibdepth; + temp>>=8; - temp*=a->vibdepth; - temp>>=8; + if (a->vibpos>=0) + a->period=a->tmpperiod+temp; + else + a->period=a->tmpperiod-temp; - if(a->vibpos>=0) - a->period = a->tmpperiod+temp; - else - a->period = a->tmpperiod-temp; - - a->vibpos += a->vibspd; + a->vibpos+=a->vibspd; } - static void DoS3MTremolo(void) { - UBYTE q; - UWORD temp; - - q = (a->trmpos>>2)&0x1f; + UBYTE q; + UWORD temp=0; - switch((a->wavecontrol>>4)&3) - { case 0: /* sine */ - temp = VibratoTable[q]; - break; + q=(a->trmpos>>2)&0x1f; - case 1: /* ramp down */ - q<<=3; - if(a->trmpos<0) q = 255-q; - temp = q; - break; + switch ((a->wavecontrol>>4)&3) { + case 0: /* sine */ + temp=VibratoTable[q]; + break; + case 1: /* ramp down */ + q<<=3; + if (a->trmpos<0) q=255-q; + temp=q; + break; + case 2: /* square wave */ + temp=255; + break; + case 3: /* random */ + temp=getrandom(256); + break; + } - case 2: /* square wave */ - temp=255; - break; + temp*=a->trmdepth; + temp>>=7; - case 3: /* evil random */ - temp = rand() & 255; /* (range 0 to 255) */ - } + if (a->trmpos>=0) { + a->volume=a->tmpvolume+temp; + if (a->volume>64) a->volume=64; + } else { + a->volume=a->tmpvolume-temp; + if (a->volume<0) a->volume=0; + } - temp*=a->trmdepth; - temp>>=7; - - if(a->trmpos>=0) - { a->volume = a->tmpvolume + temp; - if(a->volume>64) a->volume = 64; - } else - { a->volume = a->tmpvolume - temp; - if(a->volume<0) a->volume = 0; - } - - if(pf->vbtick) a->trmpos += a->trmspd; /* do not update when pf->vbtick==0 */ + if (pf->vbtick) a->trmpos+=a->trmspd; } - -/* -------------------------------------- */ -/* --> FastTracker 2 Specific Effects <-- */ -/* -------------------------------------- */ +/*========== Fast Tracker effects */ static void DoXMVolSlide(UBYTE inf) { - UBYTE lo,hi; + UBYTE lo,hi; - if(inf) - a->s3mvolslide = inf; + explicitslides=2; - inf = a->s3mvolslide; - if(!pf->vbtick) return; + if (inf) a->s3mvolslide=inf; + else inf=a->s3mvolslide; - lo = inf&0xf; - hi = inf>>4; + if (!pf->vbtick) return; - if(hi==0) - a->tmpvolume-=lo; - else - a->tmpvolume+=hi; + lo=inf&0xf; + hi=inf>>4; - if(a->tmpvolume<0) a->tmpvolume=0; - else if(a->tmpvolume>64) a->tmpvolume=64; + if (!hi) { + a->tmpvolume-=lo; + if (a->tmpvolume<0) a->tmpvolume=0; + } else { + a->tmpvolume+=hi; + if (a->tmpvolume>64) a->tmpvolume=64; + } } - static void DoXMGlobalSlide(UBYTE inf) { - if(pf->vbtick) - { if(inf) pf->globalslide=inf; else inf=pf->globalslide; - if(inf & 0xf0) inf &= 0xf0; - pf->volume = pf->volume + ((inf >> 4) - (inf & 0xf))*2; + if (pf->vbtick) { + if (inf) pf->globalslide=inf; + else inf=pf->globalslide; + if (inf & 0xf0) inf&=0xf0; + pf->volume=pf->volume+((inf>>4)-(inf&0xf))*2; - if(pf->volume<0) pf->volume = 0; - else if(pf->volume>128) pf->volume = 128; - } + if (pf->volume<0) pf->volume=0; + else if (pf->volume>128) pf->volume=128; + } } - static void DoXMPanSlide(UBYTE inf) { - UBYTE lo,hi; - SWORD pan; - + UBYTE lo,hi; + SWORD pan; - if(inf!=0) a->pansspd = inf; - else inf = a->pansspd; + if (inf) a->pansspd=inf; + else inf=a->pansspd; - if(!pf->vbtick) return; + if (!pf->vbtick) return; - lo = inf & 0xf; - hi = inf >> 4; + lo=inf&0xf; + hi=inf>>4; - /* slide right has absolute priority: */ + /* slide right has absolute priority */ + if (hi) lo=0; - if(hi) lo = 0; + pan=((a->panning==PAN_SURROUND)?PAN_CENTER:a->panning)+hi-lo; - pan = (a->panning == PAN_SURROUND) ? 128 : a->panning; - - pan -= lo; - pan += hi; - - if(pan < 0) pan = 0; - if(pan > 255) pan = 255; - - a->panning = pan; + a->panning=(panPAN_RIGHT?PAN_RIGHT:pan); } - static void DoXMExtraFineSlideUp(UBYTE inf) { - if(!pf->vbtick) - { if(inf) a->ffportupspd = inf; else inf = a->ffportupspd; - a->period -= inf; - } - a->tmpperiod = a->period; + if (!pf->vbtick) { + a->period-=inf; + a->tmpperiod-=inf; + } } - static void DoXMExtraFineSlideDown(UBYTE inf) { - if(!pf->vbtick) - { if(inf) a->ffportdnspd = inf; else inf = a->ffportdnspd; - a->period += inf; - } - a->tmpperiod = a->period; + if (!pf->vbtick) { + a->period+=inf; + a->tmpperiod+=inf; + } } - -/* --------------------------------------- */ -/* --> ImpulseTracker Player Functions <-- */ -/* --------------------------------------- */ +/*========== Impulse Tracker effects */ static void DoITChanVolSlide(UBYTE inf) { - UBYTE lo, hi; + UBYTE lo, hi; - if(inf) a->chanvolslide = inf; - inf = a->chanvolslide; + if (inf) a->chanvolslide=inf; + inf=a->chanvolslide; - lo = inf&0xf; - hi = inf>>4; + lo=inf&0xf; + hi=inf>>4; - if(hi==0) - { a->chanvol-=lo; - } else if(lo==0) - { a->chanvol+=hi; - } else if(hi==0xf) - { if(!pf->vbtick) a->chanvol-=lo; - } else if(lo==0xf) - { if(!pf->vbtick) a->chanvol+=hi; - } + if (!hi) + a->chanvol-=lo; + else + if (!lo) { + a->chanvol+=hi; + } else + if (hi==0xf) { + if (!pf->vbtick) a->chanvol-=lo; + } else + if (lo==0xf) { + if (!pf->vbtick) a->chanvol+=hi; + } - if(a->chanvol<0) a->chanvol = 0; - if(a->chanvol>64) a->chanvol = 64; + if (a->chanvol<0) a->chanvol=0; + if (a->chanvol>64) a->chanvol=64; } - static void DoITGlobalSlide(UBYTE inf) { - UBYTE lo,hi; + UBYTE lo,hi; - if(inf) pf->globalslide = inf; - inf = pf->globalslide; + if (inf) pf->globalslide=inf; + inf=pf->globalslide; - lo = inf&0xf; - hi = inf>>4; + lo=inf&0xf; + hi=inf>>4; - if(lo==0) - { pf->volume += hi; - } else if(hi==0) - { pf->volume -= lo; - } else if(lo==0xf) - { if(!pf->vbtick) pf->volume += hi; - } else if(hi==0xf) - { if(!pf->vbtick) pf->volume -= lo; - } + if (!lo) { + if (pf->vbtick) pf->volume+=hi; + } else + if (!hi) { + if (pf->vbtick) pf->volume-=lo; + } else + if (lo==0xf) { + if (!pf->vbtick) pf->volume+=hi; + } else + if (hi==0xf) { + if (!pf->vbtick) pf->volume-=lo; + } - if(pf->volume < 0) pf->volume = 0; - if(pf->volume > 128) pf->volume = 128; + if (pf->volume<0) pf->volume=0; + if (pf->volume>128) pf->volume=128; } - static void DoITPanSlide(UBYTE inf) { - UBYTE lo,hi; - SWORD pan; + UBYTE lo,hi; + SWORD pan; - if(inf) a->pansspd = inf; - inf = a->pansspd; + if (inf) a->pansspd=inf; + else inf=a->pansspd; - lo = inf & 0xf; - hi = inf >> 4; + lo=inf&0xf; + hi=inf>>4; - pan = (a->panning == PAN_SURROUND) ? 128 : a->panning; + pan=(a->panning==PAN_SURROUND)?PAN_CENTER:a->panning; - if(hi==0) - { pan += lo << 2; - } else if(lo==0) - { pan -= hi << 2; - } else if(hi==0xf) - { if(!pf->vbtick) pan += lo << 2; - } else if(lo==0xf) - { if(!pf->vbtick) pan -= hi << 2; - } - if(pan > 255) pan = 255; - if(pan < 0) pan = 0; - a->panning = /*pf->panning[mp_channel] =*/ pan; + if (!hi) + pan+=lo<<2; + else + if (!lo) { + pan-=hi<<2; + } else + if (hi==0xf) { + if (!pf->vbtick) pan+=lo<<2; + } else + if (lo==0xf) { + if (!pf->vbtick) pan-=hi<<2; + } + a->panning=/*pf->panning[mp_channel]=*/ + (panPAN_RIGHT?PAN_RIGHT:pan); } - -static void DoITVibrato(void) +static void DoITTempo(UBYTE tempo) { - UBYTE q; - UWORD temp; + SWORD temp=pf->bpm; - q = (a->vibpos>>2)&0x1f; + if (pf->vbtick||pf->patdly2) return; - switch(a->wavecontrol&3) - { case 0: /* sine */ - temp=VibratoTable[q]; - break; + if (tempo&0x10) + temp+=(tempo&0x0f); + else + temp-=tempo; - case 1: /* ramp down */ - q<<=3; - if(a->vibpos<0) q=255-q; - temp=q; - break; + pf->bpm=(temp>255)?255:(temp<1?1:temp); +} - case 2: /* square wave */ - temp=255; - break; +static void DoITVibrato(void) +{ + UBYTE q; + UWORD temp=0; - case 3: /* evil random */ - temp = rand() & 255; /* (range 0 to 255) */ - break; - } + q=(a->vibpos>>2)&0x1f; - temp*=a->vibdepth; - temp>>=8; - temp<<=2; + switch (a->wavecontrol&3) { + case 0: /* sine */ + temp=VibratoTable[q]; + break; + case 1: /* square wave */ + temp=255; + break; + case 2: /* ramp down */ + q<<=3; + if (a->vibpos<0) q=255-q; + temp=q; + break; + case 3: /* random */ + temp=getrandom(256); + break; + } - if(a->vibpos>=0) - a->period = a->tmpperiod+temp; - else - a->period = a->tmpperiod-temp; + temp*=a->vibdepth; + temp>>=8; + temp<<=2; - a->vibpos+=a->vibspd; -} + if (a->vibpos>=0) + a->period=a->tmpperiod+temp; + else + a->period=a->tmpperiod-temp; + a->vibpos+=a->vibspd; +} static void DoITFineVibrato(void) { - UBYTE q; - UWORD temp; - - q = (a->vibpos>>2)&0x1f; - - switch(a->wavecontrol&3) - { case 0: /* sine */ - temp=VibratoTable[q]; - break; - - case 1: /* ramp down */ - q<<=3; - if(a->vibpos<0) q = 255-q; - temp = q; - break; + UBYTE q; + UWORD temp=0; - case 2: /* square wave */ - temp = 255; - break; + q=(a->vibpos>>2)&0x1f; - case 3: /* evil random */ - temp = rand() & 255; /* (range 0 to 255) */ - break; - } + switch (a->wavecontrol&3) { + case 0: /* sine */ + temp=VibratoTable[q]; + break; + case 1: /* square wave */ + temp=255; + break; + case 2: /* ramp down */ + q<<=3; + if (a->vibpos<0) q=255-q; + temp=q; + break; + case 3: /* random */ + temp=getrandom(256); + break; + } - temp*=a->vibdepth; - temp>>=8; + temp*=a->vibdepth; + temp>>=8; - if(a->vibpos>=0) - a->period = a->tmpperiod+temp; - else - a->period = a->tmpperiod-temp; + if (a->vibpos>=0) + a->period=a->tmpperiod+temp; + else + a->period=a->tmpperiod-temp; - a->vibpos+=a->vibspd; + a->vibpos+=a->vibspd; } - static void DoITTremor(UBYTE inf) { - UBYTE on,off; + UBYTE on,off; - if(inf!=0) a->s3mtronof = inf; - else inf = a->s3mtronof; + if (inf) + a->s3mtronof=inf; + else { + inf=a->s3mtronof; + if (!inf) return; + } - if(!pf->vbtick) return; + if (!pf->vbtick) return; - on=(inf>>4); - off=(inf&0xf); + on=(inf>>4); + off=(inf&0xf); - a->s3mtremor%=(on+off); - a->volume = (a->s3mtremor < on ) ? a->tmpvolume : 0; - a->s3mtremor++; + a->s3mtremor%=(on+off); + a->volume=(a->s3mtremortmpvolume:0; + a->s3mtremor++; } - static void DoITPanbrello(void) { - UBYTE q; - static SLONG temp; - - q = a->panbpos; - - switch(a->panbwave) - { case 0: /* sine */ - temp = PanbrelloTable[q]; - break; - - /* only sinewave is correctly supported right now */ - - case 1: /* ramp down */ - q<<=3; - temp = q; - break; + UBYTE q; + SLONG temp=0; - case 2: /* square wave */ - temp = 64; - break; + q=a->panbpos; - case 3: /* evil random */ - if(a->panbpos >= a->panbspd) - { a->panbpos = 0; - temp = rand() & 255; - } - } + switch (a->panbwave) { + case 0: /* sine */ + temp=PanbrelloTable[q]; + break; + case 1: /* square wave */ + temp=(q<0x80)?64:0; + break; + case 2: /* ramp down */ + q<<=3; + temp=q; + break; + case 3: /* random */ + if (a->panbpos>=a->panbspd) { + a->panbpos=0; + temp=getrandom(256); + } + } - temp*=a->panbdepth; - temp/=8; + temp*=a->panbdepth; + temp=(temp/8)+pf->panning[mp_channel]; - a->panning = pf->panning[mp_channel] + temp; - a->panbpos += a->panbspd; + a->panning=(tempPAN_RIGHT?PAN_RIGHT:temp); + a->panbpos+=a->panbspd; } - static void DoITToneSlide(void) { - int dist; - - if(a->period == 0) return; - - if(!pf->vbtick) - { a->tmpperiod = a->period; - return; - } - - /* We have to slide a->period towards a->wantedperiod, */ - /* compute the difference between those two values */ - - dist = a->period - a->wantedperiod; - - if( (dist == 0) || /* if they are equal */ - ((a->slidespeed<<2) > abs(dist)) ) /* or if portamentospeed is too big */ - { a->period = a->wantedperiod; /* make tmpperiod equal tperiod */ - } else if(dist > 0) /* dist>0 ? */ - { a->period -= a->slidespeed << 2; /* then slide up */ - } else - { a->period += a->slidespeed << 2; /* dist<0 -> slide down */ - } - a->tmpperiod = a->period; + /* if we don't come from another note, ignore the slide and play the note + as is */ + if (!a->oldnote) return; + + if (pf->vbtick) { + int dist; + + /* We have to slide a->period towards a->wantedperiod, compute the + difference between those two values */ + dist=a->period-a->wantedperiod; + + /* if they are equal or if portamentospeed is too big... */ + if ((!dist)||((a->portspeed<<2)>abs(dist))) + /* ... make tmpperiod equal tperiod */ + a->tmpperiod=a->period=a->wantedperiod; + else + if (dist>0) { + a->tmpperiod-=a->portspeed<<2; + a->period-=a->portspeed<<2; /* dist>0 slide up */ + } else { + a->tmpperiod+=a->portspeed<<2; + a->period+=a->portspeed<<2; /* dist<0 slide down */ + } + } else + a->tmpperiod=a->period; } - +static void DoNNAEffects(UBYTE dat); +/* Impulse/Scream Tracker Sxx effects. + All Sxx effects share the same memory space. */ static void DoSSEffects(UBYTE dat) - -/* Impulse/Scream Tracker Sxx effects. */ -/* All Sxx effects share the same memory space. */ - -{ - UBYTE inf,c; - - inf = dat&0xf; - c = dat>>4; - - if(dat==0) - { c = a->sseffect; - inf = a->ssdata; - } else - { a->sseffect = c; - a->ssdata = inf; - } - - switch(c) - { case SS_GLISSANDO: /* S1x set glissando voice */ - DoEEffects(0x30|inf); - break; - - case SS_FINETUNE: /* S2x set finetune */ - DoEEffects(0x50|inf); - break; - - case SS_VIBWAVE: /* S3x set vibrato waveform */ - DoEEffects(0x40|inf); - break; - - case SS_TREMWAVE: /* S4x set tremolo waveform */ - DoEEffects(0x70|inf); - break; - - case SS_PANWAVE: /* The Satanic Panbrello waveform */ - a->panbwave = (UniGetByte()); - break; - - case SS_FRAMEDELAY: /* S6x Delay x number of frames (patdly) */ - DoEEffects(0xe0|inf); - break; - - case SS_S7EFFECTS: /* S7x Instrument / NNA commands */ - DoNNAEffects(UniGetByte()); - break; - - case SS_PANNING: /* S8x set panning position */ - DoEEffects(0x80 | inf); - break; - - case SS_SURROUND: /* S9x Set Surround Sound */ - a->panning = pf->panning[mp_channel] = PAN_SURROUND; - break; - - case SS_HIOFFSET: /* SAy Set high order sample offset yxx00h */ - a->hioffset |= UniGetByte() << 16; - break; - - case SS_PATLOOP: /* SBx pattern loop */ - DoEEffects(0x60|inf); - break; - - case SS_NOTECUT: /* SCx notecut */ - DoEEffects(0xC0|inf); - break; - - case SS_NOTEDELAY: /* SDx notedelay */ - DoEEffects(0xD0|inf); - break; - - case SS_PATDELAY: /* SEx patterndelay */ - DoEEffects(0xE0|inf); - break; - } -} - - +{ + UBYTE inf,c; + + inf=dat&0xf; + c=dat>>4; + + if (!dat) { + c=a->sseffect; + inf=a->ssdata; + } else { + a->sseffect=c; + a->ssdata=inf; + } + + switch (c) { + case SS_GLISSANDO: /* S1x set glissando voice */ + DoEEffects(0x30|inf); + break; + case SS_FINETUNE: /* S2x set finetune */ + DoEEffects(0x50|inf); + break; + case SS_VIBWAVE: /* S3x set vibrato waveform */ + DoEEffects(0x40|inf); + break; + case SS_TREMWAVE: /* S4x set tremolo waveform */ + DoEEffects(0x70|inf); + break; + case SS_PANWAVE: /* S5x panbrello */ + a->panbwave=inf; + break; + case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */ + DoEEffects(0xe0|inf); + break; + case SS_S7EFFECTS: /* S7x instrument / NNA commands */ + DoNNAEffects(inf); + break; + case SS_PANNING: /* S8x set panning position */ + DoEEffects(0x80 | inf); + break; + case SS_SURROUND: /* S9x set surround Sound */ + if (pf->panflag) + a->panning=pf->panning[mp_channel]=PAN_SURROUND; + break; + case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */ + if (!pf->vbtick) { + a->hioffset=inf<<16; + a->start=a->hioffset|a->soffset; + + if ((a->s)&&(a->start>a->s->length)) + a->start=a->s->flags&(SF_LOOP|SF_BIDI)?a->s->loopstart:a->s->length; + } + break; + case SS_PATLOOP: /* SBx pattern loop */ + DoEEffects(0x60|inf); + break; + case SS_NOTECUT: /* SCx notecut */ + DoEEffects(0xC0|inf); + break; + case SS_NOTEDELAY: /* SDx notedelay */ + DoEEffects(0xD0|inf); + break; + case SS_PATDELAY: /* SEx patterndelay */ + DoEEffects(0xE0|inf); + break; + } +} + +/* Impulse Tracker Volume/Pan Column effects. + All volume/pan column effects share the same memory space. */ static void DoVolEffects(UBYTE c) - -/* Impulse Tracker Volume/Pan Column effects. */ -/* All volume/pan column effects share the same memory space. */ - -{ - UBYTE inf; - - inf = UniGetByte(); - - if(c==0 && inf==0) - { c = a->voleffect; - inf = a->voldata; - } else - { a->voleffect = c; - a->voldata = inf; - } - - switch(c) - { case 0: break; /* do nothing */ - case VOL_VOLUME: - if(pf->vbtick) break; - if(inf>64) inf = 64; - a->tmpvolume = inf; - break; - - case VOL_PANNING: - if(pf->panflag) - { a->panning = inf; - pf->panning[mp_channel] = inf; - } - break; - - case VOL_VOLSLIDE: - DoS3MVolSlide(inf); - break; - - case VOL_PITCHSLIDEDN: - DoS3MSlideDn(UniGetByte()); - break; - - case VOL_PITCHSLIDEUP: - DoS3MSlideUp(UniGetByte()); - break; - - case VOL_PORTAMENTO: - if(inf != 0) a->slidespeed = inf; - - if(a->period != 0) - { if(!(pf->vbtick==pf->sngspd-1) && (a->newsamp)) - { a->kick = 1; - a->start = -1; - /*a->period *= a->speed * a->newsamp; */ - } else - a->kick = 0; - - DoITToneSlide(); - a->ownper = 1; - } - break; - - case VOL_VIBRATO: - if(inf & 0x0f) a->vibdepth = inf & 0xf; - if(inf & 0xf0) a->vibspd = (inf & 0xf0) >> 2; - DoITVibrato(); - a->ownper = 1; - break; - } -} - - - -/* -------------------------------- */ -/* --> General Player Functions <-- */ -/* -------------------------------- */ +{ + UBYTE inf=UniGetByte(); + + if ((!c)&&(!inf)) { + c=a->voleffect; + inf=a->voldata; + } else { + a->voleffect=c; + a->voldata=inf; + } + + if (c) + switch (c) { + case VOL_VOLUME: + if (pf->vbtick) break; + if (inf>64) inf=64; + a->tmpvolume=inf; + break; + case VOL_PANNING: + if (pf->panflag) + a->panning=/*pf->panning[mp_channel]=*/inf; + break; + case VOL_VOLSLIDE: + DoS3MVolSlide(inf); + break; + case VOL_PITCHSLIDEDN: + if (a->period) + DoS3MSlideDn(inf); + break; + case VOL_PITCHSLIDEUP: + if (a->period) + DoS3MSlideUp(inf); + break; + case VOL_PORTAMENTO: + if (inf) a->slidespeed=inf; + if (a->period) { + if ((!pf->vbtick)||(a->newsamp)){ + a->kick=KICK_NOTE; + a->start=-1; + } else + a->kick=(a->kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT; + DoITToneSlide(); + a->ownper=1; + } + break; + case VOL_VIBRATO: + if (!pf->vbtick) { + if (inf&0x0f) a->vibdepth=inf&0xf; + if (inf&0xf0) a->vibspd=(inf&0xf0)>>2; + } + if (a->period) { + DoITVibrato(); + a->ownper=1; + } + break; + } +} + +/*========== UltraTracker effects */ + +static void DoULTSampleOffset(void) +{ + UWORD offset=UniGetWord(); + + if (offset) + a->ultoffset=offset; + + a->start=a->ultoffset<<2; + if ((a->s)&&(a->start>a->s->length)) + a->start=a->s->flags&(SF_LOOP|SF_BIDI)?a->s->loopstart:a->s->length; +} + +/*========== OctaMED effects */ + +static void DoMEDSpeed(void) +{ + UWORD speed=UniGetWord(); + + pf->bpm=speed; +} + +/*========== General player functions */ static void pt_playeffects(void) { - UBYTE dat,c; - - while(c = UniGetByte()) - switch(c) - { case UNI_NOTE: - case UNI_INSTRUMENT: - UniSkipOpcode(c); - break; - - case UNI_PTEFFECT0: - DoPTEffect0(UniGetByte()); - break; - - case UNI_PTEFFECT1: - dat = UniGetByte(); - if(dat != 0) a->slidespeed = (UWORD)dat << 2; - if(pf->vbtick) a->tmpperiod -= a->slidespeed; - break; - - case UNI_PTEFFECT2: - dat = UniGetByte(); - if(dat != 0) a->slidespeed = (UWORD)dat << 2; - if(pf->vbtick) a->tmpperiod += a->slidespeed; - break; - - case UNI_PTEFFECT3: - dat = UniGetByte(); - - if(dat!=0) - { a->portspeed = dat; - a->portspeed <<= 2; - } - - if(a->period != 0) - { a->kick = 0; /* temp XM fix */ - DoToneSlide(); - a->ownper = 1; - } - break; - - case UNI_PTEFFECT4: - dat = UniGetByte(); - if(dat & 0x0f) a->vibdepth = dat & 0xf; - if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; - DoVibrato(); - a->ownper = 1; - break; - - case UNI_PTEFFECT5: - dat = UniGetByte(); - a->kick = 0; - DoToneSlide(); - DoVolSlide(dat); - a->ownper = 1; - break; - - case UNI_PTEFFECT6: - dat = UniGetByte(); - DoVibrato(); - DoVolSlide(dat); - a->ownper = 1; - break; - - case UNI_PTEFFECT7: - dat = UniGetByte(); - if(dat & 0x0f) a->trmdepth = dat & 0xf; - if(dat & 0xf0) a->trmspd = (dat & 0xf0) >> 2; - DoTremolo(); - a->ownvol = 1; - break; - - case UNI_PTEFFECT8: - dat = UniGetByte(); - if(pf->panflag) - { a->panning = dat; - pf->panning[mp_channel] = dat; - } - break; - - case UNI_PTEFFECT9: - dat = UniGetByte(); - if(dat) a->soffset = (UWORD)dat << 8; - a->start = a->hioffset | a->soffset; - if((a->s != NULL) && (a->start > a->s->length)) a->start = a->s->loopstart; - break; - - case UNI_PTEFFECTA: - DoVolSlide(UniGetByte()); - break; - - case UNI_PTEFFECTB: - dat = UniGetByte(); - if(pf->patdly2) break; - pf->patbrk = 0; - pf->sngpos = dat-1; - pf->posjmp = 3; - break; - - case UNI_PTEFFECTC: - dat = UniGetByte(); - if(pf->vbtick) break; - if(dat>64) dat = 64; - a->tmpvolume = dat; - break; - - case UNI_PTEFFECTD: - dat = UniGetByte(); - if(pf->patdly2) break; - pf->patbrk = dat; - if(pf->patbrk>pf->pattrows[mp_channel]) - pf->patbrk = pf->pattrows[mp_channel]; - pf->posjmp = 3; - break; - - case UNI_PTEFFECTE: - DoEEffects(UniGetByte()); - break; - - case UNI_PTEFFECTF: - dat = UniGetByte(); - - if(pf->vbtick || pf->patdly2) break; - - if(pf->extspd && (dat >= 0x20)) - pf->bpm = dat; - else - { if(dat) - { pf->sngspd = dat; - pf->vbtick = 0; - } - } - break; - - case UNI_S3MEFFECTA: - DoS3MSpeed(UniGetByte()); - break; - - case UNI_S3MEFFECTD: - DoS3MVolSlide(UniGetByte()); - break; - - case UNI_S3MEFFECTE: - DoS3MSlideDn(UniGetByte()); - break; - - case UNI_S3MEFFECTF: - DoS3MSlideUp(UniGetByte()); - break; - - case UNI_S3MEFFECTI: - DoS3MTremor(UniGetByte()); - a->ownvol = 1; - break; - - case UNI_S3MEFFECTQ: - DoS3MRetrig(UniGetByte()); - break; - - case UNI_S3MEFFECTR: - dat = UniGetByte(); - if(dat & 0x0f) a->trmdepth = dat & 0xf; - if(dat & 0xf0) a->trmspd = (dat & 0xf0) >> 2; - DoS3MTremolo(); - a->ownvol = 1; - break; - - case UNI_S3MEFFECTT: - DoS3MTempo(UniGetByte()); - break; - - case UNI_S3MEFFECTU: - dat = UniGetByte(); - if(dat & 0x0f) a->vibdepth = dat & 0xf; - if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; - DoS3MFineVibrato(); - a->ownper = 1; - break; - - case UNI_KEYOFF: - a->keyoff |= KEY_OFF; - if(a->i != NULL) - { if(!(a->i->volflg & EF_ON) || (a->i->volflg & EF_LOOP)) - a->keyoff = KEY_KILL; - } - break; - - case UNI_KEYFADE: - if(pf->vbtick >= UniGetByte()) - { a->keyoff = KEY_KILL; - if((a->i != NULL) && !(a->i->volflg & EF_ON)) - a->fadevol = 0; - } - break; - - case UNI_VOLEFFECTS: - DoVolEffects(UniGetByte()); - break; - - case UNI_XMEFFECT4: - dat = UniGetByte(); - if(pf->vbtick) - { if(dat & 0x0f) a->vibdepth = dat & 0xf; - if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; - } - DoVibrato(); - a->ownper = 1; - break; - - case UNI_XMEFFECTA: - DoXMVolSlide(UniGetByte()); - break; - - case UNI_XMEFFECTE1: /* xm fineslide up */ - dat = UniGetByte(); - if(!pf->vbtick) - { if(dat) a->fportupspd = dat; else dat = a->fportupspd; - a->tmpperiod -= (dat << 2); - } - break; - - case UNI_XMEFFECTE2: /* xm fineslide dn */ - dat = UniGetByte(); - if(!pf->vbtick) - { if(dat) a->fportdnspd = dat; else dat = a->fportdnspd; - a->tmpperiod += (dat<<2); - } - break; - - case UNI_XMEFFECTEA: /* fine volume slide up */ - dat = UniGetByte(); - if(pf->vbtick) break; - if(dat) a->fslideupspd = dat; else dat = a->fslideupspd; - a->tmpvolume+=dat; - if(a->tmpvolume>64) a->tmpvolume = 64; - break; - - case UNI_XMEFFECTEB: /* fine volume slide dn */ - dat = UniGetByte(); - if(pf->vbtick) break; - if(dat) a->fslidednspd = dat; else dat = a->fslidednspd; - a->tmpvolume-=dat; - if(a->tmpvolume<0) a->tmpvolume = 0; - break; - - case UNI_XMEFFECTG: - pf->volume = UniGetByte(); - break; - - case UNI_XMEFFECTH: - DoXMGlobalSlide(UniGetByte()); - break; - - case UNI_XMEFFECTL: - dat = UniGetByte(); - if(!pf->vbtick && a->i!=NULL) - { UWORD points; - INSTRUMENT *i = a->i; - MP_VOICE *aout; - - if((aout = a->slave) != NULL) - { points = i->volenv[i->volpts-1].pos; - aout->venv.p = aout->venv.env[(dat>points) ? points : dat].pos; - - points = i->panenv[i->panpts-1].pos; - aout->penv.p = aout->penv.env[(dat>points) ? points : dat].pos; - } - } - break; - - case UNI_XMEFFECTP: - DoXMPanSlide(UniGetByte()); - break; - - case UNI_XMEFFECTX1: - DoXMExtraFineSlideUp(UniGetByte()); - a->ownper = 1; - break; - - case UNI_XMEFFECTX2: - DoXMExtraFineSlideDown(UniGetByte()); - a->ownper = 1; - break; - - case UNI_ITEFFECTG: - dat = UniGetByte(); - if(dat != 0) a->slidespeed = dat; - - if(a->period != 0) - { if((pf->vbtick < 1) && (a->newsamp)) - { a->kick = 1; - a->start = -1; - /*a->period *= a->speed * a->newsamp; */ - } else - a->kick = 0; - - DoITToneSlide(); - a->ownper = 1; - } - break; - - case UNI_ITEFFECTH: /* it vibrato */ - dat = UniGetByte(); - if(dat & 0x0f) a->vibdepth = dat & 0xf; - if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; - DoITVibrato(); - a->ownper = 1; - break; - - case UNI_ITEFFECTI: /* it tremor */ - DoITTremor(UniGetByte()); - a->ownvol = 1; - break; - - case UNI_ITEFFECTM: - a->chanvol = UniGetByte(); - if(a->chanvol > 64) a->chanvol = 64; - else if(a->chanvol < 0) a->chanvol = 0; - break; - - case UNI_ITEFFECTN: /* Slide / Fineslide Channel Volume */ - DoITChanVolSlide(UniGetByte()); - break; - - case UNI_ITEFFECTP: /* slide / fineslide channel panning */ - DoITPanSlide(UniGetByte()); - break; - - case UNI_ITEFFECTU: /* fine vibrato */ - dat = UniGetByte(); - if(dat & 0x0f) a->vibdepth = dat & 0xf; - if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; - DoITFineVibrato(); - a->ownper = 1; - break; - - case UNI_ITEFFECTW: /* Slide / Fineslide Global volume */ - DoITGlobalSlide(UniGetByte()); - break; - - case UNI_ITEFFECTY: /* The Satanic Panbrello */ - dat = UniGetByte(); - if(dat & 0x0f) a->panbdepth = (dat & 0xf); - if(dat & 0xf0) a->panbspd = (dat & 0xf0) >> 4; - DoITPanbrello(); - break; - - case UNI_ITEFFECTS0: - DoSSEffects(UniGetByte()); - break; - - default: - UniSkipOpcode(c); - break; - } + UBYTE dat,c; + + while((c=UniGetByte())) { + int oldsliding=a->sliding; + + a->sliding=0; + switch (c) { + case UNI_NOTE: + case UNI_INSTRUMENT: + a->sliding=oldsliding; + UniSkipOpcode(c); + break; + case UNI_PTEFFECT0: + dat=UniGetByte(); + if (!pf->vbtick) { + if ((!dat)&&(pf->flags&UF_ARPMEM)) dat=a->arpmem; + a->arpmem=dat; + } + if (a->period) + DoArpeggio(a->arpmem); + break; + case UNI_PTEFFECT1: + dat=UniGetByte(); + if ((!pf->vbtick)&&(dat)) a->slidespeed=(UWORD)dat<<2; + if (a->period) + if (pf->vbtick) a->tmpperiod-=a->slidespeed; + break; + case UNI_PTEFFECT2: + dat=UniGetByte(); + if ((!pf->vbtick)&&(dat)) a->slidespeed=(UWORD)dat<<2; + if (a->period) + if (pf->vbtick) a->tmpperiod+=a->slidespeed; + break; + case UNI_PTEFFECT3: + dat=UniGetByte(); + if ((!pf->vbtick)&&(dat)) a->portspeed=(UWORD)dat<<2; + if (a->period) { + if (!a->fadevol) + a->kick=(a->kick==KICK_NOTE)?KICK_NOTE:KICK_KEYOFF; + else + a->kick=(a->kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT; + DoToneSlide(); + a->ownper=1; + } + break; + case UNI_PTEFFECT4: + case UNI_XMEFFECT4: + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->vibdepth=dat&0xf; + if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; + } else + if (a->period) { + DoVibrato(); + a->ownper=1; + } + break; + case UNI_PTEFFECT5: + dat=UniGetByte(); + if (a->period) { + if (!a->fadevol) + a->kick=(a->kick==KICK_NOTE)?KICK_NOTE:KICK_KEYOFF; + else + a->kick=(a->kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT; + DoToneSlide(); + a->ownper=1; + } + DoVolSlide(dat); + break; + case UNI_PTEFFECT6: + dat=UniGetByte(); + if ((a->period)&&(pf->vbtick)) { + DoVibrato(); + a->ownper=1; + } + DoVolSlide(dat); + break; + case UNI_PTEFFECT7: + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->trmdepth=dat&0xf; + if (dat&0xf0) a->trmspd=(dat&0xf0)>>2; + } + if (a->period) { + DoTremolo(); + a->ownvol=1; + } + break; + case UNI_PTEFFECT8: + dat=UniGetByte(); + if (pf->panflag) + a->panning=pf->panning[mp_channel]=dat; + break; + case UNI_PTEFFECT9: + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat) a->soffset=(UWORD)dat<<8; + a->start=a->hioffset|a->soffset; + + if ((a->s)&&(a->start>a->s->length)) + a->start=a->s->flags&(SF_LOOP|SF_BIDI)?a->s->loopstart:a->s->length; + } + break; + case UNI_PTEFFECTA: + DoVolSlide(UniGetByte()); + break; + case UNI_PTEFFECTB: + dat=UniGetByte(); + if ((pf->vbtick)||(pf->patdly2)) break; + /* Vincent Voois uses a nasty trick in "Universal Bolero" */ + if (dat==pf->sngpos && pf->patbrk==pf->patpos) break; + if ((!pf->loop)&&(!pf->patbrk)&&((datsngpos)|| + ((pf->sngpos==pf->numpos-1)&&(!pf->patbrk))|| + ((dat==pf->sngpos)&&(pf->flags&UF_NOWRAP)))) { + /* if we don't loop, better not to skip the end of the + pattern, after all... so: + pf->patbrk=0; */ + pf->posjmp=3; + } else { + /* if we were fading, adjust... */ + if (pf->sngpos==(pf->numpos-1)) + pf->volume=pf->initvolume>128?128:pf->initvolume; + pf->sngpos=dat; + pf->posjmp=2; + pf->patpos=0; + } + break; + case UNI_PTEFFECTC: + dat=UniGetByte(); + if (pf->vbtick) break; + if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */ + else if (dat>64) dat=64; + a->tmpvolume=dat; + break; + case UNI_PTEFFECTD: + dat=UniGetByte(); + if ((pf->vbtick)||(pf->patdly2)) break; + if ((pf->positions[pf->sngpos]!=255)&& + (dat>pf->pattrows[pf->positions[pf->sngpos]])) + dat=pf->pattrows[pf->positions[pf->sngpos]]; + pf->patbrk=dat; + if (!pf->posjmp) { + /* don't ask me to explain this code - it makes + backwards.s3m and children.xm (heretic's version) play + correctly, among others. Take that for granted, or write + the page of comments yourself... you might need some + aspirin - Miod */ + if ((pf->sngpos==pf->numpos-1)&&(dat)&&((pf->loop)|| + (pf->positions[pf->sngpos]==(pf->numpat-1) + && !(pf->flags&UF_NOWRAP)))) { + pf->sngpos=0; + pf->posjmp=2; + } else + pf->posjmp=3; + } + break; + case UNI_PTEFFECTE: + DoEEffects(UniGetByte()); + break; + case UNI_PTEFFECTF: + dat=UniGetByte(); + if (pf->vbtick||pf->patdly2) break; + if (pf->extspd&&(dat>=0x20)) + pf->bpm=dat; + else + if (dat) { + pf->sngspd=(dat>32)?32:dat; + pf->vbtick=0; + } + break; + case UNI_S3MEFFECTA: + DoS3MSpeed(UniGetByte()); + break; + case UNI_S3MEFFECTD: + DoS3MVolSlide(UniGetByte()); + break; + case UNI_S3MEFFECTE: + dat=UniGetByte(); + if (a->period) + DoS3MSlideDn(dat); + break; + case UNI_S3MEFFECTF: + dat=UniGetByte(); + if (a->period) + DoS3MSlideUp(dat); + break; + case UNI_S3MEFFECTI: + DoS3MTremor(UniGetByte()); + a->ownvol=1; + break; + case UNI_S3MEFFECTQ: + dat=UniGetByte(); + if (a->period) + DoS3MRetrig(dat); + break; + case UNI_S3MEFFECTR: + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->trmdepth=dat&0xf; + if (dat&0xf0) a->trmspd=(dat&0xf0)>>2; + } + DoS3MTremolo(); + a->ownvol=1; + break; + case UNI_S3MEFFECTT: + DoS3MTempo(UniGetByte()); + break; + case UNI_S3MEFFECTU: + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->vibdepth=dat&0xf; + if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; + } else + if (a->period) { + DoS3MFineVibrato(); + a->ownper=1; + } + break; + case UNI_KEYOFF: + a->keyoff|=KEY_OFF; + if ((!(a->volflg&EF_ON))||(a->volflg&EF_LOOP)) + a->keyoff=KEY_KILL; + break; + case UNI_KEYFADE: + dat=UniGetByte(); + if ((pf->vbtick>=dat)||(pf->vbtick==pf->sngspd-1)) { + a->keyoff=KEY_KILL; + if (!(a->volflg&EF_ON)) + a->fadevol=0; + } + break; + case UNI_VOLEFFECTS: + DoVolEffects(UniGetByte()); + break; + case UNI_XMEFFECTA: + DoXMVolSlide(UniGetByte()); + break; + case UNI_XMEFFECTE1: /* XM fineslide up */ + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat) a->fportupspd=dat; + if (a->period) + a->tmpperiod-=(a->fportupspd<<2); + } + break; + case UNI_XMEFFECTE2: /* XM fineslide dn */ + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat) a->fportdnspd=dat; + if (a->period) + a->tmpperiod+=(a->fportdnspd<<2); + } + break; + case UNI_XMEFFECTEA: /* fine volume slide up */ + dat=UniGetByte(); + if (!pf->vbtick) + if (dat) a->fslideupspd=dat; + a->tmpvolume+=a->fslideupspd; + if (a->tmpvolume>64) a->tmpvolume=64; + break; + case UNI_XMEFFECTEB: /* fine volume slide dn */ + dat=UniGetByte(); + if (!pf->vbtick) + if (dat) a->fslidednspd=dat; + a->tmpvolume-=a->fslidednspd; + if (a->tmpvolume<0) a->tmpvolume=0; + break; + case UNI_XMEFFECTG: + pf->volume=UniGetByte()<<1; + if (pf->volume>128) pf->volume=128; + break; + case UNI_XMEFFECTH: + DoXMGlobalSlide(UniGetByte()); + break; + case UNI_XMEFFECTL: + dat=UniGetByte(); + if ((!pf->vbtick)&&(a->i)) { + UWORD points; + INSTRUMENT *i=a->i; + MP_VOICE *aout; + + if ((aout=a->slave)) { + points=i->volenv[i->volpts-1].pos; + aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos; + points=i->panenv[i->panpts-1].pos; + aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos; + } + } + break; + case UNI_XMEFFECTP: + dat=UniGetByte(); + if (pf->panflag) + DoXMPanSlide(dat); + break; + case UNI_XMEFFECTX1: + dat=UniGetByte(); + if (dat) a->ffportupspd=dat; + else dat=a->ffportupspd; + if (a->period) { + DoXMExtraFineSlideUp(dat); + a->ownper=1; + } + break; + case UNI_XMEFFECTX2: + dat=UniGetByte(); + if (dat) a->ffportdnspd=dat; + else dat=a->ffportdnspd; + if (a->period) { + DoXMExtraFineSlideDown(dat); + a->ownper=1; + } + break; + case UNI_ITEFFECTG: + dat=UniGetByte(); + if (dat) { + a->portspeed=dat; + } + if (a->period) { + if ((!pf->vbtick)&&(a->newsamp)){ + a->kick=KICK_NOTE; + a->start=-1; + } else + a->kick=(a->kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT; + DoITToneSlide(); + a->ownper=1; + } + break; + case UNI_ITEFFECTH: /* IT vibrato */ + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->vibdepth=dat&0xf; + if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; + } + if (a->period) { + DoITVibrato(); + a->ownper=1; + } + break; + case UNI_ITEFFECTI: /* IT tremor */ + DoITTremor(UniGetByte()); + a->ownvol=1; + break; + case UNI_ITEFFECTM: + a->chanvol=UniGetByte(); + if (a->chanvol>64) a->chanvol=64; + else if (a->chanvol<0) a->chanvol=0; + break; + case UNI_ITEFFECTN: /* slide / fineslide channel volume */ + DoITChanVolSlide(UniGetByte()); + break; + case UNI_ITEFFECTP: /* slide / fineslide channel panning */ + dat=UniGetByte(); + if (pf->panflag) + DoITPanSlide(dat); + break; + case UNI_ITEFFECTT: /* slide / fineslide tempo */ + DoITTempo(UniGetByte()); + break; + case UNI_ITEFFECTU: /* fine vibrato */ + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->vibdepth=dat&0xf; + if (dat&0xf0) a->vibspd=(dat&0xf0)>>2; + } + if (a->period) { + DoITFineVibrato(); + a->ownper=1; + } + break; + case UNI_ITEFFECTW: /* slide / fineslide global volume */ + DoITGlobalSlide(UniGetByte()); + break; + case UNI_ITEFFECTY: /* panbrello */ + dat=UniGetByte(); + if (!pf->vbtick) { + if (dat&0x0f) a->panbdepth=(dat&0xf); + if (dat&0xf0) a->panbspd=(dat&0xf0)>>4; + } + if (pf->panflag) DoITPanbrello(); + break; + case UNI_ITEFFECTS0: + DoSSEffects(UniGetByte()); + break; + case UNI_ITEFFECTZ: + /* FIXME not yet implemented */ + UniSkipOpcode(UNI_ITEFFECTZ); + break; + case UNI_ULTEFFECT9: + DoULTSampleOffset(); + break; + case UNI_MEDSPEED: + DoMEDSpeed(); + break; + case UNI_MEDEFFECTF1: + DoEEffects(0x90|(pf->sngspd/2)); + break; + case UNI_MEDEFFECTF2: + DoEEffects(0xd0|(pf->sngspd/2)); + break; + case UNI_MEDEFFECTF3: + DoEEffects(0x90|(pf->sngspd/3)); + break; + default: + a->sliding=oldsliding; + UniSkipOpcode(c); + break; + } + } } - static void DoNNAEffects(UBYTE dat) { - int t; - MP_VOICE *aout; - - dat &= 0xf; - aout = (a->slave==NULL) ? &aout_dummy : a->slave; - - switch(dat) - { case 0x0: /* Past note cut */ - for(t=0; tvoice[t].master == a) - pf->voice[t].fadevol = 0; - break; - - case 0x1: /* Past note off */ - for(t=0; tvoice[t].master == a) - { pf->voice[t].keyoff |= KEY_OFF; - if(!(pf->voice[t].venv.flg & EF_ON)) - pf->voice[t].keyoff = KEY_KILL; - } - break; - - case 0x2: /* Past note fade */ - for(t=0; tvoice[t].master == a) - pf->voice[t].keyoff |= KEY_FADE; - break; - - case 0x3: /* set NNA note cut */ - a->nna = (a->nna & ~0x3f) | NNA_CUT; - break; - - case 0x4: /* set NNA note continue */ - a->nna = (a->nna & ~0x3f) | NNA_CONTINUE; - break; - - case 0x5: /* set NNA note off */ - a->nna = (a->nna & ~0x3f) | NNA_OFF; - break; - - case 0x6: /* set NNA note fade */ - a->nna = (a->nna & ~0x3f) | NNA_FADE; - break; - - case 0x7: /* disable volume envelope */ - aout->volflg &= ~EF_ON; - break; - - case 0x8: /* enable volume envelope */ - aout->volflg |= EF_ON; - break; - - case 0x9: /* disable panning envelope */ - aout->panflg &= ~EF_ON; - break; - - case 0xa: /* enable panning envelope */ - aout->panflg |= EF_ON; - break; - - case 0xb: /* disable pitch envelope */ - aout->pitflg &= ~EF_ON; - break; - - case 0xc: /* enable pitch envelope */ - aout->pitflg |= EF_ON; - break; - } + int t; + MP_VOICE *aout; + + dat&=0xf; + aout=(a->slave)?a->slave:NULL; + + switch (dat) { + case 0x0: /* past note cut */ + for (t=0;tvoice[t].master==a) + pf->voice[t].fadevol=0; + break; + case 0x1: /* past note off */ + for (t=0;tvoice[t].master==a) { + pf->voice[t].keyoff|=KEY_OFF; + if ((!(pf->voice[t].venv.flg & EF_ON))|| + (pf->voice[t].venv.flg & EF_LOOP)) + pf->voice[t].keyoff=KEY_KILL; + } + break; + case 0x2: /* past note fade */ + for (t=0;tvoice[t].master==a) + pf->voice[t].keyoff|=KEY_FADE; + break; + case 0x3: /* set NNA note cut */ + a->nna=(a->nna&~NNA_MASK)|NNA_CUT; + break; + case 0x4: /* set NNA note continue */ + a->nna=(a->nna&~NNA_MASK)|NNA_CONTINUE; + break; + case 0x5: /* set NNA note off */ + a->nna=(a->nna&~NNA_MASK)|NNA_OFF; + break; + case 0x6: /* set NNA note fade */ + a->nna=(a->nna&~NNA_MASK)|NNA_FADE; + break; + case 0x7: /* disable volume envelope */ + if (aout) + aout->volflg&=~EF_ON; + break; + case 0x8: /* enable volume envelope */ + if (aout) + aout->volflg|=EF_ON; + break; + case 0x9: /* disable panning envelope */ + if (aout) + aout->panflg&=~EF_ON; + break; + case 0xa: /* enable panning envelope */ + if (aout) + aout->panflg|=EF_ON; + break; + case 0xb: /* disable pitch envelope */ + if (aout) + aout->pitflg&=~EF_ON; + break; + case 0xc: /* enable pitch envelope */ + if (aout) + aout->pitflg|=EF_ON; + break; + } +} + +void pt_UpdateVoices(int max_volume) +{ + SWORD envpan,envvol,envpit; + UWORD playperiod; + SLONG vibval,vibdpt; + ULONG tmpvol; + + MP_VOICE *aout; + INSTRUMENT *i; + SAMPLE *s; + + pf->totalchn=pf->realchn=0; + for (mp_channel=0;mp_channelvoice[mp_channel]; + i=aout->i; + s=aout->s; + + if ((!s)||(!s->length)) continue; + + if (aout->period<40) aout->period=40; + else if (aout->period>50000) aout->period=50000; + + if ((aout->kick==KICK_NOTE)||(aout->kick==KICK_KEYOFF)) { + Voice_Play_internal(mp_channel,s,(aout->start==-1)?((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->start); + aout->fadevol=32768; + aout->aswppos=0; + } + + if (i && ((aout->kick==KICK_NOTE)||(aout->kick==KICK_ENV))) { + StartEnvelope(&aout->venv,aout->volflg,i->volpts,i->volsusbeg, + i->volsusend,i->volbeg,i->volend,i->volenv,aout->keyoff); + StartEnvelope(&aout->penv,aout->panflg,i->panpts,i->pansusbeg, + i->pansusend,i->panbeg,i->panend,i->panenv,aout->keyoff); + StartEnvelope(&aout->cenv,aout->pitflg,i->pitpts,i->pitsusbeg, + i->pitsusend,i->pitbeg,i->pitend,i->pitenv,aout->keyoff); + if (aout->cenv.flg&EF_ON) + aout->masterperiod=GetPeriod((UWORD)aout->note<<1,aout->master->speed); + } + aout->kick=KICK_ABSENT; + + envvol=(!(aout->volflg & EF_ON))?256: + ProcessEnvelope(&aout->venv,256,aout->keyoff); + envpan=(!(aout->panflg & EF_ON))?PAN_CENTER: + ProcessEnvelope(&aout->penv,PAN_CENTER,aout->keyoff); + envpit=(!(aout->pitflg & EF_ON))?32: + ProcessEnvelope(&aout->cenv,32,aout->keyoff); + + tmpvol=aout->fadevol; /* max 32768 */ + tmpvol*=aout->chanvol; /* * max 64 */ + tmpvol*=aout->volume; /* * max 256 */ + tmpvol/=16384L; /* tmpvol is max 32768 */ + aout->totalvol=tmpvol>>2; /* totalvolume used to determine samplevolume */ + tmpvol*=envvol; /* * max 256 */ + tmpvol*=pf->volume; /* * max 128 */ + tmpvol/=4194304UL; + + /* fade out */ + if (pf->sngpos>=pf->numpos) tmpvol=0; + else + tmpvol=(tmpvol*max_volume)/128; + + if ((aout->masterchn!=-1)&& pf->control[aout->masterchn].muted) + Voice_SetVolume_internal(mp_channel,0); + else { + Voice_SetVolume_internal(mp_channel,tmpvol); + if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout)) + pf->realchn++; + pf->totalchn++; + } + + if (aout->panning==PAN_SURROUND) + Voice_SetPanning_internal(mp_channel,PAN_SURROUND); + else + if ((pf->panflag)&&(aout->penv.flg & EF_ON)) + Voice_SetPanning_internal(mp_channel,DoPan(envpan,aout->panning)); + else + Voice_SetPanning_internal(mp_channel,aout->panning); + + if (aout->period && s->vibdepth) + switch (s->vibtype) { + case 0: + vibval=avibtab[s->avibpos&127]; + if (s->avibpos & 0x80) vibval=-vibval; + break; + case 1: + vibval=64; + if (s->avibpos & 0x80) vibval=-vibval; + break; + case 2: + vibval=63-(((s->avibpos+128)&255)>>1); + break; + default: + vibval=(((s->avibpos+128)&255)>>1)-64; + break; + } + else + vibval=0; + + if (s->vibflags & AV_IT) { + if ((aout->aswppos>>8)vibdepth) { + aout->aswppos += s->vibsweep; + vibdpt=aout->aswppos; + } else + vibdpt=s->vibdepth<<8; + vibval=(vibval*vibdpt)>>16; + if (aout->mflag) { + if (!(pf->flags&UF_LINEAR)) vibval>>=1; + aout->period-=vibval; + } + } else { + /* do XM style auto-vibrato */ + if (!(aout->keyoff & KEY_OFF)) { + if (aout->aswpposvibsweep) { + vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep; + aout->aswppos++; + } else + vibdpt=s->vibdepth; + } else { + /* keyoff -> depth becomes 0 if final depth wasn't reached or + stays at final level if depth WAS reached */ + if (aout->aswppos>=s->vibsweep) + vibdpt=s->vibdepth; + else + vibdpt=0; + } + vibval=(vibval*vibdpt)>>8; + aout->period-=vibval; + } + + /* update vibrato position */ + s->avibpos=(s->avibpos+s->vibrate)&0xff; + + /* process pitch envelope */ + playperiod=aout->period; + + if ((aout->pitflg&EF_ON)&&(envpit!=32)) { + long p1; + + envpit-=32; + if ((aout->note<<1)+envpit<=0) envpit=-(aout->note<<1); + + p1=GetPeriod(((UWORD)aout->note<<1)+envpit,aout->master->speed)-aout->masterperiod; + if (p1>0) { + if ((UWORD)(playperiod+p1)<=playperiod) { + p1=0; + aout->keyoff|=KEY_OFF; + } + } else if (p1<0) { + if ((UWORD)(playperiod+p1)>=playperiod) { + p1=0; + aout->keyoff|=KEY_OFF; + } + } + playperiod+=p1; + } + + if (!aout->fadevol) { /* check for a dead note (fadevol=0) */ + Voice_Stop_internal(mp_channel); + pf->totalchn--; + if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout)) + pf->realchn--; + } else { + Voice_SetFrequency_internal(mp_channel, + getfrequency(pf->flags,playperiod)); + + /* if keyfade, start substracting fadeoutspeed from fadevol: */ + if ((i)&&(aout->keyoff&KEY_FADE)) { + if (aout->fadevol>=i->volfade) + aout->fadevol-=i->volfade; + else + aout->fadevol=0; + } + } + + md_bpm=pf->bpm+pf->relspd; + if (md_bpm<32) md_bpm=32; + else if (md_bpm>255) md_bpm=255; + } +} + +/* Handles new notes or instruments */ +void pt_Notes(void) +{ + UBYTE c,inst; + int tr,funky; /* funky is set to indicate note or instrument change */ + + for (mp_channel=0;mp_channelnumchn;mp_channel++) { + a=&pf->control[mp_channel]; + + if (pf->sngpos>=pf->numpos) { + tr=pf->numtrk; + pf->numrow=0; + } else { + tr=pf->patterns[(pf->positions[pf->sngpos]*pf->numchn)+mp_channel]; + pf->numrow=pf->pattrows[pf->positions[pf->sngpos]]; + } + + a->row=(trnumtrk)?UniFindRow(pf->tracks[tr],pf->patpos):NULL; + a->newsamp=0; + if (!pf->vbtick) a->notedelay=0; + + if (!a->row) continue; + UniSetRow(a->row); + funky=0; + + while((c=UniGetByte())) + switch (c) { + case UNI_NOTE: + funky|=1; + a->oldnote=a->anote,a->anote=UniGetByte(); + a->kick =KICK_NOTE; + a->start=-1; + a->sliding=0; + + /* retrig tremolo and vibrato waves ? */ + if (!(a->wavecontrol & 0x80)) a->trmpos=0; + if (!(a->wavecontrol & 0x08)) a->vibpos=0; + if (!a->panbwave) a->panbpos=0; + break; + case UNI_INSTRUMENT: + inst=UniGetByte(); + if (inst>=pf->numins) break; /* safety valve */ + funky|=2; + a->i=(pf->flags & UF_INST)?&pf->instruments[inst]:NULL; + a->retrig=0; + a->s3mtremor=0; + a->sample=inst; + break; + default: + UniSkipOpcode(c); + break; + } + + if (funky) { + INSTRUMENT *i; + SAMPLE *s; + + i=a->i; + if (i) { + if (i->samplenumber[a->anote] >= pf->numsmp) continue; + s=&pf->samples[i->samplenumber[a->anote]]; + a->note=i->samplenote[a->anote]; + } else { + a->note=a->anote; + s=&pf->samples[a->sample]; + } + + if (a->s!=s) { + a->s=s; + a->newsamp=a->period; + } + + /* channel or instrument determined panning ? */ + a->panning=pf->panning[mp_channel]; + if (s->flags & SF_OWNPAN) + a->panning=s->panning; + else if ((i)&&(i->flags & IF_OWNPAN)) + a->panning=i->panning; + + a->handle=s->handle; + a->speed=s->speed; + + if (i) { + if ((pf->panflag)&&(i->flags & IF_PITCHPAN) + &&(a->panning!=PAN_SURROUND)){ + a->panning+=((a->anote-i->pitpancenter)*i->pitpansep)/8; + if (a->panningpanning=PAN_LEFT; + else if (a->panning>PAN_RIGHT) a->panning=PAN_RIGHT; + } + a->pitflg=i->pitflg; + a->volflg=i->volflg; + a->panflg=i->panflg; + a->nna=i->nnatype; + a->dca=i->dca; + a->dct=i->dct; + } else { + a->pitflg=0; + a->volflg=0; + a->panflg=0; + a->nna=0; + a->dca=0; + a->dct=0; + } + + if (funky&2) /* instrument change */ { + /* IT random volume variations: 0:8 bit fixed, and one bit for + sign. */ + a->volume=a->tmpvolume=s->volume; + if ((s)&&(i)) { + if (i->rvolvar) { + a->volume=a->tmpvolume=s->volume+ + ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512) + ))/25600); + if (a->volume<0) a->volume=a->tmpvolume=0; + else if (a->volume>64) a->volume=a->tmpvolume=64; + } + if ((pf->panflag)&&(a->panning!=PAN_SURROUND)) { + a->panning+=((a->panning*((SLONG)i->rpanvar* + (SLONG)getrandom(512)))/25600); + if (a->panningpanning=PAN_LEFT; + else if (a->panning>PAN_RIGHT) a->panning=PAN_RIGHT; + } + } + } + + a->wantedperiod=a->tmpperiod=GetPeriod((UWORD)a->note<<1,a->speed); + a->keyoff=KEY_KICK; + } + } +} + +/* Handles effects */ +void pt_EffectsPass1(void) +{ + MP_VOICE *aout; + + for (mp_channel=0;mp_channelnumchn;mp_channel++) { + a=&pf->control[mp_channel]; + + if ((aout=a->slave)) { + a->fadevol=aout->fadevol; + a->period=aout->period; + if (a->kick==KICK_KEYOFF) a->keyoff=aout->keyoff; + } + + if (!a->row) continue; + UniSetRow(a->row); + + a->ownper=a->ownvol=0; + explicitslides=0; + pt_playeffects(); + + /* continue volume slide if necessary for XM and IT */ + if (pf->flags&UF_BGSLIDES) { + if (!explicitslides) + switch (a->sliding) { + case 1: + DoS3MVolSlide(0); + break; + case 2: + DoXMVolSlide(0); + break; + } + else if (a->tmpvolume) a->sliding=explicitslides; + } + + if (!a->ownper) a->period=a->tmpperiod; + if (!a->ownvol) a->volume=a->tmpvolume; + + if (a->s) { + if (a->i) + a->outvolume=(a->volume*a->s->globvol*a->i->globvol)>>10; + else + a->outvolume=(a->volume*a->s->globvol)>>4; + if (a->outvolume>256)a->volume=256; + else if (a->outvolume<0) a->outvolume=0; + } + } +} + +/* NNA management */ +void pt_NNA(void) +{ + for (mp_channel=0;mp_channelnumchn;mp_channel++) { + a=&pf->control[mp_channel]; + + if (a->kick==KICK_NOTE) { + BOOL k=0; + + if (a->slave) { + MP_VOICE *aout; + + aout=a->slave; + if (aout->nna & NNA_MASK) { + /* Make sure the old MP_VOICE channel knows it has no + master now ! */ + a->slave=NULL; + /* assume the channel is taken by NNA */ + aout->mflag=0; + + switch (aout->nna) { + case NNA_CONTINUE: /* continue note, do nothing */ + break; + case NNA_OFF: /* note off */ + aout->keyoff|=KEY_OFF; + if ((!(aout->volflg & EF_ON))||(aout->volflg & EF_LOOP)) + aout->keyoff=KEY_KILL; + break; + case NNA_FADE: + aout->keyoff |= KEY_FADE; + break; + } + } + } + + if (a->dct!=DCT_OFF) { + int t; + + for (t=0;tvoice[t].masterchn==mp_channel)&& + (a->sample==pf->voice[t].sample)) { + k=0; + switch (a->dct) { + case DCT_NOTE: + if (a->note==pf->voice[t].note) + k=1; + break; + case DCT_SAMPLE: + if (a->handle==pf->voice[t].handle) + k=1; + break; + case DCT_INST: + k=1; + break; + } + if (k) + switch (a->dca) { + case DCA_CUT: + pf->voice[t].fadevol=0; + break; + case DCA_OFF: + pf->voice[t].keyoff|=KEY_OFF; + if ((!(pf->voice[t].volflg&EF_ON))|| + (pf->voice[t].volflg&EF_LOOP)) + pf->voice[t].keyoff=KEY_KILL; + break; + case DCA_FADE: + pf->voice[t].keyoff|=KEY_FADE; + break; + } + } + } + } /* if (a->kick==KICK_NOTE) */ + } +} + +/* Setup module and NNA voices */ +void pt_SetupVoices(void) +{ + MP_VOICE *aout; + + for (mp_channel=0;mp_channelnumchn;mp_channel++) { + a=&pf->control[mp_channel]; + + if (a->notedelay) continue; + if (a->kick==KICK_NOTE) { + /* if no channel was cut above, find an empty or quiet channel + here */ + if (pf->flags&UF_NNA) { + if (!a->slave) { + int newchn; + + if ((newchn=MP_FindEmptyChannel())!=-1) + a->slave=&pf->voice[a->slavechn=newchn]; + } + } else + a->slave=&pf->voice[a->slavechn=mp_channel]; + + /* assign parts of MP_VOICE only done for a KICK ! */ + if ((aout=a->slave)) { + if (aout->mflag && aout->master) aout->master->slave=NULL; + a->slave=aout; + aout->master=a; + aout->masterchn=mp_channel; + aout->mflag=1; + } + } else + aout=a->slave; + + if (aout) { + aout->kick=a->kick; + aout->i=a->i; + aout->s=a->s; + aout->sample=a->sample; + aout->handle=a->handle; + aout->period=a->period; + aout->panning=a->panning; + aout->chanvol=a->chanvol; + aout->fadevol=a->fadevol; + aout->start=a->start; + aout->volflg=a->volflg; + aout->panflg=a->panflg; + aout->pitflg=a->pitflg; + aout->volume=a->outvolume; + aout->keyoff=a->keyoff; + aout->note=a->note; + aout->nna=a->nna; + } + a->kick=KICK_ABSENT; + } +} + +/* second effect pass */ +void pt_EffectsPass2(void) +{ + UBYTE c; + + for (mp_channel=0;mp_channelnumchn;mp_channel++) { + a=&pf->control[mp_channel]; + + if (!a->row) continue; + UniSetRow(a->row); + + while((c=UniGetByte())) + if (c==UNI_ITEFFECTS0) { + c=UniGetByte(); + if ((c>>4)==SS_S7EFFECTS) + DoNNAEffects(c&0xf); + } else + UniSkipOpcode(c); + } } - void Player_HandleTick(void) { - MP_VOICE *aout; /* current audout (slave of audtmp) it's working on */ - int t, tr, t2, k; - ULONG tmpvol, period; - UBYTE c; - BOOL funky; - SAMPLE *s; - INSTRUMENT *i; - - if(isfirst) - { /* don't handle the very first ticks, this allows the */ - /* other hardware to settle down so we don't loose any */ - /* starting notes */ - isfirst--; - return; - } - - if(pf==NULL || pf->forbid) return; - - if(++pf->vbtick >= pf->sngspd) - { pf->patpos++; - pf->vbtick = 0; - - /* process pattern-delay. pf->patdly2 is the counter and pf->patdly */ - /* is the command memory. */ - - if(pf->patdly) - { pf->patdly2 = pf->patdly; - pf->patdly = 0; - } - - if(pf->patdly2) - { /* patterndelay active */ - if(--pf->patdly2) pf->patpos--; /* so turn back pf->patpos by 1 */ - } - - /* Do we have to get a new patternpointer ? */ - /* (when pf->patpos reaches 64 or when */ - /* a patternbreak is active) */ - - if(pf->patpos == pf->numrow) pf->posjmp = 3; - - if(pf->posjmp) - { pf->patpos = pf->patbrk; - pf->sngpos+=(pf->posjmp-2); - pf->patbrk = pf->posjmp = 0; - if(pf->sngpos>=pf->numpos) - { if(!pf->loop) return; - if((pf->sngpos = pf->reppos) == 0) - { pf->volume = pf->initvolume; - pf->sngspd = pf->initspeed; - pf->bpm = pf->inittempo; - } - } - if(pf->sngpos<0) pf->sngpos = pf->numpos-1; - } - - if(!pf->patdly2) - { for(t=0; tnumchn; t++) - { UBYTE inst; - - tr = pf->patterns[(pf->positions[pf->sngpos]*pf->numchn)+t]; - pf->numrow = pf->pattrows[pf->positions[pf->sngpos]]; - - mp_channel = t; - a = &pf->control[t]; - a->row = (tr < pf->numtrk) ? UniFindRow(pf->tracks[tr],pf->patpos) : NULL; - a->newsamp = 0; - - if(a->row==NULL) continue; - UniSetRow(a->row); - funky = 0; /* Funky is set to indicate note or inst change */ - - while(c = UniGetByte()) - { switch(c) - { case UNI_NOTE: - funky |= 1; - a->anote = UniGetByte(); - a->kick = 1; - a->start = -1; - - /* retrig tremolo and vibrato waves ? */ - - if(!(a->wavecontrol & 0x80)) a->trmpos = 0; - if(!(a->wavecontrol & 0x08)) a->vibpos = 0; - if(!a->panbwave) a->panbpos = 0; - break; - - case UNI_INSTRUMENT: - funky |= 2; - inst = UniGetByte(); - if(inst >= pf->numins) break; /* <- safety valve */ - - a->i = (pf->flags & UF_INST) ? &pf->instruments[inst] : NULL; - a->retrig = 0; - a->s3mtremor = 0; - a->sample = inst; - break; - - default: - UniSkipOpcode(c); - break; - } - } - - if(funky) - { i = a->i; - if(i != NULL) - { if(i->samplenumber[a->anote] >= pf->numsmp) continue; - s = &pf->samples[i->samplenumber[a->anote]]; - a->note = i->samplenote[a->anote]; - } else - { a->note = a->anote; - s = &pf->samples[a->sample]; - } - - if(a->s != s) - { a->s = s; - a->newsamp = a->period; - } - - /* channel or instrument determined panning ? */ - - a->panning = pf->panning[t]; - if(s->flags & SF_OWNPAN) - a->panning = s->panning; - else if((i != NULL) && (i->flags & IF_OWNPAN)) - a->panning = i->panning; - - a->handle = s->handle; - a->speed = s->speed; - - if(i != NULL) - { if(i->flags & IF_PITCHPAN) - a->panning += ((a->anote-i->pitpancenter) * i->pitpansep) / 8; - a->pitflg = i->pitflg; - a->volflg = i->volflg; - a->panflg = i->panflg; - a->nna = i->nnatype; - a->dca = i->dca; - a->dct = i->dct; - } else - { a->pitflg = 0; - a->volflg = 0; - a->panflg = 0; - a->nna = 0; - a->dca = 0; - a->dct = 0; - } - - if(funky & 2) - { /* IT's random volume variations: 0:8 bit fixed, and one bit for sign. */ - a->volume = s->volume; - a->tmpvolume = s->volume; - if((s != NULL) && (i != NULL)) - { a->volume = a->tmpvolume = s->volume + ((s->volume * ((SLONG)i->rvolvar * (SLONG)((rand() & 511)-255))) / 25600); - if(a->panning != PAN_SURROUND) a->panning += ((a->panning * ((SLONG)i->rpanvar * (SLONG)((rand() & 511)-255))) / 25600); - } - } - - period = GetPeriod(a->note, a->speed); - a->wantedperiod = period; - a->tmpperiod = period; - a->keyoff = KEY_KICK; - } - } - } - } - - /* Update effects */ - - for(t=0; tnumchn; t++) - { mp_channel = t; - a = &pf->control[t]; - - if((aout = a->slave) != NULL) - { a->fadevol = aout->fadevol; - a->period = aout->period; - if(a->kick != 1) a->keyoff = aout->keyoff; - } - - if(a->row == NULL) continue; - UniSetRow(a->row); - - a->ownper = a->ownvol = 0; - pt_playeffects(); - if(!a->ownper) a->period = a->tmpperiod; - if(!a->ownvol) a->volume = a->tmpvolume; - - if(a->s != NULL) - { if(a->i != NULL) - a->outvolume = (a->volume * a->s->globvol * a->i->globvol) / 1024; /* max val: 256 */ - else - a->outvolume = (a->volume * a->s->globvol) / 16; /* max val: 256 */ - if(a->outvolume > 256) a->volume = 256; - } - } - - - a = pf->control; - if(pf->flags & UF_NNA) - { for(t=0; tnumchn; t++, a++) - { if(a->kick == 1) - { if(a->slave != NULL) - { aout = a->slave; - if(aout->nna & 0x3f) - { /* oh boy, we have to do an NNA */ - /* Make sure the old MP_VOICE channel knows it has no master now! */ - - a->slave = NULL; /* assume the channel is taken by NNA */ - aout->mflag = 0; - - switch(aout->nna) - { case NNA_CONTINUE: - break; /* continue note, do nothing */ - - case NNA_OFF: /* note off */ - aout->keyoff |= KEY_OFF; - if(!(aout->volflg & EF_ON) || (aout->volflg & EF_LOOP)) - aout->keyoff = KEY_KILL; - break; - - case NNA_FADE: - aout->keyoff |= KEY_FADE; - break; - } - } - } - - k = 0; - if(a->dct != DCT_OFF) - { for(t2=0; t2voice[t2].masterchn == t) && (a->sample == pf->voice[t2].sample)) - { switch(a->dct) - { case DCT_NOTE: - if(a->note == pf->voice[t2].note) - k = 1; - break; - - case DCT_SAMPLE: - if(a->handle == pf->voice[t2].handle) - k = 1; - break; - - case DCT_INST: - k = 1; - break; - } - - if(k==1) - { k = 0; - switch(a->dca) - { case DCA_CUT : - pf->voice[t2].fadevol = 0; - a->slave = &pf->voice[a->slavechn=t2]; - break; - - case DCA_OFF : - /*a->slave = &pf->voice[newchn]; */ - pf->voice[t2].keyoff |= KEY_OFF; - if(!(pf->voice[t2].volflg & EF_ON) || (pf->voice[t2].volflg & EF_LOOP)) - pf->voice[t2].keyoff = KEY_KILL; - break; - - case DCA_FADE: - /*a->slave = &pf->voice[newchn]; */ - pf->voice[t2].keyoff |= KEY_FADE; - break; - } - } - } - } - } /* DCT checking */ - } /* if a->kick */ - } /* for loop */ - } - - a = pf->control; - for(t=0; tnumchn; t++, a++) - { int newchn; - - if(a->notedelay) continue; - - if(a->kick == 1) - { /* If no channel was cut above, find an empty or quiet channel here */ - if(pf->flags & UF_NNA) - { if(a->slave==NULL) - { if((newchn = MP_FindEmptyChannel(t)) != -1) - a->slave = &pf->voice[a->slavechn=newchn]; - } - } else - a->slave = &pf->voice[a->slavechn=t]; - - /* Assign parts of MP_VOICE only done for a KICK! */ - - if((aout = a->slave) != NULL) - { if(aout->mflag && (aout->master!=NULL)) aout->master->slave = NULL; - a->slave = aout; - aout->master = a; - aout->masterchn = t; - aout->mflag = 1; - } - } else - { aout = a->slave; - } - - if(aout != NULL) - { aout->kick = a->kick; - aout->i = a->i; - aout->s = a->s; - aout->sample = a->sample; - aout->handle = a->handle; - aout->period = a->period; - aout->panning = a->panning; - aout->chanvol = a->chanvol; - aout->fadevol = a->fadevol; - aout->start = a->start; - aout->volflg = a->volflg; - aout->panflg = a->panflg; - aout->pitflg = a->pitflg; - aout->volume = a->outvolume; - aout->keyoff = a->keyoff; - aout->note = a->note; - aout->nna = a->nna; - } - a->kick = 0; - - } - - /* Now set up the actual hardware channel playback information */ - - for(t=0; tvoice[mp_channel = t]; - i = aout->i; - s = aout->s; - - if(s==NULL) continue; - - if(aout->period < 40) aout->period = 40; - if(aout->period > 50000) aout->period = 50000; - - if(aout->kick) - { Voice_Play(t,s,(aout->start == -1) ? ((s->flags & SF_UST_LOOP) ? s->loopstart : 0) : aout->start); - /*aout->keyoff = KEY_KICK; */ - aout->fadevol = 32768; - aout->aswppos = 0; - - if((i != NULL) && (aout->kick != 2)) - { StartEnvelope(&aout->venv, aout->volflg, i->volpts, i->volsusbeg, i->volsusend, i->volbeg, i->volend, i->volenv, aout->keyoff); - StartEnvelope(&aout->penv, aout->panflg, i->panpts, i->pansusbeg, i->pansusend, i->panbeg, i->panend, i->panenv, aout->keyoff); - StartEnvelope(&aout->cenv, aout->pitflg, i->pitpts, i->pitsusbeg, i->pitsusend, i->pitbeg, i->pitend, i->pitenv, aout->keyoff); - } - aout->kick = 0; - } - - if(i != NULL) - { envvol = ProcessEnvelope(&aout->venv,256,aout->keyoff); - envpan = ProcessEnvelope(&aout->penv,128,aout->keyoff); - envpit = ProcessEnvelope(&aout->cenv,32,aout->keyoff); - } - - tmpvol = aout->fadevol; /* max 32768 */ - tmpvol *= aout->chanvol; /* * max 64 */ - tmpvol *= aout->volume; /* * max 256 */ - tmpvol /= 16384L; /* tmpvol is max 32768 */ - aout->totalvol = tmpvol>>2; /* totalvolume used to determine samplevolume */ - tmpvol *= envvol; /* * max 256 */ - tmpvol *= pf->volume; /* * max 128 */ - tmpvol /= 4194304UL; - - if((aout->masterchn != -1) && pf->control[aout->masterchn].muted) /* Channel Muting Line */ - Voice_SetVolume(t,0); - else - Voice_SetVolume(t,tmpvol); - - - if(aout->panning == PAN_SURROUND) - Voice_SetPanning(t, PAN_SURROUND); - else - { if(aout->penv.flg & EF_ON) - Voice_SetPanning(t,DoPan(envpan,aout->panning)); - else - Voice_SetPanning(t,aout->panning); - } - - if(aout->period && s->vibdepth) - { switch(s->vibtype) - { case 0: - vibval = avibtab[s->avibpos & 127]; - if(s->avibpos & 0x80) vibval=-vibval; - break; - - case 1: - vibval = 64; - if(s->avibpos & 0x80) vibval=-vibval; - break; - - case 2: - vibval = 63-(((s->avibpos + 128) & 255) >> 1); - break; - - case 3: - vibval = (((s->avibpos + 128) & 255) >> 1) - 64; - break; - } - } - - if(s->vibflags & AV_IT) - { if((aout->aswppos >> 8) < s->vibdepth) - { aout->aswppos += s->vibsweep; - vibdpt = aout->aswppos; - } else - vibdpt = s->vibdepth << 8; - vibval = (vibval*vibdpt) >> 16; - if(aout->mflag) - { if(!(pf->flags & UF_LINEAR)) vibval>>=1; - aout->period -= vibval; - } - } else /* do XM style auto-vibrato */ - { if(!(aout->keyoff & KEY_OFF)) - { if(aout->aswppos < s->vibsweep) - { vibdpt = (aout->aswppos*s->vibdepth) / s->vibsweep; - aout->aswppos++; - } else - vibdpt = s->vibdepth; - } else - { /* key-off -> depth becomes 0 if final depth wasn't reached */ - /* or stays at final level if depth WAS reached */ - if(aout->aswppos>=s->vibsweep) - vibdpt = s->vibdepth; - else - vibdpt = 0; - } - vibval = (vibval*vibdpt)>>8; - aout->period -= vibval; - } - - /* update vibrato position */ - s->avibpos = (s->avibpos+s->vibrate) & 0xff; - - if(aout->cenv.flg & EF_ON) - { envpit = envpit-32; - aout->period -= envpit; - } - - Voice_SetFrequency(t,getfrequency(pf->flags,aout->period)); - - if(aout->fadevol == 0) /* check for a dead note (fadevol = 0) */ - Voice_Stop(t); - else - { /* if keyfade, start substracting */ - /* fadeoutspeed from fadevol: */ + int max_volume; + +#if 0 + /* don't handle the very first ticks, this allows the other hardware to + settle down so we don't loose any starting notes */ + if (isfirst) { + isfirst--; + return; + } +#endif + + if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return; + + /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */ + pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */ + pf->sngtime+=pf->sngremainder/pf->bpm; + pf->sngremainder%=pf->bpm; + + if (++pf->vbtick>=pf->sngspd) { + if (pf->pat_repcrazy) + pf->pat_repcrazy=0; /* play 2 times row 0 */ + else + pf->patpos++; + pf->vbtick=0; + + /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is + the command memory. */ + if (pf->patdly) + pf->patdly2=pf->patdly,pf->patdly=0; + if (pf->patdly2) { + /* patterndelay active */ + if (--pf->patdly2) + /* so turn back pf->patpos by 1 */ + if (pf->patpos) pf->patpos--; + } + + /* do we have to get a new patternpointer ? (when pf->patpos reaches the + pattern size, or when a patternbreak is active) */ + if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp)) + pf->posjmp=3; + + if (pf->posjmp) { + pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0; + pf->pat_repcrazy=0; + pf->sngpos+=(pf->posjmp-2); + for (mp_channel=0;mp_channelnumchn;mp_channel++) + pf->control[mp_channel].pat_reppos=-1; + + pf->patbrk=pf->posjmp=0; + /* handle the "---" (end of song) pattern since it can occur + *inside* the module in .IT and .S3M */ + if ((pf->sngpos>=pf->numpos)||(pf->positions[pf->sngpos]==255)) { + if (!pf->wrap) return; + if (!(pf->sngpos=pf->reppos)) { + pf->volume=pf->initvolume>128?128:pf->initvolume; + pf->sngspd=pf->initspeed?(pf->initspeed<32?pf->initspeed:32):6; + pf->bpm=pf->inittempo<32?32:pf->inittempo; + } + } + if (pf->sngpos<0) pf->sngpos=pf->numpos-1; + } + + if (!pf->patdly2) + pt_Notes(); + } + + if (((pf->sngpos==pf->numpos-1)||(pf->positions[pf->sngpos+1]==255))&& + (pf->fadeout)) + max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0; + else + max_volume=128; - if((i != NULL) && (aout->keyoff & KEY_FADE)) - { if(aout->fadevol >= i->volfade) - aout->fadevol -= i->volfade; - else - aout->fadevol = 0; - } - } + pt_EffectsPass1(); + if (pf->flags&UF_NNA) + pt_NNA(); + pt_SetupVoices(); + pt_EffectsPass2(); - MD_SetBPM(pf->bpm); - } + /* now set up the actual hardware channel playback information */ + pt_UpdateVoices(max_volume); } - -BOOL Player_Init(UNIMOD *mf) +static void Player_Init_internal(MODULE* mf) { - int t; + int t; + + for (t=0;tnumchn;t++) { + mf->control[t].chanvol=mf->chanvol[t]; + mf->control[t].panning=mf->panning[t]; + } - mf->extspd = 1; - mf->panflag = 1; - mf->loop = 0; + mf->sngtime=0; + mf->sngremainder=0; - mf->pat_reppos = 0; - mf->pat_repcnt = 0; - mf->sngpos = 0; - mf->sngspd = mf->initspeed; - mf->volume = mf->initvolume; + mf->pat_repcrazy=0; + mf->sngpos=0; + mf->sngspd=mf->initspeed?(mf->initspeed<32?mf->initspeed:32):6; + mf->volume=mf->initvolume>128?128:mf->initvolume; - mf->vbtick = mf->sngspd; - mf->patdly = 0; - mf->patdly2 = 0; - mf->bpm = mf->inittempo; + mf->vbtick=mf->sngspd; + mf->patdly=0; + mf->patdly2=0; + mf->bpm=mf->inittempo<32?32:mf->inittempo; + mf->realchn=0; - mf->patpos = 0; - mf->posjmp = 2; /* <- make sure the player fetches the first note */ - mf->patbrk = 0; + mf->patpos=0; + mf->posjmp=2; /* make sure the player fetches the first note */ + mf->numrow=-1; + mf->patbrk=0; +} - /* Make sure the player doesn't start with garbage: */ +BOOL Player_Init(MODULE* mf) +{ + mf->extspd=1; + mf->panflag=1; + mf->wrap=0; + mf->loop=1; + mf->fadeout=0; - if((mf->control=(MP_CONTROL *)_mm_calloc(mf->numchn,sizeof(MP_CONTROL)))==NULL) return 1; - if((mf->voice=(MP_VOICE *)_mm_calloc(md_sngchn,sizeof(MP_VOICE)))==NULL) return 1; + mf->relspd=0; - for(t=0; tnumchn; t++) - { mf->control[t].chanvol = mf->chanvol[t]; - mf->control[t].panning = mf->panning[t]; - } + /* make sure the player doesn't start with garbage */ + if (!(mf->control=(MP_CONTROL*)_mm_calloc(mf->numchn,sizeof(MP_CONTROL)))) + return 1; + if (!(mf->voice=(MP_VOICE*)_mm_calloc(md_sngchn,sizeof(MP_VOICE)))) + return 1; - return 0; + Player_Init_internal(mf); + return 0; } - -void Player_Exit(UNIMOD *mf) +void Player_Exit_internal(MODULE* mf) { - if(mf==NULL) return; - if(mf==pf) - { Player_Stop(); - pf = NULL; - } - if(mf->control!=NULL) free(mf->control); - if(mf->voice!=NULL) free(mf->voice); - mf->control = NULL; - mf->voice = NULL; - + if (!mf) return; + if (mf==pf) { + Player_Stop_internal(); + pf=NULL; + } + if (mf->control) free(mf->control); + if (mf->voice) free(mf->voice); + mf->control=NULL; + mf->voice=NULL; } - -void Player_SetVolume(int volume) +void Player_Exit(MODULE* mf) { - if(pf==NULL) return; - - if(volume > 128) volume = 128; - if(volume < 0) volume = 0; - - pf->volume = volume; + MUTEX_LOCK(vars); + Player_Exit_internal(mf); + MUTEX_UNLOCK(vars); } - -UNIMOD *Player_GetUnimod(void) +void Player_SetVolume(SWORD volume) { - return pf; + MUTEX_LOCK(vars); + if (pf) + pf->volume=(volume<0)?0:(volume>128)?128:volume; + MUTEX_UNLOCK(vars); } - -void Player_Start(UNIMOD *mf) +MODULE* Player_GetModule(void) { - int t; + MODULE* result; + + MUTEX_LOCK(vars); + result=pf; + MUTEX_UNLOCK(vars); - if(!MikMod_Active()) - { isfirst = 2; - MikMod_EnableOutput(); - } + return result; +} - if(mf==NULL) return; +void Player_Start(MODULE *mf) +{ + int t; - mf->forbid = 0; - if(pf != mf) - { /* new song is being started, so completely stop out the old one. */ - if(pf!=NULL) pf->forbid = 1; - for(t=0; tforbid=0; -void Player_Stop(void) -{ - if(md_sfxchn==0) MikMod_DisableOutput(); - if(pf != NULL) pf->forbid = 1; - pf = NULL; + MUTEX_LOCK(vars); + if (pf!=mf) { + /* new song is being started, so completely stop out the old one. */ + if (pf) pf->forbid=1; + for (t=0;tsngpos>=mf->numpos)); + if (!md_sfxchn) MikMod_DisableOutput_internal(); + if (pf) pf->forbid=1; + pf=NULL; } - -BOOL Player_Active(void) +void Player_Stop(void) { - if(pf==NULL) return 0; - return(!(pf->sngpos>=pf->numpos)); + MUTEX_LOCK(vars); + Player_Stop_internal(); + MUTEX_UNLOCK(vars); } - -void MP_NextPosition(UNIMOD *mf) +BOOL Player_Active(void) { - int t; - - if(mf==NULL) return; - mf->forbid = 1; - mf->posjmp = 3; - mf->patbrk = 0; - mf->vbtick = mf->sngspd; + BOOL result=0; - for(t=0; tvoice[t].i = NULL; - mf->voice[t].s = NULL; - } + MUTEX_LOCK(vars); + if (pf) + result=(!(pf->sngpos>=pf->numpos)); + MUTEX_UNLOCK(vars); - for(t=0; tnumchn; t++) - { mf->control[t].i = NULL; - mf->control[t].s = NULL; - } - mf->forbid = 0; + return result; } - void Player_NextPosition(void) { - MP_NextPosition(pf); + MUTEX_LOCK(vars); + if (pf) { + int t; + + pf->forbid=1; + pf->posjmp=3; + pf->patbrk=0; + pf->vbtick=pf->sngspd; + + for (t=0;tvoice[t].i=NULL; + pf->voice[t].s=NULL; + } + for (t=0;tnumchn;t++) { + pf->control[t].i=NULL; + pf->control[t].s=NULL; + } + pf->forbid=0; + } + MUTEX_UNLOCK(vars); } - -void MP_PrevPosition(UNIMOD *mf) +void Player_PrevPosition(void) { - int t; - - if(mf==NULL) return; - mf->forbid = 1; - mf->posjmp = 1; - mf->patbrk = 0; - mf->vbtick = mf->sngspd; - - for(t=0; tvoice[t].i = NULL; - mf->voice[t].s = NULL; - } - - for(t=0; tnumchn; t++) - { mf->control[t].i = NULL; - mf->control[t].s = NULL; - } - - mf->forbid = 0; + MUTEX_LOCK(vars); + if (pf) { + int t; + + pf->forbid=1; + pf->posjmp=1; + pf->patbrk=0; + pf->vbtick=pf->sngspd; + + for (t=0;tvoice[t].i=NULL; + pf->voice[t].s=NULL; + } + for (t=0;tnumchn;t++) { + pf->control[t].i=NULL; + pf->control[t].s=NULL; + } + pf->forbid=0; + } + MUTEX_UNLOCK(vars); } - -void Player_PrevPosition(void) +void Player_SetPosition(UWORD pos) { - MP_PrevPosition(pf); + MUTEX_LOCK(vars); + if (pf) { + int t; + + pf->forbid=1; + if (pos>=pf->numpos) pos=pf->numpos; + pf->posjmp=2; + pf->patbrk=0; + pf->sngpos=pos; + pf->vbtick=pf->sngspd; + + for (t=0;tvoice[t].i=NULL; + pf->voice[t].s=NULL; + } + for (t=0;tnumchn;t++) { + pf->control[t].i=NULL; + pf->control[t].s=NULL; + } + pf->forbid=0; + + if (!pos) + Player_Init_internal(pf); + } + MUTEX_UNLOCK(vars); +} + +static void Player_Unmute_internal(SLONG arg1,va_list ap) +{ + SLONG t,arg2,arg3=0; + + if (pf) { + switch (arg1) { + case MUTE_INCLUSIVE: + if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| + (arg2>arg3)||(arg3>=pf->numchn)) + return; + for (;arg2numchn && arg2<=arg3;arg2++) + pf->control[arg2].muted=0; + break; + case MUTE_EXCLUSIVE: + if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| + (arg2>arg3)||(arg3>=pf->numchn)) + return; + for (t=0;tnumchn;t++) { + if ((t>=arg2) && (t<=arg3)) continue; + pf->control[t].muted=0; + } + break; + default: + if (arg1numchn) pf->control[arg1].muted=0; + break; + } + } } - -void MP_SetPosition(UNIMOD *mf, UWORD pos) +void Player_Unmute(SLONG arg1, ...) { - int t; - - if(mf==NULL) return; - mf->forbid = 1; - if(pos>=mf->numpos) pos = mf->numpos; - mf->posjmp = 2; - mf->patbrk = 0; - mf->sngpos = pos; - mf->vbtick = mf->sngspd; - - for(t=0; tvoice[t].i = NULL; - mf->voice[t].s = NULL; - } - - for(t=0; tnumchn; t++) - { mf->control[t].i = NULL; - mf->control[t].s = NULL; - } - - mf->forbid = 0; -} + va_list args; + + va_start(args,arg1); + MUTEX_LOCK(vars); + Player_Unmute_internal(arg1,args); + MUTEX_UNLOCK(vars); + va_end(args); +} +static void Player_Mute_internal(SLONG arg1,va_list ap) +{ + SLONG t,arg2,arg3=0; -void Player_SetPosition(UWORD pos) -{ - MP_SetPosition(pf,pos); + if (pf) { + switch (arg1) { + case MUTE_INCLUSIVE: + if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| + (arg2>arg3)||(arg3>=pf->numchn)) + return; + for (;arg2numchn && arg2<=arg3;arg2++) + pf->control[arg2].muted=1; + break; + case MUTE_EXCLUSIVE: + if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| + (arg2>arg3)||(arg3>=pf->numchn)) + return; + for (t=0;tnumchn;t++) { + if ((t>=arg2) && (t<=arg3)) continue; + pf->control[t].muted=1; + } + break; + default: + if (arg1numchn) + pf->control[arg1].muted=1; + break; + } + } } - -void MP_Unmute(UNIMOD *mf, SLONG arg1, ...) +void Player_Mute(SLONG arg1,...) { - va_list ap; - SLONG t, arg2, arg3; - - va_start(ap,arg1); + va_list args; - if(mf != NULL) - { switch(arg1) - { case MUTE_INCLUSIVE: - if((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) - { va_end(ap); - return; - } - for(;arg2numchn && arg2<=arg3;arg2++) - mf->control[arg2].muted = 0; - break; - - case MUTE_EXCLUSIVE: - if((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) - { va_end(ap); - return; - } - for(t=0;tnumchn;t++) - { if ((t>=arg2) && (t<=arg3)) continue; - mf->control[t].muted = 0; - } - break; - - default: - if(arg1numchn) mf->control[arg1].muted = 0; - break; - } - } - va_end(ap); - - return; + va_start(args,arg1); + MUTEX_LOCK(vars); + Player_Mute_internal(arg1,args); + MUTEX_UNLOCK(vars); + va_end(args); } - -void Player_Unmute(SLONG arg1, ...) +static void Player_ToggleMute_internal(SLONG arg1,va_list ap) { - va_list argptr; - va_start(argptr,arg1); - MP_Unmute(pf,arg1, argptr); - va_end(argptr); -} - - -void MP_Mute(UNIMOD *mf, SLONG arg1, ...) -{ - va_list ap; - SLONG t, arg2, arg3; - - va_start(ap,arg1); - - if(mf != NULL) - { switch (arg1) - { case MUTE_INCLUSIVE: - if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) - { va_end(ap); - return; - } - for(;arg2numchn && arg2<=arg3;arg2++) - mf->control[arg2].muted = 1; - break; - - case MUTE_EXCLUSIVE: - if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) - { va_end(ap); - return; - } - for (t=0; tnumchn; t++) - { if ((t>=arg2) && (t<=arg3)) continue; - mf->control[t].muted = 1; - } - break; - - default: - if(arg1numchn) - mf->control[arg1].muted = 1; - break; - } - } - va_end(ap); + SLONG arg2,arg3=0; + ULONG t; - return; + if (pf) { + switch (arg1) { + case MUTE_INCLUSIVE: + if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| + (arg2>arg3)||(arg3>=pf->numchn)) + return; + for (;arg2numchn && arg2<=arg3;arg2++) + pf->control[arg2].muted=1-pf->control[arg2].muted; + break; + case MUTE_EXCLUSIVE: + if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))|| + (arg2>arg3)||(arg3>=pf->numchn)) + return; + for (t=0;tnumchn;t++) { + if ((t>=arg2) && (t<=arg3)) continue; + pf->control[t].muted=1-pf->control[t].muted; + } + break; + default: + if (arg1numchn) + pf->control[arg1].muted=1-pf->control[arg1].muted; + break; + } + } } - -void Player_Mute(SLONG arg1, ...) +void Player_ToggleMute(SLONG arg1,...) { - va_list argptr; - va_start(argptr,arg1); - MP_Mute(pf,arg1, argptr); - va_end(argptr); -} + va_list args; + va_start(args,arg1); + MUTEX_LOCK(vars); + Player_ToggleMute_internal(arg1,args); + MUTEX_UNLOCK(vars); + va_end(args); +} -void MP_ToggleMute(UNIMOD *mf, SLONG arg1, ...) +BOOL Player_Muted(UBYTE chan) { - va_list ap; - SLONG arg2, arg3; - ULONG t; - - va_start(ap,arg1); + BOOL result=1; - if(mf != NULL) - { switch (arg1) - { case MUTE_INCLUSIVE: - if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) - { va_end(ap); - return; - } - for(; arg2numchn && arg2<=arg3; arg2++) - mf->control[arg2].muted = (mf->control[arg2].muted) ? 0 : 1; - - break; - - case MUTE_EXCLUSIVE: - if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) - { va_end(ap); - return; - } - for (t=0;tnumchn;t++) - { if((t>=arg2) && (t<=arg3)) continue; - mf->control[t].muted = (mf->control[t].muted) ? 0 : 1; - } - break; - - default: - if(arg1numchn) - mf->control[arg1].muted = (mf->control[arg1].muted) ? 0 : 1; - break; - } - } - va_end(ap); + MUTEX_LOCK(vars); + if (pf) + result=(channumchn)?pf->control[chan].muted:1; + MUTEX_UNLOCK(vars); - return; + return result; } - -void Player_ToggleMute(SLONG arg1, ...) +int Player_GetChannelVoice(UBYTE chan) { - va_list argptr; - va_start(argptr,arg1); - MP_ToggleMute(pf,arg1, argptr); - va_end(argptr); -} + int result=0; + MUTEX_LOCK(vars); + if (pf) + result=(channumchn)?pf->control[chan].slavechn:-1; + MUTEX_UNLOCK(vars); -BOOL MP_Muted(UNIMOD *mf, int chan) -{ - if(mf==NULL) return 1; - return (channumchn) ? mf->control[chan].muted : 1; + return result; } - -BOOL Player_Muted(int chan) +UWORD Player_GetChannelPeriod(UBYTE chan) { - if(pf==NULL) return 1; - return (channumchn) ? pf->control[chan].muted : 1; -} + UWORD result=0; + MUTEX_LOCK(vars); + if (pf) + result=(channumchn)?pf->control[chan].period:0; + MUTEX_UNLOCK(vars); -int MP_GetChannelVoice(UNIMOD *mf, int chan) -{ - if(mf==NULL) return 0; - return mf->control[chan].slavechn; + return result; } - -int Player_GetChannelVoice(int chan) +BOOL Player_Paused_internal(void) { - if(pf==NULL) return 0; - return pf->control[chan].slavechn; + return pf?pf->forbid:1; } - -void Player_TogglePause(void) +BOOL Player_Paused(void) { - if(pf==NULL) return; - if(pf->forbid == 1) - pf->forbid = 0; - else - pf->forbid = 1; -} - + BOOL result; -/* --> The following procedures were taken from UNITRK because they */ -/* -> are ProTracker format specific. */ + MUTEX_LOCK(vars); + result=Player_Paused_internal(); + MUTEX_UNLOCK(vars); -void UniInstrument(UBYTE ins) -/* Appends UNI_INSTRUMENT opcode to the unitrk stream. */ -{ - UniWrite(UNI_INSTRUMENT); - UniWrite(ins); + return result; } -void UniNote(UBYTE note) -/* Appends UNI_NOTE opcode to the unitrk stream. */ +void Player_TogglePause(void) { - UniWrite(UNI_NOTE); - UniWrite(note); + MUTEX_LOCK(vars); + if (pf) + pf->forbid=1-pf->forbid; + MUTEX_UNLOCK(vars); } -void UniPTEffect(UBYTE eff, UBYTE dat) -/* Appends UNI_PTEFFECTX opcode to the unitrk stream. */ +void Player_SetSpeed(UWORD speed) { - if(eff!=0 || dat!=0) /* don't write empty effect */ - { UniWrite(UNI_PTEFFECT0+eff); - UniWrite(dat); - } + MUTEX_LOCK(vars); + if (pf) + pf->sngspd=speed?(speed<32?speed:32):1; + MUTEX_UNLOCK(vars); } -void UniVolEffect(UWORD eff, UBYTE dat) -/* Appends UNI_VOLEFFECT + effect/dat to unistream. */ +void Player_SetTempo(UWORD tempo) { - if(eff!=0 || dat!=0) /* don't write empty effect */ - { UniWrite(UNI_VOLEFFECTS); - UniWrite(eff); UniWrite(dat); - } + if (tempo<32) tempo=32; + + MUTEX_LOCK(vars); + if (pf) { + if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255; + pf->bpm=tempo; + } + MUTEX_UNLOCK(vars); } +/* ex:set ts=4: */ diff --git a/mikmod/munitrk.c b/mikmod/munitrk.c index a2fba726..30aa9f57 100644 --- a/mikmod/munitrk.c +++ b/mikmod/munitrk.c @@ -1,307 +1,299 @@ -/* - -Name: -MUNITRK.C - -Description: -All routines dealing with the manipulation of UNITRK(tm) streams - -Portability: -All systems - all compilers - +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ -#include -#include "mikmod.h" - -#define BUFPAGE 128 /* smallest unibuffer size */ -#define TRESHOLD 16 - -UWORD unioperands[256] = -{ 0, /* not used */ - 1, /* UNI_NOTE */ - 1, /* UNI_INSTRUMENT */ - 1, /* UNI_PTEFFECT0 */ - 1, /* UNI_PTEFFECT1 */ - 1, /* UNI_PTEFFECT2 */ - 1, /* UNI_PTEFFECT3 */ - 1, /* UNI_PTEFFECT4 */ - 1, /* UNI_PTEFFECT5 */ - 1, /* UNI_PTEFFECT6 */ - 1, /* UNI_PTEFFECT7 */ - 1, /* UNI_PTEFFECT8 */ - 1, /* UNI_PTEFFECT9 */ - 1, /* UNI_PTEFFECTA */ - 1, /* UNI_PTEFFECTB */ - 1, /* UNI_PTEFFECTC */ - 1, /* UNI_PTEFFECTD */ - 1, /* UNI_PTEFFECTE */ - 1, /* UNI_PTEFFECTF */ - 1, /* UNI_S3MEFFECTA */ - 1, /* UNI_S3MEFFECTD */ - 1, /* UNI_S3MEFFECTE */ - 1, /* UNI_S3MEFFECTF */ - 1, /* UNI_S3MEFFECTI */ - 1, /* UNI_S3MEFFECTQ */ - 1, /* UNI_S3MEFFECTR */ - 1, /* UNI_S3MEFFECTT */ - 1, /* UNI_S3MEFFECTU */ - 0, /* UNI_KEYOFF */ - 1, /* UNI_KEYFADE */ - 2, /* UNI_VOLEFFECTS */ - 1, /* UNI_XMEFFECT4 */ - 1, /* UNI_XMEFFECTA */ - 1, /* UNI_XMEFFECTE1 */ - 1, /* UNI_XMEFFECTE2 */ - 1, /* UNI_XMEFFECTEA */ - 1, /* UNI_XMEFFECTEB */ - 1, /* UNI_XMEFFECTG */ - 1, /* UNI_XMEFFECTH */ - 1, /* UNI_XMEFFECTL */ - 1, /* UNI_XMEFFECTP */ - 1, /* UNI_XMEFFECTX1 */ - 1, /* UNI_XMEFFECTX2 */ - 1, /* UNI_ITEFFECTG */ - 1, /* UNI_ITEFFECTH */ - 1, /* UNI_ITEFFECTI */ - 1, /* UNI_ITEFFECTM */ - 1, /* UNI_ITEFFECTN */ - 1, /* UNI_ITEFFECTP */ - 1, /* UNI_ITEFFECTU */ - 1, /* UNI_ITEFFECTW */ - 1, /* UNI_ITEFFECTY */ - 1 /* UNI_ITEFFECTS0 */ -}; - +/*============================================================================== -/* unibuffer is increased by BUFPAGE */ -/* bytes when unipc reaches unimax-TRESHOLD */ + $Id$ + All routines dealing with the manipulation of UNITRK streams -/* - Ok.. I'll try to explain the new internal module format.. so here it goes: +==============================================================================*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif - The UNITRK(tm) Format: - ====================== +#include "mikmod_internals.h" - A UNITRK stream is an array of bytes representing a single track - of a pattern. It's made up of 'repeat/length' bytes, opcodes and - operands (sort of a assembly language): +#include - rrrlllll - [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. - ^ ^ ^ - |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... +/* Unibuffer chunk size */ +#define BUFPAGE 128 + +UWORD unioperands[UNI_LAST]={ + 0, /* not used */ + 1, /* UNI_NOTE */ + 1, /* UNI_INSTRUMENT */ + 1, /* UNI_PTEFFECT0 */ + 1, /* UNI_PTEFFECT1 */ + 1, /* UNI_PTEFFECT2 */ + 1, /* UNI_PTEFFECT3 */ + 1, /* UNI_PTEFFECT4 */ + 1, /* UNI_PTEFFECT5 */ + 1, /* UNI_PTEFFECT6 */ + 1, /* UNI_PTEFFECT7 */ + 1, /* UNI_PTEFFECT8 */ + 1, /* UNI_PTEFFECT9 */ + 1, /* UNI_PTEFFECTA */ + 1, /* UNI_PTEFFECTB */ + 1, /* UNI_PTEFFECTC */ + 1, /* UNI_PTEFFECTD */ + 1, /* UNI_PTEFFECTE */ + 1, /* UNI_PTEFFECTF */ + 1, /* UNI_S3MEFFECTA */ + 1, /* UNI_S3MEFFECTD */ + 1, /* UNI_S3MEFFECTE */ + 1, /* UNI_S3MEFFECTF */ + 1, /* UNI_S3MEFFECTI */ + 1, /* UNI_S3MEFFECTQ */ + 1, /* UNI_S3MEFFECTR */ + 1, /* UNI_S3MEFFECTT */ + 1, /* UNI_S3MEFFECTU */ + 0, /* UNI_KEYOFF */ + 1, /* UNI_KEYFADE */ + 2, /* UNI_VOLEFFECTS */ + 1, /* UNI_XMEFFECT4 */ + 1, /* UNI_XMEFFECTA */ + 1, /* UNI_XMEFFECTE1 */ + 1, /* UNI_XMEFFECTE2 */ + 1, /* UNI_XMEFFECTEA */ + 1, /* UNI_XMEFFECTEB */ + 1, /* UNI_XMEFFECTG */ + 1, /* UNI_XMEFFECTH */ + 1, /* UNI_XMEFFECTL */ + 1, /* UNI_XMEFFECTP */ + 1, /* UNI_XMEFFECTX1 */ + 1, /* UNI_XMEFFECTX2 */ + 1, /* UNI_ITEFFECTG */ + 1, /* UNI_ITEFFECTH */ + 1, /* UNI_ITEFFECTI */ + 1, /* UNI_ITEFFECTM */ + 1, /* UNI_ITEFFECTN */ + 1, /* UNI_ITEFFECTP */ + 1, /* UNI_ITEFFECTT */ + 1, /* UNI_ITEFFECTU */ + 1, /* UNI_ITEFFECTW */ + 1, /* UNI_ITEFFECTY */ + 2, /* UNI_ITEFFECTZ */ + 1, /* UNI_ITEFFECTS0 */ + 2, /* UNI_ULTEFFECT9 */ + 2, /* UNI_MEDSPEED */ + 0, /* UNI_MEDEFFECTF1 */ + 0, /* UNI_MEDEFFECTF2 */ + 0 /* UNI_MEDEFFECTF3 */ +}; +/* Sparse description of the internal module format + ------------------------------------------------ - The rep/len byte contains the number of bytes in the current row, - _including_ the length byte itself (So the LENGTH byte of row 0 in the - previous example would have a value of 5). This makes it easy to search - through a stream for a particular row. A track is concluded by a 0-value - length byte. + A UNITRK stream is an array of bytes representing a single track of a pattern. +It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly +language): - The upper 3 bits of the rep/len byte contain the number of times -1 this - row is repeated for this track. (so a value of 7 means this row is repeated - 8 times) +rrrlllll +[REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. +^ ^ ^ +|-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... - Opcodes can range from 1 to 255 but currently only opcodes 1 to 45 are - being used. Each opcode can have a different number of operands. You can - find the number of operands to a particular opcode by using the opcode - as an index into the 'unioperands' table. + The rep/len byte contains the number of bytes in the current row, _including_ +the length byte itself (So the LENGTH byte of row 0 in the previous example +would have a value of 5). This makes it easy to search through a stream for a +particular row. A track is concluded by a 0-value length byte. -*/ + The upper 3 bits of the rep/len byte contain the number of times -1 this row +is repeated for this track. (so a value of 7 means this row is repeated 8 times) + Opcodes can range from 1 to 255 but currently only opcodes 1 to 52 are being +used. Each opcode can have a different number of operands. You can find the +number of operands to a particular opcode by using the opcode as an index into +the 'unioperands' table. -/*************************************************************************** ->>>>>>>>>>> Next are the routines for reading a UNITRK stream: <<<<<<<<<<<<< -***************************************************************************/ +*/ +/*========== Reading routines */ -static UBYTE *rowstart; /* startadress of a row */ -static UBYTE *rowend; /* endaddress of a row (exclusive) */ -static UBYTE *rowpc; /* current unimod(tm) programcounter */ +static UBYTE *rowstart; /* startadress of a row */ +static UBYTE *rowend; /* endaddress of a row (exclusive) */ +static UBYTE *rowpc; /* current unimod(tm) programcounter */ -void UniSetRow(UBYTE *t) +void UniSetRow(UBYTE* t) { - rowstart = t; - rowpc = rowstart; - rowend = rowstart+(*(rowpc++)&0x1f); + rowstart = t; + rowpc = rowstart; + rowend = t?rowstart+(*(rowpc++)&0x1f):t; } - UBYTE UniGetByte(void) { - return (rowpc end of track.. */ - l = (c>>5)+1; /* extract repeat value */ - if(l>row) break; /* reached wanted row? -> return pointer */ - row -= l; /* haven't reached row yet.. update row */ - t += c&0x1f; /* point t to the next row */ - } - - return t; + UBYTE c,l; + + if(t) + while(1) { + c = *t; /* get rep/len byte */ + if(!c) return NULL; /* zero ? -> end of track.. */ + l = (c>>5)+1; /* extract repeat value */ + if(l>row) break; /* reached wanted row? -> return pointer */ + row -= l; /* haven't reached row yet.. update row */ + t += c&0x1f; /* point t to the next row */ + } + return t; } +/*========== Writing routines */ +static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */ +static UWORD unimax; /* buffer size */ -/*************************************************************************** ->>>>>>>>>>> Next are the routines for CREATING UNITRK streams: <<<<<<<<<<<<< -***************************************************************************/ - - -static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */ -static UWORD unimax; /* maximum number of bytes to be written to this buffer */ - -static UWORD unipc; /* index in the buffer where next opcode will be written */ -static UWORD unitt; /* holds index of the rep/len byte of a row */ -static UWORD lastp; /* holds index to the previous row (needed for compressing) */ +static UWORD unipc; /* buffer cursor */ +static UWORD unitt; /* current row index */ +static UWORD lastp; /* previous row index */ - -void UniReset(void) /* Resets index-pointers to create a new track. */ +void UniReset(void) { - unitt = 0; /* reset index to rep/len byte */ - unipc = 1; /* first opcode will be written to index 1 */ - lastp = 0; /* no previous row yet */ - unibuf[0] = 0; /* clear rep/len byte */ + unitt = 0; /* reset index to rep/len byte */ + unipc = 1; /* first opcode will be written to index 1 */ + lastp = 0; /* no previous row yet */ + unibuf[0] = 0; /* clear rep/len byte */ } +/* Expands the buffer */ +static BOOL UniExpand(int wanted) +{ + if ((unipc+wanted)>=unimax) { + UBYTE *newbuf; + + /* Expand the buffer by BUFPAGE bytes */ + newbuf=(UBYTE*)realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE)); + + /* Check if realloc succeeded */ + if(newbuf) { + unibuf = newbuf; + unimax+=BUFPAGE; + return 1; + } else + return 0; + } + return 1; +} -void UniWrite(UBYTE data) /* Appends one byte of data to the current row of a track. */ +void UniWriteByte(UBYTE data) { - /* write byte to current position and update */ - - unibuf[unipc++] = data; - - /* Check if we've reached the end of the buffer */ - - if(unipc > (unimax-TRESHOLD)) - { UBYTE *newbuf; - - /* We've reached the end of the buffer, so expand */ - /* the buffer by BUFPAGE bytes */ - - newbuf = (UBYTE *)realloc(unibuf, unimax+BUFPAGE); - - /* Check if realloc succeeded */ - - if(newbuf!=NULL) - { unibuf = newbuf; - unimax+=BUFPAGE; - } else - { /* realloc failed, so decrease unipc so we won't write beyond */ - /* the end of the buffer.. I don't report the out-of-memory */ - /* here; the UniDup() will fail anyway so that's where the */ - /* loader sees that something went wrong */ - - unipc--; - } - } + if (UniExpand(1)) + /* write byte to current position and update */ + unibuf[unipc++]=data; } - -BOOL MyCmp(UBYTE *a, UBYTE *b, UWORD l) +void UniWriteWord(UWORD data) { - UWORD t; - - for(t=0; t>8; + unibuf[unipc++]=data&0xff; + } } - -void UniNewline(void) -/* Closes the current row of a unitrk stream (updates the rep/len byte) */ -/* and sets pointers to start a new row. */ +static BOOL MyCmp(UBYTE* a,UBYTE* b,UWORD l) { - UWORD n,l,len; - - n = (unibuf[lastp]>>5)+1; /* repeat of previous row */ - l = (unibuf[lastp]&0x1f); /* length of previous row */ + UWORD t; - len = unipc-unitt; /* length of current row */ - - /* Now, check if the previous and the current row are identical.. */ - /* when they are, just increase the repeat field of the previous row */ - - if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) - { unibuf[lastp]+=0x20; - unipc = unitt+1; - } else - { /* current and previous row aren't equal.. so just update the pointers */ - - unibuf[unitt] = len; - lastp = unitt; - unitt = unipc; - unipc++; - } + for(t=0;t>5)+1; /* repeat of previous row */ + l = (unibuf[lastp]&0x1f); /* length of previous row */ + + len = unipc-unitt; /* length of current row */ + + /* Now, check if the previous and the current row are identical.. when they + are, just increase the repeat field of the previous row */ + if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) { + unibuf[lastp]+=0x20; + unipc = unitt+1; + } else { + if (UniExpand(unitt-unipc)) { + /* current and previous row aren't equal... update the pointers */ + unibuf[unitt] = len; + lastp = unitt; + unitt = unipc++; + } + } } - -UWORD TrkLen(UBYTE *t) -/* Determines the length (in rows) of a unitrk stream 't' */ +/* Terminates the current unitrk stream and returns a pointer to a copy of the + stream. */ +UBYTE* UniDup(void) { - UWORD len = 0; - UBYTE c; + UBYTE *d; - while(c = *t & 0x1f) - { len += c; - t += c; - } - len++; + if (!UniExpand(unitt-unipc)) return NULL; + unibuf[unitt] = 0; - return len; -} + if(!(d=(UBYTE *)_mm_malloc(unipc))) return NULL; + memcpy(d,unibuf,unipc); + return d; +} BOOL UniInit(void) { - unimax = BUFPAGE; + unimax = BUFPAGE; - if(!(unibuf=(UBYTE *)_mm_malloc(unimax))) return 0; - return 1; + if(!(unibuf=(UBYTE*)_mm_malloc(unimax*sizeof(UBYTE)))) return 0; + return 1; } - void UniCleanup(void) { - if(unibuf!=NULL) free(unibuf); - unibuf = NULL; + if(unibuf) free(unibuf); + unibuf = NULL; } +/* ex:set ts=4: */ diff --git a/mikmod/npertab.c b/mikmod/npertab.c index d888ffa5..3be755ad 100644 --- a/mikmod/npertab.c +++ b/mikmod/npertab.c @@ -1,14 +1,47 @@ -/* MOD format period table. Used by both the MOD and */ -/* M15 (15-inst mod) Loaders. */ - -#include "tdefs.h" - -UWORD npertab[60] = -{ /* -> Tuning 0 */ - 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906, - 856,808,762,720,678,640,604,570,538,508,480,453, - 428,404,381,360,339,320,302,285,269,254,240,226, - 214,202,190,180,170,160,151,143,135,127,120,113, - 107,101,95,90,85,80,75,71,67,63,60,56 +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +/*============================================================================== + + $Id$ + + MOD format period table. Used by both the MOD and M15 (15-inst mod) Loaders. + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mikmod_internals.h" + +UWORD npertab[7*OCTAVE]={ + /* -> Tuning 0 */ + 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016, 960, 906, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56, + + 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28, + 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14 }; +/* ex:set ts=4: */ diff --git a/mikmod/sloader.c b/mikmod/sloader.c index 7c791593..d4b06e2a 100644 --- a/mikmod/sloader.c +++ b/mikmod/sloader.c @@ -1,407 +1,515 @@ -/* - --> Sample Loaders and Sample Processing +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ -Name: sloader.c +/*============================================================================== -Description: -Routines for loading samples. The sample loader utilizes the routines -provided by the "registered" sample loader. See SAMPLELOADER in -MIKMOD.H for the sample loader structure. + $Id$ -Portability: -All systems - all compilers + Routines for loading samples. The sample loader utilizes the routines + provided by the "registered" sample loader. -*/ +==============================================================================*/ -#include "mikmod.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include -static int sl_rlength; -static SWORD sl_old; -static SWORD *sl_buffer = NULL; -static SAMPLOAD *musiclist = NULL, - *sndfxlist = NULL; +static int sl_rlength; +static SWORD sl_old; +static SWORD *sl_buffer=NULL; +static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL; +/* size of the loader buffer in words */ +#define SLBUFSIZE 2048 +/* IT-Compressed status structure */ +typedef struct ITPACK { + UWORD bits; /* current number of bits */ + UWORD bufbits; /* bits in buffer */ + SWORD last; /* last output */ + UBYTE buf; /* bit buffer */ +} ITPACK; -BOOL SL_Init(SAMPLOAD *s) /* returns 0 on error! */ +BOOL SL_Init(SAMPLOAD* s) { - if(sl_buffer==NULL) - if((sl_buffer=_mm_malloc(4100)) == NULL) return 0; + if(!sl_buffer) + if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0; - sl_rlength = s->length; - if(s->infmt & SF_16BITS) sl_rlength>>=1; - sl_old = 0; + sl_rlength = s->length; + if(s->infmt & SF_16BITS) sl_rlength>>=1; + sl_old = 0; - return 1; + return 1; } - void SL_Exit(SAMPLOAD *s) { - if(sl_rlength > 0) _mm_fseek(s->fp,sl_rlength,SEEK_CUR); + if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR); + if(sl_buffer) { + free(sl_buffer); + sl_buffer=NULL; + } } - -void SL_Reset(void) +/* unpack a 8bit IT packed sample */ +static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt) { - sl_old = 0; + SWORD *dest=sl_buffer,*end=sl_buffer+count; + UWORD x,y,needbits,havebits,new_count=0; + UWORD bits = status->bits; + UWORD bufbits = status->bufbits; + SBYTE last = status->last; + UBYTE buf = status->buf; + + while (dest>=y; + bufbits-=y; + needbits-=y; + havebits+=y; + } + if (new_count) { + new_count = 0; + if (++x >= bits) + x++; + bits = x; + continue; + } + if (bits<7) { + if (x==(1<<(bits-1))) { + new_count = 1; + continue; + } + } + else if (bits<9) { + y = (0xff >> (9-bits)) - 4; + if ((x>y)&&(x<=y+8)) { + if ((x-=y)>=bits) + x++; + bits = x; + continue; + } + } + else if (bits<10) { + if (x>=0x100) { + bits=x-0x100+1; + continue; + } + } else { + /* error in compressed data... */ + _mm_errno=MMERR_ITPACK_INVALID_DATA; + return 0; + } + + if (bits<8) /* extend sign */ + x = ((SBYTE)(x <<(8-bits))) >> (8-bits); + *(dest++)= (last+=x) << 8; /* convert to 16 bit */ + } + status->bits = bits; + status->bufbits = bufbits; + status->last = last; + status->buf = buf; + return dest-sl_buffer; } - -void SL_Load(void *buffer, SAMPLOAD *smp, int length) +/* unpack a 16bit IT packed sample */ +static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt) { - UWORD infmt = smp->infmt, outfmt = smp->outfmt; - SBYTE *bptr = (SBYTE *)buffer; - SWORD *wptr = (SWORD *)buffer; - int stodo; - int t, u; - - while(length) - { stodo = (length<2048) ? length : 2048; - - if(infmt & SF_16BITS) - { if(infmt & SF_BIG_ENDIAN) - _mm_read_M_SWORDS(sl_buffer,stodo,smp->fp); - else - _mm_read_I_SWORDS(sl_buffer,stodo,smp->fp); - } else - { SBYTE *s; - SWORD *d; - - fread(sl_buffer,sizeof(SBYTE),stodo,smp->fp); - - s = (SBYTE *)sl_buffer; - d = sl_buffer; - s += stodo; - d += stodo; - - for(t=0; tscalefactor) - { int idx = 0; - SLONG scaleval; - - /* Sample Scaling... average values for better results. */ - t = 0; - while(tscalefactor; u && tscalefactor-u); - length--; - } - sl_rlength -= stodo; - stodo = idx; - } else - { length -= stodo; - sl_rlength -= stodo; - } - - if(outfmt & SF_16BITS) - { for(t=0; t>8; - } - } + SWORD *dest=sl_buffer,*end=sl_buffer+count; + SLONG x,y,needbits,havebits,new_count=0; + UWORD bits = status->bits; + UWORD bufbits = status->bufbits; + SWORD last = status->last; + UBYTE buf = status->buf; + + while (dest>=y; + bufbits-=y; + needbits-=y; + havebits+=y; + } + if (new_count) { + new_count = 0; + if (++x >= bits) + x++; + bits = x; + continue; + } + if (bits<7) { + if (x==(1<<(bits-1))) { + new_count=1; + continue; + } + } + else if (bits<17) { + y=(0xffff>>(17-bits))-8; + if ((x>y)&&(x<=y+16)) { + if ((x-=y)>=bits) + x++; + bits = x; + continue; + } + } + else if (bits<18) { + if (x>=0x10000) { + bits=x-0x10000+1; + continue; + } + } else { + /* error in compressed data... */ + _mm_errno=MMERR_ITPACK_INVALID_DATA; + return 0; + } + + if (bits<16) /* extend sign */ + x = ((SWORD)(x<<(16-bits)))>>(16-bits); + *(dest++)=(last+=x); + } + status->bits = bits; + status->bufbits = bufbits; + status->last = last; + status->buf = buf; + return dest-sl_buffer; } - -void SL_LoadStream(void *buffer, UWORD infmt, UWORD outfmt, int length, FILE *fp) - -/* This is like SL_Load, but does not perform sample scaling, and does not */ -/* require calls to SL_Init / SL_Exit. */ - +static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither) { - SBYTE *bptr = (SBYTE *)buffer; - SWORD *wptr = (SWORD *)buffer; - int stodo; - int t; - - /* compute number of samples to load */ - - if(sl_buffer==NULL) - if((sl_buffer=_mm_malloc(4100)) == NULL) return; - - while(length) - { stodo = (length<2048) ? length : 2048; - - if(infmt & SF_16BITS) - { if(infmt & SF_BIG_ENDIAN) - _mm_read_M_SWORDS(sl_buffer,stodo,fp); - else - _mm_read_I_SWORDS(sl_buffer,stodo,fp); - } else - { SBYTE *s; - SWORD *d; - - fread(sl_buffer,sizeof(SBYTE),stodo,fp); - - s = (SBYTE *)sl_buffer; - d = sl_buffer; - s += stodo; - d += stodo; - - for(t=0; t> 1; - length-=2; - } - stodo = idx; - } - - if(outfmt & SF_16BITS) - { for(t=0; t>8; - } - } + SBYTE *bptr = (SBYTE*)buffer; + SWORD *wptr = (SWORD*)buffer; + int stodo,t,u; + + int result,c_block=0; /* compression bytes until next block */ + ITPACK status; + UWORD incnt; + + while(length) { + stodo=(lengthRead(reader,sl_buffer,sizeof(SBYTE)*stodo); + src = (SBYTE*)sl_buffer; + dest = sl_buffer; + src += stodo;dest += stodo; + + for(t=0;t>1; + length-=2; + } + stodo = idx; + } + } + + if(outfmt & SF_16BITS) { + for(t=0;t>8; + } + } + return 0; } - -SAMPLOAD *SL_RegisterSample(SAMPLE *s, int type, FILE *fp) /* Returns 1 on error! */ +BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length) +{ + return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor, + length,smp->reader,0); +} /* Registers a sample for loading when SL_LoadSamples() is called. */ -/* type - type of sample to be loaded .. */ -/* MD_MUSIC, MD_SNDFX */ - +SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader) { - SAMPLOAD *news, **samplist, *cruise; - - if(type==MD_MUSIC) - { samplist = & musiclist; - cruise = musiclist; - } else - { samplist = &sndfxlist; - cruise = sndfxlist; - } - - /* Allocate and add structure to the END of the list */ - - if((news=(SAMPLOAD *)_mm_calloc(1,sizeof(SAMPLOAD))) == NULL) return NULL; - - if(cruise!=NULL) - { while(cruise->next!=NULL) cruise = cruise->next; - cruise->next = news; - } else - *samplist = news; - - news->infmt = s->flags & 31; - news->outfmt = news->infmt; - news->fp = fp; - news->sample = s; - news->length = s->length; - news->loopstart = s->loopstart; - news->loopend = s->loopend; - - return news; + SAMPLOAD *news,**samplist,*cruise; + + if(type==MD_MUSIC) { + samplist = &musiclist; + cruise = musiclist; + } else + if (type==MD_SNDFX) { + samplist = &sndfxlist; + cruise = sndfxlist; + } else + return NULL; + + /* Allocate and add structure to the END of the list */ + if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL; + + if(cruise) { + while(cruise->next) cruise=cruise->next; + cruise->next = news; + } else + *samplist = news; + + news->infmt = s->flags & SF_FORMATMASK; + news->outfmt = news->infmt; + news->reader = reader; + news->sample = s; + news->length = s->length; + news->loopstart = s->loopstart; + news->loopend = s->loopend; + + return news; } - -static void FreeSampleList(SAMPLOAD *s) +static void FreeSampleList(SAMPLOAD* s) { - SAMPLOAD *old; + SAMPLOAD *old; - while(s!=NULL) - { old = s; - s = s->next; - free(old); - } + while(s) { + old = s; + s = s->next; + free(old); + } } - -static ULONG SampleTotal(SAMPLOAD *samplist, int type) /* Returns the total amount of memory required by the samplelist queue. */ +static ULONG SampleTotal(SAMPLOAD* samplist,int type) { - int total = 0; + int total = 0; - while(samplist!=NULL) - { samplist->sample->flags = (samplist->sample->flags&~31) | samplist->outfmt; - total += MD_SampleLength(type,samplist->sample); - samplist = samplist->next; - } + while(samplist) { + samplist->sample->flags= + (samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt; + total += MD_SampleLength(type,samplist->sample); + samplist=samplist->next; + } - return total; + return total; } - static ULONG RealSpeed(SAMPLOAD *s) { - return(s->sample->speed / ((s->scalefactor==0) ? 1 : s->scalefactor)); -} - + return(s->sample->speed/(s->scalefactor?s->scalefactor:1)); +} -static BOOL DitherSamples(SAMPLOAD *samplist, int type) +static BOOL DitherSamples(SAMPLOAD* samplist,int type) { - SAMPLOAD *c2smp; - ULONG maxsize, speed; - SAMPLOAD *s; - - if(samplist==NULL) return 0; - - /* make sure the samples will fit inside available RAM */ - if((maxsize = MD_SampleSpace(type)*1024) != 0) - { while(SampleTotal(samplist, type) > maxsize) - { /* First Pass - check for any 16 bit samples */ - s = samplist; - while(s!=NULL) - { if(s->outfmt & SF_16BITS) - { SL_Sample16to8(s); - break; - } - s = s->next; - } - - /* Second pass (if no 16bits found above) is to take the sample */ - /* with the highest speed and dither it by half. */ - if(s==NULL) - { s = samplist; - speed = 0; - while(s!=NULL) - { if((s->sample->length) && (RealSpeed(s) > speed)) - { speed = RealSpeed(s); - c2smp = s; - } - s = s->next; - } - SL_HalveSample(c2smp); - } - } - } - - - /* Samples dithered, now load them! */ - /* ================================ */ - - s = samplist; - while(s != NULL) - { /* sample has to be loaded ? -> increase number of */ - /* samples, allocate memory and load sample. */ - - if(s->sample->length) - { if(s->sample->seekpos) - _mm_fseek(s->fp, s->sample->seekpos, SEEK_SET); - - /* Call the sample load routine of the driver module. */ - /* It has to return a 'handle' (>=0) that identifies */ - /* the sample. */ - - s->sample->handle = MD_SampleLoad(s, type, s->fp); - s->sample->flags = (s->sample->flags & ~31) | s->outfmt; - if(s->sample->handle < 0) - { FreeSampleList(samplist); - if(_mm_errorhandler!=NULL) _mm_errorhandler(); - return 1; - } - } - s = s->next; - } - - FreeSampleList(samplist); - return 0; + SAMPLOAD *c2smp=NULL; + ULONG maxsize, speed; + SAMPLOAD *s; + + if(!samplist) return 0; + + if((maxsize=MD_SampleSpace(type)*1024)) + while(SampleTotal(samplist,type)>maxsize) { + /* First Pass - check for any 16 bit samples */ + s = samplist; + while(s) { + if(s->outfmt & SF_16BITS) { + SL_Sample16to8(s); + break; + } + s=s->next; + } + /* Second pass (if no 16bits found above) is to take the sample with + the highest speed and dither it by half. */ + if(!s) { + s = samplist; + speed = 0; + while(s) { + if((s->sample->length) && (RealSpeed(s)>speed)) { + speed=RealSpeed(s); + c2smp=s; + } + s=s->next; + } + if (c2smp) + SL_HalveSample(c2smp,2); + } + } + + /* Samples dithered, now load them ! */ + s = samplist; + while(s) { + /* sample has to be loaded ? -> increase number of samples, allocate + memory and load sample. */ + if(s->sample->length) { + if(s->sample->seekpos) + _mm_fseek(s->reader, s->sample->seekpos, SEEK_SET); + + /* Call the sample load routine of the driver module. It has to + return a 'handle' (>=0) that identifies the sample. */ + s->sample->handle = MD_SampleLoad(s, type); + s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt; + if(s->sample->handle<0) { + FreeSampleList(samplist); + if(_mm_errorhandler) _mm_errorhandler(); + return 1; + } + } + s = s->next; + } + + FreeSampleList(samplist); + return 0; } - -BOOL SL_LoadSamples(void) /* Returns 1 on error! */ +BOOL SL_LoadSamples(void) { - BOOL ok; - - _mm_critical = 0; + BOOL ok; - if((musiclist==NULL) && (sndfxlist==NULL)) return 0; -/* MikMod_Exit(); */ -/* exit(1); */ - ok = DitherSamples(musiclist,MD_MUSIC) || DitherSamples(sndfxlist,MD_SNDFX); + _mm_critical = 0; - musiclist = sndfxlist = NULL; + if((!musiclist)&&(!sndfxlist)) return 0; + ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX); + musiclist=sndfxlist=NULL; - return ok; + return ok; } - -void SL_Sample16to8(SAMPLOAD *s) +void SL_Sample16to8(SAMPLOAD* s) { - s->outfmt &= ~SF_16BITS; - s->sample->flags = (s->sample->flags&~31) | s->outfmt; + s->outfmt &= ~SF_16BITS; + s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt; } - -void SL_Sample8to16(SAMPLOAD *s) +void SL_Sample8to16(SAMPLOAD* s) { - s->outfmt |= SF_16BITS; - s->sample->flags = (s->sample->flags&~31) | s->outfmt; + s->outfmt |= SF_16BITS; + s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt; } - -void SL_SampleSigned(SAMPLOAD *s) +void SL_SampleSigned(SAMPLOAD* s) { - s->outfmt |= SF_SIGNED; - s->sample->flags = (s->sample->flags&~31) | s->outfmt; + s->outfmt |= SF_SIGNED; + s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt; } - -void SL_SampleUnsigned(SAMPLOAD *s) +void SL_SampleUnsigned(SAMPLOAD* s) { - s->outfmt &= ~SF_SIGNED; - s->sample->flags = (s->sample->flags&~31) | s->outfmt; + s->outfmt &= ~SF_SIGNED; + s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt; } - -void SL_HalveSample(SAMPLOAD *s) +void SL_HalveSample(SAMPLOAD* s,int factor) { - if(s->scalefactor) - s->scalefactor++; - else - s->scalefactor = 2; - - s->sample->divfactor = s->scalefactor; - s->sample->length = s->length / s->scalefactor; - s->sample->loopstart = s->loopstart / s->scalefactor; - s->sample->loopend = s->loopend / s->scalefactor; + s->scalefactor=factor>0?factor:2; + + s->sample->divfactor = s->scalefactor; + s->sample->length = s->length / s->scalefactor; + s->sample->loopstart = s->loopstart / s->scalefactor; + s->sample->loopend = s->loopend / s->scalefactor; } + +/* ex:set ts=4: */ diff --git a/mikmod/virtch.c b/mikmod/virtch.c index 85781fe8..00371ad5 100644 --- a/mikmod/virtch.c +++ b/mikmod/virtch.c @@ -1,1362 +1,824 @@ -/* +/* MikMod sound library + (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for + complete list. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ -Name: VIRTCH.C +/*============================================================================== -Description: - Sample mixing routines, using a 32 bits mixing buffer. + $Id$ - Optional features include: - (a) 4-step reverb (for 16 bit output only) - (b) Interpolation of sample data during mixing - (c) Dolby Surround Sound - (d) Optimized assembly mixers for the Intel platform - (e) Optional high-speed or high-quality modes + Sample mixing routines, using a 32 bits mixing buffer. -C Mixer Portability: - All Systems -- All compilers. +==============================================================================*/ -Assembly Mixer Portability: +/* - MSDOS: BC(?) Watcom(y) DJGPP(y) - Win95: ? - Os2: ? - Linux: y + Optional features include: + (a) 4-step reverb (for 16 bit output only) + (b) Interpolation of sample data during mixing + (c) Dolby Surround Sound +*/ - (y) - yes - (n) - no (not possible or not useful) - (?) - may be possible, but not tested +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -*/ +#include "mikmod_internals.h" #include #include -#include "mikmod.h" - /* -// ** For PC-assembly mixing -// ========================= -// Uncomment both lines below for assembly mixing under WATCOM or GCC for -// Linux. Note that there is no 16 bit mixers for assembly yet (C only), so -// defining __ASSEMBLY__ when not defining __FASTMIXER__ will lead to compiler -// errors. -*/ + Constant definitions + ==================== -#define __FASTMIXER__ -/* #define __ASSEMBLY__ */ -#define __FAST_REVERB__ + BITSHIFT + Controls the maximum volume of the sound output. All data is shifted + right by BITSHIFT after being mixed. Higher values result in quieter + sound and less chance of distortion. -/* -// Various other VIRTCH.C Compiler Options -// ======================================= - -// BITSHIFT : Controls the maximum volume of the sound output. All data -// is shifted right by BITSHIFT after being mixed. Higher values -// result in quieter sound and less chance of distortion. If you -// are using the assembly mixer, you must change the bitshift const- -// ant in RESAMPLE.ASM or RESAMPLE.S as well! -*/ - -#define BITSHIFT 9 - -/* -// REVERBERATION : Controls the duration of the reverb. Larger values -// represent a shorter reverb loop. Smaller values extend the reverb -// but can result in more of an echo-ish sound. -*/ - -#define REVERBERATION 110000l + REVERBERATION + Controls the duration of the reverb. Larger values represent a shorter + reverb loop. Smaller values extend the reverb but can result in more of + an echo-ish sound. -/* -// BOUNDS_CHECKING : Forces VIRTCH to perform bounds checking. Commenting -// the line below will result in a slightly faster mixing process but -// could cause nasty clicks and pops on some modules. Disable this -// option on games or demos only, where speed is very important all -// songs / sndfx played can be specifically tested for pops. */ -#define BOUNDS_CHECKING - - -#ifndef __cdecl -#ifdef __GNUC__ -#define __cdecl -#endif -#endif - -#ifdef __WATCOMC__ -#define inline -#endif +#define BITSHIFT 9 +#define REVERBERATION 110000L #define FRACBITS 11 -#define FRACMASK ((1l<(b))?(a):(b)) -#endif - - -typedef struct -{ UBYTE kick; /* =1 -> sample has to be restarted */ - UBYTE active; /* =1 -> sample is playing */ - UWORD flags; /* 16/8 bits looping/one-shot */ - SWORD handle; /* identifies the sample */ - ULONG start; /* start index */ - ULONG size; /* samplesize */ - ULONG reppos; /* loop start */ - ULONG repend; /* loop end */ - ULONG frq; /* current frequency */ - int vol; /* current volume */ - int pan; /* current panning position */ - SLONG current; /* current index in the sample */ - SLONG increment; /* fixed-point increment value */ +typedef struct VINFO { + UBYTE kick; /* =1 -> sample has to be restarted */ + UBYTE active; /* =1 -> sample is playing */ + UWORD flags; /* 16/8 bits looping/one-shot */ + SWORD handle; /* identifies the sample */ + ULONG start; /* start index */ + ULONG size; /* samplesize */ + ULONG reppos; /* loop start */ + ULONG repend; /* loop end */ + ULONG frq; /* current frequency */ + int vol; /* current volume */ + int pan; /* current panning position */ + + int rampvol; + int lvolsel,rvolsel; /* Volume factor in range 0-255 */ + int oldlvol,oldrvol; + + SLONGLONG current; /* current index in the sample */ + SLONGLONG increment; /* increment value */ } VINFO; -#ifdef __FASTMIXER__ -static SBYTE **Samples; -SLONG *lvoltab, *rvoltab; /* Volume Table values for use by 8 bit mixers */ -#else -static SWORD **Samples; -static SLONG lvolsel, rvolsel; /* Volume Selectors for 16 bit mixers. */ -#endif - -/* Volume table for 8 bit sample mixing */ -#ifdef __FASTMIXER__ -static SLONG **voltab; -#endif - -static VINFO *vinf = NULL, *vnf; -static long TICKLEFT, samplesthatfit, vc_memory = 0; -static int vc_softchn; -static SLONG idxsize, idxlpos, idxlend; -static SLONG *VC_TICKBUF = NULL; -static UWORD vc_mode; +static SWORD **Samples; +static VINFO *vinf=NULL,*vnf; +static long tickleft,samplesthatfit,vc_memory=0; +static int vc_softchn; +static SLONGLONG idxsize,idxlpos,idxlend; +static SLONG *vc_tickbuf=NULL; +static UWORD vc_mode; +/* Reverb control variables */ -/* -// Reverb control variables -// ======================== -*/ - -static int RVc1, RVc2, RVc3, RVc4; -#ifndef __FAST_REVERB__ -static int RVc5, RVc6, RVc7, RVc8; -#endif -static ULONG RVRindex; - +static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8; +static ULONG RVRindex; /* For Mono or Left Channel */ +static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL, + *RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL; -static SLONG *RVbuf1 = NULL, *RVbuf2 = NULL, *RVbuf3 = NULL, *RVbuf4 = NULL; -#ifndef __FAST_REVERB__ -static SLONG *RVbuf5 = NULL, *RVbuf6 = NULL, *RVbuf7 = NULL, *RVbuf8 = NULL; -#endif - -/* -// For Stereo only (Right Channel) -// Values start at 9 to leave room for expanding this to 8-step -// reverb in the future. -*/ - -static SLONG *RVbuf9 = NULL, *RVbuf10 = NULL, *RVbuf11 = NULL, *RVbuf12 = NULL; -#ifndef __FAST_REVERB__ -static SLONG *RVbuf13 = NULL, *RVbuf14 = NULL, *RVbuf15 = NULL, *RVbuf16 = NULL; -#endif - - -/* -// Define external Assembly Language Prototypes -// ============================================ -*/ - -#ifdef __ASSEMBLY__ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __cdecl -#ifdef __GNUC__ -#define __cdecl -#endif -#endif - -void __cdecl AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); -void __cdecl AsmStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); -void __cdecl AsmSurroundNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); -void __cdecl AsmSurroundInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); -void __cdecl AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); -void __cdecl AsmMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); - -#ifdef __cplusplus -}; -#endif - -#else - -#ifdef __FASTMIXER__ - -/* -// ============================================================== -// 8 bit sample mixers! -*/ - -static SLONG MixStereoNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - UBYTE sample1, sample2, sample3, sample4; - int remain; - - remain = todo & 3; - - for(todo>>=2; todo; todo--) - { - sample1 = srce[index >> FRACBITS]; - index += increment; - sample2 = srce[index >> FRACBITS]; - index += increment; - sample3 = srce[index >> FRACBITS]; - index += increment; - sample4 = srce[index >> FRACBITS]; - index += increment; - - *dest++ += lvoltab[sample1]; - *dest++ += rvoltab[sample1]; - *dest++ += lvoltab[sample2]; - *dest++ += rvoltab[sample2]; - *dest++ += lvoltab[sample3]; - *dest++ += rvoltab[sample3]; - *dest++ += lvoltab[sample4]; - *dest++ += rvoltab[sample4]; - } - - for(; remain--; ) - { - sample1 = srce[index >> FRACBITS]; - index += increment; - *dest++ += lvoltab[sample1]; - *dest++ += rvoltab[sample1]; - } - - return index; -} - - -static SLONG MixStereoInterp(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - UBYTE sample; - - for(; todo; todo--) - { sample = (UBYTE)((srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + - (srce[(index >> FRACBITS) + 1] * (index & FRACMASK)) >> FRACBITS); - index += increment; - - *dest++ += lvoltab[sample]; - *dest++ += rvoltab[sample]; - } - - return index; -} - - -static SLONG MixSurroundNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - SLONG sample1, sample2, sample3, sample4; - int remain; - - remain = todo & 3; - - for(todo>>=2; todo; todo--) - { - sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - sample2 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - sample3 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - sample4 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - - *dest++ += sample1; - *dest++ -= sample1; - *dest++ += sample2; - *dest++ -= sample2; - *dest++ += sample3; - *dest++ -= sample3; - *dest++ += sample4; - *dest++ -= sample4; - } - - for(; remain--; ) - { sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - *dest++ += sample1; - *dest++ -= sample1; - } - - return index; -} - - -static SLONG MixSurroundInterp(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - SLONG sample; - - for(; todo; todo--) - { sample = lvoltab[(UBYTE)((srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + - (srce[(index >> FRACBITS) + 1] * (index & FRACMASK)) >> FRACBITS)]; - index += increment; - - *dest++ += sample; - *dest++ -= sample; - } - - return index; -} - - -static SLONG MixMonoNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - SLONG sample1, sample2, sample3, sample4; - int remain; - - remain = todo & 3; - - for(todo>>=2; todo; todo--) - { - sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - sample2 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - sample3 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - sample4 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - - *dest++ += sample1; - *dest++ += sample2; - *dest++ += sample3; - *dest++ += sample4; - } - - for(; remain--;) - { sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; - index += increment; - *dest++ += sample1; - } - - return index; -} - - -static SLONG MixMonoInterp(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - SLONG sample; - - for(; todo; todo--) - { sample = lvoltab[(UBYTE)(((srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + - (srce[(index >> FRACBITS) + 1] * (index & FRACMASK))) >> FRACBITS)]; - index += increment; - - *dest++ += sample; - } - - return index; -} - - -#else - -/* -// ============================================================== -// 16 bit sample mixers! -*/ - -static SLONG MixStereoNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) -{ - SWORD sample; - - for(; todo; todo--) - { - sample = srce[index >> FRACBITS]; - index += increment; - - *dest++ += lvolsel * sample; - *dest++ += rvolsel * sample; - } - - return index; -} - - -static SLONG MixStereoInterp(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) -{ - SWORD sample; - - for(; todo; todo--) - { - sample = (srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + - (srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS; - index += increment; - - *dest++ += lvolsel * sample; - *dest++ += rvolsel * sample; - } - - return index; -} - - -static SLONG MixSurroundNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) -{ - SWORD sample; - - for (; todo; todo--) - { - sample = srce[index >> FRACBITS]; - index += increment; - - *dest++ += lvolsel * sample; - *dest++ -= lvolsel * sample; - } - - return index; -} - - -static SLONG MixSurroundInterp(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) -{ - SWORD sample; - - for (; todo; todo--) - { - sample = (srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + - (srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS; - index += increment; - - *dest++ += lvolsel * sample; - *dest++ -= lvolsel * sample; - } - - return index; -} - - -static SLONG MixMonoNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - SWORD sample; - - for(; todo; todo--) - { - sample = srce[index >> FRACBITS]; - index += increment; - - *dest++ += lvolsel * sample; - } - - return index; -} - - -static SLONG MixMonoInterp(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) -{ - SWORD sample; - - for(; todo; todo--) - { - sample = (srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + - (srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS; - index += increment; - - *dest++ += lvolsel * sample; - } - - return index; -} - - -#endif -#endif - -static void (*MixReverb)(SLONG *srce, SLONG count); - -static void MixReverb_Normal(SLONG *srce, SLONG count) -{ - unsigned int speedup; - int ReverbPct; - unsigned int loc1, loc2, loc3, loc4; -#ifndef __FAST_REVERB__ - unsigned int loc5, loc6, loc7, loc8; - - ReverbPct = 58 + (md_reverb*4); -#else - ReverbPct = 89 + (md_reverb*2); -#endif +/* For Stereo only (Right Channel) */ +static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL, + *RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL; - loc1 = RVRindex % RVc1; - loc2 = RVRindex % RVc2; - loc3 = RVRindex % RVc3; - loc4 = RVRindex % RVc4; -#ifndef __FAST_REVERB__ - loc5 = RVRindex % RVc5; - loc6 = RVRindex % RVc6; - loc7 = RVRindex % RVc7; - loc8 = RVRindex % RVc8; -#endif - - for(; count; count--) - { - /* Compute the LEFT CHANNEL echo buffers! */ - - speedup = *srce >> 3; - - RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); - RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); - RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); - RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); -#ifndef __FAST_REVERB__ - RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); - RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); - RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); - RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); -#endif - - /* Prepare to compute actual finalized data! */ - - RVRindex++; - loc1 = RVRindex % RVc1; - loc2 = RVRindex % RVc2; - loc3 = RVRindex % RVc3; - loc4 = RVRindex % RVc4; -#ifndef __FAST_REVERB__ - loc5 = RVRindex % RVc5; - loc6 = RVRindex % RVc6; - loc7 = RVRindex % RVc7; - loc8 = RVRindex % RVc8; -#endif - /* Left Channel! */ - -#ifdef __FAST_REVERB__ - *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4]; +#ifdef NATIVE_64BIT_INT +#define NATIVE SLONGLONG #else - *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + - RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]; +#define NATIVE SLONG #endif - } -} +/*========== 32 bit sample mixers - only for 32 bit platforms */ +#ifndef NATIVE_64BIT_INT -static void MixReverb_Stereo(SLONG *srce, SLONG count) +static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) { - unsigned int speedup; - int ReverbPct; - unsigned int loc1, loc2, loc3, loc4; -#ifndef __FAST_REVERB__ - unsigned int loc5, loc6, loc7, loc8; + SWORD sample; - ReverbPct = 63 + (md_reverb*4); -#else - ReverbPct = 92 + (md_reverb*2); -#endif - - loc1 = RVRindex % RVc1; - loc2 = RVRindex % RVc2; - loc3 = RVRindex % RVc3; - loc4 = RVRindex % RVc4; -#ifndef __FAST_REVERB__ - loc5 = RVRindex % RVc5; - loc6 = RVRindex % RVc6; - loc7 = RVRindex % RVc7; - loc8 = RVRindex % RVc8; -#endif - - for(; count; count--) - { - /* Compute the LEFT CHANNEL echo buffers! */ - - speedup = *srce >> 3; - - RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); - RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); - RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); - RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); -#ifndef __FAST_REVERB__ - RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); - RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); - RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); - RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); -#endif - - /* Compute the RIGHT CHANNEL echo buffers! */ - - speedup = srce[1] >> 3; - - RVbuf9[loc1] = speedup + ((ReverbPct * RVbuf9[loc1]) / 128); - RVbuf10[loc2] = speedup + ((ReverbPct * RVbuf11[loc2]) / 128); - RVbuf11[loc3] = speedup + ((ReverbPct * RVbuf12[loc3]) / 128); - RVbuf12[loc4] = speedup + ((ReverbPct * RVbuf12[loc4]) / 128); -#ifndef __FAST_REVERB__ - RVbuf13[loc5] = speedup + ((ReverbPct * RVbuf13[loc5]) / 128); - RVbuf14[loc6] = speedup + ((ReverbPct * RVbuf14[loc6]) / 128); - RVbuf15[loc7] = speedup + ((ReverbPct * RVbuf15[loc7]) / 128); - RVbuf16[loc8] = speedup + ((ReverbPct * RVbuf16[loc8]) / 128); -#endif + while(todo--) { + sample = srce[index >> FRACBITS]; + index += increment; - /* Prepare to compute actual finalized data! */ - - RVRindex++; - loc1 = RVRindex % RVc1; - loc2 = RVRindex % RVc2; - loc3 = RVRindex % RVc3; - loc4 = RVRindex % RVc4; -#ifndef __FAST_REVERB__ - loc5 = RVRindex % RVc5; - loc6 = RVRindex % RVc6; - loc7 = RVRindex % RVc7; - loc8 = RVRindex % RVc8; -#endif - -#ifdef __FAST_REVERB__ - /* Left Channel then right channel! */ - *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4]; - *srce++ += RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4]; -#else - /* Left Channel then right channel! */ - *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + - RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]; - - *srce++ += RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4] + - RVbuf13[loc5] - RVbuf14[loc6] + RVbuf15[loc7] - RVbuf16[loc8]; -#endif - } + *dest++ += vnf->lvolsel * sample; + } + return index; } - -static void Mix32To16(SWORD *dste, SLONG *srce, SLONG count) +static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) { - SLONG x1, x2, x3, x4; - int remain; - - remain = count & 3; - - for(count>>=2; count; count--) - { x1 = *srce++ >> BITSHIFT; - x2 = *srce++ >> BITSHIFT; - x3 = *srce++ >> BITSHIFT; - x4 = *srce++ >> BITSHIFT; - -#ifdef BOUNDS_CHECKING - x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; - x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; - x3 = (x3 > 32767) ? 32767 : (x3 < -32768) ? -32768 : x3; - x4 = (x4 > 32767) ? 32767 : (x4 < -32768) ? -32768 : x4; -#endif + SWORD sample; - *dste++ = x1; - *dste++ = x2; - *dste++ = x3; - *dste++ = x4; - } + while(todo--) { + sample=srce[index >> FRACBITS]; + index += increment; - for(; remain; remain--) - { x1 = *srce++ >> BITSHIFT; -#ifdef BOUNDS_CHECKING - x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; -#endif - *dste++ = x1; - } + *dest++ += vnf->lvolsel * sample; + *dest++ += vnf->rvolsel * sample; + } + return index; } - -static void Mix32To8(SBYTE *dste, SLONG *srce, SLONG count) +static SLONG Mix32SurroundNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) { - int x1, x2, x3, x4; - int remain; - - remain = count & 3; - - for(count>>=2; count; count--) - { x1 = *srce++ >> (BITSHIFT + 8); - x2 = *srce++ >> (BITSHIFT + 8); - x3 = *srce++ >> (BITSHIFT + 8); - x4 = *srce++ >> (BITSHIFT + 8); - -#ifdef BOUNDS_CHECKING - x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; - x2 = (x2 > 127) ? 127 : (x2 < -128) ? -128 : x2; - x3 = (x3 > 127) ? 127 : (x3 < -128) ? -128 : x3; - x4 = (x4 > 127) ? 127 : (x4 < -128) ? -128 : x4; -#endif + SWORD sample; - *dste++ = x1 + 128; - *dste++ = x2 + 128; - *dste++ = x3 + 128; - *dste++ = x4 + 128; - } + while(todo--) { + sample = srce[index >> FRACBITS]; + index += increment; - for(; remain; remain--) - { x1 = *srce++ >> (BITSHIFT + 8); -#ifdef BOUNDS_CHECKING - x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; -#endif - *dste++ = x1 + 128; - } + if(vnf->lvolsel>=vnf->rvolsel) { + *dest++ += vnf->lvolsel*sample; + *dest++ -= vnf->lvolsel*sample; + } else { + *dest++ -= vnf->rvolsel*sample; + *dest++ += vnf->rvolsel*sample; + } + } + return index; } - -static ULONG samples2bytes(ULONG samples) +static SLONG Mix32MonoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) { - if(vc_mode & DMODE_16BITS) samples <<= 1; - if(vc_mode & DMODE_STEREO) samples <<= 1; - return samples; -} + SLONG sample; + while(todo--) { + sample=(SLONG)srce[index>>FRACBITS]+ + ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) + *(index&FRACMASK)>>FRACBITS); + index += increment; -static ULONG bytes2samples(ULONG bytes) -{ - if(vc_mode & DMODE_16BITS) bytes >>= 1; - if(vc_mode & DMODE_STEREO) bytes >>= 1; - return bytes; + if(vnf->rampvol) { + *dest++ += (((SLONG)vnf->lvolsel<oldlvol-vnf->lvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + vnf->rampvol--; + } else + *dest++ += vnf->lvolsel * sample; + } + return index; } - -static void AddChannel(SLONG *ptr, SLONG todo) +static SLONG Mix32StereoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) { - SLONG end, done; -#ifdef __FASTMIXER__ - SBYTE *s; -#else - SWORD *s; -#endif - - if((s=Samples[vnf->handle]) == NULL) - { vnf->current = 0; - vnf->active = 0; - return; - } - - while(todo > 0) - { /* update the 'current' index so the sample loops, or - // stops playing if it reached the end of the sample - */ - - if(vnf->flags & SF_REVERSE) - { - /* The sample is playing in reverse */ - - if((vnf->flags & SF_LOOP) && (vnf->current < idxlpos)) - { - /* the sample is looping, and it has - // reached the loopstart index - */ - - if(vnf->flags & SF_BIDI) - { - /* sample is doing bidirectional loops, so 'bounce' - // the current index against the idxlpos - */ - - vnf->current = idxlpos + (idxlpos - vnf->current); - vnf->flags &= ~SF_REVERSE; - vnf->increment = -vnf->increment; - } else - /* normal backwards looping, so set the - // current position to loopend index - */ - - vnf->current = idxlend - (idxlpos-vnf->current); - } else - { - /* the sample is not looping, so check if it reached index 0 */ - - if(vnf->current < 0) - { - /* playing index reached 0, so stop playing this sample */ - - vnf->current = 0; - vnf->active = 0; - break; - } - } - } else - { - /* The sample is playing forward */ - - if((vnf->flags & SF_LOOP) && (vnf->current > idxlend)) - { - /* the sample is looping, so check if - // it reached the loopend index - */ - - if(vnf->flags & SF_BIDI) - { - /* sample is doing bidirectional loops, so 'bounce' - // the current index against the idxlend - */ - - vnf->flags |= SF_REVERSE; - vnf->increment = -vnf->increment; - vnf->current = idxlend - (vnf->current-idxlend); - } else - /* normal backwards looping, so set the - // current position to loopend index - */ - - vnf->current = idxlpos + (vnf->current-idxlend); - } else - { - /* sample is not looping, so check - // if it reached the last position - */ - - if(vnf->current > idxsize) - { - /* yes, so stop playing this sample */ - - vnf->current = 0; - vnf->active = 0; - break; - } - } - } - - end = (vnf->flags & SF_REVERSE) ? - (vnf->flags & SF_LOOP) ? idxlpos : 0 : - (vnf->flags & SF_LOOP) ? idxlend : idxsize; - - done = MIN((end - vnf->current) / vnf->increment + 1, todo); - - if(!done) - { vnf->active = 0; - break; - } - - if(vnf->vol) - { -#ifdef __ASSEMBLY__ - if(md_mode & DMODE_INTERP) - { if(vc_mode & DMODE_STEREO) - if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) - AsmSurroundInterp(s,ptr,vnf->current,vnf->increment,done); - else - AsmStereoInterp(s,ptr,vnf->current,vnf->increment,done); - else - AsmMonoInterp(s,ptr,vnf->current,vnf->increment,done); - } else if(vc_mode & DMODE_STEREO) - if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) - AsmSurroundNormal(s,ptr,vnf->current,vnf->increment,done); - else - AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done); - else - AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done); - - vnf->current += (vnf->increment*done); -#else - if((md_mode & DMODE_INTERP)) - { if(vc_mode & DMODE_STEREO) - if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) - vnf->current = MixSurroundInterp(s,ptr,vnf->current,vnf->increment,done); - else - vnf->current = MixStereoInterp(s,ptr,vnf->current,vnf->increment,done); - else - vnf->current = MixMonoInterp(s,ptr,vnf->current,vnf->increment,done); - } else if(vc_mode & DMODE_STEREO) - if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) - vnf->current = MixSurroundNormal(s,ptr,vnf->current,vnf->increment,done); - else - vnf->current = MixStereoNormal(s,ptr,vnf->current,vnf->increment,done); - else - vnf->current = MixMonoNormal(s,ptr,vnf->current,vnf->increment,done); -#endif - } - - todo -= done; - ptr += (vc_mode & DMODE_STEREO) ? (done<<1) : done; - } - -} + SLONG sample; + while(todo--) { + sample=(SLONG)srce[index>>FRACBITS]+ + ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) + *(index&FRACMASK)>>FRACBITS); + index += increment; -void VC_WriteSamples(SBYTE *buf, ULONG todo) -{ - int left, portion = 0, count; - SBYTE *buffer; - int t; - int pan, vol; - - while(todo) - { if(TICKLEFT==0) - { if(vc_mode & DMODE_SOFT_MUSIC) md_player(); - TICKLEFT = (md_mixfreq * 125l) / (md_bpm * 50L); - } - - left = MIN(TICKLEFT, todo); - - buffer = buf; - TICKLEFT -= left; - todo -= left; - - buf += samples2bytes(left); - - while(left) - { portion = MIN(left, samplesthatfit); - count = (vc_mode & DMODE_STEREO) ? (portion<<1) : portion; - - memset(VC_TICKBUF, 0, count<<2); - - for(t=0; tkick) - { vnf->current = vnf->start << FRACBITS; - vnf->kick = 0; - vnf->active = 1; - } - - if((vnf->frq == 0) || (vnf->size == 0)) vnf->active = 0; - - if(vnf->active) - { vnf->increment = (vnf->frq << FRACBITS) / md_mixfreq; - if(vnf->flags & SF_REVERSE) vnf->increment =- vnf->increment; - vol = vnf->vol; pan = vnf->pan; - - if(vc_mode & DMODE_STEREO) - { if(pan != PAN_SURROUND) - { -#ifdef __FASTMIXER__ - lvoltab = voltab[(vol * (255-pan)) / 1024]; - rvoltab = voltab[(vol * pan) / 1024]; -#else - lvolsel = (vol * (255-pan)) >> 8; - rvolsel = (vol * pan) >> 8; -#endif - } else - { -#ifdef __FASTMIXER__ - lvoltab = voltab[(vol+1)>>3]; -#else - lvolsel = vol/2; -#endif - } - } else - { -#ifdef __FASTMIXER__ - lvoltab = voltab[vol>>2]; -#else - lvolsel = vol; -#endif - } - - idxsize = (vnf->size) ? (vnf->size << FRACBITS)-1 : 0; - idxlend = (vnf->repend) ? (vnf->repend << FRACBITS)-1 : 0; - idxlpos = vnf->reppos << FRACBITS; - AddChannel(VC_TICKBUF, portion); - } - } - - if(md_reverb) MixReverb(VC_TICKBUF, portion); - - if(vc_mode & DMODE_16BITS) - Mix32To16((SWORD *) buffer, VC_TICKBUF, count); - else - Mix32To8((SBYTE *) buffer, VC_TICKBUF, count); - - buffer += samples2bytes(portion); - left -= portion; - } - } + if(vnf->rampvol) { + *dest++ += (((SLONG)vnf->lvolsel<oldlvol-vnf->lvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + *dest++ += (((SLONG)vnf->rvolsel<oldrvol-vnf->rvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + vnf->rampvol--; + } else { + *dest++ += vnf->lvolsel * sample; + *dest++ += vnf->rvolsel * sample; + } + } + return index; } - -void VC_SilenceBytes(SBYTE *buf, ULONG todo) - -/* Fill the buffer with 'todo' bytes of silence (it depends on the mixing -// mode how the buffer is filled) -*/ - +static SLONG Mix32SurroundInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo) { - /* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */ - - if(vc_mode & DMODE_16BITS) - memset(buf,0,todo); - else - memset(buf,0x80,todo); -} - + SLONG sample; -ULONG VC_WriteBytes(SBYTE *buf, ULONG todo) + while(todo--) { + int oldvol,vol; -/* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of -// SBYTES actually written to 'buf' (which is rounded to number of samples -// that fit into 'todo' bytes). -*/ - -{ - if(vc_softchn == 0) - { VC_SilenceBytes(buf,todo); - return todo; - } + sample=(SLONG)srce[index>>FRACBITS]+ + ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) + *(index&FRACMASK)>>FRACBITS); + index += increment; - todo = bytes2samples(todo); - VC_WriteSamples(buf,todo); + if(vnf->lvolsel>=vnf->rvolsel) { + vol=vnf->lvolsel;oldvol=vnf->oldlvol; + } else { + vol=vnf->rvolsel;oldvol=vnf->oldrvol; + } - return samples2bytes(todo); + if(vnf->rampvol) { + sample=(((SLONG)vnf->lvolsel<oldlvol-vnf->lvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + *dest++ += sample; + *dest++ -= sample; + vnf->rampvol--; + } else { + *dest++ += vol*sample; + *dest++ -= vol*sample; + } + } + return index; } - - -BOOL VC_Init(void) -{ - -#ifdef __FASTMIXER__ - int t; - - _mm_errno = MMERR_INITIALIZING_MIXER; - if((voltab = (SLONG **)calloc(65,sizeof(SLONG *))) == NULL) return 1; - for(t=0; t<65; t++) - if((voltab[t] = (SLONG *)calloc(256,sizeof(SLONG))) == NULL) return 1; - - if((Samples = (SBYTE **)calloc(MAXSAMPLEHANDLES, sizeof(SBYTE *))) == NULL) return 1; -#else - _mm_errno = MMERR_INITIALIZING_MIXER; - if((Samples = (SWORD **)calloc(MAXSAMPLEHANDLES, sizeof(SWORD *))) == NULL) return 1; #endif - if(VC_TICKBUF==NULL) if((VC_TICKBUF=(SLONG *)malloc((TICKLSIZE+32) * sizeof(SLONG))) == NULL) return 1; - - MixReverb = (md_mode & DMODE_STEREO) ? MixReverb_Stereo : MixReverb_Normal; - - vc_mode = md_mode; +/*========== 64 bit sample mixers - all platforms */ - _mm_errno = 0; - return 0; -} - - -void VC_Exit(void) -{ -#ifdef __FASTMIXER__ - int t; - if(voltab!=NULL) - { for(t=0; t<65; t++) if(voltab[t]!=NULL) free(voltab[t]); - free(voltab); voltab = NULL; - } -#endif - - if(vinf!=NULL) free(vinf); - if(Samples!=NULL) free(Samples); - - vinf = NULL; - Samples = NULL; -} - - -BOOL VC_PlayStart(void) +static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) { - int numchn; - - numchn = md_softchn; -#ifdef __FASTMIXER__ - if(numchn > 0) - { - int c, t; - SLONG volmul; - - for(t=0; t<65; t++) - { volmul = (65536l*t) / 64; - for(c=-128; c<128; c++) - voltab[t][(UBYTE)c] = (SLONG)c*volmul; - } - } -#endif - - samplesthatfit = TICKLSIZE; - if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; - TICKLEFT = 0; - -#ifdef __FAST_REVERB__ - RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 2); - RVc2 = (5946L * md_mixfreq) / (REVERBERATION * 2); - RVc3 = (7071L * md_mixfreq) / (REVERBERATION * 2); - RVc4 = (8409L * md_mixfreq) / (REVERBERATION * 2); -#else - RVc1 = (5000L * md_mixfreq) / REVERBERATION; - RVc2 = (5078L * md_mixfreq) / REVERBERATION; - RVc3 = (5313L * md_mixfreq) / REVERBERATION; - RVc4 = (5703L * md_mixfreq) / REVERBERATION; - RVc5 = (6250L * md_mixfreq) / REVERBERATION; - RVc6 = (6953L * md_mixfreq) / REVERBERATION; - RVc7 = (7813L * md_mixfreq) / REVERBERATION; - RVc8 = (8828L * md_mixfreq) / REVERBERATION; -#endif - - if((RVbuf1 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf2 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf3 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf4 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; -#ifndef __FAST_REVERB__ - if((RVbuf5 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf6 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf7 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf8 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; -#endif - - if((RVbuf9 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf10 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf11 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf12 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; -#ifndef __FAST_REVERB__ - if((RVbuf13 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf14 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf15 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; - if((RVbuf16 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; -#endif + SWORD sample; - RVRindex = 0; + while(todo--) { + sample = srce[index >> FRACBITS]; + index += increment; - return 0; + *dest++ += vnf->lvolsel * sample; + } + return index; } - -void VC_PlayStop(void) +static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) { - if(RVbuf1 != NULL) free(RVbuf1); - if(RVbuf2 != NULL) free(RVbuf2); - if(RVbuf3 != NULL) free(RVbuf3); - if(RVbuf4 != NULL) free(RVbuf4); - if(RVbuf9 != NULL) free(RVbuf9); - if(RVbuf10 != NULL) free(RVbuf10); - if(RVbuf11 != NULL) free(RVbuf11); - if(RVbuf12 != NULL) free(RVbuf12); - - RVbuf1 = RVbuf2 = RVbuf3 = RVbuf4 = NULL; - RVbuf9 = RVbuf10 = RVbuf11 = RVbuf12 = NULL; - -#ifndef __FAST_REVERB__ - if(RVbuf5 != NULL) free(RVbuf5); - if(RVbuf6 != NULL) free(RVbuf6); - if(RVbuf7 != NULL) free(RVbuf7); - if(RVbuf8 != NULL) free(RVbuf8); - if(RVbuf13 != NULL) free(RVbuf13); - if(RVbuf14 != NULL) free(RVbuf14); - if(RVbuf15 != NULL) free(RVbuf15); - if(RVbuf16 != NULL) free(RVbuf16); - - RVbuf13 = RVbuf14 = RVbuf15 = RVbuf16 = NULL; - RVbuf5 = RVbuf6 = RVbuf7 = RVbuf8 = NULL; -#endif - -} + SWORD sample; + while(todo--) { + sample=srce[index >> FRACBITS]; + index += increment; + + *dest++ += vnf->lvolsel * sample; + *dest++ += vnf->rvolsel * sample; + } + return index; +} + +static SLONGLONG MixSurroundNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) +{ + SWORD sample; + + while(todo--) { + sample = srce[index >> FRACBITS]; + index += increment; -BOOL VC_SetNumVoices(void) -{ - int t; - - if((vc_softchn = md_softchn) == 0) return 0; - - if(vinf!=NULL) free(vinf); - if((vinf = _mm_calloc(sizeof(VINFO),vc_softchn)) == NULL) return 1; - - for(t=0; tlvolsel>=vnf->rvolsel) { + *dest++ += vnf->lvolsel*sample; + *dest++ -= vnf->lvolsel*sample; + } else { + *dest++ -= vnf->rvolsel*sample; + *dest++ += vnf->rvolsel*sample; + } + } + return index; } - -void VC_VoiceSetVolume(UBYTE voice, UWORD vol) +static SLONGLONG MixMonoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) { - vinf[voice].vol = vol; -} + SLONG sample; + while(todo--) { + sample=(SLONG)srce[index>>FRACBITS]+ + ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) + *(index&FRACMASK)>>FRACBITS); + index += increment; -void VC_VoiceSetFrequency(UBYTE voice, ULONG frq) -{ - vinf[voice].frq = frq; + if(vnf->rampvol) { + *dest++ += (((SLONG)vnf->lvolsel<oldlvol-vnf->lvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + vnf->rampvol--; + } else + *dest++ += vnf->lvolsel * sample; + } + return index; } - -void VC_VoiceSetPanning(UBYTE voice, ULONG pan) +static SLONGLONG MixStereoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) { - vinf[voice].pan = pan; -} + SLONG sample; + while(todo--) { + sample=(SLONG)srce[index>>FRACBITS]+ + ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) + *(index&FRACMASK)>>FRACBITS); + index += increment; -void VC_VoicePlay(UBYTE voice, SWORD handle, ULONG start, ULONG size, ULONG reppos, ULONG repend, UWORD flags) -{ - vinf[voice].flags = flags; - vinf[voice].handle = handle; - vinf[voice].start = start; - vinf[voice].size = size; - vinf[voice].reppos = reppos; - vinf[voice].repend = repend; - vinf[voice].kick = 1; + if(vnf->rampvol) { + *dest++ +=(((SLONG)vnf->lvolsel<oldlvol-vnf->lvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + *dest++ +=(((SLONG)vnf->rvolsel<oldrvol-vnf->rvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + vnf->rampvol--; + } else { + *dest++ += vnf->lvolsel * sample; + *dest++ += vnf->rvolsel * sample; + } + } + return index; } - -void VC_VoiceStop(UBYTE voice) -{ - vinf[voice].active = 0; -} - - -BOOL VC_VoiceStopped(UBYTE voice) +static SLONGLONG MixSurroundInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo) { - return(vinf[voice].active==0); -} - + SLONG sample; -void VC_VoiceReleaseSustain(UBYTE voice) -{ + while(todo--) { + int oldvol,vol; -} + sample=(SLONG)srce[index>>FRACBITS]+ + ((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS]) + *(index&FRACMASK)>>FRACBITS); + index += increment; + if(vnf->lvolsel>=vnf->rvolsel) { + vol=vnf->lvolsel;oldvol=vnf->oldlvol; + } else { + vol=vnf->rvolsel;oldvol=vnf->oldrvol; + } -SLONG VC_VoiceGetPosition(UBYTE voice) -{ - return(vinf[voice].current >> FRACBITS); + if(vnf->rampvol) { + sample=(((SLONG)vnf->lvolsel<oldlvol-vnf->lvolsel)*vnf->rampvol + )*sample>>CLICK_SHIFT; + *dest++ += sample; + *dest++ -= sample; + vnf->rampvol--; + } else { + *dest++ += vol*sample; + *dest++ -= vol*sample; + } + } + return index; } +static void (*MixReverb)(SLONG* srce,NATIVE count); -/************************************************** -*************************************************** -*************************************************** -**************************************************/ - - -void VC_SampleUnload(SWORD handle) -{ - free(Samples[handle]); - Samples[handle] = NULL; -} - +/* Reverb macros */ +#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n +#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7) +#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7) -SWORD VC_SampleLoad(SAMPLOAD *sload, int type) +static void MixReverb_Normal(SLONG* srce,NATIVE count) { - SAMPLE *s = sload->sample; - int handle; - ULONG t, length,loopstart,loopend; - - if(type==MD_HARDWARE) return -1; - - /* Find empty slot to put sample address in */ - - for(handle=0; handlelength; - loopstart = s->loopstart; - loopend = s->loopend; - - SL_SampleSigned(sload); + unsigned int speedup; + int ReverbPct; + unsigned int loc1,loc2,loc3,loc4; + unsigned int loc5,loc6,loc7,loc8; -#ifdef __FASTMIXER__ - SL_Sample16to8(sload); - if((Samples[handle]=(SBYTE *)malloc(length+20))==NULL) - { _mm_errno = MMERR_SAMPLE_TOO_BIG; - return -1; - } + ReverbPct=58+(md_reverb<<2); - /* read sample into buffer. */ - SL_Load(Samples[handle],sload,length); -#else - SL_Sample8to16(sload); - if((Samples[handle]=(SWORD *)malloc((length+20)<<1))==NULL) - { _mm_errno = MMERR_SAMPLE_TOO_BIG; - return -1; - } - - /* read sample into buffer. */ - SL_Load(Samples[handle],sload,length); -#endif + COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); + COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); + while(count--) { + /* Compute the left channel echo buffers */ + speedup = *srce >> 3; - /* Unclick samples: */ + COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4); + COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8); - if(s->flags & SF_LOOP) - { if(s->flags & SF_BIDI) - for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][(loopend-t)-1]; - else - for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][t+loopstart]; - } else - for(t=0; t<16; t++) Samples[handle][t+length] = 0; - - return handle; -} + /* Prepare to compute actual finalized data */ + RVRindex++; + COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); + COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); -ULONG VC_SampleSpace(int type) -{ - return vc_memory; + /* left channel */ + *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+ + RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8]; + } } - -ULONG VC_SampleLength(int type, SAMPLE *s) +static void MixReverb_Stereo(SLONG* srce,NATIVE count) { -#ifdef __FASTMIXER__ - return s->length + 16; -#else - return (s->length * ((s->flags&SF_16BITS) ? 2 : 1)) + 16; -#endif -} - + unsigned int speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4; + unsigned int loc5, loc6, loc7, loc8; -/************************************************** -*************************************************** -*************************************************** -**************************************************/ + ReverbPct = 92+(md_reverb<<1); + COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); + COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); -ULONG VC_VoiceRealVolume(UBYTE voice) -{ - ULONG i,s,size; - int k,j; -#ifdef __FASTMIXER__ - SBYTE *smp; -#else - SWORD *smp; -#endif - SLONG t; - - t = vinf[voice].current>>FRACBITS; - if(vinf[voice].active==0) return 0; - - s = vinf[voice].handle; - size = vinf[voice].size; + while(count--) { + /* Compute the left channel echo buffers */ + speedup = *srce >> 3; - i=64; t-=64; k=0; j=0; - if(i>size) i = size; - if(t<0) t = 0; - if(t+i > size) t = size-i; + COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4); + COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8); - i &= ~1; /* make sure it's EVEN. */ + /* Compute the right channel echo buffers */ + speedup = srce[1] >> 3; - smp = &Samples[s][t]; - for(; i; i--, smp++) - { if(k<*smp) k = *smp; - if(j>*smp) j = *smp; - } + COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4); + COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8); -#ifdef __FASTMIXER__ - k = abs(k-j)<<8; -#else - k = abs(k-j); -#endif + /* Prepare to compute actual finalized data */ + RVRindex++; - return k; + COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4); + COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8); + + /* left channel then right channel */ + *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+ + RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8]; + + *srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+ + RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8]; + } +} + +/* Mixing macros */ +#define EXTRACT_SAMPLE(var,size) var=*srce++>>(BITSHIFT+16-size) +#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var +#define PUT_SAMPLE(var) *dste++=var + +static void Mix32To16(SWORD* dste,SLONG* srce,NATIVE count) +{ + SLONG x1,x2,x3,x4; + int remain; + + remain=count&3; + for(count>>=2;count;count--) { + EXTRACT_SAMPLE(x1,16); EXTRACT_SAMPLE(x2,16); + EXTRACT_SAMPLE(x3,16); EXTRACT_SAMPLE(x4,16); + + CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768); + CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768); + + PUT_SAMPLE(x1); PUT_SAMPLE(x2); PUT_SAMPLE(x3); PUT_SAMPLE(x4); + } + while(remain--) { + EXTRACT_SAMPLE(x1,16); + CHECK_SAMPLE(x1,32768); + PUT_SAMPLE(x1); + } +} + +static void Mix32To8(SBYTE* dste,SLONG* srce,NATIVE count) +{ + SWORD x1,x2,x3,x4; + int remain; + + remain=count&3; + for(count>>=2;count;count--) { + EXTRACT_SAMPLE(x1,8); EXTRACT_SAMPLE(x2,8); + EXTRACT_SAMPLE(x3,8); EXTRACT_SAMPLE(x4,8); + + CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128); + CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128); + + PUT_SAMPLE(x1+128); PUT_SAMPLE(x2+128); + PUT_SAMPLE(x3+128); PUT_SAMPLE(x4+128); + } + while(remain--) { + EXTRACT_SAMPLE(x1,8); + CHECK_SAMPLE(x1,128); + PUT_SAMPLE(x1+128); + } +} + +static void AddChannel(SLONG* ptr,NATIVE todo) +{ + SLONGLONG end,done; + SWORD *s; + + if(!(s=Samples[vnf->handle])) { + vnf->current = vnf->active = 0; + return; + } + + /* update the 'current' index so the sample loops, or stops playing if it + reached the end of the sample */ + while(todo>0) { + SLONGLONG endpos; + + if(vnf->flags & SF_REVERSE) { + /* The sample is playing in reverse */ + if((vnf->flags&SF_LOOP)&&(vnf->currentflags & SF_BIDI) { + /* sample is doing bidirectional loops, so 'bounce' the + current index against the idxlpos */ + vnf->current = idxlpos+(idxlpos-vnf->current); + vnf->flags &= ~SF_REVERSE; + vnf->increment = -vnf->increment; + } else + /* normal backwards looping, so set the current position to + loopend index */ + vnf->current=idxlend-(idxlpos-vnf->current); + } else { + /* the sample is not looping, so check if it reached index 0 */ + if(vnf->current < 0) { + /* playing index reached 0, so stop playing this sample */ + vnf->current = vnf->active = 0; + break; + } + } + } else { + /* The sample is playing forward */ + if((vnf->flags & SF_LOOP) && (vnf->current >= idxlend)) { + /* the sample is looping, check the loopend index */ + if(vnf->flags & SF_BIDI) { + /* sample is doing bidirectional loops, so 'bounce' the + current index against the idxlend */ + vnf->flags |= SF_REVERSE; + vnf->increment = -vnf->increment; + vnf->current = idxlend-(vnf->current-idxlend); + } else + /* normal backwards looping, so set the current position + to loopend index */ + vnf->current=idxlpos+(vnf->current-idxlend); + } else { + /* sample is not looping, so check if it reached the last + position */ + if(vnf->current >= idxsize) { + /* yes, so stop playing this sample */ + vnf->current = vnf->active = 0; + break; + } + } + } + + end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0: + (vnf->flags&SF_LOOP)?idxlend:idxsize; + + /* if the sample is not blocked... */ + if((end==vnf->current)||(!vnf->increment)) + done=0; + else { + done=MIN((end-vnf->current)/vnf->increment+1,todo); + if(done<0) done=0; + } + + if(!done) { + vnf->active = 0; + break; + } + + endpos=vnf->current+done*vnf->increment; + + if(vnf->vol) { +#ifndef NATIVE_64BIT_INT + /* use the 32 bit mixers as often as we can (they're much faster) */ + if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) { + if((md_mode & DMODE_INTERP)) { + if(vc_mode & DMODE_STEREO) { + if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND)) + vnf->current=Mix32SurroundInterp + (s,ptr,vnf->current,vnf->increment,done); + else + vnf->current=Mix32StereoInterp + (s,ptr,vnf->current,vnf->increment,done); + } else + vnf->current=Mix32MonoInterp + (s,ptr,vnf->current,vnf->increment,done); + } else if(vc_mode & DMODE_STEREO) { + if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND)) + vnf->current=Mix32SurroundNormal + (s,ptr,vnf->current,vnf->increment,done); + else + vnf->current=Mix32StereoNormal + (s,ptr,vnf->current,vnf->increment,done); + } else + vnf->current=Mix32MonoNormal + (s,ptr,vnf->current,vnf->increment,done); + } else +#endif + { + if((md_mode & DMODE_INTERP)) { + if(vc_mode & DMODE_STEREO) { + if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND)) + vnf->current=MixSurroundInterp + (s,ptr,vnf->current,vnf->increment,done); + else + vnf->current=MixStereoInterp + (s,ptr,vnf->current,vnf->increment,done); + } else + vnf->current=MixMonoInterp + (s,ptr,vnf->current,vnf->increment,done); + } else if(vc_mode & DMODE_STEREO) { + if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND)) + vnf->current=MixSurroundNormal + (s,ptr,vnf->current,vnf->increment,done); + else + vnf->current=MixStereoNormal + (s,ptr,vnf->current,vnf->increment,done); + } else + vnf->current=MixMonoNormal + (s,ptr,vnf->current,vnf->increment,done); + } + } else + /* update sample position */ + vnf->current=endpos; + + todo-=done; + ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done; + } +} + +#define _IN_VIRTCH_ +#include "virtch_common.c" +#undef _IN_VIRTCH_ + +void VC1_WriteSamples(SBYTE* buf,ULONG todo) +{ + int left,portion=0,count; + SBYTE *buffer; + int t, pan, vol; + + while(todo) { + if(!tickleft) { + if(vc_mode & DMODE_SOFT_MUSIC) md_player(); + tickleft=(md_mixfreq*125L)/(md_bpm*50L); + } + left = MIN(tickleft, todo); + buffer = buf; + tickleft -= left; + todo -= left; + buf += samples2bytes(left); + + while(left) { + portion = MIN(left, samplesthatfit); + count = (vc_mode & DMODE_STEREO)?(portion<<1):portion; + memset(vc_tickbuf, 0, count<<2); + for(t=0;tkick) { + vnf->current=((SLONGLONG)vnf->start)<kick =0; + vnf->active =1; + } + + if(!vnf->frq) vnf->active = 0; + + if(vnf->active) { + vnf->increment=((SLONGLONG)(vnf->frq<flags&SF_REVERSE) vnf->increment=-vnf->increment; + vol = vnf->vol; pan = vnf->pan; + + vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel; + if(vc_mode & DMODE_STEREO) { + if(pan != PAN_SURROUND) { + vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8; + vnf->rvolsel=(vol*pan)>>8; + } else + vnf->lvolsel=vnf->rvolsel=vol/2; + } else + vnf->lvolsel=vol; + + idxsize = (vnf->size)? ((SLONGLONG)vnf->size << FRACBITS)-1 : 0; + idxlend = (vnf->repend)? ((SLONGLONG)vnf->repend << FRACBITS)-1 : 0; + idxlpos = (SLONGLONG)vnf->reppos << FRACBITS; + AddChannel(vc_tickbuf, portion); + } + } + + if(md_reverb) { + if(md_reverb>15) md_reverb=15; + MixReverb(vc_tickbuf, portion); + } + + if(vc_mode & DMODE_16BITS) + Mix32To16((SWORD*) buffer, vc_tickbuf, count); + else + Mix32To8((SBYTE*) buffer, vc_tickbuf, count); + + buffer += samples2bytes(portion); + left -= portion; + } + } +} + +BOOL VC1_Init(void) +{ + VC_SetupPointers(); + + if (md_mode&DMODE_HQMIXER) + return VC2_Init(); + + if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) { + _mm_errno = MMERR_INITIALIZING_MIXER; + return 1; + } + if(!vc_tickbuf) + if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) { + _mm_errno = MMERR_INITIALIZING_MIXER; + return 1; + } + + MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal; + vc_mode = md_mode; + return 0; +} + +BOOL VC1_PlayStart(void) +{ + samplesthatfit=TICKLSIZE; + if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; + tickleft = 0; + + RVc1 = (5000L * md_mixfreq) / REVERBERATION; + RVc2 = (5078L * md_mixfreq) / REVERBERATION; + RVc3 = (5313L * md_mixfreq) / REVERBERATION; + RVc4 = (5703L * md_mixfreq) / REVERBERATION; + RVc5 = (6250L * md_mixfreq) / REVERBERATION; + RVc6 = (6953L * md_mixfreq) / REVERBERATION; + RVc7 = (7813L * md_mixfreq) / REVERBERATION; + RVc8 = (8828L * md_mixfreq) / REVERBERATION; + + if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1; + if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1; + if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1; + if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1; + if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1; + if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1; + if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1; + if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1; + + if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1; + if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1; + if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1; + if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1; + if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1; + if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1; + if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1; + if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1; + + RVRindex = 0; + return 0; +} + +void VC1_PlayStop(void) +{ + if(RVbufL1) free(RVbufL1); + if(RVbufL2) free(RVbufL2); + if(RVbufL3) free(RVbufL3); + if(RVbufL4) free(RVbufL4); + if(RVbufL5) free(RVbufL5); + if(RVbufL6) free(RVbufL6); + if(RVbufL7) free(RVbufL7); + if(RVbufL8) free(RVbufL8); + RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL; + if(RVbufR1) free(RVbufR1); + if(RVbufR2) free(RVbufR2); + if(RVbufR3) free(RVbufR3); + if(RVbufR4) free(RVbufR4); + if(RVbufR5) free(RVbufR5); + if(RVbufR6) free(RVbufR6); + if(RVbufR7) free(RVbufR7); + if(RVbufR8) free(RVbufR8); + RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL; +} + +BOOL VC1_SetNumVoices(void) +{ + int t; + + if(!(vc_softchn=md_softchn)) return 0; + + if(vinf) free(vinf); + if(!(vinf= _mm_calloc(sizeof(VINFO),vc_softchn))) return 1; + + for(t=0;t0) ? (SDL_GetTicks() + ticks) : -1; + channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : -1; SDL_mutexV(mixer_lock); ++ status; } @@ -642,7 +643,7 @@ int Mix_FadeOutChannel(int which, int ms) } } else { SDL_mutexP(mixer_lock); - if ( channel[which].playing && channel[which].volume>0 && + if ( channel[which].playing && channel[which].volume>0 && channel[which].fading==MIX_NO_FADING ) { channel[which].fading = MIX_FADING_OUT; @@ -829,7 +830,7 @@ int Mix_GroupOldest(int tag) Uint32 mintime = SDL_GetTicks(); int i; for( i=0; i < num_channels; i ++ ) { - if ( (channel[i].tag==tag || tag==-1) && channel[i].playing > 0 + if ( (channel[i].tag==tag || tag==-1) && channel[i].playing > 0 && channel[i].start_time <= mintime ) { mintime = channel[i].start_time; chan = i; @@ -845,7 +846,7 @@ int Mix_GroupNewer(int tag) Uint32 maxtime = 0; int i; for( i=0; i < num_channels; i ++ ) { - if ( (channel[i].tag==tag || tag==-1) && channel[i].playing > 0 + if ( (channel[i].tag==tag || tag==-1) && channel[i].playing > 0 && channel[i].start_time >= maxtime ) { maxtime = channel[i].start_time; chan = i; diff --git a/mixer.h b/mixer.h new file mode 100644 index 00000000..05b8c739 --- /dev/null +++ b/mixer.h @@ -0,0 +1,225 @@ +/* + MIXERLIB: An audio mixer library based on the SDL library + Copyright (C) 1997-1999 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 + 5635-34 Springhouse Dr. + Pleasanton, CA 94588 (USA) + slouken@devolution.com +*/ + +#ifndef _MIXER_H_ +#define _MIXER_H_ + +#include "SDL_types.h" +#include "SDL_rwops.h" +#include "SDL_audio.h" + +#include + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/* 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 +#define MIX_DEFAULT_FORMAT AUDIO_S16 +#define MIX_DEFAULT_CHANNELS 2 +#define MIX_MAX_VOLUME 128 /* Volume of a chunk */ + +/* The internal format for an audio chunk */ +typedef struct { + 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; + +/* 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 int 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 int 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 int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels); + +/* Load a wave file or a music (.mod .s3m .it .xm) file */ +extern Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc); +#define Mix_LoadWAV(file) Mix_LoadWAV_RW(SDL_RWFromFile(file, "rb"), 1) +extern Mix_Music *Mix_LoadMUS(const char *file); + +/* Load a wave file of the mixer format from a memory buffer */ +extern Mix_Chunk *Mix_QuickLoad_WAV(Uint8 *mem); + +/* Free an audio chunk previously loaded */ +extern void Mix_FreeChunk(Mix_Chunk *chunk); +extern void Mix_FreeMusic(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 void 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 void Mix_HookMusic(void (*mix_func) + (void *udata, Uint8 *stream, int len), void *arg); + +/* Add your own callback when the music has finished playing. + */ +extern void Mix_HookMusicFinished(void (*music_finished)(void)); + +/* Get a pointer to the user data for the current music hook */ +extern void *Mix_GetMusicHookData(void); + +/* 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 int 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 int Mix_GroupChannel(int which, int tag); +/* Assign several consecutive channels to a group */ +extern int Mix_GroupChannels(int from, int to, int tag); +/* Finds the first available channel in a group of channels */ +extern int 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 int Mix_GroupCount(int tag); +/* Finds the "oldest" sample playing in a group of channels */ +extern int Mix_GroupOldest(int tag); +/* Finds the "most recent" (i.e. last) sample playing in a group of channels */ +extern int 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 int Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks); +extern int Mix_PlayMusic(Mix_Music *music, int loops); + +/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */ +extern int Mix_FadeInMusic(Mix_Music *music, int loops, int ms); +#define Mix_FadeInChannel(channel,chunk,loops,ms) Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1) +extern int 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 int Mix_Volume(int channel, int volume); +extern int Mix_VolumeChunk(Mix_Chunk *chunk, int volume); +extern int Mix_VolumeMusic(int volume); + +/* Halt playing of a particular channel */ +extern int Mix_HaltChannel(int channel); +extern int Mix_HaltGroup(int tag); +extern int 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 int 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 int Mix_FadeOutChannel(int which, int ms); +extern int Mix_FadeOutGroup(int tag, int ms); +extern int Mix_FadeOutMusic(int ms); + +/* Query the fading status of a channel */ +extern Mix_Fading Mix_FadingMusic(void); +extern Mix_Fading Mix_FadingChannel(int which); + +/* Pause/Resume a particular channel */ +extern void Mix_Pause(int channel); +extern void Mix_Resume(int channel); +extern int Mix_Paused(int channel); + +/* Pause/Resume the music stream */ +extern void Mix_PauseMusic(void); +extern void Mix_ResumeMusic(void); +extern void Mix_RewindMusic(void); +extern int Mix_PausedMusic(void); + +/* Check the status of a specific channel. + If the specified channel is -1, check all channels. +*/ +extern int Mix_Playing(int channel); +extern int Mix_PlayingMusic(void); + +/* Stop music and set external music playback command */ +extern int Mix_SetMusicCMD(const char *command); + +/* Close the mixer, halting all playing audio */ +extern void 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 + +#endif /* _MIXER_H_ */ diff --git a/music.c b/music.c index 4aab5dd5..f7c82ae6 100644 --- a/music.c +++ b/music.c @@ -26,6 +26,7 @@ #include #include "SDL_endian.h" #include "SDL_audio.h" +#include "SDL_timer.h" #include "mixer.h" @@ -41,7 +42,17 @@ #include "wavestream.h" #endif #ifdef MOD_MUSIC -#include "mikmod.h" +# include "mikmod.h" +# if defined(LIBMIKMOD_VERSION) /* libmikmod 3.1.8 */ +# define UNIMOD MODULE +# define MikMod_Init() MikMod_Init(NULL) +# define MikMod_LoadSong(a,b) Player_Load(a,b,0) +# define MikMod_FreeSong Player_Free + extern int MikMod_errno; +# else /* old MikMod 3.0.3 */ +# define MikMod_strerror(x) _mm_errmsg[x]) +# define MikMod_errno _mm_errno +# endif #endif #ifdef MID_MUSIC #include "timidity.h" @@ -93,7 +104,9 @@ struct _Mix_Music { int fade_steps; int error; }; +#ifdef MID_MUSIC static int timidity_ok; +#endif /* Used to calculate fading steps */ static int ms_per_step; @@ -102,6 +115,18 @@ static int ms_per_step; static void lowlevel_halt(void); static int lowlevel_play(Mix_Music *music); + +/* 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(); +} + + /* Mixing function */ void music_mixer(void *udata, Uint8 *stream, int len) { @@ -113,7 +138,7 @@ void music_mixer(void *udata, Uint8 *stream, int len) the music is always stopped from the sound thread */ lowlevel_halt(); /* This function sets music_playing to NULL */ return; - } + } /* Handle fading */ if ( music_playing->fading != MIX_NO_FADING ) { if ( music_playing->fade_step++ < music_playing->fade_steps ) { @@ -122,7 +147,7 @@ void music_mixer(void *udata, Uint8 *stream, int len) int fade_steps = music_playing->fade_steps; if ( music_playing->fading == MIX_FADING_OUT ) { - Mix_VolumeMusic((fade_volume * (fade_steps-fade_step)) + Mix_VolumeMusic((fade_volume * (fade_steps-fade_step)) / fade_steps); } else { /* Fading in */ Mix_VolumeMusic((fade_volume * fade_step) / fade_steps); @@ -136,8 +161,9 @@ void music_mixer(void *udata, Uint8 *stream, int len) } } /* Restart music if it has to loop */ - if ( music_loops && !Mix_PlayingMusic() ) { - if ( -- music_loops ) { + if ( !Mix_PlayingMusic() ) { + /* Restart music if it has to loop */ + if ( music_loops && --music_loops ) { Mix_RewindMusic(); if ( lowlevel_play(music_playing) < 0 ) { fprintf(stderr,"Warning: Music restart failed.\n"); @@ -145,6 +171,11 @@ void music_mixer(void *udata, Uint8 *stream, int len) music_playing->fading = MIX_NO_FADING; } } + else if (music_finished_hook) { + lowlevel_halt(); + music_finished_hook(); + return; + } } if ( music_volume <= 0 ) { /* Don't mix if volume is null */ return; @@ -264,7 +295,7 @@ int open_music(SDL_AudioSpec *mixer) MikMod_RegisterAllLoaders(); MikMod_RegisterAllDrivers(); if ( MikMod_Init() ) { - Mix_SetError("%s", _mm_errmsg[_mm_errno]); + Mix_SetError("%s", MikMod_strerror(MikMod_errno)); ++music_error; } #endif @@ -376,7 +407,7 @@ Mix_Music *Mix_LoadMUS(const char *file) music->type = MUS_MOD; music->data.module = MikMod_LoadSong((char *)file, 64); if ( music->data.module == NULL ) { - Mix_SetError("%s", _mm_errmsg[_mm_errno]); + Mix_SetError("%s", MikMod_strerror(MikMod_errno)); music->error = 1; } } else @@ -670,12 +701,20 @@ void Mix_RewindMusic(void) { if ( music_playing && !music_stopped ) { switch ( music_playing->type ) { +#ifdef MOD_MUSIC + case MUS_MOD: + Player_Start(music_playing->data.module); + Player_SetPosition(0); + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: SMPEG_rewind(music_playing->data.mp3); break; #endif + default: /* TODO: Implement this for other music backends */ + break; } } } @@ -724,6 +763,8 @@ int Mix_PlayingMusic(void) return(0); break; #endif + default: + break; } return(1); } diff --git a/timidity/Makefile.in b/timidity/Makefile.in index c8954945..46645f3b 100644 --- a/timidity/Makefile.in +++ b/timidity/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated automatically by automake 1.4 from Makefile.am +# Makefile.in generated automatically by automake 1.4a from Makefile.am # Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation @@ -46,9 +46,10 @@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = transform = @program_transform_name@ NORMAL_INSTALL = : @@ -221,7 +222,7 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ - cp -pr $$/$$file $(distdir)/$$file; \ + cp -pr $$d/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ @@ -282,7 +283,7 @@ uninstall: uninstall-am all-am: Makefile $(LTLIBRARIES) all-redirect: all-am install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install installdirs: diff --git a/wavestream.c b/wavestream.c index a2ecfc5c..d4cef1c3 100644 --- a/wavestream.c +++ b/wavestream.c @@ -248,7 +248,7 @@ static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec, was_error = 1; goto done; } - + /* Check the magic header */ RIFFchunk = SDL_ReadLE32(src); wavelen = SDL_ReadLE32(src); @@ -356,8 +356,6 @@ static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, int was_error; FILE *wavefp; SDL_RWops *src; - Chunk chunk; - int lenread; /* AIFF magic header */ Uint32 FORMchunk; @@ -379,7 +377,7 @@ static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, Uint32 l2; Uint16 s1; } sane_freq; - + Uint32 frequency; @@ -394,7 +392,7 @@ static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, was_error = 1; goto done; } - + /* Check the magic header */ FORMchunk = SDL_ReadLE32(src); chunklen = SDL_ReadLE32(src);