libxmp-4.4.1/0000775000175000017500000000000012777546220012653 5ustar claudioclaudiolibxmp-4.4.1/libxmp.map0000664000175000017500000000216112742415254014637 0ustar claudioclaudioXMP_4.0 { global: xmp_version; xmp_vercode; xmp_get_format_list; xmp_create_context; xmp_free_context; xmp_test_module; xmp_load_module; xmp_release_module; xmp_scan_module; xmp_get_module_info; xmp_start_player; xmp_play_frame; xmp_get_frame_info; xmp_end_player; xmp_next_position; xmp_prev_position; xmp_set_position; xmp_stop_module; xmp_restart_module; xmp_seek_time; xmp_channel_mute; xmp_channel_vol; xmp_inject_event; xmp_set_player; xmp_get_player; xmp_set_instrument_path; local: *; }; XMP_4.1 { global: xmp_set_player; xmp_get_player; xmp_play_buffer; } XMP_4.0; XMP_4.2 { global: xmp_get_player; xmp_load_module_from_memory; xmp_start_smix; xmp_end_smix; xmp_smix_play_instrument; xmp_smix_play_sample; xmp_smix_channel_pan; xmp_smix_load_sample; xmp_smix_release_sample; } XMP_4.1; XMP_4.3 { global: xmp_set_player; xmp_get_player; xmp_load_module_from_file; } XMP_4.2; XMP_4.4 { global: xmp_set_player; xmp_get_player; } XMP_4.3; libxmp-4.4.1/jni/0000775000175000017500000000000012777546217013441 5ustar claudioclaudiolibxmp-4.4.1/jni/Android.mk0000664000175000017500000000140212777546217015347 0ustar claudioclaudioLOCAL_PATH := $(call my-dir)/.. include $(CLEAR_VARS) include $(LOCAL_PATH)/src/Makefile include $(LOCAL_PATH)/src/loaders/Makefile include $(LOCAL_PATH)/src/loaders/prowizard/Makefile include $(LOCAL_PATH)/src/depackers/Makefile SRC_SOURCES := $(addprefix src/,$(SRC_OBJS)) LOADERS_SOURCES := $(addprefix src/loaders/,$(LOADERS_OBJS)) PROWIZ_SOURCES := $(addprefix src/loaders/prowizard/,$(PROWIZ_OBJS)) DEPACKERS_SOURCES := $(addprefix src/depackers/,$(DEPACKERS_OBJS)) LOCAL_MODULE := xmp LOCAL_CFLAGS := -O3 -DHAVE_MKSTEMP -DHAVE_FNMATCH -I$(LOCAL_PATH)/include \ -I$(LOCAL_PATH)/src LOCAL_SRC_FILES := $(SRC_SOURCES:.o=.c) \ $(LOADERS_SOURCES:.o=.c) \ $(PROWIZ_SOURCES:.o=.c) \ $(DEPACKERS_SOURCES:.o=.c) include $(BUILD_STATIC_LIBRARY) libxmp-4.4.1/jni/Application.mk0000664000175000017500000000023512777546217016235 0ustar claudioclaudioAPP_PROJECT_PATH := $(call my-dir) APP_MODULES := libxmp APP_ABI := armeabi armeabi-v7a x86 APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/Android.mk libxmp-4.4.1/libxmp.pc.in0000664000175000017500000000034312777546217015105 0ustar claudioclaudioprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libxmp Description: Xmp module player library Version: 4.4.1 Requires: Libs: -L${libdir} -lxmp Cflags: -I${includedir} Libs.private: -lm libxmp-4.4.1/INSTALL0000664000175000017500000000146412664701326013704 0ustar claudioclaudioRequirements ------------ - This package needs to be built using GNU make (https://www.gnu.org/software/make/). On BSD or SysV systems, you may need to use "gmake" instead of "make". Building the library -------------------- In most systems just execute: $ ./configure $ make We'll build the shared library by default. Use ./configure --enable-static to build the static library. To check if the library was correctly built, run: $ make check Use ./configure --help to see more options. Installation ------------ To install the library and development components, just run: # make install as the superuser. This will install the shared and static libraries, header file and pkg-config file into directories under /usr/local or a different location selected with the --prefix option in configure. libxmp-4.4.1/config.guess0000775000175000017500000012761512656346554015213 0ustar claudioclaudio#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Free Software Foundation, Inc. timestamp='2009-11-20' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: libxmp-4.4.1/README0000664000175000017500000000520412742415254013526 0ustar claudioclaudio __ _____ | | |__| |______ ___ ____________ | | | || __ \ \/ // ____ \ | |_| || |_> > <| Y Y \ |_> > |____/__||_____/__/\ \__|_| / ___/ \_/ \/|_| Extended Module Player Library Version 4.4 OVERVIEW Libxmp is a library that renders module files to PCM data. It supports over 90 mainstream and obscure module formats including Protracker (MOD), Scream Tracker 3 (S3M), Fast Tracker II (XM), and Impulse Tracker (IT). Many compressed module formats are supported, including popular Unix, DOS, and Amiga file packers including gzip, bzip2, SQSH, Powerpack, etc. LIBRARY API See docs/libxmp.html for the library API reference. The documentation is also available in man page and PDF formats. SUPPORTED FORMATS See docs/formats.txt for the list of supported formats. By default, Protracker modules are played with a reasonable mix of Protracker 2/3 quirks (because certain Protracker 1/2 bugs are just too weird and generally not worth emulating). Other Amiga 4 channel MODs are played with a generic Noisetracker/Protracker-style replayer, Scream Tracker III MODs are played with a Scream Tracker style replayer and multichannel MOD variations are played with a Fasttracker II style replayer. Multifile formats (Startrekker AM, Magnetic Fields, etc). must have all files in the same directory. SUPPORTED PACKERS The following formats have built-in decompressors: bz2, gz, lha, oxm, xz, Z, zip, ArcFS, arc, MMCMP, PowerPack, !Spark, SQSH, MUSE, LZX, and S404. Other compressed formats need helpers to be installed on the system: mo3 (unmo3) and rar (unrar). AUTHORS AND CONTACT See docs/CREDITS for the full list of authors. Send your comments and bug reports to xmp-devel@lists.sourceforge.net, or directly to cmatsuoka@gmail.com. LICENSE This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA libxmp-4.4.1/configure.ac0000664000175000017500000000620512756462463015147 0ustar claudioclaudiodnl AC_CONFIG_AUX_DIR(./scripts) AC_INIT AC_ARG_ENABLE(static, [ --enable-static Build static library]) AC_ARG_ENABLE(shared, [ --disable-shared Don't build shared library]) AC_SUBST(LD_VERSCRIPT) AC_SUBST(DARWIN_VERSION) AC_CANONICAL_HOST AC_PROG_CC AC_PROG_INSTALL AC_PROG_RANLIB AC_C_BIGENDIAN dnl XMP_TRY_COMPILE(,,,,,) AC_DEFUN([XMP_TRY_COMPILE],[ AC_CACHE_CHECK([$1],[$2],[ oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} $3" AC_COMPILE_IFELSE([AC_LANG_SOURCE([[$4]])],[$2=yes],[$2=no],[true]) CFLAGS="${oldcflags}"]) AS_IF([test "x$$2" = xyes], [$5], [$6])]) AC_DEFUN([AC_CHECK_DEFINED],[ AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl AC_CACHE_CHECK([for $1 defined], ac_var, AC_TRY_COMPILE(,[ #ifdef $1 int ok; #else choke me #endif ],AS_VAR_SET(ac_var, yes),AS_VAR_SET(ac_var, no))) AS_IF([test AS_VAR_GET(ac_var) != "no"], [$2], [$3])dnl AS_VAR_POPDEF([ac_var])dnl ]) case "${host_cpu}" in powerpc64) CFLAGS="${CFLAGS} -m64" LDFLAGS="${LDFLAGS} -m64" ;; esac case "${host_os}" in darwin*) DARWIN_VERSION="`echo ${host_os#darwin}|cut -f1 -d'.'`" ;; cygwin* | mint*) enable_static=yes enable_shared=no ;; esac if test "${enable_static}" = yes; then AC_SUBST(STATIC,static) fi if test "${enable_shared}" != no; then AC_CHECK_DEFINED(_WIN32,[ AC_SUBST(SHARED,dll) CFLAGS="${CFLAGS} -DBUILDING_DLL" ],[ AC_CHECK_DEFINED(__APPLE__,[ AC_SUBST(SHARED,dylib) ],[ AC_SUBST(SHARED,shared) ]) ]) fi XMP_TRY_COMPILE(whether compiler understands -Wall, ac_cv_c_flag_w_all, -Wall,[ int main(){}], CFLAGS="${CFLAGS} -Wall") XMP_TRY_COMPILE(whether compiler understands -xldscope=hidden, ac_cv_c_flag_xldscope_hidden, -xldscope=hidden,[ int main(){}], [LDFLAGS="${LDFLAGS} -xldscope=hidden"], [XMP_TRY_COMPILE(whether compiler understands -fvisibility=hidden, ac_cv_c_flag_f_visibility_hidden, -fvisibility=hidden,[ int main(){}], [LDFLAGS="${LDFLAGS} -fvisibility=hidden" LD_VERSCRIPT="-Wl,--version-script,libxmp.map"])] ) dnl for clang XMP_TRY_COMPILE(whether compiler understands -Wunknown-warning-option, ac_cv_c_flag_w_unknown_warning_option, -Wunknown-warning-option,[ int main(){}], CFLAGS="${CFLAGS} -Wno-unknown-warning-option") XMP_TRY_COMPILE(whether compiler understands -Wunused-but-set-variable, ac_cv_c_flag_w_unused_but_set_variable, -Wunused-but-set-variable,[ int main(){}], CFLAGS="${CFLAGS} -Wno-unused-but-set-variable") XMP_TRY_COMPILE(whether compiler understands -Wunused-result, ac_cv_c_flag_w_unused_result, -Wunused-result,[ int main(){}], CFLAGS="${CFLAGS} -Wno-unused-result") XMP_TRY_COMPILE(whether compiler understands -Warray-bounds, ac_cv_c_flag_w_array_bounds, -Warray-bounds,[ int main(){}], CFLAGS="${CFLAGS} -Wno-array-bounds") XMP_TRY_COMPILE(whether alloca() needs alloca.h, ac_cv_c_flag_w_have_alloca_h,,[ #include int main(){}], AC_DEFINE(HAVE_ALLOCA_H)) AC_CHECK_LIB(m,pow) AC_CHECK_FUNCS(popen mkstemp fnmatch umask) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([libxmp.pc]) AC_OUTPUT libxmp-4.4.1/test/0000775000175000017500000000000012777546220013632 5ustar claudioclaudiolibxmp-4.4.1/test/md5.h0000664000175000017500000000171712664701332014466 0ustar claudioclaudio/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. */ #ifndef LIBXMP_MD5_H #define LIBXMP_MD5_H #include "common.h" #define MD5_BLOCK_LENGTH 64 #define MD5_DIGEST_LENGTH 16 #define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) typedef struct MD5Context { uint32 state[4]; /* state */ uint64 count; /* number of bits, mod 2^64 */ uint8 buffer[MD5_BLOCK_LENGTH]; /* input buffer */ } MD5_CTX; void MD5Init(MD5_CTX *); void MD5Update(MD5_CTX *, const unsigned char *, size_t); void MD5Final(uint8[MD5_DIGEST_LENGTH], MD5_CTX *); #endif /* LIBXMP_MD5_H */ libxmp-4.4.1/test/test.itz0000664000175000017500000000201412706551122015323 0ustar claudioclaudioPK Y|F4htest.itUT صUصUux SSg>I@TA5-Q%j_yT_Aδ3P'te]Sqlyrs䞹g>7@~vrfVXm`l:@lj化7_Fs0Ef3 |K%/o}ѩfm{@OuYY³WU^,J& )P֩JZժNJAڠڤڢڦjRZM;KծQKڧsxw8Ȼ"{O}討#>Vr::NtV4!]԰.鲮誮F41&4ۚմf4'Ӽ$Qg˚뮵ΔU659 0a??72*<)Ĉ IjSC-uԓF6Mlf [vh4;hb7tNE7^;O?9NpS989<0r0`InrLqLs #include #include "../src/common.h" #include "md5.h" #define PUT_64BIT_LE(cp, value) do { \ (cp)[7] = (value) >> 56; \ (cp)[6] = (value) >> 48; \ (cp)[5] = (value) >> 40; \ (cp)[4] = (value) >> 32; \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) #define PUT_32BIT_LE(cp, value) do { \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) static uint8 PADDING[MD5_BLOCK_LENGTH] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(uint32 state[4], const uint8 block[MD5_BLOCK_LENGTH]) { uint32 a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; #ifndef WORDS_BIGENDIAN memcpy(in, block, sizeof(in)); #else for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { in[a] = (uint32)( (uint32)(block[a * 4 + 0]) | (uint32)(block[a * 4 + 1]) << 8 | (uint32)(block[a * 4 + 2]) << 16 | (uint32)(block[a * 4 + 3]) << 24); } #endif a = state[0]; b = state[1]; c = state[2]; d = state[3]; MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); state[0] += a; state[1] += b; state[2] += c; state[3] += d; } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(MD5_CTX *ctx) { ctx->count = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len) { size_t have, need; /* Check how many bytes we already have and how many more we need. */ have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); need = MD5_BLOCK_LENGTH - have; /* Update bitcount */ ctx->count += (uint64)len << 3; if (len >= need) { if (have != 0) { memcpy(ctx->buffer + have, input, need); MD5Transform(ctx->state, ctx->buffer); input += need; len -= need; have = 0; } /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ while (len >= MD5_BLOCK_LENGTH) { MD5Transform(ctx->state, input); input += MD5_BLOCK_LENGTH; len -= MD5_BLOCK_LENGTH; } } /* Handle any remaining bytes of data. */ if (len != 0) memcpy(ctx->buffer + have, input, len); } /* * Pad pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Pad(MD5_CTX *ctx) { uint8 count[8]; size_t padlen; /* Convert count to 8 bytes in little endian order. */ PUT_64BIT_LE(count, ctx->count); /* Pad out to 56 mod 64. */ padlen = MD5_BLOCK_LENGTH - ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); if (padlen < 1 + 8) padlen += MD5_BLOCK_LENGTH; MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ MD5Update(ctx, count, 8); } /* * Final wrapup--call MD5Pad, fill in digest and zero out ctx. */ void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) { int i; MD5Pad(ctx); if (digest != NULL) { for (i = 0; i < 4; i++) PUT_32BIT_LE(digest + i * 4, ctx->state[i]); memset(ctx, 0, sizeof(*ctx)); } } libxmp-4.4.1/test/test.c0000664000175000017500000000363612742775441014766 0ustar claudioclaudio#include #include #include #include "md5.h" #include "xmp.h" static inline int is_big_endian() { unsigned short w = 0x00ff; return (*(char *)&w == 0x00); } /* Convert little-endian 16 bit samples to big-endian */ static void convert_endian(unsigned char *p, int l) { unsigned char b; int i; for (i = 0; i < l; i++) { b = p[0]; p[0] = p[1]; p[1] = b; p += 2; } } static int compare_md5(unsigned char *d, char *digest) { int i; /*for (i = 0; i < 16 ; i++) printf("%02x", d[i]); printf("\n");*/ for (i = 0; i < 16 && *digest; i++, digest += 2) { char hex[3]; hex[0] = digest[0]; hex[1] = digest[1]; hex[2] = 0; if (d[i] != strtoul(hex, NULL, 16)) return -1; } return 0; } int main() { int ret; xmp_context c; struct xmp_frame_info info; long time; unsigned char digest[16]; MD5_CTX ctx; c = xmp_create_context(); if (c == NULL) goto err; ret = xmp_load_module(c, "test.itz"); if (ret != 0) { printf("can't load module\n"); goto err; } xmp_get_frame_info(c, &info); if (info.total_time != 4800) { printf("estimated replay time error\n"); goto err; } xmp_start_player(c, 22050, 0); xmp_set_player(c, XMP_PLAYER_MIX, 100); xmp_set_player(c, XMP_PLAYER_INTERP, XMP_INTERP_SPLINE); printf("Testing "); fflush(stdout); time = 0; MD5Init(&ctx); while (1) { xmp_play_frame(c); xmp_get_frame_info(c, &info); if (info.loop_count > 0) break; time += info.frame_time; if (is_big_endian()) convert_endian(info.buffer, info.buffer_size >> 1); MD5Update(&ctx, info.buffer, info.buffer_size); printf("."); fflush(stdout); } MD5Final(digest, &ctx); if (compare_md5(digest, "8ddeaa84bf9d90fd3b3c0a19453d005b") < 0) { printf("rendering error\n"); goto err; } if (time / 1000 != info.total_time) { printf("replay time error\n"); goto err; } printf(" pass\n"); exit(0); err: printf(" fail\n"); exit(1); } libxmp-4.4.1/test/Makefile0000664000175000017500000000116512664701332015265 0ustar claudioclaudio TEST_OBJS = test.o md5.o TEST_DFILES = Makefile $(TEST_OBJS:.o=.c) test.itz md5.h TEST_PATH = test T_OBJS = $(addprefix $(TEST_PATH)/,$(TEST_OBJS)) default: $(MAKE) -C .. check dist-test: mkdir -p $(DIST)/$(TEST_PATH) cp -RPp $(addprefix $(TEST_PATH)/,$(TEST_DFILES)) $(DIST)/$(TEST_PATH) check: $(TEST_PATH)/libxmp-test cd $(TEST_PATH); LD_LIBRARY_PATH=../lib DYLD_LIBRARY_PATH=../lib LIBRARY_PATH=../lib:$$LIBRARY_PATH PATH=$$PATH:../lib ./libxmp-test $(TEST_PATH)/libxmp-test: $(T_OBJS) @CMD='$(LD) -o $@ $(T_OBJS) $(LIBS) -Llib -lxmp'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \ eval $$CMD libxmp-4.4.1/include/0000775000175000017500000000000012777546220014276 5ustar claudioclaudiolibxmp-4.4.1/include/xmp.h0000664000175000017500000003247012777546217015267 0ustar claudioclaudio#ifndef XMP_H #define XMP_H #ifdef __cplusplus extern "C" { #endif #define XMP_VERSION "4.4.1" #define XMP_VERCODE 0x040401 #define XMP_VER_MAJOR 4 #define XMP_VER_MINOR 4 #define XMP_VER_RELEASE 1 #if defined(_WIN32) && !defined(__CYGWIN__) # if defined(BUILDING_STATIC) # define EXPORT # elif defined(BUILDING_DLL) # define EXPORT __declspec(dllexport) # else # define EXPORT __declspec(dllimport) # endif #elif __GNUC__ >= 4 || defined(__HP_cc) # define EXPORT __attribute__((visibility ("default"))) #elif defined(__SUNPRO_C) # define EXPORT __global #elif defined(EMSCRIPTEN) # define EXPORT EMSCRIPTEN_KEEPALIVE #else # define EXPORT #endif #define XMP_NAME_SIZE 64 /* Size of module name and type */ #define XMP_KEY_OFF 0x81 /* Note number for key off event */ #define XMP_KEY_CUT 0x82 /* Note number for key cut event */ #define XMP_KEY_FADE 0x83 /* Note number for fade event */ /* mixer parameter macros */ /* sample format flags */ #define XMP_FORMAT_8BIT (1 << 0) /* Mix to 8-bit instead of 16 */ #define XMP_FORMAT_UNSIGNED (1 << 1) /* Mix to unsigned samples */ #define XMP_FORMAT_MONO (1 << 2) /* Mix to mono instead of stereo */ /* player parameters */ #define XMP_PLAYER_AMP 0 /* Amplification factor */ #define XMP_PLAYER_MIX 1 /* Stereo mixing */ #define XMP_PLAYER_INTERP 2 /* Interpolation type */ #define XMP_PLAYER_DSP 3 /* DSP effect flags */ #define XMP_PLAYER_FLAGS 4 /* Player flags */ #define XMP_PLAYER_CFLAGS 5 /* Player flags for current module */ #define XMP_PLAYER_SMPCTL 6 /* Sample control flags */ #define XMP_PLAYER_VOLUME 7 /* Player module volume */ #define XMP_PLAYER_STATE 8 /* Internal player state (read only) */ #define XMP_PLAYER_SMIX_VOLUME 9 /* SMIX volume */ #define XMP_PLAYER_DEFPAN 10 /* Default pan setting */ #define XMP_PLAYER_MODE 11 /* Player personality */ #define XMP_PLAYER_MIXER_TYPE 12 /* Current mixer (read only) */ #define XMP_PLAYER_VOICES 13 /* Maximum number of mixer voices */ /* interpolation types */ #define XMP_INTERP_NEAREST 0 /* Nearest neighbor */ #define XMP_INTERP_LINEAR 1 /* Linear (default) */ #define XMP_INTERP_SPLINE 2 /* Cubic spline */ /* dsp effect types */ #define XMP_DSP_LOWPASS (1 << 0) /* Lowpass filter effect */ #define XMP_DSP_ALL (XMP_DSP_LOWPASS) /* player state */ #define XMP_STATE_UNLOADED 0 /* Context created */ #define XMP_STATE_LOADED 1 /* Module loaded */ #define XMP_STATE_PLAYING 2 /* Module playing */ /* player flags */ #define XMP_FLAGS_VBLANK (1 << 0) /* Use vblank timing */ #define XMP_FLAGS_FX9BUG (1 << 1) /* Emulate FX9 bug */ #define XMP_FLAGS_FIXLOOP (1 << 2) /* Emulate sample loop bug */ #define XMP_FLAGS_A500 (1 << 3) /* Use Paula mixer in Amiga modules */ /* player modes */ #define XMP_MODE_AUTO 0 /* Autodetect mode (default) */ #define XMP_MODE_MOD 1 /* Play as a generic MOD player */ #define XMP_MODE_NOISETRACKER 2 /* Play using Noisetracker quirks */ #define XMP_MODE_PROTRACKER 3 /* Play using Protracker quirks */ #define XMP_MODE_S3M 4 /* Play as a generic S3M player */ #define XMP_MODE_ST3 5 /* Play using ST3 bug emulation */ #define XMP_MODE_ST3GUS 6 /* Play using ST3+GUS quirks */ #define XMP_MODE_XM 7 /* Play as a generic XM player */ #define XMP_MODE_FT2 8 /* Play using FT2 bug emulation */ #define XMP_MODE_IT 9 /* Play using IT quirks */ #define XMP_MODE_ITSMP 10 /* Play using IT sample mode quirks */ /* mixer types */ #define XMP_MIXER_STANDARD 0 /* Standard mixer */ #define XMP_MIXER_A500 1 /* Amiga 500 */ #define XMP_MIXER_A500F 2 /* Amiga 500 with led filter */ /* sample flags */ #define XMP_SMPCTL_SKIP (1 << 0) /* Don't load samples */ /* limits */ #define XMP_MAX_KEYS 121 /* Number of valid keys */ #define XMP_MAX_ENV_POINTS 32 /* Max number of envelope points */ #define XMP_MAX_MOD_LENGTH 256 /* Max number of patterns in module */ #define XMP_MAX_CHANNELS 64 /* Max number of channels in module */ #define XMP_MAX_SRATE 49170 /* max sampling rate (Hz) */ #define XMP_MIN_SRATE 4000 /* min sampling rate (Hz) */ #define XMP_MIN_BPM 20 /* min BPM */ /* frame rate = (50 * bpm / 125) Hz */ /* frame size = (sampling rate * channels * size) / frame rate */ #define XMP_MAX_FRAMESIZE (5 * XMP_MAX_SRATE * 2 / XMP_MIN_BPM) /* error codes */ #define XMP_END 1 #define XMP_ERROR_INTERNAL 2 /* Internal error */ #define XMP_ERROR_FORMAT 3 /* Unsupported module format */ #define XMP_ERROR_LOAD 4 /* Error loading file */ #define XMP_ERROR_DEPACK 5 /* Error depacking file */ #define XMP_ERROR_SYSTEM 6 /* System error */ #define XMP_ERROR_INVALID 7 /* Invalid parameter */ #define XMP_ERROR_STATE 8 /* Invalid player state */ struct xmp_channel { int pan; /* Channel pan (0x80 is center) */ int vol; /* Channel volume */ #define XMP_CHANNEL_SYNTH (1 << 0) /* Channel is synthesized */ #define XMP_CHANNEL_MUTE (1 << 1) /* Channel is muted */ #define XMP_CHANNEL_SPLIT (1 << 2) /* Split Amiga channel in bits 5-4 */ #define XMP_CHANNEL_SURROUND (1 << 4) /* Surround channel */ int flg; /* Channel flags */ }; struct xmp_pattern { int rows; /* Number of rows */ int index[1]; /* Track index */ }; struct xmp_event { unsigned char note; /* Note number (0 means no note) */ unsigned char ins; /* Patch number */ unsigned char vol; /* Volume (0 to basevol) */ unsigned char fxt; /* Effect type */ unsigned char fxp; /* Effect parameter */ unsigned char f2t; /* Secondary effect type */ unsigned char f2p; /* Secondary effect parameter */ unsigned char _flag; /* Internal (reserved) flags */ }; struct xmp_track { int rows; /* Number of rows */ struct xmp_event event[1]; /* Event data */ }; struct xmp_envelope { #define XMP_ENVELOPE_ON (1 << 0) /* Envelope is enabled */ #define XMP_ENVELOPE_SUS (1 << 1) /* Envelope has sustain point */ #define XMP_ENVELOPE_LOOP (1 << 2) /* Envelope has loop */ #define XMP_ENVELOPE_FLT (1 << 3) /* Envelope is used for filter */ #define XMP_ENVELOPE_SLOOP (1 << 4) /* Envelope has sustain loop */ #define XMP_ENVELOPE_CARRY (1 << 5) /* Don't reset envelope position */ int flg; /* Flags */ int npt; /* Number of envelope points */ int scl; /* Envelope scaling */ int sus; /* Sustain start point */ int sue; /* Sustain end point */ int lps; /* Loop start point */ int lpe; /* Loop end point */ short data[XMP_MAX_ENV_POINTS * 2]; }; struct xmp_instrument { char name[32]; /* Instrument name */ int vol; /* Instrument volume */ int nsm; /* Number of samples */ int rls; /* Release (fadeout) */ struct xmp_envelope aei; /* Amplitude envelope info */ struct xmp_envelope pei; /* Pan envelope info */ struct xmp_envelope fei; /* Frequency envelope info */ struct { unsigned char ins; /* Instrument number for each key */ signed char xpo; /* Instrument transpose for each key */ } map[XMP_MAX_KEYS]; struct xmp_subinstrument { int vol; /* Default volume */ int gvl; /* Global volume */ int pan; /* Pan */ int xpo; /* Transpose */ int fin; /* Finetune */ int vwf; /* Vibrato waveform */ int vde; /* Vibrato depth */ int vra; /* Vibrato rate */ int vsw; /* Vibrato sweep */ int rvv; /* Random volume/pan variation (IT) */ int sid; /* Sample number */ #define XMP_INST_NNA_CUT 0x00 #define XMP_INST_NNA_CONT 0x01 #define XMP_INST_NNA_OFF 0x02 #define XMP_INST_NNA_FADE 0x03 int nna; /* New note action */ #define XMP_INST_DCT_OFF 0x00 #define XMP_INST_DCT_NOTE 0x01 #define XMP_INST_DCT_SMP 0x02 #define XMP_INST_DCT_INST 0x03 int dct; /* Duplicate check type */ #define XMP_INST_DCA_CUT XMP_INST_NNA_CUT #define XMP_INST_DCA_OFF XMP_INST_NNA_OFF #define XMP_INST_DCA_FADE XMP_INST_NNA_FADE int dca; /* Duplicate check action */ int ifc; /* Initial filter cutoff */ int ifr; /* Initial filter resonance */ } *sub; void *extra; /* Extra fields */ }; struct xmp_sample { char name[32]; /* Sample name */ int len; /* Sample length */ int lps; /* Loop start */ int lpe; /* Loop end */ #define XMP_SAMPLE_16BIT (1 << 0) /* 16bit sample */ #define XMP_SAMPLE_LOOP (1 << 1) /* Sample is looped */ #define XMP_SAMPLE_LOOP_BIDIR (1 << 2) /* Bidirectional sample loop */ #define XMP_SAMPLE_LOOP_REVERSE (1 << 3) /* Backwards sample loop */ #define XMP_SAMPLE_LOOP_FULL (1 << 4) /* Play full sample before looping */ #define XMP_SAMPLE_SLOOP (1 << 5) /* Sample has sustain loop */ #define XMP_SAMPLE_SLOOP_BIDIR (1 << 6) /* Bidirectional sustain loop */ #define XMP_SAMPLE_SYNTH (1 << 15) /* Data contains synth patch */ int flg; /* Flags */ unsigned char *data; /* Sample data */ }; struct xmp_sequence { int entry_point; int duration; }; struct xmp_module { char name[XMP_NAME_SIZE]; /* Module title */ char type[XMP_NAME_SIZE]; /* Module format */ int pat; /* Number of patterns */ int trk; /* Number of tracks */ int chn; /* Tracks per pattern */ int ins; /* Number of instruments */ int smp; /* Number of samples */ int spd; /* Initial speed */ int bpm; /* Initial BPM */ int len; /* Module length in patterns */ int rst; /* Restart position */ int gvl; /* Global volume */ struct xmp_pattern **xxp; /* Patterns */ struct xmp_track **xxt; /* Tracks */ struct xmp_instrument *xxi; /* Instruments */ struct xmp_sample *xxs; /* Samples */ struct xmp_channel xxc[XMP_MAX_CHANNELS]; /* Channel info */ unsigned char xxo[XMP_MAX_MOD_LENGTH]; /* Orders */ }; struct xmp_test_info { char name[XMP_NAME_SIZE]; /* Module title */ char type[XMP_NAME_SIZE]; /* Module format */ }; struct xmp_module_info { unsigned char md5[16]; /* MD5 message digest */ int vol_base; /* Volume scale */ struct xmp_module *mod; /* Pointer to module data */ char *comment; /* Comment text, if any */ int num_sequences; /* Number of valid sequences */ struct xmp_sequence *seq_data; /* Pointer to sequence data */ }; struct xmp_frame_info { /* Current frame information */ int pos; /* Current position */ int pattern; /* Current pattern */ int row; /* Current row in pattern */ int num_rows; /* Number of rows in current pattern */ int frame; /* Current frame */ int speed; /* Current replay speed */ int bpm; /* Current bpm */ int time; /* Current module time in ms */ int total_time; /* Estimated replay time in ms*/ int frame_time; /* Frame replay time in us */ void *buffer; /* Pointer to sound buffer */ int buffer_size; /* Used buffer size */ int total_size; /* Total buffer size */ int volume; /* Current master volume */ int loop_count; /* Loop counter */ int virt_channels; /* Number of virtual channels */ int virt_used; /* Used virtual channels */ int sequence; /* Current sequence */ struct xmp_channel_info { /* Current channel information */ unsigned int period; /* Sample period (* 4096) */ unsigned int position; /* Sample position */ short pitchbend; /* Linear bend from base note*/ unsigned char note; /* Current base note number */ unsigned char instrument; /* Current instrument number */ unsigned char sample; /* Current sample number */ unsigned char volume; /* Current volume */ unsigned char pan; /* Current stereo pan */ unsigned char reserved; /* Reserved */ struct xmp_event event; /* Current track event */ } channel_info[XMP_MAX_CHANNELS]; }; typedef char *xmp_context; EXPORT extern const char *xmp_version; EXPORT extern const unsigned int xmp_vercode; EXPORT xmp_context xmp_create_context (void); EXPORT void xmp_free_context (xmp_context); EXPORT int xmp_test_module (char *, struct xmp_test_info *); EXPORT int xmp_load_module (xmp_context, char *); EXPORT void xmp_scan_module (xmp_context); EXPORT void xmp_release_module (xmp_context); EXPORT int xmp_start_player (xmp_context, int, int); EXPORT int xmp_play_frame (xmp_context); EXPORT int xmp_play_buffer (xmp_context, void *, int, int); EXPORT void xmp_get_frame_info (xmp_context, struct xmp_frame_info *); EXPORT void xmp_end_player (xmp_context); EXPORT void xmp_inject_event (xmp_context, int, struct xmp_event *); EXPORT void xmp_get_module_info (xmp_context, struct xmp_module_info *); EXPORT char **xmp_get_format_list (void); EXPORT int xmp_next_position (xmp_context); EXPORT int xmp_prev_position (xmp_context); EXPORT int xmp_set_position (xmp_context, int); EXPORT void xmp_stop_module (xmp_context); EXPORT void xmp_restart_module (xmp_context); EXPORT int xmp_seek_time (xmp_context, int); EXPORT int xmp_channel_mute (xmp_context, int, int); EXPORT int xmp_channel_vol (xmp_context, int, int); EXPORT int xmp_set_player (xmp_context, int, int); EXPORT int xmp_get_player (xmp_context, int); EXPORT int xmp_set_instrument_path (xmp_context, char *); EXPORT int xmp_load_module_from_memory (xmp_context, void *, long); EXPORT int xmp_load_module_from_file (xmp_context, void *, long); /* External sample mixer API */ EXPORT int xmp_start_smix (xmp_context, int, int); EXPORT void xmp_end_smix (xmp_context); EXPORT int xmp_smix_play_instrument(xmp_context, int, int, int, int); EXPORT int xmp_smix_play_sample (xmp_context, int, int, int, int); EXPORT int xmp_smix_channel_pan (xmp_context, int, int); EXPORT int xmp_smix_load_sample (xmp_context, int, char *); EXPORT int xmp_smix_release_sample (xmp_context, int); #ifdef __cplusplus } #endif #endif /* XMP_H */ libxmp-4.4.1/include/Makefile0000664000175000017500000000037512304451505015726 0ustar claudioclaudio INCLUDE_DFILES = Makefile xmp.h INCLUDE_PATH = include install-include: $(INSTALL_DATA) xmp.h $(DESTDIR)$(INCLUDEDIR) dist-include: mkdir -p $(DIST)/$(INCLUDE_PATH) cp -RPp $(addprefix $(INCLUDE_PATH)/,$(INCLUDE_DFILES)) $(DIST)/$(INCLUDE_PATH) libxmp-4.4.1/config.sub0000775000175000017500000010670112777410253014637 0ustar claudioclaudio#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2016 Free Software Foundation, Inc. timestamp='2016-08-25' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` os=$os"spe" ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -ios) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: libxmp-4.4.1/install-sh0000775000175000017500000003253712301762730014656 0ustar claudioclaudio#!/bin/sh # install - install a program, script, or datafile scriptversion=2009-04-28.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: libxmp-4.4.1/configure0000775000175000017500000045062712775035400014567 0ustar claudioclaudio#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS SHARED STATIC EGREP GREP CPP RANLIB INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build DARWIN_VERSION LD_VERSCRIPT target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_static enable_shared ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-static Build static library --disable-shared Don't build shared library Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; fi # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test -n "$ac_tool_prefix"; then # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac case "${host_cpu}" in powerpc64) CFLAGS="${CFLAGS} -m64" LDFLAGS="${LDFLAGS} -m64" ;; esac case "${host_os}" in darwin*) DARWIN_VERSION="`echo ${host_os#darwin}|cut -f1 -d'.'`" ;; cygwin* | mint*) enable_static=yes enable_shared=no ;; esac if test "${enable_static}" = yes; then STATIC=static fi if test "${enable_shared}" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _WIN32 defined" >&5 $as_echo_n "checking for _WIN32 defined... " >&6; } if ${ac_cv_defined__WIN32+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifdef _WIN32 int ok; #else choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_defined__WIN32=yes else ac_cv_defined__WIN32=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined__WIN32" >&5 $as_echo "$ac_cv_defined__WIN32" >&6; } if test $ac_cv_defined__WIN32 != "no"; then : SHARED=dll CFLAGS="${CFLAGS} -DBUILDING_DLL" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __APPLE__ defined" >&5 $as_echo_n "checking for __APPLE__ defined... " >&6; } if ${ac_cv_defined___APPLE__+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifdef __APPLE__ int ok; #else choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_defined___APPLE__=yes else ac_cv_defined___APPLE__=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_defined___APPLE__" >&5 $as_echo "$ac_cv_defined___APPLE__" >&6; } if test $ac_cv_defined___APPLE__ != "no"; then : SHARED=dylib else SHARED=shared fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -Wall" >&5 $as_echo_n "checking whether compiler understands -Wall... " >&6; } if ${ac_cv_c_flag_w_all+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -Wall" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_w_all=yes else ac_cv_c_flag_w_all=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_w_all" >&5 $as_echo "$ac_cv_c_flag_w_all" >&6; } if test "x$ac_cv_c_flag_w_all" = xyes; then : CFLAGS="${CFLAGS} -Wall" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -xldscope=hidden" >&5 $as_echo_n "checking whether compiler understands -xldscope=hidden... " >&6; } if ${ac_cv_c_flag_xldscope_hidden+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -xldscope=hidden" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_xldscope_hidden=yes else ac_cv_c_flag_xldscope_hidden=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_xldscope_hidden" >&5 $as_echo "$ac_cv_c_flag_xldscope_hidden" >&6; } if test "x$ac_cv_c_flag_xldscope_hidden" = xyes; then : LDFLAGS="${LDFLAGS} -xldscope=hidden" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -fvisibility=hidden" >&5 $as_echo_n "checking whether compiler understands -fvisibility=hidden... " >&6; } if ${ac_cv_c_flag_f_visibility_hidden+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -fvisibility=hidden" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_f_visibility_hidden=yes else ac_cv_c_flag_f_visibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_f_visibility_hidden" >&5 $as_echo "$ac_cv_c_flag_f_visibility_hidden" >&6; } if test "x$ac_cv_c_flag_f_visibility_hidden" = xyes; then : LDFLAGS="${LDFLAGS} -fvisibility=hidden" LD_VERSCRIPT="-Wl,--version-script,libxmp.map" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -Wunknown-warning-option" >&5 $as_echo_n "checking whether compiler understands -Wunknown-warning-option... " >&6; } if ${ac_cv_c_flag_w_unknown_warning_option+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -Wunknown-warning-option" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_w_unknown_warning_option=yes else ac_cv_c_flag_w_unknown_warning_option=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_w_unknown_warning_option" >&5 $as_echo "$ac_cv_c_flag_w_unknown_warning_option" >&6; } if test "x$ac_cv_c_flag_w_unknown_warning_option" = xyes; then : CFLAGS="${CFLAGS} -Wno-unknown-warning-option" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -Wunused-but-set-variable" >&5 $as_echo_n "checking whether compiler understands -Wunused-but-set-variable... " >&6; } if ${ac_cv_c_flag_w_unused_but_set_variable+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -Wunused-but-set-variable" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_w_unused_but_set_variable=yes else ac_cv_c_flag_w_unused_but_set_variable=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_w_unused_but_set_variable" >&5 $as_echo "$ac_cv_c_flag_w_unused_but_set_variable" >&6; } if test "x$ac_cv_c_flag_w_unused_but_set_variable" = xyes; then : CFLAGS="${CFLAGS} -Wno-unused-but-set-variable" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -Wunused-result" >&5 $as_echo_n "checking whether compiler understands -Wunused-result... " >&6; } if ${ac_cv_c_flag_w_unused_result+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -Wunused-result" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_w_unused_result=yes else ac_cv_c_flag_w_unused_result=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_w_unused_result" >&5 $as_echo "$ac_cv_c_flag_w_unused_result" >&6; } if test "x$ac_cv_c_flag_w_unused_result" = xyes; then : CFLAGS="${CFLAGS} -Wno-unused-result" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler understands -Warray-bounds" >&5 $as_echo_n "checking whether compiler understands -Warray-bounds... " >&6; } if ${ac_cv_c_flag_w_array_bounds+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} -Warray-bounds" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_w_array_bounds=yes else ac_cv_c_flag_w_array_bounds=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_w_array_bounds" >&5 $as_echo "$ac_cv_c_flag_w_array_bounds" >&6; } if test "x$ac_cv_c_flag_w_array_bounds" = xyes; then : CFLAGS="${CFLAGS} -Wno-array-bounds" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether alloca() needs alloca.h" >&5 $as_echo_n "checking whether alloca() needs alloca.h... " >&6; } if ${ac_cv_c_flag_w_have_alloca_h+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS}" CFLAGS="${CFLAGS} " cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main(){} _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_flag_w_have_alloca_h=yes else ac_cv_c_flag_w_have_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_flag_w_have_alloca_h" >&5 $as_echo "$ac_cv_c_flag_w_have_alloca_h" >&6; } if test "x$ac_cv_c_flag_w_have_alloca_h" = xyes; then : $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if ${ac_cv_lib_m_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi for ac_func in popen mkstemp fnmatch umask do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_config_files="$ac_config_files Makefile" ac_config_files="$ac_config_files libxmp.pc" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "libxmp.pc") CONFIG_FILES="$CONFIG_FILES libxmp.pc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi libxmp-4.4.1/Makefile.in0000664000175000017500000001420012774322476014717 0ustar claudioclaudioVERSION_MAJOR = 4 VERSION_MINOR = 4 VERSION_RELEASE = 1 VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE) # This dylib will support anything linked against COMPAT_VERSION through VERSION COMPAT_VERSION = $(VERSION_MAJOR) CC = @CC@ CFLAGS = -c @CFLAGS@ @DEFS@ -D_REENTRANT LD = @CC@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ RANLIB = @RANLIB@ INSTALL = @INSTALL@ DESTDIR = prefix = @prefix@ exec_prefix = @prefix@ datarootdir = @datarootdir@ BINDIR = @bindir@ LIBDIR = @libdir@ MANDIR = @mandir@/man3 INCLUDEDIR = @includedir@ LD_VERSCRIPT = @LD_VERSCRIPT@ SHELL = /bin/sh DIST = libxmp-$(VERSION) DFILES = README INSTALL install-sh configure configure.ac config.sub \ config.guess Makefile.in libxmp.pc.in libxmp.map Makefile.vc DDIRS = docs include src loaders prowiz depackers win32 test V = 0 LIB = libxmp.a SOLIB = libxmp.so SHLIB = $(SOLIB).$(VERSION) SONAME = $(SOLIB).$(VERSION_MAJOR) DLL = libxmp.dll DYLIB = libxmp.$(VERSION_MAJOR).dylib GCLIB = libxmp-gc.a DYLIB_COMPAT = -compatibility_version,$(COMPAT_VERSION), DARWIN_VERSION = @DARWIN_VERSION@ # https://github.com/cmatsuoka/libxmp/issues/1 ifneq ($(DARWIN_VERSION),) ifeq ($(shell test $(DARWIN_VERSION) -lt 9 && echo true), true) DYLIB_COMPAT = "" endif endif all: @STATIC@ @SHARED@ include docs/Makefile include include/Makefile include src/Makefile include src/loaders/Makefile include src/loaders/prowizard/Makefile include src/depackers/Makefile include src/win32/Makefile include test/Makefile LOBJS = $(OBJS:.o=.lo) GCOBJS = $(OBJS:.o=.gco) CFLAGS += -Iinclude -Isrc .SUFFIXES: .c .o .lo .a .so .dll .in .gco .gcda .gcno .c.o: @CMD='$(CC) $(CPPFLAGS) $(CFLAGS) -o $*.o $<'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo CC $*.o ; fi; \ eval $$CMD .c.lo: @CMD='$(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -o $*.lo $<'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo CC $*.lo ; fi; \ eval $$CMD .c.gco: @CMD='$(CC) $(CPPFLAGS) $(CFLAGS) -O0 -fno-inline -fprofile-arcs -ftest-coverage -o $*.gco $<'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo CC $*.gco ; fi; \ eval $$CMD static: lib/$(LIB) shared: lib/$(SHLIB) coverage: lib/$(GCLIB) dll: lib/$(DLL) dylib: lib/$(DYLIB) lib/$(LIB): $(OBJS) @mkdir -p lib @CMD='$(AR) r $@ $(OBJS)'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo AR $@ ; fi; \ eval $$CMD $(RANLIB) $@ lib/$(SHLIB): $(LOBJS) @mkdir -p lib @CMD='$(LD) $(LDFLAGS) -shared -Wl,-soname,$(SONAME) $(LD_VERSCRIPT) -o $@ $(LOBJS) $(LIBS)'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \ eval $$CMD ln -sf $(SHLIB) lib/$(SONAME) ln -sf $(SONAME) lib/$(SOLIB) lib/$(DLL): $(OBJS) @mkdir -p lib @CMD='$(LD) $(LDFLAGS) -shared -Wl,--output-def,lib/libxmp.def,--out-implib,lib/libxmp_dll.a -o $@ $(OBJS) $(LIBS)'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \ eval $$CMD # From http://stackoverflow.com/questions/15905310: # The version number checks that dyld performs are limited to ensuring that # the compatibility version of the library being loaded is higher than the # compatibility version of the library that was used at build time. lib/$(DYLIB): $(LOBJS) @mkdir -p lib @CMD='$(LD) $(LDFLAGS) -dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,$(DYLIB_COMPAT)-current_version,$(VERSION),-install_name,$(prefix)/lib/$(DYLIB) -o $@ $(LOBJS) $(LIBS)'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo LD $@ ; fi; \ eval $$CMD ln -sf $(DYLIB) lib/libxmp.dylib lib/$(GCLIB): $(GCOBJS) @mkdir -p lib @CMD='$(AR) r $@ $(GCOBJS)'; \ if [ "$(V)" -gt 0 ]; then echo $$CMD; else echo AR $@ ; fi; \ eval $$CMD $(RANLIB) $@ clean: @rm -f $(OBJS) $(LOBJS) lib/lib* @rm -f $(GCOBJS) $(OBJS:.o=.gcno) $(OBJS:.o=.gcda) install: all @mkdir -p $(DESTDIR)$(LIBDIR) $(DESTDIR)$(INCLUDEDIR) @if [ -f lib/$(LIB) ]; then \ echo "Installing $(LIB)..."; \ $(INSTALL) -m644 lib/$(LIB) $(DESTDIR)$(LIBDIR); \ fi @if [ -f lib/$(DYLIB) ]; then \ echo "Installing $(DYLIB)..."; \ $(INSTALL) -m755 lib/$(DYLIB) $(DESTDIR)$(LIBDIR); \ ln -sf $(DYLIB) $(DESTDIR)$(LIBDIR)/libxmp.dylib; \ fi @if [ -f lib/$(SHLIB) ]; then \ echo "Installing $(SHLIB)..."; \ $(INSTALL) -m644 lib/$(SHLIB) $(DESTDIR)$(LIBDIR); \ ln -sf $(SHLIB) $(DESTDIR)$(LIBDIR)/$(SONAME); \ ln -sf $(SONAME) $(DESTDIR)$(LIBDIR)/$(SOLIB); \ fi @echo "Installing xmp.h..." @$(INSTALL) -m644 include/xmp.h $(DESTDIR)$(INCLUDEDIR) @echo "Installing libxmp.pc..." @mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig @$(INSTALL) -m644 libxmp.pc $(DESTDIR)$(LIBDIR)/pkgconfig/ depend: @echo Building dependencies... @echo > $@ @for i in $(OBJS) $(T_OBJS); do \ c="$${i%.o}.c"; l="$${i%.o}.lo"; \ $(CC) $(CFLAGS) -MM $$c | \ sed "s!^.*\.o:!$$i $$l:!" >> $@ ; \ done dist: version-prepare all-docs dist-prepare vc-prepare dist-jni dist-subdirs dist-jni: mkdir $(DIST)/jni cp jni/Android.mk jni/Application.mk $(DIST)/jni dist-prepare: ./config.status rm -Rf $(DIST) $(DIST).tar.gz mkdir -p $(DIST) cp -RPp $(DFILES) $(DIST)/ vc-prepare: @echo Generate Makefile.vc @sed -e 's!@OBJS@!$(subst /,\\,$(OBJS:.o=.obj))!' Makefile.vc.in > Makefile.vc dist-subdirs: $(addprefix dist-,$(DDIRS)) chmod -R u+w $(DIST)/* tar cvf - $(DIST) | gzip -9c > $(DIST).tar.gz rm -Rf $(DIST) ls -l $(DIST).tar.gz distcheck: rm -Rf $(DIST) tar xf $(DIST).tar.gz (cd $(DIST); ./configure --enable-static --prefix=`pwd`/test-install; make; make check; make install; find test-install) devcheck: $(MAKE) -C test-dev covercheck: coverage $(MAKE) -C test-dev covercheck coverclean: rm -f $(OBJS:.o=.gco) $(OBJS:.o=.gcno) $(OBJS:.o=.gcda) $(MAKE) -C test-dev coverclean $(OBJS): Makefile $(LOBJS): Makefile version-prepare: sed -i -e '/^Version: /s/:.*/: $(VERSION)/g' libxmp.pc.in sed -i -e '/^Version: /s/:.*/: $(VERSION)/g' lite/libxmp-lite.pc.in vercode=`printf "0x%02x%02x%02x" $(VERSION_MAJOR) $(VERSION_MINOR) $(VERSION_RELEASE)`; \ sed -i -e "s/\(^#define XMP_VERSION\).*/\1 \"$(VERSION)\"/;s/\(^#define XMP_VERCODE\).*/\1 $$vercode/;s/\(^#define XMP_VER_MAJOR\).*/\1 $(VERSION_MAJOR)/;s/\(^#define XMP_VER_MINOR\).*/\1 $(VERSION_MINOR)/;s/\(^#define XMP_VER_RELEASE\).*/\1 $(VERSION_RELEASE)/" include/xmp.h ./config.status sinclude depend libxmp-4.4.1/src/0000775000175000017500000000000012777546220013442 5ustar claudioclaudiolibxmp-4.4.1/src/mdataio.h0000664000175000017500000000326612773463510015234 0ustar claudioclaudio#ifndef LIBXMP_MDATAIO_H #define LIBXMP_MDATAIO_H #include #include "common.h" static inline ptrdiff_t CAN_READ(MFILE *m) { if (m->size >= 0) return m->pos >= 0 ? m->size - m->pos : 0; return INT_MAX; } static inline uint8 mread8(MFILE *m) { uint8 x = 0xff; mread(&x, 1, 1, m); return x; } static inline int8 mread8s(MFILE *m) { return (int8)mgetc(m); } static inline uint16 mread16l(MFILE *m) { ptrdiff_t can_read = CAN_READ(m); if (can_read >= 2) { uint16 n = readmem16l(m->start + m->pos); m->pos += 2; return n; } else { m->pos += can_read; return EOF; } } static inline uint16 mread16b(MFILE *m) { ptrdiff_t can_read = CAN_READ(m); if (can_read >= 2) { uint16 n = readmem16b(m->start + m->pos); m->pos += 2; return n; } else { m->pos += can_read; return EOF; } } static inline uint32 mread24l(MFILE *m) { ptrdiff_t can_read = CAN_READ(m); if (can_read >= 3) { uint32 n = readmem24l(m->start + m->pos); m->pos += 3; return n; } else { m->pos += can_read; return EOF; } } static inline uint32 mread24b(MFILE *m) { ptrdiff_t can_read = CAN_READ(m); if (can_read >= 3) { uint32 n = readmem24b(m->start + m->pos); m->pos += 3; return n; } else { m->pos += can_read; return EOF; } } static inline uint32 mread32l(MFILE *m) { ptrdiff_t can_read = CAN_READ(m); if (can_read >= 4) { uint32 n = readmem32l(m->start + m->pos); m->pos += 4; return n; } else { m->pos += can_read; return EOF; } } static inline uint32 mread32b(MFILE *m) { ptrdiff_t can_read = CAN_READ(m); if (can_read >= 4) { uint32 n = readmem32b(m->start + m->pos); m->pos += 4; return n; } else { m->pos += can_read; return EOF; } } #endif libxmp-4.4.1/src/period.h0000664000175000017500000000127212774567167015111 0ustar claudioclaudio#ifndef LIBXMP_PERIOD_H #define LIBXMP_PERIOD_H #define PERIOD_BASE 13696.0 /* C0 period */ /* Macros for period conversion */ #define NOTE_B0 11 #define NOTE_Bb0 (NOTE_B0 + 1) #define MAX_NOTE (NOTE_B0 * 8) #define MAX_PERIOD 0x1c56 #define MIN_PERIOD_A 0x0071 #define MAX_PERIOD_A 0x0358 #define MIN_PERIOD_L 0x0000 #define MAX_PERIOD_L 0x1e00 #define MIN_NOTE_MOD 48 #define MAX_NOTE_MOD 83 double libxmp_note_to_period (struct context_data *, int, int, double); double libxmp_note_to_period_mix (int, int); int libxmp_period_to_note (int); int libxmp_period_to_bend (struct context_data *, double, int, double); void libxmp_c2spd_to_note (int, int *, int *); #endif /* LIBXMP_PERIOD_H */ libxmp-4.4.1/src/win32/0000775000175000017500000000000012777546220014404 5ustar claudioclaudiolibxmp-4.4.1/src/win32/sys/0000775000175000017500000000000012641457214015214 5ustar claudioclaudiolibxmp-4.4.1/src/win32/sys/time.h0000664000175000017500000000002312641457214016316 0ustar claudioclaudio /* empty file */ libxmp-4.4.1/src/win32/sys/Makefile0000664000175000017500000000016712304451505016651 0ustar claudioclaudio TOPDIR = ../../.. OBJS = DFILES = Makefile time.h DDIRS = CFILES = DCFILES = all: include $(TOPDIR)/Makefile.rules libxmp-4.4.1/src/win32/ptpopen.c0000664000175000017500000001241012664701330016221 0ustar claudioclaudio/* * pt_popen/pt_pclose functions * Written somewhere in the 90s by Kurt Keller * Comments translated by Steve Donovan * Modified for use in xmp by Mirko Buffoni and Claudio Matsuoka */ /* * This piece of code is in the public domain. I do not claim any rights * on it. Do whatever you want to do with it and I hope it will be still * useful. -- Kurt Keller, Aug 2013 */ #if !defined(HAVE_POPEN) && defined(WIN32) #include "ptpopen.h" /* > Hello, > I am currently porting a UNIX program to WINDOWS. > Most difficulty time I have is to find the popen()-like function under > WINDOWS. Any help and hints would be greatly appreciated. > > Thanks in advance > Tianlin Wang This is what I use instead of popen(): (Sorry for the comments in german ;-)) It is not an **EXACT** replacement for popen() but it is OK for me. Kurt. --------------------------------------------------- Tel.: (49)7150/393394 Parity Software GmbH Fax.: (49)7150/393351 Stuttgarter Strasse 42/3 E-Mail: kk@parity-soft.de D-71701 Schwieberdingen Web: www.parity-soft.de --------------------------------------------------- */ /*---------------------------------------------------------------------------- Globals for the Routines pt_popen() / pt_pclose() ----------------------------------------------------------------------------*/ #include #include #include #include static HANDLE my_pipein[2], my_pipeout[2], my_pipeerr[2]; static char my_popenmode = ' '; static int my_pipe(HANDLE *readwrite) { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); /* Length in bytes */ sa.bInheritHandle = 1; /* the child must inherit these handles */ sa.lpSecurityDescriptor = NULL; if (! CreatePipe (&readwrite[0],&readwrite[1],&sa,1 << 13)) { errno = EMFILE; return -1; } return 0; } /*---------------------------------------------------------------------------- Replacement for 'popen()' under WIN32. NOTE: if cmd contains '2>&1', we connect the standard error file handle to the standard output file handle. ----------------------------------------------------------------------------*/ FILE * pt_popen(const char *cmd, const char *mode) { FILE *fptr = (FILE *)0; PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; int success, umlenkung; my_pipein[0] = INVALID_HANDLE_VALUE; my_pipein[1] = INVALID_HANDLE_VALUE; my_pipeout[0] = INVALID_HANDLE_VALUE; my_pipeout[1] = INVALID_HANDLE_VALUE; my_pipeerr[0] = INVALID_HANDLE_VALUE; my_pipeerr[1] = INVALID_HANDLE_VALUE; if (!mode || !*mode) goto finito; my_popenmode = *mode; if (my_popenmode != 'r' && my_popenmode != 'w') goto finito; /* * Shall we redirect stderr to stdout ? */ umlenkung = strstr("2>&1",(char *)cmd) != 0; /* * Create the Pipes... */ if (my_pipe(my_pipein) == -1 || my_pipe(my_pipeout) == -1) goto finito; if (!umlenkung && my_pipe(my_pipeerr) == -1) goto finito; /* * Now create the child process */ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdInput = my_pipein[0]; siStartInfo.hStdOutput = my_pipeout[1]; if (umlenkung) siStartInfo.hStdError = my_pipeout[1]; else siStartInfo.hStdError = my_pipeerr[1]; siStartInfo.dwFlags = STARTF_USESTDHANDLES; success = CreateProcess(NULL, (LPTSTR)cmd, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited DETACHED_PROCESS, // creation flags: without window (?) NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer &piProcInfo); // receives PROCESS_INFORMATION if (!success) goto finito; /* * These handles listen to the child process */ CloseHandle(my_pipein[0]); my_pipein[0] = INVALID_HANDLE_VALUE; CloseHandle(my_pipeout[1]); my_pipeout[1] = INVALID_HANDLE_VALUE; CloseHandle(my_pipeerr[1]); my_pipeerr[1] = INVALID_HANDLE_VALUE; if (my_popenmode == 'r') fptr = _fdopen(_open_osfhandle((long)my_pipeout[0],_O_BINARY),"r"); else fptr = _fdopen(_open_osfhandle((long)my_pipein[1],_O_BINARY),"w"); finito: if (!fptr) { if (my_pipein[0] != INVALID_HANDLE_VALUE) CloseHandle(my_pipein[0]); if (my_pipein[1] != INVALID_HANDLE_VALUE) CloseHandle(my_pipein[1]); if (my_pipeout[0] != INVALID_HANDLE_VALUE) CloseHandle(my_pipeout[0]); if (my_pipeout[1] != INVALID_HANDLE_VALUE) CloseHandle(my_pipeout[1]); if (my_pipeerr[0] != INVALID_HANDLE_VALUE) CloseHandle(my_pipeerr[0]); if (my_pipeerr[1] != INVALID_HANDLE_VALUE) CloseHandle(my_pipeerr[1]); } return fptr; } /*---------------------------------------------------------------------------- Replacement for 'pclose()' under WIN32 ----------------------------------------------------------------------------*/ int pt_pclose(FILE *fle) { if (fle) { (void)fclose(fle); CloseHandle(my_pipeerr[0]); if (my_popenmode == 'r') CloseHandle(my_pipein[1]); else CloseHandle(my_pipeout[0]); return 0; } return -1; } #endif /* !HAVE_POPEN && WIN32 */ libxmp-4.4.1/src/win32/ptpopen.h0000664000175000017500000000043612641457214016237 0ustar claudioclaudio#ifndef _PT_POPEN_H #define _PT_POPEN_H 1 #include #define popen pt_popen #define pclose pt_pclose #ifdef __cplusplus extern "C" { #endif FILE * pt_popen(const char *cmd, const char *mode); int pt_pclose(FILE *fle); #ifdef __cplusplus } #endif #endif /* _PT_POPEN_H */ libxmp-4.4.1/src/win32/osdcomm.h0000664000175000017500000000544112641457214016214 0ustar claudioclaudio#pragma once #ifndef __OSDCOMM_H__ #define __OSDCOMM_H__ #include #include #include #ifdef __cplusplus #include #endif /*************************************************************************** COMPILER-SPECIFIC NASTINESS ***************************************************************************/ /* The Win32 port requires this constant for variable arg routines. */ #ifndef CLIB_DECL #define CLIB_DECL #endif /* In C++ we can do type checking via typeid */ #ifdef __cplusplus #define TYPES_COMPATIBLE(a,b) (typeid(a) == typeid(b)) #endif /* Some optimizations/warnings cleanups for GCC */ #if defined(__GNUC__) && (__GNUC__ >= 3) #define ATTR_UNUSED __attribute__((__unused__)) #define ATTR_NORETURN __attribute__((noreturn)) #define ATTR_PRINTF(x,y) __attribute__((format(printf, x, y))) #define ATTR_MALLOC __attribute__((malloc)) #define ATTR_PURE __attribute__((pure)) #define ATTR_CONST __attribute__((const)) #define ATTR_FORCE_INLINE __attribute__((always_inline)) #define ATTR_NONNULL __attribute__((nonnull(1))) #define UNEXPECTED(exp) __builtin_expect((exp), 0) #define RESTRICT __restrict__ #define SETJMP_GNUC_PROTECT() (void)__builtin_return_address(1) #ifndef TYPES_COMPATIBLE #define TYPES_COMPATIBLE(a,b) __builtin_types_compatible_p(typeof(a), b) #endif #else #define ATTR_UNUSED #define ATTR_NORETURN #define ATTR_PRINTF(x,y) #define ATTR_MALLOC #define ATTR_PURE #define ATTR_CONST #define ATTR_FORCE_INLINE #define ATTR_NONNULL #define UNEXPECTED(exp) (exp) #define RESTRICT #define SETJMP_GNUC_PROTECT() do {} while (0) #ifndef TYPES_COMPATIBLE #define TYPES_COMPATIBLE(a,b) 1 #endif #endif /* And some MSVC optimizations/warnings */ #if defined(_MSC_VER) && (_MSC_VER >= 1200) #define DECL_NORETURN __declspec(noreturn) #else #define DECL_NORETURN #endif /*************************************************************************** FUNDAMENTAL CONSTANTS ***************************************************************************/ /* Ensure that TRUE/FALSE are defined */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /*************************************************************************** FUNDAMENTAL MACROS ***************************************************************************/ /* Standard MIN/MAX macros */ #ifndef MIN #define MIN(x,y) ((x) < (y) ? (x) : (y)) #endif #ifndef MAX #define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif /* U64 and S64 are used to wrap long integer constants. */ #ifdef __GNUC__ #define U64(val) val##ULL #define S64(val) val##LL #else #define U64(val) val #define S64(val) val #endif /* Highly useful macro for compile-time knowledge of an array size */ #define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])) #endif /* __OSDCOMM_H__ */ libxmp-4.4.1/src/win32/unistd.h0000664000175000017500000000012512664701330016047 0ustar claudioclaudio#ifndef LIBXMP_WIN32_UNISTD_H #define LIBXMP_WIN32_UNISTD_H #include #endif libxmp-4.4.1/src/win32/debug.c0000664000175000017500000000045412641457214015633 0ustar claudioclaudio/* * Win32 debug message helper by Mirko Buffoni */ #if defined WIN32 && defined _DEBUG #include #include void _D(const char *format, ...) { va_list argptr; /* do the output */ va_start(argptr, format); vprintf(format, argptr); printf("\n"); va_end(argptr); } #endif libxmp-4.4.1/src/win32/Makefile0000664000175000017500000000070212664701330016031 0ustar claudioclaudio WIN32_OBJS = ptpopen.o debug.o WIN32_DFILES = Makefile $(WIN32_OBJS:.o=.c) unistd.h ptpopen.h \ osdcomm.h sys WIN32_PATH = src/win32 ifeq ($(PLATFORM_DIR),win32) OBJS += $(addprefix $(WIN32_PATH)/,$(WIN32_OBJS)) CLEAN += $(addprefix $(WIN32_PATH)/,$(WIN32_CLEAN)) endif dist-win32: mkdir -p $(DIST)/$(WIN32_PATH) cp -RPp $(addprefix $(WIN32_PATH)/,$(WIN32_DFILES)) $(DIST)/$(WIN32_PATH) W_OBJS = $(addprefix $(WIN32_PATH)/,$(WIN32_OBJS)) libxmp-4.4.1/src/player.h0000664000175000017500000001525112774567167015125 0ustar claudioclaudio#ifndef LIBXMP_PLAYER_H #define LIBXMP_PLAYER_H #include "lfo.h" /* Quirk control */ #define HAS_QUIRK(x) (m->quirk & (x)) /* Channel flag control */ #define SET(f) SET_FLAG(xc->flags,(f)) #define RESET(f) RESET_FLAG(xc->flags,(f)) #define TEST(f) TEST_FLAG(xc->flags,(f)) /* Persistent effect flag control */ #define SET_PER(f) SET_FLAG(xc->per_flags,(f)) #define RESET_PER(f) RESET_FLAG(xc->per_flags,(f)) #define TEST_PER(f) TEST_FLAG(xc->per_flags,(f)) /* Note flag control */ #define SET_NOTE(f) SET_FLAG(xc->note_flags,(f)) #define RESET_NOTE(f) RESET_FLAG(xc->note_flags,(f)) #define TEST_NOTE(f) TEST_FLAG(xc->note_flags,(f)) struct retrig_control { int s; int m; int d; }; /* The following macros are used to set the flags for each channel */ #define VOL_SLIDE (1 << 0) #define PAN_SLIDE (1 << 1) #define TONEPORTA (1 << 2) #define PITCHBEND (1 << 3) #define VIBRATO (1 << 4) #define TREMOLO (1 << 5) #define FINE_VOLS (1 << 6) #define FINE_BEND (1 << 7) #define OFFSET (1 << 8) #define TRK_VSLIDE (1 << 9) #define TRK_FVSLIDE (1 << 10) #define NEW_INS (1 << 11) #define NEW_VOL (1 << 12) #define VOL_SLIDE_2 (1 << 13) #define NOTE_SLIDE (1 << 14) #define FINE_NSLIDE (1 << 15) #define NEW_NOTE (1 << 16) #define FINE_TPORTA (1 << 17) #define RETRIG (1 << 18) #define PANBRELLO (1 << 19) #define GVOL_SLIDE (1 << 20) #define TEMPO_SLIDE (1 << 21) #define VENV_PAUSE (1 << 22) #define PENV_PAUSE (1 << 23) #define FENV_PAUSE (1 << 24) #define FINE_VOLS_2 (1 << 25) #define KEY_OFF (1 << 26) /* for IT release on envloop end */ #define TREMOR (1 << 27) /* for XM tremor */ #define NOTE_FADEOUT (1 << 0) #define NOTE_RELEASE (1 << 1) #define NOTE_END (1 << 2) #define NOTE_CUT (1 << 3) #define NOTE_ENV_END (1 << 4) #define NOTE_SAMPLE_END (1 << 5) #define NOTE_SET (1 << 6) /* for IT portamento after keyoff */ #define NOTE_SUSEXIT (1 << 7) /* for delayed note release */ #define NOTE_KEY_CUT (1 << 8) /* note cut with XMP_KEY_CUT event */ #define NOTE_GLISSANDO (1 << 9) #define IS_VALID_INSTRUMENT(x) ((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 0) #define IS_VALID_INSTRUMENT_OR_SFX(x) (((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 0) || (smix->ins > 0 && (uint32)(x) < mod->ins + smix->ins)) struct instrument_vibrato { int phase; int sweep; }; struct channel_data { int flags; /* Channel flags */ int per_flags; /* Persistent effect channel flags */ int note_flags; /* Note release, fadeout or end */ int note; /* Note number */ int key; /* Key number */ double period; /* Amiga or linear period */ double per_adj; /* MED period/pitch adjustment factor hack */ int finetune; /* Guess what */ int ins; /* Instrument number */ int old_ins; /* Last instruemnt */ int smp; /* Sample number */ int mastervol; /* Master vol -- for IT track vol effect */ int delay; /* Note delay in frames */ int keyoff; /* Key off counter */ int fadeout; /* Current fadeout (release) value */ int ins_fade; /* Instrument fadeout value */ int volume; /* Current volume */ int gvl; /* Global volume for instrument for IT */ int rvv; /* Random volume variation */ int rpv; /* Random pan variation */ uint8 split; /* Split channel */ uint8 pair; /* Split channel pair */ int v_idx; /* Volume envelope index */ int p_idx; /* Pan envelope index */ int f_idx; /* Freq envelope index */ int key_porta; /* Key number for portamento target * -- needed to handle IT portamento xpo */ struct { struct lfo lfo; int memory; } vibrato; struct { struct lfo lfo; int memory; } tremolo; #ifndef LIBXMP_CORE_DISABLE_IT struct { struct lfo lfo; int memory; } panbrello; #endif struct { int8 val[16]; /* 16 for Smaksak MegaArps */ int size; int count; int memory; } arpeggio; struct { struct lfo lfo; int sweep; } insvib; struct { int val; int val2; /* For fx9 bug emulation */ int memory; } offset; struct { int val; /* Retrig value */ int count; /* Retrig counter */ int type; /* Retrig type */ } retrig; struct { uint8 up,down; /* Tremor value */ uint8 count; /* Tremor counter */ uint8 memory; /* Tremor memory */ } tremor; struct { int slide; /* Volume slide value */ int fslide; /* Fine volume slide value */ int slide2; /* Volume slide value */ int memory; /* Volume slide effect memory */ #ifndef LIBXMP_CORE_DISABLE_IT int fslide2; int memory2; /* Volume slide effect memory */ #endif } vol; struct { int up_memory; /* Fine volume slide up memory (XM) */ int down_memory;/* Fine volume slide up memory (XM) */ } fine_vol; struct { int slide; /* Global volume slide value */ int fslide; /* Fine global volume slide value */ int memory; /* Global volume memory is saved per channel */ } gvol; struct { int slide; /* Track volume slide value */ int fslide; /* Track fine volume slide value */ int memory; /* Track volume slide effect memory */ } trackvol; struct { int slide; /* Frequency slide value */ double fslide; /* Fine frequency slide value */ int memory; /* Portamento effect memory */ } freq; struct { double target; /* Target period for tone portamento */ int dir; /* Tone portamento up/down directionh */ int slide; /* Delta for tone portamento */ int memory; /* Tone portamento effect memory */ } porta; struct { int up_memory; /* FT2 has separate memories for these */ int down_memory;/* cases (see Porta-LinkMem.xm) */ } fine_porta; struct { int val; /* Current pan value */ int slide; /* Pan slide value */ int fslide; /* Pan fine slide value */ int memory; /* Pan slide effect memory */ int surround; /* Surround channel flag */ } pan; struct { int speed; int count; int pos; } invloop; #ifndef LIBXMP_CORE_DISABLE_IT struct { int slide; /* IT tempo slide */ } tempo; struct { int cutoff; /* IT filter cutoff frequency */ int resonance; /* IT filter resonance */ int envelope; /* IT filter envelope */ } filter; #endif #ifndef LIBXMP_CORE_PLAYER struct { int slide; /* PTM note slide amount */ int fslide; /* OKT fine note slide amount */ int speed; /* PTM note slide speed */ int count; /* PTM note slide counter */ } noteslide; void *extra; #endif struct xmp_event delayed_event; int delayed_ins; /* IT save instrument emulation */ int info_period; /* Period */ int info_pitchbend; /* Linear pitchbend */ int info_position; /* Position before mixing */ int info_finalvol; /* Final volume including envelopes */ int info_finalpan; /* Final pan including envelopes */ }; void libxmp_process_fx (struct context_data *, struct channel_data *, int, struct xmp_event *, int); void libxmp_filter_setup (int, int, int, int*, int*, int *); int libxmp_read_event (struct context_data *, struct xmp_event *, int); #endif /* LIBXMP_PLAYER_H */ libxmp-4.4.1/src/memio.c0000664000175000017500000000551312773571316014720 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #ifndef LIBXMP_CORE_PLAYER #include #include #endif #include "common.h" #include "memio.h" static inline ptrdiff_t CAN_READ(MFILE *m) { if (m->size >= 0) return m->pos >= 0 ? m->size - m->pos : 0; return INT_MAX; } int mgetc(MFILE *m) { if (CAN_READ(m) >= 1) return *(uint8 *)(m->start + m->pos++); else return EOF; } size_t mread(void *buf, size_t size, size_t num, MFILE *m) { size_t should_read = size * num; ptrdiff_t can_read = CAN_READ(m); if (size <= 0 || num <= 0 || can_read <= 0) { return 0; } if (should_read > can_read) { should_read = can_read; } memcpy(buf, m->start + m->pos, should_read); m->pos += should_read; return should_read / size; } int mseek(MFILE *m, long offset, int whence) { switch (whence) { default: case SEEK_SET: if (m->size >= 0 && (offset > m->size || offset < 0)) return -1; m->pos = offset; return 0; case SEEK_CUR: if (m->size >= 0 && (offset > CAN_READ(m) || offset < -m->pos)) return -1; m->pos += offset; return 0; case SEEK_END: if (m->size < 0) return -1; m->pos = m->size + offset; return 0; } } long mtell(MFILE *m) { return (long)m->pos; } int meof(MFILE *m) { if (m->size <= 0) return 0; else return CAN_READ(m) <= 0; } MFILE *mopen(void *ptr, long size) { MFILE *m; m = (MFILE *)malloc(sizeof (MFILE)); if (m == NULL) return NULL; m->start = ptr; m->pos = 0; m->size = size; return m; } int mclose(MFILE *m) { free(m); return 0; } #ifndef LIBXMP_CORE_PLAYER int mstat(MFILE *m, struct stat *st) { memset(st, 0, sizeof (struct stat)); st->st_size = m->size; return 0; } #endif libxmp-4.4.1/src/list.h0000664000175000017500000000647612773463510014577 0ustar claudioclaudio#ifndef LIBXMP_LIST_H #define LIBXMP_LIST_H #ifdef _MSC_VER #define __inline__ __inline #endif /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_add(struct list_head *_new, struct list_head * prev, struct list_head * next) { next->prev = _new; _new->next = next; _new->prev = prev; prev->next = _new; } /** * list_add - add a new entry * @_new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static __inline__ void list_add(struct list_head *_new, struct list_head *head) { __list_add(_new, head, head->next); } /** * list_add_tail - add a new entry * @_new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static __inline__ void list_add_tail(struct list_head *_new, struct list_head *head) { __list_add(_new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. */ static __inline__ void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static __inline__ int list_empty(struct list_head *head) { return head->next == head; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static __inline__ void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #endif libxmp-4.4.1/src/filter.c0000664000175000017500000001211612773571316015074 0ustar claudioclaudio/* * Based on the public domain version by Olivier Lapicque * Rewritten for libxmp by Claudio Matsuoka * * Copyright (C) 2012 Claudio Matsuoka * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef LIBXMP_CORE_DISABLE_IT #include #include "xmp.h" #include "common.h" #include "mixer.h" /* LUT for 2 * damping factor */ static const float resonance_table[128] = { 1.0000000000000000f, 0.9786446094512940f, 0.9577452540397644f, 0.9372922182083130f, 0.9172759056091309f, 0.8976871371269226f, 0.8785166740417481f, 0.8597555756568909f, 0.8413951396942139f, 0.8234267830848694f, 0.8058421611785889f, 0.7886331081390381f, 0.7717915177345276f, 0.7553095817565918f, 0.7391796708106995f, 0.7233941555023193f, 0.7079457640647888f, 0.6928272843360901f, 0.6780316829681397f, 0.6635520458221436f, 0.6493816375732422f, 0.6355138421058655f, 0.6219421625137329f, 0.6086603403091431f, 0.5956621170043945f, 0.5829415321350098f, 0.5704925656318665f, 0.5583094954490662f, 0.5463865399360657f, 0.5347182154655457f, 0.5232990980148315f, 0.5121238231658936f, 0.5011872053146362f, 0.4904841780662537f, 0.4800096750259399f, 0.4697588682174683f, 0.4597269892692566f, 0.4499093294143677f, 0.4403013288974762f, 0.4308985173702240f, 0.4216965138912201f, 0.4126909971237183f, 0.4038778245449066f, 0.3952528536319733f, 0.3868120610713959f, 0.3785515129566193f, 0.3704673945903778f, 0.3625559210777283f, 0.3548133969306946f, 0.3472362160682678f, 0.3398208320140839f, 0.3325638175010681f, 0.3254617750644684f, 0.3185114264488220f, 0.3117094635963440f, 0.3050527870655060f, 0.2985382676124573f, 0.2921628654003143f, 0.2859236001968384f, 0.2798175811767578f, 0.2738419771194458f, 0.2679939568042755f, 0.2622708380222321f, 0.2566699385643005f, 0.2511886358261108f, 0.2458244115114212f, 0.2405747324228287f, 0.2354371547698975f, 0.2304092943668366f, 0.2254888117313385f, 0.2206734120845795f, 0.2159608304500580f, 0.2113489061594009f, 0.2068354636430740f, 0.2024184018373489f, 0.1980956792831421f, 0.1938652694225311f, 0.1897251904010773f, 0.1856735348701477f, 0.1817083954811096f, 0.1778279393911362f, 0.1740303486585617f, 0.1703138649463654f, 0.1666767448186874f, 0.1631172895431519f, 0.1596338599920273f, 0.1562248021364212f, 0.1528885662555695f, 0.1496235728263855f, 0.1464282870292664f, 0.1433012634515762f, 0.1402409970760346f, 0.1372461020946503f, 0.1343151479959488f, 0.1314467936754227f, 0.1286396980285645f, 0.1258925348520279f, 0.1232040524482727f, 0.1205729842185974f, 0.1179980933666229f, 0.1154781952500343f, 0.1130121126770973f, 0.1105986908078194f, 0.1082368120551109f, 0.1059253737330437f, 0.1036632955074310f, 0.1014495193958283f, 0.0992830246686935f, 0.0971627980470657f, 0.0950878411531448f, 0.0930572077631950f, 0.0910699293017387f, 0.0891250967979431f, 0.0872217938303947f, 0.0853591337800026f, 0.0835362523794174f, 0.0817523002624512f, 0.0800064504146576f, 0.0782978758215904f, 0.0766257941722870f, 0.0749894231557846f, 0.0733879879117012f, 0.0718207582831383f, 0.0702869966626167f, 0.0687859877943993f, 0.0673170387744904f, 0.0658794566988945f, 0.0644725710153580f, }; /* * Simple 2-poles resonant filter */ #define FREQ_PARAM_MULT (128.0f / (24.0f * 256.0f)) void libxmp_filter_setup(int srate, int cutoff, int res, int *a0, int *b0, int *b1) { float fc, fs = (float)srate; float fg, fb0, fb1; float r, d, e; /* [0-255] => [100Hz-8000Hz] */ CLAMP(cutoff, 0, 255); CLAMP(res, 0, 255); fc = 110.0f * powf(2.0f, (float)cutoff * FREQ_PARAM_MULT + 0.25f); if (fc > fs / 2.0f) { fc = fs / 2.0f; } r = fs / (2.0 * 3.14159265358979f * fc); d = resonance_table[res >> 1] * (r + 1.0) - 1.0; e = r * r; fg = 1.0 / (1.0 + d + e); fb0 = (d + e + e) / (1.0 + d + e); fb1 = -e / (1.0 + d + e); *a0 = (int)(fg * (1 << FILTER_SHIFT)); *b0 = (int)(fb0 * (1 << FILTER_SHIFT)); *b1 = (int)(fb1 * (1 << FILTER_SHIFT)); } #endif libxmp-4.4.1/src/mix_paula.c0000664000175000017500000000707612775035311015567 0ustar claudioclaudio#include "common.h" #ifdef LIBXMP_PAULA_SIMULATOR /* * Based on Antti S. Lankila's reference code, modified for libxmp * by Claudio Matsuoka. */ #include "virtual.h" #include "mixer.h" #include "paula.h" #include "precomp_blep.h" void libxmp_paula_init(struct context_data *ctx, struct paula_state *paula) { struct mixer_data *s = &ctx->s; paula->global_output_level = 0; paula->active_bleps = 0; paula->fdiv = (double)PAULA_HZ / s->freq; paula->remainder = paula->fdiv; } /* return output simulated as series of bleps */ static int16 output_sample(struct paula_state *paula, int tabnum) { int i; int32 output; output = paula->global_output_level << BLEP_SCALE; for (i = 0; i < paula->active_bleps; i++) { int age = paula->blepstate[i].age; int level = paula->blepstate[i].level; output -= winsinc_integral[tabnum][age] * level; } output >>= BLEP_SCALE; if (output < -32768) output = -32768; else if (output > 32767) output = 32767; return output; } static void input_sample(struct paula_state *paula, int16 sample) { if (sample != paula->global_output_level) { /* Start a new blep: level is the difference, age (or phase) is 0 clocks. */ if (paula->active_bleps > MAX_BLEPS - 1) { fprintf(stderr, "warning: active blep list truncated!\n"); paula->active_bleps = MAX_BLEPS - 1; } /* Make room for new blep */ memmove(&paula->blepstate[1], &paula->blepstate[0], sizeof(struct blep_state) * paula->active_bleps); /* Update state to account for the new blep */ paula->active_bleps++; paula->blepstate[0].age = 0; paula->blepstate[0].level = sample - paula->global_output_level; paula->global_output_level = sample; } } static void do_clock(struct paula_state *paula, unsigned int cycles) { int i; if (cycles <= 0) { return; } for (i = 0; i < paula->active_bleps; i++) { paula->blepstate[i].age += cycles; if (paula->blepstate[i].age >= BLEP_SIZE) { paula->active_bleps = i; break; } } } #define LOOP for (; count; count--) #define UPDATE_POS(x) do { \ frac += (x); \ pos += frac >> SMIX_SHIFT; \ frac &= SMIX_MASK; \ } while (0) #define PAULA_SIMULATION(x) do { \ int num_in = vi->paula->remainder / MINIMUM_INTERVAL; \ int ministep = step / num_in; \ int i; \ \ /* input is always sampled at a higher rate than output */ \ for (i = 0; i < num_in - 1; i++) { \ input_sample(vi->paula, sptr[pos]); \ do_clock(vi->paula, MINIMUM_INTERVAL); \ UPDATE_POS(ministep); \ } \ input_sample(vi->paula, sptr[pos]); \ vi->paula->remainder -= num_in * MINIMUM_INTERVAL; \ \ do_clock(vi->paula, (int)vi->paula->remainder); \ smp_in = output_sample(vi->paula, (x)); \ do_clock(vi->paula, MINIMUM_INTERVAL - (int)vi->paula->remainder); \ UPDATE_POS(step - (num_in - 1) * ministep); \ \ vi->paula->remainder += vi->paula->fdiv; \ } while (0) #define MIX_MONO() do { \ *(buffer++) += smp_in * vl; \ } while (0) #define MIX_STEREO() do { \ *(buffer++) += smp_in * vr; \ *(buffer++) += smp_in * vl; \ } while (0) #define VAR_NORM(x) \ int smp_in; \ x *sptr = vi->sptr; \ unsigned int pos = vi->pos; \ int frac = (1 << SMIX_SHIFT) * (vi->pos - (int)vi->pos) #define VAR_PAULA(x) \ VAR_NORM(x); \ vl <<= 8; \ vr <<= 8 MIXER(mono_a500) { VAR_PAULA(int8); LOOP { PAULA_SIMULATION(0); MIX_MONO(); } } MIXER(mono_a500_filter) { VAR_PAULA(int8); LOOP { PAULA_SIMULATION(1); MIX_MONO(); } } MIXER(stereo_a500) { VAR_PAULA(int8); LOOP { PAULA_SIMULATION(0); MIX_STEREO(); } } MIXER(stereo_a500_filter) { VAR_PAULA(int8); LOOP { PAULA_SIMULATION(1); MIX_STEREO(); } } #endif /* LIBXMP_PAULA_SIMULATOR */ libxmp-4.4.1/src/mixer.c0000664000175000017500000004371012775035311014727 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "common.h" #include "virtual.h" #include "mixer.h" #include "period.h" #include "player.h" /* for set_sample_end() */ #ifdef LIBXMP_PAULA_SIMULATOR #include "paula.h" #endif #define FLAG_16_BITS 0x01 #define FLAG_STEREO 0x02 #define FLAG_FILTER 0x04 #define FLAG_ACTIVE 0x10 /* #define FLAG_SYNTH 0x20 */ #define FIDX_FLAGMASK (FLAG_16_BITS | FLAG_STEREO | FLAG_FILTER) #define DOWNMIX_SHIFT 12 #define LIM8_HI 127 #define LIM8_LO -128 #define LIM16_HI 32767 #define LIM16_LO -32768 #define MIX_FN(x) void libxmp_mix_##x(struct mixer_voice *, int *, int, int, int, int, int, int, int) MIX_FN(mono_8bit_nearest); MIX_FN(mono_8bit_linear); MIX_FN(mono_16bit_nearest); MIX_FN(mono_16bit_linear); MIX_FN(stereo_8bit_nearest); MIX_FN(stereo_8bit_linear); MIX_FN(stereo_16bit_nearest); MIX_FN(stereo_16bit_linear); MIX_FN(mono_8bit_spline); MIX_FN(mono_16bit_spline); MIX_FN(stereo_8bit_spline); MIX_FN(stereo_16bit_spline); #ifndef LIBXMP_CORE_DISABLE_IT MIX_FN(mono_8bit_linear_filter); MIX_FN(mono_16bit_linear_filter); MIX_FN(stereo_8bit_linear_filter); MIX_FN(stereo_16bit_linear_filter); MIX_FN(mono_8bit_spline_filter); MIX_FN(mono_16bit_spline_filter); MIX_FN(stereo_8bit_spline_filter); MIX_FN(stereo_16bit_spline_filter); #endif #ifdef LIBXMP_PAULA_SIMULATOR MIX_FN(mono_a500); MIX_FN(mono_a500_filter); MIX_FN(stereo_a500); MIX_FN(stereo_a500_filter); #endif /* Mixers array index: * * bit 0: 0=8 bit sample, 1=16 bit sample * bit 1: 0=mono output, 1=stereo output * bit 2: 0=unfiltered, 1=filtered */ typedef void (*mixer_set[])(struct mixer_voice *, int *, int, int, int, int, int, int, int); static mixer_set nearest_mixers = { libxmp_mix_mono_8bit_nearest, libxmp_mix_mono_16bit_nearest, libxmp_mix_stereo_8bit_nearest, libxmp_mix_stereo_16bit_nearest, #ifndef LIBXMP_CORE_DISABLE_IT libxmp_mix_mono_8bit_nearest, libxmp_mix_mono_16bit_nearest, libxmp_mix_stereo_8bit_nearest, libxmp_mix_stereo_16bit_nearest, #endif }; static mixer_set linear_mixers = { libxmp_mix_mono_8bit_linear, libxmp_mix_mono_16bit_linear, libxmp_mix_stereo_8bit_linear, libxmp_mix_stereo_16bit_linear, #ifndef LIBXMP_CORE_DISABLE_IT libxmp_mix_mono_8bit_linear_filter, libxmp_mix_mono_16bit_linear_filter, libxmp_mix_stereo_8bit_linear_filter, libxmp_mix_stereo_16bit_linear_filter #endif }; static mixer_set spline_mixers = { libxmp_mix_mono_8bit_spline, libxmp_mix_mono_16bit_spline, libxmp_mix_stereo_8bit_spline, libxmp_mix_stereo_16bit_spline, #ifndef LIBXMP_CORE_DISABLE_IT libxmp_mix_mono_8bit_spline_filter, libxmp_mix_mono_16bit_spline_filter, libxmp_mix_stereo_8bit_spline_filter, libxmp_mix_stereo_16bit_spline_filter #endif }; #ifdef LIBXMP_PAULA_SIMULATOR static mixer_set a500_mixers = { libxmp_mix_mono_a500, NULL, libxmp_mix_stereo_a500, NULL, NULL, NULL, NULL, NULL }; static mixer_set a500led_mixers = { libxmp_mix_mono_a500_filter, NULL, libxmp_mix_stereo_a500_filter, NULL, NULL, NULL, NULL, NULL }; #endif /* Downmix 32bit samples to 8bit, signed or unsigned, mono or stereo output */ static void downmix_int_8bit(char *dest, int32 *src, int num, int amp, int offs) { int smp; int shift = DOWNMIX_SHIFT + 8 - amp; for (; num--; src++, dest++) { smp = *src >> shift; if (smp > LIM8_HI) { *dest = LIM8_HI; } else if (smp < LIM8_LO) { *dest = LIM8_LO; } else { *dest = smp; } if (offs) *dest += offs; } } /* Downmix 32bit samples to 16bit, signed or unsigned, mono or stereo output */ static void downmix_int_16bit(int16 *dest, int32 *src, int num, int amp, int offs) { int smp; int shift = DOWNMIX_SHIFT - amp; for (; num--; src++, dest++) { smp = *src >> shift; if (smp > LIM16_HI) { *dest = LIM16_HI; } else if (smp < LIM16_LO) { *dest = LIM16_LO; } else { *dest = smp; } if (offs) *dest += offs; } } static void anticlick(struct mixer_voice *vi) { vi->flags |= ANTICLICK; vi->old_vl = 0; vi->old_vr = 0; } /* Ok, it's messy, but it works :-) Hipolito */ static void do_anticlick(struct context_data *ctx, int voc, int32 *buf, int count) { struct player_data *p = &ctx->p; struct mixer_data *s = &ctx->s; struct mixer_voice *vi = &p->virt.voice_array[voc]; int smp_l, smp_r, max_x2; int discharge = s->ticksize >> ANTICLICK_SHIFT; smp_r = vi->sright; smp_l = vi->sleft; vi->sright = vi->sleft = 0; if (smp_l == 0 && smp_r == 0) { return; } if (buf == NULL) { buf = s->buf32; count = discharge; } else if (count > discharge) { count = discharge; } if (count <= 0) { return; } max_x2 = count * count; while (count--) { if (~s->format & XMP_FORMAT_MONO) { *buf++ += (count * (smp_r >> 10) / max_x2 * count) << 10; } *buf++ += (count * (smp_l >> 10) / max_x2 * count) << 10; } } static void set_sample_end(struct context_data *ctx, int voc, int end) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct mixer_voice *vi = &p->virt.voice_array[voc]; struct channel_data *xc; if ((uint32)voc >= p->virt.maxvoc) return; xc = &p->xc_data[vi->chn]; if (end) { SET_NOTE(NOTE_SAMPLE_END); if (HAS_QUIRK(QUIRK_RSTCHN)) { libxmp_virt_resetvoice(ctx, voc, 0); } } else { RESET_NOTE(NOTE_SAMPLE_END); } } static void adjust_voice_end(struct mixer_voice *vi, struct xmp_sample *xxs) { if (xxs->flg & XMP_SAMPLE_LOOP) { if ((xxs->flg & XMP_SAMPLE_LOOP_FULL) && (~vi->flags & SAMPLE_LOOP)) { vi->end = xxs->len; } else { vi->end = xxs->lpe; } } else { vi->end = xxs->len; } } static void loop_reposition(struct context_data *ctx, struct mixer_voice *vi, struct xmp_sample *xxs) { #ifndef LIBXMP_CORE_DISABLE_IT struct module_data *m = &ctx->m; #endif int loop_size = xxs->lpe - xxs->lps; /* Reposition for next loop */ vi->pos -= loop_size; /* forward loop */ vi->end = xxs->lpe; vi->flags |= SAMPLE_LOOP; if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { vi->end += loop_size; /* unrolled loop */ vi->pos -= loop_size; /* forward loop */ #ifndef LIBXMP_CORE_DISABLE_IT /* OpenMPT Bidi-Loops.it: "In Impulse Tracker’s software mixer, * ping-pong loops are shortened by one sample. */ if (IS_PLAYER_MODE_IT()) { vi->end--; vi->pos++; } #endif } } /* Prepare the mixer for the next tick */ void libxmp_mixer_prepare(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct mixer_data *s = &ctx->s; int bytelen; s->ticksize = s->freq * m->time_factor * m->rrate / p->bpm / 1000; bytelen = s->ticksize * sizeof(int); if (~s->format & XMP_FORMAT_MONO) { bytelen *= 2; } memset(s->buf32, 0, bytelen); } /* Fill the output buffer calling one of the handlers. The buffer contains * sound for one tick (a PAL frame or 1/50s for standard vblank-timed mods) */ void libxmp_mixer_softmixer(struct context_data *ctx) { struct player_data *p = &ctx->p; struct mixer_data *s = &ctx->s; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_sample *xxs; struct mixer_voice *vi; double step; int samples, size; int vol_l, vol_r, voc, usmp; int prev_l, prev_r = 0; int lps, lpe; int32 *buf_pos; void (*mix_fn)(struct mixer_voice *, int *, int, int, int, int, int, int, int); mixer_set *mixers; switch (s->interp) { case XMP_INTERP_NEAREST: mixers = &nearest_mixers; break; case XMP_INTERP_LINEAR: mixers = &linear_mixers; break; case XMP_INTERP_SPLINE: mixers = &spline_mixers; break; default: mixers = &linear_mixers; } #ifdef LIBXMP_PAULA_SIMULATOR if (p->flags & XMP_FLAGS_A500) { if (IS_AMIGA_MOD()) { if (p->filter) { mixers = &a500led_mixers; } else { mixers = &a500_mixers; } } } #endif libxmp_mixer_prepare(ctx); for (voc = 0; voc < p->virt.maxvoc; voc++) { int c5spd; vi = &p->virt.voice_array[voc]; if (vi->flags & ANTICLICK) { if (s->interp > XMP_INTERP_NEAREST) { do_anticlick(ctx, voc, NULL, 0); } vi->flags &= ~ANTICLICK; } if (vi->chn < 0) { continue; } if (vi->period < 1) { libxmp_virt_resetvoice(ctx, voc, 1); continue; } vi->pos0 = vi->pos; buf_pos = s->buf32; if (vi->pan == PAN_SURROUND) { vol_r = vi->vol * 0x80; vol_l = -vi->vol * 0x80; } else { vol_r = vi->vol * (0x80 - vi->pan); vol_l = vi->vol * (0x80 + vi->pan); } if (vi->smp < mod->smp) { xxs = &mod->xxs[vi->smp]; c5spd = m->xtra[vi->smp].c5spd; } else { xxs = &ctx->smix.xxs[vi->smp - mod->smp]; c5spd = m->c4rate; } step = C4_PERIOD * c5spd / s->freq / vi->period; if (step < 0.001) { /* otherwise m5v-nwlf.it crashes */ continue; } #ifndef LIBXMP_CORE_DISABLE_IT if (xxs->flg & XMP_SAMPLE_SLOOP && vi->smp < mod->smp) { if (~vi->flags & VOICE_RELEASE) { if (vi->pos < m->xsmp[vi->smp].lpe) { xxs = &m->xsmp[vi->smp]; } } } adjust_voice_end(vi, xxs); #endif lps = xxs->lps; lpe = xxs->lpe; if (p->flags & XMP_FLAGS_FIXLOOP) { lps >>= 1; } if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { vi->end += lpe - lps; #ifndef LIBXMP_CORE_DISABLE_IT if (IS_PLAYER_MODE_IT()) { vi->end--; } #endif } int rampsize = s->ticksize >> ANTICLICK_SHIFT; int delta_l = (vol_l - vi->old_vl) / rampsize; int delta_r = (vol_r - vi->old_vr) / rampsize; usmp = 0; for (size = s->ticksize; size > 0; ) { int split_noloop = 0; if (p->xc_data[vi->chn].split) { split_noloop = 1; } /* How many samples we can write before the loop break * or sample end... */ if (vi->pos >= vi->end) { samples = 0; usmp = 1; } else { int s = ceil(((double)vi->end - vi->pos) / step); /* ...inside the tick boundaries */ if (s > size) { s = size; } samples = s; if (samples > 0) { usmp = 0; } } if (vi->vol) { int mix_size = samples; int mixer = vi->fidx & FIDX_FLAGMASK; if (~s->format & XMP_FORMAT_MONO) { mix_size *= 2; } /* For Hipolito's anticlick routine */ if (samples > 0) { if (~s->format & XMP_FORMAT_MONO) { prev_r = buf_pos[mix_size - 2]; } prev_l = buf_pos[mix_size - 1]; } else { prev_r = prev_l = 0; } #ifndef LIBXMP_CORE_DISABLE_IT /* See OpenMPT env-flt-max.it */ if (vi->filter.cutoff >= 0xfe && vi->filter.resonance == 0) { mixer &= ~FLAG_FILTER; } #endif mix_fn = (*mixers)[mixer]; /* Call the output handler */ if (samples > 0 && vi->sptr != NULL) { int rsize = 0; if (rampsize > samples) { rampsize -= samples; } else { rsize = samples - rampsize; rampsize = 0; } if (delta_l == 0 && delta_r == 0) { /* no need to ramp */ rsize = samples; } if (mix_fn != NULL) { mix_fn(vi, buf_pos, samples, vol_l >> 8, vol_r >> 8, step * (1 << SMIX_SHIFT), rsize, delta_l, delta_r); } buf_pos += mix_size; vi->old_vl += samples * delta_l; vi->old_vr += samples * delta_r; /* For Hipolito's anticlick routine */ if (~s->format & XMP_FORMAT_MONO) { vi->sright = buf_pos[-2] - prev_r; } vi->sleft = buf_pos[-1] - prev_l; } } vi->pos += step * samples; /* No more samples in this tick */ size -= samples + usmp; if (size <= 0) { if (xxs->flg & XMP_SAMPLE_LOOP) { if (vi->pos + step > vi->end) { vi->pos += step; loop_reposition(ctx, vi, xxs); } } continue; } /* First sample loop run */ if ((~xxs->flg & XMP_SAMPLE_LOOP) || split_noloop) { do_anticlick(ctx, voc, buf_pos, size); set_sample_end(ctx, voc, 1); size = 0; continue; } loop_reposition(ctx, vi, xxs); } vi->old_vl = vol_l; vi->old_vr = vol_r; } /* Render final frame */ size = s->ticksize; if (~s->format & XMP_FORMAT_MONO) { size *= 2; } if (size > XMP_MAX_FRAMESIZE) { size = XMP_MAX_FRAMESIZE; } if (s->format & XMP_FORMAT_8BIT) { downmix_int_8bit(s->buffer, s->buf32, size, s->amplify, s->format & XMP_FORMAT_UNSIGNED ? 0x80 : 0); } else { downmix_int_16bit((int16 *)s->buffer, s->buf32, size,s->amplify, s->format & XMP_FORMAT_UNSIGNED ? 0x8000 : 0); } s->dtright = s->dtleft = 0; } void libxmp_mixer_voicepos(struct context_data *ctx, int voc, double pos, int ac) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct mixer_voice *vi = &p->virt.voice_array[voc]; struct xmp_sample *xxs; int lps; if (vi->smp < m->mod.smp) { xxs = &m->mod.xxs[vi->smp]; } else { xxs = &ctx->smix.xxs[vi->smp - m->mod.smp]; } if (xxs->flg & XMP_SAMPLE_SYNTH) { return; } vi->pos = pos; adjust_voice_end(vi, xxs); if (vi->pos >= vi->end) { if (xxs->flg & XMP_SAMPLE_LOOP) { vi->pos = xxs->lps; } else { vi->pos = xxs->len; } } lps = xxs->lps; if (p->flags & XMP_FLAGS_FIXLOOP) { lps >>= 1; } if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { vi->end += (xxs->lpe - lps); #ifndef LIBXMP_CORE_DISABLE_IT if (IS_PLAYER_MODE_IT()) { vi->end--; } #endif } if (ac) { anticlick(vi); } } double libxmp_mixer_getvoicepos(struct context_data *ctx, int voc) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; struct xmp_sample *xxs; xxs = libxmp_get_sample(ctx, vi->smp); if (xxs->flg & XMP_SAMPLE_SYNTH) { return 0; } if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { if (vi->pos >= xxs->lpe) { return xxs->lpe - (vi->pos - xxs->lpe) - 1; } } return vi->pos; } void libxmp_mixer_setpatch(struct context_data *ctx, int voc, int smp, int ac) { struct player_data *p = &ctx->p; #ifndef LIBXMP_CORE_DISABLE_IT struct module_data *m = &ctx->m; #endif struct mixer_data *s = &ctx->s; struct mixer_voice *vi = &p->virt.voice_array[voc]; struct xmp_sample *xxs; xxs = libxmp_get_sample(ctx, smp); vi->smp = smp; vi->vol = 0; vi->pan = 0; vi->flags &= ~SAMPLE_LOOP; vi->fidx = 0; if (~s->format & XMP_FORMAT_MONO) { vi->fidx |= FLAG_STEREO; } set_sample_end(ctx, voc, 0); /*mixer_setvol(ctx, voc, 0);*/ vi->sptr = xxs->data; vi->fidx |= FLAG_ACTIVE; #ifndef LIBXMP_CORE_DISABLE_IT if (HAS_QUIRK(QUIRK_FILTER) && s->dsp & XMP_DSP_LOWPASS) { vi->fidx |= FLAG_FILTER; } #endif if (xxs->flg & XMP_SAMPLE_16BIT) { vi->fidx |= FLAG_16_BITS; } libxmp_mixer_voicepos(ctx, voc, 0, ac); } void libxmp_mixer_setnote(struct context_data *ctx, int voc, int note) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; /* FIXME: Workaround for crash on notes that are too high * see 6nations.it (+114 transposition on instrument 16) */ if (note > 149) { note = 149; } vi->note = note; vi->period = libxmp_note_to_period_mix(note, 0); anticlick(vi); } void libxmp_mixer_setperiod(struct context_data *ctx, int voc, double period) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; vi->period = period; } void libxmp_mixer_setvol(struct context_data *ctx, int voc, int vol) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; if (vol == 0) { anticlick(vi); } vi->vol = vol; } void libxmp_mixer_release(struct context_data *ctx, int voc, int rel) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; if (rel) { vi->flags |= VOICE_RELEASE; } else { vi->flags &= ~VOICE_RELEASE; } } void libxmp_mixer_seteffect(struct context_data *ctx, int voc, int type, int val) { #ifndef LIBXMP_CORE_DISABLE_IT struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; switch (type) { case DSP_EFFECT_CUTOFF: vi->filter.cutoff = val; break; case DSP_EFFECT_RESONANCE: vi->filter.resonance = val; break; case DSP_EFFECT_FILTER_A0: vi->filter.a0 = val; break; case DSP_EFFECT_FILTER_B0: vi->filter.b0 = val; break; case DSP_EFFECT_FILTER_B1: vi->filter.b1 = val; break; } #endif } void libxmp_mixer_setpan(struct context_data *ctx, int voc, int pan) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; vi->pan = pan; } int libxmp_mixer_numvoices(struct context_data *ctx, int num) { struct mixer_data *s = &ctx->s; if (num > s->numvoc || num < 0) { return s->numvoc; } else { return num; } } int libxmp_mixer_on(struct context_data *ctx, int rate, int format, int c4rate) { struct mixer_data *s = &ctx->s; s->buffer = calloc(2, XMP_MAX_FRAMESIZE); if (s->buffer == NULL) goto err; s->buf32 = calloc(sizeof(int), XMP_MAX_FRAMESIZE); if (s->buf32 == NULL) goto err1; s->freq = rate; s->format = format; s->amplify = DEFAULT_AMPLIFY; s->mix = DEFAULT_MIX; /* s->pbase = C4_PERIOD * c4rate / s->freq; */ s->interp = XMP_INTERP_LINEAR; /* default interpolation type */ s->dsp = XMP_DSP_LOWPASS; /* enable filters by default */ /* s->numvoc = SMIX_NUMVOC; */ s->dtright = s->dtleft = 0; return 0; err1: free(s->buffer); err: return -1; } void libxmp_mixer_off(struct context_data *ctx) { struct mixer_data *s = &ctx->s; free(s->buffer); free(s->buf32); s->buf32 = NULL; s->buffer = NULL; } libxmp-4.4.1/src/loaders/0000775000175000017500000000000012777546220015073 5ustar claudioclaudiolibxmp-4.4.1/src/loaders/dt_load.c0000664000175000017500000001716312775035311016645 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "loader.h" #include "iff.h" #include "period.h" #define MAGIC_D_T_ MAGIC4('D','.','T','.') static int dt_test(HIO_HANDLE *, char *, const int); static int dt_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_dt = { "Digital Tracker", dt_test, dt_load }; static int dt_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_D_T_) return -1; hio_read32b(f); /* chunk size */ hio_read16b(f); /* type */ hio_read16b(f); /* 0xff then mono */ hio_read16b(f); /* reserved */ hio_read16b(f); /* tempo */ hio_read16b(f); /* bpm */ hio_read32b(f); /* undocumented */ libxmp_read_title(f, t, 32); return 0; } struct local_data { int pflag, sflag; int realpat; int last_pat; int insnum; }; static int get_d_t_(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int b; hio_read16b(f); /* type */ hio_read16b(f); /* 0xff then mono */ hio_read16b(f); /* reserved */ mod->spd = hio_read16b(f); if ((b = hio_read16b(f)) > 0) /* RAMBO.DTM has bpm 0 */ mod->bpm = b; hio_read32b(f); /* undocumented */ hio_read(mod->name, 32, 1, f); libxmp_set_type(m, "Digital Tracker DTM"); MODULE_INFO(); return 0; } static int get_s_q_(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, maxpat; /* Sanity check */ if (mod->pat != 0) { return -1; } mod->len = hio_read16b(f); mod->rst = hio_read16b(f); /* Sanity check */ if (mod->len > 256 || mod->rst > 255) { return -1; } hio_read32b(f); /* reserved */ for (maxpat = i = 0; i < 128; i++) { mod->xxo[i] = hio_read8(f); if (mod->xxo[i] > maxpat) maxpat = mod->xxo[i]; } mod->pat = maxpat + 1; return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; mod->chn = hio_read16b(f); data->realpat = hio_read16b(f); mod->trk = mod->chn * mod->pat; return 0; } static int get_inst(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, c2spd; uint8 name[30]; mod->ins = mod->smp = hio_read16b(f); D_(D_INFO "Instruments : %d ", mod->ins); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { int fine, replen, flag; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; hio_read32b(f); /* reserved */ mod->xxs[i].len = hio_read32b(f); mod->xxi[i].nsm = !!mod->xxs[i].len; fine = hio_read8s(f); /* finetune */ mod->xxi[i].sub[0].vol = hio_read8(f); mod->xxi[i].sub[0].pan = 0x80; mod->xxs[i].lps = hio_read32b(f); replen = hio_read32b(f); mod->xxs[i].lpe = mod->xxs[i].lps + replen - 1; mod->xxs[i].flg = replen > 2 ? XMP_SAMPLE_LOOP : 0; hio_read(name, 22, 1, f); libxmp_instrument_name(mod, i, name, 22); flag = hio_read16b(f); /* bit 0-7:resol 8:stereo */ if ((flag & 0xff) > 8) { mod->xxs[i].flg |= XMP_SAMPLE_16BIT; mod->xxs[i].len >>= 1; mod->xxs[i].lps >>= 1; mod->xxs[i].lpe >>= 1; } hio_read32b(f); /* midi note (0x00300000) */ c2spd = hio_read32b(f); /* frequency */ libxmp_c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); /* It's strange that we have both c2spd and finetune */ mod->xxi[i].sub[0].fin += fine; mod->xxi[i].sub[0].sid = i; D_(D_INFO "[%2X] %-22.22s %05x%c%05x %05x %c%c %2db V%02x F%+03d %5d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[i].lps, replen, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', flag & 0x100 ? 'S' : ' ', flag & 0xff, mod->xxi[i].sub[0].vol, fine, c2spd); } return 0; } static int get_dapt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int pat, i, j, k; struct xmp_event *event; int rows; if (!data->pflag) { D_(D_INFO "Stored patterns: %d", mod->pat); data->pflag = 1; data->last_pat = 0; if (libxmp_init_pattern(mod) < 0) return -1; } hio_read32b(f); /* 0xffffffff */ pat = hio_read16b(f); rows = hio_read16b(f); /* Sanity check */ if (pat < 0 || pat >= mod->pat || rows < 0 || rows > 256) { return -1; } if (pat < data->last_pat) { return -1; } for (i = data->last_pat; i <= pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; } data->last_pat = pat + 1; for (j = 0; j < rows; j++) { for (k = 0; k < mod->chn; k++) { uint8 a, b, c, d; event = &EVENT(pat, k, j); a = hio_read8(f); b = hio_read8(f); c = hio_read8(f); d = hio_read8(f); if (a) { a--; event->note = 12 * (a >> 4) + (a & 0x0f) + 12; } event->vol = (b & 0xfc) >> 2; event->ins = ((b & 0x03) << 4) + (c >> 4); event->fxt = c & 0xf; event->fxp = d; } } return 0; } static int get_dait(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; if (!data->sflag) { D_(D_INFO "Stored samples : %d ", mod->smp); data->sflag = 1; data->insnum = 0; } if (size > 2) { int ret; /* Sanity check */ if (data->insnum >= mod->ins) { return -1; } ret = libxmp_load_sample(m, f, SAMPLE_FLAG_BIGEND, &mod->xxs[mod->xxi[data->insnum].sub[0].sid], NULL); if (ret < 0) return -1; } data->insnum++; return 0; } static int dt_load(struct module_data *m, HIO_HANDLE *f, const int start) { iff_handle handle; struct local_data data; struct xmp_module *mod = &m->mod; int ret, i; LOAD_INIT(); memset(&data, 0, sizeof (struct local_data)); handle = libxmp_iff_new(); if (handle == NULL) return -1; m->c4rate = C4_NTSC_RATE; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "D.T.", get_d_t_); ret |= libxmp_iff_register(handle, "S.Q.", get_s_q_); ret |= libxmp_iff_register(handle, "PATT", get_patt); ret |= libxmp_iff_register(handle, "INST", get_inst); ret |= libxmp_iff_register(handle, "DAPT", get_dapt); ret |= libxmp_iff_register(handle, "DAIT", get_dait); if (ret != 0) return -1; /* Load IFF chunks */ ret = libxmp_iff_load(handle, m, f , &data); libxmp_iff_release(handle); if (ret < 0) return -1; /* alloc remaining patterns */ if (mod->xxp != NULL) { for (i = data.last_pat; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) { return -1; } } } return 0; } libxmp-4.4.1/src/loaders/mgt_load.c0000664000175000017500000002152112774567167017040 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "period.h" #define MAGIC_MGT MAGIC4(0x00,'M','G','T') #define MAGIC_MCS MAGIC4(0xbd,'M','C','S') static int mgt_test (HIO_HANDLE *, char *, const int); static int mgt_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mgt = { "Megatracker", mgt_test, mgt_load }; static int mgt_test(HIO_HANDLE *f, char *t, const int start) { int sng_ptr; if (hio_read24b(f) != MAGIC_MGT) return -1; hio_read8(f); if (hio_read32b(f) != MAGIC_MCS) return -1; hio_seek(f, 18, SEEK_CUR); sng_ptr = hio_read32b(f); hio_seek(f, start + sng_ptr, SEEK_SET); libxmp_read_title(f, t, 32); return 0; } static int mgt_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event; int i, j; int ver; int sng_ptr, seq_ptr, ins_ptr, pat_ptr, trk_ptr, smp_ptr; int sdata[64]; LOAD_INIT(); hio_read24b(f); /* MGT */ ver = hio_read8(f); hio_read32b(f); /* MCS */ libxmp_set_type(m, "Megatracker MGT v%d.%d", MSN(ver), LSN(ver)); mod->chn = hio_read16b(f); hio_read16b(f); /* number of songs */ mod->len = hio_read16b(f); mod->pat = hio_read16b(f); mod->trk = hio_read16b(f); mod->ins = mod->smp = hio_read16b(f); hio_read16b(f); /* reserved */ hio_read32b(f); /* reserved */ /* Sanity check */ if (mod->chn > XMP_MAX_CHANNELS || mod->ins > 64) { return -1; } sng_ptr = hio_read32b(f); seq_ptr = hio_read32b(f); ins_ptr = hio_read32b(f); pat_ptr = hio_read32b(f); trk_ptr = hio_read32b(f); smp_ptr = hio_read32b(f); hio_read32b(f); /* total smp len */ hio_read32b(f); /* unpacked trk size */ hio_seek(f, start + sng_ptr, SEEK_SET); hio_read(mod->name, 1, 32, f); seq_ptr = hio_read32b(f); mod->len = hio_read16b(f); mod->rst = hio_read16b(f); mod->bpm = hio_read8(f); mod->spd = hio_read8(f); hio_read16b(f); /* global volume */ hio_read8(f); /* master L */ hio_read8(f); /* master R */ /* Sanity check */ if (mod->len > 256 || mod->rst > 255) { return -1; } for (i = 0; i < mod->chn; i++) { hio_read16b(f); /* pan */ } m->c4rate = C4_NTSC_RATE; MODULE_INFO(); /* Sequence */ hio_seek(f, start + seq_ptr, SEEK_SET); for (i = 0; i < mod->len; i++) { mod->xxo[i] = hio_read16b(f); /* Sanity check */ if (mod->xxo[i] >= mod->pat) { return -1; } } /* Instruments */ if (libxmp_init_instrument(m) < 0) return -1; hio_seek(f, start + ins_ptr, SEEK_SET); for (i = 0; i < mod->ins; i++) { int c2spd, flags; if (libxmp_alloc_subinstrument(mod, i , 1) < 0) return -1; hio_read(mod->xxi[i].name, 1, 32, f); sdata[i] = hio_read32b(f); mod->xxs[i].len = hio_read32b(f); /* Sanity check */ if (mod->xxs[i].len > MAX_SAMPLE_SIZE) { return -1; } mod->xxs[i].lps = hio_read32b(f); mod->xxs[i].lpe = mod->xxs[i].lps + hio_read32b(f); hio_read32b(f); hio_read32b(f); c2spd = hio_read32b(f); libxmp_c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); mod->xxi[i].sub[0].vol = hio_read16b(f) >> 4; hio_read8(f); /* vol L */ hio_read8(f); /* vol R */ mod->xxi[i].sub[0].pan = 0x80; flags = hio_read8(f); mod->xxs[i].flg = flags & 0x03 ? XMP_SAMPLE_LOOP : 0; mod->xxs[i].flg |= flags & 0x02 ? XMP_SAMPLE_LOOP_BIDIR : 0; mod->xxi[i].sub[0].fin += 0 * hio_read8(f); // FIXME hio_read8(f); /* unused */ hio_read8(f); hio_read8(f); hio_read8(f); hio_read16b(f); hio_read32b(f); hio_read32b(f); mod->xxi[i].nsm = !!mod->xxs[i].len; mod->xxi[i].sub[0].sid = i; D_(D_INFO "[%2X] %-32.32s %04x %04x %04x %c V%02x %5d\n", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, c2spd); } /* PATTERN_INIT - alloc extra track*/ if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored tracks: %d", mod->trk); /* Tracks */ for (i = 1; i < mod->trk; i++) { int offset, rows; uint8 b; hio_seek(f, start + trk_ptr + i * 4, SEEK_SET); offset = hio_read32b(f); hio_seek(f, start + offset, SEEK_SET); rows = hio_read16b(f); /* Sanity check */ if (rows > 255) return -1; if (libxmp_alloc_track(mod, i, rows) < 0) return -1; //printf("\n=== Track %d ===\n\n", i); for (j = 0; j < rows; j++) { uint8 note, f2p; b = hio_read8(f); j += b & 0x03; /* Sanity check */ if (j >= rows) return -1; note = 0; event = &mod->xxt[i]->event[j]; if (b & 0x04) note = hio_read8(f); if (b & 0x08) event->ins = hio_read8(f); if (b & 0x10) event->vol = hio_read8(f); if (b & 0x20) event->fxt = hio_read8(f); if (b & 0x40) event->fxp = hio_read8(f); if (b & 0x80) f2p = hio_read8(f); if (note == 1) event->note = XMP_KEY_OFF; else if (note > 11) /* adjusted to play codeine.mgt */ event->note = note + 1; /* effects */ if (event->fxt < 0x10) /* like amiga */ ; else switch (event->fxt) { case 0x13: case 0x14: case 0x15: case 0x17: case 0x1c: case 0x1d: case 0x1e: event->fxt = FX_EXTENDED; event->fxp = ((event->fxt & 0x0f) << 4) | (event->fxp & 0x0f); break; default: event->fxt = event->fxp = 0; } /* volume and volume column effects */ if ((event->vol >= 0x10) && (event->vol <= 0x50)) { event->vol -= 0x0f; continue; } switch (event->vol >> 4) { case 0x06: /* Volume slide down */ event->f2t = FX_VOLSLIDE_2; event->f2p = event->vol - 0x60; break; case 0x07: /* Volume slide up */ event->f2t = FX_VOLSLIDE_2; event->f2p = (event->vol - 0x70) << 4; break; case 0x08: /* Fine volume slide down */ event->f2t = FX_EXTENDED; event->f2p = (EX_F_VSLIDE_DN << 4) | (event->vol - 0x80); break; case 0x09: /* Fine volume slide up */ event->f2t = FX_EXTENDED; event->f2p = (EX_F_VSLIDE_UP << 4) | (event->vol - 0x90); break; case 0x0a: /* Set vibrato speed */ event->f2t = FX_VIBRATO; event->f2p = (event->vol - 0xa0) << 4; break; case 0x0b: /* Vibrato */ event->f2t = FX_VIBRATO; event->f2p = event->vol - 0xb0; break; case 0x0c: /* Set panning */ event->f2t = FX_SETPAN; event->f2p = ((event->vol - 0xc0) << 4) + 8; break; case 0x0d: /* Pan slide left */ event->f2t = FX_PANSLIDE; event->f2p = (event->vol - 0xd0) << 4; break; case 0x0e: /* Pan slide right */ event->f2t = FX_PANSLIDE; event->f2p = event->vol - 0xe0; break; case 0x0f: /* Tone portamento */ event->f2t = FX_TONEPORTA; event->f2p = (event->vol - 0xf0) << 4; break; } event->vol = 0; /*printf("%02x %02x %02x %02x %02x %02x\n", j, event->note, event->ins, event->vol, event->fxt, event->fxp);*/ } } /* Extra track */ if (mod->trk > 0) { mod->xxt[0] = calloc(sizeof(struct xmp_track) + sizeof(struct xmp_event) * 64 - 1, 1); mod->xxt[0]->rows = 64; } /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); hio_seek(f, start + pat_ptr, SEEK_SET); for (i = 0; i < mod->pat; i++) { int rows; if (libxmp_alloc_pattern(mod, i) < 0) return -1; rows = hio_read16b(f); /* Sanity check */ if (rows > 256) { return -1; } mod->xxp[i]->rows = rows; for (j = 0; j < mod->chn; j++) { int track = hio_read16b(f) - 1; /* Sanity check */ if (track >= mod->trk) { return -1; } mod->xxp[i]->index[j] = track; } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxi[i].nsm == 0) continue; hio_seek(f, start + sdata[i], SEEK_SET); if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/voltable.c0000664000175000017500000001230112773571316017044 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" /* from Tom Hargreaves date Sat, Jan 16, 2010 at 9:38 PM the volume table for volume commands and the VIDC lookup table for sample conversion are (should be) one and the same. A full-precision version of the table is as follows: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 120 128 136 144 152 160 168 176 184 192 200 208 216 224 232 240 256 272 288 304 320 336 352 368 384 400 416 432 448 464 480 496 528 560 592 624 656 688 720 752 784 816 848 880 912 944 976 1008 1072 1136 1200 1264 1328 1392 1456 1520 1584 1648 1712 1776 1840 1904 1968 2032 2160 2288 2416 2544 2672 2800 2928 3056 3184 3312 3440 3568 3696 3824 3952 */ /* Claudio's note: this is a curve approximation using linear segments, * so I'll perform linear interpolation to have all 256 values */ int const libxmp_arch_vol_table[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f, 0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x81, 0x83, 0x87, 0x8b, 0x8f, 0x93, 0x97, 0x9b, 0xa0, 0xa4, 0xa8, 0xac, 0xb0, 0xb4, 0xb8, 0xbc, 0xc1, 0xc5, 0xc9, 0xcd, 0xd1, 0xd5, 0xd9, 0xdd, 0xe2, 0xe6, 0xea, 0xee, 0xf2, 0xf6, 0xfa, 0xff, 0xff }; #if 0 int arch_vol_table[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1c, 0x1c, 0x1d, 0x1e, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x3a, 0x3b, 0x3c, 0x3e, 0x3f, 0x40, 0x42, 0x43, 0x45, 0x46, 0x48, 0x49, 0x4b, 0x4d, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5b, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6b, 0x6d, 0x6f, 0x72, 0x74, 0x77, 0x7a, 0x7c, 0x7f, 0x82, 0x85, 0x88, 0x8b, 0x8e, 0x91, 0x94, 0x97, 0x9b, 0x9e, 0xa1, 0xa5, 0xa9, 0xac, 0xb0, 0xb4, 0xb8, 0xbc, 0xc0, 0xc4, 0xc9, 0xcd, 0xd2, 0xd6, 0xdb, 0xe0, 0xe5, 0xea, 0xef, 0xf4, 0xfa, 0xff, 0xff }; #endif libxmp-4.4.1/src/loaders/669_load.c0000664000175000017500000001522412774567167016600 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" static int c669_test (HIO_HANDLE *, char *, const int); static int c669_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_669 = { "Composer 669", c669_test, c669_load }; static int c669_test(HIO_HANDLE *f, char *t, const int start) { uint16 id; id = hio_read16b(f); if (id != 0x6966 && id != 0x4a4e) return -1; hio_seek(f, 110, SEEK_SET); if (hio_read8(f) > 64) return -1; if (hio_read8(f) > 128) return -1; hio_seek(f, 240, SEEK_SET); if (hio_read8(f) != 0xff) return -1; hio_seek(f, start + 2, SEEK_SET); libxmp_read_title(f, t, 36); return 0; } struct c669_file_header { uint8 marker[2]; /* 'if'=standard, 'JN'=extended */ uint8 message[108]; /* Song message */ uint8 nos; /* Number of samples (0-64) */ uint8 nop; /* Number of patterns (0-128) */ uint8 loop; /* Loop order number */ uint8 order[128]; /* Order list */ uint8 speed[128]; /* Tempo list for patterns */ uint8 pbrk[128]; /* Break list for patterns */ }; struct c669_instrument_header { uint8 name[13]; /* ASCIIZ instrument name */ uint32 length; /* Instrument length */ uint32 loop_start; /* Instrument loop start */ uint32 loopend; /* Instrument loop end */ }; #define NONE 0xff /* Effects bug fixed by Miod Vallat */ static const uint8 fx[] = { FX_669_PORTA_UP, FX_669_PORTA_DN, FX_669_TPORTA, FX_669_FINETUNE, FX_669_VIBRATO, FX_SPEED_CP }; static int c669_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct c669_file_header sfh; struct c669_instrument_header sih; uint8 ev[3]; LOAD_INIT(); hio_read(&sfh.marker, 2, 1, f); /* 'if'=standard, 'JN'=extended */ hio_read(&sfh.message, 108, 1, f); /* Song message */ sfh.nos = hio_read8(f); /* Number of samples (0-64) */ sfh.nop = hio_read8(f); /* Number of patterns (0-128) */ /* Sanity check */ if (sfh.nos > 64 || sfh.nop > 128) return -1; sfh.loop = hio_read8(f); /* Loop order number */ if (hio_read(&sfh.order, 1, 128, f) != 128) /* Order list */ return -1; if (hio_read(&sfh.speed, 1, 128, f) != 128) /* Tempo list for patterns */ return -1; if (hio_read(&sfh.pbrk, 1, 128, f) != 128) /* Break list for patterns */ return -1; mod->chn = 8; mod->ins = sfh.nos; mod->pat = sfh.nop; mod->trk = mod->chn * mod->pat; for (i = 0; i < 128; i++) { if (sfh.order[i] > sfh.nop) break; } mod->len = i; memcpy (mod->xxo, sfh.order, mod->len); mod->spd = 6; mod->bpm = 78; mod->smp = mod->ins; m->period_type = PERIOD_CSPD; m->c4rate = C4_NTSC_RATE; libxmp_copy_adjust(mod->name, sfh.message, 36); libxmp_set_type(m, strncmp((char *)sfh.marker, "if", 2) ? "UNIS 669" : "Composer 669"); MODULE_INFO(); m->comment = malloc(109); memcpy(m->comment, sfh.message, 108); m->comment[108] = 0; /* Read and convert instruments and samples */ if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->pat); for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; hio_read (&sih.name, 13, 1, f); /* ASCIIZ instrument name */ sih.length = hio_read32l(f); /* Instrument size */ sih.loop_start = hio_read32l(f); /* Instrument loop start */ sih.loopend = hio_read32l(f); /* Instrument loop end */ /* Sanity check */ if (sih.length > MAX_SAMPLE_SIZE) return -1; xxs->len = sih.length; xxs->lps = sih.loop_start; xxs->lpe = sih.loopend >= 0xfffff ? 0 : sih.loopend; xxs->flg = xxs->lpe ? XMP_SAMPLE_LOOP : 0; /* 1 == Forward loop */ sub->vol = 0x40; sub->pan = 0x80; sub->sid = i; if (xxs->len > 0) xxi->nsm = 1; libxmp_instrument_name(mod, i, sih.name, 13); D_(D_INFO "[%2X] %-14.14s %04x %04x %04x %c", i, xxi->name, xxs->len, xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' '); } if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { int pbrk; if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; event = &EVENT(i, 0, 0); event->f2t = FX_SPEED_CP; event->f2p = sfh.speed[i]; pbrk = sfh.pbrk[i]; if (pbrk >= 64) return -1; event = &EVENT(i, 1, pbrk); event->f2t = FX_BREAK; event->f2p = 0; for (j = 0; j < 64 * 8; j++) { event = &EVENT(i, j % 8, j / 8); hio_read(&ev, 1, 3, f); if ((ev[0] & 0xfe) != 0xfe) { event->note = 1 + 36 + (ev[0] >> 2); event->ins = 1 + MSN(ev[1]) + ((ev[0] & 0x03) << 4); } if (ev[0] != 0xff) event->vol = (LSN(ev[1]) << 2) + 1; if (ev[2] != 0xff) { if (MSN(ev[2]) > 5) continue; event->fxt = fx[MSN(ev[2])]; event->fxp = LSN(ev[2]); if (event->fxt == FX_SPEED_CP) { event->f2t = FX_PER_CANCEL; } } } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len <= 2) continue; if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0) return -1; } for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = DEFPAN((i % 2) * 0xff); } m->quirk |= QUIRK_PBALL|QUIRK_PERPAT; return 0; } libxmp-4.4.1/src/loaders/med3_load.c0000664000175000017500000002307212774567167017104 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * MED 2.00 is in Fish disk #349 and has a couple of demo modules, get it * from ftp://ftp.funet.fi/pub/amiga/fish/301-400/ff349 */ #include #include "loader.h" #define MAGIC_MED3 MAGIC4('M','E','D',3) static int med3_test(HIO_HANDLE *, char *, const int); static int med3_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_med3 = { "MED 2.00 MED3", med3_test, med3_load }; static int med3_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_MED3) return -1; libxmp_read_title(f, t, 0); return 0; } #define MASK 0x80000000 #define M0F_LINEMSK0F 0x01 #define M0F_LINEMSK1F 0x02 #define M0F_FXMSK0F 0x04 #define M0F_FXMSK1F 0x08 #define M0F_LINEMSK00 0x10 #define M0F_LINEMSK10 0x20 #define M0F_FXMSK00 0x40 #define M0F_FXMSK10 0x80 /* * From the MED 2.00 file loading/saving routines by Teijo Kinnunen, 1990 */ static uint8 get_nibble(uint8 *mem, uint16 *nbnum) { uint8 *mloc = mem + (*nbnum / 2), res; if(*nbnum & 0x1) res = *mloc & 0x0f; else res = *mloc >> 4; (*nbnum)++; return res; } static uint16 get_nibbles(uint8 *mem, uint16 *nbnum, uint8 nbs) { uint16 res = 0; while (nbs--) { res <<= 4; res |= get_nibble(mem, nbnum); } return res; } static int unpack_block(struct module_data *m, uint16 bnum, uint8 *from, uint16 convsz) { struct xmp_module *mod = &m->mod; struct xmp_event *event; uint32 linemsk0 = *((uint32 *)from), linemsk1 = *((uint32 *)from + 1); uint32 fxmsk0 = *((uint32 *)from + 2), fxmsk1 = *((uint32 *)from + 3); uint32 *lmptr = &linemsk0, *fxptr = &fxmsk0; uint16 fromn = 0, lmsk; uint8 *fromst = from + 16, bcnt, *tmpto; uint8 *patbuf, *to; int i, j, trkn = mod->chn; /*from += 16;*/ patbuf = to = calloc(3, 4 * 64); if (to == NULL) { goto err; } for (i = 0; i < 64; i++) { if (i == 32) { lmptr = &linemsk1; fxptr = &fxmsk1; } if (*lmptr & MASK) { if (trkn / 2 > convsz) { goto err2; } convsz -= trkn / 2; lmsk = get_nibbles(fromst, &fromn, (uint8)(trkn / 4)); lmsk <<= (16 - trkn); tmpto = to; for (bcnt = 0; bcnt < trkn; bcnt++) { if (lmsk & 0x8000) { *tmpto = (uint8)get_nibbles(fromst, &fromn,2); *(tmpto + 1) = (get_nibble(fromst, &fromn) << 4); } lmsk <<= 1; tmpto += 3; } } if (*fxptr & MASK) { if (trkn / 2 > convsz) { goto err2; } convsz -= trkn / 2; lmsk = get_nibbles(fromst,&fromn,(uint8)(trkn / 4)); lmsk <<= (16 - trkn); tmpto = to; for (bcnt = 0; bcnt < trkn; bcnt++) { if (lmsk & 0x8000) { *(tmpto+1) |= get_nibble(fromst, &fromn); *(tmpto+2) = (uint8)get_nibbles(fromst, &fromn,2); } lmsk <<= 1; tmpto += 3; } } to += 3 * trkn; *lmptr <<= 1; *fxptr <<= 1; } for (i = 0; i < 64; i++) { for (j = 0; j < 4; j++) { event = &EVENT(bnum, j, i); event->note = patbuf[i * 12 + j * 3 + 0]; if (event->note) event->note += 48; event->ins = patbuf[i * 12 + j * 3 + 1] >> 4; if (event->ins) event->ins++; event->fxt = patbuf[i * 12 + j * 3 + 1] & 0x0f; event->fxp = patbuf[i * 12 + j * 3 + 2]; switch (event->fxt) { case 0x00: /* arpeggio */ case 0x01: /* slide up */ case 0x02: /* slide down */ case 0x03: /* portamento */ case 0x04: /* vibrato? */ break; case 0x0c: /* set volume (BCD) */ event->fxp = MSN(event->fxp) * 10 + LSN(event->fxp); break; case 0x0d: /* volume slides */ event->fxt = FX_VOLSLIDE; break; case 0x0f: /* tempo/break */ if (event->fxp == 0) event->fxt = FX_BREAK; if (event->fxp == 0xff) { event->fxp = event->fxt = 0; event->vol = 1; } else if (event->fxp == 0xfe) { event->fxp = event->fxt = 0; } else if (event->fxp == 0xf1) { event->fxt = FX_EXTENDED; event->fxp = (EX_RETRIG << 4) | 3; } else if (event->fxp == 0xf2) { event->fxt = FX_EXTENDED; event->fxp = (EX_CUT << 4) | 3; } else if (event->fxp == 0xf3) { event->fxt = FX_EXTENDED; event->fxp = (EX_DELAY << 4) | 3; } else if (event->fxp > 10) { event->fxt = FX_S3M_BPM; event->fxp = 125 * event->fxp / 33; } break; default: event->fxp = event->fxt = 0; } } } free(patbuf); return 0; err2: free(patbuf); err: return -1; } static int med3_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; uint32 mask; int transp, sliding; LOAD_INIT(); hio_read32b(f); libxmp_set_type(m, "MED 2.00 MED3"); mod->ins = mod->smp = 32; if (libxmp_init_instrument(m) < 0) return -1; /* read instrument names */ for (i = 0; i < 32; i++) { uint8 c, buf[40]; for (j = 0; j < 40; j++) { c = hio_read8(f); buf[j] = c; if (c == 0) break; } libxmp_instrument_name(mod, i, buf, 32); if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; } /* read instrument volumes */ mask = hio_read32b(f); for (i = 0; i < 32; i++, mask <<= 1) { mod->xxi[i].sub[0].vol = mask & MASK ? hio_read8(f) : 0; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].fin = 0; mod->xxi[i].sub[0].sid = i; } /* read instrument loops */ mask = hio_read32b(f); for (i = 0; i < 32; i++, mask <<= 1) { mod->xxs[i].lps = mask & MASK ? hio_read16b(f) : 0; } /* read instrument loop length */ mask = hio_read32b(f); for (i = 0; i < 32; i++, mask <<= 1) { uint32 lsiz = mask & MASK ? hio_read16b(f) : 0; mod->xxs[i].len = mod->xxs[i].lps + lsiz; mod->xxs[i].lpe = mod->xxs[i].lps + lsiz; mod->xxs[i].flg = lsiz > 1 ? XMP_SAMPLE_LOOP : 0; } mod->chn = 4; mod->pat = hio_read16b(f); mod->trk = mod->chn * mod->pat; mod->len = hio_read16b(f); /* Sanity check */ if (mod->len > 256 || mod->pat > 256) return -1; hio_read(mod->xxo, 1, mod->len, f); mod->spd = hio_read16b(f); if (mod->spd > 10) { mod->bpm = 125 * mod->spd / 33; mod->spd = 6; } transp = hio_read8s(f); hio_read8(f); /* flags */ sliding = hio_read16b(f); /* sliding */ hio_read32b(f); /* jumping mask */ hio_seek(f, 16, SEEK_CUR); /* rgb */ /* read midi channels */ mask = hio_read32b(f); for (i = 0; i < 32; i++, mask <<= 1) { if (mask & MASK) hio_read8(f); } /* read midi programs */ mask = hio_read32b(f); for (i = 0; i < 32; i++, mask <<= 1) { if (mask & MASK) hio_read8(f); } MODULE_INFO(); D_(D_INFO "Sliding: %d", sliding); D_(D_INFO "Play transpose: %d", transp); if (sliding == 6) m->quirk |= QUIRK_VSALL | QUIRK_PBALL; for (i = 0; i < 32; i++) mod->xxi[i].sub[0].xpo = transp; if (libxmp_init_pattern(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { uint32 *conv; uint8 b, tracks; uint16 convsz; if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; tracks = hio_read8(f); b = hio_read8(f); convsz = hio_read16b(f); conv = calloc(1, convsz + 16); if (conv == NULL) return -1; if (b & M0F_LINEMSK00) *conv = 0L; else if (b & M0F_LINEMSK0F) *conv = 0xffffffff; else *conv = hio_read32b(f); if (b & M0F_LINEMSK10) *(conv + 1) = 0L; else if (b & M0F_LINEMSK1F) *(conv + 1) = 0xffffffff; else *(conv + 1) = hio_read32b(f); if (b & M0F_FXMSK00) *(conv + 2) = 0L; else if (b & M0F_FXMSK0F) *(conv + 2) = 0xffffffff; else *(conv + 2) = hio_read32b(f); if (b & M0F_FXMSK10) *(conv + 3) = 0L; else if (b & M0F_FXMSK1F) *(conv + 3) = 0xffffffff; else *(conv + 3) = hio_read32b(f); if (hio_read(conv + 4, 1, convsz, f) != convsz) { free(conv); return -1; } if (unpack_block(m, i, (uint8 *)conv, convsz) < 0) { free(conv); return -1; } free(conv); } /* Load samples */ D_(D_INFO "Instruments: %d", mod->ins); mask = hio_read32b(f); for (i = 0; i < 32; i++, mask <<= 1) { if (~mask & MASK) continue; mod->xxi[i].nsm = 1; mod->xxs[i].len = hio_read32b(f); if (mod->xxs[i].len == 0) mod->xxi[i].nsm = 0; if (hio_read16b(f)) /* type */ continue; D_(D_INFO "[%2X] %-32.32s %04x %04x %04x %c V%02x ", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol); if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/xm_load.c0000664000175000017500000004605512776512544016675 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Fri, 26 Jun 1998 17:45:59 +1000 Andrew Leahy * Finally got it working on the DEC Alpha running DEC UNIX! In the pattern * reading loop I found I was getting "0" for (p-patbuf) and "0" for * xph.datasize, the next if statement (where it tries to read the patbuf) * would then cause a seg_fault. * * Sun Sep 27 12:07:12 EST 1998 Claudio Matsuoka * Extended Module 1.02 stores data in a different order, we must handle * this accordingly. MAX_SAMP used as a workaround to check the number of * samples recognized by the player. */ #include "loader.h" #include "xm.h" static int xm_test(HIO_HANDLE *, char *, const int); static int xm_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_xm = { "Fast Tracker II", xm_test, xm_load }; static int xm_test(HIO_HANDLE *f, char *t, const int start) { char buf[20]; if (hio_read(buf, 1, 17, f) < 17) /* ID text */ return -1; if (memcmp(buf, "Extended Module: ", 17)) return -1; libxmp_read_title(f, t, 20); return 0; } static int load_xm_pattern(struct module_data *m, int num, int version, HIO_HANDLE *f) { const int headsize = version > 0x0102 ? 9 : 8; struct xmp_module *mod = &m->mod; struct xm_pattern_header xph; struct xmp_event *event; uint8 *patbuf, *pat, b; int j, r; int size; xph.length = hio_read32l(f); xph.packing = hio_read8(f); xph.rows = version > 0x0102 ? hio_read16l(f) : hio_read8(f) + 1; /* Sanity check */ if (xph.rows > 256) { goto err; } xph.datasize = hio_read16l(f); hio_seek(f, xph.length - headsize, SEEK_CUR); if (hio_error(f)) { goto err; } r = xph.rows; if (r == 0) { r = 0x100; } if (libxmp_alloc_pattern_tracks(mod, num, r) < 0) { goto err; } if (xph.datasize == 0) { return 0; } size = xph.datasize; pat = patbuf = calloc(1, size); if (patbuf == NULL) { goto err; } hio_read(patbuf, 1, size, f); for (j = 0; j < (mod->chn * r); j++) { /*if ((pat - patbuf) >= xph.datasize) break; */ event = &EVENT(num, j % mod->chn, j / mod->chn); if (--size < 0) { goto err2; } if ((b = *pat++) & XM_EVENT_PACKING) { if (b & XM_EVENT_NOTE_FOLLOWS) { if (--size < 0) goto err2; event->note = *pat++; } if (b & XM_EVENT_INSTRUMENT_FOLLOWS) { if (--size < 0) goto err2; event->ins = *pat++; } if (b & XM_EVENT_VOLUME_FOLLOWS) { if (--size < 0) goto err2; event->vol = *pat++; } if (b & XM_EVENT_FXTYPE_FOLLOWS) { if (--size < 0) goto err2; event->fxt = *pat++; } if (b & XM_EVENT_FXPARM_FOLLOWS) { if (--size < 0) goto err2; event->fxp = *pat++; } } else { size -= 4; if (size < 0) goto err2; event->note = b; event->ins = *pat++; event->vol = *pat++; event->fxt = *pat++; event->fxp = *pat++; } /* Sanity check */ switch (event->fxt) { case 18: case 19: case 22: case 23: case 24: case 26: case 28: case 30: case 31: case 32: event->fxt = 0; } if (event->fxt > 34) { event->fxt = 0; } if (event->note == 0x61) { /* See OpenMPT keyoff+instr.xm test case */ if (event->fxt == 0x0e && MSN(event->fxp) == 0x0d) { event->note = XMP_KEY_OFF; } else { event->note = event->ins ? XMP_KEY_FADE : XMP_KEY_OFF; } } else if (event->note > 0) { event->note += 12; } if (event->fxt == 0x0e) { if (MSN(event->fxp) == EX_FINETUNE) { unsigned char val = (LSN(event->fxp) - 8) & 0xf; event->fxp = (EX_FINETUNE << 4) | val; } switch (event->fxp) { case 0x43: case 0x73: event->fxp--; break; } } if (!event->vol) { continue; } /* Volume set */ if ((event->vol >= 0x10) && (event->vol <= 0x50)) { event->vol -= 0x0f; continue; } /* Volume column effects */ switch (event->vol >> 4) { case 0x06: /* Volume slide down */ event->f2t = FX_VOLSLIDE_2; event->f2p = event->vol - 0x60; break; case 0x07: /* Volume slide up */ event->f2t = FX_VOLSLIDE_2; event->f2p = (event->vol - 0x70) << 4; break; case 0x08: /* Fine volume slide down */ event->f2t = FX_EXTENDED; event->f2p = (EX_F_VSLIDE_DN << 4) | (event->vol - 0x80); break; case 0x09: /* Fine volume slide up */ event->f2t = FX_EXTENDED; event->f2p = (EX_F_VSLIDE_UP << 4) | (event->vol - 0x90); break; case 0x0a: /* Set vibrato speed */ event->f2t = FX_VIBRATO; event->f2p = (event->vol - 0xa0) << 4; break; case 0x0b: /* Vibrato */ event->f2t = FX_VIBRATO; event->f2p = event->vol - 0xb0; break; case 0x0c: /* Set panning */ event->f2t = FX_SETPAN; event->f2p = (event->vol - 0xc0) << 4; break; case 0x0d: /* Pan slide left */ event->f2t = FX_PANSL_NOMEM; event->f2p = (event->vol - 0xd0) << 4; break; case 0x0e: /* Pan slide right */ event->f2t = FX_PANSL_NOMEM; event->f2p = event->vol - 0xe0; break; case 0x0f: /* Tone portamento */ event->f2t = FX_TONEPORTA; event->f2p = (event->vol - 0xf0) << 4; /* From OpenMPT TonePortamentoMemory.xm: * "Another nice bug (...) is the combination of both * portamento commands (Mx and 3xx) in the same cell: * The 3xx parameter is ignored completely, and the Mx * parameter is doubled. (M2 3FF is the same as M4 000) */ if (event->fxt == FX_TONEPORTA || event->fxt == FX_TONE_VSLIDE) { if (event->fxt == FX_TONEPORTA) { event->fxt = 0; } else { event->fxt = FX_VOLSLIDE; } event->fxp = 0; if (event->f2p < 0x80) { event->f2p <<= 1; } else { event->f2p = 0xff; } } /* From OpenMPT porta-offset.xm: * "If there is a portamento command next to an offset * command, the offset command is ignored completely. In * particular, the offset parameter is not memorized." */ if (event->fxt == FX_OFFSET && event->f2t == FX_TONEPORTA) { event->fxt = event->fxp = 0; } break; } event->vol = 0; } free(patbuf); return 0; err2: free(patbuf); err: return -1; } static int load_patterns(struct module_data *m, int version, HIO_HANDLE *f) { struct xmp_module *mod = &m->mod; int i, j; mod->pat++; if (libxmp_init_pattern(mod) < 0) { return -1; } D_(D_INFO "Stored patterns: %d", mod->pat - 1); for (i = 0; i < mod->pat - 1; i++) { if (load_xm_pattern(m, i, version, f) < 0) { goto err; } } /* Alloc one extra pattern */ { int t = i * mod->chn; if (libxmp_alloc_pattern(mod, i) < 0) { goto err; } mod->xxp[i]->rows = 64; if (libxmp_alloc_track(mod, t, 64) < 0) { goto err; } for (j = 0; j < mod->chn; j++) { mod->xxp[i]->index[j] = t; } } return 0; err: return -1; } /* Packed structures size */ #define XM_INST_HEADER_SIZE 33 #define XM_INST_SIZE 208 static int load_instruments(struct module_data *m, int version, HIO_HANDLE *f) { struct xmp_module *mod = &m->mod; struct xm_instrument_header xih; struct xm_instrument xi; struct xm_sample_header xsh[16]; int sample_num = 0; int i, j; D_(D_INFO "Instruments: %d", mod->ins); /* ESTIMATED value! We don't know the actual value at this point */ mod->smp = MAX_SAMPLES; if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; xih.size = hio_read32l(f); /* Instrument size */ /* Modules converted with MOD2XM 1.0 always say we have 31 * instruments, but file may end abruptly before that. This test * will not work if file has trailing garbage. */ if (hio_eof(f)) { break; } hio_read(&xih.name, 22, 1, f); /* Instrument name */ xih.type = hio_read8(f); /* Instrument type (always 0) */ xih.samples = hio_read16l(f); /* Number of samples */ xih.sh_size = hio_read32l(f); /* Sample header size */ /* Sanity check */ if (xih.samples > 0x10 || (xih.samples > 0 && xih.sh_size > 0x100)) { D_(D_CRIT "Sanity check: %d %d", xih.samples, xih.sh_size); return -1; } libxmp_instrument_name(mod, i, xih.name, 22); xxi->nsm = xih.samples; if (xxi->nsm > 16) xxi->nsm = 16; D_(D_INFO "[%2X] %-22.22s %2d", i, xxi->name, xxi->nsm); if (xxi->nsm) { if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) return -1; if (xih.size < XM_INST_HEADER_SIZE) return -1; /* for BoobieSqueezer (see http://boobie.rotfl.at/) * It works pretty much the same way as Impulse Tracker's sample * only mode, where it will strip off the instrument data. */ if (xih.size < XM_INST_HEADER_SIZE + XM_INST_SIZE) { memset(&xi, 0, sizeof (struct xm_instrument)); hio_seek(f, xih.size - XM_INST_HEADER_SIZE, SEEK_CUR); } else { hio_read(&xi.sample, 96, 1, f); /* Sample map */ for (j = 0; j < 24; j++) xi.v_env[j] = hio_read16l(f); /* Points for volume envelope */ for (j = 0; j < 24; j++) xi.p_env[j] = hio_read16l(f); /* Points for pan envelope */ xi.v_pts = hio_read8(f); /* Number of volume points */ xi.p_pts = hio_read8(f); /* Number of pan points */ xi.v_sus = hio_read8(f); /* Volume sustain point */ xi.v_start = hio_read8(f); /* Volume loop start point */ xi.v_end = hio_read8(f); /* Volume loop end point */ xi.p_sus = hio_read8(f); /* Pan sustain point */ xi.p_start = hio_read8(f); /* Pan loop start point */ xi.p_end = hio_read8(f); /* Pan loop end point */ xi.v_type = hio_read8(f); /* Bit 0:On 1:Sustain 2:Loop */ xi.p_type = hio_read8(f); /* Bit 0:On 1:Sustain 2:Loop */ xi.y_wave = hio_read8(f); /* Vibrato waveform */ xi.y_sweep = hio_read8(f); /* Vibrato sweep */ xi.y_depth = hio_read8(f); /* Vibrato depth */ xi.y_rate = hio_read8(f); /* Vibrato rate */ xi.v_fade = hio_read16l(f); /* Volume fadeout */ /* Skip reserved space */ hio_seek(f, (int)xih.size - (XM_INST_HEADER_SIZE + XM_INST_SIZE), SEEK_CUR); /* Envelope */ xxi->rls = xi.v_fade << 1; xxi->aei.npt = xi.v_pts; xxi->aei.sus = xi.v_sus; xxi->aei.lps = xi.v_start; xxi->aei.lpe = xi.v_end; xxi->aei.flg = xi.v_type; xxi->pei.npt = xi.p_pts; xxi->pei.sus = xi.p_sus; xxi->pei.lps = xi.p_start; xxi->pei.lpe = xi.p_end; xxi->pei.flg = xi.p_type; if (xxi->aei.npt <= 0 || xxi->aei.npt > 12 /*XMP_MAX_ENV_POINTS*/) xxi->aei.flg &= ~XMP_ENVELOPE_ON; else memcpy(xxi->aei.data, xi.v_env, xxi->aei.npt * 4); if (xxi->pei.npt <= 0 || xxi->pei.npt > 12 /*XMP_MAX_ENV_POINTS*/) xxi->pei.flg &= ~XMP_ENVELOPE_ON; else memcpy(xxi->pei.data, xi.p_env, xxi->pei.npt * 4); for (j = 12; j < 108; j++) { xxi->map[j].ins = xi.sample[j - 12]; if (xxi->map[j].ins >= xxi->nsm) xxi->map[j].ins = -1; } } for (j = 0; j < xxi->nsm; j++, sample_num++) { struct xmp_subinstrument *sub = &xxi->sub[j]; struct xmp_sample *xxs; if (sample_num >= mod->smp) { mod->xxs = libxmp_realloc_samples(mod->xxs, &mod->smp, mod->smp * 3 / 2); if (mod->xxs == NULL) return -1; } xxs = &mod->xxs[sample_num]; xsh[j].length = hio_read32l(f); /* Sample length */ /* Sanity check */ if (xsh[j].length > MAX_SAMPLE_SIZE) return -1; xsh[j].loop_start = hio_read32l(f); /* Sample loop start */ xsh[j].loop_length = hio_read32l(f); /* Sample loop length */ xsh[j].volume = hio_read8(f); /* Volume */ xsh[j].finetune = hio_read8s(f); /* Finetune (-128..+127) */ xsh[j].type = hio_read8(f); /* Flags */ xsh[j].pan = hio_read8(f); /* Panning (0-255) */ xsh[j].relnote = hio_read8s(f); /* Relative note number */ xsh[j].reserved = hio_read8(f); hio_read(&xsh[j].name, 22, 1, f); /* Sample_name */ sub->vol = xsh[j].volume; sub->pan = xsh[j].pan; sub->xpo = xsh[j].relnote; sub->fin = xsh[j].finetune; sub->vwf = xi.y_wave; sub->vde = xi.y_depth << 2; sub->vra = xi.y_rate; sub->vsw = xi.y_sweep; sub->sid = sample_num; libxmp_copy_adjust(xxs->name, xsh[j].name, 22); xxs->len = xsh[j].length; xxs->lps = xsh[j].loop_start; xxs->lpe = xsh[j].loop_start + xsh[j].loop_length; xxs->flg = 0; if (xsh[j].type & XM_SAMPLE_16BIT) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } xxs->flg |= xsh[j].type & XM_LOOP_FORWARD ? XMP_SAMPLE_LOOP : 0; xxs->flg |= xsh[j].type & XM_LOOP_PINGPONG ? XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR : 0; } for (j = 0; j < xxi->nsm; j++) { struct xmp_subinstrument *sub = &xxi->sub[j]; int flags; D_(D_INFO " %1x: %06x%c%06x %06x %c V%02x F%+04d P%02x R%+03d", j, mod->xxs[sub->sid].len, mod->xxs[sub->sid].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[sub->sid].lps, mod->xxs[sub->sid].lpe, mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->fin, sub->pan, sub->xpo); flags = SAMPLE_FLAG_DIFF; #ifndef LIBXMP_CORE_PLAYER if (xsh[j].reserved == 0xad) { flags = SAMPLE_FLAG_ADPCM; } #endif if (version > 0x0103) { if (libxmp_load_sample(m, f, flags, &mod->xxs[sub->sid], NULL) < 0) { return -1; } } } } else { /* Sample size should be in struct xm_instrument according to * the official format description, but FT2 actually puts it in * struct xm_instrument header. There's a tracker or converter * that follow the specs, so we must handle both cases (see * "Braintomb" by Jazztiz/ART). */ /* Umm, Cyke O'Path sent me a couple of * mods ("Breath of the Wind" and "Broken Dimension") that * reserve the instrument data space after the instrument header * even if the number of instruments is set to 0. In these modules * the instrument header size is marked as 263. The following * generalization should take care of both cases. */ hio_seek(f, (int)xih.size - XM_INST_HEADER_SIZE, SEEK_CUR); } } /* Final sample number adjustment */ mod->xxs = libxmp_realloc_samples(mod->xxs, &mod->smp, sample_num); if (mod->xxs == NULL) return -1; return 0; } static int xm_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xm_file_header xfh; char tracker_name[21]; int len; LOAD_INIT(); hio_read(&xfh.id, 17, 1, f); /* ID text */ hio_read(&xfh.name, 20, 1, f); /* Module name */ hio_read8(f); /* 0x1a */ hio_read(&xfh.tracker, 20, 1, f); /* Tracker name */ xfh.version = hio_read16l(f); /* Version number, minor-major */ xfh.headersz = hio_read32l(f); /* Header size */ xfh.songlen = hio_read16l(f); /* Song length */ xfh.restart = hio_read16l(f); /* Restart position */ xfh.channels = hio_read16l(f); /* Number of channels */ xfh.patterns = hio_read16l(f); /* Number of patterns */ xfh.instruments = hio_read16l(f); /* Number of instruments */ xfh.flags = hio_read16l(f); /* 0=Amiga freq table, 1=Linear */ xfh.tempo = hio_read16l(f); /* Default tempo */ xfh.bpm = hio_read16l(f); /* Default BPM */ /* Sanity checks */ if (xfh.songlen > 256 || xfh.patterns > 256 || xfh.instruments > 255) { D_(D_CRIT "Sanity check: %d %d %d", xfh.songlen, xfh.patterns, xfh.instruments); return -1; } if (xfh.restart > 255 || xfh.channels > XMP_MAX_CHANNELS) { D_(D_CRIT "Sanity check: %d %d", xfh.restart, xfh.channels); return -1; } if (xfh.tempo >= 32 || xfh.bpm < 32 || xfh.bpm > 255) { if (memcmp("MED2XM", xfh.tracker, 6)) { D_(D_CRIT "Sanity check: %d %d", xfh.tempo, xfh.bpm); return -1; } } len = xfh.headersz - 0x14; if (len < 0 || len > 256) { D_(D_CRIT "Sanity check: %d", len); return -1; } /* Honor header size -- needed by BoobieSqueezer XMs */ hio_read(&xfh.order, len, 1, f); /* Pattern order table */ strncpy(mod->name, (char *)xfh.name, 20); mod->len = xfh.songlen; mod->chn = xfh.channels; mod->pat = xfh.patterns; mod->ins = xfh.instruments; mod->rst = xfh.restart; mod->spd = xfh.tempo; mod->bpm = xfh.bpm; mod->trk = mod->chn * mod->pat + 1; m->c4rate = C4_NTSC_RATE; m->period_type = xfh.flags & XM_LINEAR_PERIOD_MODE ? PERIOD_LINEAR : PERIOD_AMIGA; memcpy(mod->xxo, xfh.order, mod->len); tracker_name[20] = 0; snprintf(tracker_name, 20, "%-20.20s", xfh.tracker); for (i = 20; i >= 0; i--) { if (tracker_name[i] == 0x20) tracker_name[i] = 0; if (tracker_name[i]) break; } /* OpenMPT accurately emulates weird FT2 bugs */ if (!strncmp(tracker_name, "FastTracker v2.00", 17) || !strncmp(tracker_name, "OpenMPT ", 8)) { m->quirk |= QUIRK_FT2BUGS; } #ifndef LIBXMP_CORE_PLAYER if (xfh.headersz == 0x0113) { strcpy(tracker_name, "unknown tracker"); m->quirk &= ~QUIRK_FT2BUGS; } else if (*tracker_name == 0) { strcpy(tracker_name, "Digitrakker"); /* best guess */ m->quirk &= ~QUIRK_FT2BUGS; } /* See MMD1 loader for explanation */ if (!strncmp(tracker_name, "MED2XM by J.Pynnone", 19)) { if (mod->bpm <= 10) mod->bpm = 125 * (0x35 - mod->bpm * 2) / 33; m->quirk &= ~QUIRK_FT2BUGS; } if (!strncmp(tracker_name, "FastTracker v 2.00", 18)) { strcpy(tracker_name, "old ModPlug Tracker"); m->quirk &= ~QUIRK_FT2BUGS; } libxmp_set_type(m, "%s XM %d.%02d", tracker_name, xfh.version >> 8, xfh.version & 0xff); #else libxmp_set_type(m, tracker_name); #endif MODULE_INFO(); /* Honor header size */ hio_seek(f, start + xfh.headersz + 60, SEEK_SET); /* XM 1.02/1.03 has a different patterns and instruments order */ if (xfh.version <= 0x0103) { if (load_instruments(m, xfh.version, f) < 0) return -1; if (load_patterns(m, xfh.version, f) < 0) return -1; } else { if (load_patterns(m, xfh.version, f) < 0) return -1; if (load_instruments(m, xfh.version, f) < 0) return -1; } D_(D_INFO "Stored samples: %d", mod->smp); /* XM 1.02 stores all samples after the patterns */ if (xfh.version <= 0x0103) { for (i = 0; i < mod->ins; i++) { for (j = 0; j < mod->xxi[i].nsm; j++) { int sid = mod->xxi[i].sub[j].sid; if (libxmp_load_sample(m, f, SAMPLE_FLAG_DIFF, &mod->xxs[sid], NULL) < 0) { return -1; } } } } for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = 0x80; } m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; return 0; } libxmp-4.4.1/src/loaders/fnk_load.c0000664000175000017500000002030412774567167017025 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #define MAGIC_Funk MAGIC4('F','u','n','k') static int fnk_test (HIO_HANDLE *, char *, const int); static int fnk_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_fnk = { "Funktracker", fnk_test, fnk_load }; static int fnk_test(HIO_HANDLE *f, char *t, const int start) { uint8 a, b; int size; if (hio_read32b(f) != MAGIC_Funk) return -1; hio_read8(f); a = hio_read8(f); b = hio_read8(f); hio_read8(f); if ((a >> 1) < 10) /* creation year (-1980) */ return -1; if (MSN(b) > 7 || LSN(b) > 9) /* CPU and card */ return -1; size = hio_read32l(f); if (size < 1024) return -1; if (hio_size(f) != size) return -1; libxmp_read_title(f, t, 0); return 0; } struct fnk_instrument { uint8 name[19]; /* ASCIIZ instrument name */ uint32 loop_start; /* Instrument loop start */ uint32 length; /* Instrument length */ uint8 volume; /* Volume (0-255) */ uint8 pan; /* Pan (0-255) */ uint8 shifter; /* Portamento and offset shift */ uint8 waveform; /* Vibrato and tremolo waveforms */ uint8 retrig; /* Retrig and arpeggio speed */ }; struct fnk_header { uint8 marker[4]; /* 'Funk' */ uint8 info[4]; /* */ uint32 filesize; /* File size */ uint8 fmt[4]; /* F2xx, Fkxx or Fvxx */ uint8 loop; /* Loop order number */ uint8 order[256]; /* Order list */ uint8 pbrk[128]; /* Break list for patterns */ struct fnk_instrument fih[64]; /* Instruments */ }; static int fnk_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; /* int day, month, year; */ struct xmp_event *event; struct fnk_header ffh; uint8 ev[3]; LOAD_INIT(); hio_read(&ffh.marker, 4, 1, f); hio_read(&ffh.info, 4, 1, f); ffh.filesize = hio_read32l(f); hio_read(&ffh.fmt, 4, 1, f); ffh.loop = hio_read8(f); hio_read(&ffh.order, 256, 1, f); hio_read(&ffh.pbrk, 128, 1, f); for (i = 0; i < 128; i++) { if (ffh.pbrk[i] >= 64) { return -1; } } for (i = 0; i < 64; i++) { hio_read(&ffh.fih[i].name, 19, 1, f); ffh.fih[i].loop_start = hio_read32l(f); ffh.fih[i].length = hio_read32l(f); ffh.fih[i].volume = hio_read8(f); ffh.fih[i].pan = hio_read8(f); ffh.fih[i].shifter = hio_read8(f); ffh.fih[i].waveform = hio_read8(f); ffh.fih[i].retrig = hio_read8(f); } /* day = ffh.info[0] & 0x1f; month = ((ffh.info[1] & 0x01) << 3) | ((ffh.info[0] & 0xe0) >> 5); year = 1980 + ((ffh.info[1] & 0xfe) >> 1); */ mod->smp = mod->ins = 64; for (i = 0; i < 256 && ffh.order[i] != 0xff; i++) { if (ffh.order[i] > mod->pat) mod->pat = ffh.order[i]; } mod->pat++; mod->len = i; memcpy (mod->xxo, ffh.order, mod->len); mod->spd = 4; mod->bpm = 125; mod->chn = 0; /* * If an R1 fmt (funktype = Fk** or Fv**), then ignore byte 3. It's * unreliable. It used to store the (GUS) sample memory requirement. */ if (ffh.fmt[0] == 'F' && ffh.fmt[1] == '2') { if (((int8)ffh.info[3] >> 1) & 0x40) mod->bpm -= (ffh.info[3] >> 1) & 0x3f; else mod->bpm += (ffh.info[3] >> 1) & 0x3f; libxmp_set_type(m, "FunktrackerGOLD"); } else if (ffh.fmt[0] == 'F' && (ffh.fmt[1] == 'v' || ffh.fmt[1] == 'k')) { libxmp_set_type(m, "Funktracker"); } else { mod->chn = 8; libxmp_set_type(m, "Funktracker DOS32"); } if (mod->chn == 0) { mod->chn = (ffh.fmt[2] < '0') || (ffh.fmt[2] > '9') || (ffh.fmt[3] < '0') || (ffh.fmt[3] > '9') ? 8 : (ffh.fmt[2] - '0') * 10 + ffh.fmt[3] - '0'; } mod->bpm = 4 * mod->bpm / 5; mod->trk = mod->chn * mod->pat; /* FNK allows mode per instrument but we don't, so use linear for all */ m->period_type = PERIOD_LINEAR; MODULE_INFO(); /* D_(D_INFO "Creation date: %02d/%02d/%04d", day, month, year); */ if (libxmp_init_instrument(m) < 0) return -1; /* Convert instruments */ for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; mod->xxs[i].len = ffh.fih[i].length; mod->xxs[i].lps = ffh.fih[i].loop_start; if (mod->xxs[i].lps == -1) mod->xxs[i].lps = 0; mod->xxs[i].lpe = ffh.fih[i].length; mod->xxs[i].flg = ffh.fih[i].loop_start != -1 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].vol = ffh.fih[i].volume; mod->xxi[i].sub[0].pan = ffh.fih[i].pan; mod->xxi[i].sub[0].sid = i; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; libxmp_instrument_name(mod, i, ffh.fih[i].name, 19); D_(D_INFO "[%2X] %-20.20s %04x %04x %04x %c V%02x P%02x", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].pan); } if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; EVENT(i, 1, ffh.pbrk[i]).f2t = FX_BREAK; for (j = 0; j < 64 * mod->chn; j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); hio_read(&ev, 1, 3, f); switch (ev[0] >> 2) { case 0x3f: case 0x3e: case 0x3d: break; default: event->note = 37 + (ev[0] >> 2); event->ins = 1 + MSN(ev[1]) + ((ev[0] & 0x03) << 4); event->vol = ffh.fih[event->ins - 1].volume; } switch (LSN(ev[1])) { case 0x00: event->fxt = FX_PER_PORTA_UP; event->fxp = ev[2]; break; case 0x01: event->fxt = FX_PER_PORTA_DN; event->fxp = ev[2]; break; case 0x02: event->fxt = FX_PER_TPORTA; event->fxp = ev[2]; break; case 0x03: event->fxt = FX_PER_VIBRATO; event->fxp = ev[2]; break; case 0x06: event->fxt = FX_PER_VSLD_UP; event->fxp = ev[2] << 1; break; case 0x07: event->fxt = FX_PER_VSLD_DN; event->fxp = ev[2] << 1; break; case 0x0b: event->fxt = FX_ARPEGGIO; event->fxp = ev[2]; break; case 0x0d: event->fxt = FX_VOLSET; event->fxp = ev[2]; break; case 0x0e: if (ev[2] == 0x0a || ev[2] == 0x0b || ev[2] == 0x0c) { event->fxt = FX_PER_CANCEL; break; } switch (MSN(ev[2])) { case 0x1: event->fxt = FX_EXTENDED; event->fxp = (EX_CUT << 4) | LSN(ev[2]); break; case 0x2: event->fxt = FX_EXTENDED; event->fxp = (EX_DELAY << 4) | LSN(ev[2]); break; case 0xd: event->fxt = FX_EXTENDED; event->fxp = (EX_RETRIG << 4) | LSN(ev[2]); break; case 0xe: event->fxt = FX_SETPAN; event->fxp = 8 + (LSN(ev[2]) << 4); break; case 0xf: event->fxt = FX_SPEED; event->fxp = LSN(ev[2]); break; } } } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len <= 2) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } for (i = 0; i < mod->chn; i++) mod->xxc[i].pan = 0x80; m->volbase = 0xff; m->quirk = QUIRK_VSALL; return 0; } libxmp-4.4.1/src/loaders/chip_load.c0000664000175000017500000001100712774567167017172 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "mod.h" #include "period.h" static int chip_test(HIO_HANDLE *, char *, const int); static int chip_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_chip = { "Chiptracker", chip_test, chip_load }; static int chip_test(HIO_HANDLE *f, char *t, const int start) { char buf[4]; hio_seek(f, start + 952, SEEK_SET); if (hio_read(buf, 1, 4, f) < 4) return -1; /* Also RASP? */ if (memcmp(buf, "KRIS", 4) != 0) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } static int chip_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct mod_header mh; uint8 *tidx; int i, j, tnum; LOAD_INIT(); if ((tidx = calloc(1, 1024)) == NULL) { goto err; } hio_read(&mh.name, 20, 1, f); hio_read16b(f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } hio_read(&mh.magic, 4, 1, f); mh.len = hio_read8(f); /* Sanity check */ if (mh.len > 128) { goto err2; } mh.restart = hio_read8(f); hio_read(tidx, 1024, 1, f); hio_read16b(f); mod->chn = 4; mod->ins = 31; mod->smp = mod->ins; mod->len = mh.len; mod->pat = mh.len; mod->rst = mh.restart; tnum = 0; for (i = 0; i < mod->len; i++) { mod->xxo[i] = i; for (j = 0; j < 4; j++) { int t = tidx[2 * (4 * i + j)]; if (t > tnum) tnum = t; } } mod->trk = tnum + 1; strncpy(mod->name, (char *)mh.name, 20); libxmp_set_type(m, "Chiptracker"); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) goto err2; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) goto err2; sub = &xxi->sub[0]; xxs->len = 2 * mh.ins[i].size; xxs->lps = mh.ins[i].loop_start; xxs->lpe = xxs->lps + 2 * mh.ins[i].loop_size; xxs->flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; sub->fin = (int8) (mh.ins[i].finetune << 4); sub->vol = mh.ins[i].volume; sub->pan = 0x80; sub->sid = i; if (xxs->len > 0) xxi->nsm = 1; libxmp_instrument_name(mod, i, mh.ins[i].name, 22); } if (libxmp_init_pattern(mod) < 0) goto err2; for (i = 0; i < mod->len; i++) { if (libxmp_alloc_pattern(mod, i) < 0) goto err2; mod->xxp[i]->rows = 64; for (j = 0; j < 4; j++) { int t = tidx[2 * (4 * i + j)]; mod->xxp[i]->index[j] = t; } } /* Load and convert tracks */ D_(D_INFO "Stored tracks: %d", mod->trk); for (i = 0; i < mod->trk; i++) { if (libxmp_alloc_track(mod, i, 64) < 0) goto err2; for (j = 0; j < 64; j++) { struct xmp_event *event = &mod->xxt[i]->event[j]; uint8 e[4]; hio_read(e, 1, 4, f); if (e[0] && e[0] != 0xa8) event->note = 13 + e[0] / 2; event->ins = e[1]; event->fxt = e[2] & 0x0f; event->fxp = e[3]; } } m->period_type = PERIOD_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (mod->xxs[i].len == 0) continue; if (libxmp_load_sample(m, f, SAMPLE_FLAG_FULLREP, &mod->xxs[i], NULL) < 0) goto err2; } free(tidx); return 0; err2: free(tidx); err: return -1; } libxmp-4.4.1/src/loaders/med.h0000664000175000017500000002504112773463501016007 0ustar claudioclaudio#ifndef LIBXMP_MED_H #define LIBXMP_MED_H #include "common.h" #include "hio.h" #define MMD_INST_TYPES 9 #ifdef DEBUG extern const char *const mmd_inst_type[]; #endif typedef int32 LONG; typedef uint32 ULONG; typedef int16 WORD; typedef uint16 UWORD; typedef int8 BYTE; typedef uint8 UBYTE; #ifndef __amigaos4__ typedef char *STRPTR; #endif /* Structures as defined in the MED/OctaMED MMD0 and MMD1 file formats, * revision 1, described by Teijo Kinnunen in Apr 25 1992 */ struct PlaySeq { char name[32]; /* (0) 31 chars + \0 */ ULONG reserved[2]; /* (32) for possible extensions */ UWORD length; /* (40) # of entries */ UWORD seq[1]; /* (42) block numbers.. */ }; struct MMD0sample { UWORD rep, replen; /* offs: 0(s), 2(s) */ UBYTE midich; /* offs: 4(s) */ UBYTE midipreset; /* offs: 5(s) */ UBYTE svol; /* offs: 6(s) */ BYTE strans; /* offs: 7(s) */ }; struct MMD0song { struct MMD0sample sample[63]; /* 63 * 8 bytes = 504 bytes */ UWORD numblocks; /* offs: 504 */ UWORD songlen; /* offs: 506 */ UBYTE playseq[256]; /* offs: 508 */ UWORD deftempo; /* offs: 764 */ BYTE playtransp; /* offs: 766 */ #define FLAG_FILTERON 0x1 /* the hardware audio filter is on */ #define FLAG_JUMPINGON 0x2 /* mouse pointer jumping on */ #define FLAG_JUMP8TH 0x4 /* ump every 8th line (not in OctaMED Pro) */ #define FLAG_INSTRSATT 0x8 /* sng+samples indicator (not useful in MMDs) */ #define FLAG_VOLHEX 0x10 /* volumes are HEX */ #define FLAG_STSLIDE 0x20 /* use ST/NT/PT compatible sliding */ #define FLAG_8CHANNEL 0x40 /* this is OctaMED 5-8 channel song */ #define FLAG_SLOWHQ 0X80 /* HQ V2-4 compatibility mode */ UBYTE flags; /* offs: 767 */ #define FLAG2_BMASK 0x1F /* (bits 0-4) BPM beat length (in lines) */ #define FLAG2_BPM 0x20 /* BPM mode on */ #define FLAG2_MIX 0x80 /* Module uses mixing */ UBYTE flags2; /* offs: 768 */ UBYTE tempo2; /* offs: 769 */ UBYTE trkvol[16]; /* offs: 770 */ UBYTE mastervol; /* offs: 786 */ UBYTE numsamples; /* offs: 787 */ }; /* length = 788 bytes */ /* This structure is exactly as long as the MMDsong structure. Common fields * are located at same offsets. You can also see, that there's a lot of room * for expansion in this structure. */ struct MMD2song { struct MMD0sample sample[63]; UWORD numblocks; UWORD songlen; /* NOTE: number of sections in MMD2 */ struct PlaySeq **playseqtable; UWORD *sectiontable; /* UWORD section numbers */ UBYTE *trackvols; /* UBYTE track volumes */ UWORD numtracks; /* max. number of tracks in the song * (also the number of entries in * 'trackvols' table) */ UWORD numpseqs; /* number of PlaySeqs in 'playseqtable' */ BYTE *trackpans; /* NULL means 'all centered */ #define FLAG3_STEREO 0x1 /* Mixing in stereo */ #define FLAG3_FREEPAN 0x2 /* Mixing flag: free pan */ ULONG flags3; /* see defs below */ UWORD voladj; /* volume adjust (%), 0 means 100 */ UWORD channels; /* mixing channels, 0 means 4 */ UBYTE mix_echotype; /* 0 = nothing, 1 = normal, 2 = cross */ UBYTE mix_echodepth; /* 1 - 6, 0 = default */ UWORD mix_echolen; /* echo length in milliseconds */ BYTE mix_stereosep; /* stereo separation */ UBYTE pad0[223]; /* reserved for future expansion */ /* Fields below are MMD0/MMD1-compatible (except pad1[]) */ UWORD deftempo; BYTE playtransp; UBYTE flags; UBYTE flags2; UBYTE tempo2; UBYTE pad1[16]; /* used to be trackvols, in MMD2 reserved */ UBYTE mastervol; UBYTE numsamples; }; /* length = 788 bytes */ struct MMD0 { ULONG id; ULONG modlen; struct MMD0song *song; UWORD psecnum; /* MMD2 only */ UWORD pseq; /* MMD2 only */ struct MMD0Block **blockarr; #define MMD_LOADTOFASTMEM 0x1 UBYTE mmdflags; /* MMD2 only */ UBYTE reserved[3]; struct InstrHdr **smplarr; ULONG reserved2; struct MMD0exp *expdata; ULONG reserved3; UWORD pstate; /* some data for the player routine */ UWORD pblock; UWORD pline; UWORD pseqnum; WORD actplayline; UBYTE counter; UBYTE extra_songs; /* number of songs - 1 */ }; /* length = 52 bytes */ struct MMD0Block { UBYTE numtracks, lines; }; struct BlockCmdPageTable { UWORD num_pages; UWORD reserved; UWORD *page[1]; }; struct BlockInfo { ULONG *hlmask; UBYTE *blockname; ULONG blocknamelen; struct BlockCmdPageTable *pagetable; ULONG reserved[5]; }; struct MMD1Block { UWORD numtracks; UWORD lines; struct BlockInfo *info; }; struct InstrHdr { ULONG length; #define S_16 0x10 /* 16-bit sample */ #define STEREO 0x20 /* Stereo sample, not interleaved */ WORD type; /* Followed by actual data */ }; struct SynthWF { UWORD length; /* length in words */ BYTE wfdata[1]; /* the waveform */ }; struct SynthInstr { ULONG length; /* length of this struct */ WORD type; /* -1 or -2 (offs: 4) */ UBYTE defaultdecay; UBYTE reserved[3]; UWORD rep; UWORD replen; UWORD voltbllen; /* offs: 14 */ UWORD wftbllen; /* offs: 16 */ UBYTE volspeed; /* offs: 18 */ UBYTE wfspeed; /* offs: 19 */ UWORD wforms; /* offs: 20 */ UBYTE voltbl[128]; /* offs: 22 */ UBYTE wftbl[128]; /* offs: 150 */ ULONG wf[64]; /* offs: 278 */ }; struct InstrExt { UBYTE hold; UBYTE decay; UBYTE suppress_midi_off; BYTE finetune; /* Below fields saved by >= V5 */ UBYTE default_pitch; UBYTE instr_flags; UWORD long_midi_preset; /* Below fields saved by >= V5.02 */ UBYTE output_device; UBYTE reserved; /* Below fields saved by >= V7 */ ULONG long_repeat; ULONG long_replen; }; struct MMDInfo { struct MMDInfo *next; /* next MMDInfo structure */ UWORD reserved; UWORD type; /* data type (1 = ASCII) */ ULONG length; /* data length in bytes */ /* data follows... */ }; struct MMDARexxTrigCmd { struct MMDARexxTrigCmd *next; /* the next command, or NULL */ UBYTE cmdnum; /* command number (01..FF) */ UBYTE pad; WORD cmdtype; /* command type (OMACTION_...) */ STRPTR cmd; /* command, or NULL */ STRPTR port; /* port, or NULL */ UWORD cmd_len; /* length of 'cmd' string (without * term. 0) */ UWORD port_len; /* length of 'port' string (without * term. 0) */ }; /* current (V7) structure size: 20 */ struct MMDARexx { UWORD res; /* reserved, must be zero! */ UWORD trigcmdlen; /* size of trigcmd entries * (MUST be used!!) */ struct MMDARexxTrigCmd *trigcmd; /* chain of MMDARexxTrigCmds or NULL */ }; struct MMDMIDICmd3x { UBYTE struct_vers; /* current version = 0 */ UBYTE pad; UWORD num_of_settings; /* number of Cmd3x settings * (currently set to 15) */ UBYTE *ctrlr_types; /* controller types */ UWORD *ctrlr_numbers; /* controller numbers */ }; struct MMDInstrInfo { UBYTE name[40]; }; struct MMD0exp { struct MMD0 *nextmod; /* pointer to the next module */ struct InstrExt *exp_smp; /* pointer to InstrExt */ UWORD s_ext_entries; /* size of InstrExt structure array */ UWORD s_ext_entrsz; /* size of each InstrExt structure */ UBYTE *annotxt; /* pointer to the annotation text */ ULONG annolen; /* length of 'annotxt' */ struct MMDInstrInfo *iinfo; /* pointer to MMDInstrInfo */ UWORD i_ext_entries; /* size of MMDInstrInfo struct array */ UWORD i_ext_entrsz; /* size of each MMDInstrInfo struct */ ULONG jumpmask; /* mouse pointer jump control */ UWORD *rgbtable; /* screen colors */ UBYTE channelsplit[4]; /* channel splitting control */ struct NotationInfo *n_info; /* info for the notation editor */ UBYTE *songname; /* song name of the current song */ ULONG songnamelen; /* song name length */ struct MMDDumpData *dumps; /* MIDI dump data */ struct MMDInfo *mmdinfo; /* more information about the song */ struct MMDARexx *mmdrexx; /* embedded ARexx commands */ struct MMDMIDICmd3x *mmdcmd3x; /* settings for command 3x */ ULONG reserved2[3]; /* future expansion fields */ ULONG tag_end; }; struct NotationInfo { UBYTE n_of_sharps; /* number of sharps or flats */ #define NFLG_FLAT 1 #define NFLG_3_4 2 UBYTE flags; WORD trksel[5]; /* number of the selected track */ UBYTE trkshow[16]; /* tracks shown */ UBYTE trkghost[16]; /* tracks ghosted */ BYTE notetr[63]; /* note transpose for each instrument */ UBYTE pad; }; struct MMDDumpData { UWORD numdumps; UWORD reserved[3]; }; struct MMDDump { ULONG length; /* length of the MIDI message dump */ UBYTE *data; /* pointer to MIDI dump data */ UWORD ext_len; /* MMDDump struct extension length */ /* if ext_len >= 20: */ UBYTE name[20]; /* name of the dump */ }; void mmd_xlat_fx(struct xmp_event *, int, int, int, int); int mmd_alloc_tables(struct module_data *, int, struct SynthInstr *); int mmd_load_hybrid_instrument(HIO_HANDLE *, struct module_data *, int, int, struct SynthInstr *, struct InstrExt *, struct MMD0sample *); int mmd_load_synth_instrument(HIO_HANDLE *, struct module_data *, int, int, struct SynthInstr *, struct InstrExt *, struct MMD0sample *); int mmd_load_sampled_instrument(HIO_HANDLE *, struct module_data *, int, int, struct InstrHdr *, struct MMD0exp *, struct InstrExt *, struct MMD0sample *, int); int mmd_load_iffoct_instrument(HIO_HANDLE *, struct module_data *, int, int, struct InstrHdr *, int, struct InstrExt *, struct MMD0sample *); void mmd_set_bpm(struct module_data *, int, int, int, int); void mmd_info_text(HIO_HANDLE *, struct module_data *, int); #endif /* LIBXMP_MED_H */ libxmp-4.4.1/src/loaders/loader.h0000664000175000017500000000471312773566054016522 0ustar claudioclaudio#ifndef XMP_LOADER_H #define XMP_LOADER_H #include #include #include #include "common.h" #include "effects.h" #include "format.h" #include "hio.h" /* Sample flags */ #define SAMPLE_FLAG_DIFF 0x0001 /* Differential */ #define SAMPLE_FLAG_UNS 0x0002 /* Unsigned */ #define SAMPLE_FLAG_8BDIFF 0x0004 #define SAMPLE_FLAG_7BIT 0x0008 #define SAMPLE_FLAG_NOLOAD 0x0010 /* Get from buffer, don't load */ #define SAMPLE_FLAG_BIGEND 0x0040 /* Big-endian */ #define SAMPLE_FLAG_VIDC 0x0080 /* Archimedes VIDC logarithmic */ /*#define SAMPLE_FLAG_STEREO 0x0100 Interleaved stereo sample */ #define SAMPLE_FLAG_FULLREP 0x0200 /* Play full sample before looping */ #define SAMPLE_FLAG_ADLIB 0x1000 /* Adlib synth instrument */ #define SAMPLE_FLAG_HSC 0x2000 /* HSC Adlib synth instrument */ #define SAMPLE_FLAG_ADPCM 0x4000 /* ADPCM4 encoded samples */ #define DEFPAN(x) (0x80 + ((x) - 0x80) * m->defpan / 100) int libxmp_init_instrument (struct module_data *); int libxmp_alloc_subinstrument (struct xmp_module *, int, int); int libxmp_init_pattern (struct xmp_module *); int libxmp_alloc_pattern (struct xmp_module *, int); int libxmp_alloc_track (struct xmp_module *, int, int); int libxmp_alloc_tracks_in_pattern (struct xmp_module *, int); int libxmp_alloc_pattern_tracks (struct xmp_module *, int, int); char *libxmp_instrument_name (struct xmp_module *, int, uint8 *, int); struct xmp_sample* libxmp_realloc_samples(struct xmp_sample *, int *, int); char *libxmp_copy_adjust (char *, uint8 *, int); int libxmp_test_name (uint8 *, int); void libxmp_read_title (HIO_HANDLE *, char *, int); void libxmp_set_xxh_defaults (struct xmp_module *); void libxmp_decode_protracker_event (struct xmp_event *, uint8 *); void libxmp_decode_noisetracker_event(struct xmp_event *, uint8 *); void libxmp_disable_continue_fx (struct xmp_event *); int libxmp_check_filename_case (char *, char *, char *, int); void libxmp_get_instrument_path (struct module_data *, char *, int); void libxmp_set_type (struct module_data *, char *, ...); int libxmp_load_sample (struct module_data *, HIO_HANDLE *, int, struct xmp_sample *, void *); extern uint8 libxmp_ord_xlat[]; extern const int libxmp_arch_vol_table[]; #define MAGIC4(a,b,c,d) \ (((uint32)(a)<<24)|((uint32)(b)<<16)|((uint32)(c)<<8)|(d)) #define LOAD_INIT() #define MODULE_INFO() do { \ D_(D_WARN "Module title: \"%s\"", m->mod.name); \ D_(D_WARN "Module type: %s", m->mod.type); \ } while (0) #endif libxmp-4.4.1/src/loaders/sfx_load.c0000664000175000017500000001467112774567167017061 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Reverse engineered from the two SFX files in the Delitracker mods disk * and music from Future Wars, Twinworld and Operation Stealth. Effects * must be verified/implemented. */ /* From the ExoticRipper docs: * [SoundFX 2.0 is] simply the same as SoundFX 1.3, except that it * uses 31 samples [instead of 15]. */ #include "loader.h" #include "period.h" #define MAGIC_SONG MAGIC4('S','O','N','G') static int sfx_test(HIO_HANDLE *, char *, const int); static int sfx_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_sfx = { "SoundFX v1.3/2.0", sfx_test, sfx_load }; static int sfx_test(HIO_HANDLE * f, char *t, const int start) { uint32 a, b; hio_seek(f, 4 * 15, SEEK_CUR); a = hio_read32b(f); hio_seek(f, 4 * 15, SEEK_CUR); b = hio_read32b(f); if (a != MAGIC_SONG && b != MAGIC_SONG) return -1; libxmp_read_title(f, t, 0); return 0; } struct sfx_ins { uint8 name[22]; /* Instrument name */ uint16 len; /* Sample length in words */ uint8 finetune; /* Finetune */ uint8 volume; /* Volume (0-63) */ uint16 loop_start; /* Sample loop start in bytes */ uint16 loop_length; /* Sample loop length in words */ }; struct sfx_header { uint32 magic; /* 'SONG' */ uint16 delay; /* Delay value (tempo), default is 0x38e5 */ uint16 unknown[7]; /* ? */ }; struct sfx_header2 { uint8 len; /* Song length */ uint8 restart; /* Restart pos (?) */ uint8 order[128]; /* Order list */ }; static int sfx_13_20_load(struct module_data *m, HIO_HANDLE *f, const int nins, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct sfx_header sfx; struct sfx_header2 sfx2; uint8 ev[4]; int ins_size[31]; struct sfx_ins ins[31]; /* Instruments */ LOAD_INIT(); for (i = 0; i < nins; i++) ins_size[i] = hio_read32b(f); sfx.magic = hio_read32b(f); sfx.delay = hio_read16b(f); if (sfx.delay < 178) /* min value for 10000bpm */ return -1; hio_read(&sfx.unknown, 14, 1, f); if (sfx.magic != MAGIC_SONG) return -1; mod->chn = 4; mod->ins = nins; mod->smp = mod->ins; mod->bpm = 14565 * 122 / sfx.delay; for (i = 0; i < mod->ins; i++) { hio_read(&ins[i].name, 22, 1, f); ins[i].len = hio_read16b(f); ins[i].finetune = hio_read8(f); ins[i].volume = hio_read8(f); ins[i].loop_start = hio_read16b(f); ins[i].loop_length = hio_read16b(f); } sfx2.len = hio_read8(f); sfx2.restart = hio_read8(f); if (hio_read(&sfx2.order, 1, 128, f) != 128) return -1; mod->len = sfx2.len; if (mod->len > 0x7f) return -1; memcpy(mod->xxo, sfx2.order, mod->len); for (mod->pat = i = 0; i < mod->len; i++) if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; mod->pat++; mod->trk = mod->chn * mod->pat; if (mod->ins == 15) { libxmp_set_type(m, "SoundFX 1.3"); } else { libxmp_set_type(m, "SoundFX 2.0"); } MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi; struct xmp_subinstrument *sub; struct xmp_sample *xxs; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; xxi = &mod->xxi[i]; xxs = &mod->xxs[i]; sub = &xxi->sub[0]; xxs->len = ins_size[i]; xxs->lps = ins[i].loop_start; xxs->lpe = xxs->lps + 2 * ins[i].loop_length; xxs->flg = ins[i].loop_length > 1 ? XMP_SAMPLE_LOOP : 0; xxi->nsm = 1; sub->vol = ins[i].volume; sub->fin = (int8) (ins[i].finetune << 4); /* unsure */ sub->pan = 0x80; sub->sid = i; libxmp_instrument_name(mod, i, ins[i].name, 22); D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c %02x %+d", i, xxi->name, xxs->len, xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->fin >> 4); } if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < 64 * mod->chn; j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); hio_read(ev, 1, 4, f); event->note = libxmp_period_to_note((LSN(ev[0]) << 8) | ev[1]); event->ins = (MSN(ev[0]) << 4) | MSN(ev[2]); event->fxp = ev[3]; switch (LSN(ev[2])) { case 0x01: /* Arpeggio */ event->fxt = FX_ARPEGGIO; break; case 0x02: /* Pitch bend */ if (event->fxp >> 4) { event->fxt = FX_PORTA_DN; event->fxp >>= 4; } else if (event->fxp & 0x0f) { event->fxt = FX_PORTA_UP; event->fxp &= 0x0f; } break; case 0x5: /* Add to volume */ event->fxt = FX_VOL_ADD; break; case 0x6: /* Subtract from volume */ event->fxt = FX_VOL_SUB; break; case 0x7: /* Add semitones to period */ event->fxt = FX_PITCH_ADD; break; case 0x8: /* Subtract semitones from period */ event->fxt = FX_PITCH_SUB; break; case 0x3: /* LED on */ case 0x4: /* LED off */ default: event->fxt = event->fxp = 0; break; } } } m->quirk |= QUIRK_PBALL; m->period_type = PERIOD_MODRNG; /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len <= 2) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } static int sfx_load(struct module_data *m, HIO_HANDLE *f, const int start) { if (sfx_13_20_load(m, f, 15, start) < 0) return sfx_13_20_load(m, f, 31, start); return 0; } libxmp-4.4.1/src/loaders/pt3_load.c0000664000175000017500000001604412775035311016741 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "loader.h" #include "mod.h" #include "iff.h" #define MAGIC_FORM MAGIC4('F','O','R','M') #define MAGIC_MODL MAGIC4('M','O','D','L') #define MAGIC_VERS MAGIC4('V','E','R','S') #define MAGIC_INFO MAGIC4('I','N','F','O') static int pt3_test(HIO_HANDLE *, char *, const int); static int pt3_load(struct module_data *, HIO_HANDLE *, const int); static int ptdt_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_pt3 = { "Protracker 3", pt3_test, pt3_load }; static int pt3_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_FORM) return -1; hio_read32b(f); /* skip size */ if (hio_read32b(f) != MAGIC_MODL) return -1; if (hio_read32b(f) != MAGIC_VERS) return -1; hio_read32b(f); /* skip size */ hio_seek(f, 10, SEEK_CUR); if (hio_read32b(f) == MAGIC_INFO) { hio_read32b(f); /* skip size */ libxmp_read_title(f, t, 32); } else { libxmp_read_title(f, t, 0); } return 0; } #define PT3_FLAG_CIA 0x0001 /* VBlank if not set */ #define PT3_FLAG_FILTER 0x0002 /* Filter status */ #define PT3_FLAG_SONG 0x0004 /* Modules have this bit unset */ #define PT3_FLAG_IRQ 0x0008 /* Soft IRQ */ #define PT3_FLAG_VARPAT 0x0010 /* Variable pattern length */ #define PT3_FLAG_8VOICE 0x0020 /* 4 voices if not set */ #define PT3_FLAG_16BIT 0x0040 /* 8 bit samples if not set */ #define PT3_FLAG_RAWPAT 0x0080 /* Packed patterns if not set */ static int get_info(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; /* int flags; */ /* int day, month, year, hour, min, sec; int dhour, dmin, dsec; */ hio_read(mod->name, 1, 32, f); mod->ins = hio_read16b(f); mod->len = hio_read16b(f); mod->pat = hio_read16b(f); mod->gvl = hio_read16b(f); mod->bpm = hio_read16b(f); /*flags =*/ hio_read16b(f); /*day =*/ hio_read16b(f); /*month =*/ hio_read16b(f); /*year =*/ hio_read16b(f); /*hour =*/ hio_read16b(f); /*min =*/ hio_read16b(f); /*sec =*/ hio_read16b(f); /*dhour =*/ hio_read16b(f); /*dmin =*/ hio_read16b(f); /*dsec =*/ hio_read16b(f); /* Sanity check */ if (mod->ins > 255 || mod->len > 256 || mod->pat > 255) { return -1; } MODULE_INFO(); /*D_(D_INFO "Creation date: %02d/%02d/%02d %02d:%02d:%02d", day, month, year, hour, min, sec); D_(D_INFO "Playing time: %02d:%02d:%02d", dhour, dmin, dsec);*/ return 0; } static int get_cmnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { D_(D_INFO "Comment size: %d", size); return 0; } static int get_ptdt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { ptdt_load(m, f, 0); return 0; } static int pt3_load(struct module_data *m, HIO_HANDLE *f, const int start) { iff_handle handle; char buf[20]; int ret; LOAD_INIT(); hio_read32b(f); /* FORM */ hio_read32b(f); /* size */ hio_read32b(f); /* MODL */ hio_read32b(f); /* VERS */ hio_read32b(f); /* VERS size */ hio_read(buf, 1, 10, f); libxmp_set_type(m, "%-6.6s IFFMODL", buf + 4); handle = libxmp_iff_new(); if (handle == NULL) return -1; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "INFO", get_info); ret |= libxmp_iff_register(handle, "CMNT", get_cmnt); ret |= libxmp_iff_register(handle, "PTDT", get_ptdt); if (ret != 0) return -1; libxmp_iff_set_quirk(handle, IFF_FULL_CHUNK_SIZE); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, NULL) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); /* Sanity check */ if (m->mod.smp <= 0) { return -1; } return 0; } static int ptdt_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); hio_read(&mh.magic, 4, 1, f); mod->ins = 31; mod->smp = mod->ins; mod->chn = 4; mod->len = mh.len; mod->rst = mh.restart; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; mod->trk = mod->chn * mod->pat; if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; mod->xxs[i].flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; mod->xxi[i].sub[0].fin = (int8)(mh.ins[i].finetune << 4); mod->xxi[i].sub[0].vol = mh.ins[i].volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].rls = 0xfff; libxmp_instrument_name(mod, i, mh.ins[i].name, 22); D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mh.ins[i].loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); } if (libxmp_init_pattern(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, j % 4, j / 4); hio_read(mod_event, 1, 4, f); libxmp_decode_protracker_event(event, mod_event); } } m->period_type = PERIOD_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (!mod->xxs[i].len) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/it_load.c0000664000175000017500000007476612777410630016671 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef LIBXMP_CORE_DISABLE_IT #include #include "loader.h" #include "it.h" #include "period.h" #define MAGIC_IMPM MAGIC4('I','M','P','M') #define MAGIC_IMPI MAGIC4('I','M','P','I') #define MAGIC_IMPS MAGIC4('I','M','P','S') static int it_test(HIO_HANDLE *, char *, const int); static int it_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_it = { "Impulse Tracker", it_test, it_load }; #ifdef WIN32 struct tm *localtime_r(const time_t * timep, struct tm *result) { /* Note: Win32 localtime() is thread-safe */ memcpy(result, localtime(timep), sizeof(struct tm)); return result; } #endif static int it_test(HIO_HANDLE * f, char *t, const int start) { if (hio_read32b(f) != MAGIC_IMPM) return -1; libxmp_read_title(f, t, 26); return 0; } #define FX_NONE 0xff #define FX_XTND 0xfe #define L_CHANNELS 64 static const uint8 fx[] = { /* */ FX_NONE, /* A */ FX_S3M_SPEED, /* B */ FX_JUMP, /* C */ FX_IT_BREAK, /* D */ FX_VOLSLIDE, /* E */ FX_PORTA_DN, /* F */ FX_PORTA_UP, /* G */ FX_TONEPORTA, /* H */ FX_VIBRATO, /* I */ FX_TREMOR, /* J */ FX_S3M_ARPEGGIO, /* K */ FX_VIBRA_VSLIDE, /* L */ FX_TONE_VSLIDE, /* M */ FX_TRK_VOL, /* N */ FX_TRK_VSLIDE, /* O */ FX_OFFSET, /* P */ FX_IT_PANSLIDE, /* Q */ FX_MULTI_RETRIG, /* R */ FX_TREMOLO, /* S */ FX_XTND, /* T */ FX_IT_BPM, /* U */ FX_FINE_VIBRATO, /* V */ FX_GLOBALVOL, /* W */ FX_GVOL_SLIDE, /* X */ FX_SETPAN, /* Y */ FX_PANBRELLO, /* Z */ FX_FLT_CUTOFF }; int itsex_decompress8 (HIO_HANDLE *, void *, int, int); int itsex_decompress16 (HIO_HANDLE *, void *, int, int); static void xlat_fx(int c, struct xmp_event *e, uint8 *last_fxp, int new_fx) { uint8 h = MSN(e->fxp), l = LSN(e->fxp); switch (e->fxt = fx[e->fxt]) { case FX_XTND: /* Extended effect */ e->fxt = FX_EXTENDED; if (h == 0 && e->fxp == 0) { e->fxp = last_fxp[c]; h = MSN(e->fxp); l = LSN(e->fxp); } else { last_fxp[c] = e->fxp; } switch (h) { case 0x1: /* Glissando */ e->fxp = 0x30 | l; break; case 0x2: /* Finetune -- not supported */ e->fxt = e->fxp = 0; break; case 0x3: /* Vibrato wave */ e->fxp = 0x40 | l; break; case 0x4: /* Tremolo wave */ e->fxp = 0x70 | l; break; case 0x5: /* Panbrello wave */ if (l <= 3) { e->fxt = FX_PANBRELLO_WF; e->fxp = l; } else { e->fxt = e->fxp = 0; } break; case 0x6: /* Pattern delay */ e->fxp = 0xe0 | l; break; case 0x7: /* Instrument functions */ e->fxt = FX_IT_INSTFUNC; e->fxp &= 0x0f; break; case 0x8: /* Set pan position */ e->fxt = FX_SETPAN; e->fxp = l << 4; break; case 0x9: /* 0x91 = set surround */ e->fxt = FX_SURROUND; e->fxp = l; break; case 0xa: /* High offset */ e->fxt = FX_HIOFFSET; e->fxp = l; break; case 0xb: /* Pattern loop */ e->fxp = 0x60 | l; break; case 0xc: /* Note cut */ case 0xd: /* Note delay */ if ((e->fxp = l) == 0) e->fxp++; /* SD0 and SC0 become SD1 and SC1 */ e->fxp |= h << 4; break; case 0xe: /* Pattern row delay */ e->fxt = FX_IT_ROWDELAY; e->fxp = l; break; default: e->fxt = e->fxp = 0; } break; case FX_FLT_CUTOFF: if (e->fxp > 0x7f && e->fxp < 0x90) { /* Resonance */ e->fxt = FX_FLT_RESN; e->fxp = (e->fxp - 0x80) * 16; } else { /* Cutoff */ e->fxp *= 2; } break; case FX_TREMOR: if (!new_fx && e->fxp != 0) { e->fxp = ((MSN(e->fxp) + 1) << 4) | (LSN(e->fxp) + 1); } break; case FX_GLOBALVOL: if (e->fxp > 0x80) { /* See storlek test 16 */ e->fxt = e->fxp = 0; } break; case FX_NONE: /* No effect */ e->fxt = e->fxp = 0; break; } } static void xlat_volfx(struct xmp_event *event) { int b; b = event->vol; event->vol = 0; if (b <= 0x40) { event->vol = b + 1; } else if (b >= 65 && b <= 74) { /* A */ event->f2t = FX_F_VSLIDE_UP_2; event->f2p = b - 65; } else if (b >= 75 && b <= 84) { /* B */ event->f2t = FX_F_VSLIDE_DN_2; event->f2p = b - 75; } else if (b >= 85 && b <= 94) { /* C */ event->f2t = FX_VSLIDE_UP_2; event->f2p = b - 85; } else if (b >= 95 && b <= 104) { /* D */ event->f2t = FX_VSLIDE_DN_2; event->f2p = b - 95; } else if (b >= 105 && b <= 114) { /* E */ event->f2t = FX_PORTA_DN; event->f2p = (b - 105) << 2; } else if (b >= 115 && b <= 124) { /* F */ event->f2t = FX_PORTA_UP; event->f2p = (b - 115) << 2; } else if (b >= 128 && b <= 192) { /* pan */ if (b == 192) { event->f2p = 0xff; } else { event->f2p = (b - 128) << 2; } event->f2t = FX_SETPAN; } else if (b >= 193 && b <= 202) { /* G */ uint8 val[10] = { 0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60, 0x80, 0xff }; event->f2t = FX_TONEPORTA; event->f2p = val[b - 193]; } else if (b >= 203 && b <= 212) { /* H */ event->f2t = FX_VIBRATO; event->f2p = b - 203; } } static void fix_name(uint8 *s, int l) { int i; /* IT names can have 0 at start of data, replace with space */ for (l--, i = 0; i < l; i++) { if (s[i] == 0) s[i] = ' '; } for (i--; i >= 0 && s[i] == ' '; i--) { if (s[i] == ' ') s[i] = 0; } } static void read_envelope(struct xmp_envelope *ei, struct it_envelope *env, HIO_HANDLE *f) { int j; env->flg = hio_read8(f); env->num = hio_read8(f); /* Sanity check */ if (env->num >= XMP_MAX_ENV_POINTS) { env->flg = 0; env->num = 0; return; } env->lpb = hio_read8(f); env->lpe = hio_read8(f); env->slb = hio_read8(f); env->sle = hio_read8(f); for (j = 0; j < 25; j++) { env->node[j].y = hio_read8(f); env->node[j].x = hio_read16l(f); } env->unused = hio_read8(f); ei->flg = env->flg & IT_ENV_ON ? XMP_ENVELOPE_ON : 0; if (env->flg & IT_ENV_LOOP) { ei->flg |= XMP_ENVELOPE_LOOP; } if (env->flg & IT_ENV_SLOOP) { ei->flg |= XMP_ENVELOPE_SUS | XMP_ENVELOPE_SLOOP; } if (env->flg & IT_ENV_CARRY) { ei->flg |= XMP_ENVELOPE_CARRY; } ei->npt = env->num; ei->sus = env->slb; ei->sue = env->sle; ei->lps = env->lpb; ei->lpe = env->lpe; if (ei->npt > 0 && ei->npt <= 25 /* XMP_MAX_ENV_POINTS */ ) { for (j = 0; j < ei->npt; j++) { ei->data[j * 2] = env->node[j].x; ei->data[j * 2 + 1] = env->node[j].y; } } else { ei->flg &= ~XMP_ENVELOPE_ON; } } static void identify_tracker(struct module_data *m, struct it_file_header *ifh) { #ifndef LIBXMP_CORE_PLAYER char tracker_name[40]; int sample_mode = ~ifh->flags & IT_USE_INST; switch (ifh->cwt >> 8) { case 0x00: strcpy(tracker_name, "unmo3"); break; case 0x01: case 0x02: /* test from Schism Tracker sources */ if (ifh->cmwt == 0x0200 && ifh->cwt == 0x0214 && ifh->flags == 9 && ifh->special == 0 && ifh->hilite_maj == 0 && ifh->hilite_min == 0 && ifh->insnum == 0 && ifh->patnum + 1 == ifh->ordnum && ifh->gv == 128 && ifh->mv == 100 && ifh->is == 1 && ifh->sep == 128 && ifh->pwd == 0 && ifh->msglen == 0 && ifh->msgofs == 0 && ifh->rsvd == 0) { strcpy(tracker_name, "OpenSPC conversion"); } else if (ifh->cmwt == 0x0200 && ifh->cwt == 0x0217) { strcpy(tracker_name, "ModPlug Tracker 1.16"); /* ModPlug Tracker files aren't really IMPM 2.00 */ ifh->cmwt = sample_mode ? 0x100 : 0x214; } else if (ifh->cwt == 0x0216) { strcpy(tracker_name, "Impulse Tracker 2.14v3"); } else if (ifh->cwt == 0x0217) { strcpy(tracker_name, "Impulse Tracker 2.14v5"); } else if (ifh->cwt == 0x0214 && !memcmp(&ifh->rsvd, "CHBI", 4)) { strcpy(tracker_name, "Chibi Tracker"); } else { snprintf(tracker_name, 40, "Impulse Tracker %d.%02x", (ifh->cwt & 0x0f00) >> 8, ifh->cwt & 0xff); } break; case 0x08: case 0x7f: if (ifh->cwt == 0x0888) { strcpy(tracker_name, "OpenMPT 1.17"); } else if (ifh->cwt == 0x7fff) { strcpy(tracker_name, "munch.py"); } else { snprintf(tracker_name, 40, "unknown (%04x)", ifh->cwt); } break; default: switch (ifh->cwt >> 12) { case 0x1:{ uint16 cwtv = ifh->cwt & 0x0fff; struct tm version; time_t version_sec; if (cwtv > 0x50) { version_sec = ((cwtv - 0x050) * 86400) + 1254355200; if (localtime_r(&version_sec, &version)) { snprintf(tracker_name, 40, "Schism Tracker %04d-%02d-%02d", version.tm_year + 1900, version.tm_mon + 1, version.tm_mday); } } else { snprintf(tracker_name, 40, "Schism Tracker 0.%x", cwtv); } break; } case 0x5: snprintf(tracker_name, 40, "OpenMPT %d.%02x", (ifh->cwt & 0x0f00) >> 8, ifh->cwt & 0xff); if (memcmp(&ifh->rsvd, "OMPT", 4)) strncat(tracker_name, " (compat.)", 39); break; case 0x06: snprintf(tracker_name, 40, "BeRoTracker %d.%02x", (ifh->cwt & 0x0f00) >> 8, ifh->cwt & 0xff); break; default: snprintf(tracker_name, 40, "unknown (%04x)", ifh->cwt); } } libxmp_set_type(m, "%s IT %d.%02x", tracker_name, ifh->cmwt >> 8, ifh->cmwt & 0xff); #else libxmp_set_type(m, "Impulse Tracker"); #endif } static int load_old_it_instrument(struct xmp_instrument *xxi, HIO_HANDLE *f) { int inst_map[120], inst_rmap[XMP_MAX_KEYS]; struct it_instrument1_header i1h; int c, k, j; i1h.magic = hio_read32b(f); hio_read(&i1h.dosname, 12, 1, f); i1h.zero = hio_read8(f); i1h.flags = hio_read8(f); i1h.vls = hio_read8(f); i1h.vle = hio_read8(f); i1h.sls = hio_read8(f); i1h.sle = hio_read8(f); i1h.rsvd1 = hio_read16l(f); i1h.fadeout = hio_read16l(f); i1h.nna = hio_read8(f); i1h.dnc = hio_read8(f); i1h.trkvers = hio_read16l(f); i1h.nos = hio_read8(f); i1h.rsvd2 = hio_read8(f); if (hio_error(f)) { return -1; } if (hio_read(&i1h.name, 1, 26, f) != 26) { return -1; } fix_name(i1h.name, 26); if (hio_read(&i1h.rsvd3, 1, 6, f) != 6) return -1; if (hio_read(&i1h.keys, 1, 240, f) != 240) return -1; if (hio_read(&i1h.epoint, 1, 200, f) != 200) return -1; if (hio_read(&i1h.enode, 1, 50, f) != 50) return -1; libxmp_copy_adjust(xxi->name, i1h.name, 25); xxi->rls = i1h.fadeout << 7; xxi->aei.flg = 0; if (i1h.flags & IT_ENV_ON) { xxi->aei.flg |= XMP_ENVELOPE_ON; } if (i1h.flags & IT_ENV_LOOP) { xxi->aei.flg |= XMP_ENVELOPE_LOOP; } if (i1h.flags & IT_ENV_SLOOP) { xxi->aei.flg |= XMP_ENVELOPE_SUS | XMP_ENVELOPE_SLOOP; } if (i1h.flags & IT_ENV_CARRY) { xxi->aei.flg |= XMP_ENVELOPE_SUS | XMP_ENVELOPE_CARRY; } xxi->aei.lps = i1h.vls; xxi->aei.lpe = i1h.vle; xxi->aei.sus = i1h.sls; xxi->aei.sue = i1h.sle; for (k = 0; k < 25 && i1h.enode[k * 2] != 0xff; k++) ; /* Sanity check */ if (k >= 25 || i1h.enode[k * 2] != 0xff) { return -1; } for (xxi->aei.npt = k; k--;) { xxi->aei.data[k * 2] = i1h.enode[k * 2]; xxi->aei.data[k * 2 + 1] = i1h.enode[k * 2 + 1]; } /* See how many different instruments we have */ for (j = 0; j < 120; j++) inst_map[j] = -1; for (k = j = 0; j < XMP_MAX_KEYS; j++) { c = j < 120 ? i1h.keys[j * 2 + 1] - 1 : -1; if (c < 0 || c >= 120) { xxi->map[j].ins = 0; xxi->map[j].xpo = 0; continue; } if (inst_map[c] == -1) { inst_map[c] = k; inst_rmap[k] = c; k++; } xxi->map[j].ins = inst_map[c]; xxi->map[j].xpo = i1h.keys[j * 2] - j; } xxi->nsm = k; xxi->vol = 0x40; if (k) { xxi->sub = calloc(sizeof(struct xmp_subinstrument), k); if (xxi->sub == NULL) { return -1; } for (j = 0; j < k; j++) { struct xmp_subinstrument *sub = &xxi->sub[j]; sub->sid = inst_rmap[j]; sub->nna = i1h.nna; sub->dct = i1h.dnc ? XMP_INST_DCT_NOTE : XMP_INST_DCT_OFF; sub->dca = XMP_INST_DCA_CUT; sub->pan = -1; } } D_(D_INFO "[ ] %-26.26s %d %-4.4s %4d %2d %c%c%c %3d", /*i,*/ i1h.name, i1h.nna, i1h.dnc ? "on" : "off", i1h.fadeout, xxi->aei.npt, xxi->aei.flg & XMP_ENVELOPE_ON ? 'V' : '-', xxi->aei.flg & XMP_ENVELOPE_LOOP ? 'L' : '-', xxi->aei.flg & XMP_ENVELOPE_SUS ? 'S' : '-', xxi->nsm); return 0; } static int load_new_it_instrument(struct xmp_instrument *xxi, HIO_HANDLE *f) { int inst_map[120], inst_rmap[XMP_MAX_KEYS]; struct it_instrument2_header i2h; struct it_envelope env; int dca2nna[] = { 0, 2, 3 }; int c, k, j; i2h.magic = hio_read32b(f); if (i2h.magic != MAGIC_IMPI) { D_(D_CRIT "bad instrument magic"); return -1; } hio_read(&i2h.dosname, 12, 1, f); i2h.zero = hio_read8(f); i2h.nna = hio_read8(f); i2h.dct = hio_read8(f); i2h.dca = hio_read8(f); /* Sanity check */ if (i2h.dca > 3) { /* Northern Sky has an instrument with DCA 3 */ D_(D_WARN "bad instrument dca: %d", i2h.dca); i2h.dca = 0; } i2h.fadeout = hio_read16l(f); i2h.pps = hio_read8(f); i2h.ppc = hio_read8(f); i2h.gbv = hio_read8(f); i2h.dfp = hio_read8(f); i2h.rv = hio_read8(f); i2h.rp = hio_read8(f); i2h.trkvers = hio_read16l(f); i2h.nos = hio_read8(f); i2h.rsvd1 = hio_read8(f); if (hio_error(f)) { D_(D_CRIT "read error"); return -1; } if (hio_read(&i2h.name, 1, 26, f) != 26) { D_(D_CRIT "name read error"); return -1; } fix_name(i2h.name, 26); i2h.ifc = hio_read8(f); i2h.ifr = hio_read8(f); i2h.mch = hio_read8(f); i2h.mpr = hio_read8(f); i2h.mbnk = hio_read16l(f); if (hio_read(&i2h.keys, 1, 240, f) != 240) { D_(D_CRIT "key map read error"); return -1; } libxmp_copy_adjust(xxi->name, i2h.name, 25); xxi->rls = i2h.fadeout << 6; /* Envelopes */ read_envelope(&xxi->aei, &env, f); read_envelope(&xxi->pei, &env, f); read_envelope(&xxi->fei, &env, f); if (xxi->pei.flg & XMP_ENVELOPE_ON) { for (j = 0; j < xxi->pei.npt; j++) xxi->pei.data[j * 2 + 1] += 32; } if (xxi->aei.flg & XMP_ENVELOPE_ON && xxi->aei.npt == 0) xxi->aei.npt = 1; if (xxi->pei.flg & XMP_ENVELOPE_ON && xxi->pei.npt == 0) xxi->pei.npt = 1; if (xxi->fei.flg & XMP_ENVELOPE_ON && xxi->fei.npt == 0) xxi->fei.npt = 1; if (env.flg & IT_ENV_FILTER) { xxi->fei.flg |= XMP_ENVELOPE_FLT; for (j = 0; j < env.num; j++) { xxi->fei.data[j * 2 + 1] += 32; xxi->fei.data[j * 2 + 1] *= 4; } } else { /* Pitch envelope is *50 to get fine interpolation */ for (j = 0; j < env.num; j++) xxi->fei.data[j * 2 + 1] *= 50; } /* See how many different instruments we have */ for (j = 0; j < 120; j++) inst_map[j] = -1; for (k = j = 0; j < 120; j++) { c = i2h.keys[j * 2 + 1] - 1; if (c < 0 || c >= 120) { xxi->map[j].ins = 0xff; /* No sample */ xxi->map[j].xpo = 0; continue; } if (inst_map[c] == -1) { inst_map[c] = k; inst_rmap[k] = c; k++; } xxi->map[j].ins = inst_map[c]; xxi->map[j].xpo = i2h.keys[j * 2] - j; } xxi->nsm = k; xxi->vol = i2h.gbv >> 1; if (k) { xxi->sub = calloc(sizeof(struct xmp_subinstrument), k); if (xxi->sub == NULL) return -1; for (j = 0; j < k; j++) { struct xmp_subinstrument *sub = &xxi->sub[j]; sub->sid = inst_rmap[j]; sub->nna = i2h.nna; sub->dct = i2h.dct; sub->dca = dca2nna[i2h.dca]; sub->pan = i2h.dfp & 0x80 ? -1 : i2h.dfp * 4; sub->ifc = i2h.ifc; sub->ifr = i2h.ifr; sub->rvv = ((int)i2h.rp << 8) | i2h.rv; } } D_(D_INFO "[ ] %-26.26s %d %d %d %4d %4d %2x " "%02x %c%c%c %3d %02x %02x", /*i,*/ i2h.name, i2h.nna, i2h.dct, i2h.dca, i2h.fadeout, i2h.gbv, i2h.dfp & 0x80 ? 0x80 : i2h.dfp * 4, i2h.rv, xxi->aei.flg & XMP_ENVELOPE_ON ? 'V' : '-', xxi->pei.flg & XMP_ENVELOPE_ON ? 'P' : '-', env.flg & 0x01 ? env.flg & 0x80 ? 'F' : 'P' : '-', xxi->nsm, i2h.ifc, i2h.ifr); return 0; } static int load_it_sample(struct module_data *m, int i, int start, int sample_mode, HIO_HANDLE *f) { struct it_sample_header ish; struct xmp_module *mod = &m->mod; struct xmp_sample *xxs, *xsmp; int j, k; if (sample_mode) { mod->xxi[i].sub = calloc(sizeof(struct xmp_subinstrument), 1); if (mod->xxi[i].sub == NULL) { return -1; } } ish.magic = hio_read32b(f); if (ish.magic != MAGIC_IMPS) { return -1; } xxs = &mod->xxs[i]; xsmp = &m->xsmp[i]; hio_read(&ish.dosname, 12, 1, f); ish.zero = hio_read8(f); ish.gvl = hio_read8(f); ish.flags = hio_read8(f); ish.vol = hio_read8(f); if (hio_error(f)) { return -1; } if (hio_read(&ish.name, 1, 26, f) != 26) { return -1; } fix_name(ish.name, 26); ish.convert = hio_read8(f); ish.dfp = hio_read8(f); ish.length = hio_read32l(f); ish.loopbeg = hio_read32l(f); ish.loopend = hio_read32l(f); ish.c5spd = hio_read32l(f); ish.sloopbeg = hio_read32l(f); ish.sloopend = hio_read32l(f); ish.sample_ptr = hio_read32l(f); ish.vis = hio_read8(f); ish.vid = hio_read8(f); ish.vir = hio_read8(f); ish.vit = hio_read8(f); /* Changed to continue to allow use-brdg.it and use-funk.it to * load correctly (both IT 2.04) */ if (ish.magic != MAGIC_IMPS) return 0; if (ish.flags & IT_SMP_16BIT) { xxs->flg = XMP_SAMPLE_16BIT; } xxs->len = ish.length; /* Sanity check */ if (xxs->len > MAX_SAMPLE_SIZE) { return -1; } xxs->lps = ish.loopbeg; xxs->lpe = ish.loopend; xxs->flg |= ish.flags & IT_SMP_LOOP ? XMP_SAMPLE_LOOP : 0; xxs->flg |= ish.flags & IT_SMP_BLOOP ? XMP_SAMPLE_LOOP_BIDIR : 0; xxs->flg |= ish.flags & IT_SMP_SLOOP ? XMP_SAMPLE_SLOOP : 0; xxs->flg |= ish.flags & IT_SMP_BSLOOP ? XMP_SAMPLE_SLOOP_BIDIR : 0; if (ish.flags & IT_SMP_SLOOP) { memcpy(xsmp, xxs, sizeof (struct xmp_sample)); xsmp->lps = ish.sloopbeg; xsmp->lpe = ish.sloopend; xsmp->flg |= XMP_SAMPLE_LOOP; xsmp->flg &= ~XMP_SAMPLE_LOOP_BIDIR; if (ish.flags & IT_SMP_BSLOOP) { xsmp->flg |= XMP_SAMPLE_LOOP_BIDIR; } } if (sample_mode) { /* Create an instrument for each sample */ mod->xxi[i].sub[0].vol = ish.vol; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].nsm = !!(xxs->len); libxmp_instrument_name(mod, i, ish.name, 25); } else { libxmp_copy_adjust(xxs->name, ish.name, 25); } D_(D_INFO "\n[%2X] %-26.26s %05x%c%05x %05x %05x %05x " "%02x%02x %02x%02x %5d ", i, sample_mode ? xxs->name : mod->xxi[i].name, xxs->len, ish.flags & IT_SMP_16BIT ? '+' : ' ', MIN(xxs->lps, 0xfffff), MIN(xxs->lpe, 0xfffff), MIN(ish.sloopbeg, 0xfffff), MIN(ish.sloopend, 0xfffff), ish.flags, ish.convert, ish.vol, ish.gvl, ish.c5spd); /* Convert C5SPD to relnote/finetune * * In IT we can have a sample associated with two or more * instruments, but c5spd is a sample attribute -- so we must * scan all xmp instruments to set the correct transposition */ for (j = 0; j < mod->ins; j++) { for (k = 0; k < mod->xxi[j].nsm; k++) { struct xmp_subinstrument *sub = &mod->xxi[j].sub[k]; if (sub->sid == i) { sub->vol = ish.vol; sub->gvl = ish.gvl; sub->vra = ish.vis; /* sample to sub-instrument vibrato */ sub->vde = ish.vid >> 1; sub->vwf = ish.vit; sub->vsw = (0xff - ish.vir) >> 1; libxmp_c2spd_to_note(ish.c5spd, &mod->xxi[j].sub[k].xpo, &mod->xxi[j].sub[k].fin); /* Set sample pan (overrides subinstrument) */ if (ish.dfp & 0x80) { sub->pan = (ish.dfp & 0x7f) * 4; } else if (sample_mode) { sub->pan = -1; } } } } if (ish.flags & IT_SMP_SAMPLE && xxs->len > 1) { int cvt = 0; if (0 != hio_seek(f, start + ish.sample_ptr, SEEK_SET)) return -1; if (xxs->lpe > xxs->len || xxs->lps >= xxs->lpe) xxs->flg &= ~XMP_SAMPLE_LOOP; if (~ish.convert & IT_CVT_SIGNED) cvt |= SAMPLE_FLAG_UNS; /* compressed samples */ if (ish.flags & IT_SMP_COMP) { uint8 *buf; int ret; buf = calloc(1, xxs->len * 2); if (buf == NULL) return -1; if (ish.flags & IT_SMP_16BIT) { itsex_decompress16(f, buf, xxs->len, ish.convert & IT_CVT_DIFF); #ifdef WORDS_BIGENDIAN /* decompression generates native-endian * samples, but we want little-endian */ cvt |= SAMPLE_FLAG_BIGEND; #endif } else { itsex_decompress8(f, buf, xxs->len, ish.convert & IT_CVT_DIFF); } if (ish.flags & IT_SMP_SLOOP) { long pos = hio_tell(f); if (pos < 0) { free(buf); return -1; } ret = libxmp_load_sample(m, NULL, SAMPLE_FLAG_NOLOAD | cvt, &m->xsmp[i], buf); if (ret < 0) { free(buf); return -1; } hio_seek(f, pos, SEEK_SET); } ret = libxmp_load_sample(m, NULL, SAMPLE_FLAG_NOLOAD | cvt, &mod->xxs[i], buf); if (ret < 0) { free(buf); return -1; } free(buf); } else { if (ish.flags & IT_SMP_SLOOP) { long pos = hio_tell(f); if (pos < 0) { return -1; } if (libxmp_load_sample(m, f, cvt, &m->xsmp[i], NULL) < 0) return -1; hio_seek(f, pos, SEEK_SET); } if (libxmp_load_sample(m, f, cvt, &mod->xxs[i], NULL) < 0) return -1; } } return 0; } static int load_it_pattern(struct module_data *m, int i, int new_fx, HIO_HANDLE *f) { struct xmp_module *mod = &m->mod; struct xmp_event *event, dummy, lastevent[L_CHANNELS]; uint8 mask[L_CHANNELS]; uint8 last_fxp[64]; int r, c, pat_len; uint8 b; r = 0; memset(last_fxp, 0, 64); memset(lastevent, 0, L_CHANNELS * sizeof(struct xmp_event)); memset(&dummy, 0, sizeof(struct xmp_event)); pat_len = hio_read16l(f) /* - 4 */ ; mod->xxp[i]->rows = hio_read16l(f); if (libxmp_alloc_tracks_in_pattern(mod, i) < 0) return -1; memset(mask, 0, L_CHANNELS); hio_read16l(f); hio_read16l(f); while (--pat_len >= 0) { b = hio_read8(f); if (!b) { r++; continue; } c = (b - 1) & 63; if (b & 0x80) { mask[c] = hio_read8(f); pat_len--; } /* * WARNING: we IGNORE events in disabled channels. Disabled * channels should be muted only, but we don't know the * real number of channels before loading the patterns and * we don't want to set it to 64 channels. */ if (c >= mod->chn || r >= mod->xxp[i]->rows) { event = &dummy; } else { event = &EVENT(i, c, r); } if (mask[c] & 0x01) { b = hio_read8(f); /* From ittech.txt: * Note ranges from 0->119 (C-0 -> B-9) * 255 = note off, 254 = notecut * Others = note fade (already programmed into IT's player * but not available in the editor) */ switch (b) { case 0xff: /* key off */ b = XMP_KEY_OFF; break; case 0xfe: /* cut */ b = XMP_KEY_CUT; break; default: if (b > 119) { /* fade */ b = XMP_KEY_FADE; } else { b++; /* note */ } } lastevent[c].note = event->note = b; pat_len--; } if (mask[c] & 0x02) { b = hio_read8(f); lastevent[c].ins = event->ins = b; pat_len--; } if (mask[c] & 0x04) { b = hio_read8(f); lastevent[c].vol = event->vol = b; xlat_volfx(event); pat_len--; } if (mask[c] & 0x08) { b = hio_read8(f); if (b > 26) { return -1; } event->fxt = b; event->fxp = hio_read8(f); xlat_fx(c, event, last_fxp, new_fx); lastevent[c].fxt = event->fxt; lastevent[c].fxp = event->fxp; pat_len -= 2; } if (mask[c] & 0x10) { event->note = lastevent[c].note; } if (mask[c] & 0x20) { event->ins = lastevent[c].ins; } if (mask[c] & 0x40) { event->vol = lastevent[c].vol; xlat_volfx(event); } if (mask[c] & 0x80) { event->fxt = lastevent[c].fxt; event->fxp = lastevent[c].fxp; } } return 0; } static int it_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int c, i, j; struct it_file_header ifh; int max_ch; uint32 *pp_ins; /* Pointers to instruments */ uint32 *pp_smp; /* Pointers to samples */ uint32 *pp_pat; /* Pointers to patterns */ int new_fx, sample_mode; LOAD_INIT(); /* Load and convert header */ ifh.magic = hio_read32b(f); if (ifh.magic != MAGIC_IMPM) { return -1; } hio_read(&ifh.name, 26, 1, f); ifh.hilite_min = hio_read8(f); ifh.hilite_maj = hio_read8(f); ifh.ordnum = hio_read16l(f); ifh.insnum = hio_read16l(f); ifh.smpnum = hio_read16l(f); ifh.patnum = hio_read16l(f); ifh.cwt = hio_read16l(f); ifh.cmwt = hio_read16l(f); ifh.flags = hio_read16l(f); ifh.special = hio_read16l(f); ifh.gv = hio_read8(f); ifh.mv = hio_read8(f); ifh.is = hio_read8(f); ifh.it = hio_read8(f); ifh.sep = hio_read8(f); ifh.pwd = hio_read8(f); /* Sanity check */ if (ifh.gv > 0x80 || ifh.mv > 0x80) { goto err; } ifh.msglen = hio_read16l(f); ifh.msgofs = hio_read32l(f); ifh.rsvd = hio_read32l(f); hio_read(&ifh.chpan, 64, 1, f); hio_read(&ifh.chvol, 64, 1, f); strncpy(mod->name, (char *)ifh.name, XMP_NAME_SIZE); mod->len = ifh.ordnum; mod->ins = ifh.insnum; mod->smp = ifh.smpnum; mod->pat = ifh.patnum; /* Sanity check */ if (mod->ins > 255 || mod->smp > 255 || mod->pat > 255) { goto err; } if (mod->ins) { pp_ins = calloc(4, mod->ins); if (pp_ins == NULL) goto err; } else { pp_ins = NULL; } pp_smp = calloc(4, mod->smp); if (pp_smp == NULL) goto err2; pp_pat = calloc(4, mod->pat); if (pp_pat == NULL) goto err3; mod->spd = ifh.is; mod->bpm = ifh.it; sample_mode = ~ifh.flags & IT_USE_INST; if (ifh.flags & IT_LINEAR_FREQ) { m->period_type = PERIOD_LINEAR; } if (!sample_mode && ifh.cmwt >= 0x200) { m->quirk |= QUIRK_INSVOL; } for (i = 0; i < 64; i++) { struct xmp_channel *xxc = &mod->xxc[i]; if (ifh.chpan[i] == 100) { /* Surround -> center */ xxc->flg |= XMP_CHANNEL_SURROUND; } if (ifh.chpan[i] & 0x80) { /* Channel mute */ ifh.chvol[i] = 0; xxc->flg |= XMP_CHANNEL_MUTE; } if (ifh.flags & IT_STEREO) { xxc->pan = (int)ifh.chpan[i] * 0x80 >> 5; if (xxc->pan > 0xff) xxc->pan = 0xff; } else { xxc->pan = 0x80; } xxc->vol = ifh.chvol[i]; } if (mod->len <= XMP_MAX_MOD_LENGTH) { hio_read(mod->xxo, 1, mod->len, f); } else { hio_read(mod->xxo, 1, XMP_MAX_MOD_LENGTH, f); hio_seek(f, mod->len - XMP_MAX_MOD_LENGTH, SEEK_CUR); mod->len = XMP_MAX_MOD_LENGTH; } new_fx = ifh.flags & IT_OLD_FX ? 0 : 1; for (i = 0; i < mod->ins; i++) pp_ins[i] = hio_read32l(f); for (i = 0; i < mod->smp; i++) pp_smp[i] = hio_read32l(f); for (i = 0; i < mod->pat; i++) pp_pat[i] = hio_read32l(f); m->c4rate = C4_NTSC_RATE; identify_tracker(m, &ifh); MODULE_INFO(); D_(D_INFO "Instrument/FX mode: %s/%s", sample_mode ? "sample" : ifh.cmwt >= 0x200 ? "new" : "old", ifh.flags & IT_OLD_FX ? "old" : "IT"); if (sample_mode) mod->ins = mod->smp; if (libxmp_init_instrument(m) < 0) goto err4; /* Alloc extra samples for sustain loop */ if (mod->smp > 0) { m->xsmp = calloc(sizeof (struct xmp_sample), mod->smp); if (m->xsmp == NULL) { goto err4; } } D_(D_INFO "Instruments: %d", mod->ins); for (i = 0; i < mod->ins; i++) { /* * IT files can have three different instrument types: 'New' * instruments, 'old' instruments or just samples. We need a * different loader for each of them. */ struct xmp_instrument *xxi = &mod->xxi[i]; if (!sample_mode && ifh.cmwt >= 0x200) { /* New instrument format */ if (hio_seek(f, start + pp_ins[i], SEEK_SET) < 0) { goto err4; } if (load_new_it_instrument(xxi, f) < 0) { goto err4; } } else if (!sample_mode) { /* Old instrument format */ if (hio_seek(f, start + pp_ins[i], SEEK_SET) < 0) { goto err4; } if (load_old_it_instrument(xxi, f) < 0) { goto err4; } } } D_(D_INFO "Stored Samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (hio_seek(f, start + pp_smp[i], SEEK_SET) < 0) { goto err4; } if (load_it_sample(m, i, start, sample_mode, f) < 0) { goto err4; } } D_(D_INFO "Stored Patterns: %d", mod->pat); /* Effects in muted channels are processed, so scan patterns first to * see the real number of channels */ max_ch = 0; for (i = 0; i < mod->pat; i++) { uint8 mask[L_CHANNELS]; int pat_len; /* If the offset to a pattern is 0, the pattern is empty */ if (pp_pat[i] == 0) continue; hio_seek(f, start + pp_pat[i], SEEK_SET); pat_len = hio_read16l(f) /* - 4 */ ; hio_read16l(f); memset(mask, 0, L_CHANNELS); hio_read16l(f); hio_read16l(f); while (--pat_len >= 0) { int b = hio_read8(f); if (b == 0) continue; c = (b - 1) & 63; if (c > max_ch) max_ch = c; if (b & 0x80) { mask[c] = hio_read8(f); pat_len--; } if (mask[c] & 0x01) { hio_read8(f); pat_len--; } if (mask[c] & 0x02) { hio_read8(f); pat_len--; } if (mask[c] & 0x04) { hio_read8(f); pat_len--; } if (mask[c] & 0x08) { hio_read8(f); hio_read8(f); pat_len -= 2; } } } /* Set the number of channels actually used */ mod->chn = max_ch + 1; mod->trk = mod->pat * mod->chn; if (libxmp_init_pattern(mod) < 0) goto err4; /* Read patterns */ for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern(mod, i) < 0) goto err4; /* If the offset to a pattern is 0, the pattern is empty */ if (pp_pat[i] == 0) { mod->xxp[i]->rows = 64; for (j = 0; j < mod->chn; j++) { int tnum = i * mod->chn + j; if (libxmp_alloc_track(mod, tnum, 64) < 0) goto err4; mod->xxp[i]->index[j] = tnum; } continue; } if (hio_seek(f, start + pp_pat[i], SEEK_SET) < 0) { goto err4; } if (load_it_pattern(m, i, new_fx, f) < 0) { goto err4; } } free(pp_pat); free(pp_smp); free(pp_ins); /* Song message */ if (ifh.special & IT_HAS_MSG) { if ((m->comment = malloc(ifh.msglen + 1)) != NULL) { hio_seek(f, start + ifh.msgofs, SEEK_SET); D_(D_INFO "Message length : %d", ifh.msglen); for (j = 0; j < ifh.msglen; j++) { int b = hio_read8(f); if (b == '\r') { b = '\n'; } else if ((b < 32 || b > 127) && b != '\n' && b != '\t') { b = '.'; } m->comment[j] = b; } m->comment[j] = 0; } } /* Format quirks */ m->quirk |= QUIRKS_IT | QUIRK_ARPMEM; if (ifh.flags & IT_LINK_GXX) { m->quirk |= QUIRK_PRENV; } else { m->quirk |= QUIRK_UNISLD; } if (new_fx) { m->quirk |= QUIRK_VIBHALF | QUIRK_VIBINV; } else { m->quirk &= ~QUIRK_VIBALL; m->quirk |= QUIRK_ITOLDFX; } if (sample_mode) { m->quirk &= ~(QUIRK_VIRTUAL | QUIRK_RSTCHN); } m->gvolbase = 0x80; m->gvol = ifh.gv; m->read_event_type = READ_EVENT_IT; return 0; err4: free(pp_pat); err3: free(pp_smp); err2: free(pp_ins); err: return -1; } #endif /* LIBXMP_CORE_DISABLE_IT */ libxmp-4.4.1/src/loaders/imf_load.c0000664000175000017500000003107212775035311017004 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Loader for Imago Orpheus modules based on the format description * written by Lutz Roeder. */ #include "loader.h" #include "period.h" #define IMF_EOR 0x00 #define IMF_CH_MASK 0x1f #define IMF_NI_FOLLOW 0x20 #define IMF_FX_FOLLOWS 0x80 #define IMF_F2_FOLLOWS 0x40 struct imf_channel { char name[12]; /* Channelname (ASCIIZ-String, max 11 chars) */ uint8 status; /* Channel status */ uint8 pan; /* Pan positions */ uint8 chorus; /* Default chorus */ uint8 reverb; /* Default reverb */ }; struct imf_header { char name[32]; /* Songname (ASCIIZ-String, max. 31 chars) */ uint16 len; /* Number of orders saved */ uint16 pat; /* Number of patterns saved */ uint16 ins; /* Number of instruments saved */ uint16 flg; /* Module flags */ uint8 unused1[8]; uint8 tpo; /* Default tempo (1..255) */ uint8 bpm; /* Default beats per minute (BPM) (32..255) */ uint8 vol; /* Default mastervolume (0..64) */ uint8 amp; /* Amplification factor (4..127) */ uint8 unused2[8]; uint32 magic; /* 'IM10' */ struct imf_channel chn[32]; /* Channel settings */ uint8 pos[256]; /* Order list */ }; struct imf_env { uint8 npt; /* Number of envelope points */ uint8 sus; /* Envelope sustain point */ uint8 lps; /* Envelope loop start point */ uint8 lpe; /* Envelope loop end point */ uint8 flg; /* Envelope flags */ uint8 unused[3]; }; struct imf_instrument { char name[32]; /* Inst. name (ASCIIZ-String, max. 31 chars) */ uint8 map[120]; /* Multisample settings */ uint8 unused[8]; uint16 vol_env[32]; /* Volume envelope settings */ uint16 pan_env[32]; /* Pan envelope settings */ uint16 pitch_env[32]; /* Pitch envelope settings */ struct imf_env env[3]; uint16 fadeout; /* Fadeout rate (0...0FFFH) */ uint16 nsm; /* Number of samples in instrument */ uint32 magic; /* 'II10' */ }; struct imf_sample { char name[13]; /* Sample filename (12345678.ABC) */ uint8 unused1[3]; uint32 len; /* Length */ uint32 lps; /* Loop start */ uint32 lpe; /* Loop end */ uint32 rate; /* Samplerate */ uint8 vol; /* Default volume (0..64) */ uint8 pan; /* Default pan (00h = Left / 80h = Middle) */ uint8 unused2[14]; uint8 flg; /* Sample flags */ uint8 unused3[5]; uint16 ems; /* Reserved for internal usage */ uint32 dram; /* Reserved for internal usage */ uint32 magic; /* 'IS10' */ }; #define MAGIC_IM10 MAGIC4('I','M','1','0') #define MAGIC_II10 MAGIC4('I','I','1','0') static int imf_test (HIO_HANDLE *, char *, const int); static int imf_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_imf = { "Imago Orpheus v1.0", imf_test, imf_load }; static int imf_test(HIO_HANDLE *f, char *t, const int start) { hio_seek(f, start + 60, SEEK_SET); if (hio_read32b(f) != MAGIC_IM10) return -1; hio_seek(f, start, SEEK_SET); libxmp_read_title(f, t, 32); return 0; } #define NONE 0xff #define FX_IMF_FPORTA_UP 0xfe #define FX_IMF_FPORTA_DN 0xfd /* Effect conversion table */ static const uint8 fx[] = { NONE, FX_S3M_SPEED, FX_S3M_BPM, FX_TONEPORTA, FX_TONE_VSLIDE, FX_VIBRATO, FX_VIBRA_VSLIDE, FX_FINE_VIBRATO, FX_TREMOLO, FX_S3M_ARPEGGIO, FX_SETPAN, FX_PANSLIDE, FX_VOLSET, FX_VOLSLIDE, FX_F_VSLIDE, FX_FINETUNE, FX_NSLIDE_UP, FX_NSLIDE_DN, FX_PORTA_UP, FX_PORTA_DN, FX_IMF_FPORTA_UP, FX_IMF_FPORTA_DN, FX_FLT_CUTOFF, FX_FLT_RESN, FX_OFFSET, NONE /* fine offset */, FX_KEYOFF, FX_MULTI_RETRIG, FX_TREMOR, FX_JUMP, FX_BREAK, FX_GLOBALVOL, FX_GVOL_SLIDE, FX_EXTENDED, FX_CHORUS, FX_REVERB }; /* Effect translation */ static void xlat_fx (int c, uint8 *fxt, uint8 *fxp) { uint8 h = MSN (*fxp), l = LSN (*fxp); switch (*fxt = fx[*fxt]) { case FX_IMF_FPORTA_UP: *fxt = FX_PORTA_UP; if (*fxp < 0x30) *fxp = LSN (*fxp >> 2) | 0xe0; else *fxp = LSN (*fxp >> 4) | 0xf0; break; case FX_IMF_FPORTA_DN: *fxt = FX_PORTA_DN; if (*fxp < 0x30) *fxp = LSN (*fxp >> 2) | 0xe0; else *fxp = LSN (*fxp >> 4) | 0xf0; break; case FX_EXTENDED: /* Extended effects */ switch (h) { case 0x1: /* Set filter */ case 0x2: /* Undefined */ case 0x4: /* Undefined */ case 0x6: /* Undefined */ case 0x7: /* Undefined */ case 0x9: /* Undefined */ case 0xe: /* Ignore envelope */ case 0xf: /* Invert loop */ *fxp = *fxt = 0; break; case 0x3: /* Glissando */ *fxp = l | (EX_GLISS << 4); break; case 0x5: /* Vibrato waveform */ *fxp = l | (EX_VIBRATO_WF << 4); break; case 0x8: /* Tremolo waveform */ *fxp = l | (EX_TREMOLO_WF << 4); break; case 0xa: /* Pattern loop */ *fxp = l | (EX_PATTERN_LOOP << 4); break; case 0xb: /* Pattern delay */ *fxp = l | (EX_PATT_DELAY << 4); break; case 0xc: if (l == 0) *fxt = *fxp = 0; } break; case NONE: /* No effect */ *fxt = *fxp = 0; break; } } static int imf_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int c, r, i, j; struct xmp_event *event = 0, dummy; struct imf_header ih; struct imf_instrument ii; struct imf_sample is; int pat_len, smp_num; uint8 n, b; LOAD_INIT(); /* Load and convert header */ hio_read(&ih.name, 32, 1, f); ih.len = hio_read16l(f); ih.pat = hio_read16l(f); ih.ins = hio_read16l(f); ih.flg = hio_read16l(f); hio_read(&ih.unused1, 8, 1, f); ih.tpo = hio_read8(f); ih.bpm = hio_read8(f); ih.vol = hio_read8(f); ih.amp = hio_read8(f); hio_read(&ih.unused2, 8, 1, f); ih.magic = hio_read32b(f); /* Sanity check */ if (ih.len > 256 || ih.pat > 256 || ih.ins > 255) { return -1; } for (i = 0; i < 32; i++) { hio_read(&ih.chn[i].name, 12, 1, f); ih.chn[i].status = hio_read8(f); ih.chn[i].pan = hio_read8(f); ih.chn[i].chorus = hio_read8(f); ih.chn[i].reverb = hio_read8(f); } hio_read(&ih.pos, 256, 1, f); if (ih.magic != MAGIC_IM10) { return -1; } libxmp_copy_adjust(mod->name, (uint8 *)ih.name, 32); mod->len = ih.len; mod->ins = ih.ins; mod->smp = 1024; mod->pat = ih.pat; if (ih.flg & 0x01) m->period_type = PERIOD_LINEAR; mod->spd = ih.tpo; mod->bpm = ih.bpm; libxmp_set_type(m, "Imago Orpheus 1.0 IMF"); MODULE_INFO(); mod->chn = 0; for (i = 0; i < 32; i++) { if (ih.chn[i].status == 0x00) continue; mod->chn = i + 1; mod->xxc[i].pan = ih.chn[i].pan; #if 0 /* FIXME */ mod->xxc[i].cho = ih.chn[i].chorus; mod->xxc[i].rvb = ih.chn[i].reverb; mod->xxc[i].flg |= XMP_CHANNEL_FX; #endif } mod->trk = mod->pat * mod->chn; memcpy(mod->xxo, ih.pos, mod->len); for (i = 0; i < mod->len; i++) { if (mod->xxo[i] == 0xff) mod->xxo[i]--; } m->c4rate = C4_NTSC_RATE; if (libxmp_init_pattern(mod) < 0) return -1; /* Read patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { int rows; pat_len = hio_read16l(f) - 4; rows = hio_read16l(f); /* Sanity check */ if (rows > 256) { return -1; } if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; r = 0; while (--pat_len >= 0) { b = hio_read8(f); if (b == IMF_EOR) { r++; continue; } /* Sanity check */ if (r >= rows) { return -1; } c = b & IMF_CH_MASK; event = c >= mod->chn ? &dummy : &EVENT(i, c, r); if (b & IMF_NI_FOLLOW) { n = hio_read8(f); switch (n) { case 255: case 160: /* ??!? */ n = XMP_KEY_OFF; break; /* Key off */ default: n = 13 + 12 * MSN (n) + LSN (n); } event->note = n; event->ins = hio_read8(f); pat_len -= 2; } if (b & IMF_FX_FOLLOWS) { event->fxt = hio_read8(f); event->fxp = hio_read8(f); xlat_fx(c, &event->fxt, &event->fxp); pat_len -= 2; } if (b & IMF_F2_FOLLOWS) { event->f2t = hio_read8(f); event->f2p = hio_read8(f); xlat_fx(c, &event->f2t, &event->f2p); pat_len -= 2; } } } if (libxmp_init_instrument(m) < 0) return -1; /* Read and convert instruments and samples */ D_(D_INFO "Instruments: %d", mod->ins); for (smp_num = i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; hio_read(&ii.name, 32, 1, f); ii.name[31] = 0; hio_read(&ii.map, 120, 1, f); hio_read(&ii.unused, 8, 1, f); for (j = 0; j < 32; j++) ii.vol_env[j] = hio_read16l(f); for (j = 0; j < 32; j++) ii.pan_env[j] = hio_read16l(f); for (j = 0; j < 32; j++) ii.pitch_env[j] = hio_read16l(f); for (j = 0; j < 3; j++) { ii.env[j].npt = hio_read8(f); ii.env[j].sus = hio_read8(f); ii.env[j].lps = hio_read8(f); ii.env[j].lpe = hio_read8(f); ii.env[j].flg = hio_read8(f); hio_read(&ii.env[j].unused, 3, 1, f); } ii.fadeout = hio_read16l(f); ii.nsm = hio_read16l(f); ii.magic = hio_read32b(f); /* Sanity check */ if (ii.nsm > 255) return -1; if (ii.magic != MAGIC_II10) return -2; xxi->nsm = ii.nsm; if (xxi->nsm > 0) { if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) return -1; } strncpy((char *)xxi->name, ii.name, 24); for (j = 0; j < 108; j++) { xxi->map[j + 12].ins = ii.map[j]; } D_(D_INFO "[%2X] %-31.31s %2d %4x %c", i, ii.name, ii.nsm, ii.fadeout, ii.env[0].flg & 0x01 ? 'V' : '-'); xxi->aei.npt = ii.env[0].npt; xxi->aei.sus = ii.env[0].sus; xxi->aei.lps = ii.env[0].lps; xxi->aei.lpe = ii.env[0].lpe; xxi->aei.flg = ii.env[0].flg & 0x01 ? XMP_ENVELOPE_ON : 0; xxi->aei.flg |= ii.env[0].flg & 0x02 ? XMP_ENVELOPE_SUS : 0; xxi->aei.flg |= ii.env[0].flg & 0x04 ? XMP_ENVELOPE_LOOP : 0; /* Sanity check */ if (xxi->aei.npt >= 16) { return -1; } for (j = 0; j < xxi->aei.npt; j++) { xxi->aei.data[j * 2] = ii.vol_env[j * 2]; xxi->aei.data[j * 2 + 1] = ii.vol_env[j * 2 + 1]; } for (j = 0; j < ii.nsm; j++, smp_num++) { struct xmp_subinstrument *sub = &xxi->sub[j]; struct xmp_sample *xxs = &mod->xxs[smp_num]; int sid; hio_read(&is.name, 13, 1, f); hio_read(&is.unused1, 3, 1, f); is.len = hio_read32l(f); is.lps = hio_read32l(f); is.lpe = hio_read32l(f); is.rate = hio_read32l(f); is.vol = hio_read8(f); is.pan = hio_read8(f); hio_read(&is.unused2, 14, 1, f); is.flg = hio_read8(f); hio_read(&is.unused3, 5, 1, f); is.ems = hio_read16l(f); is.dram = hio_read32l(f); is.magic = hio_read32b(f); /* Sanity check */ if (is.len > 0x100000 || is.lps > 0x100000 || is.lpe > 0x100000) return -1; sub->sid = smp_num; sub->vol = is.vol; sub->pan = is.pan; xxs->len = is.len; xxs->lps = is.lps; xxs->lpe = is.lpe; xxs->flg = is.flg & 1 ? XMP_SAMPLE_LOOP : 0; if (is.flg & 4) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } D_(D_INFO " %02x: %05x %05x %05x %5d", j, is.len, is.lps, is.lpe, is.rate); libxmp_c2spd_to_note(is.rate, &sub->xpo, &sub->fin); if (xxs->len <= 0) continue; sid = sub->sid; if (libxmp_load_sample(m, f, 0, &mod->xxs[sid], NULL) < 0) return -1; } } mod->smp = smp_num; mod->xxs = realloc(mod->xxs, sizeof (struct xmp_sample) * mod->smp); if (mod->xxs == NULL) { return -1; } m->xtra = realloc(m->xtra, sizeof (struct extra_sample_data) * mod->smp); if (m->xtra == NULL) { return -1; } m->c4rate = C4_NTSC_RATE; m->quirk |= QUIRK_FILTER | QUIRKS_ST3 | QUIRK_ARPMEM; m->read_event_type = READ_EVENT_ST3; return 0; } libxmp-4.4.1/src/loaders/flt_load.c0000664000175000017500000003002712774567167017037 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "mod.h" #include "period.h" static int flt_test(HIO_HANDLE *, char *, const int); static int flt_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_flt = { "Startrekker", flt_test, flt_load }; static int flt_test(HIO_HANDLE * f, char *t, const int start) { char buf[4]; hio_seek(f, start + 1080, SEEK_SET); if (hio_read(buf, 1, 4, f) < 4) return -1; /* Also RASP? */ if (memcmp(buf, "FLT", 3) && memcmp(buf, "EXO", 3)) return -1; if (buf[3] != '4' && buf[3] != '8' && buf[3] != 'M') return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } /* Waveforms from the Startrekker 1.2 AM synth replayer code */ static const int8 am_waveform[3][32] = { { 0, 25, 49, 71, 90, 106, 117, 125, /* Sine */ 127, 125, 117, 106, 90, 71, 49, 25, 0, -25, -49, -71, -90, -106, -117, -125, -127, -125, -117, -106, -90, -71, -49, -25 }, { -128, -120, -112, -104, -96, -88, -80, -72, /* Ramp */ -64, -56, -48, -40, -32, -24, -16, -8, 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }, { -128, -128, -128, -128, -128, -128, -128, -128, /* Square */ -128, -128, -128, -128, -128, -128, -128, -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 } }; struct am_instrument { int16 l0; /* start amplitude */ int16 a1l; /* attack level */ int16 a1s; /* attack speed */ int16 a2l; /* secondary attack level */ int16 a2s; /* secondary attack speed */ int16 sl; /* sustain level */ int16 ds; /* decay speed */ int16 st; /* sustain time */ int16 rs; /* release speed */ int16 wf; /* waveform */ int16 p_fall; /* ? */ int16 v_amp; /* vibrato amplitude */ int16 v_spd; /* vibrato speed */ int16 fq; /* base frequency */ }; static int is_am_instrument(HIO_HANDLE *nt, int i) { char buf[2]; int16 wf; hio_seek(nt, 144 + i * 120, SEEK_SET); hio_read(buf, 1, 2, nt); if (memcmp(buf, "AM", 2)) return 0; hio_seek(nt, 24, SEEK_CUR); wf = hio_read16b(nt); if (hio_error(nt) || wf < 0 || wf > 3) return 0; return 1; } static int read_am_instrument(struct module_data *m, HIO_HANDLE *nt, int i) { struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_envelope *vol_env = &xxi->aei; struct xmp_envelope *freq_env = &xxi->fei; struct am_instrument am; char *wave; int a, b; int8 am_noise[1024]; hio_seek(nt, 144 + i * 120 + 2 + 4, SEEK_SET); am.l0 = hio_read16b(nt); am.a1l = hio_read16b(nt); am.a1s = hio_read16b(nt); am.a2l = hio_read16b(nt); am.a2s = hio_read16b(nt); am.sl = hio_read16b(nt); am.ds = hio_read16b(nt); am.st = hio_read16b(nt); hio_read16b(nt); am.rs = hio_read16b(nt); am.wf = hio_read16b(nt); am.p_fall = -(int16) hio_read16b(nt); am.v_amp = hio_read16b(nt); am.v_spd = hio_read16b(nt); am.fq = hio_read16b(nt); if (hio_error(nt)) { return -1; } #if 0 printf ("L0=%d A1L=%d A1S=%d A2L=%d A2S=%d SL=%d DS=%d ST=%d RS=%d WF=%d\n", am.l0, am.a1l, am.a1s, am.a2l, am.a2s, am.sl, am.ds, am.st, am.rs, am.wf); #endif if (am.wf < 3) { xxs->len = 32; xxs->lps = 0; xxs->lpe = 32; wave = (char *)&am_waveform[am.wf][0]; } else { int j; xxs->len = 1024; xxs->lps = 0; xxs->lpe = 1024; for (j = 0; j < 1024; j++) am_noise[j] = rand() % 256; wave = (char *)&am_noise[0]; } xxs->flg = XMP_SAMPLE_LOOP; xxi->sub[0].vol = 0x40; /* prelude.mod has 0 in instrument */ xxi->nsm = 1; xxi->sub[0].xpo = -12 * am.fq; xxi->sub[0].vwf = 0; xxi->sub[0].vde = am.v_amp << 2; xxi->sub[0].vra = am.v_spd; /* * AM synth envelope parameters based on the Startrekker 1.2 docs * * L0 Start amplitude for the envelope * A1L Attack level * A1S The speed that the amplitude changes to the attack level, $1 * is slow and $40 is fast. * A2L Secondary attack level, for those who likes envelopes... * A2S Secondary attack speed. * DS The speed that the amplitude decays down to the: * SL Sustain level. There is remains for the time set by the * ST Sustain time. * RS Release speed. The speed that the amplitude falls from ST to 0. */ if (am.a1s == 0) am.a1s = 1; if (am.a2s == 0) am.a2s = 1; if (am.ds == 0) am.ds = 1; if (am.rs == 0) am.rs = 1; vol_env->npt = 6; vol_env->flg = XMP_ENVELOPE_ON; vol_env->data[0] = 0; vol_env->data[1] = am.l0 / 4; /* * Startrekker increments/decrements the envelope by the stage speed * until it reaches the next stage level. * * ^ * | * 100 +.........o * | /: * A2L +.......o : x = 256 * (A2L - A1L) / (256 - A1L) * | /: : * | / : : * A1L +....o..:.: * | : : : * | :x : : * +----+--+-+-----> * | | * |256/| * A2S */ if (am.a1l > am.l0) { a = am.a1l - am.l0; b = 256 - am.l0; } else { a = am.l0 - am.a1l; b = am.l0; } if (b == 0) b = 1; vol_env->data[2] = vol_env->data[0] + (256 * a) / (am.a1s * b); vol_env->data[3] = am.a1l / 4; if (am.a2l > am.a1l) { a = am.a2l - am.a1l; b = 256 - am.a1l; } else { a = am.a1l - am.a2l; b = am.a1l; } if (b == 0) b = 1; vol_env->data[4] = vol_env->data[2] + (256 * a) / (am.a2s * b); vol_env->data[5] = am.a2l / 4; if (am.sl > am.a2l) { a = am.sl - am.a2l; b = 256 - am.a2l; } else { a = am.a2l - am.sl; b = am.a2l; } if (b == 0) b = 1; vol_env->data[6] = vol_env->data[4] + (256 * a) / (am.ds * b); vol_env->data[7] = am.sl / 4; vol_env->data[8] = vol_env->data[6] + am.st; vol_env->data[9] = am.sl / 4; vol_env->data[10] = vol_env->data[8] + (256 / am.rs); vol_env->data[11] = 0; /* * Implement P.FALL using pitch envelope */ if (am.p_fall) { freq_env->npt = 2; freq_env->flg = XMP_ENVELOPE_ON; freq_env->data[0] = 0; freq_env->data[1] = 0; freq_env->data[2] = 1024 / abs(am.p_fall); freq_env->data[3] = 10 * (am.p_fall < 0 ? -256 : 256); } if (libxmp_load_sample(m, NULL, SAMPLE_FLAG_NOLOAD, xxs, wave)) return -1; return 0; } static int flt_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; char *tracker; char filename[1024]; char buf[16]; HIO_HANDLE *nt; int am_synth; LOAD_INIT(); /* See if we have the synth parameters file */ am_synth = 0; snprintf(filename, 1024, "%s%s.NT", m->dirname, m->basename); if ((nt = hio_open(filename, "rb")) == NULL) { snprintf(filename, 1024, "%s%s.nt", m->dirname, m->basename); if ((nt = hio_open(filename, "rb")) == NULL) { snprintf(filename, 1024, "%s%s.AS", m->dirname, m->basename); if ((nt = hio_open(filename, "rb")) == NULL) { snprintf(filename, 1024, "%s%s.as", m->dirname, m->basename); nt = hio_open(filename, "rb"); } } } tracker = "Startrekker"; if (nt) { if (hio_read(buf, 1, 16, nt) != 16) { goto err; } if (memcmp(buf, "ST1.2 ModuleINFO", 16) == 0) { am_synth = 1; tracker = "Startrekker 1.2"; } else if (memcmp(buf, "ST1.3 ModuleINFO", 16) == 0) { am_synth = 1; tracker = "Startrekker 1.3"; } else if (memcmp(buf, "AudioSculpture10", 16) == 0) { am_synth = 1; tracker = "AudioSculpture 1.0"; } } hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); hio_read(&mh.magic, 4, 1, f); if (mh.magic[3] == '4') { mod->chn = 4; } else { mod->chn = 8; } mod->ins = 31; mod->smp = mod->ins; mod->len = mh.len; mod->rst = mh.restart; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->chn > 4) mod->xxo[i] >>= 1; if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; mod->trk = mod->chn * mod->pat; strncpy(mod->name, (char *)mh.name, 20); libxmp_set_type(m, "%s %4.4s", tracker, mh.magic); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) goto err; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) goto err; sub = &xxi->sub[0]; xxs->len = 2 * mh.ins[i].size; xxs->lps = 2 * mh.ins[i].loop_start; xxs->lpe = xxs->lps + 2 * mh.ins[i].loop_size; xxs->flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; sub->fin = (int8) (mh.ins[i].finetune << 4); sub->vol = mh.ins[i].volume; sub->pan = 0x80; sub->sid = i; xxi->rls = 0xfff; if (xxs->len > 0) xxi->nsm = 1; libxmp_instrument_name(mod, i, mh.ins[i].name, 22); } if (libxmp_init_pattern(mod) < 0) goto err; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); /* "The format you are looking for is FLT8, and the ONLY two * differences are: It says FLT8 instead of FLT4 or M.K., AND, the * patterns are PAIRED. I thought this was the easiest 8 track * format possible, since it can be loaded in a normal 4 channel * tracker if you should want to rip sounds or patterns. So, in a * 8 track FLT8 module, patterns 00 and 01 is "really" pattern 00. * Patterns 02 and 03 together is "really" pattern 01. Thats it. * Oh well, I didnt have the time to implement all effect commands * either, so some FLT8 modules would play back badly (I think * especially the portamento command uses a different "scale" than * the normal portamento command, that would be hard to patch). */ for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) goto err; for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, j % 4, j / 4); hio_read(mod_event, 1, 4, f); libxmp_decode_noisetracker_event(event, mod_event); } if (mod->chn > 4) { for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, (j % 4) + 4, j / 4); hio_read(mod_event, 1, 4, f); libxmp_decode_noisetracker_event(event, mod_event); /* no macros */ if (event->fxt == 0x0e) event->fxt = event->fxp = 0; } } } /* no such limit for synth instruments * mod->flg |= XXM_FLG_MODRNG; */ /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (mod->xxs[i].len == 0) { if (am_synth && is_am_instrument(nt, i)) { if (read_am_instrument(m, nt, i) < 0) { D_(D_CRIT "Missing nt file"); goto err; } } continue; } if (libxmp_load_sample(m, f, SAMPLE_FLAG_FULLREP, &mod->xxs[i], NULL) < 0) { goto err; } } if (nt) { hio_close(nt); } return 0; err: if (nt) { hio_close(nt); } return -1; } libxmp-4.4.1/src/loaders/abk_load.c0000664000175000017500000004231012774567167017005 0ustar claudioclaudio/* Extended Module Player * AMOS/STOS Music Bank Loader * Copyright (C) 2014 Stephen J Leary and Claudio Matsuoka * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "loader.h" #include "effects.h" #include "period.h" #define AMOS_BANK 0x416d426b #define AMOS_MUSIC_TYPE 0x0003 #define AMOS_MAIN_HEADER 0x14L #define AMOS_STRING_LEN 0x10 #define AMOS_BASE_FREQ 8192 #define AMOS_ABK_CHANNELS 4 #define ABK_HEADER_SECTION_COUNT 3 static int abk_test (HIO_HANDLE *, char *, const int); static int abk_load (struct module_data *, HIO_HANDLE *, const int); struct format_loader libxmp_loader_abk = { "AMOS Music Bank", abk_test, abk_load }; /** * @class abk_header * @brief represents the main ABK header. */ struct abk_header { uint32 instruments_offset; uint32 songs_offset; uint32 patterns_offset; }; /** * @class abk_song * @brief represents a song in an ABK module. */ struct abk_song { uint32 playlist_offset[AMOS_ABK_CHANNELS]; uint16 tempo; char song_name[AMOS_STRING_LEN]; }; /** * @class abk_playlist * @brief represents an ABK playlist. */ struct abk_playlist { uint16 length; uint16 *pattern; }; /** * @class abk_instrument * @brief represents an ABK instrument. */ struct abk_instrument { uint32 sample_offset; uint32 sample_length; uint32 repeat_offset; uint16 repeat_end; uint16 sample_volume; char sample_name[AMOS_STRING_LEN]; }; /** * @brief read the ABK playlist out from the file stream. This method malloc's some memory for the playlist * and can realloc if the playlist is very long. * @param f the stream to read from * @param playlist_offset the offset to the playlist sections. * @param playlist this structure is populated with the result. */ static void read_abk_playlist(HIO_HANDLE *f, uint32 playlist_offset, struct abk_playlist *playlist) { uint16 playdata; int arraysize; arraysize = 64; /* clear the length */ playlist->length = 0; /* move to the start of the songs data section. */ hio_seek(f, playlist_offset, SEEK_SET); playlist->pattern = (uint16 *) malloc(arraysize * sizeof(uint16)); playdata = hio_read16b(f); while((playdata != 0xFFFF) && (playdata != 0xFFFE)) { /* i hate doing a realloc in a loop but i'd rather not traverse the list twice.*/ if (playlist->length >= arraysize) { arraysize *= 2; playlist->pattern = (uint16 *) realloc(playlist->pattern , arraysize * sizeof(uint16)); } playlist->pattern[playlist->length++] = playdata; playdata = hio_read16b(f); }; } static int read_abk_song(HIO_HANDLE *f, struct abk_song *song, uint32 songs_section_offset) { int i; uint32 song_section; /* move to the start of the songs data section */ hio_seek(f, songs_section_offset, SEEK_SET); if (hio_read16b(f) != 1) { /* we only support a single song. * in a an abk file for now */ return -1; } song_section = hio_read32b(f); if (hio_seek(f, songs_section_offset + song_section, SEEK_SET) < 0) { return -1; } for (i=0; iplaylist_offset[i] = hio_read16b(f) + songs_section_offset + song_section; } song->tempo = hio_read16b(f); /* unused. just progress the file pointer forward */ (void) hio_read16b(f); if (hio_read(song->song_name, 1, AMOS_STRING_LEN, f) != AMOS_STRING_LEN) { return -1; } return 0; } /** * @brief reads an ABK pattern into a xmp_event structure. * @param f stream to read data from. * @param events events object to populate. * @param pattern_offset_abs the absolute file offset to the start of the patter to read. * @return returns the size of the pattern. */ static int read_abk_pattern(HIO_HANDLE *f, struct xmp_event *events, uint32 pattern_offset_abs) { uint8 position; uint8 command; uint8 param; uint8 inst = 0; uint8 jumped = 0; uint8 per_command = 0; uint8 per_param = 0; uint16 delay; uint16 patdata; int storepos; if ((storepos = hio_tell(f)) < 0) { return -1; } /* count how many abk positions are used in this pattern */ position = 0; hio_seek(f, pattern_offset_abs, SEEK_SET); /* read the first bit of pattern data */ patdata = hio_read16b(f); while ((patdata != 0x8000) && (jumped == 0)) { if (patdata == 0x9100) { break; } if (patdata & 0x8000) { command = (patdata >> 8) & 0x7F; param = patdata & 0x007F; if (command != 0x03 && command != 0x09 && command != 0x0b && command != 0x0c && command != 0x0d && command < 0x10) { per_command = 0; per_param = 0; } switch (command) { case 0x01: /* portamento up */ case 0x0e: events[position].fxt = FX_PORTA_UP; events[position].fxp = param; break; case 0x02: /* portamento down */ case 0x0f: events[position].fxt = FX_PORTA_DN; events[position].fxp = param; break; case 0x03: /* set volume */ events[position].fxt = FX_VOLSET; events[position].fxp = param; break; case 0x04: /* stop effect */ break; case 0x05: /* repeat */ events[position].fxt = FX_EXTENDED; if (param == 0) { events[position].fxp = 0x50; } else { events[position].fxp = 0x60 | (param & 0x0f); } break; case 0x06: /* lowpass filter off */ events[position].fxt = FX_EXTENDED; events[position].fxp = 0x00; break; case 0x07: /* lowpass filter on */ events[position].fxt = FX_EXTENDED; events[position].fxp = 0x01; break; case 0x08: /* set tempo */ if (param > 0) { events[position].fxt = FX_SPEED; events[position].fxp = 100/param; } break; case 0x09: /* set instrument */ inst = param + 1; break; case 0x0a: /* arpeggio */ per_command = FX_ARPEGGIO; per_param = param; break; case 0x0b: /* tone portamento */ per_command = FX_TONEPORTA; per_param = param; break; case 0x0c: /* vibrato */ per_command = FX_VIBRATO; per_param = param; break; case 0x0d: /* volume slide */ if (param != 0) { per_command = FX_VOLSLIDE; per_param = param; } else { per_command = 0; per_param = 0; } break; case 0x10: /* delay */ if (per_command != 0 || per_param != 0) { int i; for (i = 0; i < param && position < 64; i++) { events[position].fxt = per_command; events[position].fxp = per_param; position++; } } else { position += param; } if (position >= 64) { jumped = 1; } break; case 0x11: /* position jump */ events[position].fxt = FX_JUMP; events[position].fxp = param; /* break out of the loop because we've jumped.*/ jumped = 1; break; default: #if 0 /* write out an error for any unprocessed commands.*/ D_(D_WARN "ABK UNPROCESSED COMMAND: %x,%x\n", command, param); break; #else return -1; #endif } } else { if (patdata & 0x4000) { /* old note format.*/ /* old note format is 2 x 2 byte words with bit 14 set on the first word */ /* WORD 1: 0x4XDD | X = dont care, D = delay to apply after note. (Usually in 7FDD form). * WORD 2: 0xXPPP | PPP = Amiga Period */ delay = patdata & 0xff; patdata = hio_read16b(f); if (patdata == 0 && delay == 0) { /* a zero note, with zero delay ends the pattern */ break; } if (patdata != 0) { /* convert the note from amiga period format to xmp's internal format.*/ events[position].note = libxmp_period_to_note(patdata & 0x0fff); events[position].ins = inst; } /* now add on the delay */ position += delay; if (position >= 64) { break; } } else /* new note format */ { /* convert the note from amiga period format to xmp's internal format.*/ events[position].note = libxmp_period_to_note(patdata & 0x0fff); events[position].ins = inst; } } /* read the data for the next pass round the loop */ patdata = hio_read16b(f); /* check for an EOF while reading */ if (hio_eof(f)) { break; } } if (position < 64) { events[position - 1].f2t = FX_BREAK; } hio_seek(f, storepos, SEEK_SET); return position; } static struct abk_instrument* read_abk_insts(HIO_HANDLE *f, uint32 inst_section_size, int count) { uint16 i; struct abk_instrument *inst; inst = (struct abk_instrument*) malloc(count * sizeof(struct abk_instrument)); memset(inst, 0, count * sizeof(struct abk_instrument)); for (i = 0; i < count; i++) { uint32 sampleLength; inst[i].sample_offset = hio_read32b(f); inst[i].repeat_offset = hio_read32b(f); inst[i].sample_length = hio_read16b(f); inst[i].repeat_end = hio_read16b(f); inst[i].sample_volume = hio_read16b(f); sampleLength = hio_read16b(f); /* detect a potential bug where the sample length is not specified (and we might already know the length) */ if (sampleLength > 4) { inst[i].sample_length = sampleLength; } if (hio_read(inst[i].sample_name, 1, 16, f) != 16) { free(inst); return NULL; } } return inst; } static int abk_test(HIO_HANDLE *f, char *t, const int start) { char music[8]; if (hio_read32b(f) != AMOS_BANK) { return -1; } if (hio_read16b(f) != AMOS_MUSIC_TYPE) { return -1; } /* skip over length and chip/fastmem.*/ hio_seek(f, 6, SEEK_CUR); hio_read(music, 1, 8, f); /* get the "Music " */ if (memcmp(music, "Music ", 8)) { return -1; } return 0; } static int abk_load(struct module_data *m, HIO_HANDLE *f, const int start) { int i,j,k; uint16 pattern; uint32 first_sample_offset; uint32 inst_section_size; struct xmp_module *mod = &m->mod; struct abk_header main_header; struct abk_instrument *ci; struct abk_song song; struct abk_playlist playlist; hio_seek(f, AMOS_MAIN_HEADER, SEEK_SET); main_header.instruments_offset = hio_read32b(f); main_header.songs_offset = hio_read32b(f); main_header.patterns_offset = hio_read32b(f); /* Sanity check */ if (main_header.instruments_offset > 0x00100000 || main_header.songs_offset > 0x00100000 || main_header.patterns_offset > 0x00100000) { return -1; } inst_section_size = main_header.instruments_offset; D_(D_INFO "Sample Bytes: %d", inst_section_size); LOAD_INIT(); libxmp_set_type(m, "AMOS Music Bank"); if (read_abk_song(f, &song, AMOS_MAIN_HEADER + main_header.songs_offset) < 0) { return -1; } libxmp_copy_adjust(mod->name, (uint8*) song.song_name, AMOS_STRING_LEN); MODULE_INFO(); hio_seek(f, AMOS_MAIN_HEADER + main_header.patterns_offset, SEEK_SET); mod->chn = AMOS_ABK_CHANNELS; mod->pat = hio_read16b(f); /* Sanity check */ if (mod->pat > 256) { return -1; } mod->trk = mod->chn * mod->pat; /* move to the start of the instruments section. */ hio_seek(f, AMOS_MAIN_HEADER + main_header.instruments_offset, SEEK_SET); mod->ins = hio_read16b(f); /* Sanity check */ if (mod->ins > 255) { return -1; } mod->smp = mod->ins; /* Read and convert instruments and samples */ if (libxmp_init_instrument(m) < 0) { return -1; } D_(D_INFO "Instruments: %d", mod->ins); /* read all the instruments in */ ci = read_abk_insts(f, inst_section_size, mod->ins); if (ci == NULL) { return -1; } /* store the location of the first sample so we can read them later. */ first_sample_offset = AMOS_MAIN_HEADER + main_header.instruments_offset + ci[0].sample_offset; for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) { free(ci); return -1; } mod->xxs[i].len = ci[i].sample_length << 1; if (mod->xxs[i].len > 0) { mod->xxi[i].nsm = 1; } /* the repeating stuff. */ if (ci[i].repeat_offset > ci[i].sample_offset) { mod->xxs[i].lps = (ci[i].repeat_offset - ci[i].sample_offset) << 1; } else { mod->xxs[i].lps = 0; } mod->xxs[i].lpe = ci[i].repeat_end; if (mod->xxs[i].lpe > 2) { mod->xxs[i].lpe <<= 1; mod->xxs[i].flg = XMP_SAMPLE_LOOP; } /*printf("%02x lps=%04x lpe=%04x\n", i, mod->xxs[i].lps, mod->xxs[i].lpe);*/ mod->xxi[i].sub[0].vol = ci[i].sample_volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; libxmp_instrument_name(mod, i, (uint8*)ci[i].sample_name, 16); D_(D_INFO "[%2X] %-14.14s %04x %04x %04x %c", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' '); } free(ci); if (libxmp_init_pattern(mod) < 0) { return -1; } /* figure out the playlist order. * TODO: if the 4 channels arent in the same order then * we need to fail here. */ read_abk_playlist(f, song.playlist_offset[0], &playlist); /* move to the start of the instruments section */ /* then convert the patterns one at a time. there is a pattern for each channel.*/ hio_seek(f, AMOS_MAIN_HEADER + main_header.patterns_offset + 2, SEEK_SET); mod->len = 0; i = 0; for (j = 0; j < mod->pat; j++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) { free(playlist.pattern); return -1; } for (k = 0; k < mod->chn; k++) { pattern = hio_read16b(f); if (read_abk_pattern(f, mod->xxt[(i*mod->chn)+k]->event, AMOS_MAIN_HEADER + main_header.patterns_offset + pattern) < 0) { free(playlist.pattern); return -1; } } i++; } /* Sanity check */ if (playlist.length > 256) { free(playlist.pattern); return -1; } mod->len = playlist.length; /* now push all the patterns into the module and set the length */ for (i = 0; i < playlist.length; i++) { mod->xxo[i] = playlist.pattern[i]; } /* free up some memory here */ free(playlist.pattern); D_(D_INFO "Stored patterns: %d", mod->pat); D_(D_INFO "Stored tracks: %d", mod->trk); /* Read samples */ hio_seek(f, first_sample_offset, SEEK_SET); D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len <= 2) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) { return -1; } } return 0; } libxmp-4.4.1/src/loaders/asif.c0000664000175000017500000000570212773571316016165 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "loader.h" #include "asif.h" #define MAGIC_FORM MAGIC4('F','O','R','M') #define MAGIC_ASIF MAGIC4('A','S','I','F') #define MAGIC_NAME MAGIC4('N','A','M','E') #define MAGIC_INST MAGIC4('I','N','S','T') #define MAGIC_WAVE MAGIC4('W','A','V','E') int asif_load(struct module_data *m, HIO_HANDLE *f, int i) { struct xmp_module *mod = &m->mod; int size, pos; uint32 id; int chunk; int j; if (f == NULL) return -1; if (hio_read32b(f) != MAGIC_FORM) return -1; /*size =*/ hio_read32b(f); if (hio_read32b(f) != MAGIC_ASIF) return -1; for (chunk = 0; chunk < 2; ) { id = hio_read32b(f); size = hio_read32b(f); pos = hio_tell(f) + size; switch (id) { case MAGIC_WAVE: //printf("wave chunk\n"); hio_seek(f, hio_read8(f), SEEK_CUR); /* skip name */ mod->xxs[i].len = hio_read16l(f) + 1; size = hio_read16l(f); /* NumSamples */ for (j = 0; j < size; j++) { hio_read16l(f); /* Location */ mod->xxs[j].len = 256 * hio_read16l(f); hio_read16l(f); /* OrigFreq */ hio_read16l(f); /* SampRate */ } if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0) { return -1; } chunk++; break; case MAGIC_INST: //printf("inst chunk\n"); hio_seek(f, hio_read8(f), SEEK_CUR); /* skip name */ hio_read16l(f); /* SampNum */ hio_seek(f, 24, SEEK_CUR); /* skip envelope */ hio_read8(f); /* ReleaseSegment */ hio_read8(f); /* PriorityIncrement */ hio_read8(f); /* PitchBendRange */ hio_read8(f); /* VibratoDepth */ hio_read8(f); /* VibratoSpeed */ hio_read8(f); /* UpdateRate */ mod->xxi[i].nsm = 1; mod->xxi[i].sub[0].vol = 0x40; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; chunk++; } hio_seek(f, pos, SEEK_SET); } return 0; } libxmp-4.4.1/src/loaders/iff.h0000664000175000017500000000221212775035311015775 0ustar claudioclaudio#ifndef LIBXMP_IFF_H #define LIBXMP_IFF_H #include "list.h" #include "hio.h" #define IFF_NOBUFFER 0x0001 #define IFF_LITTLE_ENDIAN 0x01 #define IFF_FULL_CHUNK_SIZE 0x02 #define IFF_CHUNK_ALIGN2 0x04 #define IFF_CHUNK_ALIGN4 0x08 #define IFF_SKIP_EMBEDDED 0x10 #define IFF_CHUNK_TRUNC4 0x20 #define IFF_MAX_CHUNK_SIZE 0x400000 typedef void *iff_handle; struct iff_header { char form[4]; /* FORM */ int len; /* File length */ char id[4]; /* IFF type identifier */ }; struct iff_info { char id[4]; int (*loader)(struct module_data *, int, HIO_HANDLE *, void *); struct list_head list; }; iff_handle libxmp_iff_new(void); int libxmp_iff_load(iff_handle, struct module_data *, HIO_HANDLE *, void *); /* int libxmp_iff_chunk(iff_handle, struct module_data *, HIO_HANDLE *, void *); */ int libxmp_iff_register(iff_handle, char *, int (*loader)(struct module_data *, int, HIO_HANDLE *, void *)); void libxmp_iff_id_size(iff_handle, int); void libxmp_iff_set_quirk(iff_handle, int); void libxmp_iff_release(iff_handle); /* int libxmp_iff_process(iff_handle, struct module_data *, char *, long, HIO_HANDLE *, void *); */ #endif /* LIBXMP_IFF_H */ libxmp-4.4.1/src/loaders/mmd_common.c0000664000175000017500000004623412775035311017365 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Common functions for MMD0/1 and MMD2/3 loaders * Tempo fixed by Francis Russell */ #include "med.h" #include "loader.h" #include "med_extras.h" #ifdef DEBUG const char *const mmd_inst_type[] = { "HYB", /* -2 */ "SYN", /* -1 */ "SMP", /* 0 */ "I5O", /* 1 */ "I3O", /* 2 */ "I2O", /* 3 */ "I4O", /* 4 */ "I6O", /* 5 */ "I7O", /* 6 */ "EXT", /* 7 */ }; #endif static int get_8ch_tempo(int tempo) { const int tempos[10] = { 47, 43, 40, 37, 35, 32, 30, 29, 27, 26 }; if (tempo > 0) { tempo = tempo > 10 ? 10 : tempo; return tempos[tempo-1]; } else { return tempo; } } void mmd_xlat_fx(struct xmp_event *event, int bpm_on, int bpmlen, int med_8ch, int hexvol) { switch (event->fxt) { case 0x00: /* ARPEGGIO 00 * Changes the pitch six times between three different * pitches during the duration of the note. It can create a * chord sound or other special effect. Arpeggio works better * with some instruments than others. */ /* fall-through */ case 0x01: /* SLIDE UP 01 * This slides the pitch of the current track up. It decreases * the period of the note by the amount of the argument on each * timing pulse. OctaMED-Pro can create slides automatically, * but you may want to use this function for special effects. */ /* fall-through */ case 0x02: /* SLIDE DOWN 02 * The same as SLIDE UP, but it slides down. */ /* fall-through */ case 0x03: /* PORTAMENTO 03 * Makes precise sliding easy. */ break; case 0x04: /* VIBRATO 04 * The left half of the argument is the vibrato speed, the * right half is the depth. If the numbers are zeros, the * previous speed and depth are used. */ /* Note: this is twice as deep as the Protracker vibrato */ event->fxt = FX_VIBRATO2; break; case 0x05: /* SLIDE + FADE 05 * ProTracker compatible. This command is the combination of * commands 0300 and 0Dxx. The argument is the fade speed. * The slide will continue during this command. */ /* fall-through */ case 0x06: /* VIBRATO + FADE 06 * ProTracker compatible. Combines commands 0400 and 0Dxx. * The argument is the fade speed. The vibrato will continue * during this command. */ /* fall-through */ case 0x07: /* TREMOLO 07 * ProTracker compatible. * This command is a kind of "volume vibrato". The left * number is the speed of the tremolo, and the right one is * the depth. The depth must be quite high before the effect * is audible. */ break; case 0x08: /* HOLD and DECAY 08 * This command must be on the same line as the note. The * left half of the argument determines the decay and the * right half the hold. */ event->fxt = event->fxp = 0; break; case 0x09: /* SECONDARY TEMPO 09 * This sets the secondary tempo (the number of timing * pulses per note). The argument must be from 01 to 20. */ if (event->fxp >= 1 && event->fxp <= 20) { event->fxt = FX_SPEED; } else { event->fxt = event->fxp = 0; } break; case 0x0a: /* 0A not mentioned but it's Protracker-compatible */ /* fall-through */ case 0x0b: /* POSITION JUMP 0B * The song plays up to this command and then jumps to * another position in the play sequence. The song then * loops from the point jumped to, to the end of the song * forever. The purpose is to allow for introductions that * play only once. */ /* fall-through */ case 0x0c: /* SET VOLUME 0C * Overrides the default volume of an instrument. */ if (!hexvol) { int p = event->fxp; event->fxp = (p >> 8) * 10 + (p & 0xff); } break; case 0x0d: /* VOLUME SLIDE 0D * Smoothly slides the volume up or down. The left half of * the argument increases the volume. The right decreases it. */ event->fxt = FX_VOLSLIDE; break; case 0x0e: /* SYNTH JUMP 0E * When used with synthetic or hybrid instruments, it * triggers a jump in the Waveform Sequence List. The argument * is the jump destination (line no). */ event->fxt = event->fxp = 0; break; case 0x0f: /* MISCELLANEOUS 0F * The effect depends upon the value of the argument. */ if (event->fxp == 0x00) { /* Jump to next block */ event->fxt = 0x0d; break; } else if (event->fxp <= 0xf0) { event->fxt = FX_S3M_BPM; event->fxp = med_8ch ? get_8ch_tempo(event->fxp) : event->fxp; break; } else switch (event->fxp) { case 0xf1: /* Play note twice */ event->fxt = FX_EXTENDED; event->fxp = (EX_RETRIG << 4) | 3; break; case 0xf2: /* Delay note */ event->fxt = FX_EXTENDED; event->fxp = (EX_DELAY << 4) | 3; break; case 0xf3: /* Play note three times */ event->fxt = FX_EXTENDED; event->fxp = (EX_RETRIG << 4) | 2; break; case 0xf8: /* Turn filter off */ case 0xf9: /* Turn filter on */ case 0xfa: /* MIDI pedal on */ case 0xfb: /* MIDI pedal off */ case 0xfd: /* Set pitch */ case 0xfe: /* End of song */ event->fxt = event->fxp = 0; break; case 0xff: /* Turn note off */ event->fxt = event->fxp = 0; event->note = XMP_KEY_CUT; break; default: event->fxt = event->fxp = 0; } break; case 0x11: /* SLIDE PITCH UP (only once) 11 * Equivalent to ProTracker command E1x. * Lets you control the pitch with great accuracy. This * command changes only this occurrence of the note. */ event->fxt = FX_F_PORTA_UP; break; case 0x12: /* SLIDE DOWN (only once) 12 * Equivalent to ProTracker command E2x. */ event->fxt = FX_F_PORTA_DN; break; case 0x14: /* VIBRATO 14 * ProTracker compatible. This is similar to command 04 * except the depth is halved, to give greater accuracy. */ event->fxt = FX_VIBRATO; break; case 0x15: /* SET FINETUNE 15 * Set a finetune value for a note, overrides the default * fine tune value of the instrument. Negative numbers must * be entered as follows: * -1 => FF -3 => FD -5 => FB -7 => F9 * -2 => FE -4 => FC -6 => FA -8 => F8 */ event->fxt = FX_FINETUNE; event->fxp = (event->fxp + 8) << 4; break; case 0x16: /* LOOP 16 * Creates a loop within a block. 1600 marks the beginning * of the loop. The next occurrence of the 16 command * designates the number of loops. Same as ProTracker E6x. */ event->fxt = FX_EXTENDED; if (event->fxp > 0x0f) event->fxp = 0x0f; event->fxp |= 0x60; break; case 0x18: /* STOP NOTE 18 * Cuts the note by zeroing the volume at the pulse specified * in the argument value. This is the same as ProTracker * command ECx. */ event->fxt = FX_EXTENDED; if (event->fxp > 0x0f) event->fxp = 0x0f; event->fxp |= 0xc0; break; case 0x19: /* SET SAMPLE START OFFSET * Same as ProTracker command 9. * When playing a sample, this command sets the starting * offset (at steps of $100 = 256 bytes). Useful for speech * samples. */ event->fxt = FX_OFFSET; break; case 0x1a: /* SLIDE VOLUME UP ONCE * Only once ProTracker command EAx. Lets volume slide * slowly once per line. */ event->fxt = FX_F_VSLIDE_UP; break; case 0x1b: /* VOLUME DOWN? * Only once ProTracker command EBx ? */ event->fxt = FX_F_VSLIDE_DN; break; case 0x1d: /* JUMP TO NEXT BLOCK 1D * Jumps to the next line in the PLAY SEQUENCE LIST at the * specified line. ProTracker command D. This command is * like F00, except that you can specify the line number of * the first line to be played. The line number must be * specified in HEX. */ event->fxt = FX_BREAK; break; case 0x1e: /* PLAY LINE x TIMES 1E * Plays only commands, notes not replayed. ProTracker * pattern delay. */ event->fxt = FX_PATT_DELAY; break; case 0x1f: /* Command 1F: NOTE DELAY AND RETRIGGER * (Protracker commands EC and ED) * Gives you accurate control over note playing. You can * delay the note any number of ticks, and initiate fast * retrigger. Level 1 = note delay value, level 2 = retrigger * value. */ if (MSN(event->fxp)) { /* delay */ event->fxt = FX_EXTENDED; event->fxp = 0xd0 | (event->fxp >> 4); } else if (LSN(event->fxp)) { /* retrig */ event->fxt = FX_EXTENDED; event->fxp = 0x90 | (event->fxp & 0x0f); } break; case 0x2e: /* Command 2E: SET TRACK PANNING * Allows track panning to be changed during play. The track * on which the player command appears is the track affected. * The command level is in signed hex: $F0 to $10 = -16 to 16 * decimal. */ if (event->fxp >= 0xf0 || event->fxp <= 0x10) { int fxp = (signed char)event->fxp + 16; fxp <<= 3; if (fxp == 0x100) fxp--; event->fxt = FX_SETPAN; event->fxp = fxp; } break; default: event->fxt = event->fxp = 0; break; } } int mmd_alloc_tables(struct module_data *m, int i, struct SynthInstr *synth) { struct med_module_extras *me = (struct med_module_extras *)m->extra; me->vol_table[i] = calloc(1, synth->voltbllen); if (me->vol_table[i] == NULL) goto err; memcpy(me->vol_table[i], synth->voltbl, synth->voltbllen); me->wav_table[i] = calloc(1, synth->wftbllen); if (me->wav_table[i] == NULL) goto err1; memcpy(me->wav_table[i], synth->wftbl, synth->wftbllen); return 0; err1: free(me->vol_table[i]); err: return -1; } int mmd_load_hybrid_instrument(HIO_HANDLE *f, struct module_data *m, int i, int smp_idx, struct SynthInstr *synth, struct InstrExt *exp_smp, struct MMD0sample *sample) { struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_subinstrument *sub; struct xmp_sample *xxs; int length, type; int pos = hio_tell(f); /* Sanity check */ if (smp_idx >= mod->smp) { return -1; } synth->defaultdecay = hio_read8(f); hio_seek(f, 3, SEEK_CUR); synth->rep = hio_read16b(f); synth->replen = hio_read16b(f); synth->voltbllen = hio_read16b(f); synth->wftbllen = hio_read16b(f); synth->volspeed = hio_read8(f); synth->wfspeed = hio_read8(f); synth->wforms = hio_read16b(f); hio_read(synth->voltbl, 1, 128, f);; hio_read(synth->wftbl, 1, 128, f);; /* Sanity check */ if (synth->voltbllen > 128 || synth->wftbllen > 128) { return -1; } hio_seek(f, pos - 6 + hio_read32b(f), SEEK_SET); length = hio_read32b(f); type = hio_read16b(f); if (libxmp_med_new_instrument_extras(xxi) != 0) return -1; xxi->nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; MED_INSTRUMENT_EXTRAS((*xxi))->vts = synth->volspeed; MED_INSTRUMENT_EXTRAS((*xxi))->wts = synth->wfspeed; sub = &xxi->sub[0]; sub->pan = 0x80; sub->vol = sample->svol; sub->xpo = sample->strans + 36; sub->sid = smp_idx; sub->fin = exp_smp->finetune; xxs = &mod->xxs[smp_idx]; xxs->len = length; xxs->lps = 2 * sample->rep; xxs->lpe = xxs->lps + 2 * sample->replen; xxs->flg = sample->replen > 1 ? XMP_SAMPLE_LOOP : 0; if (libxmp_load_sample(m, f, 0, xxs, NULL) < 0) return -1; return 0; } int mmd_load_synth_instrument(HIO_HANDLE *f, struct module_data *m, int i, int smp_idx, struct SynthInstr *synth, struct InstrExt *exp_smp, struct MMD0sample *sample) { struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi = &mod->xxi[i]; int pos = hio_tell(f); int j; synth->defaultdecay = hio_read8(f); hio_seek(f, 3, SEEK_CUR); synth->rep = hio_read16b(f); synth->replen = hio_read16b(f); synth->voltbllen = hio_read16b(f); synth->wftbllen = hio_read16b(f); synth->volspeed = hio_read8(f); synth->wfspeed = hio_read8(f); synth->wforms = hio_read16b(f); hio_read(synth->voltbl, 1, 128, f);; hio_read(synth->wftbl, 1, 128, f);; for (j = 0; j < 64; j++) synth->wf[j] = hio_read32b(f); /* Sanity check */ if (synth->voltbllen > 128 || synth->wftbllen > 128 || synth->wforms > 256) { return -1; } D_(D_INFO " VS:%02x WS:%02x WF:%02x %02x %+3d %+1d", synth->volspeed, synth->wfspeed, synth->wforms & 0xff, sample->svol, sample->strans, exp_smp->finetune); if (synth->wforms == 0xffff) { xxi->nsm = 0; return 1; } if (synth->wforms > 64) return -1; if (libxmp_med_new_instrument_extras(&mod->xxi[i]) != 0) return -1; mod->xxi[i].nsm = synth->wforms; if (libxmp_alloc_subinstrument(mod, i, synth->wforms) < 0) return -1; MED_INSTRUMENT_EXTRAS((*xxi))->vts = synth->volspeed; MED_INSTRUMENT_EXTRAS((*xxi))->wts = synth->wfspeed; for (j = 0; j < synth->wforms; j++) { struct xmp_subinstrument *sub = &xxi->sub[j]; struct xmp_sample *xxs = &mod->xxs[smp_idx]; /* Sanity check */ if (j >= xxi->nsm || smp_idx >= mod->smp) return -1; sub->pan = 0x80; sub->vol = 64; sub->xpo = 12 + sample->strans; sub->sid = smp_idx; sub->fin = exp_smp->finetune; hio_seek(f, pos - 6 + synth->wf[j], SEEK_SET); xxs->len = hio_read16b(f) * 2; xxs->lps = 0; xxs->lpe = mod->xxs[smp_idx].len; xxs->flg = XMP_SAMPLE_LOOP; if (libxmp_load_sample(m, f, 0, xxs, NULL) < 0) return -1; smp_idx++; } return 0; } int mmd_load_sampled_instrument(HIO_HANDLE *f, struct module_data *m, int i, int smp_idx, struct InstrHdr *instr, struct MMD0exp *expdata, struct InstrExt *exp_smp, struct MMD0sample *sample, int ver) { struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_subinstrument *sub; struct xmp_sample *xxs; int j, k; /* Sanity check */ if (smp_idx >= mod->smp) return -1; /* hold & decay support */ if (libxmp_med_new_instrument_extras(xxi) != 0) return -1; MED_INSTRUMENT_EXTRAS(*xxi)->hold = exp_smp->hold; xxi->rls = 0xfff - (exp_smp->decay << 4); xxi->nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; sub->vol = sample->svol; sub->pan = 0x80; sub->xpo = sample->strans + 36; if (ver >= 2 && expdata->s_ext_entrsz > 4) { /* MMD2+ */ if (exp_smp->default_pitch) { sub->xpo += exp_smp->default_pitch - 25; } } sub->sid = smp_idx; sub->fin = exp_smp->finetune << 4; xxs = &mod->xxs[smp_idx]; xxs->len = instr->length; xxs->lps = 2 * sample->rep; xxs->lpe = xxs->lps + 2 * sample->replen; xxs->flg = 0; if (sample->replen > 1) { xxs->flg |= XMP_SAMPLE_LOOP; } if (instr->type & S_16) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } /* STEREO means that this is a stereo sample. The sample * is not interleaved. The left channel comes first, * followed by the right channel. Important: Length * specifies the size of one channel only! The actual memory * usage for both samples is length * 2 bytes. */ /* Restrict sampled instruments to 3 octave range except for MMD3. * Checked in MMD0 with med.egypian/med.medieval from Lemmings 2 * and MED.ParasolStars, MMD1 with med.Lemmings2 */ if (ver < 3) { for (j = 0; j < 9; j++) { for (k = 0; k < 12; k++) { int xpo = 0; if (j < 1) xpo = 12 * (1 - j); else if (j > 3) xpo = -12 * (j - 3); xxi->map[12 * j + k].xpo = xpo; } } } if (libxmp_load_sample(m, f, SAMPLE_FLAG_BIGEND, xxs, NULL) < 0) { return -1; } return 0; } static const char iffoct_insmap[6][9] = { /* 2 */ { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* 3 */ { 2, 2, 2, 2, 2, 2, 1, 1, 0 }, /* 4 */ { 3, 3, 3, 2, 2, 2, 1, 1, 0 }, /* 5 */ { 4, 4, 4, 3, 2, 2, 1, 1, 0 }, /* 6 */ { 5, 5, 5, 5, 4, 3, 2, 1, 0 }, /* 7 */ { 6, 6, 6, 6, 5, 4, 3, 2, 1 } }; static const char iffoct_xpomap[6][9] = { /* 2 */ { 12, 12, 12, 0, 0, 0, 0, 0, 0 }, /* 3 */ { 12, 12, 12, 12, 12, 12, 0, 0,-12 }, /* 4 */ { 12, 12, 12, 0, 0, 0,-12,-12,-24 }, /* 5 */ { 24, 24, 24, 12, 0, 0,-12,-24,-36 }, /* 6 */ { 12, 12, 12, 12, 0,-12,-24,-36,-48 }, /* 7 */ { 12, 12, 12, 12, 0,-12,-24,-36,-48 }, }; int mmd_load_iffoct_instrument(HIO_HANDLE *f, struct module_data *m, int i, int smp_idx, struct InstrHdr *instr, int num_oct, struct InstrExt *exp_smp, struct MMD0sample *sample) { struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_subinstrument *sub; struct xmp_sample *xxs; int size, rep, replen, j, k; if (num_oct < 2 || num_oct > 7) return -1; /* Sanity check */ if (smp_idx + num_oct > mod->smp) return -1; /* hold & decay support */ if (libxmp_med_new_instrument_extras(xxi) != 0) return -1; MED_INSTRUMENT_EXTRAS(*xxi)->hold = exp_smp->hold; xxi->rls = 0xfff - (exp_smp->decay << 4); xxi->nsm = num_oct; if (libxmp_alloc_subinstrument(mod, i, num_oct) < 0) return -1; /* base octave size */ size = instr->length / ((1 << num_oct) - 1); rep = 2 * sample->rep; replen = 2 * sample->replen; for (j = 0; j < num_oct; j++) { sub = &xxi->sub[j]; sub->vol = sample->svol; sub->pan = 0x80; sub->xpo = 24 + sample->strans; sub->sid = smp_idx; sub->fin = exp_smp->finetune << 4; xxs = &mod->xxs[smp_idx]; xxs->len = size; xxs->lps = rep; xxs->lpe = rep + replen; xxs->flg = 0; if (sample->replen > 1) { xxs->flg |= XMP_SAMPLE_LOOP; } if (libxmp_load_sample(m, f, SAMPLE_FLAG_BIGEND, xxs, NULL) < 0) { return -1; } smp_idx++; size <<= 1; rep <<= 1; replen <<= 1; } /* instrument mapping */ for (j = 0; j < 9; j++) { for (k = 0; k < 12; k++) { xxi->map[12 * j + k].ins = iffoct_insmap[num_oct - 2][j]; xxi->map[12 * j + k].xpo = iffoct_xpomap[num_oct - 2][j]; } } return 0; } void mmd_set_bpm(struct module_data *m, int med_8ch, int deftempo, int bpm_on, int bpmlen) { struct xmp_module *mod = &m->mod; /* From the OctaMEDv4 documentation: * * In 8-channel mode, you can control the playing speed more * accurately (to techies: by changing the size of the mix buffer). * This can be done with the left tempo gadget (values 1-10; the * lower, the faster). Values 11-240 are equivalent to 10. */ if (med_8ch) { mod->bpm = get_8ch_tempo(deftempo); } else { mod->bpm = deftempo; if (bpm_on) { m->time_factor = DEFAULT_TIME_FACTOR * 4 / bpmlen; } } } void mmd_info_text(HIO_HANDLE *f, struct module_data *m, int offset) { int type, len; /* Copy song info text */ hio_read32b(f); /* skip next */ hio_read16b(f); /* skip reserved */ type = hio_read16b(f); if (type == 1) { /* 1 = ASCII */ len = hio_read32b(f); if (len != 0 && len < 0x7fffffff) { m->comment = malloc(len + 1); if (m->comment == NULL) return; hio_read(m->comment, 1, len, f); m->comment[len] = 0; } } } libxmp-4.4.1/src/loaders/arch_load.c0000664000175000017500000002663412775035311017156 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "iff.h" #define MAGIC_MUSX MAGIC4('M','U','S','X') #define MAGIC_MNAM MAGIC4('M','N','A','M') #define MAGIC_SNAM MAGIC4('S','N','A','M') #define MAGIC_SVOL MAGIC4('S','V','O','L') #define MAGIC_SLEN MAGIC4('S','L','E','N') #define MAGIC_ROFS MAGIC4('R','O','F','S') #define MAGIC_RLEN MAGIC4('R','L','E','N') #define MAGIC_SDAT MAGIC4('S','D','A','T') static int arch_test (HIO_HANDLE *, char *, const int); static int arch_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_arch = { "Archimedes Tracker", arch_test, arch_load }; /* * Linear (0 to 0x40) to logarithmic volume conversion. * This is only used for the Protracker-compatible "linear volume" effect in * Andy Southgate's StasisMod. In this implementation linear and logarithmic * volumes can be freely intermixed. */ static const uint8 lin_table[65]={ 0x00, 0x48, 0x64, 0x74, 0x82, 0x8a, 0x92, 0x9a, 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xea, 0xbe, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe2, 0xe4, 0xe4, 0xe6, 0xe6, 0xe8, 0xe8, 0xea, 0xea, 0xec, 0xec, 0xee, 0xee, 0xf0, 0xf0, 0xf2, 0xf2, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfa, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }; #if 0 static uint8 convert_vol(uint8 vol) { /* return pow(2,6.0-(255.0-vol)/32)+.5; */ return vol_table[vol]; } #endif static int arch_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_MUSX) { return -1; } hio_read32l(f); while (!hio_eof(f)) { uint32 id = hio_read32b(f); uint32 len = hio_read32l(f); /* Sanity check */ if (len > 0x100000) { return -1; } if (id == MAGIC_MNAM) { libxmp_read_title(f, t, 32); return 0; } hio_seek(f, len, SEEK_CUR); } libxmp_read_title(f, t, 0); return 0; } struct local_data { int year, month, day; int pflag, sflag, max_ins, max_pat; uint8 ster[8], rows[64]; }; static void fix_effect(struct xmp_event *e) { #if 0 /* for debugging */ printf ("%c%02x ", e->fxt["0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"], e->fxp); #endif switch (e->fxt) { case 0x00: /* 00 xy Normal play or Arpeggio */ e->fxt = FX_ARPEGGIO; /* x: first halfnote to add y: second halftone to subtract */ break; case 0x01: /* 01 xx Slide Up */ e->fxt = FX_PORTA_UP; break; case 0x02: /* 02 xx Slide Down */ e->fxt = FX_PORTA_DN; break; case 0x03: /* 03 xx Tone Portamento */ e->fxt = FX_TONEPORTA; break; case 0x0b: /* 0B xx Break Pattern */ e->fxt = FX_BREAK; break; case 0x0c: /* Set linear volume */ if (e->fxp <= 64) { e->fxt = FX_VOLSET; e->fxp = lin_table[e->fxp]; } else { e->fxp = e->fxt = 0; } break; case 0x0e: /* 0E xy Set Stereo */ case 0x19: /* StasisMod's non-standard set panning effect */ /* y: stereo position (1-7,ignored). 1=left 4=center 7=right */ if (e->fxp>0 && e->fxp<8) { e->fxt = FX_SETPAN; e->fxp = 42*e->fxp-40; } else e->fxt = e->fxp = 0; break; case 0x10: /* 10 xx Volume Slide Up */ e->fxt = FX_VOLSLIDE_UP; break; case 0x11: /* 11 xx Volume Slide Down */ e->fxt = FX_VOLSLIDE_DN; break; case 0x13: /* 13 xx Position Jump */ e->fxt = FX_JUMP; break; case 0x15: /* 15 xy Line Jump. (not in manual) */ e->fxt = e->fxp = 0; /* Jump to line 10*x+y in same pattern. (10*x+y>63 ignored) */ break; case 0x1c: /* 1C xy Set Speed */ e->fxt = FX_SPEED; break; case 0x1f: /* 1F xx Set Volume */ e->fxt = FX_VOLSET; /* all volumes are logarithmic */ /* e->fxp = convert_vol (e->fxp); */ break; default: e->fxt = e->fxp = 0; } } static int get_tinf(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct local_data *data = (struct local_data *)parm; int x; x = hio_read8(f); data->year = ((x & 0xf0) >> 4) * 10 + (x & 0x0f); x = hio_read8(f); data->year += ((x & 0xf0) >> 4) * 1000 + (x & 0x0f) * 100; x = hio_read8(f); data->month = ((x & 0xf0) >> 4) * 10 + (x & 0x0f); x = hio_read8(f); data->day = ((x & 0xf0) >> 4) * 10 + (x & 0x0f); return 0; } static int get_mvox(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->chn = hio_read32l(f); /* Sanity check */ if (mod->chn < 1 || mod->chn > 8) { return -1; } return 0; } static int get_ster(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i; if (hio_read(data->ster, 1, 8, f) != 8) { return -1; } for (i = 0; i < mod->chn; i++) { if (data->ster[i] > 0 && data->ster[i] < 8) { mod->xxc[i].pan = 42 * data->ster[i] - 40; } } return 0; } static int get_mnam(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; if (hio_read(mod->name, 1, 32, f) != 32) return -1; return 0; } static int get_anam(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { /*hio_read(m->author, 1, 32, f); */ return 0; } static int get_mlen(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->len = hio_read32l(f); /* Sanity check */ if (mod->len > 0xff) return -1; return 0; } static int get_pnum(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->pat = hio_read32l(f); /* Sanity check */ if (mod->pat > 64 ) return -1; return 0; } static int get_plen(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct local_data *data = (struct local_data *)parm; if (hio_read(data->rows, 1, 64, f) != 64) return -1; return 0; } static int get_sequ(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; hio_read(mod->xxo, 1, 128, f); libxmp_set_type(m, "Archimedes Tracker"); MODULE_INFO(); return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i, j, k; struct xmp_event *event; if (!data->pflag) { D_(D_INFO "Stored patterns: %d", mod->pat); data->pflag = 1; data->max_pat = 0; mod->trk = mod->pat * mod->chn; if (libxmp_init_pattern(mod) < 0) return -1; } /* Sanity check */ if (data->max_pat >= mod->pat || data->max_pat >= 64) return -1; i = data->max_pat; if (libxmp_alloc_pattern_tracks(mod, i, data->rows[i]) < 0) return -1; for (j = 0; j < data->rows[i]; j++) { for (k = 0; k < mod->chn; k++) { event = &EVENT(i, k, j); event->fxp = hio_read8(f); event->fxt = hio_read8(f); event->ins = hio_read8(f); event->note = hio_read8(f); if (event->note) event->note += 48; fix_effect(event); } } data->max_pat++; return 0; } static int get_samp(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i; if (!data->sflag) { mod->smp = mod->ins = 36; if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->ins); data->sflag = 1; data->max_ins = 0; } /* FIXME: More than 36 sample slots used. Unfortunately we * have no way to handle this without two passes, and it's * officially supposed to be 36, so ignore the rest. */ if (data->max_ins >= 36) return 0; i = data->max_ins; mod->xxi[i].nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; if (hio_read32b(f) != MAGIC_SNAM) /* SNAM */ return -1; { /* should usually be 0x14 but zero is not unknown */ int name_len = hio_read32l(f); /* Sanity check */ if (name_len < 0 || name_len > 32) return -1; hio_read(mod->xxi[i].name, 1, name_len, f); } if (hio_read32b(f) != MAGIC_SVOL) /* SVOL */ return -1; hio_read32l(f); /* mod->xxi[i].sub[0].vol = convert_vol(hio_read32l(f)); */ mod->xxi[i].sub[0].vol = hio_read32l(f) & 0xff; if (hio_read32b(f) != MAGIC_SLEN) /* SLEN */ return -1; hio_read32l(f); mod->xxs[i].len = hio_read32l(f); if (hio_read32b(f) != MAGIC_ROFS) /* ROFS */ return -1; hio_read32l(f); mod->xxs[i].lps = hio_read32l(f); if (hio_read32b(f) != MAGIC_RLEN) /* RLEN */ return -1; hio_read32l(f); mod->xxs[i].lpe = hio_read32l(f); if (hio_read32b(f) != MAGIC_SDAT) /* SDAT */ return -1; hio_read32l(f); hio_read32l(f); /* 0x00000000 */ mod->xxi[i].sub[0].sid = i; mod->xxi[i].sub[0].pan = 0x80; m->vol_table = (int *)libxmp_arch_vol_table; m->volbase = 0xff; if (mod->xxs[i].lpe > 2) { mod->xxs[i].flg = XMP_SAMPLE_LOOP; mod->xxs[i].lpe = mod->xxs[i].lps + mod->xxs[i].lpe; } else if (mod->xxs[i].lpe == 2 && mod->xxs[i].lps > 0) { /* non-zero repeat offset and repeat length of 2 * means loop to end of sample */ mod->xxs[i].flg = XMP_SAMPLE_LOOP; mod->xxs[i].lpe = mod->xxs[i].len; } if (libxmp_load_sample(m, f, SAMPLE_FLAG_VIDC, &mod->xxs[i], NULL) < 0) return -1; D_(D_INFO "[%2X] %-20.20s %05x %05x %05x %c V%02x", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol); data->max_ins++; return 0; } static int arch_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; iff_handle handle; int i; struct local_data data; LOAD_INIT(); hio_read32b(f); /* MUSX */ hio_read32b(f); data.pflag = data.sflag = 0; data.year = data.month = data.day = 0; handle = libxmp_iff_new(); if (handle == NULL) return -1; /* IFF chunk IDs */ libxmp_iff_register(handle, "TINF", get_tinf); libxmp_iff_register(handle, "MVOX", get_mvox); libxmp_iff_register(handle, "STER", get_ster); libxmp_iff_register(handle, "MNAM", get_mnam); libxmp_iff_register(handle, "ANAM", get_anam); libxmp_iff_register(handle, "MLEN", get_mlen); libxmp_iff_register(handle, "PNUM", get_pnum); libxmp_iff_register(handle, "PLEN", get_plen); libxmp_iff_register(handle, "SEQU", get_sequ); libxmp_iff_register(handle, "PATT", get_patt); libxmp_iff_register(handle, "SAMP", get_samp); libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = DEFPAN((((i + 3) / 2) % 2) * 0xff); } return 0; } libxmp-4.4.1/src/loaders/med2_load.c0000664000175000017500000001260412774567167017102 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * MED 1.12 is in Fish disk #255 */ #ifdef __native_client__ #include #else #include #endif #include "loader.h" #include "period.h" #define MAGIC_MED2 MAGIC4('M','E','D',2) static int med2_test(HIO_HANDLE *, char *, const int); static int med2_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_med2 = { "MED 1.12 MED2", med2_test, med2_load }; static int med2_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_MED2) return -1; libxmp_read_title(f, t, 0); return 0; } int med2_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k; int sliding; struct xmp_event *event; uint8 buf[40]; LOAD_INIT(); if (hio_read32b(f) != MAGIC_MED2) return -1; libxmp_set_type(m, "MED 1.12 MED2"); mod->ins = mod->smp = 32; if (libxmp_init_instrument(m) < 0) return -1; /* read instrument names */ hio_read(buf, 1, 40, f); /* skip 0 */ for (i = 0; i < 31; i++) { hio_read(buf, 1, 40, f); libxmp_instrument_name(mod, i, buf, 32); if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; } /* read instrument volumes */ hio_read8(f); /* skip 0 */ for (i = 0; i < 31; i++) { mod->xxi[i].sub[0].vol = hio_read8(f); mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].fin = 0; mod->xxi[i].sub[0].sid = i; } /* read instrument loops */ hio_read16b(f); /* skip 0 */ for (i = 0; i < 31; i++) { mod->xxs[i].lps = hio_read16b(f); } /* read instrument loop length */ hio_read16b(f); /* skip 0 */ for (i = 0; i < 31; i++) { uint32 lsiz = hio_read16b(f); mod->xxs[i].lpe = mod->xxs[i].lps + lsiz; mod->xxs[i].flg = lsiz > 1 ? XMP_SAMPLE_LOOP : 0; } mod->chn = 4; mod->pat = hio_read16b(f); mod->trk = mod->chn * mod->pat; if (hio_read(mod->xxo, 1, 100, f) != 100) return -1; mod->len = hio_read16b(f); /* Sanity check */ if (mod->pat > 256 || mod->len > 100) return -1; k = hio_read16b(f); if (k < 1) { return -1; } mod->spd = 192 / k; hio_read16b(f); /* flags */ sliding = hio_read16b(f); /* sliding */ hio_read32b(f); /* jumping mask */ hio_seek(f, 16, SEEK_CUR); /* rgb */ MODULE_INFO(); D_(D_INFO "Sliding: %d", sliding); if (sliding == 6) m->quirk |= QUIRK_VSALL | QUIRK_PBALL; if (libxmp_init_pattern(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; hio_read32b(f); for (j = 0; j < 64; j++) { for (k = 0; k < 4; k++) { uint8 x; event = &EVENT(i, k, j); event->note = libxmp_period_to_note(hio_read16b(f)); x = hio_read8(f); event->ins = x >> 4; event->fxt = x & 0x0f; event->fxp = hio_read8(f); switch (event->fxt) { case 0x00: /* arpeggio */ case 0x01: /* slide up */ case 0x02: /* slide down */ case 0x03: /* portamento */ case 0x04: /* vibrato? */ case 0x0c: /* volume */ break; /* ...like protracker */ case 0x0d: /* volslide */ case 0x0e: /* volslide */ event->fxt = FX_VOLSLIDE; break; case 0x0f: event->fxt = 192 / event->fxt; break; } } } } /* Load samples */ D_(D_INFO "Instruments : %d ", mod->ins); for (i = 0; i < 31; i++) { char path[PATH_MAX]; char ins_path[256]; char name[256]; HIO_HANDLE *s = NULL; int found; libxmp_get_instrument_path(m, ins_path, 256); found = libxmp_check_filename_case(ins_path, (char *)mod->xxi[i].name, name, 256); if (found) { snprintf(path, PATH_MAX, "%s/%s", ins_path, name); if ((s = hio_open(path, "rb"))) { mod->xxs[i].len = hio_size(s); } } if (mod->xxs[i].len > 0) { mod->xxi[i].nsm = 1; } if (!strlen((char *)mod->xxi[i].name) && !mod->xxs[i].len) { if (s != NULL) { hio_close(s); } continue; } D_(D_INFO "[%2X] %-32.32s %04x %04x %04x %c V%02x", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol); if (s != NULL) { int ret = libxmp_load_sample(m, s, 0, &mod->xxs[i], NULL); hio_close(s); if (ret < 0) { return -1; } } } return 0; } libxmp-4.4.1/src/loaders/mfp_load.c0000664000175000017500000001427512774567167017043 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * A module packer created by Shaun Southern. Samples are stored in a * separate file. File prefixes are mfp for song and smp for samples. For * more information see http://www.exotica.org.uk/wiki/Magnetic_Fields_Packer */ #include "loader.h" #include #include #ifdef __native_client__ #include #else #include #endif #include static int mfp_test(HIO_HANDLE *, char *, const int); static int mfp_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mfp = { "Magnetic Fields Packer", mfp_test, mfp_load }; static int mfp_test(HIO_HANDLE *f, char *t, const int start) { uint8 buf[384]; int i, len, lps, lsz; if (HIO_HANDLE_TYPE(f) != HIO_HANDLE_TYPE_FILE) return -1; if (hio_read(buf, 1, 384, f) < 384) return -1; /* check restart byte */ if (buf[249] != 0x7f) return -1; for (i = 0; i < 31; i++) { /* check size */ len = readmem16b(buf + i * 8); if (len > 0x7fff) return -1; /* check finetune */ if (buf[i * 8 + 2] & 0xf0) return -1; /* check volume */ if (buf[i * 8 + 3] > 0x40) return -1; /* check loop start */ lps = readmem16b(buf + i * 8 + 4); if (lps > len) return -1; /* check loop size */ lsz = readmem16b(buf + i * 8 + 6); if (lps + lsz - 1 > len) return -1; if (len > 0 && lsz == 0) return -1; } if (buf[248] != readmem16b(buf + 378)) return -1; if (readmem16b(buf + 378) != readmem16b(buf + 380)) return -1; libxmp_read_title(f, t, 0); return 0; } static int mfp_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k, x, y; struct xmp_event *event; struct stat st; char smp_filename[PATH_MAX]; HIO_HANDLE *s; int size1 /*, size2*/; int pat_addr, pat_table[128][4]; uint8 buf[1024], mod_event[4]; int row; LOAD_INIT(); libxmp_set_type(m, "Magnetic Fields Packer"); MODULE_INFO(); mod->chn = 4; mod->ins = mod->smp = 31; if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < 31; i++) { int loop_size; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * hio_read16b(f); mod->xxi[i].sub[0].fin = (int8)(hio_read8(f) << 4); mod->xxi[i].sub[0].vol = hio_read8(f); mod->xxs[i].lps = 2 * hio_read16b(f); loop_size = hio_read16b(f); mod->xxs[i].lpe = mod->xxs[i].lps + 2 * loop_size; mod->xxs[i].flg = loop_size > 1 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].rls = 0xfff; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; D_(D_INFO "[%2X] %04x %04x %04x %c V%02x %+d", i, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); } mod->len = mod->pat = hio_read8(f); hio_read8(f); /* restart */ for (i = 0; i < 128; i++) { mod->xxo[i] = hio_read8(f); } if (hio_error(f)) { return -1; } mod->trk = mod->pat * mod->chn; /* Read and convert patterns */ if (libxmp_init_pattern(mod) < 0) return -1; size1 = hio_read16b(f); /* size2 = */ hio_read16b(f); for (i = 0; i < size1; i++) { /* Read pattern table */ for (j = 0; j < 4; j++) { pat_table[i][j] = hio_read16b(f); } } D_(D_INFO "Stored patterns: %d ", mod->pat); pat_addr = hio_tell(f); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < 4; j++) { hio_seek(f, pat_addr + pat_table[i][j], SEEK_SET); hio_read(buf, 1, 1024, f); for (row = k = 0; k < 4; k++) { for (x = 0; x < 4; x++) { for (y = 0; y < 4; y++, row++) { event = &EVENT(i, j, row); memcpy(mod_event, &buf[buf[buf[buf[k] + x] + y] * 2], 4); libxmp_decode_protracker_event(event, mod_event); } } } } } /* Read samples */ D_(D_INFO "Loading samples: %d", mod->ins); /* first check smp.filename */ if (strlen(m->basename) < 5 || m->basename[3] != '.') { fprintf(stderr, "libxmp: invalid filename %s\n", m->basename); goto err; } m->basename[0] = 's'; m->basename[1] = 'm'; m->basename[2] = 'p'; snprintf(smp_filename, PATH_MAX, "%s%s", m->dirname, m->basename); if (stat(smp_filename, &st) < 0) { /* handle .set filenames like in Kid Chaos*/ char *x; if (strchr(m->basename, '-')) { if ((x = strrchr(smp_filename, '-'))) strcpy(x, ".set"); } if (stat(smp_filename, &st) < 0) { fprintf(stderr, "libxmp: missing file %s\n", smp_filename); goto err; } } if ((s = hio_open(smp_filename, "rb")) == NULL) { fprintf(stderr, "libxmp: can't open sample file %s\n", smp_filename); goto err; } for (i = 0; i < mod->ins; i++) { if (libxmp_load_sample(m, s, SAMPLE_FLAG_FULLREP, &mod->xxs[mod->xxi[i].sub[0].sid], NULL) < 0) { free(s); return -1; } } hio_close(s); m->period_type = PERIOD_MODRNG; return 0; err: for (i = 0; i < mod->ins; i++) { mod->xxi[i].nsm = 0; memset(&mod->xxs[i], 0, sizeof(struct xmp_sample)); } return 0; } libxmp-4.4.1/src/loaders/s3m_load.c0000664000175000017500000004167112774567167016763 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Tue, 30 Jun 1998 20:23:11 +0200 * Reported by John v/d Kamp : * I have this song from Purple Motion called wcharts.s3m, the global * volume was set to 0, creating a devide by 0 error in xmp. There should * be an extra test if it's 0 or not. * * Claudio's fix: global volume ignored */ /* * Sat, 29 Aug 1998 18:50:43 -0500 (CDT) * Reported by Joel Jordan : * S3M files support tempos outside the ranges defined by xmp (that is, * the MOD/XM tempo ranges). S3M's can have tempos from 0 to 255 and speeds * from 0 to 255 as well, since these are handled with separate effects * unlike the MOD format. This becomes an issue in such songs as Skaven's * "Catch that Goblin", which uses speeds above 0x1f. * * Claudio's fix: FX_S3M_SPEED added. S3M supports speeds from 0 to 255 and * tempos from 32 to 255 (S3M speed == xmp tempo, S3M tempo == xmp BPM). */ /* Wed, 21 Oct 1998 15:03:44 -0500 Geoff Reedy * It appears that xmp has issues loading/playing a specific instrument * used in LUCCA.S3M. * (Fixed by Hipolito in xmp-2.0.0dev34) */ /* * From http://code.pui.ch/2007/02/18/turn-demoscene-modules-into-mp3s/ * The only flaw I noticed [in xmp] is a problem with portamento in Purple * Motion's second reality soundtrack (1:06-1:17) * * Claudio's note: that's a dissonant beating between channels 6 and 7 * starting at pos12, caused by pitchbending effect F25. */ /* * From: Ralf Hoffmann * Date: Wed, 26 Sep 2007 17:12:41 +0200 * ftp://ftp.scenesp.org/pub/compilations/modplanet/normal/bonuscd/artists/ * Iq/return%20of%20litmus.s3m doesn't start playing, just uses 100% cpu, * the number of patterns is unusually high * * Claudio's fix: this module seems to be a bad conversion, bad rip or * simply corrupted since it has many instances of 0x87 instead of 0x00 * in the module and instrument headers. I'm adding a simple workaround * to be able to load/play the module as is, see the fix87() macro below. */ #include "loader.h" #include "s3m.h" #include "period.h" #define MAGIC_SCRM MAGIC4('S','C','R','M') #define MAGIC_SCRI MAGIC4('S','C','R','I') #define MAGIC_SCRS MAGIC4('S','C','R','S') static int s3m_test(HIO_HANDLE *, char *, const int); static int s3m_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_s3m = { "Scream Tracker 3", s3m_test, s3m_load }; static int s3m_test(HIO_HANDLE *f, char *t, const int start) { hio_seek(f, start + 44, SEEK_SET); if (hio_read32b(f) != MAGIC_SCRM) return -1; hio_seek(f, start + 29, SEEK_SET); if (hio_read8(f) != 0x10) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 28); return 0; } #define NONE 0xff #define FX_S3M_EXTENDED 0xfe #define fix87(x) do { \ int i; for (i = 0; i < sizeof(x); i++) { \ if (*((uint8 *)&x + i) == 0x87) *((uint8 *)&x + i) = 0; } \ } while (0) /* Effect conversion table */ static const uint8 fx[] = { NONE, FX_S3M_SPEED, /* Axx Set speed to xx (the default is 06) */ FX_JUMP, /* Bxx Jump to order xx (hexadecimal) */ FX_BREAK, /* Cxx Break pattern to row xx (decimal) */ FX_VOLSLIDE, /* Dxy Volume slide down by y/up by x */ FX_PORTA_DN, /* Exx Slide down by xx */ FX_PORTA_UP, /* Fxx Slide up by xx */ FX_TONEPORTA, /* Gxx Tone portamento with speed xx */ FX_VIBRATO, /* Hxy Vibrato with speed x and depth y */ FX_TREMOR, /* Ixy Tremor with ontime x and offtime y */ FX_S3M_ARPEGGIO, /* Jxy Arpeggio with halfnote additions */ FX_VIBRA_VSLIDE, /* Kxy Dual command: H00 and Dxy */ FX_TONE_VSLIDE, /* Lxy Dual command: G00 and Dxy */ NONE, NONE, FX_OFFSET, /* Oxy Set sample offset */ NONE, FX_MULTI_RETRIG, /* Qxy Retrig (+volumeslide) note */ FX_TREMOLO, /* Rxy Tremolo with speed x and depth y */ FX_S3M_EXTENDED, /* Sxx (misc effects) */ FX_S3M_BPM, /* Txx Tempo = xx (hex) */ FX_FINE_VIBRATO, /* Uxx Fine vibrato */ FX_GLOBALVOL, /* Vxx Set global volume */ NONE, FX_SETPAN, /* Xxx Set pan */ NONE, NONE }; /* Effect translation */ static void xlat_fx(int c, struct xmp_event *e) { uint8 h = MSN(e->fxp), l = LSN(e->fxp); if (e->fxt > 26) { D_(D_WARN "invalid effect %02x", e->fxt); e->fxt = e->fxp = 0; return; } switch (e->fxt = fx[e->fxt]) { case FX_S3M_BPM: if (e->fxp < 0x20) { e->fxp = e->fxt = 0; } break; case FX_S3M_EXTENDED: /* Extended effects */ e->fxt = FX_EXTENDED; switch (h) { case 0x1: /* Glissando */ e->fxp = LSN(e->fxp) | (EX_GLISS << 4); break; case 0x2: /* Finetune */ e->fxp = ((LSN(e->fxp) - 8) & 0x0f) | (EX_FINETUNE << 4); break; case 0x3: /* Vibrato wave */ e->fxp = LSN(e->fxp) | (EX_VIBRATO_WF << 4); break; case 0x4: /* Tremolo wave */ e->fxp = LSN(e->fxp) | (EX_TREMOLO_WF << 4); break; case 0x5: case 0x6: case 0x7: case 0x9: case 0xa: /* Ignore */ e->fxt = e->fxp = 0; break; case 0x8: /* Set pan */ e->fxt = FX_SETPAN; e->fxp = l << 4; break; case 0xb: /* Pattern loop */ e->fxp = LSN(e->fxp) | (EX_PATTERN_LOOP << 4); break; case 0xc: if (!l) e->fxt = e->fxp = 0; } break; case FX_SETPAN: /* Saga Musix says: "The X effect in S3M files is not * exclusive to IT and clones. You will find tons of S3Ms made * with ST3 itself using this effect (and relying on an * external player being used). X in S3M also behaves * differently than in IT, which your code does not seem to * handle: X00 - X80 is left... right, XA4 is surround (like * S91 in IT), other values are not supposed to do anything. */ if (e->fxp == 0xa4) { // surround e->fxt = FX_SURROUND; e->fxp = 1; } else { int pan = ((int)e->fxp) << 1; if (pan > 0xff) { pan = 0xff; } e->fxp = pan; } break; case NONE: /* No effect */ e->fxt = e->fxp = 0; break; } } static int s3m_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int c, r, i; struct xmp_event *event = 0, dummy; struct s3m_file_header sfh; struct s3m_instrument_header sih; #ifndef LIBXMP_CORE_PLAYER struct s3m_adlib_header sah; char tracker_name[40]; int quirk87 = 0; #endif int pat_len; uint8 n, b, x8; uint16 *pp_ins; /* Parapointers to instruments */ uint16 *pp_pat; /* Parapointers to patterns */ int ret; LOAD_INIT(); hio_read(&sfh.name, 28, 1, f); /* Song name */ hio_read8(f); /* 0x1a */ sfh.type = hio_read8(f); /* File type */ hio_read16l(f); /* Reserved */ sfh.ordnum = hio_read16l(f); /* Number of orders (must be even) */ sfh.insnum = hio_read16l(f); /* Number of instruments */ sfh.patnum = hio_read16l(f); /* Number of patterns */ sfh.flags = hio_read16l(f); /* Flags */ sfh.version = hio_read16l(f); /* Tracker ID and version */ sfh.ffi = hio_read16l(f); /* File format information */ /* Sanity check */ if (hio_error(f)) { goto err; } if (sfh.ffi != 1 && sfh.ffi != 2) { goto err; } if (sfh.ordnum > 255 || sfh.insnum > 255 || sfh.patnum > 255) { goto err; } sfh.magic = hio_read32b(f); /* 'SCRM' */ sfh.gv = hio_read8(f); /* Global volume */ sfh.is = hio_read8(f); /* Initial speed */ sfh.it = hio_read8(f); /* Initial tempo */ sfh.mv = hio_read8(f); /* Master volume */ sfh.uc = hio_read8(f); /* Ultra click removal */ sfh.dp = hio_read8(f); /* Default pan positions if 0xfc */ hio_read32l(f); /* Reserved */ hio_read32l(f); /* Reserved */ sfh.special = hio_read16l(f); /* Ptr to special custom data */ hio_read(sfh.chset, 32, 1, f); /* Channel settings */ if (hio_error(f)) { goto err; } #if 0 if (sfh.magic != MAGIC_SCRM) return -1; #endif #ifndef LIBXMP_CORE_PLAYER /* S3M anomaly in return_of_litmus.s3m */ if (sfh.version == 0x1301 && sfh.name[27] == 0x87) quirk87 = 1; if (quirk87) { fix87(sfh.name); fix87(sfh.patnum); fix87(sfh.flags); } #endif libxmp_copy_adjust(mod->name, sfh.name, 28); pp_ins = calloc(2, sfh.insnum); if (pp_ins == NULL) goto err; pp_pat = calloc(2, sfh.patnum); if (pp_pat == NULL) goto err2; if (sfh.flags & S3M_AMIGA_RANGE) m->period_type = PERIOD_MODRNG; if (sfh.flags & S3M_ST300_VOLS) m->quirk |= QUIRK_VSALL; /* m->volbase = 4096 / sfh.gv; */ mod->spd = sfh.is; mod->bpm = sfh.it; mod->chn = 0; for (i = 0; i < 32; i++) { if (sfh.chset[i] == S3M_CH_OFF) continue; mod->chn = i + 1; if (sfh.mv & 0x80) { /* stereo */ int x = sfh.chset[i] & S3M_CH_PAN; mod->xxc[i].pan = (x & 0x0f) < 8 ? 0x30 : 0xc0; } else { mod->xxc[i].pan = 0x80; } } if (sfh.ordnum <= XMP_MAX_MOD_LENGTH) { mod->len = sfh.ordnum; hio_read(mod->xxo, 1, mod->len, f); } else { mod->len = XMP_MAX_MOD_LENGTH; hio_read(mod->xxo, 1, mod->len, f); hio_seek(f, sfh.ordnum - XMP_MAX_MOD_LENGTH, SEEK_CUR); } if (hio_error(f)) { goto err3; } /* Don't trust sfh.patnum */ mod->pat = -1; for (i = 0; i < mod->len; ++i) { if (mod->xxo[i] < 0xfe && mod->xxo[i] > mod->pat) { mod->pat = mod->xxo[i]; } } mod->pat++; if (mod->pat > sfh.patnum) mod->pat = sfh.patnum; if (mod->pat == 0) goto err3; mod->trk = mod->pat * mod->chn; /* Load and convert header */ mod->ins = sfh.insnum; mod->smp = mod->ins; for (i = 0; i < sfh.insnum; i++) pp_ins[i] = hio_read16l(f); for (i = 0; i < sfh.patnum; i++) pp_pat[i] = hio_read16l(f); /* Default pan positions */ for (i = 0, sfh.dp -= 0xfc; !sfh.dp /* && n */ && (i < 32); i++) { uint8 x = hio_read8(f); if (x & S3M_PAN_SET) { mod->xxc[i].pan = (x << 4) & 0xff; } else { mod->xxc[i].pan = sfh.mv % 0x80 ? 0x30 + 0xa0 * (i & 1) : 0x80; } } m->c4rate = C4_NTSC_RATE; if (sfh.version == 0x1300) { m->quirk |= QUIRK_VSALL; } #ifndef LIBXMP_CORE_PLAYER switch (sfh.version >> 12) { case 1: snprintf(tracker_name, 40, "Scream Tracker %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); m->quirk |= QUIRK_ST3BUGS; break; case 2: snprintf(tracker_name, 40, "Imago Orpheus %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); break; case 3: if (sfh.version == 0x3216) { strcpy(tracker_name, "Impulse Tracker 2.14v3"); } else if (sfh.version == 0x3217) { strcpy(tracker_name, "Impulse Tracker 2.14v5"); } else { snprintf(tracker_name, 40, "Impulse Tracker %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); } break; case 5: snprintf(tracker_name, 40, "OpenMPT %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); m->quirk |= QUIRK_ST3BUGS; break; case 4: if (sfh.version != 0x4100) { snprintf(tracker_name, 40, "Schism Tracker %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); break; } /* fall through */ case 6: snprintf(tracker_name, 40, "BeRoTracker %d.%02x", (sfh.version & 0x0f00) >> 8, sfh.version & 0xff); break; default: snprintf(tracker_name, 40, "unknown (%04x)", sfh.version); } libxmp_set_type(m, "%s S3M", tracker_name); #else libxmp_set_type(m, "Scream Tracker 3"); m->quirk |= QUIRK_ST3BUGS; #endif MODULE_INFO(); if (libxmp_init_pattern(mod) < 0) goto err3; /* Read patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) goto err3; if (pp_pat[i] == 0) continue; hio_seek(f, start + pp_pat[i] * 16, SEEK_SET); r = 0; pat_len = hio_read16l(f) - 2; while (pat_len >= 0 && r < mod->xxp[i]->rows) { b = hio_read8(f); if (hio_error(f)) { goto err3; } if (b == S3M_EOR) { r++; continue; } c = b & S3M_CH_MASK; event = c >= mod->chn ? &dummy : &EVENT(i, c, r); if (b & S3M_NI_FOLLOW) { switch (n = hio_read8(f)) { case 255: n = 0; break; /* Empty note */ case 254: n = XMP_KEY_OFF; break; /* Key off */ default: n = 13 + 12 * MSN(n) + LSN(n); } event->note = n; event->ins = hio_read8(f); pat_len -= 2; } if (b & S3M_VOL_FOLLOWS) { event->vol = hio_read8(f) + 1; pat_len--; } if (b & S3M_FX_FOLLOWS) { event->fxt = hio_read8(f); event->fxp = hio_read8(f); xlat_fx(c, event); pat_len -= 2; } } } D_(D_INFO "Stereo enabled: %s", sfh.mv & 0x80 ? "yes" : "no"); D_(D_INFO "Pan settings: %s", sfh.dp ? "no" : "yes"); if (libxmp_init_instrument(m) < 0) goto err3; /* Read and convert instruments and samples */ D_(D_INFO "Instruments: %d", mod->ins); for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; xxi->sub = calloc(sizeof(struct xmp_subinstrument), 1); if (xxi->sub == NULL) { goto err3; } sub = &xxi->sub[0]; hio_seek(f, start + pp_ins[i] * 16, SEEK_SET); x8 = hio_read8(f); sub->pan = 0x80; sub->sid = i; if (x8 >= 2) { #ifndef LIBXMP_CORE_PLAYER /* OPL2 FM instrument */ hio_read(&sah.dosname, 12, 1, f); /* DOS file name */ hio_read(&sah.rsvd1, 3, 1, f); /* 0x00 0x00 0x00 */ hio_read(&sah.reg, 12, 1, f); /* Adlib registers */ sah.vol = hio_read8(f); sah.dsk = hio_read8(f); hio_read16l(f); sah.c2spd = hio_read16l(f); /* C 4 speed */ hio_read16l(f); hio_read(&sah.rsvd4, 12, 1, f); /* Reserved */ hio_read(&sah.name, 28, 1, f); /* Instrument name */ sah.magic = hio_read32b(f); /* 'SCRI' */ if (sah.magic != MAGIC_SCRI) { D_(D_CRIT "error: FM instrument magic"); goto err3; } sah.magic = 0; libxmp_instrument_name(mod, i, sah.name, 28); xxi->nsm = 1; sub->vol = sah.vol; libxmp_c2spd_to_note(sah.c2spd, &sub->xpo, &sub->fin); sub->xpo += 12; ret = libxmp_load_sample(m, f, SAMPLE_FLAG_ADLIB, xxs, (char *)&sah.reg); if (ret < 0) goto err3; D_(D_INFO "[%2X] %-28.28s", i, xxi->name); continue; #else goto err3; #endif } hio_read(&sih.dosname, 13, 1, f); /* DOS file name */ sih.memseg = hio_read16l(f); /* Pointer to sample data */ sih.length = hio_read32l(f); /* Length */ #if 0 /* ST3 limit */ if ((sfh.version >> 12) == 1 && sih.length > 64000) sih.length = 64000; #endif if (sih.length > MAX_SAMPLE_SIZE) { goto err3; } sih.loopbeg = hio_read32l(f); /* Loop begin */ sih.loopend = hio_read32l(f); /* Loop end */ sih.vol = hio_read8(f); /* Volume */ sih.rsvd1 = hio_read8(f); /* Reserved */ sih.pack = hio_read8(f); /* Packing type (not used) */ sih.flags = hio_read8(f); /* Loop/stereo/16bit flags */ sih.c2spd = hio_read16l(f); /* C 4 speed */ sih.rsvd2 = hio_read16l(f); /* Reserved */ hio_read(&sih.rsvd3, 4, 1, f); /* Reserved */ sih.int_gp = hio_read16l(f); /* Internal - GUS pointer */ sih.int_512 = hio_read16l(f); /* Internal - SB pointer */ sih.int_last = hio_read32l(f); /* Internal - SB index */ hio_read(&sih.name, 28, 1, f); /* Instrument name */ sih.magic = hio_read32b(f); /* 'SCRS' */ if (x8 == 1 && sih.magic != MAGIC_SCRS) { D_(D_CRIT "error: instrument magic"); goto err3; } #ifndef LIBXMP_CORE_PLAYER if (quirk87) { fix87(sih.length); fix87(sih.loopbeg); fix87(sih.loopend); fix87(sih.flags); } #endif xxs->len = sih.length; xxi->nsm = sih.length > 0 ? 1 : 0; xxs->lps = sih.loopbeg; xxs->lpe = sih.loopend; xxs->flg = sih.flags & 1 ? XMP_SAMPLE_LOOP : 0; if (sih.flags & 4) { xxs->flg |= XMP_SAMPLE_16BIT; } sub->vol = sih.vol; sih.magic = 0; libxmp_instrument_name(mod, i, sih.name, 28); D_(D_INFO "[%2X] %-28.28s %04x%c%04x %04x %c V%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ', xxs->lps, mod->xxs[i].lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sih.c2spd); libxmp_c2spd_to_note(sih.c2spd, &sub->xpo, &sub->fin); hio_seek(f, start + 16L * sih.memseg, SEEK_SET); ret = libxmp_load_sample(m, f, sfh.ffi == 1 ? 0 : SAMPLE_FLAG_UNS, xxs, NULL); if (ret < 0) { goto err3; } } free(pp_pat); free(pp_ins); m->quirk |= QUIRKS_ST3 | QUIRK_ARPMEM; m->read_event_type = READ_EVENT_ST3; return 0; err3: free(pp_pat); err2: free(pp_ins); err: return -1; } libxmp-4.4.1/src/loaders/ptm_load.c0000664000175000017500000002241312774567167017052 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "period.h" #define PTM_CH_MASK 0x1f #define PTM_NI_FOLLOW 0x20 #define PTM_VOL_FOLLOWS 0x80 #define PTM_FX_FOLLOWS 0x40 struct ptm_file_header { uint8 name[28]; /* Song name */ uint8 doseof; /* 0x1a */ uint8 vermin; /* Minor version */ uint8 vermaj; /* Major type */ uint8 rsvd1; /* Reserved */ uint16 ordnum; /* Number of orders (must be even) */ uint16 insnum; /* Number of instruments */ uint16 patnum; /* Number of patterns */ uint16 chnnum; /* Number of channels */ uint16 flags; /* Flags (set to 0) */ uint16 rsvd2; /* Reserved */ uint32 magic; /* 'PTMF' */ uint8 rsvd3[16]; /* Reserved */ uint8 chset[32]; /* Channel settings */ uint8 order[256]; /* Orders */ uint16 patseg[128]; }; struct ptm_instrument_header { uint8 type; /* Sample type */ uint8 dosname[12]; /* DOS file name */ uint8 vol; /* Volume */ uint16 c4spd; /* C4 speed */ uint16 smpseg; /* Sample segment (not used) */ uint32 smpofs; /* Sample offset */ uint32 length; /* Length */ uint32 loopbeg; /* Loop begin */ uint32 loopend; /* Loop end */ uint32 gusbeg; /* GUS begin address */ uint32 guslps; /* GUS loop start address */ uint32 guslpe; /* GUS loop end address */ uint8 gusflg; /* GUS loop flags */ uint8 rsvd1; /* Reserved */ uint8 name[28]; /* Instrument name */ uint32 magic; /* 'PTMS' */ }; #define MAGIC_PTMF MAGIC4('P','T','M','F') static int ptm_test(HIO_HANDLE *, char *, const int); static int ptm_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_ptm = { "Poly Tracker", ptm_test, ptm_load }; static int ptm_test(HIO_HANDLE *f, char *t, const int start) { hio_seek(f, start + 44, SEEK_SET); if (hio_read32b(f) != MAGIC_PTMF) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 28); return 0; } static const int ptm_vol[] = { 0, 5, 8, 10, 12, 14, 15, 17, 18, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 46, 47, 48, 49, 49, 50, 51, 51, 52, 53, 54, 54, 55, 56, 56, 57, 58, 58, 59, 59, 60, 61, 61, 62, 63, 63, 64, 64 }; static int ptm_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int c, r, i, smp_ofs[256]; struct xmp_event *event; struct ptm_file_header pfh; struct ptm_instrument_header pih; uint8 n, b; LOAD_INIT(); /* Load and convert header */ hio_read(&pfh.name, 28, 1, f); /* Song name */ pfh.doseof = hio_read8(f); /* 0x1a */ pfh.vermin = hio_read8(f); /* Minor version */ pfh.vermaj = hio_read8(f); /* Major type */ pfh.rsvd1 = hio_read8(f); /* Reserved */ pfh.ordnum = hio_read16l(f); /* Number of orders (must be even) */ pfh.insnum = hio_read16l(f); /* Number of instruments */ pfh.patnum = hio_read16l(f); /* Number of patterns */ pfh.chnnum = hio_read16l(f); /* Number of channels */ pfh.flags = hio_read16l(f); /* Flags (set to 0) */ pfh.rsvd2 = hio_read16l(f); /* Reserved */ pfh.magic = hio_read32b(f); /* 'PTMF' */ if (pfh.magic != MAGIC_PTMF) return -1; /* Sanity check */ if (pfh.ordnum > 256 || pfh.insnum > 255 || pfh.patnum > 128 || pfh.chnnum > 32) { return -1; } hio_read(&pfh.rsvd3, 16, 1, f); /* Reserved */ hio_read(&pfh.chset, 32, 1, f); /* Channel settings */ hio_read(&pfh.order, 256, 1, f); /* Orders */ for (i = 0; i < 128; i++) pfh.patseg[i] = hio_read16l(f); mod->len = pfh.ordnum; mod->ins = pfh.insnum; mod->pat = pfh.patnum; mod->chn = pfh.chnnum; mod->trk = mod->pat * mod->chn; mod->smp = mod->ins; mod->spd = 6; mod->bpm = 125; memcpy(mod->xxo, pfh.order, 256); m->c4rate = C4_NTSC_RATE; libxmp_copy_adjust(mod->name, pfh.name, 28); libxmp_set_type(m, "Poly Tracker PTM %d.%02x", pfh.vermaj, pfh.vermin); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) { return -1; } /* Read and convert instruments and samples */ for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; pih.type = hio_read8(f); /* Sample type */ hio_read(&pih.dosname, 12, 1, f); /* DOS file name */ pih.vol = hio_read8(f); /* Volume */ pih.c4spd = hio_read16l(f); /* C4 speed */ pih.smpseg = hio_read16l(f); /* Sample segment (not used) */ pih.smpofs = hio_read32l(f); /* Sample offset */ pih.length = hio_read32l(f); /* Length */ pih.loopbeg = hio_read32l(f); /* Loop begin */ pih.loopend = hio_read32l(f); /* Loop end */ pih.gusbeg = hio_read32l(f); /* GUS begin address */ pih.guslps = hio_read32l(f); /* GUS loop start address */ pih.guslpe = hio_read32l(f); /* GUS loop end address */ pih.gusflg = hio_read8(f); /* GUS loop flags */ pih.rsvd1 = hio_read8(f); /* Reserved */ hio_read(&pih.name, 28, 1, f); /* Instrument name */ pih.magic = hio_read32b(f); /* 'PTMS' */ if (hio_error(f)) { return -1; } if ((pih.type & 3) != 1) continue; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) { return -1; } sub = &xxi->sub[0]; smp_ofs[i] = pih.smpofs; xxs->len = pih.length; xxs->lps = pih.loopbeg; xxs->lpe = pih.loopend; if (mod->xxs[i].len > 0) { mod->xxi[i].nsm = 1; } xxs->flg = 0; if (pih.type & 0x04) { xxs->flg |= XMP_SAMPLE_LOOP; } if (pih.type & 0x08) { xxs->flg |= XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR; } if (pih.type & 0x10) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } sub->vol = pih.vol; sub->pan = 0x80; sub->sid = i; pih.magic = 0; libxmp_instrument_name(mod, i, pih.name, 28); D_(D_INFO "[%2X] %-28.28s %05x%c%05x %05x %c V%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, pih.type & 0x10 ? '+' : ' ', xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, pih.c4spd); /* Convert C4SPD to relnote/finetune */ libxmp_c2spd_to_note(pih.c4spd, &sub->xpo, &sub->fin); } if (libxmp_init_pattern(mod) < 0) return -1; /* Read patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (!pfh.patseg[i]) continue; if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; hio_seek(f, start + 16L * pfh.patseg[i], SEEK_SET); r = 0; while (r < 64) { b = hio_read8(f); if (!b) { r++; continue; } c = b & PTM_CH_MASK; if (c >= mod->chn) continue; event = &EVENT(i, c, r); if (b & PTM_NI_FOLLOW) { n = hio_read8(f); switch (n) { case 255: n = 0; break; /* Empty note */ case 254: n = XMP_KEY_OFF; break; /* Key off */ default: n += 12; } event->note = n; event->ins = hio_read8(f); } if (b & PTM_FX_FOLLOWS) { event->fxt = hio_read8(f); event->fxp = hio_read8(f); if (event->fxt > 0x17) event->fxt = event->fxp = 0; switch (event->fxt) { case 0x0e: /* Extended effect */ if (MSN(event->fxp) == 0x8) { /* Pan set */ event->fxt = FX_SETPAN; event->fxp = LSN(event->fxp) << 4; } break; case 0x10: /* Set global volume */ event->fxt = FX_GLOBALVOL; break; case 0x11: /* Multi retrig */ event->fxt = FX_MULTI_RETRIG; break; case 0x12: /* Fine vibrato */ event->fxt = FX_FINE_VIBRATO; break; case 0x13: /* Note slide down */ event->fxt = FX_NSLIDE_DN; break; case 0x14: /* Note slide up */ event->fxt = FX_NSLIDE_UP; break; case 0x15: /* Note slide down + retrig */ event->fxt = FX_NSLIDE_R_DN; break; case 0x16: /* Note slide up + retrig */ event->fxt = FX_NSLIDE_R_UP; break; case 0x17: /* Reverse sample */ event->fxt = event->fxp = 0; break; } } if (b & PTM_VOL_FOLLOWS) { event->vol = hio_read8(f) + 1; } } } D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (mod->xxi[i].nsm == 0) continue; if (mod->xxs[i].len == 0) continue; hio_seek(f, start + smp_ofs[i], SEEK_SET); if (libxmp_load_sample(m, f, SAMPLE_FLAG_8BDIFF, &mod->xxs[i], NULL) < 0) return -1; } m->vol_table = (int *)ptm_vol; for (i = 0; i < mod->chn; i++) mod->xxc[i].pan = pfh.chset[i] << 4; m->quirk |= QUIRKS_ST3; m->read_event_type = READ_EVENT_ST3; return 0; } libxmp-4.4.1/src/loaders/ult_load.c0000664000175000017500000002261212774567167017057 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Based on the format description by FreeJack of The Elven Nation * * The loader recognizes four subformats: * - MAS_UTrack_V001: Ultra Tracker version < 1.4 * - MAS_UTrack_V002: Ultra Tracker version 1.4 * - MAS_UTrack_V003: Ultra Tracker version 1.5 * - MAS_UTrack_V004: Ultra Tracker version 1.6 */ #include "loader.h" #include "period.h" static int ult_test (HIO_HANDLE *, char *, const int); static int ult_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_ult = { "Ultra Tracker", ult_test, ult_load }; static int ult_test(HIO_HANDLE *f, char *t, const int start) { char buf[15]; if (hio_read(buf, 1, 15, f) < 15) return -1; if (memcmp(buf, "MAS_UTrack_V000", 14)) return -1; if (buf[14] < '0' || buf[14] > '4') return -1; libxmp_read_title(f, t, 32); return 0; } #define KEEP_TONEPORTA 32 /* Rows to keep portamento effect */ struct ult_header { uint8 magic[15]; /* 'MAS_UTrack_V00x' */ uint8 name[32]; /* Song name */ uint8 msgsize; /* ver < 1.4: zero */ }; struct ult_header2 { uint8 order[256]; /* Orders */ uint8 channels; /* Number of channels - 1 */ uint8 patterns; /* Number of patterns - 1 */ }; struct ult_instrument { uint8 name[32]; /* Instrument name */ uint8 dosname[12]; /* DOS file name */ uint32 loop_start; /* Loop start */ uint32 loopend; /* Loop end */ uint32 sizestart; /* Sample size is sizeend - sizestart */ uint32 sizeend; uint8 volume; /* Volume (log; ver >= 1.4 linear) */ uint8 bidiloop; /* Sample loop flags */ uint16 finetune; /* Finetune */ uint16 c2spd; /* C2 frequency */ }; struct ult_event { /* uint8 note; */ uint8 ins; uint8 fxt; /* MSN = fxt, LSN = f2t */ uint8 f2p; /* Secondary comes first -- little endian! */ uint8 fxp; }; static int ult_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k, ver, cnt; struct xmp_event *event; struct ult_header ufh; struct ult_header2 ufh2; struct ult_instrument uih; struct ult_event ue; char *verstr[4] = { "< 1.4", "1.4", "1.5", "1.6" }; int keep_porta1 = 0, keep_porta2 = 0; uint8 x8; LOAD_INIT(); hio_read(&ufh.magic, 15, 1, f); hio_read(&ufh.name, 32, 1, f); ufh.msgsize = hio_read8(f); ver = ufh.magic[14] - '0'; strncpy(mod->name, (char *)ufh.name, 32); ufh.name[0] = 0; libxmp_set_type(m, "Ultra Tracker %s ULT V%04d", verstr[ver - 1], ver); m->c4rate = C4_NTSC_RATE; MODULE_INFO(); hio_seek(f, ufh.msgsize * 32, SEEK_CUR); mod->ins = mod->smp = hio_read8(f); /* mod->flg |= XXM_FLG_LINEAR; */ /* Read and convert instruments */ if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->ins); for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; hio_read(&uih.name, 32, 1, f); hio_read(&uih.dosname, 12, 1, f); uih.loop_start = hio_read32l(f); uih.loopend = hio_read32l(f); uih.sizestart = hio_read32l(f); uih.sizeend = hio_read32l(f); uih.volume = hio_read8(f); uih.bidiloop = hio_read8(f); uih.finetune = hio_read16l(f); uih.c2spd = ver < 4 ? 0 : hio_read16l(f); if (ver > 3) { /* Incorrect in ult_form.txt */ uih.c2spd ^= uih.finetune; uih.finetune ^= uih.c2spd; uih.c2spd ^= uih.finetune; } mod->xxs[i].len = uih.sizeend - uih.sizestart; mod->xxs[i].lps = uih.loop_start; mod->xxs[i].lpe = uih.loopend; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; /* BiDi Loop : (Bidirectional Loop) * * UT takes advantage of the Gus's ability to loop a sample in * several different ways. By setting the Bidi Loop, the sample can * be played forward or backwards, looped or not looped. The Bidi * variable also tracks the sample resolution (8 or 16 bit). * * The following table shows the possible values of the Bidi Loop. * Bidi = 0 : No looping, forward playback, 8bit sample * Bidi = 4 : No Looping, forward playback, 16bit sample * Bidi = 8 : Loop Sample, forward playback, 8bit sample * Bidi = 12 : Loop Sample, forward playback, 16bit sample * Bidi = 24 : Loop Sample, reverse playback 8bit sample * Bidi = 28 : Loop Sample, reverse playback, 16bit sample */ /* Claudio's note: I'm ignoring reverse playback for samples */ switch (uih.bidiloop) { case 20: /* Type 20 is in seasons.ult */ case 4: mod->xxs[i].flg = XMP_SAMPLE_16BIT; break; case 8: mod->xxs[i].flg = XMP_SAMPLE_LOOP; break; case 12: mod->xxs[i].flg = XMP_SAMPLE_16BIT | XMP_SAMPLE_LOOP; break; case 24: mod->xxs[i].flg = XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_REVERSE; break; case 28: mod->xxs[i].flg = XMP_SAMPLE_16BIT | XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_REVERSE; break; } /* TODO: Add logarithmic volume support */ mod->xxi[i].sub[0].vol = uih.volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; libxmp_instrument_name(mod, i, uih.name, 24); D_(D_INFO "[%2X] %-32.32s %05x%c%05x %05x %c V%02x F%04x %5d", i, uih.name, mod->xxs[i].len, mod->xxs[i].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, uih.finetune, uih.c2spd); if (ver > 3) libxmp_c2spd_to_note(uih.c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); } hio_read(&ufh2.order, 256, 1, f); ufh2.channels = hio_read8(f); ufh2.patterns = hio_read8(f); for (i = 0; i < 256; i++) { if (ufh2.order[i] == 0xff) break; mod->xxo[i] = ufh2.order[i]; } mod->len = i; mod->chn = ufh2.channels + 1; mod->pat = ufh2.patterns + 1; mod->spd = 6; mod->bpm = 125; mod->trk = mod->chn * mod->pat; for (i = 0; i < mod->chn; i++) { if (ver >= 3) { x8 = hio_read8(f); mod->xxc[i].pan = 255 * x8 / 15; } else { mod->xxc[i].pan = DEFPAN((((i + 1) / 2) % 2) * 0xff); /* ??? */ } } if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); /* Events are stored by channel */ for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; } for (i = 0; i < mod->chn; i++) { for (j = 0; j < 64 * mod->pat; ) { cnt = 1; x8 = hio_read8(f); /* Read note or repeat code (0xfc) */ if (x8 == 0xfc) { cnt = hio_read8(f); /* Read repeat count */ x8 = hio_read8(f); /* Read note */ } hio_read(&ue, 4, 1, f); /* Read rest of the event */ if (cnt == 0) cnt++; for (k = 0; k < cnt; k++, j++) { event = &EVENT (j >> 6, i , j & 0x3f); memset(event, 0, sizeof (struct xmp_event)); if (x8) event->note = x8 + 36; event->ins = ue.ins; event->fxt = MSN (ue.fxt); event->f2t = LSN (ue.fxt); event->fxp = ue.fxp; event->f2p = ue.f2p; switch (event->fxt) { case 0x00: /* */ if (event->fxp) keep_porta1 = 0; if (keep_porta1) { event->fxt = 0x03; keep_porta1--; } break; case 0x03: /* Portamento kludge */ keep_porta1 = KEEP_TONEPORTA; break; case 0x05: /* 'Special' effect */ case 0x06: /* Reserved */ event->fxt = event->fxp = 0; break; case 0x0b: /* Pan */ event->fxt = FX_SETPAN; event->fxp <<= 4; break; case 0x09: /* Sample offset */ /* TODO: fine sample offset */ event->fxp <<= 2; break; } switch (event->f2t) { case 0x00: /* */ if (event->f2p) keep_porta2 = 0; if (keep_porta2) { event->f2t = 0x03; keep_porta2--; } break; case 0x03: /* Portamento kludge */ keep_porta2 = KEEP_TONEPORTA; break; case 0x05: /* 'Special' effect */ case 0x06: /* Reserved */ event->f2t = event->f2p = 0; break; case 0x0b: /* Pan */ event->f2t = FX_SETPAN; event->f2p <<= 4; break; case 0x09: /* Sample offset */ /* TODO: fine sample offset */ event->f2p <<= 2; break; } } } } D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (!mod->xxs[i].len) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } m->volbase = 0x100; return 0; } libxmp-4.4.1/src/loaders/asylum_load.c0000664000175000017500000001055012774567167017563 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Based on AMF->MOD converter written by Mr. P / Powersource, 1995 */ #include "loader.h" #include "period.h" static int asylum_test(HIO_HANDLE *, char *, const int); static int asylum_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_asylum = { "Asylum Music Format v1.0", asylum_test, asylum_load }; static int asylum_test(HIO_HANDLE *f, char *t, const int start) { char buf[32]; if (hio_read(buf, 1, 32, f) < 32) return -1; if (memcmp(buf, "ASYLUM Music Format V1.0\0\0\0\0\0\0\0\0", 32)) return -1; libxmp_read_title(f, t, 0); return 0; } static int asylum_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event; int i, j; LOAD_INIT(); hio_seek(f, 32, SEEK_CUR); /* skip magic */ mod->spd = hio_read8(f); /* initial speed */ mod->bpm = hio_read8(f); /* initial BPM */ mod->ins = hio_read8(f); /* number of instruments */ mod->pat = hio_read8(f); /* number of patterns */ mod->len = hio_read8(f); /* module length */ hio_read8(f); hio_read(mod->xxo, 1, mod->len, f); /* read orders */ hio_seek(f, start + 294, SEEK_SET); mod->chn = 8; mod->smp = mod->ins; mod->trk = mod->pat * mod->chn; snprintf(mod->type, XMP_NAME_SIZE, "Asylum Music Format v1.0"); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; /* Read and convert instruments and samples */ for (i = 0; i < mod->ins; i++) { uint8 insbuf[37]; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) { return -1; } if (hio_read(insbuf, 1, 37, f) != 37) { return -1; } libxmp_instrument_name(mod, i, insbuf, 22); mod->xxi[i].sub[0].fin = (int8)(insbuf[22] << 4); mod->xxi[i].sub[0].vol = insbuf[23]; mod->xxi[i].sub[0].xpo = (int8)insbuf[24]; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxs[i].len = readmem32l(insbuf + 25); mod->xxs[i].lps = readmem32l(insbuf + 29); mod->xxs[i].lpe = mod->xxs[i].lps + readmem32l(insbuf + 33); mod->xxs[i].flg = mod->xxs[i].lpe > 2 ? XMP_SAMPLE_LOOP : 0; D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin); } hio_seek(f, 37 * (64 - mod->ins), SEEK_CUR); D_(D_INFO "Module length: %d", mod->len); if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < 64 * mod->chn; j++) { uint8 note; event = &EVENT(i, j % mod->chn, j / mod->chn); memset(event, 0, sizeof(struct xmp_event)); note = hio_read8(f); if (note != 0) { event->note = note + 13; } event->ins = hio_read8(f); event->fxt = hio_read8(f); event->fxp = hio_read8(f); if (hio_error(f)) { return -1; } } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len > 1) { if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; mod->xxi[i].nsm = 1; } } return 0; } libxmp-4.4.1/src/loaders/okt_load.c0000664000175000017500000001760312775035311017032 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Based on the format description written by Harald Zappe. * Additional information about Oktalyzer modules from Bernardo * Innocenti's XModule 3.4 sources. */ #include "loader.h" #include "iff.h" static int okt_test(HIO_HANDLE *, char *, const int); static int okt_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_okt = { "Oktalyzer", okt_test, okt_load }; static int okt_test(HIO_HANDLE *f, char *t, const int start) { char magic[8]; if (hio_read(magic, 1, 8, f) < 8) return -1; if (strncmp(magic, "OKTASONG", 8)) return -1; libxmp_read_title(f, t, 0); return 0; } #define OKT_MODE8 0x00 /* 7 bit samples */ #define OKT_MODE4 0x01 /* 8 bit samples */ #define OKT_MODEB 0x02 /* Both */ #define NONE 0xff struct local_data { int mode[36]; int idx[36]; int pattern; int sample; }; static const int fx[] = { NONE, FX_PORTA_UP, /* 1 */ FX_PORTA_DN, /* 2 */ NONE, NONE, NONE, NONE, NONE, NONE, NONE, FX_OKT_ARP3, /* 10 */ FX_OKT_ARP4, /* 11 */ FX_OKT_ARP5, /* 12 */ FX_NSLIDE2_DN, /* 13 */ NONE, NONE, /* 15 - filter */ NONE, FX_NSLIDE2_UP, /* 17 */ NONE, NONE, NONE, FX_NSLIDE_DN, /* 21 */ NONE, NONE, NONE, FX_JUMP, /* 25 */ NONE, NONE, /* 27 - release */ FX_SPEED, /* 28 */ NONE, FX_NSLIDE_UP, /* 30 */ FX_VOLSET /* 31 */ }; static int get_cmod(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; mod->chn = 0; for (i = 0; i < 4; i++) { int pan = (((i + 1) / 2) % 2) * 0xff; int p = 0x80 + (pan - 0x80) * m->defpan / 100; if (hio_read16b(f) == 0) { mod->xxc[mod->chn++].pan = p; } else { mod->xxc[mod->chn].flg |= XMP_CHANNEL_SPLIT | (i << 4); mod->xxc[mod->chn++].pan = p; mod->xxc[mod->chn].flg |= XMP_CHANNEL_SPLIT | (i << 4); mod->xxc[mod->chn++].pan = p; } } return 0; } static int get_samp(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i, j; int looplen; /* Sanity check */ if (size != 36 * 32) return -1; /* Should be always 36 */ mod->ins = size / 32; /* sizeof(struct okt_instrument_header); */ mod->smp = mod->ins; if (libxmp_init_instrument(m) < 0) return -1; for (j = i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[j]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; hio_read(xxi->name, 1, 20, f); /* Sample size is always rounded down */ xxs->len = hio_read32b(f) & ~1; xxs->lps = hio_read16b(f) << 1; looplen = hio_read16b(f) << 1; xxs->lpe = xxs->lps + looplen; xxs->flg = looplen > 2 ? XMP_SAMPLE_LOOP : 0; sub->vol = hio_read16b(f); data->mode[i] = hio_read16b(f); sub->pan = 0x80; sub->sid = j; data->idx[j] = i; if (xxs->len > 0) { xxi->nsm = 1; j++; } } return 0; } static int get_spee(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->spd = hio_read16b(f); mod->bpm = 125; return 0; } static int get_slen(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->pat = hio_read16b(f); mod->trk = mod->pat * mod->chn; return 0; } static int get_plen(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->len = hio_read16b(f); /* Sanity check */ if (mod->len > 256) return -1; D_(D_INFO "Module length: %d", mod->len); return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; if (hio_read(mod->xxo, 1, mod->len, f) != mod->len) return -1; return 0; } static int get_pbod(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; struct xmp_event *e; uint16 rows; int j; if (data->pattern >= mod->pat) return 0; if (!data->pattern) { if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); } rows = hio_read16b(f); if (libxmp_alloc_pattern_tracks(mod, data->pattern, rows) < 0) return -1; for (j = 0; j < rows * mod->chn; j++) { uint8 note, ins, fxt; e = &EVENT(data->pattern, j % mod->chn, j / mod->chn); memset(e, 0, sizeof(struct xmp_event)); note = hio_read8(f); ins = hio_read8(f); if (note) { e->note = 48 + note; e->ins = 1 + ins; } fxt = hio_read8(f); if (fxt >= 32) { return -1; } e->fxt = fx[fxt]; e->fxp = hio_read8(f); if ((e->fxt == FX_VOLSET) && (e->fxp > 0x40)) { if (e->fxp <= 0x50) { e->fxt = FX_VOLSLIDE; e->fxp -= 0x40; } else if (e->fxp <= 0x60) { e->fxt = FX_VOLSLIDE; e->fxp = (e->fxp - 0x50) << 4; } else if (e->fxp <= 0x70) { e->fxt = FX_F_VSLIDE_DN; e->fxp = e->fxp - 0x60; } else if (e->fxp <= 0x80) { e->fxt = FX_F_VSLIDE_UP; e->fxp = e->fxp - 0x70; } } if (e->fxt == FX_ARPEGGIO) /* Arpeggio fixup */ e->fxp = (((24 - MSN(e->fxp)) % 12) << 4) | LSN(e->fxp); if (e->fxt == NONE) e->fxt = e->fxp = 0; } data->pattern++; return 0; } static int get_sbod(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int flags = 0; int i, sid; if (data->sample >= mod->ins) return 0; D_(D_INFO "Stored samples: %d", mod->smp); i = data->idx[data->sample]; if (data->mode[i] == OKT_MODE8 || data->mode[i] == OKT_MODEB) flags = SAMPLE_FLAG_7BIT; sid = mod->xxi[i].sub[0].sid; if (libxmp_load_sample(m, f, flags, &mod->xxs[sid], NULL) < 0) return -1; data->sample++; return 0; } static int okt_load(struct module_data *m, HIO_HANDLE * f, const int start) { iff_handle handle; struct local_data data; int ret; LOAD_INIT(); hio_seek(f, 8, SEEK_CUR); /* OKTASONG */ handle = libxmp_iff_new(); if (handle == NULL) return -1; memset(&data, 0, sizeof(struct local_data)); /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "CMOD", get_cmod); ret |= libxmp_iff_register(handle, "SAMP", get_samp); ret |= libxmp_iff_register(handle, "SPEE", get_spee); ret |= libxmp_iff_register(handle, "SLEN", get_slen); ret |= libxmp_iff_register(handle, "PLEN", get_plen); ret |= libxmp_iff_register(handle, "PATT", get_patt); ret |= libxmp_iff_register(handle, "PBOD", get_pbod); ret |= libxmp_iff_register(handle, "SBOD", get_sbod); if (ret != 0) return -1; libxmp_set_type(m, "Oktalyzer"); MODULE_INFO(); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); m->period_type = PERIOD_MODRNG; return 0; } libxmp-4.4.1/src/loaders/med4_load.c0000664000175000017500000004442412775035311017067 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * MED 2.13 is in Fish disk #424 and has a couple of demo modules, get it * from ftp://ftp.funet.fi/pub/amiga/fish/401-500/ff424. Alex Van Starrex's * HappySong MED4 is in ff401. MED 3.00 is in ff476. */ #include #include "med.h" #include "loader.h" #include "med_extras.h" #define MAGIC_MED4 MAGIC4('M','E','D',4) #undef MED4_DEBUG static int med4_test(HIO_HANDLE *, char *, const int); static int med4_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_med4 = { "MED 2.10 MED4", med4_test, med4_load }; static int med4_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_MED4) return -1; libxmp_read_title(f, t, 0); return 0; } const unsigned MAX_CHANNELS = 16; static void fix_effect(struct xmp_event *event) { switch (event->fxt) { case 0x00: /* arpeggio */ case 0x01: /* slide up */ case 0x02: /* slide down */ case 0x03: /* portamento */ case 0x04: /* vibrato? */ break; case 0x0c: /* set volume (BCD) */ event->fxp = MSN(event->fxp) * 10 + LSN(event->fxp); break; case 0x0d: /* volume slides */ event->fxt = FX_VOLSLIDE; break; case 0x0f: /* tempo/break */ if (event->fxp == 0) event->fxt = FX_BREAK; if (event->fxp == 0xff) { event->fxp = event->fxt = 0; event->vol = 1; } else if (event->fxp == 0xf1) { event->fxt = FX_EXTENDED; event->fxp = (EX_RETRIG << 4) | 3; } else if (event->fxp == 0xf2) { event->fxt = FX_EXTENDED; event->fxp = (EX_CUT << 4) | 3; } else if (event->fxp == 0xf3) { event->fxt = FX_EXTENDED; event->fxp = (EX_DELAY << 4) | 3; } else if (event->fxp > 0xf0) { event->fxp = event->fxt = 0; } else if (event->fxp > 10) { event->fxt = FX_S3M_BPM; event->fxp = 125 * event->fxp / 33; } break; default: event->fxp = event->fxt = 0; } } struct stream { HIO_HANDLE* f; int has_nibble; uint8 value; }; static inline void stream_init(HIO_HANDLE* f, struct stream* s) { s->f = f; s->has_nibble = s->value = 0; } static inline unsigned stream_read4(struct stream* s) { s->has_nibble = !s->has_nibble; if (!s->has_nibble) { return s->value & 0x0f; } else { s->value = hio_read8(s->f); return s->value >> 4; } } static inline unsigned stream_read8(struct stream* s) { unsigned a = stream_read4(s); unsigned b = stream_read4(s); return (a << 4) | b; } static inline unsigned stream_read12(struct stream* s) { unsigned a = stream_read4(s); unsigned b = stream_read4(s); unsigned c = stream_read4(s); return (a << 8) | (b << 4) | c; } static inline uint16 stream_read16(struct stream* s) { unsigned a = stream_read4(s); unsigned b = stream_read4(s); unsigned c = stream_read4(s); unsigned d = stream_read4(s); return (a << 12) | (b << 8) | (c << 4) | d; } static inline uint16 stream_read_aligned16(struct stream* s, int bits) { if (bits <= 4) { return stream_read4(s) << 12; } else if (bits <= 8) { return stream_read8(s) << 8; } else if (bits <= 12) { return stream_read12(s) << 4; } else { return stream_read16(s); } } struct temp_inst { char name[32]; int loop_start; int loop_end; int volume; int transpose; }; static int med4_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k, y; uint8 m0; uint64 mask; int transp, masksz; int pos, vermaj, vermin; uint8 trkvol[16], buf[1024]; struct xmp_event *event; int flags, hexvol = 0; int num_ins, num_smp; int smp_idx; int tempo; struct temp_inst temp_inst[64]; LOAD_INIT(); hio_read32b(f); /* Skip magic */ vermaj = 2; vermin = 10; /* * Check if we have a MEDV chunk at the end of the file */ if ((pos = hio_tell(f)) < 0) { return -1; } hio_seek(f, 0, SEEK_END); if (hio_tell(f) > 2000) { hio_seek(f, -1024, SEEK_CUR); hio_read(buf, 1, 1024, f); for (i = 0; i < 1013; i++) { if (!memcmp(buf + i, "MEDV\000\000\000\004", 8)) { vermaj = *(buf + i + 10); vermin = *(buf + i + 11); break; } } } hio_seek(f, start + pos, SEEK_SET); snprintf(mod->type, XMP_NAME_SIZE, "MED %d.%02d MED4", vermaj, vermin); m0 = hio_read8(f); mask = masksz = 0; for (i = 0; m0 != 0 && i < 8; i++, m0 <<= 1) { if (m0 & 0x80) { mask <<= 8; mask |= hio_read8(f); masksz++; } } /* CID 128662 (#1 of 1): Bad bit shift operation (BAD_SHIFT) * large_shift: left shifting by more than 63 bits has undefined * behavior. */ if (masksz > 0) { mask <<= 8 * (sizeof(mask) - masksz); } /*printf("m0=%x mask=%x\n", m0, mask);*/ /* read instrument names in temporary space */ num_ins = 0; memset(&temp_inst, 0, sizeof(temp_inst)); for (i = 0; mask != 0 && i < 64; i++, mask <<= 1) { uint8 c, size, buf[40]; uint16 loop_len = 0; if ((int64)mask > 0) continue; num_ins = i + 1; /* read flags */ c = hio_read8(f); /* read instrument name */ size = hio_read8(f); for (j = 0; j < size; j++) buf[j] = hio_read8(f); buf[j] = 0; #ifdef MED4_DEBUG printf("%02x %02x %2d [%s]\n", i, c, size, buf); #endif temp_inst[i].volume = 0x40; if ((c & 0x01) == 0) temp_inst[i].loop_start = hio_read16b(f) << 1; if ((c & 0x02) == 0) loop_len = hio_read16b(f) << 1; if ((c & 0x04) == 0) /* ? Tanko2 (MED 3.00 demo) */ hio_read8(f); if ((c & 0x08) == 0) /* Tim Newsham's "span" */ hio_read8(f); if ((c & 0x30) == 0) temp_inst[i].volume = hio_read8(f); if ((c & 0x40) == 0) temp_inst[i].transpose = hio_read8s(f); temp_inst[i].loop_end = temp_inst[i].loop_start + loop_len; libxmp_copy_adjust(temp_inst[i].name, buf, 32); } mod->pat = hio_read16b(f); mod->len = hio_read16b(f); if (hio_error(f)) { return -1; } #ifdef MED4_DEBUG printf("pat=%x len=%x\n", mod->pat, mod->len); #endif if (mod->pat > 256 || mod->len > XMP_MAX_MOD_LENGTH) return -1; hio_read(mod->xxo, 1, mod->len, f); /* From MED V3.00 docs: * * The left proportional gadget controls the primary tempo. It canbe * 1 - 240. The bigger the number, the faster the speed. Note that * tempos 1 - 10 are Tracker-compatible (but obsolete, because * secondary tempo can be used now). */ tempo = hio_read16b(f); if (tempo <= 10) { mod->spd = tempo; mod->bpm = 125; } else { mod->bpm = 125 * tempo / 33; } transp = hio_read8s(f); hio_read8s(f); flags = hio_read8s(f); mod->spd = hio_read8(f); if (~flags & 0x20) /* sliding */ m->quirk |= QUIRK_VSALL | QUIRK_PBALL; if (flags & 0x10) /* dec/hex volumes */ hexvol = 1; /* not implemented */ /* This is just a guess... */ if (vermaj == 2) /* Happy.med has tempo 5 but loads as 6 */ mod->spd = flags & 0x20 ? 5 : 6; hio_seek(f, 20, SEEK_CUR); hio_read(trkvol, 1, 16, f); hio_read8(f); /* master vol */ MODULE_INFO(); D_(D_INFO "Play transpose: %d", transp); for (i = 0; i < 64; i++) temp_inst[i].transpose += transp; /* Scan patterns to determine number of channels */ mod->chn = 0; if ((pos = hio_tell(f)) < 0) { return -1; } for (i = 0; i < mod->pat; i++) { int size, plen, chn; size = hio_read8(f); /* pattern control block */ chn = hio_read8(f); if (chn > mod->chn) mod->chn = chn; hio_read8(f); /* skip number of rows */ plen = hio_read16b(f); hio_seek(f, size + plen - 4, SEEK_CUR); } /* Sanity check */ if (mod->chn > 16) { return -1; } mod->trk = mod->chn * mod->pat; if (libxmp_init_pattern(mod) < 0) return -1; hio_seek(f, pos, SEEK_SET); /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { int size, plen, rows; uint8 ctl[4], chn; unsigned chmsk; uint32 linemask[8], fxmask[8], x; int num_masks; struct stream stream; #ifdef MED4_DEBUG printf("\n===== PATTERN %d =====\n", i); printf("offset = %lx\n", hio_tell(f)); #endif size = hio_read8(f); /* pattern control block */ if ((pos = hio_tell(f)) < 0) { return -1; } chn = hio_read8(f); if (chn > mod->chn) { return -1; } rows = (int)hio_read8(f) + 1; plen = hio_read16b(f); #ifdef MED4_DEBUG printf("size = %02x\n", size); printf("chn = %01x\n", chn); printf("rows = %01x\n", rows); printf("plen = %04x\n", plen); #endif /* read control byte */ for (j = 0; j < 4; j++) { if (rows > j * 64) ctl[j] = hio_read8(f); else break; #ifdef MED4_DEBUG printf("ctl[%d] = %02x\n", j, ctl[j]); #endif } if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; /* initialize masks */ for (y = 0; y < 8; y++) { linemask[y] = 0; fxmask[y] = 0; } /* read masks */ num_masks = 0; for (y = 0; y < 8; y++) { if (rows > y * 32) { int c = ctl[y / 2]; int s = 4 * (y % 2); linemask[y] = c & (0x80 >> s) ? ~0 : c & (0x40 >> s) ? 0 : hio_read32b(f); fxmask[y] = c & (0x20 >> s) ? ~0 : c & (0x10 >> s) ? 0 : hio_read32b(f); num_masks++; #ifdef MED4_DEBUG printf("linemask[%d] = %08x\n", y, linemask[y]); printf("fxmask[%d] = %08x\n", y, fxmask[y]); #endif } else { break; } } hio_seek(f, pos + size, SEEK_SET); stream_init(f, &stream); for (y = 0; y < num_masks; y++) { for (j = 0; j < 32; j++) { int line = y * 32 + j; if (line >= rows) break; if (linemask[y] & 0x80000000) { chmsk = stream_read_aligned16(&stream, chn); for (k = 0; k < chn; k++, chmsk <<= 1) { event = &EVENT(i, k, line); if (chmsk & 0x8000) { x = stream_read12(&stream); event->note = x >> 4; if (event->note) event->note += 48; event->ins = x & 0x0f; } } } if (fxmask[y] & 0x80000000) { chmsk = stream_read_aligned16(&stream, chn); for (k = 0; k < chn; k++, chmsk <<= 1) { event = &EVENT(i, k, line); if (chmsk & 0x8000) { x = stream_read12(&stream); event->fxt = x >> 8; event->fxp = x & 0xff; fix_effect(event); } } } #ifdef MED4_DEBUG printf("%03d ", line); for (k = 0; k < 4; k++) { event = &EVENT(i, k, line); if (event->note) printf("%03d", event->note); else printf("---"); printf(" %1x%1x%02x ", event->ins, event->fxt, event->fxp); } printf("\n"); #endif linemask[y] <<= 1; fxmask[y] <<= 1; } } hio_seek(f, pos + size + plen, SEEK_SET); } mod->ins = num_ins; if (libxmp_med_new_module_extras(m) != 0) return -1; /* * Load samples */ mask = hio_read32b(f); if (mask == MAGIC4('M','E','D','V')) { mod->smp = 0; if (libxmp_init_instrument(m) < 0) return -1; hio_seek(f, -4, SEEK_CUR); goto parse_iff; } mask <<= 32; mask |= hio_read32b(f); mask <<= 1; /* no instrument #0 */ /* obtain number of samples */ if ((pos = hio_tell(f)) < 0) { return -1; } num_smp = 0; { int _len, _type; uint64 _mask = mask; for (i = 0; _mask != 0 && i < 64; i++, _mask <<= 1) { int _pos; if ((int64)_mask > 0) continue; _len = hio_read32b(f); _type = (int16)hio_read16b(f); if ((_pos = hio_tell(f)) < 0) { return -1; } if (_type == 0 || _type == -2) { num_smp++; } else if (_type == -1) { hio_seek(f, 20, SEEK_CUR); num_smp += hio_read16b(f); } hio_seek(f, _pos + _len, SEEK_SET); } } hio_seek(f, pos, SEEK_SET); mod->smp = num_smp; if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->ins); smp_idx = 0; for (i = 0; mask != 0 && i < num_ins; i++, mask <<= 1) { int length, type; struct SynthInstr synth; struct xmp_instrument *xxi; struct xmp_subinstrument *sub; struct xmp_sample *xxs; if ((int64)mask > 0) continue; xxi = &mod->xxi[i]; length = hio_read32b(f); type = (int16)hio_read16b(f); /* instrument type */ strncpy((char *)xxi->name, temp_inst[i].name, 32); D_(D_INFO "\n[%2X] %-32.32s %d", i, xxi->name, type); /* This is very similar to MMD1 synth/hybrid instruments, * but just different enough to be reimplemented here. */ if (type == -2) { /* Hybrid */ int length, type; int pos = hio_tell(f); if (pos < 0) { return -1; } hio_read32b(f); /* ? - MSH 00 */ hio_read16b(f); /* ? - ffff */ hio_read16b(f); /* ? - 0000 */ hio_read16b(f); /* ? - 0000 */ synth.rep = hio_read16b(f); /* ? */ synth.replen = hio_read16b(f); /* ? */ synth.voltbllen = hio_read16b(f); synth.wftbllen = hio_read16b(f); synth.volspeed = hio_read8(f); synth.wfspeed = hio_read8(f); synth.wforms = hio_read16b(f); /* Sanity check */ if (synth.voltbllen > 128 || synth.wftbllen > 128 || synth.wforms > 256) { return -1; } hio_read(synth.voltbl, 1, synth.voltbllen, f);; hio_read(synth.wftbl, 1, synth.wftbllen, f);; hio_seek(f, pos + hio_read32b(f), SEEK_SET); length = hio_read32b(f); type = hio_read16b(f); if (libxmp_med_new_instrument_extras(xxi) != 0) return -1; xxi->nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; MED_INSTRUMENT_EXTRAS(*xxi)->vts = synth.volspeed; MED_INSTRUMENT_EXTRAS(*xxi)->wts = synth.wfspeed; sub->pan = 0x80; sub->vol = temp_inst[i].volume; sub->xpo = temp_inst[i].transpose; sub->sid = smp_idx; sub->fin = 0 /*exp_smp.finetune*/; xxs = &mod->xxs[smp_idx]; xxs->len = length; xxs->lps = temp_inst[i].loop_start; xxs->lpe = temp_inst[i].loop_end; xxs->flg = temp_inst[i].loop_end > 2 ? XMP_SAMPLE_LOOP : 0; D_(D_INFO " %05x %05x %05x %02x %+03d", xxs->len, xxs->lps, xxs->lpe, sub->vol, sub->xpo /*, sub->fin >> 4*/); if (libxmp_load_sample(m, f, 0, xxs, NULL) < 0) return -1; smp_idx++; if (mmd_alloc_tables(m, i, &synth) != 0) return -1; continue; } if (type == -1) { /* Synthetic */ int pos = hio_tell(f); if (pos < 0) { return -1; } hio_read32b(f); /* ? - MSH 00 */ hio_read16b(f); /* ? - ffff */ hio_read16b(f); /* ? - 0000 */ hio_read16b(f); /* ? - 0000 */ synth.rep = hio_read16b(f); /* ? */ synth.replen = hio_read16b(f); /* ? */ synth.voltbllen = hio_read16b(f); synth.wftbllen = hio_read16b(f); synth.volspeed = hio_read8(f); synth.wfspeed = hio_read8(f); synth.wforms = hio_read16b(f); /* Sanity check */ if (synth.voltbllen > 128 || synth.wftbllen > 128 || synth.wforms > 256) { return -1; } hio_read(synth.voltbl, 1, synth.voltbllen, f);; hio_read(synth.wftbl, 1, synth.wftbllen, f);; if (synth.wforms == 0xffff) continue; if (synth.wforms > 64) return -1; for (j = 0; j < synth.wforms; j++) synth.wf[j] = hio_read32b(f); D_(D_INFO " VS:%02x WS:%02x WF:%02x %02x %+03d", synth.volspeed, synth.wfspeed, synth.wforms & 0xff, temp_inst[i].volume, temp_inst[i].transpose /*, exp_smp.finetune*/); if (libxmp_med_new_instrument_extras(&mod->xxi[i]) != 0) return -1; mod->xxi[i].nsm = synth.wforms; if (libxmp_alloc_subinstrument(mod, i, synth.wforms) < 0) return -1; MED_INSTRUMENT_EXTRAS(*xxi)->vts = synth.volspeed; MED_INSTRUMENT_EXTRAS(*xxi)->wts = synth.wfspeed; for (j = 0; j < synth.wforms; j++) { sub = &xxi->sub[j]; sub->pan = 0x80; sub->vol = 64; sub->xpo = -24; sub->sid = smp_idx; sub->fin = 0 /*exp_smp.finetune*/; hio_seek(f, pos + synth.wf[j], SEEK_SET); xxs = &mod->xxs[smp_idx]; xxs->len = hio_read16b(f) * 2; xxs->lps = 0; xxs->lpe = xxs->len; xxs->flg = XMP_SAMPLE_LOOP; if (libxmp_load_sample(m, f, 0, xxs, NULL) < 0) { return -1; } smp_idx++; } if (mmd_alloc_tables(m, i, &synth) != 0) return -1; hio_seek(f, pos + length, SEEK_SET); continue; } if (type != 0) { hio_seek(f, length, SEEK_CUR); continue; } /* instr type is sample */ xxi->nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; sub->vol = temp_inst[i].volume; sub->pan = 0x80; sub->xpo = temp_inst[i].transpose; sub->sid = smp_idx; /* Sanity check */ if (smp_idx >= mod->smp) return -1; xxs = &mod->xxs[smp_idx]; xxs->len = length; xxs->lps = temp_inst[i].loop_start; xxs->lpe = temp_inst[i].loop_end; xxs->flg = temp_inst[i].loop_end > 2 ? XMP_SAMPLE_LOOP : 0; D_(D_INFO " %04x %04x %04x %c V%02x %+03d", xxs->len, mod->xxs[smp_idx].lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->xpo); if (libxmp_load_sample(m, f, 0, xxs, NULL) < 0) return -1; /* Limit range to 3 octave (see MED.El toro) */ for (j = 0; j < 9; j++) { for (k = 0; k < 12; k++) { int xpo = 0; if (j < 4) xpo = 12 * (4 - j); else if (j > 6) xpo = -12 * (j - 6); xxi->map[12 * j + k].xpo = xpo; } } smp_idx++; } hio_read16b(f); /* unknown */ /* IFF-like section */ parse_iff: while (!hio_eof(f)) { int32 id, size, s2, pos, ver; if ((id = hio_read32b(f)) <= 0) break; if ((size = hio_read32b(f)) <= 0) break; if ((pos = hio_tell(f)) < 0) { return -1; } switch (id) { case MAGIC4('M','E','D','V'): ver = hio_read32b(f); D_(D_INFO "MED Version: %d.%0d\n", (ver & 0xff00) >> 8, ver & 0xff); break; case MAGIC4('A','N','N','O'): /* annotation */ s2 = size < 1023 ? size : 1023; hio_read(buf, 1, s2, f); buf[s2] = 0; D_(D_INFO "Annotation: %s\n", buf); break; case MAGIC4('H','L','D','C'): /* hold & decay */ break; } hio_seek(f, pos + size, SEEK_SET); } m->read_event_type = READ_EVENT_MED; return 0; } libxmp-4.4.1/src/loaders/mtm_load.c0000664000175000017500000001537212774567167017055 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" struct mtm_file_header { uint8 magic[3]; /* "MTM" */ uint8 version; /* MSN=major, LSN=minor */ uint8 name[20]; /* ASCIIZ Module name */ uint16 tracks; /* Number of tracks saved */ uint8 patterns; /* Number of patterns saved */ uint8 modlen; /* Module length */ uint16 extralen; /* Length of the comment field */ uint8 samples; /* Number of samples */ uint8 attr; /* Always zero */ uint8 rows; /* Number rows per track */ uint8 channels; /* Number of tracks per pattern */ uint8 pan[32]; /* Pan positions for each channel */ }; struct mtm_instrument_header { uint8 name[22]; /* Instrument name */ uint32 length; /* Instrument length in bytes */ uint32 loop_start; /* Sample loop start */ uint32 loopend; /* Sample loop end */ uint8 finetune; /* Finetune */ uint8 volume; /* Playback volume */ uint8 attr; /* &0x01: 16bit sample */ }; static int mtm_test(HIO_HANDLE *, char *, const int); static int mtm_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mtm = { "Multitracker", mtm_test, mtm_load }; static int mtm_test(HIO_HANDLE *f, char *t, const int start) { uint8 buf[4]; if (hio_read(buf, 1, 4, f) < 4) return -1; if (memcmp(buf, "MTM", 3)) return -1; if (buf[3] != 0x10) return -1; libxmp_read_title(f, t, 20); return 0; } static int mtm_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct mtm_file_header mfh; struct mtm_instrument_header mih; uint8 mt[192]; LOAD_INIT(); hio_read(&mfh.magic, 3, 1, f); /* "MTM" */ mfh.version = hio_read8(f); /* MSN=major, LSN=minor */ hio_read(&mfh.name, 20, 1, f); /* ASCIIZ Module name */ mfh.tracks = hio_read16l(f); /* Number of tracks saved */ mfh.patterns = hio_read8(f); /* Number of patterns saved */ mfh.modlen = hio_read8(f); /* Module length */ mfh.extralen = hio_read16l(f); /* Length of the comment field */ mfh.samples = hio_read8(f); /* Number of samples */ if (mfh.samples > 63) { return -1; } mfh.attr = hio_read8(f); /* Always zero */ mfh.rows = hio_read8(f); /* Number rows per track */ if (mfh.rows != 64) return -1; mfh.channels = hio_read8(f); /* Number of tracks per pattern */ if (mfh.channels > XMP_MAX_CHANNELS) { return -1; } hio_read(&mfh.pan, 32, 1, f); /* Pan positions for each channel */ if (hio_error(f)) { return -1; } #if 0 if (strncmp((char *)mfh.magic, "MTM", 3)) return -1; #endif mod->trk = mfh.tracks + 1; mod->pat = mfh.patterns + 1; mod->len = mfh.modlen + 1; mod->ins = mfh.samples; mod->smp = mod->ins; mod->chn = mfh.channels; mod->spd = 6; mod->bpm = 125; strncpy(mod->name, (char *)mfh.name, 20); libxmp_set_type(m, "MultiTracker %d.%02d MTM", MSN(mfh.version), LSN(mfh.version)); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; /* Read and convert instruments */ for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; hio_read(&mih.name, 22, 1, f); /* Instrument name */ mih.length = hio_read32l(f); /* Instrument length in bytes */ if (mih.length > MAX_SAMPLE_SIZE) return -1; mih.loop_start = hio_read32l(f); /* Sample loop start */ mih.loopend = hio_read32l(f); /* Sample loop end */ mih.finetune = hio_read8(f); /* Finetune */ mih.volume = hio_read8(f); /* Playback volume */ mih.attr = hio_read8(f); /* &0x01: 16bit sample */ xxs->len = mih.length; xxs->lps = mih.loop_start; xxs->lpe = mih.loopend; xxs->flg = xxs->lpe ? XMP_SAMPLE_LOOP : 0; /* 1 == Forward loop */ if (mfh.attr & 1) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } sub->vol = mih.volume; sub->fin = mih.finetune; sub->pan = 0x80; sub->sid = i; libxmp_instrument_name(mod, i, mih.name, 22); if (xxs->len > 0) mod->xxi[i].nsm = 1; D_(D_INFO "[%2X] %-22.22s %04x%c%04x %04x %c V%02x F%+03d\n", i, xxi->name, xxs->len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ', xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->fin - 0x80); } hio_read(mod->xxo, 1, 128, f); if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored tracks: %d", mod->trk - 1); for (i = 0; i < mod->trk; i++) { if (libxmp_alloc_track(mod, i, mfh.rows) < 0) return -1; if (i == 0) continue; if (hio_read(&mt, 3, 64, f) != 64) return -1; for (j = 0; j < 64; j++) { struct xmp_event *e = &mod->xxt[i]->event[j]; uint8 *d = mt + j * 3; if ((e->note = d[0] >> 2)) { e->note += 37; } e->ins = ((d[0] & 0x3) << 4) + MSN(d[1]); e->fxt = LSN(d[1]); e->fxp = d[2]; if (e->fxt > FX_SPEED) { e->fxt = e->fxp = 0; } /* Set pan effect translation */ if (e->fxt == FX_EXTENDED && MSN(e->fxp) == 0x8) { e->fxt = FX_SETPAN; e->fxp <<= 4; } } } /* Read patterns */ D_(D_INFO "Stored patterns: %d", mod->pat - 1); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern(mod, i) < 0) return -1; mod->xxp[i]->rows = 64; for (j = 0; j < 32; j++) { int track = hio_read16l(f); if (track >= mod->trk) { track = 0; } if (j < mod->chn) { mod->xxp[i]->index[j] = track; } } } /* Comments */ hio_seek(f, mfh.extralen, SEEK_CUR); /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0) return -1; } for (i = 0; i < mod->chn; i++) mod->xxc[i].pan = mfh.pan[i] << 4; return 0; } libxmp-4.4.1/src/loaders/iff.c0000664000175000017500000001135312775035311015776 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "common.h" #include "list.h" #include "iff.h" #include "loader.h" struct iff_data { struct list_head iff_list; unsigned id_size; unsigned flags; }; static int iff_process(iff_handle opaque, struct module_data *m, char *id, long size, HIO_HANDLE *f, void *parm) { struct iff_data *data = (struct iff_data *)opaque; struct list_head *tmp; struct iff_info *i; int pos; pos = hio_tell(f); list_for_each(tmp, &data->iff_list) { i = list_entry(tmp, struct iff_info, list); if (id && !memcmp(id, i->id, data->id_size)) { D_(D_WARN "Load IFF chunk %s (%ld) @%d", id, size, pos); if (size > IFF_MAX_CHUNK_SIZE) { return -1; } if (i->loader(m, size, f, parm) < 0) { return -1; } break; } } if (hio_seek(f, pos + size, SEEK_SET) < 0) { return -1; } return 0; } static int iff_chunk(iff_handle opaque, struct module_data *m, HIO_HANDLE *f, void *parm) { struct iff_data *data = (struct iff_data *)opaque; unsigned size; char id[17] = ""; D_(D_INFO "chunk id size: %d", data->id_size); if (hio_read(id, 1, data->id_size, f) != data->id_size) { (void)hio_error(f); /* clear error flag */ return 1; } D_(D_INFO "chunk id: [%s]", id); if (data->flags & IFF_SKIP_EMBEDDED) { /* embedded RIFF hack */ if (!strncmp(id, "RIFF", 4)) { hio_read32b(f); hio_read32b(f); /* read first chunk ID instead */ if (hio_read(id, 1, data->id_size, f) != data->id_size){ return 1; } } } if (data->flags & IFF_LITTLE_ENDIAN) { size = hio_read32l(f); } else { size = hio_read32b(f); } D_(D_INFO "size: %d", size); if (hio_error(f)) { return -1; } if (data->flags & IFF_CHUNK_ALIGN2) { /* Sanity check */ if (size > 0xfffffffe) { return -1; } size = (size + 1) & ~1; } if (data->flags & IFF_CHUNK_ALIGN4) { /* Sanity check */ if (size > 0xfffffffc) { return -1; } size = (size + 3) & ~3; } if (data->flags & IFF_FULL_CHUNK_SIZE) { if (size < data->id_size + 4) return -1; size -= data->id_size + 4; } return iff_process(opaque, m, id, size, f, parm); } iff_handle libxmp_iff_new() { struct iff_data *data; data = malloc(sizeof(struct iff_data)); if (data == NULL) { return NULL; } INIT_LIST_HEAD(&data->iff_list); data->id_size = 4; data->flags = 0; return (iff_handle)data; } int libxmp_iff_load(iff_handle opaque, struct module_data *m, HIO_HANDLE *f, void *parm) { int ret; while (!hio_eof(f)) { ret = iff_chunk(opaque, m, f, parm); if (ret > 0) break; if (ret < 0) return -1; } return 0; } int libxmp_iff_register(iff_handle opaque, char *id, int (*loader)(struct module_data *, int, HIO_HANDLE *, void *)) { struct iff_data *data = (struct iff_data *)opaque; struct iff_info *f; f = malloc(sizeof(struct iff_info)); if (f == NULL) return -1; strncpy(f->id, id, 4); f->loader = loader; list_add_tail(&f->list, &data->iff_list); return 0; } void libxmp_iff_release(iff_handle opaque) { struct iff_data *data = (struct iff_data *)opaque; struct list_head *tmp; struct iff_info *i; /* can't use list_for_each, we free the node before incrementing */ for (tmp = (&data->iff_list)->next; tmp != (&data->iff_list);) { i = list_entry(tmp, struct iff_info, list); list_del(&i->list); tmp = tmp->next; free(i); } free(data); } /* Functions to tune IFF mutations */ void libxmp_iff_id_size(iff_handle opaque, int n) { struct iff_data *data = (struct iff_data *)opaque; data->id_size = n; } void libxmp_iff_set_quirk(iff_handle opaque, int i) { struct iff_data *data = (struct iff_data *)opaque; data->flags |= i; } libxmp-4.4.1/src/loaders/ice_load.c0000664000175000017500000001217312774567167017014 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Loader for Soundtracker 2.6/Ice Tracker modules */ #include "loader.h" #define MAGIC_MTN_ MAGIC4('M','T','N',0) #define MAGIC_IT10 MAGIC4('I','T','1','0') static int ice_test(HIO_HANDLE *, char *, const int); static int ice_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_ice = { "Soundtracker 2.6/Ice Tracker", ice_test, ice_load }; static int ice_test(HIO_HANDLE * f, char *t, const int start) { uint32 magic; hio_seek(f, start + 1464, SEEK_SET); magic = hio_read32b(f); if (magic != MAGIC_MTN_ && magic != MAGIC_IT10) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 28); return 0; } struct ice_ins { char name[22]; /* Instrument name */ uint16 len; /* Sample length / 2 */ uint8 finetune; /* Finetune */ uint8 volume; /* Volume (0-63) */ uint16 loop_start; /* Sample loop start in file */ uint16 loop_size; /* Loop size / 2 */ }; struct ice_header { char title[20]; struct ice_ins ins[31]; /* Instruments */ uint8 len; /* Size of the pattern list */ uint8 trk; /* Number of tracks */ uint8 ord[128][4]; uint32 magic; /* 'MTN\0', 'IT10' */ }; static int ice_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct ice_header ih; uint8 ev[4]; LOAD_INIT(); hio_read(&ih.title, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&ih.ins[i].name, 22, 1, f); ih.ins[i].len = hio_read16b(f); ih.ins[i].finetune = hio_read8(f); ih.ins[i].volume = hio_read8(f); ih.ins[i].loop_start = hio_read16b(f); ih.ins[i].loop_size = hio_read16b(f); } ih.len = hio_read8(f); ih.trk = hio_read8(f); hio_read(&ih.ord, 128 * 4, 1, f); ih.magic = hio_read32b(f); /* Sanity check */ if (ih.len > 128) { return -1; } for (i = 0; i < ih.len; i++) { for (j = 0; j < 4; j++) { if (ih.ord[i][j] >= ih.trk) return -1; } } if (ih.magic == MAGIC_IT10) libxmp_set_type(m, "Ice Tracker"); else if (ih.magic == MAGIC_MTN_) libxmp_set_type(m, "Soundtracker 2.6"); else return -1; mod->ins = 31; mod->smp = mod->ins; mod->pat = ih.len; mod->len = ih.len; mod->trk = ih.trk; strncpy(mod->name, (char *)ih.title, 20); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi; struct xmp_sample *xxs; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; xxi = &mod->xxi[i]; xxs = &mod->xxs[i]; xxs->len = 2 * ih.ins[i].len; xxs->lps = 2 * ih.ins[i].loop_start; xxs->lpe = xxs->lps + 2 * ih.ins[i].loop_size; xxs->flg = ih.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; xxi->sub[0].vol = ih.ins[i].volume; /* xxi->sub[0].fin = (int8)(ih.ins[i].finetune << 4); */ xxi->sub[0].pan = 0x80; xxi->sub[0].sid = i; if (xxs->len > 0) xxi->nsm = 1; D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c %02x %01x", i, ih.ins[i].name, xxs->len, xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', xxi->sub[0].vol, xxi->sub[0].fin >> 4); } if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern(mod, i) < 0) return -1; mod->xxp[i]->rows = 64; for (j = 0; j < mod->chn; j++) { mod->xxp[i]->index[j] = ih.ord[i][j]; } mod->xxo[i] = i; } D_(D_INFO "Stored tracks: %d", mod->trk); for (i = 0; i < mod->trk; i++) { if (libxmp_alloc_track(mod, i, 64) < 0) return -1; for (j = 0; j < mod->xxt[i]->rows; j++) { event = &mod->xxt[i]->event[j]; hio_read(ev, 1, 4, f); libxmp_decode_protracker_event(event, ev); if (event->fxt == FX_SPEED) { if (MSN(event->fxp) && LSN(event->fxp)) { event->fxt = FX_ICE_SPEED; } } } } m->period_type = PERIOD_MODRNG; /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len <= 4) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/liq_load.c0000664000175000017500000003517112774567167017044 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Liquid Tracker module loader based on the format description written * by Nir Oren. Tested with Shell.liq sent by Adi Sapir. */ #include "loader.h" #include "period.h" struct liq_header { uint8 magic[14]; /* "Liquid Module:" */ uint8 name[30]; /* ASCIIZ module name */ uint8 author[20]; /* Author name */ uint8 _0x1a; /* 0x1a */ uint8 tracker[20]; /* Tracker name */ uint16 version; /* Format version */ uint16 speed; /* Initial speed */ uint16 bpm; /* Initial bpm */ uint16 low; /* Lowest note (Amiga Period*4) */ uint16 high; /* Uppest note (Amiga Period*4) */ uint16 chn; /* Number of channels */ uint32 flags; /* Module flags */ uint16 pat; /* Number of patterns saved */ uint16 ins; /* Number of instruments */ uint16 len; /* Module length */ uint16 hdrsz; /* Header size */ }; struct liq_instrument { #if 0 uint8 magic[4]; /* 'L', 'D', 'S', 'S' */ #endif uint16 version; /* LDSS header version */ uint8 name[30]; /* Instrument name */ uint8 editor[20]; /* Generator name */ uint8 author[20]; /* Author name */ uint8 hw_id; /* Hardware used to record the sample */ uint32 length; /* Sample length */ uint32 loopstart; /* Sample loop start */ uint32 loopend; /* Sample loop end */ uint32 c2spd; /* C2SPD */ uint8 vol; /* Volume */ uint8 flags; /* Flags */ uint8 pan; /* Pan */ uint8 midi_ins; /* General MIDI instrument */ uint8 gvl; /* Global volume */ uint8 chord; /* Chord type */ uint16 hdrsz; /* LDSS header size */ uint16 comp; /* Compression algorithm */ uint32 crc; /* CRC */ uint8 midi_ch; /* MIDI channel */ uint8 rsvd[11]; /* Reserved */ uint8 filename[25]; /* DOS file name */ }; struct liq_pattern { #if 0 uint8 magic[4]; /* 'L', 'P', 0, 0 */ #endif uint8 name[30]; /* ASCIIZ pattern name */ uint16 rows; /* Number of rows */ uint32 size; /* Size of packed pattern */ uint32 reserved; /* Reserved */ }; static int liq_test (HIO_HANDLE *, char *, const int); static int liq_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_liq = { "Liquid Tracker", liq_test, liq_load }; static int liq_test(HIO_HANDLE *f, char *t, const int start) { char buf[15]; if (hio_read(buf, 1, 14, f) < 14) return -1; if (memcmp(buf, "Liquid Module:", 14)) return -1; libxmp_read_title(f, t, 30); return 0; } #define NONE 0xff static const uint8 fx[] = { FX_ARPEGGIO, FX_S3M_BPM, FX_BREAK, FX_PORTA_DN, NONE, FX_FINE_VIBRATO, NONE, NONE, NONE, FX_JUMP, NONE, FX_VOLSLIDE, FX_EXTENDED, FX_TONEPORTA, FX_OFFSET, NONE, /* FIXME: Pan */ NONE, NONE, /*FX_MULTI_RETRIG,*/ FX_S3M_SPEED, FX_TREMOLO, FX_PORTA_UP, FX_VIBRATO, NONE, FX_TONE_VSLIDE, FX_VIBRA_VSLIDE }; /* Effect translation */ static void xlat_fx(int c, struct xmp_event *e) { uint8 h = MSN (e->fxp), l = LSN (e->fxp); switch (e->fxt = fx[e->fxt]) { case FX_EXTENDED: /* Extended effects */ switch (h) { case 0x3: /* Glissando */ e->fxp = l | (EX_GLISS << 4); break; case 0x4: /* Vibrato wave */ if (l == 3) l++; e->fxp = l | (EX_VIBRATO_WF << 4); break; case 0x5: /* Finetune */ e->fxp = l | (EX_FINETUNE << 4); break; case 0x6: /* Pattern loop */ e->fxp = l | (EX_PATTERN_LOOP << 4); break; case 0x7: /* Tremolo wave */ if (l == 3) l++; e->fxp = l | (EX_TREMOLO_WF << 4); break; case 0xc: /* Cut */ e->fxp = l | (EX_CUT << 4); break; case 0xd: /* Delay */ e->fxp = l | (EX_DELAY << 4); break; case 0xe: /* Pattern delay */ e->fxp = l | (EX_PATT_DELAY << 4); break; default: /* Ignore */ e->fxt = e->fxp = 0; break; } break; case NONE: /* No effect */ e->fxt = e->fxp = 0; break; } } static int decode_event(uint8 x1, struct xmp_event *event, HIO_HANDLE *f) { uint8 x2; memset (event, 0, sizeof (struct xmp_event)); if (x1 & 0x01) { x2 = hio_read8(f); if (x2 == 0xfe) event->note = XMP_KEY_OFF; else event->note = x2 + 1 + 36; } if (x1 & 0x02) event->ins = hio_read8(f) + 1; if (x1 & 0x04) event->vol = hio_read8(f); if (x1 & 0x08) event->fxt = hio_read8(f) - 'A'; if (x1 & 0x10) event->fxp = hio_read8(f); D_(D_INFO " event: %02x %02x %02x %02x %02x", event->note, event->ins, event->vol, event->fxt, event->fxp); /* Sanity check */ if (event->note > 107 && event->note != XMP_KEY_OFF) return -1; if (event->ins > 100 || event->vol > 64 || event->fxt > 26) return -1; return 0; } static int liq_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i; struct xmp_event *event = NULL; struct liq_header lh; struct liq_instrument li; struct liq_pattern lp; uint8 x1, x2; uint32 pmag; char tracker_name[21]; LOAD_INIT(); hio_read(&lh.magic, 14, 1, f); hio_read(&lh.name, 30, 1, f); hio_read(&lh.author, 20, 1, f); hio_read8(f); hio_read(&lh.tracker, 20, 1, f); lh.version = hio_read16l(f); lh.speed = hio_read16l(f); lh.bpm = hio_read16l(f); lh.low = hio_read16l(f); lh.high = hio_read16l(f); lh.chn = hio_read16l(f); lh.flags = hio_read32l(f); lh.pat = hio_read16l(f); lh.ins = hio_read16l(f); lh.len = hio_read16l(f); lh.hdrsz = hio_read16l(f); /* Sanity check */ if (lh.chn > XMP_MAX_CHANNELS || lh.pat > 256 || lh.ins > 256) { return -1; } if ((lh.version >> 8) == 0) { lh.hdrsz = lh.len; lh.len = 0; hio_seek(f, -2, SEEK_CUR); } if (lh.len > 256) { return -1; } mod->spd = lh.speed; mod->bpm = lh.bpm; mod->chn = lh.chn; mod->pat = lh.pat; mod->ins = mod->smp = lh.ins; mod->len = lh.len; mod->trk = mod->chn * mod->pat; m->quirk |= QUIRK_INSVOL; strncpy(mod->name, (char *)lh.name, 30); strncpy(tracker_name, (char *)lh.tracker, 20); /* strncpy(m->author, (char *)lh.author, 20); */ tracker_name[20] = 0; for (i = 20; i >= 0; i--) { if (tracker_name[i] == 0x20) tracker_name[i] = 0; if (tracker_name[i]) break; } snprintf(mod->type, XMP_NAME_SIZE, "%s LIQ %d.%02d", tracker_name, lh.version >> 8, lh.version & 0x00ff); if (lh.version > 0) { for (i = 0; i < mod->chn; i++) { uint8 pan = hio_read8(f); if (pan >= 64) { if (pan == 64) { pan = 63; } else if (pan == 66) { pan = 31; mod->xxc[i].flg |= XMP_CHANNEL_SURROUND; } else { /* Sanity check */ return -1; } } mod->xxc[i].pan = pan << 2; } for (i = 0; i < mod->chn; i++) mod->xxc[i].vol = hio_read8(f); hio_read(mod->xxo, 1, mod->len, f); /* Skip 1.01 echo pools */ hio_seek(f, lh.hdrsz - (0x6d + mod->chn * 2 + mod->len), SEEK_CUR); } else { hio_seek(f, start + 0xf0, SEEK_SET); hio_read (mod->xxo, 1, 256, f); hio_seek(f, start + lh.hdrsz, SEEK_SET); for (i = 0; i < 256; i++) { if (mod->xxo[i] == 0xff) break; } mod->len = i; } m->c4rate = C4_NTSC_RATE; MODULE_INFO(); if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); x1 = x2 = 0; for (i = 0; i < mod->pat; i++) { int row, channel, count; if (libxmp_alloc_pattern(mod, i) < 0) return -1; pmag = hio_read32b(f); if (pmag == 0x21212121) /* !!!! */ continue; if (pmag != 0x4c500000) /* LP\0\0 */ return -1; hio_read(&lp.name, 30, 1, f); lp.rows = hio_read16l(f); lp.size = hio_read32l(f); lp.reserved = hio_read32l(f); /* Sanity check */ if (lp.rows > 256) { return -1; } D_(D_INFO "rows: %d size: %d\n", lp.rows, lp.size); mod->xxp[i]->rows = lp.rows; libxmp_alloc_tracks_in_pattern(mod, i); row = 0; channel = 0; count = hio_tell(f); /* * Packed pattern data is stored full Track after full Track from the left to * the right (all Intervals in Track and then going Track right). You should * expect 0C0h on any pattern end, and then your Unpacked Patterndata Pointer * should be equal to the value in offset [24h]; if it's not, you should exit * with an error. */ read_event: /* Sanity check */ if (i >= mod->pat || channel >= mod->chn || row >= mod->xxp[i]->rows) return -1; event = &EVENT(i, channel, row); if (x2) { if (decode_event(x1, event, f) < 0) return -1; xlat_fx (channel, event); x2--; goto next_row; } x1 = hio_read8(f); test_event: /* Sanity check */ if (i >= mod->pat || channel >= mod->chn || row >= mod->xxp[i]->rows) return -1; event = &EVENT(i, channel, row); D_(D_INFO "* count=%ld chan=%d row=%d event=%02x", hio_tell(f) - count, channel, row, x1); switch (x1) { case 0xc0: /* end of pattern */ D_(D_WARN "- end of pattern"); if (hio_tell(f) - count != lp.size) return -1; goto next_pattern; case 0xe1: /* skip channels */ x1 = hio_read8(f); channel += x1; D_(D_INFO " [skip %d channels]", x1); /* fall thru */ case 0xa0: /* next channel */ D_(D_INFO " [next channel]"); channel++; if (channel >= mod->chn) { D_(D_CRIT "uh-oh! bad channel number!"); channel--; } row = -1; goto next_row; case 0xe0: /* skip rows */ x1 = hio_read8(f); D_(D_INFO " [skip %d rows]", x1); row += x1; /* fall thru */ case 0x80: /* next row */ D_(D_INFO " [next row]"); goto next_row; } if (x1 > 0xc0 && x1 < 0xe0) { /* packed data */ D_(D_INFO " [packed data]"); if (decode_event(x1, event, f) < 0) return -1; xlat_fx (channel, event); goto next_row; } if (x1 > 0xa0 && x1 < 0xc0) { /* packed data repeat */ x2 = hio_read8(f); D_(D_INFO " [packed data - repeat %d times]", x2); if (decode_event(x1, event, f) < 0) return -1; xlat_fx (channel, event); goto next_row; } if (x1 > 0x80 && x1 < 0xa0) { /* packed data repeat, keep note */ x2 = hio_read8(f); D_(D_INFO " [packed data - repeat %d times, keep note]", x2); if (decode_event(x1, event, f) < 0) return -1; xlat_fx (channel, event); while (x2) { row++; /* Sanity check */ if (row >= lp.rows) return -1; memcpy(&EVENT(i, channel, row), event, sizeof (struct xmp_event)); x2--; } goto next_row; } /* unpacked data */ D_ (D_INFO " [unpacked data]"); if (x1 < 0xfe) event->note = 1 + 36 + x1; else if (x1 == 0xfe) event->note = XMP_KEY_OFF; x1 = hio_read8(f); if (x1 > 100) { row++; goto test_event; } if (x1 != 0xff) event->ins = x1 + 1; x1 = hio_read8(f); if (x1 != 0xff) event->vol = x1; x1 = hio_read8(f); if (x1 != 0xff) event->fxt = x1 - 'A'; x1 = hio_read8(f); event->fxp = x1; /* Sanity check */ if (event->fxt > 24) { return -1; } xlat_fx(channel, event); D_(D_INFO " event: %02x %02x %02x %02x %02x\n", event->note, event->ins, event->vol, event->fxt, event->fxp); /* Sanity check */ if (event->note > 119 && event->note != XMP_KEY_OFF) return -1; if (event->ins > 100 || event->vol > 65) return -1; next_row: row++; if (row >= mod->xxp[i]->rows) { row = 0; x2 = 0; channel++; } /* Sanity check */ if (channel >= mod->chn) { channel = 0; } goto read_event; next_pattern: ; } /* Read and convert instruments */ if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->ins); for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_subinstrument *sub; struct xmp_sample *xxs = &mod->xxs[i]; unsigned char b[4]; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; hio_read (&b, 1, 4, f); if (b[0] == '?' && b[1] == '?' && b[2] == '?' && b[3] == '?') continue; if (b[0] != 'L' || b[1] != 'D' || b[2] != 'S' || b[3] != 'S') return -1; li.version = hio_read16l(f); hio_read(&li.name, 30, 1, f); hio_read(&li.editor, 20, 1, f); hio_read(&li.author, 20, 1, f); li.hw_id = hio_read8(f); li.length = hio_read32l(f); li.loopstart = hio_read32l(f); li.loopend = hio_read32l(f); li.c2spd = hio_read32l(f); li.vol = hio_read8(f); li.flags = hio_read8(f); li.pan = hio_read8(f); li.midi_ins = hio_read8(f); li.gvl = hio_read8(f); li.chord = hio_read8(f); li.hdrsz = hio_read16l(f); li.comp = hio_read16l(f); li.crc = hio_read32l(f); li.midi_ch = hio_read8(f); hio_read(&li.rsvd, 11, 1, f); hio_read(&li.filename, 25, 1, f); xxi->nsm = !!(li.length); xxi->vol = 0x40; xxs->len = li.length; xxs->lps = li.loopstart; xxs->lpe = li.loopend; if (li.flags & 0x01) { xxs->flg = XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } if (li.loopend > 0) xxs->flg = XMP_SAMPLE_LOOP; /* FIXME: LDSS 1.0 have global vol == 0 ? */ /* if (li.gvl == 0) */ li.gvl = 0x40; sub->vol = li.vol; sub->gvl = li.gvl; sub->pan = li.pan; sub->sid = i; libxmp_instrument_name(mod, i, li.name, 31); D_(D_INFO "[%2X] %-30.30s %05x%c%05x %05x %c %02x %02x %2d.%02d %5d", i, mod->xxi[i].name, mod->xxs[i].len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ', xxs->lps, xxs->lpe, xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->gvl, li.version >> 8, li.version & 0xff, li.c2spd); libxmp_c2spd_to_note(li.c2spd, &sub->xpo, &sub->fin); hio_seek(f, li.hdrsz - 0x90, SEEK_CUR); if (xxs->len == 0) continue; if (libxmp_load_sample(m, f, 0, xxs, NULL) < 0) return -1; } m->quirk |= QUIRKS_ST3; m->read_event_type = READ_EVENT_ST3; return 0; } libxmp-4.4.1/src/loaders/asif.h0000664000175000017500000000024012773463501016156 0ustar claudioclaudio#ifndef XMP_ASIF_H #define XMP_ASIF_H #include #include "common.h" #include "hio.h" int asif_load(struct module_data *, HIO_HANDLE *, int); #endif libxmp-4.4.1/src/loaders/prowizard/0000775000175000017500000000000012777546220017114 5ustar claudioclaudiolibxmp-4.4.1/src/loaders/prowizard/heatseek.c0000664000175000017500000001030412706551122021034 0ustar claudioclaudio/* * Heatseeker_mc1.0.c Copyright (C) 1997 Asle / ReDoX * * Converts back to ptk Heatseeker packed MODs * * Asle's note: There's a good job ! .. gosh !. * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_crb(HIO_HANDLE *in, FILE *out) { uint8 c1; uint8 ptable[128]; uint8 pat_pos, pat_max; uint8 pat[1024]; int taddr[512]; int i, j, k, l, m; int size, ssize = 0; memset(ptable, 0, 128); memset(taddr, 0, 512 * 4); pw_write_zero(out, 20); /* write title */ /* read and write sample descriptions */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /*sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ size = hio_read16b(in); /* loop size */ write16b(out, size ? size : 1); } write8(out, pat_pos = hio_read8(in)); /* pat table length */ write8(out, hio_read8(in)); /* NoiseTracker byte */ /* read and write pattern list and get highest patt number */ for (pat_max = i = 0; i < 128; i++) { write8(out, c1 = hio_read8(in)); if (c1 > pat_max) pat_max = c1; } pat_max++; /* write ptk's ID */ write32b(out, PW_MOD_MAGIC); /* pattern data */ for (i = 0; i < pat_max; i++) { memset(pat, 0, 1024); for (j = 0; j < 4; j++) { int x = hio_tell(in); if (x < 0) { return -1; } taddr[i * 4 + j] = x; for (k = 0; k < 64; k++) { int y = k * 16 + j * 4; c1 = hio_read8(in); if (c1 == 0x80) { k += hio_read24b(in); continue; } if (c1 == 0xc0) { m = hio_read24b(in); l = hio_tell(in); /* Sanity check */ if (l < 0 || m >= 2048) return -1; hio_seek(in, taddr[m >> 2], SEEK_SET); for (m = 0; m < 64; m++) { int x = m * 16 + j * 4; c1 = hio_read8(in); if (c1 == 0x80) { m += hio_read24b(in); continue; } pat[x] = c1; pat[x + 1] = hio_read8(in); pat[x + 2] = hio_read8(in); pat[x + 3] = hio_read8(in); } hio_seek(in, l, SEEK_SET); k += 100; continue; } pat[y] = c1; pat[y + 1] = hio_read8(in); pat[y + 2] = hio_read8(in); pat[y + 3] = hio_read8(in); } } fwrite (pat, 1024, 1, out); } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_crb(uint8 *data, char *t, int s) { int i, j, k; int ssize, max, idx; PW_REQUEST_DATA (s, 378); /* size of the pattern table */ if (data[248] > 0x7f || data[248] == 0x00) return -1; /* test noisetracker byte */ if (data[249] != 0x7f) return -1; /* test samples */ ssize = 0; for (i = 0; i < 31; i++) { int len, start, lsize; uint8 *d = data + i * 8; if (d[2] > 0x0f) return -1; /* test volumes */ if (d[3] > 0x40) return -1; len = readmem16b(d) << 1; /* size */ start = readmem16b(d + 4) << 1; /* loop start */ lsize = readmem16b(d + 6) << 1; /* loop size */ if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (lsize != 0 && lsize != 2 && (start + lsize) > len) return -1; if (start != 0 && lsize <= 2) return -1; ssize += len; } /* printf ("3\n"); */ if (ssize <= 4) return -1; /* test pattern table */ { uint8 *d = data + 250; max = 0; for (i = 0; i < 128; i++) { if (d[i] > 0x7f) return -1; if (d[i] > max) max = data[250 + i]; } /* FIXME */ PW_REQUEST_DATA(s, 379 + 4 * max * 4 * 64); } /* test notes */ idx = 0; for (i = 0; i <= max; i++) { for (j = 0; j < 4; j++) { for (k = 0; k < 64; k++) { uint8 *d = data + 378 + idx; switch (d[0] & 0xC0) { case 0x00: if ((d[0] & 0x0F) > 0x03) return -1; idx += 4; break; case 0x80: if (d[1] != 0) return -1; k += d[3]; idx += 4; break; case 0xC0: if (d[1] != 0) return -1; k = 100; idx += 4; break; default: break; } } } } /* k is the size of the pattern data */ /* ssize is the size of the sample data */ pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_crb = { "Heatseeker 1.0", test_crb, depack_crb }; libxmp-4.4.1/src/loaders/prowizard/tp1.c0000664000175000017500000000752012706551122017755 0ustar claudioclaudio/* * TrackerPacker_v1.c Copyright (C) 1998 Asle / ReDoX * * Converts TP1 packed MODs back to PTK MODs * * Modified in 2016 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_tp1(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4; uint8 pnum[128]; uint8 pdata[1024]; uint8 note, ins, fxt, fxp; uint8 npat = 0x00; uint8 len; int i, j; int pat_ofs = 999999; int paddr[128]; int paddr_ord[128]; int size, ssize = 0; int smp_ofs; memset(paddr, 0, 128 * 4); memset(paddr_ord, 0, 128 * 4); memset(pnum, 0, 128); hio_read32b(in); /* skip magic */ hio_read32b(in); /* skip size */ pw_move_data(out, in, 20); /* title */ smp_ofs = hio_read32b(in); /* sample data address */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ c3 = hio_read8(in); /* read finetune */ c4 = hio_read8(in); /* read volume */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, c3); /* write finetune */ write8(out, c4); /* write volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } /* read size of pattern table */ len = hio_read16b(in) + 1; write8(out, len); /* ntk byte */ write8(out, 0x7f); for (i = 0; i < len; i++) { paddr[i] = hio_read32b(in); if (hio_error(in)) { return -1; } if (pat_ofs > paddr[i]) { pat_ofs = paddr[i]; } } /* ordering of pattern addresses */ pnum[0] = 0; paddr_ord[0] = paddr[0]; npat = 1; for (i = 1; i < len; i++) { for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) { paddr_ord[npat] = paddr[i]; pnum[i] = npat++; } } fwrite(pnum, 128, 1, out); /* write pattern list */ write32b(out, PW_MOD_MAGIC); /* ID string */ /* pattern datas */ for (i = 0; i < npat; i++) { if (hio_seek(in, 794 + paddr_ord[i] - pat_ofs, SEEK_SET) < 0) { return -1; } memset(pdata, 0, 1024); for (j = 0; j < 256; j++) { uint8 *p = pdata + j * 4; c1 = hio_read8(in); if (c1 == 0xc0) { continue; } if ((c1 & 0xc0) == 0x80) { fxt = (c1 >> 2) & 0x0f; fxp = hio_read8(in); p[2] = fxt; p[3] = fxp; continue; } c2 = hio_read8(in); c3 = hio_read8(in); note = (c1 & 0xfe) >> 1; if (note > 36) { return -1; } ins = ((c2 >> 4) & 0x0f) | ((c1 << 4) & 0x10); fxt = c2 & 0x0f; fxp = c3; p[0] = (ins & 0xf0) | ptk_table[note][0]; p[1] = ptk_table[note][1]; p[2] = ((ins << 4) & 0xf0) | fxt; p[3] = fxp; } fwrite(pdata, 1024, 1, out); } /* Sample data */ if (hio_seek(in, smp_ofs, SEEK_SET) < 0) { return -1; } pw_move_data(out, in, ssize); return 0; } static int test_tp1(uint8 *data, char *t, int s) { int i; int len, size, smp_ofs; PW_REQUEST_DATA(s, 1024); if (memcmp(data, "MEXX", 4)) { return -1; } /* size of the module */ size = readmem32b(data + 4); if (size < 794 || size > 2129178) { return -1; } for (i = 0; i < 31; i++) { uint8 *d = data + i * 8 + 32; /* test finetunes */ if (d[0] > 0x0f) return -1; /* test volumes */ if (d[1] > 0x40) return -1; } /* sample data address */ smp_ofs = readmem32b(data + 28); if (smp_ofs == 0 || smp_ofs > size) { return -1; } /* test sample sizes */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 8 + 32; int len = readmem16b(d + 2) << 1; /* size */ int start = readmem16b(d + 4) << 1; /* loop start */ int lsize = readmem16b(d + 6) << 1; /* loop size */ if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > len + 2) return -1; if (start != 0 && lsize == 0) return -1; } /* pattern list size */ len = data[281]; if (len == 0 || len > 128) { return -1; } return 0; } const struct pw_format pw_tp1 = { "Tracker Packer v1", test_tp1, depack_tp1 }; libxmp-4.4.1/src/loaders/prowizard/pm18a.c0000664000175000017500000001123112706551122020171 0ustar claudioclaudio/* * Promizer_18a.c Copyright (C) 1997 Asle / ReDoX * * Converts PM18a packed MODs back to PTK MODs * thanks to Gryzor and his ProWizard tool ! ... without it, this prog * would not exist !!! * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_p18a(HIO_HANDLE *in, FILE *out) { short pat_max; int tmp_ptr; int refmax; uint8 pnum[128]; int paddr[128]; short pptr[64][256]; int num_pat; uint8 *reftab; uint8 pat[128][1024]; int i, j, k, l; int size, ssize; int psize; int smp_ofs; uint8 fin[31]; uint8 oldins[4]; memset(pnum, 0, 128); memset(pptr, 0, 64 << 8); memset(pat, 0, 128 * 1024); memset(fin, 0, 31); memset(oldins, 0, 4); memset(paddr, 0, 128 * 4); pw_write_zero(out, 20); /* title */ /* bypass replaycode routine */ hio_seek(in, 4464, SEEK_SET); ssize = 0; for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); ssize += size * 2; write8(out, fin[i] = hio_read8(in)); /* finetune table */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } num_pat = hio_read16b(in) / 4; /* pat table length */ /* Sanity check */ if (num_pat > 128) { return -1; } write8(out, num_pat); write8(out, 0x7f); /* NoiseTracker byte */ for (i = 0; i < 128; i++) paddr[i] = hio_read32b(in); /* ordering of patterns addresses */ tmp_ptr = 0; for (i = 0; i < num_pat; i++) { if (i == 0) { pnum[0] = 0; tmp_ptr++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) pnum[i] = tmp_ptr++; } pat_max = tmp_ptr - 1; fwrite(pnum, 128, 1, out); /* pattern table */ write32b(out, PW_MOD_MAGIC); /* M.K. */ /* a little pre-calc code ... no other way to deal with these unknown * pattern data sizes ! :( */ hio_seek(in, 4460, SEEK_SET); psize = hio_read32b(in); hio_seek(in, 5226, SEEK_SET); /* back to pattern data start */ /* now, reading all pattern data to get the max value of note */ refmax = 0; for (j = 0; j < psize; j += 2) { int x = hio_read16b(in); if (hio_error(in)) { return -1; } if (x > refmax) refmax = x; } /* read "reference table" */ refmax += 1; /* 1st value is 0 ! */ i = refmax * 4; /* each block is 4 bytes long */ if ((reftab = (uint8 *)malloc(i)) == NULL) { return -1; } hio_read(reftab, i, 1, in); hio_seek(in, 5226, SEEK_SET); /* back to pattern data start */ for (j = 0; j <= pat_max; j++) { int flag = 0; hio_seek(in, paddr[j] + 5226, 0); for (i = 0; i < 64; i++) { for (k = 0; k < 4; k++) { uint8 *p = &pat[j][i * 16 + k * 4]; int x = hio_read16b(in) << 2; int fine, ins, per, fxt; memcpy(p, &reftab[x], 4); ins = ((p[2] >> 4) & 0x0f) | (p[0] & 0xf0); if (ins != 0) { oldins[k] = ins; } per = ((p[0] & 0x0f) << 8) | p[1]; fxt = p[2] & 0x0f; if (oldins[k] > 0 && oldins[k] < 32) { fine = fin[oldins[k] - 1]; } else { fine = 0; } /* Sanity check */ if (fine >= 16) { goto err; } if (per != 0 && oldins[k] > 0 && fine != 0) { for (l = 0; l < 36; l++) { if (tun_table[fine][l] == per) { p[0] &= 0xf0; p[0] |= ptk_table[l + 1][0]; p[1] = ptk_table[l + 1][1]; break; } } } if (fxt == 0x0d || fxt == 0x0b) { flag = 1; } } if (flag == 1) { break; } } fwrite(pat[j], 1024, 1, out); } /* printf ( "Highest value in pattern data : %d\n" , refmax ); */ free(reftab); hio_seek(in, 4456, SEEK_SET); smp_ofs = hio_read32b(in); hio_seek(in, 4460 + smp_ofs, SEEK_SET); /* Now, it's sample data ... though, VERY quickly handled :) */ pw_move_data(out, in, ssize); return 0; err: free(reftab); return -1; } static int test_p18a(uint8 * data, char *t, int s) { uint8 magic[] = { 0x60, 0x38, 0x60, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x01, 0x3e, 0x60, 0x00, 0x01, 0x0c, 0x48, 0xe7 }; /* test 1 */ PW_REQUEST_DATA(s, 22); if (memcmp(data, magic, 16) != 0) return -1; /* test 2 */ if (data[21] != 0xd2) return -1; #if 0 /* test 3 */ PW_REQUEST_DATA(s, 4460); j = readmem32b(data + 4456); if ((start + j + 4456) > in_size) { Test = BAD; return; } #endif /* test 4 */ PW_REQUEST_DATA(s, 4714); if (readmem16b(data + 4712) & 0x03) return -1; /* test 5 */ if (data[36] != 0x11) return -1; /* test 6 */ if (data[37] != 0x00) return -1; pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_p18a = { "Promizer 1.8a", test_p18a, depack_p18a }; libxmp-4.4.1/src/loaders/prowizard/titanics.c0000664000175000017500000000776112706551122021076 0ustar claudioclaudio/* * TitanicsPlayer.c Copyright (C) 2007 Sylvain "Asle" Chipaux * * Modified in 2009,2014 by Claudio Matsuoka */ /* * Titan Trax vol. 1: http://www.youtube.com/watch?v=blgm0EcPUd8 */ #include #include #include "prowiz.h" /* With the help of Xigh :) .. thx */ static int cmplong(const void *a, const void *b) { return *(int *)a == *(int *)b ? 0 : *(int *)a > *(int *)b ? 1 : -1; } static int depack_titanics(HIO_HANDLE *in, FILE *out) { uint8 buf[1024]; long pat_addr[128]; long pat_addr_ord[128]; long pat_addr_final[128]; long max = 0l; uint8 pat; uint32 smp_addr[15]; uint16 smp_size[15]; int i, j, k; for (i = 0; i < 128; i++) pat_addr[i] = pat_addr_ord[i] = pat_addr_final[i] = 0; pw_write_zero(out, 20); /* write title */ for (i = 0; i < 15; i++) { smp_addr[i] = hio_read32b(in); pw_write_zero(out, 22); /* write name */ write16b(out, smp_size[i] = hio_read16b(in)); smp_size[i] *= 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } for (i = 15; i < 31; i++) { pw_write_zero(out, 22); /* write name */ write16b(out, 0); /* sample size */ write8(out, 0); /* finetune */ write8(out, 0x40); /* volume */ write16b(out, 0); /* loop start */ write16b(out, 1); /* loop size */ } /* pattern list */ hio_read(buf, 2, 128, in); for (pat = 0; pat < 128; pat++) { if (buf[pat * 2] == 0xff) break; pat_addr_ord[pat] = pat_addr[pat] = readmem16b(buf + pat * 2); } write8(out, pat); /* patterns */ write8(out, 0x7f); /* write ntk byte */ /* With the help of Xigh :) .. thx */ qsort(pat_addr_ord, pat, sizeof(long), cmplong); for (j = i = 0; i < pat; i++) { pat_addr_final[j++] = pat_addr_ord[i]; while (pat_addr_ord[i + 1] == pat_addr_ord[i] && i < pat) i++; } memset(buf, 0, 128); /* write pattern list */ for (i = 0; i < pat; i++) { for (j = 0; pat_addr[i] != pat_addr_final[j]; j++) ; buf[i] = j; if (j > max) max = j; } fwrite(buf, 128, 1, out); write32b(out, PW_MOD_MAGIC); /* write M.K. */ /* pattern data */ for (i = 0; i <= max; i++) { uint8 x, y, c; int note; hio_seek(in, pat_addr_final[i], SEEK_SET); memset(buf, 0, 1024); x = hio_read8(in); for (k = 0; k < 64; ) { /* row number */ y = hio_read8(in); c = (y >> 6) * 4; /* channel */ note = y & 0x3f; if (note <= 36) { buf[k * 16 + c] = ptk_table[note][0]; buf[k * 16 + c + 1] = ptk_table[note][1]; } buf[k * 16 + c + 2] = hio_read8(in); buf[k * 16 + c + 3] = hio_read8(in); if (x & 0x80) break; /* next event */ x = hio_read8(in); k += x & 0x7f; } fwrite(&buf[0], 1024, 1, out); } /* sample data */ for (i = 0; i < 15; i++) { if (smp_addr[i]) { hio_seek(in, smp_addr[i], SEEK_SET); pw_move_data(out, in, smp_size[i]); } } return 0; } static int test_titanics(uint8 *data, char *t, int s) { int i; int ssize; PW_REQUEST_DATA(s, 182); /* test samples */ ssize = 0; for (i = 0; i < 15; i++) { int len, start, lsize; int addr; uint8 *d = data + i * 12; if (d[7] > 0x40) return -1; if (d[6] != 0) return -1; addr = readmem32b(d); if (/*addr > in_size ||*/ addr != 0 && addr < 180) return -1; len = readmem16b(d + 4); /* size */ start = readmem16b(d + 8); /* loop start */ lsize = readmem16b(d + 10); /* loop size */ if (start > len || lsize > (len + 1) || len > 32768) return -1; if (lsize == 0) return -1; if (len == 0 && (start != 0 || lsize != 1)) return -1; ssize += len; } if (ssize < 2) { return -1; } /* test pattern addresses */ { int addr = 0; for (i = 0; i < 256; i += 2) { addr = readmem16b(data + i + 180); if (addr == 0xffff) break; if (addr < 180) return -1; } if (addr != 0xffff) { return -1; } } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_titanics = { "Titanics Player", test_titanics, depack_titanics }; libxmp-4.4.1/src/loaders/prowizard/zen.c0000664000175000017500000001026412706551122020044 0ustar claudioclaudio/* * Zen_Packer.c Copyright (C) 1998 Asle / ReDoX * * Converts ZEN packed MODs back to PTK MODs * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_zen(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4; uint8 finetune, vol; uint8 pat_pos; uint8 pat_max; uint8 note, ins, fxt, fxp; uint8 pat[1024]; uint8 ptable[128]; int size, ssize = 0; int paddr[128]; int paddr2[128]; int ptable_addr; int sdata_addr = 999999l; int i, j, k; memset(paddr, 0, 128 * 4); memset(paddr2, 0, 128 * 4); memset(ptable, 0, 128); ptable_addr = hio_read32b(in); /* read pattern table address */ pat_max = hio_read8(in); /* read patmax */ pat_pos = hio_read8(in); /* read size of pattern table */ /* Sanity check */ if (pat_pos >= 128 || pat_max >= 128) { return -1; } pw_write_zero(out, 20); /* write title */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ finetune = hio_read16b(in) / 0x48; /* read finetune */ hio_read8(in); vol = hio_read8(in); /* read volume */ write16b(out, size = hio_read16b(in)); /* read sample size */ ssize += size * 2; write8(out, finetune); /* write finetune */ write8(out, vol); /* write volume */ size = hio_read16b(in); /* read loop size */ k = hio_read32b(in); /* sample start addr */ if (k < sdata_addr) { sdata_addr = k; } /* read loop start address */ j = (hio_read32b(in) - k) / 2; write16b(out, j); /* write loop start */ write16b(out, size); /* write loop size */ } write8(out, pat_pos); /* write size of pattern list */ write8(out, 0x7f); /* write ntk byte */ /* read pattern table */ hio_seek(in, ptable_addr, SEEK_SET); for (i = 0; i < pat_pos; i++) paddr[i] = hio_read32b(in); /* deduce pattern list */ c4 = 0; for (i = 0; i < pat_pos; i++) { if (i == 0) { ptable[0] = 0; paddr2[0] = paddr[0]; c4++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { ptable[i] = ptable[j]; break; } } if (j == i) { paddr2[c4] = paddr[i]; ptable[i] = c4; c4++; } } fwrite(ptable, 128, 1, out); /* write pattern table */ write32b(out, PW_MOD_MAGIC); /* write ptk ID */ /* pattern data */ /*printf ( "converting pattern datas " ); */ for (i = 0; i <= pat_max; i++) { memset(pat, 0, 1024); hio_seek(in, paddr2[i], SEEK_SET); for (j = 0; j < 256; j++) { uint8 *p; c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); note = (c2 & 0x7f) / 2; fxp = c4; ins = ((c2 << 4) & 0x10) | ((c3 >> 4) & 0x0f); fxt = c3 & 0x0f; p = pat + c1 * 4; p[0] = ins & 0xf0; p[0] |= ptk_table[note][0]; p[1] = ptk_table[note][1]; p[2] = fxt | ((ins << 4) & 0xf0); p[3] = fxp; j = c1; } fwrite (pat, 1024, 1, out); } /* sample data */ hio_seek(in, sdata_addr, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_zen(uint8 *data, char *t, int s) { int i; int len, pat_ofs; PW_REQUEST_DATA(s, 9 + 16 * 31); /* test #2 */ pat_ofs = readmem32b(data); if (pat_ofs < 502 || pat_ofs > 2163190L) return -1; for (i = 0; i < 31; i++) { uint8 *d = data + 16 * i; if (d[9] > 0x40) return -1; /* finetune */ if (readmem16b(d + 6) % 72) return -1; } /* smp sizes .. */ for (i = 0; i < 31; i++) { int size = readmem16b(data + 10 + i * 16) << 1; int lsize = readmem16b(data + 12 + i * 16) << 1; int sdata = readmem32b(data + 14 + i * 16); /* sample size and loop size > 64k ? */ if (size > 0xffff || lsize > 0xffff) return -1; /* sample address < pattern table address? */ if (sdata < pat_ofs) return -1; #if 0 /* too big an address ? */ if (sdata > in_size) { Test = BAD; return; } #endif } /* test size of the pattern list */ len = data[5]; if (len == 0 || len > 0x7f) return -1; PW_REQUEST_DATA(s, pat_ofs + len * 4 + 4); /* test if the end of pattern list is $FFFFFFFF */ if (readmem32b(data + pat_ofs + len * 4) != 0xffffffff) return -1; /* n is the highest address of a sample data */ /* ssize is its size */ pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_zen = { "Zen Packer", test_zen, depack_zen }; libxmp-4.4.1/src/loaders/prowizard/prun1.c0000664000175000017500000000374312706551122020321 0ustar claudioclaudio/* * ProRunner1.c Copyright (C) 1996 Asle / ReDoX * * Converts MODs packed with Prorunner v1.0 * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_pru1 (HIO_HANDLE *in, FILE *out) { uint8 header[2048]; uint8 c1, c2, c3, c4; uint8 npat, max; uint8 ptable[128]; int ssize = 0; int i, j; memset(header, 0, 2048); memset(ptable, 0, 128); /* read and write whole header */ hio_read(header, 950, 1, in); fwrite(header, 950, 1, out); /* get whole sample size */ for (i = 0; i < 31; i++) { ssize += readmem16b(header + i * 30 + 42) * 2; } /* read and write size of pattern list */ write8(out, npat = hio_read8(in)); memset(header, 0, 2048); /* read and write ntk byte and pattern list */ hio_read(header, 129, 1, in); fwrite(header, 129, 1, out); /* write ID */ write32b(out, PW_MOD_MAGIC); /* get number of pattern */ max = 0; for (i = 1; i < 129; i++) { if (header[i] > max) max = header[i]; } /* pattern data */ hio_seek(in, 1084, SEEK_SET); for (i = 0; i <= max; i++) { for (j = 0; j < 256; j++) { header[0] = hio_read8(in); header[1] = hio_read8(in); header[2] = hio_read8(in); header[3] = hio_read8(in); /* Sanity check */ if (header[1] >= 37) { return -1; } c1 = header[0] & 0xf0; c3 = (header[0] & 0x0f) << 4; c3 |= header[2]; c4 = header[3]; c1 |= ptk_table[header[1]][0]; c2 = ptk_table[header[1]][1]; write8(out, c1); write8(out, c2); write8(out, c3); write8(out, c4); } } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_pru1(uint8 *data, char *t, int s) { PW_REQUEST_DATA(s, 1084); if (readmem32b(data + 1080) != 0x534e542e) /* "SNT." */ return -1; /* test 2 */ if (data[951] != 0x7f) return -1; /* test 3 */ if (data[950] > 0x7f) return -1; pw_read_title(data, t, 20); return 0; } const struct pw_format pw_pru1 = { "Prorunner 1.0", test_pru1, depack_pru1 }; libxmp-4.4.1/src/loaders/prowizard/pm.c0000664000175000017500000000520512706551122017663 0ustar claudioclaudio/* * PowerMusic.c 1996 (c) Asle / ReDoX * * Converts back to ptk Optimod's power music files * */ #include #include void Depack_PM (FILE * in, FILE * out) { uint8 Header[2048]; signed char *tmp; signed char *ins_Data; uint8 c1 = 0x00, c2 = 0x00, c3 = 0x00; uint8 npat = 0x00; uint8 ptable[128]; uint8 Max = 0x00; long ssize = 0; long i = 0; // HIO_HANDLE *in,*out; if (Save_Status == BAD) return; memset(Header, 0, 2048); memset(ptable, 0, 128); // in = fdopen (fd_in, "rb"); // sprintf ( Depacked_OutName , "%ld.mod" , Cpt_Filename-1 ); // out = fdopen (fd_out, "w+b"); /* read and write whole header */ fseek (in, 0, SEEK_SET); fread (Header, 950, 1, in); fwrite (Header, 950, 1, out); /* get whole sample size */ for (i = 0; i < 31; i++) ssize += (((Header[42 + i * 30] << 8) + Header[43 + i * 30]) * 2); /*printf ( "Whole sanple size : %ld\n" , ssize ); */ /* read and write size of pattern list */ fread (&npat, 1, 1, in); fwrite (&npat, 1, 1, out); /*printf ( "Size of pattern list : %d\n" , npat ); */ memset(Header, 0, 2048); /* read and write ntk byte and pattern list */ fread (Header, 129, 1, in); Header[0] = 0x7f; fwrite (Header, 129, 1, out); /* write ID */ c1 = 'M'; c2 = '.'; c3 = 'K'; fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fwrite (&c3, 1, 1, out); fwrite (&c2, 1, 1, out); /* get number of pattern */ Max = 0x00; for (i = 1; i < 129; i++) { if (Header[i] > Max) Max = Header[i]; } Max += 1; /*printf ( "Number of pattern : %d\n" , Max ); */ /* pattern data */ fseek (in, 1084, SEEK_SET); tmp = (uint8 *) malloc (Max * 1024); memset(tmp, 0, Max * 1024); fread (tmp, Max * 1024, 1, in); fwrite (tmp, Max * 1024, 1, out); free (tmp); /* sample data */ tmp = (signed char *) malloc (ssize); ins_Data = (signed char *) malloc (ssize); memset(tmp, 0, ssize); memset(ins_Data, 0, ssize); fread (tmp, ssize, 1, in); ins_Data[0] = tmp[0]; for (i = 1; i < ssize - 1; i++) { ins_Data[i] = ins_Data[i - 1] + tmp[i]; } fwrite (ins_Data, ssize, 1, out); free (tmp); free (ins_Data); /* crap */ Crap ("PM:Power Music", BAD, BAD, out); fflush (in); fflush (out); printf ("done\n"); return; /* useless ... but */ } /* Power Music */ int testPM (void) { if ((data[i] != '!') || (data[i + 1] != 'P') || (data[i + 2] != 'M') || (data[i + 3] != '!')) return BAD; /* test 1 */ if (i < 1080) return BAD; /* test 2 */ start = i - 1080; for (j = 0; j < 31; j++) { if (data[start + 45 + 30 * j] > 0x40) return BAD; } /* test 3 */ if (data[start + 951] != 0xFF) return BAD; return GOOD; } libxmp-4.4.1/src/loaders/prowizard/prowiz.h0000664000175000017500000000562312706551122020612 0ustar claudioclaudio#ifndef PROWIZ_H #define PROWIZ_H #include #include "list.h" #include "common.h" #include "format.h" #include "hio.h" #define MIN_FILE_LENGHT 2048 #define PW_TEST_CHUNK 0x10000 #define MAGIC4(a,b,c,d) \ (((uint32)(a)<<24)|((uint32)(b)<<16)|((uint32)(c)<<8)|(d)) #define PW_MOD_MAGIC MAGIC4('M','.','K','.') #define PW_REQUEST_DATA(s,n) \ do { if ((s)<(n)) return ((n)-(s)); } while (0) /* * depackb() and depackf() perform the same action reading the packed * module from a buffer or a file. We're supporting both protocols to * to avoid rewriting Asle's functions. */ struct pw_format { char *name; int (*test)(uint8 *, char *, int); int (*depack)(HIO_HANDLE *, FILE *); struct list_head list; }; int pw_wizardry(HIO_HANDLE *, FILE *, char **); int pw_move_data(FILE *, HIO_HANDLE *, int); int pw_write_zero(FILE *, int); /* int pw_enable(char *, int); */ int pw_check(unsigned char *, int, struct xmp_test_info *); void pw_read_title(unsigned char *, char *, int); extern const uint8 ptk_table[37][2]; extern const short tun_table[16][36]; extern const struct pw_format pw_ac1d; extern const struct pw_format pw_crb; extern const struct pw_format pw_di; extern const struct pw_format pw_eu; extern const struct pw_format pw_emod; extern const struct pw_format pw_fcm; extern const struct pw_format pw_fchs; extern const struct pw_format pw_fuzz; extern const struct pw_format pw_gmc; extern const struct pw_format pw_hrt; extern const struct pw_format pw_kris; extern const struct pw_format pw_ksm; extern const struct pw_format pw_mp_id; extern const struct pw_format pw_mp_noid; extern const struct pw_format pw_np1; extern const struct pw_format pw_np2; extern const struct pw_format pw_np3; extern const struct pw_format pw_nru; extern const struct pw_format pw_ntp; extern const struct pw_format pw_pm01; extern const struct pw_format pw_p10c; extern const struct pw_format pw_p18a; extern const struct pw_format pw_p20; extern const struct pw_format pw_p4x; extern const struct pw_format pw_p50a; extern const struct pw_format pw_p60a; extern const struct pw_format pw_p61a; extern const struct pw_format pw_pha; extern const struct pw_format pw_pp10; extern const struct pw_format pw_pp21; extern const struct pw_format pw_pp30; extern const struct pw_format pw_pru1; extern const struct pw_format pw_pru2; extern const struct pw_format pw_skyt; extern const struct pw_format pw_starpack; extern const struct pw_format pw_stim; extern const struct pw_format pw_tdd; extern const struct pw_format pw_titanics; extern const struct pw_format pw_tp1; extern const struct pw_format pw_tp2; extern const struct pw_format pw_tp3; extern const struct pw_format pw_unic_emptyid; extern const struct pw_format pw_unic_id; extern const struct pw_format pw_unic_noid; extern const struct pw_format pw_unic2; extern const struct pw_format pw_wn; extern const struct pw_format pw_xann; extern const struct pw_format pw_zen; #endif libxmp-4.4.1/src/loaders/prowizard/ptktable.c0000664000175000017500000000171312641457214021062 0ustar claudioclaudio #include "prowiz.h" const uint8 ptk_table[37][2] = { { 0x00, 0x00 }, { 0x03, 0x58 }, { 0x03, 0x28 }, { 0x02, 0xfa }, { 0x02, 0xd0 }, { 0x02, 0xa6 }, { 0x02, 0x80 }, /* 1 */ { 0x02, 0x5c }, { 0x02, 0x3a }, { 0x02, 0x1a }, { 0x01, 0xfc }, { 0x01, 0xe0 }, { 0x01, 0xc5 }, { 0x01, 0xac }, { 0x01, 0x94 }, { 0x01, 0x7d }, { 0x01, 0x68 }, { 0x01, 0x53 }, { 0x01, 0x40 }, /* 2 */ { 0x01, 0x2e }, { 0x01, 0x1d }, { 0x01, 0x0d }, { 0x00, 0xfe }, { 0x00, 0xf0 }, { 0x00, 0xe2 }, { 0x00, 0xd6 }, { 0x00, 0xca }, { 0x00, 0xbe }, { 0x00, 0xb4 }, { 0x00, 0xaa }, { 0x00, 0xa0 }, /* 3 */ { 0x00, 0x97 }, { 0x00, 0x8f }, { 0x00, 0x87 }, { 0x00, 0x7f }, { 0x00, 0x78 }, { 0x00, 0x71 } }; libxmp-4.4.1/src/loaders/prowizard/di.c0000664000175000017500000001104712706551122017644 0ustar claudioclaudio/* * Digital_Illusion.c Copyright (C) 1997 Asle / ReDoX * * Converts DI packed MODs back to PTK MODs * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int write_event(uint8 c1, uint8 c2, uint8 fxp, FILE *out) { uint8 note, ins, fxt; uint8 p[4]; note = ((c1 << 4) & 0x30) | ((c2 >> 4) & 0x0f); if (note >= 37) { /* di.nightmare has note 49! */ uint32 x = 0; fwrite(&x, 4, 1, out); return 0; } p[0] = ptk_table[note][0]; p[1] = ptk_table[note][1]; ins = (c1 >> 2) & 0x1f; p[0] |= (ins & 0xf0); p[2] = (ins << 4) & 0xf0; fxt = c2 & 0x0f; p[2] |= fxt; p[3] = fxp; fwrite(p, 4, 1, out); return 0; } static int depack_di(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3; uint8 nins, npat, max; uint8 ptable[128]; uint16 paddr[128]; uint8 tmp[50]; int i, k; int seq_offs, /*pat_offs,*/ smp_offs; int size, ssize; int pos; memset(ptable, 0, 128); memset(paddr, 0, 256); pw_write_zero(out, 20); /* title */ nins = hio_read16b(in); /* Sanity check */ if (nins > 31) { return -1; } seq_offs = hio_read32b(in); /*pat_offs =*/ hio_read32b(in); smp_offs = hio_read32b(in); ssize = 0; for (i = 0; i < nins; i++) { pw_write_zero(out, 22); /* name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } memset(tmp, 0, 50); for (i = nins; i < 31; i++) { fwrite(tmp, 30, 1, out); } if ((pos = hio_tell(in)) < 0) { return -1; } hio_seek(in, seq_offs, SEEK_SET); i = 0; do { c1 = hio_read8(in); ptable[i++] = c1; } while (c1 != 0xff); ptable[i - 1] = 0; write8(out, npat = i - 1); write8(out, 0x7f); for (max = i = 0; i < 128; i++) { write8(out, ptable[i]); if (ptable[i] > max) max = ptable[i]; } write32b(out, PW_MOD_MAGIC); hio_seek(in, pos, SEEK_SET); for (i = 0; i <= max; i++) paddr[i] = hio_read16b(in); for (i = 0; i <= max; i++) { hio_seek(in, paddr[i], 0); for (k = 0; k < 256; k++) { /* 256 = 4 voices * 64 rows */ c1 = hio_read8(in); if ((c1 & 0x80) == 0) { c2 = hio_read8(in); if (write_event(c1, c2, 0, out) < 0) { return -1; } } else if (c1 == 0xff) { uint32 x = 0; fwrite(&x, 1, 4, out); } else { c2 = hio_read8(in); c3 = hio_read8(in); if (write_event(c1, c2, c3, out) < 0) { return -1; } } } } hio_seek(in, smp_offs, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_di(uint8 *data, char *t, int s) { int i; int numsmp, ssize, psize; int ptab_offs, pat_offs, smp_offs; PW_REQUEST_DATA (s, 21); #if 0 /* test #1 */ if (i < 17) { Test = BAD; return; } #endif /* test #2 (number of sample) */ numsmp = readmem16b(data); if (numsmp > 31) return -1; /* test #3 (finetunes and whole sample size) */ ssize = 0; for (i = 0; i < numsmp; i++) { int len = readmem16b(data + 14) << 1; int start = readmem16b(data + 18) << 1; int lsize = readmem16b(data + 20) << 1; uint8 *d = data + i * 8; if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > len) return -1; if (d[16] > 0x0f) return -1; if (d[17] > 0x40) return -1; /* get total size of samples */ ssize += len; } if (ssize <= 2) { return -1; } /* test #4 (addresses of pattern in file ... ptk_tableible ?) */ psize = numsmp * 8 + 2; ptab_offs = readmem32b(data + 2); /* address of pattern table */ pat_offs = readmem32b(data + 6); /* address of pattern data */ smp_offs = readmem32b(data + 10); /* address of sample data */ if (pat_offs <= ptab_offs || smp_offs <= ptab_offs || smp_offs <= pat_offs) return -1; if (pat_offs - ptab_offs > 128) return -1; #if 0 if (k > in_size || l > in_size || l > in_size) return -1; #endif /* test #4,1 :) */ if (ptab_offs < psize) return -1; #if 0 /* test #5 */ if ((pat_offs + start) > in_size) { Test = BAD; return; } #endif PW_REQUEST_DATA(s, pat_offs - 1); /* test pattern table reliability */ for (i = ptab_offs; i < pat_offs - 1; i++) { if (data[i] > 0x80) return -1; } /* test #6 ($FF at the end of pattern list ?) */ if (data[pat_offs - 1] != 0xff) return -1; /* test #7 (address of sample data > $FFFF ? ) */ /* l is still the address of the sample data */ if (smp_offs > 65535) return -1; pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_di = { "Digital Illusions", test_di, depack_di }; libxmp-4.4.1/src/loaders/prowizard/theplayer.c0000664000175000017500000003345312706551122021252 0ustar claudioclaudio/* * The Player common decoding * Copyright (C) 1998 Sylvain "Asle" Chipaux * Copyright (C) 2006-2013 Sylvain "Asle" Chipaux * * Code consolidated from depackers for different versions of The Player. * Original code by Sylvain Chipaux, modified for xmp by Claudio Matsuoka. */ #include #include #include "prowiz.h" static uint8 set_event(uint8 *x, uint8 c1, uint8 c2, uint8 c3) { uint8 b; *x++ = ((c1 << 4) & 0x10) | ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; b = c2 & 0x0f; if (b == 0x08) c2 -= 0x08; *x++ = c2; if (b == 0x05 || b == 0x06 || b == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; return b; } #define track(p,c,r) tdata[((int)(p) * 4 + (c)) * 512 + (r) * 4] static int decode_pattern(HIO_HANDLE *in, int npat, uint8 *tdata, int taddr[128][4]) { int i, j, k, l; int max_row; int effect; long tdata_addr; long pos; uint8 c1, c2, c3, c4; if ((tdata_addr = hio_tell(in)) < 0) { return -1; } for (i = 0; i < npat; i++) { max_row = 63; for (j = 0; j < 4; j++) { hio_seek(in, taddr[i][j] + tdata_addr, SEEK_SET); for (k = 0; k <= max_row; k++) { uint8 *x = &track(i, j, k); c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); /* case 2 */ if (c1 & 0x80 && c1 != 0x80) { c4 = hio_read8(in); /* number of empty rows */ c1 = 0xff - c1; /* relative note number */ effect = set_event(x, c1, c2, c3); if (effect == 0x0d) { /* pattern break */ max_row = k; break; } if (effect == 0x0b) { /* pattern jump */ max_row = k; break; } if (c4 < 0x80) { /* skip rows */ k += c4; continue; } c4 = 0x100 - c4; for (l = 0; l < c4; l++) { if (++k >= 64) break; x = &track(i, j, k); set_event(x, c1, c2, c3); } continue; } /* case 3 * if the first byte is $80, the second is the number of * lines we'll have to repeat, and the last two bytes is the * number of bytes to go back to reach the starting point * where to read our lines */ if (c1 == 0x80) { int lines; c4 = hio_read8(in); if ((pos = hio_tell(in)) < 0) { return -1; } lines = c2; hio_seek(in, -(((int)c3 << 8) + c4), SEEK_CUR); for (l = 0; l <= lines; l++, k++) { x = &track(i, j, k); c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); if (c1 & 0x80 && c1 != 0x80) { c4 = hio_read8(in); c1 = 0xff - c1; if (k >= 64) continue; effect = set_event(x, c1, c2, c3); if (effect == 0x0d) { /* pattern break */ max_row = k; k = l = 9999; continue; } if (effect == 0x0b) { /* pattern jump */ max_row = k; k = l = 9999; continue; } if (c4 < 0x80) { /* skip rows */ k += c4; continue; } c4 = 0x100 - c4; while (c4--) { if (++k >= 64) break; x = &track(i, j, k); set_event(x, c1, c2, c3); } } x = &track(i, j, k); set_event(x, c1, c2, c3); } hio_seek(in, pos, SEEK_SET); k--; continue; } /* case 1 */ x = &track(i, j, k); effect = set_event(x, c1, c2, c3); if (effect == 0x0d) { /* pattern break */ max_row = k; break; } if (effect == 0x0b) { /* pattern jump */ max_row = k; break; } } } } return 0; } static int theplayer_depack(HIO_HANDLE *in, FILE *out, int version) { uint8 c1, c3; signed char *smp_buffer; int pat_pos = 0; int npat = 0; int nins = 0; uint8 *tdata; uint8 ptable[128]; int isize[31]; uint8 delta = 0; /*uint8 pack = 0;*/ int taddr[128][4]; int sdata_addr = 0; int ssize = 0; int i, j, k; int smp_size[31]; int saddr[31]; /*int unpacked_ssize;*/ int val; uint8 buf[1024]; if ((tdata = calloc(512, 256)) == NULL) { return -1; } memset(taddr, 0, 128 * 4 * 4); memset(ptable, 0, 128); memset(smp_size, 0, 31 * 4); memset(isize, 0, 31 * sizeof(int)); /*for (i = 0; i < 31; i++) { PACK[i] = 0; DELTA[i] = 0; }*/ saddr[0] = 0; sdata_addr = hio_read16b(in); /* read sample data address */ npat = hio_read8(in); /* read real number of patterns */ /* Sanity check */ if (npat > 128) { free(tdata); return -1; } nins = hio_read8(in); /* read number of samples */ if (nins & 0x80) { /* Samples saved as delta values */ delta = 1; } if (version >= 0x60 && nins & 0x40) { /* Some samples are packed -- depacking not implemented */ /* pack = 1; */ free(tdata); return -1; } nins &= 0x3f; /* Sanity check */ if (nins > 31) { free(tdata); return -1; } #if 0 if (pack == 1) /* unpacked_ssize =*/ hio_read32b(in); /* unpacked sample data size */ #endif pw_write_zero(out, 20); /* write title */ /* sample headers */ for (i = 0; i < nins; i++) { pw_write_zero(out, 22); /* name */ j = isize[i] = hio_read16b(in); /* sample size */ if (j > 0xff00) { smp_size[i] = smp_size[0xffff - j]; isize[i] = isize[0xffff - j]; saddr[i] = saddr[0xffff - j]; } else { if (i > 0) { saddr[i] = saddr[i - 1] + smp_size[i - 1]; } smp_size[i] = j * 2; ssize += smp_size[i]; } j = smp_size[i] / 2; write16b(out, isize[i]); /* size */ c1 = hio_read8(in); /* finetune */ /*if (c1 & 0x40) PACK[i] = 1;*/ write8(out, c1 & 0x3f); write8(out, hio_read8(in)); /* volume */ val = hio_read16b(in); /* loop start */ if (val == 0xffff) { write16b(out, 0x0000); /* loop start */ write16b(out, 0x0001); /* loop size */ } else { write16b(out, val); /* loop start */ write16b(out, j - val); /* loop size */ } } /* go up to 31 samples */ memset(buf, 0, 30); buf[29] = 0x01; for (; i < 31; i++) fwrite(buf, 30, 1, out); /* read tracks addresses per pattern */ for (i = 0; i < npat; i++) { for (j = 0; j < 4; j++) taddr[i][j] = hio_read16b(in); } /* pattern table */ for (pat_pos = 0; pat_pos < 128; pat_pos++) { c1 = hio_read8(in); if (c1 == 0xff) break; ptable[pat_pos] = version >= 0x60 ? c1 : c1 / 2; /* <--- /2 in p50a */ } write8(out, pat_pos); /* write size of pattern list */ write8(out, 0x7f); /* write noisetracker byte */ fwrite(ptable, 128, 1, out); /* write pattern table */ write32b(out, PW_MOD_MAGIC); /* M.K. */ /* patterns */ if (decode_pattern(in, npat, tdata, taddr) < 0) { free(tdata); return -1; } /* write pattern data */ for (i = 0; i < npat; i++) { memset(buf, 0, 1024); for (j = 0; j < 64; j++) { for (k = 0; k < 4; k++) memcpy(&buf[j * 16 + k * 4], &track(i, k, j), 4); } fwrite(buf, 1024, 1, out); } free(tdata); /* read and write sample data */ for (i = 0; i < nins; i++) { hio_seek(in, sdata_addr + saddr[i], SEEK_SET); smp_buffer = malloc(smp_size[i]); memset(smp_buffer, 0, smp_size[i]); hio_read(smp_buffer, smp_size[i], 1, in); if (delta == 1) { for (j = 1; j < smp_size[i]; j++) { c3 = 0x100 - smp_buffer[j] + smp_buffer[j - 1]; /* P50A: c3 = smp_buffer[j - 1] - smp_buffer[j]; */ smp_buffer[j] = c3; } } fwrite(smp_buffer, smp_size[i], 1, out); free(smp_buffer); } /* if (delta == 1) pw_p60a.flags |= PW_DELTA; */ return 0; } static int theplayer_test(uint8 *data, char *t, int s, int version) { int i; int len, num_pat, num_ins, sdata; /* FIXME: add PW_REQUEST_DATA */ /* number of pattern (real) */ num_pat = data[2]; if (num_pat == 0 || num_pat > 0x7f) return -1; /* number of sample */ num_ins = (data[3] & 0x3f); if (num_ins == 0 || num_ins > 0x1f) return -1; for (i = 0; i < num_ins; i++) { /* test volumes */ if (data[i * 6 + 7] > 0x40) return -1; /* test finetunes */ if (data[i * 6 + 6] > 0x0f) return -1; } /* test sample sizes and loop start */ for (i = 0; i < num_ins; i++) { int start, size = readmem16b(data + i * 6 + 4); if ((size < 0xffdf && size > 0x8000) || size == 0) return -1; /* if (size < 0xff00) ssize += size * 2; */ start = readmem16b(data + i * 6 + 8); if (start != 0xffff && start >= size) return -1; if (size > 0xffdf) { if (0xffff - size > num_ins) return -1; } } /* test sample data address */ /* sdata is the address of the sample data */ sdata = readmem16b(data); if (sdata < num_ins * 6 + 4 + num_pat * 8) return -1; /* test track table */ for (i = 0; i < num_pat * 4; i++) { int x = readmem16b(data + 4 + num_ins * 6 + i * 2); if (x + num_ins * 6 + 4 + num_pat * 8 > sdata) return -1; } /* first, test if we dont oversize the input file */ PW_REQUEST_DATA(s, num_ins * 6 + 4 + num_pat * 8); /* test pattern table */ len = 0; while (1) { int pat = data[num_ins * 6 + 4 + num_pat * 8 + len]; if (pat == 0xff || len >= 128) break; if (version >= 0x60) { if (pat > num_pat - 1) return -1; } else { if (pat & 0x01) return -1; if (pat > num_pat * 2) return -1; } len++; } /* are we beside the sample data address ? */ if (num_ins * 6 + 4 + num_pat * 8 + len > sdata) return -1; if (len == 0 || len == 128) return -1; /* test notes ... pfiew */ PW_REQUEST_DATA(s, sdata + 1); len++; for (i = num_ins * 6 + 4 + num_pat * 8 + len; i < sdata; i++) { uint8 *d = data + i; int ins; if (~d[0] & 0x80) { if (d[0] > 0x49) return -1; ins = ((d[0] << 4) & 0x10) | ((d[1] >> 4) & 0x0f); if (ins > num_ins) return -1; i += 2; } else { i += 3; } } pw_read_title(NULL, t, 0); return 0; } static int depack_p50a(HIO_HANDLE *in, FILE *out) { return theplayer_depack(in, out, 0x50); } static int test_p50a(uint8 *data, char *t, int s) { return theplayer_test(data, t, s, 0x50); } const struct pw_format pw_p50a = { "The Player 5.0a", test_p50a, depack_p50a }; static int depack_p60a(HIO_HANDLE *in, FILE *out) { return theplayer_depack(in, out, 0x60); } static int test_p60a(uint8 *data, char *t, int s) { return theplayer_test(data, t, s, 0x60); } const struct pw_format pw_p60a = { "The Player 6.0a", test_p60a, depack_p60a }; #if 0 /******************/ /* packed samples */ /******************/ void testP60A_pack (void) { if (i < 11) { Test = BAD; return; } start = i - 11; /* number of pattern (real) */ m = data[start + 2]; if ((m > 0x7f) || (m == 0)) { /*printf ( "#1 Start:%ld\n" , start );*/ Test = BAD; return; } /* m is the real number of pattern */ /* number of sample */ k = data[start + 3]; if ((k & 0x40) != 0x40) { /*printf ( "#2,0 Start:%ld\n" , start );*/ Test = BAD; return; } k &= 0x3F; if ((k > 0x1F) || (k == 0)) { /*printf ( "#2,1 Start:%ld (k:%ld)\n" , start,k );*/ Test = BAD; return; } /* k is the number of sample */ /* test volumes */ for (l = 0; l < k; l++) { if (data[start + 11 + l * 6] > 0x40) { /*printf ( "#3 Start:%ld\n" , start );*/ Test = BAD; return; } } /* test fines */ for (l = 0; l < k; l++) { if ((data[start + 10 + l * 6] & 0x3F) > 0x0F) { Test = BAD; /*printf ( "#4 Start:%ld\n" , start );*/ return; } } /* test sample sizes and loop start */ ssize = 0; for (n = 0; n < k; n++) { o = ((data[start + 8 + n * 6] << 8) + data[start + 9 + n * 6]); if (((o < 0xFFDF) && (o > 0x8000)) || (o == 0)) { /*printf ( "#5 Start:%ld\n" , start );*/ Test = BAD; return; } if (o < 0xFF00) ssize += (o * 2); j = ((data[start + 12 + n * 6] << 8) + data[start + 13 + n * 6]); if ((j != 0xFFFF) && (j >= o)) { /*printf ( "#5,1 Start:%ld\n" , start );*/ Test = BAD; return; } if (o > 0xFFDF) { if ((0xFFFF - o) > k) { /*printf ( "#5,2 Start:%ld\n" , start );*/ Test = BAD; return; } } } /* test sample data address */ j = (data[start] << 8) + data[start + 1]; if (j < (k * 6 + 8 + m * 8)) { /*printf ( "#6 Start:%ld\n" , start );*/ Test = BAD; ssize = 0; return; } /* j is the address of the sample data */ /* test track table */ for (l = 0; l < (m * 4); l++) { o = ((data[start + 8 + k * 6 + l * 2] << 8) + data[start + 8 + k * 6 + l * 2 + 1]); if ((o + k * 6 + 8 + m * 8) > j) { /*printf ( "#7 Start:%ld (value:%ld)(where:%x)(l:%ld)(m:%ld)(o:%ld)\n" , start , (data[start+k*6+8+l*2]*256)+data[start+8+k*6+l*2+1] , start+k*6+8+l*2 , l , m , o );*/ Test = BAD; return; } } /* test pattern table */ l = 0; o = 0; /* first, test if we dont oversize the input file */ if ((k * 6 + 8 + m * 8) > in_size) { /*printf ( "8,0 Start:%ld\n" , start );*/ Test = BAD; return; } while ((data[start + k * 6 + 8 + m * 8 + l] != 0xFF) && (l < 128)) { if (data[start + k * 6 + 8 + m * 8 + l] > (m - 1)) { /*printf ( "#8,1 Start:%ld (value:%ld)(where:%x)(l:%ld)(m:%ld)(k:%ld)\n" , start , data[start+k*6+8+m*8+l] , start+k*6+8+m*8+l , l , m , k );*/ Test = BAD; ssize = 0; return; } if (data[start + k * 6 + 8 + m * 8 + l] > o) o = data[start + k * 6 + 8 + m * 8 + l]; l++; } if ((l == 0) || (l == 128)) { /*printf ( "#8.2 Start:%ld\n" , start );*/ Test = BAD; return; } o /= 2; o += 1; /* o is the highest number of pattern */ /* test notes ... pfiew */ l += 1; for (n = (k * 6 + 8 + m * 8 + l); n < j; n++) { if ((data[start + n] & 0x80) == 0x00) { if (data[start + n] > 0x49) { /*printf ( "#9,0 Start:%ld (value:%ld) (where:%x) (n:%ld) (j:%ld)\n" , start , data[start+n] , start+n , n , j );*/ Test = BAD; return; } if ((((data[start + n] << 4) & 0x10) | ((data[start + n + 1] >> 4) & 0x0F)) > k) { /*printf ( "#9,1 Start:%ld (value:%ld) (where:%x) (n:%ld) (j:%ld)\n" , start , data[start+n] , start+n , n , j );*/ Test = BAD; return; } n += 2; } else n += 3; } /* ssize is the whole sample data size */ /* j is the address of the sample data */ Test = GOOD; } #endif libxmp-4.4.1/src/loaders/prowizard/np2.c0000664000175000017500000001314012706551122017743 0ustar claudioclaudio/* * NoisePacker_v2.c Copyright (C) 1997 Asle / ReDoX * * Converts NoisePacked MODs back to ptk * * Modified in 2006,2007,2014,2015 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_np2(HIO_HANDLE *in, FILE *out) { uint8 tmp[1024]; uint8 c1, c2, c3, c4; uint8 ptable[128]; int len, nins, npat; int max_addr; int size, ssize = 0; /*int tsize;*/ int trk_addr[128][4]; int i, j, k; int trk_start; memset(ptable, 0, 128); memset(trk_addr, 0, 128 * 4 * 4); c1 = hio_read8(in); /* read number of samples */ c2 = hio_read8(in); nins = ((c1 << 4) & 0xf0) | ((c2 >> 4) & 0x0f); pw_write_zero(out, 20); /* write title */ len = hio_read16b(in) >> 1; /* size of pattern list */ /* Sanity check */ if (len > 128) { return -1; } hio_read16b(in); /* 2 unknown bytes */ /*tsize =*/ hio_read16b(in); /* read track data size */ /* read sample descriptions */ for (i = 0; i < nins; i++) { hio_read32b(in); /* bypass 4 unknown bytes */ pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ hio_read32b(in); /* bypass 4 unknown bytes */ size = hio_read16b(in); /* read loop size */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, size); /* write loop size */ } /* fill up to 31 samples */ memset(tmp, 0, 30); tmp[29] = 0x01; for (; i < 31; i++) { fwrite(tmp, 30, 1, out); } write8(out, len); /* write size of pattern list */ write8(out, 0x7f); /* write noisetracker byte */ hio_seek(in, 2, SEEK_CUR); /* always $02? */ hio_seek(in, 2, SEEK_CUR); /* unknown */ /* read pattern table */ npat = 0; for (i = 0; i < len; i++) { ptable[i] = hio_read16b(in) >> 3; if (ptable[i] > 255) { return -1; } if (ptable[i] > npat) { npat = ptable[i]; } } npat++; fwrite(ptable, 128, 1, out); /* write pattern table */ write32b(out, PW_MOD_MAGIC); /* write ptk ID */ /* read tracks addresses per pattern */ max_addr = 0; for (i = 0; i < npat; i++) { if ((trk_addr[i][0] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][0]; if ((trk_addr[i][1] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][1]; if ((trk_addr[i][2] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][2]; if ((trk_addr[i][3] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][3]; } trk_start = hio_tell(in); /* the track data now ... */ for (i = 0; i < npat; i++) { memset(tmp, 0, 1024); for (j = 0; j < 4; j++) { hio_seek(in, trk_start + trk_addr[i][3 - j], SEEK_SET); for (k = 0; k < 64; k++) { int x = k * 16 + j * 4; c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = (c1 & 0xfe) / 2; if (hio_error(in) || c4 >= 37) { return -1; } tmp[x] = ((c1 << 4) & 0x10) | ptk_table[c4][0]; tmp[x + 1] = ptk_table[c4][1]; switch (c2 & 0x0f) { case 0x08: c2 &= 0xf0; break; case 0x07: c2 = (c2 & 0xf0) + 0x0a; /* fall through */ case 0x06: case 0x05: c3 = c3 > 0x80 ? 0x100 - c3 : (c3 << 4) & 0xf0; break; case 0x0e: c3--; break; case 0x0b: c3 = (c3 + 4) / 2; break; } tmp[x + 2] = c2; tmp[x + 3] = c3; } } fwrite(tmp, 1024, 1, out); } /* sample data */ hio_seek(in, max_addr + 192 + trk_start, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_np2(uint8 *data, char *t, int s) { int num_ins, ssize, hdr_size, ptab_size, trk_size, max_pptr; int i; PW_REQUEST_DATA(s, 10); /* size of the pattern table */ ptab_size = readmem16b(data + 2); if (ptab_size == 0 || ptab_size & 1 || ptab_size > 0xff) return -1; /* test number of samples */ if ((data[1] & 0x0f) != 0x0c) return -1; /* number of samples */ num_ins = ((data[0] << 4) & 0xf0) | ((data[1] >> 4) & 0x0f); if (num_ins == 0 || num_ins > 0x1f) return -1; PW_REQUEST_DATA(s, 15 + num_ins * 16); /* test volumes */ for (i = 0; i < num_ins; i++) { if (data[15 + i * 16] > 0x40) return -1; } /* test sample sizes */ ssize = 0; for (i = 0; i < num_ins; i++) { uint8 *d = data + i * 16; int len = readmem16b(d + 12) << 1; int start = readmem16b(d + 20) << 1; int lsize = readmem16b(d + 22) << 1; if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > len + 2) return -1; if (start == 0 && lsize != 0) return -1; ssize += len; } if (ssize <= 4) return -1; /* size of the header til the end of sample descriptions */ hdr_size = num_ins * 16 + 8 + 4; PW_REQUEST_DATA(s, hdr_size + ptab_size + 2); /* test pattern table */ max_pptr = 0; for (i = 0; i < ptab_size; i += 2) { int pptr = readmem16b(data + hdr_size + i); if (pptr & 0x07 || pptr > 0x400) return -1; if (pptr > max_pptr) max_pptr = pptr; } /* max_pptr is the highest pattern number (*8) */ /* paske on a que l'address du dernier pattern... */ /* size of the header 'til the end of the track list */ hdr_size += ptab_size + max_pptr + 8; /* test track data size */ trk_size = readmem16b(data + 6); if (trk_size < 192 || (trk_size & 0x3f)) return -1; PW_REQUEST_DATA(s, hdr_size + trk_size + 16); /* test notes */ for (i = 0; i < trk_size; i += 3) { uint8 *d = data + hdr_size + i; if (d[0] > 0x49) { return -1; } if ((((d[0] << 4) & 0x10) | ((d[1] >> 4) & 0x0f)) > num_ins) { return -1; } if ((d[1] & 0x0f) == 0 && d[2] != 0) { return -1; } } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_np2 = { "NoisePacker v2", test_np2, depack_np2 }; libxmp-4.4.1/src/loaders/prowizard/pp21.c0000664000175000017500000001320212706551122020025 0ustar claudioclaudio/* * ProPacker_21.c Copyright (C) 1997 Sylvain "Asle" Chipaux * * Converts PP21 packed MODs back to PTK MODs * thanks to Gryzor and his ProWizard tool ! ... without it, this prog * would not exist !!! * * Modified in 2006,2009,2014 by Claudio Matsuoka * - Code cleanup * * Modified in 2015 by Claudio Matsuoka * - Add PP30 support */ #include #include #include "prowiz.h" static int depack_pp21_pp30(HIO_HANDLE *in, FILE *out, int is_30) { uint8 ptable[128]; int max = 0; uint8 trk[4][128]; int tptr[512][64]; uint8 numpat; uint8 *tab; uint8 buf[1024]; int i, j; int size; int ssize; int tabsize; /* Reference Table Size */ memset(ptable, 0, 128); memset(trk, 0, 4 * 128); memset(tptr, 0, 512 * 64 * sizeof (int)); pw_write_zero(out, 20); /* title */ ssize = 0; for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } numpat = hio_read8(in); /* number of patterns */ /* Sanity check */ if (numpat > 128) { return -1; } write8(out, numpat); /* number of patterns */ write8(out, hio_read8(in)); /* NoiseTracker restart byte */ max = 0; for (j = 0; j < 4; j++) { for (i = 0; i < 128; i++) { trk[j][i] = hio_read8(in); if (trk[j][i] > max) max = trk[j][i]; } } /* write pattern table without any optimizing ! */ for (i = 0; i < numpat; i++) write8(out, i); pw_write_zero(out, 128 - i); write32b(out, PW_MOD_MAGIC); /* M.K. */ /* PATTERN DATA code starts here */ /*printf ("Highest track number : %d\n", max); */ for (j = 0; j <= max; j++) { for (i = 0; i < 64; i++) { tptr[j][i] = hio_read16b(in); if (is_30) { tptr[j][i] >>= 2; } } } /* read "reference table" size */ tabsize = hio_read32b(in); if (tabsize == 0) { return -1; } /* read "reference Table" */ tab = (uint8 *)malloc(tabsize); hio_read(tab, tabsize, 1, in); for (i = 0; i < numpat; i++) { memset(buf, 0, 1024); for (j = 0; j < 64; j++) { uint8 *b = buf + j * 16; memcpy(b, tab + tptr[trk[0][i]][j] * 4, 4); memcpy(b + 4, tab + tptr[trk[1][i]][j] * 4, 4); memcpy(b + 8, tab + tptr[trk[2][i]][j] * 4, 4); memcpy(b + 12, tab + tptr[trk[3][i]][j] * 4, 4); } fwrite (buf, 1024, 1, out); } free (tab); /* Now, it's sample data ... though, VERY quickly handled :) */ pw_move_data(out, in, ssize); return 0; } static int depack_pp21(HIO_HANDLE *in, FILE *out) { return depack_pp21_pp30(in, out, 0); } static int depack_pp30(HIO_HANDLE *in, FILE *out) { return depack_pp21_pp30(in, out, 1); } static int test_pp21(uint8 *data, char *t, int s) { int i; int ssize, tsize, npat, max_ref; ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int len = readmem16b(d) << 1; int start = readmem16b(d + 4) << 1; ssize += len; /* finetune > 0x0f ? */ if (d[2] > 0x0f) return -1; /* volume > 0x40 ? */ if (d[3] > 0x40) return -1; /* loop start > size ? */ if (start > len) return -1; } if (ssize <= 2) return -1; /* test #3 about size of pattern list */ npat = data[248]; if (npat == 0 || npat > 127) return -1; /* get the highest track value */ tsize = 0; for (i = 0; i < 512; i++) { int trk = data[250 + i]; if (trk > tsize) tsize = trk; } tsize++; tsize <<= 6; /* test #4 track data value > $4000 ? */ max_ref = 0; for (i = 0; i < tsize; i++) { int ref = readmem16b(data + i * 2 + 762); if (ref > 0x4000) return -1; if (ref > max_ref) max_ref = ref; } /* test #5 reference table size *4 ? */ if (readmem32b(data + (tsize << 1) + 762) != (max_ref + 1) * 4) return -1; pw_read_title(NULL, t, 0); return 0; } static int test_pp30(uint8 *data, char *t, int s) { int i; int ssize, tsize, npat, max_ref, ref_size; ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int len = readmem16b(d) << 1; int start = readmem16b(d + 4) << 1; ssize += len; /* finetune > 0x0f ? */ if (d[2] > 0x0f) return -1; /* volume > 0x40 ? */ if (d[3] > 0x40) return -1; /* loop start > size ? */ if (start > len) return -1; } if (ssize <= 2) return -1; /* test #3 about size of pattern list */ npat = data[248]; if (npat == 0 || npat > 127) return -1; /* get the highest track value */ tsize = 0; for (i = 0; i < 512; i++) { int trk = data[250 + i]; if (trk > tsize) tsize = trk; } tsize++; tsize <<= 6; /* test #4 track data value *4 ? */ max_ref = 0; for (i = 0; i < tsize; i++) { int ref = readmem16b(data + i * 2 + 762); if (ref > max_ref) max_ref = ref; if (ref & 0x0003) { return -1; } } max_ref >>= 2; /* test #5 reference table size *4 ? */ ref_size = readmem32b(data + (tsize << 1) + 762); if (ref_size > 0xffff) { return -1; } if (ref_size != ((max_ref + 1) << 2)) { return -1; } ref_size >>= 2; /* test #6 data in reference table ... */ for (i = 0; i < ref_size; i++) { uint8 *d = data + tsize + 766 + i * 4; uint8 fxt = d[2] & 0x0f; uint8 fxp = d[3]; /* volume > 41 ? */ if (fxt == 0x0c && fxp > 0x41) { return -1; } /* break > 40 ? */ if (fxt == 0x0d && fxp > 0x40) { return -1; } /* jump > 128 */ if (fxt == 0x0b && fxp > 0x7f) { return -1; } /* smp > 1f ? */ if ((d[0] & 0xf0) > 0x10) { return -1; } } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_pp21 = { "ProPacker 2.1", test_pp21, depack_pp21 }; const struct pw_format pw_pp30 = { "ProPacker 3.0", test_pp30, depack_pp30 }; libxmp-4.4.1/src/loaders/prowizard/p40.c0000664000175000017500000001640212706551122017653 0ustar claudioclaudio/* * The_Player_4.0.c Copyright (C) 1997 Asle / ReDoX * Copyright (C) 2007 Claudio Matsuoka * * The Player 4.0a and 4.0b to Protracker. */ #include #include #include "prowiz.h" #define MAGIC_P40A MAGIC4('P','4','0','A') #define MAGIC_P40B MAGIC4('P','4','0','B') #define MAGIC_P41A MAGIC4('P','4','1','A') struct smp { uint8 name[22]; int addr; uint16 size; int loop_addr; uint16 loop_size; int16 fine; uint8 vol; }; static int depack_p4x(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4, c5; uint8 tmp[1024]; uint8 len, npat, nsmp; uint8 sample, mynote, note[2]; uint8 tr[512][256]; uint16 track_addr[128][4]; int trkdat_ofs, trktab_ofs, smp_ofs; int ssize = 0; int SampleAddress[31]; int SampleSize[31]; int i, j, k, l, a, b, c; struct smp ins; uint32 id; memset(track_addr, 0, 128 * 4 * 2); memset(tr, 0, 512 << 8); memset(SampleAddress, 0, 31 * 4); memset(SampleSize, 0, 31 * 4); id = hio_read32b(in); #if 0 if (id == MAGIC_P40A) { pw_p4x.id = "P40A"; pw_p4x.name = "The Player 4.0A"; } else if (id == MAGIC_P40B) { pw_p4x.id = "P40B"; pw_p4x.name = "The Player 4.0B"; } else { pw_p4x.id = "P41A"; pw_p4x.name = "The Player 4.1A"; } #endif npat = hio_read8(in); /* read Real number of pattern */ len = hio_read8(in); /* read number of patterns in list */ /* Sanity check */ if (len >= 128) { return -1; } nsmp = hio_read8(in); /* read number of samples */ /* Sanity check */ if (nsmp > 31) { return -1; } hio_read8(in); /* bypass empty byte */ trkdat_ofs = hio_read32b(in); /* read track data address */ trktab_ofs = hio_read32b(in); /* read track table address */ smp_ofs = hio_read32b(in); /* read sample data address */ if (hio_error(in)) { return -1; } pw_write_zero(out, 20); /* write title */ /* sample headers stuff */ for (i = 0; i < nsmp; i++) { ins.addr = hio_read32b(in); /* sample address */ SampleAddress[i] = ins.addr; ins.size = hio_read16b(in); /* sample size */ SampleSize[i] = ins.size * 2; ssize += SampleSize[i]; ins.loop_addr = hio_read32b(in); /* loop start */ ins.loop_size = hio_read16b(in); /* loop size */ ins.fine = 0; if (id == MAGIC_P40A || id == MAGIC_P40B) ins.fine = hio_read16b(in); /* finetune */ hio_read8(in); /* bypass 00h */ ins.vol = hio_read8(in); /* read vol */ if (id == MAGIC_P41A) ins.fine = hio_read16b(in); /* finetune */ /* writing now */ pw_write_zero(out, 22); /* sample name */ write16b(out, ins.size); write8(out, ins.fine / 74); write8(out, ins.vol); write16b(out, (ins.loop_addr - ins.addr) / 2); write16b(out, ins.loop_size); } /* go up to 31 samples */ memset(tmp, 0, 30); tmp[29] = 0x01; for (; i < 31; i++) fwrite (tmp, 30, 1, out); write8(out, len); /* write size of pattern list */ write8(out, 0x7f); /* write noisetracker byte */ hio_seek(in, trktab_ofs + 4, SEEK_SET); for (c1 = 0; c1 < len; c1++) /* write pattern list */ write8(out, c1); for (; c1 < 128; c1++) write8(out, 0); write32b(out, PW_MOD_MAGIC); /* write ptk ID */ for (i = 0; i < len; i++) { /* read all track addresses */ for (j = 0; j < 4; j++) track_addr[i][j] = hio_read16b(in) + trkdat_ofs + 4; } hio_seek(in, trkdat_ofs + 4, SEEK_SET); for (i = 0; i < len; i++) { /* rewrite the track data */ for (j = 0; j < 4; j++) { int y, x = i * 4 + j; hio_seek(in, track_addr[i][j], SEEK_SET); for (k = 0; k < 64; k++) { c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); if (c1 != 0x80) { sample = ((c1 << 4) & 0x10) | ((c2 >> 4) & 0x0f); memset(note, 0, 2); mynote = c1 & 0x7f; note[0] = ptk_table[mynote / 2][0]; note[1] = ptk_table[mynote / 2][1]; switch (c2 & 0x0f) { case 0x08: c2 -= 0x08; break; case 0x05: case 0x06: case 0x0A: if (c3 >= 0x80) c3 = (c3 << 4) & 0xf0; break; default: break; } y = k * 4; tr[x][y] = (sample & 0xf0) | (note[0] & 0x0f); tr[x][y + 1] = note[1]; tr[x][y + 2] = c2; tr[x][y + 3] = c3; if ((c4 > 0x00) && (c4 < 0x80)) k += c4; if (c4 > 0x7f) { k++; for (l = 256; l > c4; l--) { y = k * 4; tr[x][y] = (sample & 0xf0) | (note[0] & 0x0f); tr[x][y + 1] = note[1]; tr[x][y + 2] = c2; tr[x][y + 3] = c3; k++; } k--; } continue; } if ((a = hio_tell(in)) < 0) { return -1; } c5 = c2; b = (c3 << 8) + c4 + trkdat_ofs + 4; hio_seek(in, b, SEEK_SET); for (c = 0; c <= c5; c++) { c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); sample = ((c1 << 4) & 0x10) | ((c2 >> 4) & 0x0f); memset(note, 0, 2); mynote = c1 & 0x7f; note[0] = ptk_table[mynote / 2][0]; note[1] = ptk_table[mynote / 2][1]; switch (c2 & 0x0f) { case 0x08: c2 -= 0x08; break; case 0x05: case 0x06: case 0x0A: if (c3 >= 0x80) c3 = (c3 << 4) & 0xf0; break; default: break; } tr[x][k * 4] = (sample & 0xf0) | (note[0] & 0x0f); tr[x][k * 4 + 1] = note[1]; tr[x][k * 4 + 2] = c2; tr[x][k * 4 + 3] = c3; if ((c4 > 0x00) && (c4 < 0x80)) k += c4; if (c4 > 0x7f) { k++; for (l = 256; l > c4; l--) { y = k * 4; tr[x][y] = (sample & 0xf0) | (note [0] & 0x0f); tr[x][y + 1] = note[1]; tr[x][y + 2] = c2; tr[x][y + 3] = c3; k++; } k--; } k++; } k--; hio_seek(in, a, SEEK_SET); } } } /* write pattern data */ for (i = 0; i < len; i++) { memset(tmp, 0, 1024); for (j = 0; j < 64; j++) { for (k = 0; k < 4; k++) { int x = j * 16 + k * 4; int y = k + i * 4; tmp[x + 0] = tr[y][j * 4]; tmp[x + 1] = tr[y][j * 4 + 1]; tmp[x + 2] = tr[y][j * 4 + 2]; tmp[x + 3] = tr[y][j * 4 + 3]; } } fwrite(tmp, 1024, 1, out); } /* read and write sample data */ for (i = 0; i < nsmp; i++) { hio_seek(in, SampleAddress[i] + smp_ofs, SEEK_SET); pw_move_data(out, in, SampleSize[i]); } return 0; } static int test_p4x(uint8 *data, char *t, int s) { //int j, k, l, o, n; //int start = 0, ssize; uint32 id; id = readmem32b(data); if (id != MAGIC_P40A && id != MAGIC_P40B && id != MAGIC_P41A) return -1; pw_read_title(NULL, t, 0); return 0; #if 0 /* number of pattern (real) */ j = data[start + 4]; if (j > 0x7f) return -1; /* number of sample */ k = data[start + 6]; if ((k > 0x1F) || (k == 0)) return -1; /* test volumes */ for (l = 0; l < k; l++) { if (data[start + 35 + l * 16] > 0x40) return -1; } /* test sample sizes */ ssize = 0; for (l = 0; l < k; l++) { /* size */ o = (data[start + 24 + l * 16] << 8) + data[start + 25 + l * 16]; /* loop size */ n = (data[start + 30 + l * 16] << 8) + data[start + 31 + l * 16]; o *= 2; n *= 2; if ((o > 0xFFFF) || (n > 0xFFFF)) return -1; if (n > (o + 2)) return -1; ssize += o; } if (ssize <= 4) return -1; /* ssize is the size of the sample data .. WRONG !! */ /* k is the number of samples */ return 0; #endif } const struct pw_format pw_p4x = { "The Player 4.x", test_p4x, depack_p4x }; libxmp-4.4.1/src/loaders/prowizard/fuchs.c0000664000175000017500000000732212706551122020361 0ustar claudioclaudio/* * FuchsTracker.c Copyright (C) 1999 Sylvain "Asle" Chipaux * * Depacks Fuchs Tracker modules * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_fuchs(HIO_HANDLE *in, FILE *out) { uint8 *tmp; uint8 max_pat; /*int ssize;*/ uint8 data[1080]; unsigned smp_len[16]; unsigned loop_start[16]; unsigned pat_size; unsigned i; memset(smp_len, 0, 16 * 4); memset(loop_start, 0, 16 * 4); memset(data, 0, 1080); hio_read(data, 1, 10, in); /* read/write title */ /*ssize =*/ hio_read32b(in); /* read all sample data size */ /* read/write sample sizes */ for (i = 0; i < 16; i++) { smp_len[i] = hio_read16b(in); data[42 + i * 30] = smp_len[i] >> 9; data[43 + i * 30] = smp_len[i] >> 1; } /* read/write volumes */ for (i = 0; i < 16; i++) { data[45 + i * 30] = hio_read16b(in); } /* read/write loop start */ for (i = 0; i < 16; i++) { loop_start[i] = hio_read16b(in); data[46 + i * 30] = loop_start[i] >> 1; } /* write replen */ for (i = 0; i < 16; i++) { int loop_size; loop_size = smp_len[i] - loop_start[i]; if (loop_size == 0 || loop_start[i] == 0) { data[49 + i * 30] = 1; } else { data[48 + i * 30] = loop_size >> 9; data[49 + i * 30] = loop_size >> 1; } } /* fill replens up to 31st sample wiz $0001 */ for (i = 16; i < 31; i++) { data[49 + i * 30] = 1; } /* that's it for the samples ! */ /* now, the pattern list */ /* read number of pattern to play */ data[950] = hio_read16b(in); data[951] = 0x7f; /* read/write pattern list */ for (max_pat = i = 0; i < 40; i++) { uint8 pat = hio_read16b(in); data[952 + i] = pat; if (pat > max_pat) { max_pat = pat; } } /* write ptk's ID */ if (fwrite(data, 1, 1080, out) != 1080) { return -1; } write32b(out, PW_MOD_MAGIC); /* now, the pattern data */ /* bypass the "SONG" ID */ hio_read32b(in); /* read pattern data size */ pat_size = hio_read32b(in); /* Sanity check */ if (pat_size <= 0 || pat_size > 0x20000) return -1; /* read pattern data */ tmp = (uint8 *)malloc(pat_size); if (hio_read(tmp, 1, pat_size, in) != pat_size) { free(tmp); return -1; } /* convert shits */ for (i = 0; i < pat_size; i += 4) { /* convert fx C arg back to hex value */ if ((tmp[i + 2] & 0x0f) == 0x0c) { int x = tmp[i + 3]; tmp[i + 3] = 10 * (x >> 4) + (x & 0xf); } } /* write pattern data */ fwrite(tmp, pat_size, 1, out); free(tmp); /* read/write sample data */ hio_read32b(in); /* bypass "INST" Id */ for (i = 0; i < 16; i++) { if (smp_len[i] != 0) pw_move_data(out, in, smp_len[i]); } return 0; } static int test_fuchs (uint8 *data, char *t, int s) { int i; int ssize, hdr_ssize; #if 0 /* test #1 */ if (i < 192) { Test = BAD; return; } start = i - 192; #endif if (readmem32b(data + 192) != 0x534f4e47) /* SONG */ return -1; /* all sample size */ hdr_ssize = readmem32b(data + 10); if (hdr_ssize <= 2 || hdr_ssize >= 65535 * 16) return -1; /* samples descriptions */ ssize = 0; for (i = 0; i < 16; i++) { uint8 *d = data + i * 2; int len = readmem16b(d + 14); int start = readmem16b(d + 78); /* volumes */ if (d[46] > 0x40) return -1; if (len < start) return -1; ssize += len; } if (ssize <= 2 || ssize > hdr_ssize) return -1; /* get highest pattern number in pattern list */ /*max_pat = 0;*/ for (i = 0; i < 40; i++) { int pat = data[i * 2 + 113]; if (pat > 40) return -1; /*if (pat > max_pat) max_pat = pat;*/ } #if 0 /* input file not long enough ? */ max_pat++; max_pat *= 1024; PW_REQUEST_DATA (s, k + 200); #endif pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_fchs = { "Fuchs Tracker", test_fuchs, depack_fuchs }; libxmp-4.4.1/src/loaders/prowizard/fuzzac.c0000664000175000017500000001105212706551122020546 0ustar claudioclaudio/* * fuzzac.c Copyright (C) 1997 Asle / ReDoX * * Converts Fuzzac packed MODs back to PTK MODs * thanks to Gryzor and his ProWizard tool ! ... without it, this prog * would not exist !!! * * note: A most worked-up prog ... took some time to finish this !. * there's what lot of my other depacker are missing : the correct * pattern order (most of the time the list is generated badly ..). * Dont know why I did it for this depacker because I've but one * exemple file ! :) * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_fuzz(HIO_HANDLE *in, FILE *out) { uint8 c1; uint8 data[1024]; uint8 ord[128]; uint8 tidx[128][16]; uint8 tidx_real[128][4]; uint8 track[4][256]; uint8 status = 1; int len, ntrk, npat; int size, ssize = 0; int lps, lsz; int i, j, k, l; memset(tidx, 0, 128 * 16); memset(tidx_real, 0, 128 * 4); memset(ord, 0, 128); hio_read32b(in); /* bypass ID */ hio_read16b(in); /* bypass 2 unknown bytes */ pw_write_zero(out, 20); /* write title */ for (i = 0; i < 31; i++) { pw_move_data(out, in, 22); /*sample name */ hio_seek(in, 38, SEEK_CUR); write16b(out, size = hio_read16b(in)); ssize += size * 2; lps = hio_read16b(in); /* loop start */ lsz = hio_read16b(in); /* loop size */ write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, lps); write16b(out, lsz > 0 ? lsz : 1); } len = hio_read8(in); /* size of pattern list */ /* Sanity check */ if (len > 128) return -1; write8(out, len); ntrk = hio_read8(in); /* read the number of tracks */ write8(out, 0x7f); /* write noisetracker byte */ /* place file pointer at track number list address */ hio_seek(in, 2118, SEEK_SET); /* read tracks numbers */ for (i = 0; i < 4; i++) { for (j = 0; j < len; j++) hio_read(&tidx[j][i * 4], 1, 4, in); } /* sort tracks numbers */ npat = 0; for (i = 0; i < len; i++) { if (i == 0) { ord[0] = npat++; continue; } for (j = 0; j < i; j++) { status = 1; for (k = 0; k < 4; k++) { if (tidx[j][k * 4] != tidx[i][k * 4]) { status = 0; break; } } if (status == 1) { ord[i] = ord[j]; break; } } if (status == 0) ord[i] = npat++; status = 1; } /* create a list of tracks numbers for the really existing patterns */ c1 = 0x00; for (i = 0; i < len; i++) { if (i == 0) { tidx_real[c1][0] = tidx[i][0]; tidx_real[c1][1] = tidx[i][4]; tidx_real[c1][2] = tidx[i][8]; tidx_real[c1][3] = tidx[i][12]; c1++; continue; } for (j = 0; j < i; j++) { status = 1; if (ord[i] == ord[j]) { status = 0; break; } } if (status == 0) continue; tidx_real[c1][0] = tidx[i][0]; tidx_real[c1][1] = tidx[i][4]; tidx_real[c1][2] = tidx[i][8]; tidx_real[c1][3] = tidx[i][12]; c1++; status = 1; } fwrite(ord, 128, 1, out); /* write pattern list */ write32b(out, PW_MOD_MAGIC); /* write ID */ /* pattern data */ l = 2118 + len * 16; for (i = 0; i < npat; i++) { memset(data, 0, 1024); memset(track, 0, 4 << 8); hio_seek(in, l + (tidx_real[i][0] << 8), SEEK_SET); hio_read(track[0], 256, 1, in); hio_seek(in, l + (tidx_real[i][1] << 8), SEEK_SET); hio_read(track[1], 256, 1, in); hio_seek(in, l + (tidx_real[i][2] << 8), SEEK_SET); hio_read(track[2], 256, 1, in); hio_seek(in, l + (tidx_real[i][3] << 8), SEEK_SET); hio_read(track[3], 256, 1, in); for (j = 0; j < 64; j++) { memcpy(&data[j * 16 ], &track[0][j * 4], 4); memcpy(&data[j * 16 + 4 ], &track[1][j * 4], 4); memcpy(&data[j * 16 + 8 ], &track[2][j * 4], 4); memcpy(&data[j * 16 + 12], &track[3][j * 4], 4); data[j * 16 + 15] = track[3][j * 4 + 3]; } fwrite(data, 1024, 1, out); } /* sample data */ /* bypass the "SEnd" unidentified ID */ hio_seek(in, l + (ntrk << 8) + 4, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_fuzz(uint8 *data, char *t, int s) { int i; if (readmem32b(data) != MAGIC4('M','1','.','0')) return -1; /* test finetune */ for (i = 0; i < 31; i++) { if (data[72 + i * 68] > 0x0f) return -1; } /* test volumes */ for (i = 0; i < 31; i++) { if (data[73 + i * 68] > 0x40) return -1; } /* test sample sizes */ for (i = 0; i < 31; i++) { int len = readmem16b(data + i * 68 + 66); if (len > 0x8000) return -1; } /* test size of pattern list */ if (data[2114] == 0x00) return -1; pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_fuzz = { "Fuzzac Packer", test_fuzz, depack_fuzz }; libxmp-4.4.1/src/loaders/prowizard/mp.c0000664000175000017500000000774212706551122017673 0ustar claudioclaudio/* * Module_Protector.c Copyright (C) 1997 Asle / ReDoX * * Converts MP packed MODs back to PTK MODs * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" #define MAGIC_TRK1 MAGIC4('T','R','K','1') static int depack_mp(HIO_HANDLE *in, FILE *out) { uint8 c1; uint8 ptable[128]; uint8 max; int i; int size, ssize = 0; memset(ptable, 0, 128); pw_write_zero(out, 20); /* title */ if (hio_read32b(in) != MAGIC_TRK1) /* TRK1 */ hio_seek(in, -4, SEEK_CUR); for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } write8(out, hio_read8(in)); /* pattern table length */ write8(out, hio_read8(in)); /* NoiseTracker restart byte */ for (max = i = 0; i < 128; i++) { write8(out, c1 = hio_read8(in)); if (c1 > max) max = c1; } max++; write32b(out, PW_MOD_MAGIC); /* M.K. */ if (hio_read32b(in) != 0) /* bypass unknown empty bytes */ hio_seek(in, -4, SEEK_CUR); pw_move_data(out, in, 1024 * max); /* pattern data */ pw_move_data(out, in, ssize); /* sample data */ return 0; } static int test_mp_noid(uint8 *data, char *t, int s) { int i; int len, psize, hdr_ssize; #if 0 if (s < 378) { return - 1; } #endif /* test #2 */ hdr_ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int size = readmem16b(d) << 1; /* size */ int start = readmem16b(d + 4) << 1; /* loop start */ int lsize = readmem16b(d + 6) << 1; /* loop size */ hdr_ssize += size; /* finetune > 0x0f ? */ if (d[2] > 0x0f) return -1; /* loop start+repsize > size ? */ if (lsize != 2 && (start + lsize) > size) return -1; /* loop size > size ? */ if (lsize > (size + 2)) return -1; /* loop start != 0 and loop size = 0 */ if (start != 0 && lsize <= 2) return -1; /* when size!=0 loopsize==0 ? */ if (size != 0 && lsize == 0) return -1; } if (hdr_ssize <= 2) return -1; /* test #3 */ len = data[248]; if (len == 0 || len > 0x7f) return -1; /* test #4 */ psize = 0; for (i = 0; i < 128; i++) { int pat = data[250 + i]; if (pat > 0x7f) return -1; if (pat > psize) psize = pat; if (i > len + 3) { if (pat != 0) return -1; } } psize++; psize <<= 8; PW_REQUEST_DATA(s, 378 + psize * 4); /* test #5 ptk notes .. gosh ! (testing all patterns !) */ for (i = 0; i < psize; i++) { uint8 *d = data + 378 + i * 4; uint16 data; /* MadeInCroatia has l == 74 */ if (*d > 19 && *d != 74) return -1; data = readmem16b(d) & 0x0fff; if (data > 0 && data < 0x71) return -1; } /* test #6 (loopStart+LoopSize > Sample ? ) */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int size = readmem16b(d) << 1; int lend = (readmem16b(d + 4) + readmem16b(d + 6)) << 1; if (lend > size + 2) return -1; } pw_read_title(NULL, t, 0); return 0; } static int test_mp_id(uint8 *data, char *t, int s) { int i; int len, psize; /* "TRK1" Module Protector */ if (readmem32b(data) != MAGIC_TRK1) return -1; /* test #1 */ for (i = 0; i < 31; i++) { if (data[6 + 8 * i] > 0x0f) return -1; } /* test #2 */ len = data[252]; if (len == 0 || len > 0x7f) return -1; /* test #4 */ psize = 0; for (i = 0; i < 128; i++) { int pat = data[254 + i]; if (pat > 0x7f) return -1; if (pat > psize) psize = pat; } psize++; psize <<= 8; /* test #5 ptk notes .. gosh ! (testing all patterns !) */ /* k contains the number of pattern saved */ for (i = 0; i < psize; i++) { int x = data[382 + i * 4]; if (x > 19) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_mp_id = { "Module Protector", test_mp_id, depack_mp }; const struct pw_format pw_mp_noid = { "Module Protector noID", test_mp_noid, depack_mp }; libxmp-4.4.1/src/loaders/prowizard/gmc.c0000664000175000017500000001025412706551122020015 0ustar claudioclaudio/* * gmc.c Copyright (C) 1997 Sylvain "Asle" Chipaux * * Depacks musics in the Game Music Creator format and saves in ptk. * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_GMC(HIO_HANDLE *in, FILE *out) { uint8 tmp[1024]; uint8 ptable[128]; uint8 max; uint8 pat_pos; uint16 len, looplen; long ssize = 0; long i = 0, j = 0; memset(ptable, 0, 128); pw_write_zero(out, 20); /* title */ for (i = 0; i < 15; i++) { pw_write_zero(out, 22); /* name */ hio_read32b(in); /* bypass 4 address bytes */ len = hio_read16b(in); write16b(out, len); /* size */ ssize += len * 2; hio_read8(in); write8(out, 0); /* finetune */ write8(out, hio_read8(in)); /* volume */ hio_read32b(in); /* bypass 4 address bytes */ looplen = hio_read16b(in); /* loop size */ write16b(out, looplen > 2 ? len - looplen : 0); write16b(out, looplen <= 2 ? 1 : looplen); hio_read16b(in); /* always zero? */ } memset(tmp, 0, 30); tmp[29] = 0x01; for (i = 0; i < 16; i++) fwrite(tmp, 30, 1, out); hio_seek(in, 0xf3, 0); write8(out, pat_pos = hio_read8(in)); /* pattern list size */ write8(out, 0x7f); /* ntk byte */ /* read and write size of pattern list */ /*printf ( "Creating the pattern table ... " ); */ for (i = 0; i < 100; i++) ptable[i] = hio_read16b(in) / 1024; fwrite(ptable, 128, 1, out); /* get number of pattern */ for (max = i = 0; i < 128; i++) { if (ptable[i] > max) max = ptable[i]; } /* write ID */ write32b(out, PW_MOD_MAGIC); /* pattern data */ hio_seek(in, 444, SEEK_SET); for (i = 0; i <= max; i++) { memset(tmp, 0, 1024); hio_read(tmp, 1024, 1, in); for (j = 0; j < 256; j++) { switch (tmp[(j * 4) + 2] & 0x0f) { case 3: /* replace by C */ tmp[(j * 4) + 2] += 0x09; break; case 4: /* replace by D */ tmp[(j * 4) + 2] += 0x09; break; case 5: /* replace by B */ tmp[(j * 4) + 2] += 0x06; break; case 6: /* replace by E0 */ tmp[(j * 4) + 2] += 0x08; break; case 7: /* replace by E0 */ tmp[(j * 4) + 2] += 0x07; break; case 8: /* replace by F */ tmp[(j * 4) + 2] += 0x07; break; default: break; } } fwrite(tmp, 1024, 1, out); } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_GMC(uint8 *data, char *t, int s) { int i, j, k; int ssize, numpat; PW_REQUEST_DATA(s, 1024); #if 0 /* test #1 */ if (i < 7) { return -1; } start = i - 7; #endif /* samples descriptions */ ssize = 0; for (i = 0; i < 15; i++) { int len, lsize; uint8 *d = data + 16 * i; /* volumes */ if (d[7] > 0x40) return -1; len = readmem16b(d + 4) << 1; lsize = readmem16b(d + 12); /* size */ if (len > 0xffff) return -1; if (lsize > len) return -1; ssize += len; } if (ssize <= 4) return -1; /* pattern table size */ if (data[243] > 0x64 || data[243] == 0) return -1; /* pattern order table */ numpat = 0; for (i = 0; i < 100; i++) { k = readmem16b(data + 244 + i * 2); if (k & 0x03ff) return -1; if ((k >> 10) > numpat) numpat = k >> 10; } numpat++; if (numpat == 1 || numpat > 100) return -1; PW_REQUEST_DATA(s, 444 + k * 1024 + i * 4 + 3); /* test pattern data */ for (i = 0; i < numpat; i++) { for (j = 0; j < 256; j++) { int offset = 444 + i * 1024 + j * 4; uint8 *d; PW_REQUEST_DATA(s, offset + 4); d = &data[offset]; if (offset > (PW_TEST_CHUNK - 4)) return -1; #if 0 /* First test fails with Jumping Jackson */ /* Second test never succeeds! */ if (/*d[0] > 0x03 ||*/ (d[2] & 0x0f) >= 0x90) return -1; #endif #if 0 /* Test fails with Jumping Jackson */ /* x is the highest jot jull sample */ if (((d[2] & 0xf0) >> 4) > x) return -1; #endif if ((d[2] & 0x0f) == 3 && d[3] > 0x40) return -1; if ((d[2] & 0x0f) == 4 && d[3] > 0x63) return -1; if ((d[2] & 0x0f) == 5 && d[3] > (data[243] + 1)) return -1; if ((d[2] & 0x0f) == 6 && d[3] >= 0x02) return -1; if ((d[2] & 0x0f) == 7 && d[3] >= 0x02) return -1; } } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_gmc = { "Game Music Creator", test_GMC, depack_GMC }; libxmp-4.4.1/src/loaders/prowizard/pha.c0000664000175000017500000001350112706551122020015 0ustar claudioclaudio/* * PhaPacker.c Copyright (C) 1996-1999 Asle / ReDoX * * Converts PHA packed MODs back to PTK MODs * nth revision :(. * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_pha(HIO_HANDLE *in, FILE *out) { uint8 c1, c2; uint8 pnum[128]; uint8 pnum1[128]; uint8 nop; uint8 *pdata; uint8 *pat; uint8 onote[4][4]; uint8 note, ins, fxt, fxp; uint8 npat = 0x00; int paddr[128]; int i, j, k; int paddr1[128]; int paddr2[128]; int tmp_ptr, tmp; int pat_addr; int psize; int size, ssize = 0; int smp_addr; short ocpt[4]; memset(paddr, 0, 128 * 4); memset(paddr1, 0, 128 * 4); memset(paddr2, 0, 128 * 4); memset(pnum, 0, 128); memset(pnum1, 0, 128); memset(onote, 0, 4 * 4); memset(ocpt, 0, 4 * 2); pw_write_zero(out, 20); /* title */ for (i = 0; i < 31; i++) { int vol, fin, lps, lsz; pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; hio_read8(in); /* ??? */ vol = hio_read8(in); /* volume */ lps = hio_read16b(in); /* loop start */ lsz = hio_read16b(in); /* loop size */ hio_read32b(in); /* sample address */ hio_read8(in); /* ??? */ fin = hio_read8(in); /* finetune - 11 */ if (fin != 0) { fin += 11; } write8(out, fin); write8(out, vol); write16b(out, lps); write16b(out, lsz); } hio_seek(in, 14, SEEK_CUR); /* bypass unknown 14 bytes */ for (i = 0; i < 128; i++) paddr[i] = hio_read32b(in); /* ordering of patterns addresses */ tmp_ptr = 0; for (i = 0; i < 128; i++) { if (i == 0) { pnum[0] = 0; tmp_ptr++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) pnum[i] = tmp_ptr++; } /* correct re-order */ for (i = 0; i < 128; i++) paddr1[i] = paddr[i]; restart: for (i = 0; i < 128; i++) { for (j = 0; j < i; j++) { if (paddr1[i] < paddr1[j]) { tmp = pnum[j]; pnum[j] = pnum[i]; pnum[i] = tmp; tmp = paddr1[j]; paddr1[j] = paddr1[i]; paddr1[i] = tmp; goto restart; } } } j = 0; for (i = 0; i < 128; i++) { if (i == 0) { paddr2[j] = paddr1[i]; continue; } if (paddr1[i] == paddr2[j]) continue; paddr2[++j] = paddr1[i]; } /* try to take care of unused patterns ... HARRRRRRD */ memset(paddr1, 0, 128 * 4); j = 0; k = paddr[0]; /* 120 ... leaves 8 unused ptk_tableible patterns .. */ for (i = 0; i < 120; i++) { paddr1[j] = paddr2[i]; j += 1; if ((paddr2[i + 1] - paddr2[i]) > 1024) { paddr1[j] = paddr2[i] + 1024; j += 1; } } for (c1 = 0; c1 < 128; c1++) { for (c2 = 0; c2 < 128; c2++) { if (paddr[c1] == paddr1[c2]) { pnum1[c1] = c2; } } } memset(pnum, 0, 128); pat_addr = 999999l; for (i = 0; i < 128; i++) { pnum[i] = pnum1[i]; if (paddr[i] < pat_addr) pat_addr = paddr[i]; } /* try to get the number of pattern in pattern list */ for (nop = 128; nop > 0; nop--) { if (pnum[nop - 1] != 0) break; } /* write this value */ write8(out, nop); /* get highest pattern number */ for (i = 0; i < nop; i++) if (pnum[i] > npat) npat = pnum[i]; write8(out, 0x7f); /* ntk restart byte */ for (i = 0; i < 128; i++) /* write pattern list */ write8(out, pnum[i]); write32b(out, PW_MOD_MAGIC); /* ID string */ smp_addr = hio_tell(in); hio_seek(in, pat_addr, SEEK_SET); /* pattern datas */ /* read ALL pattern data */ /* FIXME: shouldn't use file size */ #if 0 j = ftell (in); fseek (in, 0, 2); /* SEEK_END */ psize = ftell (in) - j; fseek (in, j, 0); /* SEEK_SET */ #endif psize = npat * 1024; pdata = (uint8 *) malloc (psize); psize = hio_read(pdata, 1, psize, in); npat += 1; /* coz first value is $00 */ pat = (uint8 *)malloc(npat * 1024); memset(pat, 0, npat * 1024); j = 0; for (i = 0; j < psize; i++) { if (pdata[i] == 0xff) { i += 1; ocpt[(k + 3) % 4] = 0xff - pdata[i]; continue; } if (ocpt[k % 4] != 0) { ins = onote[k % 4][0]; note = onote[k % 4][1]; fxt = onote[k % 4][2]; fxp = onote[k % 4][3]; ocpt[k % 4] -= 1; pat[j] = ins & 0xf0; pat[j] |= ptk_table[(note / 2)][0]; pat[j + 1] = ptk_table[(note / 2)][1]; pat[j + 2] = (ins << 4) & 0xf0; pat[j + 2] |= fxt; pat[j + 3] = fxp; k += 1; j += 4; i -= 1; continue; } ins = pdata[i]; note = pdata[i + 1]; fxt = pdata[i + 2]; fxp = pdata[i + 3]; onote[k % 4][0] = ins; onote[k % 4][1] = note; onote[k % 4][2] = fxt; onote[k % 4][3] = fxp; i += 3; pat[j] = ins & 0xf0; pat[j] |= ptk_table[(note / 2)][0]; pat[j + 1] = ptk_table[(note / 2)][1]; pat[j + 2] = (ins << 4) & 0xf0; pat[j + 2] |= fxt; pat[j + 3] = fxp; k += 1; j += 4; } fwrite(pat, npat * 1024, 1, out); free(pdata); free(pat); /* Sample data */ hio_seek(in, smp_addr, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_pha(uint8 *data, char *t, int s) { int i; int ptr, ssize; PW_REQUEST_DATA(s, 451 + 128 * 4); if (data[10] != 0x03 || data[11] != 0xc0) return -1; /* test #2 (volumes,sample addresses and whole sample size) */ ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 14; /* sample size */ ssize += readmem16b(d) << 1; if (d[3] > 0x40) return -1; /* loop start */ if ((readmem16b(d + 4) << 1) > ssize) return -1; /* address of sample data */ if (readmem32b(d + 8) < 0x3c0) return -1; } if (ssize <= 2 || ssize > 31 * 65535) return -1; /* test #3 (addresses of pattern in file ... ptk_tableible ?) */ /* l is the whole sample size */ /* ssize is used here as a variable ... set to 0 afterward */ for (i = 0; i < 128; i++) { ptr = readmem32b(data + 448 + i * 4); if (ptr + 2 - 960 < ssize) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_pha = { "Pha Packer", test_pha, depack_pha }; libxmp-4.4.1/src/loaders/prowizard/p61a.c0000664000175000017500000005627212706551122020030 0ustar claudioclaudio/* * The_Player_6.1a.c 1998 (c) Asle / ReDoX * Modified by Claudio Matsuoka * * The Player 6.1a to Protracker. * * note: As for version 5.0A and 6.0A, it's a REAL mess !. * It's VERY badly coded, I know. Just dont forget it was mainly done * to test the description I made of P61a format. * I certainly wont dare to beat Gryzor on the ground :). His Prowiz IS * the converter to use !!!. Though, using the official depacker could * be a good idea too :). */ #include #include #include "prowiz.h" static int depack_p61a(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4, c5, c6; long max_row; uint8 tmp[1024]; signed char *smp_buffer; int len; int npat; int nins; uint8 tdata[512][256]; uint8 ptable[128]; int isize[31]; uint8 PACK[31]; uint8 use_delta = 0; uint8 use_packed = 0; int taddr[128][4]; int tdata_addr = 0; int sdata_addr = 0; int ssize = 0; int i = 0, j, k, l, a, b, z; int smp_size[31]; int saddr[31]; int Unpacked_Sample_Data_Size; int x; memset(taddr, 0, 128 * 4 * 4); memset(tdata, 0, 512 << 8); memset(ptable, 0, 128); memset(smp_size, 0, 31 * 4); memset(isize, 0, 31 * 2); for (i = 0; i < 31; i++) { PACK[i] = 0; /* DELTA[i] = 0;*/ } saddr[0] = 0; sdata_addr = hio_read16b(in); /* read sample data address */ npat = hio_read8(in); /* read real number of pattern */ /* Sanity check */ if (npat >= 128) { return -1; } nins = hio_read8(in); /* read number of samples */ if (nins & 0x80) { /* Samples are saved as delta values */ use_delta = 1; } if (nins & 0x40) { /* Some samples are packed -- depacking not implemented */ use_packed = 1; return -1; } nins &= 0x3f; /* read unpacked sample data size */ if (use_packed == 1) Unpacked_Sample_Data_Size = hio_read32b(in); pw_write_zero(out, 20); /* write title */ /* sample headers stuff */ for (i = 0; i < nins; i++) { pw_write_zero(out, 22); /* write sample name */ j = isize[i] = hio_read16b(in); /* sample size */ if (j > 0xff00) { smp_size[i] = smp_size[0xffff - j]; isize[i] = isize[0xffff - j]; saddr[i] = saddr[0xffff - j]; } else { if (i > 0) { saddr[i] = saddr[i - 1] + smp_size[i - 1]; } smp_size[i] = j * 2; ssize += smp_size[i]; } j = smp_size[i] / 2; write16b(out, isize[i]); c1 = hio_read8(in); /* finetune */ if (c1 & 0x40) PACK[i] = 1; c1 &= 0x3f; write8(out, c1); write8(out, hio_read8(in)); /* volume */ /* loop start */ x = hio_read16b(in); if (x == 0xffff) { write16b(out, 0x0000); write16b(out, 0x0001); continue; } write16b(out, x); write16b(out, j - x); } /* go up to 31 samples */ memset(tmp, 0, 30); tmp[29] = 0x01; for (; i < 31; i++) fwrite(tmp, 30, 1, out); /* read tracks addresses per pattern */ for (i = 0; i < npat; i++) { for (j = 0; j < 4; j++) taddr[i][j] = hio_read16b(in); } /* pattern table */ for (len = 0; len < 128; len++) { c1 = hio_read8(in); if (c1 == 0xff) break; ptable[len] = c1; /* <--- /2 in p50a */ } write8(out, len); /* write size of pattern list */ write8(out, 0x7f); /* write noisetracker byte */ fwrite(ptable, 128, 1, out); /* write pattern table */ write32b(out, PW_MOD_MAGIC); /* write ptk ID */ if ((tdata_addr = hio_tell(in)) < 0) { return -1; } /* rewrite the track data */ for (i = 0; i < npat; i++) { max_row = 63; for (j = 0; j < 4; j++) { hio_seek(in, taddr[i][j] + tdata_addr, SEEK_SET); for (k = 0; k <= max_row; k++) { uint8 *x = &tdata[i * 4 + j][k * 4]; c1 = hio_read8(in); /* case no fxt nor fxtArg (3 bytes) */ if ((c1 & 0x70) == 0x70 && c1 != 0xff && c1 != 0x7F) { c2 = hio_read8(in); c6 = ((c1 << 4) & 0xf0) | ((c2 >> 4) & 0x0e); *x++ = (c2 & 0x10) | (ptk_table[c6 / 2][0]); *x++ = ptk_table[c6 / 2][1]; *x++ = (c2 << 4) & 0xf0; if (c1 & 0x80) { c3 = hio_read8(in); if (c3 < 0x80) { k += c3; continue; } c4 = c3 - 0x80; for (l = 0; l < c4; l++) { k++; x = &tdata[i * 4 + j][k * 4]; *x++ = (c2 & 0x10) | ptk_table[c6 / 2][0]; *x++ = ptk_table[c6 / 2][1]; *x++ = (c2 << 4) & 0xf0; } } continue; } /* end of case no fxt nor fxtArg */ /* case no sample number nor relative note number */ if ((c1 & 0x70) == 0x60 && c1 != 0xff) { c2 = hio_read8(in); c6 = c1 & 0x0f; if (c6 == 0x08) c1 -= 0x08; x += 2; *x++ = c1 & 0x0f; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c2 = c2 > 0x7f ? (0x100 - c2) << 4 : c2; *x++ = c2; if (c6 == 0x0d) { /* PATTERN BREAK, track ends */ max_row = k; break; } if (c6 == 0x0B) { /* PATTERN JUMP, track ends */ max_row = k; break; } if (c1 & 0x80) { c3 = hio_read8(in); if (c3 < 0x80) { /* bypass c3 rows */ k += c3; continue; } c4 = c3 - 0x80; /* repeat current row */ for (l = 0; l < c4; l++) { k++; x = &tdata[i * 4 + j][k * 4] + 2; *x++ = c1 & 0x0f; *x++ = c2; } } continue; } /* end of case no Sample number nor Relative not number */ if ((c1 & 0x80) == 0x80 && c1 != 0xff) { c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); c1 &= 0x7f; *x++ = ((c1 << 4) & 0x10) | ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; c6 = c2 & 0x0f; if (c6 == 0x08) c2 -= 0x08; *x++ = c2; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; if (c6 == 0x0d) { /* PATTERN BREAK, track ends */ max_row = k; break; } if (c6 == 0x0B) { /* PATTERN JUMP, track ends */ max_row = k; break; } if (c4 < 0x80) { /* bypass c4 rows */ k += c4; continue; } c4 = c4 - 0x80; for (l = 0; l < c4; l++) { /* repeat row c4-0x80 times */ k++; x = &tdata[i * 4 + j][k * 4]; *x++ = ((c1 << 4) & 0x10) | ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; c6 = c2 & 0x0f; if (c6 == 0x08) c2 -= 0x08; *x++ = c2; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; } continue; } if ((c1 & 0x7f) == 0x7f) { if (~c1 & 0x80) { /* bypass 1 row */ /*k += 1; */ continue; } c2 = hio_read8(in); if (c2 < 0x40) { /* bypass c2 rows */ k += c2; continue; } c2 -= 0x40; c3 = hio_read8(in); z = c3; if (c2 >= 0x80) { c2 -= 0x80; c4 = hio_read8(in); z = (c3 << 8) + c4; } if ((a = hio_tell(in)) < 0) { return -1; } c5 = c2; hio_seek(in, -z, SEEK_CUR); for (l = 0; l <= c5 && k <= max_row; l++, k++) { c1 = hio_read8(in); x = &tdata[i * 4 + j][k * 4]; /* case no fxt nor fxtArg (3 bytes) */ if ((c1 & 0x70) == 0x70 && c1 != 0xff && c1 != 0x7f) { c2 = hio_read8(in); c6 = ((c1 << 4) & 0xf0) | ((c2 >> 4) & 0x0e); *x++ = (c2 & 0x10) | ptk_table[c6 / 2][0]; *x++ = ptk_table[c6 / 2][1]; *x++ = (c2 << 4) & 0xf0; if (c1 & 0x80) { c3 = hio_read8(in); if (c3 < 0x80) { /* bypass c3 rows */ k += c3; continue; } c4 = c3 - 0x80; /* repeat row c3-0x80 times */ for (b = 0; b < c4; b++) { k++; x = &tdata[i * 4 + j][k * 4]; *x++ = (c2 & 0x10) | ptk_table[c6 / 2][0]; *x++ = ptk_table[c6 / 2][1]; *x++ = (c2 << 4) & 0xf0; } } continue; } /* end of case no fxt nor fxtArg */ /* case no sample number nor relative note number */ if ((c1 & 0x60) == 0x60 && c1 != 0xff && c1 != 0x7f) { c2 = hio_read8(in); c6 = c1 & 0x0f; if (c6 == 0x08) c1 -= 0x08; x += 2; *x++ = c1 & 0x0f; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c2 = c2 > 0x7f ? (0x100 - c2) << 4 : c2; *x++ = c2; if (c6 == 0x0d) { /* PATTERN BREAK, track ends */ max_row = k; goto brk_k; } if (c6 == 0x0b) { /* PATTERN JUMP, track ends */ max_row = k; goto brk_k; } if (c1 & 0x80) { c3 = hio_read8(in); if (c3 < 0x80) { /* bypass c3 rows */ k += c3; continue; } c4 = c3 - 0x80; /* repeat row c3-0x80 times */ for (b = 0; b < c4; b++) { k++; x = &tdata[i * 4 + j][k * 4] + 2; *x++ = c1 & 0x0f; *x++ = c2; } } continue; } /* end of case no sample nor relative note number */ if ((c1 & 0x80) && c1 != 0xff && c1 != 0x7f) { c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); c1 &= 0x7f; *x++ = ((c1 << 4) & 0x10) | ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; c6 = c2 & 0x0f; if (c6 == 0x08) c2 -= 0x08; *x++ = c2; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; if (c6 == 0x0d) { /* PATTERN BREAK, track ends */ max_row = k; goto brk_k; } if (c6 == 0x0b) { /* PATTERN JUMP, track ends */ max_row = k; goto brk_k; } if (c4 < 0x80) { /* bypass c4 rows */ k += c4; continue; } c4 = c4 - 0x80; /* repeat row c4-0x80 times */ for (b = 0; b < c4; b++) { k += 1; x = &tdata[i * 4 + j][k * 4]; *x++ = ((c1 << 4) & 0x10) |ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; c6 = c2 & 0x0f; if (c6 == 0x08) c2 -= 0x08; *x++ = c2; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; } continue; } if ((c1 & 0x7f) == 0x7f) { if ((c1 & 0x80) == 0x00) { /* bypass 1 row */ /*k += 1; */ continue; } c2 = hio_read8(in); if (c2 < 0x40) { /* bypass c2 rows */ k += c2; continue; } continue; } c2 = hio_read8(in); c3 = hio_read8(in); *x++ = ((c1 << 4) & 0x10) | ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; c6 = c2 & 0x0f; if (c6 == 0x08) c2 -= 0x08; *x++ = c2; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; } hio_seek(in, a, SEEK_SET); k -= 1; continue; } c2 = hio_read8(in); c3 = hio_read8(in); *x++ = ((c1 << 4) & 0x10) | ptk_table[c1 / 2][0]; *x++ = ptk_table[c1 / 2][1]; c6 = c2 & 0x0f; if (c6 == 0x08) c2 -= 0x08; *x++ = c2; if (c6 == 0x05 || c6 == 0x06 || c6 == 0x0a) c3 = c3 > 0x7f ? (0x100 - c3) << 4 : c3; *x++ = c3; if (c6 == 0x0d) { /* PATTERN BREAK, track ends */ max_row = k; break; } if (c6 == 0x0b) { /* PATTERN JUMP, track ends */ max_row = k; break; } } brk_k: ; } } /* write pattern data */ for (i = 0; i < npat; i++) { memset(tmp, 0, 1024); for (j = 0; j < 64; j++) { for (k = 0; k < 4; k++) memcpy(&tmp[j * 16 + k * 4], &tdata[k + i * 4][j * 4], 4); } fwrite (tmp, 1024, 1, out); } /* go to sample data address */ hio_seek(in, sdata_addr, SEEK_SET); /* read and write sample data */ /*printf ( "writing sample data ... " ); */ for (i = 0; i < nins; i++) { hio_seek(in, sdata_addr + saddr[i], 0); smp_buffer = malloc(smp_size[i]); memset(smp_buffer, 0, smp_size[i]); hio_read(smp_buffer, smp_size[i], 1, in); if (use_delta == 1) { c1 = 0; for (j = 1; j < smp_size[i]; j++) { c2 = smp_buffer[j]; c2 = 0x100 - c2; c3 = c2 + c1; smp_buffer[j] = c3; c1 = c3; } } fwrite(smp_buffer, smp_size[i], 1, out); free(smp_buffer); } /* if (use_delta == 1) pw_p60a.flags |= PW_DELTA; */ return 0; } static int test_p61a(uint8 *data, char *t, int s) { int j, k, l, m, n, o; int start = 0, ssize; int x; #if 0 if (i < 7) { Test = BAD; return; } start = i - 7; #endif /* number of pattern (real) */ /* m is the real number of pattern */ m = data[start + 2]; if (m > 0x7f || m == 0) return -1; /* number of sample */ /* k is the number of sample */ k = (data[start + 3] & 0x3f); if (k > 0x1f || k == 0) return -1; for (l = 0; l < k; l++) { /* test volumes */ if (data[start + 7 + l * 6] > 0x40) return -1; /* test finetunes */ if (data[start + 6 + l * 6] > 0x0f) return -1; } /* test sample sizes and loop start */ ssize = 0; for (n = 0; n < k; n++) { o = readmem16b(data + start + n * 6 + 4); if ((o < 0xffdf && o > 0x8000) || o == 0) return -1; if (o < 0xff00) ssize += o * 2; j = readmem16b(data + start + n * 6 + 8); if (j != 0xffff && j >= o) return -1; if (o > 0xffdf) { if (0xffff - o > k) return -1; } } /* test sample data address */ /* j is the address of the sample data */ j = readmem16b(data + start); if (j < k * 6 + 4 + m * 8) return -1; /* test track table */ for (l = 0; l < m * 4; l++) { o = readmem16b(data + start + 4 + k * 6 + l * 2); if (o + k * 6 + 4 + m * 8 > j) return -1; } /* test pattern table */ l = 0; o = 0; /* first, test if we dont oversize the input file */ x = k * 6 + 4 + m * 8; PW_REQUEST_DATA(s, start + x); while (data[start + x + l] != 0xff && l < 128) { if (data[start + x + l] > m - 1) return -1; if (data[start + x + l] > o) o = data[start + x + l]; l++; } /* are we beside the sample data address ? */ if (x + l > j) return -1; if (l == 0 || l == 128) return -1; o += 1; /* o is the highest number of pattern */ /* test notes ... pfiew */ PW_REQUEST_DATA (s, start + j + 1); l += 1; for (n = x + l; n < j; n++) { uint8 d, e; d = data[start + n]; e = data[start + n + 1]; if ((d & 0xff) == 0xff) { if ((e & 0xc0) == 0x00) { n += 1; continue; } if ((e & 0xc0) == 0x40) { n += 2; continue; } if ((e & 0xc0) == 0xc0) { n += 3; continue; } } if ((d & 0xff) == 0x7f) continue; /* no fxt nor fxtArg */ if ((d & 0xf0) == 0xf0) { if ((e & 0x1f) > k) return -1; n += 2; continue; } if ((d & 0xf0) == 0x70) { if ((e & 0x1f) > k) return -1; n += 1; continue; } /* no note nor Sample number */ if ((d & 0xf0) == 0xe0) { n += 2; continue; } if ((d & 0xf0) == 0x60) { n += 1; continue; } if ((d & 0x80) == 0x80) { if ((((d << 4) & 0x10) | ((e >> 4) & 0x0f)) > k) return -1; n += 3; continue; } if ((((d << 4) & 0x10) | ((e >> 4) & 0x0F)) > k) return -1; n += 2; } /* ssize is the whole sample data size */ /* j is the address of the sample data */ return 0; } #if 0 /******************/ /* packed samples */ /******************/ void testP61A_pack (void) { if (i < 11) { Test = BAD; return; } start = i - 11; /* number of pattern (real) */ m = data[start + 2]; if ((m > 0x7f) || (m == 0)) { /*printf ( "#1 Start:%ld\n" , start );*/ Test = BAD; return; } /* m is the real number of pattern */ /* number of sample */ k = data[start + 3]; if ((k & 0x40) != 0x40) { /*printf ( "#2,0 Start:%ld\n" , start );*/ Test = BAD; return; } k &= 0x3F; if ((k > 0x1F) || (k == 0)) { /*printf ( "#2,1 Start:%ld (k:%ld)\n" , start,k );*/ Test = BAD; return; } /* k is the number of sample */ /* test volumes */ for (l = 0; l < k; l++) { if (data[start + 11 + l * 6] > 0x40) { /*printf ( "#3 Start:%ld\n" , start );*/ Test = BAD; return; } } /* test fines */ for (l = 0; l < k; l++) { if ((data[start + 10 + l * 6] & 0x3F) > 0x0F) { Test = BAD; /*printf ( "#4 Start:%ld\n" , start );*/ return; } } /* test sample sizes and loop start */ ssize = 0; for (n = 0; n < k; n++) { o = ((data[start + 8 + n * 6] << 8) + data[start + 9 + n * 6]); if (((o < 0xFFDF) && (o > 0x8000)) || (o == 0)) { /*printf ( "#5 Start:%ld\n" , start );*/ Test = BAD; return; } if (o < 0xFF00) ssize += (o * 2); j = ((data[start + 12 + n * 6] << 8) + data[start + 13 + n * 6]); if ((j != 0xFFFF) && (j >= o)) { /*printf ( "#5,1 Start:%ld\n" , start );*/ Test = BAD; return; } if (o > 0xFFDF) { if ((0xFFFF - o) > k) { /*printf ( "#5,2 Start:%ld\n" , start );*/ Test = BAD; return; } } } /* test sample data address */ j = (data[start] << 8) + data[start + 1]; if (j < (k * 6 + 8 + m * 8)) { /*printf ( "#6 Start:%ld\n" , start );*/ Test = BAD; ssize = 0; return; } /* j is the address of the sample data */ /* test track table */ for (l = 0; l < (m * 4); l++) { o = ((data[start + 8 + k * 6 + l * 2] << 8) + data[start + 8 + k * 6 + l * 2 + 1]); if ((o + k * 6 + 8 + m * 8) > j) { /*printf ( "#7 Start:%ld (value:%ld)(where:%x)(l:%ld)(m:%ld)(o:%ld)\n" , start , (data[start+k*6+8+l*2]*256)+data[start+8+k*6+l*2+1] , start+k*6+8+l*2 , l , m , o );*/ Test = BAD; return; } } /* test pattern table */ l = 0; o = 0; /* first, test if we dont oversize the input file */ if ((k * 6 + 8 + m * 8) > in_size) { /*printf ( "8,0 Start:%ld\n" , start );*/ Test = BAD; return; } while ((data[start + k * 6 + 8 + m * 8 + l] != 0xFF) && (l < 128)) { if (data[start + k * 6 + 8 + m * 8 + l] > (m - 1)) { /*printf ( "#8,1 Start:%ld (value:%ld)(where:%x)(l:%ld)(m:%ld)(k:%ld)\n" , start , data[start+k*6+8+m*8+l] , start+k*6+8+m*8+l , l , m , k );*/ Test = BAD; ssize = 0; return; } if (data[start + k * 6 + 8 + m * 8 + l] > o) o = data[start + k * 6 + 8 + m * 8 + l]; l++; } if ((l == 0) || (l == 128)) { /*printf ( "#8.2 Start:%ld\n" , start );*/ Test = BAD; return; } o /= 2; o += 1; /* o is the highest number of pattern */ /* test notes ... pfiew */ l += 1; for (n = (k * 6 + 8 + m * 8 + l); n < j; n++) { if ((data[start + n] & 0xff) == 0xff) { if ((data[start + n + 1] & 0xc0) == 0x00) { n += 1; continue; } if ((data[start + n + 1] & 0xc0) == 0x40) { n += 2; continue; } if ((data[start + n + 1] & 0xc0) == 0xc0) { n += 3; continue; } } if ((data[start + n] & 0xff) == 0x7f) { continue; } /* no fxt nor fxtArg */ if ((data[start + n] & 0xf0) == 0xf0) { if ((data[start + n + 1] & 0x1F) > k) { /*printf ( "#9,1 Start:%ld (value:%ld) (where:%x) (n:%ld) (j:%ld)\n" , start , data[start+n] , start+n , n , j );*/ Test = BAD; return; } n += 2; continue; } if ((data[start + n] & 0xf0) == 0x70) { if ((data[start + n + 1] & 0x1F) > k) { /*printf ( "#9,1 Start:%ld (value:%ld) (where:%x) (n:%ld) (j:%ld)\n" , start , data[start+n] , start+n , n , j );*/ Test = BAD; return; } n += 1; continue; } /* no note nor Sample number */ if ((data[start + n] & 0xf0) == 0xe0) { n += 2; continue; } if ((data[start + n] & 0xf0) == 0x60) { n += 1; continue; } if ((data[start + n] & 0x80) == 0x80) { if ((((data[start + n] << 4) & 0x10) | ((data[start + n + 1] >> 4) & 0x0F)) > k) { /*printf ( "#9,1 Start:%ld (value:%ld) (where:%x) (n:%ld) (j:%ld)\n" , start , data[start+n] , start+n , n , j );*/ Test = BAD; return; } n += 3; continue; } if ((((data[start + n] << 4) & 0x10) | ((data[start + n + 1] >> 4) & 0x0F)) > k) { /*printf ( "#9,1 Start:%ld (value:%ld) (where:%x) (n:%ld) (j:%ld)\n" , start , data[start+n] , start+n , n , j );*/ Test = BAD; return; } n += 2; } /* ssize is the whole sample data size */ /* j is the address of the sample data */ Test = GOOD; } #endif const struct pw_format pw_p61a = { "The Player 6.1a", test_p61a, depack_p61a }; libxmp-4.4.1/src/loaders/prowizard/noiserun.c0000664000175000017500000000740412706551122021114 0ustar claudioclaudio/* * NoiseRunner.c Copyright (C) 1997 Asle / ReDoX * * Converts NoiseRunner packed MODs back to Protracker * * Modified in 2010,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int fine_table[] = { 0x0000, 0xffb8, 0xff70, 0xff28, 0xfee0, 0xfe98, 0xfe50, 0xfe08, 0xfdc0, 0xfd78, 0xfd30, 0xfce8, 0xfca0, 0xfc58, 0xfc10, 0xfbc8 }; static int depack_nru(HIO_HANDLE *in, FILE *out) { uint8 tmp[1025]; uint8 ptable[128]; uint8 note, ins, fxt, fxp; uint8 pat_data[1025]; int fine; int i, j; int max_pat; long ssize = 0; pw_write_zero(out, 20); /* title */ for (i = 0; i < 31; i++) { /* 31 samples */ int vol, size, addr, start, lsize; pw_write_zero(out, 22); /* sample name */ hio_read8(in); /* bypass 0x00 */ vol = hio_read8(in); /* read volume */ addr = hio_read32b(in); /* read sample address */ write16b(out, size = hio_read16b(in)); /* read/write sample size */ ssize += size * 2; start = hio_read32b(in); /* read loop start address */ lsize = hio_read16b(in); /* read loop size */ fine = hio_read16b(in); /* read finetune ?!? */ for (j = 0; j < 16; j++) { if (fine == fine_table[j]) { fine = j; break; } } if (j == 16) fine = 0; write8(out, fine); /* write fine */ write8(out, vol); /* write vol */ write16b(out, (start - addr) / 2); /* write loop start */ write16b(out, lsize); /* write loop size */ } hio_seek(in, 950, SEEK_SET); write8(out, hio_read8(in)); /* size of pattern list */ write8(out, hio_read8(in)); /* ntk byte */ /* pattern table */ max_pat = 0; hio_read(ptable, 128, 1, in); fwrite(ptable, 128, 1, out); for (i = 0; i < 128; i++) { if (ptable[i] > max_pat) max_pat = ptable[i]; } max_pat++; write32b(out, PW_MOD_MAGIC); /* pattern data */ hio_seek(in, 0x043c, SEEK_SET); for (i = 0; i < max_pat; i++) { memset(pat_data, 0, 1025); hio_read(tmp, 1024, 1, in); for (j = 0; j < 256; j++) { ins = (tmp[j * 4 + 3] >> 3) & 0x1f; note = tmp[j * 4 + 2]; fxt = tmp[j * 4]; fxp = tmp[j * 4 + 1]; switch (fxt) { case 0x00: /* tone portamento */ fxt = 0x03; break; case 0x0C: /* no fxt */ fxt = 0x00; break; default: fxt >>= 2; break; } pat_data[j * 4] = ins & 0xf0; pat_data[j * 4] |= ptk_table[note / 2][0]; pat_data[j * 4 + 1] = ptk_table[note / 2][1]; pat_data[j * 4 + 2] = (ins << 4) & 0xf0; pat_data[j * 4 + 2] |= fxt; pat_data[j * 4 + 3] = fxp; } fwrite (pat_data, 1024, 1, out); } pw_move_data(out, in, ssize); /* sample data */ return 0; } static int test_nru(uint8 *data, char *t, int s) { int i; int len, psize, ssize; PW_REQUEST_DATA(s, 1500); #if 0 /* test 1 */ if (i < 1080) { return -1; } #endif if (readmem32b(data + 1080) != PW_MOD_MAGIC) return -1; /* test 2 */ ssize = 0; for (i = 0; i < 31; i++) ssize += 2 * readmem16b(data + 6 + i * 16); if (ssize == 0) return -1; /* test #3 volumes */ for (i = 0; i < 31; i++) { if (data[1 + i * 16] > 0x40) return -1; } /* test #4 pattern list size */ len = data[950]; if (len == 0 || len > 127) { return -1; } /* l holds the size of the pattern list */ psize = 0; for (i = 0; i < len; i++) { int x = data[952 + i]; if (x > psize) psize = x; if (x > 127) { return -1; } } /* test last patterns of the pattern list = 0 ? */ while (i != 128) { if (data[952 + i] != 0) { return -1; } i++; } psize++; psize <<= 8; /* test #5 pattern data ... */ for (i = 0; i < psize; i++) { uint8 *d = data + 1084 + i * 4; /* note > 48h ? */ if (d[2] > 0x48) return -1; if (d[3] & 0x07) return -1; if (d[0] & 0x03) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_nru = { "NoiseRunner", test_nru, depack_nru }; libxmp-4.4.1/src/loaders/prowizard/tdd.c0000664000175000017500000001075512706551122020030 0ustar claudioclaudio/* * tdd.c Copyright (C) 1999 Asle / ReDoX * * Converts TDD packed MODs back to PTK MODs * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_tdd(HIO_HANDLE *in, FILE *out) { uint8 tmp[1024]; uint8 pat[1024]; uint8 pmax; int i, j, k; int size, ssize = 0; int saddr[31]; int ssizes[31]; memset(saddr, 0, 31 * 4); memset(ssizes, 0, 31 * 4); /* write ptk header */ pw_write_zero(out, 1080); /* read/write pattern list + size and ntk byte */ if (fseek(out, 950, SEEK_SET) < 0) { return -1; } hio_read(tmp, 130, 1, in); fwrite(tmp, 130, 1, out); for (pmax = i = 0; i < 128; i++) { if (tmp[i + 2] > pmax) { pmax = tmp[i + 2]; } } /* sample descriptions */ for (i = 0; i < 31; i++) { if (fseek(out, 42 + (i * 30), SEEK_SET) < 0) { return -1; } /* sample address */ saddr[i] = hio_read32b(in); /* read/write size */ write16b(out, size = hio_read16b(in)); ssize += size; ssizes[i] = size; write8(out, hio_read8(in)); /* read/write finetune */ write8(out, hio_read8(in)); /* read/write volume */ /* read/write loop start */ write16b(out, (hio_read32b(in) - saddr[i]) / 2); write16b(out, hio_read16b(in)); /* read/write replen */ } /* bypass Samples datas */ if (hio_seek(in, ssize, SEEK_CUR) < 0) { return -1; } /* write ptk's ID string */ if (fseek(out, 0, SEEK_END) < 0) { return -1; } write32b(out, PW_MOD_MAGIC); /* read/write pattern data */ for (i = 0; i <= pmax; i++) { memset(tmp, 0, 1024); memset(pat, 0, 1024); if (hio_read(tmp, 1, 1024, in) != 1024) { return -1; } for (j = 0; j < 64; j++) { for (k = 0; k < 4; k++) { int x = j * 16 + k * 4; /* fx arg */ pat[x + 3] = tmp[x + 3]; /* fx */ pat[x + 2] = tmp[x + 2] & 0x0f; /* smp */ pat[x] = tmp[x] & 0xf0; pat[x + 2] |= (tmp[x] << 4) & 0xf0; /* note */ pat[x] |= ptk_table[tmp[x + 1] / 2][0]; pat[x + 1] = ptk_table[tmp[x + 1] / 2][1]; } } if (fwrite(pat, 1, 1024, out) != 1024) { return -1; } } /* Sample data */ for (i = 0; i < 31; i++) { if (ssizes[i] == 0) continue; hio_seek(in, saddr[i], SEEK_SET); pw_move_data(out, in, ssizes[i]); } return 0; } static int test_tdd(uint8 *data, char *t, int s) { int i; int ssize, psize, pdata_ofs; PW_REQUEST_DATA(s, 564); /* test #2 (volumes,sample addresses and whole sample size) */ ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 14; int addr = readmem32b(d + 130); /* sample address */ int size = readmem16b(d + 134); /* sample size */ int sadr = readmem32b(d + 138); /* loop start address */ int lsiz = readmem16b(d + 142); /* loop size (replen) */ /* volume > 40h ? */ if (d[137] > 0x40) return -1; /* loop start addy < sampl addy ? */ if (sadr < addr) return -1; /* addy < 564 ? */ if (addr < 564 || sadr < 564) return -1; /* loop start > size ? */ if (sadr - addr > size) return -1; /* loop start+replen > size ? */ if (sadr - addr + lsiz > size + 2) return -1; ssize += size; } if (ssize <= 2 || ssize > 31 * 65535) return -1; #if 0 /* test #3 (addresses of pattern in file ... ptk_tableible ?) */ /* ssize is the whole sample size :) */ if ((ssize + 564) > in_size) { Test = BAD; return; } #endif /* test size of pattern list */ if (data[0] == 0 || data[0] > 0x7f) return -1; /* test pattern list */ psize = 0; for (i = 0; i < 128; i++) { int pat = data[i + 2]; if (pat > 0x7f) return -1; if (pat > psize) psize = pat; } psize++; psize <<= 10; /* test end of pattern list */ for (i = data[0] + 2; i < 128; i++) { if (data[i + 2] != 0) return -1; } #if 0 /* test if not out of file range */ if ((ssize + 564 + k) > in_size) return -1; #endif /* ssize is the whole sample data size */ /* test pattern data now ... */ pdata_ofs = 564 + ssize; PW_REQUEST_DATA(s, 564 + ssize + psize); for (i = 0; i < psize; i += 4) { uint8 *d = data + pdata_ofs + i; /* sample number > 31 ? */ if (d[0] > 0x1f) return -1; /* note > 0x48 (36*2) */ if (d[1] > 0x48 || (d[1] & 0x01) == 0x01) return -1; /* fx=C and fxtArg > 64 ? */ if ((d[2] & 0x0f) == 0x0c && d[3] > 0x40) return -1; /* fx=D and fxtArg > 64 ? */ if ((d[2] & 0x0f) == 0x0d && d[3] > 0x40) return -1; /* fx=B and fxtArg > 127 ? */ if ((d[2] & 0x0f) == 0x0b) return -1; } pw_read_title(NULL, t, 0); return -1; } const struct pw_format pw_tdd = { "The Dark Demon", test_tdd, depack_tdd }; libxmp-4.4.1/src/loaders/prowizard/tuning.c0000664000175000017500000000631012641457214020556 0ustar claudioclaudio /* period tables for each tuning * part of Pro-Wizard package */ const short tun_table[16][36] = { { 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 }, { 850,802,757,715,674,637,601,567,535,505,477,450, 425,401,379,357,337,318,300,284,268,253,239,225, 213,201,189,179,169,159,150,142,134,126,119,113 }, { 844,796,752,709,670,632,597,563,532,502,474,447, 422,398,376,355,335,316,298,282,266,251,237,224, 211,199,188,177,167,158,149,141,133,125,118,112 }, { 838,791,746,704,665,628,592,559,528,498,470,444, 419,395,373,352,332,314,296,280,264,249,235,222, 209,198,187,176,166,157,148,140,132,125,118,111 }, { 832,785,741,699,660,623,588,555,524,495,467,441, 416,392,370,350,330,312,294,278,262,247,233,220, 208,196,185,175,165,156,147,139,131,124,117,110 }, { 826,779,736,694,655,619,584,551,520,491,463,437, 413,390,368,347,328,309,292,276,260,245,232,219, 206,195,184,174,164,155,146,138,130,123,116,109 }, { 820,774,730,689,651,614,580,547,516,487,460,434, 410,387,365,345,325,307,290,274,258,244,230,217, 205,193,183,172,163,154,145,137,129,122,115,109 }, { 814,768,725,684,646,610,575,543,513,484,457,431, 407,384,363,342,323,305,288,272,256,242,228,216, 204,192,181,171,161,152,144,136,128,121,114,108 }, { 907,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 }, { 900,850,802,757,715,675,636,601,567,535,505,477, 450,425,401,379,357,337,318,300,284,268,253,238, 225,212,200,189,179,169,159,150,142,134,126,119 }, { 894,844,796,752,709,670,632,597,563,532,502,474, 447,422,398,376,355,335,316,298,282,266,251,237, 223,211,199,188,177,167,158,149,141,133,125,118 }, { 887,838,791,746,704,665,628,592,559,528,498,470, 444,419,395,373,352,332,314,296,280,264,249,235, 222,209,198,187,176,166,157,148,140,132,125,118 }, { 881,832,785,741,699,660,623,588,555,524,494,467, 441,416,392,370,350,330,312,294,278,262,247,233, 220,208,196,185,175,165,156,147,139,131,123,117 }, { 875,826,779,736,694,655,619,584,551,520,491,463, 437,413,390,368,347,328,309,292,276,260,245,232, 219,206,195,184,174,164,155,146,138,130,123,116 }, { 868,820,774,730,689,651,614,580,547,516,487,460, 434,410,387,365,345,325,307,290,274,258,244,230, 217,205,193,183,172,163,154,145,137,129,122,115 }, { 862,814,768,725,684,646,610,575,543,513,484,457, 431,407,384,363,342,323,305,288,272,256,242,228, 216,203,192,181,171,161,152,144,136,128,121,114 } }; libxmp-4.4.1/src/loaders/prowizard/hrt.c0000664000175000017500000000366612706551122020055 0ustar claudioclaudio/* * Hornet_Packer.c Copyright (C) 1997 Asle / ReDoX * * Modified in 2009,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_hrt(HIO_HANDLE *in, FILE *out) { uint8 buf[1024]; uint8 c1, c2, c3, c4; int len, npat; int ssize = 0; int i, j; memset(buf, 0, 950); hio_read(buf, 950, 1, in); /* read header */ for (i = 0; i < 31; i++) /* erase addresses */ *(uint32 *)(buf + 38 + 30 * i) = 0; fwrite(buf, 950, 1, out); /* write header */ for (i = 0; i < 31; i++) /* samples size */ ssize += readmem16b(buf + 42 + 30 * i) * 2; write8(out, len = hio_read8(in)); /* song length */ write8(out, hio_read8(in)); /* nst byte */ hio_read(buf, 1, 128, in); /* pattern list */ npat = 0; /* number of patterns */ for (i = 0; i < 128; i++) { if (buf[i] > npat) npat = buf[i]; } npat++; write32b(out, PW_MOD_MAGIC); /* write ptk ID */ /* pattern data */ hio_seek(in, 1084, SEEK_SET); for (i = 0; i < npat; i++) { for (j = 0; j < 256; j++) { buf[0] = hio_read8(in); buf[1] = hio_read8(in); buf[2] = hio_read8(in); buf[3] = hio_read8(in); buf[0] /= 2; c1 = buf[0] & 0xf0; if (buf[1] == 0) c2 = 0; else { c1 |= ptk_table[buf[1] / 2][0]; c2 = ptk_table[buf[1] / 2][1]; } c3 = ((buf[0] << 4) & 0xf0) | buf[2]; c4 = buf[3]; write8(out, c1); write8(out, c2); write8(out, c3); write8(out, c4); } } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_hrt(uint8 *data, char *t, int s) { int i; PW_REQUEST_DATA(s, 1084); if (readmem32b(data + 1080) != MAGIC4('H','R','T','!')) return -1; for (i = 0; i < 31; i++) { uint8 *d = data + 20 + i * 30; /* test finetune */ if (d[24] > 0x0f) return -1; /* test volume */ if (d[25] > 0x40) return -1; } pw_read_title(data, t, 20); return 0; } const struct pw_format pw_hrt = { "Hornet Packer", test_hrt, depack_hrt }; libxmp-4.4.1/src/loaders/prowizard/prun2.c0000664000175000017500000000522212706551122020314 0ustar claudioclaudio/* * ProRunner2.c Copyright (C) 1996-1999 Asle / ReDoX * * Converts ProRunner v2 packed MODs back to Protracker * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_pru2(HIO_HANDLE *in, FILE *out) { uint8 header[2048]; uint8 npat; uint8 ptable[128]; uint8 max = 0; uint8 v[4][4]; int size, ssize = 0; int i, j; memset(header, 0, 2048); memset(ptable, 0, 128); memset(v, 0, 16); pw_write_zero(out, 20); /* title */ hio_seek(in, 8, SEEK_SET); for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /*sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } write8(out, npat = hio_read8(in)); /* number of patterns */ write8(out, hio_read8(in)); /* noisetracker byte */ for (i = 0; i < 128; i++) { uint8 x; write8(out, x = hio_read8(in)); max = (x > max) ? x : max; } write32b(out, PW_MOD_MAGIC); /* pattern data stuff */ hio_seek(in, 770, SEEK_SET); for (i = 0; i <= max; i++) { for (j = 0; j < 256; j++) { uint8 c[4]; memset(c, 0, 4); header[0] = hio_read8(in); if (header[0] == 0x80) { write32b(out, 0); } else if (header[0] == 0xc0) { fwrite(v[0], 4, 1, out); memcpy(c, v[0], 4); } else if (header[0] >= 74) { return -1; } else { header[1] = hio_read8(in); header[2] = hio_read8(in); c[0] = (header[1] & 0x80) >> 3; c[0] |= ptk_table[(header[0] >> 1)][0]; c[1] = ptk_table[(header[0] >> 1)][1]; c[2] = (header[1] & 0x70) << 1; c[2] |= (header[0] & 0x01) << 4; c[2] |= (header[1] & 0x0f); c[3] = header[2]; fwrite(c, 1, 4, out); } /* rol previous values */ memcpy(&v[0], &v[1], 4); memcpy(&v[1], &v[2], 4); memcpy(&v[2], &v[3], 4); memcpy(v[3], c, 4); } } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_pru2(uint8 *data, char *t, int s) { int k; PW_REQUEST_DATA(s, 12 + 31 * 8); if (readmem32b(data) != 0x534e5421) return -1; #if 0 /* check sample address */ j = (data[i + 4] << 24) + (data[i + 5] << 16) + (data[i + 6] << 8) + data[i + 7]; PW_REQUEST_DATA (s, j); #endif /* test volumes */ for (k = 0; k < 31; k++) { if (data[11 + k * 8] > 0x40) return -1; } /* test finetunes */ for (k = 0; k < 31; k++) { if (data[10 + k * 8] > 0x0F) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_pru2 = { "Prorunner 2.0", test_pru2, depack_pru2 }; libxmp-4.4.1/src/loaders/prowizard/novotrade.c0000664000175000017500000000532012706551122021246 0ustar claudioclaudio/* * NovoTrade.c Copyright (C) 2007 Asle / ReDoX * * Modified in 2009,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_ntp(HIO_HANDLE *in, FILE *out) { uint8 buf[1024]; int i, j; int pat_addr[128]; short body_addr, smp_addr, nins, len, npat; int size, ssize = 0; hio_read32b(in); /* skip MODU */ pw_move_data(out, in, 16); /* title */ write32b(out, 0); body_addr = hio_read16b(in) + 4; /* get 'BODY' address */ nins = hio_read16b(in); /* number of samples */ len = hio_read16b(in); /* size of pattern list */ npat = hio_read16b(in); /* number of patterns stored */ smp_addr = hio_read16b(in) + body_addr + 4; /* get 'SAMP' address */ memset(buf, 0, 930); /* instruments */ for (i = 0; i < nins; i++) { int x = hio_read8(in); /* instrument number */ if (x > 30) { hio_seek(in, 7, SEEK_CUR); continue; } x *= 30; buf[x + 25] = hio_read8(in); /* volume */ size = hio_read16b(in); /* size */ buf[x + 22] = size >> 8; buf[x + 23] = size & 0xff; ssize += size * 2; buf[x + 26] = hio_read8(in); /* loop start */ buf[x + 27] = hio_read8(in); buf[x + 28] = hio_read8(in); /* loop size */ buf[x + 29] = hio_read8(in); } fwrite(buf, 930, 1, out); write8(out, len); write8(out, 0x7f); /* pattern list */ memset(buf, 0, 128); for (i = 0; i < len; i++) buf[i] = hio_read16b(in); fwrite(buf, 128, 1, out); /* pattern addresses now */ /* Where is on it */ memset(pat_addr, 0, 256); for (i = 0; i < npat; i++) pat_addr[i] = hio_read16b(in); write32b(out, PW_MOD_MAGIC); /* pattern data now ... *gee* */ for (i = 0; i < npat; i++) { hio_seek(in, body_addr + 4 + pat_addr[i], SEEK_SET); memset(buf, 0, 1024); for (j = 0; j < 64; j++) { int x = hio_read16b(in); if (x & 0x0001) hio_read(buf + j * 16, 1, 4, in); if (x & 0x0002) hio_read(buf + j * 16 + 4, 1, 4, in); if (x & 0x0004) hio_read(buf + j * 16 + 8, 1, 4, in); if (x & 0x0008) hio_read(buf + j * 16 + 12, 1, 4, in); } fwrite(buf, 1024, 1, out); } /* samples */ hio_seek(in, smp_addr, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_ntp(uint8 *data, char *t, int s) { int j, k; PW_REQUEST_DATA(s, 64); if (readmem32b(data) != MAGIC4('M','O','D','U')) return -1; j = readmem16b(data + 20) + 4; /* "BODY" tag */ k = readmem16b(data + 28) + j + 4; /* "SAMP" tag */ PW_REQUEST_DATA(s, j + 4); if (readmem32b(data + j) != MAGIC4('B','O','D','Y')) return -1; PW_REQUEST_DATA(s, k + 4); if (readmem32b(data + k) != MAGIC4('S','A','M','P')) return -1; pw_read_title(data + 4, t, 16); return 0; } const struct pw_format pw_ntp = { "Novotrade Packer", test_ntp, depack_ntp }; libxmp-4.4.1/src/loaders/prowizard/xann.c0000664000175000017500000001265412706551122020221 0ustar claudioclaudio/* * XANN_Packer.c Copyright (C) 1997 Asle / ReDoX * * XANN Packer to Protracker. * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include "prowiz.h" #define SMP_DESC_ADDRESS 0x206 #define PAT_DATA_ADDRESS 0x43C static int depack_xann(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c5; uint8 ptable[128]; uint8 pat = 0x00; uint8 note, ins, fxt, fxp; uint8 fine, vol; uint8 pdata[1025]; int i, j, k; int size, ssize = 0; int lsize; memset(ptable, 0, 128); memset(pdata, 0, 1025); pw_write_zero(out, 20); /* title */ /* 31 samples */ hio_seek(in, SMP_DESC_ADDRESS, SEEK_SET); for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ fine = hio_read8(in); /* read finetune */ vol = hio_read8(in); /* read volume */ j = hio_read32b(in); /* read loop start address */ lsize = hio_read16b(in); /* read loop size */ k = hio_read32b(in); /* read sample address */ write16b(out, size = hio_read16b(in)); /* sample size */ ssize += size * 2; j = j - k; /* calculate loop start value */ write8(out, fine); /* write fine */ write8(out, vol); /* write vol */ write16b(out, j / 2); /* write loop start */ write16b(out, lsize); /* write loop size */ hio_read16b(in); /* bypass two unknown bytes */ } /* pattern table */ hio_seek(in, 0, SEEK_SET); for (pat = c5 = 0; c5 < 128; c5++) { k = hio_read32b(in); if (k == 0) break; ptable[c5] = ((k - 0x3c) / 1024) - 1; if (ptable[c5] > pat) pat = ptable[c5]; } pat++; /* starts at $00 */ write8(out, c5); /* write number of pattern */ write8(out, 0x7f); /* write noisetracker byte */ fwrite(ptable, 128, 1, out); /* write pattern list */ write32b(out, PW_MOD_MAGIC); /* write Protracker's ID */ /* pattern data */ hio_seek(in, PAT_DATA_ADDRESS, SEEK_SET); for (i = 0; i < pat; i++) { for (j = 0; j < 256; j++) { uint8 *p = pdata + j * 4; ins = (hio_read8(in) >> 3) & 0x1f; note = hio_read8(in); fxt = hio_read8(in); fxp = hio_read8(in); if (hio_error(in) || note >= 74) { return -1; } switch (fxt) { case 0x00: /* no fxt */ fxt = 0x00; break; case 0x04: /* arpeggio */ fxt = 0x00; break; case 0x08: /* portamento up */ fxt = 0x01; break; case 0x0C: /* portamento down */ fxt = 0x02; break; case 0x10: /* tone portamento with no fxp */ fxt = 0x03; break; case 0x14: /* tone portamento */ fxt = 0x03; break; case 0x18: /* vibrato with no fxp */ fxt = 0x04; break; case 0x1C: /* vibrato */ fxt = 0x04; break; case 0x24: /* tone portamento + vol slide DOWN */ fxt = 0x05; break; case 0x28: /* vibrato + volume slide UP */ fxt = 0x06; c1 = (fxp << 4) & 0xf0; c2 = (fxp >> 4) & 0x0f; fxp = c1 | c2; break; case 0x2C: /* vibrato + volume slide DOWN */ fxt = 0x06; break; case 0x38: /* sample offset */ fxt = 0x09; break; case 0x3C: /* volume slide up */ fxt = 0x0A; c1 = (fxp << 4) & 0xf0; c2 = (fxp >> 4) & 0x0f; fxp = c1 | c2; break; case 0x40: /* volume slide down */ fxt = 0x0A; break; case 0x44: /* position jump */ fxt = 0x0B; break; case 0x48: /* set volume */ fxt = 0x0C; break; case 0x4C: /* pattern break */ fxt = 0x0D; break; case 0x50: /* set speed */ fxt = 0x0F; break; case 0x58: /* set filter */ fxt = 0x0E; fxp = 0x01; break; case 0x5C: /* fine slide up */ fxt = 0x0E; fxp |= 0x10; break; case 0x60: /* fine slide down */ fxt = 0x0E; fxp |= 0x20; break; case 0x84: /* retriger */ fxt = 0x0E; fxp |= 0x90; break; case 0x88: /* fine volume slide up */ fxt = 0x0E; fxp |= 0xa0; break; case 0x8C: /* fine volume slide down */ fxt = 0x0E; fxp |= 0xb0; break; case 0x94: /* note delay */ fxt = 0x0E; fxp |= 0xd0; break; case 0x98: /* pattern delay */ fxt = 0x0E; fxp |= 0xe0; break; default: fxt = fxp = 0; break; } p[0] = ins & 0xf0; p[0] |= ptk_table[note >> 1][0]; p[1] = ptk_table[note >> 1][1]; p[2] = (ins << 4) & 0xf0; p[2] |= fxt; p[3] = fxp; } fwrite(pdata, 1024, 1, out); } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_xann(uint8 *data, char *t, int s) { int i; PW_REQUEST_DATA(s, 2048); /* test 1 */ if (data[3] != 0x3c) return -1; /* test 2 */ for (i = 0; i < 128; i++) { uint32 j = readmem32b(data + i * 4); uint32 k = j & ~3; if (k != j || j > 132156) return -1; } #if 0 /* test 3 */ if (size < 2108) return -1; #endif /* test 4 */ for (i = 0; i < 64; i++) { if (data[3 + i * 4] != 0x3c && data[3 + i * 4] != 0) { return -1; } } /* test 5 */ for (i = 0; i < 31; i++) { if (data[519 + 16 * i] > 0x40) return -1; } /* test #6 (address of samples) */ for (i = 0; i < 30; i++) { uint32 j = readmem32b(data + 526 + 16 * i); /* j = readmem16b(data + 524 + 16 * i) * 2; */ uint32 k = readmem32b(data + 520 + 16 * (i + 1)); if (j < 2108 || k < 2108) return -1; if (j > k) return -1; } #if 0 /* test #7 first pattern data .. */ for (j = 0; j < 256; j++) { #if 0 k = data[j * 4 + 1085] / 2; l = k * 2; if (data[j * 4 + 1085] != l) return -1; #endif if (data[j * 4 + 1085] & 1) return -1; } #endif pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_xann = { "XANN Packer", test_xann, depack_xann }; libxmp-4.4.1/src/loaders/prowizard/prowiz.c0000664000175000017500000000623712706551122020607 0ustar claudioclaudio/* * Pro-Wizard_1.c * * Copyright (C) 1997-1999 Sylvain "Asle" Chipaux * Copyright (C) 2006-2007 Claudio Matsuoka */ #include #include #include #include #include #include "xmp.h" #include "prowiz.h" const struct pw_format *const pw_format[NUM_PW_FORMATS + 1] = { /* With signature */ &pw_ac1d, &pw_fchs, &pw_fcm, &pw_fuzz, &pw_hrt, /* &pw_kris, */ &pw_ksm, &pw_mp_id, &pw_ntp, &pw_p18a, &pw_p10c, &pw_pru1, &pw_pru2, &pw_pha, &pw_wn, &pw_unic_id, &pw_tp3, &pw_tp2, &pw_tp1, &pw_skyt, /* No signature */ &pw_xann, &pw_mp_noid, /* Must check before Heatseeker */ &pw_di, &pw_eu, &pw_p4x, &pw_pp21, &pw_pp30, &pw_pp10, &pw_p50a, &pw_p60a, &pw_p61a, &pw_nru, &pw_np2, &pw_np1, &pw_np3, &pw_zen, &pw_unic_emptyid, &pw_unic_noid, &pw_unic2, &pw_crb, &pw_tdd, &pw_starpack, &pw_gmc, /* &pw_pm01, */ &pw_titanics, NULL }; int pw_move_data(FILE *out, HIO_HANDLE *in, int len) { uint8 buf[1024]; int l; do { l = hio_read(buf, 1, len > 1024 ? 1024 : len, in); fwrite(buf, 1, l, out); len -= l; } while (l > 0 && len > 0); return 0; } int pw_write_zero(FILE *out, int len) { uint8 buf[1024]; int l; do { l = len > 1024 ? 1024 : len; memset(buf, 0, l); fwrite(buf, 1, l, out); len -= l; } while (l > 0 && len > 0); return 0; } int pw_wizardry(HIO_HANDLE *file_in, FILE *file_out, char **name) { int in_size; uint8 *data; char title[21]; int i; in_size = hio_size(file_in); /* printf ("input file size : %d\n", in_size); */ if (in_size < MIN_FILE_LENGHT) { return -2; } if ((data = (uint8 *)malloc(in_size)) == NULL) { goto err; } if (hio_read(data, 1, in_size, file_in) != in_size) { goto err2; } /********************************************************************/ /************************** SEARCH ******************************/ /********************************************************************/ for (i = 0; pw_format[i] != NULL; i++) { D_("checking format: %s", pw_format[i]->name); if (pw_format[i]->test(data, title, in_size) >= 0) break; } if (pw_format[i] == NULL) { goto err2; } if (hio_error(file_in)) { /* reset error flag */ } hio_seek(file_in, 0, SEEK_SET); if (pw_format[i]->depack(file_in, file_out) < 0) { goto err2; } if (hio_error(file_in)) { goto err2; } fflush(file_out); free(data); if (name != NULL) { *name = pw_format[i]->name; } return 0; err2: free(data); err: return -1; } int pw_check(unsigned char *b, int s, struct xmp_test_info *info) { int i, res; char title[21]; for (i = 0; pw_format[i] != NULL; i++) { D_("checking format [%d]: %s", s, pw_format[i]->name); res = pw_format[i]->test(b, title, s); if (res > 0) { return res; } else if (res == 0) { D_("format ok: %s\n", pw_format[i]->name); if (info != NULL) { memcpy(info->name, title, 21); strncpy(info->type, pw_format[i]->name, XMP_NAME_SIZE - 1); } return 0; } } return -1; } void pw_read_title(unsigned char *b, char *t, int s) { if (t == NULL) { return; } if (b == NULL) { *t = 0; return; } if (s > 20) { s = 20; } memcpy(t, b, s); t[s] = 0; } libxmp-4.4.1/src/loaders/prowizard/unic2.c0000664000175000017500000001004012706551122020260 0ustar claudioclaudio/* * Unic_Tracker_2.c Copyright (C) 1997 Asle / ReDoX * * Convert Unic Tracker 2 MODs to Protracker * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_unic2(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4; uint8 npat, maxpat; uint8 ins, note, fxt, fxp; uint8 fine; uint8 tmp[1025]; int i, j; int ssize; pw_write_zero(out, 20); /* title */ ssize = 0; for (i = 0; i < 31; i++) { int len, start, lsize; pw_move_data(out, in, 20); /* sample name */ write8(out, 0); write8(out, 0); /* fine on ? */ c1 = hio_read8(in); c2 = hio_read8(in); j = (c1 << 8) + c2; if (j != 0) { if (j < 256) fine = 0x10 - c2; else fine = 0x100 - c2; } else { fine = 0; } /* smp size */ len = hio_read16b(in); write16b(out, len); ssize += len << 1; hio_read8(in); write8(out, fine); /* fine */ write8(out, hio_read8(in)); /* vol */ start = hio_read16b(in); /* loop start */ lsize = hio_read16b(in); /* loop size */ if (start * 2 + lsize <= len && start != 0) { start <<= 1; } write16b(out, start); write16b(out, lsize); } write8(out, npat = hio_read8(in)); /* number of pattern */ write8(out, 0x7f); /* noisetracker byte */ hio_read8(in); hio_read(tmp, 128, 1, in); fwrite(tmp, 128, 1, out); /* pat table */ /* get highest pattern number */ for (maxpat = i = 0; i < 128; i++) { if (tmp[i] > maxpat) maxpat = tmp[i]; } maxpat++; /* coz first is $00 */ write32b(out, PW_MOD_MAGIC); /* pattern data */ for (i = 0; i < maxpat; i++) { for (j = 0; j < 256; j++) { c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); ins = ((c1 >> 2) & 0x10) | ((c2 >> 4) & 0x0f); note = c1 & 0x3f; /* Sanity check */ if (note >= 37) { return -1; } fxt = c2 & 0x0f; fxp = c3; if (fxt == 0x0d) { /* pattern break */ c4 = fxp % 10; c3 = fxp / 10; fxp = 16 * c3 + c4; } tmp[j * 4] = (ins & 0xf0); tmp[j * 4] |= ptk_table[note][0]; tmp[j * 4 + 1] = ptk_table[note][1]; tmp[j * 4 + 2] = ((ins << 4) & 0xf0) | fxt; tmp[j * 4 + 3] = fxp; } fwrite(tmp, 1024, 1, out); } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_unic2(uint8 *data, char *t, int s) { int i; int len, psize, ssize, max_ins; /* test 1 */ PW_REQUEST_DATA (s, 1084); /* test #2 ID = $00000000 ? */ if (readmem32b(data + 1080) == 0x00000000) return -1; /* test 2,5 :) */ ssize = 0; max_ins = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 30; int size = readmem16b(d + 22) << 1; int start = readmem16b(d + 26) << 1; int lsize = readmem16b(d + 28) << 1; ssize += size; if (size + 2 < start + lsize) return -1; if (size > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (d[25] > 0x40) return -1; if (readmem16b(d + 20) && size == 0) return -1; if (d[25] != 0 && size == 0) return -1; /* get the highest !0 sample */ if (size != 0) max_ins = i + 1; } if (ssize <= 2) return -1; /* test #4 pattern list size */ len = data[930]; if (len == 0 || len > 127) return -1; psize = 0; for (i = 0; i < len; i++) { int x = data[932 + i]; if (x > 127) return -1; if (x > psize) psize = x; } /* test last patterns of the pattern list = 0 ? */ for (i += 2; i != 128; i++) { if (data[932 + i] != 0) return -1; } psize++; psize <<= 8; PW_REQUEST_DATA (s, 1060 + psize * 3 + 2); for (i = 0; i < psize; i++) { uint8 *d = data + 1060 + i * 3; int ins; /* relative note number + last bit of sample > $34 ? */ if (d[0] > 0x74) return -1; if ((d[0] & 0x3F) > 0x24) return -1; if ((d[1] & 0x0F) == 0x0C && d[2] > 0x40) return -1; if ((d[1] & 0x0F) == 0x0B && d[2] > 0x7F) return -1; if ((d[1] & 0x0F) == 0x0D && d[2] > 0x40) return -1; ins = ((d[0] >> 2) & 0x30) | ((d[2] >> 4) & 0x0f); if (ins > max_ins) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_unic2 = { "Unic Tracker 2", test_unic2, depack_unic2 }; libxmp-4.4.1/src/loaders/prowizard/unic.c0000664000175000017500000001576012706551122020214 0ustar claudioclaudio/* * Unic_Tracker.c Copyright (C) 1997 Asle / ReDoX * * Unic tracked MODs to Protracker * both with or without ID Unic files will be converted * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" #define MAGIC_UNIC MAGIC4('U','N','I','C') #define MAGIC_M_K_ MAGIC4('M','.','K','.') #define MAGIC_0000 MAGIC4(0x0,0x0,0x0,0x0) static int depack_unic(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4; uint8 npat; uint8 max = 0; uint8 ins, note, fxt, fxp; uint8 fine; uint8 tmp[1025]; int i, j; int ssize; uint32 id; pw_move_data(out, in, 20); /* title */ ssize = 0; for (i = 0; i < 31; i++) { int len, start, lsize; pw_move_data(out, in, 20); /* sample name */ write8(out, 0); write8(out, 0); /* fine on ? */ c1 = hio_read8(in); c2 = hio_read8(in); j = (c1 << 8) + c2; if (j != 0) { if (j < 256) fine = 0x10 - c2; else fine = 0x100 - c2; } else { fine = 0; } /* smp size */ len = hio_read16b(in); write16b(out, len); ssize += len * 2; hio_read8(in); write8(out, fine); /* fine */ write8(out, hio_read8(in)); /* vol */ start = hio_read16b(in); /* loop start */ lsize = hio_read16b(in); /* loop size */ if (start * 2 + lsize <= len && start != 0) { start <<= 1; } write16b(out, start); write16b(out, lsize); } npat = hio_read8(in); write8(out, npat); /* number of pattern */ write8(out, 0x7f); /* noisetracker byte */ hio_read8(in); hio_read(tmp, 128, 1, in); /* pat table */ fwrite(tmp, 128, 1, out); /* get highest pattern number */ for (i = 0; i < 128; i++) { if (tmp[i] > max) max = tmp[i]; } max++; /* coz first is $00 */ write32b(out, PW_MOD_MAGIC); /* verify UNIC ID */ hio_seek(in, 1080, SEEK_SET); id = hio_read32b(in); if (id && id != MAGIC_M_K_ && id != MAGIC_UNIC) hio_seek(in, -4, SEEK_CUR); /* pattern data */ for (i = 0; i < max; i++) { for (j = 0; j < 256; j++) { c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); if (hio_error(in)) { return -1; } ins = ((c1 >> 2) & 0x10) | ((c2 >> 4) & 0x0f); note = c1 & 0x3f; /* Sanity check */ if (note >= 37) { return -1; } fxt = c2 & 0x0f; fxp = c3; if (fxt == 0x0d) { /* pattern break */ c3 = fxp / 10; c4 = fxp % 10; fxp = 16 * c3 + c4; } tmp[j * 4] = (ins & 0xf0) | ptk_table[note][0]; tmp[j * 4 + 1] = ptk_table[note][1]; tmp[j * 4 + 2] = ((ins << 4) & 0xf0) | fxt; tmp[j * 4 + 3] = fxp; } fwrite(tmp, 1024, 1, out); } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int check_instruments(uint8 *data) { int ssize, max_ins; int i; ssize = 0; max_ins = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 30; int len = readmem16b(d + 42) << 1; int start = readmem16b(d + 46) << 1; int lsize = readmem16b(d + 48) << 1; int fine; ssize += len; if (lsize != 0 && (len + 2) < (start + lsize)) return -1; /* samples too big ? */ if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; /* volume too big */ if (d[45] > 0x40) return -1; /* finetune ... */ fine = readmem16b(d + 40); if ((fine != 0 && len == 0) || (fine > 8 && fine < 247)) return -1; /* loop start but no replen ? */ if (start != 0 && lsize <= 2) return -1; if (d[45] != 0 && len == 0) return -1; /* get the highest !0 sample */ if (len != 0) max_ins = i + 1; } if (ssize <= 2) { return -1; } return max_ins; } static int check_pattern_list_size(uint8 *data) { int len, psize; int i; /* test #4 pattern list size */ len = data[950]; if (len == 0 || len > 127) return -1; psize = 0; for (i = 0; i < len; i++) { int x = data[952 + i]; if (x > 127) return -1; if (x > psize) psize = x; } /* test last patterns of the pattern list = 0 ? */ for (; i != 128; i++) { if (data[952 + i] != 0) return -1; } psize++; psize <<= 8; return psize; } static int check_pattern(uint8 *data, int s, int psize, int max_ins, int offset) { int i; PW_REQUEST_DATA(s, offset + psize * 3 + 2); for (i = 0; i < psize; i++) { uint8 *d = data + offset + i * 3; int ins; /* relative note number + last bit of sample > $34 ? */ if (d[0] > 0x74) return -1; if ((d[0] & 0x3F) > 0x24) return -1; if ((d[1] & 0x0F) == 0x0C && d[2] > 0x40) return -1; if ((d[1] & 0x0F) == 0x0B && d[2] > 0x7F) return -1; if ((d[1] & 0x0F) == 0x0D && d[2] > 0x40) return -1; ins = ((d[0] >> 2) & 0x30) | ((d[2] >> 4) & 0x0F); if (ins > max_ins) return -1; } return 0; } static int test_unic_id(uint8 *data, char *t, int s) { int i; int psize, ssize; /* test 1 */ PW_REQUEST_DATA(s, 1084); if (readmem32b(data + 1080) != MAGIC_M_K_) return -1; /* test 2 */ ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 30; int size, end; size = readmem16b(d + 42) << 1; ssize += size; end = (readmem16b(d + 46) + readmem16b(d + 48)) << 1; if ((size + 2) < end) return -1; } if (ssize <= 2) return -1; /* test #3 finetunes & volumes */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 30; if ((int8)d[40] < -8 || (int8)d[40] > 7) return -1; if (d[44] != 0 || d[45] > 0x40) return -1; } /* test #4 pattern list size */ psize = check_pattern_list_size(data); if (psize < 0) return -1; /* test #5 pattern data ... */ for (i = 0; i < psize; i++) { /* relative note number + last bit of sample > $34 ? */ if (data[1084 + i * 3] > 0x74) return -1; } pw_read_title(data, t, 20); return 0; } static int test_unic_emptyid(uint8 *data, char *t, int s) { int psize, max_ins; /* test 1 */ PW_REQUEST_DATA(s, 1084); /* test #2 ID = $00000000 ? */ if (readmem32b(data + 1080) != MAGIC_0000) return -1; /* test 2,5 :) */ max_ins = check_instruments(data); if (max_ins < 0) return -1; /* test #4 pattern list size */ psize = check_pattern_list_size(data); if (psize < 0) return -1; /* test #5 pattern data ... */ if (check_pattern(data, s, psize, max_ins, 1084) < 0) return -1; pw_read_title(data, t, 20); return 0; } static int test_unic_noid(uint8 *data, char *t, int s) { int i; int psize, max_ins; /* test 1 */ PW_REQUEST_DATA(s, 1084); /* test #2 ID = $00000000 ? */ if (readmem32b(data + 1080) == MAGIC_0000) return -1; /* test 2,5 :) */ max_ins = check_instruments(data); if (max_ins < 0) return -1; /* test #4 pattern list size */ psize = check_pattern_list_size(data); if (psize < 0) return -1; /* test #5 pattern data ... */ if (check_pattern(data, s, psize, max_ins, 1080) < 0) return -1; /* test #6 title coherent ? */ for (i = 0; i < 20; i++) { if ((data[i] != 0 && data[i] < 32) || data[i] > 180) return -1; } pw_read_title(data, t, 20); return 0; } const struct pw_format pw_unic_id = { "UNIC Tracker", test_unic_id, depack_unic }; const struct pw_format pw_unic_noid = { "UNIC Tracker noid", test_unic_noid, depack_unic }; const struct pw_format pw_unic_emptyid = { "UNIC Tracker id0", test_unic_emptyid, depack_unic }; libxmp-4.4.1/src/loaders/prowizard/ac1d.c0000664000175000017500000000637312706551122020066 0ustar claudioclaudio/* * ac1d.c Copyright (C) 1996-1997 Asle / ReDoX * * Converts ac1d packed MODs back to PTK MODs * thanks to Gryzor and his ProWizard tool ! ... without it, this prog * would not exist !!! * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" #define NO_NOTE 0xff static int depack_ac1d(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4; uint8 npos; uint8 ntk_byte; uint8 tmp[1024]; uint8 npat; uint8 note, ins, fxt, fxp; int size; int saddr; int ssize = 0; int paddr[128]; int psize[128]; /*int tsize1, tsize2, tsize3;*/ int i, j, k; memset(paddr, 0, 128 * 4); memset(psize, 0, 128 * 4); npos = hio_read8(in); ntk_byte = hio_read8(in); hio_read16b(in); /* bypass ID */ saddr = hio_read32b(in); /* sample data address */ pw_write_zero(out, 20); /* write title */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } /* pattern addresses */ for (npat = 0; npat < 128; npat++) { paddr[npat] = hio_read32b(in); if (paddr[npat] == 0) break; } if (npat == 0) { return -1; } npat--; for (i = 0; i < (npat - 1); i++) psize[i] = paddr[i + 1] - paddr[i]; write8(out, npos); /* write number of pattern pos */ write8(out, ntk_byte); /* write "noisetracker" byte */ hio_seek(in, 0x300, SEEK_SET); /* go to pattern table .. */ pw_move_data(out, in, 128); /* pattern table */ write32b(out, PW_MOD_MAGIC); /* M.K. */ /* pattern data */ for (i = 0; i < npat; i++) { hio_seek(in, paddr[i], SEEK_SET); /*tsize1 =*/ hio_read32b(in); /*tsize2 =*/ hio_read32b(in); /*tsize3 =*/ hio_read32b(in); memset(tmp, 0, 1024); for (k = 0; k < 4; k++) { for (j = 0; j < 64; j++) { int x = j * 16 + k * 4; c1 = hio_read8(in); if (c1 & 0x80) { c4 = c1 & 0x7f; j += (c4 - 1); continue; } c2 = hio_read8(in); ins = ((c1 & 0xc0) >> 2) | ((c2 >> 4) & 0x0f); note = c1 & 0x3f; if (note == 0x3f) note = NO_NOTE; else if (note) note -= 0x0b; if (note == 0) note++; tmp[x] = ins & 0xf0; if (note != NO_NOTE) { tmp[x] |= ptk_table[note][0]; tmp[x + 1] = ptk_table[note][1]; } if ((c2 & 0x0f) == 0x07) { tmp[x + 2] = (ins << 4) & 0xf0; continue; } c3 = hio_read8(in); fxt = c2 & 0x0f; fxp = c3; tmp[x + 2] = ((ins << 4) & 0xf0) | fxt; tmp[x + 3] = fxp; } } fwrite(tmp, 1024, 1, out); } /* sample data */ hio_seek(in, saddr, 0); pw_move_data(out, in, ssize); return 0; } static int test_ac1d(uint8 *data, char *t, int s) { int i; PW_REQUEST_DATA(s, 896); /* test #1 */ if (data[2] != 0xac || data[3] != 0x1d) return -1; /* test #2 */ if (data[0] > 0x7f) return -1; /* test #4 */ for (i = 0; i < 31; i++) { if (data[10 + 8 * i] > 0x0f) return -1; } /* test #5 */ for (i = 0; i < 128; i++) { if (data[768 + i] > 0x7f) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_ac1d = { "AC1D Packer", test_ac1d, depack_ac1d }; libxmp-4.4.1/src/loaders/prowizard/pm40.c0000664000175000017500000002322012706551122020024 0ustar claudioclaudio/* * Promizer_40.c 1997 (c) Asle / ReDoX * * Converts PM40 packed MODs back to PTK MODs * */ #include #include #define ON 0 #define OFF 1 #define SAMPLE_DESC 264 #define ADDRESS_SAMPLE_DATA 512 #define ADDRESS_REF_TABLE 516 #define PATTERN_DATA 520 void Depack_PM40 (FILE * in, FILE * out) { uint8 c1 = 0x00, c2 = 0x00, c3 = 0x00, c4 = 0x00; uint8 PatPos = 0x00; short pat_max = 0; long tmp_ptr, tmp1, tmp2; short refmax = 0; uint8 pnum[128]; uint8 pnum_tmp[128]; long paddr[128]; long paddr_tmp[128]; long paddr_tmp2[128]; short pptr[64][256]; uint8 *reftab; uint8 *sdata; uint8 Pattern[128][1024]; long i = 0, j = 0, k = 0; long ssize = 0; long psize = 0l; long SDAV = 0l; uint8 FLAG = OFF; uint8 ptk_table[37][2]; uint8 note, ins; // HIO_HANDLE *in,*out; if (Save_Status == BAD) return; #include "ptktable.h" // in = fdopen (fd_in, "rb"); // sprintf ( Depacked_OutName , "%ld.mod" , Cpt_Filename-1 ); // out = fdopen (fd_out, "w+b"); memset(pnum, 0, 128); memset(pnum_tmp, 0, 128); memset(pptr, 0, 64 << 8); memset(Pattern, 0, 128 * 1024); memset(paddr, 0, 128 * 4); memset(paddr_tmp, 0, 128 * 4); for (i = 0; i < 128; i++) paddr_tmp2[i] = 9999l; /* write title */ for (i = 0; i < 20; i++) /* title */ fwrite (&c1, 1, 1, out); /* read and write sample headers */ /*printf ( "Converting sample headers ... " ); */ fseek (in, SAMPLE_DESC, 0); for (i = 0; i < 31; i++) { c1 = 0x00; for (j = 0; j < 22; j++) /*sample name */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* size */ fread (&c2, 1, 1, in); ssize += (((c1 << 8) + c2) * 2); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fread (&c1, 1, 1, in); /* finetune */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* volume */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* loop start */ fread (&c2, 1, 1, in); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fread (&c1, 1, 1, in); /* loop size */ fread (&c2, 1, 1, in); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); } /*printf ( "ok\n" ); */ /* read and write the size of the pattern list */ fseek (in, 7, 0); /* SEEK_SET */ fread (&PatPos, 1, 1, in); fwrite (&PatPos, 1, 1, out); /* NoiseTracker restart byte */ c1 = 0x7f; fwrite (&c1, 1, 1, out); /* pattern addresses */ fseek (in, 8, 0); /* SEEK_SET */ for (i = 0; i < 128; i++) { fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); paddr[i] = (c1 << 8) + c2; } /* ordering of patterns addresses */ /* PatPos contains the size of the pattern list .. */ /*printf ( "Creating pattern list ... " ); */ tmp_ptr = 0; for (i = 0; i < PatPos; i++) { if (i == 0) { pnum[0] = 0x00; tmp_ptr++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) pnum[i] = tmp_ptr++; } pat_max = tmp_ptr - 1; /* correct re-order */ /********************/ for (i = 0; i < c4; i++) paddr_tmp[i] = paddr[i]; restart: for (i = 0; i < c4; i++) { for (j = 0; j < i; j++) { if (paddr_tmp[i] < paddr_tmp[j]) { tmp2 = pnum[j]; pnum[j] = pnum[i]; pnum[i] = tmp2; tmp1 = paddr_tmp[j]; paddr_tmp[j] = paddr_tmp[i]; paddr_tmp[i] = tmp1; goto restart; } } } j = 0; for (i = 0; i < c4; i++) { if (i == 0) { paddr_tmp2[j] = paddr_tmp[i]; continue; } if (paddr_tmp[i] == paddr_tmp2[j]) continue; paddr_tmp2[++j] = paddr_tmp[i]; } for (c1 = 0x00; c1 < c4; c1++) { for (c2 = 0x00; c2 < c4; c2++) if (paddr[c1] == paddr_tmp2[c2]) { pnum_tmp[c1] = c2; } } for (i = 0; i < c4; i++) pnum[i] = pnum_tmp[i]; /* write pattern table */ for (c1 = 0x00; c1 < 128; c1++) { fwrite (&pnum[c1], 1, 1, out); } /*printf ( "ok\n" ); */ c1 = 'M'; c2 = '.'; c3 = 'K'; fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fwrite (&c3, 1, 1, out); fwrite (&c2, 1, 1, out); /* a little pre-calc code ... no other way to deal with these unknown pattern data sizes ! :( */ /* so, first, we get the pattern data size .. */ fseek (in, ADDRESS_REF_TABLE, 0); /* SEEK_SET */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); j = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; psize = (8 + j) - PATTERN_DATA; /* printf ( "Pattern data size : %ld\n" , psize );*/ /* go back to pattern data starting address */ fseek (in, PATTERN_DATA, 0); /* SEEK_SET */ /* now, reading all pattern data to get the max value of note */ for (j = 0; j < psize; j += 2) { fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); if (((c1 << 8) + c2) > refmax) refmax = (c1 << 8) + c2; } /* printf ( "* refmax = %d\n" , refmax ); printf ( "* where : %ld\n" , ftell ( in ) ); */ /* read "reference Table" */ fseek (in, ADDRESS_REF_TABLE, 0); /* SEEK_SET */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); j = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; fseek (in, 8 + j, 0); /* SEEK_SET */ /* printf ( "address of 'reference table' : %ld\n" , ftell (in ) );*/ refmax += 1; /* coz 1st value is 0 and will be empty in this table */ i = refmax * 4; /* coz each block is 4 bytes long */ reftab = (uint8 *) malloc (i); memset(reftab, 0, i); fread (&reftab[4], i, 1, in); /* go back to pattern data starting address */ fseek (in, PATTERN_DATA, 0); /* SEEK_SET */ /* printf ( "Highest pattern number : %d\n" , pat_max );*/ /*printf ( "Computing the pattern datas " ); */ k = 0; for (j = 0; j <= pat_max; j++) { for (i = 0; i < 64; i++) { /* VOICE #1 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16] = (ins & 0xf0); Pattern[j][i * 16] |= ptk_table[note][0]; Pattern[j][i * 16 + 1] = ptk_table[note][1]; Pattern[j][i * 16 + 2] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 2] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 3] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 2] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 2] & 0x0f) == 0x0b)) { FLAG = ON; } /* VOICE #2 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16 + 4] = (ins & 0xf0); Pattern[j][i * 16 + 4] |= ptk_table[note][0]; Pattern[j][i * 16 + 5] = ptk_table[note][1]; Pattern[j][i * 16 + 6] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 6] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 7] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 6] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 6] & 0x0f) == 0x0b)) { FLAG = ON; } /* VOICE #3 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16 + 8] = (ins & 0xf0); Pattern[j][i * 16 + 8] |= ptk_table[note][0]; Pattern[j][i * 16 + 9] = ptk_table[note][1]; Pattern[j][i * 16 + 10] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 10] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 11] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 10] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 10] & 0x0f) == 0x0b)) { FLAG = ON; } /* VOICE #4 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16 + 12] = (ins & 0xf0); Pattern[j][i * 16 + 12] |= ptk_table[note][0]; Pattern[j][i * 16 + 13] = ptk_table[note][1]; Pattern[j][i * 16 + 14] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 14] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 15] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 14] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 14] & 0x0f) == 0x0b)) { FLAG = ON; } if (FLAG == ON) { FLAG = OFF; break; } } fwrite (Pattern[j], 1024, 1, out); /*printf ( "." ); */ } free (reftab); /*printf ( " ok\n" ); */ /* get address of sample data .. and go there */ /*printf ( "Saving sample datas ... " ); */ fseek (in, ADDRESS_SAMPLE_DATA, 0); /* SEEK_SET */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); SDAV = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; fseek (in, 4 + SDAV, 0); /* SEEK_SET */ /* read and save sample data */ /* printf ( "out: where before saving sample data : %ld\n" , ftell ( out ) );*/ /* printf ( "Whole sample size : %ld\n" , ssize );*/ sdata = (uint8 *) malloc (ssize); fread (sdata, ssize, 1, in); fwrite (sdata, ssize, 1, out); free (sdata); /*printf ( " ok\n" ); */ Crap ("PM40:Promizer 4.0", BAD, BAD, out); fflush (in); fflush (out); printf ("done\n"); return; /* useless ... but */ } void testPM40 (void) { start = i; /* size of the pattern list */ j = data[start + 7]; if (j > 0x7f) { /*printf ( "#1 Start:%ld\n" , start );*/ Test = BAD; return; } /* j is the size of the pattern list */ /* finetune */ for (k = 0; k < 31; k++) { if (data[start + k * 8 + 266] > 0x0f) { /*printf ( "#2 Start:%ld\n" , start );*/ Test = BAD; return; } } /* volume */ for (k = 0; k < 31; k++) { if (data[start + k * 8 + 267] > 0x40) { /*printf ( "#3 Start:%ld\n" , start );*/ Test = BAD; return; } } /* sample data address */ l = ((data[start + 512] << 24) + (data[start + 513] << 16) + (data[start + 514] << 8) + data[start + 515]); if ((l <= 520) || (l > 2500000l)) { /*printf ( "#4 Start:%ld\n" , start );*/ Test = BAD; return; } /* l is the sample data address */ Test = GOOD; } libxmp-4.4.1/src/loaders/prowizard/pm01.c0000664000175000017500000001005312706551122020021 0ustar claudioclaudio/* * Promizer_0.1_Packer.c Copyright (C) 1997 Asle / ReDoX * * Converts back to ptk Promizer 0.1 packed MODs * * Modified in 2016 by Claudio Matsuoka */ #include #include #include #include "prowiz.h" static int depack_pm01(HIO_HANDLE *in, FILE *out) { uint8 ptable[128]; uint8 len; uint8 npat; uint8 tmp[1024]; uint8 pdata[1024]; uint8 fin[31]; uint8 oldins[4]; int i, j; int psize, size, ssize = 0; int pat_ofs[128]; memset(ptable, 0, 128); memset(pat_ofs, 0, 128 * 4); memset(fin, 0, 31); memset(oldins, 0, 4); pw_write_zero(out, 20); /* title */ /* read and write sample descriptions */ for (i = 0; i < 31; i++) { if (hio_read(tmp, 1, 8, in) != 8) { return -1; } pw_write_zero(out, 22); /* sample name */ size = readmem16b(tmp); /* size */ ssize += size * 2; fin[i] = tmp[2]; if (tmp[4] == 0 && tmp[5] == 0) { /* loop size */ tmp[5] = 1; } if (fwrite(tmp, 1, 8, out) != 8) { return -1; } } len = hio_read16b(in) >> 2; /* pattern table lenght */ write8(out, len); write8(out, 0x7f); /* write NoiseTracker byte */ /* read pattern address list */ for (i = 0; i < 128; i++) { pat_ofs[i] = hio_read32b(in); } /* deduce pattern list and write it */ for (npat = i = 0; i < 128; i++) { ptable[i] = pat_ofs[i] / 1024; write8(out, ptable[i]); if (ptable[i] > npat) { npat = ptable[i]; } } npat++; write32b(out, PW_MOD_MAGIC); /* ID string */ psize = hio_read32b(in); /* get pattern data size */ if (npat * 1024 != psize) { return -1; } /* read and XOR pattern data */ for (i = 0; i < npat; i++) { memset(pdata, 0, 1024); if (hio_read(pdata, 1, 1024, in) != 1024) { return -1; } for (j = 0; j < 1024; j++) { if (j % 4 == 3) { pdata[j] = (240 - (pdata[j] & 0xf0)) + (pdata[j] & 0x0f); continue; } pdata[j] = pdata[j] ^ 0xff; } /* now take care of these 'finetuned' values ... pfff */ oldins[0] = oldins[1] = oldins[2] = oldins[3] = 0x1f; for (j = 0; j < 64 * 4; j++) { uint8 *p = pdata + j * 4; int note = readmem16b(p) & 0x0fff; int ins = (p[0] & 0xf0) | ((p[2] >> 4) & 0x0f); if (note == 0) { continue; } if (ins == 0) { ins = oldins[i % 4]; } else { oldins[i % 4] = ins; } note = (int)((double)note * pow(2, -1.0 * fin[j % 4] / 12 / 8)); if (note > 0) { note = period_to_note(note) - 48; } p[0] = ptk_table[note][0]; p[1] = ptk_table[note][1]; } if (fwrite(pdata, 1, 1024, out) != 1024) { return -1; } } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_pm01(uint8 *data, char *t, int s) { int i; int len, psize, ssize = 0; PW_REQUEST_DATA(s, 1024); #if 0 /* test #1 */ if (i < 3) { Test = BAD; return; } #endif /* test #2 */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int size = readmem16b(data) << 1; int start = readmem16b(data + 4) << 1; int lsize = readmem16b(data + 6) << 1; ssize += size; if (d[2] > 0x0f) { /* finetune > 0x0f ? */ return -1; } /* loop start > size ? */ if (start > size || lsize > size) { return -1; } if (lsize <= 2) { return -1; } } /* test #3 about size of pattern list */ len = readmem16b(data + 248); if (len & 0x03) { return -1; } len >>= 2; if (len == 0 || len > 127) { return -1; } /* test #4 size of all the pattern data */ /* k contains the size of the pattern list */ psize = readmem32b(data + 762); if (psize < 1024 || psize > 131072) { return -1; } /* test #5 first pattern address != $00000000 ? */ if (readmem32b(data + 250) != 0) { return -1; } /* test #6 pattern addresses */ for (i = 0; i < len; i++) { int addr = readmem32b(data + 250 + i * 4); if (addr & 0x3ff || addr > 131072) { return -1; } } /* test #7 last patterns in pattern table != $00000000 ? */ i += 4; /* just to be sure */ for (; i < 128; i++) { int addr = readmem32b(data + 250 + i * 4); if (addr != 0) { return -1; } } return 0; } const struct pw_format pw_pm01 = { "Promizer 0.1", test_pm01, depack_pm01 }; libxmp-4.4.1/src/loaders/prowizard/np1.c0000664000175000017500000001244512706551122017751 0ustar claudioclaudio/* * NoisePacker_v1.c Copyright (C) 1997 Asle / ReDoX * * Converts NoisePacked MODs back to ptk * * Modified in 2006,2007,2014,2015 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_np1(HIO_HANDLE *in, FILE *out) { uint8 tmp[1024]; uint8 c1, c2, c3, c4; uint8 ptable[128]; int len, nins, npat; int max_addr; int size, ssize = 0; /*int tsize;*/ int trk_addr[128][4]; int i, j, k; int trk_start; memset(ptable, 0, 128); memset(trk_addr, 0, 128 * 4 * 4); c1 = hio_read8(in); /* read number of samples */ c2 = hio_read8(in); nins = ((c1 << 4) & 0xf0) | ((c2 >> 4) & 0x0f); pw_write_zero(out, 20); /* write title */ len = hio_read16b(in) >> 1; /* size of pattern list */ /* Sanity check */ if (len > 128) { return -1; } hio_read16b(in); /* 2 unknown bytes */ /*tsize =*/ hio_read16b(in); /* read track data size */ /* read sample descriptions */ for (i = 0; i < nins; i++) { hio_read32b(in); /* bypass 4 unknown bytes */ pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ hio_read32b(in); /* bypass 4 unknown bytes */ size = hio_read16b(in); /* read loop size */ write16b(out, hio_read16b(in) / 2); /* loop start */ write16b(out, size); /* write loop size */ } /* fill up to 31 samples */ memset(tmp, 0, 30); tmp[29] = 0x01; for (; i < 31; i++) { fwrite(tmp, 30, 1, out); } write8(out, len); /* write size of pattern list */ write8(out, 0x7f); /* write noisetracker byte */ hio_seek(in, 2, SEEK_CUR); /* always $02? */ hio_seek(in, 2, SEEK_CUR); /* unknown */ /* read pattern table */ npat = 0; for (i = 0; i < len; i++) { ptable[i] = hio_read16b(in) >> 3; if (ptable[i] > npat) npat = ptable[i]; } npat++; fwrite(ptable, 128, 1, out); /* write pattern table */ write32b(out, PW_MOD_MAGIC); /* write ptk ID */ /* read tracks addresses per pattern */ max_addr = 0; for (i = 0; i < npat; i++) { if ((trk_addr[i][0] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][0]; if ((trk_addr[i][1] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][1]; if ((trk_addr[i][2] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][2]; if ((trk_addr[i][3] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][3]; } trk_start = hio_tell(in); /* the track data now ... */ for (i = 0; i < npat; i++) { memset(tmp, 0, 1024); for (j = 0; j < 4; j++) { hio_seek(in, trk_start + trk_addr[i][3 - j], SEEK_SET); for (k = 0; k < 64; k++) { int x = k * 16 + j * 4; c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = (c1 & 0xfe) / 2; if (hio_error(in) || c4 >= 37) { return -1; } tmp[x] = ((c1 << 4) & 0x10) | ptk_table[c4][0]; tmp[x + 1] = ptk_table[c4][1]; switch (c2 & 0x0f) { case 0x08: c2 &= 0xf0; break; case 0x07: c2 = (c2 & 0xf0) + 0x0a; /* fall through */ case 0x06: case 0x05: c3 = c3 > 0x80 ? 0x100 - c3 : (c3 << 4) & 0xf0; break; case 0x0b: c3 = (c3 + 4) / 2; break; } tmp[x + 2] = c2; tmp[x + 3] = c3; } } fwrite(tmp, 1024, 1, out); } /* sample data */ hio_seek(in, max_addr + 192 + trk_start, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_np1(uint8 *data, char *t, int s) { int num_ins, ssize, hdr_size, ptab_size, trk_size, max_pptr; int i; PW_REQUEST_DATA(s, 10); /* size of the pattern table */ ptab_size = readmem16b(data + 2); if (ptab_size == 0 || ptab_size & 1 || ptab_size > 0xff) return -1; /* test number of samples */ if ((data[1] & 0x0f) != 0x0c) return -1; /* number of samples */ num_ins = ((data[0] << 4) & 0xf0) | ((data[1] >> 4) & 0x0f); if (num_ins == 0 || num_ins > 0x1f) return -1; PW_REQUEST_DATA(s, 15 + num_ins * 16); /* test volumes */ for (i = 0; i < num_ins; i++) { if (data[15 + i * 16] > 0x40) return -1; } /* test sample sizes */ ssize = 0; for (i = 0; i < num_ins; i++) { uint8 *d = data + i * 16; int len = readmem16b(d + 12) << 1; int start = readmem16b(d + 20) << 1; int lsize = readmem16b(d + 22); if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > len + 2) return -1; if (start == 0 && lsize != 0) return -1; ssize += len; } if (ssize <= 4) return -1; /* size of the header til the end of sample descriptions */ hdr_size = num_ins * 16 + 8 + 4; PW_REQUEST_DATA(s, hdr_size + ptab_size + 2); /* test pattern table */ max_pptr = 0; for (i = 0; i < ptab_size; i += 2) { int pptr = readmem16b(data + hdr_size + i); if (pptr & 0x07 || pptr >= 0x400) return -1; if (pptr > max_pptr) max_pptr = pptr; } /* paske on a que l'address du dernier pattern .. */ /* size of the header 'til the end of the track list */ hdr_size += ptab_size + max_pptr + 8; /* test track data size */ trk_size = readmem16b(data + 6); if (trk_size < 192 || (trk_size & 0x3f)) return -1; PW_REQUEST_DATA(s, hdr_size + trk_size); /* test notes */ for (i = 0; i < trk_size; i += 3) { if (data[hdr_size + i] > 0x49) return -1; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_np1 = { "NoisePacker v1", test_np1, depack_np1 }; libxmp-4.4.1/src/loaders/prowizard/wn.c0000664000175000017500000000330512706551122017672 0ustar claudioclaudio/* * Wanton_Packer.c Copyright (C) 1997 Asle / ReDoX * * Converts MODs converted with Wanton packer * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_wn(HIO_HANDLE *in, FILE * out) { uint8 c1, c2, c3, c4; uint8 npat, max; uint8 tmp[1024]; int ssize = 0; int i, j; /* read header */ pw_move_data(out, in, 950); /* get whole sample size */ for (i = 0; i < 31; i++) { hio_seek(in, 42 + i * 30, SEEK_SET); ssize += hio_read16b(in) * 2; } /* read size of pattern list */ hio_seek(in, 950, SEEK_SET); write8(out, npat = hio_read8(in)); hio_read(tmp, 129, 1, in); fwrite(tmp, 129, 1, out); /* write ptk's ID */ write32b(out, PW_MOD_MAGIC); /* get highest pattern number */ for (max = i = 0; i < 128; i++) { if (tmp[i + 1] > max) max = tmp[i + 1]; } max++; /* pattern data */ hio_seek(in, 1084, SEEK_SET); for (i = 0; i < max; i++) { for (j = 0; j < 256; j++) { c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); if (hio_error(in) || c1 >= 74) { return -1; } write8(out, c1 * 0xf0 | ptk_table[c1 / 2][0]); write8(out, ptk_table[c1 / 2][1]); write8(out, ((c2 << 4) & 0xf0) | c3); write8(out, c4); } } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_wn(uint8 *data, char *t, int s) { PW_REQUEST_DATA(s, 1082); /* test 1 */ if (data[1080] != 'W' || data[1081] !='N') return -1; /* test 2 */ if (data[951] != 0x7f) return -1; /* test 3 */ if (data[950] > 0x7f) return -1; pw_read_title(data, t, 20); return 0; } const struct pw_format pw_wn = { "Wanton Packer", test_wn, depack_wn }; libxmp-4.4.1/src/loaders/prowizard/pp10.c0000664000175000017500000000634612706551122020036 0ustar claudioclaudio/* * ProPacker_v1.0 Copyright (C) 1997 Asle / ReDoX * * Converts back to ptk ProPacker v1 MODs * * Modified in 2016 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_pp10(HIO_HANDLE *in, FILE *out) { uint8 c1; uint8 trk_num[4][128]; uint8 len; uint8 tmp[8]; uint8 pdata[1024]; int i, j, k; int ntrk, size, ssize = 0; memset(trk_num, 0, 128 * 4); pw_write_zero(out, 20); /* write title */ /* read and write sample descriptions */ for (i = 0; i < 31; i++) { if (hio_read(tmp, 1, 8, in) != 8) { return -1; } pw_write_zero(out, 22); /* sample name */ size = readmem16b(tmp); /* size */ ssize += size * 2; if (tmp[4] == 0 && tmp[5] == 0) { /* loop size */ tmp[5] = 1; } if (fwrite(tmp, 1, 8, out) != 8) { return -1; } } len = hio_read8(in); /* pattern table lenght */ write8(out, len); c1 = hio_read8(in); /* Noisetracker byte */ write8(out, c1); /* read track list and get highest track number */ for (ntrk = j = 0; j < 4; j++) { for (i = 0; i < 128; i++) { trk_num[j][i] = hio_read8(in); if (trk_num[j][i] > ntrk) { ntrk = trk_num[j][i]; } } } /* write pattern table "as is" ... */ for (i = 0; i < len; i++) { write8(out, i); } pw_write_zero(out, 128 - i); write32b(out, PW_MOD_MAGIC); /* ID string */ /* track/pattern data */ for (i = 0; i < len; i++) { memset(pdata, 0, 1024); for (j = 0; j < 4; j++) { hio_seek(in, 762 + (trk_num[j][i] << 8), SEEK_SET); for (k = 0; k < 64; k++) { hio_read(pdata + k * 16 + j * 4, 1, 4, in); } } fwrite(pdata, 1024, 1, out); } /* now, lets put file pointer at the beginning of the sample datas */ if (hio_seek(in, 762 + ((ntrk + 1) << 8), SEEK_SET) < 0) { return -1; } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_pp10(uint8 *data, char *t, int s) { int i; int ntrk, ssize; PW_REQUEST_DATA(s, 1024); #if 0 /* test #1 */ if (i < 3) { Test = BAD; return; } start = i - 3; #endif /* noisetracker byte */ if (data[249] > 0x7f) { return -1; } /* test #2 */ ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int size = readmem16b(d) << 1; int start = readmem16b(d + 4) << 1; int lsize = readmem16b(d + 6) << 1; ssize += size; if (lsize == 0) { return -1; } if (start != 0 && lsize <= 2) { return -1; } if (start + lsize > size + 2) { return -1; } #if 0 if (start != 0 && lsize == 0) { return -1; } #endif if (d[2] > 0x0f) { /* finetune > 0x0f ? */ return -1; } if (d[3] > 0x40) { /* volume > 0x40 ? */ return -1; } if (start > size) { /* loop start > size ? */ return -1; } if (size > 0xffff) { /* size > 0xffff ? */ return -1; } } if (ssize <= 2) { return -1; } /* test #3 about size of pattern list */ if (data[248] == 0 || data[248] > 127) { return -1; } /* get the highest track value */ for (ntrk = i = 0; i < 512; i++) { if (data[250 + i] > ntrk) { ntrk = data[250 + i]; } } PW_REQUEST_DATA(s, 762 + ntrk * 64); ntrk++; for (i = 0; i < ntrk * 64; i++) { if (data[762 + i * 4] > 0x13) { return -1; } } return 0; } const struct pw_format pw_pp10 = { "ProPacker 1.0", test_pp10, depack_pp10 }; libxmp-4.4.1/src/loaders/prowizard/starpack.c0000664000175000017500000001344012706551122021057 0ustar claudioclaudio/* * StarTrekker_Packer.c Copyright (C) 1997 Sylvain "Asle" Chipaux * * Converts back to ptk StarTrekker packed MODs * * Modified in 2006,2009,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_starpack(HIO_HANDLE *in, FILE *out) { uint8 pnum[128]; uint8 pnum_tmp[128]; uint8 pat_pos; uint8 buffer[1024]; uint8 num_pat = 0x00; int i = 0, j = 0, k = 0; int size, ssize = 0; int paddr[128]; int paddr_tmp[128]; int paddr_tmp2[128]; int tmp_ptr, tmp1, tmp2; int smp_addr = 0; memset(pnum, 0, 128); memset(pnum_tmp, 0, 128); memset(paddr, 0, 128 * 4); memset(paddr_tmp, 0, 128 * 4); memset(paddr_tmp2, 0, 128 * 4); pw_move_data(out, in, 20); /* title */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /* sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += 2 * size; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } pat_pos = hio_read16b(in); /* size of pattern table */ if (pat_pos >= 128) { return -1; } hio_seek(in, 2, SEEK_CUR); /* bypass $0000 unknown bytes */ for (i = 0; i < 128; i++) { paddr[i] = hio_read32b(in); } /* ordering of patterns addresses */ tmp_ptr = 0; for (i = 0; i < pat_pos; i++) { if (i == 0) { pnum[0] = 0; tmp_ptr++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) pnum[i] = tmp_ptr++; } for (i = 0; i < 128; i++) paddr_tmp[i] = paddr[i]; restart: for (i = 0; i < pat_pos; i++) { for (j = 0; j < i; j++) { if (paddr_tmp[i] < paddr_tmp[j]) { tmp2 = pnum[j]; pnum[j] = pnum[i]; pnum[i] = tmp2; tmp1 = paddr_tmp[j]; paddr_tmp[j] = paddr_tmp[i]; paddr_tmp[i] = tmp1; goto restart; } } } j = 0; for (i = 0; i < 128; i++) { if (i == 0) { paddr_tmp2[j] = paddr_tmp[i]; continue; } if (paddr_tmp[i] == paddr_tmp2[j]) continue; paddr_tmp2[++j] = paddr_tmp[i]; } /* try to locate unused patterns .. hard ! */ j = 0; for (i = 0; i < (pat_pos - 1); i++) { paddr_tmp[j] = paddr_tmp2[i]; j += 1; if ((paddr_tmp2[i + 1] - paddr_tmp2[i]) > 1024) { /*printf ( "! pattern %ld is not used ... saved anyway\n" , j ); */ paddr_tmp[j] = paddr_tmp2[i] + 1024; j += 1; } } /* assign pattern list */ for (i = 0; i < 128; i++) { for (j = 0; j < 128; j++) if (paddr[i] == paddr_tmp[j]) { pnum_tmp[i] = j; break; } } memset(pnum, 0, 128); for (i = 0; i < pat_pos; i++) { pnum[i] = pnum_tmp[i]; } write8(out, pat_pos); /* write number of position */ /* get highest pattern number */ for (i = 0; i < pat_pos; i++) { if (pnum[i] > num_pat) num_pat = pnum[i]; } write8(out, 0x7f); /* write noisetracker byte */ fwrite(pnum, 128, 1, out); /* write pattern list */ write32b(out, PW_MOD_MAGIC); /* M.K. */ /* read sample data address */ hio_seek(in, 0x310, SEEK_SET); smp_addr = hio_read32b(in) + 0x314; /* pattern data */ num_pat += 1; for (i = 0; i < num_pat; i++) { memset(buffer, 0, 1024); for (j = 0; j < 64; j++) { for (k = 0; k < 4; k++) { uint8 c1, c2, c3, c4, c5; int ofs = j * 16 + k * 4; c1 = hio_read8(in); if (c1 == 0x80) continue; c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); buffer[ofs] = c1 & 0x0f; buffer[ofs + 1] = c2; buffer[ofs + 2] = c3 & 0x0f; buffer[ofs + 3] = c4; c5 = ((c1 & 0xf0) | ((c3 >> 4) & 0x0f)) >> 2; buffer[ofs] |= c5 & 0xf0; buffer[ofs + 2] |= (c5 << 4) & 0xf0; } } fwrite(buffer, 1024, 1, out); /*printf ( "+" ); */ } /*printf ( "\n" ); */ /* sample data */ hio_seek(in, smp_addr, 0); pw_move_data(out, in, ssize); return 0; } static int test_starpack(uint8 *data, char *t, int s) { int i; int plist_size, len, sdata_ofs, pdata_ofs; #if 0 /* test 1 */ if (i < 23) { Test = BAD; return; } #endif /* test 2 */ plist_size = readmem16b(data + 268); if (plist_size & 0x03) return -1; len = plist_size >> 2; if (len == 0 || len > 127) return -1; if (data[784] != 0) return -1; /* test #3 smp size < loop start + loop size ? */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int size = readmem16b(d + 20) << 1; int lend = (readmem16b(d + 24) + readmem16b(d + 26)) << 1; if (lend > size + 2) return -1; } /* test #4 finetunes & volumes */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; if (d[22] > 0x0f || d[23] > 0x40) return -1; } /* test #5 pattern addresses > sample address ? */ /* get sample data address */ #if 0 if ((start + 0x314) > in_size) { Test = BAD; return; } #endif /* address of sample data */ sdata_ofs = readmem32b(data + 784); #if 0 if ((k + start) > in_size) { Test = BAD; return; } #endif if (sdata_ofs < 788) return -1; /* pattern addresses > sample address ? */ for (i = 0; i < len; i += 4) { /* each pattern address */ if (readmem32b(data + i + 272) > sdata_ofs) return -1; } /* test last patterns of the pattern list == 0 ? */ for (i += 2; i < 128; i++) { if (readmem32b(data + i * 4 + 272) != 0) return -1; } /* test pattern data */ pdata_ofs = 788; while (pdata_ofs < sdata_ofs + 4) { uint8 *d = data + pdata_ofs; if (d[0] == 0x80) { pdata_ofs++; continue; } if (d[0] > 0x80) return -1; /* empty row ? ... not possible ! */ if (readmem32b(d) == 0) return - 1; /* fx = C .. arg > 64 ? */ if ((d[2] * 0x0f) == 0x0c && d[3] > 0x40) return - 1; /* fx = D .. arg > 64 ? */ if ((d[2] * 0x0f) == 0x0d && d[3] > 0x40) return - 1; pdata_ofs += 4; } pw_read_title(data, t, 20); return 0; } const struct pw_format pw_starpack = { "Startrekker Packer", test_starpack, depack_starpack }; libxmp-4.4.1/src/loaders/prowizard/ksm.c0000664000175000017500000001144112706551122020040 0ustar claudioclaudio/* * Kefrens_Sound_Machine.c Copyright (C) 1997 Sylvain "Asle" Chipaux * * Depacks musics in the Kefrens Sound Machine format and saves in ptk. * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_ksm(HIO_HANDLE *in, FILE *out) { uint8 tmp[1024]; uint8 c1, c5; uint8 plist[128]; uint8 trknum[128][4]; uint8 real_tnum[128][4]; uint8 tdata[4][192]; uint8 max_trknum; uint8 len; uint8 status = 1; int ssize = 0; int i, j, k; memset(plist, 0, 128); memset(trknum, 0, 128 * 4); memset(real_tnum, 0, 128 * 4); /* title */ hio_seek(in, 2, SEEK_SET); pw_move_data(out, in, 13); pw_write_zero(out, 7); /* read and write whole header */ /*printf ( "Converting sample headers ... " ); */ hio_seek(in, 32, SEEK_SET); for (i = 0; i < 15; i++) { pw_write_zero(out, 22); /* write name */ hio_seek(in, 20, SEEK_CUR); /* 16 unknown/4 addr bytes */ write16b(out, (k = hio_read16b(in)) / 2); /* size */ ssize += k; write8(out, 0); /* finetune */ write8(out, hio_read8(in)); /* volume */ hio_read8(in); /* bypass 1 unknown byte */ write16b(out, (j = hio_read16b(in)) / 2); /* loop start */ j = k - j; write16b(out, j != k ? j / 2 : 1); /* loop size */ hio_seek(in, 6, SEEK_CUR); /* bypass 6 unknown bytes */ } memset(tmp, 0, 30); tmp[29] = 1; for (i = 0; i < 16; i++) fwrite(tmp, 30, 1, out); /* pattern list */ hio_seek(in, 512, SEEK_SET); for (max_trknum = len = 0; len < 128; len++) { hio_read(&trknum[len][0], 1, 1, in); hio_read(&trknum[len][1], 1, 1, in); hio_read(&trknum[len][2], 1, 1, in); hio_read(&trknum[len][3], 1, 1, in); if (trknum[len][0] == 0xFF) break; if (trknum[len][0] > max_trknum) max_trknum = trknum[len][0]; if (trknum[len][1] > max_trknum) max_trknum = trknum[len][1]; if (trknum[len][2] > max_trknum) max_trknum = trknum[len][2]; if (trknum[len][3] > max_trknum) max_trknum = trknum[len][3]; } write8(out, len); /* write patpos */ write8(out, 0x7f); /* ntk byte */ /* sort tracks numbers */ c5 = 0x00; for (i = 0; i < len; i++) { if (i == 0) { plist[0] = c5; c5++; continue; } for (j = 0; j < i; j++) { status = 1; for (k = 0; k < 4; k++) { if (trknum[j][k] != trknum[i][k]) { status = 0; break; } } if (status == 1) { plist[i] = plist[j]; break; } } if (status == 0) { plist[i] = c5; c5++; } status = 1; } /* c5 is the max pattern number */ /* create real list of tracks numbers for really existing patterns */ c1 = 0; for (i = 0; i < len; i++) { if (i == 0) { real_tnum[c1][0] = trknum[i][0]; real_tnum[c1][1] = trknum[i][1]; real_tnum[c1][2] = trknum[i][2]; real_tnum[c1][3] = trknum[i][3]; c1++; continue; } for (j = 0; j < i; j++) { status = 1; if (plist[i] == plist[j]) { status = 0; break; } } if (status == 0) continue; real_tnum[c1][0] = trknum[i][0]; real_tnum[c1][1] = trknum[i][1]; real_tnum[c1][2] = trknum[i][2]; real_tnum[c1][3] = trknum[i][3]; c1++; status = 1; } fwrite(plist, 128, 1, out); /* write pattern list */ write32b(out, PW_MOD_MAGIC); /* write ID */ /* pattern data */ for (i = 0; i < c5; i++) { memset(tmp, 0, 1024); memset(tdata, 0, 192 * 4); for (k = 0; k < 4; k++) { hio_seek(in, 1536 + 192 * real_tnum[i][k], SEEK_SET); hio_read(tdata[k], 192, 1, in); } for (j = 0; j < 64; j++) { int x = j * 16; for (k = 0; k < 4; k++) { uint8 *t = &tdata[k][j * 3]; /* Sanity check */ if (t[0] >= 37) { return -1; } memcpy(tmp + x + k * 4, ptk_table[t[0]], 2); if ((t[1] & 0x0f) == 0x0d) t[1] -= 0x03; memcpy(tmp + x + k * 4 + 2, &t[1], 2); } } fwrite(tmp, 1024, 1, out); } /* sample data */ hio_seek(in, 1536 + (192 * (max_trknum + 1)), SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_ksm (uint8 *data, char *t, int s) { int i, j; int max_trk; PW_REQUEST_DATA(s, 1536); if (data[0] != 'M' || data[1] != '.') return -1; /* test "a" */ if (data[15] != 'a') return -1; /* test volumes */ for (i = 0; i < 15; i++) { if (data[54 + i * 32] > 0x40) return -1; } /* test tracks data */ /* first, get the highest track number .. */ max_trk = 0; for (i = 0; i < 1024; i++) { int x = data[i + 512]; if (x == 0xff) break; if (x > max_trk) max_trk = x; } if (i == 1024) return -1; if (max_trk == 0) return -1; PW_REQUEST_DATA(s, 1536 + max_trk * 192 + 63 * 3); /* real test on tracks data starts now */ for (i = 0; i <= max_trk; i++) { uint8 *d = data + 1536 + i * 192; for (j = 0; j < 64; j++) { if (d[j * 3] > 0x24) return -1; } } pw_read_title(data + 2, t, 13); return 0; } const struct pw_format pw_ksm = { "Kefrens Sound Machine", test_ksm, depack_ksm }; libxmp-4.4.1/src/loaders/prowizard/pm20.c0000664000175000017500000002261112706551122020025 0ustar claudioclaudio/* * Promizer_20.c 1997 (c) Asle / ReDoX * * Converts PM20 packed MODs back to PTK MODs * */ #include #include #define ON 0 #define OFF 1 #define AFTER_REPLAY_CODE 5198 #define SAMPLE_DESC 5458 #define ADDRESS_SAMPLE_DATA 5706 #define ADDRESS_REF_TABLE 5710 #define PATTERN_DATA 5714 void Depack_PM20 (FILE * in, FILE * out) { uint8 c1 = 0x00, c2 = 0x00, c3 = 0x00, c4 = 0x00; short pat_max = 0; long tmp_ptr, tmp1, tmp2; short refmax = 0; uint8 pnum[128]; uint8 pnum_tmp[128]; long paddr[128]; long paddr_tmp[128]; long paddr_tmp2[128]; short pptr[64][256]; uint8 NOP = 0x00; /* number of pattern */ uint8 *reftab; uint8 *sdata; uint8 Pattern[128][1024]; long i = 0, j = 0, k = 0; long ssize = 0; long psize = 0l; long SDAV = 0l; uint8 FLAG = OFF; uint8 ptk_table[37][2]; uint8 note, ins; // HIO_HANDLE *in,*out; if (Save_Status == BAD) return; #include "ptktable.h" // in = fdopen (fd_in, "rb"); // sprintf ( Depacked_OutName , "%ld.mod" , Cpt_Filename-1 ); // out = fdopen (fd_out, "w+b"); memset(pnum, 0, 128); memset(pnum_tmp, 0, 128); memset(pptr, 0, 64 << 8); memset(Pattern, 0, 128 * 1024); memset(paddr, 0, 128 * 4); memset(paddr_tmp, 0, 128 * 4); for (i = 0; i < 128; i++) paddr_tmp2[i] = 9999l; for (i = 0; i < 20; i++) /* title */ fwrite (&c1, 1, 1, out); /* bypass replaycode routine */ fseek (in, SAMPLE_DESC, 0); /* SEEK_SET */ for (i = 0; i < 31; i++) { c1 = 0x00; for (j = 0; j < 22; j++) /*sample name */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* size */ fread (&c2, 1, 1, in); ssize += (((c1 << 8) + c2) * 2); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fread (&c1, 1, 1, in); /* finetune */ c1 /= 2; fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* volume */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* loop start */ fread (&c2, 1, 1, in); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fread (&c1, 1, 1, in); /* loop size */ fread (&c2, 1, 1, in); if ((c1 == 0x00) && (c2 == 0x00)) c2 = 0x01; fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); } /* read REAL number of pattern */ fseek (in, AFTER_REPLAY_CODE + 1, 0); /* SEEK_SET */ fread (&NOP, 1, 1, in); /*printf ( "REAL Number of patterns : %d\n" , NOP ); */ /* read "used" size of pattern table */ fseek (in, 1, 1); /* SEEK_CUR */ fread (&c1, 1, 1, in); c4 = c1 / 2; /*printf ( "Number of pattern in pattern list : %d\n" , c4 ); */ /* write size of pattern list */ fwrite (&c4, 1, 1, out); /* NoiseTracker restart byte */ c1 = 0x7f; fwrite (&c1, 1, 1, out); for (i = 0; i < 128; i++) { fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); paddr[i] = (c1 << 8) + c2; } /* ordering of patterns addresses */ /* c4 contains the size of the pattern list .. */ tmp_ptr = 0; for (i = 0; i < c4; i++) { if (i == 0) { pnum[0] = 0x00; tmp_ptr++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) pnum[i] = tmp_ptr++; } pat_max = tmp_ptr - 1; /* correct re-order */ /********************/ for (i = 0; i < c4; i++) paddr_tmp[i] = paddr[i]; restart: for (i = 0; i < c4; i++) { for (j = 0; j < i; j++) { if (paddr_tmp[i] < paddr_tmp[j]) { tmp2 = pnum[j]; pnum[j] = pnum[i]; pnum[i] = tmp2; tmp1 = paddr_tmp[j]; paddr_tmp[j] = paddr_tmp[i]; paddr_tmp[i] = tmp1; goto restart; } } } j = 0; for (i = 0; i < c4; i++) { if (i == 0) { paddr_tmp2[j] = paddr_tmp[i]; continue; } if (paddr_tmp[i] == paddr_tmp2[j]) continue; paddr_tmp2[++j] = paddr_tmp[i]; } for (c1 = 0x00; c1 < c4; c1++) { for (c2 = 0x00; c2 < c4; c2++) if (paddr[c1] == paddr_tmp2[c2]) { pnum_tmp[c1] = c2; } } for (i = 0; i < c4; i++) pnum[i] = pnum_tmp[i]; /* write pattern table */ for (c1 = 0x00; c1 < 128; c1++) { fwrite (&pnum[c1], 1, 1, out); } c1 = 'M'; c2 = '.'; c3 = 'K'; fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fwrite (&c3, 1, 1, out); fwrite (&c2, 1, 1, out); /* a little pre-calc code ... no other way to deal with these unknown pattern data sizes ! :( */ /* so, first, we get the pattern data size .. */ fseek (in, ADDRESS_REF_TABLE, 0); /* SEEK_SET */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); j = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; psize = (AFTER_REPLAY_CODE + j) - PATTERN_DATA; /*printf ( "Pattern data size : %ld\n" , psize ); */ /* go back to pattern data starting address */ fseek (in, 5226, 0); /* SEEK_SET */ /* now, reading all pattern data to get the max value of note */ for (j = 0; j < psize; j += 2) { fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); if (((c1 << 8) + c2) > refmax) refmax = (c1 << 8) + c2; } /* printf ( "* refmax = %d\n" , refmax ); printf ( "* where : %ld\n" , ftell ( in ) ); */ /* read "reference Table" */ fseek (in, ADDRESS_REF_TABLE, 0); /* SEEK_SET */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); j = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; fseek (in, AFTER_REPLAY_CODE + j, 0); /* SEEK_SET */ /*printf ( "address of 'reference table' : %ld\n" , ftell (in ) ); */ refmax += 1; /* coz 1st value is 0 ! */ i = refmax * 4; /* coz each block is 4 bytes long */ reftab = (uint8 *) malloc (i); fread (reftab, i, 1, in); /* go back to pattern data starting address */ fseek (in, PATTERN_DATA, 0); /* SEEK_SET */ /*printf ( "Highest pattern number : %d\n" , pat_max ); */ k = 0; for (j = 0; j <= pat_max; j++) { for (i = 0; i < 64; i++) { /* VOICE #1 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; ins = ins >> 2; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16] = (ins & 0xf0); Pattern[j][i * 16] |= ptk_table[(note / 2)][0]; Pattern[j][i * 16 + 1] = ptk_table[(note / 2)][1]; Pattern[j][i * 16 + 2] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 2] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 3] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 2] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 2] & 0x0f) == 0x0b)) { FLAG = ON; } /* VOICE #2 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; ins = ins >> 2; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16 + 4] = (ins & 0xf0); Pattern[j][i * 16 + 4] |= ptk_table[(note / 2)][0]; Pattern[j][i * 16 + 5] = ptk_table[(note / 2)][1]; Pattern[j][i * 16 + 6] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 6] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 7] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 6] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 6] & 0x0f) == 0x0b)) { FLAG = ON; } /* VOICE #3 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; ins = ins >> 2; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16 + 8] = (ins & 0xf0); if (note != 0) Pattern[j][i * 16 + 8] |= ptk_table[(note / 2)][0]; Pattern[j][i * 16 + 9] = ptk_table[(note / 2)][1]; Pattern[j][i * 16 + 10] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 10] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 11] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 10] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 10] & 0x0f) == 0x0b)) { FLAG = ON; } /* VOICE #4 */ fread (&c1, 1, 1, in); k += 1; fread (&c2, 1, 1, in); k += 1; ins = reftab[((c1 << 8) + c2) * 4]; ins = ins >> 2; note = reftab[((c1 << 8) + c2) * 4 + 1]; Pattern[j][i * 16 + 12] = (ins & 0xf0); Pattern[j][i * 16 + 12] |= ptk_table[(note / 2)][0]; Pattern[j][i * 16 + 13] = ptk_table[(note / 2)][1]; Pattern[j][i * 16 + 14] = reftab[((c1 << 8) + c2) * 4 + 2]; Pattern[j][i * 16 + 14] |= ((ins << 4) & 0xf0); Pattern[j][i * 16 + 15] = reftab[((c1 << 8) + c2) * 4 + 3]; if (((Pattern[j][i * 16 + 14] & 0x0f) == 0x0d) || ((Pattern[j][i * 16 + 14] & 0x0f) == 0x0b)) { FLAG = ON; } if (FLAG == ON) { FLAG = OFF; break; } } fwrite (Pattern[j], 1024, 1, out); } free (reftab); /* get address of sample data .. and go there */ fseek (in, ADDRESS_SAMPLE_DATA, 0); /* SEEK_SET */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); SDAV = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; fseek (in, AFTER_REPLAY_CODE + SDAV, 0); /* SEEK_SET */ /* read and save sample data */ /*printf ( "out: where before saving sample data : %ld\n" , ftell ( out ) ); */ /*printf ( "Total sample size : %ld\n" , ssize ); */ sdata = (uint8 *) malloc (ssize); fread (sdata, ssize, 1, in); fwrite (sdata, ssize, 1, out); free (sdata); Crap ("PM20:Promizer 2.0", BAD, BAD, out); fflush (in); fflush (out); printf ("done\n"); return; /* useless ... but */ } void testPM2 (void) { start = i; /* test 1 */ if ((start + 5714) > in_size) { Test = BAD; return; } /* test 2 */ if (data[start + 5094] != 0x03) /* not sure in fact ... */ /* well, it IS the frequency table, it always seem */ /* to be the 'standard one .. so here, there is 0358h */ { Test = BAD; return; } /* test 3 */ if (data[start + 5461] > 0x40) /* testing a volume */ { Test = BAD; return; } Test = GOOD; } libxmp-4.4.1/src/loaders/prowizard/pp30.c0000664000175000017500000001746312706551122020042 0ustar claudioclaudio/* * ProPacker_30.c 1997 (c) Asle / ReDoX * * Converts PP30 packed MODs back to PTK MODs * thanks to Gryzor and his ProWizard tool ! ... without it, this prog * would not exist !!! * */ #include #include void Depack_PP30 (FILE * in, FILE * out) { uint8 c1 = 0x00, c2 = 0x00, c3 = 0x00, c4 = 0x00; uint8 ptable[128]; short Max = 0; uint8 Tracks_Numbers[4][128]; short Tracks_PrePointers[512][64]; uint8 NOP = 0x00; /* number of pattern */ uint8 *reftab; uint8 Pattern[1024]; long i = 0, j = 0; long ssize = 0; long RTS = 0; /* Reference Table Size */ // HIO_HANDLE *in,*out; if (Save_Status == BAD) return; memset(ptable, 0, 128); memset(Tracks_Numbers, 0, 4 * 128); memset(Tracks_PrePointers, 0, 512 * 64); // in = fdopen (fd_in, "rb"); // sprintf ( Depacked_OutName , "%ld.mod" , Cpt_Filename-1 ); // out = fdopen (fd_out, "w+b"); for (i = 0; i < 20; i++) /* title */ fwrite (&c1, 1, 1, out); for (i = 0; i < 31; i++) { c1 = 0x00; for (j = 0; j < 22; j++) /*sample name */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* size */ fread (&c2, 1, 1, in); ssize += (((c1 << 8) + c2) * 2); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fread (&c1, 1, 1, in); /* finetune */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* volume */ fwrite (&c1, 1, 1, out); fread (&c1, 1, 1, in); /* loop start */ fread (&c2, 1, 1, in); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fread (&c1, 1, 1, in); /* loop size */ fread (&c2, 1, 1, in); fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); } /* pattern table lenght */ fread (&NOP, 1, 1, in); fwrite (&NOP, 1, 1, out); /*printf ( "Number of patterns : %d\n" , NOP ); */ /* NoiseTracker restart byte */ fread (&c1, 1, 1, in); fwrite (&c1, 1, 1, out); Max = 0; for (j = 0; j < 4; j++) { for (i = 0; i < 128; i++) { fread (&c1, 1, 1, in); Tracks_Numbers[j][i] = c1; if (Tracks_Numbers[j][i] > Max) Max = Tracks_Numbers[j][i]; } } /* write pattern table without any optimizing ! */ for (c1 = 0x00; c1 < NOP; c1++) fwrite (&c1, 1, 1, out); c4 = 0x00; for (; c1 < 128; c1++) fwrite (&c4, 1, 1, out); c1 = 'M'; c2 = '.'; c3 = 'K'; fwrite (&c1, 1, 1, out); fwrite (&c2, 1, 1, out); fwrite (&c3, 1, 1, out); fwrite (&c2, 1, 1, out); /* PATTERN DATA code starts here */ /*printf ( "Highest track number : %d\n" , Max ); */ for (j = 0; j <= Max; j++) { for (i = 0; i < 64; i++) { fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); Tracks_PrePointers[j][i] = ((c1 << 8) + c2) / 4; } } /* read "reference table" size */ fread (&c1, 1, 1, in); fread (&c2, 1, 1, in); fread (&c3, 1, 1, in); fread (&c4, 1, 1, in); RTS = (c1 << 24) + (c2 << 16) + (c3 << 8) + c4; /* read "reference Table" */ reftab = (uint8 *) malloc (RTS); fread (reftab, RTS, 1, in); /* NOW, the real shit takes place :) */ for (i = 0; i < NOP; i++) { memset(Pattern, 0, 1024); for (j = 0; j < 64; j++) { Pattern[j * 16] = reftab[Tracks_PrePointers [Tracks_Numbers[0][i]][j] * 4]; Pattern[j * 16 + 1] = reftab[Tracks_PrePointers [Tracks_Numbers[0][i]][j] * 4 + 1]; Pattern[j * 16 + 2] = reftab[Tracks_PrePointers [Tracks_Numbers[0][i]][j] * 4 + 2]; Pattern[j * 16 + 3] = reftab[Tracks_PrePointers [Tracks_Numbers[0][i]][j] * 4 + 3]; Pattern[j * 16 + 4] = reftab[Tracks_PrePointers [Tracks_Numbers[1][i]][j] * 4]; Pattern[j * 16 + 5] = reftab[Tracks_PrePointers [Tracks_Numbers[1][i]][j] * 4 + 1]; Pattern[j * 16 + 6] = reftab[Tracks_PrePointers [Tracks_Numbers[1][i]][j] * 4 + 2]; Pattern[j * 16 + 7] = reftab[Tracks_PrePointers [Tracks_Numbers[1][i]][j] * 4 + 3]; Pattern[j * 16 + 8] = reftab[Tracks_PrePointers [Tracks_Numbers[2][i]][j] * 4]; Pattern[j * 16 + 9] = reftab[Tracks_PrePointers [Tracks_Numbers[2][i]][j] * 4 + 1]; Pattern[j * 16 + 10] = reftab[Tracks_PrePointers [Tracks_Numbers[2][i]][j] * 4 + 2]; Pattern[j * 16 + 11] = reftab[Tracks_PrePointers [Tracks_Numbers[2][i]][j] * 4 + 3]; Pattern[j * 16 + 12] = reftab[Tracks_PrePointers [Tracks_Numbers[3][i]][j] * 4]; Pattern[j * 16 + 13] = reftab[Tracks_PrePointers [Tracks_Numbers[3][i]][j] * 4 + 1]; Pattern[j * 16 + 14] = reftab[Tracks_PrePointers [Tracks_Numbers[3][i]][j] * 4 + 2]; Pattern[j * 16 + 15] = reftab[Tracks_PrePointers [Tracks_Numbers[3][i]][j] * 4 + 3]; } fwrite (Pattern, 1024, 1, out); } free (reftab); /* Now, it's sample data ... though, VERY quickly handled :) */ /* thx GCC ! (GNU C COMPILER). */ /*printf ( "Total sample size : %ld\n" , ssize ); */ reftab = (uint8 *) malloc (ssize); fread (reftab, ssize, 1, in); fwrite (reftab, ssize, 1, out); free (reftab); Crap ("PP30:ProPacker v3.0", BAD, BAD, out); fflush (in); fflush (out); printf ("done\n"); return; /* useless ... but */ } void testPP30 (void) { /* test #1 */ if (i < 3) { /*printf ( "#1 (i:%ld)\n" , i );*/ Test = BAD; return; } /* test #2 */ start = i - 3; l = 0; for (j = 0; j < 31; j++) { k = (((data[start + j * 8] << 8) + data[start + j * 8 + 1]) * 2); l += k; /* finetune > 0x0f ? */ if (data[start + 8 * j + 2] > 0x0f) { /*printf ( "#2 (start:%ld)\n" , start );*/ Test = BAD; return; } /* volume > 0x40 ? */ if (data[start + 8 * j + 3] > 0x40) { /*printf ( "#2,0 (start:%ld)\n" , start );*/ Test = BAD; return; } /* loop start > size ? */ if ((((data[start + 4 + j * 8] << 8) + data[start + 5 + j * 8]) * 2) > k) { Test = BAD; /*printf ( "#2,1 (start:%ld)\n" , start );*/ return; } } if (l <= 2) { /*printf ( "#2,2 (start:%ld)\n" , start );*/ Test = BAD; return; } /* test #3 about size of pattern list */ l = data[start + 248]; if ((l > 127) || (l == 0)) { /*printf ( "#3 (start:%ld)\n" , start );*/ Test = BAD; return; } /* get the highest track value */ k = 0; for (j = 0; j < 512; j++) { l = data[start + 250 + j]; if (l > k) k = l; } /* k is the highest track number */ k += 1; k *= 64; /* test #4 track data value *4 ? */ /* ssize used as a variable .. set to 0 afterward */ ssize = 0; if (((k * 2) + start) > in_size) { Test = BAD; ssize = 0; return; } for (j = 0; j < k; j++) { l = (data[start + 762 + j * 2] << 8) + data[start + 763 + j * 2]; if (l > ssize) ssize = l; if (((l * 4) / 4) != l) { /*printf ( "#4 (start:%ld)(where:%ld)\n" , start,start+j*2+762 );*/ Test = BAD; ssize = 0; return; } } /* test #5 reference table size *4 ? */ /* ssize is the highest reference number */ k *= 2; ssize /= 4; l = (data[start + k + 762] << 24) + (data[start + k + 763] << 16) + (data[start + k + 764] << 8) + data[start + k + 765]; if (l > 65535) { Test = BAD; ssize = 0; return; } if (l != ((ssize + 1) * 4)) { /*printf ( "#5 (start:%ld)(where:%ld)\n" , start,(start+k+762) );*/ Test = BAD; ssize = 0; return; } /* test #6 data in reference table ... */ for (j = 0; j < (l / 4); j++) { /* volume > 41 ? */ if (((data[start + k + 766 + j * 4 + 2] & 0x0f) == 0x0c) && (data[start + k + 766 + j * 4 + 3] > 0x41)) { /*printf ( "#6 (vol > 40 at : %ld)\n" , start+k+766+j*4+2 );*/ Test = BAD; ssize = 0; return; } /* break > 40 ? */ if (((data[start + k + 766 + j * 4 + 2] & 0x0f) == 0x0d) && (data[start + k + 766 + j * 4 + 3] > 0x40)) { /*printf ( "#6,1\n" );*/ Test = BAD; ssize = 0; return; } /* jump > 128 */ if (((data[start + k + 766 + j * 4 + 2] & 0x0f) == 0x0b) && (data[start + k + 766 + j * 4 + 3] > 0x7f)) { /*printf ( "#6,2\n" );*/ Test = BAD; ssize = 0; return; } /* smp > 1f ? */ if ((data[start + k + 766 + j * 4] & 0xf0) > 0x10) { /*printf ( "#6,3\n" );*/ Test = BAD; ssize = 0; return; } } ssize = 0; Test = GOOD; } libxmp-4.4.1/src/loaders/prowizard/tp3.c0000664000175000017500000001327212706551122017760 0ustar claudioclaudio/* * TrackerPacker_v3.c Copyright (C) 1998 Asle / ReDoX * * Converts tp2/tp3 packed MODs back to PTK MODs * * Modified in 2007,2014,2016 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_tp23(HIO_HANDLE *in, FILE *out, int ver) { uint8 c1, c2, c3, c4; uint8 pnum[128]; uint8 pdata[1024]; uint8 tmp[50]; uint8 note, ins, fxt, fxp; uint8 npat, nins; uint8 len; int trk_ofs[128][4]; int i, j, k; int pat_ofs = 999999; int size, ssize = 0; int max_trk_ofs = 0; memset(trk_ofs, 0, 128 * 4 * 4); memset(pnum, 0, 128); hio_seek(in, 8, SEEK_CUR); pw_move_data(out, in, 20); /* title */ nins = hio_read16b(in) / 8; /* number of sample */ for (i = 0; i < nins; i++) { pw_write_zero(out, 22); /*sample name */ c3 = hio_read8(in); /* read finetune */ c4 = hio_read8(in); /* read volume */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, c3); /* write finetune */ write8(out, c4); /* write volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } memset(tmp, 0, 30); tmp[29] = 0x01; for (; i < 31; i++) { fwrite(tmp, 30, 1, out); } /* read size of pattern table */ hio_read8(in); write8(out, len = hio_read8(in)); /* sequence length */ /* Sanity check */ if (len >= 128) { return -1; } write8(out, 0x7f); /* ntk byte */ for (npat = i = 0; i < len; i++) { pnum[i] = hio_read16b(in) / 8; if (pnum[i] > npat) npat = pnum[i]; } /* read tracks addresses */ /* bypass 4 bytes or not ?!? */ /* Here, I choose not :) */ for (i = 0; i <= npat; i++) { for (j = 0; j < 4; j++) { trk_ofs[i][j] = hio_read16b(in); if (trk_ofs[i][j] > max_trk_ofs) max_trk_ofs = trk_ofs[i][j]; } } fwrite(pnum, 128, 1, out); /* write pattern list */ write32b(out, PW_MOD_MAGIC); /* ID string */ pat_ofs = hio_tell(in) + 2; /* pattern datas */ for (i = 0; i <= npat; i++) { memset(pdata, 0, 1024); for (j = 0; j < 4; j++) { int where; hio_seek(in, pat_ofs + trk_ofs[i][j], SEEK_SET); for (k = 0; k >= 0 && k < 64; k++) { uint8 *p = pdata + k * 16 + j * 4; c1 = hio_read8(in); if ((c1 & 0xc0) == 0xc0) { k += 0x100 - c1 - 1; continue; } if ((c1 & 0xc0) == 0x80) { c2 = hio_read8(in); if (ver == 2) { fxt = (c1 >> 2) & 0x0f; } else { fxt = (c1 >> 1) & 0x0f; } fxp = c2; if ((fxt == 0x05) || (fxt == 0x06) || (fxt == 0x0a)) { if (fxp > 0x80) fxp = 0x100 - fxp; else if (fxp <= 0x80) fxp = (fxp << 4) & 0xf0; } if (fxt == 0x08) fxt = 0x00; p[2] = fxt; p[3] = fxp; continue; } c2 = hio_read8(in); ins = ((c2 >> 4) & 0x0f) | ((c1 >> 2) & 0x10); if (ver == 2) { note = (c1 & 0xfe) >> 1; if (note >= 37) { return -1; } fxt = c2 & 0x0f; if (fxt == 0x00) { p[0] = ins & 0xf0; p[0] |= ptk_table[note][0]; p[1] = ptk_table[note][1]; p[2] = ((ins << 4) & 0xf0) | fxt; continue; } } else { if ((c1 & 0x40) == 0x40) { note = 0x7f - c1; } else { note = c1 & 0x3f; } if (note >= 37) { return -1; } fxt = c2 & 0x0f; if (fxt == 0x00) { p[0] = ins & 0xf0; p[0] |= ptk_table[note][0]; p[1] = ptk_table[note][1]; p[2] = (ins << 4) & 0xf0; continue; } } c3 = hio_read8(in); if (fxt == 0x08) fxt = 0x00; fxp = c3; if (fxt == 0x05 || fxt == 0x06 || fxt == 0x0a) { if (fxp > 0x80) { fxp = 0x100 - fxp; } else if (fxp <= 0x80) { fxp = (fxp << 4) & 0xf0; } } p[0] = (ins & 0xf0) | ptk_table[note][0]; p[1] = ptk_table[note][1]; p[2] = ((ins << 4) & 0xf0) | fxt; p[3] = fxp; } where = hio_tell(in); if (where < 0) { return -1; } if (where > max_trk_ofs) { max_trk_ofs = where; } } fwrite(pdata, 1024, 1, out); } /* Sample data */ if (ver > 2 && max_trk_ofs & 0x01) { max_trk_ofs += 1; } hio_seek(in, max_trk_ofs, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int depack_tp3(HIO_HANDLE *in, FILE *out) { return depack_tp23(in, out, 3); } static int depack_tp2(HIO_HANDLE *in, FILE *out) { return depack_tp23(in, out, 2); } static int test_tp23(uint8 *data, char *t, int s, char *magic) { int i; int npat, nins, ssize; PW_REQUEST_DATA(s, 1024); if (memcmp(data, magic, 8)) return -1; /* number of sample */ nins = readmem16b(data + 28); if (nins == 0 || nins & 0x07) return -1; nins >>= 3; for (i = 0; i < nins; i++) { uint8 *d = data + i * 8; /* test finetunes */ if (d[30] > 0x0f) return -1; /* test volumes */ if (d[31] > 0x40) return -1; } /* test sample sizes */ ssize = 0; for (i = 0; i < nins; i++) { uint8 *d = data + i * 8; int len = readmem16b(d + 32) << 1; /* size */ int start = readmem16b(d + 34) << 1; /* loop start */ int lsize = readmem16b(d + 36) << 1; /* loop size */ if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > len + 2) return -1; if (start != 0 && lsize == 0) return -1; ssize += len; } if (ssize <= 4) return -1; /* pattern list size */ npat = data[nins * 8 + 31]; if (npat == 0 || npat > 128) return -1; pw_read_title(data + 8, t, 20); return 0; } static int test_tp3(uint8 *data, char *t, int s) { return test_tp23(data, t, s, "CPLX_TP3"); } static int test_tp2(uint8 *data, char *t, int s) { return test_tp23(data, t, s, "MEXX_TP2"); } const struct pw_format pw_tp3 = { "Tracker Packer v3", test_tp3, depack_tp3 }; const struct pw_format pw_tp2 = { "Tracker Packer v2", test_tp2, depack_tp2 }; libxmp-4.4.1/src/loaders/prowizard/skyt.c0000664000175000017500000000474212706551122020246 0ustar claudioclaudio/* * Skyt_Packer.c Copyright (C) 1997 Asle / ReDoX * * Modified in 2009,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_skyt(HIO_HANDLE *in, FILE *out) { uint8 c1, c2, c3, c4; uint8 ptable[128]; uint8 pat_pos; uint8 pat[1024]; int i = 0, j = 0, k = 0; int trkval[128][4]; int trk_addr; int size, ssize = 0; memset(ptable, 0, 128); memset(trkval, 0, 128 * 4); pw_write_zero(out, 20); /* write title */ /* read and write sample descriptions */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /*sample name */ write16b(out, size = hio_read16b(in)); /* sample size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } hio_read32b(in); /* bypass 8 empty bytes */ hio_read32b(in); hio_read32b(in); /* bypass "SKYT" ID */ pat_pos = hio_read8(in) + 1; /* pattern table lenght */ if (pat_pos >= 128) { return -1; } write8(out, pat_pos); write8(out, 0x7f); /* write NoiseTracker byte */ /* read track numbers ... and deduce pattern list */ for (i = 0; i < pat_pos; i++) { for (j = 0; j < 4; j++) { trkval[i][j] = hio_read16b(in); } } /* write pseudo pattern list */ for (i = 0; i < 128; i++) { write8(out, i < pat_pos ? i : 0); } write32b(out, PW_MOD_MAGIC); /* write ptk's ID */ hio_read8(in); /* bypass $00 unknown byte */ /* get track address */ trk_addr = hio_tell(in); /* track data */ for (i = 0; i < pat_pos; i++) { memset(pat, 0, 1024); for (j = 0; j < 4; j++) { hio_seek(in, trk_addr + ((trkval[i][j] - 1)<<8), SEEK_SET); for (k = 0; k < 64; k++) { int x = k * 16 + j * 4; c1 = hio_read8(in); c2 = hio_read8(in); c3 = hio_read8(in); c4 = hio_read8(in); pat[x] = (c2 & 0xf0) | ptk_table[c1][0]; pat[x + 1] = ptk_table[c1][1]; pat[x + 2] = ((c2 << 4) & 0xf0) | c3; pat[x + 3] = c4; } } fwrite(pat, 1024, 1, out); } /* sample data */ pw_move_data(out, in, ssize); return 0; } static int test_skyt(uint8 *data, char *t, int s) { int i; PW_REQUEST_DATA(s, 8 * 31 + 12); /* test 2 */ for (i = 0; i < 31; i++) { if (data[8 * i + 4] > 0x40) return -1; } if (readmem32b(data + 256) != MAGIC4('S','K','Y','T')) return -1; pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_skyt = { "SKYT Packer", test_skyt, depack_skyt }; libxmp-4.4.1/src/loaders/prowizard/np3.c0000664000175000017500000001405012706551122017745 0ustar claudioclaudio/* * NoisePacker_v3.c Copyright (C) 1998 Asle / ReDoX * * Converts NoisePacked MODs back to ptk * Last revision : 26/11/1999 by Sylvain "Asle" Chipaux * reduced to only one FREAD. * Speed-up and Binary smaller. * * Modified in 2006,2007,2014,2015 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_np3(HIO_HANDLE *in, FILE *out) { uint8 tmp[1024]; uint8 c1, c2, c3, c4; uint8 ptable[128]; int len, nins, npat; int max_addr, smp_addr; int size, ssize = 0; /*int tsize;*/ int trk_addr[128][4]; int i, j, k; int trk_start; memset(ptable, 0, 128); memset(trk_addr, 0, 128 * 4 * 4); c1 = hio_read8(in); /* read number of samples */ c2 = hio_read8(in); nins = ((c1 << 4) & 0xf0) | ((c2 >> 4) & 0x0f); pw_write_zero(out, 20); /* write title */ len = hio_read16b(in) >> 1; /* size of pattern list */ if (len > 128) { return -1; } hio_read16b(in); /* 2 unknown bytes */ /*tsize =*/ hio_read16b(in); /* read track data size */ /* read sample descriptions */ for (i = 0; i < nins; i++) { hio_read(tmp, 1, 16, in); pw_write_zero(out, 22); /* sample name */ write16b(out, size = readmem16b(tmp + 6)); ssize += size * 2; write8(out, tmp[0]); /* write finetune */ write8(out, tmp[1]); /* write volume */ fwrite(tmp + 14, 2, 1, out); /* write loop start */ fwrite(tmp + 12, 2, 1, out); /* write loop size */ } /* fill up to 31 samples */ memset(tmp, 0, 30); tmp[29] = 0x01; for (; i < 31; i++) fwrite(tmp, 30, 1, out); write8(out, len); /* write size of pattern list */ write8(out, 0x7f); /* write noisetracker byte */ hio_seek(in, 2, SEEK_CUR); /* always $02? */ hio_seek(in, 2, SEEK_CUR); /* unknown */ /* read pattern table */ npat = 0; for (i = 0; i < len; i++) { ptable[i] = hio_read16b(in) / 8; if (ptable[i] > npat) npat = ptable[i]; } npat++; fwrite(ptable, 128, 1, out); /* write pattern table */ write32b(out, PW_MOD_MAGIC); /* write ptk ID */ /* read tracks addresses per pattern */ for (max_addr = i = 0; i < npat; i++) { if ((trk_addr[i][0] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][0]; if ((trk_addr[i][1] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][1]; if ((trk_addr[i][2] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][2]; if ((trk_addr[i][3] = hio_read16b(in)) > max_addr) max_addr = trk_addr[i][3]; } trk_start = hio_tell(in); /* the track data now ... */ smp_addr = 0; for (i = 0; i < npat; i++) { memset(tmp, 0, 1024); for (j = 0; j < 4; j++) { int x; hio_seek(in, trk_start + trk_addr[i][3 - j], SEEK_SET); for (k = 0; k < 64; k++) { int x = k * 16 + j * 4; if ((c1 = hio_read8(in)) >= 0x80) { k += (0x100 - c1) - 1; continue; } c2 = hio_read8(in); c3 = hio_read8(in); c4 = (c1 & 0xfe) / 2; tmp[x] = ((c1 << 4) & 0x10) | ptk_table[c4][0]; tmp[x + 1] = ptk_table[c4][1]; switch (c2 & 0x0f) { case 0x08: c2 &= 0xf0; break; case 0x07: c2 = (c2 & 0xf0) + 0x0a; /* fall through */ case 0x06: case 0x05: c3 = c3 > 0x80 ? 0x100 - c3 : (c3 << 4) & 0xf0; break; case 0x0e: c3 = 1; break; case 0x0b: c3 = (c3 + 4) / 2; break; } tmp[x + 2] = c2; tmp[x + 3] = c3; if ((c2 & 0x0f) == 0x0d) break; } x = hio_tell(in); if (x < 0) { return -1; } if (x > smp_addr) { smp_addr = x; } } fwrite(tmp, 1024, 1, out); } /* sample data */ if (smp_addr & 1) smp_addr++; hio_seek(in, smp_addr, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_np3(uint8 *data, char *t, int s) { int num_ins, ssize, hdr_size, ptab_size, trk_size, max_pptr; int i; PW_REQUEST_DATA(s, 10); /* size of the pattern table */ ptab_size = readmem16b(data + 2); if (ptab_size == 0 || ptab_size & 0x01 || ptab_size > 0xff) return -1; /* test number of samples */ if ((data[1] & 0x0f) != 0x0c) return -1; num_ins = ((data[0] << 4) & 0xf0) | ((data[1] >> 4) & 0x0f); if (num_ins == 0 || num_ins > 0x1f) return -1; PW_REQUEST_DATA(s, 15 + num_ins * 16); /* test volumes */ for (i = 0; i < num_ins; i++) { if (data[9 + i * 16] > 0x40) return -1; } /* test sample sizes */ ssize = 0; for (i = 0; i < num_ins; i++) { uint8 *d = data + i * 16; int len = readmem16b(d + 14) << 1; int start = readmem16b(d + 20) << 1; int lsize = readmem16b(d + 22) << 1; if (len > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > len + 2) return -1; if (start == 0 && lsize != 0) return -1; ssize += len; } if (ssize <= 4) return -1; /* size of the header 'til the end of sample descriptions */ hdr_size = num_ins * 16 + 8 + 4; PW_REQUEST_DATA(s, hdr_size + ptab_size + 2); /* test pattern table */ max_pptr = 0; for (i = 0; i < ptab_size; i += 2) { int pptr = readmem16b(data + hdr_size + i); if (pptr & 0x07 || pptr > 0x400) return -1; if (pptr > max_pptr) max_pptr = pptr; } /* max_pptr is the highest pattern number (*8) */ /* paske on a que l'address du dernier pattern .. */ /* size of the header 'til the end of the track list */ hdr_size += ptab_size + max_pptr + 8; /* test track data size */ trk_size = readmem16b(data + 6); if (trk_size <= 63) return -1; PW_REQUEST_DATA(s, hdr_size + trk_size + 2); /* test notes */ /* re-calculate the number of sample */ for (i = 0; i < trk_size ; i++) { uint8 *d = data + hdr_size + i; if (d[0] & 0x80) continue; /* si note trop grande et si effet = A */ if (d[0] > 0x49 || (d[1] & 0x0f) == 0x0a) return -1; /* si effet D et arg > 0x40 */ if ((d[1] & 0x0f) == 0x0d && d[2] > 0x40) return -1; /* sample nbr > ce qui est defini au debut ? */ if ((((d[0] << 4) & 0x10) | ((d[1] >> 4) & 0x0f)) > num_ins) return -1; /* all is empty ?!? ... cannot be ! */ if (d[0] == 0 && d[1] == 0 && d[2] == 0 && i < (trk_size - 3)) return -1; i += 2; } pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_np3 = { "NoisePacker v3", test_np3, depack_np3 }; libxmp-4.4.1/src/loaders/prowizard/pm10c.c0000664000175000017500000001176712706551122020201 0ustar claudioclaudio/* * Promizer_10c.c Copyright (C) 1997 Asle / ReDoX * * Converts PM10c packed MODs back to PTK MODs * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_p10c(HIO_HANDLE *in, FILE *out) { uint8 c1, c2; int pat_max; int tmp_ptr, tmp1, tmp2; int refmax; uint8 pnum[128]; uint8 pnum1[128]; int paddr[128]; int paddr1[128]; int paddr2[128]; short pptr[64][256]; int num_pat; uint8 *reftab; uint8 pat[128][1024]; int i, j, k, l; int size, ssize; int psize; int smp_ofs; uint8 fin[31]; uint8 oldins[4]; memset(pnum, 0, 128); memset(pnum1, 0, 128); memset(pptr, 0, 64 << 8); memset(pat, 0, 128 * 1024); memset(fin, 0, 31); memset(oldins, 0, 4); memset(paddr, 0, 128 * 4); memset(paddr1, 0, 128 * 4); for (i = 0; i < 128; i++) paddr2[i] = 9999L; pw_write_zero(out, 20); /* title */ /* bypass replaycode routine */ hio_seek(in, 4460, SEEK_SET); ssize = 0; for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /*sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, fin[i] = hio_read8(in)); /* fin */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ write16b(out, hio_read16b(in)); /* loop size */ } num_pat = hio_read16b(in) / 4; /* pat table length */ /* Sanity check */ if (num_pat > 128) { return -1; } write8(out, num_pat); write8(out, 0x7f); /* NoiseTracker byte */ for (i = 0; i < 128; i++) paddr[i] = hio_read32b(in); /* ordering of patterns addresses */ tmp_ptr = 0; for (i = 0; i < num_pat; i++) { if (i == 0) { pnum[0] = 0; tmp_ptr++; continue; } for (j = 0; j < i; j++) { if (paddr[i] == paddr[j]) { pnum[i] = pnum[j]; break; } } if (j == i) pnum[i] = tmp_ptr++; } pat_max = tmp_ptr - 1; /* correct re-order */ for (i = 0; i < num_pat; i++) paddr1[i] = paddr[i]; restart: for (i = 0; i < num_pat; i++) { for (j = 0; j < i; j++) { if (paddr1[i] < paddr1[j]) { tmp2 = pnum[j]; pnum[j] = pnum[i]; pnum[i] = tmp2; tmp1 = paddr1[j]; paddr1[j] = paddr1[i]; paddr1[i] = tmp1; goto restart; } } } for (j = i = 0; i < num_pat; i++) { if (i == 0) { paddr2[j] = paddr1[i]; continue; } if (paddr1[i] == paddr2[j]) continue; paddr2[++j] = paddr1[i]; } for (c1 = 0; c1 < num_pat; c1++) { for (c2 = 0; c2 < num_pat; c2++) { if (paddr[c1] == paddr2[c2]) pnum1[c1] = c2; } } for (i = 0; i < num_pat; i++) pnum[i] = pnum1[i]; /* write pattern table */ fwrite(pnum, 128, 1, out); write32b(out, PW_MOD_MAGIC); /* a little pre-calc code ... no other way to deal with these unknown * pattern data sizes ! :( */ hio_seek(in, 4456, SEEK_SET); psize = hio_read32b(in); /* go back to pattern data starting address */ hio_seek(in, 5222, SEEK_SET); /* now, reading all pattern data to get the max value of note */ refmax = 0; for (j = 0; j < psize; j += 2) { int x = hio_read16b(in); if (x > refmax) refmax = x; } /* read "reference Table" */ refmax++; /* coz 1st value is 0 ! */ i = refmax * 4; /* coz each block is 4 bytes long */ reftab = (uint8 *) malloc(i); hio_read(reftab, i, 1, in); /* go back to pattern data starting address */ hio_seek(in, 5222, SEEK_SET); for (j = 0; j <= pat_max; j++) { int flag = 0; for (i = 0; i < 64; i++) { for (k = 0; k < 4; k++) { uint8 *p = &pat[j][i * 16 + k * 4]; int x = hio_read16b(in) << 2; int fine, ins, per, fxt; memcpy(p, &reftab[x], 4); ins = ((p[2] >> 4) & 0x0f) | (p[0] & 0xf0); if (ins != 0) { oldins[k] = ins; } per = ((p[0] & 0x0f) << 8) | p[1]; fxt = p[2] & 0x0f; fine = fin[oldins[k] - 1]; if (per != 0 && oldins[k] > 0 && fine != 0) { for (l = 0; l < 36; l++) { if (tun_table[fine][l] == per) { p[0] &= 0xf0; p[0] |= ptk_table[l + 1][0]; p[1] = ptk_table[l + 1][1]; break; } } } if (fxt == 0x0d || fxt == 0x0b) { flag = 1; } } if (flag == 1) { break; } } fwrite(pat[j], 1024, 1, out); } free(reftab); hio_seek(in, 4452, SEEK_SET); smp_ofs = hio_read32b(in); hio_seek(in, 4456 + smp_ofs, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_p10c(uint8 *data, char *t, int s) { uint8 magic[] = { 0x60, 0x38, 0x60, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x01, 0x3e, 0x60, 0x00, 0x01, 0x0c, 0x48, 0xe7 }; /* test 1 */ PW_REQUEST_DATA(s, 22); if (memcmp(data, magic, 16) != 0) return -1; /* test 2 */ if (data[21] != 0xce) return -1; PW_REQUEST_DATA(s, 4714); #if 0 /* test 3 */ j = readmem32b(data + 4452); if (j + 4452 > in_size) return -1; #endif /* test 4 */ if (readmem16b(data + 4712) & 0x03) return -1; /* test 5 */ if (data[36] != 0x10) return -1; /* test 6 */ if (data[37] != 0xfc) return -1; pw_read_title(NULL, t, 0); return 0; } const struct pw_format pw_p10c = { "Promizer 1.0c", test_p10c, depack_p10c }; libxmp-4.4.1/src/loaders/prowizard/Makefile0000664000175000017500000000126612706551122020546 0ustar claudioclaudio PROWIZ_OBJS = prowiz.o ptktable.o tuning.o ac1d.o di.o eureka.o \ fc-m.o fuchs.o fuzzac.o gmc.o heatseek.o ksm.o \ mp.o np1.o np2.o np3.o p61a.o pm10c.o pm18a.o \ pha.o prun1.o prun2.o tdd.o unic.o unic2.o wn.o zen.o \ tp1.o tp3.o p40.o xann.o theplayer.o pp10.o pp21.o \ starpack.o titanics.o skyt.o novotrade.o hrt.o noiserun.o PROWIZ_OBJS2 = pm.o pm01.o pm20.o pm40.o pp30.o PROWIZ_DFILES = Makefile $(PROWIZ_OBJS:.o=.c) $(PROWIZ_OBJS2:.o=.c) prowiz.h PROWIZ_PATH = src/loaders/prowizard OBJS += $(addprefix $(PROWIZ_PATH)/, $(PROWIZ_OBJS)) dist-prowiz:: mkdir -p $(DIST)/$(PROWIZ_PATH) cp -RPp $(addprefix $(PROWIZ_PATH)/,$(PROWIZ_DFILES)) $(DIST)/$(PROWIZ_PATH) libxmp-4.4.1/src/loaders/prowizard/fc-m.c0000664000175000017500000000442212706551122020071 0ustar claudioclaudio/* * FC-M_Packer.c Copyright (C) 1997 Asle / ReDoX * * Converts back to ptk FC-M packed MODs * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_fcm(HIO_HANDLE *in, FILE *out) { uint8 c1; uint8 ptable[128]; uint8 pat_pos; uint8 pat_max; int i; int size, ssize = 0; memset(ptable, 0, 128); hio_read32b(in); /* bypass "FC-M" ID */ hio_read16b(in); /* version number? */ hio_read32b(in); /* bypass "NAME" chunk */ pw_move_data(out, in, 20); /* read and write title */ hio_read32b(in); /* bypass "INST" chunk */ /* read and write sample descriptions */ for (i = 0; i < 31; i++) { pw_write_zero(out, 22); /*sample name */ write16b(out, size = hio_read16b(in)); /* size */ ssize += size * 2; write8(out, hio_read8(in)); /* finetune */ write8(out, hio_read8(in)); /* volume */ write16b(out, hio_read16b(in)); /* loop start */ size = hio_read16b(in); /* loop size */ if (size == 0) size = 1; write16b(out, size); } hio_read32b(in); /* bypass "LONG" chunk */ write8(out, pat_pos = hio_read8(in)); /* pattern table lenght */ write8(out, hio_read8(in)); /* NoiseTracker byte */ hio_read32b(in); /* bypass "PATT" chunk */ /* read and write pattern list and get highest patt number */ for (pat_max = i = 0; i < pat_pos; i++) { write8(out, c1 = hio_read8(in)); if (c1 > pat_max) pat_max = c1; } for (; i < 128; i++) write8(out, 0); write32b(out, PW_MOD_MAGIC); /* write ptk ID */ hio_read32b(in); /* bypass "SONG" chunk */ for (i = 0; i <= pat_max; i++) /* pattern data */ pw_move_data(out, in, 1024); hio_read32b(in); /* bypass "SAMP" chunk */ pw_move_data(out, in, ssize); /* sample data */ return 0; } static int test_fcm(uint8 *data, char *t, int s) { int j; PW_REQUEST_DATA(s, 37 + 8 * 31); /* "FC-M" : ID of FC-M packer */ if (data[0] != 'F' || data[1] != 'C' || data[2] != '-' || data[3] != 'M') return -1; /* test 1 */ if (data[4] != 0x01) return -1; /* test 2 */ if (data[5] != 0x00) return -1; /* test 3 */ for (j = 0; j < 31; j++) { if (data[37 + 8 * j] > 0x40) return -1; } pw_read_title(data + 10, t, 20); return 0; } const struct pw_format pw_fcm = { "FC-M Packer", test_fcm, depack_fcm }; libxmp-4.4.1/src/loaders/prowizard/eureka.c0000664000175000017500000000733512706551122020531 0ustar claudioclaudio/* * EurekaPacker.c Copyright (C) 1997 Asle / ReDoX * * Converts MODs packed with Eureka packer back to ptk * * Modified in 2006,2007,2014 by Claudio Matsuoka */ #include #include #include "prowiz.h" static int depack_eu(HIO_HANDLE *in, FILE *out) { uint8 tmp[1080]; uint8 c1; int npat, smp_addr; int ssize = 0; int trk_addr[128][4]; int i, j, k; /* read header ... same as ptk */ hio_read(tmp, 1080, 1, in); fwrite(tmp, 1080, 1, out); /* now, let's sort out that a bit :) */ /* first, the whole sample size */ for (i = 0; i < 31; i++) ssize += 2 * readmem16b(tmp + i * 30 + 42); /* now, the pattern list .. and the max */ for (npat = i = 0; i < 128; i++) { if (tmp[952 + i] > npat) npat = tmp[952 + i]; } npat++; write32b(out, PW_MOD_MAGIC); /* write ptk ID */ smp_addr = hio_read32b(in); /* read sample data address */ /* read tracks addresses */ for (i = 0; i < npat; i++) { for (j = 0; j < 4; j++) trk_addr[i][j] = hio_read16b(in); } /* the track data now ... */ for (i = 0; i < npat; i++) { memset(tmp, 0, 1024); for (j = 0; j < 4; j++) { hio_seek(in, trk_addr[i][j], SEEK_SET); for (k = 0; k < 64; k++) { uint8 *x = &tmp[k * 16 + j * 4]; c1 = hio_read8(in); if ((c1 & 0xc0) == 0x00) { *x++ = c1; *x++ = hio_read8(in); *x++ = hio_read8(in); *x++ = hio_read8(in); continue; } if ((c1 & 0xc0) == 0xc0) { k += (c1 & 0x3f); continue; } if ((c1 & 0xc0) == 0x40) { x += 2; *x++ = c1 & 0x0f; *x++ = hio_read8(in); continue; } if ((c1 & 0xc0) == 0x80) { *x++ = hio_read8(in); *x++ = hio_read8(in); *x++ = (c1 << 4) & 0xf0; continue; } } } fwrite(tmp, 1024, 1, out); } hio_seek(in, smp_addr, SEEK_SET); pw_move_data(out, in, ssize); return 0; } static int test_eu(uint8 *data, char *t, int s) { int i; int len, max_pat, smp_offs; int max_trk, min_trk; PW_REQUEST_DATA(s, 1084); /* test 2 */ len = data[950]; if (len == 0 || len > 127) return -1; /* test #3 finetunes & volumes */ for (i = 0; i < 31; i++) { uint8 *d = data + i * 30; int size = readmem16b(d + 42) << 1; int start = readmem16b(d + 46) << 1; int lsize = readmem16b(d + 48) << 1; if (size > 0xffff || start > 0xffff || lsize > 0xffff) return -1; if (start + lsize > size + 2) return -1; if (d[44] > 0x0f || d[45] > 0x40) return -1; } /* test 4 */ smp_offs = readmem32b(data + 1080); #if 0 if (smp_offs > in_size) return -1; #endif if (smp_offs < 1084) return -1; /* pattern list */ max_pat = 0; for (i = 0; i < len; i++) { int pat = data[952 + i]; if (pat > 127) return -1; if (pat > max_pat) max_pat = pat; } for (/*i += 2*/; i < 128; i++) { if (data[952 + i] != 0) return -1; } max_pat++; /* test #5 */ /* max_trkptr is the highest track address */ /* min_trkptr is the lowest track address */ max_trk = 0; min_trk = 999999; PW_REQUEST_DATA(s, max_pat * 4 * 2 + 1085); for (i = 0; i < (max_pat * 4); i++) { int trk = readmem16b(data + i * 2 + 1084); if (trk > smp_offs || trk < 1084) return -1; if (trk > max_trk) max_trk = trk; if (trk < min_trk) min_trk = trk; } /* test track datas */ /* last track wont be tested ... */ for (i = min_trk; i < max_trk; i++) { if ((data[i] & 0xc0) == 0xc0) continue; if ((data[i] & 0xc0) == 0x80) { i += 2; continue; } if ((data[i] & 0xc0) == 0x40) { if ((data[i] & 0x3f) == 0 && data[i + 1] == 0) return -1; i++; continue; } if ((data[i] & 0xc0) == 0) { if (data[i] > 0x13) return -1; i += 3; continue; } } pw_read_title(data, t, 20); return 0; } const struct pw_format pw_eu = { "Eureka Packer", test_eu, depack_eu }; libxmp-4.4.1/src/loaders/gal5_load.c0000664000175000017500000002204012775035311017054 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "loader.h" #include "iff.h" #include "period.h" /* Galaxy Music System 5.0 module file loader * * Based on the format description by Dr.Eggman * (http://www.jazz2online.com/J2Ov2/articles/view.php?articleID=288) * and Jazz Jackrabbit modules by Alexander Brandon from Lori Central * (http://www.loricentral.com/jj2music.html) */ static int gal5_test(HIO_HANDLE *, char *, const int); static int gal5_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_gal5 = { "Galaxy Music System 5.0 (J2B)", gal5_test, gal5_load }; struct local_data { uint8 chn_pan[64]; }; static int gal5_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC4('R', 'I', 'F', 'F')) return -1; hio_read32b(f); if (hio_read32b(f) != MAGIC4('A', 'M', ' ', ' ')) return -1; if (hio_read32b(f) != MAGIC4('I', 'N', 'I', 'T')) return -1; hio_read32b(f); /* skip size */ libxmp_read_title(f, t, 64); return 0; } static int get_init(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; char buf[64]; int flags; hio_read(buf, 1, 64, f); strncpy(mod->name, buf, 63); /* ensure string terminator */ libxmp_set_type(m, "Galaxy Music System 5.0"); flags = hio_read8(f); /* bit 0: Amiga period */ if (~flags & 0x01) m->period_type = PERIOD_LINEAR; mod->chn = hio_read8(f); mod->spd = hio_read8(f); mod->bpm = hio_read8(f); hio_read16l(f); /* unknown - 0x01c5 */ hio_read16l(f); /* unknown - 0xff00 */ hio_read8(f); /* unknown - 0x80 */ hio_read(data->chn_pan, 1, 64, f); return 0; } static int get_ordr(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; mod->len = hio_read8(f) + 1; /* Don't follow Dr.Eggman's specs here */ for (i = 0; i < mod->len; i++) mod->xxo[i] = hio_read8(f); return 0; } static int get_patt_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; i = hio_read8(f) + 1; /* pattern number */ if (i > mod->pat) mod->pat = i; return 0; } static int get_inst_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; hio_read32b(f); /* 42 01 00 00 */ hio_read8(f); /* 00 */ i = hio_read8(f) + 1; /* instrument number */ if (i > mod->ins) mod->ins = i; return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct xmp_event *event, dummy; int i, len, chan; int rows, r; uint8 flag; i = hio_read8(f); /* pattern number */ len = hio_read32l(f); rows = hio_read8(f) + 1; if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; for (r = 0; r < rows; ) { if ((flag = hio_read8(f)) == 0) { r++; continue; } chan = flag & 0x1f; event = chan < mod->chn ? &EVENT(i, chan, r) : &dummy; if (flag & 0x80) { uint8 fxp = hio_read8(f); uint8 fxt = hio_read8(f); switch (fxt) { case 0x14: /* speed */ fxt = FX_S3M_SPEED; break; default: if (fxt > 0x0f) { printf("unknown effect %02x %02x\n", fxt, fxp); fxt = fxp = 0; } } event->fxt = fxt; event->fxp = fxp; } if (flag & 0x40) { event->ins = hio_read8(f); event->note = hio_read8(f); if (event->note == 128) { event->note = XMP_KEY_OFF; } } if (flag & 0x20) { event->vol = 1 + hio_read8(f) / 2; } } return 0; } static int get_inst(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, srate, finetune, flags; int has_unsigned_sample; hio_read32b(f); /* 42 01 00 00 */ hio_read8(f); /* 00 */ i = hio_read8(f); /* instrument number */ hio_read(&mod->xxi[i].name, 1, 28, f); hio_seek(f, 290, SEEK_CUR); /* Sample/note map, envelopes */ mod->xxi[i].nsm = hio_read16l(f); D_(D_INFO "[%2X] %-28.28s %2d ", i, mod->xxi[i].name, mod->xxi[i].nsm); if (mod->xxi[i].nsm == 0) return 0; if (libxmp_alloc_subinstrument(mod, i, mod->xxi[i].nsm) < 0) return -1; /* FIXME: Currently reading only the first sample */ hio_read32b(f); /* RIFF */ hio_read32b(f); /* size */ hio_read32b(f); /* AS */ hio_read32b(f); /* SAMP */ hio_read32b(f); /* size */ hio_read32b(f); /* unknown - usually 0x40000000 */ hio_read(&mod->xxs[i].name, 1, 28, f); hio_read32b(f); /* unknown - 0x0000 */ hio_read8(f); /* unknown - 0x00 */ mod->xxi[i].sub[0].sid = i; mod->xxi[i].vol = hio_read8(f); mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].vol = (hio_read16l(f) + 1) / 512; flags = hio_read16l(f); hio_read16l(f); /* unknown - 0x0080 */ mod->xxs[i].len = hio_read32l(f); mod->xxs[i].lps = hio_read32l(f); mod->xxs[i].lpe = hio_read32l(f); mod->xxs[i].flg = 0; has_unsigned_sample = 0; if (flags & 0x04) mod->xxs[i].flg |= XMP_SAMPLE_16BIT; if (flags & 0x08) mod->xxs[i].flg |= XMP_SAMPLE_LOOP; if (flags & 0x10) mod->xxs[i].flg |= XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR; if (~flags & 0x80) has_unsigned_sample = 1; srate = hio_read32l(f); finetune = 0; libxmp_c2spd_to_note(srate, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); mod->xxi[i].sub[0].fin += finetune; hio_read32l(f); /* 0x00000000 */ hio_read32l(f); /* unknown */ D_(D_INFO " %x: %05x%c%05x %05x %c V%02x %04x %5d", 0, mod->xxs[i].len, mod->xxs[i].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, flags, srate); if (mod->xxs[i].len > 1) { if (libxmp_load_sample(m, f, has_unsigned_sample ? SAMPLE_FLAG_UNS : 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } static int gal5_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; iff_handle handle; int i, ret, offset; struct local_data data; LOAD_INIT(); hio_read32b(f); /* Skip RIFF */ hio_read32b(f); /* Skip size */ hio_read32b(f); /* Skip AM */ offset = hio_tell(f); mod->smp = mod->ins = 0; handle = libxmp_iff_new(); if (handle == NULL) return -1; m->c4rate = C4_NTSC_RATE; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "INIT", get_init); /* Galaxy 5.0 */ ret |= libxmp_iff_register(handle, "ORDR", get_ordr); ret |= libxmp_iff_register(handle, "PATT", get_patt_cnt); ret |= libxmp_iff_register(handle, "INST", get_inst_cnt); if (ret != 0) return -1; libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); libxmp_iff_set_quirk(handle, IFF_SKIP_EMBEDDED); libxmp_iff_set_quirk(handle, IFF_CHUNK_ALIGN2); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); mod->trk = mod->pat * mod->chn; mod->smp = mod->ins; MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); D_(D_INFO "Stored samples: %d ", mod->smp); hio_seek(f, start + offset, SEEK_SET); handle = libxmp_iff_new(); if (handle == NULL) return -1; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "PATT", get_patt); ret |= libxmp_iff_register(handle, "INST", get_inst); if (ret != 0) return -1; libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); libxmp_iff_set_quirk(handle, IFF_SKIP_EMBEDDED); libxmp_iff_set_quirk(handle, IFF_CHUNK_ALIGN2); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); /* Alloc missing patterns */ for (i = 0; i < mod->pat; i++) { if (mod->xxp[i] == NULL) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) { return -1; } } } for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = data.chn_pan[i] * 2; } m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; return 0; } libxmp-4.4.1/src/loaders/stm_load.c0000664000175000017500000002022712774567167017056 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "period.h" #define STM_TYPE_SONG 0x01 #define STM_TYPE_MODULE 0x02 struct stm_instrument_header { uint8 name[12]; /* ASCIIZ instrument name */ uint8 id; /* Id=0 */ uint8 idisk; /* Instrument disk */ uint16 rsvd1; /* Reserved */ uint16 length; /* Sample length */ uint16 loopbeg; /* Loop begin */ uint16 loopend; /* Loop end */ uint8 volume; /* Playback volume */ uint8 rsvd2; /* Reserved */ uint16 c2spd; /* C4 speed */ uint32 rsvd3; /* Reserved */ uint16 paralen; /* Length in paragraphs */ }; struct stm_file_header { uint8 name[20]; /* ASCIIZ song name */ uint8 magic[8]; /* '!Scream!' */ uint8 rsvd1; /* '\x1a' */ uint8 type; /* 1=song, 2=module */ uint8 vermaj; /* Major version number */ uint8 vermin; /* Minor version number */ uint8 tempo; /* Playback tempo */ uint8 patterns; /* Number of patterns */ uint8 gvol; /* Global volume */ uint8 rsvd2[13]; /* Reserved */ struct stm_instrument_header ins[31]; }; static int stm_test(HIO_HANDLE *, char *, const int); static int stm_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_stm = { "Scream Tracker 2", stm_test, stm_load }; static int stm_test(HIO_HANDLE * f, char *t, const int start) { char buf[8]; hio_seek(f, start + 20, SEEK_SET); if (hio_read(buf, 1, 8, f) < 8) return -1; if (memcmp(buf, "!Scream!", 8) && memcmp(buf, "BMOD2STM", 8)) return -1; hio_read8(f); if (hio_read8(f) != STM_TYPE_MODULE) return -1; if (hio_read8(f) < 1) /* We don't want STX files */ return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } #define FX_NONE 0xff /* * Skaven's note from http://www.futurecrew.com/skaven/oldies_music.html * * FYI for the tech-heads: In the old Scream Tracker 2 the Arpeggio command * (Jxx), if used in a single row with a 0x value, caused the note to skip * the specified amount of halftones upwards halfway through the row. I used * this in some songs to give the lead some character. However, when played * in ModPlug Tracker, this effect doesn't work the way it did back then. */ static const uint8 fx[] = { FX_NONE, FX_SPEED, /* A - Set tempo to [INFO]. 60 normal. */ FX_JUMP, /* B - Break pattern and jmp to order [INFO] */ FX_BREAK, /* C - Break pattern */ FX_VOLSLIDE, /* D - Slide volume; Hi-nibble=up, Lo-nibble=down */ FX_PORTA_DN, /* E - Slide down at speed [INFO] */ FX_PORTA_UP, /* F - Slide up at speed [INFO] */ FX_TONEPORTA, /* G - Slide to the note specified at speed [INFO] */ FX_VIBRATO, /* H - Vibrato; Hi-nibble, speed. Lo-nibble, size */ FX_TREMOR, /* I - Tremor; Hi-nibble, ontime. Lo-nibble, offtime */ FX_ARPEGGIO /* J - Arpeggio */ }; static int stm_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct stm_file_header sfh; uint8 b; int bmod2stm = 0; LOAD_INIT(); hio_read(&sfh.name, 20, 1, f); /* ASCIIZ song name */ hio_read(&sfh.magic, 8, 1, f); /* '!Scream!' */ sfh.rsvd1 = hio_read8(f); /* '\x1a' */ sfh.type = hio_read8(f); /* 1=song, 2=module */ sfh.vermaj = hio_read8(f); /* Major version number */ sfh.vermin = hio_read8(f); /* Minor version number */ sfh.tempo = hio_read8(f); /* Playback tempo */ sfh.patterns = hio_read8(f); /* Number of patterns */ sfh.gvol = hio_read8(f); /* Global volume */ hio_read(&sfh.rsvd2, 13, 1, f); /* Reserved */ for (i = 0; i < 31; i++) { hio_read(&sfh.ins[i].name, 12, 1, f); /* Instrument name */ sfh.ins[i].id = hio_read8(f); /* Id=0 */ sfh.ins[i].idisk = hio_read8(f); /* Instrument disk */ sfh.ins[i].rsvd1 = hio_read16l(f); /* Reserved */ sfh.ins[i].length = hio_read16l(f); /* Sample length */ sfh.ins[i].loopbeg = hio_read16l(f); /* Loop begin */ sfh.ins[i].loopend = hio_read16l(f); /* Loop end */ sfh.ins[i].volume = hio_read8(f); /* Playback volume */ sfh.ins[i].rsvd2 = hio_read8(f); /* Reserved */ sfh.ins[i].c2spd = hio_read16l(f); /* C4 speed */ sfh.ins[i].rsvd3 = hio_read32l(f); /* Reserved */ sfh.ins[i].paralen = hio_read16l(f); /* Length in paragraphs */ } if (hio_error(f)) { return -1; } if (!strncmp((char *)sfh.magic, "BMOD2STM", 8)) bmod2stm = 1; mod->chn = 4; mod->pat = sfh.patterns; mod->trk = mod->pat * mod->chn; mod->spd = MSN(sfh.tempo); mod->ins = 31; mod->smp = mod->ins; m->c4rate = C4_NTSC_RATE; libxmp_copy_adjust(mod->name, sfh.name, 20); if (bmod2stm) { snprintf(mod->type, XMP_NAME_SIZE, "BMOD2STM STM"); } else { snprintf(mod->type, XMP_NAME_SIZE, "Scream Tracker %d.%02d STM", sfh.vermaj, sfh.vermin); } MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; /* Read and convert instruments and samples */ for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; mod->xxs[i].len = sfh.ins[i].length; mod->xxs[i].lps = sfh.ins[i].loopbeg; mod->xxs[i].lpe = sfh.ins[i].loopend; if (mod->xxs[i].lpe == 0xffff) mod->xxs[i].lpe = 0; mod->xxs[i].flg = mod->xxs[i].lpe > 0 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].vol = sfh.ins[i].volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; libxmp_instrument_name(mod, i, sfh.ins[i].name, 12); D_(D_INFO "[%2X] %-14.14s %04x %04x %04x %c V%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, sfh.ins[i].c2spd); libxmp_c2spd_to_note(sfh.ins[i].c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); } hio_read(mod->xxo, 1, 128, f); for (i = 0; i < 128; i++) if (mod->xxo[i] >= mod->pat) break; mod->len = i; D_(D_INFO "Module length: %d", mod->len); if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < 64 * mod->chn; j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); b = hio_read8(f); memset(event, 0, sizeof(struct xmp_event)); switch (b) { case 251: case 252: case 253: break; case 255: default: event->note = b == 255 ? 0 : 1 + LSN(b) + 12 * (3 + MSN(b)); b = hio_read8(f); event->vol = b & 0x07; event->ins = (b & 0xf8) >> 3; b = hio_read8(f); event->vol += (b & 0xf0) >> 1; if (event->vol > 0x40) event->vol = 0; else event->vol++; event->fxt = fx[LSN(b)]; event->fxp = hio_read8(f); switch (event->fxt) { case FX_SPEED: event->fxp = MSN(event->fxp); break; case FX_NONE: event->fxp = event->fxt = 0; break; } } } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len > 1) { if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } else { mod->xxi[i].nsm = 0; } } m->quirk |= QUIRK_VSALL | QUIRKS_ST3; m->read_event_type = READ_EVENT_ST3; return 0; } libxmp-4.4.1/src/loaders/ims_load.c0000664000175000017500000001721612774567167017047 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Loader for Images Music System modules based on the EP replayer. * * Date: Thu, 19 Apr 2001 19:13:06 +0200 * From: Michael Doering * * I just "stumbled" upon something about the Unic.3C format when I was * testing replayers for the upcoming UADE 0.21 that might be also * interesting to you for xmp. The "Beastbusters" tune is not a UNIC file :) * It's actually a different Format, although obviously related, called * "Images Music System". * * I was testing the replayer from the Wanted Team with one of their test * tunes, among them also the beastbuster music. When I first listened to * it, I knew I have heard it somewhere, a bit different but it was alike. * This one had more/richer percussions and there was no strange beep in * the bg. ;) After some searching on my HD I found it among the xmp test * tunes as a UNIC file. */ #include #include #include "loader.h" #include "period.h" struct ims_instrument { uint8 name[20]; int16 finetune; /* Causes squeaks in beast-busters1! */ uint16 size; uint8 unknown; uint8 volume; uint16 loop_start; uint16 loop_size; }; struct ims_header { uint8 title[20]; struct ims_instrument ins[31]; uint8 len; uint8 zero; uint8 orders[128]; uint8 magic[4]; }; static int ims_test (HIO_HANDLE *, char *, const int); static int ims_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_ims = { "Images Music System", ims_test, ims_load }; static int ims_test(HIO_HANDLE *f, char *t, const int start) { int i; int smp_size, pat; struct ims_header ih; smp_size = 0; hio_read(&ih.title, 20, 1, f); for (i = 0; i < 31; i++) { if (hio_read(&ih.ins[i].name, 1, 20, f) < 20) return -1; ih.ins[i].finetune = (int16)hio_read16b(f); ih.ins[i].size = hio_read16b(f); ih.ins[i].unknown = hio_read8(f); ih.ins[i].volume = hio_read8(f); ih.ins[i].loop_start = hio_read16b(f); ih.ins[i].loop_size = hio_read16b(f); smp_size += ih.ins[i].size * 2; if (libxmp_test_name(ih.ins[i].name, 20) < 0) return -1; if (ih.ins[i].volume > 0x40) return -1; if (ih.ins[i].size > 0x8000) return -1; if (ih.ins[i].loop_start > ih.ins[i].size) return -1; if (ih.ins[i].size && ih.ins[i].loop_size > 2 * ih.ins[i].size) return -1; } if (smp_size < 8) return -1; ih.len = hio_read8(f); ih.zero = hio_read8(f); hio_read(&ih.orders, 128, 1, f); hio_read(&ih.magic, 4, 1, f); if (ih.zero > 1) /* not sure what this is */ return -1; if (ih.magic[3] != 0x3c) return -1; if (ih.len > 0x7f) return -1; for (pat = i = 0; i < ih.len; i++) if (ih.orders[i] > pat) pat = ih.orders[i]; pat++; if (pat > 0x7f || ih.len == 0 || ih.len > 0x7f) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } static int ims_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; int smp_size; struct xmp_event *event; struct ims_header ih; uint8 ims_event[3]; int xpo = 21; /* Tuned against UADE */ LOAD_INIT(); mod->chn = 4; mod->ins = 31; mod->smp = mod->ins; smp_size = 0; hio_read (&ih.title, 20, 1, f); for (i = 0; i < 31; i++) { hio_read (&ih.ins[i].name, 20, 1, f); ih.ins[i].finetune = (int16)hio_read16b(f); ih.ins[i].size = hio_read16b(f); ih.ins[i].unknown = hio_read8(f); ih.ins[i].volume = hio_read8(f); ih.ins[i].loop_start = hio_read16b(f); ih.ins[i].loop_size = hio_read16b(f); smp_size += ih.ins[i].size * 2; } ih.len = hio_read8(f); if (ih.len > 128) { return -1; } ih.zero = hio_read8(f); hio_read (&ih.orders, 128, 1, f); hio_read (&ih.magic, 4, 1, f); mod->len = ih.len; memcpy (mod->xxo, ih.orders, mod->len); for (i = 0; i < mod->len; i++) if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; mod->pat++; mod->trk = mod->chn * mod->pat; strncpy(mod->name, (char *)ih.title, 20); libxmp_set_type(m, "Images Music System"); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi; struct xmp_subinstrument *sub; struct xmp_sample *xxs; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; xxi = &mod->xxi[i]; sub = &xxi->sub[0]; xxs = &mod->xxs[i]; xxs->len = 2 * ih.ins[i].size; xxs->lps = 2 * ih.ins[i].loop_start; xxs->lpe = xxs->lps + 2 * ih.ins[i].loop_size; xxs->flg = ih.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; sub->fin = 0; /* ih.ins[i].finetune; */ sub->vol = ih.ins[i].volume; sub->pan = 0x80; sub->sid = i; //mod->xxi[i].rls = 0xfff; if (xxs->len > 0) { xxi->nsm = 1; } libxmp_instrument_name(mod, i, ih.ins[i].name, 20); D_(D_INFO "[%2X] %-20.20s %04x %04x %04x %c V%02x %+d", i, xxi->name, xxs->len, xxs->lps, xxs->lpe, ih.ins[i].loop_size > 1 ? 'L' : ' ', sub->vol, sub->fin >> 4); } if (libxmp_init_pattern(mod) < 0) { return -1; } /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < 0x100; j++) { event = &EVENT (i, j & 0x3, j >> 2); hio_read(ims_event, 1, 3, f); /* Event format: * * 0000 0000 0000 0000 0000 0000 * |\ / \ / \ / \ / * | note ins fx parameter * ins * * 0x3f is a blank note. */ event->note = ims_event[0] & 0x3f; if (event->note != 0x00 && event->note != 0x3f) event->note += xpo + 12; else event->note = 0; event->ins = ((ims_event[0] & 0x40) >> 2) | MSN(ims_event[1]); event->fxt = LSN(ims_event[1]); event->fxp = ims_event[2]; libxmp_disable_continue_fx (event); /* According to Asle: * ``Just note that pattern break effect command (D**) uses * HEX value in UNIC format (while it is DEC values in PTK). * Thus, it has to be converted!'' * * Is this valid for IMS as well? --claudio */ if (event->fxt == 0x0d) event->fxp = (event->fxp / 10) << 4 | (event->fxp % 10); } } m->period_type = PERIOD_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (!mod->xxs[i].len) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/stx_load.c0000664000175000017500000002332412774567167017072 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* From the STMIK 0.2 documentation: * * "The STMIK uses a special [Scream Tracker] beta-V3.0 module format. * Due to the module formats beta nature, the current STMIK uses a .STX * extension instead of the normal .STM. I'm not intending to do a * STX->STM converter, so treat STX as the format to be used in finished * programs, NOT as a format to be used in distributing modules. A program * called STM2STX is included, and it'll convert STM modules to the STX * format for usage in your own programs." * * Tested using "Future Brain" from Mental Surgery by Future Crew and * STMs converted with STM2STX. */ #include "loader.h" #include "s3m.h" #include "period.h" struct stx_file_header { uint8 name[20]; /* Song name */ uint8 magic[8]; /* !Scream! */ uint16 psize; /* Pattern 0 size? */ uint16 unknown1; /* ??!? */ uint16 pp_pat; /* Pointer to pattern table */ uint16 pp_ins; /* Pattern to instrument table */ uint16 pp_chn; /* Pointer to channel table (?) */ uint16 unknown2; uint16 unknown3; uint8 gvol; /* Global volume */ uint8 tempo; /* Playback tempo */ uint16 unknown4; uint16 unknown5; uint16 patnum; /* Number of patterns */ uint16 insnum; /* Number of instruments */ uint16 ordnum; /* Number of orders */ uint16 unknown6; /* Flags? */ uint16 unknown7; /* Version? */ uint16 unknown8; /* Ffi? */ uint8 magic2[4]; /* 'SCRM' */ }; struct stx_instrument_header { uint8 type; /* Instrument type */ uint8 dosname[13]; /* DOS file name */ uint16 memseg; /* Pointer to sample data */ uint32 length; /* Length */ uint32 loopbeg; /* Loop begin */ uint32 loopend; /* Loop end */ uint8 vol; /* Volume */ uint8 rsvd1; /* Reserved */ uint8 pack; /* Packing type (not used) */ uint8 flags; /* Loop/stereo/16bit samples flags */ uint16 c2spd; /* C 4 speed */ uint16 rsvd2; /* Reserved */ uint8 rsvd3[4]; /* Reserved */ uint16 int_gp; /* Internal - GUS pointer */ uint16 int_512; /* Internal - SB pointer */ uint32 int_last; /* Internal - SB index */ uint8 name[28]; /* Instrument name */ uint8 magic[4]; /* Reserved (for 'SCRS') */ }; static int stx_test(HIO_HANDLE *, char *, const int); static int stx_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_stx = { "STMIK 0.2", stx_test, stx_load }; static int stx_test(HIO_HANDLE * f, char *t, const int start) { char buf[8]; hio_seek(f, start + 20, SEEK_SET); if (hio_read(buf, 1, 8, f) < 8) return -1; if (memcmp(buf, "!Scream!", 8) && memcmp(buf, "BMOD2STM", 8)) return -1; hio_seek(f, start + 60, SEEK_SET); if (hio_read(buf, 1, 4, f) < 4) return -1; if (memcmp(buf, "SCRM", 4)) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } #define FX_NONE 0xff static const uint8 fx[] = { FX_NONE, FX_SPEED, FX_JUMP, FX_BREAK, FX_VOLSLIDE, FX_PORTA_DN, FX_PORTA_UP, FX_TONEPORTA, FX_VIBRATO, FX_TREMOR, FX_ARPEGGIO }; static int stx_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int c, r, i, broken = 0; struct xmp_event *event = 0, dummy; struct stx_file_header sfh; struct stx_instrument_header sih; uint8 n, b; uint16 x16; int bmod2stm = 0; uint16 *pp_ins; /* Parapointers to instruments */ uint16 *pp_pat; /* Parapointers to patterns */ LOAD_INIT(); hio_read(&sfh.name, 20, 1, f); hio_read(&sfh.magic, 8, 1, f); sfh.psize = hio_read16l(f); sfh.unknown1 = hio_read16l(f); sfh.pp_pat = hio_read16l(f); sfh.pp_ins = hio_read16l(f); sfh.pp_chn = hio_read16l(f); sfh.unknown2 = hio_read16l(f); sfh.unknown3 = hio_read16l(f); sfh.gvol = hio_read8(f); sfh.tempo = hio_read8(f); sfh.unknown4 = hio_read16l(f); sfh.unknown5 = hio_read16l(f); sfh.patnum = hio_read16l(f); sfh.insnum = hio_read16l(f); sfh.ordnum = hio_read16l(f); sfh.unknown6 = hio_read16l(f); sfh.unknown7 = hio_read16l(f); sfh.unknown8 = hio_read16l(f); hio_read(&sfh.magic2, 4, 1, f); /* Sanity check */ if (sfh.patnum > 254 || sfh.insnum > 256 || sfh.ordnum > 256) return -1; /* BMOD2STM does not convert pitch */ if (!strncmp((char *)sfh.magic, "BMOD2STM", 8)) bmod2stm = 1; #if 0 if ((strncmp((char *)sfh.magic, "!Scream!", 8) && !bmod2stm) || strncmp((char *)sfh.magic2, "SCRM", 4)) return -1; #endif mod->ins = sfh.insnum; mod->pat = sfh.patnum; mod->trk = mod->pat * mod->chn; mod->len = sfh.ordnum; mod->spd = MSN(sfh.tempo); mod->smp = mod->ins; m->c4rate = C4_NTSC_RATE; /* STM2STX 1.0 released with STMIK 0.2 converts STMs with the pattern * length encoded in the first two bytes of the pattern (like S3M). */ hio_seek(f, start + (sfh.pp_pat << 4), SEEK_SET); x16 = hio_read16l(f); hio_seek(f, start + (x16 << 4), SEEK_SET); x16 = hio_read16l(f); if (x16 == sfh.psize) broken = 1; strncpy(mod->name, (char *)sfh.name, 20); if (bmod2stm) libxmp_set_type(m, "BMOD2STM STX"); else snprintf(mod->type, XMP_NAME_SIZE, "STM2STX 1.%d", broken ? 0 : 1); MODULE_INFO(); pp_pat = calloc(2, mod->pat); if (pp_pat == NULL) goto err; pp_ins = calloc(2, mod->ins); if (pp_ins == NULL) goto err2; /* Read pattern pointers */ hio_seek(f, start + (sfh.pp_pat << 4), SEEK_SET); for (i = 0; i < mod->pat; i++) pp_pat[i] = hio_read16l(f); /* Read instrument pointers */ hio_seek(f, start + (sfh.pp_ins << 4), SEEK_SET); for (i = 0; i < mod->ins; i++) pp_ins[i] = hio_read16l(f); /* Skip channel table (?) */ hio_seek(f, start + (sfh.pp_chn << 4) + 32, SEEK_SET); /* Read orders */ for (i = 0; i < mod->len; i++) { mod->xxo[i] = hio_read8(f); hio_seek(f, 4, SEEK_CUR); } if (libxmp_init_instrument(m) < 0) goto err3; /* Read and convert instruments and samples */ for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) goto err3; hio_seek(f, start + (pp_ins[i] << 4), SEEK_SET); sih.type = hio_read8(f); hio_read(&sih.dosname, 13, 1, f); sih.memseg = hio_read16l(f); sih.length = hio_read32l(f); sih.loopbeg = hio_read32l(f); sih.loopend = hio_read32l(f); sih.vol = hio_read8(f); sih.rsvd1 = hio_read8(f); sih.pack = hio_read8(f); sih.flags = hio_read8(f); sih.c2spd = hio_read16l(f); sih.rsvd2 = hio_read16l(f); hio_read(&sih.rsvd3, 4, 1, f); sih.int_gp = hio_read16l(f); sih.int_512 = hio_read16l(f); sih.int_last = hio_read32l(f); hio_read(&sih.name, 28, 1, f); hio_read(&sih.magic, 4, 1, f); mod->xxs[i].len = sih.length; mod->xxs[i].lps = sih.loopbeg; mod->xxs[i].lpe = sih.loopend; if (mod->xxs[i].lpe == 0xffff) mod->xxs[i].lpe = 0; mod->xxs[i].flg = mod->xxs[i].lpe > 0 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].vol = sih.vol; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].nsm = 1; libxmp_instrument_name(mod, i, sih.name, 12); D_(D_INFO "[%2X] %-14.14s %04x %04x %04x %c V%02x %5d\n", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, sih.c2spd); libxmp_c2spd_to_note(sih.c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); } if (libxmp_init_pattern(mod) < 0) goto err3; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) goto err3; if (pp_pat[i] == 0) continue; hio_seek(f, start + (pp_pat[i] << 4), SEEK_SET); if (broken) hio_seek(f, 2, SEEK_CUR); for (r = 0; r < 64;) { b = hio_read8(f); if (b == S3M_EOR) { r++; continue; } c = b & S3M_CH_MASK; event = c >= mod->chn ? &dummy : &EVENT(i, c, r); if (b & S3M_NI_FOLLOW) { n = hio_read8(f); switch (n) { case 255: n = 0; break; /* Empty note */ case 254: n = XMP_KEY_OFF; break; /* Key off */ default: n = 37 + 12 * MSN(n) + LSN(n); } event->note = n; event->ins = hio_read8(f);; } if (b & S3M_VOL_FOLLOWS) { event->vol = hio_read8(f) + 1; } if (b & S3M_FX_FOLLOWS) { int t = hio_read8(f); int p = hio_read8(f); if (t <= 10) { event->fxt = fx[t]; event->fxp = p; switch (event->fxt) { case FX_SPEED: event->fxp = MSN(event->fxp); break; case FX_NONE: event->fxp = event->fxt = 0; break; } } } } } free(pp_ins); free(pp_pat); /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) goto err; } m->quirk |= QUIRK_VSALL | QUIRKS_ST3; m->read_event_type = READ_EVENT_ST3; return 0; err3: free(pp_ins); err2: free(pp_pat); err: return -1; } libxmp-4.4.1/src/loaders/stim_load.c0000664000175000017500000001274512774567167017235 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Loader for Slamtilt modules based on the format description * written by Sylvain Chipaux (Asle/ReDoX). Get the Slamtilt demo * from game/demo in Aminet. */ /* Tested with the Slamtilt modules sent by Sipos Attila */ #include "loader.h" #define MAGIC_STIM MAGIC4('S','T','I','M') static int stim_test(HIO_HANDLE *, char *, const int); static int stim_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_stim = { "Slamtilt", stim_test, stim_load }; static int stim_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_STIM) return -1; if (hio_read16b(f) > 16) return -1; libxmp_read_title(f, t, 0); return 0; } struct stim_instrument { uint16 size; /* Lenght of the sample (/2) */ uint8 finetune; /* Finetune (as ptk) */ uint8 volume; /* Volume (as ptk) */ uint16 loop_start; /* Loop start (/2) */ uint16 loop_size; /* Loop lenght (/2) */ }; struct stim_header { uint32 id; /* "STIM" ID string */ uint32 smpaddr; /* Address of the sample descriptions */ uint32 unknown[2]; uint16 nos; /* Number of samples (?) */ uint16 len; /* Size of pattern list */ uint16 pat; /* Number of patterns saved */ uint8 order[128]; /* Pattern list */ uint32 pataddr[64]; /* Pattern addresses (add 0xc) */ }; static int stim_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k; struct xmp_event *event; struct stim_header sh; struct stim_instrument si; uint8 b1, b2, b3; LOAD_INIT(); sh.id = hio_read32b(f); sh.smpaddr = hio_read32b(f); hio_read32b(f); hio_read32b(f); sh.nos = hio_read16b(f); sh.len = hio_read16b(f); sh.pat = hio_read16b(f); hio_read(&sh.order, 128, 1, f); /* Sanity check */ if (sh.nos > 31 || sh.len > 128 || sh.pat > 64) { return -1; } for (i = 0; i < 64; i++) { sh.pataddr[i] = hio_read32b(f) + 0x0c; if (sh.pataddr[i] > 0x00100000) return -1; } mod->chn = 4; mod->len = sh.len; mod->pat = sh.pat; mod->ins = sh.nos; mod->smp = mod->ins; mod->trk = mod->pat * mod->chn; for (i = 0; i < mod->len; i++) mod->xxo[i] = sh.order[i]; libxmp_set_type(m, "Slamtilt"); MODULE_INFO(); if (libxmp_init_pattern(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; hio_seek(f, start + sh.pataddr[i] + 8, SEEK_SET); for (j = 0; j < 4; j++) { for (k = 0; k < 64; k++) { event = &EVENT(i, j, k); b1 = hio_read8(f); if (b1 & 0x80) { k += b1 & 0x7f; continue; } /* STIM event format: * * __ Fx __ * / \ * || || * 0000 0000 0000 0000 0000 0000 * | | | | | | | * | \ / \ / \ / * | smp note Fx Val * | * Description bit set to 0. */ b2 = hio_read8(f); b3 = hio_read8(f); if ((event->note = b2 & 0x3f) != 0) event->note += 47; event->ins = b1 & 0x1f; event->fxt = ((b2 >> 4) & 0x0c) | (b1 >> 5); event->fxp = b3; libxmp_disable_continue_fx(event); } } } if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Stored samples: %d", mod->smp); hio_seek(f, start + sh.smpaddr + mod->smp * 4, SEEK_SET); for (i = 0; i < mod->smp; i++) { si.size = hio_read16b(f); si.finetune = hio_read8(f); si.volume = hio_read8(f); si.loop_start = hio_read16b(f); si.loop_size = hio_read16b(f); if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; mod->xxs[i].len = 2 * si.size; mod->xxs[i].lps = 2 * si.loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * si.loop_size; mod->xxs[i].flg = si.loop_size > 1 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].fin = (int8) (si.finetune << 4); mod->xxi[i].sub[0].vol = si.volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].rls = 0xfff; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; D_(D_INFO "[%2X] %04x %04x %04x %c V%02x %+d", i, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, si.loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); if (!mod->xxs[i].len) continue; if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } m->period_type = PERIOD_MODRNG; return 0; } libxmp-4.4.1/src/loaders/emod_load.c0000664000175000017500000001271412775035311017157 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "loader.h" #include "iff.h" #define MAGIC_FORM MAGIC4('F','O','R','M') #define MAGIC_EMOD MAGIC4('E','M','O','D') #define MAGIC_EMIC MAGIC4('E','M','I','C') static int emod_test(HIO_HANDLE *, char *, const int); static int emod_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_emod = { "Quadra Composer", emod_test, emod_load }; static int emod_test(HIO_HANDLE * f, char *t, const int start) { if (hio_read32b(f) != MAGIC_FORM) return -1; hio_read32b(f); if (hio_read32b(f) != MAGIC_EMOD) return -1; if (hio_read32b(f) == MAGIC_EMIC) { hio_read32b(f); /* skip size */ hio_read16b(f); /* skip version */ libxmp_read_title(f, t, 20); } else { libxmp_read_title(f, t, 0); } return 0; } static int get_emic(struct module_data *m, int size, HIO_HANDLE * f, void *parm) { struct xmp_module *mod = &m->mod; int i, ver; uint8 reorder[256]; ver = hio_read16b(f); hio_read(mod->name, 1, 20, f); hio_seek(f, 20, SEEK_CUR); mod->bpm = hio_read8(f); mod->ins = hio_read8(f); mod->smp = mod->ins; m->period_type = PERIOD_MODRNG; snprintf(mod->type, XMP_NAME_SIZE, "Quadra Composer EMOD v%d", ver); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; hio_read8(f); /* num */ sub->vol = hio_read8(f); xxs->len = 2 * hio_read16b(f); hio_read(xxi->name, 1, 20, f); xxs->flg = hio_read8(f) & 1 ? XMP_SAMPLE_LOOP : 0; sub->fin = hio_read8s(f) << 4; xxs->lps = 2 * hio_read16b(f); xxs->lpe = xxs->lps + 2 * hio_read16b(f); hio_read32b(f); /* ptr */ xxi->nsm = 1; sub->pan = 0x80; sub->sid = i; D_(D_INFO "[%2X] %-20.20s %05x %05x %05x %c V%02x %+d", i, xxi->name, xxs->len, xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->fin >> 4); } hio_read8(f); /* pad */ mod->pat = hio_read8(f); mod->trk = mod->pat * mod->chn; if (libxmp_init_pattern(mod) < 0) return -1; memset(reorder, 0, 256); for (i = 0; i < mod->pat; i++) { reorder[hio_read8(f)] = i; if (libxmp_alloc_pattern_tracks(mod, i, hio_read8(f) + 1) < 0) return -1; hio_seek(f, 20, SEEK_CUR); /* skip name */ hio_read32b(f); /* ptr */ } mod->len = hio_read8(f); D_(D_INFO "Module length: %d", mod->len); for (i = 0; i < mod->len; i++) mod->xxo[i] = reorder[hio_read8(f)]; return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE * f, void *parm) { struct xmp_module *mod = &m->mod; struct xmp_event *event; int i, j, k; uint8 x; D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { for (j = 0; j < mod->xxp[i]->rows; j++) { for (k = 0; k < mod->chn; k++) { event = &EVENT(i, k, j); event->ins = hio_read8(f); event->note = hio_read8(f) + 1; if (event->note != 0) event->note += 48; event->fxt = hio_read8(f) & 0x0f; event->fxp = hio_read8(f); /* Fix effects */ switch (event->fxt) { case 0x04: x = event->fxp; event->fxp = (x & 0xf0) | ((x << 1) & 0x0f); break; case 0x09: event->fxt <<= 1; break; case 0x0b: x = event->fxt; event->fxt = 16 * (x / 10) + x % 10; break; } } } } return 0; } static int get_8smp(struct module_data *m, int size, HIO_HANDLE * f, void *parm) { struct xmp_module *mod = &m->mod; int i; D_(D_INFO "Stored samples : %d ", mod->smp); for (i = 0; i < mod->smp; i++) { if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } static int emod_load(struct module_data *m, HIO_HANDLE * f, const int start) { iff_handle handle; int ret; LOAD_INIT(); hio_read32b(f); /* FORM */ hio_read32b(f); hio_read32b(f); /* EMOD */ handle = libxmp_iff_new(); if (handle == NULL) return -1; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "EMIC", get_emic); ret |= libxmp_iff_register(handle, "PATT", get_patt); ret |= libxmp_iff_register(handle, "8SMP", get_8smp); if (ret != 0) return -1; /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, NULL) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); return 0; } libxmp-4.4.1/src/loaders/amf_load.c0000664000175000017500000002655612774567167017031 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* AMF loader written based on the format specs by Miodrag Vallat with * fixes by Andre Timmermans. * * The AMF format is the internal format used by DSMI, the DOS Sound and Music * Interface, which is the engine of DMP. As DMP was able to play more and more * module formats, the format evolved to support more features. There were 5 * official formats, numbered from 10 (AMF 1.0) to 14 (AMF 1.4). */ #include "loader.h" #include "period.h" static int amf_test(HIO_HANDLE *, char *, const int); static int amf_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_amf = { "DSMI Advanced Module Format", amf_test, amf_load }; static int amf_test(HIO_HANDLE * f, char *t, const int start) { char buf[4]; int ver; if (hio_read(buf, 1, 3, f) < 3) return -1; if (buf[0] != 'A' || buf[1] != 'M' || buf[2] != 'F') return -1; ver = hio_read8(f); if (ver < 0x0a || ver > 0x0e) return -1; libxmp_read_title(f, t, 32); return 0; } static int amf_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; uint8 buf[1024]; int *trkmap, newtrk; int ver; LOAD_INIT(); hio_read(buf, 1, 3, f); ver = hio_read8(f); hio_read(buf, 1, 32, f); strncpy(mod->name, (char *)buf, 32); libxmp_set_type(m, "DSMI %d.%d AMF", ver / 10, ver % 10); mod->ins = hio_read8(f); mod->len = hio_read8(f); mod->trk = hio_read16l(f); mod->chn = hio_read8(f); /* Sanity check */ if (mod->ins == 0 || mod->len == 0 || mod->trk == 0 || mod->chn == 0 || mod->chn > XMP_MAX_CHANNELS) { return -1; } mod->smp = mod->ins; mod->pat = mod->len; if (ver == 0x0a) hio_read(buf, 1, 16, f); /* channel remap table */ if (ver >= 0x0d) { hio_read(buf, 1, 32, f); /* panning table */ for (i = 0; i < 32; i++) { mod->xxc->pan = 0x80 + 2 * (int8)buf[i]; } mod->bpm = hio_read8(f); mod->spd = hio_read8(f); } else if (ver >= 0x0b) { hio_read(buf, 1, 16, f); } m->c4rate = C4_NTSC_RATE; MODULE_INFO(); /* Orders */ /* * Andre Timmermans says: * * Order table: track numbers in this table are not explained, * but as you noticed you have to perform -1 to obtain the index * in the track table. For value 0, found in some files, I think * it means an empty track. */ for (i = 0; i < mod->len; i++) mod->xxo[i] = i; D_(D_INFO "Stored patterns: %d", mod->pat); mod->xxp = calloc(sizeof(struct xmp_pattern *), mod->pat); if (mod->xxp == NULL) return -1; for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern(mod, i) < 0) return -1; mod->xxp[i]->rows = ver >= 0x0e ? hio_read16l(f) : 64; if (mod->xxp[i]->rows > 256) return -1; for (j = 0; j < mod->chn; j++) { uint16 t = hio_read16l(f); mod->xxp[i]->index[j] = t; } } /* Instruments */ if (libxmp_init_instrument(m) < 0) return -1; /* Probe for 2-byte loop start 1.0 format * in facing_n.amf and sweetdrm.amf have only the sample * loop start specified in 2 bytes */ if (ver <= 0x0a) { uint8 b; uint32 len, start, end; long pos = hio_tell(f); if (pos < 0) { return -1; } for (i = 0; i < mod->ins; i++) { b = hio_read8(f); if (b != 0 && b != 1) { ver = 0x09; break; } hio_seek(f, 32 + 13, SEEK_CUR); if (hio_read32l(f) > 0x100000) { /* check index */ ver = 0x09; break; } len = hio_read32l(f); if (len > 0x100000) { /* check len */ ver = 0x09; break; } if (hio_read16l(f) == 0x0000) { /* check c2spd */ ver = 0x09; break; } if (hio_read8(f) > 0x40) { /* check volume */ ver = 0x09; break; } start = hio_read32l(f); if (start > len) { /* check loop start */ ver = 0x09; break; } end = hio_read32l(f); if (end > len) { /* check loop end */ ver = 0x09; break; } } hio_seek(f, pos, SEEK_SET); } for (i = 0; i < mod->ins; i++) { /*uint8 b;*/ int c2spd; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; /*b =*/ hio_read8(f); hio_read(buf, 1, 32, f); libxmp_instrument_name(mod, i, buf, 32); hio_read(buf, 1, 13, f); /* sample name */ hio_read32l(f); /* sample index */ mod->xxi[i].nsm = 1; mod->xxi[i].sub[0].sid = i; mod->xxi[i].sub[0].pan = 0x80; mod->xxs[i].len = hio_read32l(f); c2spd = hio_read16l(f); libxmp_c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); mod->xxi[i].sub[0].vol = hio_read8(f); /* * Andre Timmermans says: * * [Miodrag Vallat's] doc tells that in version 1.0 only * sample loop start is present (2 bytes) but the files I * have tells both start and end are present (2*4 bytes). * Maybe it should be read as version < 1.0. * * CM: confirmed with Maelcum's "The tribal zone" */ if (ver < 0x0a) { mod->xxs[i].lps = hio_read16l(f); mod->xxs[i].lpe = mod->xxs[i].len; } else { mod->xxs[i].lps = hio_read32l(f); mod->xxs[i].lpe = hio_read32l(f); } if (ver < 0x0a) { mod->xxs[i].flg = mod->xxs[i].lps > 0 ? XMP_SAMPLE_LOOP : 0; } else { mod->xxs[i].flg = mod->xxs[i].lpe > mod->xxs[i].lps ? XMP_SAMPLE_LOOP : 0; } D_(D_INFO "[%2X] %-32.32s %05x %05x %05x %c V%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, c2spd); } /* Tracks */ trkmap = calloc(sizeof(int), mod->trk); if (trkmap == NULL) return -1; newtrk = 0; for (i = 0; i < mod->trk; i++) { /* read track table */ uint16 t; t = hio_read16l(f); trkmap[i] = t; if (t > newtrk) newtrk = t; } for (i = 0; i < mod->pat; i++) { /* read track table */ for (j = 0; j < mod->chn; j++) { int k = mod->xxp[i]->index[j] - 1; /* Use empty track if an invalid track is requested * (such as in Lasse Makkonen "faster and louder") */ if (k < 0 || k >= mod->trk) k = 0; mod->xxp[i]->index[j] = trkmap[k]; } } mod->trk = newtrk; /* + empty track */ free(trkmap); D_(D_INFO "Stored tracks: %d", mod->trk); mod->trk++; mod->xxt = calloc (sizeof (struct xmp_track *), mod->trk); if (mod->xxt == NULL) return -1; /* Alloc track 0 as empty track */ if (libxmp_alloc_track(mod, 0, 64) < 0) return -1; /* Alloc rest of the tracks */ for (i = 1; i < mod->trk; i++) { uint8 t1, t2, t3; int size; if (libxmp_alloc_track(mod, i, 64) < 0) /* FIXME! */ return -1; size = hio_read24l(f); for (j = 0; j < size; j++) { t1 = hio_read8(f); /* row */ t2 = hio_read8(f); /* type */ t3 = hio_read8(f); /* parameter */ if (t1 == 0xff && t2 == 0xff && t3 == 0xff) break; /* Sanity check */ if (t1 >= mod->xxt[i]->rows) return -1; event = &mod->xxt[i]->event[t1]; if (t2 < 0x7f) { /* note */ if (t2 > 0) event->note = t2 + 1; event->vol = t3; } else if (t2 == 0x7f) { /* copy previous */ /* Sanity check */ if (t1 == 0) { return -1; } memcpy(event, &mod->xxt[i]->event[t1 - 1], sizeof(struct xmp_event)); } else if (t2 == 0x80) { /* instrument */ event->ins = t3 + 1; } else { /* effects */ uint8 fxp, fxt; fxp = fxt = 0; switch (t2) { case 0x81: fxt = FX_SPEED; fxp = t3; break; case 0x82: if ((int8)t3 > 0) { fxt = FX_VOLSLIDE; fxp = t3 << 4; } else { fxt = FX_VOLSLIDE; fxp = -(int8)t3 & 0x0f; } break; case 0x83: event->vol = t3; break; case 0x84: /* AT: Not explained for 0x84, pitch * slide, value 0x00 corresponds to * S3M E00 and 0x80 stands for S3M F00 * (I checked with M2AMF) */ if ((int8)t3 >= 0) { fxt = FX_PORTA_DN; fxp = t3; } else if (t3 == 0x80) { fxt = FX_PORTA_UP; fxp = 0; } else { fxt = FX_PORTA_UP; fxp = -(int8)t3; } break; case 0x85: /* porta abs -- unknown */ break; case 0x86: fxt = FX_TONEPORTA; fxp = t3; break; /* AT: M2AMF maps both tremolo and tremor to * 0x87. Since tremor is only found in certain * formats, maybe it would be better to * consider it is a tremolo. */ case 0x87: fxt = FX_TREMOLO; fxp = t3; break; case 0x88: fxt = FX_ARPEGGIO; fxp = t3; break; case 0x89: fxt = FX_VIBRATO; fxp = t3; break; case 0x8a: if ((int8)t3 > 0) { fxt = FX_TONE_VSLIDE; fxp = t3 << 4; } else { fxt = FX_TONE_VSLIDE; fxp = -(int8)t3 & 0x0f; } break; case 0x8b: if ((int8)t3 > 0) { fxt = FX_VIBRA_VSLIDE; fxp = t3 << 4; } else { fxt = FX_VIBRA_VSLIDE; fxp = -(int8)t3 & 0x0f; } break; case 0x8c: fxt = FX_BREAK; fxp = t3; break; case 0x8d: fxt = FX_JUMP; fxp = t3; break; case 0x8e: /* sync -- unknown */ break; case 0x8f: fxt = FX_EXTENDED; fxp = (EX_RETRIG << 4) | (t3 & 0x0f); break; case 0x90: fxt = FX_OFFSET; fxp = t3; break; case 0x91: if ((int8)t3 > 0) { fxt = FX_EXTENDED; fxp = (EX_F_VSLIDE_UP << 4) | (t3 & 0x0f); } else { fxt = FX_EXTENDED; fxp = (EX_F_VSLIDE_DN << 4) | (t3 & 0x0f); } break; case 0x92: if ((int8)t3 > 0) { fxt = FX_PORTA_DN; fxp = 0xf0 | (fxp & 0x0f); } else { fxt = FX_PORTA_UP; fxp = 0xf0 | (fxp & 0x0f); } break; case 0x93: fxt = FX_EXTENDED; fxp = (EX_DELAY << 4) | (t3 & 0x0f); break; case 0x94: fxt = FX_EXTENDED; fxp = (EX_CUT << 4) | (t3 & 0x0f); break; case 0x95: fxt = FX_SPEED; if (t3 < 0x21) t3 = 0x21; fxp = t3; break; case 0x96: if ((int8)t3 > 0) { fxt = FX_PORTA_DN; fxp = 0xe0 | (fxp & 0x0f); } else { fxt = FX_PORTA_UP; fxp = 0xe0 | (fxp & 0x0f); } break; case 0x97: fxt = FX_SETPAN; fxp = 0x80 + 2 * (int8)t3; break; } event->fxt = fxt; event->fxp = fxp; } } } /* Samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0) return -1; } m->quirk |= QUIRK_FINEFX; return 0; } libxmp-4.4.1/src/loaders/sym_load.c0000664000175000017500000002677212774567167017076 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "depackers/readlzw.h" static int sym_test(HIO_HANDLE *, char *, const int); static int sym_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_sym = { "Digital Symphony", sym_test, sym_load }; static int sym_test(HIO_HANDLE *f, char *t, const int start) { uint32 a, b; int i, ver; /* Load from memory not supported until we handle sample depacking */ if (HIO_HANDLE_TYPE(f) != HIO_HANDLE_TYPE_FILE) return -1; a = hio_read32b(f); b = hio_read32b(f); if (a != 0x02011313 || b != 0x1412010B) /* BASSTRAK */ return -1; ver = hio_read8(f); /* v1 files are the same as v0 but may contain strange compression * formats. Deal with that problem later if it arises. */ if (ver > 1) { return -1; } hio_read8(f); /* chn */ hio_read16l(f); /* pat */ hio_read16l(f); /* trk */ hio_read24l(f); /* infolen */ for (i = 0; i < 63; i++) { if (~hio_read8(f) & 0x80) hio_read24l(f); } libxmp_read_title(f, t, hio_read8(f)); return 0; } static void fix_effect(struct xmp_event *e, int parm) { switch (e->fxt) { case 0x00: /* 00 xyz Normal play or Arpeggio + Volume Slide Up */ case 0x01: /* 01 xyy Slide Up + Volume Slide Up */ case 0x02: /* 01 xyy Slide Up + Volume Slide Up */ e->fxp = parm & 0xff; if (parm >> 8) { e->f2t = FX_VOLSLIDE_UP; e->f2p = parm >> 8; } break; case 0x03: /* 03 xyy Tone Portamento */ case 0x04: /* 04 xyz Vibrato */ case 0x07: /* 07 xyz Tremolo */ e->fxp = parm; break; case 0x05: /* 05 xyz Tone Portamento + Volume Slide */ case 0x06: /* 06 xyz Vibrato + Volume Slide */ e->fxp = parm; if (!parm) e->fxt -= 2; break; case 0x09: /* 09 xxx Set Sample Offset */ e->fxp = parm >> 1; break; case 0x0a: /* 0A xyz Volume Slide + Fine Slide Up */ if (parm & 0xff) { e->fxp = parm & 0xff; } else { e->fxt = 0; } e->f2t = FX_EXTENDED; e->f2p = (EX_F_PORTA_UP << 4) | ((parm & 0xf00) >> 8); break; case 0x0b: /* 0B xxx Position Jump */ case 0x0c: /* 0C xyy Set Volume */ case 0x0d: /* 0D xyy Pattern Break */ case 0x0f: /* 0F xxx Set Speed */ e->fxp = parm; break; case 0x13: /* 13 xxy Glissando Control */ e->fxt = FX_EXTENDED; e->fxp = (EX_GLISS << 4) | (parm & 0x0f); break; case 0x14: /* 14 xxy Set Vibrato Waveform */ e->fxt = FX_EXTENDED; e->fxp = (EX_VIBRATO_WF << 4) | (parm & 0x0f); break; case 0x15: /* 15 xxy Set Fine Tune */ e->fxt = FX_EXTENDED; e->fxp = (EX_FINETUNE << 4) | (parm & 0x0f); break; case 0x16: /* 16 xxx Jump to Loop */ e->fxt = FX_EXTENDED; e->fxp = (EX_PATTERN_LOOP << 4) | (parm & 0x0f); break; case 0x17: /* 17 xxy Set Tremolo Waveform */ e->fxt = FX_EXTENDED; e->fxp = (EX_TREMOLO_WF << 4) | (parm & 0x0f); break; case 0x19: /* 19 xxx Retrig Note */ if (parm < 0x10) { e->fxt = FX_EXTENDED; e->fxp = (EX_RETRIG << 4) | (parm & 0x0f); } else { /* ignore */ e->fxt = 0; } break; case 0x11: /* 11 xyy Fine Slide Up + Fine Volume Slide Up */ case 0x12: /* 12 xyy Fine Slide Down + Fine Volume Slide Up */ case 0x1a: /* 1A xyy Fine Slide Up + Fine Volume Slide Down */ case 0x1b: /* 1B xyy Fine Slide Down + Fine Volume Slide Down */ { uint8 pitch_effect = ((e->fxt == 0x11 || e->fxt == 0x1a) ? EX_F_PORTA_UP : EX_F_PORTA_DN); uint8 vol_effect = ((e->fxt == 0x11 || e->fxt == 0x12) ? EX_F_VSLIDE_UP : EX_F_VSLIDE_DN); if ((parm & 0xff) && ((parm & 0xff) < 0x10)) { e->fxt = FX_EXTENDED; e->fxp = (pitch_effect << 4) | (parm & 0x0f); } else e->fxt = 0; if (parm >> 8) { e->f2t = FX_EXTENDED; e->f2p = (vol_effect << 4) | (parm >> 8); } break; } case 0x1c: /* 1C xxx Note Cut */ e->fxt = FX_EXTENDED; e->fxp = (EX_CUT << 4) | (parm & 0x0f); break; case 0x1d: /* 1D xxx Note Delay */ e->fxt = FX_EXTENDED; e->fxp = (EX_DELAY << 4) | (parm & 0x0f); break; case 0x1e: /* 1E xxx Pattern Delay */ e->fxt = FX_EXTENDED; e->fxp = (EX_PATT_DELAY << 4) | (parm & 0x0f); break; case 0x1f: /* 1F xxy Invert Loop */ e->fxt = 0; break; case 0x20: /* 20 xyz Normal play or Arpeggio + Volume Slide Down */ e->fxt = FX_ARPEGGIO; e->fxp = parm & 0xff; if (parm >> 8) { e->f2t = FX_VOLSLIDE_DN; e->f2p = parm >> 8; } break; case 0x21: /* 21 xyy Slide Up + Volume Slide Down */ e->fxt = FX_PORTA_UP; e->fxp = parm & 0xff; if (parm >> 8) { e->f2t = FX_VOLSLIDE_DN; e->f2p = parm >> 8; } break; case 0x22: /* 22 xyy Slide Down + Volume Slide Down */ e->fxt = FX_PORTA_DN; e->fxp = parm & 0xff; if (parm >> 8) { e->f2t = FX_VOLSLIDE_DN; e->f2p = parm >> 8; } break; case 0x2f: /* 2F xxx Set Tempo */ if (parm >= 0x100 && parm <= 0x800) { e->fxt = FX_SPEED; e->fxp = (parm+4) >> 3; /* round to nearest */ } else { /* umm... */ } break; case 0x2a: /* 2A xyz Volume Slide + Fine Slide Down */ case 0x2b: /* 2B xyy Line Jump */ case 0x30: /* 30 xxy Set Stereo */ case 0x31: /* 31 xxx Song Upcall */ case 0x32: /* 32 xxx Unset Sample Repeat */ default: e->fxt = 0; } } static uint32 readptr32l(uint8 *p) { uint32 a, b, c, d; a = *p++; b = *p++; c = *p++; d = *p++; return (d << 24) | (c << 16) | (b << 8) | a; } static uint32 readptr16l(uint8 *p) { uint32 a, b; a = *p++; b = *p++; return (b << 8) | a; } static int sym_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event; int i, j; int /*ver,*/ infolen, sn[64]; uint32 a, b; uint8 *buf; int size, ret; uint8 allowed_effects[8]; LOAD_INIT(); hio_seek(f, 8, SEEK_CUR); /* BASSTRAK */ /*ver =*/ hio_read8(f); libxmp_set_type(m, "Digital Symphony"); mod->chn = hio_read8(f); mod->len = mod->pat = hio_read16l(f); /* Sanity check */ if (mod->chn > 8 || mod->pat > 256) return -1; mod->trk = hio_read16l(f); /* Symphony patterns are actually tracks */ infolen = hio_read24l(f); mod->ins = mod->smp = 63; if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sn[i] = hio_read8(f); /* sample name length */ if (~sn[i] & 0x80) { mod->xxs[i].len = hio_read24l(f) << 1; mod->xxi[i].nsm = 1; /* Sanity check */ if (mod->xxs[i].len > 0x80000) return -1; } } a = hio_read8(f); /* track name length */ if (a > 32) { hio_read(mod->name, 1, 32, f); hio_seek(f, a - 32, SEEK_SET); } else { hio_read(mod->name, 1, a, f); } hio_read(&allowed_effects, 1, 8, f); MODULE_INFO(); mod->trk++; /* alloc extra empty track */ if (libxmp_init_pattern(mod) < 0) return -1; /* Sequence */ a = hio_read8(f); /* packing */ if (a != 0 && a != 1) return -1; D_(D_INFO "Packed sequence: %s", a ? "yes" : "no"); size = mod->len * mod->chn * 2; if ((buf = malloc(size)) == NULL) return -1; if (a) { unsigned char *x = libxmp_read_lzw_dynamic(f->handle.file, buf, 13, 0, size, size, XMP_LZW_QUIRK_DSYM); if (x == NULL) { free(buf); return -1; } } else { if (hio_read(buf, 1, size, f) != size) { free(buf); return -1; } } for (i = 0; i < mod->len; i++) { /* len == pat */ if (libxmp_alloc_pattern(mod, i) < 0) { free(buf); return -1; } mod->xxp[i]->rows = 64; for (j = 0; j < mod->chn; j++) { int idx = 2 * (i * mod->chn + j); int t = readptr16l(&buf[idx]); /* Sanity check */ if (t >= mod->trk - 1) { free(buf); return -1; } if (t == 0x1000) /* empty trk */ t = mod->trk - 1; mod->xxp[i]->index[j] = t; } mod->xxo[i] = i; } free(buf); /* Read and convert patterns */ a = hio_read8(f); if (a != 0 && a != 1) return -1; D_(D_INFO "Packed tracks: %s", a ? "yes" : "no"); D_(D_INFO "Stored tracks: %d", mod->trk - 1); size = 64 * (mod->trk - 1) * 4; if ((buf = malloc(size)) == NULL) return -1; if (a) { unsigned char *x = libxmp_read_lzw_dynamic(f->handle.file, buf, 13, 0, size, size, XMP_LZW_QUIRK_DSYM); if (x == NULL) { free(buf); return -1; } } else { if (hio_read(buf, 1, size, f) != size) { free(buf); return -1; } } for (i = 0; i < mod->trk - 1; i++) { if (libxmp_alloc_track(mod, i, 64) < 0) { free(buf); return -1; } for (j = 0; j < mod->xxt[i]->rows; j++) { int parm; event = &mod->xxt[i]->event[j]; b = readptr32l(&buf[4 * (i * 64 + j)]); event->note = b & 0x0000003f; if (event->note) event->note += 48; event->ins = (b & 0x00001fc0) >> 6; event->fxt = (b & 0x000fc000) >> 14; parm = (b & 0xfff00000) >> 20; if (allowed_effects[event->fxt >> 3] & (1 << (event->fxt & 7))) { fix_effect(event, parm); } else { event->fxt = 0; } } } free(buf); /* Extra track */ if (libxmp_alloc_track(mod, i, 64) < 0) return -1; /* Load and convert instruments */ D_(D_INFO "Instruments: %d", mod->ins); for (i = 0; i < mod->ins; i++) { uint8 buf[128]; memset(buf, 0, 128); hio_read(buf, 1, sn[i] & 0x7f, f); libxmp_instrument_name(mod, i, buf, 32); if (~sn[i] & 0x80) { int looplen; mod->xxs[i].lps = hio_read24l(f) << 1; looplen = hio_read24l(f) << 1; if (looplen > 2) mod->xxs[i].flg |= XMP_SAMPLE_LOOP; mod->xxs[i].lpe = mod->xxs[i].lps + looplen; mod->xxi[i].sub[0].vol = hio_read8(f); mod->xxi[i].sub[0].pan = 0x80; /* finetune adjusted comparing DSym and S3M versions * of "inside out" */ mod->xxi[i].sub[0].fin = (int8)(hio_read8(f) << 4); mod->xxi[i].sub[0].sid = i; } D_(D_INFO "[%2X] %-22.22s %05x %05x %05x %c V%02x %+03d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin); if (sn[i] & 0x80 || mod->xxs[i].len == 0) continue; a = hio_read8(f); if (a != 0 && a != 1) { fprintf(stderr, "libxmp: unsupported sample type\n"); //return -1; } if (a == 1) { uint8 *b = malloc(mod->xxs[i].len); libxmp_read_lzw_dynamic(f->handle.file, b, 13, 0, mod->xxs[i].len, mod->xxs[i].len, XMP_LZW_QUIRK_DSYM); ret = libxmp_load_sample(m, NULL, SAMPLE_FLAG_NOLOAD | SAMPLE_FLAG_DIFF, &mod->xxs[i], (char*)b); free(b); /*} else if (a == 4) { ret = libxmp_load_sample(m, f, SAMPLE_FLAG_VIDC, &mod->xxs[i], NULL);*/ } else { ret = libxmp_load_sample(m, f, SAMPLE_FLAG_VIDC, &mod->xxs[i], NULL); } if (ret < 0) return -1; } for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = DEFPAN((((i + 3) / 2) % 2) * 0xff); } return 0; } libxmp-4.4.1/src/loaders/hmn_load.c0000664000175000017500000002205412775035311017013 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "mod.h" #include "period.h" #include "hmn_extras.h" /* * From http://www.livet.se/mahoney/: * * Most modules from His Master's Noise uses special chip-sounds or * fine-tuning of samples that never was a part of the standard NoiseTracker * v2.0 command set. So if you want to listen to them correctly use an Amiga * emulator and run the demo! DeliPlayer does a good job of playing them * (there are some occasional error mostly concerning vibrato and portamento * effects, but I can live with that!), and it can be downloaded from * http://www.deliplayer.com */ /* * From http://www.cactus.jawnet.pl/attitude/index.php?action=readtext&issue=12&which=12 * * [Bepp] For your final Amiga release, the music disk His Master's Noise, * you developed a special version of NoiseTracker. Could you tell us a * little about this project? * * [Mahoney] I wanted to make a music disk with loads of songs, without being * too repetitive or boring. So all of my "experimental features" that did not * belong to NoiseTracker v2.0 were put into a separate version that would * feature wavetable sounds, chord calculations, off-line filter calculations, * mixing, reversing, sample accurate delays, resampling, fades - calculations * that would be done on a standard setup of sounds instead of on individual * modules. This "compression technique" lead to some 100 songs fitting on two * standard 3.5" disks, written by 22 different composers. I'd say that writing * a music program does give you loads of talented friends - you should try * that yourself someday! */ /* * From: Pex Tufvesson * To: Claudio Matsuoka * Date: Sat, Jun 1, 2013 at 4:16 AM * Subject: Re: A question about (very) old stuff * * (...) * If I remember correctly, these chip sounds were done with several short * waveforms, and an index table that was loopable that would choose which * waveform to play each frame. And, you didn't have to "draw" every * waveform in the instrument - you would choose which waveforms to draw * and the replayer would (at startup) interpolate the waveforms that you * didn't draw. * * In the special noisetracker, you could draw all of these waveforms, draw * the index table, and the instrument would be stored in one of the * "patterns" of the song. */ static int hmn_test(HIO_HANDLE *, char *, const int); static int hmn_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_hmn = { "His Master's Noise", hmn_test, hmn_load }; /* His Master's Noise M&K! will fail in regular Noisetracker loading * due to invalid finetune values. */ #define MAGIC_FEST MAGIC4('F', 'E', 'S', 'T') #define MAGIC_MK MAGIC4('M', '&', 'K', '!') static int hmn_test(HIO_HANDLE * f, char *t, const int start) { int magic; hio_seek(f, start + 1080, SEEK_SET); magic = hio_read32b(f); if (magic != MAGIC_FEST && magic != MAGIC_MK) return -1; hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } struct mupp { uint8 prgon; uint8 pattno; uint8 dataloopstart; uint8 dataloopend; }; static int hmn_load(struct module_data *m, HIO_HANDLE * f, const int start) { struct xmp_module *mod = &m->mod; int i, j; struct xmp_event *event; struct mod_header mh; struct mupp mupp[31]; uint8 mod_event[4]; int mupp_index, num_mupp; LOAD_INIT(); /* * clr.b $1c(a6) ;prog on/off * CMP.L #'Mupp',-$16(a3,d4.l) * bne.s noprgo * move.l a0,-(a7) * move.b #1,$1c(a6) ;prog on * move.l l697,a0 * lea $43c(a0),a0 * moveq #0,d2 * move.b -$16+$4(a3,d4.l),d2 ;pattno * mulu #$400,d2 * lea (a0,d2.l),a0 * move.l a0,4(a6) ;proginstr data-start * moveq #0,d2 * MOVE.B $3C0(A0),$12(A6) * AND.B #$7F,$12(A6) * move.b $380(a0),d2 * mulu #$20,d2 * lea (a0,d2.w),a0 * move.l a0,$a(a6) ;loopstartmempoi = startmempoi * move.B $3(a3,d4.l),$13(a6) ;volume * move.b -$16+$5(a3,d4.l),8(a6) ;dataloopstart * move.b -$16+$6(a3,d4.l),9(a6) ;dataloopend * move.w #$10,$e(a6) ;looplen * move.l (a7)+,a0 * MOVE.W $12(A6),(A2) * AND.W #$FF,(A2) * BRA.S L505_LQ */ /* * Wavetable structure is 22 * 32 byte waveforms and 32 byte * wave control data with looping. */ memset(mupp, 0, 31 * sizeof (struct mupp)); hio_read(&mh.name, 20, 1, f); num_mupp = 0; for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); /* Instrument name */ if (memcmp(mh.ins[i].name, "Mupp", 4) == 0) { mupp[i].prgon = 1; mupp[i].pattno = mh.ins[i].name[4]; mupp[i].dataloopstart = mh.ins[i].name[5]; mupp[i].dataloopend = mh.ins[i].name[6]; num_mupp++; } mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); hio_read(&mh.magic, 4, 1, f); mod->chn = 4; mod->ins = 31; mod->smp = mod->ins + 28 * num_mupp; mod->len = mh.len; mod->rst = mh.restart; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; mod->trk = mod->chn * mod->pat; if (libxmp_hmn_new_module_extras(m) != 0) return -1; strncpy(mod->name, (char *)mh.name, 20); libxmp_set_type(m, "%s (%4.4s)", "His Master's Noise", mh.magic); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { if (mupp[i].prgon) { mod->xxi[i].nsm = 28; snprintf(mod->xxi[i].name, 32, "Mupp %02x %02x %02x", mupp[i].pattno, mupp[i].dataloopstart, mupp[i].dataloopend); if (libxmp_hmn_new_instrument_extras(&mod->xxi[i]) != 0) return -1; } else { mod->xxi[i].nsm = 1; libxmp_instrument_name(mod, i, mh.ins[i].name, 22); mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; mod->xxs[i].flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; } if (libxmp_alloc_subinstrument(mod, i, mod->xxi[i].nsm) < 0) return -1; for (j = 0; j < mod->xxi[i].nsm; j++) { mod->xxi[i].sub[j].fin = -(int8)(mh.ins[i].finetune << 3); mod->xxi[i].sub[j].vol = mh.ins[i].volume; mod->xxi[i].sub[j].pan = 0x80; mod->xxi[i].sub[j].sid = i; } } if (libxmp_init_pattern(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, j % 4, j / 4); hio_read(mod_event, 1, 4, f); libxmp_decode_protracker_event(event, mod_event); switch (event->fxt) { case 0x07: event->fxt = FX_MEGAARP; break; case 0x08: case 0x09: case 0x0e: event->fxt = event->fxp = 0; break; } } } m->period_type = PERIOD_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < 31; i++) { if (libxmp_load_sample(m, f, SAMPLE_FLAG_FULLREP, &mod->xxs[i], NULL) < 0) { return -1; } } /* Load Mupp samples */ mupp_index = 0; for (i = 0; i < 31; i ++) { struct hmn_instrument_extras *extra = (struct hmn_instrument_extras *)mod->xxi[i].extra; if (!mupp[i].prgon) continue; hio_seek(f, start + 1084 + 1024 * mupp[i].pattno, SEEK_SET); for (j = 0; j < 28; j++) { int k = 31 + 28 * mupp_index + j; mod->xxi[i].sub[j].sid = k; mod->xxs[k].len = 32; mod->xxs[k].lps = 0; mod->xxs[k].lpe = 32; mod->xxs[k].flg = XMP_SAMPLE_LOOP; if (libxmp_load_sample(m, f, 0, &mod->xxs[k], NULL) < 0) return -1; } extra->dataloopstart = mupp[i].dataloopstart; extra->dataloopend = mupp[i].dataloopend; hio_read(extra->data, 1, 64, f); hio_read(extra->progvolume, 1, 64, f); mupp_index++; } return 0; } libxmp-4.4.1/src/loaders/s3m.h0000664000175000017500000001004412773463501015741 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* S3M packed pattern macros */ #define S3M_EOR 0 /* End of row */ #define S3M_CH_MASK 0x1f /* Channel */ #define S3M_NI_FOLLOW 0x20 /* Note and instrument follow */ #define S3M_VOL_FOLLOWS 0x40 /* Volume follows */ #define S3M_FX_FOLLOWS 0x80 /* Effect and parameter follow */ /* S3M channel info macros */ #define S3M_CH_ON 0x80 /* Psi says it's bit 8, I'll assume bit 7 */ #define S3M_CH_OFF 0xff #define S3M_CH_PAN 0x7f /* Left/Right */ /* S3M channel pan macros */ #define S3M_PAN_SET 0x20 #define S3M_PAN_MASK 0x0f /* S3M flags */ #define S3M_ST2_VIB 0x01 /* Not recognized */ #define S3M_ST2_TEMPO 0x02 /* Not recognized */ #define S3M_AMIGA_SLIDE 0x04 /* Not recognized */ #define S3M_VOL_OPT 0x08 /* Not recognized */ #define S3M_AMIGA_RANGE 0x10 #define S3M_SB_FILTER 0x20 /* Not recognized */ #define S3M_ST300_VOLS 0x40 #define S3M_CUSTOM_DATA 0x80 /* Not recognized */ /* S3M Adlib instrument types */ #define S3M_INST_SAMPLE 0x01 #define S3M_INST_AMEL 0x02 #define S3M_INST_ABD 0x03 #define S3M_INST_ASNARE 0x04 #define S3M_INST_ATOM 0x05 #define S3M_INST_ACYM 0x06 #define S3M_INST_AHIHAT 0x07 struct s3m_file_header { uint8 name[28]; /* Song name */ uint8 doseof; /* 0x1a */ uint8 type; /* File type */ uint8 rsvd1[2]; /* Reserved */ uint16 ordnum; /* Number of orders (must be even) */ uint16 insnum; /* Number of instruments */ uint16 patnum; /* Number of patterns */ uint16 flags; /* Flags */ uint16 version; /* Tracker ID and version */ uint16 ffi; /* File format information */ uint32 magic; /* 'SCRM' */ uint8 gv; /* Global volume */ uint8 is; /* Initial speed */ uint8 it; /* Initial tempo */ uint8 mv; /* Master volume */ uint8 uc; /* Ultra click removal */ uint8 dp; /* Default pan positions if 0xfc */ uint8 rsvd2[8]; /* Reserved */ uint16 special; /* Ptr to special custom data */ uint8 chset[32]; /* Channel settings */ }; struct s3m_instrument_header { uint8 dosname[13]; /* DOS file name */ uint16 memseg; /* Pointer to sample data */ uint32 length; /* Length */ uint32 loopbeg; /* Loop begin */ uint32 loopend; /* Loop end */ uint8 vol; /* Volume */ uint8 rsvd1; /* Reserved */ uint8 pack; /* Packing type (not used) */ uint8 flags; /* Loop/stereo/16bit samples flags */ uint16 c2spd; /* C 4 speed */ uint16 rsvd2; /* Reserved */ uint8 rsvd3[4]; /* Reserved */ uint16 int_gp; /* Internal - GUS pointer */ uint16 int_512; /* Internal - SB pointer */ uint32 int_last; /* Internal - SB index */ uint8 name[28]; /* Instrument name */ uint32 magic; /* 'SCRS' */ }; #ifndef LIBXMP_CORE_PLAYER struct s3m_adlib_header { uint8 dosname[12]; /* DOS file name */ uint8 rsvd1[3]; /* 0x00 0x00 0x00 */ uint8 reg[12]; /* Adlib registers */ uint8 vol; uint8 dsk; uint8 rsvd2[2]; uint16 c2spd; /* C 4 speed */ uint16 rsvd3; /* Reserved */ uint8 rsvd4[12]; /* Reserved */ uint8 name[28]; /* Instrument name */ uint32 magic; /* 'SCRI' */ }; #endif libxmp-4.4.1/src/loaders/gdm_load.c0000664000175000017500000001770312774567167017027 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Based on the GDM (General Digital Music) version 1.0 File Format * Specification - Revision 2 by MenTaLguY */ #include "loader.h" #include "period.h" #define MAGIC_GDM MAGIC4('G','D','M',0xfe) #define MAGIC_GMFS MAGIC4('G','M','F','S') static int gdm_test(HIO_HANDLE *, char *, const int); static int gdm_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_gdm = { "Generic Digital Music", gdm_test, gdm_load }; static int gdm_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_GDM) return -1; hio_seek(f, start + 0x47, SEEK_SET); if (hio_read32b(f) != MAGIC_GMFS) return -1; hio_seek(f, start + 4, SEEK_SET); libxmp_read_title(f, t, 32); return 0; } void fix_effect(uint8 *fxt, uint8 *fxp) { switch (*fxt) { case 0x00: /* no effect */ *fxp = 0; break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: /* same as protracker */ break; case 0x08: *fxt = FX_TREMOR; break; case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* same as protracker */ break; case 0x10: /* arpeggio */ *fxt = FX_S3M_ARPEGGIO; break; case 0x11: /* set internal flag */ *fxt = *fxp = 0; break; case 0x12: *fxt = FX_MULTI_RETRIG; break; case 0x13: *fxt = FX_GLOBALVOL; break; case 0x14: *fxt = FX_FINE_VIBRATO; break; case 0x1e: /* special misc */ *fxt = *fxp = 0; break; case 0x1f: *fxt = FX_S3M_BPM; break; default: *fxt = *fxp = 0; } } static int gdm_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event; int vermaj, vermin, tvmaj, tvmin, tracker; int /*origfmt,*/ ord_ofs, pat_ofs, ins_ofs, smp_ofs; uint8 buffer[32], panmap[32]; int i; LOAD_INIT(); hio_read32b(f); /* skip magic */ hio_read(mod->name, 1, 32, f); hio_seek(f, 32, SEEK_CUR); /* skip author */ hio_seek(f, 7, SEEK_CUR); vermaj = hio_read8(f); vermin = hio_read8(f); tracker = hio_read16l(f); tvmaj = hio_read8(f); tvmin = hio_read8(f); if (tracker == 0) { libxmp_set_type(m, "GDM %d.%02d (2GDM %d.%02d)", vermaj, vermin, tvmaj, tvmin); } else { libxmp_set_type(m, "GDM %d.%02d (unknown tracker %d.%02d)", vermaj, vermin, tvmaj, tvmin); } hio_read(panmap, 32, 1, f); for (i = 0; i < 32; i++) { if (panmap[i] == 255) { panmap[i] = 8; mod->xxc[i].vol = 0; mod->xxc[i].flg |= XMP_CHANNEL_MUTE; } else if (panmap[i] == 16) { panmap[i] = 8; } mod->xxc[i].pan = 0x80 + (panmap[i] - 8) * 16; } mod->gvl = hio_read8(f); mod->spd = hio_read8(f); mod->bpm = hio_read8(f); /*origfmt =*/ hio_read16l(f); ord_ofs = hio_read32l(f); mod->len = hio_read8(f) + 1; pat_ofs = hio_read32l(f); mod->pat = hio_read8(f) + 1; ins_ofs = hio_read32l(f); smp_ofs = hio_read32l(f); mod->ins = mod->smp = hio_read8(f) + 1; m->c4rate = C4_NTSC_RATE; MODULE_INFO(); hio_seek(f, start + ord_ofs, SEEK_SET); for (i = 0; i < mod->len; i++) mod->xxo[i] = hio_read8(f); /* Read instrument data */ hio_seek(f, start + ins_ofs, SEEK_SET); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { int flg, c4spd, vol, pan; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; if (hio_read(buffer, 1, 32, f) != 32) return -1; libxmp_instrument_name(mod, i, buffer, 32); hio_seek(f, 12, SEEK_CUR); /* skip filename */ hio_read8(f); /* skip EMS handle */ mod->xxs[i].len = hio_read32l(f); mod->xxs[i].lps = hio_read32l(f); mod->xxs[i].lpe = hio_read32l(f); flg = hio_read8(f); c4spd = hio_read16l(f); vol = hio_read8(f); pan = hio_read8(f); mod->xxi[i].sub[0].vol = vol > 0x40 ? 0x40 : vol; mod->xxi[i].sub[0].pan = pan > 15 ? 0x80 : 0x80 + (pan - 8) * 16; libxmp_c2spd_to_note(c4spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); mod->xxi[i].sub[0].sid = i; mod->xxs[i].flg = 0; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; if (flg & 0x01) { mod->xxs[i].flg |= XMP_SAMPLE_LOOP; } if (flg & 0x02) { mod->xxs[i].flg |= XMP_SAMPLE_16BIT; mod->xxs[i].len >>= 1; mod->xxs[i].lps >>= 1; mod->xxs[i].lpe >>= 1; } D_(D_INFO "[%2X] %-32.32s %05x%c%05x %05x %c V%02x P%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].pan, c4spd); } /* Read and convert patterns */ hio_seek(f, start + pat_ofs, SEEK_SET); /* Effects in muted channels are processed, so scan patterns first to * see the real number of channels */ mod->chn = 0; for (i = 0; i < mod->pat; i++) { int len, c, r, k; len = hio_read16l(f); len -= 2; for (r = 0; len > 0; ) { c = hio_read8(f); len--; if (c == 0) { r++; /* Sanity check */ if (len == 0) { if (r > 64) return -1; } else { if (r >= 64) return -1; } continue; } if (mod->chn <= (c & 0x1f)) mod->chn = (c & 0x1f) + 1; if (c & 0x20) { /* note and sample follows */ hio_read8(f); hio_read8(f); len -= 2; } if (c & 0x40) { /* effect(s) follow */ do { k = hio_read8(f); len--; if ((k & 0xc0) != 0xc0) { hio_read8(f); len--; } } while (k & 0x20); } } } mod->trk = mod->pat * mod->chn; if (libxmp_init_pattern(mod) < 0) return -1; hio_seek(f, start + pat_ofs, SEEK_SET); D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { int len, c, r, k; if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; len = hio_read16l(f); len -= 2; for (r = 0; len > 0; ) { c = hio_read8(f); len--; if (c == 0) { r++; continue; } /* Sanity check */ if ((c & 0x1f) >= mod->chn || r >= 64) { return -1; } event = &EVENT(i, c & 0x1f, r); if (c & 0x20) { /* note and sample follows */ k = hio_read8(f); event->note = 12 + 12 * MSN(k & 0x7f) + LSN(k); event->ins = hio_read8(f); len -= 2; } if (c & 0x40) { /* effect(s) follow */ do { k = hio_read8(f); len--; switch ((k & 0xc0) >> 6) { case 0: event->fxt = k & 0x1f; event->fxp = hio_read8(f); len--; fix_effect(&event->fxt, &event->fxp); break; case 1: event->f2t = k & 0x1f; event->f2p = hio_read8(f); len--; fix_effect(&event->f2t, &event->f2p); break; case 2: hio_read8(f); len--; } } while (k & 0x20); } } } /* Read samples */ hio_seek(f, start + smp_ofs, SEEK_SET); D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0) return -1; } m->quirk |= QUIRK_ARPMEM; return 0; } libxmp-4.4.1/src/loaders/xm.h0000664000175000017500000000653512773463501015675 0ustar claudioclaudio#ifndef LIBXMP_LOADERS_XM_H #define LIBXMP_LOADERS_XM_H #define XM_EVENT_PACKING 0x80 #define XM_EVENT_PACK_MASK 0x7f #define XM_EVENT_NOTE_FOLLOWS 0x01 #define XM_EVENT_INSTRUMENT_FOLLOWS 0x02 #define XM_EVENT_VOLUME_FOLLOWS 0x04 #define XM_EVENT_FXTYPE_FOLLOWS 0x08 #define XM_EVENT_FXPARM_FOLLOWS 0x10 #define XM_LINEAR_FREQ 0x01 #define XM_LOOP_MASK 0x03 #define XM_LOOP_NONE 0 #define XM_LOOP_FORWARD 1 #define XM_LOOP_PINGPONG 2 #define XM_SAMPLE_16BIT 0x10 #define XM_ENVELOPE_ON 0x01 #define XM_ENVELOPE_SUSTAIN 0x02 #define XM_ENVELOPE_LOOP 0x04 #define XM_LINEAR_PERIOD_MODE 0x01 struct xm_file_header { uint8 id[17]; /* ID text: "Extended module: " */ uint8 name[20]; /* Module name, padded with zeroes */ uint8 doseof; /* 0x1a */ uint8 tracker[20]; /* Tracker name */ uint16 version; /* Version number, minor-major */ uint32 headersz; /* Header size */ uint16 songlen; /* Song length (in patten order table) */ uint16 restart; /* Restart position */ uint16 channels; /* Number of channels (2,4,6,8,10,...,32) */ uint16 patterns; /* Number of patterns (max 256) */ uint16 instruments; /* Number of instruments (max 128) */ uint16 flags; /* bit 0: 0=Amiga freq table, 1=Linear */ uint16 tempo; /* Default tempo */ uint16 bpm; /* Default BPM */ uint8 order[256]; /* Pattern order table */ }; struct xm_pattern_header { uint32 length; /* Pattern header length */ uint8 packing; /* Packing type (always 0) */ uint16 rows; /* Number of rows in pattern (1..256) */ uint16 datasize; /* Packed patterndata size */ }; struct xm_instrument_header { uint32 size; /* Instrument size */ uint8 name[22]; /* Instrument name */ uint8 type; /* Instrument type (always 0) */ uint16 samples; /* Number of samples in instrument */ uint32 sh_size; /* Sample header size */ }; struct xm_instrument { uint8 sample[96]; /* Sample number for all notes */ uint16 v_env[24]; /* Points for volume envelope */ uint16 p_env[24]; /* Points for panning envelope */ uint8 v_pts; /* Number of volume points */ uint8 p_pts; /* Number of panning points */ uint8 v_sus; /* Volume sustain point */ uint8 v_start; /* Volume loop start point */ uint8 v_end; /* Volume loop end point */ uint8 p_sus; /* Panning sustain point */ uint8 p_start; /* Panning loop start point */ uint8 p_end; /* Panning loop end point */ uint8 v_type; /* Bit 0: On; 1: Sustain; 2: Loop */ uint8 p_type; /* Bit 0: On; 1: Sustain; 2: Loop */ uint8 y_wave; /* Vibrato waveform */ uint8 y_sweep; /* Vibrato sweep */ uint8 y_depth; /* Vibrato depth */ uint8 y_rate; /* Vibrato rate */ uint16 v_fade; /* Volume fadeout */ #if 0 uint8 reserved[22]; /* Reserved; 2 bytes in specs, 22 in 1.04 */ #endif }; struct xm_sample_header { uint32 length; /* Sample length */ uint32 loop_start; /* Sample loop start */ uint32 loop_length; /* Sample loop length */ uint8 volume; /* Volume */ int8 finetune; /* Finetune (signed byte -128..+127) */ uint8 type; /* 0=No loop,1=Fwd loop,2=Ping-pong,16-bit */ uint8 pan; /* Panning (0-255) */ int8 relnote; /* Relative note number (signed byte) */ uint8 reserved; /* Reserved */ uint8 name[22]; /* Sample_name */ }; struct xm_event { uint8 note; /* Note (0-71, 0 = C-0) */ uint8 instrument; /* Instrument (0-128) */ uint8 volume; /* Volume column byte */ uint8 fx_type; /* Effect type */ uint8 fx_parm; /* Effect parameter */ }; #endif libxmp-4.4.1/src/loaders/mod_load.c0000664000175000017500000004651012774567167017035 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* This loader recognizes the following variants of the Protracker * module format: * * - Protracker M.K. and M!K! * - Protracker songs * - Noisetracker N.T. and M&K! (not tested) * - Fast Tracker 6CHN and 8CHN * - Fasttracker II/Take Tracker ?CHN and ??CH * - Mod's Grave M.K. w/ 8 channels (WOW) * - Atari Octalyser CD61 and CD81 * - Digital Tracker FA04, FA06 and FA08 * - TakeTracker TDZ4 * - (unknown) NSMS */ #include #include #include "loader.h" #include "mod.h" struct mod_magic { char *magic; int flag; int id; int ch; }; #define TRACKER_PROTRACKER 0 #define TRACKER_NOISETRACKER 1 #define TRACKER_SOUNDTRACKER 2 #define TRACKER_FASTTRACKER 3 #define TRACKER_FASTTRACKER2 4 #define TRACKER_OCTALYSER 5 #define TRACKER_TAKETRACKER 6 #define TRACKER_DIGITALTRACKER 7 #define TRACKER_FLEXTRAX 8 #define TRACKER_MODSGRAVE 9 #define TRACKER_SCREAMTRACKER3 10 #define TRACKER_OPENMPT 11 #define TRACKER_UNKNOWN_CONV 95 #define TRACKER_CONVERTEDST 96 #define TRACKER_CONVERTED 97 #define TRACKER_CLONE 98 #define TRACKER_UNKNOWN 99 #define TRACKER_PROBABLY_NOISETRACKER 20 const struct mod_magic mod_magic[] = { {"M.K.", 0, TRACKER_PROTRACKER, 4}, {"M!K!", 1, TRACKER_PROTRACKER, 4}, {"M&K!", 1, TRACKER_NOISETRACKER, 4}, {"N.T.", 1, TRACKER_NOISETRACKER, 4}, {"6CHN", 0, TRACKER_FASTTRACKER, 6}, {"8CHN", 0, TRACKER_FASTTRACKER, 8}, {"CD61", 1, TRACKER_OCTALYSER, 6}, /* Atari STe/Falcon */ {"CD81", 1, TRACKER_OCTALYSER, 8}, /* Atari STe/Falcon */ {"TDZ4", 1, TRACKER_TAKETRACKER, 4}, /* see XModule SaveTracker.c */ {"FA04", 1, TRACKER_DIGITALTRACKER, 4}, /* Atari Falcon */ {"FA06", 1, TRACKER_DIGITALTRACKER, 6}, /* Atari Falcon */ {"FA08", 1, TRACKER_DIGITALTRACKER, 8}, /* Atari Falcon */ {"NSMS", 1, TRACKER_UNKNOWN, 4}, /* in Kingdom.mod */ {"", 0} }; static int mod_test(HIO_HANDLE *, char *, const int); static int mod_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mod = { "Amiga Protracker/Compatible", mod_test, mod_load }; static int validate_pattern(uint8 *buf) { int i, j; for (i = 0; i < 64; i++) { for (j = 0; j < 4; j++) { uint8 *d = buf + (i * 4 + j) * 4; if ((d[0] >> 4) > 1) { return -1; } } } return 0; } static int mod_test(HIO_HANDLE * f, char *t, const int start) { int i; char buf[4]; uint8 pat_buf[1024]; int smp_size, num_pat; long size; hio_seek(f, start + 1080, SEEK_SET); if (hio_read(buf, 1, 4, f) < 4) { return -1; } if (!strncmp(buf + 2, "CH", 2) && isdigit((int)buf[0]) && isdigit((int)buf[1])) { i = (buf[0] - '0') * 10 + buf[1] - '0'; if (i > 0 && i <= 32) { goto found; } } if (!strncmp(buf + 1, "CHN", 3) && isdigit((int)*buf)) { if (*buf - '0') { goto found; } } for (i = 0; mod_magic[i].ch; i++) { if (!memcmp(buf, mod_magic[i].magic, 4)) break; } if (mod_magic[i].ch == 0) { return -1; } /* * Sanity check to prevent loading NoiseRunner and other module * formats with valid magic at offset 1080 */ hio_seek(f, start + 20, SEEK_SET); for (i = 0; i < 31; i++) { uint8 x; hio_seek(f, 22, SEEK_CUR); /* Instrument name */ /* OpenMPT can create mods with large samples */ hio_read16b(f); /* sample size */ /* Chris Spiegel tells me that sandman.mod has 0x20 in finetune */ x = hio_read8(f); if (x & 0xf0 && x != 0x20) /* test finetune */ return -1; if (hio_read8(f) > 0x40) /* test volume */ return -1; hio_read16b(f); /* loop start */ hio_read16b(f); /* loop size */ } /* Test for UNIC tracker modules * * From Gryzor's Pro-Wizard PW_FORMATS-Engl.guide: * ``The UNIC format is very similar to Protracker... At least in the * heading... same length : 1084 bytes. Even the "M.K." is present, * sometimes !! Maybe to disturb the rippers.. hehe but Pro-Wizard * doesn't test this only!'' */ /* get file size */ size = hio_size(f); smp_size = 0; hio_seek(f, start + 20, SEEK_SET); /* get samples size */ for (i = 0; i < 31; i++) { hio_seek(f, 22, SEEK_CUR); smp_size += 2 * hio_read16b(f); /* Length in 16-bit words */ hio_seek(f, 6, SEEK_CUR); } /* get number of patterns */ num_pat = 0; hio_seek(f, start + 952, SEEK_SET); for (i = 0; i < 128; i++) { uint8 x = hio_read8(f); if (x > 0x7f) break; if (x > num_pat) num_pat = x; } num_pat++; /* see if module size matches UNIC */ if (start + 1084 + num_pat * 0x300 + smp_size == size) return -1; /* validate pattern data in an attempt to catch UNICs with MOD size */ for (i = 0; i < num_pat; i++) { hio_seek(f, start + 1084 + 1024 * i, SEEK_SET); hio_read(pat_buf, 1024, 1, f); if (validate_pattern(pat_buf) < 0) return -1; } found: hio_seek(f, start + 0, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } static int is_st_ins(char *s) { if (s[0] != 's' && s[0] != 'S') return 0; if (s[1] != 't' && s[1] != 'T') return 0; if (s[2] != '-' || s[5] != ':') return 0; if (!isdigit((int)s[3]) || !isdigit((int)s[4])) return 0; return 1; } static int get_tracker_id(struct module_data *m, struct mod_header *mh, int id) { struct xmp_module *mod = &m->mod; int has_loop_0 = 0; int has_vol_in_empty_ins = 0; int i; /* Check if has instruments with loop size 0 */ for (i = 0; i < 31; i++) { if (mh->ins[i].loop_size == 0) { has_loop_0 = 1; break; } } /* Check if has instruments with size 0 and volume > 0 */ for (i = 0; i < 31; i++) { if (mh->ins[i].size == 0 && mh->ins[i].volume > 0) { has_vol_in_empty_ins = 1; break; } } /* * Test Protracker-like files */ if (mh->restart == mod->pat) { if (mod->chn == 4) { id = TRACKER_SOUNDTRACKER; } else { id = TRACKER_UNKNOWN; } } else if (mh->restart == 0x78) { if (mod->chn == 4) { /* Can't trust this for Noisetracker, MOD.Data City Remix * has Protracker effects and Noisetracker restart byte */ id = TRACKER_PROBABLY_NOISETRACKER; } else { id = TRACKER_UNKNOWN; } return id; } else if (mh->restart < 0x7f) { if (mod->chn == 4 && !has_vol_in_empty_ins) { id = TRACKER_NOISETRACKER; } else { id = TRACKER_UNKNOWN; /* ? */ } mod->rst = mh->restart; } else if (mh->restart == 0x7f) { if (mod->chn == 4) { if (has_loop_0) { id = TRACKER_CLONE; } } else { id = TRACKER_SCREAMTRACKER3; } return id; } else if (mh->restart > 0x7f) { id = TRACKER_UNKNOWN; /* ? */ return id; } if (!has_loop_0) { /* All loops are size 2 or greater */ for (i = 0; i < 31; i++) { if (mh->ins[i].size == 1 && mh->ins[i].volume == 0) { return TRACKER_CONVERTED; } } for (i = 0; i < 31; i++) { if (is_st_ins((char *)mh->ins[i].name)) break; } if (i == 31) { /* No st- instruments */ for (i = 0; i < 31; i++) { if (mh->ins[i].size != 0 || mh->ins[i].loop_size != 1) { continue; } switch (mod->chn) { case 4: if (has_vol_in_empty_ins) { id = TRACKER_OPENMPT; } else { id = TRACKER_NOISETRACKER; /* or Octalyser */ } break; case 6: case 8: id = TRACKER_OCTALYSER; break; default: id = TRACKER_UNKNOWN; } return id; } if (mod->chn == 4) { id = TRACKER_PROTRACKER; } else if (mod->chn == 6 || mod->chn == 8) { /* FastTracker 1.01? */ id = TRACKER_FASTTRACKER; } else { id = TRACKER_UNKNOWN; } } } else { /* Has loops with size 0 */ for (i = 15; i < 31; i++) { if (strlen((char *)mh->ins[i].name) || mh->ins[i].size > 0) break; } if (i == 31 && is_st_ins((char *)mh->ins[14].name)) { return TRACKER_CONVERTEDST; } /* Assume that Fast Tracker modules won't have ST- instruments */ for (i = 0; i < 31; i++) { if (is_st_ins((char *)mh->ins[i].name)) break; } if (i < 31) { return TRACKER_UNKNOWN_CONV; } if (mod->chn == 4 || mod->chn == 6 || mod->chn == 8) { return TRACKER_FASTTRACKER; } id = TRACKER_UNKNOWN; /* ??!? */ } return id; } static int mod_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; int smp_size, ptsong = 0; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; char *x, pathname[PATH_MAX] = "", *tracker = ""; int detected = 0; char magic[8], idbuffer[32]; int ptkloop = 0; /* Protracker loop */ int tracker_id = TRACKER_PROTRACKER; int out_of_range = 0; LOAD_INIT(); mod->ins = 31; mod->smp = mod->ins; mod->chn = 0; smp_size = 0; /*pat_size = 0;*/ m->period_type = PERIOD_MODRNG; hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); /* Instrument name */ mh.ins[i].size = hio_read16b(f); /* Length in 16-bit words */ mh.ins[i].finetune = hio_read8(f); /* Finetune (signed nibble) */ mh.ins[i].volume = hio_read8(f); /* Linear playback volume */ mh.ins[i].loop_start = hio_read16b(f); /* Loop start in 16-bit words */ mh.ins[i].loop_size = hio_read16b(f); /* Loop size in 16-bit words */ smp_size += 2 * mh.ins[i].size; } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); memset(magic, 0, 8); hio_read(magic, 1, 4, f); if (hio_error(f)) { return -1; } for (i = 0; mod_magic[i].ch; i++) { if (!(strncmp (magic, mod_magic[i].magic, 4))) { mod->chn = mod_magic[i].ch; tracker_id = mod_magic[i].id; detected = mod_magic[i].flag; break; } } if (mod->chn == 0) { if (!strncmp(magic + 2, "CH", 2) && isdigit((int)magic[0]) && isdigit((int)magic[1])) { mod->chn = (*magic - '0') * 10 + magic[1] - '0'; } else if (!strncmp(magic + 1, "CHN", 3) && isdigit((int)*magic)) { mod->chn = *magic - '0'; } else { return -1; } tracker_id = mod->chn & 1 ? TRACKER_TAKETRACKER : TRACKER_FASTTRACKER2; detected = 1; } strncpy(mod->name, (char *) mh.name, 20); mod->len = mh.len; /* mod->rst = mh.restart; */ if (mod->rst >= mod->len) mod->rst = 0; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { /* This fixes dragnet.mod (garbage in the order list) */ if (mod->xxo[i] > 0x7f) break; if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; /*pat_size = 256 * mod->chn * mod->pat;*/ if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi; struct xmp_subinstrument *sub; struct xmp_sample *xxs; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; if (mh.ins[i].size >= 0x8000) { tracker_id = TRACKER_OPENMPT; detected = 1; } xxi = &mod->xxi[i]; sub = &xxi->sub[0]; xxs = &mod->xxs[i]; xxs->len = 2 * mh.ins[i].size; xxs->lps = 2 * mh.ins[i].loop_start; xxs->lpe = xxs->lps + 2 * mh.ins[i].loop_size; if (xxs->lpe > xxs->len) { xxs->lpe = xxs->len; } xxs->flg = (mh.ins[i].loop_size > 1 && xxs->lpe >= 4) ? XMP_SAMPLE_LOOP : 0; sub->fin = (int8)(mh.ins[i].finetune << 4); sub->vol = mh.ins[i].volume; sub->pan = 0x80; sub->sid = i; libxmp_instrument_name(mod, i, mh.ins[i].name, 22); if (xxs->len > 0) { xxi->nsm = 1; } } /* * Experimental tracker-detection routine */ if (detected) goto skip_test; /* Test for Flextrax modules * * FlexTrax is a soundtracker for Atari Falcon030 compatible computers. * FlexTrax supports the standard MOD file format (up to eight channels) * for compatibility reasons but also features a new enhanced module * format FLX. The FLX format is an extended version of the standard * MOD file format with support for real-time sound effects like reverb * and delay. */ if (0x43c + mod->pat * 4 * mod->chn * 0x40 + smp_size < m->size) { int pos = hio_tell(f); if (pos < 0) { return -1; } hio_seek(f, start + 0x43c + mod->pat * 4 * mod->chn * 0x40 + smp_size, SEEK_SET); hio_read(idbuffer, 1, 4, f); hio_seek(f, start + pos, SEEK_SET); if (!memcmp(idbuffer, "FLEX", 4)) { tracker_id = TRACKER_FLEXTRAX; goto skip_test; } } /* Test for Mod's Grave WOW modules * * Stefan Danes said: * This weird format is identical to '8CHN' but still uses the 'M.K.' ID. * You can only test for WOW by calculating the size of the module for 8 * channels and comparing this to the actual module length. If it's equal, * the module is an 8 channel WOW. */ if ((!strncmp(magic, "M.K.", 4) && (0x43c + mod->pat * 32 * 0x40 + smp_size == m->size))) { mod->chn = 8; tracker_id = TRACKER_MODSGRAVE; } /* Test for Protracker song files */ else if ((ptsong = (!strncmp((char *)magic, "M.K.", 4) && (0x43c + mod->pat * 0x400 == m->size)))) { tracker_id = TRACKER_PROTRACKER; goto skip_test; } /* something else */ else { tracker_id = get_tracker_id(m, &mh, tracker_id); } skip_test: if (mod->chn >= XMP_MAX_CHANNELS) { return -1; } mod->trk = mod->chn * mod->pat; for (i = 0; i < mod->ins; i++) { D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d %c", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, (mh.ins[i].loop_size > 1 && mod->xxs[i].lpe > 8) ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4, ptkloop && mod->xxs[i].lps == 0 && mh.ins[i].loop_size > 1 && mod->xxs[i].len > mod->xxs[i].lpe ? '!' : ' '); } if (libxmp_init_pattern(mod) < 0) return -1; /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { long pos; if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; pos = hio_tell(f); if (pos < 0) { return -1; } for (j = 0; j < (64 * mod->chn); j++) { int period; event = &EVENT(i, j % mod->chn, j / mod->chn); hio_read(mod_event, 1, 4, f); period = ((int)(LSN(mod_event[0])) << 8) | mod_event[1]; if (period != 0 && (period < 108 || period > 907)) { out_of_range = 1; } /* Filter noisetracker events */ if (tracker_id == TRACKER_PROBABLY_NOISETRACKER) { unsigned char fxt = LSN(mod_event[2]); unsigned char fxp = LSN(mod_event[3]); if ((fxt > 0x06 && fxt < 0x0a) || (fxt == 0x0e && fxp > 1)) { tracker_id = TRACKER_UNKNOWN; } } } if (out_of_range) { if (tracker_id == TRACKER_UNKNOWN && mh.restart == 0x7f) { tracker_id = TRACKER_SCREAMTRACKER3; } /* Check out-of-range notes in Amiga trackers */ if (tracker_id == TRACKER_PROTRACKER || tracker_id == TRACKER_NOISETRACKER || tracker_id == TRACKER_PROBABLY_NOISETRACKER || tracker_id == TRACKER_SOUNDTRACKER) { /* note > B-3 */ tracker_id = TRACKER_UNKNOWN; } } hio_seek(f, pos, SEEK_SET); for (j = 0; j < (64 * mod->chn); j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); hio_read(mod_event, 1, 4, f); switch (tracker_id) { case TRACKER_PROBABLY_NOISETRACKER: case TRACKER_NOISETRACKER: libxmp_decode_noisetracker_event(event, mod_event); break; default: libxmp_decode_protracker_event(event, mod_event); } } } switch (tracker_id) { case TRACKER_PROTRACKER: tracker = "Protracker"; ptkloop = 1; break; case TRACKER_PROBABLY_NOISETRACKER: case TRACKER_NOISETRACKER: tracker = "Noisetracker"; m->quirk |= QUIRK_NOBPM; break; case TRACKER_SOUNDTRACKER: tracker = "Soundtracker"; m->quirk |= QUIRK_NOBPM; break; case TRACKER_FASTTRACKER: case TRACKER_FASTTRACKER2: tracker = "Fast Tracker"; m->period_type = PERIOD_AMIGA; break; case TRACKER_TAKETRACKER: tracker = "Take Tracker"; m->period_type = PERIOD_AMIGA; break; case TRACKER_OCTALYSER: tracker = "Octalyser"; break; case TRACKER_DIGITALTRACKER: tracker = "Digital Tracker"; break; case TRACKER_FLEXTRAX: tracker = "Flextrax"; break; case TRACKER_MODSGRAVE: tracker = "Mod's Grave"; break; case TRACKER_SCREAMTRACKER3: tracker = "Scream Tracker"; m->period_type = PERIOD_AMIGA; break; case TRACKER_CONVERTEDST: case TRACKER_CONVERTED: tracker = "Converted"; break; case TRACKER_CLONE: tracker = "Protracker clone"; m->period_type = PERIOD_AMIGA; break; case TRACKER_OPENMPT: tracker = "OpenMPT"; ptkloop = 1; break; default: case TRACKER_UNKNOWN_CONV: case TRACKER_UNKNOWN: tracker = "Unknown tracker"; m->period_type = PERIOD_AMIGA; break; } if (out_of_range) { m->period_type = PERIOD_AMIGA; } if (tracker_id == TRACKER_MODSGRAVE) { snprintf(mod->type, XMP_NAME_SIZE, "%s", tracker); } else { snprintf(mod->type, XMP_NAME_SIZE, "%s %s", tracker, magic); } MODULE_INFO(); /* Load samples */ if (m->filename && (x = strrchr(m->filename, '/'))) strncpy(pathname, m->filename, x - m->filename); D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { int flags; if (!mod->xxs[i].len) continue; flags = (ptkloop && mod->xxs[i].lps == 0) ? SAMPLE_FLAG_FULLREP : 0; if (ptsong) { HIO_HANDLE *s; char sn[256]; snprintf(sn, XMP_NAME_SIZE, "%s%s", pathname, mod->xxi[i].name); if ((s = hio_open(sn, "rb"))) { if (libxmp_load_sample(m, s, flags, &mod->xxs[i], NULL) < 0) { hio_close(s); return -1; } hio_close(s); } } else { uint8 buf[5]; long pos; int num; if ((pos = hio_tell(f)) < 0) { return -1; } num = hio_read(buf, 1, 5, f); if (num == 5 && !memcmp(buf, "ADPCM", 5)) { flags |= SAMPLE_FLAG_ADPCM; } else { hio_seek(f, pos, SEEK_SET); } if (libxmp_load_sample(m, f, flags, &mod->xxs[i], NULL) < 0) return -1; } } if (tracker_id == TRACKER_PROTRACKER || tracker_id == TRACKER_OPENMPT) { m->quirk |= QUIRK_PROTRACK; } else if (tracker_id == TRACKER_SCREAMTRACKER3) { m->c4rate = C4_NTSC_RATE; m->quirk |= QUIRKS_ST3; m->read_event_type = READ_EVENT_ST3; } else if (tracker_id == TRACKER_FASTTRACKER || tracker_id == TRACKER_FASTTRACKER2 || tracker_id == TRACKER_TAKETRACKER || tracker_id == TRACKER_MODSGRAVE || mod->chn > 4) { m->c4rate = C4_NTSC_RATE; m->quirk |= QUIRKS_FT2 | QUIRK_FTMOD; m->read_event_type = READ_EVENT_FT2; m->period_type = PERIOD_AMIGA; } return 0; } libxmp-4.4.1/src/loaders/umx_load.c0000664000175000017500000000646612774567167017075 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #define TEST_SIZE 1500 #define MAGIC_UMX MAGIC4(0xc1,0x83,0x2a,0x9e) #define MAGIC_IMPM MAGIC4('I','M','P','M') #define MAGIC_SCRM MAGIC4('S','C','R','M') #define MAGIC_M_K_ MAGIC4('M','.','K','.') extern const struct format_loader libxmp_loader_xm; extern const struct format_loader libxmp_loader_it; extern const struct format_loader libxmp_loader_s3m; extern const struct format_loader libxmp_loader_mod; static int umx_test (HIO_HANDLE *, char *, const int); static int umx_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_umx = { "Epic Games UMX", umx_test, umx_load }; static int umx_test(HIO_HANDLE *f, char *t, const int start) { int i, offset = -1; uint8 buf[TEST_SIZE], *b = buf; uint32 id; if (hio_read(buf, 1, TEST_SIZE, f) < TEST_SIZE) return -1; ; id = readmem32b(b); if (id != MAGIC_UMX) return -1; for (i = 0; i < TEST_SIZE; i++, b++) { id = readmem32b(b); if (!memcmp(b, "Extended Module:", 16)) { offset = i; break; } if (id == MAGIC_IMPM) { offset = i; break; } if (i > 44 && id == MAGIC_SCRM) { offset = i - 44; break; } if (i > 1080 && id == MAGIC_M_K_) { offset = i - 1080; break; } } if (offset < 0) return -1; return 0; } static int umx_load(struct module_data *m, HIO_HANDLE *f, const int start) { int i; uint8 buf[TEST_SIZE], *b = buf; uint32 id; LOAD_INIT(); D_(D_INFO "Container type : Epic Games UMX"); hio_read(buf, 1, TEST_SIZE, f); for (i = 0; i < TEST_SIZE; i++, b++) { id = readmem32b(b); if (!memcmp(b, "Extended Module:", 16)) { if (hio_seek(f, i, SEEK_SET) < 0) { return -1; } return libxmp_loader_xm.loader(m, f, i); } if (id == MAGIC_IMPM) { if (hio_seek(f, i, SEEK_SET) < 0) { return -1; } return libxmp_loader_it.loader(m, f, i); } if (i > 44 && id == MAGIC_SCRM) { i -= 44; if (hio_seek(f, i, SEEK_SET) < 0) { return -1; } return libxmp_loader_s3m.loader(m, f, i); } if (i > 1080 && id == MAGIC_M_K_) { i -= 1080; if (hio_seek(f, i, SEEK_SET) < 0) { return -1; } return libxmp_loader_mod.loader(m, f, i); } } return -1; } libxmp-4.4.1/src/loaders/common.c0000664000175000017500000001775412774567167016557 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #ifndef WIN32 #include #endif #include "xmp.h" #include "common.h" #include "period.h" #include "loader.h" int libxmp_init_instrument(struct module_data *m) { struct xmp_module *mod = &m->mod; if (mod->ins > 0) { mod->xxi = calloc(sizeof (struct xmp_instrument), mod->ins); if (mod->xxi == NULL) return -1; } if (mod->smp > 0) { int i; mod->xxs = calloc(sizeof (struct xmp_sample), mod->smp); if (mod->xxs == NULL) return -1; m->xtra = calloc(sizeof (struct extra_sample_data), mod->smp); if (m->xtra == NULL) return -1; for (i = 0; i < mod->smp; i++) { m->xtra[i].c5spd = m->c4rate; } } return 0; } int libxmp_alloc_subinstrument(struct xmp_module *mod, int i, int num) { if (num == 0) return 0; mod->xxi[i].sub = calloc(sizeof (struct xmp_subinstrument), num); if (mod->xxi[i].sub == NULL) return -1; return 0; } int libxmp_init_pattern(struct xmp_module *mod) { mod->xxt = calloc(sizeof (struct xmp_track *), mod->trk); if (mod->xxt == NULL) return -1; mod->xxp = calloc(sizeof (struct xmp_pattern *), mod->pat); if (mod->xxp == NULL) return -1; return 0; } int libxmp_alloc_pattern(struct xmp_module *mod, int num) { /* Sanity check */ if (num < 0 || num >= mod->pat || mod->xxp[num] != NULL) return -1; mod->xxp[num] = calloc(1, sizeof (struct xmp_pattern) + sizeof (int) * (mod->chn - 1)); if (mod->xxp[num] == NULL) return -1; return 0; } int libxmp_alloc_track(struct xmp_module *mod, int num, int rows) { /* Sanity check */ if (num < 0 || num >= mod->trk || mod->xxt[num] != NULL || rows <= 0) return -1; mod->xxt[num] = calloc(sizeof (struct xmp_track) + sizeof (struct xmp_event) * (rows - 1), 1); if (mod->xxt[num] == NULL) return -1; mod->xxt[num]->rows = rows; return 0; } int libxmp_alloc_tracks_in_pattern(struct xmp_module *mod, int num) { int i; D_(D_INFO "Alloc %d tracks of %d rows", mod->chn, mod->xxp[num]->rows); for (i = 0; i < mod->chn; i++) { int t = num * mod->chn + i; int rows = mod->xxp[num]->rows; if (libxmp_alloc_track(mod, t, rows) < 0) return -1; mod->xxp[num]->index[i] = t; } return 0; } int libxmp_alloc_pattern_tracks(struct xmp_module *mod, int num, int rows) { /* Sanity check */ if (rows < 0 || rows > 256) return -1; if (libxmp_alloc_pattern(mod, num) < 0) return -1; mod->xxp[num]->rows = rows; if (libxmp_alloc_tracks_in_pattern(mod, num) < 0) return -1; return 0; } /* Sample number adjustment by Vitamin/CAIG */ struct xmp_sample *libxmp_realloc_samples(struct xmp_sample *buf, int *size, int new_size) { buf = realloc(buf, sizeof (struct xmp_sample) * new_size); if (buf == NULL) return NULL; if (new_size > *size) memset(buf + *size, 0, sizeof (struct xmp_sample) * (new_size - *size)); *size = new_size; return buf; } char *libxmp_instrument_name(struct xmp_module *mod, int i, uint8 *r, int n) { CLAMP(n, 0, 31); return libxmp_copy_adjust(mod->xxi[i].name, r, n); } char *libxmp_copy_adjust(char *s, uint8 *r, int n) { int i; memset(s, 0, n + 1); strncpy(s, (char *)r, n); for (i = 0; s[i] && i < n; i++) { if (!isprint((int)s[i]) || ((uint8)s[i] > 127)) s[i] = '.'; } while (*s && (s[strlen(s) - 1] == ' ')) s[strlen(s) - 1] = 0; return s; } void libxmp_read_title(HIO_HANDLE *f, char *t, int s) { uint8 buf[XMP_NAME_SIZE]; if (t == NULL) return; if (s >= XMP_NAME_SIZE) s = XMP_NAME_SIZE -1; memset(t, 0, s + 1); hio_read(buf, 1, s, f); /* coverity[check_return] */ buf[s] = 0; libxmp_copy_adjust(t, buf, s); } #ifndef LIBXMP_CORE_PLAYER int libxmp_test_name(uint8 *s, int n) { int i; /* ACS_Team2.mod has a backspace in instrument name */ for (i = 0; i < n; i++) { if (s[i] > 0x7f) return -1; if (s[i] > 0 && s[i] < 32 && s[i] != 0x08) return -1; } return 0; } /* * Honor Noisetracker effects: * * 0 - arpeggio * 1 - portamento up * 2 - portamento down * 3 - Tone-portamento * 4 - Vibrato * A - Slide volume * B - Position jump * C - Set volume * D - Pattern break * E - Set filter (keep the led off, please!) * F - Set speed (now up to $1F) * * Pex Tufvesson's notes from http://www.livet.se/mahoney/: * * Note that some of the modules will have bugs in the playback with all * known PC module players. This is due to that in many demos where I synced * events in the demo with the music, I used commands that these newer PC * module players erroneously interpret as "newer-version-trackers commands". * Which they aren't. */ void libxmp_decode_noisetracker_event(struct xmp_event *event, uint8 *mod_event) { int fxt; memset(event, 0, sizeof (struct xmp_event)); event->note = libxmp_period_to_note((LSN(mod_event[0]) << 8) + mod_event[1]); event->ins = ((MSN(mod_event[0]) << 4) | MSN(mod_event[2])); fxt = LSN(mod_event[2]); if (fxt <= 0x06 || (fxt >= 0x0a && fxt != 0x0e)) { event->fxt = fxt; event->fxp = mod_event[3]; } libxmp_disable_continue_fx(event); } #endif void libxmp_decode_protracker_event(struct xmp_event *event, uint8 *mod_event) { int fxt = LSN(mod_event[2]); memset(event, 0, sizeof (struct xmp_event)); event->note = libxmp_period_to_note((LSN(mod_event[0]) << 8) + mod_event[1]); event->ins = ((MSN(mod_event[0]) << 4) | MSN(mod_event[2])); if (fxt != 0x08) { event->fxt = fxt; event->fxp = mod_event[3]; } libxmp_disable_continue_fx(event); } void libxmp_disable_continue_fx(struct xmp_event *event) { if (event->fxp == 0) { switch (event->fxt) { case 0x05: event->fxt = 0x03; break; case 0x06: event->fxt = 0x04; break; case 0x01: case 0x02: case 0x0a: event->fxt = 0x00; } } else if (event->fxt == 0x0e) { if (event->fxp == 0xa0 || event->fxp == 0xb0) { event->fxt = event->fxp = 0; } } } #ifndef LIBXMP_CORE_PLAYER #ifndef WIN32 /* Given a directory, see if file exists there, ignoring case */ int libxmp_check_filename_case(char *dir, char *name, char *new_name, int size) { int found = 0; DIR *dirfd; struct dirent *d; dirfd = opendir(dir); if (dirfd == NULL) return 0; while ((d = readdir(dirfd))) { if (!strcasecmp(d->d_name, name)) { found = 1; break; } } if (found) strncpy(new_name, d->d_name, size); closedir(dirfd); return found; } #else /* FIXME: implement functionality for Win32 */ int libxmp_check_filename_case(char *dir, char *name, char *new_name, int size) { return 0; } #endif void libxmp_get_instrument_path(struct module_data *m, char *path, int size) { if (m->instrument_path) { strncpy(path, m->instrument_path, size); } else if (getenv("XMP_INSTRUMENT_PATH")) { strncpy(path, getenv("XMP_INSTRUMENT_PATH"), size); } else { strncpy(path, ".", size); } } #endif /* LIBXMP_CORE_PLAYER */ void libxmp_set_type(struct module_data *m, char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(m->mod.type, XMP_NAME_SIZE, fmt, ap); va_end(ap); } libxmp-4.4.1/src/loaders/itsex.c0000664000175000017500000000775412773571316016410 0ustar claudioclaudio#ifndef LIBXMP_CORE_DISABLE_IT /* Public domain IT sample decompressor by Olivier Lapicque */ #include "loader.h" static inline uint32 read_bits(HIO_HANDLE *ibuf, uint32 *bitbuf, int *bitnum, int n) { uint32 retval = 0; int i = n; int bnum = *bitnum, bbuf = *bitbuf; if (n > 0) { do { if (bnum == 0) { bbuf = hio_read8(ibuf); bnum = 8; } retval >>= 1; retval |= bbuf << 31; bbuf >>= 1; bnum--; i--; } while (i != 0); i = n; *bitnum = bnum; *bitbuf = bbuf; } return (retval >> (32 - i)); } int itsex_decompress8(HIO_HANDLE *src, uint8 *dst, int len, int it215) { /* uint32 size = 0; */ uint32 block_count = 0; uint32 bitbuf = 0; int bitnum = 0; uint8 left = 0, temp = 0, temp2 = 0; uint32 d, pos; while (len) { if (!block_count) { block_count = 0x8000; /*size =*/ hio_read16l(src); left = 9; temp = temp2 = 0; bitbuf = bitnum = 0; } d = block_count; if (d > len) d = len; /* Unpacking */ pos = 0; do { uint16 bits = read_bits(src, &bitbuf, &bitnum, left); if (hio_eof(src)) return -1; if (left < 7) { uint32 i = 1 << (left - 1); uint32 j = bits & 0xffff; if (i != j) goto unpack_byte; bits = (read_bits(src, &bitbuf, &bitnum, 3) + 1) & 0xff; if (hio_eof(src)) return -1; left = ((uint8)bits < left) ? (uint8)bits : (uint8)((bits + 1) & 0xff); goto next; } if (left < 9) { uint16 i = (0xff >> (9 - left)) + 4; uint16 j = i - 8; if ((bits <= j) || (bits > i)) goto unpack_byte; bits -= j; left = ((uint8)(bits & 0xff) < left) ? (uint8)(bits & 0xff) : (uint8)((bits + 1) & 0xff); goto next; } if (left >= 10) goto skip_byte; if (bits >= 256) { left = (uint8) (bits + 1) & 0xff; goto next; } unpack_byte: if (left < 8) { uint8 shift = 8 - left; signed char c = (signed char)(bits << shift); c >>= shift; bits = (uint16) c; } bits += temp; temp = (uint8)bits; temp2 += temp; dst[pos] = it215 ? temp2 : temp; skip_byte: pos++; next: /* if (slen <= 0) return -1 */; } while (pos < d); /* Move On */ block_count -= d; len -= d; dst += d; } return 0; } int itsex_decompress16(HIO_HANDLE *src, int16 *dst, int len, int it215) { /* uint32 size = 0; */ uint32 block_count = 0; uint32 bitbuf = 0; int bitnum = 0; uint8 left = 0; int16 temp = 0, temp2 = 0; uint32 d, pos; while (len) { if (!block_count) { block_count = 0x4000; /*size =*/ hio_read16l(src); left = 17; temp = temp2 = 0; bitbuf = bitnum = 0; } d = block_count; if (d > len) d = len; /* Unpacking */ pos = 0; do { uint32 bits = read_bits(src, &bitbuf, &bitnum, left); if (hio_eof(src)) return -1; if (left < 7) { uint32 i = 1 << (left - 1); uint32 j = bits; if (i != j) goto unpack_byte; bits = read_bits(src, &bitbuf, &bitnum, 4) + 1; if (hio_eof(src)) return -1; left = ((uint8)(bits & 0xff) < left) ? (uint8)(bits & 0xff) : (uint8)((bits + 1) & 0xff); goto next; } if (left < 17) { uint32 i = (0xffff >> (17 - left)) + 8; uint32 j = (i - 16) & 0xffff; if ((bits <= j) || (bits > (i & 0xffff))) goto unpack_byte; bits -= j; left = ((uint8)(bits & 0xff) < left) ? (uint8)(bits & 0xff) : (uint8)((bits + 1) & 0xff); goto next; } if (left >= 18) goto skip_byte; if (bits >= 0x10000) { left = (uint8)(bits + 1) & 0xff; goto next; } unpack_byte: if (left < 16) { uint8 shift = 16 - left; int16 c = (int16)(bits << shift); c >>= shift; bits = (uint32) c; } bits += temp; temp = (int16)bits; temp2 += temp; dst[pos] = (it215) ? temp2 : temp; skip_byte: pos++; next: /* if (slen <= 0) return -1 */; } while (pos < d); /* Move On */ block_count -= d; len -= d; dst += d; if (len <= 0) break; } return 0; } #endif /* LIBXMP_CORE_DISABLE_IT */ libxmp-4.4.1/src/loaders/mod.h0000664000175000017500000000363312773463501016024 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ struct mod_instrument { uint8 name[22]; /* Instrument name */ uint16 size; /* Sample length in 16-bit words */ int8 finetune; /* Finetune (signed nibble) */ int8 volume; /* Linear playback volume */ uint16 loop_start; /* Loop start in 16-bit words */ uint16 loop_size; /* Loop length in 16-bit words */ }; struct mod_header { uint8 name[20]; struct mod_instrument ins[31]; uint8 len; uint8 restart; /* Number of patterns in Soundtracker, * Restart in Noisetracker/Startrekker, * 0x7F in Protracker */ uint8 order[128]; uint8 magic[4]; }; #ifndef LIBXMP_CORE_PLAYER /* Soundtracker 15-instrument module header */ struct st_header { uint8 name[20]; struct mod_instrument ins[15]; uint8 len; uint8 restart; uint8 order[128]; }; #endif libxmp-4.4.1/src/loaders/sample.c0000664000175000017500000002247112773571316016526 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "common.h" #include "loader.h" #ifndef LIBXMP_CORE_PLAYER /* * From the Audio File Formats (version 2.5) * Submitted-by: Guido van Rossum * Last-modified: 27-Aug-1992 * * The Acorn Archimedes uses a variation on U-LAW with the bit order * reversed and the sign bit in bit 0. Being a 'minority' architecture, * Arc owners are quite adept at converting sound/image formats from * other machines, and it is unlikely that you'll ever encounter sound in * one of the Arc's own formats (there are several). */ static const int8 vdic_table[128] = { /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 24 */ 1, 1, 1, 1, 1, 1, 1, 1, /* 32 */ 1, 1, 1, 1, 2, 2, 2, 2, /* 40 */ 2, 2, 2, 2, 3, 3, 3, 3, /* 48 */ 3, 3, 4, 4, 4, 4, 5, 5, /* 56 */ 5, 5, 6, 6, 6, 6, 7, 7, /* 64 */ 7, 8, 8, 9, 9, 10, 10, 11, /* 72 */ 11, 12, 12, 13, 13, 14, 14, 15, /* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, /* 88 */ 23, 24, 25, 26, 27, 28, 29, 30, /* 96 */ 31, 33, 34, 36, 38, 40, 42, 44, /* 104 */ 46, 48, 50, 52, 54, 56, 58, 60, /* 112 */ 62, 65, 68, 72, 77, 80, 84, 91, /* 120 */ 95, 98, 103, 109, 114, 120, 126, 127 }; /* Convert 7 bit samples to 8 bit */ static void convert_7bit_to_8bit(uint8 *p, int l) { for (; l--; p++) { *p <<= 1; } } /* Convert Archimedes VIDC samples to linear */ static void convert_vidc_to_linear(uint8 *p, int l) { int i; uint8 x; for (i = 0; i < l; i++) { x = p[i]; p[i] = vdic_table[x >> 1]; if (x & 0x01) p[i] *= -1; } } static void adpcm4_decoder(uint8 *inp, uint8 *outp, char *tab, int len) { char delta = 0; uint8 b0, b1; int i; len = (len + 1) / 2; for (i = 0; i < len; i++) { b0 = *inp; b1 = *inp++ >> 4; delta += tab[b0 & 0x0f]; *outp++ = delta; delta += tab[b1 & 0x0f]; *outp++ = delta; } } #endif /* Convert differential to absolute sample data */ static void convert_delta(uint8 *p, int l, int r) { uint16 *w = (uint16 *)p; uint16 abs = 0; if (r) { for (; l--;) { abs = *w + abs; *w++ = abs; } } else { for (; l--;) { abs = *p + abs; *p++ = (uint8) abs; } } } /* Convert signed to unsigned sample data */ static void convert_signal(uint8 *p, int l, int r) { uint16 *w = (uint16 *)p; if (r) { for (; l--; w++) *w += 0x8000; } else { for (; l--; p++) *p += (char)0x80; /* cast needed by MSVC++ */ } } /* Convert little-endian 16 bit samples to big-endian */ static void convert_endian(uint8 *p, int l) { uint8 b; int i; for (i = 0; i < l; i++) { b = p[0]; p[0] = p[1]; p[1] = b; p += 2; } } #if 0 /* Downmix stereo samples to mono */ static void convert_stereo_to_mono(uint8 *p, int l, int r) { int16 *b = (int16 *)p; int i; if (r) { l /= 2; for (i = 0; i < l; i++) b[i] = (b[i * 2] + b[i * 2 + 1]) / 2; } else { for (i = 0; i < l; i++) p[i] = (p[i * 2] + p[i * 2 + 1]) / 2; } } #endif static void unroll_loop(struct xmp_sample *xxs) { int8 *s8; int16 *s16; int start, loop_size; int i; s16 = (int16 *)xxs->data; s8 = (int8 *)xxs->data; if (xxs->len > xxs->lpe) { start = xxs->lpe; } else { start = xxs->len; } loop_size = xxs->lpe - xxs->lps; if (xxs->flg & XMP_SAMPLE_16BIT) { s16 += start; for (i = 0; i < loop_size; i++) { *(s16 + i) = *(s16 - i - 1); } } else { s8 += start; for (i = 0; i < loop_size; i++) { *(s8 + i) = *(s8 - i - 1); } } } int libxmp_load_sample(struct module_data *m, HIO_HANDLE *f, int flags, struct xmp_sample *xxs, void *buffer) { int bytelen, extralen, unroll_extralen, i; #ifndef LIBXMP_CORE_PLAYER /* Adlib FM patches */ if (flags & SAMPLE_FLAG_ADLIB) { return 0; } #endif /* Empty or invalid samples */ if (xxs->len <= 0) { return 0; } /* Skip sample loading * FIXME: fails for ADPCM samples * * + Sanity check: skip huge samples (likely corrupt module) */ if (xxs->len > MAX_SAMPLE_SIZE || (m && m->smpctl & XMP_SMPCTL_SKIP)) { if (~flags & SAMPLE_FLAG_NOLOAD) { /* coverity[check_return] */ hio_seek(f, xxs->len, SEEK_CUR); } return 0; } /* Loop parameters sanity check */ if (xxs->lps < 0) { xxs->lps = 0; } if (xxs->lpe > xxs->len) { xxs->lpe = xxs->len; } if (xxs->lps >= xxs->len || xxs->lps >= xxs->lpe) { xxs->lps = xxs->lpe = 0; xxs->flg &= ~(XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR); } /* Patches with samples * Allocate extra sample for interpolation. */ bytelen = xxs->len; extralen = 4; unroll_extralen = 0; /* Disable birectional loop flag if sample is not looped */ if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { if (~xxs->flg & XMP_SAMPLE_LOOP) xxs->flg &= ~XMP_SAMPLE_LOOP_BIDIR; } /* Unroll bidirectional loops */ if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { unroll_extralen = (xxs->lpe - xxs->lps) - (xxs->len - xxs->lpe); if (unroll_extralen < 0) { unroll_extralen = 0; } } if (xxs->flg & XMP_SAMPLE_16BIT) { bytelen *= 2; extralen *= 2; unroll_extralen *= 2; } /* add guard bytes before the buffer for higher order interpolation */ xxs->data = malloc(bytelen + extralen + unroll_extralen + 4); if (xxs->data == NULL) { goto err; } *(uint32 *)xxs->data = 0; xxs->data += 4; if (flags & SAMPLE_FLAG_NOLOAD) { memcpy(xxs->data, buffer, bytelen); } else #ifndef LIBXMP_CORE_PLAYER if (flags & SAMPLE_FLAG_ADPCM) { int x2 = (bytelen + 1) >> 1; char table[16]; if (hio_read(table, 1, 16, f) != 16) { goto err2; } if (hio_read(xxs->data + x2, 1, x2, f) != x2) { goto err2; } adpcm4_decoder((uint8 *)xxs->data + x2, (uint8 *)xxs->data, table, bytelen); } else #endif { int x = hio_read(xxs->data, 1, bytelen, f); if (x != bytelen) { D_(D_WARN "short read (%d) in sample load", x - bytelen); memset(xxs->data + x, 0, bytelen - x); } } #ifndef LIBXMP_CORE_PLAYER if (flags & SAMPLE_FLAG_7BIT) { convert_7bit_to_8bit(xxs->data, xxs->len); } #endif /* Fix endianism if needed */ if (xxs->flg & XMP_SAMPLE_16BIT) { #ifdef WORDS_BIGENDIAN if (~flags & SAMPLE_FLAG_BIGEND) convert_endian(xxs->data, xxs->len); #else if (flags & SAMPLE_FLAG_BIGEND) convert_endian(xxs->data, xxs->len); #endif } /* Convert delta samples */ if (flags & SAMPLE_FLAG_DIFF) { convert_delta(xxs->data, xxs->len, xxs->flg & XMP_SAMPLE_16BIT); } else if (flags & SAMPLE_FLAG_8BDIFF) { int len = xxs->len; if (xxs->flg & XMP_SAMPLE_16BIT) { len *= 2; } convert_delta(xxs->data, len, 0); } /* Convert samples to signed */ if (flags & SAMPLE_FLAG_UNS) { convert_signal(xxs->data, xxs->len, xxs->flg & XMP_SAMPLE_16BIT); } #if 0 /* Downmix stereo samples */ if (flags & SAMPLE_FLAG_STEREO) { convert_stereo_to_mono(xxs->data, xxs->len, xxs->flg & XMP_SAMPLE_16BIT); xxs->len /= 2; } #endif #ifndef LIBXMP_CORE_PLAYER if (flags & SAMPLE_FLAG_VIDC) { convert_vidc_to_linear(xxs->data, xxs->len); } #endif /* Check for full loop samples */ if (flags & SAMPLE_FLAG_FULLREP) { if (xxs->lps == 0 && xxs->len > xxs->lpe) xxs->flg |= XMP_SAMPLE_LOOP_FULL; } /* Unroll bidirectional loops */ if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { unroll_loop(xxs); bytelen += unroll_extralen; } /* Add extra samples at end */ if (xxs->flg & XMP_SAMPLE_16BIT) { for (i = 0; i < 8; i++) { xxs->data[bytelen + i] = xxs->data[bytelen - 2 + i]; } } else { for (i = 0; i < 4; i++) { xxs->data[bytelen + i] = xxs->data[bytelen - 1 + i]; } } /* Add extra samples at start */ if (xxs->flg & XMP_SAMPLE_16BIT) { xxs->data[-2] = xxs->data[0]; xxs->data[-1] = xxs->data[1]; } else { xxs->data[-1] = xxs->data[0]; } /* Fix sample at loop */ if (xxs->flg & XMP_SAMPLE_LOOP) { int lpe = xxs->lpe; int lps = xxs->lps; if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) { lpe += lpe - lps; } if (xxs->flg & XMP_SAMPLE_16BIT) { lpe <<= 1; lps <<= 1; for (i = 0; i < 8; i++) { xxs->data[lpe + i] = xxs->data[lps + i]; } } else { for (i = 0; i < 4; i++) { xxs->data[lpe + i] = xxs->data[lps + i]; } } } return 0; #ifndef LIBXMP_CORE_PLAYER err2: free(xxs->data - 4); #endif err: return -1; } libxmp-4.4.1/src/loaders/pw_load.c0000664000175000017500000001242312774567167016700 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #ifdef __native_client__ #include #else #include #endif #include "loader.h" #include "mod.h" #include "period.h" #include "prowizard/prowiz.h" #include "tempfile.h" extern struct list_head *checked_format; static int pw_test(HIO_HANDLE *, char *, const int); static int pw_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_pw = { "prowizard", pw_test, pw_load }; #define BUF_SIZE 0x10000 int pw_test_format(HIO_HANDLE *f, char *t, const int start, struct xmp_test_info *info) { unsigned char *b; int extra; int s = BUF_SIZE; b = calloc(1, BUF_SIZE); if (b == NULL) return -1; s = hio_read(b, 1, s, f); while ((extra = pw_check(b, s, info)) > 0) { unsigned char *buf = realloc(b, s + extra); if (buf == NULL) { free(b); return -1; } b = buf; if (hio_read(b + s, extra, 1, f) == 0) { free(b); return -1; } s += extra; } free(b); return extra == 0 ? 0 : -1; } static int pw_test(HIO_HANDLE *f, char *t, const int start) { return pw_test_format(f, t, start, NULL); } static int pw_load(struct module_data *m, HIO_HANDLE *h, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event; struct mod_header mh; uint8 mod_event[4]; HIO_HANDLE *f; FILE *temp; char *name; char *temp_name; int i, j; /* Prowizard depacking */ if ((temp = make_temp_file(&temp_name)) == NULL) { goto err; } if (pw_wizardry(h, temp, &name) < 0) { fclose(temp); goto err2; } /* Module loading */ if ((f = hio_open_file(temp)) == NULL) { goto err2; } if (hio_seek(f, 0, start) < 0) { goto err3; } hio_read(&mh.name, 20, 1, f); for (i = 0; i < 31; i++) { hio_read(&mh.ins[i].name, 22, 1, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(&mh.order, 128, 1, f); hio_read(&mh.magic, 4, 1, f); if (memcmp(mh.magic, "M.K.", 4)) { goto err3; } mod->ins = 31; mod->smp = mod->ins; mod->chn = 4; mod->len = mh.len; mod->rst = mh.restart; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; mod->trk = mod->chn * mod->pat; snprintf(mod->name, XMP_NAME_SIZE, "%s", (char *)mh.name); snprintf(mod->type, XMP_NAME_SIZE, "%s", name); MODULE_INFO(); if (libxmp_init_instrument(m) < 0) { goto err3; } for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) goto err3; mod->xxs[i].len = 2 * mh.ins[i].size; mod->xxs[i].lps = 2 * mh.ins[i].loop_start; mod->xxs[i].lpe = mod->xxs[i].lps + 2 * mh.ins[i].loop_size; mod->xxs[i].flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].fin = (int8) (mh.ins[i].finetune << 4); mod->xxi[i].sub[0].vol = mh.ins[i].volume; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxi[i].rls = 0xfff; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; libxmp_instrument_name(mod, i, mh.ins[i].name, 22); D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mh.ins[i].loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); } if (libxmp_init_pattern(mod) < 0) { goto err3; } /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) goto err3; for (j = 0; j < (64 * 4); j++) { event = &EVENT(i, j % 4, j / 4); hio_read(mod_event, 1, 4, f); libxmp_decode_protracker_event(event, mod_event); } } m->period_type = PERIOD_MODRNG; /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) goto err3; } hio_close(f); unlink_temp_file(temp_name); return 0; err3: hio_close(f); err2: unlink_temp_file(temp_name); err: return -1; } libxmp-4.4.1/src/loaders/masi_load.c0000664000175000017500000004457712775035311017200 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Originally based on the PSM loader from Modplug by Olivier Lapicque and * fixed comparing the One Must Fall! PSMs with Kenny Chou's MTM files. */ /* * From EPICTEST Readme.1st: * * The Music And Sound Interface, MASI, is the basis behind all new Epic * games. MASI uses its own proprietary file format, PSM, for storing * its music. */ /* * kode54's comment on Sinaria PSMs in the foo_dumb hydrogenaudio forum: * * "The Sinaria variant uses eight character pattern and instrument IDs, * the sample headers are laid out slightly different, and the patterns * use a different format for the note values, and also different effect * scales for certain commands. * * [Epic] PSM uses high nibble for octave and low nibble for note, for * a valid range up to 0x7F, for a range of D-1 through D#9 compared to * IT. (...) Sinaria PSM uses plain note values, from 1 - 83, for a * range of C-3 through B-9. * * [Epic] PSM also uses an effect scale for portamento, volume slides, * and vibrato that is about four times as sensitive as the IT equivalents. * Sinaria does not. This seems to coincide with the MOD/S3M to PSM * converter that Joshua Jensen released in the EPICTEST.ZIP file which * can still be found on a few FTP sites. It converted effects literally, * even though the bundled players behaved as the libraries used with * Epic's games did and made the effects sound too strong." */ /* * Claudio's note: Sinaria seems to have a finetune byte just before * volume and some kind of (stereo?) interleaved sample, with 16-byte * frames (see Sinaria songs 5 and 8). Sinaria song 10 still sounds * ugly, maybe caused by finetune issues? */ #include #include "loader.h" #include "iff.h" #include "period.h" #define MAGIC_PSM_ MAGIC4('P','S','M',' ') #define MAGIC_FILE MAGIC4('F','I','L','E') #define MAGIC_TITL MAGIC4('T','I','T','L') #define MAGIC_OPLH MAGIC4('O','P','L','H') #define MAGIC_PPAN MAGIC4('P','P','A','N') static int masi_test (HIO_HANDLE *, char *, const int); static int masi_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_masi = { "Epic MegaGames MASI", masi_test, masi_load }; static int masi_test(HIO_HANDLE *f, char *t, const int start) { int val; if (hio_read32b(f) != MAGIC_PSM_) return -1; hio_read8(f); hio_read8(f); hio_read8(f); if (hio_read8(f) != 0) return -1; if (hio_read32b(f) != MAGIC_FILE) return -1; hio_read32b(f); val = hio_read32l(f); hio_seek(f, val, SEEK_CUR); if (hio_read32b(f) == MAGIC_TITL) { val = hio_read32l(f); libxmp_read_title(f, t, val); } else { libxmp_read_title(f, t, 0); } return 0; } struct local_data { int sinaria; int cur_pat; int cur_ins; uint8 *pnam; uint8 *pord; }; static int get_sdft(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { return 0; } static int get_titl(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; char buf[40]; hio_read(buf, 1, 40, f); strncpy(mod->name, buf, size > 32 ? 32 : size); return 0; } static int get_dsmp_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; mod->ins++; mod->smp = mod->ins; return 0; } static int get_pbod_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; char buf[20]; mod->pat++; hio_read(buf, 1, 20, f); if (buf[9] != 0 && buf[13] == 0) data->sinaria = 1; return 0; } static int get_dsmp(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi; struct xmp_subinstrument *sub; struct xmp_sample *xxs; struct local_data *data = (struct local_data *)parm; int i, srate, flags; int finetune; flags = hio_read8(f); /* flags */ hio_seek(f, 8, SEEK_CUR); /* songname */ hio_seek(f, data->sinaria ? 8 : 4, SEEK_CUR); /* smpid */ i = data->cur_ins; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; xxi = &mod->xxi[i]; sub = &xxi->sub[0]; xxs = &mod->xxs[i]; hio_read(&xxi->name, 1, 31, f); hio_seek(f, 8, SEEK_CUR); hio_read8(f); /* insno */ hio_read8(f); xxs->len = hio_read32l(f); xxs->lps = hio_read32l(f); xxs->lpe = hio_read32l(f); xxs->flg = flags & 0x80 ? XMP_SAMPLE_LOOP : 0; hio_read16l(f); if ((int32)xxs->lpe < 0) xxs->lpe = 0; if (xxs->len > 0) xxi->nsm = 1; finetune = 0; if (data->sinaria) { finetune = (int8)(hio_read8s(f) << 4); } sub->vol = hio_read8(f) / 2 + 1; hio_read32l(f); sub->pan = 0x80; sub->sid = i; srate = hio_read16l(f); D_(D_INFO "[%2X] %-32.32s %05x %05x %05x %c V%02x %+04d %5d", i, xxi->name, xxs->len, xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, finetune, srate); libxmp_c2spd_to_note(srate, &sub->xpo, &sub->fin); sub->fin += finetune; hio_seek(f, 16, SEEK_CUR); if (libxmp_load_sample(m, f, SAMPLE_FLAG_8BDIFF, xxs, NULL) < 0) return -1; data->cur_ins++; return 0; } static uint8 convert_porta(uint8 param, int sinaria) { if (sinaria) { return param; } if (param < 4) { return param | 0xf0; } else { return param >> 2; } } static int get_pbod(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i, r; struct xmp_event *event, dummy; uint8 flag, chan; /* uint32 len; */ int rows, rowlen; i = data->cur_pat; /*len =*/ hio_read32l(f); hio_read(data->pnam + i * 8, 1, data->sinaria ? 8 : 4, f); rows = hio_read16l(f); if (hio_error(f)) { return -1; } if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; r = 0; do { rowlen = hio_read16l(f) - 2; if (hio_error(f)) { return -1; } while (rowlen > 0) { flag = hio_read8(f); if (rowlen == 1) break; chan = hio_read8(f); rowlen -= 2; event = chan < mod->chn ? &EVENT(i, chan, r) : &dummy; if (flag & 0x80) { uint8 note = hio_read8(f); rowlen--; if (data->sinaria) note += 36; else note = (note >> 4) * 12 + (note & 0x0f) + 1 + 12; event->note = note; } if (flag & 0x40) { event->ins = hio_read8(f) + 1; rowlen--; } if (flag & 0x20) { event->vol = hio_read8(f) / 2 + 1; rowlen--; } if (flag & 0x10) { uint8 fxt = hio_read8(f); uint8 fxp = hio_read8(f); rowlen -= 2; #if 0 /* compressed events */ if (fxt >= 0x40) { switch (fxp >> 4) { case 0x0: { uint8 note; note = (fxt>>4)*12 + (fxt & 0x0f) + 1; event->note = note; fxt = FX_TONEPORTA; fxp = (fxp + 1) * 2; break; } default: D_(D_CRIT "p%d r%d c%d: compressed event %02x %02x\n", i, r, chan, fxt, fxp); return -1; } } else #endif switch (fxt) { /* Volume slide */ case 0x01: /* fine volslide up */ fxt = FX_EXTENDED; fxp = (EX_F_VSLIDE_UP << 4) | ((fxp / 2) & 0x0f); break; case 0x02: /* volslide up */ fxt = FX_VOLSLIDE; fxp = (fxp / 2) << 4; break; case 0x03: /* fine volslide down */ fxt = FX_EXTENDED; fxp = (EX_F_VSLIDE_DN << 4) | ((fxp / 2) & 0x0f); break; case 0x04: /* volslide down */ fxt = FX_VOLSLIDE; fxp /= 2; break; /* Portamento */ case 0x0b: /* fine portamento up */ fxt = FX_PORTA_UP; fxp = (EX_F_PORTA_UP << 4) | convert_porta(fxp, data->sinaria); break; case 0x0c: /* portamento up */ fxt = FX_PORTA_UP; fxp = convert_porta(fxp, data->sinaria); break; case 0x0d: /* fine portamento up */ fxt = FX_PORTA_DN; fxp = (EX_F_PORTA_DN << 4) | convert_porta(fxp, data->sinaria); break; case 0x0e: /* portamento down */ fxt = FX_PORTA_DN; fxp = convert_porta(fxp, data->sinaria); break; case 0x0f: /* tone portamento */ fxt = FX_TONEPORTA; fxp >>= 2; break; case 0x10: /* toneporta + vslide up */ fxt = FX_TONE_VSLIDE; fxp = fxt & 0xf0; break; case 0x11: /* glissando */ fxt = FX_EXTENDED; fxp = (EX_GLISS << 4) | (fxp & 0x0f); break; case 0x12: /* toneporta + vslide down */ fxt = FX_TONE_VSLIDE; fxp >>= 4; break; /* 0x13: S3M S: crashes MASI */ /* Vibrato */ case 0x15: /* vibrato */ fxt = data->sinaria ? FX_VIBRATO : FX_FINE_VIBRATO; /* fxp remains the same */ break; case 0x16: /* vibrato waveform */ fxt = FX_EXTENDED; fxp = (EX_VIBRATO_WF << 4) | (fxp & 0x0f); break; case 0x17: /* vibrato + vslide up */ fxt = FX_VIBRA_VSLIDE; fxp >>= 4; break; case 0x18: /* vibrato + vslide down */ fxt = FX_VIBRA_VSLIDE; fxp = fxp & 0x0f; break; /* Tremolo */ case 0x1f: /* tremolo */ fxt = FX_TREMOLO; /* fxp remains the same */ break; case 0x20: /* tremolo waveform */ fxt = FX_EXTENDED; fxp = (EX_TREMOLO_WF << 4) | (fxp & 0x0f); break; /* Sample commands */ case 0x29: /* 3-byte offset */ fxt = FX_OFFSET; /* use only the middle byte */ fxp = hio_read8(f); hio_read8(f); rowlen -= 2; break; case 0x2a: /* retrig note */ fxt = FX_EXTENDED; fxp = (EX_RETRIG << 4) | (fxp & 0x0f); break; case 0x2b: /* note cut */ fxt = FX_EXTENDED; fxp = (EX_CUT << 4) | (fxp & 0x0f); break; case 0x2c: /* note delay */ fxt = FX_EXTENDED; fxp = (EX_DELAY << 4) | (fxp & 0x0f); break; /* Position change */ case 0x33: /* position jump */ /* not used in MASI */ fxt = FX_JUMP; fxp >>= 1; hio_read8(f); rowlen--; break; case 0x34: /* pattern break */ /* not used in MASI */ fxt = FX_BREAK; break; case 0x35: /* pattern loop */ fxt = FX_EXTENDED; fxp = (EX_PATTERN_LOOP << 4) | (fxp & 0x0f); break; case 0x36: /* pattern delay */ fxt = FX_EXTENDED; fxp = (EX_PATT_DELAY << 4) | (fxp & 0x0f); break; /* Speed change */ case 0x3d: /* speed */ fxt = FX_SPEED; break; case 0x3e: /* tempo */ fxt = FX_SPEED; break; /* Other */ case 0x47: /* arpeggio */ fxt = FX_S3M_ARPEGGIO; break; case 0x48: /* set finetune */ fxt = FX_EXTENDED; fxp = (EX_FINETUNE << 4) | (fxp & 0x0f); break; case 0x49: /* set pan */ fxt = FX_SETPAN; fxp <<= 4; break; default: D_(D_CRIT "p%d r%d c%d: unknown effect %02x %02x\n", i, r, chan, fxt, fxp); fxt = fxp = 0; } event->fxt = fxt; event->fxp = fxp; } } r++; } while (r < rows); data->cur_pat++; return 0; } static int get_song(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; hio_seek(f, 10, SEEK_CUR); mod->chn = hio_read8(f); return 0; } static int subchunk_oplh(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int first_order_chunk = INT_MAX; int num_chunk, i; /* First two bytes = Number of chunks that follow */ num_chunk = hio_read16l(f); /* Sub sub chunks */ for (i = 0; i < num_chunk && size > 0; i++) { int opcode = hio_read8(f); size--; if (opcode == 0) { /* last sub sub chunk */ break; } /* Saga Musix's note in OpenMPT: * * "This is more like a playlist than a collection of global * values. In theory, a tempo item inbetween two order items * should modify the tempo when switching patterns. No module * uses this feature in practice though, so we can keep our * loader simple. Unimplemented opcodes do nothing or freeze * MASI." */ switch (opcode) { case 0x01: /* Play order list item */ hio_read(data->pord + mod->len * 8, 1, data->sinaria ? 8 : 4, f); size -= data->sinaria ? 8 : 4; mod->len++; if (first_order_chunk == INT_MAX) { first_order_chunk = i; } break; /* 0x02: Play range */ /* 0x03: Jump loop */ case 0x04: { /* Jump line (restart position) */ int restart_chunk = hio_read16l(f); size -= 2; /* This jumps to the command line, but since we're converting * play order list items to our order list, only change the * restart position if it's after the first order chunk. */ if (restart_chunk >= first_order_chunk) { mod->rst = restart_chunk - first_order_chunk; } break; } /* 0x05: Channel flip */ /* 0x06: Transpose */ case 0x07: /* Default speed */ mod->spd = hio_read8(f); size--; break; case 0x08: /* Default tempo */ mod->bpm = hio_read8(f); size--; break; case 0x0c: /* Sample map table */ hio_read16l(f); hio_read16l(f); hio_read16l(f); size -= 6; break; case 0x0d: { /* Channel panning table */ int chn = hio_read8(f); int pan = hio_read8(f); int type = hio_read8(f); struct xmp_channel *xxc; if (chn >= XMP_MAX_CHANNELS) { break; } xxc = &mod->xxc[chn]; size -= 3; switch (type) { case 0: /* use panning */ xxc->pan = pan ^ 0x80; break; case 2: /* surround */ xxc->pan = 0x80; xxc->flg |= XMP_CHANNEL_SURROUND; break; case 4: /* center */ xxc->pan = 0x80; break; } break; } case 0x0e: { /* Channel volume table */ int chn = hio_read8(f); int vol = hio_read8(f); struct xmp_channel *xxc; if (chn >= XMP_MAX_CHANNELS) { break; } xxc = &mod->xxc[chn]; size -= 2; xxc->vol = (vol >> 2) + 1; break; } default: /*printf("channel %d: %02x %02x\n", i, c, hio_read8(f));*/ return -1; } } return 0; } /* Sinaria channel panning table */ static int subchunk_ppan(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; for (i = 0; i < XMP_MAX_CHANNELS && size > 0; i++) { struct xmp_channel *xxc = &mod->xxc[i]; int type = hio_read8(f); int pan = hio_read8(f); size -= 2; switch (type) { case 0: /* use panning */ xxc->pan = pan ^ 0x80; break; case 2: /* surround */ xxc->pan = 0x80; xxc->flg |= XMP_CHANNEL_SURROUND; break; case 4: /* center */ xxc->pan = 0x80; break; } } return 0; } /* Subchunk loader based on OpenMPT LoadPSM.cpp */ static int get_song_2(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { uint32 magic; char buf[20]; hio_read(buf, 1, 9, f); hio_read16l(f); size -= 11; D_(D_INFO "Subsong title: %-9.9s", buf); /* Iterate over subchunks. We want OPLH and PPAN */ while (size > 0) { magic = hio_read32b(f); int subchunk_size = hio_read32l(f); if (subchunk_size == 0) { return -1; } size -= subchunk_size; switch (magic) { case MAGIC_OPLH: if (subchunk_oplh(m, size, f, parm) < 0) { return -1; } break; case MAGIC_PPAN: if (subchunk_ppan(m, size, f, parm) < 0) { return -1; } break; default: hio_seek(f, subchunk_size, SEEK_CUR); } } return 0; } static int masi_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; iff_handle handle; int ret, offset; int i, j; struct local_data data; LOAD_INIT(); hio_read32b(f); data.sinaria = 0; mod->name[0] = 0; hio_seek(f, 8, SEEK_CUR); /* skip file size and FILE */ mod->smp = mod->ins = 0; data.cur_pat = 0; data.cur_ins = 0; offset = hio_tell(f); handle = libxmp_iff_new(); if (handle == NULL) goto err; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "TITL", get_titl); ret |= libxmp_iff_register(handle, "SDFT", get_sdft); ret |= libxmp_iff_register(handle, "SONG", get_song); ret |= libxmp_iff_register(handle, "DSMP", get_dsmp_cnt); ret |= libxmp_iff_register(handle, "PBOD", get_pbod_cnt); if (ret != 0) goto err; libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); goto err; } libxmp_iff_release(handle); mod->trk = mod->pat * mod->chn; data.pnam = malloc(mod->pat * 8); /* pattern names */ if (data.pnam == NULL) goto err; data.pord = malloc(255 * 8); /* pattern orders */ if (data.pord == NULL) goto err2; libxmp_set_type(m, data.sinaria ? "Sinaria PSM" : "Epic MegaGames MASI PSM"); m->c4rate = C4_NTSC_RATE; MODULE_INFO(); if (libxmp_init_instrument(m) < 0) goto err3; if (libxmp_init_pattern(mod) < 0) goto err3; D_(D_INFO "Stored patterns: %d", mod->pat); D_(D_INFO "Stored samples : %d", mod->smp); hio_seek(f, start + offset, SEEK_SET); mod->len = 0; handle = libxmp_iff_new(); if (handle == NULL) goto err3; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "SONG", get_song_2); ret |= libxmp_iff_register(handle, "DSMP", get_dsmp); ret |= libxmp_iff_register(handle, "PBOD", get_pbod); if (ret != 0) goto err3; libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); goto err3; } libxmp_iff_release(handle); for (i = 0; i < mod->len; i++) { for (j = 0; j < mod->pat; j++) { if (!memcmp(data.pord + i * 8, data.pnam + j * 8, data.sinaria ? 8 : 4)) { mod->xxo[i] = j; break; } } if (j == mod->pat) break; } free(data.pord); free(data.pnam); return 0; err3: free(data.pord); err2: free(data.pnam); err: return -1; } libxmp-4.4.1/src/loaders/it.h0000664000175000017500000001345512773463501015664 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* IT flags */ #define IT_STEREO 0x01 #define IT_VOL_OPT 0x02 /* Not recognized */ #define IT_USE_INST 0x04 #define IT_LINEAR_FREQ 0x08 #define IT_OLD_FX 0x10 #define IT_LINK_GXX 0x20 /* IT special */ #define IT_HAS_MSG 0x01 /* IT instrument flags */ #define IT_INST_SAMPLE 0x01 #define IT_INST_16BIT 0x02 #define IT_INST_STEREO 0x04 #define IT_INST_LOOP 0x10 #define IT_INST_SLOOP 0x20 #define IT_INST_BLOOP 0x40 #define IT_INST_BSLOOP 0x80 /* IT sample flags */ #define IT_SMP_SAMPLE 0x01 #define IT_SMP_16BIT 0x02 #define IT_SMP_STEREO 0x04 /* unsupported */ #define IT_SMP_COMP 0x08 /* unsupported */ #define IT_SMP_LOOP 0x10 #define IT_SMP_SLOOP 0x20 #define IT_SMP_BLOOP 0x40 #define IT_SMP_BSLOOP 0x80 /* IT sample conversion flags */ #define IT_CVT_SIGNED 0x01 #define IT_CVT_BIGEND 0x02 /* 'safe to ignore' according to ittech.txt */ #define IT_CVT_DIFF 0x04 /* Compressed sample flag */ #define IT_CVT_BYTEDIFF 0x08 /* 'safe to ignore' according to ittech.txt */ #define IT_CVT_12BIT 0x10 /* 'safe to ignore' according to ittech.txt */ /* IT envelope flags */ #define IT_ENV_ON 0x01 #define IT_ENV_LOOP 0x02 #define IT_ENV_SLOOP 0x04 #define IT_ENV_CARRY 0x08 #define IT_ENV_FILTER 0x80 struct it_file_header { uint32 magic; /* 'IMPM' */ uint8 name[26]; /* ASCIIZ Song name */ uint8 hilite_min; /* Pattern editor highlight */ uint8 hilite_maj; /* Pattern editor highlight */ uint16 ordnum; /* Number of orders (must be even) */ uint16 insnum; /* Number of instruments */ uint16 smpnum; /* Number of samples */ uint16 patnum; /* Number of patterns */ uint16 cwt; /* Tracker ID and version */ uint16 cmwt; /* Format version */ uint16 flags; /* Flags */ uint16 special; /* More flags */ uint8 gv; /* Global volume */ uint8 mv; /* Master volume */ uint8 is; /* Initial speed */ uint8 it; /* Initial tempo */ uint8 sep; /* Panning separation */ uint8 pwd; /* Pitch wheel depth */ uint16 msglen; /* Message length */ uint32 msgofs; /* Message offset */ uint32 rsvd; /* Reserved */ uint8 chpan[64]; /* Channel pan settings */ uint8 chvol[64]; /* Channel volume settings */ }; struct it_instrument1_header { uint32 magic; /* 'IMPI' */ uint8 dosname[12]; /* DOS filename */ uint8 zero; /* Always zero */ uint8 flags; /* Instrument flags */ uint8 vls; /* Volume loop start */ uint8 vle; /* Volume loop end */ uint8 sls; /* Sustain loop start */ uint8 sle; /* Sustain loop end */ uint16 rsvd1; /* Reserved */ uint16 fadeout; /* Fadeout (release) */ uint8 nna; /* New note action */ uint8 dnc; /* Duplicate note check */ uint16 trkvers; /* Tracker version */ uint8 nos; /* Number of samples */ uint8 rsvd2; /* Reserved */ uint8 name[26]; /* ASCIIZ Instrument name */ uint8 rsvd3[6]; /* Reserved */ uint8 keys[240]; uint8 epoint[200]; uint8 enode[50]; }; struct it_instrument2_header { uint32 magic; /* 'IMPI' */ uint8 dosname[12]; /* DOS filename */ uint8 zero; /* Always zero */ uint8 nna; /* New Note Action */ uint8 dct; /* Duplicate Check Type */ uint8 dca; /* Duplicate Check Action */ uint16 fadeout; uint8 pps; /* Pitch-Pan Separation */ uint8 ppc; /* Pitch-Pan Center */ uint8 gbv; /* Global Volume */ uint8 dfp; /* Default pan */ uint8 rv; /* Random volume variation */ uint8 rp; /* Random pan variation */ uint16 trkvers; /* Not used: tracked version */ uint8 nos; /* Not used: number of samples */ uint8 rsvd1; /* Reserved */ uint8 name[26]; /* ASCIIZ Instrument name */ uint8 ifc; /* Initial filter cutoff */ uint8 ifr; /* Initial filter resonance */ uint8 mch; /* MIDI channel */ uint8 mpr; /* MIDI program */ uint16 mbnk; /* MIDI bank */ uint8 keys[240]; }; struct it_envelope_node { int8 y; uint16 x; }; struct it_envelope { uint8 flg; /* Flags */ uint8 num; /* Number of node points */ uint8 lpb; /* Loop beginning */ uint8 lpe; /* Loop end */ uint8 slb; /* Sustain loop beginning */ uint8 sle; /* Sustain loop end */ struct it_envelope_node node[25]; uint8 unused; }; struct it_sample_header { uint32 magic; /* 'IMPS' */ uint8 dosname[12]; /* DOS filename */ uint8 zero; /* Always zero */ uint8 gvl; /* Global volume for instrument */ uint8 flags; /* Sample flags */ uint8 vol; /* Volume */ uint8 name[26]; /* ASCIIZ sample name */ uint8 convert; /* Sample flags */ uint8 dfp; /* Default pan */ uint32 length; /* Length */ uint32 loopbeg; /* Loop begin */ uint32 loopend; /* Loop end */ uint32 c5spd; /* C 5 speed */ uint32 sloopbeg; /* SusLoop begin */ uint32 sloopend; /* SusLoop end */ uint32 sample_ptr; /* Sample pointer */ uint8 vis; /* Vibrato speed */ uint8 vid; /* Vibrato depth */ uint8 vir; /* Vibrato rate */ uint8 vit; /* Vibrato waveform */ }; libxmp-4.4.1/src/loaders/rtm_load.c0000664000175000017500000003202412774567167017053 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "period.h" #ifndef __amigaos4__ typedef uint8 BYTE; typedef uint16 WORD; #endif typedef uint32 DWORD; /* Data structures from the specification of the RTM format version 1.10 by * Arnaud Hasenfratz */ struct ObjectHeader { char id[4]; /* "RTMM", "RTND", "RTIN" or "RTSM" */ char rc; /* 0x20 */ char name[32]; /* object name */ char eof; /* "\x1A" */ WORD version; /* version of the format (actual : 0x110) */ WORD headerSize; /* object header size */ }; struct RTMMHeader { /* Real Tracker Music Module */ char software[20]; /* software used for saving the module */ char composer[32]; WORD flags; /* song flags */ /* bit 0 : linear table, bit 1 : track names present */ BYTE ntrack; /* number of tracks */ BYTE ninstr; /* number of instruments */ WORD nposition; /* number of positions */ WORD npattern; /* number of patterns */ BYTE speed; /* initial speed */ BYTE tempo; /* initial tempo */ char panning[32]; /* initial pannings (for S3M compatibility) */ DWORD extraDataSize; /* length of data after the header */ /* version 1.12 */ char originalName[32]; }; struct RTNDHeader { /* Real Tracker Note Data */ WORD flags; /* Always 1 */ BYTE ntrack; WORD nrows; DWORD datasize; /* Size of packed data */ }; struct EnvelopePoint { long x; long y; }; struct Envelope { BYTE npoint; struct EnvelopePoint point[12]; BYTE sustain; BYTE loopstart; BYTE loopend; WORD flags; /* bit 0 : enable envelope, bit 1 : sustain, bit 2 : loop */ }; struct RTINHeader { /* Real Tracker Instrument */ BYTE nsample; WORD flags; /* bit 0 : default panning enabled bit 1 : mute samples */ BYTE table[120]; /* sample number for each note */ struct Envelope volumeEnv; struct Envelope panningEnv; char vibflg; /* vibrato type */ char vibsweep; /* vibrato sweep */ char vibdepth; /* vibrato depth */ char vibrate; /* vibrato rate */ WORD volfade; /* version 1.10 */ BYTE midiPort; BYTE midiChannel; BYTE midiProgram; BYTE midiEnable; /* version 1.12 */ char midiTranspose; BYTE midiBenderRange; BYTE midiBaseVolume; char midiUseVelocity; }; struct RTSMHeader { /* Real Tracker Sample */ WORD flags; /* bit 1 : 16 bits, bit 2 : delta encoded (always) */ BYTE basevolume; BYTE defaultvolume; DWORD length; BYTE loop; /* =0:no loop, =1:forward loop, =2:bi-directional loop */ BYTE reserved[3]; DWORD loopbegin; DWORD loopend; DWORD basefreq; BYTE basenote; char panning; /* Panning from -64 to 64 */ }; static int rtm_test(HIO_HANDLE *, char *, const int); static int rtm_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_rtm = { "Real Tracker", rtm_test, rtm_load }; static int rtm_test(HIO_HANDLE *f, char *t, const int start) { char buf[4]; if (hio_read(buf, 1, 4, f) < 4) return -1; if (memcmp(buf, "RTMM", 4)) return -1; if (hio_read8(f) != 0x20) return -1; libxmp_read_title(f, t, 32); return 0; } #define MAX_SAMP 1024 static int read_object_header(HIO_HANDLE *f, struct ObjectHeader *h, char *id) { hio_read(&h->id, 4, 1, f); D_(D_WARN "object id: %02x %02x %02x %02x", h->id[0], h->id[1], h->id[2], h->id[3]); if (memcmp(id, h->id, 4)) return -1; h->rc = hio_read8(f); if (h->rc != 0x20) return -1; if (hio_read(&h->name, 1, 32, f) != 32) return -1; h->eof = hio_read8(f); h->version = hio_read16l(f); h->headerSize = hio_read16l(f); D_(D_INFO "object %-4.4s (%d)", h->id, h->headerSize); return 0; } static int rtm_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, r; struct xmp_event *event; struct ObjectHeader oh; struct RTMMHeader rh; struct RTNDHeader rp; struct RTINHeader ri; struct RTSMHeader rs; int offset, smpnum, version; char tracker_name[21], composer[33]; LOAD_INIT(); if (read_object_header(f, &oh, "RTMM") < 0) return -1; version = oh.version; hio_read(tracker_name, 1, 20, f); tracker_name[20] = 0; hio_read(composer, 1, 32, f); composer[32] = 0; rh.flags = hio_read16l(f); /* bit 0: linear table, bit 1: track names */ rh.ntrack = hio_read8(f); rh.ninstr = hio_read8(f); rh.nposition = hio_read16l(f); rh.npattern = hio_read16l(f); rh.speed = hio_read8(f); rh.tempo = hio_read8(f); hio_read(&rh.panning, 32, 1, f); rh.extraDataSize = hio_read32l(f); /* Sanity check */ if (rh.nposition > 255 || rh.ntrack > 32 || rh.npattern > 255) { return -1; } if (version >= 0x0112) hio_seek(f, 32, SEEK_CUR); /* skip original name */ for (i = 0; i < rh.nposition; i++) { mod->xxo[i] = hio_read16l(f); if (mod->xxo[i] >= rh.npattern) { return -1; } } strncpy(mod->name, oh.name, 20); snprintf(mod->type, XMP_NAME_SIZE, "%s RTM %x.%02x", tracker_name, version >> 8, version & 0xff); /* strncpy(m->author, composer, XMP_NAME_SIZE); */ mod->len = rh.nposition; mod->pat = rh.npattern; mod->chn = rh.ntrack; mod->trk = mod->chn * mod->pat; mod->ins = rh.ninstr; mod->spd = rh.speed; mod->bpm = rh.tempo; m->c4rate = C4_NTSC_RATE; m->period_type = rh.flags & 0x01 ? PERIOD_LINEAR : PERIOD_AMIGA; MODULE_INFO(); for (i = 0; i < mod->chn; i++) mod->xxc[i].pan = rh.panning[i] & 0xff; if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); offset = 42 + oh.headerSize + rh.extraDataSize; for (i = 0; i < mod->pat; i++) { uint8 c; hio_seek(f, start + offset, SEEK_SET); if (read_object_header(f, &oh, "RTND") < 0) { D_(D_CRIT "Error reading pattern %d", i); return -1; } rp.flags = hio_read16l(f); rp.ntrack = hio_read8(f); rp.nrows = hio_read16l(f); rp.datasize = hio_read32l(f); /* Sanity check */ if (rp.ntrack > rh.ntrack || rp.nrows > 256) { return -1; } offset += 42 + oh.headerSize + rp.datasize; if (libxmp_alloc_pattern_tracks(mod, i, rp.nrows) < 0) return -1; for (r = 0; r < rp.nrows; r++) { for (j = 0; /*j < rp.ntrack */; j++) { c = hio_read8(f); if (c == 0) /* next row */ break; /* Sanity check */ if (j >= rp.ntrack) { return -1; } event = &EVENT(i, j, r); if (c & 0x01) { /* set track */ j = hio_read8(f); /* Sanity check */ if (j >= rp.ntrack) { return -1; } event = &EVENT(i, j, r); } if (c & 0x02) { /* read note */ event->note = hio_read8(f) + 1; if (event->note == 0xff) { event->note = XMP_KEY_OFF; } else { event->note += 12; } } if (c & 0x04) /* read instrument */ event->ins = hio_read8(f); if (c & 0x08) /* read effect */ event->fxt = hio_read8(f); if (c & 0x10) /* read parameter */ event->fxp = hio_read8(f); if (c & 0x20) /* read effect 2 */ event->f2t = hio_read8(f); if (c & 0x40) /* read parameter 2 */ event->f2p = hio_read8(f); } } } /* * load instruments */ D_(D_INFO "Instruments: %d", mod->ins); hio_seek(f, start + offset, SEEK_SET); /* ESTIMATED value! We don't know the actual value at this point */ mod->smp = MAX_SAMP; if (libxmp_init_instrument(m) < 0) return -1; smpnum = 0; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; if (read_object_header(f, &oh, "RTIN") < 0) { D_(D_CRIT "Error reading instrument %d", i); return -1; } libxmp_instrument_name(mod, i, (uint8 *)&oh.name, 32); if (oh.headerSize == 0) { D_(D_INFO "[%2X] %-26.26s %2d ", i, xxi->name, xxi->nsm); ri.nsample = 0; continue; } ri.nsample = hio_read8(f); ri.flags = hio_read16l(f); /* bit 0 : default panning enabled */ if (hio_read(&ri.table, 1, 120, f) != 120) return -1; ri.volumeEnv.npoint = hio_read8(f); /* Sanity check */ if (ri.volumeEnv.npoint >= 12) return -1; for (j = 0; j < 12; j++) { ri.volumeEnv.point[j].x = hio_read32l(f); ri.volumeEnv.point[j].y = hio_read32l(f); } ri.volumeEnv.sustain = hio_read8(f); ri.volumeEnv.loopstart = hio_read8(f); ri.volumeEnv.loopend = hio_read8(f); ri.volumeEnv.flags = hio_read16l(f); /* bit 0:enable 1:sus 2:loop */ ri.panningEnv.npoint = hio_read8(f); /* Sanity check */ if (ri.panningEnv.npoint >= 12) return -1; for (j = 0; j < 12; j++) { ri.panningEnv.point[j].x = hio_read32l(f); ri.panningEnv.point[j].y = hio_read32l(f); } ri.panningEnv.sustain = hio_read8(f); ri.panningEnv.loopstart = hio_read8(f); ri.panningEnv.loopend = hio_read8(f); ri.panningEnv.flags = hio_read16l(f); ri.vibflg = hio_read8(f); ri.vibsweep = hio_read8(f); ri.vibdepth = hio_read8(f); ri.vibrate = hio_read8(f); ri.volfade = hio_read16l(f); if (version >= 0x0110) { ri.midiPort = hio_read8(f); ri.midiChannel = hio_read8(f); ri.midiProgram = hio_read8(f); ri.midiEnable = hio_read8(f); } if (version >= 0x0112) { ri.midiTranspose = hio_read8(f); ri.midiBenderRange = hio_read8(f); ri.midiBaseVolume = hio_read8(f); ri.midiUseVelocity = hio_read8(f); } xxi->nsm = ri.nsample; D_(D_INFO "[%2X] %-26.26s %2d", i, xxi->name, xxi->nsm); if (xxi->nsm > 16) xxi->nsm = 16; if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) return -1; for (j = 0; j < 120; j++) xxi->map[j].ins = ri.table[j]; /* Envelope */ xxi->rls = ri.volfade; xxi->aei.npt = ri.volumeEnv.npoint; xxi->aei.sus = ri.volumeEnv.sustain; xxi->aei.lps = ri.volumeEnv.loopstart; xxi->aei.lpe = ri.volumeEnv.loopend; xxi->aei.flg = ri.volumeEnv.flags; xxi->pei.npt = ri.panningEnv.npoint; xxi->pei.sus = ri.panningEnv.sustain; xxi->pei.lps = ri.panningEnv.loopstart; xxi->pei.lpe = ri.panningEnv.loopend; xxi->pei.flg = ri.panningEnv.flags; for (j = 0; j < xxi->aei.npt; j++) { xxi->aei.data[j * 2 + 0] = ri.volumeEnv.point[j].x; xxi->aei.data[j * 2 + 1] = ri.volumeEnv.point[j].y / 2; } for (j = 0; j < xxi->pei.npt; j++) { xxi->pei.data[j * 2 + 0] = ri.panningEnv.point[j].x; xxi->pei.data[j * 2 + 1] = 32 + ri.panningEnv.point[j].y / 2; } /* For each sample */ for (j = 0; j < xxi->nsm; j++, smpnum++) { struct xmp_subinstrument *sub = &xxi->sub[j]; struct xmp_sample *xxs; if (read_object_header(f, &oh, "RTSM") < 0) { D_(D_CRIT "Error reading sample %d", j); return -1; } rs.flags = hio_read16l(f); rs.basevolume = hio_read8(f); rs.defaultvolume = hio_read8(f); rs.length = hio_read32l(f); rs.loop = hio_read32l(f); rs.loopbegin = hio_read32l(f); rs.loopend = hio_read32l(f); rs.basefreq = hio_read32l(f); rs.basenote = hio_read8(f); rs.panning = hio_read8(f); libxmp_c2spd_to_note(rs.basefreq, &sub->xpo, &sub->fin); sub->xpo += 48 - rs.basenote; sub->vol = rs.defaultvolume * rs.basevolume / 0x40; sub->pan = 0x80 + rs.panning * 2; sub->vwf = ri.vibflg; sub->vde = ri.vibdepth << 2; sub->vra = ri.vibrate; sub->vsw = ri.vibsweep; sub->sid = smpnum; if (smpnum >= mod->smp) { mod->xxs = libxmp_realloc_samples(mod->xxs, &mod->smp, mod->smp * 3 / 2); if (mod->xxs == NULL) return -1; } xxs = &mod->xxs[smpnum]; libxmp_copy_adjust(xxs->name, (uint8 *)oh.name, 31); xxs->len = rs.length; xxs->lps = rs.loopbegin; xxs->lpe = rs.loopend; xxs->flg = 0; if (rs.flags & 0x02) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } xxs->flg |= rs.loop & 0x03 ? XMP_SAMPLE_LOOP : 0; xxs->flg |= rs.loop == 2 ? XMP_SAMPLE_LOOP_BIDIR : 0; D_(D_INFO " [%1x] %05x%c%05x %05x %c " "V%02x F%+04d P%02x R%+03d", j, xxs->len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ', xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sub->fin, sub->pan, sub->xpo); if (libxmp_load_sample(m, f, SAMPLE_FLAG_DIFF, xxs, NULL) < 0) return -1; } } /* Final sample number adjustment */ mod->xxs = libxmp_realloc_samples(mod->xxs, &mod->smp, smpnum); if (mod->xxs == NULL) return -1; m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; return 0; } libxmp-4.4.1/src/loaders/gal4_load.c0000664000175000017500000002564412775035311017070 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "loader.h" #include "iff.h" #include "period.h" /* Galaxy Music System 4.0 module file loader * * Based on modules converted using mod2j2b.exe */ static int gal4_test(HIO_HANDLE *, char *, const int); static int gal4_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_gal4 = { "Galaxy Music System 4.0", gal4_test, gal4_load }; static int gal4_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC4('R', 'I', 'F', 'F')) return -1; hio_read32b(f); if (hio_read32b(f) != MAGIC4('A', 'M', 'F', 'F')) return -1; if (hio_read32b(f) != MAGIC4('M', 'A', 'I', 'N')) return -1; hio_read32b(f); /* skip size */ libxmp_read_title(f, t, 64); return 0; } struct local_data { int snum; }; static int get_main(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; char buf[64]; int flags; hio_read(buf, 1, 64, f); strncpy(mod->name, buf, 63); /* ensure string terminator */ libxmp_set_type(m, "Galaxy Music System 4.0"); flags = hio_read8(f); if (~flags & 0x01) m->period_type = PERIOD_LINEAR; mod->chn = hio_read8(f); mod->spd = hio_read8(f); mod->bpm = hio_read8(f); hio_read16l(f); /* unknown - 0x01c5 */ hio_read16l(f); /* unknown - 0xff00 */ hio_read8(f); /* unknown - 0x80 */ /* Sanity check */ if (mod->chn > 32) { return -1; } return 0; } static int get_ordr(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; mod->len = hio_read8(f) + 1; if (hio_error(f)) { return -1; } for (i = 0; i < mod->len; i++) { mod->xxo[i] = hio_read8(f); } return 0; } static int get_patt_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; i = hio_read8(f) + 1; /* pattern number */ if (i > mod->pat) mod->pat = i; return 0; } static int get_inst_cnt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; hio_read8(f); /* 00 */ i = hio_read8(f) + 1; /* instrument number */ if (i > mod->ins) mod->ins = i; hio_seek(f, 28, SEEK_CUR); /* skip name */ mod->smp += hio_read8(f); return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct xmp_event *event, dummy; int i, len, chan; int rows, r; uint8 flag; i = hio_read8(f); /* pattern number */ len = hio_read32l(f); /* Sanity check */ if (i >= mod->pat || len <= 0) { return -1; } rows = hio_read8(f) + 1; if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; for (r = 0; r < rows; ) { if ((flag = hio_read8(f)) == 0) { r++; continue; } chan = flag & 0x1f; event = chan < mod->chn ? &EVENT(i, chan, r) : &dummy; if (flag & 0x80) { uint8 fxp = hio_read8(f); uint8 fxt = hio_read8(f); switch (fxt) { case 0x14: /* speed */ fxt = FX_S3M_SPEED; break; default: if (fxt > 0x0f) { printf("unknown effect %02x %02x\n", fxt, fxp); fxt = fxp = 0; } } event->fxt = fxt; event->fxp = fxp; } if (flag & 0x40) { event->ins = hio_read8(f); event->note = hio_read8(f); if (event->note == 128) { event->note = XMP_KEY_OFF; } } if (flag & 0x20) { event->vol = 1 + hio_read8(f) / 2; } } return 9; } static int get_inst(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i, j; int srate, finetune, flags; int val, vwf, vra, vde, vsw, fade; uint8 buf[30]; hio_read8(f); /* 00 */ i = hio_read8(f); /* instrument number */ hio_read(&mod->xxi[i].name, 1, 28, f); mod->xxi[i].nsm = hio_read8(f); for (j = 0; j < 108; j++) { mod->xxi[i].map[j].ins = hio_read8(f); } hio_seek(f, 11, SEEK_CUR); /* unknown */ vwf = hio_read8(f); /* vibrato waveform */ vsw = hio_read8(f); /* vibrato sweep */ hio_read8(f); /* unknown */ hio_read8(f); /* unknown */ vde = hio_read8(f); /* vibrato depth */ vra = hio_read16l(f) / 16; /* vibrato speed */ hio_read8(f); /* unknown */ val = hio_read8(f); /* PV envelopes flags */ if (LSN(val) & 0x01) mod->xxi[i].aei.flg |= XMP_ENVELOPE_ON; if (LSN(val) & 0x02) mod->xxi[i].aei.flg |= XMP_ENVELOPE_SUS; if (LSN(val) & 0x04) mod->xxi[i].aei.flg |= XMP_ENVELOPE_LOOP; if (MSN(val) & 0x01) mod->xxi[i].pei.flg |= XMP_ENVELOPE_ON; if (MSN(val) & 0x02) mod->xxi[i].pei.flg |= XMP_ENVELOPE_SUS; if (MSN(val) & 0x04) mod->xxi[i].pei.flg |= XMP_ENVELOPE_LOOP; val = hio_read8(f); /* PV envelopes points */ mod->xxi[i].aei.npt = LSN(val) + 1; mod->xxi[i].pei.npt = MSN(val) + 1; val = hio_read8(f); /* PV envelopes sustain point */ mod->xxi[i].aei.sus = LSN(val); mod->xxi[i].pei.sus = MSN(val); val = hio_read8(f); /* PV envelopes loop start */ mod->xxi[i].aei.lps = LSN(val); mod->xxi[i].pei.lps = MSN(val); hio_read8(f); /* PV envelopes loop end */ mod->xxi[i].aei.lpe = LSN(val); mod->xxi[i].pei.lpe = MSN(val); if (mod->xxi[i].aei.npt <= 0 || mod->xxi[i].aei.npt >= XMP_MAX_ENV_POINTS) mod->xxi[i].aei.flg &= ~XMP_ENVELOPE_ON; if (mod->xxi[i].pei.npt <= 0 || mod->xxi[i].pei.npt >= XMP_MAX_ENV_POINTS) mod->xxi[i].pei.flg &= ~XMP_ENVELOPE_ON; hio_read(buf, 1, 30, f); /* volume envelope points */; for (j = 0; j < mod->xxi[i].aei.npt; j++) { mod->xxi[i].aei.data[j * 2] = readmem16l(buf + j * 3) / 16; mod->xxi[i].aei.data[j * 2 + 1] = buf[j * 3 + 2]; } hio_read(buf, 1, 30, f); /* pan envelope points */; for (j = 0; j < mod->xxi[i].pei.npt; j++) { mod->xxi[i].pei.data[j * 2] = readmem16l(buf + j * 3) / 16; mod->xxi[i].pei.data[j * 2 + 1] = buf[j * 3 + 2]; } fade = hio_read8(f); /* fadeout - 0x80->0x02 0x310->0x0c */ hio_read8(f); /* unknown */ D_(D_INFO "[%2X] %-28.28s %2d ", i, mod->xxi[i].name, mod->xxi[i].nsm); if (mod->xxi[i].nsm == 0) return 0; if (libxmp_alloc_subinstrument(mod, i, mod->xxi[i].nsm) < 0) return -1; for (j = 0; j < mod->xxi[i].nsm; j++, data->snum++) { hio_read32b(f); /* SAMP */ hio_read32b(f); /* size */ hio_read(&mod->xxs[data->snum].name, 1, 28, f); mod->xxi[i].sub[j].pan = hio_read8(f) * 4; if (mod->xxi[i].sub[j].pan == 0) /* not sure about this */ mod->xxi[i].sub[j].pan = 0x80; mod->xxi[i].sub[j].vol = hio_read8(f); flags = hio_read8(f); hio_read8(f); /* unknown - 0x80 */ mod->xxi[i].sub[j].vwf = vwf; mod->xxi[i].sub[j].vde = vde; mod->xxi[i].sub[j].vra = vra; mod->xxi[i].sub[j].vsw = vsw; mod->xxi[i].sub[j].sid = data->snum; mod->xxs[data->snum].len = hio_read32l(f); mod->xxs[data->snum].lps = hio_read32l(f); mod->xxs[data->snum].lpe = hio_read32l(f); mod->xxs[data->snum].flg = 0; if (flags & 0x04) mod->xxs[data->snum].flg |= XMP_SAMPLE_16BIT; if (flags & 0x08) mod->xxs[data->snum].flg |= XMP_SAMPLE_LOOP; if (flags & 0x10) mod->xxs[data->snum].flg |= XMP_SAMPLE_LOOP_BIDIR; /* if (flags & 0x80) mod->xxs[data->snum].flg |= ? */ srate = hio_read32l(f); finetune = 0; libxmp_c2spd_to_note(srate, &mod->xxi[i].sub[j].xpo, &mod->xxi[i].sub[j].fin); mod->xxi[i].sub[j].fin += finetune; hio_read32l(f); /* 0x00000000 */ hio_read32l(f); /* unknown */ D_(D_INFO " %X: %05x%c%05x %05x %c V%02x P%02x %5d", j, mod->xxs[data->snum].len, mod->xxs[data->snum].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[data->snum].lps, mod->xxs[data->snum].lpe, mod->xxs[data->snum].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : mod->xxs[data->snum].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[j].vol, mod->xxi[i].sub[j].pan, srate); if (mod->xxs[data->snum].len > 1) { int snum = data->snum; if (libxmp_load_sample(m, f, 0, &mod->xxs[snum], NULL) < 0) return -1; } } return 0; } static int gal4_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; iff_handle handle; int i, ret, offset; struct local_data data; LOAD_INIT(); hio_read32b(f); /* Skip RIFF */ hio_read32b(f); /* Skip size */ hio_read32b(f); /* Skip AM */ offset = hio_tell(f); mod->smp = mod->ins = 0; handle = libxmp_iff_new(); if (handle == NULL) return -1; m->c4rate = C4_NTSC_RATE; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "MAIN", get_main); ret |= libxmp_iff_register(handle, "ORDR", get_ordr); ret |= libxmp_iff_register(handle, "PATT", get_patt_cnt); ret |= libxmp_iff_register(handle, "INST", get_inst_cnt); if (ret != 0) return -1; libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); libxmp_iff_set_quirk(handle, IFF_CHUNK_TRUNC4); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); mod->trk = mod->pat * mod->chn; MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d\n", mod->pat); D_(D_INFO "Stored samples : %d ", mod->smp); hio_seek(f, start + offset, SEEK_SET); data.snum = 0; handle = libxmp_iff_new(); if (handle == NULL) return -1; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "PATT", get_patt); ret |= libxmp_iff_register(handle, "INST", get_inst); if (ret != 0) return -1; libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); libxmp_iff_set_quirk(handle, IFF_CHUNK_TRUNC4); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); /* Alloc missing patterns */ for (i = 0; i < mod->pat; i++) { if (mod->xxp[i] == NULL) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) { return -1; } } } for (i = 0; i < mod->chn; i++) { mod->xxc[i].pan = 0x80; } m->quirk |= QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; return 0; } libxmp-4.4.1/src/loaders/digi_load.c0000664000175000017500000001447412774567167017176 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Based on the DIGI Booster player v1.6 by Tap (Tomasz Piasta), with the * help of Louise Heimann . The following * DIGI Booster effects are _NOT_ recognized by this player: * * 8xx robot * e00 filter off * e01 filter on * e30 backwd play sample * e31 backwd play sample+loop * e50 channel off * e51 channel on * e8x sample offset 2 * e9x retrace */ #include "loader.h" static int digi_test (HIO_HANDLE *, char *, const int); static int digi_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_digi = { "DIGI Booster", digi_test, digi_load }; static int digi_test(HIO_HANDLE *f, char *t, const int start) { char buf[20]; if (hio_read(buf, 1, 20, f) < 20) return -1; if (memcmp(buf, "DIGI Booster module", 19)) return -1; hio_seek(f, 156, SEEK_CUR); hio_seek(f, 3 * 4 * 32, SEEK_CUR); hio_seek(f, 2 * 1 * 32, SEEK_CUR); libxmp_read_title(f, t, 32); return 0; } struct digi_header { uint8 id[20]; /* ID: "DIGI Booster module\0" */ uint8 vstr[4]; /* Version string: "Vx.y" */ uint8 ver; /* Version hi-nibble.lo-nibble */ uint8 chn; /* Number of channels */ uint8 pack; /* PackEnable */ uint8 unknown[19]; /* ??!? */ uint8 pat; /* Number of patterns */ uint8 len; /* Song length */ uint8 ord[128]; /* Orders */ uint32 slen[31]; /* Sample length for 31 samples */ uint32 sloop[31]; /* Sample loop start for 31 samples */ uint32 sllen[31]; /* Sample loop length for 31 samples */ uint8 vol[31]; /* Instrument volumes */ int8 fin[31]; /* Finetunes */ uint8 title[32]; /* Song name */ uint8 insname[31][30]; /* Instrument names */ }; static int digi_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event = 0; struct digi_header dh; uint8 digi_event[4], chn_table[64]; uint16 w; int i, j, k, c; LOAD_INIT(); hio_read(&dh.id, 20, 1, f); hio_read(&dh.vstr, 4, 1, f); dh.ver = hio_read8(f); dh.chn = hio_read8(f); dh.pack = hio_read8(f); hio_read(&dh.unknown, 19, 1, f); dh.pat = hio_read8(f); dh.len = hio_read8(f); /* Sanity check */ if (dh.len > 127) { return -1; } hio_read(&dh.ord, 128, 1, f); for (i = 0; i < 31; i++) dh.slen[i] = hio_read32b(f); for (i = 0; i < 31; i++) dh.sloop[i] = hio_read32b(f); for (i = 0; i < 31; i++) dh.sllen[i] = hio_read32b(f); for (i = 0; i < 31; i++) dh.vol[i] = hio_read8(f); for (i = 0; i < 31; i++) dh.fin[i] = hio_read8s(f); hio_read(&dh.title, 32, 1, f); for (i = 0; i < 31; i++) hio_read(&dh.insname[i], 30, 1, f); mod->ins = 31; mod->smp = mod->ins; mod->pat = dh.pat + 1; mod->chn = dh.chn; mod->trk = mod->pat * mod->chn; mod->len = dh.len + 1; m->period_type = PERIOD_MODRNG; libxmp_copy_adjust(mod->name, dh.title, 32); libxmp_set_type(m, "DIGI Booster %-4.4s", dh.vstr); MODULE_INFO(); for (i = 0; i < mod->len; i++) mod->xxo[i] = dh.ord[i]; if (libxmp_init_instrument(m) < 0) return -1; /* Read and convert instruments and samples */ for (i = 0; i < mod->ins; i++) { if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; mod->xxs[i].len = dh.slen[i]; mod->xxs[i].lps = dh.sloop[i]; mod->xxs[i].lpe = dh.sloop[i] + dh.sllen[i]; mod->xxs[i].flg = mod->xxs[i].lpe > 0 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].vol = dh.vol[i]; mod->xxi[i].sub[0].fin = dh.fin[i]; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; libxmp_instrument_name(mod, i, dh.insname[i], 30); D_(D_INFO "[%2X] %-30.30s %04x %04x %04x %c V%02x", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol); } if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; if (dh.pack) { w = (hio_read16b(f) - 64) >> 2; hio_read (chn_table, 1, 64, f); } else { w = 64 * mod->chn; memset (chn_table, 0xff, 64); } for (j = 0; j < 64; j++) { for (c = 0, k = 0x80; c < mod->chn; c++, k >>= 1) { if (chn_table[j] & k) { hio_read (digi_event, 4, 1, f); event = &EVENT (i, c, j); libxmp_decode_protracker_event(event, digi_event); switch (event->fxt) { case 0x08: /* Robot */ event->fxt = event->fxp = 0; break; case 0x0e: switch (MSN (event->fxp)) { case 0x00: case 0x03: case 0x08: case 0x09: event->fxt = event->fxp = 0; break; case 0x04: event->fxt = 0x0c; event->fxp = 0x00; break; } } w--; } } } if (w) { D_(D_CRIT "Corrupted file (w = %d)", w); } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/psm_load.c0000664000175000017500000001332112775035311017025 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "period.h" #define MAGIC_PSM_ MAGIC4('P','S','M',0xfe) static int psm_test (HIO_HANDLE *, char *, const int); static int psm_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_psm = { "Protracker Studio", psm_test, psm_load }; static int psm_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_PSM_) return -1; libxmp_read_title(f, t, 60); return 0; } /* FIXME: effects translation */ static int psm_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int c, r, i; struct xmp_event *event; uint8 buf[1024]; uint32 p_ord, p_chn, p_pat, p_ins; uint32 p_smp[64]; int type, ver /*, mode*/; LOAD_INIT(); hio_read32b(f); hio_read(buf, 1, 60, f); strncpy(mod->name, (char *)buf, 60); type = hio_read8(f); /* song type */ ver = hio_read8(f); /* song version */ /*mode =*/ hio_read8(f); /* pattern version */ if (type & 0x01) /* song mode not supported */ return -1; libxmp_set_type(m, "Protracker Studio PSM %d.%02d", MSN(ver), LSN(ver)); mod->spd = hio_read8(f); mod->bpm = hio_read8(f); hio_read8(f); /* master volume */ hio_read16l(f); /* song length */ mod->len = hio_read16l(f); mod->pat = hio_read16l(f); mod->ins = hio_read16l(f); hio_read16l(f); /* ignore channels to play */ mod->chn = hio_read16l(f); /* use channels to proceed */ mod->smp = mod->ins; mod->trk = mod->pat * mod->chn; /* Sanity check */ if (mod->len > 256 || mod->pat > 256 || mod->ins > 255 || mod->chn > XMP_MAX_CHANNELS) { return -1; } p_ord = hio_read32l(f); p_chn = hio_read32l(f); p_pat = hio_read32l(f); p_ins = hio_read32l(f); /* should be this way but fails with Silverball song 6 */ //mod->flg |= ~type & 0x02 ? XXM_FLG_MODRNG : 0; m->c4rate = C4_NTSC_RATE; MODULE_INFO(); hio_seek(f, start + p_ord, SEEK_SET); hio_read(mod->xxo, 1, mod->len, f); hio_seek(f, start + p_chn, SEEK_SET); hio_read(buf, 1, 16, f); if (libxmp_init_instrument(m) < 0) return -1; hio_seek(f, start + p_ins, SEEK_SET); for (i = 0; i < mod->ins; i++) { uint16 flags, c2spd; int finetune; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; hio_read(buf, 1, 13, f); /* sample filename */ hio_read(buf, 1, 24, f); /* sample description */ buf[24] = 0; /* add string termination */ strncpy((char *)mod->xxi[i].name, (char *)buf, 24); p_smp[i] = hio_read32l(f); hio_read32l(f); /* memory location */ hio_read16l(f); /* sample number */ flags = hio_read8(f); /* sample type */ mod->xxs[i].len = hio_read32l(f); mod->xxs[i].lps = hio_read32l(f); mod->xxs[i].lpe = hio_read32l(f); finetune = (int8)(hio_read8(f) << 4); mod->xxi[i].sub[0].vol = hio_read8(f); c2spd = hio_read16l(f); mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; mod->xxs[i].flg = flags & 0x80 ? XMP_SAMPLE_LOOP : 0; mod->xxs[i].flg |= flags & 0x20 ? XMP_SAMPLE_LOOP_BIDIR : 0; libxmp_c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); mod->xxi[i].sub[0].fin += finetune; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, c2spd); } if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); hio_seek(f, start + p_pat, SEEK_SET); for (i = 0; i < mod->pat; i++) { int len; uint8 b, rows, chan; len = hio_read16l(f) - 4; rows = hio_read8(f); if (rows > 64) { return -1; } chan = hio_read8(f); if (chan > 32) { return -1; } if (libxmp_alloc_pattern_tracks(mod, i, rows) < 0) return -1; for (r = 0; r < rows; r++) { while (len > 0) { b = hio_read8(f); len--; if (b == 0) break; c = b & 0x0f; if (c >= mod->chn) return -1; event = &EVENT(i, c, r); if (b & 0x80) { event->note = hio_read8(f) + 36 + 1; event->ins = hio_read8(f); len -= 2; } if (b & 0x40) { event->vol = hio_read8(f) + 1; len--; } if (b & 0x20) { event->fxt = hio_read8(f); event->fxp = hio_read8(f); len -= 2; } } } if (len > 0) hio_seek(f, len, SEEK_CUR); } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { hio_seek(f, start + p_smp[i], SEEK_SET); if (libxmp_load_sample(m, f, SAMPLE_FLAG_DIFF, &mod->xxs[mod->xxi[i].sub[0].sid], NULL) < 0) return -1; } return 0; } libxmp-4.4.1/src/loaders/mmd1_load.c0000664000175000017500000003220012775035311017061 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * OctaMED v1.00b: ftp://ftp.funet.fi/pub/amiga/fish/501-600/ff579 */ #include "med.h" #include "loader.h" #include "med_extras.h" static int mmd1_test(HIO_HANDLE *, char *, const int); static int mmd1_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mmd1 = { "MED 2.10/OctaMED", mmd1_test, mmd1_load }; static int mmd1_test(HIO_HANDLE *f, char *t, const int start) { char id[4]; uint32 offset, len; if (hio_read(id, 1, 4, f) < 4) return -1; if (memcmp(id, "MMD0", 4) && memcmp(id, "MMD1", 4)) return -1; hio_seek(f, 28, SEEK_CUR); offset = hio_read32b(f); /* expdata_offset */ if (offset) { hio_seek(f, start + offset + 44, SEEK_SET); offset = hio_read32b(f); len = hio_read32b(f); hio_seek(f, start + offset, SEEK_SET); libxmp_read_title(f, t, len); } else { libxmp_read_title(f, t, 0); } return 0; } /* Number of octaves in IFFOCT samples */ static const int num_oct[6] = { 5, 3, 2, 4, 6, 7 }; static int mmd1_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k; struct MMD0 header; struct MMD0song song; struct MMD1Block block; struct InstrHdr instr; struct SynthInstr synth; struct InstrExt exp_smp; struct MMD0exp expdata; struct xmp_event *event; int ver = 0; int smp_idx = 0; uint8 e[4]; int song_offset; int blockarr_offset; int smplarr_offset; int expdata_offset; int expsmp_offset; int songname_offset; int iinfo_offset; int annotxt_offset; int pos; int bpm_on, bpmlen, med_8ch, hexvol; LOAD_INIT(); hio_read(&header.id, 4, 1, f); ver = *((char *)&header.id + 3) - '1' + 1; D_(D_WARN "load header"); header.modlen = hio_read32b(f); song_offset = hio_read32b(f); D_(D_INFO "song_offset = 0x%08x", song_offset); hio_read16b(f); hio_read16b(f); blockarr_offset = hio_read32b(f); D_(D_INFO "blockarr_offset = 0x%08x", blockarr_offset); hio_read32b(f); smplarr_offset = hio_read32b(f); D_(D_INFO "smplarr_offset = 0x%08x", smplarr_offset); hio_read32b(f); expdata_offset = hio_read32b(f); D_(D_INFO "expdata_offset = 0x%08x", expdata_offset); hio_read32b(f); header.pstate = hio_read16b(f); header.pblock = hio_read16b(f); header.pline = hio_read16b(f); header.pseqnum = hio_read16b(f); header.actplayline = hio_read16b(f); header.counter = hio_read8(f); header.extra_songs = hio_read8(f); /* * song structure */ D_(D_WARN "load song"); if (hio_seek(f, start + song_offset, SEEK_SET) != 0) return -1; for (i = 0; i < 63; i++) { song.sample[i].rep = hio_read16b(f); song.sample[i].replen = hio_read16b(f); song.sample[i].midich = hio_read8(f); song.sample[i].midipreset = hio_read8(f); song.sample[i].svol = hio_read8(f); song.sample[i].strans = hio_read8s(f); } song.numblocks = hio_read16b(f); song.songlen = hio_read16b(f); /* Sanity check */ if (song.numblocks > 255 || song.songlen > 256) { return -1; } D_(D_INFO "song.songlen = %d", song.songlen); for (i = 0; i < 256; i++) song.playseq[i] = hio_read8(f); song.deftempo = hio_read16b(f); song.playtransp = hio_read8(f); song.flags = hio_read8(f); song.flags2 = hio_read8(f); song.tempo2 = hio_read8(f); for (i = 0; i < 16; i++) song.trkvol[i] = hio_read8(f); song.mastervol = hio_read8(f); song.numsamples = hio_read8(f); /* Sanity check */ if (song.numsamples > 63) { return -1; } /* * convert header */ m->c4rate = C4_NTSC_RATE; m->quirk |= song.flags & FLAG_STSLIDE ? 0 : QUIRK_VSALL | QUIRK_PBALL; hexvol = song.flags & FLAG_VOLHEX; med_8ch = song.flags & FLAG_8CHANNEL; bpm_on = song.flags2 & FLAG2_BPM; bpmlen = 1 + (song.flags2 & FLAG2_BMASK); m->time_factor = MED_TIME_FACTOR; mmd_set_bpm(m, med_8ch, song.deftempo, bpm_on, bpmlen); mod->spd = song.tempo2; mod->pat = song.numblocks; mod->ins = song.numsamples; mod->len = song.songlen; mod->rst = 0; mod->chn = 0; memcpy(mod->xxo, song.playseq, mod->len); mod->name[0] = 0; /* * Obtain number of samples from each instrument */ mod->smp = 0; for (i = 0; i < mod->ins; i++) { uint32 smpl_offset; int16 type; if (hio_seek(f, start + smplarr_offset + i * 4, SEEK_SET) != 0) return -1; smpl_offset = hio_read32b(f); if (smpl_offset == 0) continue; if (hio_seek(f, start + smpl_offset, SEEK_SET) != 0) return -1; hio_read32b(f); /* length */ type = hio_read16b(f); if (type == -1) { /* type is synth? */ int wforms; hio_seek(f, 14, SEEK_CUR); wforms = hio_read16b(f); /* Sanity check */ if (wforms > 256) return -1; mod->smp += wforms; } else if (type >= 1 && type <= 6) { mod->smp += num_oct[type - 1]; } else { mod->smp++; } } /* * expdata */ D_(D_WARN "load expdata"); expdata.s_ext_entries = 0; expdata.s_ext_entrsz = 0; expdata.i_ext_entries = 0; expdata.i_ext_entrsz = 0; expsmp_offset = 0; iinfo_offset = 0; if (expdata_offset) { if (hio_seek(f, start + expdata_offset, SEEK_SET) != 0) return -1; hio_read32b(f); expsmp_offset = hio_read32b(f); D_(D_INFO "expsmp_offset = 0x%08x", expsmp_offset); expdata.s_ext_entries = hio_read16b(f); expdata.s_ext_entrsz = hio_read16b(f); annotxt_offset = hio_read32b(f); expdata.annolen = hio_read32b(f); iinfo_offset = hio_read32b(f); D_(D_INFO "iinfo_offset = 0x%08x", iinfo_offset); expdata.i_ext_entries = hio_read16b(f); expdata.i_ext_entrsz = hio_read16b(f); /* Sanity check */ if (expsmp_offset < 0 || annotxt_offset < 0 || expdata.annolen > 0x10000 || iinfo_offset < 0) { return -1; } hio_read32b(f); hio_read32b(f); hio_read32b(f); hio_read32b(f); songname_offset = hio_read32b(f); expdata.songnamelen = hio_read32b(f); hio_seek(f, start + songname_offset, SEEK_SET); for (i = 0; i < expdata.songnamelen; i++) { if (i >= XMP_NAME_SIZE) break; mod->name[i] = hio_read8(f); } /* Read annotation */ if (annotxt_offset != 0 && expdata.annolen != 0) { m->comment = malloc(expdata.annolen + 1); if (m->comment != NULL) { hio_seek(f, start + annotxt_offset, SEEK_SET); hio_read(m->comment, 1, expdata.annolen, f); m->comment[expdata.annolen] = 0; } } } /* * Quickly scan patterns to check the number of channels */ D_(D_WARN "find number of channels"); for (i = 0; i < mod->pat; i++) { int block_offset; if (hio_seek(f, start + blockarr_offset + i * 4, SEEK_SET) != 0) return -1; block_offset = hio_read32b(f); D_(D_INFO "block %d block_offset = 0x%08x", i, block_offset); if (block_offset == 0) continue; if (hio_seek(f, start + block_offset, SEEK_SET) != 0) return -1; if (ver > 0) { block.numtracks = hio_read16b(f); /* block.lines = */ hio_read16b(f); } else { block.numtracks = hio_read8(f); /* block.lines = */ hio_read8(f); } if (block.numtracks > mod->chn) { mod->chn = block.numtracks; } } /* Sanity check */ if (mod->chn > XMP_MAX_CHANNELS) { return -1; } mod->trk = mod->pat * mod->chn; libxmp_set_type(m, ver == 0 ? mod->chn > 4 ? "OctaMED 2.00 MMD0" : "MED 2.10 MMD0" : "OctaMED 4.00 MMD1"); MODULE_INFO(); D_(D_INFO "BPM mode: %s (length = %d)", bpm_on ? "on" : "off", bpmlen); D_(D_INFO "Song transpose: %d", song.playtransp); D_(D_INFO "Stored patterns: %d", mod->pat); /* * Read and convert patterns */ D_(D_WARN "read patterns"); if (libxmp_init_pattern(mod) < 0) return -1; for (i = 0; i < mod->pat; i++) { int block_offset; if (hio_seek(f, start + blockarr_offset + i * 4, SEEK_SET) != 0) return -1; block_offset = hio_read32b(f); if (block_offset == 0) continue; if (hio_seek(f, start + block_offset, SEEK_SET) != 0) return -1; if (ver > 0) { block.numtracks = hio_read16b(f); block.lines = hio_read16b(f); hio_read32b(f); } else { block.numtracks = hio_read8(f); block.lines = hio_read8(f); } if (libxmp_alloc_pattern_tracks(mod, i, block.lines + 1) < 0) return -1; if (ver > 0) { /* MMD1 */ for (j = 0; j < mod->xxp[i]->rows; j++) { for (k = 0; k < block.numtracks; k++) { e[0] = hio_read8(f); e[1] = hio_read8(f); e[2] = hio_read8(f); e[3] = hio_read8(f); event = &EVENT(i, k, j); event->note = e[0] & 0x7f; if (event->note) event->note += 12 + song.playtransp; if (event->note >= XMP_MAX_KEYS) event->note = 0; event->ins = e[1] & 0x3f; /* Decay */ if (event->ins && !event->note) { event->f2t = FX_MED_HOLD; } event->fxt = e[2]; event->fxp = e[3]; mmd_xlat_fx(event, bpm_on, bpmlen, med_8ch, hexvol); } } } else { /* MMD0 */ for (j = 0; j < mod->xxp[i]->rows; j++) { for (k = 0; k < block.numtracks; k++) { e[0] = hio_read8(f); e[1] = hio_read8(f); e[2] = hio_read8(f); event = &EVENT(i, k, j); event->note = e[0] & 0x3f; if (event->note) event->note += 12; if (event->note >= XMP_MAX_KEYS) event->note = 0; event->ins = (e[1] >> 4) | ((e[0] & 0x80) >> 3) | ((e[0] & 0x40) >> 1); /* Decay */ if (event->ins && !event->note) { event->f2t = FX_MED_HOLD; } event->fxt = e[1] & 0x0f; event->fxp = e[2]; mmd_xlat_fx(event, bpm_on, bpmlen, med_8ch, hexvol); } } } } if (libxmp_med_new_module_extras(m)) return -1; /* * Read and convert instruments and samples */ D_(D_WARN "read instruments"); if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->ins); for (smp_idx = i = 0; i < mod->ins; i++) { int smpl_offset; if (hio_seek(f, start + smplarr_offset + i * 4, SEEK_SET) != 0) return -1; smpl_offset = hio_read32b(f); D_(D_INFO "sample %d smpl_offset = 0x%08x", i, smpl_offset); if (smpl_offset == 0) { continue; } if (hio_seek(f, start + smpl_offset, SEEK_SET) < 0) { return -1; } instr.length = hio_read32b(f); instr.type = hio_read16b(f); if ((pos = hio_tell(f)) < 0) { return -1; } if (expdata_offset && i < expdata.i_ext_entries) { struct xmp_instrument *xxi = &mod->xxi[i]; int offset = iinfo_offset + i * expdata.i_ext_entrsz; if (offset < 0 || hio_seek(f, offset, SEEK_SET) < 0) { return -1; } hio_read(&xxi->name, 40, 1, f); } D_(D_INFO "[%2x] %-40.40s %d", i, mod->xxi[i].name, instr.type); exp_smp.finetune = 0; if (expdata_offset && i < expdata.s_ext_entries) { int offset = expsmp_offset + i * expdata.s_ext_entrsz; if (offset < 0 || hio_seek(f, offset, SEEK_SET) < 0) { return -1; } exp_smp.hold = hio_read8(f); exp_smp.decay = hio_read8(f); exp_smp.suppress_midi_off = hio_read8(f); exp_smp.finetune = hio_read8(f); } hio_seek(f, pos, SEEK_SET); if (instr.type == -2) { /* Hybrid */ int ret = mmd_load_hybrid_instrument(f, m, i, smp_idx, &synth, &exp_smp, &song.sample[i]); smp_idx++; if (ret < 0) return -1; if (mmd_alloc_tables(m, i, &synth) != 0) return -1; continue; } else if (instr.type == -1) { /* Synthetic */ int ret = mmd_load_synth_instrument(f, m, i, smp_idx, &synth, &exp_smp, &song.sample[i]); if (ret > 0) continue; if (ret < 0) return -1; smp_idx += synth.wforms; if (mmd_alloc_tables(m, i, &synth) != 0) return -1; continue; } else if (instr.type >= 1 && instr.type <= 6) { /* IFFOCT */ int ret; const int oct = num_oct[instr.type - 1]; hio_seek(f, start + smpl_offset + 6, SEEK_SET); ret = mmd_load_iffoct_instrument(f, m, i, smp_idx, &instr, oct, &exp_smp, &song.sample[i]); if (ret < 0) return -1; smp_idx += oct; continue; } else if (instr.type == 0) { /* Sample */ int ret; hio_seek(f, start + smpl_offset + 6, SEEK_SET); ret = mmd_load_sampled_instrument(f, m, i, smp_idx, &instr, &expdata, &exp_smp, &song.sample[i], ver); if (ret < 0) return -1; smp_idx++; continue; } else { /* Invalid instrument type */ return -1; } } for (i = 0; i < mod->chn; i++) { mod->xxc[i].vol = song.trkvol[i]; mod->xxc[i].pan = DEFPAN((((i + 1) / 2) % 2) * 0xff); } m->read_event_type = READ_EVENT_MED; return 0; } libxmp-4.4.1/src/loaders/mdl_load.c0000664000175000017500000006216312775035311017012 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Note: envelope switching (effect 9) and sample status change (effect 8) * not supported. */ #include "loader.h" #include "iff.h" #include "period.h" #define MAGIC_DMDL MAGIC4('D','M','D','L') static int mdl_test (HIO_HANDLE *, char *, const int); static int mdl_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mdl = { "Digitrakker", mdl_test, mdl_load }; static int mdl_test(HIO_HANDLE *f, char *t, const int start) { uint16 id; if (hio_read32b(f) != MAGIC_DMDL) return -1; hio_read8(f); /* version */ id = hio_read16b(f); if (id == 0x494e) { /* IN */ hio_read32b(f); libxmp_read_title(f, t, 32); } else { libxmp_read_title(f, t, 0); } return 0; } #define MDL_NOTE_FOLLOWS 0x04 #define MDL_INSTRUMENT_FOLLOWS 0x08 #define MDL_VOLUME_FOLLOWS 0x10 #define MDL_EFFECT_FOLLOWS 0x20 #define MDL_PARAMETER1_FOLLOWS 0x40 #define MDL_PARAMETER2_FOLLOWS 0x80 struct mdl_envelope { uint8 num; uint8 data[30]; uint8 sus; uint8 loop; }; struct local_data { int *i_index; int *s_index; int *v_index; /* volume envelope */ int *p_index; /* pan envelope */ int *f_index; /* pitch envelope */ int *packinfo; int v_envnum; int p_envnum; int f_envnum; struct mdl_envelope *v_env; struct mdl_envelope *p_env; struct mdl_envelope *f_env; }; static void fix_env(int i, struct xmp_envelope *ei, struct mdl_envelope *env, int *index, int envnum) { int j, k, lastx; if (index[i] >= 0) { ei->flg = XMP_ENVELOPE_ON; ei->npt = 15; for (j = 0; j < envnum; j++) { if (index[i] == env[j].num) { ei->flg |= env[j].sus & 0x10 ? XMP_ENVELOPE_SUS : 0; ei->flg |= env[j].sus & 0x20 ? XMP_ENVELOPE_LOOP : 0; ei->sus = env[j].sus & 0x0f; ei->lps = env[j].loop & 0x0f; ei->lpe = env[j].loop & 0xf0; lastx = -1; for (k = 0; k < ei->npt; k++) { int x = env[j].data[k * 2]; if (x == 0) break; ei->data[k * 2] = lastx + x; ei->data[k * 2 + 1] = env[j].data[k * 2 + 1]; lastx = ei->data[k * 2]; } ei->npt = k; break; } } } } /* Effects 1-6 (note effects) can only be entered in the first effect * column, G-L (volume-effects) only in the second column. */ static void xlat_fx_common(uint8 *t, uint8 *p) { switch (*t) { case 0x07: /* 7 - Set BPM */ *t = FX_S3M_BPM; break; case 0x08: /* 8 - Set pan */ case 0x09: /* 9 - Set envelope -- not supported */ case 0x0a: /* A - Not used */ *t = *p = 0x00; break; case 0x0b: /* B - Position jump */ case 0x0c: /* C - Set volume */ case 0x0d: /* D - Pattern break */ /* Like protracker */ break; case 0x0e: /* E - Extended */ switch (MSN (*p)) { case 0x0: /* E0 - not used */ case 0x3: /* E3 - not used */ case 0x8: /* Set sample status -- unsupported */ *t = *p = 0x00; break; case 0x1: /* Pan slide left */ *t = FX_PANSLIDE; *p <<= 4; break; case 0x2: /* Pan slide right */ *t = FX_PANSLIDE; *p &= 0x0f; break; } break; case 0x0f: *t = FX_S3M_SPEED; break; } } static void xlat_fx1(uint8 *t, uint8 *p) { switch (*t) { case 0x00: /* - - No effect */ *p = 0; break; case 0x05: /* 5 - Arpeggio */ *t = FX_ARPEGGIO; break; case 0x06: /* 6 - Not used */ *t = *p = 0x00; break; } xlat_fx_common(t, p); } static void xlat_fx2(uint8 *t, uint8 *p) { switch (*t) { case 0x00: /* - - No effect */ *p = 0; break; case 0x01: /* G - Volume slide up */ *t = FX_VOLSLIDE_UP; break; case 0x02: /* H - Volume slide down */ *t = FX_VOLSLIDE_DN; break; case 0x03: /* I - Multi-retrig */ *t = FX_MULTI_RETRIG; break; case 0x04: /* J - Tremolo */ *t = FX_TREMOLO; break; case 0x05: /* K - Tremor */ *t = FX_TREMOR; break; case 0x06: /* L - Not used */ *t = *p = 0x00; break; } xlat_fx_common(t, p); } struct bits { uint32 b, n; }; static unsigned int get_bits(char i, uint8 **buf, int *len, struct bits *bits) { unsigned int x; if (i == 0) { bits->b = readmem32l(*buf); *buf += 4; *len -= 4; bits->n = 32; } x = bits->b & ((1 << i) - 1); /* get i bits */ bits->b >>= i; if ((bits->n -= i) <= 24) { if (*len <= 0) /* FIXME: last few bits can't be consumed */ return x; bits->b |= readmem32l((*buf)++) << bits->n; bits->n += 8; (*len)--; } return x; } /* From the Digitrakker docs: * * The description of the sample-packmethode (1) [8bit packing]:... * ---------------------------------------------------------------- * * The method is based on the Huffman algorithm. It's easy and very fast * and effective on samples. The packed sample is a bit stream: * * Byte 0 Byte 1 Byte 2 Byte 3 * Bit 76543210 fedcba98 nmlkjihg ....rqpo * * A packed byte is stored in the following form: * * xxxx10..0s => byte = + (number of <0> bits between * s and 1) * 16 - 8; * if s==1 then byte = byte xor 255 * * If there are no <0> bits between the first bit (sign) and the <1> bit, * you have the following form: * * xxx1s => byte = ; if s=1 then byte = byte xor 255 */ static int unpack_sample8(uint8 *t, uint8 *f, int len, int l) { int i, s; uint8 b, d; struct bits bits; D_(D_INFO "unpack sample 8bit, len=%d", len); get_bits(0, &f, &len, &bits); for (i = b = d = 0; i < l; i++) { /* Sanity check */ if (len < 0) return -1; s = get_bits(1, &f, &len, &bits); if (get_bits(1, &f, &len, &bits)) { b = get_bits(3, &f, &len, &bits); } else { b = 8; while (len >= 0 && get_bits(1, &f, &len, &bits) == 0) { /* Sanity check */ if (b >= 240) { return -1; } b += 16; } b += get_bits(4, &f, &len, &bits); } if (s) { b ^= 0xff; } d += b; *t++ = d; } return 0; } /* * The description of the sample-packmethode (2) [16bit packing]:... * ---------------------------------------------------------------- * * It works as methode (1) but it only crunches every 2nd byte (the high- * bytes of 16 bit samples). So when you depack 16 bit samples, you have to * read 8 bits from the data-stream first. They present the lowbyte of the * sample-word. Then depack the highbyte in the descripted way (methode [1]). * Only the highbytes are delta-values. So take the lowbytes as they are. * Go on this way for the whole sample! */ static int unpack_sample16(uint8 *t, uint8 *f, int len, int l) { int i, lo, s; uint8 b, d; struct bits bits; D_(D_INFO "unpack sample 16bit, len=%d", len); get_bits(0, &f, &len, &bits); for (i = lo = b = d = 0; i < l; i++) { /* Sanity check */ if (len < 0) return -1; lo = get_bits(8, &f, &len, &bits); s = get_bits(1, &f, &len, &bits); if (get_bits(1, &f, &len, &bits)) { b = get_bits(3, &f, &len, &bits); } else { b = 8; while (len >= 0 && get_bits(1, &f, &len, &bits) == 0) { /* Sanity check */ if (b >= 240) { return -1; } b += 16; } b += get_bits(4, &f, &len, &bits); } if (s) b ^= 0xff; d += b; *t++ = lo; *t++ = d; } return 0; } /* * IFF chunk handlers */ static int get_chunk_in(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; hio_read(mod->name, 1, 32, f); hio_seek(f, 20, SEEK_CUR); mod->len = hio_read16l(f); mod->rst = hio_read16l(f); hio_read8(f); /* gvol */ mod->spd = hio_read8(f); mod->bpm = hio_read8(f); /* Sanity check */ if (mod->len > 256 || mod->rst > 255) { return -1; } for (i = 0; i < 32; i++) { uint8 chinfo = hio_read8(f); if (chinfo & 0x80) break; mod->xxc[i].pan = chinfo << 1; } mod->chn = i; hio_seek(f, 32 - i - 1, SEEK_CUR); hio_read(mod->xxo, 1, mod->len, f); MODULE_INFO(); return 0; } static int get_chunk_pa(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, j, chn; int x; /* Sanity check */ if (mod->pat != 0) return -1; mod->pat = hio_read8(f); if ((mod->xxp = calloc(sizeof (struct xmp_pattern *), mod->pat)) == NULL) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern(mod, i) < 0) return -1; chn = hio_read8(f); mod->xxp[i]->rows = (int)hio_read8(f) + 1; hio_seek(f, 16, SEEK_CUR); /* Skip pattern name */ for (j = 0; j < chn; j++) { x = hio_read16l(f); if (j < mod->chn) mod->xxp[i]->index[j] = x; } } return 0; } static int get_chunk_p0(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, j; uint16 x; /* Sanity check */ if (mod->pat != 0) return -1; mod->pat = hio_read8(f); if ((mod->xxp = calloc(sizeof (struct xmp_pattern *), mod->pat)) == NULL) return -1; D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern(mod, i) < 0) return -1; mod->xxp[i]->rows = 64; for (j = 0; j < 32; j++) { x = hio_read16l(f); if (j < mod->chn) mod->xxp[i]->index[j] = x; } } return 0; } static int get_chunk_tr(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, j, k, row, len, max_trk; struct xmp_track *track; mod->trk = hio_read16l(f) + 1; /* Sanity check */ max_trk = 0; for (i = 0; i < mod->pat; i++) { for (j = 0; j < mod->chn; j++) { if (max_trk < mod->xxp[i]->index[j]) max_trk = mod->xxp[i]->index[j]; } } if (max_trk >= mod->trk) { return -1; } if ((mod->xxt = calloc(sizeof (struct xmp_track *), mod->trk)) == NULL) return -1; D_(D_INFO "Stored tracks: %d", mod->trk); track = calloc(1, sizeof (struct xmp_track) + sizeof (struct xmp_event) * 255); if (track == NULL) goto err; /* Empty track 0 is not stored in the file */ if (libxmp_alloc_track(mod, 0, 256) < 0) goto err2; for (i = 1; i < mod->trk; i++) { /* Length of the track in bytes */ len = hio_read16l(f); memset(track, 0, sizeof (struct xmp_track) + sizeof (struct xmp_event) * 255); for (row = 0; len;) { struct xmp_event *ev; /* Sanity check */ if (row > 255) { goto err2; } ev = &track->event[row]; j = hio_read8(f); len--; switch (j & 0x03) { case 0: row += j >> 2; break; case 1: /* Sanity check */ if (row + (j >> 2) > 255) goto err2; for (k = 0; k <= (j >> 2); k++) memcpy(&ev[k], &ev[-1], sizeof (struct xmp_event)); row += k - 1; break; case 2: /* Sanity check */ if ((j >> 2) == row) { goto err2; } memcpy(ev, &track->event[j >> 2], sizeof (struct xmp_event)); break; case 3: if (j & MDL_NOTE_FOLLOWS) { uint8 b = hio_read8(f); len--; ev->note = b == 0xff ? XMP_KEY_OFF : b + 12; } if (j & MDL_INSTRUMENT_FOLLOWS) len--, ev->ins = hio_read8(f); if (j & MDL_VOLUME_FOLLOWS) len--, ev->vol = hio_read8(f); if (j & MDL_EFFECT_FOLLOWS) { len--, k = hio_read8(f); ev->fxt = LSN(k); ev->f2t = MSN(k); } if (j & MDL_PARAMETER1_FOLLOWS) len--, ev->fxp = hio_read8(f); if (j & MDL_PARAMETER2_FOLLOWS) len--, ev->f2p = hio_read8(f); break; } row++; } if (row <= 64) row = 64; else if (row <= 128) row = 128; else row = 256; if (libxmp_alloc_track(mod, i, row) < 0) goto err2; memcpy(mod->xxt[i], track, sizeof (struct xmp_track) + sizeof (struct xmp_event) * (row - 1)); mod->xxt[i]->rows = row; /* Translate effects */ for (j = 0; j < row; j++) { struct xmp_event *ev = &mod->xxt[i]->event[j]; xlat_fx1(&ev->fxt, &ev->fxp); xlat_fx2(&ev->f2t, &ev->f2p); } } free(track); return 0; err2: free(track); err: return -1; } static int get_chunk_ii(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i, j, k; int map, last_map; char buf[40]; mod->ins = hio_read8(f); D_(D_INFO "Instruments: %d", mod->ins); if (libxmp_init_instrument(m) < 0) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; data->i_index[i] = hio_read8(f); xxi->nsm = hio_read8(f); hio_read(buf, 1, 32, f); buf[32] = 0; strncpy(xxi->name, buf, 31); D_(D_INFO "[%2X] %-32.32s %2d", data->i_index[i], xxi->name, xxi->nsm); if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) return -1; for (j = 0; j < XMP_MAX_KEYS; j++) xxi->map[j].ins = -1; for (last_map = j = 0; j < mod->xxi[i].nsm; j++) { int x; struct xmp_subinstrument *sub = &xxi->sub[j]; sub->sid = hio_read8(f); map = hio_read8(f) + 12; sub->vol = hio_read8(f); for (k = last_map; k <= map; k++) { if (k < XMP_MAX_KEYS) xxi->map[k].ins = j; } last_map = map + 1; x = hio_read8(f); /* Volume envelope */ if (j == 0) data->v_index[i] = x & 0x80 ? x & 0x3f : -1; if (~x & 0x40) sub->vol = 0xff; mod->xxi[i].sub[j].pan = hio_read8(f) << 1; x = hio_read8(f); /* Pan envelope */ if (j == 0) data->p_index[i] = x & 0x80 ? x & 0x3f : -1; if (~x & 0x40) sub->pan = 0x80; x = hio_read16l(f); if (j == 0) xxi->rls = x; sub->vra = hio_read8(f); /* vibrato rate */ sub->vde = hio_read8(f) << 1; /* vibrato depth */ sub->vsw = hio_read8(f); /* vibrato sweep */ sub->vwf = hio_read8(f); /* vibrato waveform */ hio_read8(f); /* Reserved */ x = hio_read8(f); /* Pitch envelope */ if (j == 0) data->f_index[i] = x & 0x80 ? x & 0x3f : -1; D_(D_INFO " %2x: V%02x S%02x v%02x p%02x f%02x", j, sub->vol, sub->sid, data->v_index[i], data->p_index[i], data->f_index[i]); } } return 0; } static int get_chunk_is(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i; char buf[64]; uint8 x; mod->smp = hio_read8(f); if ((mod->xxs = calloc(sizeof (struct xmp_sample), mod->smp)) == NULL) return -1; if ((m->xtra = calloc(sizeof (struct extra_sample_data), mod->smp)) == NULL) return -1; data->packinfo = calloc(sizeof (int), mod->smp); if (data->packinfo == NULL) return -1; D_(D_INFO "Sample infos: %d", mod->smp); for (i = 0; i < mod->smp; i++) { struct xmp_sample *xxs = &mod->xxs[i]; int c5spd; data->s_index[i] = hio_read8(f); /* Sample number */ hio_read(buf, 1, 32, f); buf[32] = 0; strncpy(xxs->name, buf, 31); hio_seek(f, 8, SEEK_CUR); /* Sample filename */ c5spd = hio_read32l(f); xxs->len = hio_read32l(f); xxs->lps = hio_read32l(f); xxs->lpe = hio_read32l(f); xxs->flg = xxs->lpe > 0 ? XMP_SAMPLE_LOOP : 0; xxs->lpe = xxs->lps + xxs->lpe; m->xtra[i].c5spd = (double)c5spd; hio_read8(f); /* Volume in DMDL 0.0 */ x = hio_read8(f); if (x & 0x01) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } xxs->flg |= (x & 0x02) ? XMP_SAMPLE_LOOP_BIDIR : 0; data->packinfo[i] = (x & 0x0c) >> 2; D_(D_INFO "[%2X] %-32.32s %05x%c %05x %05x %c %6d %d", data->s_index[i], buf, xxs->len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ', xxs->lps, xxs->lpe, xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', c5spd, data->packinfo[i]); } return 0; } static int get_chunk_i0(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i; char buf[64]; uint8 x; mod->ins = mod->smp = hio_read8(f); D_(D_INFO "Instruments: %d", mod->ins); if (libxmp_init_instrument(m) < 0) return -1; if ((data->packinfo = calloc(sizeof (int), mod->smp)) == NULL) return -1; for (i = 0; i < mod->ins; i++) { struct xmp_subinstrument *sub; struct xmp_sample *xxs = &mod->xxs[i]; int c5spd; mod->xxi[i].nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &mod->xxi[i].sub[0]; sub->sid = data->i_index[i] = data->s_index[i] = hio_read8(f); hio_read(buf, 1, 32, f); buf[32] = 0; hio_seek(f, 8, SEEK_CUR); /* Sample filename */ strncpy(mod->xxi[i].name, buf, 31); c5spd = hio_read16l(f); xxs->len = hio_read32l(f); xxs->lps = hio_read32l(f); xxs->lpe = hio_read32l(f); xxs->flg = xxs->lpe > 0 ? XMP_SAMPLE_LOOP : 0; xxs->lpe = xxs->lps + xxs->lpe; sub->vol = hio_read8(f); /* Volume */ sub->pan = 0x80; m->xtra[i].c5spd = (double)c5spd; x = hio_read8(f); if (x & 0x01) { xxs->flg |= XMP_SAMPLE_16BIT; xxs->len >>= 1; xxs->lps >>= 1; xxs->lpe >>= 1; } xxs->flg |= (x & 0x02) ? XMP_SAMPLE_LOOP_BIDIR : 0; data->packinfo[i] = (x & 0x0c) >> 2; D_(D_INFO "[%2X] %-32.32s %5d V%02x %05x%c %05x %05x %d", data->i_index[i], buf, c5spd, sub->vol, xxs->len, xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ', xxs->lps, xxs->lpe, data->packinfo[i]); } return 0; } static int get_chunk_sa(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i, len; uint8 *smpbuf, *buf; D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { struct xmp_sample *xxs = &mod->xxs[i]; len = xxs->len; if (xxs->flg & XMP_SAMPLE_16BIT) len <<= 1; if ((smpbuf = calloc(1, len)) == NULL) goto err; switch (data->packinfo[i]) { case 0: hio_read(smpbuf, 1, len, f); break; case 1: len = hio_read32l(f); /* Sanity check */ if (xxs->flg & XMP_SAMPLE_16BIT) goto err2; if (len <= 0 || len > 0x80000) /* Max compressed sample size */ goto err2; if ((buf = malloc(len + 4)) == NULL) goto err2; if (hio_read(buf, 1, len, f) != len) goto err3; if (unpack_sample8(smpbuf, buf, len, xxs->len) < 0) goto err3; free(buf); break; case 2: len = hio_read32l(f); /* Sanity check */ if (~xxs->flg & XMP_SAMPLE_16BIT) goto err2; if (len <= 0 || len > MAX_SAMPLE_SIZE) goto err2; if ((buf = malloc(len + 4)) == NULL) goto err2; if (hio_read(buf, 1, len, f) != len) goto err3; if (unpack_sample16(smpbuf, buf, len, xxs->len) < 0) goto err3; free(buf); break; default: /* Sanity check */ goto err2; } if (libxmp_load_sample(m, NULL, SAMPLE_FLAG_NOLOAD, xxs, (char *)smpbuf) < 0) goto err2; free(smpbuf); } return 0; err3: free(buf); err2: free(smpbuf); err: return -1; } static int get_chunk_ve(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct local_data *data = (struct local_data *)parm; int i; if ((data->v_envnum = hio_read8(f)) == 0) return 0; D_(D_INFO "Vol envelopes: %d", data->v_envnum); data->v_env = calloc(data->v_envnum, sizeof (struct mdl_envelope)); for (i = 0; i < data->v_envnum; i++) { data->v_env[i].num = hio_read8(f); hio_read(data->v_env[i].data, 1, 30, f); data->v_env[i].sus = hio_read8(f); data->v_env[i].loop = hio_read8(f); } return 0; } static int get_chunk_pe(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct local_data *data = (struct local_data *)parm; int i; if ((data->p_envnum = hio_read8(f)) == 0) return 0; D_(D_INFO "Pan envelopes: %d", data->p_envnum); data->p_env = calloc(data->p_envnum, sizeof (struct mdl_envelope)); for (i = 0; i < data->p_envnum; i++) { data->p_env[i].num = hio_read8(f); hio_read(data->p_env[i].data, 1, 30, f); data->p_env[i].sus = hio_read8(f); data->p_env[i].loop = hio_read8(f); } return 0; } static int get_chunk_fe(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct local_data *data = (struct local_data *)parm; int i; if ((data->f_envnum = hio_read8(f)) == 0) return 0; D_(D_INFO "Pitch envelopes: %d", data->f_envnum); data->f_env = calloc(data->f_envnum, sizeof (struct mdl_envelope)); for (i = 0; i < data->f_envnum; i++) { data->f_env[i].num = hio_read8(f); hio_read(data->f_env[i].data, 1, 30, f); data->f_env[i].sus = hio_read8(f); data->f_env[i].loop = hio_read8(f); } return 0; } static int mdl_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; iff_handle handle; int i, j, k, l; char buf[8]; struct local_data data; int retval = 0; LOAD_INIT(); memset(&data, 0, sizeof (struct local_data)); /* Check magic and get version */ hio_read32b(f); hio_read(buf, 1, 1, f); handle = libxmp_iff_new(); if (handle == NULL) return -1; /* IFFoid chunk IDs */ libxmp_iff_register(handle, "IN", get_chunk_in); /* Module info */ libxmp_iff_register(handle, "TR", get_chunk_tr); /* Tracks */ libxmp_iff_register(handle, "SA", get_chunk_sa); /* Sampled data */ libxmp_iff_register(handle, "VE", get_chunk_ve); /* Volume envelopes */ libxmp_iff_register(handle, "PE", get_chunk_pe); /* Pan envelopes */ libxmp_iff_register(handle, "FE", get_chunk_fe); /* Pitch envelopes */ if (MSN(*buf)) { libxmp_iff_register(handle, "II", get_chunk_ii); /* Instruments */ libxmp_iff_register(handle, "PA", get_chunk_pa); /* Patterns */ libxmp_iff_register(handle, "IS", get_chunk_is); /* Sample info */ } else { libxmp_iff_register(handle, "PA", get_chunk_p0); /* Old 0.0 patterns */ libxmp_iff_register(handle, "IS", get_chunk_i0); /* Old 0.0 Sample info */ } /* MDL uses a IFF-style file format with 16 bit IDs and little endian * 32 bit chunk size. There's only one chunk per data type (i.e. one * big chunk for all samples). */ libxmp_iff_id_size(handle, 2); libxmp_iff_set_quirk(handle, IFF_LITTLE_ENDIAN); libxmp_set_type(m, "Digitrakker MDL %d.%d", MSN(*buf), LSN(*buf)); m->volbase = 0xff; m->c4rate = C4_NTSC_RATE; data.v_envnum = data.p_envnum = data.f_envnum = 0; data.s_index = calloc(256, sizeof (int)); data.i_index = calloc(256, sizeof (int)); data.v_index = malloc(256 * sizeof (int)); data.p_index = malloc(256 * sizeof (int)); data.f_index = malloc(256 * sizeof (int)); for (i = 0; i < 256; i++) { data.v_index[i] = data.p_index[i] = data.f_index[i] = -1; } /* Load IFFoid chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); retval = -1; goto err; } libxmp_iff_release(handle); /* Reindex instruments */ for (i = 0; i < mod->trk; i++) { for (j = 0; j < mod->xxt[i]->rows; j++) { struct xmp_event *e = &mod->xxt[i]->event[j]; for (l = 0; l < mod->ins; l++) { if (e->ins && e->ins == data.i_index[l]) { e->ins = l + 1; break; } } } } /* Reindex envelopes, etc. */ for (i = 0; i < mod->ins; i++) { fix_env(i, &mod->xxi[i].aei, data.v_env, data.v_index, data.v_envnum); fix_env(i, &mod->xxi[i].pei, data.p_env, data.p_index, data.p_envnum); fix_env(i, &mod->xxi[i].fei, data.f_env, data.f_index, data.f_envnum); for (j = 0; j < mod->xxi[i].nsm; j++) { for (k = 0; k < mod->smp; k++) { if (mod->xxi[i].sub[j].sid == data.s_index[k]) { mod->xxi[i].sub[j].sid = k; /*libxmp_c2spd_to_note(data.c2spd[k], &mod->xxi[i].sub[j].xpo, &mod->xxi[i].sub[j].fin);*/ break; } } } } err: free(data.f_index); free(data.p_index); free(data.v_index); free(data.i_index); free(data.s_index); free(data.v_env); free(data.p_env); free(data.f_env); free(data.packinfo); m->quirk |= QUIRKS_FT2 | QUIRK_KEYOFF; m->read_event_type = READ_EVENT_FT2; return retval; } libxmp-4.4.1/src/loaders/st_load.c0000664000175000017500000002460212775035311016660 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Ultimate Soundtracker support based on the module format description * written by Michael Schwendt */ #include #include "loader.h" #include "mod.h" #include "period.h" static int st_test(HIO_HANDLE *, char *, const int); static int st_load(struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_st = { "Soundtracker", st_test, st_load }; static const int period[] = { 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, -1 }; static int st_test(HIO_HANDLE *f, char *t, const int start) { int i, j, k; int pat, ins, smp_size; struct st_header mh; uint8 mod_event[4]; long size; size = hio_size(f); if (size < 600) { return -1; } smp_size = 0; hio_seek(f, start, SEEK_SET); hio_read(mh.name, 1, 20, f); if (libxmp_test_name(mh.name, 20) < 0) { return -1; } for (i = 0; i < 15; i++) { hio_read(mh.ins[i].name, 1, 22, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(mh.order, 1, 128, f); for (pat = i = 0; i < 128; i++) { if (mh.order[i] > 0x7f) return -1; if (mh.order[i] > pat) pat = mh.order[i]; } pat++; if (pat > 0x7f || mh.len == 0 || mh.len > 0x7f) return -1; for (i = 0; i < 15; i++) { if (libxmp_test_name(mh.ins[i].name, 22) < 0) return -1; if (mh.ins[i].volume > 0x40) return -1; if (mh.ins[i].finetune > 0x0f) return -1; if (mh.ins[i].size > 0x8000) return -1; /* This test is always false, disable it * * if ((mh.ins[i].loop_start >> 1) > 0x8000) * return -1; */ if (mh.ins[i].loop_size > 0x8000) return -1; /* This test fails in atmosfer.mod, disable it * * if (mh.ins[i].loop_size > 1 && mh.ins[i].loop_size > mh.ins[i].size) * return -1; */ if ((mh.ins[i].loop_start >> 1) > mh.ins[i].size) return -1; if (mh.ins[i].size && (mh.ins[i].loop_start >> 1) == mh.ins[i].size) return -1; if (mh.ins[i].size == 0 && mh.ins[i].loop_start > 0) return -1; smp_size += 2 * mh.ins[i].size; } if (smp_size < 8) return -1; for (ins = i = 0; i < pat; i++) { for (j = 0; j < (64 * 4); j++) { int p, s; hio_read(mod_event, 1, 4, f); s = (mod_event[0] & 0xf0) | MSN(mod_event[2]); if (s > 15) /* sample number > 15 */ return -1; if (s > ins) /* find highest used sample */ ins = s; p = 256 * LSN(mod_event[0]) + mod_event[1]; if (p == 0) continue; if (p == 162) /* used in Karsten Obarski's blueberry.mod */ continue; for (k = 0; period[k] >= 0; k++) { if (p == period[k]) break; } if (period[k] < 0) return -1; } } /* Check if file was cut before any unused samples */ if (size < 600 + pat * 1024 + smp_size) { int ss; for (ss = i = 0; i < ins; i++) { ss += 2 * mh.ins[i].size; } if (size < 600 + pat * 1024 + ss) { return -1; } } hio_seek(f, start, SEEK_SET); libxmp_read_title(f, t, 20); return 0; } static int st_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j; int smp_size; struct xmp_event ev, *event; struct st_header mh; uint8 mod_event[4]; int ust = 1; /* int lps_mult = m->fetch & XMP_CTL_FIXLOOP ? 1 : 2; */ char *modtype; int fxused; int pos; int used_ins; /* Number of samples actually used */ long size; LOAD_INIT(); size = hio_size(f); mod->chn = 4; mod->ins = 15; mod->smp = mod->ins; smp_size = 0; hio_read(mh.name, 1, 20, f); for (i = 0; i < 15; i++) { hio_read(mh.ins[i].name, 1, 22, f); mh.ins[i].size = hio_read16b(f); mh.ins[i].finetune = hio_read8(f); mh.ins[i].volume = hio_read8(f); mh.ins[i].loop_start = hio_read16b(f); mh.ins[i].loop_size = hio_read16b(f); } mh.len = hio_read8(f); mh.restart = hio_read8(f); hio_read(mh.order, 1, 128, f); mod->len = mh.len; mod->rst = mh.restart; /* UST: The byte at module offset 471 is BPM, not the song restart * The default for UST modules is 0x78 = 120 BPM = 48 Hz. */ if (mod->rst < 0x40) /* should be 0x20 */ ust = 0; memcpy(mod->xxo, mh.order, 128); for (i = 0; i < 128; i++) { if (mod->xxo[i] > mod->pat) mod->pat = mod->xxo[i]; } mod->pat++; for (i = 0; i < mod->ins; i++) { /* UST: Volume word does not contain a "Finetuning" value in its * high-byte. */ if (mh.ins[i].finetune) ust = 0; /* if (mh.ins[i].size == 0 && mh.ins[i].loop_size == 1) nt = 1; */ /* UST: Maximum sample length is 9999 bytes decimal, but 1387 * words hexadecimal. Longest samples on original sample disk * ST-01 were 9900 bytes. */ if (mh.ins[i].size > 0x1387 || mh.ins[i].loop_start > 9999 || mh.ins[i].loop_size > 0x1387) { ust = 0; } smp_size += 2 * mh.ins[i].size; } if (libxmp_init_instrument(m) < 0) { return -1; } for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; struct xmp_sample *xxs = &mod->xxs[i]; struct xmp_subinstrument *sub; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; sub = &xxi->sub[0]; xxs->len = 2 * mh.ins[i].size - mh.ins[i].loop_start; xxs->lps = 0; xxs->lpe = xxs->lps + 2 * mh.ins[i].loop_size; xxs->flg = mh.ins[i].loop_size > 1 ? XMP_SAMPLE_LOOP : 0; sub->fin = (int8) (mh.ins[i].finetune << 4); sub->vol = mh.ins[i].volume; sub->pan = 0x80; sub->sid = i; strncpy((char *)xxi->name, (char *)mh.ins[i].name, 22); if (xxs->len > 0) { xxi->nsm = 1; } } mod->trk = mod->chn * mod->pat; strncpy(mod->name, (char *)mh.name, 20); /* Scan patterns for tracker detection */ fxused = 0; pos = hio_tell(f); for (i = 0; i < mod->pat; i++) { for (j = 0; j < (64 * mod->chn); j++) { hio_read(mod_event, 1, 4, f); libxmp_decode_protracker_event(&ev, mod_event); if (ev.fxt) fxused |= 1 << ev.fxt; else if (ev.fxp) fxused |= 1; /* UST: Only effects 1 (arpeggio) and 2 (pitchbend) are * available. */ if (ev.fxt && ev.fxt != 1 && ev.fxt != 2) ust = 0; /* Karsten Obarski's sleepwalk uses arpeggio 30 and 40 */ if (ev.fxt == 1) { /* unlikely arpeggio */ if (ev.fxp == 0x00) ust = 0; /*if ((ev.fxp & 0x0f) == 0 || (ev.fxp & 0xf0) == 0) ust = 0; */ } if (ev.fxt == 2) { /* bend up and down at same time? */ if ((ev.fxp & 0x0f) != 0 && (ev.fxp & 0xf0) != 0) ust = 0; } } } if (fxused & ~0x0006) { ust = 0; } if (ust) { modtype = "Ultimate Soundtracker"; } else if ((fxused & ~0xd007) == 0) { modtype = "Soundtracker IX"; /* or MasterSoundtracker? */ } else if ((fxused & ~0xf807) == 0) { modtype = "D.O.C Soundtracker 2.0"; } else { modtype = "unknown tracker"; } snprintf(mod->type, XMP_NAME_SIZE, "%s", modtype); MODULE_INFO(); if (hio_seek(f, start + pos, SEEK_SET) < 0) { return -1; } if (libxmp_init_pattern(mod) < 0) { return -1; } /* Load and convert patterns */ D_(D_INFO "Stored patterns: %d", mod->pat); used_ins = 0; for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < (64 * mod->chn); j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); hio_read(mod_event, 1, 4, f); libxmp_decode_protracker_event(event, mod_event); if (ev.ins > used_ins) used_ins = ev.ins; } } for (i = 0; i < mod->ins; i++) { D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mh.ins[i].loop_size > 1 ? 'L' : ' ', mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].fin >> 4); } m->quirk |= QUIRK_NOBPM; m->period_type = PERIOD_MODRNG; /* Perform the necessary conversions for Ultimate Soundtracker */ if (ust) { /* Fix restart & bpm */ mod->bpm = mod->rst; mod->rst = 0; /* Fix sample loops */ for (i = 0; i < mod->ins; i++) { /* FIXME */ } /* Fix effects (arpeggio and pitchbending) */ for (i = 0; i < mod->pat; i++) { for (j = 0; j < (64 * mod->chn); j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); if (event->fxt == 1) event->fxt = 0; else if (event->fxt == 2 && (event->fxp & 0xf0) == 0) event->fxt = 1; else if (event->fxt == 2 && (event->fxp & 0x0f) == 0) event->fxp >>= 4; } } } else { if (mod->rst >= mod->len) mod->rst = 0; } /* Load samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (!mod->xxs[i].len) continue; /* Skip transient part of sample. * * Dennis Lindroos reports: One main thing is * sample-looping which on all trackers up to Noisetracker 1 (i * think it was Mahoney who actually changed the loopstart to be * in WORDS) never play looped samples from the beginning, i.e. * only plays the looped part. This can be heard in old modules * especially with "analogstring", "strings2" or "strings3" * samples because these have "slow attack" that is not part of * the loop and thus they sound "sharper".. */ hio_seek(f, mh.ins[i].loop_start, SEEK_CUR); if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) { return -1; } } return 0; } libxmp-4.4.1/src/loaders/far_load.c0000664000175000017500000002347112774567167017027 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Based on the Farandole Composer format specifications by Daniel Potter. * * "(...) this format is for EDITING purposes (storing EVERYTHING you're * working on) so it may include information not completely neccessary." */ #include "loader.h" struct far_header { uint32 magic; /* File magic: 'FAR\xfe' */ uint8 name[40]; /* Song name */ uint8 crlf[3]; /* 0x0d 0x0a 0x1A */ uint16 headersize; /* Remaining header size in bytes */ uint8 version; /* Version MSN=major, LSN=minor */ uint8 ch_on[16]; /* Channel on/off switches */ uint8 rsvd1[9]; /* Current editing values */ uint8 tempo; /* Default tempo */ uint8 pan[16]; /* Channel pan definitions */ uint8 rsvd2[4]; /* Grid, mode (for editor) */ uint16 textlen; /* Length of embedded text */ }; struct far_header2 { uint8 order[256]; /* Orders */ uint8 patterns; /* Number of stored patterns (?) */ uint8 songlen; /* Song length in patterns */ uint8 restart; /* Restart pos */ uint16 patsize[256]; /* Size of each pattern in bytes */ }; struct far_instrument { uint8 name[32]; /* Instrument name */ uint32 length; /* Length of sample (up to 64Kb) */ uint8 finetune; /* Finetune (unsuported) */ uint8 volume; /* Volume (unsuported?) */ uint32 loop_start; /* Loop start */ uint32 loopend; /* Loop end */ uint8 sampletype; /* 1=16 bit sample */ uint8 loopmode; }; struct far_event { uint8 note; uint8 instrument; uint8 volume; /* In reverse nibble order? */ uint8 effect; }; #define MAGIC_FAR MAGIC4('F','A','R',0xfe) static int far_test (HIO_HANDLE *, char *, const int); static int far_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_far = { "Farandole Composer", far_test, far_load }; static int far_test(HIO_HANDLE *f, char *t, const int start) { if (hio_read32b(f) != MAGIC_FAR) return -1; libxmp_read_title(f, t, 40); return 0; } #define NONE 0xff #define FX_FAR_SETVIBRATO 0xfe #define FX_FAR_VSLIDE_UP 0xfd #define FX_FAR_VSLIDE_DN 0xfc #define FX_FAR_RETRIG 0xfb #define FX_FAR_DELAY 0xfa #define FX_FAR_PORTA_UP 0xf9 #define FX_FAR_PORTA_DN 0xf8 static const uint8 fx[] = { NONE, FX_FAR_PORTA_UP, /* 0x1? Pitch Adjust */ FX_FAR_PORTA_DN, /* 0x2? Pitch Adjust */ FX_PER_TPORTA, /* 0x3? Port to Note -- FIXME */ FX_FAR_RETRIG, /* 0x4? Retrigger */ FX_FAR_SETVIBRATO, /* 0x5? Set VibDepth */ FX_VIBRATO, /* 0x6? Vibrato note */ FX_FAR_VSLIDE_UP, /* 0x7? VolSld Up */ FX_FAR_VSLIDE_DN, /* 0x8? VolSld Dn */ FX_PER_VIBRATO, /* 0x9? Vibrato Sust */ NONE, /* 0xa? Port To Vol */ NONE, /* N/A */ FX_FAR_DELAY, /* 0xc? Note Offset */ NONE, /* 0xd? Fine Tempo dn */ NONE, /* 0xe? Fine Tempo up */ FX_SPEED /* 0xf? Tempo */ }; static int far_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, vib = 0; struct xmp_event *event; struct far_header ffh; struct far_header2 ffh2; struct far_instrument fih; uint8 sample_map[8]; LOAD_INIT(); hio_read32b(f); /* File magic: 'FAR\xfe' */ hio_read(&ffh.name, 40, 1, f); /* Song name */ hio_read(&ffh.crlf, 3, 1, f); /* 0x0d 0x0a 0x1A */ ffh.headersize = hio_read16l(f); /* Remaining header size in bytes */ ffh.version = hio_read8(f); /* Version MSN=major, LSN=minor */ hio_read(&ffh.ch_on, 16, 1, f); /* Channel on/off switches */ hio_seek(f, 9, SEEK_CUR); /* Current editing values */ ffh.tempo = hio_read8(f); /* Default tempo */ hio_read(&ffh.pan, 16, 1, f); /* Channel pan definitions */ hio_read32l(f); /* Grid, mode (for editor) */ ffh.textlen = hio_read16l(f); /* Length of embedded text */ /* Sanity check */ if (ffh.tempo == 0) { return -1; } hio_seek(f, ffh.textlen, SEEK_CUR); /* Skip song text */ hio_read(&ffh2.order, 256, 1, f); /* Orders */ ffh2.patterns = hio_read8(f); /* Number of stored patterns (?) */ ffh2.songlen = hio_read8(f); /* Song length in patterns */ ffh2.restart = hio_read8(f); /* Restart pos */ for (i = 0; i < 256; i++) { ffh2.patsize[i] = hio_read16l(f); /* Size of each pattern in bytes */ } if (hio_error(f)) { return -1; } mod->chn = 16; /*mod->pat=ffh2.patterns; (Error in specs? --claudio) */ mod->len = ffh2.songlen; mod->spd = 6; mod->bpm = 8 * 60 / ffh.tempo; memcpy (mod->xxo, ffh2.order, mod->len); for (mod->pat = i = 0; i < 256; i++) { if (ffh2.patsize[i]) mod->pat = i + 1; } mod->trk = mod->chn * mod->pat; strncpy(mod->name, (char *)ffh.name, 40); libxmp_set_type(m, "Farandole Composer %d.%d", MSN(ffh.version), LSN(ffh.version)); MODULE_INFO(); if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Comment bytes : %d", ffh.textlen); D_(D_INFO "Stored patterns: %d", mod->pat); for (i = 0; i < mod->pat; i++) { uint8 brk, note, ins, vol, fxb; int rows; if (libxmp_alloc_pattern(mod, i) < 0) return -1; if (!ffh2.patsize[i]) continue; rows = (ffh2.patsize[i] - 2) / 64; /* Sanity check */ if (rows <= 0 || rows > 256) { return -1; } mod->xxp[i]->rows = rows; if (libxmp_alloc_tracks_in_pattern(mod, i) < 0) return -1; brk = hio_read8(f) + 1; hio_read8(f); for (j = 0; j < mod->xxp[i]->rows * mod->chn; j++) { event = &EVENT(i, j % mod->chn, j / mod->chn); if ((j % mod->chn) == 0 && (j / mod->chn) == brk) event->f2t = FX_BREAK; note = hio_read8(f); ins = hio_read8(f); vol = hio_read8(f); fxb = hio_read8(f); if (note) event->note = note + 48; if (event->note || ins) event->ins = ins + 1; vol = 16 * LSN(vol) + MSN(vol); if (vol) event->vol = vol - 0x10; /* ? */ event->fxt = fx[MSN(fxb)]; event->fxp = LSN(fxb); switch (event->fxt) { case NONE: event->fxt = event->fxp = 0; break; case FX_FAR_PORTA_UP: event->fxt = FX_EXTENDED; event->fxp |= (EX_F_PORTA_UP << 4); break; case FX_FAR_PORTA_DN: event->fxt = FX_EXTENDED; event->fxp |= (EX_F_PORTA_DN << 4); break; case FX_FAR_RETRIG: event->fxt = FX_EXTENDED; event->fxp |= (EX_RETRIG << 4); break; case FX_FAR_DELAY: event->fxt = FX_EXTENDED; event->fxp |= (EX_DELAY << 4); break; case FX_FAR_SETVIBRATO: vib = event->fxp & 0x0f; event->fxt = event->fxp = 0; break; case FX_VIBRATO: event->fxp = (event->fxp << 4) + vib; break; case FX_PER_VIBRATO: event->fxp = (event->fxp << 4) + vib; break; case FX_FAR_VSLIDE_UP: /* Fine volume slide up */ event->fxt = FX_EXTENDED; event->fxp |= (EX_F_VSLIDE_UP << 4); break; case FX_FAR_VSLIDE_DN: /* Fine volume slide down */ event->fxt = FX_EXTENDED; event->fxp |= (EX_F_VSLIDE_DN << 4); break; case FX_SPEED: if (event->fxp != 0) { event->fxp = 8 * 60 / event->fxp; } else { event->fxt = 0; } break; } } } mod->ins = -1; hio_read(sample_map, 1, 8, f); for (i = 0; i < 64; i++) { if (sample_map[i / 8] & (1 << (i % 8))) mod->ins = i; } mod->ins++; mod->smp = mod->ins; if (libxmp_init_instrument(m) < 0) return -1; /* Read and convert instruments and samples */ for (i = 0; i < mod->ins; i++) { if (!(sample_map[i / 8] & (1 << (i % 8)))) continue; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; hio_read(&fih.name, 32, 1, f); /* Instrument name */ fih.length = hio_read32l(f); /* Length of sample (up to 64Kb) */ fih.finetune = hio_read8(f); /* Finetune (unsuported) */ fih.volume = hio_read8(f); /* Volume (unsuported?) */ fih.loop_start = hio_read32l(f);/* Loop start */ fih.loopend = hio_read32l(f); /* Loop end */ fih.sampletype = hio_read8(f); /* 1=16 bit sample */ fih.loopmode = hio_read8(f); /* Sanity check */ if (fih.length > 0x10000 || fih.loop_start > 0x10000 || fih.loopend > 0x10000) { return -1; } mod->xxs[i].len = fih.length; mod->xxs[i].lps = fih.loop_start; mod->xxs[i].lpe = fih.loopend; mod->xxs[i].flg = 0; if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; if (fih.sampletype != 0) { mod->xxs[i].flg |= XMP_SAMPLE_16BIT; mod->xxs[i].len >>= 1; mod->xxs[i].lps >>= 1; mod->xxs[i].lpe >>= 1; } mod->xxs[i].flg |= fih.loopmode ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].vol = 0xff; /* fih.volume; */ mod->xxi[i].sub[0].sid = i; libxmp_instrument_name(mod, i, fih.name, 32); D_(D_INFO "[%2X] %-32.32s %04x %04x %04x %c V%02x", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, fih.loopmode ? 'L' : ' ', mod->xxi[i].sub[0].vol); if (libxmp_load_sample(m, f, 0, &mod->xxs[i], NULL) < 0) return -1; } m->volbase = 0xff; return 0; } libxmp-4.4.1/src/loaders/no_load.c0000664000175000017500000001272412774567167016672 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "loader.h" #include "period.h" /* Nir Oren's Liquid Tracker old "NO" format. I have only one NO module, * Moti Radomski's "Time after time" from ftp.modland.com. */ static int no_test (HIO_HANDLE *, char *, const int); static int no_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_no = { "Liquid Tracker NO", no_test, no_load }; static int no_test(HIO_HANDLE *f, char *t, const int start) { int nsize, pat, chn; int i; hio_seek(f, start, SEEK_CUR); if (hio_read32b(f) != 0x4e4f0000) /* NO 0x00 0x00 */ return -1; nsize = hio_read8(f); if (nsize != 20) return -1; /* test title */ for (i = 0; i < nsize; i++) { if (hio_read8(f) == 0) return -1; } hio_seek(f, 9, SEEK_CUR); /* test number of patterns */ pat = hio_read8(f); if (pat == 0) return -1; hio_read8(f); /* test number of channels */ chn = hio_read8(f); if (chn <= 0 || chn > 16) return -1; hio_seek(f, start + 5, SEEK_SET); libxmp_read_title(f, t, nsize); return 0; } static const uint8 fx[] = { FX_ARPEGGIO, 0, FX_BREAK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static int no_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; struct xmp_event *event; int i, j, k; int nsize; LOAD_INIT(); hio_read32b(f); /* NO 0x00 0x00 */ libxmp_set_type(m, "Liquid Tracker"); nsize = hio_read8(f); for (i = 0; i < nsize; i++) { uint8 x = hio_read8(f); if (i < XMP_NAME_SIZE) mod->name[i] = x; } hio_read16l(f); hio_read16l(f); hio_read16l(f); hio_read16l(f); hio_read8(f); mod->pat = hio_read8(f); hio_read8(f); mod->chn = hio_read8(f); mod->trk = mod->pat * mod->chn; hio_read8(f); hio_read16l(f); hio_read16l(f); hio_read8(f); mod->ins = mod->smp = 63; for (i = 0; i < 256; i++) { uint8 x = hio_read8(f); if (x == 0xff) break; mod->xxo[i] = x; } hio_seek(f, 255 - i, SEEK_CUR); mod->len = i; m->c4rate = C4_NTSC_RATE; MODULE_INFO(); if (libxmp_init_instrument(m) < 0) return -1; /* Read instrument names */ for (i = 0; i < mod->ins; i++) { int hasname, c2spd; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; nsize = hio_read8(f); if (hio_error(f)) { return -1; } hasname = 0; for (j = 0; j < nsize; j++) { uint8 x = hio_read8(f); if (x != 0x20) hasname = 1; if (j < 32) mod->xxi[i].name[j] = x; } if (!hasname) mod->xxi[i].name[0] = 0; hio_read32l(f); hio_read32l(f); mod->xxi[i].sub[0].vol = hio_read8(f); c2spd = hio_read16l(f); mod->xxs[i].len = hio_read16l(f); mod->xxs[i].lps = hio_read16l(f); mod->xxs[i].lpe = hio_read16l(f); hio_read32l(f); hio_read16l(f); if (mod->xxs[i].len > 0) mod->xxi[i].nsm = 1; /* mod->xxs[i].lps = 0; mod->xxs[i].lpe = 0; */ mod->xxs[i].flg = mod->xxs[i].lpe > 0 ? XMP_SAMPLE_LOOP : 0; mod->xxi[i].sub[0].fin = 0; mod->xxi[i].sub[0].pan = 0x80; mod->xxi[i].sub[0].sid = i; D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %5d", i, mod->xxi[i].name, mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? 'L' : ' ', mod->xxi[i].sub[0].vol, c2spd); libxmp_c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); } if (libxmp_init_pattern(mod) < 0) return -1; /* Read and convert patterns */ D_(D_INFO "Stored patterns: %d ", mod->pat); for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0) return -1; for (j = 0; j < mod->xxp[i]->rows; j++) { for (k = 0; k < mod->chn; k++) { uint32 x, note, ins, vol, fxt, fxp; event = &EVENT (i, k, j); x = hio_read32l(f); note = x & 0x0000003f; ins = (x & 0x00001fc0) >> 6; vol = (x & 0x000fe000) >> 13; fxt = (x & 0x00f00000) >> 20; fxp = (x & 0xff000000) >> 24; if (note != 0x3f) event->note = 36 + note; if (ins != 0x7f) event->ins = 1 + ins; if (vol != 0x7f) event->vol = vol; if (fxt != 0x0f) { event->fxt = fx[fxt]; event->fxp = fxp; } } } } /* Read samples */ D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->ins; i++) { if (mod->xxs[i].len == 0) continue; if (libxmp_load_sample(m, f, SAMPLE_FLAG_UNS, &mod->xxs[i], NULL) < 0) return -1; } m->quirk |= QUIRKS_ST3; m->read_event_type = READ_EVENT_ST3; return 0; } libxmp-4.4.1/src/loaders/dbm_load.c0000664000175000017500000002176112775035311016777 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* Based on DigiBooster_E.guide from the DigiBoosterPro 2.20 package. * DigiBooster Pro written by Tomasz & Waldemar Piasta */ #include "loader.h" #include "iff.h" #include "period.h" #define MAGIC_DBM0 MAGIC4('D','B','M','0') static int dbm_test(HIO_HANDLE *, char *, const int); static int dbm_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_dbm = { "DigiBooster Pro", dbm_test, dbm_load }; static int dbm_test(HIO_HANDLE * f, char *t, const int start) { if (hio_read32b(f) != MAGIC_DBM0) return -1; hio_seek(f, 12, SEEK_CUR); libxmp_read_title(f, t, 44); return 0; } struct local_data { int have_song; }; static int get_info(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int val; /* Sanity check */ if (mod->ins != 0) { return -1; } val = hio_read16b(f); if (val < 0 || val > 255) { D_(D_CRIT "Invalid number of instruments: %d", val); goto err; } mod->ins = val; val = hio_read16b(f); if (val < 0) { D_(D_CRIT "Invalid number of samples: %d", val); goto err2; } mod->smp = val; hio_read16b(f); /* Songs */ val = hio_read16b(f); if (val < 0 || val > 256) { D_(D_CRIT "Invalid number of patterns: %d", val); goto err3; } mod->pat = val; val = hio_read16b(f); if (val < 0 || val > XMP_MAX_CHANNELS) { D_(D_CRIT "Invalid number of channels: %d", val); goto err4; } mod->chn = val; mod->trk = mod->pat * mod->chn; if (libxmp_init_instrument(m) < 0) return -1; return 0; err4: mod->pat = 0; err3: mod->smp = 0; err2: mod->ins = 0; err: return -1; } static int get_song(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; struct local_data *data = (struct local_data *)parm; int i; char buffer[50]; if (data->have_song) return 0; data->have_song = 1; hio_read(buffer, 44, 1, f); D_(D_INFO "Song name: %s", buffer); mod->len = hio_read16b(f); D_(D_INFO "Song length: %d patterns", mod->len); /* Sanity check */ if (mod->len > 256) { return -1; } for (i = 0; i < mod->len; i++) mod->xxo[i] = hio_read16b(f); return 0; } static int get_inst(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i; int c2spd, flags, snum; uint8 buffer[50]; D_(D_INFO "Instruments: %d", mod->ins); for (i = 0; i < mod->ins; i++) { mod->xxi[i].nsm = 1; if (libxmp_alloc_subinstrument(mod, i, 1) < 0) return -1; hio_read(buffer, 30, 1, f); libxmp_instrument_name(mod, i, buffer, 30); snum = hio_read16b(f); if (snum == 0 || snum > mod->smp) continue; mod->xxi[i].sub[0].sid = --snum; mod->xxi[i].sub[0].vol = hio_read16b(f); c2spd = hio_read32b(f); mod->xxs[snum].lps = hio_read32b(f); mod->xxs[snum].lpe = mod->xxs[i].lps + hio_read32b(f); mod->xxi[i].sub[0].pan = 0x80 + (int16)hio_read16b(f); if (mod->xxi[i].sub[0].pan > 0xff) mod->xxi[i].sub[0].pan = 0xff; flags = hio_read16b(f); mod->xxs[snum].flg = flags & 0x03 ? XMP_SAMPLE_LOOP : 0; mod->xxs[snum].flg |= flags & 0x02 ? XMP_SAMPLE_LOOP_BIDIR : 0; libxmp_c2spd_to_note(c2spd, &mod->xxi[i].sub[0].xpo, &mod->xxi[i].sub[0].fin); D_(D_INFO "[%2X] %-30.30s #%02X V%02x P%02x %5d", i, mod->xxi[i].name, snum, mod->xxi[i].sub[0].vol, mod->xxi[i].sub[0].pan, c2spd); } return 0; } static int get_patt(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, c, r, n, sz; struct xmp_event *event, dummy; uint8 x; if (libxmp_init_pattern(mod) < 0) return -1; D_(D_INFO "Stored patterns: %d ", mod->pat); /* * Note: channel and flag bytes are inverted in the format * description document */ for (i = 0; i < mod->pat; i++) { if (libxmp_alloc_pattern_tracks(mod, i, hio_read16b(f)) < 0) return -1; sz = hio_read32b(f); //printf("rows = %d, size = %d\n", mod->xxp[i]->rows, sz); r = 0; /*c = -1;*/ while (sz > 0) { //printf(" offset=%x, sz = %d, ", hio_tell(f), sz); c = hio_read8(f); if (--sz <= 0) break; //printf("c = %02x\n", c); if (c == 0) { r++; continue; } c--; n = hio_read8(f); if (--sz <= 0) break; //printf(" n = %d\n", n); if (c >= mod->chn || r >= mod->xxp[i]->rows) { event = &dummy; } else { event = &EVENT(i, c, r); } memset(event, 0, sizeof (struct xmp_event)); if (n & 0x01) { x = hio_read8(f); event->note = 13 + MSN(x) * 12 + LSN(x); if (--sz <= 0) break; } if (n & 0x02) { event->ins = hio_read8(f); if (--sz <= 0) break; } if (n & 0x04) { event->fxt = hio_read8(f); if (--sz <= 0) break; } if (n & 0x08) { event->fxp = hio_read8(f); if (--sz <= 0) break; } if (n & 0x10) { event->f2t = hio_read8(f); if (--sz <= 0) break; } if (n & 0x20) { event->f2p = hio_read8(f); if (--sz <= 0) break; } if (event->fxt == 0x1c) event->fxt = FX_S3M_BPM; if (event->fxt > 0x1c) event->fxt = event->f2p = 0; if (event->f2t == 0x1c) event->f2t = FX_S3M_BPM; if (event->f2t > 0x1c) event->f2t = event->f2p = 0; } } return 0; } static int get_smpl(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, flags; D_(D_INFO "Stored samples: %d", mod->smp); for (i = 0; i < mod->smp; i++) { flags = hio_read32b(f); mod->xxs[i].len = hio_read32b(f); if (flags & 0x02) { mod->xxs[i].flg |= XMP_SAMPLE_16BIT; } if (flags & 0x04) { /* Skip 32-bit samples */ mod->xxs[i].len <<= 2; hio_seek(f, mod->xxs[i].len, SEEK_CUR); continue; } if (libxmp_load_sample(m, f, SAMPLE_FLAG_BIGEND, &mod->xxs[i], NULL) < 0) return -1; if (mod->xxs[i].len == 0) continue; D_(D_INFO "[%2X] %08x %05x%c%05x %05x %c", i, flags, mod->xxs[i].len, mod->xxs[i].flg & XMP_SAMPLE_16BIT ? '+' : ' ', mod->xxs[i].lps, mod->xxs[i].lpe, mod->xxs[i].flg & XMP_SAMPLE_LOOP ? (mod->xxs[i].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' : 'L') : ' '); } return 0; } static int get_venv(struct module_data *m, int size, HIO_HANDLE *f, void *parm) { struct xmp_module *mod = &m->mod; int i, j, nenv, ins; nenv = hio_read16b(f); D_(D_INFO "Vol envelopes : %d ", nenv); for (i = 0; i < nenv; i++) { ins = hio_read16b(f) - 1; mod->xxi[ins].aei.flg = hio_read8(f) & 0x07; mod->xxi[ins].aei.npt = hio_read8(f); mod->xxi[ins].aei.sus = hio_read8(f); mod->xxi[ins].aei.lps = hio_read8(f); mod->xxi[ins].aei.lpe = hio_read8(f); hio_read8(f); /* 2nd sustain */ //hio_read8(f); /* reserved */ for (j = 0; j < 32; j++) { mod->xxi[ins].aei.data[j * 2 + 0] = hio_read16b(f); mod->xxi[ins].aei.data[j * 2 + 1] = hio_read16b(f); } } return 0; } static int dbm_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; iff_handle handle; char name[44]; uint16 version; int i, ret; struct local_data data; LOAD_INIT(); hio_read32b(f); /* DBM0 */ data.have_song = 0; version = hio_read16b(f); hio_seek(f, 10, SEEK_CUR); hio_read(name, 1, 44, f); handle = libxmp_iff_new(); if (handle == NULL) return -1; m->c4rate = C4_NTSC_RATE; /* IFF chunk IDs */ ret = libxmp_iff_register(handle, "INFO", get_info); ret |= libxmp_iff_register(handle, "SONG", get_song); ret |= libxmp_iff_register(handle, "INST", get_inst); ret |= libxmp_iff_register(handle, "PATT", get_patt); ret |= libxmp_iff_register(handle, "SMPL", get_smpl); ret |= libxmp_iff_register(handle, "VENV", get_venv); if (ret != 0) return -1; strncpy(mod->name, name, XMP_NAME_SIZE); snprintf(mod->type, XMP_NAME_SIZE, "DigiBooster Pro %d.%02x DBM0", version >> 8, version & 0xff); MODULE_INFO(); /* Load IFF chunks */ if (libxmp_iff_load(handle, m, f, &data) < 0) { libxmp_iff_release(handle); return -1; } libxmp_iff_release(handle); for (i = 0; i < mod->chn; i++) mod->xxc[i].pan = 0x80; return 0; } libxmp-4.4.1/src/loaders/Makefile0000664000175000017500000000200412773463501016523 0ustar claudioclaudio LOADERS = xm_load.o mod_load.o s3m_load.o stm_load.o 669_load.o far_load.o \ mtm_load.o ptm_load.o okt_load.o ult_load.o mdl_load.o it_load.o \ stx_load.o pt3_load.o sfx_load.o flt_load.o st_load.o emod_load.o \ imf_load.o digi_load.o fnk_load.o ice_load.o liq_load.o ims_load.o \ masi_load.o amf_load.o psm_load.o stim_load.o mmd_common.o \ mmd1_load.o mmd3_load.o rtm_load.o dt_load.o no_load.o arch_load.o \ sym_load.o med2_load.o med3_load.o med4_load.o dbm_load.o umx_load.o \ gdm_load.o pw_load.o gal5_load.o gal4_load.o mfp_load.o asylum_load.o \ hmn_load.o mgt_load.o chip_load.o abk_load.o LOADERS_OBJS = common.o iff.o itsex.o asif.o voltable.o sample.o $(LOADERS) LOADERS_DFILES = Makefile $(LOADERS_OBJS:.o=.c) \ asif.h iff.h it.h loader.h med.h mod.h s3m.h xm.h LOADERS_PATH = src/loaders OBJS += $(addprefix $(LOADERS_PATH)/,$(LOADERS_OBJS)) default: dist-loaders:: mkdir -p $(DIST)/$(LOADERS_PATH) cp -RPp $(addprefix $(LOADERS_PATH)/,$(LOADERS_DFILES)) $(DIST)/$(LOADERS_PATH) libxmp-4.4.1/src/loaders/mmd3_load.c0000664000175000017500000003203412775035311017070 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "med.h" #include "loader.h" #include "med_extras.h" static int mmd3_test (HIO_HANDLE *, char *, const int); static int mmd3_load (struct module_data *, HIO_HANDLE *, const int); const struct format_loader libxmp_loader_mmd3 = { "OctaMED", mmd3_test, mmd3_load }; static int mmd3_test(HIO_HANDLE *f, char *t, const int start) { char id[4]; uint32 offset, len; if (hio_read(id, 1, 4, f) < 4) return -1; if (memcmp(id, "MMD2", 4) && memcmp(id, "MMD3", 4)) return -1; hio_seek(f, 28, SEEK_CUR); offset = hio_read32b(f); /* expdata_offset */ if (offset) { hio_seek(f, start + offset + 44, SEEK_SET); offset = hio_read32b(f); len = hio_read32b(f); hio_seek(f, start + offset, SEEK_SET); libxmp_read_title(f, t, len); } else { libxmp_read_title(f, t, 0); } return 0; } /* Number of octaves in IFFOCT samples */ static const int num_oct[6] = { 5, 3, 2, 4, 6, 7 }; static int mmd3_load(struct module_data *m, HIO_HANDLE *f, const int start) { struct xmp_module *mod = &m->mod; int i, j, k; struct MMD0 header; struct MMD2song song; struct MMD1Block block; struct InstrHdr instr; struct SynthInstr synth; struct InstrExt exp_smp; struct MMD0exp expdata; struct xmp_event *event; int ver = 0; int smp_idx = 0; uint8 e[4]; int song_offset; int seqtable_offset; int trackvols_offset; int trackpans_offset; int blockarr_offset; int smplarr_offset; int expdata_offset; int expsmp_offset; int songname_offset; int iinfo_offset; int mmdinfo_offset; int playseq_offset; int pos; int bpm_on, bpmlen, med_8ch, hexvol; LOAD_INIT(); hio_read(&header.id, 4, 1, f); ver = *((char *)&header.id + 3) - '1' + 1; D_(D_WARN "load header"); header.modlen = hio_read32b(f); song_offset = hio_read32b(f); D_(D_INFO "song_offset = 0x%08x", song_offset); hio_read16b(f); hio_read16b(f); blockarr_offset = hio_read32b(f); D_(D_INFO "blockarr_offset = 0x%08x", blockarr_offset); hio_read32b(f); smplarr_offset = hio_read32b(f); D_(D_INFO "smplarr_offset = 0x%08x", smplarr_offset); hio_read32b(f); expdata_offset = hio_read32b(f); D_(D_INFO "expdata_offset = 0x%08x", expdata_offset); hio_read32b(f); header.pstate = hio_read16b(f); header.pblock = hio_read16b(f); header.pline = hio_read16b(f); header.pseqnum = hio_read16b(f); header.actplayline = hio_read16b(f); header.counter = hio_read8(f); header.extra_songs = hio_read8(f); /* * song structure */ D_(D_WARN "load song"); hio_seek(f, start + song_offset, SEEK_SET); for (i = 0; i < 63; i++) { song.sample[i].rep = hio_read16b(f); song.sample[i].replen = hio_read16b(f); song.sample[i].midich = hio_read8(f); song.sample[i].midipreset = hio_read8(f); song.sample[i].svol = hio_read8(f); song.sample[i].strans = hio_read8s(f); } song.numblocks = hio_read16b(f); song.songlen = hio_read16b(f); D_(D_INFO "song.songlen = %d", song.songlen); seqtable_offset = hio_read32b(f); hio_read32b(f); trackvols_offset = hio_read32b(f); song.numtracks = hio_read16b(f); song.numpseqs = hio_read16b(f); trackpans_offset = hio_read32b(f); song.flags3 = hio_read32b(f); song.voladj = hio_read16b(f); song.channels = hio_read16b(f); song.mix_echotype = hio_read8(f); song.mix_echodepth = hio_read8(f); song.mix_echolen = hio_read16b(f); song.mix_stereosep = hio_read8(f); hio_seek(f, 223, SEEK_CUR); song.deftempo = hio_read16b(f); song.playtransp = hio_read8(f); song.flags = hio_read8(f); song.flags2 = hio_read8(f); song.tempo2 = hio_read8(f); for (i = 0; i < 16; i++) hio_read8(f); /* reserved */ song.mastervol = hio_read8(f); song.numsamples = hio_read8(f); /* Sanity check */ if (song.numsamples > 63) { return -1; } /* * read sequence */ hio_seek(f, start + seqtable_offset, SEEK_SET); playseq_offset = hio_read32b(f); hio_seek(f, start + playseq_offset, SEEK_SET); hio_seek(f, 32, SEEK_CUR); /* skip name */ hio_read32b(f); hio_read32b(f); mod->len = hio_read16b(f); /* Sanity check */ if (mod->len > 255) { return -1; } for (i = 0; i < mod->len; i++) { mod->xxo[i] = hio_read16b(f); } /* * convert header */ m->c4rate = C4_NTSC_RATE; m->quirk |= song.flags & FLAG_STSLIDE ? 0 : QUIRK_VSALL | QUIRK_PBALL; hexvol = song.flags & FLAG_VOLHEX; med_8ch = song.flags & FLAG_8CHANNEL; bpm_on = song.flags2 & FLAG2_BPM; bpmlen = 1 + (song.flags2 & FLAG2_BMASK); m->time_factor = MED_TIME_FACTOR; mmd_set_bpm(m, med_8ch, song.deftempo, bpm_on, bpmlen); mod->spd = song.tempo2; mod->pat = song.numblocks; mod->ins = song.numsamples; mod->rst = 0; mod->chn = 0; mod->name[0] = 0; /* * Obtain number of samples from each instrument */ mod->smp = 0; for (i = 0; i < mod->ins; i++) { uint32 smpl_offset; int16 type; hio_seek(f, start + smplarr_offset + i * 4, SEEK_SET); smpl_offset = hio_read32b(f); if (smpl_offset == 0) continue; hio_seek(f, start + smpl_offset, SEEK_SET); hio_read32b(f); /* length */ type = hio_read16b(f); if (type == -1) { /* type is synth? */ hio_seek(f, 14, SEEK_CUR); mod->smp += hio_read16b(f); /* wforms */ } else { mod->smp++; } } /* * expdata */ D_(D_WARN "load expdata"); expdata.s_ext_entries = 0; expdata.s_ext_entrsz = 0; expdata.i_ext_entries = 0; expdata.i_ext_entrsz = 0; expsmp_offset = 0; iinfo_offset = 0; if (expdata_offset) { hio_seek(f, start + expdata_offset, SEEK_SET); hio_read32b(f); expsmp_offset = hio_read32b(f); D_(D_INFO "expsmp_offset = 0x%08x", expsmp_offset); expdata.s_ext_entries = hio_read16b(f); expdata.s_ext_entrsz = hio_read16b(f); hio_read32b(f); /* annotxt */ hio_read32b(f); /* annolen */ iinfo_offset = hio_read32b(f); D_(D_INFO "iinfo_offset = 0x%08x", iinfo_offset); expdata.i_ext_entries = hio_read16b(f); expdata.i_ext_entrsz = hio_read16b(f); /* Sanity check */ if (expsmp_offset < 0 || iinfo_offset < 0) { return -1; } hio_read32b(f); hio_read32b(f); hio_read32b(f); hio_read32b(f); songname_offset = hio_read32b(f); expdata.songnamelen = hio_read32b(f); hio_read32b(f); /* dumps */ mmdinfo_offset = hio_read32b(f); if (hio_error(f)) { return -1; } hio_seek(f, start + songname_offset, SEEK_SET); D_(D_INFO "expdata.songnamelen = %d", expdata.songnamelen); for (i = 0; i < expdata.songnamelen; i++) { if (i >= XMP_NAME_SIZE) break; mod->name[i] = hio_read8(f); } if (mmdinfo_offset != 0) { hio_seek(f, start + mmdinfo_offset, SEEK_SET); mmd_info_text(f, m, mmdinfo_offset); } } /* * Quickly scan patterns to check the number of channels */ D_(D_WARN "find number of channels"); for (i = 0; i < mod->pat; i++) { int block_offset; hio_seek(f, start + blockarr_offset + i * 4, SEEK_SET); block_offset = hio_read32b(f); D_(D_INFO "block %d block_offset = 0x%08x", i, block_offset); if (block_offset == 0) continue; hio_seek(f, start + block_offset, SEEK_SET); block.numtracks = hio_read16b(f); /* block.lines = */ hio_read16b(f); if (block.numtracks > mod->chn) { mod->chn = block.numtracks; } } /* Sanity check */ if (mod->chn <= 0 || mod->chn > XMP_MAX_CHANNELS) return -1; mod->trk = mod->pat * mod->chn; if (ver == 2) libxmp_set_type(m, "OctaMED v5 MMD2"); else libxmp_set_type(m, "OctaMED Soundstudio MMD%c", '0' + ver); MODULE_INFO(); D_(D_INFO "BPM mode: %s (length = %d)", bpm_on ? "on" : "off", bpmlen); D_(D_INFO "Song transpose : %d", song.playtransp); D_(D_INFO "Stored patterns: %d", mod->pat); /* * Read and convert patterns */ D_(D_WARN "read patterns"); if (libxmp_init_pattern(mod) < 0) return -1; for (i = 0; i < mod->pat; i++) { int block_offset; hio_seek(f, start + blockarr_offset + i * 4, SEEK_SET); block_offset = hio_read32b(f); if (block_offset == 0) continue; hio_seek(f, start + block_offset, SEEK_SET); block.numtracks = hio_read16b(f); block.lines = hio_read16b(f); hio_read32b(f); if (libxmp_alloc_pattern_tracks(mod, i, block.lines + 1) < 0) return -1; for (j = 0; j < mod->xxp[i]->rows; j++) { for (k = 0; k < block.numtracks; k++) { e[0] = hio_read8(f); e[1] = hio_read8(f); e[2] = hio_read8(f); e[3] = hio_read8(f); event = &EVENT(i, k, j); event->note = e[0] & 0x7f; if (event->note) { event->note += song.playtransp; if (ver == 2) event->note += 12; else event->note -= 12; }; if (event->note >= XMP_MAX_KEYS) event->note = 0; event->ins = e[1] & 0x3f; /* Decay */ if (event->ins && !event->note) { event->f2t = FX_MED_HOLD; } event->fxt = e[2]; event->fxp = e[3]; mmd_xlat_fx(event, bpm_on, bpmlen, med_8ch, hexvol); } } } if (libxmp_med_new_module_extras(m) != 0) return -1; /* * Read and convert instruments and samples */ D_(D_WARN "read instruments"); if (libxmp_init_instrument(m) < 0) return -1; D_(D_INFO "Instruments: %d", mod->ins); for (smp_idx = i = 0; i < mod->ins; i++) { int smpl_offset; hio_seek(f, start + smplarr_offset + i * 4, SEEK_SET); smpl_offset = hio_read32b(f); D_(D_INFO "sample %d smpl_offset = 0x%08x", i, smpl_offset); if (smpl_offset == 0) { continue; } hio_seek(f, start + smpl_offset, SEEK_SET); instr.length = hio_read32b(f); instr.type = hio_read16b(f); if ((pos = hio_tell(f)) < 0) { return -1; } if (expdata_offset && i < expdata.i_ext_entries) { struct xmp_instrument *xxi = &mod->xxi[i]; int offset = iinfo_offset + i * expdata.i_ext_entrsz; if (offset < 0 || hio_seek(f, offset, SEEK_SET) < 0) { return -1; } hio_read(&xxi->name, 40, 1, f); D_(D_INFO "[%2x] %-40.40s %d", i, mod->xxi[i].name, instr.type); } memset(&exp_smp, 0, sizeof(struct InstrExt)); if (expdata_offset && i < expdata.s_ext_entries) { int offset = expsmp_offset + i * expdata.s_ext_entrsz; if (offset < 0 || hio_seek(f, offset, SEEK_SET) < 0) { return -1; } exp_smp.hold = hio_read8(f); exp_smp.decay = hio_read8(f); exp_smp.suppress_midi_off = hio_read8(f); exp_smp.finetune = hio_read8(f); if (expdata.s_ext_entrsz > 4) { /* Octamed V5 */ exp_smp.default_pitch = hio_read8(f); exp_smp.instr_flags = hio_read8(f); } } hio_seek(f, pos, SEEK_SET); if (instr.type == -2) { /* Hybrid */ int ret = mmd_load_hybrid_instrument(f, m, i, smp_idx, &synth, &exp_smp, &song.sample[i]); if (ret < 0) return -1; smp_idx++; if (mmd_alloc_tables(m, i, &synth) != 0) return -1; continue; } else if (instr.type == -1) { /* Synthetic */ int ret = mmd_load_synth_instrument(f, m, i, smp_idx, &synth, &exp_smp, &song.sample[i]); if (ret > 0) continue; if (ret < 0) return -1; smp_idx += synth.wforms; if (mmd_alloc_tables(m, i, &synth) != 0) return -1; continue; } else if (instr.type >= 1 && instr.type <= 6) { /* IFFOCT */ int ret; const int oct = num_oct[instr.type - 1]; hio_seek(f, start + smpl_offset + 6, SEEK_SET); ret = mmd_load_iffoct_instrument(f, m, i, smp_idx, &instr, oct, &exp_smp, &song.sample[i]); if (ret < 0) return -1; smp_idx += oct; continue; } else if ((instr.type & ~(S_16 | STEREO)) != 0) { D_(D_WARN "stereo sample unsupported"); mod->xxi[i].nsm = 0; continue; } else if ((instr.type & ~S_16) == 0) { /* Sample */ int ret; hio_seek(f, start + smpl_offset + 6, SEEK_SET); ret = mmd_load_sampled_instrument(f, m, i, smp_idx, &instr, &expdata, &exp_smp, &song.sample[i], ver); if (ret < 0) return -1; smp_idx++; continue; } else { /* Invalid instrument type */ D_(D_CRIT "invalid instrument type"); return -1; } } hio_seek(f, start + trackvols_offset, SEEK_SET); for (i = 0; i < mod->chn; i++) mod->xxc[i].vol = hio_read8(f);; if (trackpans_offset) { hio_seek(f, start + trackpans_offset, SEEK_SET); for (i = 0; i < mod->chn; i++) { int p = 8 * hio_read8s(f); mod->xxc[i].pan = 0x80 + (p > 127 ? 127 : p); } } else { for (i = 0; i < mod->chn; i++) mod->xxc[i].pan = 0x80; } m->read_event_type = READ_EVENT_MED; return 0; } libxmp-4.4.1/src/extras.h0000664000175000017500000000153112775035311015111 0ustar claudioclaudio#ifndef LIBXMP_EXTRAS_H #define LIBXMP_EXTRAS_H void libxmp_release_module_extras(struct context_data *); int libxmp_new_channel_extras(struct context_data *, struct channel_data *); void libxmp_release_channel_extras(struct context_data *, struct channel_data *); void libxmp_reset_channel_extras(struct context_data *, struct channel_data *); void libxmp_play_extras(struct context_data *, struct channel_data *, int); int libxmp_extras_get_volume(struct context_data *, struct channel_data *); int libxmp_extras_get_period(struct context_data *, struct channel_data *); int libxmp_extras_get_linear_bend(struct context_data *, struct channel_data *); void libxmp_extras_process_fx(struct context_data *, struct channel_data *, int, uint8, uint8, uint8, int); /* FIXME */ void libxmp_med_hold_hack(struct context_data *ctx, int, int, int); #endif libxmp-4.4.1/src/mkstemp.c0000664000175000017500000000500512773571316015266 0ustar claudioclaudio#ifdef __SUNPRO_C #pragma error_messages (off,E_EMPTY_TRANSLATION_UNIT) #endif #ifndef HAVE_MKSTEMP /* * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #ifdef _MSC_VER #include #define getpid _getpid #define open _open typedef int pid_t; #endif #ifndef O_BINARY #define O_BINARY 0 #endif int mkstemp(char *template) { int start, i; pid_t val; val = getpid(); start = strlen(template) - 1; while (template[start] == 'X') { template[start] = '0' + val % 10; val /= 10; start--; } do { int fd; fd = open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); if (fd >= 0 || errno != EEXIST) return fd; i = start + 1; do { if (template[i] == 0) return -1; template[i]++; if (template[i] == '9' + 1) template[i] = 'a'; if (template[i] <= 'z') break; template[i] = 'a'; i++; } while (1); } while (1); } #endif libxmp-4.4.1/src/md5.h0000664000175000017500000000171712773463510014302 0ustar claudioclaudio/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. */ #ifndef LIBXMP_MD5_H #define LIBXMP_MD5_H #include "common.h" #define MD5_BLOCK_LENGTH 64 #define MD5_DIGEST_LENGTH 16 #define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) typedef struct MD5Context { uint32 state[4]; /* state */ uint64 count; /* number of bits, mod 2^64 */ uint8 buffer[MD5_BLOCK_LENGTH]; /* input buffer */ } MD5_CTX; void MD5Init(MD5_CTX *); void MD5Update(MD5_CTX *, const unsigned char *, size_t); void MD5Final(uint8[MD5_DIGEST_LENGTH], MD5_CTX *); #endif /* LIBXMP_MD5_H */ libxmp-4.4.1/src/virtual.c0000664000175000017500000003051612774567167015313 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "common.h" #include "virtual.h" #include "mixer.h" #ifdef LIBXMP_PAULA_SIMULATOR #include "paula.h" #endif #define FREE -1 /* For virt_pastnote() */ void libxmp_player_set_release(struct context_data *, int); void libxmp_player_set_fadeout(struct context_data *, int); /* Get parent channel */ int libxmp_virt_getroot(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct mixer_voice *vi; int voc; voc = p->virt.virt_channel[chn].map; if (voc < 0) { return -1; } vi = &p->virt.voice_array[voc]; return vi->root; } void libxmp_virt_resetvoice(struct context_data *ctx, int voc, int mute) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[voc]; #ifdef LIBXMP_PAULA_SIMULATOR struct paula_state *paula; #endif if ((uint32)voc >= p->virt.maxvoc) { return; } if (mute) { libxmp_mixer_setvol(ctx, voc, 0); } p->virt.virt_used--; p->virt.virt_channel[vi->root].count--; p->virt.virt_channel[vi->chn].map = FREE; #ifdef LIBXMP_PAULA_SIMULATOR paula = vi->paula; #endif memset(vi, 0, sizeof(struct mixer_voice)); #ifdef LIBXMP_PAULA_SIMULATOR vi->paula = paula; #endif vi->chn = vi->root = FREE; } /* virt_on (number of tracks) */ int libxmp_virt_on(struct context_data *ctx, int num) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; int i; p->virt.num_tracks = num; num = libxmp_mixer_numvoices(ctx, -1); p->virt.virt_channels = p->virt.num_tracks; if (HAS_QUIRK(QUIRK_VIRTUAL)) { p->virt.virt_channels += num; } else if (num > p->virt.virt_channels) { num = p->virt.virt_channels; } p->virt.maxvoc = libxmp_mixer_numvoices(ctx, num); p->virt.voice_array = calloc(p->virt.maxvoc, sizeof(struct mixer_voice)); if (p->virt.voice_array == NULL) goto err; for (i = 0; i < p->virt.maxvoc; i++) { p->virt.voice_array[i].chn = FREE; p->virt.voice_array[i].root = FREE; } #ifdef LIBXMP_PAULA_SIMULATOR /* Initialize Paula simulator */ if (IS_AMIGA_MOD()) { for (i = 0; i < p->virt.maxvoc; i++) { p->virt.voice_array[i].paula = calloc(1, sizeof (struct paula_state)); if (p->virt.voice_array[i].paula == NULL) { goto err2; } libxmp_paula_init(ctx, p->virt.voice_array[i].paula); } } #endif p->virt.virt_channel = malloc(p->virt.virt_channels * sizeof(struct virt_channel)); if (p->virt.virt_channel == NULL) goto err2; for (i = 0; i < p->virt.virt_channels; i++) { p->virt.virt_channel[i].map = FREE; p->virt.virt_channel[i].count = 0; } p->virt.virt_used = 0; return 0; err2: #ifdef LIBXMP_PAULA_SIMULATOR if (IS_AMIGA_MOD()) { for (i = 0; i < p->virt.maxvoc; i++) { free(p->virt.voice_array[i].paula); } } #endif free(p->virt.voice_array); err: return -1; } void libxmp_virt_off(struct context_data *ctx) { struct player_data *p = &ctx->p; #ifdef LIBXMP_PAULA_SIMULATOR struct module_data *m = &ctx->m; int i; #endif #ifdef LIBXMP_PAULA_SIMULATOR /* Free Paula simulator state */ if (IS_AMIGA_MOD()) { for (i = 0; i < p->virt.maxvoc; i++) { free(p->virt.voice_array[i].paula); } } #endif p->virt.virt_used = p->virt.maxvoc = 0; p->virt.virt_channels = 0; p->virt.num_tracks = 0; free(p->virt.voice_array); free(p->virt.virt_channel); } void libxmp_virt_reset(struct context_data *ctx) { struct player_data *p = &ctx->p; int i; if (p->virt.virt_channels < 1) { return; } /* CID 129203 (#1 of 1): Useless call (USELESS_CALL) * Call is only useful for its return value, which is ignored. * * libxmp_mixer_numvoices(ctx, p->virt.maxvoc); */ for (i = 0; i < p->virt.maxvoc; i++) { struct mixer_voice *vi = &p->virt.voice_array[i]; #ifdef LIBXMP_PAULA_SIMULATOR struct paula_state *paula = vi->paula; #endif memset(vi, 0, sizeof(struct mixer_voice)); #ifdef LIBXMP_PAULA_SIMULATOR vi->paula = paula; #endif vi->chn = FREE; vi->root = FREE; } for (i = 0; i < p->virt.virt_channels; i++) { p->virt.virt_channel[i].map = FREE; p->virt.virt_channel[i].count = 0; } p->virt.virt_used = 0; } static int free_voice(struct context_data *ctx) { struct player_data *p = &ctx->p; int i, num, vol; /* Find background voice with lowest volume*/ num = FREE; vol = INT_MAX; for (i = 0; i < p->virt.maxvoc; i++) { struct mixer_voice *vi = &p->virt.voice_array[i]; if (vi->chn >= p->virt.num_tracks && vi->vol < vol) { num = i; vol = vi->vol; } } /* Free voice */ if (num >= 0) { p->virt.virt_channel[p->virt.voice_array[num].chn].map = FREE; p->virt.virt_channel[p->virt.voice_array[num].root].count--; p->virt.virt_used--; } return num; } static int alloc_voice(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; int i; /* Find free voice */ for (i = 0; i < p->virt.maxvoc; i++) { if (p->virt.voice_array[i].chn == FREE) break; } /* not found */ if (i == p->virt.maxvoc) { i = free_voice(ctx); } if (i >= 0) { p->virt.virt_channel[chn].count++; p->virt.virt_used++; p->virt.voice_array[i].chn = chn; p->virt.voice_array[i].root = chn; p->virt.virt_channel[chn].map = i; } return i; } static int map_virt_channel(struct player_data *p, int chn) { int voc; if ((uint32)chn >= p->virt.virt_channels) return -1; voc = p->virt.virt_channel[chn].map; if ((uint32)voc >= p->virt.maxvoc) return -1; return voc; } int libxmp_virt_mapchannel(struct context_data *ctx, int chn) { return map_virt_channel(&ctx->p, chn); } void libxmp_virt_resetchannel(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct mixer_voice *vi; #ifdef LIBXMP_PAULA_SIMULATOR struct paula_state *paula; #endif int voc; if ((voc = map_virt_channel(p, chn)) < 0) return; libxmp_mixer_setvol(ctx, voc, 0); p->virt.virt_used--; p->virt.virt_channel[p->virt.voice_array[voc].root].count--; p->virt.virt_channel[chn].map = FREE; vi = &p->virt.voice_array[voc]; #ifdef LIBXMP_PAULA_SIMULATOR paula = vi->paula; #endif memset(vi, 0, sizeof(struct mixer_voice)); #ifdef LIBXMP_PAULA_SIMULATOR vi->paula = paula; #endif vi->chn = vi->root = FREE; } void libxmp_virt_setvol(struct context_data *ctx, int chn, int vol) { struct player_data *p = &ctx->p; int voc, root; if ((voc = map_virt_channel(p, chn)) < 0) { return; } root = p->virt.voice_array[voc].root; if (root < XMP_MAX_CHANNELS && p->channel_mute[root]) { vol = 0; } libxmp_mixer_setvol(ctx, voc, vol); if (vol == 0 && chn >= p->virt.num_tracks) { libxmp_virt_resetvoice(ctx, voc, 1); } } void libxmp_virt_release(struct context_data *ctx, int chn, int rel) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } libxmp_mixer_release(ctx, voc, rel); } void libxmp_virt_setpan(struct context_data *ctx, int chn, int pan) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } libxmp_mixer_setpan(ctx, voc, pan); } void libxmp_virt_seteffect(struct context_data *ctx, int chn, int type, int val) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } libxmp_mixer_seteffect(ctx, voc, type, val); } double libxmp_virt_getvoicepos(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return -1; } return libxmp_mixer_getvoicepos(ctx, voc); } #ifndef LIBXMP_CORE_PLAYER void libxmp_virt_setsmp(struct context_data *ctx, int chn, int smp) { struct player_data *p = &ctx->p; struct mixer_voice *vi; double pos; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } vi = &p->virt.voice_array[voc]; if (vi->smp == smp) { return; } pos = libxmp_mixer_getvoicepos(ctx, voc); libxmp_mixer_setpatch(ctx, voc, smp, 0); libxmp_mixer_voicepos(ctx, voc, pos, 0); /* Restore old position */ } #endif #ifndef LIBXMP_CORE_DISABLE_IT void libxmp_virt_setnna(struct context_data *ctx, int chn, int nna) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } p->virt.voice_array[voc].act = nna; } static void check_dct(struct context_data *ctx, int i, int chn, int ins, int smp, int note, int dct, int dca) { struct player_data *p = &ctx->p; struct mixer_voice *vi = &p->virt.voice_array[i]; int voc; voc = p->virt.virt_channel[chn].map; if (vi->root == chn && vi->ins == ins) { if (dct == XMP_INST_DCT_INST || (dct == XMP_INST_DCT_SMP && vi->smp == smp) || (dct == XMP_INST_DCT_NOTE && vi->note == note)) { if (dca) { if (i != voc || vi->act) vi->act = dca; } else { libxmp_virt_resetvoice(ctx, i, 1); } } } } #endif /* For note slides */ void libxmp_virt_setnote(struct context_data *ctx, int chn, int note) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } libxmp_mixer_setnote(ctx, voc, note); } int libxmp_virt_setpatch(struct context_data *ctx, int chn, int ins, int smp, int note, int nna, int dct, int dca) { struct player_data *p = &ctx->p; int voc, vfree; if ((uint32)chn >= p->virt.virt_channels) { return -1; } if (ins < 0) { smp = -1; } #ifndef LIBXMP_CORE_DISABLE_IT if (dct) { int i; for (i = 0; i < p->virt.maxvoc; i++) { check_dct(ctx, i, chn, ins, smp, note, dct, dca); } } #endif voc = p->virt.virt_channel[chn].map; if (voc > FREE) { if (p->virt.voice_array[voc].act) { vfree = alloc_voice(ctx, chn); if (vfree < 0) { return -1; } for (chn = p->virt.num_tracks; p->virt.virt_channel[chn++].map > FREE;) ; p->virt.voice_array[voc].chn = --chn; p->virt.virt_channel[chn].map = voc; voc = vfree; } } else { voc = alloc_voice(ctx, chn); if (voc < 0) { return -1; } } if (smp < 0) { libxmp_virt_resetvoice(ctx, voc, 1); return chn; /* was -1 */ } libxmp_mixer_setpatch(ctx, voc, smp, 1); libxmp_mixer_setnote(ctx, voc, note); p->virt.voice_array[voc].ins = ins; p->virt.voice_array[voc].act = nna; return chn; } void libxmp_virt_setperiod(struct context_data *ctx, int chn, double period) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } libxmp_mixer_setperiod(ctx, voc, period); } void libxmp_virt_voicepos(struct context_data *ctx, int chn, double pos) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return; } libxmp_mixer_voicepos(ctx, voc, pos, 1); } #ifndef LIBXMP_CORE_DISABLE_IT void libxmp_virt_pastnote(struct context_data *ctx, int chn, int act) { struct player_data *p = &ctx->p; int c, voc; for (c = p->virt.num_tracks; c < p->virt.virt_channels; c++) { if ((voc = map_virt_channel(p, c)) < 0) continue; if (p->virt.voice_array[voc].root == chn) { switch (act) { case VIRT_ACTION_CUT: libxmp_virt_resetvoice(ctx, voc, 1); break; case VIRT_ACTION_OFF: libxmp_player_set_release(ctx, c); break; case VIRT_ACTION_FADE: libxmp_player_set_fadeout(ctx, c); break; } } } } #endif int libxmp_virt_cstat(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; int voc; if ((voc = map_virt_channel(p, chn)) < 0) { return VIRT_INVALID; } if (chn < p->virt.num_tracks) { return VIRT_ACTIVE; } return p->virt.voice_array[voc].act; } libxmp-4.4.1/src/format.c0000664000175000017500000001477212774567167015123 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "loaders/prowizard/prowiz.h" #include "format.h" extern const struct format_loader libxmp_loader_xm; extern const struct format_loader libxmp_loader_mod; extern const struct format_loader libxmp_loader_flt; extern const struct format_loader libxmp_loader_st; extern const struct format_loader libxmp_loader_it; extern const struct format_loader libxmp_loader_s3m; extern const struct format_loader libxmp_loader_stm; extern const struct format_loader libxmp_loader_stx; extern const struct format_loader libxmp_loader_mtm; extern const struct format_loader libxmp_loader_ice; extern const struct format_loader libxmp_loader_imf; extern const struct format_loader libxmp_loader_ptm; extern const struct format_loader libxmp_loader_mdl; extern const struct format_loader libxmp_loader_ult; extern const struct format_loader libxmp_loader_liq; extern const struct format_loader libxmp_loader_no; extern const struct format_loader libxmp_loader_masi; extern const struct format_loader libxmp_loader_gal5; extern const struct format_loader libxmp_loader_gal4; extern const struct format_loader libxmp_loader_psm; extern const struct format_loader libxmp_loader_amf; extern const struct format_loader libxmp_loader_asylum; extern const struct format_loader libxmp_loader_gdm; extern const struct format_loader libxmp_loader_mmd1; extern const struct format_loader libxmp_loader_mmd3; extern const struct format_loader libxmp_loader_med2; extern const struct format_loader libxmp_loader_med3; extern const struct format_loader libxmp_loader_med4; /* extern const struct format_loader libxmp_loader_dmf; */ extern const struct format_loader libxmp_loader_rtm; extern const struct format_loader libxmp_loader_pt3; /* extern const struct format_loader libxmp_loader_tcb; */ extern const struct format_loader libxmp_loader_dt; /* extern const struct format_loader libxmp_loader_gtk; */ /* extern const struct format_loader libxmp_loader_dtt; */ extern const struct format_loader libxmp_loader_mgt; extern const struct format_loader libxmp_loader_arch; extern const struct format_loader libxmp_loader_sym; extern const struct format_loader libxmp_loader_digi; extern const struct format_loader libxmp_loader_dbm; extern const struct format_loader libxmp_loader_emod; extern const struct format_loader libxmp_loader_okt; extern const struct format_loader libxmp_loader_sfx; extern const struct format_loader libxmp_loader_far; extern const struct format_loader libxmp_loader_umx; extern const struct format_loader libxmp_loader_stim; /* extern const struct format_loader libxmp_loader_coco; */ /* extern const struct format_loader libxmp_loader_mtp; */ extern const struct format_loader libxmp_loader_ims; extern const struct format_loader libxmp_loader_669; extern const struct format_loader libxmp_loader_fnk; /* extern const struct format_loader libxmp_loader_amd; */ /* extern const struct format_loader libxmp_loader_rad; */ /* extern const struct format_loader libxmp_loader_hsc; */ extern const struct format_loader libxmp_loader_mfp; /* extern const struct format_loader libxmp_loader_alm; */ /* extern const struct format_loader libxmp_loader_polly; */ /* extern const struct format_loader libxmp_loader_stc; */ extern const struct format_loader libxmp_loader_pw; extern const struct format_loader libxmp_loader_hmn; extern const struct format_loader libxmp_loader_chip; extern const struct format_loader libxmp_loader_abk; extern const struct pw_format *const pw_format[]; const struct format_loader *const format_loader[NUM_FORMATS + 2] = { &libxmp_loader_xm, &libxmp_loader_mod, &libxmp_loader_flt, &libxmp_loader_st, &libxmp_loader_it, &libxmp_loader_s3m, &libxmp_loader_stm, &libxmp_loader_stx, &libxmp_loader_mtm, &libxmp_loader_ice, &libxmp_loader_imf, &libxmp_loader_ptm, &libxmp_loader_mdl, &libxmp_loader_ult, &libxmp_loader_liq, &libxmp_loader_no, &libxmp_loader_masi, &libxmp_loader_gal5, &libxmp_loader_gal4, &libxmp_loader_psm, &libxmp_loader_amf, &libxmp_loader_asylum, &libxmp_loader_gdm, &libxmp_loader_mmd1, &libxmp_loader_mmd3, &libxmp_loader_med2, &libxmp_loader_med3, &libxmp_loader_med4, /* &libxmp_loader_dmf, */ &libxmp_loader_chip, &libxmp_loader_rtm, &libxmp_loader_pt3, /* &libxmp_loader_tcb, */ &libxmp_loader_dt, /* &libxmp_loader_gtk, */ /* &libxmp_loader_dtt, */ &libxmp_loader_mgt, &libxmp_loader_arch, &libxmp_loader_sym, &libxmp_loader_digi, &libxmp_loader_dbm, &libxmp_loader_emod, &libxmp_loader_okt, &libxmp_loader_sfx, &libxmp_loader_far, &libxmp_loader_umx, &libxmp_loader_hmn, &libxmp_loader_stim, /* &libxmp_loader_coco, */ /* &libxmp_loader_mtp, */ &libxmp_loader_ims, &libxmp_loader_669, &libxmp_loader_fnk, /* &libxmp_loader_amd, */ /* &libxmp_loader_rad, */ /* &libxmp_loader_hsc, */ &libxmp_loader_mfp, &libxmp_loader_abk, /* &libxmp_loader_alm, */ /* &libxmp_loader_polly, */ /* &libxmp_loader_stc, */ &libxmp_loader_pw, NULL }; static const char *_farray[NUM_FORMATS + NUM_PW_FORMATS + 1] = { NULL }; char **format_list() { int count, i; if (_farray[0] == NULL) { for (count = i = 0; format_loader[i] != NULL; i++) { if (strcmp(format_loader[i]->name, "prowizard") == 0) { int j; for (j = 0; pw_format[j] != NULL; j++) { _farray[count++] = pw_format[j]->name; } } else { _farray[count++] = format_loader[i]->name; } } _farray[count] = NULL; } return (char **)_farray; } libxmp-4.4.1/src/period.c0000664000175000017500000001510012774567167015077 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "common.h" #include "period.h" #include #ifdef LIBXMP_PAULA_SIMULATOR /* * Period table from the Protracker V2.1A play routine */ static uint16 pt_period_table[16][36] = { /* Tuning 0, Normal */ { 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 }, /* Tuning 1 */ { 850,802,757,715,674,637,601,567,535,505,477,450, 425,401,379,357,337,318,300,284,268,253,239,225, 213,201,189,179,169,159,150,142,134,126,119,113 }, /* Tuning 2 */ { 844,796,752,709,670,632,597,563,532,502,474,447, 422,398,376,355,335,316,298,282,266,251,237,224, 211,199,188,177,167,158,149,141,133,125,118,112 }, /* Tuning 3 */ { 838,791,746,704,665,628,592,559,528,498,470,444, 419,395,373,352,332,314,296,280,264,249,235,222, 209,198,187,176,166,157,148,140,132,125,118,111 }, /* Tuning 4 */ { 832,785,741,699,660,623,588,555,524,495,467,441, 416,392,370,350,330,312,294,278,262,247,233,220, 208,196,185,175,165,156,147,139,131,124,117,110 }, /* Tuning 5 */ { 826,779,736,694,655,619,584,551,520,491,463,437, 413,390,368,347,328,309,292,276,260,245,232,219, 206,195,184,174,164,155,146,138,130,123,116,109 }, /* Tuning 6 */ { 820,774,730,689,651,614,580,547,516,487,460,434, 410,387,365,345,325,307,290,274,258,244,230,217, 205,193,183,172,163,154,145,137,129,122,115,109 }, /* Tuning 7 */ { 814,768,725,684,646,610,575,543,513,484,457,431, 407,384,363,342,323,305,288,272,256,242,228,216, 204,192,181,171,161,152,144,136,128,121,114,108 }, /* Tuning -8 */ { 907,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 }, /* Tuning -7 */ { 900,850,802,757,715,675,636,601,567,535,505,477, 450,425,401,379,357,337,318,300,284,268,253,238, 225,212,200,189,179,169,159,150,142,134,126,119 }, /* Tuning -6 */ { 894,844,796,752,709,670,632,597,563,532,502,474, 447,422,398,376,355,335,316,298,282,266,251,237, 223,211,199,188,177,167,158,149,141,133,125,118 }, /* Tuning -5 */ { 887,838,791,746,704,665,628,592,559,528,498,470, 444,419,395,373,352,332,314,296,280,264,249,235, 222,209,198,187,176,166,157,148,140,132,125,118 }, /* Tuning -4 */ { 881,832,785,741,699,660,623,588,555,524,494,467, 441,416,392,370,350,330,312,294,278,262,247,233, 220,208,196,185,175,165,156,147,139,131,123,117 }, /* Tuning -3 */ { 875,826,779,736,694,655,619,584,551,520,491,463, 437,413,390,368,347,328,309,292,276,260,245,232, 219,206,195,184,174,164,155,146,138,130,123,116 }, /* Tuning -2 */ { 868,820,774,730,689,651,614,580,547,516,487,460, 434,410,387,365,345,325,307,290,274,258,244,230, 217,205,193,183,172,163,154,145,137,129,122,115 }, /* Tuning -1 */ { 862,814,768,725,684,646,610,575,543,513,484,457, 431,407,384,363,342,323,305,288,272,256,242,228, 216,203,192,181,171,161,152,144,136,128,121,114 } }; #endif #ifdef _MSC_VER static inline double round(double val) { return floor(val + 0.5); } #endif #ifdef LIBXMP_PAULA_SIMULATOR /* Get period from note using Protracker tuning */ static inline int libxmp_note_to_period_pt(int n, int f) { if (n < MIN_NOTE_MOD || n > MAX_NOTE_MOD) { return -1; } n -= 48; f >>= 4; if (f < -8 || f > 7) { return 0; } if (f < 0) { f += 16; } return (int)pt_period_table[f][n]; } #endif /* Get period from note */ double libxmp_note_to_period(struct context_data *ctx, int n, int f, double adj) { double d, per; struct module_data *m = &ctx->m; #ifdef LIBXMP_PAULA_SIMULATOR struct player_data *p = &ctx->p; /* If mod replayer, modrng and Amiga mixing are active */ if (p->flags & XMP_FLAGS_A500) { if (IS_AMIGA_MOD()) { return libxmp_note_to_period_pt(n, f); } } #endif d = (double)n + (double)f / 128; switch (m->period_type) { case PERIOD_LINEAR: per = (240.0 - d) * 16; /* Linear */ break; case PERIOD_CSPD: per = 8363.0 * pow(2, n / 12) / 32 + f; /* Hz */ break; default: per = PERIOD_BASE / pow(2, d / 12); /* Amiga */ } #ifndef LIBXMP_CORE_PLAYER if (adj > 0.1) { per *= adj; } #endif return per; } /* For the software mixer */ double libxmp_note_to_period_mix(int n, int b) { double d = (double)n + (double)b / 12800; return PERIOD_BASE / pow(2, d / 12); } /* Get note from period */ /* This function is used only by the MOD loader */ int libxmp_period_to_note(int p) { if (p <= 0) { return 0; } return round(12.0 * log(PERIOD_BASE / p) / M_LN2) + 1; } /* Get pitchbend from base note and amiga period */ int libxmp_period_to_bend(struct context_data *ctx, double p, int n, double adj) { struct module_data *m = &ctx->m; double d; if (n == 0) { return 0; } switch (m->period_type) { case PERIOD_LINEAR: return 100 * (8 * (((240 - n) << 4) - p)); case PERIOD_CSPD: d = libxmp_note_to_period(ctx, n, 0, adj); return round(100.0 * (1536.0 / M_LN2) * log(p / d)); default: /* Amiga */ d = libxmp_note_to_period(ctx, n, 0, adj); return round(100.0 * (1536.0 / M_LN2) * log(d / p)); } } /* Convert finetune = 1200 * log2(C2SPD/8363)) * * c = (1200.0 * log(c2spd) - 1200.0 * log(c4_rate)) / M_LN2; * xpo = c/100; * fin = 128 * (c%100) / 100; */ void libxmp_c2spd_to_note(int c2spd, int *n, int *f) { int c; if (c2spd == 0) { *n = *f = 0; return; } c = (int)(1536.0 * log((double)c2spd / 8363) / M_LN2); *n = c / 128; *f = c % 128; } libxmp-4.4.1/src/common.h0000664000175000017500000002666712777410253015120 0ustar claudioclaudio#ifndef LIBXMP_COMMON_H #define LIBXMP_COMMON_H #ifdef __AROS__ #define __AMIGA__ #endif #include #include #include "xmp.h" #if defined(__GNUC__) || defined(__clang__) #if !defined(WIN32) && !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__AMIGA__) && !defined(B_BEOS_VERSION) && !defined(__ATHEOS__) && !defined(EMSCRIPTEN) && !defined(__MINT__) #define USE_VERSIONED_SYMBOLS #endif #endif /* AmigaOS fixes by Chris Young , Nov 25, 2007 */ #if defined B_BEOS_VERSION # include #elif defined __amigaos4__ # include #else typedef signed char int8; typedef signed short int int16; typedef signed int int32; typedef unsigned char uint8; typedef unsigned short int uint16; typedef unsigned int uint32; #endif #ifdef _MSC_VER /* MSVC++6.0 has no long long */ typedef signed __int64 int64; typedef unsigned __int64 uint64; #elif !defined B_BEOS_VERSION /* BeOS has its own int64 definition */ typedef unsigned long long uint64; typedef signed long long int64; #endif #ifndef LIBXMP_CORE_PLAYER #define LIBXMP_PAULA_SIMULATOR #endif /* Constants */ #define PAL_RATE 250.0 /* 1 / (50Hz * 80us) */ #define NTSC_RATE 208.0 /* 1 / (60Hz * 80us) */ #define C4_PAL_RATE 8287 /* 7093789.2 / period (C4) * 2 */ #define C4_NTSC_RATE 8363 /* 7159090.5 / period (C4) * 2 */ /* [Amiga] PAL color carrier frequency (PCCF) = 4.43361825 MHz */ /* [Amiga] CPU clock = 1.6 * PCCF = 7.0937892 MHz */ #define DEFAULT_AMPLIFY 1 #define DEFAULT_MIX 100 #define MSN(x) (((x)&0xf0)>>4) #define LSN(x) ((x)&0x0f) #define SET_FLAG(a,b) ((a)|=(b)) #define RESET_FLAG(a,b) ((a)&=~(b)) #define TEST_FLAG(a,b) !!((a)&(b)) #define CLAMP(x,a,b) do { \ if ((x) < (a)) (x) = (a); \ else if ((x) > (b)) (x) = (b); \ } while (0) #define MIN(x,y) ((x) < (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y)) #define TRACK_NUM(a,c) m->mod.xxp[a]->index[c] #define EVENT(a,c,r) m->mod.xxt[TRACK_NUM((a),(c))]->event[r] #ifdef _MSC_VER #define D_CRIT " Error: " #define D_WARN "Warning: " #define D_INFO " Info: " #ifndef CLIB_DECL #define CLIB_DECL #endif #ifdef DEBUG #ifndef ATTR_PRINTF #define ATTR_PRINTF(x,y) #endif void CLIB_DECL D_(const char *text, ...) ATTR_PRINTF(1,2); #else // VS prior to VC7.1 does not support variadic macros. VC8.0 does not optimize unused parameters passing #if _MSC_VER < 1400 void __inline CLIB_DECL D_(const char *text, ...) { do {} while (0); } #else #define D_(args, ...) do {} while (0) #endif #endif #elif defined __ANDROID__ #ifdef DEBUG #include #define D_CRIT " Error: " #define D_WARN "Warning: " #define D_INFO " Info: " #define D_(args...) do { \ __android_log_print(ANDROID_LOG_DEBUG, "libxmp", args); \ } while (0) #else #define D_(args...) do {} while (0) #endif #else #ifdef DEBUG #define D_INFO "\x1b[33m" #define D_CRIT "\x1b[31m" #define D_WARN "\x1b[36m" #define D_(args...) do { \ printf("\x1b[33m%s \x1b[37m[%s:%d] " D_INFO, __FUNCTION__, \ __FILE__, __LINE__); printf (args); printf ("\x1b[0m\n"); \ } while (0) #else #define D_(args...) do {} while (0) #endif #endif /* !_MSC_VER */ #ifdef _MSC_VER #define dup _dup #define fileno _fileno #define snprintf _snprintf #define vsnprintf _vsnprintf #define strnicmp _strnicmp #define strdup _strdup #define fdopen _fdopen #define open _open #define close _close #define unlink _unlink #endif /* Quirks */ #define QUIRK_S3MLOOP (1 << 0) /* S3M loop mode */ #define QUIRK_ENVFADE (1 << 1) /* Fade at end of envelope */ #define QUIRK_PROTRACK (1 << 2) /* Use Protracker-specific quirks */ #define QUIRK_ST3BUGS (1 << 4) /* Scream Tracker 3 bug compatibility */ #define QUIRK_FINEFX (1 << 5) /* Enable 0xf/0xe for fine effects */ #define QUIRK_VSALL (1 << 6) /* Volume slides in all frames */ #define QUIRK_PBALL (1 << 7) /* Pitch bending in all frames */ #define QUIRK_PERPAT (1 << 8) /* Cancel persistent fx at pat start */ #define QUIRK_VOLPDN (1 << 9) /* Set priority to volume slide down */ #define QUIRK_UNISLD (1 << 10) /* Unified pitch slide/portamento */ #define QUIRK_ITVPOR (1 << 11) /* Disable fine bends in IT vol fx */ #define QUIRK_FTMOD (1 << 12) /* Flag for multichannel mods */ /*#define QUIRK_MODRNG (1 << 13)*/ /* Limit periods to MOD range */ #define QUIRK_INSVOL (1 << 14) /* Use instrument volume */ #define QUIRK_VIRTUAL (1 << 15) /* Enable virtual channels */ #define QUIRK_FILTER (1 << 16) /* Enable filter */ #define QUIRK_IGSTPOR (1 << 17) /* Ignore stray tone portamento */ #define QUIRK_KEYOFF (1 << 18) /* Keyoff doesn't reset fadeout */ #define QUIRK_VIBHALF (1 << 19) /* Vibrato is half as deep */ #define QUIRK_VIBALL (1 << 20) /* Vibrato in all frames */ #define QUIRK_VIBINV (1 << 21) /* Vibrato has inverse waveform */ #define QUIRK_PRENV (1 << 22) /* Portamento resets envelope & fade */ #define QUIRK_ITOLDFX (1 << 23) /* IT old effects mode */ #define QUIRK_S3MRTG (1 << 24) /* S3M-style retrig when count == 0 */ #define QUIRK_RTDELAY (1 << 25) /* Delay effect retrigs instrument */ #define QUIRK_FT2BUGS (1 << 26) /* FT2 bug compatibility */ #define QUIRK_MARKER (1 << 27) /* Patterns 0xfe and 0xff reserved */ #define QUIRK_NOBPM (1 << 28) /* Adjust speed only, no BPM */ #define QUIRK_ARPMEM (1 << 29) /* Arpeggio has memory (S3M_ARPEGGIO) */ #define QUIRK_RSTCHN (1 << 30) /* Reset channel on sample end */ #define HAS_QUIRK(x) (m->quirk & (x)) /* Format quirks */ #define QUIRKS_ST3 (QUIRK_S3MLOOP | QUIRK_VOLPDN | QUIRK_FINEFX | \ QUIRK_S3MRTG | QUIRK_MARKER | QUIRK_RSTCHN ) #define QUIRKS_FT2 (QUIRK_RTDELAY | QUIRK_FINEFX ) #define QUIRKS_IT (QUIRK_S3MLOOP | QUIRK_FINEFX | QUIRK_VIBALL | \ QUIRK_ENVFADE | QUIRK_ITVPOR | QUIRK_KEYOFF | \ QUIRK_VIRTUAL | QUIRK_FILTER | QUIRK_RSTCHN | \ QUIRK_IGSTPOR | QUIRK_S3MRTG | QUIRK_MARKER ) /* DSP effects */ #define DSP_EFFECT_CUTOFF 0x02 #define DSP_EFFECT_RESONANCE 0x03 #define DSP_EFFECT_FILTER_A0 0xb0 #define DSP_EFFECT_FILTER_B0 0xb1 #define DSP_EFFECT_FILTER_B1 0xb2 /* Time factor */ #define DEFAULT_TIME_FACTOR 10.0 #define MED_TIME_FACTOR 2.64 #define MAX_SEQUENCES 16 #define MAX_SAMPLE_SIZE 0x10000000 #define MAX_SAMPLES 1024 #define IS_PLAYER_MODE_MOD() (m->read_event_type == READ_EVENT_MOD) #define IS_PLAYER_MODE_FT2() (m->read_event_type == READ_EVENT_FT2) #define IS_PLAYER_MODE_ST3() (m->read_event_type == READ_EVENT_ST3) #define IS_PLAYER_MODE_IT() (m->read_event_type == READ_EVENT_IT) #define IS_PLAYER_MODE_MED() (m->read_event_type == READ_EVENT_MED) #define IS_PERIOD_MODRNG() (m->period_type == PERIOD_MODRNG) #define IS_PERIOD_LINEAR() (m->period_type == PERIOD_LINEAR) #define IS_PERIOD_CSPD() (m->period_type == PERIOD_CSPD) #define IS_AMIGA_MOD() (IS_PLAYER_MODE_MOD() && IS_PERIOD_MODRNG()) struct ord_data { int speed; int bpm; int gvl; int time; int start_row; #ifndef LIBXMP_CORE_PLAYER int st26_speed; #endif }; /* Context */ struct smix_data { int chn; int ins; int smp; struct xmp_instrument *xxi; struct xmp_sample *xxs; }; /* This will be added to the sample structure in the next API revision */ struct extra_sample_data { double c5spd; }; struct module_data { struct xmp_module mod; char *dirname; /* file dirname */ char *basename; /* file basename */ char *filename; /* Module file name */ char *comment; /* Comments, if any */ uint8 md5[16]; /* MD5 message digest */ int size; /* File size */ double rrate; /* Replay rate */ double time_factor; /* Time conversion constant */ int c4rate; /* C4 replay rate */ int volbase; /* Volume base */ int gvolbase; /* Global volume base */ int gvol; /* Global volume */ int *vol_table; /* Volume translation table */ int quirk; /* player quirks */ #define READ_EVENT_MOD 0 #define READ_EVENT_FT2 1 #define READ_EVENT_ST3 2 #define READ_EVENT_IT 3 #define READ_EVENT_MED 4 int read_event_type; #define PERIOD_AMIGA 0 #define PERIOD_MODRNG 1 #define PERIOD_LINEAR 2 #define PERIOD_CSPD 3 int period_type; int smpctl; /* sample control flags */ int defpan; /* default pan setting */ struct ord_data xxo_info[XMP_MAX_MOD_LENGTH]; int num_sequences; struct xmp_sequence seq_data[MAX_SEQUENCES]; char *instrument_path; void *extra; /* format-specific extra fields */ char **scan_cnt; /* scan counters */ struct extra_sample_data *xtra; #ifndef LIBXMP_CORE_DISABLE_IT struct xmp_sample *xsmp; /* sustain loop samples */ #endif }; struct player_data { int ord; int pos; int row; int frame; int speed; int bpm; int mode; int player_flags; int flags; double current_time; double frame_time; int loop_count; int sequence; unsigned char sequence_control[XMP_MAX_MOD_LENGTH]; int smix_vol; /* SFX volume */ int master_vol; /* Music volume */ int gvol; struct flow_control { int pbreak; int jump; int delay; int jumpline; int loop_chn; struct pattern_loop { int start; int count; } *loop; int num_rows; int end_point; int rowdelay; /* For IT pattern row delay */ int rowdelay_set; } flow; struct { int time; /* replay time in ms */ int ord; int row; int num; } scan[MAX_SEQUENCES]; struct channel_data *xc_data; int channel_vol[XMP_MAX_CHANNELS]; char channel_mute[XMP_MAX_CHANNELS]; struct virt_control { int num_tracks; /* Number of tracks */ int virt_channels; /* Number of virtual channels */ int virt_used; /* Number of voices currently in use */ int maxvoc; /* Number of sound card voices */ struct virt_channel { int count; int map; } *virt_channel; struct mixer_voice *voice_array; } virt; struct xmp_event inject_event[XMP_MAX_CHANNELS]; struct { int consumed; int in_size; char *in_buffer; } buffer_data; #ifndef LIBXMP_CORE_PLAYER int st26_speed; /* For IceTracker speed effect */ #endif int filter; /* Amiga led filter */ }; struct mixer_data { int freq; /* sampling rate */ int format; /* sample format */ int amplify; /* amplification multiplier */ int mix; /* percentage of channel separation */ int interp; /* interpolation type */ int dsp; /* dsp effect flags */ char* buffer; /* output buffer */ int32* buf32; /* temporary buffer for 32 bit samples */ int numvoc; /* default softmixer voices number */ int ticksize; int dtright; /* anticlick control, right channel */ int dtleft; /* anticlick control, left channel */ double pbase; /* period base */ }; struct context_data { struct player_data p; struct mixer_data s; struct module_data m; struct smix_data smix; int state; }; /* Prototypes */ char *libxmp_adjust_string (char *); int libxmp_exclude_match (char *); int libxmp_prepare_scan (struct context_data *); int libxmp_scan_sequences (struct context_data *); int libxmp_get_sequence (struct context_data *, int); int libxmp_set_player_mode (struct context_data *); int8 read8s (FILE *, int *err); uint8 read8 (FILE *, int *err); uint16 read16l (FILE *, int *err); uint16 read16b (FILE *, int *err); uint32 read24l (FILE *, int *err); uint32 read24b (FILE *, int *err); uint32 read32l (FILE *, int *err); uint32 read32b (FILE *, int *err); void write8 (FILE *, uint8); void write16l (FILE *, uint16); void write16b (FILE *, uint16); void write32l (FILE *, uint32); void write32b (FILE *, uint32); int move_data (FILE *, FILE *, int); uint16 readmem16l (uint8 *); uint16 readmem16b (uint8 *); uint32 readmem24l (uint8 *); uint32 readmem24b (uint8 *); uint32 readmem32l (uint8 *); uint32 readmem32b (uint8 *); struct xmp_instrument *libxmp_get_instrument(struct context_data *, int); struct xmp_sample *libxmp_get_sample(struct context_data *, int); #endif /* LIBXMP_COMMON_H */ libxmp-4.4.1/src/paula.h0000664000175000017500000000161612773463510014715 0ustar claudioclaudio#ifndef LIBXMP_PAULA_H #define LIBXMP_PAULA_H /* 131072 to 0, 2048 entries */ #define PAULA_HZ 3546895 #define MINIMUM_INTERVAL 16 #define BLEP_SCALE 17 #define BLEP_SIZE 2048 #define MAX_BLEPS (BLEP_SIZE / MINIMUM_INTERVAL) /* the structure that holds data of bleps */ struct blep_state { int16 level; int16 age; }; struct paula_state { /* the instantenous value of Paula output */ int16 global_output_level; /* count of simultaneous bleps to keep track of */ unsigned int active_bleps; /* place to keep our bleps in. MAX_BLEPS should be * defined as a BLEP_SIZE / MINIMUM_EVENT_INTERVAL. * For Paula, minimum event interval could be even 1, but it makes * sense to limit it to some higher value such as 16. */ struct blep_state blepstate[MAX_BLEPS]; double remainder; double fdiv; }; void libxmp_paula_init (struct context_data *, struct paula_state *); #endif /* !LIBXMP_PAULA_H */ libxmp-4.4.1/src/lfo.h0000664000175000017500000000064612774567167014413 0ustar claudioclaudio#ifndef LIBXMP_LFO_H #define LIBXMP_LFO_H #include "common.h" struct lfo { int type; int rate; int depth; int phase; }; int libxmp_lfo_get(struct context_data *, struct lfo *, int); void libxmp_lfo_update(struct lfo *); void libxmp_lfo_set_phase(struct lfo *, int); void libxmp_lfo_set_depth(struct lfo *, int); void libxmp_lfo_set_rate(struct lfo *, int); void libxmp_lfo_set_waveform(struct lfo *, int); #endif libxmp-4.4.1/src/med_extras.h0000664000175000017500000000557312775035311015750 0ustar claudioclaudio#ifndef LIBXMP_MED_EXTRAS_H #define LIBXMP_MED_EXTRAS_H #define MED_EXTRAS_MAGIC 0x7f20ca5 struct med_instrument_extras { uint32 magic; int vts; /* Volume table speed */ int wts; /* Waveform table speed */ int hold; }; struct med_channel_extras { uint32 magic; int vp; /* MED synth volume table pointer */ int vv; /* MED synth volume slide value */ int vs; /* MED synth volume speed */ int vc; /* MED synth volume speed counter */ int vw; /* MED synth volume wait counter */ int wp; /* MED synth waveform table pointer */ int wv; /* MED synth waveform slide value */ int ws; /* MED synth waveform speed */ int wc; /* MED synth waveform speed counter */ int ww; /* MED synth waveform wait counter */ int period; /* MED synth period for RES */ int arp; /* MED synth arpeggio start */ int aidx; /* MED synth arpeggio index */ int vwf; /* MED synth vibrato waveform */ int vib_depth; /* MED synth vibrato depth */ int vib_speed; /* MED synth vibrato speed */ int vib_idx; /* MED synth vibrato index */ int vib_wf; /* MED synth vibrato waveform */ int volume; /* MED synth note volume */ int hold; /* MED note on hold flag */ int hold_count; /* MED note on hold frame counter */ int env_wav; /* MED synth volume envelope waveform */ int env_idx; /* MED synth volume envelope index */ #define MED_SYNTH_ENV_LOOP (1 << 0) int flags; /* flags */ }; struct med_module_extras { uint32 magic; uint8 **vol_table; /* MED volume sequence table */ uint8 **wav_table; /* MED waveform sequence table */ }; #define MED_INSTRUMENT_EXTRAS(x) ((struct med_instrument_extras *)(x).extra) #define HAS_MED_INSTRUMENT_EXTRAS(x) \ (MED_INSTRUMENT_EXTRAS(x) != NULL && \ MED_INSTRUMENT_EXTRAS(x)->magic == MED_EXTRAS_MAGIC) #define MED_CHANNEL_EXTRAS(x) ((struct med_channel_extras *)(x).extra) #define HAS_MED_CHANNEL_EXTRAS(x) \ (MED_CHANNEL_EXTRAS(x) != NULL && \ MED_CHANNEL_EXTRAS(x)->magic == MED_EXTRAS_MAGIC) #define MED_MODULE_EXTRAS(x) ((struct med_module_extras *)(x).extra) #define HAS_MED_MODULE_EXTRAS(x) \ (MED_MODULE_EXTRAS(x) != NULL && \ MED_MODULE_EXTRAS(x)->magic == MED_EXTRAS_MAGIC) int libxmp_med_change_period(struct context_data *, struct channel_data *); int libxmp_med_linear_bend(struct context_data *, struct channel_data *); int libxmp_med_get_vibrato(struct channel_data *); void libxmp_med_play_extras(struct context_data *, struct channel_data *, int); int libxmp_med_new_instrument_extras(struct xmp_instrument *); int libxmp_med_new_channel_extras(struct channel_data *); void libxmp_med_reset_channel_extras(struct channel_data *); void libxmp_med_release_channel_extras(struct channel_data *); int libxmp_med_new_module_extras(struct module_data *); void libxmp_med_release_module_extras(struct module_data *); void libxmp_med_extras_process_fx(struct context_data *, struct channel_data *, int, uint8, uint8, uint8, int); #endif libxmp-4.4.1/src/player.c0000664000175000017500000012670512775035311015105 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Sat, 18 Apr 1998 20:23:07 +0200 Frederic Bujon * Pan effect bug fixed: In Fastracker II the track panning effect erases * the instrument panning effect, and the same should happen in xmp. */ /* * Fri, 26 Jun 1998 13:29:25 -0400 (EDT) * Reported by Jared Spiegel * when the volume envelope is not enabled (disabled) on a sample, and a * notoff is delivered to ft2 (via either a noteoff in the note column or * command Kxx [where xx is # of ticks into row to give a noteoff to the * sample]), ft2 will set the volume of playback of the sample to 00h. * * Claudio's fix: implementing effect K */ #include #include #include "virtual.h" #include "period.h" #include "effects.h" #include "player.h" #include "mixer.h" #ifndef LIBXMP_CORE_PLAYER #include "extras.h" #endif /* Values for multi-retrig */ static const struct retrig_control rval[] = { { 0, 1, 1 }, { -1, 1, 1 }, { -2, 1, 1 }, { -4, 1, 1 }, { -8, 1, 1 }, { -16, 1, 1 }, { 0, 2, 3 }, { 0, 1, 2 }, { 0, 1, 1 }, { 1, 1, 1 }, { 2, 1, 1 }, { 4, 1, 1 }, { 8, 1, 1 }, { 16, 1, 1 }, { 0, 3, 2 }, { 0, 2, 1 }, { 0, 0, 1 } /* Note cut */ }; /* * "Anyway I think this is the most brilliant piece of crap we * have managed to put up!" * -- Ice of FC about "Mental Surgery" */ /* Envelope */ static int check_envelope_end(struct xmp_envelope *env, int x) { int16 *data = env->data; int index; if (~env->flg & XMP_ENVELOPE_ON || env->npt <= 0) return 0; index = (env->npt - 1) * 2; /* last node */ if (x >= data[index] || index == 0) { if (~env->flg & XMP_ENVELOPE_LOOP) { return 1; } } return 0; } static int get_envelope(struct xmp_envelope *env, int x, int def) { int x1, x2, y1, y2; int16 *data = env->data; int index; if (x < 0 || ~env->flg & XMP_ENVELOPE_ON || env->npt <= 0) return def; index = (env->npt - 1) * 2; x1 = data[index]; /* last node */ if (x >= x1 || index == 0) { return data[index + 1]; } do { index -= 2; x1 = data[index]; } while (index > 0 && x1 > x); /* interpolate */ y1 = data[index + 1]; x2 = data[index + 2]; y2 = data[index + 3]; return x2 == x1 ? y2 : ((y2 - y1) * (x - x1) / (x2 - x1)) + y1; } static int update_envelope_xm(struct xmp_envelope *env, int x, int release) { int16 *data = env->data; int has_loop, has_sus; int lpe, lps, sus; has_loop = env->flg & XMP_ENVELOPE_LOOP; has_sus = env->flg & XMP_ENVELOPE_SUS; lps = env->lps << 1; lpe = env->lpe << 1; sus = env->sus << 1; /* FT2 and IT envelopes behave in a different way regarding loops, * sustain and release. When the sustain point is at the end of the * envelope loop end and the key is released, FT2 escapes the loop * while IT runs another iteration. (See EnvLoops.xm in the OpenMPT * test cases.) */ if (has_loop && has_sus && sus == lpe) { if (!release) has_sus = 0; } /* If the envelope point is set to somewhere after the sustain point * or sustain loop, enable release to prevent the envelope point to * return to the sustain point or loop start. (See Filip Skutela's * farewell_tear.xm.) */ if (has_loop && x > data[lpe] + 1) { release = 1; } else if (has_sus && x > data[sus] + 1) { release = 1; } /* If enabled, stay at the sustain point */ if (has_sus && !release) { if (x >= data[sus]) { x = data[sus]; } } /* Envelope loops */ if (has_loop && x >= data[lpe]) { if (!(release && has_sus && sus == lpe)) x = data[lps]; } return x; } #ifndef LIBXMP_CORE_DISABLE_IT static int update_envelope_it(struct xmp_envelope *env, int x, int release, int key_off) { int16 *data = env->data; int has_loop, has_sus; int lpe, lps, sus, sue; has_loop = env->flg & XMP_ENVELOPE_LOOP; has_sus = env->flg & XMP_ENVELOPE_SUS; lps = env->lps << 1; lpe = env->lpe << 1; sus = env->sus << 1; sue = env->sue << 1; /* Release at the end of a sustain loop, run another loop */ if (has_sus && key_off && x == data[sue] + 1) { x = data[sus]; } else /* If enabled, stay in the sustain loop */ if (has_sus && !release) { if (x == data[sue] + 1) { x = data[sus]; } } else /* Finally, execute the envelope loop */ if (has_loop) { if (x > data[lpe]) { x = data[lps]; } } return x; } #endif static int update_envelope(struct xmp_envelope *env, int x, int release, int key_off, int it_env) { if (x < 0xffff) { /* increment tick */ x++; } if (x < 0) { return -1; } if (~env->flg & XMP_ENVELOPE_ON || env->npt <= 0) { return x; } #ifndef LIBXMP_CORE_DISABLE_IT return it_env ? update_envelope_it(env, x, release, key_off) : update_envelope_xm(env, x, release); #else return update_envelope_xm(env, x, release); #endif } /* Returns: 0 if do nothing, <0 to reset channel, >0 if has fade */ static int check_envelope_fade(struct xmp_envelope *env, int x) { int16 *data = env->data; int index; if (~env->flg & XMP_ENVELOPE_ON) return 0; index = (env->npt - 1) * 2; /* last node */ if (x > data[index]) { if (data[index + 1] == 0) return -1; else return 1; } return 0; } #ifndef LIBXMP_CORE_PLAYER /* From http://www.un4seen.com/forum/?topic=7554.0 * * "Invert loop" effect replaces (!) sample data bytes within loop with their * bitwise complement (NOT). The parameter sets speed of altering the samples. * This effectively trashes the sample data. Because of that this effect was * supposed to be removed in the very next ProTracker versions, but it was * never removed. * * Prior to [Protracker 1.1A] this effect is called "Funk Repeat" and it moves * loop of the instrument (just the loop information - sample data is not * altered). The parameter is the speed of moving the loop. */ static const int invloop_table[] = { 0, 5, 6, 7, 8, 10, 11, 13, 16, 19, 22, 26, 32, 43, 64, 128 }; static void update_invloop(struct module_data *m, struct channel_data *xc) { struct xmp_sample *xxs = &m->mod.xxs[xc->smp]; int len; xc->invloop.count += invloop_table[xc->invloop.speed]; if ((xxs->flg & XMP_SAMPLE_LOOP) && xc->invloop.count >= 128) { xc->invloop.count = 0; len = xxs->lpe - xxs->lps; if (++xc->invloop.pos > len) { xc->invloop.pos = 0; } if (~xxs->flg & XMP_SAMPLE_16BIT) { xxs->data[xxs->lps + xc->invloop.pos] ^= 0xff; } } } #endif /* * From OpenMPT Arpeggio.xm test: * * "[FT2] Arpeggio behavior is very weird with more than 16 ticks per row. This * comes from the fact that Fasttracker 2 uses a LUT for computing the arpeggio * note (instead of doing something like tick%3 or similar). The LUT only has * 16 entries, so when there are more than 16 ticks, it reads beyond array * boundaries. The vibrato table happens to be stored right after arpeggio * table. The tables look like this in memory: * * ArpTab: 0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0 * VibTab: 0,24,49,74,97,120,141,161,180,197,... * * All values except for the first in the vibrato table are greater than 1, so * they trigger the third arpeggio note. Keep in mind that Fasttracker 2 counts * downwards, so the table has to be read from back to front, i.e. at 16 ticks * per row, the 16th entry in the LUT is the first to be read. This is also the * reason why Arpeggio is played 'backwards' in Fasttracker 2." */ static int ft2_arpeggio(struct context_data *ctx, struct channel_data *xc) { struct player_data *p = &ctx->p; int i; if (xc->arpeggio.val[1] == 0 && xc->arpeggio.val[2] == 0) { return 0; } if (p->frame == 0) { return 0; } i = p->speed - (p->frame % p->speed); if (i == 16) { return 0; } else if (i > 16) { return xc->arpeggio.val[2]; } return xc->arpeggio.val[i % 3]; } static int is_first_frame(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; switch (m->read_event_type) { #ifndef LIBXMP_CORE_DISABLE_IT case READ_EVENT_IT: /* fall through */ #endif case READ_EVENT_ST3: return p->frame % p->speed == 0; default: return p->frame == 0; } } static void reset_channels(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct smix_data *smix = &ctx->smix; struct channel_data *xc; int i; #ifndef LIBXMP_CORE_PLAYER for (i = 0; i < p->virt.virt_channels; i++) { void *extra; xc = &p->xc_data[i]; extra = xc->extra; memset(xc, 0, sizeof (struct channel_data)); xc->extra = extra; libxmp_reset_channel_extras(ctx, xc); xc->ins = -1; xc->old_ins = 1; /* raw value */ xc->key = -1; xc->volume = m->volbase; } #else for (i = 0; i < p->virt.virt_channels; i++) { xc = &p->xc_data[i]; memset(xc, 0, sizeof (struct channel_data)); xc->ins = -1; xc->old_ins = 1; /* raw value */ xc->key = -1; xc->volume = m->volbase; } #endif for (i = 0; i < p->virt.num_tracks; i++) { xc = &p->xc_data[i]; if (i >= mod->chn && i < mod->chn + smix->chn) { xc->mastervol = 0x40; xc->pan.val = 0x80; } else { xc->mastervol = mod->xxc[i].vol; xc->pan.val = mod->xxc[i].pan; } #ifndef LIBXMP_CORE_DISABLE_IT xc->filter.cutoff = 0xff; /* Amiga split channel */ if (mod->xxc[i].flg & XMP_CHANNEL_SPLIT) { int j; xc->split = ((mod->xxc[i].flg & 0x30) >> 4) + 1; /* Connect split channel pairs */ for (j = 0; j < i; j++) { if (mod->xxc[j].flg & XMP_CHANNEL_SPLIT) { if (p->xc_data[j].split == xc->split) { p->xc_data[j].pair = i; xc->pair = j; } } } } else { xc->split = 0; } #endif /* Surround channel */ if (mod->xxc[i].flg & XMP_CHANNEL_SURROUND) { xc->pan.surround = 1; } } } static int check_delay(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; struct module_data *m = &ctx->m; /* Tempo affects delay and must be computed first */ if ((e->fxt == FX_SPEED && e->fxp < 0x20) || e->fxt == FX_S3M_SPEED) { if (e->fxp) { p->speed = e->fxp; } } if ((e->f2t == FX_SPEED && e->f2p < 0x20) || e->f2t == FX_S3M_SPEED) { if (e->f2p) { p->speed = e->f2p; } } /* Delay event read */ if (e->fxt == FX_EXTENDED && MSN(e->fxp) == EX_DELAY && LSN(e->fxp)) { xc->delay = LSN(e->fxp) + 1; goto do_delay; } if (e->f2t == FX_EXTENDED && MSN(e->f2p) == EX_DELAY && LSN(e->f2p)) { xc->delay = LSN(e->f2p) + 1; goto do_delay; } return 0; do_delay: memcpy(&xc->delayed_event, e, sizeof (struct xmp_event)); if (e->ins) { xc->delayed_ins = e->ins; } if (HAS_QUIRK(QUIRK_RTDELAY)) { if (e->vol == 0 && e->f2t == 0 && e->ins == 0 && e->note != XMP_KEY_OFF) xc->delayed_event.vol = xc->volume + 1; if (e->note == 0) xc->delayed_event.note = xc->key + 1; if (e->ins == 0) xc->delayed_event.ins = xc->old_ins; } return 1; } static inline void read_row(struct context_data *ctx, int pat, int row) { int chn; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct player_data *p = &ctx->p; struct flow_control *f = &p->flow; struct xmp_event ev; for (chn = 0; chn < mod->chn; chn++) { const int num_rows = mod->xxt[TRACK_NUM(pat, chn)]->rows; if (row < num_rows) { memcpy(&ev, &EVENT(pat, chn, row), sizeof(ev)); } else { memset(&ev, 0, sizeof(ev)); } if (ev.note == XMP_KEY_OFF) { int env_on = 0; int ins = ev.ins - 1; if (IS_VALID_INSTRUMENT(ins) && (mod->xxi[ins].aei.flg & XMP_ENVELOPE_ON)) { env_on = 1; } if (ev.fxt == FX_EXTENDED && MSN(ev.fxp) == EX_DELAY) { if (ev.ins && (LSN(ev.fxp) || env_on)) { if (LSN(ev.fxp)) { ev.note = 0; } ev.fxp = ev.fxt = 0; } } } if (check_delay(ctx, &ev, chn) == 0) { if (!f->rowdelay_set || f->rowdelay > 0) { libxmp_read_event(ctx, &ev, chn); #ifndef LIBXMP_CORE_PLAYER libxmp_med_hold_hack(ctx, pat, chn, row); #endif } } else { if (IS_PLAYER_MODE_IT()) { /* Reset flags. See SlideDelay.it */ p->xc_data[chn].flags = 0; } } } } static inline int get_channel_vol(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; int root; /* channel is a root channel */ if (chn < p->virt.num_tracks) return p->channel_vol[chn]; /* channel is invalid */ if (chn >= p->virt.virt_channels) return 0; /* root is invalid */ root = libxmp_virt_getroot(ctx, chn); if (root < 0) return 0; return p->channel_vol[root]; } static int tremor_ft2(struct context_data *ctx, int chn, int finalvol) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; if (xc->tremor.count & 0x80) { if (TEST(TREMOR) && p->frame != 0) { xc->tremor.count &= ~0x20; if (xc->tremor.count == 0x80) { /* end of down cycle, set up counter for up */ xc->tremor.count = xc->tremor.up | 0xc0; } else if (xc->tremor.count == 0xc0) { /* end of up cycle, set up counter for down */ xc->tremor.count = xc->tremor.down | 0x80; } else { xc->tremor.count--; } } if ((xc->tremor.count & 0xe0) == 0x80) { finalvol = 0; } } return finalvol; } static int tremor_s3m(struct context_data *ctx, int chn, int finalvol) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; if (TEST(TREMOR)) { if (xc->tremor.count == 0) { /* end of down cycle, set up counter for up */ xc->tremor.count = xc->tremor.up | 0x80; } else if (xc->tremor.count == 0x80) { /* end of up cycle, set up counter for down */ xc->tremor.count = xc->tremor.down; } xc->tremor.count--; if (~xc->tremor.count & 0x80) { finalvol = 0; } } return finalvol; } /* * Update channel data */ #define DOENV_RELEASE ((TEST_NOTE(NOTE_RELEASE) || act == VIRT_ACTION_OFF)) static void process_volume(struct context_data *ctx, int chn, int act) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct channel_data *xc = &p->xc_data[chn]; struct xmp_instrument *instrument; int finalvol; uint16 vol_envelope; int fade = 0; instrument = libxmp_get_instrument(ctx, xc->ins); /* Keyoff and fadeout */ /* Keyoff event in IT doesn't reset fadeout (see jeff93.it) * In XM it depends on envelope (see graff-strange_land.xm vs * Decibelter - Cosmic 'Wegian Mamas.xm) */ if (HAS_QUIRK(QUIRK_KEYOFF)) { /* If IT, only apply fadeout on note release if we don't * have envelope, or if we have envelope loop */ if (TEST_NOTE(NOTE_RELEASE) || act == VIRT_ACTION_OFF) { if ((~instrument->aei.flg & XMP_ENVELOPE_ON) || (instrument->aei.flg & XMP_ENVELOPE_LOOP)) { fade = 1; } } } else { if (~instrument->aei.flg & XMP_ENVELOPE_ON) { if (TEST_NOTE(NOTE_RELEASE)) { xc->fadeout = 0; } } if (TEST_NOTE(NOTE_RELEASE) || act == VIRT_ACTION_OFF) { fade = 1; } } if (TEST_NOTE(NOTE_FADEOUT) || act == VIRT_ACTION_FADE) { fade = 1; } if (fade) { if (xc->fadeout > xc->ins_fade) { xc->fadeout -= xc->ins_fade; } else { xc->fadeout = 0; SET_NOTE(NOTE_END); } } switch (check_envelope_fade(&instrument->aei, xc->v_idx)) { case -1: SET_NOTE(NOTE_END); /* Don't reset channel, we may have a tone portamento later * virt_resetchannel(ctx, chn); */ break; case 0: break; default: if (HAS_QUIRK(QUIRK_ENVFADE)) { SET_NOTE(NOTE_FADEOUT); } } if (!TEST_PER(VENV_PAUSE)) { xc->v_idx = update_envelope(&instrument->aei, xc->v_idx, DOENV_RELEASE, TEST(KEY_OFF), IS_PLAYER_MODE_IT()); } vol_envelope = get_envelope(&instrument->aei, xc->v_idx, 64); if (check_envelope_end(&instrument->aei, xc->v_idx)) { if (vol_envelope == 0) { SET_NOTE(NOTE_END); } SET_NOTE(NOTE_ENV_END); } /* If note ended in background channel, we can safely reset it */ if (TEST_NOTE(NOTE_END) && chn >= p->virt.num_tracks) { libxmp_virt_resetchannel(ctx, chn); return; } #ifndef LIBXMP_CORE_PLAYER finalvol = libxmp_extras_get_volume(ctx, xc); #else finalvol = xc->volume; #endif if (IS_PLAYER_MODE_IT()) { finalvol = xc->volume * (100 - xc->rvv) / 100; } if (TEST(TREMOLO)) { /* OpenMPT VibratoReset.mod */ if (!is_first_frame(ctx) || !HAS_QUIRK(QUIRK_PROTRACK)) { finalvol += libxmp_lfo_get(ctx, &xc->tremolo.lfo, 0) / (1 << 6); } if (!is_first_frame(ctx) || HAS_QUIRK(QUIRK_VIBALL)) { libxmp_lfo_update(&xc->tremolo.lfo); } } CLAMP(finalvol, 0, m->volbase); finalvol = (finalvol * xc->fadeout) >> 6; /* 16 bit output */ finalvol = (uint32)(vol_envelope * p->gvol * xc->mastervol / m->gvolbase * ((int)finalvol * 0x40 / m->volbase)) >> 18; /* Apply channel volume */ finalvol = finalvol * get_channel_vol(ctx, chn) / 100; #ifndef LIBXMP_CORE_PLAYER /* Volume translation table (for PTM, ARCH, COCO) */ if (m->vol_table) { finalvol = m->volbase == 0xff ? m->vol_table[finalvol >> 2] << 2 : m->vol_table[finalvol >> 4] << 4; } #endif if (HAS_QUIRK(QUIRK_INSVOL)) { finalvol = (finalvol * instrument->vol * xc->gvl) >> 12; } if (IS_PLAYER_MODE_FT2()) { finalvol = tremor_ft2(ctx, chn, finalvol); } else { finalvol = tremor_s3m(ctx, chn, finalvol); } if (chn < m->mod.chn) { finalvol = finalvol * p->master_vol / 100; } else { finalvol = finalvol * p->smix_vol / 100; } xc->info_finalvol = TEST_NOTE(NOTE_SAMPLE_END) ? 0 : finalvol; libxmp_virt_setvol(ctx, chn, finalvol); /* Check Amiga split channel */ if (xc->split) { libxmp_virt_setvol(ctx, xc->pair, finalvol); } } static void process_frequency(struct context_data *ctx, int chn, int act) { #ifndef LIBXMP_CORE_DISABLE_IT struct mixer_data *s = &ctx->s; #endif struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct channel_data *xc = &p->xc_data[chn]; struct xmp_instrument *instrument; double period, vibrato; int linear_bend; int frq_envelope; int arp; #ifndef LIBXMP_CORE_DISABLE_IT int cutoff, resonance; #endif instrument = libxmp_get_instrument(ctx, xc->ins); if (!TEST_PER(FENV_PAUSE)) { xc->f_idx = update_envelope(&instrument->fei, xc->f_idx, DOENV_RELEASE, TEST(KEY_OFF), IS_PLAYER_MODE_IT()); } frq_envelope = get_envelope(&instrument->fei, xc->f_idx, 0); #ifndef LIBXMP_CORE_PLAYER /* Do note slide */ if (TEST(NOTE_SLIDE)) { if (xc->noteslide.count == 0) { xc->note += xc->noteslide.slide; xc->period = libxmp_note_to_period(ctx, xc->note, xc->finetune, xc->per_adj); xc->noteslide.count = xc->noteslide.speed; } xc->noteslide.count--; libxmp_virt_setnote(ctx, chn, xc->note); } #endif /* Instrument vibrato */ vibrato = 1.0 * libxmp_lfo_get(ctx, &xc->insvib.lfo, 1) / (4096 * (1 + xc->insvib.sweep)); libxmp_lfo_update(&xc->insvib.lfo); if (xc->insvib.sweep > 1) { xc->insvib.sweep -= 2; } else { xc->insvib.sweep = 0; } /* Vibrato */ if (TEST(VIBRATO) || TEST_PER(VIBRATO)) { /* OpenMPT VibratoReset.mod */ if (!is_first_frame(ctx) || !HAS_QUIRK(QUIRK_PROTRACK)) { int shift = HAS_QUIRK(QUIRK_VIBHALF) ? 10 : 9; int vib = libxmp_lfo_get(ctx, &xc->vibrato.lfo, 1) / (1 << shift); if (HAS_QUIRK(QUIRK_VIBINV)) { vibrato -= vib; } else { vibrato += vib; } } if (!is_first_frame(ctx) || HAS_QUIRK(QUIRK_VIBALL)) { libxmp_lfo_update(&xc->vibrato.lfo); } } period = xc->period; #ifndef LIBXMP_CORE_PLAYER period += libxmp_extras_get_period(ctx, xc); #endif /* Sanity check */ if (period < 0.1) { period = 0.1; } /* Arpeggio */ if (HAS_QUIRK(QUIRK_FT2BUGS)) { arp = ft2_arpeggio(ctx, xc); } else { arp = xc->arpeggio.val[xc->arpeggio.count]; } /* Pitch bend */ /* From OpenMPT PeriodLimit.s3m: * "ScreamTracker 3 limits the final output period to be at least 64, * i.e. when playing a note that is too high or when sliding the * period lower than 64, the output period will simply be clamped to * 64. However, when reaching a period of 0 through slides, the * output on the channel should be stopped." */ /* ST3 uses periods*4, so the limit is 16. Adjusted to the exact * A6 value because we compute periods in floating point. */ if (HAS_QUIRK(QUIRK_ST3BUGS)) { if (period < 16.239270) { /* A6 */ period = 16.239270; } } linear_bend = libxmp_period_to_bend(ctx, period + vibrato, xc->note, xc->per_adj); if (TEST_NOTE(NOTE_GLISSANDO) && TEST(TONEPORTA)) { if (linear_bend > 0) { linear_bend = (linear_bend + 6400) / 12800 * 12800; } else if (linear_bend < 0) { linear_bend = (linear_bend - 6400) / 12800 * 12800; } } if (HAS_QUIRK(QUIRK_FT2BUGS)) { if (arp) { /* OpenMPT ArpSlide.xm */ linear_bend = linear_bend / 12800 * 12800 + xc->finetune * 100; /* OpenMPT ArpeggioClamp.xm */ if (xc->note + arp > 107) { if (p->speed - (p->frame % p->speed) > 0) { arp = 108 - xc->note; } } } } /* Envelope */ if (xc->f_idx >= 0 && (~instrument->fei.flg & XMP_ENVELOPE_FLT)) { /* IT pitch envelopes are always linear, even in Amiga period * mode. Each unit in the envelope scale is 1/25 semitone. */ linear_bend += frq_envelope << 7; } /* Arpeggio */ if (arp != 0) { linear_bend += (100 << 7) * arp; /* OpenMPT ArpWrapAround.mod */ if (HAS_QUIRK(QUIRK_PROTRACK)) { if (xc->note + arp > MAX_NOTE_MOD + 1) { linear_bend -= 12800 * (3 * 12); } else if (xc->note + arp > MAX_NOTE_MOD) { libxmp_virt_setvol(ctx, chn, 0); } } } #ifndef LIBXMP_CORE_PLAYER linear_bend += libxmp_extras_get_linear_bend(ctx, xc); #endif period = libxmp_note_to_period_mix(xc->note, linear_bend); libxmp_virt_setperiod(ctx, chn, period); /* For xmp_get_frame_info() */ xc->info_pitchbend = linear_bend >> 7; xc->info_period = period * 4096; if (IS_PERIOD_MODRNG()) { CLAMP(xc->info_period, libxmp_note_to_period(ctx, MAX_NOTE_MOD, xc->finetune, 0) * 4096, libxmp_note_to_period(ctx, MIN_NOTE_MOD, xc->finetune, 0) * 4096); } else if (xc->info_period < (1 << 12)) { xc->info_period = (1 << 12); } #ifndef LIBXMP_CORE_DISABLE_IT /* Process filter */ if (!HAS_QUIRK(QUIRK_FILTER)) { return; } if (xc->f_idx >= 0 && (instrument->fei.flg & XMP_ENVELOPE_FLT)) { if (frq_envelope < 0xfe) { xc->filter.envelope = frq_envelope; } cutoff = xc->filter.cutoff * xc->filter.envelope >> 8; } else { cutoff = xc->filter.cutoff; } resonance = xc->filter.resonance; if (cutoff > 0xff) { cutoff = 0xff; } else if (cutoff < 0xff) { int a0, b0, b1; libxmp_filter_setup(s->freq, cutoff, resonance, &a0, &b0, &b1); libxmp_virt_seteffect(ctx, chn, DSP_EFFECT_FILTER_A0, a0); libxmp_virt_seteffect(ctx, chn, DSP_EFFECT_FILTER_B0, b0); libxmp_virt_seteffect(ctx, chn, DSP_EFFECT_FILTER_B1, b1); libxmp_virt_seteffect(ctx, chn, DSP_EFFECT_RESONANCE, resonance); } /* Always set cutoff */ libxmp_virt_seteffect(ctx, chn, DSP_EFFECT_CUTOFF, cutoff); #endif } static void process_pan(struct context_data *ctx, int chn, int act) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct mixer_data *s = &ctx->s; struct channel_data *xc = &p->xc_data[chn]; struct xmp_instrument *instrument; int finalpan, panbrello = 0; int pan_envelope; int channel_pan; instrument = libxmp_get_instrument(ctx, xc->ins); if (!TEST_PER(PENV_PAUSE)) { xc->p_idx = update_envelope(&instrument->pei, xc->p_idx, DOENV_RELEASE, TEST(KEY_OFF), IS_PLAYER_MODE_IT()); } pan_envelope = get_envelope(&instrument->pei, xc->p_idx, 32); #ifndef LIBXMP_CORE_DISABLE_IT if (TEST(PANBRELLO)) { panbrello = libxmp_lfo_get(ctx, &xc->panbrello.lfo, 0) / 512; if (is_first_frame(ctx)) { libxmp_lfo_update(&xc->panbrello.lfo); } } #endif channel_pan = xc->pan.val; #if 0 #ifdef LIBXMP_PAULA_SIMULATOR /* Always use 100% pan separation in Amiga mode */ if (p->flags & XMP_FLAGS_A500) { if (IS_AMIGA_MOD()) { channel_pan = channel_pan < 0x80 ? 0 : 0xff; } } #endif #endif finalpan = channel_pan + panbrello + (pan_envelope - 32) * (128 - abs(xc->pan.val - 128)) / 32; if (IS_PLAYER_MODE_IT()) { finalpan = finalpan + xc->rpv * 4; } CLAMP(finalpan, 0, 255); if (s->format & XMP_FORMAT_MONO || xc->pan.surround) { finalpan = 0; } else { finalpan = (finalpan - 0x80) * s->mix / 100; } xc->info_finalpan = finalpan + 0x80; if (xc->pan.surround) { libxmp_virt_setpan(ctx, chn, PAN_SURROUND); } else { libxmp_virt_setpan(ctx, chn, finalpan); } } static void update_volume(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; #ifndef LIBXMP_CORE_DISABLE_IT struct flow_control *f = &p->flow; #endif struct channel_data *xc = &p->xc_data[chn]; /* Volume slides happen in all frames but the first, except when the * "volume slide on all frames" flag is set. */ if (p->frame % p->speed != 0 || HAS_QUIRK(QUIRK_VSALL)) { if (TEST(GVOL_SLIDE)) { p->gvol += xc->gvol.slide; } if (TEST(VOL_SLIDE) || TEST_PER(VOL_SLIDE)) { xc->volume += xc->vol.slide; } #ifndef LIBXMP_CORE_PLAYER if (TEST_PER(VOL_SLIDE)) { if (xc->vol.slide > 0 && xc->volume > m->volbase) { xc->volume = m->volbase; RESET_PER(VOL_SLIDE); } if (xc->vol.slide < 0 && xc->volume < 0) { xc->volume = 0; RESET_PER(VOL_SLIDE); } } #endif if (TEST(VOL_SLIDE_2)) { xc->volume += xc->vol.slide2; } if (TEST(TRK_VSLIDE)) { xc->mastervol += xc->trackvol.slide; } } if (p->frame % p->speed == 0) { /* Process "fine" effects */ if (TEST(FINE_VOLS)) { xc->volume += xc->vol.fslide; } #ifndef LIBXMP_CORE_DISABLE_IT if (TEST(FINE_VOLS_2)) { /* OpenMPT FineVolColSlide.it: * Unlike fine volume slides in the effect column, * fine volume slides in the volume column are only * ever executed on the first tick -- not on multiples * of the first tick if there is a pattern delay. */ if (!f->rowdelay_set || f->rowdelay_set & 2) { xc->volume += xc->vol.fslide2; } } f->rowdelay_set &= ~2; #endif if (TEST(TRK_FVSLIDE)) { xc->mastervol += xc->trackvol.fslide; } if (TEST(GVOL_SLIDE)) { p->gvol += xc->gvol.fslide; } } /* Clamp volumes */ CLAMP(xc->volume, 0, m->volbase); CLAMP(p->gvol, 0, m->gvolbase); CLAMP(xc->mastervol, 0, m->volbase); if (xc->split) { p->xc_data[xc->pair].volume = xc->volume; } } static void update_frequency(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct channel_data *xc = &p->xc_data[chn]; if (!is_first_frame(ctx) || HAS_QUIRK(QUIRK_PBALL)) { if (TEST(PITCHBEND) || TEST_PER(PITCHBEND)) { xc->period += xc->freq.slide; if (HAS_QUIRK(QUIRK_PROTRACK)) { xc->porta.target = xc->period; } } /* Do tone portamento */ if (TEST(TONEPORTA) || TEST_PER(TONEPORTA)) { if (xc->porta.target > 0) { int end = 0; if (xc->porta.dir > 0) { xc->period += xc->porta.slide; if (xc->period >= xc->porta.target) end = 1; } else { xc->period -= xc->porta.slide; if (xc->period <= xc->porta.target) end = 1; } if (end) { /* reached end */ xc->period = xc->porta.target; xc->porta.dir = 0; RESET(TONEPORTA); RESET_PER(TONEPORTA); if (HAS_QUIRK(QUIRK_PROTRACK)) { xc->porta.target = -1; } } } } } if (is_first_frame(ctx)) { if (TEST(FINE_BEND)) { xc->period += xc->freq.fslide; } #ifndef LIBXMP_CORE_PLAYER if (TEST(FINE_NSLIDE)) { xc->note += xc->noteslide.fslide; xc->period = libxmp_note_to_period(ctx, xc->note, xc->finetune, xc->per_adj); } #endif } switch (m->period_type) { case PERIOD_LINEAR: CLAMP(xc->period, MIN_PERIOD_L, MAX_PERIOD_L); break; case PERIOD_MODRNG: CLAMP(xc->period, libxmp_note_to_period(ctx, MAX_NOTE_MOD, xc->finetune, 0), libxmp_note_to_period(ctx, MIN_NOTE_MOD, xc->finetune, 0)); break; } xc->arpeggio.count++; xc->arpeggio.count %= xc->arpeggio.size; /* Check for invalid periods (from Toru Egashira's NSPmod) * panic.s3m has negative periods * ambio.it uses low (~8) period values */ if (xc->period < 0.25) { libxmp_virt_setvol(ctx, chn, 0); } } static void update_pan(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; if (TEST(PAN_SLIDE)) { if (is_first_frame(ctx)) { xc->pan.val += xc->pan.fslide; } else { xc->pan.val += xc->pan.slide; } if (xc->pan.val < 0) { xc->pan.val = 0; } else if (xc->pan.val > 0xff) { xc->pan.val = 0xff; } } } static void play_channel(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; int act; xc->info_finalvol = 0; #ifndef LIBXMP_CORE_DISABLE_IT /* IT tempo slide */ if (!is_first_frame(ctx) && TEST(TEMPO_SLIDE)) { p->bpm += xc->tempo.slide; CLAMP(p->bpm, 0x20, 0xff); } #endif /* Do delay */ if (xc->delay > 0) { if (--xc->delay == 0) { libxmp_read_event(ctx, &xc->delayed_event, chn); } } act = libxmp_virt_cstat(ctx, chn); if (act == VIRT_INVALID) { /* We need this to keep processing global volume slides */ update_volume(ctx, chn); return; } if (p->frame == 0 && act != VIRT_ACTIVE) { if (!IS_VALID_INSTRUMENT_OR_SFX(xc->ins) || act == VIRT_ACTION_CUT) { libxmp_virt_resetchannel(ctx, chn); return; } } if (!IS_VALID_INSTRUMENT_OR_SFX(xc->ins)) return; #ifndef LIBXMP_CORE_PLAYER libxmp_play_extras(ctx, xc, chn); #endif /* Do cut/retrig */ if (TEST(RETRIG)) { int cond = HAS_QUIRK(QUIRK_S3MRTG) ? --xc->retrig.count <= 0 : --xc->retrig.count == 0; if (cond) { if (xc->retrig.type < 0x10) { /* don't retrig on cut */ libxmp_virt_voicepos(ctx, chn, 0); } else { SET_NOTE(NOTE_END); } xc->volume += rval[xc->retrig.type].s; xc->volume *= rval[xc->retrig.type].m; xc->volume /= rval[xc->retrig.type].d; xc->retrig.count = LSN(xc->retrig.val); } } /* Do keyoff */ if (xc->keyoff) { if (--xc->keyoff == 0) SET_NOTE(NOTE_RELEASE); } libxmp_virt_release(ctx, chn, TEST_NOTE(NOTE_RELEASE)); process_volume(ctx, chn, act); process_frequency(ctx, chn, act); process_pan(ctx, chn, act); update_volume(ctx, chn); update_frequency(ctx, chn); update_pan(ctx, chn); #ifndef LIBXMP_CORE_PLAYER if (HAS_QUIRK(QUIRK_PROTRACK) && xc->ins < mod->ins) { update_invloop(m, xc); } #endif if (TEST_NOTE(NOTE_SUSEXIT)) { SET_NOTE(NOTE_RELEASE); } xc->info_position = libxmp_virt_getvoicepos(ctx, chn); } /* * Event injection */ static void inject_event(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct smix_data *smix = &ctx->smix; int chn; for (chn = 0; chn < mod->chn + smix->chn; chn++) { struct xmp_event *e = &p->inject_event[chn]; if (e->_flag > 0) { libxmp_read_event(ctx, e, chn); e->_flag = 0; } } } /* * Sequencing */ static void next_order(struct context_data *ctx) { struct player_data *p = &ctx->p; struct flow_control *f = &p->flow; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int mark; do { p->ord++; /* Restart module */ mark = HAS_QUIRK(QUIRK_MARKER) && mod->xxo[p->ord] == 0xff; if (p->ord >= mod->len || mark) { if (mod->rst > mod->len || mod->xxo[mod->rst] >= mod->pat || p->ord < m->seq_data[p->sequence].entry_point) { p->ord = m->seq_data[p->sequence].entry_point; } else { if (libxmp_get_sequence(ctx, mod->rst) == p->sequence) { p->ord = mod->rst; } else { p->ord = m->seq_data[p->sequence].entry_point; } } p->gvol = m->xxo_info[p->ord].gvl; } } while (mod->xxo[p->ord] >= mod->pat); p->current_time = m->xxo_info[p->ord].time; f->num_rows = mod->xxp[mod->xxo[p->ord]]->rows; if (f->jumpline >= f->num_rows) f->jumpline = 0; p->row = f->jumpline; f->jumpline = 0; p->pos = p->ord; p->frame = 0; #ifndef LIBXMP_CORE_PLAYER /* Reset persistent effects at new pattern */ if (HAS_QUIRK(QUIRK_PERPAT)) { int chn; for (chn = 0; chn < mod->chn; chn++) { p->xc_data[chn].per_flags = 0; } } #endif } static void next_row(struct context_data *ctx) { struct player_data *p = &ctx->p; struct flow_control *f = &p->flow; p->frame = 0; f->delay = 0; if (f->pbreak) { f->pbreak = 0; if (f->jump != -1) { p->ord = f->jump - 1; f->jump = -1; } next_order(ctx); } else { if (f->loop_chn) { p->row = f->loop[f->loop_chn - 1].start - 1; f->loop_chn = 0; } if (f->rowdelay == 0) { p->row++; f->rowdelay_set = 0; } else { f->rowdelay--; } /* check end of pattern */ if (p->row >= f->num_rows) { next_order(ctx); } } } #ifndef LIBXMP_CORE_DISABLE_IT /* * Set note action for libxmp_virt_pastnote */ void libxmp_player_set_release(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; SET_NOTE(NOTE_RELEASE); } void libxmp_player_set_fadeout(struct context_data *ctx, int chn) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; SET_NOTE(NOTE_FADEOUT); } #endif static void update_from_ord_info(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct ord_data *oinfo = &m->xxo_info[p->ord]; if (oinfo->speed) p->speed = oinfo->speed; p->bpm = oinfo->bpm; p->gvol = oinfo->gvl; p->current_time = oinfo->time; p->frame_time = m->time_factor * m->rrate / p->bpm; #ifndef LIBXMP_CORE_PLAYER p->st26_speed = oinfo->st26_speed; #endif } int xmp_start_player(xmp_context opaque, int rate, int format) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct flow_control *f = &p->flow; int i; int ret = 0; if (rate < XMP_MIN_SRATE || rate > XMP_MAX_SRATE) return -XMP_ERROR_INVALID; if (ctx->state < XMP_STATE_LOADED) return -XMP_ERROR_STATE; if (ctx->state > XMP_STATE_LOADED) xmp_end_player(opaque); if (libxmp_mixer_on(ctx, rate, format, m->c4rate) < 0) return -XMP_ERROR_INTERNAL; p->master_vol = 100; p->smix_vol = 100; p->gvol = m->volbase; p->pos = p->ord = 0; p->frame = -1; p->row = 0; p->current_time = 0; p->loop_count = 0; p->sequence = 0; /* Unmute all channels and set default volume */ for (i = 0; i < XMP_MAX_CHANNELS; i++) { p->channel_mute[i] = 0; p->channel_vol[i] = 100; } /* Skip invalid patterns at start (the seventh laboratory.it) */ while (p->ord < mod->len && mod->xxo[p->ord] >= mod->pat) { p->ord++; } /* Check if all positions skipped */ if (p->ord >= mod->len) { mod->len = 0; } if (mod->len == 0 || mod->chn == 0) { /* set variables to sane state */ p->ord = p->scan[0].ord = 0; p->row = p->scan[0].row = 0; f->end_point = 0; f->num_rows = 0; } else { f->num_rows = mod->xxp[mod->xxo[p->ord]]->rows; f->end_point = p->scan[0].num; } update_from_ord_info(ctx); if (libxmp_virt_on(ctx, mod->chn + smix->chn) != 0) { ret = -XMP_ERROR_INTERNAL; goto err; } f->delay = 0; f->jumpline = 0; f->jump = -1; f->pbreak = 0; f->rowdelay_set = 0; f->loop = calloc(p->virt.virt_channels, sizeof(struct pattern_loop)); if (f->loop == NULL) { ret = -XMP_ERROR_SYSTEM; goto err; } p->xc_data = calloc(p->virt.virt_channels, sizeof(struct channel_data)); if (p->xc_data == NULL) { ret = -XMP_ERROR_SYSTEM; goto err1; } #ifndef LIBXMP_CORE_PLAYER for (i = 0; i < p->virt.virt_channels; i++) { struct channel_data *xc = &p->xc_data[i]; if (libxmp_new_channel_extras(ctx, xc) < 0) goto err2; } #endif reset_channels(ctx); ctx->state = XMP_STATE_PLAYING; return 0; #ifndef LIBXMP_CORE_PLAYER err2: free(p->xc_data); #endif err1: free(f->loop); err: return ret; } static void check_end_of_module(struct context_data *ctx) { struct player_data *p = &ctx->p; struct flow_control *f = &p->flow; /* check end of module */ if (p->ord == p->scan[p->sequence].ord && p->row == p->scan[p->sequence].row) { if (f->end_point == 0) { p->loop_count++; f->end_point = p->scan[p->sequence].num; /* return -1; */ } f->end_point--; } } int xmp_play_frame(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct flow_control *f = &p->flow; int i; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; if (mod->len <= 0) { return -XMP_END; } if (HAS_QUIRK(QUIRK_MARKER) && mod->xxo[p->ord] == 0xff) { return -XMP_END; } /* check reposition */ if (p->ord != p->pos) { int start = m->seq_data[p->sequence].entry_point; if (p->pos == -2) { /* set by xmp_module_stop */ return -XMP_END; /* that's all folks */ } if (p->pos == -1) { /* restart sequence */ p->pos = start; } if (p->pos == start) { f->end_point = p->scan[p->sequence].num; } /* Check if lands after a loop point */ if (p->pos > p->scan[p->sequence].ord) { f->end_point = 0; } f->jumpline = 0; f->jump = -1; p->ord = p->pos - 1; /* Stay inside our subsong */ if (p->ord < start) { p->ord = start - 1; } next_order(ctx); update_from_ord_info(ctx); libxmp_virt_reset(ctx); reset_channels(ctx); } else { p->frame++; if (p->frame >= (p->speed * (1 + f->delay))) { /* If break during pattern delay, next row is skipped. * See corruption.mod order 1D (pattern 0D) last line: * EE2 + D31 ignores D00 in order 1C line 31. Reported * by The Welder , Jan 14 2012 */ if (HAS_QUIRK(QUIRK_PROTRACK) && f->delay && f->pbreak) { next_row(ctx); check_end_of_module(ctx); } next_row(ctx); } } for (i = 0; i < mod->chn; i++) { struct channel_data *xc = &p->xc_data[i]; RESET(KEY_OFF); } /* check new row */ if (p->frame == 0) { /* first frame in row */ check_end_of_module(ctx); read_row(ctx, mod->xxo[p->ord], p->row); #ifndef LIBXMP_CORE_PLAYER if (p->st26_speed) { if (p->st26_speed & 0x10000) { p->speed = (p->st26_speed & 0xff00) >> 8; } else { p->speed = p->st26_speed & 0xff; } p->st26_speed ^= 0x10000; } #endif } inject_event(ctx); /* play_frame */ for (i = 0; i < p->virt.virt_channels; i++) { play_channel(ctx, i); } p->frame_time = m->time_factor * m->rrate / p->bpm; p->current_time += p->frame_time; libxmp_mixer_softmixer(ctx); return 0; } int xmp_play_buffer(xmp_context opaque, void *out_buffer, int size, int loop) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; int ret = 0, filled = 0, copy_size; struct xmp_frame_info fi; /* Reset internal state * Syncs buffer start with frame start */ if (out_buffer == NULL) { p->loop_count = 0; p->buffer_data.consumed = 0; p->buffer_data.in_size = 0; return 0; } if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; /* Fill buffer */ while (filled < size) { /* Check if buffer full */ if (p->buffer_data.consumed == p->buffer_data.in_size) { ret = xmp_play_frame(opaque); xmp_get_frame_info(opaque, &fi); /* Check end of module */ if (ret < 0 || (loop > 0 && fi.loop_count >= loop)) { /* Start of frame, return end of replay */ if (filled == 0) { p->buffer_data.consumed = 0; p->buffer_data.in_size = 0; return -1; } /* Fill remaining of this buffer */ memset((char *)out_buffer + filled, 0, size - filled); return 0; } p->buffer_data.consumed = 0; p->buffer_data.in_buffer = fi.buffer; p->buffer_data.in_size = fi.buffer_size; } /* Copy frame data to user buffer */ copy_size = MIN(size - filled, p->buffer_data.in_size - p->buffer_data.consumed); memcpy((char *)out_buffer + filled, p->buffer_data.in_buffer + p->buffer_data.consumed, copy_size); p->buffer_data.consumed += copy_size; filled += copy_size; } return ret; } void xmp_end_player(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct flow_control *f = &p->flow; #ifndef LIBXMP_CORE_PLAYER struct channel_data *xc; int i; #endif if (ctx->state < XMP_STATE_PLAYING) return; ctx->state = XMP_STATE_LOADED; #ifndef LIBXMP_CORE_PLAYER /* Free channel extras */ for (i = 0; i < p->virt.virt_channels; i++) { xc = &p->xc_data[i]; libxmp_release_channel_extras(ctx, xc); } #endif libxmp_virt_off(ctx); free(p->xc_data); free(f->loop); p->xc_data = NULL; f->loop = NULL; libxmp_mixer_off(ctx); } void xmp_get_module_info(xmp_context opaque, struct xmp_module_info *info) { struct context_data *ctx = (struct context_data *)opaque; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; if (ctx->state < XMP_STATE_LOADED) return; memcpy(info->md5, m->md5, 16); info->mod = mod; info->comment = m->comment; info->num_sequences = m->num_sequences; info->seq_data = m->seq_data; info->vol_base = m->volbase; } void xmp_get_frame_info(xmp_context opaque, struct xmp_frame_info *info) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct mixer_data *s = &ctx->s; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int chn, i; if (ctx->state < XMP_STATE_LOADED) return; chn = mod->chn; if (p->pos >= 0 && p->pos < mod->len) { info->pos = p->pos; } else { info->pos = 0; } info->pattern = mod->xxo[info->pos]; if (info->pattern < mod->pat) { info->num_rows = mod->xxp[info->pattern]->rows; } else { info->num_rows = 0; } info->row = p->row; info->frame = p->frame; info->speed = p->speed; info->bpm = p->bpm; info->total_time = p->scan[p->sequence].time; info->frame_time = p->frame_time * 1000; info->time = p->current_time; info->buffer = s->buffer; info->total_size = XMP_MAX_FRAMESIZE; info->buffer_size = s->ticksize; if (~s->format & XMP_FORMAT_MONO) { info->buffer_size *= 2; } if (~s->format & XMP_FORMAT_8BIT) { info->buffer_size *= 2; } info->volume = p->gvol; info->loop_count = p->loop_count; info->virt_channels = p->virt.virt_channels; info->virt_used = p->virt.virt_used; info->sequence = p->sequence; if (p->xc_data != NULL) { for (i = 0; i < chn; i++) { struct channel_data *c = &p->xc_data[i]; struct xmp_channel_info *ci = &info->channel_info[i]; struct xmp_track *track; struct xmp_event *event; int trk; ci->note = c->key; ci->pitchbend = c->info_pitchbend; ci->period = c->info_period; ci->position = c->info_position; ci->instrument = c->ins; ci->sample = c->smp; ci->volume = c->info_finalvol >> 4; ci->pan = c->info_finalpan; ci->reserved = 0; memset(&ci->event, 0, sizeof(*event)); if (info->pattern < mod->pat && info->row < info->num_rows) { trk = mod->xxp[info->pattern]->index[i]; track = mod->xxt[trk]; if (info->row < track->rows) { event = &track->event[info->row]; memcpy(&ci->event, event, sizeof(*event)); } } } } } libxmp-4.4.1/src/hmn_extras.h0000664000175000017500000000323712775035311015760 0ustar claudioclaudio#ifndef XMP_HMN_EXTRAS_H #define XMP_HMN_EXTRAS_H #define HMN_EXTRAS_MAGIC 0x041bc81a struct hmn_instrument_extras { uint32 magic; int dataloopstart; int dataloopend; uint8 data[64]; uint8 progvolume[64]; }; struct hmn_channel_extras { uint32 magic; int datapos; /* HMN waveform table pointer */ int volume; /* HMN synth volume */ }; struct hmn_module_extras { uint32 magic; }; #define HMN_INSTRUMENT_EXTRAS(x) ((struct hmn_instrument_extras *)(x).extra) #define HAS_HMN_INSTRUMENT_EXTRAS(x) \ (HMN_INSTRUMENT_EXTRAS(x) != NULL && \ HMN_INSTRUMENT_EXTRAS(x)->magic == HMN_EXTRAS_MAGIC) #define HMN_CHANNEL_EXTRAS(x) ((struct hmn_channel_extras *)(x).extra) #define HAS_HMN_CHANNEL_EXTRAS(x) \ (HMN_CHANNEL_EXTRAS(x) != NULL && \ HMN_CHANNEL_EXTRAS(x)->magic == HMN_EXTRAS_MAGIC) #define HMN_MODULE_EXTRAS(x) ((struct hmn_module_extras *)(x).extra) #define HAS_HMN_MODULE_EXTRAS(x) \ (HMN_MODULE_EXTRAS(x) != NULL && \ HMN_MODULE_EXTRAS(x)->magic == HMN_EXTRAS_MAGIC) void libxmp_hmn_play_extras(struct context_data *, struct channel_data *, int); void libxmp_hmn_set_arpeggio(struct channel_data *, int); int libxmp_hmn_linear_bend(struct context_data *, struct channel_data *); int libxmp_hmn_new_instrument_extras(struct xmp_instrument *); int libxmp_hmn_new_channel_extras(struct channel_data *); void libxmp_hmn_reset_channel_extras(struct channel_data *); void libxmp_hmn_release_channel_extras(struct channel_data *); int libxmp_hmn_new_module_extras(struct module_data *); void libxmp_hmn_release_module_extras(struct module_data *); void libxmp_hmn_extras_process_fx(struct context_data *, struct channel_data *, int, uint8, uint8, uint8, int); #endif libxmp-4.4.1/src/format.h0000664000175000017500000000073012773463510015077 0ustar claudioclaudio#ifndef LIBXMP_FORMAT_H #define LIBXMP_FORMAT_H #include #include "common.h" #include "hio.h" struct format_loader { const char *name; int (*const test)(HIO_HANDLE *, char *, const int); int (*const loader)(struct module_data *, HIO_HANDLE *, const int); }; char **format_list(void); #ifndef LIBXMP_CORE_PLAYER #define NUM_FORMATS 52 #define NUM_PW_FORMATS 43 int pw_test_format(HIO_HANDLE *, char *, const int, struct xmp_test_info *); #endif #endif libxmp-4.4.1/src/mixer.h0000664000175000017500000000456112775035311014735 0ustar claudioclaudio#ifndef LIBXMP_MIXER_H #define LIBXMP_MIXER_H #define C4_PERIOD 428.0 #define SMIX_NUMVOC 128 /* default number of softmixer voices */ #define SMIX_SHIFT 16 #define SMIX_MASK 0xffff #define FILTER_SHIFT 16 #define ANTICLICK_SHIFT 3 #ifdef LIBXMP_PAULA_SIMULATOR #include "paula.h" #endif #define MIXER(f) void libxmp_mix_##f(struct mixer_voice *vi, int *buffer, \ int count, int vl, int vr, int step, int ramp, int delta_l, int delta_r) struct mixer_voice { int chn; /* channel number */ int root; /* */ int note; /* */ #define PAN_SURROUND 0x8000 int pan; /* */ int vol; /* */ double period; /* current period */ double pos; /* position in sample */ int pos0; /* position in sample before mixing */ int fidx; /* mixer function index */ int ins; /* instrument number */ int smp; /* sample number */ int end; /* loop end */ int act; /* nna info & status of voice */ int old_vl; /* previous volume, left channel */ int old_vr; /* previous volume, right channel */ int sleft; /* last left sample output, in 32bit */ int sright; /* last right sample output, in 32bit */ #define VOICE_RELEASE (1 << 0) #define ANTICLICK (1 << 1) #define SAMPLE_LOOP (1 << 2) int flags; /* flags */ void *sptr; /* sample pointer */ #ifdef LIBXMP_PAULA_SIMULATOR struct paula_state *paula; /* paula simulation state */ #endif #ifndef LIBXMP_CORE_DISABLE_IT struct { int r1; /* filter variables */ int r2; int l1; int l2; int a0; int b0; int b1; int cutoff; int resonance; } filter; #endif }; int libxmp_mixer_on (struct context_data *, int, int, int); void libxmp_mixer_off (struct context_data *); void libxmp_mixer_setvol (struct context_data *, int, int); void libxmp_mixer_seteffect (struct context_data *, int, int, int); void libxmp_mixer_setpan (struct context_data *, int, int); int libxmp_mixer_numvoices (struct context_data *, int); void libxmp_mixer_softmixer (struct context_data *); void libxmp_mixer_reset (struct context_data *); void libxmp_mixer_setpatch (struct context_data *, int, int, int); void libxmp_mixer_voicepos (struct context_data *, int, double, int); double libxmp_mixer_getvoicepos(struct context_data *, int); void libxmp_mixer_setnote (struct context_data *, int, int); void libxmp_mixer_setperiod (struct context_data *, int, double); void libxmp_mixer_release (struct context_data *, int, int); #endif /* LIBXMP_MIXER_H */ libxmp-4.4.1/src/scan.c0000664000175000017500000003423312776471771014546 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* * Sun, 31 May 1998 17:50:02 -0600 * Reported by ToyKeeper : * For loop-prevention, I know a way to do it which lets most songs play * fine once through even if they have backward-jumps. Just keep a small * array (256 bytes, or even bits) of flags, each entry determining if a * pattern in the song order has been played. If you get to an entry which * is already non-zero, skip to the next song (assuming looping is off). */ /* * Tue, 6 Oct 1998 21:23:17 +0200 (CEST) * Reported by John v/d Kamp : * scan.c was hanging when it jumps to an invalid restart value. * (Fixed by hipolito) */ #include #include #include "common.h" #include "effects.h" #include "mixer.h" #define S3M_END 0xff #define S3M_SKIP 0xfe static int scan_module(struct context_data *ctx, int ep, int chain) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int parm, gvol_memory, f1, f2, p1, p2, ord, ord2; int row, last_row, break_row, row_count; int gvl, bpm, speed, base_time, chn; int frame_count; double time, start_time; int loop_chn, loop_num, inside_loop; int pdelay = 0; int loop_count[XMP_MAX_CHANNELS]; int loop_row[XMP_MAX_CHANNELS]; struct xmp_event* event; int i, pat; int has_marker; struct ord_data *info; #ifndef LIBXMP_CORE_PLAYER int st26_speed; #endif if (mod->len == 0) return 0; for (i = 0; i < mod->len; i++) { int pat = mod->xxo[i]; memset(m->scan_cnt[i], 0, pat >= mod->pat ? 1 : mod->xxp[pat]->rows ? mod->xxp[pat]->rows : 1); } for (i = 0; i < mod->chn; i++) { loop_count[i] = 0; loop_row[i] = -1; } loop_num = 0; loop_chn = -1; gvl = mod->gvl; bpm = mod->bpm; speed = mod->spd; base_time = m->rrate; #ifndef LIBXMP_CORE_PLAYER st26_speed = 0; #endif has_marker = HAS_QUIRK(QUIRK_MARKER); /* By erlk ozlr * * xmp doesn't handle really properly the "start" option (-s for the * command-line) for DeusEx's .umx files. These .umx files contain * several loop "tracks" that never join together. That's how they put * multiple musics on each level with a file per level. Each "track" * starts at the same order in all files. The problem is that xmp starts * decoding the module at order 0 and not at the order specified with * the start option. If we have a module that does "0 -> 2 -> 0 -> ...", * we cannot play order 1, even with the supposed right option. * * was: ord2 = ord = -1; * * CM: Fixed by using different "sequences" for each loop or subsong. * Each sequence has its entry point. Sequences don't overlap. */ ord2 = -1; ord = ep - 1; gvol_memory = break_row = row_count = frame_count = 0; start_time = time = 0.0; inside_loop = 0; while (42) { if ((uint32)++ord >= mod->len) { if (mod->rst > mod->len || mod->xxo[mod->rst] >= mod->pat) { ord = ep; } else { if (libxmp_get_sequence(ctx, mod->rst) == chain) { ord = mod->rst; } else { ord = ep; } } pat = mod->xxo[ord]; if (has_marker && pat == S3M_END) { break; } } pat = mod->xxo[ord]; info = &m->xxo_info[ord]; /* Allow more complex order reuse only in main sequence */ if (ep != 0 && p->sequence_control[ord] != 0xff) { break; } p->sequence_control[ord] = chain; /* All invalid patterns skipped, only S3M_END aborts replay */ if (pat >= mod->pat) { if (has_marker && pat == S3M_END) { ord = mod->len; continue; } continue; } if (break_row >= mod->xxp[pat]->rows) { break_row = 0; } /* Loops can cross pattern boundaries, so check if we're not looping */ if (m->scan_cnt[ord][break_row] && !inside_loop) { break; } /* Don't update pattern information if we're inside a loop, otherwise * a loop containing e.g. a global volume fade can make the pattern * start with the wrong volume. */ if (!inside_loop && info->gvl < 0) { info->gvl = gvl; info->bpm = bpm; info->speed = speed; info->time = time + m->time_factor * frame_count * base_time / bpm; #ifndef LIBXMP_CORE_PLAYER info->st26_speed = st26_speed; #endif } if (info->start_row == 0 && ord != 0) { if (ord == ep) { start_time = time + m->time_factor * frame_count * base_time / bpm; } info->start_row = break_row; } last_row = mod->xxp[pat]->rows; for (row = break_row, break_row = 0; row < last_row; row++, row_count++) { /* Prevent crashes caused by large softmixer frames */ if (bpm < XMP_MIN_BPM) { bpm = XMP_MIN_BPM; } /* Date: Sat, 8 Sep 2007 04:01:06 +0200 * Reported by Zbigniew Luszpinski * The scan routine falls into infinite looping and doesn't let * xmp play jos-dr4k.xm. * Claudio's workaround: we'll break infinite loops here. * * Date: Oct 27, 2007 8:05 PM * From: Adric Riedel * Jesper Kyd: Global Trash 3.mod (the 'Hardwired' theme) only * plays the first 4:41 of what should be a 10 minute piece. * (...) it dies at the end of position 2F */ if (row_count > 512) /* was 255, but Global trash goes to 318 */ goto end_module; if (!loop_num && m->scan_cnt[ord][row]) { row_count--; goto end_module; } m->scan_cnt[ord][row]++; pdelay = 0; for (chn = 0; chn < mod->chn; chn++) { if (row >= mod->xxt[mod->xxp[pat]->index[chn]]->rows) continue; event = &EVENT(mod->xxo[ord], chn, row); f1 = event->fxt; p1 = event->fxp; f2 = event->f2t; p2 = event->f2p; if (f1 == FX_GLOBALVOL || f2 == FX_GLOBALVOL) { gvl = (f1 == FX_GLOBALVOL) ? p1 : p2; gvl = gvl > m->gvolbase ? m->gvolbase : gvl < 0 ? 0 : gvl; } /* Process fine global volume slide */ if (f1 == FX_GVOL_SLIDE || f2 == FX_GVOL_SLIDE) { int h, l; parm = (f1 == FX_GVOL_SLIDE) ? p1 : p2; process_gvol: if (parm) { gvol_memory = parm; h = MSN(parm); l = LSN(parm); if (HAS_QUIRK(QUIRK_FINEFX)) { if (l == 0xf && h != 0) { gvl += h; } else if (h == 0xf && l != 0) { gvl -= l; } else { if (m->quirk & QUIRK_VSALL) { gvl += (h - l) * speed; } else { gvl += (h - l) * (speed - 1); } } } else { if (m->quirk & QUIRK_VSALL) { gvl += (h - l) * speed; } else { gvl += (h - l) * (speed - 1); } } } else { if ((parm = gvol_memory) != 0) goto process_gvol; } } if ((f1 == FX_SPEED && p1) || (f2 == FX_SPEED && p2)) { parm = (f1 == FX_SPEED) ? p1 : p2; frame_count += row_count * speed; row_count = 0; if (parm) { if (HAS_QUIRK(QUIRK_NOBPM) || p->flags & XMP_FLAGS_VBLANK || parm < 0x20) { if (parm > 0) { speed = parm; #ifndef LIBXMP_CORE_PLAYER st26_speed = 0; #endif } } else { time += m->time_factor * frame_count * base_time / bpm; frame_count = 0; bpm = parm; } } } #ifndef LIBXMP_CORE_PLAYER if (f1 == FX_SPEED_CP) { f1 = FX_S3M_SPEED; } if (f2 == FX_SPEED_CP) { f2 = FX_S3M_SPEED; } /* ST2.6 speed processing */ if (f1 == FX_ICE_SPEED && p1) { if (LSN(p1)) { st26_speed = (MSN(p1) << 8) | LSN(p1); } else { st26_speed = MSN(p1); } } #endif if ((f1 == FX_S3M_SPEED && p1) || (f2 == FX_S3M_SPEED && p2)) { parm = (f1 == FX_S3M_SPEED) ? p1 : p2; if (parm > 0) { frame_count += row_count * speed; row_count = 0; speed = parm; #ifndef LIBXMP_CORE_PLAYER st26_speed = 0; #endif } } if ((f1 == FX_S3M_BPM && p1) || (f2 == FX_S3M_BPM && p2)) { parm = (f1 == FX_S3M_BPM) ? p1 : p2; if (parm >= 0x20) { frame_count += row_count * speed; row_count = 0; time += m->time_factor * frame_count * base_time / bpm; frame_count = 0; bpm = parm; } } #ifndef LIBXMP_CORE_DISABLE_IT if ((f1 == FX_IT_BPM && p1) || (f2 == FX_IT_BPM && p2)) { parm = (f1 == FX_IT_BPM) ? p1 : p2; frame_count += row_count * speed; row_count = 0; time += m->time_factor * frame_count * base_time / bpm; frame_count = 0; if (MSN(parm) == 0) { time += m->time_factor * base_time / bpm; for (i = 1; i < speed; i++) { bpm -= LSN(parm); if (bpm < 0x20) bpm = 0x20; time += m->time_factor * base_time / bpm; } /* remove one row at final bpm */ time -= m->time_factor * speed * base_time / bpm; } else if (MSN(parm) == 1) { time += m->time_factor * base_time / bpm; for (i = 1; i < speed; i++) { bpm += LSN(parm); if (bpm > 0xff) bpm = 0xff; time += m->time_factor * base_time / bpm; } /* remove one row at final bpm */ time -= m->time_factor * speed * base_time / bpm; } else { bpm = parm; } } if (f1 == FX_IT_ROWDELAY) { m->scan_cnt[ord][row] += p1 & 0x0f; frame_count += (p1 & 0x0f) * speed; } if (f1 == FX_IT_BREAK) { break_row = p1; last_row = 0; } #endif if (f1 == FX_JUMP || f2 == FX_JUMP) { ord2 = (f1 == FX_JUMP) ? p1 : p2; break_row = 0; last_row = 0; /* prevent infinite loop, see OpenMPT PatLoop-Various.xm */ inside_loop = 0; } if (f1 == FX_BREAK || f2 == FX_BREAK) { parm = (f1 == FX_BREAK) ? p1 : p2; break_row = 10 * MSN(parm) + LSN(parm); last_row = 0; } if (f1 == FX_EXTENDED || f2 == FX_EXTENDED) { parm = (f1 == FX_EXTENDED) ? p1 : p2; if ((parm >> 4) == EX_PATT_DELAY) { if (m->read_event_type != READ_EVENT_ST3 || !pdelay) { pdelay = parm & 0x0f; frame_count += pdelay * speed; } } if ((parm >> 4) == EX_PATTERN_LOOP) { if (parm &= 0x0f) { /* Loop end */ if (loop_count[chn]) { if (--loop_count[chn]) { /* next iteraction */ loop_chn = chn; } else { /* finish looping */ loop_num--; inside_loop = 0; if (m->quirk & QUIRK_S3MLOOP) loop_row[chn] = row; } } else { loop_count[chn] = parm; loop_chn = chn; loop_num++; } } else { /* Loop start */ loop_row[chn] = row - 1; inside_loop = 1; if (HAS_QUIRK(QUIRK_FT2BUGS)) break_row = row; } } } } if (loop_chn >= 0) { row = loop_row[loop_chn]; loop_chn = -1; } #ifndef LIBXMP_CORE_PLAYER if (st26_speed) { frame_count += row_count * speed; row_count = 0; if (st26_speed & 0x10000) { speed = (st26_speed & 0xff00) >> 8; } else { speed = st26_speed & 0xff; } st26_speed ^= 0x10000; } #endif } if (break_row && pdelay) { break_row++; } if (ord2 >= 0) { ord = ord2 - 1; ord2 = -1; } frame_count += row_count * speed; row_count = 0; } row = break_row; end_module: /* Sanity check */ { pat = mod->xxo[ord]; if (pat >= mod->pat || row >= mod->xxp[pat]->rows) { row = 0; } } p->scan[chain].num = m->scan_cnt[ord][row]; p->scan[chain].row = row; p->scan[chain].ord = ord; time -= start_time; frame_count += row_count * speed; return (time + m->time_factor * frame_count * base_time / bpm); } int libxmp_get_sequence(struct context_data *ctx, int ord) { struct player_data *p = &ctx->p; return p->sequence_control[ord]; } int libxmp_scan_sequences(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int i, ep; int seq; unsigned char temp_ep[XMP_MAX_MOD_LENGTH]; /* Initialize order data to prevent overwrite when a position is used * multiple times at different starting points (see janosik.xm). */ for (i = 0; i < XMP_MAX_MOD_LENGTH; i++) { m->xxo_info[i].gvl = -1; } ep = 0; memset(p->sequence_control, 0xff, XMP_MAX_MOD_LENGTH); temp_ep[0] = 0; p->scan[0].time = scan_module(ctx, ep, 0); seq = 1; while (1) { /* Scan song starting at given entry point */ /* Check if any patterns left */ for (i = 0; i < mod->len; i++) { if (p->sequence_control[i] == 0xff) { break; } } if (i != mod->len && seq < MAX_SEQUENCES) { /* New entry point */ ep = i; temp_ep[seq] = ep; p->scan[seq].time = scan_module(ctx, ep, seq); if (p->scan[seq].time > 0) seq++; } else { break; } } m->num_sequences = seq; /* Now place entry points in the public accessible array */ for (i = 0; i < m->num_sequences; i++) { m->seq_data[i].entry_point = temp_ep[i]; m->seq_data[i].duration = p->scan[i].time; } return 0; } libxmp-4.4.1/src/hio.c0000664000175000017500000001513112773571316014366 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "common.h" #include "hio.h" #include "mdataio.h" static long get_size(FILE *f) { long size, pos; pos = ftell(f); if (pos >= 0) { if (fseek(f, 0, SEEK_END) < 0) { return -1; } size = ftell(f); if (fseek(f, pos, SEEK_SET) < 0) { return -1; } return size; } else { return pos; } } int8 hio_read8s(HIO_HANDLE *h) { int err; int8 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read8s(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread8s(h->handle.mem); break; } return ret; } uint8 hio_read8(HIO_HANDLE *h) { int err; uint8 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read8(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread8(h->handle.mem); break; } return ret; } uint16 hio_read16l(HIO_HANDLE *h) { int err; uint16 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read16l(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread16l(h->handle.mem); break; } return ret; } uint16 hio_read16b(HIO_HANDLE *h) { int err; uint16 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read16b(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread16b(h->handle.mem); break; } return ret; } uint32 hio_read24l(HIO_HANDLE *h) { int err; uint32 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read24l(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread24l(h->handle.mem); break; } return ret; } uint32 hio_read24b(HIO_HANDLE *h) { int err; uint32 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read24b(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread24b(h->handle.mem); break; } return ret; } uint32 hio_read32l(HIO_HANDLE *h) { int err; uint32 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read32l(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread32l(h->handle.mem); break; } return ret; } uint32 hio_read32b(HIO_HANDLE *h) { int err; uint32 ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = read32b(h->handle.file, &err); if (err != 0) { h->error = err; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread32b(h->handle.mem); } return ret; } size_t hio_read(void *buf, size_t size, size_t num, HIO_HANDLE *h) { size_t ret = 0; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = fread(buf, size, num, h->handle.file); if (ret != num) { if (ferror(h->handle.file)) { h->error = errno; } else { h->error = feof(h->handle.file) ? EOF : -2; } } break; case HIO_HANDLE_TYPE_MEMORY: ret = mread(buf, size, num, h->handle.mem); if (ret != num) { h->error = errno; } break; } return ret; } int hio_seek(HIO_HANDLE *h, long offset, int whence) { int ret = -1; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = fseek(h->handle.file, offset, whence); if (ret < 0) { h->error = errno; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mseek(h->handle.mem, offset, whence); if (ret < 0) { h->error = errno; } break; } return ret; } long hio_tell(HIO_HANDLE *h) { long ret = -1; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = ftell(h->handle.file); if (ret < 0) { h->error = errno; } break; case HIO_HANDLE_TYPE_MEMORY: ret = mtell(h->handle.mem); if (ret < 0) { h->error = errno; } break; } return ret; } int hio_eof(HIO_HANDLE *h) { switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: return feof(h->handle.file); case HIO_HANDLE_TYPE_MEMORY: return meof(h->handle.mem); default: return EOF; } } int hio_error(HIO_HANDLE *h) { int error = h->error; h->error = 0; return error; } HIO_HANDLE *hio_open(void *path, char *mode) { HIO_HANDLE *h; h = (HIO_HANDLE *)malloc(sizeof (HIO_HANDLE)); if (h == NULL) goto err; h->error = 0; h->type = HIO_HANDLE_TYPE_FILE; h->handle.file = fopen(path, mode); if (h->handle.file == NULL) goto err2; h->size = get_size(h->handle.file); if (h->size < 0) goto err3; return h; err3: fclose(h->handle.file); err2: free(h); err: return NULL; } HIO_HANDLE *hio_open_mem(void *ptr, long size) { HIO_HANDLE *h; h = (HIO_HANDLE *)malloc(sizeof (HIO_HANDLE)); if (h == NULL) return NULL; h->error = 0; h->type = HIO_HANDLE_TYPE_MEMORY; h->handle.mem = mopen(ptr, size); h->size = size; return h; } HIO_HANDLE *hio_open_file(FILE *f) { HIO_HANDLE *h; h = (HIO_HANDLE *)malloc(sizeof (HIO_HANDLE)); if (h == NULL) return NULL; h->error = 0; h->type = HIO_HANDLE_TYPE_FILE; h->handle.file = f /*fdopen(fileno(f), "rb")*/; h->size = get_size(f); return h; } int hio_close(HIO_HANDLE *h) { int ret; switch (HIO_HANDLE_TYPE(h)) { case HIO_HANDLE_TYPE_FILE: ret = fclose(h->handle.file); break; case HIO_HANDLE_TYPE_MEMORY: ret = mclose(h->handle.mem); break; default: ret = -1; } free(h); return ret; } long hio_size(HIO_HANDLE *h) { return h->size; } libxmp-4.4.1/src/precomp_lut.h0000664000175000017500000006432212773463510016147 0ustar claudioclaudiostatic int16 cubic_spline_lut0[1024] = { 0, -8, -16, -24, -32, -40, -47, -55, -63, -71, -78, -86, -94, -101, -109, -117, -124, -132, -139, -146, -154, -161, -169, -176, -183, -190, -198, -205, -212, -219, -226, -233, -240, -247, -254, -261, -268, -275, -282, -289, -295, -302, -309, -316, -322, -329, -336, -342, -349, -355, -362, -368, -375, -381, -388, -394, -400, -407, -413, -419, -425, -432, -438, -444, -450, -456, -462, -468, -474, -480, -486, -492, -498, -504, -510, -515, -521, -527, -533, -538, -544, -550, -555, -561, -566, -572, -577, -583, -588, -594, -599, -604, -610, -615, -620, -626, -631, -636, -641, -646, -651, -656, -662, -667, -672, -677, -682, -686, -691, -696, -701, -706, -711, -715, -720, -725, -730, -734, -739, -744, -748, -753, -757, -762, -766, -771, -775, -780, -784, -788, -793, -797, -801, -806, -810, -814, -818, -822, -826, -831, -835, -839, -843, -847, -851, -855, -859, -863, -866, -870, -874, -878, -882, -886, -889, -893, -897, -900, -904, -908, -911, -915, -918, -922, -925, -929, -932, -936, -939, -943, -946, -949, -953, -956, -959, -962, -966, -969, -972, -975, -978, -981, -984, -987, -991, -994, -997, -999, -1002, -1005, -1008, -1011, -1014, -1017, -1020, -1022, -1025, -1028, -1031, -1033, -1036, -1039, -1041, -1044, -1047, -1049, -1052, -1054, -1057, -1059, -1062, -1064, -1066, -1069, -1071, -1074, -1076, -1078, -1080, -1083, -1085, -1087, -1089, -1092, -1094, -1096, -1098, -1100, -1102, -1104, -1106, -1108, -1110, -1112, -1114, -1116, -1118, -1120, -1122, -1124, -1125, -1127, -1129, -1131, -1133, -1134, -1136, -1138, -1139, -1141, -1143, -1144, -1146, -1147, -1149, -1150, -1152, -1153, -1155, -1156, -1158, -1159, -1161, -1162, -1163, -1165, -1166, -1167, -1169, -1170, -1171, -1172, -1174, -1175, -1176, -1177, -1178, -1179, -1180, -1181, -1182, -1184, -1185, -1186, -1187, -1187, -1188, -1189, -1190, -1191, -1192, -1193, -1194, -1195, -1195, -1196, -1197, -1198, -1198, -1199, -1200, -1200, -1201, -1202, -1202, -1203, -1204, -1204, -1205, -1205, -1206, -1206, -1207, -1207, -1208, -1208, -1208, -1209, -1209, -1210, -1210, -1210, -1211, -1211, -1211, -1212, -1212, -1212, -1212, -1212, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1214, -1214, -1214, -1214, -1214, -1214, -1214, -1214, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1212, -1212, -1212, -1212, -1211, -1211, -1211, -1211, -1210, -1210, -1210, -1209, -1209, -1209, -1208, -1208, -1207, -1207, -1207, -1206, -1206, -1205, -1205, -1204, -1204, -1203, -1202, -1202, -1201, -1201, -1200, -1199, -1199, -1198, -1197, -1197, -1196, -1195, -1195, -1194, -1193, -1192, -1192, -1191, -1190, -1189, -1188, -1187, -1187, -1186, -1185, -1184, -1183, -1182, -1181, -1180, -1179, -1178, -1177, -1176, -1175, -1174, -1173, -1172, -1171, -1170, -1169, -1168, -1167, -1166, -1165, -1163, -1162, -1161, -1160, -1159, -1158, -1156, -1155, -1154, -1153, -1151, -1150, -1149, -1148, -1146, -1145, -1144, -1142, -1141, -1140, -1138, -1137, -1135, -1134, -1133, -1131, -1130, -1128, -1127, -1125, -1124, -1122, -1121, -1119, -1118, -1116, -1115, -1113, -1112, -1110, -1109, -1107, -1105, -1104, -1102, -1101, -1099, -1097, -1096, -1094, -1092, -1091, -1089, -1087, -1085, -1084, -1082, -1080, -1079, -1077, -1075, -1073, -1071, -1070, -1068, -1066, -1064, -1062, -1061, -1059, -1057, -1055, -1053, -1051, -1049, -1047, -1046, -1044, -1042, -1040, -1038, -1036, -1034, -1032, -1030, -1028, -1026, -1024, -1022, -1020, -1018, -1016, -1014, -1012, -1010, -1008, -1006, -1004, -1002, -999, -997, -995, -993, -991, -989, -987, -985, -982, -980, -978, -976, -974, -972, -969, -967, -965, -963, -961, -958, -956, -954, -952, -950, -947, -945, -943, -941, -938, -936, -934, -931, -929, -927, -924, -922, -920, -918, -915, -913, -911, -908, -906, -903, -901, -899, -896, -894, -892, -889, -887, -884, -882, -880, -877, -875, -872, -870, -867, -865, -863, -860, -858, -855, -853, -850, -848, -845, -843, -840, -838, -835, -833, -830, -828, -825, -823, -820, -818, -815, -813, -810, -808, -805, -803, -800, -798, -795, -793, -790, -787, -785, -782, -780, -777, -775, -772, -769, -767, -764, -762, -759, -757, -754, -751, -749, -746, -744, -741, -738, -736, -733, -730, -728, -725, -723, -720, -717, -715, -712, -709, -707, -704, -702, -699, -696, -694, -691, -688, -686, -683, -680, -678, -675, -672, -670, -667, -665, -662, -659, -657, -654, -651, -649, -646, -643, -641, -638, -635, -633, -630, -627, -625, -622, -619, -617, -614, -611, -609, -606, -603, -601, -598, -595, -593, -590, -587, -585, -582, -579, -577, -574, -571, -569, -566, -563, -561, -558, -555, -553, -550, -547, -545, -542, -539, -537, -534, -531, -529, -526, -523, -521, -518, -516, -513, -510, -508, -505, -502, -500, -497, -495, -492, -489, -487, -484, -481, -479, -476, -474, -471, -468, -466, -463, -461, -458, -455, -453, -450, -448, -445, -442, -440, -437, -435, -432, -430, -427, -424, -422, -419, -417, -414, -412, -409, -407, -404, -402, -399, -397, -394, -392, -389, -387, -384, -382, -379, -377, -374, -372, -369, -367, -364, -362, -359, -357, -354, -352, -349, -347, -345, -342, -340, -337, -335, -332, -330, -328, -325, -323, -320, -318, -316, -313, -311, -309, -306, -304, -302, -299, -297, -295, -292, -290, -288, -285, -283, -281, -278, -276, -274, -272, -269, -267, -265, -263, -260, -258, -256, -254, -251, -249, -247, -245, -243, -240, -238, -236, -234, -232, -230, -228, -225, -223, -221, -219, -217, -215, -213, -211, -209, -207, -205, -202, -200, -198, -196, -194, -192, -190, -188, -186, -184, -182, -180, -178, -176, -175, -173, -171, -169, -167, -165, -163, -161, -159, -157, -156, -154, -152, -150, -148, -146, -145, -143, -141, -139, -137, -136, -134, -132, -130, -129, -127, -125, -124, -122, -120, -119, -117, -115, -114, -112, -110, -109, -107, -106, -104, -102, -101, -99, -98, -96, -95, -93, -92, -90, -89, -87, -86, -84, -83, -82, -80, -79, -77, -76, -75, -73, -72, -70, -69, -68, -67, -65, -64, -63, -61, -60, -59, -58, -57, -55, -54, -53, -52, -51, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -26, -25, -24, -23, -22, -22, -21, -20, -19, -19, -18, -17, -16, -16, -15, -14, -14, -13, -13, -12, -11, -11, -10, -10, -9, -9, -8, -8, -7, -7, -6, -6, -6, -5, -5, -4, -4, -4, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, }; static int16 cubic_spline_lut1[1024] = { 16384, 16384, 16384, 16384, 16384, 16383, 16382, 16381, 16381, 16381, 16380, 16379, 16379, 16377, 16377, 16376, 16374, 16373, 16371, 16370, 16369, 16366, 16366, 16364, 16361, 16360, 16358, 16357, 16354, 16351, 16349, 16347, 16345, 16342, 16340, 16337, 16335, 16331, 16329, 16326, 16322, 16320, 16317, 16314, 16309, 16307, 16304, 16299, 16297, 16293, 16290, 16285, 16282, 16278, 16274, 16269, 16265, 16262, 16257, 16253, 16247, 16244, 16239, 16235, 16230, 16225, 16220, 16216, 16211, 16206, 16201, 16196, 16191, 16185, 16180, 16174, 16169, 16163, 16158, 16151, 16146, 16140, 16133, 16128, 16122, 16116, 16109, 16104, 16097, 16092, 16085, 16077, 16071, 16064, 16058, 16052, 16044, 16038, 16030, 16023, 16015, 16009, 16002, 15995, 15988, 15980, 15973, 15964, 15957, 15949, 15941, 15934, 15926, 15918, 15910, 15903, 15894, 15886, 15877, 15870, 15861, 15853, 15843, 15836, 15827, 15818, 15810, 15801, 15792, 15783, 15774, 15765, 15756, 15747, 15738, 15729, 15719, 15709, 15700, 15691, 15681, 15672, 15662, 15652, 15642, 15633, 15623, 15613, 15602, 15592, 15582, 15572, 15562, 15552, 15540, 15530, 15520, 15509, 15499, 15489, 15478, 15467, 15456, 15446, 15433, 15423, 15412, 15401, 15390, 15379, 15367, 15356, 15345, 15333, 15321, 15310, 15299, 15287, 15276, 15264, 15252, 15240, 15228, 15216, 15205, 15192, 15180, 15167, 15155, 15143, 15131, 15118, 15106, 15094, 15081, 15067, 15056, 15043, 15031, 15017, 15004, 14992, 14979, 14966, 14953, 14940, 14927, 14913, 14900, 14887, 14874, 14860, 14846, 14833, 14819, 14806, 14793, 14778, 14764, 14752, 14737, 14723, 14709, 14696, 14681, 14668, 14653, 14638, 14625, 14610, 14595, 14582, 14567, 14553, 14538, 14523, 14509, 14494, 14480, 14465, 14450, 14435, 14420, 14406, 14391, 14376, 14361, 14346, 14330, 14316, 14301, 14285, 14270, 14254, 14239, 14223, 14208, 14192, 14177, 14161, 14146, 14130, 14115, 14099, 14082, 14067, 14051, 14035, 14019, 14003, 13986, 13971, 13955, 13939, 13923, 13906, 13890, 13873, 13857, 13840, 13823, 13808, 13791, 13775, 13758, 13741, 13724, 13707, 13691, 13673, 13657, 13641, 13623, 13607, 13589, 13572, 13556, 13538, 13521, 13504, 13486, 13469, 13451, 13435, 13417, 13399, 13383, 13365, 13347, 13330, 13312, 13294, 13277, 13258, 13241, 13224, 13205, 13188, 13170, 13152, 13134, 13116, 13098, 13080, 13062, 13044, 13026, 13008, 12989, 12971, 12953, 12934, 12916, 12898, 12879, 12860, 12842, 12823, 12806, 12787, 12768, 12750, 12731, 12712, 12694, 12675, 12655, 12637, 12618, 12599, 12580, 12562, 12542, 12524, 12504, 12485, 12466, 12448, 12427, 12408, 12390, 12370, 12351, 12332, 12312, 12293, 12273, 12254, 12235, 12215, 12195, 12176, 12157, 12137, 12118, 12097, 12079, 12059, 12039, 12019, 11998, 11980, 11960, 11940, 11920, 11900, 11880, 11860, 11839, 11821, 11801, 11780, 11761, 11741, 11720, 11700, 11680, 11660, 11640, 11619, 11599, 11578, 11559, 11538, 11518, 11498, 11477, 11457, 11436, 11415, 11394, 11374, 11354, 11333, 11313, 11292, 11272, 11251, 11231, 11209, 11189, 11168, 11148, 11127, 11107, 11084, 11064, 11043, 11023, 11002, 10982, 10959, 10939, 10918, 10898, 10876, 10856, 10834, 10814, 10792, 10772, 10750, 10728, 10708, 10687, 10666, 10644, 10623, 10602, 10581, 10560, 10538, 10517, 10496, 10474, 10453, 10431, 10410, 10389, 10368, 10346, 10325, 10303, 10283, 10260, 10239, 10217, 10196, 10175, 10152, 10132, 10110, 10088, 10068, 10045, 10023, 10002, 9981, 9959, 9936, 9915, 9893, 9872, 9851, 9829, 9806, 9784, 9763, 9742, 9720, 9698, 9676, 9653, 9633, 9611, 9589, 9567, 9545, 9523, 9501, 9479, 9458, 9436, 9414, 9392, 9370, 9348, 9326, 9304, 9282, 9260, 9238, 9216, 9194, 9172, 9150, 9128, 9106, 9084, 9062, 9040, 9018, 8996, 8974, 8951, 8929, 8907, 8885, 8863, 8841, 8819, 8797, 8775, 8752, 8730, 8708, 8686, 8664, 8642, 8620, 8597, 8575, 8553, 8531, 8509, 8487, 8464, 8442, 8420, 8398, 8376, 8353, 8331, 8309, 8287, 8265, 8242, 8220, 8198, 8176, 8154, 8131, 8109, 8087, 8065, 8042, 8020, 7998, 7976, 7954, 7931, 7909, 7887, 7865, 7842, 7820, 7798, 7776, 7754, 7731, 7709, 7687, 7665, 7643, 7620, 7598, 7576, 7554, 7531, 7509, 7487, 7465, 7443, 7421, 7398, 7376, 7354, 7332, 7310, 7288, 7265, 7243, 7221, 7199, 7177, 7155, 7132, 7110, 7088, 7066, 7044, 7022, 7000, 6978, 6956, 6934, 6911, 6889, 6867, 6845, 6823, 6801, 6779, 6757, 6735, 6713, 6691, 6669, 6647, 6625, 6603, 6581, 6559, 6537, 6515, 6493, 6472, 6450, 6428, 6406, 6384, 6362, 6340, 6318, 6297, 6275, 6253, 6231, 6209, 6188, 6166, 6144, 6122, 6101, 6079, 6057, 6035, 6014, 5992, 5970, 5949, 5927, 5905, 5884, 5862, 5841, 5819, 5797, 5776, 5754, 5733, 5711, 5690, 5668, 5647, 5625, 5604, 5582, 5561, 5540, 5518, 5497, 5476, 5454, 5433, 5412, 5390, 5369, 5348, 5327, 5305, 5284, 5263, 5242, 5221, 5199, 5178, 5157, 5136, 5115, 5094, 5073, 5052, 5031, 5010, 4989, 4968, 4947, 4926, 4905, 4885, 4864, 4843, 4822, 4801, 4780, 4760, 4739, 4718, 4698, 4677, 4656, 4636, 4615, 4595, 4574, 4553, 4533, 4512, 4492, 4471, 4451, 4431, 4410, 4390, 4370, 4349, 4329, 4309, 4288, 4268, 4248, 4228, 4208, 4188, 4167, 4147, 4127, 4107, 4087, 4067, 4047, 4027, 4007, 3988, 3968, 3948, 3928, 3908, 3889, 3869, 3849, 3829, 3810, 3790, 3771, 3751, 3732, 3712, 3693, 3673, 3654, 3634, 3615, 3595, 3576, 3557, 3538, 3518, 3499, 3480, 3461, 3442, 3423, 3404, 3385, 3366, 3347, 3328, 3309, 3290, 3271, 3252, 3233, 3215, 3196, 3177, 3159, 3140, 3121, 3103, 3084, 3066, 3047, 3029, 3010, 2992, 2974, 2955, 2937, 2919, 2901, 2882, 2864, 2846, 2828, 2810, 2792, 2774, 2756, 2738, 2720, 2702, 2685, 2667, 2649, 2631, 2614, 2596, 2579, 2561, 2543, 2526, 2509, 2491, 2474, 2456, 2439, 2422, 2405, 2387, 2370, 2353, 2336, 2319, 2302, 2285, 2268, 2251, 2234, 2218, 2201, 2184, 2167, 2151, 2134, 2117, 2101, 2084, 2068, 2052, 2035, 2019, 2003, 1986, 1970, 1954, 1938, 1922, 1906, 1890, 1874, 1858, 1842, 1826, 1810, 1794, 1779, 1763, 1747, 1732, 1716, 1701, 1685, 1670, 1654, 1639, 1624, 1608, 1593, 1578, 1563, 1548, 1533, 1518, 1503, 1488, 1473, 1458, 1444, 1429, 1414, 1400, 1385, 1370, 1356, 1342, 1327, 1313, 1298, 1284, 1270, 1256, 1242, 1228, 1214, 1200, 1186, 1172, 1158, 1144, 1131, 1117, 1103, 1090, 1076, 1063, 1049, 1036, 1022, 1009, 996, 983, 970, 956, 943, 930, 917, 905, 892, 879, 866, 854, 841, 828, 816, 803, 791, 778, 766, 754, 742, 729, 717, 705, 693, 681, 669, 658, 646, 634, 622, 611, 599, 588, 576, 565, 553, 542, 531, 520, 508, 497, 486, 475, 464, 453, 443, 432, 421, 411, 400, 389, 379, 369, 358, 348, 338, 327, 317, 307, 297, 287, 277, 268, 258, 248, 238, 229, 219, 210, 200, 191, 182, 172, 163, 154, 145, 136, 127, 118, 109, 100, 92, 83, 75, 66, 58, 49, 41, 32, 24, 16, 8, }; static int16 cubic_spline_lut2[1024] = { 0, 8, 16, 24, 32, 41, 49, 58, 66, 75, 83, 92, 100, 109, 118, 127, 136, 145, 154, 163, 172, 182, 191, 200, 210, 219, 229, 238, 248, 258, 268, 277, 287, 297, 307, 317, 327, 338, 348, 358, 369, 379, 389, 400, 411, 421, 432, 443, 453, 464, 475, 486, 497, 508, 520, 531, 542, 553, 565, 576, 588, 599, 611, 622, 634, 646, 658, 669, 681, 693, 705, 717, 729, 742, 754, 766, 778, 791, 803, 816, 828, 841, 854, 866, 879, 892, 905, 917, 930, 943, 956, 970, 983, 996, 1009, 1022, 1036, 1049, 1063, 1076, 1090, 1103, 1117, 1131, 1144, 1158, 1172, 1186, 1200, 1214, 1228, 1242, 1256, 1270, 1284, 1298, 1313, 1327, 1342, 1356, 1370, 1385, 1400, 1414, 1429, 1444, 1458, 1473, 1488, 1503, 1518, 1533, 1548, 1563, 1578, 1593, 1608, 1624, 1639, 1654, 1670, 1685, 1701, 1716, 1732, 1747, 1763, 1779, 1794, 1810, 1826, 1842, 1858, 1874, 1890, 1906, 1922, 1938, 1954, 1970, 1986, 2003, 2019, 2035, 2052, 2068, 2084, 2101, 2117, 2134, 2151, 2167, 2184, 2201, 2218, 2234, 2251, 2268, 2285, 2302, 2319, 2336, 2353, 2370, 2387, 2405, 2422, 2439, 2456, 2474, 2491, 2509, 2526, 2543, 2561, 2579, 2596, 2614, 2631, 2649, 2667, 2685, 2702, 2720, 2738, 2756, 2774, 2792, 2810, 2828, 2846, 2864, 2882, 2901, 2919, 2937, 2955, 2974, 2992, 3010, 3029, 3047, 3066, 3084, 3103, 3121, 3140, 3159, 3177, 3196, 3215, 3233, 3252, 3271, 3290, 3309, 3328, 3347, 3366, 3385, 3404, 3423, 3442, 3461, 3480, 3499, 3518, 3538, 3557, 3576, 3595, 3615, 3634, 3654, 3673, 3693, 3712, 3732, 3751, 3771, 3790, 3810, 3829, 3849, 3869, 3889, 3908, 3928, 3948, 3968, 3988, 4007, 4027, 4047, 4067, 4087, 4107, 4127, 4147, 4167, 4188, 4208, 4228, 4248, 4268, 4288, 4309, 4329, 4349, 4370, 4390, 4410, 4431, 4451, 4471, 4492, 4512, 4533, 4553, 4574, 4595, 4615, 4636, 4656, 4677, 4698, 4718, 4739, 4760, 4780, 4801, 4822, 4843, 4864, 4885, 4905, 4926, 4947, 4968, 4989, 5010, 5031, 5052, 5073, 5094, 5115, 5136, 5157, 5178, 5199, 5221, 5242, 5263, 5284, 5305, 5327, 5348, 5369, 5390, 5412, 5433, 5454, 5476, 5497, 5518, 5540, 5561, 5582, 5604, 5625, 5647, 5668, 5690, 5711, 5733, 5754, 5776, 5797, 5819, 5841, 5862, 5884, 5905, 5927, 5949, 5970, 5992, 6014, 6035, 6057, 6079, 6101, 6122, 6144, 6166, 6188, 6209, 6231, 6253, 6275, 6297, 6318, 6340, 6362, 6384, 6406, 6428, 6450, 6472, 6493, 6515, 6537, 6559, 6581, 6603, 6625, 6647, 6669, 6691, 6713, 6735, 6757, 6779, 6801, 6823, 6845, 6867, 6889, 6911, 6934, 6956, 6978, 7000, 7022, 7044, 7066, 7088, 7110, 7132, 7155, 7177, 7199, 7221, 7243, 7265, 7288, 7310, 7332, 7354, 7376, 7398, 7421, 7443, 7465, 7487, 7509, 7531, 7554, 7576, 7598, 7620, 7643, 7665, 7687, 7709, 7731, 7754, 7776, 7798, 7820, 7842, 7865, 7887, 7909, 7931, 7954, 7976, 7998, 8020, 8042, 8065, 8087, 8109, 8131, 8154, 8176, 8198, 8220, 8242, 8265, 8287, 8309, 8331, 8353, 8376, 8398, 8420, 8442, 8464, 8487, 8509, 8531, 8553, 8575, 8597, 8620, 8642, 8664, 8686, 8708, 8730, 8752, 8775, 8797, 8819, 8841, 8863, 8885, 8907, 8929, 8951, 8974, 8996, 9018, 9040, 9062, 9084, 9106, 9128, 9150, 9172, 9194, 9216, 9238, 9260, 9282, 9304, 9326, 9348, 9370, 9392, 9414, 9436, 9458, 9479, 9501, 9523, 9545, 9567, 9589, 9611, 9633, 9653, 9676, 9698, 9720, 9742, 9763, 9784, 9806, 9829, 9851, 9872, 9893, 9915, 9936, 9959, 9981, 10002, 10023, 10045, 10068, 10088, 10110, 10132, 10152, 10175, 10196, 10217, 10239, 10260, 10283, 10303, 10325, 10346, 10368, 10389, 10410, 10431, 10453, 10474, 10496, 10517, 10538, 10560, 10581, 10602, 10623, 10644, 10666, 10687, 10708, 10728, 10750, 10772, 10792, 10814, 10834, 10856, 10876, 10898, 10918, 10939, 10959, 10982, 11002, 11023, 11043, 11064, 11084, 11107, 11127, 11148, 11168, 11189, 11209, 11231, 11251, 11272, 11292, 11313, 11333, 11354, 11374, 11394, 11415, 11436, 11457, 11477, 11498, 11518, 11538, 11559, 11578, 11599, 11619, 11640, 11660, 11680, 11700, 11720, 11741, 11761, 11780, 11801, 11821, 11839, 11860, 11880, 11900, 11920, 11940, 11960, 11980, 11998, 12019, 12039, 12059, 12079, 12097, 12118, 12137, 12157, 12176, 12195, 12215, 12235, 12254, 12273, 12293, 12312, 12332, 12351, 12370, 12390, 12408, 12427, 12448, 12466, 12485, 12504, 12524, 12542, 12562, 12580, 12599, 12618, 12637, 12655, 12675, 12694, 12712, 12731, 12750, 12768, 12787, 12806, 12823, 12842, 12860, 12879, 12898, 12916, 12934, 12953, 12971, 12989, 13008, 13026, 13044, 13062, 13080, 13098, 13116, 13134, 13152, 13170, 13188, 13205, 13224, 13241, 13258, 13277, 13294, 13312, 13330, 13347, 13365, 13383, 13399, 13417, 13435, 13451, 13469, 13486, 13504, 13521, 13538, 13556, 13572, 13589, 13607, 13623, 13641, 13657, 13673, 13691, 13707, 13724, 13741, 13758, 13775, 13791, 13808, 13823, 13840, 13857, 13873, 13890, 13906, 13923, 13939, 13955, 13971, 13986, 14003, 14019, 14035, 14051, 14067, 14082, 14099, 14115, 14130, 14146, 14161, 14177, 14192, 14208, 14223, 14239, 14254, 14270, 14285, 14301, 14316, 14330, 14346, 14361, 14376, 14391, 14406, 14420, 14435, 14450, 14465, 14480, 14494, 14509, 14523, 14538, 14553, 14567, 14582, 14595, 14610, 14625, 14638, 14653, 14668, 14681, 14696, 14709, 14723, 14737, 14752, 14764, 14778, 14793, 14806, 14819, 14833, 14846, 14860, 14874, 14887, 14900, 14913, 14927, 14940, 14953, 14966, 14979, 14992, 15004, 15017, 15031, 15043, 15056, 15067, 15081, 15094, 15106, 15118, 15131, 15143, 15155, 15167, 15180, 15192, 15205, 15216, 15228, 15240, 15252, 15264, 15276, 15287, 15299, 15310, 15321, 15333, 15345, 15356, 15367, 15379, 15390, 15401, 15412, 15423, 15433, 15446, 15456, 15467, 15478, 15489, 15499, 15509, 15520, 15530, 15540, 15552, 15562, 15572, 15582, 15592, 15602, 15613, 15623, 15633, 15642, 15652, 15662, 15672, 15681, 15691, 15700, 15709, 15719, 15729, 15738, 15747, 15756, 15765, 15774, 15783, 15792, 15801, 15810, 15818, 15827, 15836, 15843, 15853, 15861, 15870, 15877, 15886, 15894, 15903, 15910, 15918, 15926, 15934, 15941, 15949, 15957, 15964, 15973, 15980, 15988, 15995, 16002, 16009, 16015, 16023, 16030, 16038, 16044, 16052, 16058, 16064, 16071, 16077, 16085, 16092, 16097, 16104, 16109, 16116, 16122, 16128, 16133, 16140, 16146, 16151, 16158, 16163, 16169, 16174, 16180, 16185, 16191, 16196, 16201, 16206, 16211, 16216, 16220, 16225, 16230, 16235, 16239, 16244, 16247, 16253, 16257, 16262, 16265, 16269, 16274, 16278, 16282, 16285, 16290, 16293, 16297, 16299, 16304, 16307, 16309, 16314, 16317, 16320, 16322, 16326, 16329, 16331, 16335, 16337, 16340, 16342, 16345, 16347, 16349, 16351, 16354, 16357, 16358, 16360, 16361, 16364, 16366, 16366, 16369, 16370, 16371, 16373, 16374, 16376, 16377, 16377, 16379, 16379, 16380, 16381, 16381, 16381, 16382, 16383, 16384, 16384, 16384, 16384, }; static int16 cubic_spline_lut3[1024] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -4, -4, -4, -5, -5, -6, -6, -6, -7, -7, -8, -8, -9, -9, -10, -10, -11, -11, -12, -13, -13, -14, -14, -15, -16, -16, -17, -18, -19, -19, -20, -21, -22, -22, -23, -24, -25, -26, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -51, -52, -53, -54, -55, -57, -58, -59, -60, -61, -63, -64, -65, -67, -68, -69, -70, -72, -73, -75, -76, -77, -79, -80, -82, -83, -84, -86, -87, -89, -90, -92, -93, -95, -96, -98, -99, -101, -102, -104, -106, -107, -109, -110, -112, -114, -115, -117, -119, -120, -122, -124, -125, -127, -129, -130, -132, -134, -136, -137, -139, -141, -143, -145, -146, -148, -150, -152, -154, -156, -157, -159, -161, -163, -165, -167, -169, -171, -173, -175, -176, -178, -180, -182, -184, -186, -188, -190, -192, -194, -196, -198, -200, -202, -205, -207, -209, -211, -213, -215, -217, -219, -221, -223, -225, -228, -230, -232, -234, -236, -238, -240, -243, -245, -247, -249, -251, -254, -256, -258, -260, -263, -265, -267, -269, -272, -274, -276, -278, -281, -283, -285, -288, -290, -292, -295, -297, -299, -302, -304, -306, -309, -311, -313, -316, -318, -320, -323, -325, -328, -330, -332, -335, -337, -340, -342, -345, -347, -349, -352, -354, -357, -359, -362, -364, -367, -369, -372, -374, -377, -379, -382, -384, -387, -389, -392, -394, -397, -399, -402, -404, -407, -409, -412, -414, -417, -419, -422, -424, -427, -430, -432, -435, -437, -440, -442, -445, -448, -450, -453, -455, -458, -461, -463, -466, -468, -471, -474, -476, -479, -481, -484, -487, -489, -492, -495, -497, -500, -502, -505, -508, -510, -513, -516, -518, -521, -523, -526, -529, -531, -534, -537, -539, -542, -545, -547, -550, -553, -555, -558, -561, -563, -566, -569, -571, -574, -577, -579, -582, -585, -587, -590, -593, -595, -598, -601, -603, -606, -609, -611, -614, -617, -619, -622, -625, -627, -630, -633, -635, -638, -641, -643, -646, -649, -651, -654, -657, -659, -662, -665, -667, -670, -672, -675, -678, -680, -683, -686, -688, -691, -694, -696, -699, -702, -704, -707, -709, -712, -715, -717, -720, -723, -725, -728, -730, -733, -736, -738, -741, -744, -746, -749, -751, -754, -757, -759, -762, -764, -767, -769, -772, -775, -777, -780, -782, -785, -787, -790, -793, -795, -798, -800, -803, -805, -808, -810, -813, -815, -818, -820, -823, -825, -828, -830, -833, -835, -838, -840, -843, -845, -848, -850, -853, -855, -858, -860, -863, -865, -867, -870, -872, -875, -877, -880, -882, -884, -887, -889, -892, -894, -896, -899, -901, -903, -906, -908, -911, -913, -915, -918, -920, -922, -924, -927, -929, -931, -934, -936, -938, -941, -943, -945, -947, -950, -952, -954, -956, -958, -961, -963, -965, -967, -969, -972, -974, -976, -978, -980, -982, -985, -987, -989, -991, -993, -995, -997, -999, -1002, -1004, -1006, -1008, -1010, -1012, -1014, -1016, -1018, -1020, -1022, -1024, -1026, -1028, -1030, -1032, -1034, -1036, -1038, -1040, -1042, -1044, -1046, -1047, -1049, -1051, -1053, -1055, -1057, -1059, -1061, -1062, -1064, -1066, -1068, -1070, -1071, -1073, -1075, -1077, -1079, -1080, -1082, -1084, -1085, -1087, -1089, -1091, -1092, -1094, -1096, -1097, -1099, -1101, -1102, -1104, -1105, -1107, -1109, -1110, -1112, -1113, -1115, -1116, -1118, -1119, -1121, -1122, -1124, -1125, -1127, -1128, -1130, -1131, -1133, -1134, -1135, -1137, -1138, -1140, -1141, -1142, -1144, -1145, -1146, -1148, -1149, -1150, -1151, -1153, -1154, -1155, -1156, -1158, -1159, -1160, -1161, -1162, -1163, -1165, -1166, -1167, -1168, -1169, -1170, -1171, -1172, -1173, -1174, -1175, -1176, -1177, -1178, -1179, -1180, -1181, -1182, -1183, -1184, -1185, -1186, -1187, -1187, -1188, -1189, -1190, -1191, -1192, -1192, -1193, -1194, -1195, -1195, -1196, -1197, -1197, -1198, -1199, -1199, -1200, -1201, -1201, -1202, -1202, -1203, -1204, -1204, -1205, -1205, -1206, -1206, -1207, -1207, -1207, -1208, -1208, -1209, -1209, -1209, -1210, -1210, -1210, -1211, -1211, -1211, -1211, -1212, -1212, -1212, -1212, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1214, -1214, -1214, -1214, -1214, -1214, -1214, -1214, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1213, -1212, -1212, -1212, -1212, -1212, -1211, -1211, -1211, -1210, -1210, -1210, -1209, -1209, -1208, -1208, -1208, -1207, -1207, -1206, -1206, -1205, -1205, -1204, -1204, -1203, -1202, -1202, -1201, -1200, -1200, -1199, -1198, -1198, -1197, -1196, -1195, -1195, -1194, -1193, -1192, -1191, -1190, -1189, -1188, -1187, -1187, -1186, -1185, -1184, -1182, -1181, -1180, -1179, -1178, -1177, -1176, -1175, -1174, -1172, -1171, -1170, -1169, -1167, -1166, -1165, -1163, -1162, -1161, -1159, -1158, -1156, -1155, -1153, -1152, -1150, -1149, -1147, -1146, -1144, -1143, -1141, -1139, -1138, -1136, -1134, -1133, -1131, -1129, -1127, -1125, -1124, -1122, -1120, -1118, -1116, -1114, -1112, -1110, -1108, -1106, -1104, -1102, -1100, -1098, -1096, -1094, -1092, -1089, -1087, -1085, -1083, -1080, -1078, -1076, -1074, -1071, -1069, -1066, -1064, -1062, -1059, -1057, -1054, -1052, -1049, -1047, -1044, -1041, -1039, -1036, -1033, -1031, -1028, -1025, -1022, -1020, -1017, -1014, -1011, -1008, -1005, -1002, -999, -997, -994, -991, -987, -984, -981, -978, -975, -972, -969, -966, -962, -959, -956, -953, -949, -946, -943, -939, -936, -932, -929, -925, -922, -918, -915, -911, -908, -904, -900, -897, -893, -889, -886, -882, -878, -874, -870, -866, -863, -859, -855, -851, -847, -843, -839, -835, -831, -826, -822, -818, -814, -810, -806, -801, -797, -793, -788, -784, -780, -775, -771, -766, -762, -757, -753, -748, -744, -739, -734, -730, -725, -720, -715, -711, -706, -701, -696, -691, -686, -682, -677, -672, -667, -662, -656, -651, -646, -641, -636, -631, -626, -620, -615, -610, -604, -599, -594, -588, -583, -577, -572, -566, -561, -555, -550, -544, -538, -533, -527, -521, -515, -510, -504, -498, -492, -486, -480, -474, -468, -462, -456, -450, -444, -438, -432, -425, -419, -413, -407, -400, -394, -388, -381, -375, -368, -362, -355, -349, -342, -336, -329, -322, -316, -309, -302, -295, -289, -282, -275, -268, -261, -254, -247, -240, -233, -226, -219, -212, -205, -198, -190, -183, -176, -169, -161, -154, -146, -139, -132, -124, -117, -109, -101, -94, -86, -78, -71, -63, -55, -47, -40, -32, -24, -16, -8, }; libxmp-4.4.1/src/precomp_blep.h0000664000175000017500000005010012773463510016252 0ustar claudioclaudio /* * Table generated by compute-blep.py (a1200 and vanilla tables removed) */ /* tables are: a500 off, a500 on */ const int winsinc_integral[2][2048] = { { 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131071,131071, 131071,131071,131071,131071,131071,131071,131071,131071,131071,131070,131070,131070, 131070,131070,131069,131069,131069,131068,131068,131068,131067,131067,131066,131066, 131065,131065,131064,131063,131063,131062,131061,131060,131059,131058,131056,131055, 131054,131052,131050,131049,131047,131045,131043,131040,131038,131035,131033,131030, 131026,131023,131020,131016,131012,131008,131003,130998,130993,130988,130982,130976, 130970,130963,130956,130949,130941,130932,130924,130914,130905,130895,130884,130872, 130861,130848,130835,130821,130807,130792,130776,130759,130742,130724,130705,130685, 130664,130642,130620,130596,130571,130545,130518,130490,130461,130430,130398,130365, 130331,130295,130257,130219,130178,130136,130093,130047,130000,129951,129901,129848, 129794,129737,129679,129618,129555,129490,129423,129353,129281,129207,129130,129050, 128968,128883,128795,128704,128611,128514,128415,128312,128206,128097,127985,127869, 127750,127627,127501,127371,127237,127100,126959,126813,126664,126510,126353,126191, 126025,125854,125679,125499,125315,125126,124933,124734,124531,124323,124110,123891, 123668,123439,123205,122965,122720,122470,122214,121952,121685,121412,121133,120849, 120558,120261,119959,119650,119335,119014,118687,118354,118014,117668,117315,116956, 116591,116219,115840,115455,115063,114665,114260,113849,113430,113005,112574,112135, 111690,111239,110780,110315,109843,109364,108879,108387,107888,107383,106871,106352, 105827,105295,104757,104212,103661,103104,102540,101970,101394,100812,100223,99629, 99028,98422,97810,97192,96568,95939,95305,94665,94020,93370,92714,92054,91389,90719, 90045,89366,88682,87995,87303,86607,85908,85205,84498,83788,83075,82358,81639,80916, 80191,79464,78734,78002,77268,76533,75795,75056,74316,73575,72833,72090,71346,70602, 69858,69114,68370,67626,66883,66140,65399,64658,63919,63181,62445,61711,60979,60249, 59521,58796,58074,57355,56639,55926,55217,54512,53810,53113,52419,51731,51046,50367, 49693,49023,48359,47701,47048,46400,45759,45124,44495,43872,43256,42646,42043,41447, 40858,40276,39702,39134,38575,38023,37478,36941,36413,35892,35379,34874,34378,33890, 33410,32938,32475,32020,31574,31137,30708,30288,29876,29473,29079,28693,28317,27948, 27589,27238,26896,26562,26238,25921,25613,25314,25023,24740,24466,24200,23942,23692, 23451,23217,22991,22773,22562,22359,22164,21975,21794,21621,21454,21294,21140,20994, 20853,20719,20592,20470,20354,20244,20139,20040,19946,19857,19774,19694,19620,19550, 19484,19422,19364,19310,19260,19213,19169,19128,19090,19054,19022,18991,18963,18936, 18912,18889,18867,18847,18828,18810,18792,18776,18759,18743,18727,18711,18695,18679, 18662,18644,18626,18607,18587,18565,18542,18518,18492,18465,18436,18404,18371,18336, 18298,18259,18216,18172,18124,18074,18022,17966,17908,17847,17783,17716,17646,17572, 17496,17416,17334,17248,17159,17066,16971,16872,16770,16664,16556,16444,16329,16211, 16090,15966,15839,15709,15576,15440,15301,15159,15015,14868,14718,14566,14412,14255, 14096,13935,13771,13606,13439,13270,13099,12927,12753,12578,12401,12224,12045,11866, 11685,11504,11322,11140,10958,10775,10592,10409,10226,10044,9862,9680,9499,9319,9139, 8961,8783,8607,8432,8258,8086,7915,7747,7580,7415,7252,7091,6932,6776,6622,6471, 6322,6176,6032,5892,5754,5619,5488,5359,5234,5111,4992,4877,4764,4655,4550,4448, 4349,4254,4163,4075,3990,3910,3832,3759,3689,3622,3560,3500,3445,3393,3344,3299, 3257,3219,3184,3153,3124,3099,3078,3059,3044,3031,3022,3015,3011,3010,3012,3016, 3023,3033,3044,3058,3075,3093,3113,3136,3160,3186,3213,3242,3273,3305,3338,3372, 3408,3444,3481,3520,3558,3597,3637,3677,3718,3758,3799,3839,3880,3920,3960,4000, 4039,4077,4115,4152,4188,4224,4258,4291,4323,4354,4384,4412,4439,4464,4488,4510, 4530,4549,4566,4581,4594,4606,4615,4623,4628,4631,4633,4632,4629,4624,4617,4608, 4597,4583,4568,4550,4530,4508,4484,4458,4429,4399,4366,4332,4296,4257,4217,4175, 4130,4085,4037,3988,3937,3884,3830,3774,3717,3658,3598,3537,3475,3411,3347,3281, 3215,3147,3079,3010,2940,2870,2799,2728,2657,2585,2513,2440,2368,2296,2224,2151, 2080,2008,1937,1866,1796,1726,1657,1589,1521,1454,1389,1324,1260,1197,1135,1075, 1016,958,901,846,792,740,689,640,592,546,502,459,419,379,342,307,273,241,211,183, 156,132,109,88,69,52,37,24,12,2,-5,-11,-16,-18,-19,-18,-16,-11,-6,2,11,21,33,47,61, 77,95,113,133,154,176,200,224,249,275,302,329,358,387,416,447,477,508,540,572,604, 636,669,702,734,767,800,832,864,896,928,960,991,1021,1051,1081,1110,1138,1166,1193, 1219,1245,1270,1293,1316,1338,1359,1379,1398,1416,1433,1448,1463,1476,1488,1499, 1509,1518,1525,1531,1536,1540,1542,1543,1543,1542,1539,1536,1530,1524,1517,1508, 1498,1487,1475,1462,1447,1432,1415,1397,1379,1359,1338,1317,1294,1271,1247,1222, 1196,1170,1143,1115,1086,1057,1028,998,967,936,905,874,842,809,777,744,712,679,646, 613,581,548,515,483,450,418,387,355,324,293,263,233,204,175,147,119,92,66,40,15, -10,-33,-56,-78,-99,-120,-139,-158,-176,-193,-209,-224,-238,-252,-264,-275,-286, -295,-304,-311,-318,-324,-329,-332,-335,-337,-338,-338,-338,-336,-333,-330,-326, -321,-315,-308,-301,-293,-284,-274,-264,-253,-242,-229,-217,-203,-190,-175,-161, -145,-130,-114,-98,-81,-64,-47,-29,-11,6,24,42,61,79,97,115,134,152,170,188,206,223, 241,258,275,291,308,324,340,355,370,384,399,412,425,438,450,462,473,484,494,503, 512,521,529,536,542,548,553,558,562,566,568,570,572,573,573,573,572,570,568,565, 562,558,553,548,543,537,530,523,515,507,498,489,479,469,459,448,437,426,414,402, 389,377,364,351,337,324,310,296,282,268,254,239,225,211,196,182,168,153,139,125, 111,97,83,70,56,43,30,17,5,-7,-19,-31,-42,-53,-64,-75,-85,-94,-104,-113,-121,-129, -137,-144,-151,-158,-164,-170,-175,-180,-184,-188,-192,-195,-198,-200,-202,-203, -204,-205,-205,-204,-204,-203,-201,-199,-197,-195,-192,-188,-185,-181,-176,-172, -167,-162,-156,-151,-145,-139,-132,-126,-119,-112,-104,-97,-90,-82,-74,-66,-59,-51, -42,-34,-26,-18,-10,-2,7,15,23,31,39,47,54,62,70,77,85,92,99,106,112,119,125,131, 137,143,148,154,159,163,168,172,176,180,183,187,190,192,195,197,199,201,202,203, 204,205,205,205,205,204,203,202,201,200,198,196,194,192,189,186,183,180,177,173, 169,165,161,157,153,148,143,139,134,129,124,119,113,108,103,97,92,86,81,75,70,64, 59,53,48,42,37,32,26,21,16,11,6,1,-4,-9,-13,-18,-22,-26,-30,-34,-38,-42,-46,-49, -52,-55,-58,-61,-64,-66,-69,-71,-73,-74,-76,-78,-79,-80,-81,-82,-82,-83,-83,-83, -83,-83,-83,-82,-82,-81,-80,-79,-78,-77,-75,-74,-72,-70,-68,-66,-64,-62,-60,-57, -55,-52,-50,-47,-44,-42,-39,-36,-33,-30,-27,-24,-21,-18,-15,-12,-9,-6,-3,0,3,6,8, 11,14,17,20,22,25,27,30,32,35,37,39,41,43,45,47,49,50,52,54,55,56,58,59,60,61,61, 62,63,63,64,64,65,65,65,65,65,64,64,64,63,63,62,61,61,60,59,58,57,56,55,53,52,51, 49,48,46,45,43,41,40,38,36,35,33,31,29,28,26,24,22,20,19,17,15,13,11,10,8,6,5,3,1, 0,-2,-3,-5,-6,-8,-9,-10,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-21,-22,-23,-23, -24,-24,-25,-25,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-24, -24,-23,-23,-22,-21,-21,-20,-19,-19,-18,-17,-16,-16,-15,-14,-13,-12,-11,-10,-10,-9, -8,-7,-6,-5,-4,-3,-2,-1,0,1,1,2,3,4,5,6,6,7,8,9,9,10,11,11,12,12,13,14,14,15,15, 15,16,16,16,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,16,16, 16,16,15,15,14,14,14,13,13,12,12,11,11,11,10,10,9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1, 1,0,0,-1,-1,-1,-2,-2,-3,-3,-3,-4,-4,-4,-4,-5,-5,-5,-5,-6,-6,-6,-6,-6,-6,-6,-7,-7, -7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-6,-6,-6,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-4,-4,-4, -4,-4,-3,-3,-3,-3,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,3,3,3, 3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3, 3,3,3,3,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }, { 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, 131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072,131072, 131072,131072,131072,131072,131072,131072,131072,131072,131072,131071,131071,131071, 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, 131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071,131071, 131071,131071,131071,131071,131071,131071,131070,131070,131070,131070,131070,131070, 131070,131070,131070,131070,131070,131070,131070,131070,131070,131070,131069,131069, 131069,131069,131069,131069,131069,131069,131068,131068,131068,131068,131068,131068, 131067,131067,131067,131067,131066,131066,131066,131066,131065,131065,131064,131064, 131064,131063,131063,131062,131062,131061,131061,131060,131060,131059,131058,131058, 131057,131056,131055,131055,131054,131053,131052,131051,131050,131049,131047,131046, 131045,131044,131042,131041,131039,131038,131036,131034,131032,131031,131029,131027, 131024,131022,131020,131017,131015,131012,131009,131007,131004,131001,130997,130994, 130991,130987,130983,130979,130975,130971,130967,130962,130958,130953,130948,130942, 130937,130931,130926,130920,130913,130907,130900,130893,130886,130879,130871,130863, 130855,130847,130838,130829,130820,130810,130800,130790,130779,130768,130757,130745, 130733,130721,130708,130695,130682,130668,130654,130639,130624,130608,130592,130576, 130559,130541,130523,130505,130486,130466,130446,130426,130405,130383,130361,130338, 130314,130290,130265,130240,130214,130187,130160,130132,130103,130074,130044,130013, 129981,129949,129916,129882,129847,129812,129775,129738,129700,129661,129621,129581, 129539,129497,129453,129409,129364,129318,129270,129222,129173,129123,129071,129019, 128966,128911,128856,128799,128742,128683,128623,128562,128500,128436,128372,128306, 128239,128171,128101,128031,127959,127886,127811,127736,127659,127580,127501,127420, 127337,127254,127169,127082,126995,126906,126815,126723,126630,126535,126439,126341, 126242,126142,126040,125936,125831,125725,125617,125507,125396,125284,125170,125055, 124938,124819,124699,124577,124454,124329,124203,124075,123946,123815,123683,123549, 123413,123276,123137,122997,122855,122711,122566,122420,122272,122122,121971,121818, 121663,121507,121350,121191,121030,120868,120704,120539,120372,120204,120034,119863, 119690,119515,119339,119162,118983,118803,118621,118438,118253,118067,117879,117690, 117500,117308,117114,116920,116724,116526,116327,116127,115926,115723,115519,115313, 115106,114898,114689,114478,114266,114053,113839,113624,113407,113189,112970,112750, 112528,112306,112082,111858,111632,111405,111177,110948,110718,110487,110255,110022, 109788,109553,109317,109080,108842,108604,108364,108124,107883,107641,107398,107154, 106909,106664,106418,106171,105923,105675,105426,105176,104926,104675,104423,104171, 103918,103664,103410,103155,102899,102643,102387,102130,101872,101614,101356,101096, 100837,100577,100316,100055,99794,99532,99270,99007,98745,98481,98217,97953,97689, 97424,97159,96894,96628,96362,96096,95829,95563,95296,95028,94761,94493,94225,93957, 93688,93419,93151,92881,92612,92343,92073,91803,91534,91263,90993,90723,90452,90182, 89911,89640,89369,89098,88827,88556,88284,88013,87741,87470,87198,86926,86654,86382, 86110,85838,85566,85294,85022,84750,84477,84205,83933,83660,83388,83116,82843,82571, 82298,82026,81753,81481,81208,80936,80663,80391,80118,79846,79573,79301,79029,78756, 78484,78212,77939,77667,77395,77123,76851,76579,76307,76035,75763,75491,75220,74948, 74676,74405,74134,73862,73591,73320,73049,72778,72507,72237,71966,71696,71426,71156, 70886,70616,70346,70077,69807,69538,69269,69000,68732,68463,68195,67927,67659,67391, 67124,66857,66590,66323,66056,65790,65524,65258,64993,64728,64463,64198,63934,63670, 63406,63143,62880,62617,62354,62092,61830,61569,61308,61047,60787,60527,60267,60008, 59749,59491,59233,58975,58718,58461,58205,57949,57694,57439,57184,56930,56676,56423, 56171,55918,55667,55416,55165,54915,54665,54416,54167,53919,53671,53424,53178,52932, 52686,52442,52197,51954,51710,51468,51226,50984,50743,50503,50263,50024,49786,49548, 49310,49074,48838,48602,48367,48133,47899,47666,47434,47202,46971,46740,46510,46281, 46052,45824,45597,45370,45144,44918,44693,44469,44245,44022,43800,43578,43357,43137, 42917,42698,42479,42261,42044,41827,41612,41396,41181,40967,40754,40541,40329,40118, 39907,39696,39487,39278,39069,38862,38655,38448,38242,38037,37832,37628,37425,37222, 37020,36819,36618,36417,36218,36019,35820,35622,35425,35228,35032,34837,34642,34448, 34254,34061,33869,33677,33486,33295,33105,32916,32727,32539,32352,32164,31978,31792, 31607,31422,31238,31055,30872,30690,30508,30327,30147,29967,29787,29609,29431,29253, 29076,28900,28724,28549,28374,28200,28027,27854,27682,27510,27339,27169,26999,26830, 26661,26493,26326,26159,25993,25827,25662,25498,25334,25171,25008,24846,24685,24524, 24364,24204,24045,23887,23729,23572,23416,23260,23104,22950,22796,22642,22490,22337, 22186,22035,21884,21735,21586,21437,21289,21142,20996,20850,20704,20560,20416,20272, 20129,19987,19845,19705,19564,19425,19285,19147,19009,18872,18735,18599,18464,18329, 18195,18062,17929,17797,17665,17534,17404,17274,17145,17017,16889,16762,16635,16509, 16384,16259,16135,16011,15888,15766,15644,15523,15403,15283,15163,15044,14926,14809, 14692,14575,14460,14344,14230,14116,14002,13889,13777,13665,13554,13443,13333,13224, 13115,13007,12899,12792,12685,12579,12473,12368,12264,12160,12056,11953,11851,11749, 11648,11547,11447,11347,11248,11149,11051,10953,10856,10759,10663,10568,10472,10378, 10284,10190,10097,10004,9912,9820,9729,9638,9548,9458,9369,9280,9191,9104,9016,8929, 8843,8757,8671,8586,8501,8417,8333,8250,8167,8085,8003,7921,7840,7759,7679,7599, 7520,7441,7363,7285,7207,7130,7053,6977,6901,6826,6751,6676,6602,6528,6455,6382, 6310,6237,6166,6095,6024,5954,5884,5814,5745,5676,5608,5540,5473,5405,5339,5273, 5207,5141,5076,5012,4947,4884,4820,4757,4694,4632,4570,4509,4448,4387,4327,4267, 4208,4149,4090,4032,3974,3917,3859,3803,3746,3691,3635,3580,3525,3471,3417,3363, 3310,3257,3204,3152,3100,3049,2998,2947,2897,2847,2797,2748,2699,2651,2603,2555, 2507,2460,2414,2367,2321,2276,2230,2185,2141,2096,2052,2009,1966,1923,1880,1838, 1796,1754,1713,1672,1631,1591,1551,1511,1472,1432,1394,1355,1317,1279,1242,1204, 1167,1131,1094,1058,1023,987,952,917,882,848,814,780,747,713,680,648,615,583,551, 519,488,457,426,396,365,335,305,276,246,217,188,160,132,103,76,48,21,-7,-34,-60, -87,-113,-139,-165,-190,-216,-241,-266,-290,-315,-339,-363,-387,-410,-434,-457, -480,-502,-525,-547,-569,-591,-613,-634,-656,-677,-697,-718,-739,-759,-779,-799, -818,-838,-857,-876,-895,-914,-932,-951,-969,-987,-1005,-1022,-1040,-1057,-1074, -1091,-1107,-1124,-1140,-1156,-1172,-1188,-1203,-1219,-1234,-1249,-1264,-1279,-1293, -1308,-1322,-1336,-1350,-1363,-1377,-1390,-1403,-1416,-1429,-1442,-1454,-1467,-1479, -1491,-1503,-1514,-1526,-1537,-1548,-1559,-1570,-1581,-1592,-1602,-1613,-1623,-1633, -1643,-1652,-1662,-1671,-1680,-1690,-1699,-1707,-1716,-1725,-1733,-1741,-1750,-1758, -1765,-1773,-1781,-1788,-1796,-1803,-1810,-1817,-1824,-1830,-1837,-1843,-1850,-1856, -1862,-1868,-1874,-1880,-1885,-1891,-1896,-1902,-1907,-1912,-1917,-1922,-1926,-1931, -1935,-1940,-1944,-1948,-1952,-1956,-1960,-1964,-1968,-1971,-1975,-1978,-1982,-1985, -1988,-1991,-1994,-1997,-2000,-2002,-2005,-2007,-2010,-2012,-2014,-2017,-2019,-2021, -2022,-2024,-2026,-2028,-2029,-2031,-2032,-2034,-2035,-2036,-2037,-2038,-2039,-2040, -2041,-2042,-2042,-2043,-2044,-2044,-2045,-2045,-2045,-2045,-2046,-2046,-2046,-2046, -2046,-2045,-2045,-2045,-2044,-2044,-2044,-2043,-2042,-2042,-2041,-2040,-2039,-2039, -2038,-2037,-2035,-2034,-2033,-2032,-2031,-2029,-2028,-2026,-2025,-2023,-2022,-2020, -2018,-2017,-2015,-2013,-2011,-2009,-2007,-2005,-2003,-2001,-1999,-1996,-1994,-1992, -1989,-1987,-1984,-1982,-1979,-1977,-1974,-1971,-1969,-1966,-1963,-1960,-1957,-1954, -1951,-1948,-1945,-1942,-1939,-1936,-1933,-1929,-1926,-1923,-1919,-1916,-1913,-1909, -1906,-1902,-1899,-1895,-1891,-1888,-1884,-1880,-1877,-1873,-1869,-1865,-1861,-1857, -1853,-1849,-1845,-1841,-1837,-1833,-1829,-1825,-1821,-1817,-1813,-1809,-1804,-1800, -1796,-1791,-1787,-1783,-1778,-1774,-1770,-1765,-1761,-1756,-1752,-1747,-1743,-1738, -1734,-1729,-1725,-1720,-1716,-1711,-1706,-1702,-1697,-1692,-1688,-1683,-1678,-1673, -1669,-1664,-1659,-1654,-1650,-1645,-1640,-1635,-1630,-1626,-1621,-1616,-1611,-1606, -1601,-1596,-1591,-1586,-1582,-1577,-1572,-1567,-1562,-1557,-1552,-1547,-1542,-1537, -1532,-1527,-1522,-1517,-1512,-1507,-1502,-1497,-1492,-1487,-1482,-1477,-1472,-1467, -1462,-1457,-1452,-1447,-1442,-1437,-1432,-1427,-1422,-1417,-1412,-1407,-1402,-1397, -1392,-1386,-1381,-1376,-1371,-1366,-1361,-1356,-1351,-1346,-1341,-1336,-1331,-1326, -1321,-1316,-1311,-1306,-1301,-1296,-1291,-1286,-1281,-1276,-1271,-1266,-1261,-1256, -1251,-1246,-1241,-1236,-1231,-1226,-1221,-1216,-1211,-1206,-1201,-1196,-1191,-1186, -1181,-1176,-1171,-1166,-1161,-1156,-1152,-1147,-1142,-1137,-1132,-1127,-1122,-1117, -1112,-1108,-1103,-1098,-1093,-1088,-1083,-1079,-1074,-1069,-1064,-1060,-1055,-1050, -1045,-1040,-1036,-1031,-1026,-1022,-1017,-1012,-1008,-1003,-998,-994,-989,-984,-980, -975,-970,-966,-961,-957,-952,-947,-943,-938,-934,-929,-925,-920,-916,-911,-907, -902,-898,-894,-889,-885,-880,-876,-872,-867,-863,-859,-854,-850,-846,-841,-837, -833,-828,-824,-820,-816,-812,-807,-803,-799,-795,-791,-787,-782,-778,-774,-770, -766,-762,-758,-754,-750,-746,-742,-738,-734,-730,-726,-722,-718,-714,-710,-706, -702,-699,-695,-691,-687,-683,-679,-676,-672,-668,-664,-661,-657,-653,-649,-646, -642,-638,-635,-631,-627,-624,-620,-617,-613,-609,-606,-602,-599,-595,-592,-588, -585,-581,-578,-574,-571,-568,-564,-561,-557,-554,-551,-547,-544,-541,-537,-534, -531,-528,-524,-521,-518,-515,-511,-508,-505,-502,-499,-496,-492,-489,-486,-483, -480,-477,-474,-471,-468,-465,-462,-459,-456,-453,-450,-447,-444,-441,-438,-435, -433,-430,-427,-424,-421,-418,-416,-413,-410,-407,-405,-402,-399,-396,-394,-391, -388,-386,-383,-380,-378,-375,-373,-370,-367,-365,-362,-360,-357,-355,-352,-350, -347,-345,-342,-340,-337,-335,-333,-330,-328,-325,-323,-321,-318,-316,-314,-311, -309,-307,-305,-302,-300,-298,-296,-293,-291,-289,-287,-285,-282,-280,-278,-276, -274,-272,-270,-268,-266,-264,-261,-259,-257,-255,-253,-251,-249,-247,-246,-244, -242,-240,-238,-236,-234,-232,-230,-228,-226,-225,-223,-221,-219,-217,-216,-214, -212,-210,-209,-207,-205,-203,-202,-200,-198,-197,-195,-193,-192,-190,-188,-187, -185,-183,-182,-180,-179,-177,-176,-174,-172,-171,-169,-168,-166,-165,-163,-162, -161,-159,-158,-156,-155,-153,-152,-151,-149,-148,-146,-145,-144,-142,-141,-140, -138,-137,-136,-134,-133,-132,-131,-129,-128,-127,-126,-124,-123,-122,-121,-120, -118,-117,-116,-115,-114,-113,-111,-110,-109,-108,-107,-106,-105,-104,-103,-102, -100,-99,-98,-97,-96,-95,-94,-93,-92,-91,-90,-89,-88,-87,-86,-85,-85,-84,-83,-82, -81,-80,-79,-78,-77,-76,-75,-75,-74,-73,-72,-71,-70,-70,-69,-68,-67,-66,-66,-65, -64,-63,-62,-62,-61,-60,-59,-59,-58,-57,-56,-56,-55,-54,-54,-53,-52,-52,-51,-50, -50,-49,-48,-48,-47,-46,-46,-45,-45,-44,-43,-43,-42,-42,-41,-40,-40,-39,-39,-38, -38,-37,-36,-36,-35,-35,-34,-34,-33,-33,-32,-32,-31,-31,-30,-30,-29,-29,-29,-28, -28,-27,-27,-26,-26,-25,-25,-25,-24,-24,-23,-23,-23,-22,-22,-21,-21,-21,-20,-20, -20,-19,-19,-18,-18,-18,-17,-17,-17,-16,-16,-16,-15,-15,-15,-15,-14,-14,-14,-13, -13,-13,-13,-12,-12,-12,-11,-11,-11,-11,-10,-10,-10,-10,-9,-9,-9,-9,-9,-8,-8,-8,-8, -7,-7,-7,-7,-7,-6,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,-4,-4,-3,-3,-3, -3,-3,-3,-3,-3,-2,-2,-2,-2,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0,0,0,0,0,0,0,0,0, } }; libxmp-4.4.1/src/fnmatch.c0000664000175000017500000001364112773571316015233 0ustar claudioclaudio#ifdef __SUNPRO_C #pragma error_messages (off,E_EMPTY_TRANSLATION_UNIT) #endif #ifndef HAVE_FNMATCH /*- * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Guido van Rossum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. * Compares a filename or pathname to a pattern. */ #include #include #include #include "fnmatch.h" #define EOS '\0' #define RANGE_MATCH 1 #define RANGE_NOMATCH 0 #define RANGE_ERROR (-1) static int rangematch(const char *, char, int, char **); int fnmatch(const char *pattern, const char *string, int flags) { const char *stringstart; char *newp; char c, test; for (stringstart = string;;) switch (c = *pattern++) { case EOS: if ((flags & FNM_LEADING_DIR) && *string == '/') return (0); return (*string == EOS ? 0 : FNM_NOMATCH); case '?': if (*string == EOS) return (FNM_NOMATCH); if (*string == '/' && (flags & FNM_PATHNAME)) return (FNM_NOMATCH); if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); ++string; break; case '*': c = *pattern; /* Collapse multiple stars. */ while (c == '*') c = *++pattern; if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); /* Optimize for pattern with * at end or before /. */ if (c == EOS) if (flags & FNM_PATHNAME) return ((flags & FNM_LEADING_DIR) || strchr(string, '/') == NULL ? 0 : FNM_NOMATCH); else return (0); else if (c == '/' && flags & FNM_PATHNAME) { if ((string = strchr(string, '/')) == NULL) return (FNM_NOMATCH); break; } /* General case, use recursion. */ while ((test = *string) != EOS) { if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) return (0); if (test == '/' && flags & FNM_PATHNAME) break; ++string; } return (FNM_NOMATCH); case '[': if (*string == EOS) return (FNM_NOMATCH); if (*string == '/' && (flags & FNM_PATHNAME)) return (FNM_NOMATCH); if (*string == '.' && (flags & FNM_PERIOD) && (string == stringstart || ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) return (FNM_NOMATCH); switch (rangematch(pattern, *string, flags, &newp)) { case RANGE_ERROR: goto norm; case RANGE_MATCH: pattern = newp; break; case RANGE_NOMATCH: return (FNM_NOMATCH); } ++string; break; case '\\': if (!(flags & FNM_NOESCAPE)) { if ((c = *pattern++) == EOS) { c = '\\'; --pattern; } } /* FALLTHROUGH */ default: norm: if (c == *string) ; else if ((flags & FNM_CASEFOLD) && (tolower((unsigned char)c) == tolower((unsigned char)*string))) ; else return (FNM_NOMATCH); string++; break; } /* NOTREACHED */ } static int rangematch(const char *pattern, char test, int flags, char **newp) { int negate, ok; char c, c2; /* * A bracket expression starting with an unquoted circumflex * character produces unspecified results (IEEE 1003.2-1992, * 3.13.2). This implementation treats it like '!', for * consistency with the regular expression syntax. * J.T. Conklin (conklin@ngai.kaleida.com) */ if ( (negate = (*pattern == '!' || *pattern == '^')) ) ++pattern; if (flags & FNM_CASEFOLD) test = tolower((unsigned char)test); /* * A right bracket shall lose its special meaning and represent * itself in a bracket expression if it occurs first in the list. * -- POSIX.2 2.8.3.2 */ ok = 0; c = *pattern++; do { if (c == '\\' && !(flags & FNM_NOESCAPE)) c = *pattern++; if (c == EOS) return (RANGE_ERROR); if (c == '/' && (flags & FNM_PATHNAME)) return (RANGE_NOMATCH); if (flags & FNM_CASEFOLD) c = tolower((unsigned char)c); if (*pattern == '-' && (c2 = *(pattern+1)) != EOS && c2 != ']') { pattern += 2; if (c2 == '\\' && !(flags & FNM_NOESCAPE)) c2 = *pattern++; if (c2 == EOS) return (RANGE_ERROR); if (flags & FNM_CASEFOLD) c2 = tolower((unsigned char)c2); if (c <= test && test <= c2) ok = 1; } else if (c == test) ok = 1; } while ((c = *pattern++) != ']'); *newp = (char *)pattern; return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); } #endif libxmp-4.4.1/src/md5.c0000664000175000017500000001734012773571316014300 0ustar claudioclaudio/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include #include #include "common.h" #include "md5.h" #define PUT_64BIT_LE(cp, value) do { \ (cp)[7] = (value) >> 56; \ (cp)[6] = (value) >> 48; \ (cp)[5] = (value) >> 40; \ (cp)[4] = (value) >> 32; \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) #define PUT_32BIT_LE(cp, value) do { \ (cp)[3] = (value) >> 24; \ (cp)[2] = (value) >> 16; \ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) static uint8 PADDING[MD5_BLOCK_LENGTH] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(uint32 state[4], const uint8 block[MD5_BLOCK_LENGTH]) { uint32 a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; #ifndef WORDS_BIGENDIAN memcpy(in, block, sizeof(in)); #else for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { in[a] = (uint32)( (uint32)(block[a * 4 + 0]) | (uint32)(block[a * 4 + 1]) << 8 | (uint32)(block[a * 4 + 2]) << 16 | (uint32)(block[a * 4 + 3]) << 24); } #endif a = state[0]; b = state[1]; c = state[2]; d = state[3]; MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); state[0] += a; state[1] += b; state[2] += c; state[3] += d; } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(MD5_CTX *ctx) { ctx->count = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len) { size_t have, need; /* Check how many bytes we already have and how many more we need. */ have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); need = MD5_BLOCK_LENGTH - have; /* Update bitcount */ ctx->count += (uint64)len << 3; if (len >= need) { if (have != 0) { memcpy(ctx->buffer + have, input, need); MD5Transform(ctx->state, ctx->buffer); input += need; len -= need; have = 0; } /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ while (len >= MD5_BLOCK_LENGTH) { MD5Transform(ctx->state, input); input += MD5_BLOCK_LENGTH; len -= MD5_BLOCK_LENGTH; } } /* Handle any remaining bytes of data. */ if (len != 0) memcpy(ctx->buffer + have, input, len); } /* * Pad pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Pad(MD5_CTX *ctx) { uint8 count[8]; size_t padlen; /* Convert count to 8 bytes in little endian order. */ PUT_64BIT_LE(count, ctx->count); /* Pad out to 56 mod 64. */ padlen = MD5_BLOCK_LENGTH - ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); if (padlen < 1 + 8) padlen += MD5_BLOCK_LENGTH; MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ MD5Update(ctx, count, 8); } /* * Final wrapup--call MD5Pad, fill in digest and zero out ctx. */ void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) { int i; MD5Pad(ctx); if (digest != NULL) { for (i = 0; i < 4; i++) PUT_32BIT_LE(digest + i * 4, ctx->state[i]); memset(ctx, 0, sizeof(*ctx)); } } libxmp-4.4.1/src/mix_all.c0000664000175000017500000002626712775035311015240 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "common.h" #include "virtual.h" #include "mixer.h" #include "precomp_lut.h" /* Mixers * * To increase performance eight mixers are defined, one for each * combination of the following parameters: interpolation, resolution * and number of channels. */ #define NEAREST_NEIGHBOR() do { \ smp_in = ((int16)sptr[pos] << 8); \ } while (0) #define NEAREST_NEIGHBOR_16BIT() do { \ smp_in = sptr[pos]; \ } while (0) #define LINEAR_INTERP() do { \ smp_l1 = ((int16)sptr[pos] << 8); \ smp_dt = ((int16)sptr[pos + 1] << 8) - smp_l1; \ smp_in = smp_l1 + (((frac >> 1) * smp_dt) >> (SMIX_SHIFT - 1)); \ } while (0) #define LINEAR_INTERP_16BIT() do { \ smp_l1 = sptr[pos]; \ smp_dt = sptr[pos + 1] - smp_l1; \ smp_in = smp_l1 + (((frac >> 1) * smp_dt) >> (SMIX_SHIFT - 1)); \ } while (0) /* The following lut settings are PRECOMPUTED. If you plan on changing these * settings, you MUST also regenerate the arrays. */ /* number of bits used to scale spline coefs */ #define SPLINE_QUANTBITS 14 #define SPLINE_SHIFT (SPLINE_QUANTBITS) /* log2(number) of precalculated splines (range is [4..14]) */ #define SPLINE_FRACBITS 10 #define SPLINE_LUTLEN (1L<> 6; \ smp_in = (cubic_spline_lut0[f] * sptr[(int)pos - 1] + \ cubic_spline_lut1[f] * sptr[pos ] + \ cubic_spline_lut3[f] * sptr[pos + 2] + \ cubic_spline_lut2[f] * sptr[pos + 1]) >> (SPLINE_SHIFT - 8); \ } while (0) #define SPLINE_INTERP_16BIT() do { \ int f = frac >> 6; \ smp_in = (cubic_spline_lut0[f] * sptr[(int)pos - 1] + \ cubic_spline_lut1[f] * sptr[pos ] + \ cubic_spline_lut3[f] * sptr[pos + 2] + \ cubic_spline_lut2[f] * sptr[pos + 1]) >> SPLINE_SHIFT; \ } while (0) #define LOOP_AC for (; count > ramp; count--) #define LOOP for (; count; count--) #define UPDATE_POS() do { \ frac += step; \ pos += frac >> SMIX_SHIFT; \ frac &= SMIX_MASK; \ } while (0) #define MIX_MONO() do { \ *(buffer++) += smp_in * vl; \ } while (0) #define MIX_MONO_AC() do { \ *(buffer++) += smp_in * (old_vl >> 8); old_vl += delta_l; \ } while (0) #define MIX_MONO_FILTER() do { \ sl = (a0 * smp_in * vl + b0 * fl1 + b1 * fl2) >> FILTER_SHIFT; \ fl2 = fl1; fl1 = sl; \ *(buffer++) += sl; \ } while (0) #define MIX_MONO_FILTER_AC() do { \ int vl = old_vl >> 8; \ MIX_MONO_FILTER(); \ old_vl += delta_l; \ } while (0) #define MIX_STEREO() do { \ *(buffer++) += smp_in * vr; \ *(buffer++) += smp_in * vl; \ } while (0) #define MIX_STEREO_AC() do { \ *(buffer++) += smp_in * (old_vr >> 8); old_vr += delta_r; \ *(buffer++) += smp_in * (old_vl >> 8); old_vl += delta_l; \ } while (0) #define MIX_STEREO_FILTER() do { \ sr = (a0 * smp_in * vr + b0 * fr1 + b1 * fr2) >> FILTER_SHIFT; \ fr2 = fr1; fr1 = sr; \ sl = (a0 * smp_in * vl + b0 * fl1 + b1 * fl2) >> FILTER_SHIFT; \ fl2 = fl1; fl1 = sl; \ *(buffer++) += sr; \ *(buffer++) += sl; \ } while (0) #define MIX_STEREO_FILTER_AC() do { \ int vr = old_vr >> 8; \ int vl = old_vl >> 8; \ MIX_STEREO_FILTER(); \ old_vr += delta_r; \ old_vl += delta_l; \ } while (0) #define MIX_STEREO_FILTER_AC() do { \ int vr = old_vr >> 8; \ int vl = old_vl >> 8; \ MIX_STEREO_FILTER(); \ old_vr += delta_r; \ old_vl += delta_l; \ } while (0) #define VAR_NORM(x) \ register int smp_in; \ x *sptr = vi->sptr; \ unsigned int pos = vi->pos; \ int frac = (1 << SMIX_SHIFT) * (vi->pos - (int)vi->pos) #define VAR_LINEAR_MONO(x) \ VAR_NORM(x); \ int old_vl = vi->old_vl; \ int smp_l1, smp_dt #define VAR_LINEAR_STEREO(x) \ VAR_LINEAR_MONO(x); \ int old_vr = vi->old_vr #define VAR_SPLINE_MONO(x) \ int old_vl = vi->old_vl; \ VAR_NORM(x) #define VAR_SPLINE_STEREO(x); \ VAR_SPLINE_MONO(x); \ int old_vr = vi->old_vr; \ #ifndef LIBXMP_CORE_DISABLE_IT #define VAR_FILTER_MONO \ int fl1 = vi->filter.l1, fl2 = vi->filter.l2; \ int64 a0 = vi->filter.a0, b0 = vi->filter.b0, b1 = vi->filter.b1; \ int sl #define VAR_FILTER_STEREO \ VAR_FILTER_MONO; \ int fr1 = vi->filter.r1, fr2 = vi->filter.r2; \ int sr #define SAVE_FILTER_MONO() do { \ vi->filter.l1 = fl1; \ vi->filter.l2 = fl2; \ } while (0) #define SAVE_FILTER_STEREO() do { \ SAVE_FILTER_MONO(); \ vi->filter.r1 = fr1; \ vi->filter.r2 = fr2; \ } while (0) #endif /* * Nearest neighbor mixers */ /* Handler for 8 bit samples, nearest neighbor mono output */ MIXER(mono_8bit_nearest) { VAR_NORM(int8); LOOP { NEAREST_NEIGHBOR(); MIX_MONO(); UPDATE_POS(); } } /* Handler for 16 bit samples, nearest neighbor mono output */ MIXER(mono_16bit_nearest) { VAR_NORM(int16); LOOP { NEAREST_NEIGHBOR_16BIT(); MIX_MONO(); UPDATE_POS(); } } /* Handler for 8 bit samples, nearest neighbor stereo output */ MIXER(stereo_8bit_nearest) { VAR_NORM(int8); LOOP { NEAREST_NEIGHBOR(); MIX_STEREO(); UPDATE_POS(); } } /* Handler for 16 bit samples, nearest neighbor stereo output */ MIXER(stereo_16bit_nearest) { VAR_NORM(int16); LOOP { NEAREST_NEIGHBOR_16BIT(); MIX_STEREO(); UPDATE_POS(); } } /* * Linear mixers */ /* Handler for 8 bit samples, linear interpolated mono output */ MIXER(mono_8bit_linear) { VAR_LINEAR_MONO(int8); LOOP_AC { LINEAR_INTERP(); MIX_MONO_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP(); MIX_MONO(); UPDATE_POS(); } } /* Handler for 16 bit samples, linear interpolated mono output */ MIXER(mono_16bit_linear) { VAR_LINEAR_MONO(int16); LOOP_AC { LINEAR_INTERP_16BIT(); MIX_MONO_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP_16BIT(); MIX_MONO(); UPDATE_POS(); } } /* Handler for 8 bit samples, linear interpolated stereo output */ MIXER(stereo_8bit_linear) { VAR_LINEAR_STEREO(int8); LOOP_AC { LINEAR_INTERP(); MIX_STEREO_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP(); MIX_STEREO(); UPDATE_POS(); } } /* Handler for 16 bit samples, linear interpolated stereo output */ MIXER(stereo_16bit_linear) { VAR_LINEAR_STEREO(int16); LOOP_AC { LINEAR_INTERP_16BIT(); MIX_STEREO_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP_16BIT(); MIX_STEREO(); UPDATE_POS(); } } #ifndef LIBXMP_CORE_DISABLE_IT /* Handler for 8 bit samples, filtered linear interpolated mono output */ MIXER(mono_8bit_linear_filter) { VAR_LINEAR_MONO(int8); VAR_FILTER_MONO; LOOP_AC { LINEAR_INTERP(); MIX_MONO_FILTER_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP(); MIX_MONO_FILTER(); UPDATE_POS(); } SAVE_FILTER_MONO(); } /* Handler for 16 bit samples, filtered linear interpolated mono output */ MIXER(mono_16bit_linear_filter) { VAR_LINEAR_MONO(int16); VAR_FILTER_MONO; LOOP_AC { LINEAR_INTERP_16BIT(); MIX_MONO_FILTER_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP_16BIT(); MIX_MONO_FILTER(); UPDATE_POS(); } SAVE_FILTER_MONO(); } /* Handler for 8 bit samples, filtered linear interpolated stereo output */ MIXER(stereo_8bit_linear_filter) { VAR_LINEAR_STEREO(int8); VAR_FILTER_STEREO; LOOP_AC { LINEAR_INTERP(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP(); MIX_STEREO_FILTER(); UPDATE_POS(); } SAVE_FILTER_STEREO(); } /* Handler for 16 bit samples, filtered linear interpolated stereo output */ MIXER(stereo_16bit_linear_filter) { VAR_LINEAR_STEREO(int16); VAR_FILTER_STEREO; LOOP_AC { LINEAR_INTERP_16BIT(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); } LOOP { LINEAR_INTERP_16BIT(); MIX_STEREO_FILTER(); UPDATE_POS(); } SAVE_FILTER_STEREO(); } #endif /* * Spline mixers */ /* Handler for 8 bit samples, spline interpolated mono output */ MIXER(mono_8bit_spline) { VAR_SPLINE_MONO(int8); LOOP_AC { SPLINE_INTERP(); MIX_MONO_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP(); MIX_MONO(); UPDATE_POS(); } } /* Handler for 16 bit samples, spline interpolated mono output */ MIXER(mono_16bit_spline) { VAR_SPLINE_MONO(int16); LOOP_AC { SPLINE_INTERP_16BIT(); MIX_MONO_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP_16BIT(); MIX_MONO(); UPDATE_POS(); } } /* Handler for 8 bit samples, spline interpolated stereo output */ MIXER(stereo_8bit_spline) { VAR_SPLINE_STEREO(int8); LOOP_AC { SPLINE_INTERP(); MIX_STEREO_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP(); MIX_STEREO(); UPDATE_POS(); } } /* Handler for 16 bit samples, spline interpolated stereo output */ MIXER(stereo_16bit_spline) { VAR_SPLINE_STEREO(int16); LOOP_AC { SPLINE_INTERP_16BIT(); MIX_STEREO_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP_16BIT(); MIX_STEREO(); UPDATE_POS(); } } #ifndef LIBXMP_CORE_DISABLE_IT /* Handler for 8 bit samples, filtered spline interpolated mono output */ MIXER(mono_8bit_spline_filter) { VAR_SPLINE_MONO(int8); VAR_FILTER_MONO; LOOP_AC { SPLINE_INTERP(); MIX_MONO_FILTER_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP(); MIX_MONO_FILTER(); UPDATE_POS(); } SAVE_FILTER_MONO(); } /* Handler for 16 bit samples, filtered spline interpolated mono output */ MIXER(mono_16bit_spline_filter) { VAR_SPLINE_MONO(int16); VAR_FILTER_MONO; LOOP_AC { SPLINE_INTERP_16BIT(); MIX_MONO_FILTER_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP_16BIT(); MIX_MONO_FILTER(); UPDATE_POS(); } SAVE_FILTER_MONO(); } /* Handler for 8 bit samples, filtered spline interpolated stereo output */ MIXER(stereo_8bit_spline_filter) { VAR_SPLINE_STEREO(int8); VAR_FILTER_STEREO; LOOP_AC { SPLINE_INTERP(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP(); MIX_STEREO_FILTER(); UPDATE_POS(); } SAVE_FILTER_STEREO(); } /* Handler for 16 bit samples, filtered spline interpolated stereo output */ MIXER(stereo_16bit_spline_filter) { VAR_SPLINE_STEREO(int16); VAR_FILTER_STEREO; LOOP_AC { SPLINE_INTERP_16BIT(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); } LOOP { SPLINE_INTERP_16BIT(); MIX_STEREO_FILTER(); UPDATE_POS(); } SAVE_FILTER_STEREO(); } #endif libxmp-4.4.1/src/effects.c0000664000175000017500000006274312775035311015231 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "common.h" #include "player.h" #include "effects.h" #include "period.h" #include "virtual.h" #include "mixer.h" #ifndef LIBXMP_CORE_PLAYER #include "extras.h" #endif #define NOT_IMPLEMENTED #define HAS_QUIRK(x) (m->quirk & (x)) #define SET_LFO_NOTZERO(lfo, depth, rate) do { \ if ((depth) != 0) libxmp_lfo_set_depth(lfo, depth); \ if ((rate) != 0) libxmp_lfo_set_rate(lfo, rate); \ } while (0) #define EFFECT_MEMORY__(p, m) do { \ if ((p) == 0) { (p) = (m); } else { (m) = (p); } \ } while (0) /* ST3 effect memory is not a bug, but it's a weird implementation and it's * unlikely to be supported in anything other than ST3 (or OpenMPT). */ #define EFFECT_MEMORY(p, m) do { \ if (HAS_QUIRK(QUIRK_ST3BUGS)) { \ EFFECT_MEMORY__((p), xc->vol.memory); \ } else { \ EFFECT_MEMORY__((p), (m)); \ } \ } while (0) #define EFFECT_MEMORY_SETONLY(p, m) do { \ EFFECT_MEMORY__((p), (m)); \ if (HAS_QUIRK(QUIRK_ST3BUGS)) { \ if ((p) != 0) { xc->vol.memory = (p); } \ } \ } while (0) #define EFFECT_MEMORY_S3M(p) do { \ if (HAS_QUIRK(QUIRK_ST3BUGS)) { \ EFFECT_MEMORY__((p), xc->vol.memory); \ } \ } while (0) static void do_toneporta(struct context_data *ctx, struct channel_data *xc, int note) { struct module_data *m = &ctx->m; struct xmp_instrument *instrument = &m->mod.xxi[xc->ins]; int mapped = instrument->map[xc->key].ins; struct xmp_subinstrument *sub; if (mapped >= instrument->nsm) { mapped = 0; } sub = &instrument->sub[mapped]; if (note >= 1 && note <= 0x80 && (uint32)xc->ins < m->mod.ins) { note--; xc->porta.target = libxmp_note_to_period(ctx, note + sub->xpo + instrument->map[xc->key_porta].xpo, xc->finetune, xc->per_adj); } xc->porta.dir = xc->period < xc->porta.target ? 1 : -1; } void libxmp_process_fx(struct context_data *ctx, struct channel_data *xc, int chn, struct xmp_event *e, int fnum) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct flow_control *f = &p->flow; uint8 note, fxp, fxt; int h, l; /* key_porta is IT only */ if (m->read_event_type != READ_EVENT_IT) { xc->key_porta = xc->key; } note = e->note; if (fnum == 0) { fxt = e->fxt; fxp = e->fxp; } else { fxt = e->f2t; fxp = e->f2p; } switch (fxt) { case FX_ARPEGGIO: fx_arpeggio: if (!HAS_QUIRK(QUIRK_ARPMEM) || fxp != 0) { xc->arpeggio.val[0] = 0; xc->arpeggio.val[1] = MSN(fxp); xc->arpeggio.val[2] = LSN(fxp); xc->arpeggio.size = 3; } break; case FX_S3M_ARPEGGIO: EFFECT_MEMORY(fxp, xc->arpeggio.memory); goto fx_arpeggio; #ifndef LIBXMP_CORE_PLAYER case FX_OKT_ARP3: if (fxp != 0) { xc->arpeggio.val[0] = -MSN(fxp); xc->arpeggio.val[1] = 0; xc->arpeggio.val[2] = LSN(fxp); xc->arpeggio.size = 3; } break; case FX_OKT_ARP4: if (fxp != 0) { xc->arpeggio.val[0] = 0; xc->arpeggio.val[1] = LSN(fxp); xc->arpeggio.val[2] = 0; xc->arpeggio.val[3] = -MSN(fxp); xc->arpeggio.size = 4; } break; case FX_OKT_ARP5: if (fxp != 0) { xc->arpeggio.val[0] = LSN(fxp); xc->arpeggio.val[1] = LSN(fxp); xc->arpeggio.val[2] = 0; xc->arpeggio.size = 3; } break; #endif case FX_PORTA_UP: /* Portamento up */ EFFECT_MEMORY(fxp, xc->freq.memory); if (HAS_QUIRK(QUIRK_FINEFX) && (fnum == 0 || !HAS_QUIRK(QUIRK_ITVPOR))) { switch (MSN(fxp)) { case 0xf: fxp &= 0x0f; goto fx_f_porta_up; case 0xe: fxp &= 0x0f; fxp |= 0x10; goto fx_xf_porta; } } SET(PITCHBEND); if (fxp != 0) { xc->freq.slide = -fxp; if (HAS_QUIRK(QUIRK_UNISLD)) xc->porta.memory = fxp; } else if (xc->freq.slide > 0) { xc->freq.slide *= -1; } break; case FX_PORTA_DN: /* Portamento down */ EFFECT_MEMORY(fxp, xc->freq.memory); if (HAS_QUIRK(QUIRK_FINEFX) && (fnum == 0 || !HAS_QUIRK(QUIRK_ITVPOR))) { switch (MSN(fxp)) { case 0xf: fxp &= 0x0f; goto fx_f_porta_dn; case 0xe: fxp &= 0x0f; fxp |= 0x20; goto fx_xf_porta; } } SET(PITCHBEND); if (fxp != 0) { xc->freq.slide = fxp; if (HAS_QUIRK(QUIRK_UNISLD)) xc->porta.memory = fxp; } else if (xc->freq.slide < 0) { xc->freq.slide *= -1; } break; case FX_TONEPORTA: /* Tone portamento */ EFFECT_MEMORY_SETONLY(fxp, xc->porta.memory); if (fxp != 0) { if (HAS_QUIRK(QUIRK_UNISLD)) /* IT compatible Gxx off */ xc->freq.memory = fxp; xc->porta.slide = fxp; } if (HAS_QUIRK(QUIRK_IGSTPOR)) { if (note == 0 && xc->porta.dir == 0) break; } if (!IS_VALID_INSTRUMENT(xc->ins)) break; do_toneporta(ctx, xc, note); SET(TONEPORTA); break; case FX_VIBRATO: /* Vibrato */ EFFECT_MEMORY_SETONLY(fxp, xc->vibrato.memory); SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp) << 2, MSN(fxp)); break; case FX_FINE_VIBRATO: /* Fine vibrato */ EFFECT_MEMORY_SETONLY(fxp, xc->vibrato.memory); SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp), MSN(fxp)); break; case FX_TONE_VSLIDE: /* Toneporta + vol slide */ if (!IS_VALID_INSTRUMENT(xc->ins)) break; do_toneporta(ctx, xc, note); SET(TONEPORTA); goto fx_volslide; case FX_VIBRA_VSLIDE: /* Vibrato + vol slide */ SET(VIBRATO); goto fx_volslide; case FX_TREMOLO: /* Tremolo */ EFFECT_MEMORY(fxp, xc->tremolo.memory); SET(TREMOLO); SET_LFO_NOTZERO(&xc->tremolo.lfo, LSN(fxp), MSN(fxp)); break; case FX_SETPAN: /* Set pan */ if (HAS_QUIRK(QUIRK_PROTRACK)) { break; } fx_setpan: /* From OpenMPT PanOff.xm: * "Another chapter of weird FT2 bugs: Note-Off + Note Delay * + Volume Column Panning = Panning effect is ignored." */ if (!HAS_QUIRK(QUIRK_FT2BUGS) /* If not FT2 */ || fnum == 0 /* or not vol column */ || e->note != XMP_KEY_OFF /* or not keyoff */ || e->fxt != FX_EXTENDED /* or not delay */ || MSN(e->fxp) != EX_DELAY) { xc->pan.val = fxp; xc->pan.surround = 0; } xc->rpv = 0; /* storlek_20: set pan overrides random pan */ xc->pan.surround = 0; break; case FX_OFFSET: /* Set sample offset */ EFFECT_MEMORY(fxp, xc->offset.memory); SET(OFFSET); if (note) { xc->offset.val &= xc->offset.val & ~0xffff; xc->offset.val |= fxp << 8; xc->offset.val2 = fxp << 8; } if (e->ins) { xc->offset.val2 = fxp << 8; } break; case FX_VOLSLIDE: /* Volume slide */ fx_volslide: /* S3M file volume slide note: * DFy Fine volume down by y (...) If y is 0, the command will * be treated as a volume slide up with a value of f (15). * If a DFF command is specified, the volume will be slid * up. */ if (HAS_QUIRK(QUIRK_FINEFX)) { h = MSN(fxp); l = LSN(fxp); if (l == 0xf && h != 0) { xc->vol.memory = fxp; fxp >>= 4; goto fx_f_vslide_up; } else if (h == 0xf && l != 0) { xc->vol.memory = fxp; fxp &= 0x0f; goto fx_f_vslide_dn; } } /* recover memory */ if (fxp == 0x00) { if ((fxp = xc->vol.memory) != 0) goto fx_volslide; } SET(VOL_SLIDE); /* Skaven's 2nd reality (S3M) has volslide parameter D7 => pri * down. Other trackers only compute volumes if the other * parameter is 0, Fall from sky.xm has 2C => do nothing. * Also don't assign xc->vol.memory if fxp is 0, see Guild * of Sounds.xm */ if (fxp) { xc->vol.memory = fxp; h = MSN(fxp); l = LSN(fxp); if (fxp) { if (HAS_QUIRK(QUIRK_VOLPDN)) { xc->vol.slide = l ? -l : h; } else { xc->vol.slide = h ? h : -l; } } } /* Mirko reports that a S3M with D0F effects created with ST321 * should process volume slides in all frames like ST300. I * suspect ST3/IT could be handling D0F effects like this. */ if (HAS_QUIRK(QUIRK_FINEFX)) { if (MSN(xc->vol.memory) == 0xf || LSN(xc->vol.memory) == 0xf) { SET(FINE_VOLS); xc->vol.fslide = xc->vol.slide; } } break; case FX_VOLSLIDE_2: /* Secondary volume slide */ SET(VOL_SLIDE_2); if (fxp) { h = MSN(fxp); l = LSN(fxp); xc->vol.slide2 = h ? h : -l; } break; case FX_JUMP: /* Order jump */ p->flow.pbreak = 1; p->flow.jump = fxp; /* effect B resets effect D in lower channels */ p->flow.jumpline = 0; break; case FX_VOLSET: /* Volume set */ SET(NEW_VOL); xc->volume = fxp; if (xc->split) { p->xc_data[xc->pair].volume = xc->volume; } break; case FX_BREAK: /* Pattern break */ p->flow.pbreak = 1; p->flow.jumpline = 10 * MSN(fxp) + LSN(fxp); break; case FX_EXTENDED: /* Extended effect */ EFFECT_MEMORY_S3M(fxp); fxt = fxp >> 4; fxp &= 0x0f; switch (fxt) { case EX_FILTER: /* Amiga led filter */ if (IS_AMIGA_MOD()) { p->filter = !(fxp & 1); } break; case EX_F_PORTA_UP: /* Fine portamento up */ EFFECT_MEMORY(fxp, xc->fine_porta.up_memory); goto fx_f_porta_up; case EX_F_PORTA_DN: /* Fine portamento down */ EFFECT_MEMORY(fxp, xc->fine_porta.down_memory); goto fx_f_porta_dn; case EX_GLISS: /* Glissando toggle */ if (fxp) { SET_NOTE(NOTE_GLISSANDO); } else { RESET_NOTE(NOTE_GLISSANDO); } break; case EX_VIBRATO_WF: /* Set vibrato waveform */ fxp &= 3; libxmp_lfo_set_waveform(&xc->vibrato.lfo, fxp); break; case EX_FINETUNE: /* Set finetune */ if (!HAS_QUIRK(QUIRK_FT2BUGS) || note > 0) { xc->finetune = (int8)(fxp << 4); } break; case EX_PATTERN_LOOP: /* Loop pattern */ if (fxp == 0) { /* mark start of loop */ f->loop[chn].start = p->row; if (HAS_QUIRK(QUIRK_FT2BUGS)) p->flow.jumpline = p->row; } else { /* end of loop */ if (f->loop[chn].count) { if (--f->loop[chn].count) { /* **** H:FIXME **** */ f->loop_chn = ++chn; } else { if (HAS_QUIRK(QUIRK_S3MLOOP)) f->loop[chn].start = p->row + 1; } } else { f->loop[chn].count = fxp; f->loop_chn = ++chn; } } break; case EX_TREMOLO_WF: /* Set tremolo waveform */ libxmp_lfo_set_waveform(&xc->tremolo.lfo, fxp & 3); break; case EX_SETPAN: fxp <<= 4; goto fx_setpan; case EX_RETRIG: /* Retrig note */ SET(RETRIG); xc->retrig.val = fxp; xc->retrig.count = LSN(xc->retrig.val) + 1; xc->retrig.type = 0; break; case EX_F_VSLIDE_UP: /* Fine volume slide up */ EFFECT_MEMORY(fxp, xc->fine_vol.up_memory); goto fx_f_vslide_up; case EX_F_VSLIDE_DN: /* Fine volume slide down */ EFFECT_MEMORY(fxp, xc->fine_vol.down_memory); goto fx_f_vslide_dn; case EX_CUT: /* Cut note */ SET(RETRIG); SET_NOTE(NOTE_CUT); /* for IT cut-carry */ xc->retrig.val = fxp + 1; xc->retrig.count = xc->retrig.val; xc->retrig.type = 0x10; break; case EX_DELAY: /* Note delay */ /* computed at frame loop */ break; case EX_PATT_DELAY: /* Pattern delay */ goto fx_patt_delay; case EX_INVLOOP: /* Invert loop / funk repeat */ xc->invloop.speed = fxp; break; } break; case FX_SPEED: /* Set speed */ if (HAS_QUIRK(QUIRK_NOBPM) || p->flags & XMP_FLAGS_VBLANK) { goto fx_s3m_speed; } /* speedup.xm needs BPM = 20 */ if (fxp < 0x20) { goto fx_s3m_speed; } else { goto fx_s3m_bpm; } break; case FX_FINETUNE: xc->finetune = (int16) (fxp - 0x80); break; case FX_F_VSLIDE_UP: /* Fine volume slide up */ EFFECT_MEMORY(fxp, xc->fine_vol.up_memory); fx_f_vslide_up: SET(FINE_VOLS); xc->vol.fslide = fxp; break; case FX_F_VSLIDE_DN: /* Fine volume slide down */ EFFECT_MEMORY(fxp, xc->fine_vol.up_memory); fx_f_vslide_dn: SET(FINE_VOLS); xc->vol.fslide = -fxp; break; case FX_F_PORTA_UP: /* Fine portamento up */ fx_f_porta_up: if (fxp) { SET(FINE_BEND); xc->freq.fslide = -fxp; } break; case FX_F_PORTA_DN: /* Fine portamento down */ fx_f_porta_dn: if (fxp) { SET(FINE_BEND); xc->freq.fslide = fxp; } break; case FX_PATT_DELAY: fx_patt_delay: if (m->read_event_type != READ_EVENT_ST3 || !p->flow.delay) { p->flow.delay = fxp; } break; case FX_S3M_SPEED: /* Set S3M speed */ EFFECT_MEMORY_S3M(fxp); fx_s3m_speed: if (fxp) { p->speed = fxp; #ifndef LIBXMP_CORE_PLAYER p->st26_speed = 0; #endif } break; case FX_S3M_BPM: /* Set S3M BPM */ fx_s3m_bpm: { /* Lower time factor in MED allows lower BPM values */ int min_bpm = (int)(0.5 + m->time_factor * XMP_MIN_BPM / 10); if (fxp < min_bpm) fxp = min_bpm; p->bpm = fxp; p->frame_time = m->time_factor * m->rrate / p->bpm; break; } #ifndef LIBXMP_CORE_DISABLE_IT case FX_IT_BPM: /* Set IT BPM */ if (MSN(fxp) == 0) { /* T0x - Tempo slide down by x */ SET(TEMPO_SLIDE); xc->tempo.slide = -LSN(fxp); } else if (MSN(fxp) == 1) { /* T1x - Tempo slide up by x */ SET(TEMPO_SLIDE); xc->tempo.slide = LSN(fxp); } else { if (fxp < XMP_MIN_BPM) fxp = XMP_MIN_BPM; p->bpm = fxp; } p->frame_time = m->time_factor * m->rrate / p->bpm; break; case FX_IT_ROWDELAY: if (!f->rowdelay_set) { f->rowdelay = fxp; f->rowdelay_set = 3; } break; /* From the OpenMPT VolColMemory.it test case: * "Volume column commands a, b, c and d (volume slide) share one * effect memory, but it should not be shared with Dxy in the effect * column. */ case FX_VSLIDE_UP_2: /* Fine volume slide up */ EFFECT_MEMORY(fxp, xc->vol.memory2); SET(VOL_SLIDE_2); xc->vol.slide2 = fxp; break; case FX_VSLIDE_DN_2: /* Fine volume slide down */ EFFECT_MEMORY(fxp, xc->vol.memory2); SET(VOL_SLIDE_2); xc->vol.slide2 = -fxp; break; case FX_F_VSLIDE_UP_2: /* Fine volume slide up */ EFFECT_MEMORY(fxp, xc->vol.memory2); SET(FINE_VOLS_2); xc->vol.fslide2 = fxp; break; case FX_F_VSLIDE_DN_2: /* Fine volume slide down */ EFFECT_MEMORY(fxp, xc->vol.memory2); SET(FINE_VOLS_2); xc->vol.fslide2 = -fxp; break; case FX_IT_BREAK: /* Pattern break with hex parameter */ p->flow.pbreak = 1; p->flow.jumpline = fxp; break; #endif case FX_GLOBALVOL: /* Set global volume */ if (fxp > m->gvolbase) { p->gvol = m->gvolbase; } else { p->gvol = fxp; } break; case FX_GVOL_SLIDE: /* Global volume slide */ fx_gvolslide: if (fxp) { SET(GVOL_SLIDE); xc->gvol.memory = fxp; h = MSN(fxp); l = LSN(fxp); if (HAS_QUIRK(QUIRK_FINEFX)) { if (l == 0xf && h != 0) { xc->gvol.slide = 0; xc->gvol.fslide = h; } else if (h == 0xf && l != 0) { xc->gvol.slide = 0; xc->gvol.fslide = -l; } else { xc->gvol.slide = h ? h : -l; xc->gvol.fslide = 0; } } else { xc->gvol.slide = h ? h : -l; xc->gvol.fslide = 0; } } else { if ((fxp = xc->gvol.memory) != 0) { goto fx_gvolslide; } } break; case FX_KEYOFF: /* Key off */ xc->keyoff = fxp + 1; break; case FX_ENVPOS: /* Set envelope position */ /* From OpenMPT SetEnvPos.xm: * "When using the Lxx effect, Fasttracker 2 only sets the * panning envelope position if the volume envelope’s sustain * flag is set. */ if (HAS_QUIRK(QUIRK_FT2BUGS)) { struct xmp_instrument *instrument; instrument = libxmp_get_instrument(ctx, xc->ins); if (instrument != NULL) { if (instrument->aei.flg & XMP_ENVELOPE_SUS) { xc->p_idx = fxp; } } } else { xc->p_idx = fxp; } xc->v_idx = fxp; xc->f_idx = fxp; break; case FX_PANSLIDE: /* Pan slide (XM) */ EFFECT_MEMORY(fxp, xc->pan.memory); SET(PAN_SLIDE); xc->pan.slide = LSN(fxp) - MSN(fxp); break; case FX_PANSL_NOMEM: /* Pan slide (XM volume column) */ SET(PAN_SLIDE); xc->pan.slide = LSN(fxp) - MSN(fxp); break; #ifndef LIBXMP_CORE_DISABLE_IT case FX_IT_PANSLIDE: /* Pan slide w/ fine pan (IT) */ SET(PAN_SLIDE); if (fxp) { if (MSN(fxp) == 0xf) { xc->pan.slide = 0; xc->pan.fslide = LSN(fxp); } else if (LSN(fxp) == 0xf) { xc->pan.slide = 0; xc->pan.fslide = -MSN(fxp); } else { SET(PAN_SLIDE); xc->pan.slide = LSN(fxp) - MSN(fxp); xc->pan.fslide = 0; } } break; #endif case FX_MULTI_RETRIG: /* Multi retrig */ EFFECT_MEMORY_S3M(fxp); if (fxp) { xc->retrig.val = fxp; } if (note) { xc->retrig.count = LSN(xc->retrig.val) + 1; xc->retrig.type = MSN(xc->retrig.val); } SET(RETRIG); break; case FX_TREMOR: /* Tremor */ EFFECT_MEMORY(fxp, xc->tremor.memory); xc->tremor.up = MSN(fxp); xc->tremor.down = LSN(fxp); if (IS_PLAYER_MODE_FT2()) { xc->tremor.count |= 0x80; } else { if (xc->tremor.up == 0) { xc->tremor.up++; } if (xc->tremor.down == 0) { xc->tremor.down++; } } SET(TREMOR); break; case FX_XF_PORTA: /* Extra fine portamento */ fx_xf_porta: SET(FINE_BEND); switch (MSN(fxp)) { case 1: xc->freq.fslide = -0.25 * LSN(fxp); break; case 2: xc->freq.fslide = 0.25 * LSN(fxp); break; } break; case FX_SURROUND: xc->pan.surround = fxp; break; #ifndef LIBXMP_CORE_DISABLE_IT case FX_TRK_VOL: /* Track volume setting */ if (fxp <= m->volbase) { xc->mastervol = fxp; } break; case FX_TRK_VSLIDE: /* Track volume slide */ if (fxp == 0) { if ((fxp = xc->trackvol.memory) == 0) break; } if (HAS_QUIRK(QUIRK_FINEFX)) { h = MSN(fxp); l = LSN(fxp); if (h == 0xf && l != 0) { xc->trackvol.memory = fxp; fxp &= 0x0f; goto fx_trk_fvslide; } else if (l == 0xf && h != 0) { xc->trackvol.memory = fxp; fxp &= 0xf0; goto fx_trk_fvslide; } } SET(TRK_VSLIDE); if (fxp) { h = MSN(fxp); l = LSN(fxp); xc->trackvol.memory = fxp; if (HAS_QUIRK(QUIRK_VOLPDN)) { xc->trackvol.slide = l ? -l : h; } else { xc->trackvol.slide = h ? h : -l; } } break; case FX_TRK_FVSLIDE: /* Track fine volume slide */ fx_trk_fvslide: SET(TRK_FVSLIDE); if (fxp) { xc->trackvol.fslide = MSN(fxp) - LSN(fxp); } break; case FX_IT_INSTFUNC: switch (fxp) { case 0: /* Past note cut */ libxmp_virt_pastnote(ctx, chn, VIRT_ACTION_CUT); break; case 1: /* Past note off */ libxmp_virt_pastnote(ctx, chn, VIRT_ACTION_OFF); break; case 2: /* Past note fade */ libxmp_virt_pastnote(ctx, chn, VIRT_ACTION_FADE); break; case 3: /* Set NNA to note cut */ libxmp_virt_setnna(ctx, chn, XMP_INST_NNA_CUT); break; case 4: /* Set NNA to continue */ libxmp_virt_setnna(ctx, chn, XMP_INST_NNA_CONT); break; case 5: /* Set NNA to note off */ libxmp_virt_setnna(ctx, chn, XMP_INST_NNA_OFF); break; case 6: /* Set NNA to note fade */ libxmp_virt_setnna(ctx, chn, XMP_INST_NNA_FADE); break; case 7: /* Turn off volume envelope */ SET_PER(VENV_PAUSE); break; case 8: /* Turn on volume envelope */ RESET_PER(VENV_PAUSE); break; case 9: /* Turn off pan envelope */ SET_PER(PENV_PAUSE); break; case 0xa: /* Turn on pan envelope */ RESET_PER(PENV_PAUSE); break; case 0xb: /* Turn off pitch envelope */ SET_PER(FENV_PAUSE); break; case 0xc: /* Turn on pitch envelope */ RESET_PER(FENV_PAUSE); break; } break; case FX_FLT_CUTOFF: if (fxp < 0xfe || xc->filter.resonance > 0) { xc->filter.cutoff = fxp; } break; case FX_FLT_RESN: xc->filter.resonance = fxp; break; case FX_PANBRELLO: /* Panbrello */ SET(PANBRELLO); SET_LFO_NOTZERO(&xc->panbrello.lfo, LSN(fxp) << 4, MSN(fxp)); break; case FX_PANBRELLO_WF: /* Panbrello waveform */ libxmp_lfo_set_waveform(&xc->panbrello.lfo, fxp & 3); break; case FX_HIOFFSET: /* High offset */ xc->offset.val &= 0xffff; xc->offset.val |= fxp << 16; break; #endif #ifndef LIBXMP_CORE_PLAYER /* SFX effects */ case FX_VOL_ADD: if (!IS_VALID_INSTRUMENT(xc->ins)) { break; } SET(NEW_VOL); xc->volume = m->mod.xxi[xc->ins].sub[0].vol + fxp; if (xc->volume > m->volbase) { xc->volume = m->volbase; } break; case FX_VOL_SUB: if (!IS_VALID_INSTRUMENT(xc->ins)) { break; } SET(NEW_VOL); xc->volume = m->mod.xxi[xc->ins].sub[0].vol - fxp; if (xc->volume < 0) { xc->volume =0; } break; case FX_PITCH_ADD: SET_PER(TONEPORTA); xc->porta.target = libxmp_note_to_period(ctx, note - 1, xc->finetune, 0) + fxp; xc->porta.slide = 2; xc->porta.dir = 1; break; case FX_PITCH_SUB: SET_PER(TONEPORTA); xc->porta.target = libxmp_note_to_period(ctx, note - 1, xc->finetune, 0) - fxp; xc->porta.slide = 2; xc->porta.dir = -1; break; /* Saga Musix says: * * "When both nibbles of an Fxx command are set, SoundTracker 2.6 * applies the both values alternatingly, first the high nibble, * then the low nibble on the next row, then the high nibble again... * If only the high nibble is set, it should act like if only the low * nibble is set (i.e. F30 is the same as F03). */ case FX_ICE_SPEED: if (fxp) { if (LSN(fxp)) { p->st26_speed = (MSN(fxp) << 8) | LSN(fxp); } else { p->st26_speed = MSN(fxp); } } break; case FX_VOLSLIDE_UP: /* Vol slide with uint8 arg */ if (HAS_QUIRK(QUIRK_FINEFX)) { h = MSN(fxp); l = LSN(fxp); if (h == 0xf && l != 0) { fxp &= 0x0f; goto fx_f_vslide_up; } } if (fxp) xc->vol.slide = fxp; SET(VOL_SLIDE); break; case FX_VOLSLIDE_DN: /* Vol slide with uint8 arg */ if (HAS_QUIRK(QUIRK_FINEFX)) { h = MSN(fxp); l = LSN(fxp); if (h == 0xf && l != 0) { fxp &= 0x0f; goto fx_f_vslide_dn; } } if (fxp) xc->vol.slide = -fxp; SET(VOL_SLIDE); break; case FX_F_VSLIDE: /* Fine volume slide */ SET(FINE_VOLS); if (fxp) { h = MSN(fxp); l = LSN(fxp); xc->vol.fslide = h ? h : -l; } break; case FX_NSLIDE_DN: case FX_NSLIDE_UP: case FX_NSLIDE_R_DN: case FX_NSLIDE_R_UP: if (fxp != 0) { if (fxt == FX_NSLIDE_R_DN || fxt == FX_NSLIDE_R_UP) { xc->retrig.val = MSN(fxp); xc->retrig.count = MSN(fxp) + 1; xc->retrig.type = 0; } if (fxt == FX_NSLIDE_UP || fxt == FX_NSLIDE_R_UP) xc->noteslide.slide = LSN(fxp); else xc->noteslide.slide = -LSN(fxp); xc->noteslide.count = xc->noteslide.speed = MSN(fxp); } if (fxt == FX_NSLIDE_R_DN || fxt == FX_NSLIDE_R_UP) SET(RETRIG); SET(NOTE_SLIDE); break; case FX_NSLIDE2_DN: SET(NOTE_SLIDE); xc->noteslide.slide = -fxp; xc->noteslide.count = xc->noteslide.speed = 1; break; case FX_NSLIDE2_UP: SET(NOTE_SLIDE); xc->noteslide.slide = fxp; xc->noteslide.count = xc->noteslide.speed = 1; break; case FX_F_NSLIDE_DN: SET(FINE_NSLIDE); xc->noteslide.fslide = -fxp; break; case FX_F_NSLIDE_UP: SET(FINE_NSLIDE); xc->noteslide.fslide = fxp; break; case FX_PER_VIBRATO: /* Persistent vibrato */ if (LSN(fxp) != 0) { SET_PER(VIBRATO); } else { RESET_PER(VIBRATO); } SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp) << 2, MSN(fxp)); break; case FX_PER_PORTA_UP: /* Persistent portamento up */ SET_PER(PITCHBEND); xc->freq.slide = -fxp; if ((xc->freq.memory = fxp) == 0) RESET_PER(PITCHBEND); break; case FX_PER_PORTA_DN: /* Persistent portamento down */ SET_PER(PITCHBEND); xc->freq.slide = fxp; if ((xc->freq.memory = fxp) == 0) RESET_PER(PITCHBEND); break; case FX_PER_TPORTA: /* Persistent tone portamento */ if (!IS_VALID_INSTRUMENT(xc->ins)) break; SET_PER(TONEPORTA); do_toneporta(ctx, xc, note); xc->porta.slide = fxp; if (fxp == 0) RESET_PER(TONEPORTA); break; case FX_PER_VSLD_UP: /* Persistent volslide up */ SET_PER(VOL_SLIDE); xc->vol.slide = fxp; if (fxp == 0) RESET_PER(VOL_SLIDE); break; case FX_PER_VSLD_DN: /* Persistent volslide down */ SET_PER(VOL_SLIDE); xc->vol.slide = -fxp; if (fxp == 0) RESET_PER(VOL_SLIDE); break; case FX_VIBRATO2: /* Deep vibrato (2x) */ SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp) << 3, MSN(fxp)); break; case FX_SPEED_CP: /* Set speed and ... */ if (fxp) { p->speed = fxp; p->st26_speed = 0; } /* fall through */ case FX_PER_CANCEL: /* Cancel persistent effects */ xc->per_flags = 0; break; /* 669 effects */ case FX_669_PORTA_UP: /* 669 portamento up */ SET_PER(PITCHBEND); xc->freq.slide = 80 * fxp; if ((xc->freq.memory = fxp) == 0) RESET_PER(PITCHBEND); break; case FX_669_PORTA_DN: /* 669 portamento down */ SET_PER(PITCHBEND); xc->freq.slide = -80 * fxp; if ((xc->freq.memory = fxp) == 0) RESET_PER(PITCHBEND); break; case FX_669_TPORTA: /* 669 tone portamento */ if (!IS_VALID_INSTRUMENT(xc->ins)) break; SET_PER(TONEPORTA); do_toneporta(ctx, xc, note); xc->porta.slide = 40 * fxp; if (fxp == 0) RESET_PER(TONEPORTA); break; case FX_669_FINETUNE: /* 669 finetune */ xc->finetune = 80 * (int8)fxp; break; case FX_669_VIBRATO: /* 669 vibrato */ if (LSN(fxp) != 0) { libxmp_lfo_set_waveform(&xc->vibrato.lfo, 669); SET_PER(VIBRATO); } else { RESET_PER(VIBRATO); } SET_LFO_NOTZERO(&xc->vibrato.lfo, 669, 1); break; #endif default: #ifndef LIBXMP_CORE_PLAYER libxmp_extras_process_fx(ctx, xc, chn, note, fxt, fxp, fnum); #endif break; } } libxmp-4.4.1/src/extras.c0000664000175000017500000001024612775035311015107 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "common.h" #include "player.h" #include "extras.h" #include "med_extras.h" #include "hmn_extras.h" /* * Module extras */ void libxmp_release_module_extras(struct context_data *ctx) { struct module_data *m = &ctx->m; if (HAS_MED_MODULE_EXTRAS(*m)) libxmp_med_release_module_extras(m); else if (HAS_HMN_MODULE_EXTRAS(*m)) libxmp_hmn_release_module_extras(m); } /* * Channel extras */ int libxmp_new_channel_extras(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; if (HAS_MED_MODULE_EXTRAS(*m)) { if (libxmp_med_new_channel_extras(xc) < 0) return -1; } else if (HAS_HMN_MODULE_EXTRAS(*m)) { if (libxmp_hmn_new_channel_extras(xc) < 0) return -1; } return 0; } void libxmp_release_channel_extras(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; if (HAS_MED_CHANNEL_EXTRAS(*m)) libxmp_med_release_channel_extras(xc); else if (HAS_HMN_CHANNEL_EXTRAS(*m)) libxmp_hmn_release_channel_extras(xc); } void libxmp_reset_channel_extras(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; if (HAS_MED_CHANNEL_EXTRAS(*m)) libxmp_med_reset_channel_extras(xc); else if (HAS_HMN_CHANNEL_EXTRAS(*m)) libxmp_hmn_reset_channel_extras(xc); } /* * Player extras */ void libxmp_play_extras(struct context_data *ctx, struct channel_data *xc, int chn) { struct module_data *m = &ctx->m; if (xc->ins >= m->mod.ins) /* SFX instruments have no extras */ return; if (HAS_MED_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])) libxmp_med_play_extras(ctx, xc, chn); else if (HAS_HMN_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])) libxmp_hmn_play_extras(ctx, xc, chn); } int libxmp_extras_get_volume(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; int vol; if (xc->ins >= m->mod.ins) vol = xc->volume; else if (HAS_MED_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])) vol = MED_CHANNEL_EXTRAS(*xc)->volume * xc->volume / 64; else if (HAS_HMN_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])) vol = HMN_CHANNEL_EXTRAS(*xc)->volume * xc->volume / 64; else vol = xc->volume; return vol; } int libxmp_extras_get_period(struct context_data *ctx, struct channel_data *xc) { int period; if (HAS_MED_CHANNEL_EXTRAS(*xc)) period = libxmp_med_change_period(ctx, xc); else period = 0; return period; } int libxmp_extras_get_linear_bend(struct context_data *ctx, struct channel_data *xc) { int linear_bend; if (HAS_MED_CHANNEL_EXTRAS(*xc)) linear_bend = libxmp_med_linear_bend(ctx, xc); else if (HAS_HMN_CHANNEL_EXTRAS(*xc)) linear_bend = libxmp_hmn_linear_bend(ctx, xc); else linear_bend = 0; return linear_bend; } void libxmp_extras_process_fx(struct context_data *ctx, struct channel_data *xc, int chn, uint8 note, uint8 fxt, uint8 fxp, int fnum) { if (HAS_MED_CHANNEL_EXTRAS(*xc)) libxmp_med_extras_process_fx(ctx, xc, chn, note, fxt, fxp, fnum); else if (HAS_HMN_CHANNEL_EXTRAS(*xc)) libxmp_hmn_extras_process_fx(ctx, xc, chn, note, fxt, fxp, fnum); } libxmp-4.4.1/src/load.c0000664000175000017500000003254312777410253014530 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #ifdef __native_client__ #include #else #include #endif #include "format.h" #include "list.h" #include "hio.h" #include "tempfile.h" #ifndef LIBXMP_CORE_PLAYER #if !defined(HAVE_POPEN) && defined(WIN32) #include "win32/ptpopen.h" #endif #include "md5.h" #include "extras.h" #endif extern struct format_loader *format_loader[]; void libxmp_load_prologue(struct context_data *); void libxmp_load_epilogue(struct context_data *); int libxmp_prepare_scan(struct context_data *); #ifndef LIBXMP_CORE_PLAYER #include "depacker.h" static struct depacker *depacker_list[] = { #if defined __AMIGA__ && !defined __AROS__ &libxmp_depacker_xfd, #endif &libxmp_depacker_zip, &libxmp_depacker_lha, &libxmp_depacker_gzip, &libxmp_depacker_bzip2, &libxmp_depacker_xz, &libxmp_depacker_compress, &libxmp_depacker_pp, &libxmp_depacker_sqsh, &libxmp_depacker_arcfs, &libxmp_depacker_mmcmp, &libxmp_depacker_muse, &libxmp_depacker_lzx, &libxmp_depacker_s404, &libxmp_depacker_arc, NULL }; int test_oxm (FILE *); #define BUFLEN 16384 static int execute_command(char *cmd, char *filename, FILE *t) { char line[1024], buf[BUFLEN]; FILE *p; int n; snprintf(line, 1024, cmd, filename); #ifdef WIN32 /* Note: The _popen function returns an invalid file opaque, if * used in a Windows program, that will cause the program to hang * indefinitely. _popen works properly in a Console application. * To create a Windows application that redirects input and output, * read the section "Creating a Child Process with Redirected Input * and Output" in the Win32 SDK. -- Mirko */ p = popen(line, "rb"); #else /* Linux popen fails with "rb" */ p = popen(line, "r"); #endif if (p == NULL) { return -1; } while ((n = fread(buf, 1, BUFLEN, p)) > 0) { fwrite(buf, 1, n, t); } pclose (p); return 0; } static int decrunch(HIO_HANDLE **h, char *filename, char **temp) { unsigned char b[1024]; char *cmd; FILE *f, *t; int res; int headersize; int i; struct depacker *depacker = NULL; cmd = NULL; res = 0; *temp = NULL; f = (*h)->handle.file; headersize = fread(b, 1, 1024, f); if (headersize < 100) { /* minimum valid file size */ return 0; } /* Check built-in depackers */ for (i = 0; depacker_list[i] != NULL; i++) { if (depacker_list[i]->test(b)) { depacker = depacker_list[i]; D_(D_INFO "Use depacker %d", i); break; } } /* Check external commands */ if (depacker == NULL) { if (b[0] == 'M' && b[1] == 'O' && b[2] == '3') { /* MO3 */ D_(D_INFO "mo3"); cmd = "unmo3 -s \"%s\" STDOUT"; } else if (memcmp(b, "Rar", 3) == 0) { /* rar */ D_(D_INFO "rar"); cmd = "unrar p -inul -xreadme -x*.diz -x*.nfo -x*.txt " "-x*.exe -x*.com \"%s\""; } else if (test_oxm(f) == 0) { /* oggmod */ D_(D_INFO "oggmod"); depacker = &libxmp_depacker_oxm; } } if (fseek(f, 0, SEEK_SET) < 0) { goto err; } if (depacker == NULL && cmd == NULL) { D_(D_INFO "Not packed"); return 0; } #if defined __ANDROID__ || defined __native_client__ /* Don't use external helpers in android */ if (cmd) { return 0; } #endif D_(D_WARN "Depacking file... "); if ((t = make_temp_file(temp)) == NULL) { goto err; } /* Depack file */ if (cmd) { D_(D_INFO "External depacker: %s", cmd); if (execute_command(cmd, filename, t) < 0) { D_(D_CRIT "failed"); goto err2; } } else if (depacker) { D_(D_INFO "Internal depacker"); if (depacker->depack(f, t) < 0) { D_(D_CRIT "failed"); goto err2; } } D_(D_INFO "done"); if (fseek(t, 0, SEEK_SET) < 0) { D_(D_CRIT "fseek error"); goto err2; } hio_close(*h); *h = hio_open_file(t); return res; err2: fclose(t); err: return -1; } static void set_md5sum(HIO_HANDLE *f, unsigned char *digest) { unsigned char buf[BUFLEN]; MD5_CTX ctx; int bytes_read; if (hio_size(f) <= 0) { memset(digest, 0, 16); return; } hio_seek(f, 0, SEEK_SET); MD5Init(&ctx); while ((bytes_read = hio_read(buf, 1, BUFLEN, f)) > 0) { MD5Update(&ctx, buf, bytes_read); } MD5Final(digest, &ctx); } static char *get_dirname(char *name) { char *div, *dirname; int len; if ((div = strrchr(name, '/'))) { len = div - name + 1; dirname = malloc(len + 1); if (dirname != NULL) { memcpy(dirname, name, len); dirname[len] = 0; } } else { dirname = strdup(""); } return dirname; } static char *get_basename(char *name) { char *div, *basename; if ((div = strrchr(name, '/'))) { basename = strdup(div + 1); } else { basename = strdup(name); } return basename; } #endif /* LIBXMP_CORE_PLAYER */ int xmp_test_module(char *path, struct xmp_test_info *info) { HIO_HANDLE *h; struct stat st; char buf[XMP_NAME_SIZE]; int i; int ret = -XMP_ERROR_FORMAT; #ifndef LIBXMP_CORE_PLAYER char *temp = NULL; #endif if (stat(path, &st) < 0) return -XMP_ERROR_SYSTEM; #ifndef _MSC_VER if (S_ISDIR(st.st_mode)) { errno = EISDIR; return -XMP_ERROR_SYSTEM; } #endif if ((h = hio_open(path, "rb")) == NULL) return -XMP_ERROR_SYSTEM; #ifndef LIBXMP_CORE_PLAYER if (decrunch(&h, path, &temp) < 0) { ret = -XMP_ERROR_DEPACK; goto err; } /* get size after decrunch */ if (hio_size(h) < 256) { /* set minimum valid module size */ ret = -XMP_ERROR_FORMAT; goto err; } #endif if (info != NULL) { *info->name = 0; /* reset name prior to testing */ *info->type = 0; /* reset type prior to testing */ } for (i = 0; format_loader[i] != NULL; i++) { hio_seek(h, 0, SEEK_SET); if (format_loader[i]->test(h, buf, 0) == 0) { int is_prowizard = 0; #ifndef LIBXMP_CORE_PLAYER if (strcmp(format_loader[i]->name, "prowizard") == 0) { hio_seek(h, 0, SEEK_SET); pw_test_format(h, buf, 0, info); is_prowizard = 1; } #endif fclose(h->handle.file); #ifndef LIBXMP_CORE_PLAYER unlink_temp_file(temp); #endif if (info != NULL && !is_prowizard) { strncpy(info->name, buf, XMP_NAME_SIZE - 1); strncpy(info->type, format_loader[i]->name, XMP_NAME_SIZE - 1); } return 0; } } #ifndef LIBXMP_CORE_PLAYER err: hio_close(h); unlink_temp_file(temp); #else hio_close(h); #endif return ret; } static int load_module(xmp_context opaque, HIO_HANDLE *h) { struct context_data *ctx = (struct context_data *)opaque; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int i, j, ret; int test_result, load_result; libxmp_load_prologue(ctx); D_(D_WARN "load"); test_result = load_result = -1; for (i = 0; format_loader[i] != NULL; i++) { hio_seek(h, 0, SEEK_SET); if (hio_error(h)) { /* reset error flag */ } D_(D_WARN "test %s", format_loader[i]->name); test_result = format_loader[i]->test(h, NULL, 0); if (test_result == 0) { hio_seek(h, 0, SEEK_SET); D_(D_WARN "load format: %s", format_loader[i]->name); load_result = format_loader[i]->loader(m, h, 0); break; } } #ifndef LIBXMP_CORE_PLAYER if (test_result == 0 && load_result == 0) set_md5sum(h, m->md5); #endif if (test_result < 0) { free(m->basename); free(m->dirname); return -XMP_ERROR_FORMAT; } if (load_result < 0) { goto err_load; } /* Sanity check: number of channels, module length */ if (mod->chn > XMP_MAX_CHANNELS || mod->len > XMP_MAX_MOD_LENGTH) { goto err_load; } /* Sanity check: channel pan */ for (i = 0; i < mod->chn; i++) { if (mod->xxc[i].vol < 0 || mod->xxc[i].vol > 0xff) { goto err_load; } if (mod->xxc[i].pan < 0 || mod->xxc[i].pan > 0xff) { goto err_load; } } /* Sanity check: patterns */ if (mod->xxp == NULL) { goto err_load; } for (i = 0; i < mod->pat; i++) { if (mod->xxp[i] == NULL) { goto err_load; } for (j = 0; j < mod->chn; j++) { int t = mod->xxp[i]->index[j]; if (t < 0 || t >= mod->trk || mod->xxt[t] == NULL) { goto err_load; } } } libxmp_adjust_string(mod->name); for (i = 0; i < mod->ins; i++) { libxmp_adjust_string(mod->xxi[i].name); } for (i = 0; i < mod->smp; i++) { libxmp_adjust_string(mod->xxs[i].name); } libxmp_load_epilogue(ctx); ret = libxmp_prepare_scan(ctx); if (ret < 0) { xmp_release_module(opaque); return ret; } libxmp_scan_sequences(ctx); ctx->state = XMP_STATE_LOADED; return 0; err_load: xmp_release_module(opaque); return -XMP_ERROR_LOAD; } int xmp_load_module(xmp_context opaque, char *path) { struct context_data *ctx = (struct context_data *)opaque; #ifndef LIBXMP_CORE_PLAYER struct module_data *m = &ctx->m; long size; char *temp_name; #endif HIO_HANDLE *h; struct stat st; int ret; D_(D_WARN "path = %s", path); if (stat(path, &st) < 0) { return -XMP_ERROR_SYSTEM; } #ifndef _MSC_VER if (S_ISDIR(st.st_mode)) { errno = EISDIR; return -XMP_ERROR_SYSTEM; } #endif if ((h = hio_open(path, "rb")) == NULL) { return -XMP_ERROR_SYSTEM; } #ifndef LIBXMP_CORE_PLAYER D_(D_INFO "decrunch"); if (decrunch(&h, path, &temp_name) < 0) { ret = -XMP_ERROR_DEPACK; goto err; } size = hio_size(h); if (size < 256) { /* get size after decrunch */ ret = -XMP_ERROR_FORMAT; goto err; } #endif if (ctx->state > XMP_STATE_UNLOADED) xmp_release_module(opaque); #ifndef LIBXMP_CORE_PLAYER m->dirname = get_dirname(path); if (m->dirname == NULL) { ret = -XMP_ERROR_SYSTEM; goto err; } m->basename = get_basename(path); if (m->basename == NULL) { ret = -XMP_ERROR_SYSTEM; goto err; } m->filename = path; /* For ALM, SSMT, etc */ m->size = size; #endif ret = load_module(opaque, h); hio_close(h); #ifndef LIBXMP_CORE_PLAYER unlink_temp_file(temp_name); #endif return ret; #ifndef LIBXMP_CORE_PLAYER err: hio_close(h); unlink_temp_file(temp_name); return ret; #endif } int xmp_load_module_from_memory(xmp_context opaque, void *mem, long size) { struct context_data *ctx = (struct context_data *)opaque; struct module_data *m = &ctx->m; HIO_HANDLE *h; int ret; /* Use size < 0 for unknown/undetermined size */ if (size == 0) size--; if ((h = hio_open_mem(mem, size)) == NULL) return -XMP_ERROR_SYSTEM; if (ctx->state > XMP_STATE_UNLOADED) xmp_release_module(opaque); m->filename = NULL; m->basename = NULL; m->dirname = NULL; m->size = size; ret = load_module(opaque, h); hio_close(h); return ret; } int xmp_load_module_from_file(xmp_context opaque, void *file, long size) { struct context_data *ctx = (struct context_data *)opaque; struct module_data *m = &ctx->m; HIO_HANDLE *h; FILE *f = fdopen(fileno((FILE *)file), "rb"); int ret; if ((h = hio_open_file(f)) == NULL) return -XMP_ERROR_SYSTEM; if (ctx->state > XMP_STATE_UNLOADED) xmp_release_module(opaque); m->filename = NULL; m->basename = NULL; m->dirname = NULL; m->size = hio_size(h); ret = load_module(opaque, h); hio_close(h); return ret; } void xmp_release_module(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int i; /* can't test this here, we must call release_module to clean up * load errors if (ctx->state < XMP_STATE_LOADED) return; */ if (ctx->state > XMP_STATE_LOADED) xmp_end_player(opaque); ctx->state = XMP_STATE_UNLOADED; D_(D_INFO "Freeing memory"); #ifndef LIBXMP_CORE_PLAYER libxmp_release_module_extras(ctx); #endif if (mod->xxt != NULL) { for (i = 0; i < mod->trk; i++) { free(mod->xxt[i]); } free(mod->xxt); } if (mod->xxp != NULL) { for (i = 0; i < mod->pat; i++) { free(mod->xxp[i]); } free(mod->xxp); } if (mod->xxi != NULL) { for (i = 0; i < mod->ins; i++) { free(mod->xxi[i].sub); free(mod->xxi[i].extra); } free(mod->xxi); } if (mod->xxs != NULL) { for (i = 0; i < mod->smp; i++) { if (mod->xxs[i].data != NULL) { free(mod->xxs[i].data - 4); } } free(mod->xxs); free(m->xtra); } #ifndef LIBXMP_CORE_DISABLE_IT if (m->xsmp != NULL) { for (i = 0; i < mod->smp; i++) { if (m->xsmp[i].data != NULL) { free(m->xsmp[i].data - 4); } } free(m->xsmp); } #endif if (m->scan_cnt) { for (i = 0; i < mod->len; i++) free(m->scan_cnt[i]); free(m->scan_cnt); } free(m->comment); D_("free dirname/basename"); free(m->dirname); free(m->basename); } void xmp_scan_module(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; if (ctx->state < XMP_STATE_LOADED) return; libxmp_scan_sequences(ctx); } libxmp-4.4.1/src/fnmatch.h0000664000175000017500000000421012773463510015224 0ustar claudioclaudio/*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _FNMATCH_H_ #define _FNMATCH_H_ #define FNM_NOMATCH 1 /* Match failed. */ #define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ #define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ #define FNM_PERIOD 0x04 /* Period must be matched by period. */ #define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ #define FNM_CASEFOLD 0x10 /* Case insensitive search. */ #define FNM_PREFIX_DIRS 0x20 /* Directory prefixes of pattern match too. */ int fnmatch(const char *pattern, const char *string, int flags); #endif /* !_FNMATCH_H_ */ libxmp-4.4.1/src/virtual.h0000664000175000017500000000311112774567167015307 0ustar claudioclaudio#ifndef LIBXMP_VIRTUAL_H #define LIBXMP_VIRTUAL_H #include "common.h" #define VIRT_ACTION_CUT XMP_INST_NNA_CUT #define VIRT_ACTION_CONT XMP_INST_NNA_CONT #define VIRT_ACTION_OFF XMP_INST_NNA_OFF #define VIRT_ACTION_FADE XMP_INST_NNA_FADE #define VIRT_ACTIVE 0x100 #define VIRT_INVALID -1 int libxmp_virt_on (struct context_data *, int); void libxmp_virt_off (struct context_data *); int libxmp_virt_mute (struct context_data *, int, int); int libxmp_virt_setpatch (struct context_data *, int, int, int, int, int, int, int); int libxmp_virt_cvt8bit (void); void libxmp_virt_setnote (struct context_data *, int, int); void libxmp_virt_setsmp (struct context_data *, int, int); void libxmp_virt_setnna (struct context_data *, int, int); void libxmp_virt_pastnote (struct context_data *, int, int); void libxmp_virt_setvol (struct context_data *, int, int); void libxmp_virt_voicepos (struct context_data *, int, double); double libxmp_virt_getvoicepos (struct context_data *, int); void libxmp_virt_setperiod (struct context_data *, int, double); void libxmp_virt_setpan (struct context_data *, int, int); void libxmp_virt_seteffect (struct context_data *, int, int, int); int libxmp_virt_cstat (struct context_data *, int); int libxmp_virt_mapchannel (struct context_data *, int); void libxmp_virt_resetchannel(struct context_data *, int); void libxmp_virt_resetvoice (struct context_data *, int, int); void libxmp_virt_reset (struct context_data *); void libxmp_virt_release (struct context_data *, int, int); int libxmp_virt_getroot (struct context_data *, int); #endif /* LIBXMP_VIRTUAL_H */ libxmp-4.4.1/src/read_event.c0000664000175000017500000011061412774567167015737 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "common.h" #include "player.h" #include "effects.h" #include "virtual.h" #include "period.h" #ifndef LIBXMP_CORE_PLAYER #include "med_extras.h" #endif static inline int is_valid_note(int note) { return (note >= 0 && note < XMP_MAX_KEYS); } static struct xmp_subinstrument *get_subinstrument(struct context_data *ctx, int ins, int key) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_instrument *instrument; if (IS_VALID_INSTRUMENT(ins)) { instrument = &mod->xxi[ins]; if (is_valid_note(key)) { int mapped = instrument->map[key].ins; if (mapped != 0xff && mapped >= 0 && mapped < instrument->nsm) return &instrument->sub[mapped]; } else { if (mod->xxi[ins].nsm > 0) { return &instrument->sub[0]; } } } return NULL; } static void reset_envelopes(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; if (!IS_VALID_INSTRUMENT(xc->ins)) return; RESET_NOTE(NOTE_ENV_END); xc->v_idx = -1; xc->p_idx = -1; xc->f_idx = -1; } #ifndef LIBXMP_CORE_DISABLE_IT static void reset_envelopes_carry(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi; if (!IS_VALID_INSTRUMENT(xc->ins)) return; RESET_NOTE(NOTE_ENV_END); xxi = libxmp_get_instrument(ctx, xc->ins); /* Reset envelope positions */ if (~xxi->aei.flg & XMP_ENVELOPE_CARRY) { xc->v_idx = -1; } if (~xxi->pei.flg & XMP_ENVELOPE_CARRY) { xc->p_idx = -1; } if (~xxi->fei.flg & XMP_ENVELOPE_CARRY) { xc->f_idx = -1; } } #endif static void set_effect_defaults(struct context_data *ctx, int note, struct xmp_subinstrument *sub, struct channel_data *xc, int is_toneporta) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct smix_data *smix = &ctx->smix; if (sub != NULL && note >= 0) { struct xmp_instrument *xxi; if (xc->ins >= mod->ins) { xxi = &smix->xxi[xc->ins - mod->ins]; } else { xxi = &mod->xxi[xc->ins]; } if (!HAS_QUIRK(QUIRK_PROTRACK)) { xc->finetune = sub->fin; } xc->gvl = sub->gvl; #ifndef LIBXMP_CORE_DISABLE_IT if (sub->ifc & 0x80) { xc->filter.cutoff = (sub->ifc - 0x80) * 2; } else if (~xxi->fei.flg & XMP_ENVELOPE_FLT) { xc->filter.cutoff = 0xff; } xc->filter.envelope = 0x100; if (sub->ifr & 0x80) { xc->filter.resonance = (sub->ifr - 0x80) * 2; } /* else { xc->filter.resonance = 0; } */ #endif libxmp_lfo_set_depth(&xc->insvib.lfo, sub->vde); libxmp_lfo_set_rate(&xc->insvib.lfo, sub->vra >> 2); libxmp_lfo_set_waveform(&xc->insvib.lfo, sub->vwf); xc->insvib.sweep = sub->vsw; libxmp_lfo_set_phase(&xc->vibrato.lfo, 0); libxmp_lfo_set_phase(&xc->tremolo.lfo, 0); } xc->delay = 0; xc->tremor.up = xc->tremor.down = 0; /* Reset arpeggio */ xc->arpeggio.val[0] = 0; xc->arpeggio.count = 0; xc->arpeggio.size = 1; } /* From OpenMPT PortaTarget.mod: * "A new note (with no portamento command next to it) does not reset the * portamento target. That is, if a previous portamento has not finished yet, * calling 3xx or 5xx after the new note will slide it towards the old target. * Once the portamento target period is reached, the target is reset. This * means that if the period is modified by another slide (e.g. 1xx or 2xx), * a following 3xx will not slide back to the original target." */ static void set_period(struct context_data *ctx, int note, struct xmp_subinstrument *sub, struct channel_data *xc, int is_toneporta) { struct module_data *m = &ctx->m; if (sub != NULL && note >= 0) { double per = libxmp_note_to_period(ctx, note, xc->finetune, xc->per_adj); if (!HAS_QUIRK(QUIRK_PROTRACK) || (note > 0 && is_toneporta)) { xc->porta.target = per; } if (xc->period < 1 || !is_toneporta) { xc->period = per; } } } /* From OpenMPT Porta-Pickup.xm: * "An instrument number should not reset the current portamento target. The * portamento target is valid until a new target is specified by combining a * note and a portamento effect." */ static void set_period_ft2(struct context_data *ctx, int note, struct xmp_subinstrument *sub, struct channel_data *xc, int is_toneporta) { if (note > 0 && is_toneporta) { xc->porta.target = libxmp_note_to_period(ctx, note, xc->finetune, xc->per_adj); } if (sub != NULL && note >= 0) { if (xc->period < 1 || !is_toneporta) { xc->period = libxmp_note_to_period(ctx, note, xc->finetune, xc->per_adj); } } } #ifndef LIBXMP_CORE_PLAYER #define IS_SFX_PITCH(x) ((x) == FX_PITCH_ADD || (x) == FX_PITCH_SUB) #define IS_TONEPORTA(x) ((x) == FX_TONEPORTA || (x) == FX_TONE_VSLIDE \ || (x) == FX_PER_TPORTA) #else #define IS_TONEPORTA(x) ((x) == FX_TONEPORTA || (x) == FX_TONE_VSLIDE) #endif #define set_patch(ctx,chn,ins,smp,note) \ libxmp_virt_setpatch(ctx, chn, ins, smp, note, 0, 0, 0) static int read_event_mod(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; int note; struct xmp_subinstrument *sub; int new_invalid_ins = 0; int is_toneporta; int use_ins_vol; xc->flags = 0; note = -1; is_toneporta = 0; use_ins_vol = 0; if (IS_TONEPORTA(e->fxt) || IS_TONEPORTA(e->f2t)) { is_toneporta = 1; } /* Check instrument */ if (e->ins) { int ins = e->ins - 1; use_ins_vol = 1; SET(NEW_INS); xc->fadeout = 0x10000; /* for painlace.mod pat 0 ch 3 echo */ xc->per_flags = 0; xc->offset.val = 0; RESET_NOTE(NOTE_RELEASE|NOTE_FADEOUT); if (IS_VALID_INSTRUMENT(ins)) { sub = get_subinstrument(ctx, ins, e->note - 1); if (is_toneporta) { /* Get new instrument volume */ if (sub != NULL) { /* Dennis Lindroos: instrument volume * is not used on split channels */ if (!xc->split) { xc->volume = sub->vol; } use_ins_vol = 0; } } else { xc->ins = ins; xc->ins_fade = mod->xxi[ins].rls; if (sub != NULL) { if (HAS_QUIRK(QUIRK_PROTRACK)) { xc->finetune = sub->fin; } } } } else { new_invalid_ins = 1; libxmp_virt_resetchannel(ctx, chn); } } /* Check note */ if (e->note) { SET(NEW_NOTE); if (e->note == XMP_KEY_OFF) { SET_NOTE(NOTE_RELEASE); use_ins_vol = 0; } else if (!is_toneporta) { xc->key = e->note - 1; RESET_NOTE(NOTE_END); sub = get_subinstrument(ctx, xc->ins, xc->key); if (!new_invalid_ins && sub != NULL) { int transp = mod->xxi[xc->ins].map[xc->key].xpo; int smp; note = xc->key + sub->xpo + transp; smp = sub->sid; if (mod->xxs[smp].len == 0) { smp = -1; } if (smp >= 0 && smp < mod->smp) { set_patch(ctx, chn, xc->ins, smp, note); xc->smp = smp; } } else { xc->flags = 0; use_ins_vol = 0; } } } sub = get_subinstrument(ctx, xc->ins, xc->key); set_effect_defaults(ctx, note, sub, xc, is_toneporta); if (e->ins && sub != NULL) { reset_envelopes(ctx, xc); } /* Process new volume */ if (e->vol) { xc->volume = e->vol - 1; SET(NEW_VOL); } /* Secondary effect handled first */ libxmp_process_fx(ctx, xc, chn, e, 1); libxmp_process_fx(ctx, xc, chn, e, 0); #ifndef LIBXMP_CORE_PLAYER if (IS_SFX_PITCH(e->fxt)) { xc->period = libxmp_note_to_period(ctx, note, xc->finetune, xc->per_adj); } else #endif { set_period(ctx, note, sub, xc, is_toneporta); } if (sub == NULL) { return 0; } if (note >= 0) { xc->note = note; libxmp_virt_voicepos(ctx, chn, xc->offset.val); } if (TEST(OFFSET)) { if (HAS_QUIRK(QUIRK_PROTRACK) || p->flags & XMP_FLAGS_FX9BUG) { xc->offset.val += xc->offset.val2; } RESET(OFFSET); } if (use_ins_vol && !TEST(NEW_VOL) && !xc->split) { xc->volume = sub->vol; } return 0; } static int sustain_check(struct xmp_envelope *env, int idx) { return (env && (env->flg & XMP_ENVELOPE_ON) && (~env->flg & XMP_ENVELOPE_LOOP) && idx == env->data[env->sus << 1]); } static int read_event_ft2(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; int note, key, ins; struct xmp_subinstrument *sub; int new_invalid_ins; int is_toneporta; int use_ins_vol; int k00 = 0; struct xmp_event ev; /* From the OpenMPT DelayCombination.xm test case: * "Naturally, Fasttracker 2 ignores notes next to an out-of-range * note delay. However, to check whether the delay is out of range, * it is simply compared against the current song speed, not taking * any pattern delays into account." */ if (p->frame >= p->speed) { return 0; } memcpy(&ev, e, sizeof (struct xmp_event)); /* From OpenMPT TremorReset.xm test case: * "Even if a tremor effect muted the sample on a previous row, volume * commands should be able to override this effect." */ if (ev.vol) { xc->tremor.count &= ~0x80; } xc->flags = 0; note = -1; key = ev.note; ins = ev.ins; new_invalid_ins = 0; is_toneporta = 0; use_ins_vol = 0; /* From the OpenMPT key_off.xm test case: * "Key off at tick 0 (K00) is very dodgy command. If there is a note * next to it, the note is ignored. If there is a volume column * command or instrument next to it and the current instrument has * no volume envelope, the note is faded out instead of being cut." */ if (ev.fxt == FX_KEYOFF && ev.fxp == 0) { k00 = 1; key = 0; if (ins || ev.vol || ev.f2t) { if (IS_VALID_INSTRUMENT(xc->ins) && ~mod->xxi[xc->ins].aei.flg & XMP_ENVELOPE_ON) { SET_NOTE(NOTE_FADEOUT); ev.fxt = 0; } } } if (IS_TONEPORTA(ev.fxt) || IS_TONEPORTA(ev.f2t)) { is_toneporta = 1; } /* Check instrument */ /* Ignore invalid instruments. The last instrument, invalid or * not, is preserved in channel data (see read_event() below). * Fixes stray delayed notes in forgotten_city.xm. */ if (ins > 0 && !IS_VALID_INSTRUMENT(ins - 1)) { ins = 0; } /* FT2: Retrieve old instrument volume */ if (ins) { if (key == 0 || key >= XMP_KEY_OFF) { struct xmp_subinstrument *sub; /* Previous instrument */ sub = get_subinstrument(ctx, xc->ins, xc->key); /* No note */ if (sub != NULL) { int p = mod->xxc[chn].pan - 128; xc->volume = sub->vol; if (!HAS_QUIRK(QUIRK_FTMOD)) { xc->pan.val = p + ((sub->pan - 128) * (128 - abs(p))) / 128 + 128; } xc->ins_fade = mod->xxi[xc->ins].rls; SET(NEW_VOL); } } } /* Do this regardless if the instrument is invalid or not */ if (ev.ins) { SET(NEW_INS); use_ins_vol = 1; xc->fadeout = 0x10000; xc->per_flags = 0; RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT); if (!k00) { RESET_NOTE(NOTE_FADEOUT); } if (IS_VALID_INSTRUMENT(ins - 1)) { if (!is_toneporta) xc->ins = ins - 1; } else { new_invalid_ins = 1; /* If no note is set FT2 doesn't cut on invalid * instruments (it keeps playing the previous one). * If a note is set it cuts the current sample. */ xc->flags = 0; if (is_toneporta) { key = 0; } } xc->tremor.count = 0x20; } /* Check note */ if (ins) { if (key > 0 && key < XMP_KEY_OFF) { struct xmp_subinstrument *sub; /* Retrieve volume when we have note */ /* and only if we have instrument, otherwise we're in * case 1: new note and no instrument */ /* Current instrument */ sub = get_subinstrument(ctx, xc->ins, key - 1); if (sub != NULL) { int p = mod->xxc[chn].pan - 128; xc->volume = sub->vol; if (!HAS_QUIRK(QUIRK_FTMOD)) { xc->pan.val = p + ((sub->pan - 128) * (128 - abs(p))) / 128 + 128; } xc->ins_fade = mod->xxi[xc->ins].rls; } else { xc->volume = 0; } SET(NEW_VOL); } } if (key) { SET(NEW_NOTE); if (key == XMP_KEY_OFF) { int env_on = 0; int vol_set = ev.vol != 0 || ev.fxt == FX_VOLSET; int delay_fx = ev.fxt == FX_EXTENDED && ev.fxp == 0xd0; struct xmp_envelope *env = NULL; /* OpenMPT NoteOffVolume.xm: * "If an instrument has no volume envelope, a note-off * command should cut the sample completely - unless * there is a volume command next it. This applies to * both volume commands (volume and effect column)." * * ...and unless we have a keyoff+delay without setting * an instrument. See OffDelay.xm. */ if (IS_VALID_INSTRUMENT(xc->ins)) { env = &mod->xxi[xc->ins].aei; if (env->flg & XMP_ENVELOPE_ON) { env_on = 1; } } if (env_on || (!vol_set && (!ev.ins || !delay_fx))) { if (sustain_check(env, xc->v_idx)) { /* See OpenMPT EnvOff.xm. In certain * cases a release event is effective * only in the next frame */ SET_NOTE(NOTE_SUSEXIT); } else { SET_NOTE(NOTE_RELEASE); } use_ins_vol = 0; } else { SET_NOTE(NOTE_FADEOUT); } /* See OpenMPT keyoff+instr.xm, pattern 2 row 0x40 */ if (env_on && ev.fxt == FX_EXTENDED && (ev.fxp >> 4) == EX_DELAY) { /* See OpenMPT OffDelay.xm test case */ if ((ev.fxp & 0xf) != 0) { RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT); } } } else if (key == XMP_KEY_FADE) { /* Handle keyoff + instrument case (NoteOff2.xm) */ SET_NOTE(NOTE_FADEOUT); } else if (is_toneporta) { /* set key to 0 so we can have the tone portamento from * the original note (see funky_stars.xm pos 5 ch 9) */ key = 0; /* And do the same if there's no keyoff (see comic * bakery remix.xm pos 1 ch 3) */ } if (ev.ins == 0 && !IS_VALID_INSTRUMENT(xc->old_ins - 1)) { new_invalid_ins = 1; } if (new_invalid_ins) { libxmp_virt_resetchannel(ctx, chn); } } /* Check note range -- from the OpenMPT test NoteLimit.xm: * "I think one of the first things Fasttracker 2 does when parsing a * pattern cell is calculating the “real” note (i.e. pattern note + * sample transpose), and if this “real” note falls out of its note * range, it is ignored completely (wiped from its internal channel * memory). The instrument number next it, however, is not affected * and remains in the memory." */ if (is_valid_note(key - 1)) { int k = key - 1; sub = get_subinstrument(ctx, xc->ins, k); if (!new_invalid_ins && sub != NULL) { int transp = mod->xxi[xc->ins].map[k].xpo; int k2 = k + sub->xpo + transp; if (k2 < 12 || k2 > 130) { key = 0; RESET(NEW_NOTE); } } } if (is_valid_note(key - 1)) { xc->key = --key; xc->fadeout = 0x10000; RESET_NOTE(NOTE_END); if (sub != NULL) { if (~mod->xxi[xc->ins].aei.flg & XMP_ENVELOPE_ON) { RESET_NOTE(NOTE_RELEASE|NOTE_FADEOUT); } } if (!new_invalid_ins && sub != NULL) { int transp = mod->xxi[xc->ins].map[key].xpo; int smp; note = key + sub->xpo + transp; smp = sub->sid; if (mod->xxs[smp].len == 0) { smp = -1; } if (smp >= 0 && smp < mod->smp) { set_patch(ctx, chn, xc->ins, smp, note); xc->smp = smp; } } else { xc->flags = 0; use_ins_vol = 0; } } sub = get_subinstrument(ctx, xc->ins, xc->key); set_effect_defaults(ctx, note, sub, xc, is_toneporta); if (ins && sub != NULL && !k00) { /* Reset envelopes on new instrument, see olympic.xm pos 10 * But make sure we have an instrument set, see Letting go * pos 4 chn 20 */ reset_envelopes(ctx, xc); } /* Process new volume */ if (ev.vol) { xc->volume = ev.vol - 1; SET(NEW_VOL); if (TEST_NOTE(NOTE_END)) { /* m5v-nine.xm */ xc->fadeout = 0x10000; /* OpenMPT NoteOff.xm */ RESET_NOTE(NOTE_RELEASE|NOTE_FADEOUT); } } /* FT2: always reset sample offset */ xc->offset.val = 0; /* Secondary effect handled first */ libxmp_process_fx(ctx, xc, chn, &ev, 1); libxmp_process_fx(ctx, xc, chn, &ev, 0); set_period_ft2(ctx, note, sub, xc, is_toneporta); if (sub == NULL) { return 0; } if (note >= 0) { xc->note = note; /* From the OpenMPT test cases (3xx-no-old-samp.xm): * "An offset effect that points beyond the sample end should * stop playback on this channel." * * ... except in Skale Tracker (and possibly others), so make this a * FastTracker2 quirk. See Armada Tanks game.it (actually an XM). * Reported by Vladislav Suschikh. */ if (HAS_QUIRK(QUIRK_FT2BUGS) && xc->offset.val >= mod->xxs[sub->sid].len) { libxmp_virt_resetchannel(ctx, chn); } else { /* (From Decibelter - Cosmic 'Wegian Mamas.xm p04 ch7) * We retrigger the sample only if we have a new note * without tone portamento, otherwise we won't play * sweeps and loops correctly. */ libxmp_virt_voicepos(ctx, chn, xc->offset.val); } } if (use_ins_vol && !TEST(NEW_VOL)) { xc->volume = sub->vol; } return 0; } static int read_event_st3(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; int note; struct xmp_subinstrument *sub; int not_same_ins; int is_toneporta; int use_ins_vol; xc->flags = 0; note = -1; not_same_ins = 0; is_toneporta = 0; use_ins_vol = 0; if (IS_TONEPORTA(e->fxt) || IS_TONEPORTA(e->f2t)) { is_toneporta = 1; } if (libxmp_virt_mapchannel(ctx, chn) < 0 && xc->ins != e->ins - 1) { is_toneporta = 0; } /* Check instrument */ if (e->ins) { int ins = e->ins - 1; SET(NEW_INS); use_ins_vol = 1; xc->fadeout = 0x10000; xc->per_flags = 0; xc->offset.val = 0; RESET_NOTE(NOTE_RELEASE|NOTE_FADEOUT); if (IS_VALID_INSTRUMENT(ins)) { /* valid ins */ if (xc->ins != ins) { not_same_ins = 1; if (!is_toneporta) { xc->ins = ins; xc->ins_fade = mod->xxi[ins].rls; } else { /* Get new instrument volume */ sub = get_subinstrument(ctx, ins, e->note - 1); if (sub != NULL) { xc->volume = sub->vol; use_ins_vol = 0; } } } } else { /* invalid ins */ /* Ignore invalid instruments */ xc->flags = 0; use_ins_vol = 0; } } /* Check note */ if (e->note) { SET(NEW_NOTE); if (e->note == XMP_KEY_OFF) { SET_NOTE(NOTE_RELEASE); use_ins_vol = 0; } else if (is_toneporta) { /* Always retrig in tone portamento: Fix portamento in * 7spirits.s3m, mod.Biomechanoid */ if (not_same_ins) { xc->offset.val = 0; } } else { xc->key = e->note - 1; RESET_NOTE(NOTE_END); sub = get_subinstrument(ctx, xc->ins, xc->key); if (sub != NULL) { int transp = mod->xxi[xc->ins].map[xc->key].xpo; int smp; note = xc->key + sub->xpo + transp; smp = sub->sid; if (mod->xxs[smp].len == 0) { smp = -1; } if (smp >= 0 && smp < mod->smp) { set_patch(ctx, chn, xc->ins, smp, note); xc->smp = smp; } } else { xc->flags = 0; use_ins_vol = 0; } } } sub = get_subinstrument(ctx, xc->ins, xc->key); set_effect_defaults(ctx, note, sub, xc, is_toneporta); if (e->ins && sub != NULL) { reset_envelopes(ctx, xc); } /* Process new volume */ if (e->vol) { xc->volume = e->vol - 1; SET(NEW_VOL); } /* Secondary effect handled first */ libxmp_process_fx(ctx, xc, chn, e, 1); libxmp_process_fx(ctx, xc, chn, e, 0); set_period(ctx, note, sub, xc, is_toneporta); if (sub == NULL) { return 0; } if (note >= 0) { xc->note = note; libxmp_virt_voicepos(ctx, chn, xc->offset.val); } if (use_ins_vol && !TEST(NEW_VOL)) { xc->volume = sub->vol; } if (HAS_QUIRK(QUIRK_ST3BUGS) && TEST(NEW_VOL)) { xc->volume = xc->volume * p->gvol / m->volbase; } return 0; } #ifndef LIBXMP_CORE_DISABLE_IT static inline void copy_channel(struct player_data *p, int to, int from) { if (to > 0 && to != from) { memcpy(&p->xc_data[to], &p->xc_data[from], sizeof (struct channel_data)); } } static inline int has_note_event(struct xmp_event *e) { return (e->note && e->note <= XMP_MAX_KEYS); } static int check_fadeout(struct context_data *ctx, struct channel_data *xc, int ins) { struct xmp_instrument *xxi = libxmp_get_instrument(ctx, ins); if (xxi == NULL) { return 1; } return (~xxi->aei.flg & XMP_ENVELOPE_ON || ~xxi->aei.flg & XMP_ENVELOPE_CARRY || xc->ins_fade == 0 || xc->fadeout <= xc->ins_fade); } static int check_invalid_sample(struct context_data *ctx, int ins, int key) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; if (ins < mod->ins) { int smp = mod->xxi[ins].map[key].ins; if (smp == 0xff || smp >= mod->smp) { return 1; }; } return 0; } static void fix_period(struct context_data *ctx, int chn, struct xmp_subinstrument *sub) { if (sub->nna == XMP_INST_NNA_CONT) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; struct xmp_instrument *xxi = libxmp_get_instrument(ctx, xc->ins); xc->period = libxmp_note_to_period(ctx, xc->key + sub->xpo + xxi->map[xc->key_porta].xpo, xc->finetune, xc->per_adj); } } static int is_same_sid(struct context_data *ctx, int chn, int ins, int key) { struct player_data *p = &ctx->p; struct channel_data *xc = &p->xc_data[chn]; struct xmp_subinstrument *s1, *s2; s1 = get_subinstrument(ctx, ins, key); s2 = get_subinstrument(ctx, xc->ins, xc->key); return (s1 && s2 && s1->sid == s2->sid); } static int read_event_it(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; int note, key; struct xmp_subinstrument *sub; int not_same_ins, not_same_smp; int new_invalid_ins; int is_toneporta, is_release; int candidate_ins; int reset_env; int use_ins_vol; int sample_mode; int toneporta_offset; int disabled_toneporta; int retrig_ins; struct xmp_event ev; memcpy(&ev, e, sizeof (struct xmp_event)); /* Emulate Impulse Tracker "always read instrument" bug */ if (ev.ins) { xc->delayed_ins = 0; } else if (ev.note && xc->delayed_ins) { ev.ins = xc->delayed_ins; xc->delayed_ins = 0; } xc->flags = 0; note = -1; key = ev.note; not_same_ins = 0; not_same_smp = 0; new_invalid_ins = 0; is_toneporta = 0; is_release = 0; reset_env = 0; use_ins_vol = 0; candidate_ins = xc->ins; sample_mode = !HAS_QUIRK(QUIRK_VIRTUAL); toneporta_offset = 0; disabled_toneporta = 0; retrig_ins = 0; /* Keyoff + instrument retrigs current instrument in old fx mode */ if (HAS_QUIRK(QUIRK_ITOLDFX)) { if (ev.note == XMP_KEY_OFF && IS_VALID_INSTRUMENT(ev.ins -1)) { retrig_ins = 1; } } /* Notes with unmapped instruments are ignored */ if (ev.ins) { if (ev.ins <= mod->ins && has_note_event(&ev)) { int ins = ev.ins - 1; if (check_invalid_sample(ctx, ins, ev.note - 1)) { candidate_ins = ins; memset(&ev, 0, sizeof (ev)); } } } else { if (has_note_event(&ev)) { int ins = xc->old_ins - 1; if (!IS_VALID_INSTRUMENT(ins)) { new_invalid_ins = 1; } else if (check_invalid_sample(ctx, ins, ev.note - 1)) { memset(&ev, 0, sizeof (ev)); } } } if (IS_TONEPORTA(ev.fxt) || IS_TONEPORTA(ev.f2t)) { is_toneporta = 1; } if (TEST_NOTE(NOTE_RELEASE | NOTE_FADEOUT)) { is_release = 1; } if (xc->period <= 0 || TEST_NOTE(NOTE_END)) { is_toneporta = 0; } /* Off-Porta.it */ if (is_toneporta && ev.fxt == FX_OFFSET) { disabled_toneporta = 1; is_toneporta = 0; if (!HAS_QUIRK(QUIRK_PRENV)) { toneporta_offset = 1; RESET_NOTE(NOTE_ENV_END); } } /* Check instrument */ if (ev.ins) { int ins = ev.ins - 1; int set_new_ins = 1; /* portamento_after_keyoff.it test case */ if (is_release && !key) { if (is_toneporta) { if (HAS_QUIRK(QUIRK_PRENV) || TEST_NOTE(NOTE_SET)) { is_toneporta = 0; reset_envelopes_carry(ctx, xc); } } else { /* fixes OpenMPT wnoteoff.it */ reset_envelopes_carry(ctx, xc); } } if (is_toneporta && xc->ins == ins) { if (!HAS_QUIRK(QUIRK_PRENV)) { if (is_same_sid(ctx, chn, ins, key - 1)) { /* same instrument and same sample */ set_new_ins = !is_release; } else { /* same instrument, different sample */ not_same_ins = 1; /* need this too */ not_same_smp = 1; } } } if (set_new_ins) { SET(NEW_INS); use_ins_vol = 1; reset_env = 1; } xc->per_flags = 0; if (IS_VALID_INSTRUMENT(ins)) { /* valid ins */ /* See OpenMPT StoppedInstrSwap.it for cut case */ if (!key && !TEST_NOTE(NOTE_KEY_CUT)) { /* Retrig in new ins in sample mode */ if (sample_mode && TEST_NOTE(NOTE_END)) { libxmp_virt_voicepos(ctx, chn, 0); } /* IT: Reset note for every new != ins */ if (xc->ins == ins) { SET(NEW_INS); use_ins_vol = 1; } else { key = xc->key + 1; } RESET_NOTE(NOTE_SET); } if (xc->ins != ins && (!is_toneporta || !HAS_QUIRK(QUIRK_PRENV))) { candidate_ins = ins; if (!is_same_sid(ctx, chn, ins, key - 1)) { not_same_ins = 1; if (is_toneporta) { /* Get new instrument volume */ sub = get_subinstrument(ctx, ins, key); if (sub != NULL) { xc->volume = sub->vol; use_ins_vol = 0; } } } } } else { /* In sample mode invalid ins cut previous ins */ if (sample_mode) { xc->volume = 0; } /* Ignore invalid instruments */ new_invalid_ins = 1; xc->flags = 0; use_ins_vol = 0; } } /* Check note */ if (key && !new_invalid_ins) { SET(NEW_NOTE); SET_NOTE(NOTE_SET); if (key == XMP_KEY_FADE) { SET_NOTE(NOTE_FADEOUT); reset_env = 0; use_ins_vol = 0; } else if (key == XMP_KEY_CUT) { SET_NOTE(NOTE_END | NOTE_CUT | NOTE_KEY_CUT); xc->period = 0; libxmp_virt_resetchannel(ctx, chn); } else if (key == XMP_KEY_OFF) { struct xmp_envelope *env = NULL; if (IS_VALID_INSTRUMENT(xc->ins)) { env = &mod->xxi[xc->ins].aei; } if (sustain_check(env, xc->v_idx)) { SET_NOTE(NOTE_SUSEXIT); } else { SET_NOTE(NOTE_RELEASE); } SET(KEY_OFF); reset_env = 0; use_ins_vol = 0; } else { /* portamento_after_keyoff.it test case */ /* also see suburban_streets o13 c45 */ if (ev.ins || !is_toneporta) { if (!disabled_toneporta) { reset_env = 1; } } if (is_toneporta) { if (not_same_ins || TEST_NOTE(NOTE_END)) { SET(NEW_INS); RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT|NOTE_FADEOUT); } else { if (is_valid_note(key - 1)) { xc->key_porta = key - 1; } key = 0; } } } } if (is_valid_note(key - 1) && !new_invalid_ins) { if (TEST_NOTE(NOTE_CUT)) { use_ins_vol = 1; /* See OpenMPT NoteOffInstr.it */ } xc->key = --key; RESET_NOTE(NOTE_END); sub = get_subinstrument(ctx, candidate_ins, key); if (sub != NULL) { int transp = mod->xxi[candidate_ins].map[key].xpo; int smp, to; int rvv; note = key + sub->xpo + transp; smp = sub->sid; if (smp >= mod->smp || mod->xxs[smp].len == 0) { smp = -1; } if (not_same_smp) { fix_period(ctx, chn, sub); libxmp_virt_resetchannel(ctx, chn); } to = libxmp_virt_setpatch(ctx, chn, candidate_ins, smp, note, sub->nna, sub->dct, sub->dca); /* Random value for volume swing */ rvv = sub->rvv & 0xff; if (rvv) { CLAMP(rvv, 0, 100); xc->rvv = rand() % (rvv + 1); } else { xc->rvv = 0; } /* Random value for pan swing */ rvv = (sub->rvv & 0xff00) >> 8; if (rvv) { CLAMP(rvv, 0, 64); xc->rpv = rand() % (rvv + 1) - (rvv / 2); } else { xc->rpv = 0; } if (to < 0) return -1; if (to != chn) { copy_channel(p, to, chn); p->xc_data[to].flags = 0; } if (smp >= 0) { /* Not sure if needed */ xc->smp = smp; } } else { xc->flags = 0; use_ins_vol = 0; } } /* Do after virtual channel copy */ if (is_toneporta || retrig_ins) { if (HAS_QUIRK(QUIRK_PRENV) && ev.ins) { reset_envelopes_carry(ctx, xc); } } if (IS_VALID_INSTRUMENT(candidate_ins)) { if (xc->ins != candidate_ins) { /* Reset envelopes if instrument changes */ reset_envelopes(ctx, xc); } xc->ins = candidate_ins; xc->ins_fade = mod->xxi[candidate_ins].rls; } /* Reset in case of new instrument and the previous envelope has * finished (OpenMPT test EnvReset.it). This must take place after * channel copies in case of NNA (see test/test.it) * Also if we have envelope in carry mode, check fadeout */ if (ev.ins && TEST_NOTE(NOTE_ENV_END)) { if (check_fadeout(ctx, xc, candidate_ins)) { reset_envelopes(ctx, xc); } else { reset_env = 0; } } if (reset_env) { if (ev.note) { RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT|NOTE_FADEOUT); } /* Set after copying to new virtual channel (see ambio.it) */ xc->fadeout = 0x10000; } /* See OpenMPT wnoteoff.it vs noteoff3.it */ if (retrig_ins && not_same_ins) { SET(NEW_INS); libxmp_virt_voicepos(ctx, chn, 0); xc->fadeout = 0x10000; RESET_NOTE(NOTE_RELEASE|NOTE_SUSEXIT|NOTE_FADEOUT); } sub = get_subinstrument(ctx, xc->ins, xc->key); set_effect_defaults(ctx, note, sub, xc, is_toneporta); if (sub != NULL) { if (note >= 0) { /* Reset pan, see OpenMPT PanReset.it */ if (sub->pan >= 0) { xc->pan.val = sub->pan; xc->pan.surround = 0; } if (TEST_NOTE(NOTE_CUT)) { reset_envelopes(ctx, xc); } else if (!toneporta_offset) { reset_envelopes_carry(ctx, xc); } RESET_NOTE(NOTE_CUT); } } /* Process new volume */ if (ev.vol && (!TEST_NOTE(NOTE_CUT) || ev.ins != 0)) { if (key != XMP_KEY_OFF) { /* See OpenMPT NoteOffInstr.it */ xc->volume = ev.vol - 1; SET(NEW_VOL); } } /* IT: always reset sample offset */ xc->offset.val &= ~0xffff; /* According to Storlek test 25, Impulse Tracker handles the volume * column effects after the standard effects. */ libxmp_process_fx(ctx, xc, chn, &ev, 0); libxmp_process_fx(ctx, xc, chn, &ev, 1); set_period(ctx, note, sub, xc, is_toneporta); if (sub == NULL) { return 0; } if (note >= 0) { xc->note = note; libxmp_virt_voicepos(ctx, chn, xc->offset.val); } if (use_ins_vol && !TEST(NEW_VOL)) { xc->volume = sub->vol; } return 0; } #endif #ifndef LIBXMP_CORE_PLAYER static int read_event_med(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; int note; struct xmp_subinstrument *sub; int new_invalid_ins = 0; int is_toneporta; int use_ins_vol; int finetune; xc->flags = 0; note = -1; is_toneporta = 0; use_ins_vol = 0; if (e->fxt == FX_TONEPORTA || e->fxt == FX_TONE_VSLIDE) { is_toneporta = 1; } /* Check instrument */ if (e->ins && e->note) { int ins = e->ins - 1; use_ins_vol = 1; SET(NEW_INS); xc->fadeout = 0x10000; xc->offset.val = 0; RESET_NOTE(NOTE_RELEASE|NOTE_FADEOUT); if (IS_VALID_INSTRUMENT(ins)) { if (is_toneporta) { /* Get new instrument volume */ sub = get_subinstrument(ctx, ins, e->note - 1); if (sub != NULL) { xc->volume = sub->vol; use_ins_vol = 0; } } else { xc->ins = ins; xc->ins_fade = mod->xxi[ins].rls; } } else { new_invalid_ins = 1; libxmp_virt_resetchannel(ctx, chn); } MED_CHANNEL_EXTRAS(*xc)->arp = 0; MED_CHANNEL_EXTRAS(*xc)->aidx = 0; } else { /* Hold */ if (e->ins && !e->note) { use_ins_vol = 1; } } /* Check note */ if (e->note) { SET(NEW_NOTE); if (e->note == XMP_KEY_OFF) { SET_NOTE(NOTE_RELEASE); use_ins_vol = 0; } else if (e->note == XMP_KEY_CUT) { SET_NOTE(NOTE_END); xc->period = 0; libxmp_virt_resetchannel(ctx, chn); } else if (!is_toneporta && IS_VALID_INSTRUMENT(xc->ins)) { struct xmp_instrument *xxi = &mod->xxi[xc->ins]; xc->key = e->note - 1; RESET_NOTE(NOTE_END); xc->per_adj = 0.0; if (xxi->nsm > 1 && HAS_MED_INSTRUMENT_EXTRAS(*xxi)) { /* synth or iffoct */ if (MED_INSTRUMENT_EXTRAS(*xxi)->vts == 0 && MED_INSTRUMENT_EXTRAS(*xxi)->wts == 0) { /* iffoct */ xc->per_adj = 2.0; } } sub = get_subinstrument(ctx, xc->ins, xc->key); if (!new_invalid_ins && sub != NULL) { int transp = xxi->map[xc->key].xpo; int smp; note = xc->key + sub->xpo + transp; smp = sub->sid; if (mod->xxs[smp].len == 0) { smp = -1; } if (smp >= 0 && smp < mod->smp) { set_patch(ctx, chn, xc->ins, smp, note); xc->smp = smp; } } else { xc->flags = 0; use_ins_vol = 0; } } } sub = get_subinstrument(ctx, xc->ins, xc->key); /* Keep effect-set finetune if no instrument set */ finetune = xc->finetune; set_effect_defaults(ctx, note, sub, xc, is_toneporta); if (!e->ins) { xc->finetune = finetune; } if (e->ins && sub != NULL) { reset_envelopes(ctx, xc); } /* Process new volume */ if (e->vol) { xc->volume = e->vol - 1; SET(NEW_VOL); } /* Secondary effect handled first */ libxmp_process_fx(ctx, xc, chn, e, 1); libxmp_process_fx(ctx, xc, chn, e, 0); set_period(ctx, note, sub, xc, is_toneporta); if (sub == NULL) { return 0; } if (note >= 0) { xc->note = note; libxmp_virt_voicepos(ctx, chn, xc->offset.val); } if (use_ins_vol && !TEST(NEW_VOL)) { xc->volume = sub->vol; } return 0; } #endif static int read_event_smix(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct channel_data *xc = &p->xc_data[chn]; struct xmp_subinstrument *sub; int is_smix_ins; int ins, note, transp, smp; xc->flags = 0; if (!e->ins) return 0; is_smix_ins = 0; ins = e->ins - 1; SET(NEW_INS); xc->fadeout = 0x10000; xc->per_flags = 0; xc->offset.val = 0; RESET_NOTE(NOTE_RELEASE); xc->ins = ins; if (ins >= mod->ins && ins < mod->ins + smix->ins) { is_smix_ins = 1; xc->ins_fade = smix->xxi[xc->ins - mod->ins].rls; } SET(NEW_NOTE); if (e->note == XMP_KEY_OFF) { SET_NOTE(NOTE_RELEASE); return 0; } xc->key = e->note - 1; RESET_NOTE(NOTE_END); if (is_smix_ins) { sub = &smix->xxi[xc->ins - mod->ins].sub[0]; if (sub == NULL) { return 0; } note = xc->key + sub->xpo; smp = sub->sid; if (smix->xxs[smp].len == 0) smp = -1; if (smp >= 0 && smp < smix->smp) { smp += mod->smp; set_patch(ctx, chn, xc->ins, smp, note); xc->smp = smp; } } else { transp = mod->xxi[xc->ins].map[xc->key].xpo; sub = get_subinstrument(ctx, xc->ins, xc->key); if (sub == NULL) { return 0; } note = xc->key + sub->xpo + transp; smp = sub->sid; if (mod->xxs[smp].len == 0) smp = -1; if (smp >= 0 && smp < mod->smp) { set_patch(ctx, chn, xc->ins, smp, note); xc->smp = smp; } } set_effect_defaults(ctx, note, sub, xc, 0); set_period(ctx, note, sub, xc, 0); if (e->ins) { reset_envelopes(ctx, xc); } xc->volume = e->vol - 1; xc->note = note; libxmp_virt_voicepos(ctx, chn, xc->offset.val); return 0; } int libxmp_read_event(struct context_data *ctx, struct xmp_event *e, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct channel_data *xc = &p->xc_data[chn]; if (e->ins != 0) xc->old_ins = e->ins; if (TEST_NOTE(NOTE_SAMPLE_END)) { SET_NOTE(NOTE_END); } if (chn >= m->mod.chn) { return read_event_smix(ctx, e, chn); } else switch (m->read_event_type) { case READ_EVENT_MOD: return read_event_mod(ctx, e, chn); case READ_EVENT_FT2: return read_event_ft2(ctx, e, chn); case READ_EVENT_ST3: return read_event_st3(ctx, e, chn); #ifndef LIBXMP_CORE_DISABLE_IT case READ_EVENT_IT: return read_event_it(ctx, e, chn); #endif #ifndef LIBXMP_CORE_PLAYER case READ_EVENT_MED: return read_event_med(ctx, e, chn); #endif default: return read_event_mod(ctx, e, chn); } } libxmp-4.4.1/src/smix.c0000664000175000017500000001605212774567167014604 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "common.h" #include "period.h" #include "player.h" #include "hio.h" struct xmp_instrument *libxmp_get_instrument(struct context_data *ctx, int ins) { struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_instrument *xxi; if (ins < mod->ins) { xxi = &mod->xxi[ins]; } else if (ins < mod->ins + smix->ins) { xxi = &smix->xxi[ins - mod->ins]; } else { xxi = NULL; } return xxi; } struct xmp_sample *libxmp_get_sample(struct context_data *ctx, int smp) { struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_sample *xxs; if (smp < mod->smp) { xxs = &mod->xxs[smp]; } else if (smp < mod->smp + smix->smp) { xxs = &smix->xxs[smp - mod->smp]; } else { xxs = NULL; } return xxs; } int xmp_start_smix(xmp_context opaque, int chn, int smp) { struct context_data *ctx = (struct context_data *)opaque; struct smix_data *smix = &ctx->smix; if (ctx->state > XMP_STATE_LOADED) { return -XMP_ERROR_STATE; } smix->xxi = calloc(sizeof (struct xmp_instrument), smp); if (smix->xxi == NULL) { goto err; } smix->xxs = calloc(sizeof (struct xmp_sample), smp); if (smix->xxs == NULL) { goto err1; } smix->chn = chn; smix->ins = smix->smp = smp; return 0; err1: free(smix->xxi); err: return -XMP_ERROR_INTERNAL; } int xmp_smix_play_instrument(xmp_context opaque, int ins, int note, int vol, int chn) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_event *event; if (ctx->state < XMP_STATE_PLAYING) { return -XMP_ERROR_STATE; } if (chn >= smix->chn || ins >= mod->ins) { return -XMP_ERROR_INVALID; } if (note == 0) { note = 60; /* middle C note number */ } event = &p->inject_event[mod->chn + chn]; memset(event, 0, sizeof (struct xmp_event)); event->note = note + 1; event->ins = ins + 1; event->vol = vol + 1; event->_flag = 1; return 0; } int xmp_smix_play_sample(xmp_context opaque, int ins, int note, int vol, int chn) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct xmp_event *event; if (ctx->state < XMP_STATE_PLAYING) { return -XMP_ERROR_STATE; } if (chn >= smix->chn || ins >= smix->ins) { return -XMP_ERROR_INVALID; } if (note == 0) { note = 60; /* middle C note number */ } event = &p->inject_event[mod->chn + chn]; memset(event, 0, sizeof (struct xmp_event)); event->note = note + 1; event->ins = mod->ins + ins + 1; event->vol = vol + 1; event->_flag = 1; return 0; } int xmp_smix_channel_pan(xmp_context opaque, int chn, int pan) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct channel_data *xc; if (chn >= smix->chn || pan < 0 || pan > 255) { return -XMP_ERROR_INVALID; } xc = &p->xc_data[m->mod.chn + chn]; xc->pan.val = pan; return 0; } int xmp_smix_load_sample(xmp_context opaque, int num, char *path) { struct context_data *ctx = (struct context_data *)opaque; struct smix_data *smix = &ctx->smix; struct module_data *m = &ctx->m; struct xmp_instrument *xxi; struct xmp_sample *xxs; HIO_HANDLE *h; uint32 magic; int chn, rate, bits, size; int retval = -XMP_ERROR_INTERNAL; if (num >= smix->ins) { retval = -XMP_ERROR_INVALID; goto err; } xxi = &smix->xxi[num]; xxs = &smix->xxs[num]; h = hio_open(path, "rb"); if (h == NULL) { retval = -XMP_ERROR_SYSTEM; goto err; } /* Init instrument */ xxi->sub = calloc(sizeof(struct xmp_subinstrument), 1); if (xxi->sub == NULL) { retval = -XMP_ERROR_SYSTEM; goto err1; } xxi->vol = m->volbase; xxi->nsm = 1; xxi->sub[0].sid = num; xxi->sub[0].vol = xxi->vol; xxi->sub[0].pan = 0x80; /* Load sample */ magic = hio_read32b(h); if (magic != 0x52494646) { /* RIFF */ retval = -XMP_ERROR_FORMAT; goto err2; } if (hio_seek(h, 22, SEEK_SET) < 0) { retval = -XMP_ERROR_SYSTEM; goto err2; } chn = hio_read16l(h); if (chn != 1) { retval = -XMP_ERROR_FORMAT; goto err2; } rate = hio_read32l(h); if (rate == 0) { retval = -XMP_ERROR_FORMAT; goto err2; } if (hio_seek(h, 34, SEEK_SET) < 0) { retval = -XMP_ERROR_SYSTEM; goto err2; } bits = hio_read16l(h); if (bits == 0) { retval = -XMP_ERROR_FORMAT; goto err2; } if (hio_seek(h, 40, SEEK_SET) < 0) { retval = -XMP_ERROR_SYSTEM; goto err2; } size = hio_read32l(h) / (bits / 8); if (size == 0) { retval = -XMP_ERROR_FORMAT; goto err2; } libxmp_c2spd_to_note(rate, &xxi->sub[0].xpo, &xxi->sub[0].fin); xxs->len = 8 * size / bits; xxs->lps = 0; xxs->lpe = 0; xxs->flg = bits == 16 ? XMP_SAMPLE_16BIT : 0; xxs->data = malloc(size); if (xxs->data == NULL) { retval = -XMP_ERROR_SYSTEM; goto err2; } if (hio_seek(h, 44, SEEK_SET) < 0) { retval = -XMP_ERROR_SYSTEM; goto err2; } if (hio_read(xxs->data, 1, size, h) != size) { retval = -XMP_ERROR_SYSTEM; goto err2; } hio_close(h); return 0; err2: free(xxi->sub); xxi->sub = NULL; err1: hio_close(h); err: return retval; } int xmp_smix_release_sample(xmp_context opaque, int num) { struct context_data *ctx = (struct context_data *)opaque; struct smix_data *smix = &ctx->smix; if (num >= smix->ins) { return -XMP_ERROR_INVALID; } free(smix->xxs[num].data); free(smix->xxi[num].sub); smix->xxs[num].data = NULL; smix->xxi[num].sub = NULL; return 0; } void xmp_end_smix(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct smix_data *smix = &ctx->smix; int i; for (i = 0; i < smix->smp; i++) { xmp_smix_release_sample(opaque, i); } free(smix->xxs); free(smix->xxi); } libxmp-4.4.1/src/hio.h0000664000175000017500000000173212773463510014371 0ustar claudioclaudio#ifndef XMP_HIO_H #define XMP_HIO_H #include #include #include #include "memio.h" #define HIO_HANDLE_TYPE(x) ((x)->type) typedef struct { #define HIO_HANDLE_TYPE_FILE 0 #define HIO_HANDLE_TYPE_MEMORY 1 int type; long size; union { FILE *file; MFILE *mem; } handle; int error; } HIO_HANDLE; int8 hio_read8s (HIO_HANDLE *); uint8 hio_read8 (HIO_HANDLE *); uint16 hio_read16l (HIO_HANDLE *); uint16 hio_read16b (HIO_HANDLE *); uint32 hio_read24l (HIO_HANDLE *); uint32 hio_read24b (HIO_HANDLE *); uint32 hio_read32l (HIO_HANDLE *); uint32 hio_read32b (HIO_HANDLE *); size_t hio_read (void *, size_t, size_t, HIO_HANDLE *); int hio_seek (HIO_HANDLE *, long, int); long hio_tell (HIO_HANDLE *); int hio_eof (HIO_HANDLE *); int hio_error (HIO_HANDLE *); HIO_HANDLE *hio_open (void *, char *); HIO_HANDLE *hio_open_mem (void *, long); HIO_HANDLE *hio_open_file (FILE *); int hio_close (HIO_HANDLE *); long hio_size (HIO_HANDLE *); #endif libxmp-4.4.1/src/med_extras.c0000664000175000017500000002416312775035311015737 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "common.h" #include "player.h" #include "virtual.h" #include "effects.h" #include "med_extras.h" #ifdef __SUNPRO_C #pragma error_messages (off,E_STATEMENT_NOT_REACHED) #endif /* Commands in the volume and waveform sequence table: * * Cmd Vol Wave Action * * 0xff END End sequence * 0xfe JMP Jump * 0xfd - ARE End arpeggio definition * 0xfc - ARP Begin arpeggio definition * 0xfb HLT Halt * 0xfa JWS JVS Jump waveform/volume sequence * 0xf9 - - * 0xf8 - - * 0xf7 - VWF Set vibrato waveform * 0xf6 EST RES ?/reset pitch * 0xf5 EN2 VBS Looping envelope/set vibrato speed * 0xf4 EN1 VBD One shot envelope/set vibrato depth * 0xf3 CHU Change volume/pitch up speed * 0xf2 CHD Change volume/pitch down speed * 0xf1 WAI Wait * 0xf0 SPD Set speed */ #define VT me->vol_table[xc->ins][ce->vp++] #define WT me->wav_table[xc->ins][ce->wp++] #define VT_SKIP ce->vp++ #define WT_SKIP ce->wp++ static const int sine[32] = { 0, 49, 97, 141, 180, 212, 235, 250, 255, 250, 235, 212, 180, 141, 97, 49, 0, -49, -97,-141,-180,-212,-235,-250, -255,-250,-235,-212,-180,-141, -97, -49 }; int libxmp_med_change_period(struct context_data *ctx, struct channel_data *xc) { struct med_channel_extras *ce = xc->extra; int vib; /* Vibrato */ #if 0 if (ce->vib_wf >= xxi[xc->ins].nsm) /* invalid waveform */ return 0; if (xxs[xxi[xc->ins][ce->vib_wf].sid].len != 32) return 0; #endif /* FIXME: always using sine waveform */ vib = (sine[ce->vib_idx >> 5] * ce->vib_depth) >> 10; ce->vib_idx += ce->vib_speed; ce->vib_idx %= (32 << 5); return vib; } int libxmp_med_linear_bend(struct context_data *ctx, struct channel_data *xc) { struct module_data *m = &ctx->m; struct med_module_extras *me = m->extra; struct med_channel_extras *ce = xc->extra; int arp; /* Arpeggio */ if (ce->arp == 0) return 0; if (me->wav_table[xc->ins][ce->arp] == 0xfd) /* empty arpeggio */ return 0; arp = me->wav_table[xc->ins][ce->aidx++]; if (arp == 0xfd) { ce->aidx = ce->arp; arp = me->wav_table[xc->ins][ce->aidx++]; } return (100 << 7) * arp; } void libxmp_med_play_extras(struct context_data *ctx, struct channel_data *xc, int chn) { struct module_data *m = &ctx->m; struct player_data *p = &ctx->p; struct xmp_module *mod = &m->mod; struct med_module_extras *me; struct med_channel_extras *ce; struct med_instrument_extras *ie; int b, jws = 0, jvs = 0, loop; int temp; if (!HAS_MED_MODULE_EXTRAS(*m)) return; me = (struct med_module_extras *)m->extra; ce = (struct med_channel_extras *)xc->extra; ie = MED_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins]); /* Handle hold/decay */ /* on the first row of a held note, continue note if ce->hold is 2 * (this is set after pre-fetching the next row and see if we * continue to hold. On remaining rows with hold on, we have the * FX_MED_HOLD effect and ce->hold set to 1. On the last row, see * if ce->hold_count is set (meaning that a note was held) and * ce->hold is 0 (meaning that it's not held anymore). Then * procceed with normal frame counting until decay. */ if (ce->hold_count) { /* was held in the past */ if (!ce->hold && p->frame >= ie->hold) { /* but not now */ SET_NOTE(NOTE_FADEOUT); ce->hold_count = 0; } } else if (ie->hold) { /* has instrument hold */ if (p->frame >= ie->hold && ce->hold == 0) { SET_NOTE(NOTE_FADEOUT); } } if (p->frame == (p->speed - 1) && ce->hold != 2) { ce->hold = 0; } /* Handle synth */ if (me->vol_table[xc->ins] == NULL || me->wav_table[xc->ins] == NULL) { ce->volume = 64; /* we need this in extras_get_volume() */ return; } if (p->frame == 0 && TEST(NEW_NOTE)) { ce->period = xc->period; if (TEST(NEW_INS)) { ce->arp = ce->aidx = 0; ce->vp = ce->vc = ce->vw = 0; ce->wp = ce->wc = ce->ww = 0; ce->env_wav = -1; ce->env_idx = 0; ce->flags &= ~MED_SYNTH_ENV_LOOP; ce->vv = 0; ce->wv = 0; ce->vs = ie->vts; ce->ws = ie->wts; } } if (ce->vs > 0 && ce->vc-- == 0) { ce->vc = ce->vs - 1; if (ce->vw > 0) { ce->vw--; goto skip_vol; } loop = jws = 0; /* Volume commands */ next_vt: switch (b = VT) { case 0xff: /* END */ case 0xfb: /* HLT */ ce->vp--; break; case 0xfe: /* JMP */ if (loop) /* avoid infinite loop */ break; temp = VT; ce->vp = temp; loop = 1; goto next_vt; break; case 0xfa: /* JWS */ jws = VT; break; case 0xf5: /* EN2 */ ce->env_wav = VT; ce->flags |= MED_SYNTH_ENV_LOOP; break; case 0xf4: /* EN1 */ ce->env_wav = VT; break; case 0xf3: /* CHU */ ce->vv = VT; break; case 0xf2: /* CHD */ ce->vv = -VT; break; case 0xf1: /* WAI */ ce->vw = VT; break; case 0xf0: /* SPD */ ce->vs = VT; break; default: if (b >= 0x00 && b <= 0x40) ce->volume = b; } skip_vol: /* volume envelope */ if (ce->env_wav >= 0) { int sid = mod->xxi[xc->ins].sub[ce->env_wav].sid; struct xmp_sample *xxs = &mod->xxs[sid]; if (xxs->len == 0x80) { /* sanity check */ ce->volume = ((int8)xxs->data[ce->env_idx] + 0x80) >> 2; ce->env_idx++; if (ce->env_idx >= 0x80) { if (~ce->flags & MED_SYNTH_ENV_LOOP) { ce->env_wav = -1; } ce->env_idx = 0; } } } ce->volume += ce->vv; CLAMP(ce->volume, 0, 64); if (ce->ww > 0) { ce->ww--; goto skip_wav; } loop = jvs = 0; /* Waveform commands */ next_wt: switch (b = WT) { struct xmp_instrument *xxi; case 0xff: /* END */ case 0xfb: /* HLT */ ce->wp--; break; case 0xfe: /* JMP */ if (loop) /* avoid infinite loop */ break; temp = WT; if (temp == 0xff) { /* handle JMP END case */ ce->wp--; /* see lepeltheme ins 0x02 */ break; } ce->wp = temp; loop = 1; goto next_wt; case 0xfd: /* ARE */ break; case 0xfc: /* ARP */ ce->arp = ce->aidx = ce->wp++; while (WT != 0xfd) ; break; case 0xfa: /* JVS */ jvs = WT; break; case 0xf7: /* VWF */ ce->vwf = WT; break; case 0xf6: /* RES */ xc->period = ce->period; break; case 0xf5: /* VBS */ ce->vib_speed = WT; break; case 0xf4: /* VBD */ ce->vib_depth = WT; break; case 0xf3: /* CHU */ ce->wv = -WT; break; case 0xf2: /* CHD */ ce->wv = WT; break; case 0xf1: /* WAI */ ce->ww = WT; break; case 0xf0: /* SPD */ ce->ws = WT; break; default: xxi = &m->mod.xxi[xc->ins]; if (b < xxi->nsm && xxi->sub[b].sid != xc->smp) { xc->smp = xxi->sub[b].sid; libxmp_virt_setsmp(ctx, chn, xc->smp); } } skip_wav: xc->period += ce->wv; } if (jws) { ce->wp = jws; /* jws = 0; */ } if (jvs) { ce->vp = jvs; /* jvs = 0; */ } } int libxmp_med_new_instrument_extras(struct xmp_instrument *xxi) { xxi->extra = calloc(1, sizeof(struct med_instrument_extras)); if (xxi->extra == NULL) return -1; MED_INSTRUMENT_EXTRAS((*xxi))->magic = MED_EXTRAS_MAGIC; return 0; } int libxmp_med_new_channel_extras(struct channel_data *xc) { xc->extra = calloc(1, sizeof(struct med_channel_extras)); if (xc->extra == NULL) return -1; MED_CHANNEL_EXTRAS((*xc))->magic = MED_EXTRAS_MAGIC; return 0; } void libxmp_med_reset_channel_extras(struct channel_data *xc) { memset((char *)xc->extra + 4, 0, sizeof(struct med_channel_extras) - 4); } void libxmp_med_release_channel_extras(struct channel_data *xc) { free(xc->extra); } int libxmp_med_new_module_extras(struct module_data *m) { struct med_module_extras *me; struct xmp_module *mod = &m->mod; m->extra = calloc(1, sizeof(struct med_module_extras)); if (m->extra == NULL) return -1; MED_MODULE_EXTRAS((*m))->magic = MED_EXTRAS_MAGIC; me = (struct med_module_extras *)m->extra; me->vol_table = calloc(sizeof(uint8 *), mod->ins); if (me->vol_table == NULL) return -1; me->wav_table = calloc(sizeof(uint8 *), mod->ins); if (me->wav_table == NULL) return -1; return 0; } void libxmp_med_release_module_extras(struct module_data *m) { struct med_module_extras *me; struct xmp_module *mod = &m->mod; int i; me = (struct med_module_extras *)m->extra; if (me->vol_table) { for (i = 0; i < mod->ins; i++) free(me->vol_table[i]); free(me->vol_table); } if (me->wav_table) { for (i = 0; i < mod->ins; i++) free(me->wav_table[i]); free(me->wav_table); } free(m->extra); } void libxmp_med_extras_process_fx(struct context_data *ctx, struct channel_data *xc, int chn, uint8 note, uint8 fxt, uint8 fxp, int fnum) { switch (fxt) { case FX_MED_HOLD: MED_CHANNEL_EXTRAS((*xc))->hold_count++; MED_CHANNEL_EXTRAS((*xc))->hold = 1; break; } } void libxmp_med_hold_hack(struct context_data *ctx, int pat, int chn, int row) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; const int num_rows = mod->xxt[TRACK_NUM(pat, chn)]->rows; if (row + 1 < num_rows) { struct player_data *p = &ctx->p; struct xmp_event *event = &EVENT(pat, chn, row + 1); struct channel_data *xc = &p->xc_data[chn]; if (event->f2t == FX_MED_HOLD) { MED_CHANNEL_EXTRAS(*xc)->hold = 2; } } } libxmp-4.4.1/src/dataio.c0000664000175000017500000001066712773571316015061 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "common.h" #define read_byte(x) do { \ (x) = fgetc(f); \ if ((x) < 0) goto error; \ } while (0) #define set_error(x) do { \ if (err != NULL) *err = (x); \ } while (0) uint8 read8(FILE *f, int *err) { int a; read_byte(a); set_error(0); return a; error: set_error(ferror(f) ? errno : EOF); return 0xff; } int8 read8s(FILE *f, int *err) { int a; read_byte(a); set_error(0); return (int8)a; error: set_error(ferror(f) ? errno : EOF); return 0; } uint16 read16l(FILE *f, int *err) { int a, b; read_byte(a); read_byte(b); set_error(0); return ((uint16)b << 8) | a; error: set_error(ferror(f) ? errno : EOF); return 0xffff; } uint16 read16b(FILE *f, int *err) { int a, b; read_byte(a); read_byte(b); set_error(0); return (a << 8) | b; error: set_error(ferror(f) ? errno : EOF); return 0xffff; } uint32 read24l(FILE *f, int *err) { int a, b, c; read_byte(a); read_byte(b); read_byte(c); set_error(0); return (c << 16) | (b << 8) | a; error: set_error(ferror(f) ? errno : EOF); return 0xffffff; } uint32 read24b(FILE *f, int *err) { int a, b, c; read_byte(a); read_byte(b); read_byte(c); set_error(0); return (a << 16) | (b << 8) | c; error: set_error(ferror(f) ? errno : EOF); return 0xffffff; } uint32 read32l(FILE *f, int *err) { int a, b, c, d; read_byte(a); read_byte(b); read_byte(c); read_byte(d); set_error(0); return (d << 24) | (c << 16) | (b << 8) | a; error: set_error(ferror(f) ? errno : EOF); return 0xffffffff; } uint32 read32b(FILE *f, int *err) { int a, b, c, d; read_byte(a); read_byte(b); read_byte(c); read_byte(d); set_error(0); return (a << 24) | (b << 16) | (c << 8) | d; error: set_error(ferror(f) ? errno : EOF); return 0xffffffff; } uint16 readmem16l(uint8 *m) { uint32 a, b; a = m[0]; b = m[1]; return (b << 8) | a; } uint16 readmem16b(uint8 *m) { uint32 a, b; a = m[0]; b = m[1]; return (a << 8) | b; } uint32 readmem24l(uint8 *m) { uint32 a, b, c; a = m[0]; b = m[1]; c = m[2]; return (c << 16) | (b << 8) | a; } uint32 readmem24b(uint8 *m) { uint32 a, b, c; a = m[0]; b = m[1]; c = m[2]; return (a << 16) | (b << 8) | c; } uint32 readmem32l(uint8 *m) { uint32 a, b, c, d; a = m[0]; b = m[1]; c = m[2]; d = m[3]; return (d << 24) | (c << 16) | (b << 8) | a; } uint32 readmem32b(uint8 *m) { uint32 a, b, c, d; a = m[0]; b = m[1]; c = m[2]; d = m[3]; return (a << 24) | (b << 16) | (c << 8) | d; } #ifndef LIBXMP_CORE_PLAYER inline void write8(FILE *f, uint8 b) { fputc(b, f); } void write16l(FILE *f, uint16 w) { write8(f, w & 0x00ff); write8(f, (w & 0xff00) >> 8); } void write16b(FILE *f, uint16 w) { write8(f, (w & 0xff00) >> 8); write8(f, w & 0x00ff); } void write32l(FILE *f, uint32 w) { write8(f, w & 0x000000ff); write8(f, (w & 0x0000ff00) >> 8); write8(f, (w & 0x00ff0000) >> 16); write8(f, (w & 0xff000000) >> 24); } void write32b(FILE *f, uint32 w) { write8(f, (w & 0xff000000) >> 24); write8(f, (w & 0x00ff0000) >> 16); write8(f, (w & 0x0000ff00) >> 8); write8(f, w & 0x000000ff); } int move_data(FILE *out, FILE *in, int len) { uint8 buf[1024]; int l; do { l = fread(buf, 1, len > 1024 ? 1024 : len, in); fwrite(buf, 1, l, out); len -= l; } while (l > 0 && len > 0); return 0; } #endif libxmp-4.4.1/src/hmn_extras.c0000664000175000017500000001106412775035311015750 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "common.h" #include "player.h" #include "virtual.h" #include "effects.h" #include "hmn_extras.h" static uint8 megaarp[16][16] = { { 0, 3, 7, 12, 15, 12, 7, 3, 0, 3, 7, 12, 15, 12, 7, 3 }, { 0, 4, 7, 12, 16, 12, 7, 4, 0, 4, 7, 12, 16, 12, 7, 4 }, { 0, 3, 8, 12, 15, 12, 8, 3, 0, 3, 8, 12, 15, 12, 8, 3 }, { 0, 4, 8, 12, 16, 12, 8, 4, 0, 4, 8, 12, 16, 12, 8, 4 }, { 0, 5, 8, 12, 17, 12, 8, 5, 0, 5, 8, 12, 17, 12, 8, 5 }, { 0, 5, 9, 12, 17, 12, 9, 5, 0, 5, 9, 12, 17, 12, 9, 5 }, { 12, 0, 7, 0, 3, 0, 7, 0, 12, 0, 7, 0, 3, 0, 7, 0 }, { 12, 0, 7, 0, 4, 0, 7, 0, 12, 0, 7, 0, 4, 0, 7, 0 }, { 0, 3, 7, 3, 7, 12, 7, 12, 15, 12, 7, 12, 7, 3, 7, 3 }, { 0, 4, 7, 4, 7, 12, 7, 12, 16, 12, 7, 12, 7, 4, 7, 4 }, { 31, 27, 24, 19, 15, 12, 7, 3, 0, 3, 7, 12, 15, 19, 24, 27 }, { 31, 28, 24, 19, 16, 12, 7, 4, 0, 4, 7, 12, 16, 19, 24, 28 }, { 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12 }, { 0, 12, 24, 12, 0, 12, 24, 12, 0, 12, 24, 12, 0, 12, 24, 12 }, { 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3 }, { 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4, 0, 4 } }; int libxmp_hmn_linear_bend(struct context_data *ctx, struct channel_data *xc) { return 0; } void libxmp_hmn_play_extras(struct context_data *ctx, struct channel_data *xc, int chn) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct hmn_channel_extras *ce = xc->extra; struct xmp_instrument *xxi; int pos, waveform, volume; if (p->frame == 0 && TEST(NEW_NOTE|NEW_INS)) { ce->datapos = 0; } xxi = &m->mod.xxi[xc->ins]; pos = ce->datapos; waveform = HMN_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])->data[pos]; volume = HMN_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])->progvolume[pos] & 0x7f; if (waveform < xxi->nsm && xxi->sub[waveform].sid != xc->smp) { xc->smp = xxi->sub[waveform].sid; libxmp_virt_setsmp(ctx, chn, xc->smp); } pos++; if (pos > HMN_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])->dataloopend) pos = HMN_INSTRUMENT_EXTRAS(m->mod.xxi[xc->ins])->dataloopstart; ce->datapos = pos; ce->volume = volume; } int libxmp_hmn_new_instrument_extras(struct xmp_instrument *xxi) { xxi->extra = calloc(1, sizeof(struct hmn_instrument_extras)); if (xxi->extra == NULL) return -1; HMN_INSTRUMENT_EXTRAS((*xxi))->magic = HMN_EXTRAS_MAGIC; return 0; } int libxmp_hmn_new_channel_extras(struct channel_data *xc) { xc->extra = calloc(1, sizeof(struct hmn_channel_extras)); if (xc->extra == NULL) return -1; HMN_CHANNEL_EXTRAS((*xc))->magic = HMN_EXTRAS_MAGIC; return 0; } void libxmp_hmn_reset_channel_extras(struct channel_data *xc) { memset((char *)xc->extra + 4, 0, sizeof(struct hmn_channel_extras) - 4); } void libxmp_hmn_release_channel_extras(struct channel_data *xc) { free(xc->extra); } int libxmp_hmn_new_module_extras(struct module_data *m) { m->extra = calloc(1, sizeof(struct hmn_module_extras)); if (m->extra == NULL) return -1; HMN_MODULE_EXTRAS((*m))->magic = HMN_EXTRAS_MAGIC; return 0; } void libxmp_hmn_release_module_extras(struct module_data *m) { free(m->extra); } void libxmp_hmn_extras_process_fx(struct context_data *ctx, struct channel_data *xc, int chn, uint8 note, uint8 fxt, uint8 fxp, int fnum) { switch (fxt) { case FX_MEGAARP: memcpy(xc->arpeggio.val, megaarp[fxp], 16); xc->arpeggio.size = 16; break; } } libxmp-4.4.1/src/depackers/0000775000175000017500000000000012777546220015403 5ustar claudioclaudiolibxmp-4.4.1/src/depackers/readrle.h0000664000175000017500000000121212773453727017173 0ustar claudioclaudio/* nomarch 1.0 - extract old `.arc' archives. * Copyright (C) 2001 Russell Marks. See main.c for license details. * * readrle.h */ #ifndef LIBXMP_READRLE_H #define LIBXMP_READRLE_H struct rledata { int lastchr,repeating; }; struct data_in_out { unsigned char *data_in_point,*data_in_max; unsigned char *data_out_point,*data_out_max; }; void libxmp_outputrle(int chr,void (*outputfunc)(int, struct data_in_out *), struct rledata *, struct data_in_out *); unsigned char *libxmp_convert_rle(unsigned char *data_in, unsigned long in_len, unsigned long orig_len); #endif libxmp-4.4.1/src/depackers/mmcmp.c0000664000175000017500000002074612774567167016703 0ustar claudioclaudio/* * Based on the public domain version by Olivier Lapicque * Rewritten for libxmp by Claudio Matsuoka * * Copyright (C) 2012 Claudio Matsuoka * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "common.h" #include "depacker.h" #define MMCMP_COMP 0x0001 #define MMCMP_DELTA 0x0002 #define MMCMP_16BIT 0x0004 #define MMCMP_STEREO 0x0100 #define MMCMP_ABS16 0x0200 #define MMCMP_ENDIAN 0x0400 struct header { int version; int nblocks; int filesize; int blktable; int glb_comp; int fmt_comp; }; struct block { int unpk_size; int pk_size; int xor_chk; int sub_blk; int flags; int tt_entries; int num_bits; }; struct sub_block { int unpk_pos; int unpk_size; }; static const uint32 cmd_8bits[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1e, 0x3c, 0x78, 0xf8 }; static const uint32 fetch_8bit[8] = { 3, 3, 3, 3, 2, 1, 0, 0 }; static const uint32 cmd_16bit[16] = { 0x0001, 0x0003, 0x0007, 0x000f, 0x001e, 0x003c, 0x0078, 0x00f0, 0x01f0, 0x03f0, 0x07f0, 0x0ff0, 0x1ff0, 0x3ff0, 0x7ff0, 0xfff0 }; static const uint32 fetch_16bit[16] = { 4, 4, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; struct bit_buffer { uint32 count; uint32 buffer; }; static uint32 get_bits(FILE *f, int n, struct bit_buffer *bb) { uint32 bits; if (n == 0) { return 0; } while (bb->count < 24) { bb->buffer |= read8(f, NULL) << bb->count; bb->count += 8; } bits = bb->buffer & ((1 << n) - 1); bb->buffer >>= n; bb->count -= n; return bits; } static void block_copy(struct block *block, struct sub_block *sub, FILE *in, FILE *out) { int i; for (i = 0; i < block->sub_blk; i++, sub++) { move_data(out, in, sub->unpk_size); } } static int block_unpack_16bit(struct block *block, struct sub_block *sub, FILE *in, FILE *out) { struct bit_buffer bb; uint32 pos = 0; uint32 numbits = block->num_bits; uint32 j, oldval = 0; bb.count = 0; bb.buffer = 0; if (fseek(out, sub->unpk_pos, SEEK_SET) < 0) { return -1; } if (fseek(in, block->tt_entries, SEEK_SET) < 0) { return -1; } for (j = 0; j < block->sub_blk; ) { uint32 size = sub[j].unpk_size >> 1; uint32 newval = 0x10000; uint32 d = get_bits(in, numbits + 1, &bb); if (d >= cmd_16bit[numbits]) { uint32 fetch = fetch_16bit[numbits]; uint32 newbits = get_bits(in, fetch, &bb) + ((d - cmd_16bit[numbits]) << fetch); if (newbits != numbits) { numbits = newbits & 0x0f; } else { if ((d = get_bits(in, 4, &bb)) == 0x0f) { if (get_bits(in, 1, &bb)) break; newval = 0xffff; } else { newval = 0xfff0 + d; } } } else { newval = d; } if (newval < 0x10000) { if (newval & 1) { newval = (uint32)(-(int32)((newval + 1) >> 1)); } else { newval = (uint32)(newval >> 1); } if (block->flags & MMCMP_DELTA) { newval += oldval; oldval = newval; } else if (!(block->flags & MMCMP_ABS16)) { newval ^= 0x8000; } pos++; write16l(out, newval); } if (pos >= size) { if (++j >= block->sub_blk) break; pos = 0; if (fseek(out, sub[j].unpk_pos, SEEK_SET) < 0) { return -1; } } } return 0; } static int block_unpack_8bit(struct block *block, struct sub_block *sub, FILE *in, FILE *out) { struct bit_buffer bb; uint32 pos = 0; uint32 numbits = block->num_bits; uint32 j, oldval = 0; uint8 ptable[0x100]; if (fread(ptable, 1, 0x100, in) != 0x100) { return -1; } bb.count = 0; bb.buffer = 0; if (fseek(out, sub->unpk_pos, SEEK_SET) < 0) { return -1; } if (fseek(in, block->tt_entries, SEEK_SET) < 0) { return -1; } for (j = 0; j < block->sub_blk; ) { uint32 size = sub[j].unpk_size; uint32 newval = 0x100; uint32 d = get_bits(in, numbits+1, &bb); if (d >= cmd_8bits[numbits]) { uint32 fetch = fetch_8bit[numbits]; uint32 newbits = get_bits(in, fetch, &bb) + ((d - cmd_8bits[numbits]) << fetch); if (newbits != numbits) { numbits = newbits & 0x07; } else { if ((d = get_bits(in, 3, &bb)) == 7) { if (get_bits(in, 1, &bb)) break; newval = 0xff; } else { newval = 0xf8 + d; } } } else { newval = d; } if (newval < 0x100) { int n = ptable[newval]; if (block->flags & MMCMP_DELTA) { n += oldval; oldval = n; } pos++; write8(out, n); } if (pos >= size) { if (++j >= block->sub_blk) break; pos = 0; if (fseek(out, sub[j].unpk_pos, SEEK_SET) < 0) { return -1; } } } return 0; } static int test_mmcmp(unsigned char *b) { return memcmp(b, "ziRCONia", 8) == 0; } static int decrunch_mmcmp(FILE *in, FILE *out) { struct header h; uint32 *table; uint32 i, j; int error; /* Read file header */ if (read32l(in, NULL) != 0x4352697A) /* ziRC */ goto err; if (read32l(in, NULL) != 0x61694e4f) /* ONia */ goto err; if (read16l(in, NULL) < 14) /* header size */ goto err; /* Read header */ h.version = read16l(in, &error); if (error != 0) goto err; h.nblocks = read16l(in, &error); if (error != 0) goto err; h.filesize = read32l(in, &error); if (error != 0) goto err; h.blktable = read32l(in, &error); if (error != 0) goto err; h.glb_comp = read8(in, &error); if (error != 0) goto err; h.fmt_comp = read8(in, &error); if (error != 0) goto err; if (h.nblocks == 0) goto err; /* Block table */ if (fseek(in, h.blktable, SEEK_SET) < 0) { goto err; } if ((table = malloc(h.nblocks * 4)) == NULL) { goto err; } for (i = 0; i < h.nblocks; i++) { table[i] = read32l(in, &error); if (error != 0) goto err2; } for (i = 0; i < h.nblocks; i++) { struct block block; struct sub_block *sub_block; uint8 buf[20]; if (fseek(in, table[i], SEEK_SET) < 0) { goto err2; } if (fread(buf, 1, 20, in) != 20) { goto err2; } block.unpk_size = readmem32l(buf); block.pk_size = readmem32l(buf + 4); block.xor_chk = readmem32l(buf + 8); block.sub_blk = readmem16l(buf + 12); block.flags = readmem16l(buf + 14); block.tt_entries = readmem16l(buf + 16); block.num_bits = readmem16l(buf + 18); /* Sanity check */ if (block.unpk_size <= 0 || block.pk_size <= 0) goto err2; if (block.tt_entries < 0 || block.pk_size <= block.tt_entries) goto err2; if (block.sub_blk <= 0) goto err2; if (block.flags & MMCMP_COMP) { if (block.flags & MMCMP_16BIT) { if (block.num_bits >= 16) { goto err2; } } else { if (block.num_bits >= 8) { goto err2; } } } sub_block = malloc(block.sub_blk * sizeof (struct sub_block)); if (sub_block == NULL) goto err2; for (j = 0; j < block.sub_blk; j++) { uint8 buf[8]; if (fread(buf, 1, 8, in) != 8) { free(sub_block); goto err2; } sub_block[j].unpk_pos = readmem32l(buf); sub_block[j].unpk_size = readmem32l(buf + 4); /* Sanity check */ if (sub_block[j].unpk_pos < 0 || sub_block[j].unpk_size < 0) { free(sub_block); goto err2; } } block.tt_entries += ftell(in); if (~block.flags & MMCMP_COMP) { /* Data is not packed */ block_copy(&block, sub_block, in, out); } else if (block.flags & MMCMP_16BIT) { /* Data is 16-bit packed */ if (block_unpack_16bit(&block, sub_block, in, out) < 0) { free(sub_block); goto err2; } } else { /* Data is 8-bit packed */ if (block_unpack_8bit(&block, sub_block, in, out) < 0) { free(sub_block); goto err2; } } free(sub_block); } free(table); return 0; err2: free(table); err: return -1; } struct depacker libxmp_depacker_mmcmp = { test_mmcmp, decrunch_mmcmp }; libxmp-4.4.1/src/depackers/unzip.c0000664000175000017500000001353712775035311016715 0ustar claudioclaudio/* This code is Copyright 2005-2006 by Michael Kohn This package is licensed under the LGPL. You are free to use this library in both commercial and non-commercial applications as long as you dynamically link to it. If you statically link this library you must also release your software under the LGPL. If you need more flexibility in the license email me and we can work something out. Michael Kohn */ #include #include #include #include #include #include #include #include "common.h" #include "depacker.h" #include "inflate.h" #include "crc32.h" struct zip_file_header { unsigned int signature; int version; int general_purpose_bit_flag; int compression_method; int last_mod_file_time; int last_mod_file_date; unsigned int crc_32; int compressed_size; int uncompressed_size; int file_name_length; int extra_field_length; char *file_name; unsigned char *extra_field; }; #define QUIET #define read_int(x) read32l(x, NULL) #define read_word(x) read16l(x, NULL) /*-------------------------- fileio.c ---------------------------*/ static int read_chars(FILE *in, char *s, int count) { int t; for (t=0; tsignature=read_int(in); if (header->signature!=0x04034b50) return -1; header->version=read_word(in); header->general_purpose_bit_flag=read_word(in); header->compression_method=read_word(in); header->last_mod_file_time=read_word(in); header->last_mod_file_date=read_word(in); header->crc_32=read_int(in); header->compressed_size=read_int(in); header->uncompressed_size=read_int(in); header->file_name_length=read_word(in); header->extra_field_length=read_word(in); return 0; } /* For xmp: * pass an array of patterns containing files we want to exclude from * our search (such as README, *.nfo, etc) */ static int kunzip_file_with_name(FILE *in, FILE *out) { struct zip_file_header header; int ret_code; uint32 checksum=0; long marker; struct inflate_data data; ret_code=0; if (read_zip_header(in,&header)==-1) return -1; header.file_name=(char *)malloc(header.file_name_length+1); if (header.file_name == NULL) goto err; header.extra_field=(unsigned char *)malloc(header.extra_field_length+1); if (header.extra_field == NULL) goto err2; if (read_chars(in,header.file_name,header.file_name_length) < 0) goto err2; if (read_chars(in,(char *)header.extra_field,header.extra_field_length) < 0) goto err2; marker=ftell(in); libxmp_crc32_init_A(); if (header.uncompressed_size!=0) { if (header.compression_method==0) { checksum=copy_file(in,out,header.uncompressed_size,&data); } else { if (libxmp_inflate(in, out, &checksum, 1) < 0) goto err3; } /* fclose(out); */ if (checksum!=header.crc_32) { /* fprintf(stderr, "unzip: crc error: %d %d\n",checksum,header.crc_32); */ ret_code=-4; } } free(header.file_name); free(header.extra_field); if (fseek(in,marker+header.compressed_size,SEEK_SET) < 0) { goto err; } if ((header.general_purpose_bit_flag&8)!=0) { read_int(in); read_int(in); read_int(in); } return ret_code; err3: free(header.extra_field); err2: free(header.file_name); err: return -1; } static int kunzip_get_offset_excluding(FILE *in) { struct zip_file_header header; int i=0,curr; int name_size; long marker; char name[1024]; while(1) { curr=ftell(in); if (curr < 0) { return -1; } i=read_zip_header(in,&header); if (i==-1) break; /*if (skip_offset<0 || curr>skip_offset)*/ { marker=ftell(in); /* nasty code.. please make it nice later */ if (marker < 0) { return -1; } name_size = header.file_name_length; if (name_size > 1023) { name_size = 1023; } if (read_chars(in,name,name_size) < 0) { return -1; } name[name_size]=0; if (fseek(in,marker,SEEK_SET) < 0) { /* and part 2 of nasty code */ return -1; } if (!libxmp_exclude_match(name)) { break; } } if (fseek(in,header.compressed_size+ header.file_name_length+ header.extra_field_length,SEEK_CUR) < 0) { return -1; } } if (i!=-1) { return curr; } else { return -1; } } static int test_zip(unsigned char *b) { return b[0] == 'P' && b[1] == 'K' && ((b[2] == 3 && b[3] == 4) || (b[2] == '0' && b[3] == '0' && b[4] == 'P' && b[5] == 'K' && b[6] == 3 && b[7] == 4)); } static int decrunch_zip(FILE *in, FILE *out) { int offset; offset = kunzip_get_offset_excluding(in); if (offset < 0) return -1; if (fseek(in, offset, SEEK_SET) < 0) return -1; if (kunzip_file_with_name(in,out) < 0) return -1; return 0; } struct depacker libxmp_depacker_zip = { test_zip, decrunch_zip }; libxmp-4.4.1/src/depackers/inflate.c0000664000175000017500000006611412773571316017201 0ustar claudioclaudio#include #include #include #include "common.h" #include "inflate.h" #include "crc32.h" #define read_int_b(x) read32b(x, NULL) #define read_word(x) read16l(x, NULL) #define ZIP #undef DEBUG /* This code is Copyright 2005-2006 by Michael Kohn Modified for xmp by Claudio Matsuoka, Jul 2009 This package is licensed under the LGPL. You are free to use this library in both commercial and non-commercial applications as long as you dynamically link to it. If you statically link this library you must also release your software under the LGPL. If you need more flexibility in the license email me and we can work something out. Michael Kohn */ #define WINDOW_SIZE 32768 struct bitstream_t { unsigned int holding; int bitptr; }; struct huffman_t { unsigned char window[WINDOW_SIZE]; int window_ptr; unsigned int checksum; int len[288]; int dist_len[33]; int dist_huff_count; }; struct huffman_tree_t { unsigned short int code; short int left; short int right; }; #define DIST_CODES_SIZE 30 #define LENGTH_CODES_SIZE 29 #define HUFFMAN_TREE_SIZE 1024 #define DYN_HUFF_TRANS_SIZE 19 static const int length_codes[LENGTH_CODES_SIZE] = { 3,4,5,6,7,8,9,10,11,13,15,17,19, 23,27,31,35,43,51,59,67,83,99,115, 131,163,195,227,258 }; static const int length_extra_bits[29] = { 0,0,0,0,0,0,0,0,1,1,1,1, 2,2,2,2,3,3,3,3,4,4,4,4, 5,5,5,5,0 }; static const int dist_codes[DIST_CODES_SIZE] = { 1,2,3,4,5,7,9,13,17,25, 33,49,65,97,129,193,257,385,513,769, 1025,1537,2049,3073,4097,6145,8193, 12289,16385,24577 }; static const int dist_extra_bits[30] = { 0,0,0,0,1,1,2,2,3,3, 4,4,5,5,6,6,7,7,8,8, 9,9,10,10,11,11,12,12,13,13 }; static const int dyn_huff_trans[DYN_HUFF_TRANS_SIZE] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static const unsigned char reverse[256] = { 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; #ifdef DEBUG int print_binary(int b, int l) { if ((l-1)!=0) { print_binary(b>>1,l-1); } printf("%d",(b&1)); return 0; } #endif #if 0 static int kunzip_inflate_free(struct inflate_data *data) { if (data->huffman_tree_len_static!=0) { free(data->huffman_tree_len_static); } return 0; } #endif #if 0 static unsigned int get_alder(FILE *out) { unsigned int s1,s2; unsigned int adler; int len,t,value; len=ftell(out); fseek(out,0,SEEK_SET); adler=1; s1=adler&0xffff; s2=(adler>>16); for (t=0; tholding>>24)&255)]| (reverse[((bitstream->holding>>16)&255)]<<8)| (reverse[((bitstream->holding>>8)&255)]<<16)| (reverse[(bitstream->holding&255)]<<24); i=i>>(32-bitstream->bitptr); bitstream->holding=i; return 0; } static int add_static_codes_to_tree(struct huffman_tree_t *huffman_tree, int code_len, int count, int start_code, int start_uncomp_code, int next_leaf) { struct huffman_tree_t *curr_huffman_leaf; int t,x,r; // code_len=code_len-1; for (t=0; tleft==0) { next_leaf++; curr_huffman_leaf->left=next_leaf; huffman_tree[next_leaf].left=0; huffman_tree[next_leaf].right=0; } curr_huffman_leaf=&huffman_tree[curr_huffman_leaf->left]; } else { if (curr_huffman_leaf->right==0) { next_leaf++; curr_huffman_leaf->right=next_leaf; huffman_tree[next_leaf].left=0; huffman_tree[next_leaf].right=0; } curr_huffman_leaf=&huffman_tree[curr_huffman_leaf->right]; } x=x>>1; } curr_huffman_leaf->code=start_uncomp_code++; start_code++; } return next_leaf; } static int load_fixed_huffman(struct huffman_t *huffman, struct huffman_tree_t **huffman_tree_ptr) { struct huffman_tree_t *huffman_tree; int next_leaf; /* int t; int code; */ #ifdef DEBUG printf("load_fixed_huffman()\n"); #endif /* code=0x30; // 0011 0000 for (t=0; t<=143; t++) { huffman->len[t]=8; huffman->code[t]=code; code++; } code=0x190; // 1 1001 0000 for (t=144; t<=255; t++) { huffman->len[t]=9; huffman->code[t]=code; code++; } code=0x00; // 0000000 for (t=256; t<=279; t++) { huffman->len[t]=7; huffman->code[t]=code; code++; } code=0xc0; // 1100 0000 for (t=280; t<=287; t++) { huffman->len[t]=8; huffman->code[t]=code; code++; } */ huffman->dist_huff_count=0; huffman_tree=malloc(600*sizeof(struct huffman_tree_t)); if (huffman_tree == NULL) return -1; *huffman_tree_ptr=huffman_tree; huffman_tree->left=0; huffman_tree->right=0; /* printf("adding static\n"); */ next_leaf=0; next_leaf=add_static_codes_to_tree(huffman_tree,8,144,0x30,0,next_leaf); next_leaf=add_static_codes_to_tree(huffman_tree,9,112,0x190,144,next_leaf); next_leaf=add_static_codes_to_tree(huffman_tree,7,24,0x00,256,next_leaf); next_leaf=add_static_codes_to_tree(huffman_tree,8,8,0xc0,280,next_leaf); /* printf("next_leaf=%d\n",next_leaf); */ return 0; } static int load_codes(FILE *in, struct bitstream_t *bitstream, int *lengths, int len_size, int count, int *hclen_code_length, int *hclen_code, struct huffman_tree_t *huffman_tree) { int r,t,c,x; int code,curr_code; int bl_count[512]; int next_code[512]; int bits,max_bits; int next_leaf,curr_leaf; #ifdef DEBUG printf("Entering load_codes()\n"); #endif r=0; while (rbitptrholding=reverse[getc(in)]+(bitstream->holding<<8); bitstream->bitptr+=8; } curr_code=(bitstream->holding>>(bitstream->bitptr-hclen_code_length[t])); #ifdef DEBUG /* print_binary(curr_code,hclen_code_length[t]); printf(" "); print_binary(hclen_code[t],hclen_code_length[t]); printf("\n"); */ #endif if (curr_code==hclen_code[t]) { bitstream->bitptr-=hclen_code_length[t]; bitstream->holding=bitstream->holding&((1<bitptr)-1); break; } } if (t<=15) { /* Sanity check */ if (r >= len_size) return -1; lengths[r++]=t; } else if (t==16) { if (r!=0) { code=lengths[r-1]; } else { code=0; } if (bitstream->bitptr<2) { bitstream->holding=reverse[getc(in)]+(bitstream->holding<<8); bitstream->bitptr+=8; } x=reverse[bitstream->holding>>(bitstream->bitptr-2)]>>6; bitstream->bitptr-=2; bitstream->holding=bitstream->holding&((1<bitptr)-1); /* Sanity check */ if (r + x + 3 >= len_size) return -1; for (c=0; cbitptr<3) { bitstream->holding=reverse[getc(in)]+(bitstream->holding<<8); bitstream->bitptr+=8; } x=reverse[bitstream->holding>>(bitstream->bitptr-3)]>>5; bitstream->bitptr-=3; bitstream->holding=bitstream->holding&((1<bitptr)-1); c=x+3; /* Sanity check */ if (r + c >= len_size) return -1; memset(&lengths[r],0,sizeof(int)*c); r=r+c; } else if (t==18) { if (bitstream->bitptr<7) { bitstream->holding=reverse[getc(in)]+(bitstream->holding<<8); bitstream->bitptr+=8; } x=reverse[bitstream->holding>>(bitstream->bitptr-7)]>>1; bitstream->bitptr-=7; bitstream->holding=bitstream->holding&((1<bitptr)-1); c=x+11; /* Sanity check */ if (r + c >= len_size) return -1; memset(&lengths[r],0,sizeof(int)*c); r=r+c; } else { #ifdef DEBUG fprintf(stderr, "inflate: error in bitstream reading in literal code length %d\n",t); #endif return -1; } } #ifdef DEBUG printf("r=%d count=%d\n",r,count); #endif /* time to load the codes */ memset(bl_count,0,count*sizeof(int)); /* memset(next_code,0,count*sizeof(int)); */ max_bits=0; for (t=0; t= count) { /* fprintf(stderr, "unzip: decompression error\n"); */ return -1; } bl_count[lengths[t]]++; if (max_bitsleft=0; huffman_tree->right=0; next_leaf=0; for (t=0; t> %d %d %d next_leaf=%d\n",t,lengths[t],codes[t],next_leaf); #endif code=next_code[lengths[t]]; curr_leaf=0; x=1<<(lengths[t]-1); for (r=0; r>1; } huffman_tree[curr_leaf].code=t; next_code[lengths[t]]++; } } #ifdef DEBUG printf("Leaving load_codes()\n"); #endif return 0; } static int load_dynamic_huffman(FILE *in, struct huffman_t *huffman, struct bitstream_t *bitstream, struct huffman_tree_t *huffman_tree_len, struct huffman_tree_t *huffman_tree_dist) { int hlit,hdist,hclen; int hclen_code_lengths[19]; int hclen_code[19]; int bl_count[19]; int next_code[19]; int code,bits; int t; int res; while (bitstream->bitptr<14) { bitstream->holding=reverse[getc(in)]+(bitstream->holding<<8); bitstream->bitptr+=8; } hlit=(bitstream->holding>>(bitstream->bitptr-5)); bitstream->bitptr-=5; bitstream->holding=bitstream->holding&((1<bitptr)-1); hdist=(bitstream->holding>>(bitstream->bitptr-5)); bitstream->bitptr-=5; bitstream->holding=bitstream->holding&((1<bitptr)-1); hclen=(bitstream->holding>>(bitstream->bitptr-4)); bitstream->bitptr-=4; bitstream->holding=bitstream->holding&((1<bitptr)-1); hlit=(reverse[hlit]>>3)+257; hdist=(reverse[hdist]>>3)+1; hclen=(reverse[hclen]>>4)+4; /* Sanity check */ if (hclen > DYN_HUFF_TRANS_SIZE) return -1; /* printf("%d %d %d\n",hclen,sizeof(struct huffman_tree_t),hclen*sizeof(struct huffman_tree_t)); */ #ifdef DEBUG printf("hlit: %d\n",hlit); printf("hdist: %d\n",hdist); printf("hclen: %d\n",hclen); #endif memset(hclen_code_lengths,0,19*sizeof(int)); memset(hclen_code,0,19*sizeof(int)); memset(bl_count,0,19*sizeof(int)); /* memset(next_code,0,19*sizeof(int)); */ /* load the first huffman table */ for (t=0; tbitptr<3) { bitstream->holding=reverse[getc(in)]+(bitstream->holding<<8); bitstream->bitptr+=8; } len = bitstream->holding >> (bitstream->bitptr-3); hclen_code_lengths[dyn_huff_trans[t]] = reverse[len] >> 5; bitstream->bitptr -= 3; bitstream->holding = bitstream->holding&((1<bitptr)-1); } #ifdef DEBUG printf("\nCode Lengths\n"); printf("------------------\n"); for (t=0; t<19; t++) { printf("%d %d\n",t,hclen_code_lengths[t]); } printf("\n\n"); #endif for (t=0; t<19; t++) { bl_count[hclen_code_lengths[t]]++; } #ifdef DEBUG printf("\nbl_count[]\n"); printf("------------------\n"); for (t=0; t<8; t++) { printf("%d %d\n",t,bl_count[t]); } printf("\n"); #endif code=0; bl_count[0]=0; for (bits=1; bits<=7; bits++) { code=(code+bl_count[bits-1])<<1; next_code[bits]=code; } #ifdef DEBUG printf("next_code[]\n"); printf("------------------\n"); for (t=0; tlen,0,288*sizeof(int)); /* memset(huffman->code,0,288*sizeof(int)); */ res = load_codes(in,bitstream,huffman->len,288,hlit,hclen_code_lengths,hclen_code,huffman_tree_len); if (res < 0) return -1; #ifdef DEBUG printf("\nLiteral Table\n"); printf("------------------\n"); for (t=0; tlen[t]!=0) { printf("%d %d %d ",t,huffman->code[t],huffman->len[t]); if (huffman->len[t]!=0) print_binary(huffman->code[t],huffman->len[t]); printf("\n"); } } #endif /* load distant tables */ if (hdist==0) { huffman->dist_huff_count=0; } else { huffman->dist_huff_count=hdist; memset(huffman->dist_len,0,33*sizeof(int)); /* memset(huffman->dist_code,0,33*sizeof(int)); */ res = load_codes(in,bitstream,huffman->dist_len,33,hdist,hclen_code_lengths,hclen_code,huffman_tree_dist); if (res < 0) return -1; } return 0; } int decompress(FILE *in, struct huffman_t *huffman, struct bitstream_t *bitstream, struct huffman_tree_t *huffman_tree_len, struct huffman_tree_t *huffman_tree_dist, FILE *out, struct inflate_data *data) { int code=0,len,dist; int t,r; unsigned char *window; struct huffman_tree_t *curr_huffman_leaf; int window_ptr; int curr_leaf; #ifdef DEBUG printf("decompress()\n"); printf("holding=%d bitptr=%d\n",bitstream->holding,bitstream->bitptr); #endif /* printf("bitstream: %08x %d\n",bitstream->holding,bitstream->bitptr); */ reverse_bitstream(bitstream); /* printf("bitstream: %08x %d\n",bitstream->holding,bitstream->bitptr); */ window_ptr=huffman->window_ptr; window=huffman->window; while(1) { curr_huffman_leaf=huffman_tree_len; curr_leaf=0; while(1) { if (bitstream->bitptr<=0) { /* bitstream->holding+=(getc(in)<bitptr); */ /* bitstream->bitptr+=8; */ int x = getc(in); if (x == EOF) { return -1; } bitstream->holding=x; bitstream->bitptr=8; } #ifdef DEBUG printf("%d (%c) %d %d (holding=%d bitptr=%d)\n",curr_leaf,huffman_tree_len[curr_leaf].code,huffman_tree_len[curr_leaf].left,huffman_tree_len[curr_leaf].right,bitstream->holding,bitstream->bitptr); fflush(stdout); #endif if ((bitstream->holding&1)==0) { if (huffman_tree_len[curr_leaf].left==0) { code=huffman_tree_len[curr_leaf].code; break; } curr_leaf=huffman_tree_len[curr_leaf].left; } else { if (huffman_tree_len[curr_leaf].right==0) { code=huffman_tree_len[curr_leaf].code; break; } curr_leaf=huffman_tree_len[curr_leaf].right; } /* Sanity check */ if (curr_leaf >= HUFFMAN_TREE_SIZE) { #ifdef DEBUG fprintf(stderr, "inflate: corrupt huffman tree\n"); #endif return -1; } bitstream->bitptr-=1; bitstream->holding>>=1; } /* if (t==288) { printf("Unknown huffman code\n"); return -1; } */ #ifdef DEBUG printf("------------------------\n"); printf("code=%d\n",code); #endif if (code<256) { /* putc(code,out); */ #ifdef DEBUG if (code>=32 && code<=128) { printf("output %d %c\n",code,code); } else { printf("output %d\n",code); } #endif window[window_ptr++]=code; if (window_ptr>=WINDOW_SIZE) { fwrite(window,1,WINDOW_SIZE,out); huffman->checksum=libxmp_crc32_A2(huffman->window,WINDOW_SIZE,huffman->checksum); window_ptr=0; } } else if (code==256) { #ifdef DEBUG printf("end-of-block %d\n",code); #endif break; } else { #ifdef DEBUG printf("LZ77 TIME %d\n",code); fflush(stdout); #endif code=code-257; /* Sanity check */ if (code >= LENGTH_CODES_SIZE) return -1; len=length_codes[code]; if (length_extra_bits[code]!=0) { while (bitstream->bitptrholding+=(getc(in)<bitptr); bitstream->bitptr+=8; } #ifdef DEBUG printf("len=%d extra_bits=%d extra bits value=%d\n",len,length_extra_bits[code],bitstream->holding>>(bitstream->bitptr-length_extra_bits[code])); fflush(stdout); #endif len=len+(bitstream->holding&((1<bitptr-=length_extra_bits[code]; bitstream->holding>>=length_extra_bits[code]; } if (huffman_tree_dist == 0 || huffman->dist_huff_count==0) { if (bitstream->bitptr<5) { bitstream->holding+=(getc(in)<bitptr); bitstream->bitptr+=8; } code=(bitstream->holding&0x1f); code=reverse[code&255]>>3; bitstream->bitptr-=5; bitstream->holding>>=5; #ifdef DEBUG printf("DIST code=%d\n",code); fflush(stdout); #endif } else { curr_huffman_leaf=huffman_tree_len; curr_leaf=0; while(1) { if (bitstream->bitptr<=0) { /* bitstream->holding+=(getc(in)<bitptr); */ /* bitstream->bitptr+=8; */ bitstream->holding=getc(in); bitstream->bitptr=8; } #ifdef DEBUG printf("%d (%c) %d %d (holding=%d bitptr=%d)\n",curr_leaf,huffman_tree_len[curr_leaf].code,huffman_tree_len[curr_leaf].left,huffman_tree_len[curr_leaf].right,bitstream->holding,bitstream->bitptr); fflush(stdout); #endif if ((bitstream->holding&1)==0) { if (huffman_tree_dist[curr_leaf].left==0) { code=huffman_tree_dist[curr_leaf].code; break; } curr_leaf=huffman_tree_dist[curr_leaf].left; } else { if (huffman_tree_dist[curr_leaf].right==0) { code=huffman_tree_dist[curr_leaf].code; break; } curr_leaf=huffman_tree_dist[curr_leaf].right; } /* Sanity check */ if (curr_leaf >= HUFFMAN_TREE_SIZE) { #ifdef DEBUG fprintf(stderr, "inflate: corrupt huffman tree\n"); #endif return -1; } bitstream->bitptr-=1; bitstream->holding>>=1; } } /* Sanity check */ if (code >= DIST_CODES_SIZE) { #ifdef DEBUG fprintf(stderr, "inflate: corrupt input\n"); #endif return -1; } dist=dist_codes[code]; if (dist_extra_bits[code]!=0) { while (bitstream->bitptrholding+=(getc(in)<bitptr); bitstream->bitptr+=8; } #ifdef DEBUG printf("code=%d distance=%d num_extra_bits=%d extra_bits=%d\n",code,dist_codes[code],dist_extra_bits[code],(bitstream->holding>>(bitstream->bitptr-dist_extra_bits[code]) )); #endif dist=dist+(bitstream->holding&((1<bitptr-=dist_extra_bits[code]; bitstream->holding>>=dist_extra_bits[code]; } #ifdef DEBUG printf("len: %d dist: %d\n",len,dist); #endif /* if (dist<0 || len>dist) { printf(">> OOPS! dist=%d len=%d (%d) ftell=%d\n",dist,len,huffman->dist_huff_count,ftell(out)); exit(0); } */ /* HERE */ r=window_ptr-dist; /* I would have thought the memcpy (which gets called most of the time) would have been a huge speed up. I was wrong. Maybe I'll try writing some inline assembly later for x86 for this */ if (r>=0 && (window_ptr+len=0 && (window_ptr+len=WINDOW_SIZE) r=0; if (window_ptr>=WINDOW_SIZE) { fwrite(window,1,WINDOW_SIZE,out); huffman->checksum=libxmp_crc32_A2(huffman->window,WINDOW_SIZE,huffman->checksum); window_ptr=0; } } } #ifdef DEBUG printf("\n"); #endif } } huffman->window_ptr=window_ptr; reverse_bitstream(bitstream); return 0; } int libxmp_inflate(FILE *in, FILE *out, uint32 *checksum, int is_zip) { /* #ifndef ZIP */ unsigned char CMF, FLG; unsigned int DICT; /* #endif */ struct bitstream_t bitstream; struct huffman_t huffman; int comp_method; int block_len,bfinal; int t; struct huffman_tree_t *huffman_tree_len; struct huffman_tree_t *huffman_tree_dist; struct inflate_data data; int res; memset(&huffman, 0, sizeof(struct huffman_t)); huffman.checksum=0xffffffff; data.huffman_tree_len_static=0; huffman_tree_len=malloc(HUFFMAN_TREE_SIZE * sizeof(struct huffman_tree_t)); if (huffman_tree_len == NULL) goto err; memset(huffman_tree_len, 0xff, HUFFMAN_TREE_SIZE * sizeof(struct huffman_tree_t)); huffman_tree_dist=malloc(HUFFMAN_TREE_SIZE * sizeof(struct huffman_tree_t)); if (huffman_tree_dist == NULL) goto err2; memset(huffman_tree_dist, 0xff, HUFFMAN_TREE_SIZE * sizeof(struct huffman_tree_t)); huffman.window_ptr=0; #ifdef DEBUG printf("\nStarting at %d 0x%x\n",(int)ftell(in),(int)ftell(in)); #endif if (!is_zip) { int x; if ((x = getc(in)) < 0) { goto err3; } CMF=x; if ((x = getc(in)) < 0) { goto err3; } FLG=x; #ifdef DEBUG printf(" CMF: %d\n",CMF); printf(" FLG: %d\n",FLG); printf(" CM: %d\n",CMF&15); printf(" CINFO: %d\n",(CMF>>4)&15); printf("FCHECK: %d\n",FLG&31); printf(" FDICT: %d\n",(FLG>5)&1); printf("FLEVEL: %d\n\n",(FLG>6)&3); #endif if ((CMF&15)!=8) { /* printf("Unsupported compression used.\n"); */ goto err3; } if ((FLG&32)!=0) { DICT=read_int_b(in); } if (((CMF*256+FLG)%31)!=0) { /* printf("FCHECK fails.\n"); */ goto err3; } } /* kunzip_inflate_init(&data); */ bitstream.holding=0; bitstream.bitptr=0; while(1) { if (bitstream.bitptr<3) { bitstream.holding=reverse[getc(in)]+(bitstream.holding<<8); bitstream.bitptr+=8; } #ifdef DEBUG printf("holding=%d\n",bitstream.holding); #endif bfinal=bitstream.holding>>(bitstream.bitptr-1); comp_method=(bitstream.holding>>(bitstream.bitptr-3))&3; bitstream.bitptr-=3; bitstream.holding=bitstream.holding&((1<=WINDOW_SIZE) { fwrite(huffman.window,1,WINDOW_SIZE,out); huffman.checksum=libxmp_crc32_A2(huffman.window,WINDOW_SIZE,huffman.checksum); huffman.window_ptr=0; } } } else if (comp_method==2) /* Reduced with compression factor 1 */ { /* Fixed Huffman */ if (data.huffman_tree_len_static==0) { if (load_fixed_huffman(&huffman, &data.huffman_tree_len_static) < 0) goto err4; } if (decompress(in, &huffman, &bitstream, data.huffman_tree_len_static, 0, out, &data) < 0) { goto err4; } /* free(huffman_tree_len); huffman_tree_len=0; */ } else if (comp_method==1) /* Shrunk */ { /* Dynamic Huffman */ res = load_dynamic_huffman(in,&huffman,&bitstream,huffman_tree_len,huffman_tree_dist); if (res < 0) { goto err4; } if (decompress(in, &huffman, &bitstream, huffman_tree_len, huffman_tree_dist, out, &data) < 0) { goto err4; } } else if (comp_method==3) { /* Error */ /* printf("Error (inflate): unknown compression type\n"); */ break; } if (bfinal==1) { break; } } if (huffman.window_ptr!=0) { fwrite(huffman.window,1,huffman.window_ptr,out); huffman.checksum=libxmp_crc32_A2(huffman.window,huffman.window_ptr,huffman.checksum); } free(huffman_tree_dist); free(huffman_tree_len); *checksum=huffman.checksum^0xffffffff; free(data.huffman_tree_len_static); /* for gzip */ if (bitstream.bitptr == 8) { reverse_bitstream(&bitstream); ungetc(bitstream.holding, in); } return 0; err4: free(data.huffman_tree_len_static); err3: free(huffman_tree_dist); err2: free(huffman_tree_len); err: return -1; } libxmp-4.4.1/src/depackers/unsqsh.c0000664000175000017500000001640712774567167017112 0ustar claudioclaudio/* * XPK-SQSH depacker * Algorithm from the portable decruncher by Bert Jahn (24.12.97) * Checksum added by Sipos Attila * Rewritten for libxmp by Claudio Matsuoka * * Copyright (C) 2013 Claudio Matsuoka * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "common.h" #include "depacker.h" struct io { uint8 *src; uint8 *dest; int offs; }; static uint8 ctable[] = { 2, 3, 4, 5, 6, 7, 8, 0, 3, 2, 4, 5, 6, 7, 8, 0, 4, 3, 5, 2, 6, 7, 8, 0, 5, 4, 6, 2, 3, 7, 8, 0, 6, 5, 7, 2, 3, 4, 8, 0, 7, 6, 8, 2, 3, 4, 5, 0, 8, 7, 6, 2, 3, 4, 5, 0 }; static uint16 xchecksum(uint32 * ptr, uint32 count) { register uint32 sum = 0; while (count-- > 0) { sum ^= *ptr++; } return (uint16) (sum ^ (sum >> 16)); } static int get_bits(struct io *io, int count) { int r = readmem24b(io->src + (io->offs >> 3)); r <<= io->offs % 8; r &= 0xffffff; r >>= 24 - count; io->offs += count; return r; } static int get_bits_final(struct io *io, int count) { int r = readmem24b(io->src + (io->offs >> 3)); r <<= (io->offs % 8) + 8; r >>= 32 - count; io->offs += count; return r; } static int copy_data(struct io *io, int d1, int *data, uint8 *dest_start, uint8 *dest_end) { uint8 *copy_src; int dest_offset, count, copy_len; if (get_bits(io, 1) == 0) { copy_len = get_bits(io, 1) + 2; } else if (get_bits(io, 1) == 0) { copy_len = get_bits(io, 1) + 4; } else if (get_bits(io, 1) == 0) { copy_len = get_bits(io, 1) + 6; } else if (get_bits(io, 1) == 0) { copy_len = get_bits(io, 3) + 8; } else { copy_len = get_bits(io, 5) + 16; } if (get_bits(io, 1) == 0) { if (get_bits(io, 1) == 0) { count = 8; dest_offset = 0; } else { count = 14; dest_offset = -0x1100; } } else { count = 12; dest_offset = -0x100; } copy_len -= 3; if (copy_len >= 0) { if (copy_len != 0) { d1--; } d1--; if (d1 < 0) { d1 = 0; } } copy_len += 2; copy_src = io->dest + dest_offset - get_bits(io, count) - 1; /* Sanity check */ if (copy_src < dest_start || copy_src + copy_len >= dest_end) { return -1; } do { //printf("dest=%p src=%p end=%p\n", io->dest, copy_src, dest_end); *io->dest++ = *copy_src++; } while (copy_len--); *data = *(--copy_src); return d1; } static int unsqsh_block(struct io *io, uint8 *dest_start, uint8 *dest_end) { int d1, d2, data, unpack_len, count, old_count; d1 = d2 = data = old_count = 0; io->offs = 0; data = *(io->src++); *(io->dest++) = data; do { if (d1 < 8) { if (get_bits(io, 1)) { d1 = copy_data(io, d1, &data, dest_start, dest_end); if (d1 < 0) return -1; d2 -= d2 >> 3; continue; } unpack_len = 0; count = 8; } else { if (get_bits(io, 1)) { count = 8; if (count == old_count) { if (d2 >= 20) { unpack_len = 1; d2 += 8; } else { unpack_len = 0; } } else { count = old_count; unpack_len = 4; d2 += 8; } } else { if (get_bits(io, 1) == 0) { d1 = copy_data(io, d1, &data, dest_start, dest_end); if (d1 < 0) return -1; d2 -= d2 >> 3; continue; } if (get_bits(io, 1) == 0) { count = 2; } else { if (get_bits(io, 1)) { io->offs--; count = get_bits(io, 3); } else { count = 3; } } count = ctable[8 * old_count + count - 17]; if (count != 8) { unpack_len = 4; d2 += 8; } else { if (d2 >= 20) { unpack_len = 1; d2 += 8; } else { unpack_len = 0; } } } } do { data -= get_bits_final(io, count); *io->dest++ = data; } while (unpack_len--); if (d1 != 31) { d1++; } old_count = count; d2 -= d2 >> 3; } while (io->dest < dest_end); return 0; } static int unsqsh(uint8 *src, int srclen, uint8 *dest, int destlen) { int len = destlen; int decrunched = 0; int type; int sum, packed_size, unpacked_size; int lchk; uint8 *c, *dest_start, *dest_end; uint8 bc[3]; struct io io; io.src = src; io.dest = dest; dest_start = io.dest; c = src + 20; while (len) { /* Sanity check */ if (c >= src + srclen) { return -1; } type = *c++; c++; /* hchk */ sum = *(uint16 *)c; c += 2; /* checksum */ packed_size = readmem16b(c); /* packed */ c += 2; unpacked_size = readmem16b(c); /* unpacked */ c += 2; /* Sanity check */ if (packed_size <= 0 || unpacked_size <= 0) { return -1; } if (c + packed_size + 3 > src + srclen) { return -1; } io.src = c + 2; memcpy(bc, c + packed_size, 3); memset(c + packed_size, 0, 3); lchk = xchecksum((uint32 *) (c), (packed_size + 3) >> 2); memcpy(c + packed_size, bc, 3); if (lchk != sum) { return decrunched; } if (type == 0) { /* verbatim block */ memcpy(io.dest, c, packed_size); io.dest += packed_size; c += packed_size; len -= packed_size; decrunched += packed_size; continue; } if (type != 1) { /* unknown type */ return decrunched; } len -= unpacked_size; decrunched += unpacked_size; /* Sanity check */ if (decrunched > destlen) { return -1; } packed_size = (packed_size + 3) & 0xfffc; c += packed_size; dest_end = io.dest + unpacked_size; if (unsqsh_block(&io, dest_start, dest_end) < 0) { return -1; } io.dest = dest_end; } return decrunched; } static int test_sqsh(unsigned char *b) { return memcmp(b, "XPKF", 4) == 0 && memcmp(b + 8, "SQSH", 4) == 0; } static int decrunch_sqsh(FILE * f, FILE * fo) { unsigned char *src, *dest; int srclen, destlen; if (read32b(f, NULL) != 0x58504b46) /* XPKF */ goto err; srclen = read32b(f, NULL); /* Sanity check */ if (srclen <= 8 || srclen > 0x100000) goto err; if (read32b(f, NULL) != 0x53515348) /* SQSH */ goto err; destlen = read32b(f, NULL); if (destlen < 0 || destlen > 0x100000) goto err; if ((src = malloc(srclen + 3)) == NULL) goto err; if ((dest = malloc(destlen + 100)) == NULL) goto err2; if (fread(src, srclen - 8, 1, f) != 1) goto err3; if (unsqsh(src, srclen, dest, destlen) != destlen) goto err3; if (fwrite(dest, destlen, 1, fo) != 1) goto err3; free(dest); free(src); return 0; err3: free(dest); err2: free(src); err: return -1; } struct depacker libxmp_depacker_sqsh = { test_sqsh, decrunch_sqsh }; libxmp-4.4.1/src/depackers/xz_dec_stream.c0000664000175000017500000004651012773571316020404 0ustar claudioclaudio/* * .xz Stream decoder * * Author: Lasse Collin * * This file has been put into the public domain. * You can do whatever you want with this file. */ #include "xz_private.h" #include "xz_stream.h" #include "crc32.h" /* Hash used to validate the Index field */ struct xz_dec_hash { vli_type unpadded; vli_type uncompressed; uint32 crc32; }; struct xz_dec { /* Position in dec_main() */ enum { SEQ_STREAM_HEADER, SEQ_BLOCK_START, SEQ_BLOCK_HEADER, SEQ_BLOCK_UNCOMPRESS, SEQ_BLOCK_PADDING, SEQ_BLOCK_CHECK, SEQ_INDEX, SEQ_INDEX_PADDING, SEQ_INDEX_CRC32, SEQ_STREAM_FOOTER } sequence; /* Position in variable-length integers and Check fields */ uint32 pos; /* Variable-length integer decoded by dec_vli() */ vli_type vli; /* Saved in_pos and out_pos */ size_t in_start; size_t out_start; /* CRC32 value in Block or Index */ uint32 crc32; /* Type of the integrity check calculated from uncompressed data */ enum xz_check check_type; /* Operation mode */ enum xz_mode mode; /* * True if the next call to xz_dec_run() is allowed to return * XZ_BUF_ERROR. */ bool allow_buf_error; /* Information stored in Block Header */ struct { /* * Value stored in the Compressed Size field, or * VLI_UNKNOWN if Compressed Size is not present. */ vli_type compressed; /* * Value stored in the Uncompressed Size field, or * VLI_UNKNOWN if Uncompressed Size is not present. */ vli_type uncompressed; /* Size of the Block Header field */ uint32 size; } block_header; /* Information collected when decoding Blocks */ struct { /* Observed compressed size of the current Block */ vli_type compressed; /* Observed uncompressed size of the current Block */ vli_type uncompressed; /* Number of Blocks decoded so far */ vli_type count; /* * Hash calculated from the Block sizes. This is used to * validate the Index field. */ struct xz_dec_hash hash; } block; /* Variables needed when verifying the Index field */ struct { /* Position in dec_index() */ enum { SEQ_INDEX_COUNT, SEQ_INDEX_UNPADDED, SEQ_INDEX_UNCOMPRESSED } sequence; /* Size of the Index in bytes */ vli_type size; /* Number of Records (matches block.count in valid files) */ vli_type count; /* * Hash calculated from the Records (matches block.hash in * valid files). */ struct xz_dec_hash hash; } index; /* * Temporary buffer needed to hold Stream Header, Block Header, * and Stream Footer. The Block Header is the biggest (1 KiB) * so we reserve space according to that. buf[] has to be aligned * to a multiple of four bytes; the size_t variables before it * should guarantee this. */ struct { size_t pos; size_t size; uint8 buf[1024]; } temp; struct xz_dec_lzma2 *lzma2; #ifdef XZ_DEC_BCJ struct xz_dec_bcj *bcj; bool bcj_active; #endif }; #ifdef XZ_DEC_ANY_CHECK /* Sizes of the Check field with different Check IDs */ static const uint8 check_sizes[16] = { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 }; #endif /* * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller * must have set s->temp.pos to indicate how much data we are supposed * to copy into s->temp.buf. Return true once s->temp.pos has reached * s->temp.size. */ static bool fill_temp(struct xz_dec *s, struct xz_buf *b) { size_t copy_size = min_t(size_t, b->in_size - b->in_pos, s->temp.size - s->temp.pos); memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); b->in_pos += copy_size; s->temp.pos += copy_size; if (s->temp.pos == s->temp.size) { s->temp.pos = 0; return true; } return false; } /* Decode a variable-length integer (little-endian base-128 encoding) */ static enum xz_ret dec_vli(struct xz_dec *s, const uint8 *in, size_t *in_pos, size_t in_size) { uint8 byte; if (s->pos == 0) s->vli = 0; while (*in_pos < in_size) { byte = in[*in_pos]; ++*in_pos; s->vli |= (vli_type)(byte & 0x7F) << s->pos; if ((byte & 0x80) == 0) { /* Don't allow non-minimal encodings. */ if (byte == 0 && s->pos != 0) return XZ_DATA_ERROR; s->pos = 0; return XZ_STREAM_END; } s->pos += 7; if (s->pos == 7 * VLI_BYTES_MAX) return XZ_DATA_ERROR; } return XZ_OK; } /* * Decode the Compressed Data field from a Block. Update and validate * the observed compressed and uncompressed sizes of the Block so that * they don't exceed the values possibly stored in the Block Header * (validation assumes that no integer overflow occurs, since vli_type * is normally uint64). Update the CRC32 if presence of the CRC32 * field was indicated in Stream Header. * * Once the decoding is finished, validate that the observed sizes match * the sizes possibly stored in the Block Header. Update the hash and * Block count, which are later used to validate the Index field. */ static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) { enum xz_ret ret; s->in_start = b->in_pos; s->out_start = b->out_pos; #ifdef XZ_DEC_BCJ if (s->bcj_active) ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); else #endif ret = xz_dec_lzma2_run(s->lzma2, b); s->block.compressed += b->in_pos - s->in_start; s->block.uncompressed += b->out_pos - s->out_start; /* * There is no need to separately check for VLI_UNKNOWN, since * the observed sizes are always smaller than VLI_UNKNOWN. */ if (s->block.compressed > s->block_header.compressed || s->block.uncompressed > s->block_header.uncompressed) return XZ_DATA_ERROR; if (s->check_type == XZ_CHECK_CRC32) s->crc32 = libxmp_crc32_A1(b->out + s->out_start, b->out_pos - s->out_start, s->crc32); if (ret == XZ_STREAM_END) { if (s->block_header.compressed != VLI_UNKNOWN && s->block_header.compressed != s->block.compressed) return XZ_DATA_ERROR; if (s->block_header.uncompressed != VLI_UNKNOWN && s->block_header.uncompressed != s->block.uncompressed) return XZ_DATA_ERROR; s->block.hash.unpadded += s->block_header.size + s->block.compressed; #ifdef XZ_DEC_ANY_CHECK s->block.hash.unpadded += check_sizes[s->check_type]; #else if (s->check_type == XZ_CHECK_CRC32) s->block.hash.unpadded += 4; #endif s->block.hash.uncompressed += s->block.uncompressed; s->block.hash.crc32 = libxmp_crc32_A1( (const uint8 *)&s->block.hash, sizeof(s->block.hash), s->block.hash.crc32); ++s->block.count; } return ret; } /* Update the Index size and the CRC32 value. */ static void index_update(struct xz_dec *s, const struct xz_buf *b) { size_t in_used = b->in_pos - s->in_start; s->index.size += in_used; s->crc32 = libxmp_crc32_A1(b->in + s->in_start, in_used, s->crc32); } /* * Decode the Number of Records, Unpadded Size, and Uncompressed Size * fields from the Index field. That is, Index Padding and CRC32 are not * decoded by this function. * * This can return XZ_OK (more input needed), XZ_STREAM_END (everything * successfully decoded), or XZ_DATA_ERROR (input is corrupt). */ static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) { enum xz_ret ret; do { ret = dec_vli(s, b->in, &b->in_pos, b->in_size); if (ret != XZ_STREAM_END) { index_update(s, b); return ret; } switch (s->index.sequence) { case SEQ_INDEX_COUNT: s->index.count = s->vli; /* * Validate that the Number of Records field * indicates the same number of Records as * there were Blocks in the Stream. */ if (s->index.count != s->block.count) return XZ_DATA_ERROR; s->index.sequence = SEQ_INDEX_UNPADDED; break; case SEQ_INDEX_UNPADDED: s->index.hash.unpadded += s->vli; s->index.sequence = SEQ_INDEX_UNCOMPRESSED; break; case SEQ_INDEX_UNCOMPRESSED: s->index.hash.uncompressed += s->vli; s->index.hash.crc32 = libxmp_crc32_A1( (const uint8 *)&s->index.hash, sizeof(s->index.hash), s->index.hash.crc32); --s->index.count; s->index.sequence = SEQ_INDEX_UNPADDED; break; } } while (s->index.count > 0); return XZ_STREAM_END; } /* * Validate that the next four input bytes match the value of s->crc32. * s->pos must be zero when starting to validate the first byte. */ static enum xz_ret libxmp_crc32_validate(struct xz_dec *s, struct xz_buf *b) { do { if (b->in_pos == b->in_size) return XZ_OK; if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) return XZ_DATA_ERROR; s->pos += 8; } while (s->pos < 32); s->crc32 = 0; s->pos = 0; return XZ_STREAM_END; } #ifdef XZ_DEC_ANY_CHECK /* * Skip over the Check field when the Check ID is not supported. * Returns true once the whole Check field has been skipped over. */ static bool check_skip(struct xz_dec *s, struct xz_buf *b) { while (s->pos < check_sizes[s->check_type]) { if (b->in_pos == b->in_size) return false; ++b->in_pos; ++s->pos; } s->pos = 0; return true; } #endif /* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ static enum xz_ret dec_stream_header(struct xz_dec *s) { if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) return XZ_FORMAT_ERROR; if (libxmp_crc32_A1(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) return XZ_DATA_ERROR; if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) return XZ_OPTIONS_ERROR; /* * Of integrity checks, we support only none (Check ID = 0) and * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, * we will accept other check types too, but then the check won't * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. */ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; #ifdef XZ_DEC_ANY_CHECK if (s->check_type > XZ_CHECK_MAX) return XZ_OPTIONS_ERROR; if (s->check_type > XZ_CHECK_CRC32) return XZ_UNSUPPORTED_CHECK; #else if (s->check_type > XZ_CHECK_CRC32) return XZ_OPTIONS_ERROR; #endif return XZ_OK; } /* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ static enum xz_ret dec_stream_footer(struct xz_dec *s) { if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) return XZ_DATA_ERROR; if (libxmp_crc32_A1(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) return XZ_DATA_ERROR; /* * Validate Backward Size. Note that we never added the size of the * Index CRC32 field to s->index.size, thus we use s->index.size / 4 * instead of s->index.size / 4 - 1. */ if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) return XZ_DATA_ERROR; if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) return XZ_DATA_ERROR; /* * Use XZ_STREAM_END instead of XZ_OK to be more convenient * for the caller. */ return XZ_STREAM_END; } /* Decode the Block Header and initialize the filter chain. */ static enum xz_ret dec_block_header(struct xz_dec *s) { enum xz_ret ret; /* * Validate the CRC32. We know that the temp buffer is at least * eight bytes so this is safe. */ s->temp.size -= 4; if (libxmp_crc32_A1(s->temp.buf, s->temp.size, 0) != get_le32(s->temp.buf + s->temp.size)) return XZ_DATA_ERROR; s->temp.pos = 2; /* * Catch unsupported Block Flags. We support only one or two filters * in the chain, so we catch that with the same test. */ #ifdef XZ_DEC_BCJ if (s->temp.buf[1] & 0x3E) #else if (s->temp.buf[1] & 0x3F) #endif return XZ_OPTIONS_ERROR; /* Compressed Size */ if (s->temp.buf[1] & 0x40) { if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) != XZ_STREAM_END) return XZ_DATA_ERROR; s->block_header.compressed = s->vli; } else { s->block_header.compressed = VLI_UNKNOWN; } /* Uncompressed Size */ if (s->temp.buf[1] & 0x80) { if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) != XZ_STREAM_END) return XZ_DATA_ERROR; s->block_header.uncompressed = s->vli; } else { s->block_header.uncompressed = VLI_UNKNOWN; } #ifdef XZ_DEC_BCJ /* If there are two filters, the first one must be a BCJ filter. */ s->bcj_active = s->temp.buf[1] & 0x01; if (s->bcj_active) { if (s->temp.size - s->temp.pos < 2) return XZ_OPTIONS_ERROR; ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); if (ret != XZ_OK) return ret; /* * We don't support custom start offset, * so Size of Properties must be zero. */ if (s->temp.buf[s->temp.pos++] != 0x00) return XZ_OPTIONS_ERROR; } #endif /* Valid Filter Flags always take at least two bytes. */ if (s->temp.size - s->temp.pos < 2) return XZ_DATA_ERROR; /* Filter ID = LZMA2 */ if (s->temp.buf[s->temp.pos++] != 0x21) return XZ_OPTIONS_ERROR; /* Size of Properties = 1-byte Filter Properties */ if (s->temp.buf[s->temp.pos++] != 0x01) return XZ_OPTIONS_ERROR; /* Filter Properties contains LZMA2 dictionary size. */ if (s->temp.size - s->temp.pos < 1) return XZ_DATA_ERROR; ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); if (ret != XZ_OK) return ret; /* The rest must be Header Padding. */ while (s->temp.pos < s->temp.size) if (s->temp.buf[s->temp.pos++] != 0x00) return XZ_OPTIONS_ERROR; s->temp.pos = 0; s->block.compressed = 0; s->block.uncompressed = 0; return XZ_OK; } static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) { enum xz_ret ret; /* * Store the start position for the case when we are in the middle * of the Index field. */ s->in_start = b->in_pos; while (true) { switch (s->sequence) { case SEQ_STREAM_HEADER: /* * Stream Header is copied to s->temp, and then * decoded from there. This way if the caller * gives us only little input at a time, we can * still keep the Stream Header decoding code * simple. Similar approach is used in many places * in this file. */ if (!fill_temp(s, b)) return XZ_OK; /* * If dec_stream_header() returns * XZ_UNSUPPORTED_CHECK, it is still possible * to continue decoding if working in multi-call * mode. Thus, update s->sequence before calling * dec_stream_header(). */ s->sequence = SEQ_BLOCK_START; ret = dec_stream_header(s); if (ret != XZ_OK) return ret; case SEQ_BLOCK_START: /* We need one byte of input to continue. */ if (b->in_pos == b->in_size) return XZ_OK; /* See if this is the beginning of the Index field. */ if (b->in[b->in_pos] == 0) { s->in_start = b->in_pos++; s->sequence = SEQ_INDEX; break; } /* * Calculate the size of the Block Header and * prepare to decode it. */ s->block_header.size = ((uint32)b->in[b->in_pos] + 1) * 4; s->temp.size = s->block_header.size; s->temp.pos = 0; s->sequence = SEQ_BLOCK_HEADER; case SEQ_BLOCK_HEADER: if (!fill_temp(s, b)) return XZ_OK; ret = dec_block_header(s); if (ret != XZ_OK) return ret; s->sequence = SEQ_BLOCK_UNCOMPRESS; case SEQ_BLOCK_UNCOMPRESS: ret = dec_block(s, b); if (ret != XZ_STREAM_END) return ret; s->sequence = SEQ_BLOCK_PADDING; case SEQ_BLOCK_PADDING: /* * Size of Compressed Data + Block Padding * must be a multiple of four. We don't need * s->block.compressed for anything else * anymore, so we use it here to test the size * of the Block Padding field. */ while (s->block.compressed & 3) { if (b->in_pos == b->in_size) return XZ_OK; if (b->in[b->in_pos++] != 0) return XZ_DATA_ERROR; ++s->block.compressed; } s->sequence = SEQ_BLOCK_CHECK; case SEQ_BLOCK_CHECK: if (s->check_type == XZ_CHECK_CRC32) { ret = libxmp_crc32_validate(s, b); if (ret != XZ_STREAM_END) return ret; } #ifdef XZ_DEC_ANY_CHECK else if (!check_skip(s, b)) { return XZ_OK; } #endif s->sequence = SEQ_BLOCK_START; break; case SEQ_INDEX: ret = dec_index(s, b); if (ret != XZ_STREAM_END) return ret; s->sequence = SEQ_INDEX_PADDING; case SEQ_INDEX_PADDING: while ((s->index.size + (b->in_pos - s->in_start)) & 3) { if (b->in_pos == b->in_size) { index_update(s, b); return XZ_OK; } if (b->in[b->in_pos++] != 0) return XZ_DATA_ERROR; } /* Finish the CRC32 value and Index size. */ index_update(s, b); /* Compare the hashes to validate the Index field. */ if (!memeq(&s->block.hash, &s->index.hash, sizeof(s->block.hash))) return XZ_DATA_ERROR; s->sequence = SEQ_INDEX_CRC32; case SEQ_INDEX_CRC32: ret = libxmp_crc32_validate(s, b); if (ret != XZ_STREAM_END) return ret; s->temp.size = STREAM_HEADER_SIZE; s->sequence = SEQ_STREAM_FOOTER; case SEQ_STREAM_FOOTER: if (!fill_temp(s, b)) return XZ_OK; return dec_stream_footer(s); } } /* Never reached */ } /* * xz_dec_run() is a wrapper for dec_main() to handle some special cases in * multi-call and single-call decoding. * * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we * are not going to make any progress anymore. This is to prevent the caller * from calling us infinitely when the input file is truncated or otherwise * corrupt. Since zlib-style API allows that the caller fills the input buffer * only when the decoder doesn't produce any new output, we have to be careful * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only * after the second consecutive call to xz_dec_run() that makes no progress. * * In single-call mode, if we couldn't decode everything and no error * occurred, either the input is truncated or the output buffer is too small. * Since we know that the last input byte never produces any output, we know * that if all the input was consumed and decoding wasn't finished, the file * must be corrupt. Otherwise the output buffer has to be too small or the * file is corrupt in a way that decoding it produces too big output. * * If single-call decoding fails, we reset b->in_pos and b->out_pos back to * their original values. This is because with some filter chains there won't * be any valid uncompressed data in the output buffer unless the decoding * actually succeeds (that's the price to pay of using the output buffer as * the workspace). */ XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b) { size_t in_start; size_t out_start; enum xz_ret ret; if (DEC_IS_SINGLE(s->mode)) xz_dec_reset(s); in_start = b->in_pos; out_start = b->out_pos; ret = dec_main(s, b); if (DEC_IS_SINGLE(s->mode)) { if (ret == XZ_OK) ret = b->in_pos == b->in_size ? XZ_DATA_ERROR : XZ_BUF_ERROR; if (ret != XZ_STREAM_END) { b->in_pos = in_start; b->out_pos = out_start; } } else if (ret == XZ_OK && in_start == b->in_pos && out_start == b->out_pos) { if (s->allow_buf_error) ret = XZ_BUF_ERROR; s->allow_buf_error = true; } else { s->allow_buf_error = false; } return ret; } XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32 dict_max) { struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); if (s == NULL) return NULL; s->mode = mode; #ifdef XZ_DEC_BCJ s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); if (s->bcj == NULL) goto error_bcj; #endif s->lzma2 = xz_dec_lzma2_create(mode, dict_max); if (s->lzma2 == NULL) goto error_lzma2; xz_dec_reset(s); return s; error_lzma2: #ifdef XZ_DEC_BCJ xz_dec_bcj_end(s->bcj); error_bcj: #endif kfree(s); return NULL; } XZ_EXTERN void xz_dec_reset(struct xz_dec *s) { s->sequence = SEQ_STREAM_HEADER; s->allow_buf_error = false; s->pos = 0; s->crc32 = 0; memzero(&s->block, sizeof(s->block)); memzero(&s->index, sizeof(s->index)); s->temp.pos = 0; s->temp.size = STREAM_HEADER_SIZE; } XZ_EXTERN void xz_dec_end(struct xz_dec *s) { if (s != NULL) { xz_dec_lzma2_end(s->lzma2); #ifdef XZ_DEC_BCJ xz_dec_bcj_end(s->bcj); #endif kfree(s); } } libxmp-4.4.1/src/depackers/readlzw.c0000664000175000017500000003245012773571316017223 0ustar claudioclaudio/* nomarch 1.4 - extract old `.arc' archives. * Copyright (C) 2001-2006 Russell Marks. See unarc.c for license details. * * Modified for xmp by Claudio Matsuoka, Aug 2007 * - add quirks for Digital Symphony LZW packing * - add wrapper to read data from stream * * Modified for xmp by Claudio Matsuoka, Feb 2012 * - remove global data * * readlzw.c - read (RLE+)LZW-compressed files. * * This is based on zgv's GIF reader. The LZW stuff is much the same, but * figuring out the details of the rather bizarre encoding involved much * wall therapy. %-( */ #include #include #include #include #include "readrle.h" #include "common.h" #include "readlzw.h" struct local_data { /* now this is for the string table. * the data->st_ptr array stores which pos to back reference to, * each string is [...]+ end char, [...] is traced back through * the 'pointer' (index really), then back through the next, etc. * a 'null pointer' is = to UNUSED. * the data->st_chr array gives the end char for each. * an unoccupied slot is = to UNUSED. */ #define UNUSED (-1) #define REALMAXSTR 65536 int st_ptr[REALMAXSTR],st_chr[REALMAXSTR],st_last; int st_ptr1st[REALMAXSTR]; /* this is for the byte -> bits mangler: * dc_bitbox holds the bits, dc_bitsleft is number of bits left in dc_bitbox, */ int dc_bitbox,dc_bitsleft; int codeofs; int global_use_rle,oldver; struct rledata rd; struct data_in_out io; uint32 quirk; int maxstr; int outputstring_buf[REALMAXSTR]; int st_oldverhashlinks[4096]; /* only used for 12-bit types */ int nomarch_input_size; /* hack for xmp, will fix later */ }; /* prototypes */ static void code_resync(int old, struct local_data *); static void inittable(int orgcsize, struct local_data *); static int addstring(int oldcode,int chr, struct local_data *); static int readcode(int *newcode,int numbits, struct local_data *); static void outputstring(int code, struct local_data *); static void outputchr(int chr, struct local_data *); static int findfirstchr(int code, struct local_data *); static unsigned char *convert_lzw_dynamic(unsigned char *data_in, int max_bits,int use_rle, unsigned long in_len, unsigned long orig_len, int q, struct local_data *data) { unsigned char *data_out; int csize,orgcsize; int newcode,oldcode,k=0; int first=1,noadd; //printf("in_len = %d, orig_len = %d\n", in_len, orig_len); data->quirk = q; data->global_use_rle=use_rle; data->maxstr=(1<maxstr > REALMAXSTR) return NULL; if((data_out=calloc(1, orig_len))==NULL) { //fprintf(stderr,"nomarch: out of memory!\n"); return NULL; } data->io.data_in_point=data_in; data->io.data_in_max=data_in+in_len; data->io.data_out_point=data_out; data->io.data_out_max=data_out+orig_len; data->dc_bitbox=data->dc_bitsleft=0; data->codeofs=0; libxmp_outputrle(-1,NULL, &data->rd, &data->io); /* init RLE */ data->oldver=0; csize=9; /* initial code size */ if(max_bits==0) /* special case for static 12-bit */ data->oldver=1,csize=12,data->maxstr=4096; orgcsize=csize; inittable(orgcsize, data); oldcode=newcode=0; if(data->quirk & NOMARCH_QUIRK_SKIPMAX) data->io.data_in_point++; /* skip type 8 max. code size, always 12 */ if(max_bits==16) data->maxstr=(1<<*data->io.data_in_point++); /* but compress-type *may* change it (!) */ /* XXX */ if (data->maxstr > (1 << max_bits)) return NULL; data->nomarch_input_size = 0; while(1) { //printf("input_size = %d csize = %d\n", data->nomarch_input_size, csize); if(!readcode(&newcode,csize,data)) { //printf("readcode failed!\n"); break; } //printf("newcode = %x\n", newcode); if (data->quirk & NOMARCH_QUIRK_END101) { if (newcode == 0x101 /* data_out_point>=data_out_max */) { //printf("end\n"); break; } } noadd=0; if(first) { k=newcode,first=0; if(data->oldver) noadd=1; } if(newcode==256 && !data->oldver) { /* this *doesn't* reset the table (!), merely reduces code size again. * (It makes new strings by treading on the old entries.) * This took fscking forever to work out... :-( */ data->st_last=255; if (data->quirk & NOMARCH_QUIRK_START101) /* CM: Digital symphony data->quirk */ data->st_last++; /* XXX do we need a resync if there's a reset when *already* csize==9? * (er, assuming that can ever happen?) */ code_resync(csize, data); csize=orgcsize; if(!readcode(&newcode,csize,data)) break; } if((!data->oldver && newcode<=data->st_last) || (data->oldver && data->st_chr[newcode]!=UNUSED)) { outputstring(newcode, data); k=findfirstchr(newcode, data); } else { /* this is a bit of an assumption, but these ones don't seem to happen in * non-broken files, so... */ #if 0 /* actually, don't bother, just let the CRC tell the story. */ if(newcode>data->st_last+1) fprintf(stderr,"warning: bad LZW code\n"); #endif /* k=findfirstchr(oldcode);*/ /* don't think I actually need this */ outputstring(oldcode, data); outputchr(k, data); } if(data->st_last!=data->maxstr-1) { if(!noadd) { if(!addstring(oldcode,k,data)) { /* XXX I think this is meant to be non-fatal? * well, nothing for now, anyway... */ } if(data->st_last!=data->maxstr-1 && data->st_last==((1<quirk & NOMARCH_QUIRK_NOCHK) { /* junk it on error */ if(data->io.data_in_point!=data->io.data_in_max) { free(data_out); return(NULL); } } return(data_out); } unsigned char *libxmp_convert_lzw_dynamic(unsigned char *data_in, int max_bits,int use_rle, unsigned long in_len, unsigned long orig_len, int q) { struct local_data *data; unsigned char *d; if ((data = malloc(sizeof (struct local_data))) == NULL) { goto err; } d = convert_lzw_dynamic(data_in, max_bits, use_rle, in_len, orig_len, q, data); /* Sanity check */ if (d == NULL) { goto err2; } if (d + orig_len != data->io.data_out_point) { free(d); goto err2; } free(data); return d; err2: free(data); err: return NULL; } unsigned char *libxmp_read_lzw_dynamic(FILE *f, uint8 *buf, int max_bits,int use_rle, unsigned long in_len, unsigned long orig_len, int q) { uint8 *buf2, *b; int pos; int size; struct local_data *data; if ((data = malloc(sizeof (struct local_data))) == NULL) { goto err; } if ((buf2 = malloc(in_len)) == NULL) { //perror("read_lzw_dynamic"); goto err2; } pos = ftell(f); if (fread(buf2, 1, in_len, f) != in_len) { if (~q & XMP_LZW_QUIRK_DSYM) { goto err3; } } b = convert_lzw_dynamic(buf2, max_bits, use_rle, in_len, orig_len, q, data); memcpy(buf, b, orig_len); size = q & NOMARCH_QUIRK_ALIGN4 ? ALIGN4(data->nomarch_input_size) : data->nomarch_input_size; if (fseek(f, pos + size, SEEK_SET) < 0) { goto err4; } free(b); free(buf2); free(data); return buf; err4: free(b); err3: free(buf2); err2: free(data); err: return NULL; } /* uggghhhh, this is agonisingly painful. It turns out that * the original program bunched up codes into groups of 8, so we have * to waste on average about 5 or 6 bytes when we increase code size. * (and ghod, was this ever a complete bastard to track down.) * mmm, nice, tell me again why this format is dead? */ static void code_resync(int old, struct local_data *data) { int tmp; if (data->quirk & NOMARCH_QUIRK_NOSYNC) return; while(data->codeofs) if(!readcode(&tmp,old,data)) break; } static void inittable(int orgcsize, struct local_data *data) { int f; int numcols=(1<<(orgcsize-1)); for(f=0;fst_chr[f]=UNUSED; data->st_ptr[f]=UNUSED; data->st_ptr1st[f]=UNUSED; } for(f=0;f<4096;f++) data->st_oldverhashlinks[f]=UNUSED; if(data->oldver) { data->st_last=-1; /* since it's a counter, when static */ for(f=0;f<256;f++) addstring(0xffff,f,data); } else { for(f=0;fst_chr[f]=f; data->st_last=numcols-1; /* last occupied slot */ if (data->quirk & NOMARCH_QUIRK_START101) /* CM: Digital symphony quirk */ data->st_last++; } } /* required for finding true table index in ver 1.x files */ static int oldver_getidx(int oldcode,int chr, struct local_data *data) { int lasthash,hashval; int a,f; /* in type 5/6 crunched files, we hash the code into the array. This * means we don't have a real data->st_last, but for compatibility with * the rest of the code we pretend it still means that. (data->st_last * has already been incremented by the time we get called.) In our * case it's only useful as a measure of how full the table is. * * the hash is a mid-square thing. */ a=(((oldcode+chr)|0x800)&0xffff); hashval=(((a*a)>>6)&0xfff); /* first, check link chain from there */ while(data->st_chr[hashval]!=UNUSED && data->st_oldverhashlinks[hashval]!=UNUSED) hashval=data->st_oldverhashlinks[hashval]; /* make sure we return early if possible to avoid adding link */ if(data->st_chr[hashval]==UNUSED) return(hashval); lasthash=hashval; /* slightly odd approach if it's not in that - first try skipping * 101 entries, then try them one-by-one. It should be impossible * for this to loop indefinitely, if the table isn't full. (And we * shouldn't have been called if it was full...) */ hashval+=101; hashval&=0xfff; if(data->st_chr[hashval]!=UNUSED) { for(f=0;fmaxstr;f++,hashval++,hashval&=0xfff) if(data->st_chr[hashval]==UNUSED) break; if(hashval==data->maxstr) return(-1); /* table full, can't happen */ } /* add link to here from the end of the chain */ data->st_oldverhashlinks[lasthash]=hashval; return(hashval); } /* add a string specified by oldstring + chr to string table */ int addstring(int oldcode,int chr, struct local_data *data) { int idx; //printf("oldcode = %02x\n", oldcode); data->st_last++; if((data->st_last&data->maxstr)) { data->st_last=data->maxstr-1; return(1); /* not too clear if it should die or not... */ } idx=data->st_last; //printf("addstring idx=%x, oldcode=%02x, chr=%02x\n", idx, oldcode, chr); if(data->oldver) { /* old version finds index in a rather odd way. */ if((idx=oldver_getidx(oldcode,chr,data))==-1) return(0); } data->st_chr[idx]=chr; /* XXX should I re-enable this? think it would be ok... */ #if 0 if(data->st_last==oldcode) return(0); /* corrupt */ #endif if(oldcode>=data->maxstr) return(1); data->st_ptr[idx]=oldcode; if(data->st_ptr[oldcode]==UNUSED) /* if we're pointing to a root... */ data->st_ptr1st[idx]=oldcode; /* then that holds the first char */ else /* otherwise... */ data->st_ptr1st[idx]=data->st_ptr1st[oldcode]; /* use their pointer to first */ return(1); } /* read a code of bitlength numbits */ static int readcode(int *newcode,int numbits, struct local_data *data) { int bitsfilled,got; bitsfilled=got=0; (*newcode)=0; while(bitsfilleddc_bitsleft==0) /* have we run out of bits? */ { if(data->io.data_in_point>=data->io.data_in_max) { //printf("data_in_point=%p >= data_in_max=%p\n", data_in_point, data_in_max); return(0); } data->dc_bitbox=*data->io.data_in_point++; data->dc_bitsleft=8; data->nomarch_input_size++; /* hack for xmp/dsym */ } if(data->dc_bitsleftdc_bitsleft; else got=numbits-bitsfilled; if(data->oldver) { data->dc_bitbox&=0xff; data->dc_bitbox<<=got; bitsfilled+=got; /* Sanity check */ if (bitsfilled > numbits) { return 0; } (*newcode)|=((data->dc_bitbox>>8)<<(numbits-bitsfilled)); data->dc_bitsleft-=got; } else { (*newcode)|=((data->dc_bitbox&((1<dc_bitbox>>=got; data->dc_bitsleft-=got; bitsfilled+=got; } } if((*newcode)<0 || (*newcode)>data->maxstr-1) { //printf("*newcode (= %d) < 0 || *newcode (= %d) > data->maxstr (= %d) - 1\n", newcode, newcode, data->maxstr); return(0); } /* yuck... see code_resync() for explanation */ data->codeofs++; data->codeofs&=7; return(1); } static void outputstring(int code, struct local_data *data) { int *ptr=data->outputstring_buf; while(data->st_ptr[code]!=UNUSED && ptroutputstring_buf+data->maxstr) { *ptr++=data->st_chr[code]; code=data->st_ptr[code]; } outputchr(data->st_chr[code], data); while(ptr>data->outputstring_buf) outputchr(*--ptr, data); } static void rawoutput(int byte, struct data_in_out *io) { //static int i = 0; if(io->data_out_pointdata_out_max) *io->data_out_point++=byte; //printf(" output = %02x <================ %06x\n", byte, i++); } static void outputchr(int chr, struct local_data *data) { if(data->global_use_rle) libxmp_outputrle(chr,rawoutput,&data->rd,&data->io); else rawoutput(chr,&data->io); } static int findfirstchr(int code, struct local_data *data) { if(data->st_ptr[code]!=UNUSED) /* not first? then use brand new st_ptr1st! */ code=data->st_ptr1st[code]; /* now with no artificial colouring */ return(data->st_chr[code]); } libxmp-4.4.1/src/depackers/xz_stream.h0000664000175000017500000000266712641457214017575 0ustar claudioclaudio/* * Definitions for handling the .xz file format * * Author: Lasse Collin * * This file has been put into the public domain. * You can do whatever you want with this file. */ #ifndef XZ_STREAM_H #define XZ_STREAM_H #if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 # include # undef crc32 # define xz_crc32(buf, size, crc) \ (~crc32_le(~(uint32)(crc), buf, size)) #endif /* * See the .xz file format specification at * http://tukaani.org/xz/xz-file-format.txt * to understand the container format. */ #define STREAM_HEADER_SIZE 12 #define HEADER_MAGIC "\3757zXZ" #define HEADER_MAGIC_SIZE 6 #define FOOTER_MAGIC "YZ" #define FOOTER_MAGIC_SIZE 2 /* * Variable-length integer can hold a 63-bit unsigned integer or a special * value indicating that the value is unknown. * * Experimental: vli_type can be defined to uint32 to save a few bytes * in code size (no effect on speed). Doing so limits the uncompressed and * compressed size of the file to less than 256 MiB and may also weaken * error detection slightly. */ typedef uint64 vli_type; #define VLI_MAX ((vli_type)-1 / 2) #define VLI_UNKNOWN ((vli_type)-1) /* Maximum encoded size of a VLI */ #define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) /* Integrity Check types */ enum xz_check { XZ_CHECK_NONE = 0, XZ_CHECK_CRC32 = 1, XZ_CHECK_CRC64 = 4, XZ_CHECK_SHA256 = 10 }; /* Maximum possible Check ID */ #define XZ_CHECK_MAX 15 #endif libxmp-4.4.1/src/depackers/unlha.c0000664000175000017500000012546612775035311016664 0ustar claudioclaudio/* $Id: LhA.c,v 1.16 2010/05/27 16:48:30 stoecker Exp $ LhA file archiver client XAD library system for archive handling Copyright (C) 1998 and later by Dirk Stoecker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Modified for xmp by Claudio Matsuoka, 20120812 */ #include #include #include "common.h" #include "depacker.h" #define LZHUFF0_METHOD 0x2D6C6830 /* -lh0- */ #define LZHUFF1_METHOD 0x2D6C6831 /* -lh1- */ #define LZHUFF2_METHOD 0x2D6C6832 /* -lh2- */ #define LZHUFF3_METHOD 0x2D6C6833 /* -lh3- */ #define LZHUFF4_METHOD 0x2D6C6834 /* -lh4- */ #define LZHUFF5_METHOD 0x2D6C6835 /* -lh5- */ #define LZHUFF6_METHOD 0x2D6C6836 /* -lh6- */ #define LZHUFF7_METHOD 0x2D6C6837 /* -lh7- */ #define LZHUFF8_METHOD 0x2D6C6838 /* -lh8- */ #define LARC_METHOD 0x2D6C7A73 /* -lzs- */ #define LARC5_METHOD 0x2D6C7A35 /* -lz5- */ #define LARC4_METHOD 0x2D6C7A34 /* -lz4- */ #define PMARC0_METHOD 0x2D706D30 /* -pm0- */ #define PMARC2_METHOD 0x2D706D32 /* -pm2- */ #undef UCHAR_MAX #define UCHAR_MAX ((1<<(sizeof(uint8)*8))-1) #define MAX_DICBIT 16 #undef CHAR_BIT #define CHAR_BIT 8 #define USHRT_BIT 16 /* (CHAR_BIT * sizeof(ushort)) */ #define MAXMATCH 256 /* not more than UCHAR_MAX + 1 */ #define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD) #define THRESHOLD 3 /* choose optimal value */ #define NPT 0x80 #define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */ #define TBIT 5 /* smallest integer such that (1 << TBIT) > * NT */ #define NT (USHRT_BIT + 3) #define N_CHAR (256 + 60 - THRESHOLD + 1) #define TREESIZE_C (N_CHAR * 2) #define TREESIZE_P (128 * 2) #define TREESIZE (TREESIZE_C + TREESIZE_P) #define ROOT_C 0 #define ROOT_P TREESIZE_C #define N1 286 /* alphabet size */ #define EXTRABITS 8 /* >= log2(F-THRESHOLD+258-N1) */ #define BUFBITS 16 /* >= log2(MAXBUF) */ #define NP (MAX_DICBIT + 1) #define LENFIELD 4 /* bit size of length field for tree output */ #define MAGIC0 18 #define MAGIC5 19 #ifdef ENABLE_PMARC #define PMARC2_OFFSET (0x100 - 2) struct PMARC2_Tree { uint8 *leftarr; uint8 *rightarr; uint8 root; }; #endif struct LhADecrST { int32 pbit; int32 np; int32 nn; int32 n1; int32 most_p; int32 avail; uint32 n_max; uint16 maxmatch; uint16 total_p; uint16 blocksize; uint16 c_table[4096]; uint16 pt_table[256]; uint16 left[2 * NC - 1]; uint16 right[2 * NC - 1]; uint16 freq[TREESIZE]; uint16 pt_code[NPT]; int16 child[TREESIZE]; int16 stock[TREESIZE]; int16 s_node[TREESIZE / 2]; int16 block[TREESIZE]; int16 parent[TREESIZE]; int16 edge[TREESIZE]; uint8 c_len[NC]; uint8 pt_len[NPT]; }; #ifdef ENABLE_PMARC struct LhADecrPM { struct PMARC2_Tree tree1; struct PMARC2_Tree tree2; uint16 lastupdate; uint16 dicsiz1; uint8 gettree1; uint8 tree1left[32]; uint8 tree1right[32]; uint8 table1[32]; uint8 tree2left[8]; uint8 tree2right[8]; uint8 table2[8]; uint8 tree1bound; uint8 mindepth; /* Circular double-linked list. */ uint8 prev[0x100]; uint8 next[0x100]; uint8 parentarr[0x100]; uint8 lastbyte; }; #endif #ifdef ENABLE_LARC struct LhADecrLZ { int32 matchpos; /* LARC */ int32 flag; /* LARC */ int32 flagcnt; /* LARC */ }; #endif struct LhADecrData { int error; FILE *in; char *text; uint16 DicBit; uint16 bitbuf; uint8 subbitbuf; uint8 bitcount; uint32 loc; uint32 count; uint32 nextcount; union { struct LhADecrST st; #ifdef ENABLE_PMARC struct LhADecrPM pm; #endif #ifdef ENABLE_LARC struct LhADecrLZ lz; #endif } d; }; /* Shift bitbuf n bits left, read n bits */ static inline void fillbuf(struct LhADecrData *dat, uint8 n) { #if 0 if(dat->error) return; #endif while(n > dat->bitcount) { n -= dat->bitcount; dat->bitbuf = (dat->bitbuf << dat->bitcount) + (dat->subbitbuf >> (CHAR_BIT - dat->bitcount)); dat->subbitbuf = fgetc(dat->in); dat->bitcount = CHAR_BIT; } dat->bitcount -= n; dat->bitbuf = (dat->bitbuf << n) + (dat->subbitbuf >> (CHAR_BIT - n)); dat->subbitbuf <<= n; } static inline uint16 getbits(struct LhADecrData *dat, uint8 n) { uint16 x; x = dat->bitbuf >> (2 * CHAR_BIT - n); fillbuf(dat, n); return x; } //#define init_getbits(a) fillbuf((a), 2* CHAR_BIT) /* this function can be replaced by a define! */ static void init_getbits(struct LhADecrData *dat) { dat->bitbuf = 0; dat->subbitbuf = 0; dat->bitcount = 0; fillbuf(dat, 2 * CHAR_BIT); } /* ------------------------------------------------------------------------ */ static int make_table(struct LhADecrData *dat, int16 nchar, uint8 bitlen[], int16 tablebits, uint16 table[], int table_size) { uint16 count[17]; /* count of bitlen */ uint16 weight[17]; /* 0x10000ul >> bitlen */ uint16 start[17]; /* first code of bitlen */ uint16 total; uint32 i; int32 j, k, l, m, n, avail; uint16 *p; #if 0 if(dat->error) return; #endif avail = nchar; memset(count, 0, 17*2); for(i = 1; i <= 16; i++) weight[i] = 1 << (16 - i); /* count */ for(i = 0; i < nchar; i++) count[bitlen[i]]++; /* calculate first code */ total = 0; for(i = 1; i <= 16; i++) { start[i] = total; total += weight[i] * count[i]; } if(total & 0xFFFF) { dat->error = 1; return -1; } /* shift data for make table. */ m = 16 - tablebits; for(i = 1; i <= tablebits; i++) { start[i] >>= m; weight[i] >>= m; } /* initialize */ j = start[tablebits + 1] >> m; k = 1 << tablebits; if(j != 0) { /* Sanity check */ if (k > table_size) { return -1; } for(i = j; i < k; i++) table[i] = 0; } /* create table and tree */ for(j = 0; j < nchar; j++) { k = bitlen[j]; /* Sanity check */ if(k >= 17) return -1; if(k == 0) continue; l = start[k] + weight[k]; if(k <= tablebits) { /* Sanity check */ if (l > table_size) { return -1; } /* code in table */ for(i = start[k]; i < l; i++) table[i] = j; } else { #if 0 /* CID 156018 (#1 of 1): Logically dead code (DEADCODE) * dead_error_line: Execution cannot reach this statement: return -1; */ /* Sanity check */ if(k >= 17) return -1; #endif /* code not in table */ i = start[k]; p = &table[i >> m]; i <<= tablebits; n = k - tablebits; /* make tree (n length) */ while(--n >= 0) { if(*p == 0) { dat->d.st.right[avail] = dat->d.st.left[avail] = 0; *p = avail++; } if(i & 0x8000) p = &dat->d.st.right[*p]; else p = &dat->d.st.left[*p]; i <<= 1; } *p = j; } start[k] = l; } return 0; } /* ------------------------------------------------------------------------ */ static int read_pt_len(struct LhADecrData *dat, int16 nn, int16 nbit, int16 i_special) { int16 i, c, n; if(!(n = getbits(dat, nbit))) { c = getbits(dat, nbit); for(i = 0; i < nn; i++) dat->d.st.pt_len[i] = 0; for(i = 0; i < 256; i++) dat->d.st.pt_table[i] = c; } else { i = 0; while(i < n) { c = dat->bitbuf >> (16 - 3); if(c == 7) { uint16 mask; mask = 1 << (16 - 4); while(mask & dat->bitbuf) { mask >>= 1; c++; } } fillbuf(dat, (c < 7) ? 3 : c - 3); dat->d.st.pt_len[i++] = c; if(i == i_special) { c = getbits(dat, 2); while(--c >= 0) dat->d.st.pt_len[i++] = 0; } } while(i < nn) dat->d.st.pt_len[i++] = 0; if (make_table(dat, nn, dat->d.st.pt_len, 8, dat->d.st.pt_table, 256) < 0) return -1; } return 0; } static int read_c_len(struct LhADecrData *dat) { int16 i, c, n; if(!(n = getbits(dat, CBIT))) { c = getbits(dat, CBIT); for(i = 0; i < NC; i++) dat->d.st.c_len[i] = 0; for(i = 0; i < 4096; i++) dat->d.st.c_table[i] = c; } else { i = 0; while(i < n) { c = dat->d.st.pt_table[dat->bitbuf >> (16 - 8)]; if(c >= NT) { uint16 mask; mask = 1 << (16 - 9); do { if(dat->bitbuf & mask) c = dat->d.st.right[c]; else c = dat->d.st.left[c]; mask >>= 1; } while(c >= NT); } fillbuf(dat, dat->d.st.pt_len[c]); if(c <= 2) { if(!c) c = 1; else if(c == 1) c = getbits(dat, 4) + 3; else c = getbits(dat, CBIT) + 20; /* Sanity check */ if (i + c >= NC) return -1; while(--c >= 0) dat->d.st.c_len[i++] = 0; } else dat->d.st.c_len[i++] = c - 2; } while(i < NC) dat->d.st.c_len[i++] = 0; if (make_table(dat, NC, dat->d.st.c_len, 12, dat->d.st.c_table, 4096) < 0) return -1; } return 0; } static int decode_c_st1(struct LhADecrData *dat) { uint16 j, mask; if(!dat->d.st.blocksize) { dat->d.st.blocksize = getbits(dat, 16); if (read_pt_len(dat, NT, TBIT, 3) < 0) return -1; if (read_c_len(dat) < 0) return -1; if (read_pt_len(dat, dat->d.st.np, dat->d.st.pbit, -1) < 0) return -1; } dat->d.st.blocksize--; j = dat->d.st.c_table[dat->bitbuf >> 4]; if(j < NC) fillbuf(dat, dat->d.st.c_len[j]); else { fillbuf(dat, 12); mask = 1 << (16 - 1); do { if(dat->bitbuf & mask) j = dat->d.st.right[j]; else j = dat->d.st.left[j]; mask >>= 1; } while(j >= NC); fillbuf(dat, dat->d.st.c_len[j] - 12); } return j; } static uint16 decode_p_st1(struct LhADecrData *dat) { uint16 j, mask; j = dat->d.st.pt_table[dat->bitbuf >> (16 - 8)]; if(j < dat->d.st.np) fillbuf(dat, dat->d.st.pt_len[j]); else { fillbuf(dat, 8); mask = 1 << (16 - 1); do { if(dat->bitbuf & mask) j = dat->d.st.right[j]; else j = dat->d.st.left[j]; mask >>= 1; } while(j >= dat->d.st.np); fillbuf(dat, dat->d.st.pt_len[j] - 8); } if(j) j = (1 << (j - 1)) + getbits(dat, j - 1); return j; } static int decode_start_st1(struct LhADecrData *dat) { if(dat->DicBit <= 13) { dat->d.st.np = 14; dat->d.st.pbit = 4; } else { if(dat->DicBit == 16) dat->d.st.np = 17; /* for -lh7- */ else dat->d.st.np = 16; dat->d.st.pbit = 5; } init_getbits(dat); // dat->d.st.blocksize = 0; /* done automatically */ return 0; } /* ------------------------------------------------------------------------ */ static void start_c_dyn(struct LhADecrData *dat) { int32 i, j, f; dat->d.st.n1 = (dat->d.st.n_max >= 256 + dat->d.st.maxmatch - THRESHOLD + 1) ? 512 : dat->d.st.n_max - 1; for(i = 0; i < TREESIZE_C; i++) { dat->d.st.stock[i] = i; dat->d.st.block[i] = 0; } for(i = 0, j = dat->d.st.n_max * 2 - 2; i < (int32) dat->d.st.n_max; i++, j--) { dat->d.st.freq[j] = 1; dat->d.st.child[j] = ~i; dat->d.st.s_node[i] = j; dat->d.st.block[j] = 1; } dat->d.st.avail = 2; dat->d.st.edge[1] = dat->d.st.n_max - 1; i = dat->d.st.n_max * 2 - 2; while(j >= 0) { f = dat->d.st.freq[j] = dat->d.st.freq[i] + dat->d.st.freq[i - 1]; dat->d.st.child[j] = i; dat->d.st.parent[i] = dat->d.st.parent[i - 1] = j; if(f == dat->d.st.freq[j + 1]) { dat->d.st.edge[dat->d.st.block[j] = dat->d.st.block[j + 1]] = j; } else { dat->d.st.edge[dat->d.st.block[j] = dat->d.st.stock[dat->d.st.avail++]] = j; } i -= 2; j--; } } #ifdef ENABLE_LH2 static void start_p_dyn(struct LhADecrData *dat) { dat->d.st.freq[ROOT_P] = 1; dat->d.st.child[ROOT_P] = ~(N_CHAR); dat->d.st.s_node[N_CHAR] = ROOT_P; dat->d.st.edge[dat->d.st.block[ROOT_P] = dat->d.st.stock[dat->d.st.avail++]] = ROOT_P; dat->d.st.most_p = ROOT_P; dat->d.st.total_p = 0; dat->d.st.nn = 1 << dat->DicBit; dat->nextcount = 64; } static void decode_start_dyn(struct LhADecrData *dat) { dat->d.st.n_max = 286; dat->d.st.maxmatch = MAXMATCH; init_getbits(dat); start_c_dyn(dat); start_p_dyn(dat); } #endif static void reconst(struct LhADecrData *dat, int32 start, int32 end) { int32 i, j, k, l, b = 0; uint32 f, g; for(i = j = start; i < end; i++) { if((k = dat->d.st.child[i]) < 0) { dat->d.st.freq[j] = (dat->d.st.freq[i] + 1) / 2; dat->d.st.child[j] = k; j++; } if(dat->d.st.edge[b = dat->d.st.block[i]] == i) { dat->d.st.stock[--dat->d.st.avail] = b; } } j--; i = end - 1; l = end - 2; while(i >= start) { while(i >= l) { dat->d.st.freq[i] = dat->d.st.freq[j]; dat->d.st.child[i] = dat->d.st.child[j]; i--, j--; } f = dat->d.st.freq[l] + dat->d.st.freq[l + 1]; for(k = start; f < dat->d.st.freq[k]; k++) ; while(j >= k) { dat->d.st.freq[i] = dat->d.st.freq[j]; dat->d.st.child[i] = dat->d.st.child[j]; i--, j--; } dat->d.st.freq[i] = f; dat->d.st.child[i] = l + 1; i--; l -= 2; } f = 0; for(i = start; i < end; i++) { if((j = dat->d.st.child[i]) < 0) dat->d.st.s_node[~j] = i; else dat->d.st.parent[j] = dat->d.st.parent[j - 1] = i; if((g = dat->d.st.freq[i]) == f) { dat->d.st.block[i] = b; } else { dat->d.st.edge[b = dat->d.st.block[i] = dat->d.st.stock[dat->d.st.avail++]] = i; f = g; } } } static int32 swap_inc(struct LhADecrData *dat, int32 p) { int32 b, q, r, s; b = dat->d.st.block[p]; if((q = dat->d.st.edge[b]) != p) { /* swap for leader */ r = dat->d.st.child[p]; s = dat->d.st.child[q]; dat->d.st.child[p] = s; dat->d.st.child[q] = r; if(r >= 0) dat->d.st.parent[r] = dat->d.st.parent[r - 1] = q; else dat->d.st.s_node[~r] = q; if(s >= 0) dat->d.st.parent[s] = dat->d.st.parent[s - 1] = p; else dat->d.st.s_node[~s] = p; p = q; dat->d.st.edge[b]++; if(++dat->d.st.freq[p] == dat->d.st.freq[p - 1]) { dat->d.st.block[p] = dat->d.st.block[p - 1]; } else { dat->d.st.edge[dat->d.st.block[p] = dat->d.st.stock[dat->d.st.avail++]] = p; /* create block */ } } else if(b == dat->d.st.block[p + 1]) { dat->d.st.edge[b]++; if(++dat->d.st.freq[p] == dat->d.st.freq[p - 1]) { dat->d.st.block[p] = dat->d.st.block[p - 1]; } else { dat->d.st.edge[dat->d.st.block[p] = dat->d.st.stock[dat->d.st.avail++]] = p; /* create block */ } } else if(++dat->d.st.freq[p] == dat->d.st.freq[p - 1]) { dat->d.st.stock[--dat->d.st.avail] = b; /* delete block */ dat->d.st.block[p] = dat->d.st.block[p - 1]; } return dat->d.st.parent[p]; } #ifdef ENABLE_LH2 static void update_p(struct LhADecrData *dat, int32 p) { int32 q; if(dat->d.st.total_p == 0x8000) { reconst(dat, ROOT_P, dat->d.st.most_p + 1); dat->d.st.total_p = dat->d.st.freq[ROOT_P]; dat->d.st.freq[ROOT_P] = 0xffff; } q = dat->d.st.s_node[p + N_CHAR]; while(q != ROOT_P) { q = swap_inc(dat, q); } dat->d.st.total_p++; } static void make_new_node(struct LhADecrData *dat, int32 p) { int32 q, r; r = dat->d.st.most_p + 1; q = r + 1; dat->d.st.s_node[~(dat->d.st.child[r] = dat->d.st.child[dat->d.st.most_p])] = r; dat->d.st.child[q] = ~(p + N_CHAR); dat->d.st.child[dat->d.st.most_p] = q; dat->d.st.freq[r] = dat->d.st.freq[dat->d.st.most_p]; dat->d.st.freq[q] = 0; dat->d.st.block[r] = dat->d.st.block[dat->d.st.most_p]; if(dat->d.st.most_p == ROOT_P) { dat->d.st.freq[ROOT_P] = 0xffff; dat->d.st.edge[dat->d.st.block[ROOT_P]]++; } dat->d.st.parent[r] = dat->d.st.parent[q] = dat->d.st.most_p; dat->d.st.edge[dat->d.st.block[q] = dat->d.st.stock[dat->d.st.avail++]] = dat->d.st.s_node[p + N_CHAR] = dat->d.st.most_p = q; update_p(dat, p); } #endif static void update_c(struct LhADecrData *dat, int32 p) { int32 q; if(dat->d.st.freq[ROOT_C] == 0x8000) { reconst(dat, 0, (int32) dat->d.st.n_max * 2 - 1); } dat->d.st.freq[ROOT_C]++; q = dat->d.st.s_node[p]; do { q = swap_inc(dat, q); } while(q != ROOT_C); } static int decode_c_dyn(struct LhADecrData *dat) { int32 c; int16 buf, cnt; c = dat->d.st.child[ROOT_C]; buf = dat->bitbuf; cnt = 0; do { c = dat->d.st.child[c - (buf < 0)]; buf <<= 1; if(++cnt == 16) { fillbuf(dat, 16); buf = dat->bitbuf; cnt = 0; } } while(c > 0); fillbuf(dat, cnt); c = ~c; update_c(dat, c); if(c == dat->d.st.n1) c += getbits(dat, 8); return (uint16) c; } #ifdef ENABLE_LH2 static uint16 decode_p_dyn(struct LhADecrData *dat) { int32 c; int16 buf, cnt; while(dat->count > dat->nextcount) { make_new_node(dat, (int32) dat->nextcount / 64); if((dat->nextcount += 64) >= (uint32)dat->d.st.nn) dat->nextcount = 0xffffffff; } c = dat->d.st.child[ROOT_P]; buf = dat->bitbuf; cnt = 0; while(c > 0) { c = dat->d.st.child[c - (buf < 0)]; buf <<= 1; if(++cnt == 16) { fillbuf(dat, 16); buf = dat->bitbuf; cnt = 0; } } fillbuf(dat, cnt); c = (~c) - N_CHAR; update_p(dat, c); return (uint16) ((c << 6) + getbits(dat, 6)); } #endif /* ------------------------------------------------------------------------ */ static const int32 fixed[2][16] = { {3, 0x01, 0x04, 0x0c, 0x18, 0x30, 0}, /* old compatible */ {2, 0x01, 0x01, 0x03, 0x06, 0x0D, 0x1F, 0x4E, 0} /* 8K buf */ }; static void ready_made(struct LhADecrData *dat, int32 method) { int32 i, j; uint32 code, weight; int32 *tbl; tbl = (int32 *) fixed[method]; j = *tbl++; weight = 1 << (16 - j); code = 0; for(i = 0; i < dat->d.st.np; i++) { while(*tbl == i) { j++; tbl++; weight >>= 1; } dat->d.st.pt_len[i] = j; dat->d.st.pt_code[i] = code; code += weight; } } static int decode_start_fix(struct LhADecrData *dat) { dat->d.st.n_max = 314; dat->d.st.maxmatch = 60; init_getbits(dat); dat->d.st.np = 1 << (12 - 6); start_c_dyn(dat); ready_made(dat, 0); if (make_table(dat, dat->d.st.np, dat->d.st.pt_len, 8, dat->d.st.pt_table, 256) < 0) return -1; return 0; } static uint16 decode_p_st0(struct LhADecrData *dat) { int32 i, j; j = dat->d.st.pt_table[dat->bitbuf >> 8]; if(j < dat->d.st.np) { fillbuf(dat, dat->d.st.pt_len[j]); } else { fillbuf(dat, 8); i = dat->bitbuf; do { if((int16) i < 0) j = dat->d.st.right[j]; else j = dat->d.st.left[j]; i <<= 1; } while(j >= dat->d.st.np); fillbuf(dat, dat->d.st.pt_len[j] - 8); } return (uint16)((j << 6) + getbits(dat, 6)); } #ifdef ENABLE_LH3 static void decode_start_st0(struct LhADecrData *dat) { dat->d.st.n_max = 286; dat->d.st.maxmatch = MAXMATCH; init_getbits(dat); dat->d.st.np = 1 << (MAX_DICBIT - 6); } static int read_tree_c(struct LhADecrData *dat) /* read tree from file */ { int32 i, c; i = 0; while(i < N1) { if(getbits(dat, 1)) dat->d.st.c_len[i] = getbits(dat, LENFIELD) + 1; else dat->d.st.c_len[i] = 0; if(++i == 3 && dat->d.st.c_len[0] == 1 && dat->d.st.c_len[1] == 1 && dat->d.st.c_len[2] == 1) { c = getbits(dat, CBIT); memset(dat->d.st.c_len, 0, N1); for(i = 0; i < 4096; i++) dat->d.st.c_table[i] = c; return 0; } } if (make_table(dat, N1, dat->d.st.c_len, 12, dat->d.st.c_table, 4096) < 0) return -1; return 0; } static void read_tree_p(struct LhADecrData *dat) /* read tree from file */ { int32 i, c; i = 0; while(i < NP) { dat->d.st.pt_len[i] = getbits(dat, LENFIELD); if(++i == 3 && dat->d.st.pt_len[0] == 1 && dat->d.st.pt_len[1] == 1 && dat->d.st.pt_len[2] == 1) { c = getbits(dat, MAX_DICBIT - 6); for(i = 0; i < NP; i++) dat->d.st.c_len[i] = 0; for(i = 0; i < 256; i++) dat->d.st.c_table[i] = c; return; } } } static int decode_c_st0(struct LhADecrData *dat) { int32 i, j; if(!dat->d.st.blocksize) /* read block head */ { dat->d.st.blocksize = getbits(dat, BUFBITS); /* read block blocksize */ if (read_tree_c(dat) < 0) return -1; if(getbits(dat, 1)) { read_tree_p(dat); } else { ready_made(dat, 1); } if (make_table(dat, NP, dat->d.st.pt_len, 8, dat->d.st.pt_table, 256) < 0) return -1; } dat->d.st.blocksize--; j = dat->d.st.c_table[dat->bitbuf >> 4]; if(j < N1) fillbuf(dat, dat->d.st.c_len[j]); else { fillbuf(dat, 12); i = dat->bitbuf; do { if((int16) i < 0) j = dat->d.st.right[j]; else j = dat->d.st.left[j]; i <<= 1; } while(j >= N1); fillbuf(dat, dat->d.st.c_len[j] - 12); } if (j == N1 - 1) j += getbits(dat, EXTRABITS); return (uint16) j; } #endif /* ------------------------------------------------------------------------ */ #ifdef ENABLE_PMARC static const int32 PMARC2_historyBits[8] = { 3, 3, 4, 5, 5, 5, 6, 6}; static const int32 PMARC2_historyBase[8] = { 0, 8, 16, 32, 64, 96,128,192}; static const int32 PMARC2_repeatBits[6] = { 3, 3, 5, 6, 7, 0}; static const int32 PMARC2_repeatBase[6] = {17, 25, 33, 65,129,256}; static void PMARC2_hist_update(struct LhADecrData *dat, uint8 data) { if(data != dat->d.pm.lastbyte) { uint8 oldNext, oldPrev, newNext; /* detach from old position */ oldNext = dat->d.pm.next[data]; oldPrev = dat->d.pm.prev[data]; dat->d.pm.prev[oldNext] = oldPrev; dat->d.pm.next[oldPrev] = oldNext; /* attach to new next */ newNext = dat->d.pm.next[dat->d.pm.lastbyte]; dat->d.pm.prev[newNext] = data; dat->d.pm.next[data] = newNext; /* attach to new prev */ dat->d.pm.prev[data] = dat->d.pm.lastbyte; dat->d.pm.next[dat->d.pm.lastbyte] = data; dat->d.pm.lastbyte = data; } } static int32 PMARC2_tree_get(struct LhADecrData *dat, struct PMARC2_Tree *t) { int32 i; i = t->root; while (i < 0x80) { i = (getbits(dat, 1) == 0 ? t->leftarr[i] : t->rightarr[i] ); } return i & 0x7F; } static void PMARC2_tree_rebuild(struct LhADecrData *dat, struct PMARC2_Tree *t, uint8 bound, uint8 mindepth, uint8 * table) { uint8 d; int32 i, curr, empty, n; t->root = 0; memset(t->leftarr, 0, bound); memset(t->rightarr, 0, bound); memset(dat->d.pm.parentarr, 0, bound); for(i = 0; i < dat->d.pm.mindepth - 1; i++) { t->leftarr[i] = i + 1; dat->d.pm.parentarr[i+1] = i; } curr = dat->d.pm.mindepth - 1; empty = dat->d.pm.mindepth; for(d = dat->d.pm.mindepth; ; d++) { for(i = 0; i < bound; i++) { if(table[i] == d) { if(t->leftarr[curr] == 0) t->leftarr[curr] = i | 128; else { t->rightarr[curr] = i | 128; n = 0; while(t->rightarr[curr] != 0) { if(curr == 0) /* root? -> done */ return; curr = dat->d.pm.parentarr[curr]; n++; } t->rightarr[curr] = empty; for(;;) { dat->d.pm.parentarr[empty] = curr; curr = empty; empty++; n--; if(n == 0) break; t->leftarr[curr] = empty; } } } } if(t->leftarr[curr] == 0) t->leftarr[curr] = empty; else t->rightarr[curr] = empty; dat->d.pm.parentarr[empty] = curr; curr = empty; empty++; } } static uint8 PMARC2_hist_lookup(struct LhADecrData *dat, int32 n) { uint8 i; uint8 *direction = dat->d.pm.prev; if(n >= 0x80) { /* Speedup: If you have to process more than half the ring, it's faster to walk the other way around. */ direction = dat->d.pm.next; n = 0x100 - n; } for(i = dat->d.pm.lastbyte; n != 0; n--) i = direction[i]; return i; } static void PMARC2_maketree1(struct LhADecrData *dat) { int32 i, nbits, x; dat->d.pm.tree1bound = getbits(dat, 5); dat->d.pm.mindepth = getbits(dat, 3); if(dat->d.pm.mindepth == 0) dat->d.pm.tree1.root = 128 | (dat->d.pm.tree1bound - 1); else { memset(dat->d.pm.table1, 0, 32); nbits = getbits(dat, 3); for(i = 0; i < dat->d.pm.tree1bound; i++) { if((x = getbits(dat, nbits))) dat->d.pm.table1[i] = x - 1 + dat->d.pm.mindepth; } PMARC2_tree_rebuild(dat, &dat->d.pm.tree1, dat->d.pm.tree1bound, dat->d.pm.mindepth, dat->d.pm.table1); } } static void PMARC2_maketree2(struct LhADecrData *dat, int32 par_b) /* in use: 5 <= par_b <= 8 */ { int32 i, count, index; if(dat->d.pm.tree1bound < 10) return; if(dat->d.pm.tree1bound == 29 && dat->d.pm.mindepth == 0) return; for(i = 0; i < 8; i++) dat->d.pm.table2[i] = 0; for(i = 0; i < par_b; i++) dat->d.pm.table2[i] = getbits(dat, 3); index = 0; count = 0; for(i = 0; i < 8; i++) { if(dat->d.pm.table2[i] != 0) { index = i; count++; } } if(count == 1) { dat->d.pm.tree2.root = 128 | index; } else if (count > 1) { dat->d.pm.mindepth = 1; PMARC2_tree_rebuild(dat, &dat->d.pm.tree2, 8, dat->d.pm.mindepth, dat->d.pm.table2); } /* Note: count == 0 is possible! */ } static void decode_start_pm2(struct LhADecrData *dat) { int32 i; dat->d.pm.tree1.leftarr = dat->d.pm.tree1left; dat->d.pm.tree1.rightarr = dat->d.pm.tree1right; /* dat->d.pm.tree1.root = 0; */ dat->d.pm.tree2.leftarr = dat->d.pm.tree2left; dat->d.pm.tree2.rightarr = dat->d.pm.tree2right; /* dat->d.pm.tree2.root = 0; */ dat->d.pm.dicsiz1 = (1 << dat->DicBit) - 1; init_getbits(dat); /* history init */ for(i = 0; i < 0x100; i++) { dat->d.pm.prev[(0xFF + i) & 0xFF] = i; dat->d.pm.next[(0x01 + i) & 0xFF] = i; } dat->d.pm.prev[0x7F] = 0x00; dat->d.pm.next[0x00] = 0x7F; dat->d.pm.prev[0xDF] = 0x80; dat->d.pm.next[0x80] = 0xDF; dat->d.pm.prev[0x9F] = 0xE0; dat->d.pm.next[0xE0] = 0x9F; dat->d.pm.prev[0x1F] = 0xA0; dat->d.pm.next[0xA0] = 0x1F; dat->d.pm.prev[0xFF] = 0x20; dat->d.pm.next[0x20] = 0xFF; dat->d.pm.lastbyte = 0x20; /* dat->nextcount = 0; */ /* dat->d.pm.lastupdate = 0; */ getbits(dat, 1); /* discard bit */ } static uint16 decode_c_pm2(struct LhADecrData *dat) { /* various admin: */ while(dat->d.pm.lastupdate != dat->loc) { PMARC2_hist_update(dat, dat->text[dat->d.pm.lastupdate]); dat->d.pm.lastupdate = (dat->d.pm.lastupdate + 1) & dat->d.pm.dicsiz1; } while(dat->count >= dat->nextcount) /* Actually it will never loop, because count doesn't grow that fast. However, this is the way does it. Probably other encoding methods can have repeats larger than 256 bytes. Note: puts this code in decode_p... */ { if(dat->nextcount == 0x0000) { PMARC2_maketree1(dat); PMARC2_maketree2(dat, 5); dat->nextcount = 0x0400; } else if(dat->nextcount == 0x0400) { PMARC2_maketree2(dat, 6); dat->nextcount = 0x0800; } else if(dat->nextcount == 0x0800) { PMARC2_maketree2(dat, 7); dat->nextcount = 0x1000; } else if(dat->nextcount == 0x1000) { if(getbits(dat, 1) != 0) PMARC2_maketree1(dat); PMARC2_maketree2(dat, 8); dat->nextcount = 0x2000; } else { /* 0x2000, 0x3000, 0x4000, ... */ if(getbits(dat, 1) != 0) { PMARC2_maketree1(dat); PMARC2_maketree2(dat, 8); } dat->nextcount += 0x1000; } } dat->d.pm.gettree1 = PMARC2_tree_get(dat, &dat->d.pm.tree1); /* value preserved for decode_p */ /* direct value (ret <= UCHAR_MAX) */ if(dat->d.pm.gettree1 < 8) { return (uint16) (PMARC2_hist_lookup(dat, PMARC2_historyBase[dat->d.pm.gettree1] + getbits(dat, PMARC2_historyBits[dat->d.pm.gettree1]))); } /* repeats: (ret > UCHAR_MAX) */ if(dat->d.pm.gettree1 < 23) { return (uint16) (PMARC2_OFFSET + 2 + (dat->d.pm.gettree1 - 8)); } return (uint16) (PMARC2_OFFSET + PMARC2_repeatBase[dat->d.pm.gettree1 - 23] + getbits(dat, PMARC2_repeatBits[dat->d.pm.gettree1 - 23])); } static uint16 decode_p_pm2(struct LhADecrData *dat) { /* gettree1 value preserved from decode_c */ int32 nbits, delta, gettree2; if(dat->d.pm.gettree1 == 8) { /* 2-byte repeat with offset 0..63 */ nbits = 6; delta = 0; } else if(dat->d.pm.gettree1 < 28) { /* n-byte repeat with offset 0..8191 */ if(!(gettree2 = PMARC2_tree_get(dat, &dat->d.pm.tree2))) { nbits = 6; delta = 0; } else { /* 1..7 */ nbits = 5 + gettree2; delta = 1 << nbits; } } else { /* 256 bytes repeat with offset 0 */ nbits = 0; delta = 0; } return (uint16) (delta + getbits(dat, nbits)); } #endif /* ------------------------------------------------------------------------ */ #ifdef ENABLE_LARC static uint16 decode_c_lzs(struct LhADecrData *dat) { if(getbits(dat, 1)) { return getbits(dat, 8); } else { dat->d.lz.matchpos = getbits(dat, 11); return (uint16) (getbits(dat, 4) + 0x100); } } static uint16 decode_p_lzs(struct LhADecrData *dat) { return (uint16) ((dat->loc - dat->d.lz.matchpos - MAGIC0) & 0x7ff); } static void decode_start_lzs(struct LhADecrData *dat) { init_getbits(dat); } static uint16 decode_c_lz5(struct LhADecrData *dat) { int32 c; if(!dat->d.lz.flagcnt) { dat->d.lz.flagcnt = 8; dat->d.lz.flag = fgetc(dat->in); } dat->d.lz.flagcnt--; c = fgetc(dat->in); if((dat->d.lz.flag & 1) == 0) { dat->d.lz.matchpos = c; c = fgetc(dat->in); dat->d.lz.matchpos += (c & 0xf0) << 4; c &= 0x0f; c += 0x100; } dat->d.lz.flag >>= 1; return (uint16) c; } static uint16 decode_p_lz5(struct LhADecrData *dat) { return (uint16) ((dat->loc - dat->d.lz.matchpos - MAGIC5) & 0xfff); } static void decode_start_lz5(struct LhADecrData *dat) { int32 i; char *text; text = dat->text; dat->d.lz.flagcnt = 0; for(i = 0; i < 256; i++) memset(text + i * 13 + 18, i, 13); for(i = 0; i < 256; i++) text[256 * 13 + 18 + i] = i; for(i = 0; i < 256; i++) text[256 * 13 + 256 + 18 + i] = 255 - i; memset(text + 256 * 13 + 512 + 18, 0, 128); memset(text + 256 * 13 + 512 + 128 + 18, ' ', 128-18); } #endif static int32 LhA_Decrunch(FILE *in, FILE *out, int size, uint32 Method) { struct LhADecrData *dd; int32 err = 0; if((dd = calloc(sizeof(struct LhADecrData), 1))) { int (*DecodeStart)(struct LhADecrData *); int (*DecodeC)(struct LhADecrData *); uint16 (*DecodeP)(struct LhADecrData *); /* most often used stuff */ dd->in = in; dd->DicBit = 13; DecodeStart = decode_start_st1; DecodeP = decode_p_st1; DecodeC = decode_c_st1; switch(Method) { case LZHUFF1_METHOD: dd->DicBit = 12; DecodeStart = decode_start_fix; DecodeC = decode_c_dyn; DecodeP = decode_p_st0; break; #ifdef ENABLE_LH2 case LZHUFF2_METHOD: DecodeStart = decode_start_dyn; DecodeC = decode_c_dyn; DecodeP = decode_p_dyn; break; #endif #ifdef ENABLE_LH3 case LZHUFF3_METHOD: DecodeStart = decode_start_st0; DecodeP = decode_p_st0; DecodeC = decode_c_st0; break; #endif #ifdef ENABLE_PMARC case PMARC2_METHOD: DecodeStart = decode_start_pm2; DecodeP = decode_p_pm2; DecodeC = decode_c_pm2; break; #endif case LZHUFF4_METHOD: dd->DicBit = 12; // break; case LZHUFF5_METHOD: break; case LZHUFF6_METHOD: dd->DicBit = 15; break; case LZHUFF7_METHOD: dd->DicBit = 16; break; case LZHUFF8_METHOD: dd->DicBit = 17; break; #ifdef ENABLE_LARC case LARC_METHOD: dd->DicBit = 11; DecodeStart = decode_start_lzs; DecodeC = decode_c_lzs; DecodeP = decode_p_lzs; break; case LARC5_METHOD: dd->DicBit = 12; DecodeStart = decode_start_lz5; DecodeC = decode_c_lz5; DecodeP = decode_p_lz5; break; #endif default: err = 1; break; } if(!err) { char *text; int32 i, c, offset; uint32 dicsiz; dicsiz = 1 << dd->DicBit; #ifdef ENABLE_LARC offset = (Method == LARC_METHOD || Method == PMARC2_METHOD) ? 0x100 - 2 : 0x100 - 3; #else offset = 0x100 - 3; #endif if((text = dd->text = calloc(dicsiz, 1))) { /* if(Method == LZHUFF1_METHOD || Method == LZHUFF2_METHOD || Method == LZHUFF3_METHOD || Method == LZHUFF6_METHOD || Method == LARC_METHOD || Method == LARC5_METHOD) */ memset(text, ' ', (size_t) dicsiz); if (DecodeStart(dd) < 0) { goto error; } --dicsiz; /* now used with AND */ while(1) { if (dd->count >= size) break; c = DecodeC(dd); if (c < 0) { goto error; } if (dd->error) break; if(c <= UCHAR_MAX) { int res = fputc(c, out); if (res < 0) { goto error; } text[dd->loc++] = res; dd->loc &= dicsiz; dd->count++; } else { c -= offset; i = dd->loc - DecodeP(dd) - 1; dd->count += c; while(c--) { int res = fputc(text[i++ & dicsiz], out); if (res < 0) { goto error; } text[dd->loc++] = res; dd->loc &= dicsiz; } } } err = dd->error; free(text); } else err = -1; } free(dd); } else err = -1; return err; error: free(dd->text); free(dd); return -1; } /* * For xmp */ struct lha_data { int method; char name[256]; int packed_size; int original_size; int crc; }; /* * level 0 header * * * offset size field name * ---------------------------------- * 0 1 header size [*1] * 1 1 header sum * --------------------------------------- * 2 5 method ID ^ * 7 4 packed size [*2] | * 11 4 original size | * 15 2 time | * 17 2 date | * 19 1 attribute | [*1] header size (X+Y+22) * 20 1 level (0x00 fixed) | * 21 1 name length | * 22 X pathname | * X +22 2 file crc (CRC-16) | * X +24 Y ext-header(old style) v * ------------------------------------------------- * X+Y+24 data ^ * : | [*2] packed size * : v * ------------------------------------------------- * * ext-header(old style) * 0 1 ext-type ('U') * 1 1 minor version * 2 4 UNIX time * 6 2 mode * 8 2 uid * 10 2 gid * * attribute (MS-DOS) * bit1 read only * bit2 hidden * bit3 system * bit4 volume label * bit5 directory * bit6 archive bit (need to backup) * */ /* * level 1 header * * * offset size field name * ----------------------------------- * 0 1 header size [*1] * 1 1 header sum * ------------------------------------- * 2 5 method ID ^ * 7 4 skip size [*2] | * 11 4 original size | * 15 2 time | * 17 2 date | * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25) * 20 1 level (0x01 fixed) | * 21 1 name length | * 22 X filename | * X+ 22 2 file crc (CRC-16) | * X+ 24 1 OS ID | * X +25 Y ??? | * X+Y+25 2 next-header size v * ------------------------------------------------- * X+Y+27 Z ext-header ^ * : | * ----------------------------------- | [*2] skip size * X+Y+Z+27 data | * : v * ------------------------------------------------- * */ /* * level 2 header * * * offset size field name * -------------------------------------------------- * 0 2 total header size [*1] ^ * ----------------------- | * 2 5 method ID | * 7 4 packed size [*2] | * 11 4 original size | * 15 4 time | * 19 1 RESERVED (0x20 fixed) | [*1] total header size * 20 1 level (0x02 fixed) | (X+26+(1)) * 21 2 file crc (CRC-16) | * 23 1 OS ID | * 24 2 next-header size | * ----------------------------------- | * 26 X ext-header | * : | * ----------------------------------- | * X +26 (1) padding v * ------------------------------------------------- * X +26+(1) data ^ * : | [*2] packed size * : v * ------------------------------------------------- * */ /* * level 3 header * * * offset size field name * -------------------------------------------------- * 0 2 size field length (4 fixed) ^ * 2 5 method ID | * 7 4 packed size [*2] | * 11 4 original size | * 15 4 time | * 19 1 RESERVED (0x20 fixed) | [*1] total header size * 20 1 level (0x03 fixed) | (X+32) * 21 2 file crc (CRC-16) | * 23 1 OS ID | * 24 4 total header size [*1] | * 28 4 next-header size | * ----------------------------------- | * 32 X ext-header | * : v * ------------------------------------------------- * X +32 data ^ * : | [*2] packed size * : v * ------------------------------------------------- * */ static int get_header(FILE *f, struct lha_data *data) { uint8 buf[21]; int size, level, namelen; int error; memset(data, 0, sizeof(struct lha_data)); if (fread(buf, 1, 21, f) != 21) return -1; level = buf[20]; switch (level) { case 0: size = buf[0]; data->method = readmem32b(buf + 2); data->packed_size = readmem32l(buf + 7); data->original_size = readmem32l(buf + 11); namelen = read8(f, &error); if (error != 0) { return -1; } if (fread(data->name, 1, namelen, f) != namelen) { return -1; } data->crc = read16l(f, &error); if (error != 0) { return -1; } if (fseek(f, size + 2 - 24 - namelen, SEEK_CUR) < 0) { return -1; } break; case 1: size = buf[0]; data->method = readmem32b(buf + 2); data->packed_size = readmem32l(buf + 7); data->original_size = readmem32l(buf + 11); namelen = read8(f, &error); if (error != 0) { return -1; } if (fread(data->name, 1, namelen, f) != namelen) { return -1; } data->crc = read16l(f, &error); if (error != 0) { return -1; } if (fseek(f, size - (22 + namelen) - 2, SEEK_CUR) < 0) { return -1; } while ((size = read16l(f, &error)) != 0) { if (error != 0) { return -1; } if (fseek(f, size - 2, SEEK_CUR) < 0) { return -1; } data->packed_size -= size; } break; case 2: size = readmem16l(buf); /* fall through */ case 3: data->method = readmem32b(buf + 2); data->packed_size = readmem32l(buf + 7); data->original_size = readmem32l(buf + 11); data->crc = read16l(f, &error); if (error != 0) { return -1; } read8(f, &error); /* skip OS id */ if (error != 0) { return -1; } while ((size = read16l(f, &error)) != 0) { int type; int s = size - 3; if (error != 0) { return -1; } type = read8(f, &error); if (error != 0) { return -1; } if (type == 0x01) { /* Sanity check */ if (s < 0 || s > 256) { return -1; } if (fread(data->name, 1, s, f) != s) { return -1; } } else { if (fseek(f, s, SEEK_CUR) < 0) { return -1; } } } break; default: return -1; } return 0; } static int test_lha(unsigned char *b) { return b[2] == '-' && b[3] == 'l' && b[4] == 'h' && b[6] == '-' && b[20] <= 3; } static int decrunch_lha(FILE *in, FILE *out) { struct lha_data data; while (1) { if (get_header(in, &data) < 0) break; #if 0 printf("method = %x\n", data.method); printf("name = %s\n", data.name); printf("packed size = %d\n", data.packed_size); printf("original size = %d\n", data.original_size); printf("position = %lx\n", ftell(in)); #endif if (libxmp_exclude_match(data.name)) { if (fseek(in, data.packed_size, SEEK_CUR) < 0) { return -1; } continue; } return LhA_Decrunch(in, out, data.original_size, data.method); } return -1; } struct depacker libxmp_depacker_lha = { test_lha, decrunch_lha }; libxmp-4.4.1/src/depackers/vorbis.c0000664000175000017500000051651212773571316017065 0ustar claudioclaudio// Ogg Vorbis I audio decoder -- version 0.99996 // // Written in April 2007 by Sean Barrett, sponsored by RAD Game Tools. // // Placed in the public domain April 2007 by the author: no copyright is // claimed, and you may use it for any purpose you like. // // No warranty for any purpose is expressed or implied by the author (nor // by RAD Game Tools). Report bugs and send enhancements to the author. // // Get the latest version and other information at: // http://nothings.org/stb_vorbis/ // Todo: // // - seeking (note you can seek yourself using the pushdata API) // // Limitations: // // - floor 0 not supported (used in old ogg vorbis files) // - lossless sample-truncation at beginning ignored // - cannot concatenate multiple vorbis streams // - sample positions are 32-bit, limiting seekable 192Khz // files to around 6 hours (Ogg supports 64-bit) // // All of these limitations may be removed in future versions. #ifdef HAVE_ALLOCA_H #include #endif #ifdef WIN32 #include #endif #include "vorbis.h" #include "common.h" #ifndef STB_VORBIS_HEADER_ONLY // global configuration settings (e.g. set these in the project/makefile), // or just set them in this file at the top (although ideally the first few // should be visible when the header file is compiled too, although it's not // crucial) // STB_VORBIS_NO_PUSHDATA_API // does not compile the code for the various stb_vorbis_*_pushdata() // functions #define STB_VORBIS_NO_PUSHDATA_API // STB_VORBIS_NO_PULLDATA_API // does not compile the code for the non-pushdata APIs //#define STB_VORBIS_NO_PULLDATA_API // STB_VORBIS_NO_STDIO // does not compile the code for the APIs that use FILE *s internally // or externally (implied by STB_VORBIS_NO_PULLDATA_API) #define STB_VORBIS_NO_STDIO // STB_VORBIS_NO_INTEGER_CONVERSION // does not compile the code for converting audio sample data from // float to integer (implied by STB_VORBIS_NO_PULLDATA_API) // #define STB_VORBIS_NO_INTEGER_CONVERSION // STB_VORBIS_NO_FAST_SCALED_FLOAT // does not use a fast float-to-int trick to accelerate float-to-int on // most platforms which requires endianness be defined correctly. //#define STB_VORBIS_NO_FAST_SCALED_FLOAT // STB_VORBIS_MAX_CHANNELS [number] // globally define this to the maximum number of channels you need. // The spec does not put a restriction on channels except that // the count is stored in a byte, so 255 is the hard limit. // Reducing this saves about 16 bytes per value, so using 16 saves // (255-16)*16 or around 4KB. Plus anything other memory usage // I forgot to account for. Can probably go as low as 8 (7.1 audio), // 6 (5.1 audio), or 2 (stereo only). #ifndef STB_VORBIS_MAX_CHANNELS /* #define STB_VORBIS_MAX_CHANNELS 16 // enough for anyone? */ #define STB_VORBIS_MAX_CHANNELS 1 #endif // STB_VORBIS_PUSHDATA_CRC_COUNT [number] // after a flush_pushdata(), stb_vorbis begins scanning for the // next valid page, without backtracking. when it finds something // that looks like a page, it streams through it and verifies its // CRC32. Should that validation fail, it keeps scanning. But it's // possible that _while_ streaming through to check the CRC32 of // one candidate page, it sees another candidate page. This #define // determines how many "overlapping" candidate pages it can search // at once. Note that "real" pages are typically ~4KB to ~8KB, whereas // garbage pages could be as big as 64KB, but probably average ~16KB. // So don't hose ourselves by scanning an apparent 64KB page and // missing a ton of real ones in the interim; so minimum of 2 #ifndef STB_VORBIS_PUSHDATA_CRC_COUNT #define STB_VORBIS_PUSHDATA_CRC_COUNT 4 #endif // STB_VORBIS_FAST_HUFFMAN_LENGTH [number] // sets the log size of the huffman-acceleration table. Maximum // supported value is 24. with larger numbers, more decodings are O(1), // but the table size is larger so worse cache missing, so you'll have // to probe (and try multiple ogg vorbis files) to find the sweet spot. #ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH #define STB_VORBIS_FAST_HUFFMAN_LENGTH 10 #endif // STB_VORBIS_FAST_BINARY_LENGTH [number] // sets the log size of the binary-search acceleration table. this // is used in similar fashion to the fast-huffman size to set initial // parameters for the binary search // STB_VORBIS_FAST_HUFFMAN_INT // The fast huffman tables are much more efficient if they can be // stored as 16-bit results instead of 32-bit results. This restricts // the codebooks to having only 65535 possible outcomes, though. // (At least, accelerated by the huffman table.) #ifndef STB_VORBIS_FAST_HUFFMAN_INT #define STB_VORBIS_FAST_HUFFMAN_SHORT #endif // STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH // If the 'fast huffman' search doesn't succeed, then stb_vorbis falls // back on binary searching for the correct one. This requires storing // extra tables with the huffman codes in sorted order. Defining this // symbol trades off space for speed by forcing a linear search in the // non-fast case, except for "sparse" codebooks. // #define STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH // STB_VORBIS_DIVIDES_IN_RESIDUE // stb_vorbis precomputes the result of the scalar residue decoding // that would otherwise require a divide per chunk. you can trade off // space for time by defining this symbol. // #define STB_VORBIS_DIVIDES_IN_RESIDUE // STB_VORBIS_DIVIDES_IN_CODEBOOK // vorbis VQ codebooks can be encoded two ways: with every case explicitly // stored, or with all elements being chosen from a small range of values, // and all values possible in all elements. By default, stb_vorbis expands // this latter kind out to look like the former kind for ease of decoding, // because otherwise an integer divide-per-vector-element is required to // unpack the index. If you define STB_VORBIS_DIVIDES_IN_CODEBOOK, you can // trade off storage for speed. //#define STB_VORBIS_DIVIDES_IN_CODEBOOK // STB_VORBIS_CODEBOOK_SHORTS // The vorbis file format encodes VQ codebook floats as ax+b where a and // b are floating point per-codebook constants, and x is a 16-bit int. // Normally, stb_vorbis decodes them to floats rather than leaving them // as 16-bit ints and computing ax+b while decoding. This is a speed/space // tradeoff; you can save space by defining this flag. #ifndef STB_VORBIS_CODEBOOK_SHORTS #define STB_VORBIS_CODEBOOK_FLOATS #endif // STB_VORBIS_DIVIDE_TABLE // this replaces small integer divides in the floor decode loop with // table lookups. made less than 1% difference, so disabled by default. // STB_VORBIS_NO_INLINE_DECODE // disables the inlining of the scalar codebook fast-huffman decode. // might save a little codespace; useful for debugging // #define STB_VORBIS_NO_INLINE_DECODE // STB_VORBIS_NO_DEFER_FLOOR // Normally we only decode the floor without synthesizing the actual // full curve. We can instead synthesize the curve immediately. This // requires more memory and is very likely slower, so I don't think // you'd ever want to do it except for debugging. // #define STB_VORBIS_NO_DEFER_FLOOR #define STB_VORBIS_NO_ALLOC_BUFFER ////////////////////////////////////////////////////////////////////////////// #ifdef STB_VORBIS_NO_PULLDATA_API #define STB_VORBIS_NO_INTEGER_CONVERSION #define STB_VORBIS_NO_STDIO #endif #if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) #define STB_VORBIS_NO_STDIO 1 #endif #ifndef STB_VORBIS_NO_INTEGER_CONVERSION #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT // only need endianness for fast-float-to-int, which we don't // use for pushdata #ifndef STB_VORBIS_BIG_ENDIAN #define STB_VORBIS_ENDIAN 0 #else #define STB_VORBIS_ENDIAN 1 #endif #endif #endif #ifndef STB_VORBIS_NO_STDIO #include #endif #ifndef STB_VORBIS_NO_CRT #include #include #include #include #else #define NULL 0 #endif #if !defined(_MSC_VER) #undef __forceinline #if __GNUC__ #define __forceinline inline #else #define __forceinline #endif #endif #if STB_VORBIS_MAX_CHANNELS > 256 #error "Value of STB_VORBIS_MAX_CHANNELS outside of allowed range" #endif #if STB_VORBIS_FAST_HUFFMAN_LENGTH > 24 #error "Value of STB_VORBIS_FAST_HUFFMAN_LENGTH outside of allowed range" #endif #define MAX_BLOCKSIZE_LOG 13 // from specification #define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) #if 0 typedef unsigned char uint8; typedef signed char int8; typedef unsigned short uint16; typedef signed short int16; typedef unsigned int uint32; typedef signed int int32; #endif #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifdef STB_VORBIS_CODEBOOK_FLOATS typedef float codetype; #else typedef uint16 codetype; #endif // @NOTE // // Some arrays below are tagged "//varies", which means it's actually // a variable-sized piece of data, but rather than malloc I assume it's // small enough it's better to just allocate it all together with the // main thing // // Most of the variables are specified with the smallest size I could pack // them into. It might give better performance to make them all full-sized // integers. It should be safe to freely rearrange the structures or change // the sizes larger--nothing relies on silently truncating etc., nor the // order of variables. #define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH) #define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1) typedef struct { int dimensions, entries; uint8 *codeword_lengths; float minimum_value; float delta_value; uint8 value_bits; uint8 lookup_type; uint8 sequence_p; uint8 sparse; uint32 lookup_values; codetype *multiplicands; uint32 *codewords; #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; #else int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; #endif uint32 *sorted_codewords; int *sorted_values; int sorted_entries; } Codebook; typedef struct { uint8 order; uint16 rate; uint16 bark_map_size; uint8 amplitude_bits; uint8 amplitude_offset; uint8 number_of_books; uint8 book_list[16]; // varies } Floor0; typedef struct { uint8 partitions; uint8 partition_class_list[32]; // varies uint8 class_dimensions[16]; // varies uint8 class_subclasses[16]; // varies uint8 class_masterbooks[16]; // varies int16 subclass_books[16][8]; // varies uint16 Xlist[31*8+2]; // varies uint8 sorted_order[31*8+2]; uint8 neighbors[31*8+2][2]; uint8 floor1_multiplier; uint8 rangebits; int values; } Floor1; typedef union { Floor0 floor0; Floor1 floor1; } Floor; typedef struct { uint32 begin, end; uint32 part_size; uint8 classifications; uint8 classbook; uint8 **classdata; int16 (*residue_books)[8]; } Residue; typedef struct { uint8 magnitude; uint8 angle; uint8 mux; } MappingChannel; typedef struct { uint16 coupling_steps; MappingChannel *chan; uint8 submaps; uint8 submap_floor[15]; // varies uint8 submap_residue[15]; // varies } Mapping; typedef struct { uint8 blockflag; uint8 mapping; uint16 windowtype; uint16 transformtype; } Mode; typedef struct { uint32 goal_crc; // expected crc if match int bytes_left; // bytes left in packet uint32 crc_so_far; // running crc int bytes_done; // bytes processed in _current_ chunk uint32 sample_loc; // granule pos encoded in page } CRCscan; typedef struct { uint32 page_start, page_end; uint32 after_previous_page_start; uint32 first_decoded_sample; uint32 last_decoded_sample; } ProbedPage; struct stb_vorbis { // user-accessible info unsigned int sample_rate; int channels; unsigned int setup_memory_required; unsigned int temp_memory_required; unsigned int setup_temp_memory_required; // input config #ifndef STB_VORBIS_NO_STDIO FILE *f; uint32 f_start; int close_on_free; #endif uint8 *stream; uint8 *stream_start; uint8 *stream_end; uint32 stream_len; uint8 push_mode; uint32 first_audio_page_offset; ProbedPage p_first, p_last; // memory management stb_vorbis_alloc alloc; int setup_offset; int temp_offset; // run-time results int eof; enum STBVorbisError error; // user-useful data // header info int blocksize[2]; int blocksize_0, blocksize_1; int codebook_count; Codebook *codebooks; int floor_count; uint16 floor_types[64]; // varies Floor *floor_config; int residue_count; uint16 residue_types[64]; // varies Residue *residue_config; int mapping_count; Mapping *mapping; int mode_count; Mode mode_config[64]; // varies uint32 total_samples; // decode buffer float *channel_buffers[STB_VORBIS_MAX_CHANNELS]; float *outputs [STB_VORBIS_MAX_CHANNELS]; float *previous_window[STB_VORBIS_MAX_CHANNELS]; int previous_length; #ifndef STB_VORBIS_NO_DEFER_FLOOR int16 *finalY[STB_VORBIS_MAX_CHANNELS]; #else float *floor_buffers[STB_VORBIS_MAX_CHANNELS]; #endif uint32 current_loc; // sample location of next frame to decode int current_loc_valid; // per-blocksize precomputed data // twiddle factors float *A[2],*B[2],*C[2]; float *window[2]; uint16 *bit_reverse[2]; // current page/packet/segment streaming info uint32 serial; // stream serial number for verification int last_page; int segment_count; uint8 segments[255]; uint8 page_flag; uint8 bytes_in_seg; uint8 first_decode; int next_seg; int last_seg; // flag that we're on the last segment int last_seg_which; // what was the segment number of the last seg? uint32 acc; int valid_bits; int packet_bytes; int end_seg_with_known_loc; uint32 known_loc_for_packet; int discard_samples_deferred; uint32 samples_output; // push mode scanning int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching #ifndef STB_VORBIS_NO_PUSHDATA_API CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; #endif // sample-access int channel_buffer_start; int channel_buffer_end; }; extern int my_prof(int slot); //#define stb_prof my_prof #ifndef stb_prof #define stb_prof(x) #endif #if defined(STB_VORBIS_NO_PUSHDATA_API) #define IS_PUSH_MODE(f) FALSE #elif defined(STB_VORBIS_NO_PULLDATA_API) #define IS_PUSH_MODE(f) TRUE #else #define IS_PUSH_MODE(f) ((f)->push_mode) #endif typedef struct stb_vorbis vorb; static int error(vorb *f, enum STBVorbisError e) { f->error = e; if (!f->eof && e != VORBIS_need_more_data) { f->error=e; // breakpoint for debugging } return 0; } // these functions are used for allocating temporary memory // while decoding. if you can afford the stack space, use // alloca(); otherwise, provide a temp buffer and it will // allocate out of those. #define array_size_required(count,size) (count*(sizeof(void *)+(size))) #ifndef STB_VORBIS_NO_ALLOC_BUFFER # define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) # ifdef dealloca # define temp_free(f,p) (f->alloc.alloc_buffer ? 0 : dealloca(size)) # else # define temp_free(f,p) 0 # endif #else # define temp_alloc(f,size) (alloca(size)) # ifdef dealloca # define temp_free(f,p) (dealloca(size)) # else # define temp_free(f,p) 0 # endif #endif #define temp_alloc_save(f) ((f)->temp_offset) #define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) #define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size) // given a sufficiently large block of memory, make an array of pointers to subblocks of it static void *make_block_array(void *mem, int count, int size) { int i; void ** p = (void **) mem; char *q = (char *) (p + count); for (i=0; i < count; ++i) { p[i] = q; q += size; } return p; } static void *setup_malloc(vorb *f, int sz) { sz = (sz+3) & ~3; f->setup_memory_required += sz; #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) { void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; if (f->setup_offset + sz > f->temp_offset) return NULL; f->setup_offset += sz; return p; } #endif return sz ? calloc(sz, 1) : NULL; } static void setup_free(vorb *f, void *p) { #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) return; // do nothing; setup mem is not a stack #endif free(p); } static void *setup_temp_malloc(vorb *f, int sz) { sz = (sz+3) & ~3; #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) { if (f->temp_offset - sz < f->setup_offset) return NULL; f->temp_offset -= sz; return (char *) f->alloc.alloc_buffer + f->temp_offset; } #endif return calloc(sz, 1); } static void setup_temp_free(vorb *f, void *p, size_t sz) { #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) { f->temp_offset += (sz+3)&~3; return; } #endif free(p); } #define CRC32_POLY 0x04c11db7 // from spec static uint32 crc_table[256]; static void libxmp_crc32_init_A(void) { int i,j; uint32 s; for(i=0; i < 256; i++) { for (s=i<<24, j=0; j < 8; ++j) s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0); crc_table[i] = s; } } #if 0 static __forceinline uint32 libxmp_crc32_update(uint32 crc, uint8 byte) { return (crc << 8) ^ crc_table[byte ^ (crc >> 24)]; } #endif // used in setup, and for huffman that doesn't go fast path static unsigned int bit_reverse(unsigned int n) { n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); return (n >> 16) | (n << 16); } static float square(float x) { return x*x; } // this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3 // as required by the specification. fast(?) implementation from stb.h // @OPTIMIZE: called multiple times per-packet with "constants"; move to setup static int ilog(int32 n) { static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29) if (n < (1U << 14)) if (n < (1U << 4)) return 0 + log2_4[n ]; else if (n < (1U << 9)) return 5 + log2_4[n >> 5]; else return 10 + log2_4[n >> 10]; else if (n < (1U << 24)) if (n < (1U << 19)) return 15 + log2_4[n >> 15]; else return 20 + log2_4[n >> 20]; else if (n < (1U << 29)) return 25 + log2_4[n >> 25]; else if (n < (1U << 31)) return 30 + log2_4[n >> 30]; else return 0; // signed n returns 0 } #ifndef M_PI #define M_PI 3.14159265358979323846264f // from CRC #endif // code length assigned to a value with no huffman encoding #define NO_CODE 255 /////////////////////// LEAF SETUP FUNCTIONS ////////////////////////// // // these functions are only called at setup, and only a few times // per file static float float32_unpack(uint32 x) { // from the specification uint32 mantissa = x & 0x1fffff; uint32 sign = x & 0x80000000; uint32 exp = (x & 0x7fe00000) >> 21; double res = sign ? -(double)mantissa : (double)mantissa; return (float) ldexp((float)res, exp-788); } // zlib & jpeg huffman tables assume that the output symbols // can either be arbitrarily arranged, or have monotonically // increasing frequencies--they rely on the lengths being sorted; // this makes for a very simple generation algorithm. // vorbis allows a huffman table with non-sorted lengths. This // requires a more sophisticated construction, since symbols in // order do not map to huffman codes "in order". static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values) { if (!c->sparse) { c->codewords [symbol] = huff_code; } else { c->codewords [count] = huff_code; c->codeword_lengths[count] = len; values [count] = symbol; } } static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) { int i,k,m=0; uint32 available[32]; memset(available, 0, sizeof(available)); // find the first entry for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; // sanity check if (k == n) return -1; if (len[k] >= 32) return -1; if (k == n) { assert(c->sorted_entries == 0); return TRUE; } // add to the list add_entry(c, 0, k, m++, len[k], values); // add all available leaves for (i=1; i <= len[k]; ++i) available[i] = 1 << (32-i); // note that the above code treats the first case specially, // but it's really the same as the following code, so they // could probably be combined (except the initial code is 0, // and I use 0 in available[] to mean 'empty') for (i=k+1; i < n; ++i) { uint32 res; int z = len[i], y; if (z == NO_CODE) continue; // find lowest available leaf (should always be earliest, // which is what the specification calls for) // note that this property, and the fact we can never have // more than one free leaf at a given level, isn't totally // trivial to prove, but it seems true and the assert never // fires, so! /* Sanity check */ if (z >= 32) { return FALSE; } while (z > 0 && !available[z]) --z; if (z == 0) { /*assert(0);*/ return FALSE; } res = available[z]; available[z] = 0; add_entry(c, bit_reverse(res), i, m++, len[i], values); // propogate availability up the tree if (z != len[i]) { for (y=len[i]; y > z; --y) { assert(available[y] == 0); available[y] = res + (1 << (32-y)); } } } return TRUE; } // accelerated huffman table allows fast O(1) match of all symbols // of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH static void compute_accelerated_huffman(Codebook *c) { int i, len; for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i) c->fast_huffman[i] = -1; len = c->sparse ? c->sorted_entries : c->entries; #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT if (len > 32767) len = 32767; // largest possible value we can encode! #endif for (i=0; i < len; ++i) { if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) { uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; // set table entries for all bit combinations in the higher bits while (z < FAST_HUFFMAN_TABLE_SIZE) { c->fast_huffman[z] = i; z += 1 << c->codeword_lengths[i]; } } } } static int uint32_compare(const void *p, const void *q) { uint32 x = * (uint32 *) p; uint32 y = * (uint32 *) q; return x < y ? -1 : x > y; } static int include_in_sort(Codebook *c, uint8 len) { if (c->sparse) { return (len != NO_CODE); } if (len == NO_CODE) return FALSE; if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE; return FALSE; } // if the fast table above doesn't work, we want to binary // search them... need to reverse the bits static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) { int i, len; // build a list of all the entries // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN. // this is kind of a frivolous optimization--I don't see any performance improvement, // but it's like 4 extra lines of code, so. if (!c->sparse) { int k = 0; for (i=0; i < c->entries; ++i) if (include_in_sort(c, lengths[i])) c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); assert(k == c->sorted_entries); } else { for (i=0; i < c->sorted_entries; ++i) c->sorted_codewords[i] = bit_reverse(c->codewords[i]); } qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare); c->sorted_codewords[c->sorted_entries] = 0xffffffff; len = c->sparse ? c->sorted_entries : c->entries; // now we need to indicate how they correspond; we could either // #1: sort a different data structure that says who they correspond to // #2: for each sorted entry, search the original list to find who corresponds // #3: for each original entry, find the sorted entry // #1 requires extra storage, #2 is slow, #3 can use binary search! for (i=0; i < len; ++i) { int huff_len = c->sparse ? lengths[values[i]] : lengths[i]; if (include_in_sort(c,huff_len)) { uint32 code = bit_reverse(c->codewords[i]); int x=0, n=c->sorted_entries; while (n > 1) { // invariant: sc[x] <= code < sc[x+n] int m = x + (n >> 1); if (c->sorted_codewords[m] <= code) { x = m; n -= (n>>1); } else { n >>= 1; } } assert(c->sorted_codewords[x] == code); if (c->sparse) { c->sorted_values[x] = values[i]; c->codeword_lengths[x] = huff_len; } else { c->sorted_values[x] = i; } } } } // only run while parsing the header (3 times) static int vorbis_validate(uint8 *data) { static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; return memcmp(data, vorbis, 6) == 0; } // called from setup only, once per code book // (formula implied by specification) static int lookup1_values(int entries, int dim) { int r = (int) floor(exp((float) log((float) entries) / dim)); if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; ++r; // floor() to avoid _ftol() when non-CRT if (pow((float) r+1, dim) <= entries) { return -1; } if ((int) floor(pow((float) r, dim)) > entries) { // (int),floor() as above return -1; } return r; } // called twice per file static void compute_twiddle_factors(int n, float *A, float *B, float *C) { int n4 = n >> 2, n8 = n >> 3; int k,k2; for (k=k2=0; k < n4; ++k,k2+=2) { A[k2 ] = (float) cos(4*k*M_PI/n); A[k2+1] = (float) -sin(4*k*M_PI/n); B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f; B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f; } for (k=k2=0; k < n8; ++k,k2+=2) { C[k2 ] = (float) cos(2*(k2+1)*M_PI/n); C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n); } } static void compute_window(int n, float *window) { int n2 = n >> 1, i; for (i=0; i < n2; ++i) window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); } static void compute_bitreverse(int n, uint16 *rev) { int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions int i, n8 = n >> 3; for (i=0; i < n8; ++i) { /* CID 128660 (#1 of 1): Bad bit shift operation (BAD_SHIFT) * large_shift: right shifting by more than 31 bits has undefined * behavior. The shift amount, 32 - ld + 3, is 36. */ int s = 32-ld+3; rev[i] = s > 31 ? 0 : (bit_reverse(i) >> s) << 2; } } static int init_blocksize(vorb *f, int b, int n) { int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3; f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2); f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2); f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4); if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem); compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2); if (!f->window[b]) return error(f, VORBIS_outofmem); compute_window(n, f->window[b]); f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8); if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem); compute_bitreverse(n, f->bit_reverse[b]); return TRUE; } static void neighbors(uint16 *x, int n, int *plow, int *phigh) { int low = -1; int high = 65536; int i; for (i=0; i < n; ++i) { if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; } if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; } } } // this has been repurposed so y is now the original index instead of y typedef struct { uint16 x,y; } Point; static int point_compare(const void *p, const void *q) { Point *a = (Point *) p; Point *b = (Point *) q; return a->x < b->x ? -1 : a->x > b->x; } // /////////////////////// END LEAF SETUP FUNCTIONS ////////////////////////// #if defined(STB_VORBIS_NO_STDIO) #define USE_MEMORY(z) TRUE #else #define USE_MEMORY(z) ((z)->stream) #endif static uint8 get8(vorb *z) { if (USE_MEMORY(z)) { if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; } return *z->stream++; } #ifndef STB_VORBIS_NO_STDIO { int c = fgetc(z->f); if (c == EOF) { z->eof = TRUE; return 0; } return c; } #endif } static uint32 get32(vorb *f) { uint32 x; x = get8(f); x += get8(f) << 8; x += get8(f) << 16; x += get8(f) << 24; return x; } static int getn(vorb *z, uint8 *data, int n) { if (USE_MEMORY(z)) { if (z->stream+n > z->stream_end) { z->eof = 1; return 0; } memcpy(data, z->stream, n); z->stream += n; return 1; } #ifndef STB_VORBIS_NO_STDIO if (fread(data, n, 1, z->f) == 1) return 1; else { z->eof = 1; return 0; } #endif } static void skip(vorb *z, int n) { if (USE_MEMORY(z)) { z->stream += n; if (z->stream >= z->stream_end) z->eof = 1; return; } #ifndef STB_VORBIS_NO_STDIO { long x = ftell(z->f); fseek(z->f, x+n, SEEK_SET); } #endif } #if 0 static int set_file_offset(stb_vorbis *f, unsigned int loc) { #ifndef STB_VORBIS_NO_PUSHDATA_API if (f->push_mode) return 0; #endif f->eof = 0; if (USE_MEMORY(f)) { if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) { f->stream = f->stream_end; f->eof = 1; return 0; } else { f->stream = f->stream_start + loc; return 1; } } #ifndef STB_VORBIS_NO_STDIO if (loc + f->f_start < loc || loc >= 0x80000000) { loc = 0x7fffffff; f->eof = 1; } else { loc += f->f_start; } if (!fseek(f->f, loc, SEEK_SET)) return 1; f->eof = 1; fseek(f->f, f->f_start, SEEK_END); return 0; #endif } static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; #endif static int capture_pattern(vorb *f) { if (0x4f != get8(f)) return FALSE; if (0x67 != get8(f)) return FALSE; if (0x67 != get8(f)) return FALSE; if (0x53 != get8(f)) return FALSE; return TRUE; } #define PAGEFLAG_continued_packet 1 #define PAGEFLAG_first_page 2 #define PAGEFLAG_last_page 4 static int start_page_no_capturepattern(vorb *f) { uint32 loc0,loc1,n; int i; // stream structure version if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); // header flag f->page_flag = get8(f); // absolute granule position loc0 = get32(f); loc1 = get32(f); // @TODO: validate loc0,loc1 as valid positions? // stream serial number -- vorbis doesn't interleave, so discard get32(f); //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number); // page sequence number n = get32(f); f->last_page = n; // CRC32 get32(f); // page_segments f->segment_count = get8(f); if (!getn(f, f->segments, f->segment_count)) return error(f, VORBIS_unexpected_eof); // assume we _don't_ know any the sample position of any segments f->end_seg_with_known_loc = -2; if (loc0 != ~0 || loc1 != ~0) { // determine which packet is the last one that will complete for (i=f->segment_count-1; i >= 0; --i) if (f->segments[i] < 255) break; // 'i' is now the index of the _last_ segment of a packet that ends if (i >= 0) { f->end_seg_with_known_loc = i; f->known_loc_for_packet = loc0; } } if (f->first_decode) { int i,len; ProbedPage p; len = 0; for (i=0; i < f->segment_count; ++i) len += f->segments[i]; len += 27 + f->segment_count; p.page_start = f->first_audio_page_offset; p.page_end = p.page_start + len; p.after_previous_page_start = p.page_start; p.first_decoded_sample = 0; p.last_decoded_sample = loc0; f->p_first = p; } f->next_seg = 0; return TRUE; } static int start_page(vorb *f) { if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern); return start_page_no_capturepattern(f); } static int start_packet(vorb *f) { while (f->next_seg == -1) { if (!start_page(f)) return FALSE; if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_continued_packet_flag_invalid); } f->last_seg = FALSE; f->valid_bits = 0; f->packet_bytes = 0; f->bytes_in_seg = 0; // f->next_seg is now valid return TRUE; } static int maybe_start_packet(vorb *f) { if (f->next_seg == -1) { int x = get8(f); if (f->eof) return FALSE; // EOF at page boundary is not an error! if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern); if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern); if (!start_page_no_capturepattern(f)) return FALSE; if (f->page_flag & PAGEFLAG_continued_packet) { // set up enough state that we can read this packet if we want, // e.g. during recovery f->last_seg = FALSE; f->bytes_in_seg = 0; return error(f, VORBIS_continued_packet_flag_invalid); } } return start_packet(f); } static int next_segment(vorb *f) { int len; if (f->last_seg) return 0; if (f->next_seg == -1) { f->last_seg_which = f->segment_count-1; // in case start_page fails if (!start_page(f)) { f->last_seg = 1; return 0; } if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid); } len = f->segments[f->next_seg++]; if (len < 255) { f->last_seg = TRUE; f->last_seg_which = f->next_seg-1; } if (f->next_seg >= f->segment_count) f->next_seg = -1; assert(f->bytes_in_seg == 0); f->bytes_in_seg = len; return len; } #define EOP (-1) #define INVALID_BITS (-1) static int get8_packet_raw(vorb *f) { if (!f->bytes_in_seg) { if (f->last_seg) return EOP; else if (!next_segment(f)) return EOP; } assert(f->bytes_in_seg > 0); --f->bytes_in_seg; ++f->packet_bytes; return get8(f); } static int get8_packet(vorb *f) { int x = get8_packet_raw(f); f->valid_bits = 0; return x; } static void flush_packet(vorb *f) { while (get8_packet_raw(f) != EOP); } // @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important // as the huffman decoder? static uint32 get_bits(vorb *f, int n) { uint32 z; if (f->valid_bits < 0) return 0; if (f->valid_bits < n) { if (n > 24) { // the accumulator technique below would not work correctly in this case z = get_bits(f, 24); z += get_bits(f, n-24) << 24; return z; } if (f->valid_bits == 0) f->acc = 0; while (f->valid_bits < n) { int z = get8_packet_raw(f); if (z == EOP) { f->valid_bits = INVALID_BITS; return 0; } f->acc += z << f->valid_bits; f->valid_bits += 8; } } if (f->valid_bits < 0) return 0; z = f->acc & ((1 << n)-1); f->acc >>= n; f->valid_bits -= n; return z; } #if 0 static int32 get_bits_signed(vorb *f, int n) { uint32 z = get_bits(f, n); if (z & (1 << (n-1))) z += ~((1 << n) - 1); return (int32) z; } #endif // @OPTIMIZE: primary accumulator for huffman // expand the buffer to as many bits as possible without reading off end of packet // it might be nice to allow f->valid_bits and f->acc to be stored in registers, // e.g. cache them locally and decode locally static __forceinline void prep_huffman(vorb *f) { if (f->valid_bits <= 24) { if (f->valid_bits == 0) f->acc = 0; do { int z; if (f->last_seg && !f->bytes_in_seg) return; z = get8_packet_raw(f); if (z == EOP) return; f->acc += z << f->valid_bits; f->valid_bits += 8; } while (f->valid_bits <= 24); } } enum { VORBIS_packet_id = 1, VORBIS_packet_comment = 3, VORBIS_packet_setup = 5, }; static int codebook_decode_scalar_raw(vorb *f, Codebook *c) { int i; prep_huffman(f); assert(c->sorted_codewords || c->codewords); // cases to use binary search: sorted_codewords && !c->codewords // sorted_codewords && c->entries > 8 if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { // binary search uint32 code = bit_reverse(f->acc); int x=0, n=c->sorted_entries, len; while (n > 1) { // invariant: sc[x] <= code < sc[x+n] int m = x + (n >> 1); if (c->sorted_codewords[m] <= code) { x = m; n -= (n>>1); } else { n >>= 1; } } // x is now the sorted index if (!c->sparse) x = c->sorted_values[x]; // x is now sorted index if sparse, or symbol otherwise len = c->codeword_lengths[x]; if (f->valid_bits >= len) { f->acc >>= len; f->valid_bits -= len; return x; } f->valid_bits = 0; return -1; } // if small, linear search assert(!c->sparse); for (i=0; i < c->entries; ++i) { if (c->codeword_lengths[i] == NO_CODE) continue; if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i])-1))) { if (f->valid_bits >= c->codeword_lengths[i]) { f->acc >>= c->codeword_lengths[i]; f->valid_bits -= c->codeword_lengths[i]; return i; } f->valid_bits = 0; return -1; } } error(f, VORBIS_invalid_stream); f->valid_bits = 0; return -1; } #if 0 static int codebook_decode_scalar(vorb *f, Codebook *c) { int i; if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) prep_huffman(f); // fast huffman table lookup i = f->acc & FAST_HUFFMAN_TABLE_MASK; i = c->fast_huffman[i]; if (i >= 0) { f->acc >>= c->codeword_lengths[i]; f->valid_bits -= c->codeword_lengths[i]; if (f->valid_bits < 0) { f->valid_bits = 0; return -1; } return i; } return codebook_decode_scalar_raw(f,c); } #endif #ifndef STB_VORBIS_NO_INLINE_DECODE #define DECODE_RAW(var, f,c) \ if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \ prep_huffman(f); \ var = f->acc & FAST_HUFFMAN_TABLE_MASK; \ var = c->fast_huffman[var]; \ if (var >= 0) { \ int n = c->codeword_lengths[var]; \ f->acc >>= n; \ f->valid_bits -= n; \ if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \ } else { \ var = codebook_decode_scalar_raw(f,c); \ } #else #define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c); #endif #define DECODE(var,f,c) \ DECODE_RAW(var,f,c) \ if (c->sparse) var = c->sorted_values[var]; #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c) #else #define DECODE_VQ(var,f,c) DECODE(var,f,c) #endif // CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case // where we avoid one addition #ifndef STB_VORBIS_CODEBOOK_FLOATS #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off] * c->delta_value + c->minimum_value) #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off] * c->delta_value) #define CODEBOOK_ELEMENT_BASE(c) (c->minimum_value) #else #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) #define CODEBOOK_ELEMENT_BASE(c) (0) #endif static int codebook_decode_start(vorb *f, Codebook *c, int len) { int z = -1; // type 0 is only legal in a scalar context if (c->lookup_type == 0) error(f, VORBIS_invalid_stream); else { DECODE_VQ(z,f,c); if (c->sparse) assert(z < c->sorted_entries); if (z < 0) { // check for EOP if (!f->bytes_in_seg) if (f->last_seg) return z; error(f, VORBIS_invalid_stream); } } return z; } static int codebook_decode(vorb *f, Codebook *c, float *output, int len) { int i,z = codebook_decode_start(f,c,len); if (z < 0) return FALSE; if (len > c->dimensions) len = c->dimensions; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { float last = CODEBOOK_ELEMENT_BASE(c); int div = 1; for (i=0; i < len; ++i) { int off = (z / div) % c->lookup_values; float val = CODEBOOK_ELEMENT_FAST(c,off) + last; output[i] += val; if (c->sequence_p) last = val + c->minimum_value; div *= c->lookup_values; } return TRUE; } #endif z *= c->dimensions; #if 0 /* Sanity check */ if (c->lookup_type == 1) { if (c->sparse) { if (len + z > c->sorted_entries * c->dimensions) { return FALSE; } } else { if (len + z > c->entries * c->dimensions) { return FALSE; } } } else { if (len + z > c->lookup_values) { return FALSE; } } #endif if (c->sequence_p) { float last = CODEBOOK_ELEMENT_BASE(c); for (i=0; i < len; ++i) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; output[i] += val; last = val + c->minimum_value; } } else { float last = CODEBOOK_ELEMENT_BASE(c); for (i=0; i < len; ++i) { output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last; } } return TRUE; } static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step) { int i,z = codebook_decode_start(f,c,len); float last = CODEBOOK_ELEMENT_BASE(c); if (z < 0) return FALSE; if (len > c->dimensions) len = c->dimensions; #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { int div = 1; for (i=0; i < len; ++i) { int off = (z / div) % c->lookup_values; float val = CODEBOOK_ELEMENT_FAST(c,off) + last; output[i*step] += val; if (c->sequence_p) last = val; div *= c->lookup_values; } return TRUE; } #endif z *= c->dimensions; for (i=0; i < len; ++i) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; output[i*step] += val; if (c->sequence_p) last = val; } return TRUE; } #if STB_VORBIS_MAX_CHANNELS > 1 static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) { int c_inter = *c_inter_p; int p_inter = *p_inter_p; int i,z, effective = c->dimensions; // type 0 is only legal in a scalar context if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); while (total_decode > 0) { float last = CODEBOOK_ELEMENT_BASE(c); DECODE_VQ(z,f,c); #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK assert(!c->sparse || z < c->sorted_entries); #endif if (z < 0) { if (!f->bytes_in_seg) if (f->last_seg) return FALSE; return error(f, VORBIS_invalid_stream); } // if this will take us off the end of the buffers, stop short! // we check by computing the length of the virtual interleaved // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter), // and the length we'll be using (effective) if (c_inter + p_inter*ch + effective > len * ch) { effective = len*ch - (p_inter*ch - c_inter); } #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { int div = 1; for (i=0; i < effective; ++i) { int off = (z / div) % c->lookup_values; float val = CODEBOOK_ELEMENT_FAST(c,off) + last; outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } if (c->sequence_p) last = val; div *= c->lookup_values; } } else #endif { z *= c->dimensions; if (c->sequence_p) { for (i=0; i < effective; ++i) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } last = val; } } else { for (i=0; i < effective; ++i) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; outputs[c_inter][p_inter] += val; if (++c_inter == ch) { c_inter = 0; ++p_inter; } } } } total_decode -= effective; } *c_inter_p = c_inter; *p_inter_p = p_inter; return TRUE; } #endif #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK #if STB_VORBIS_MAX_CHANNELS > 1 static int codebook_decode_deinterleave_repeat_2(vorb *f, Codebook *c, float **outputs, int *c_inter_p, int *p_inter_p, int len, int total_decode) { int c_inter = *c_inter_p; int p_inter = *p_inter_p; int i,z, effective = c->dimensions; // type 0 is only legal in a scalar context if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); while (total_decode > 0) { float last = CODEBOOK_ELEMENT_BASE(c); DECODE_VQ(z,f,c); if (z < 0) { if (!f->bytes_in_seg) if (f->last_seg) return FALSE; return error(f, VORBIS_invalid_stream); } // if this will take us off the end of the buffers, stop short! // we check by computing the length of the virtual interleaved // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter), // and the length we'll be using (effective) if (c_inter + p_inter*2 + effective > len * 2) { effective = len*2 - (p_inter*2 - c_inter); } { z *= c->dimensions; stb_prof(11); if (c->sequence_p) { // haven't optimized this case because I don't have any examples for (i=0; i < effective; ++i) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; outputs[c_inter][p_inter] += val; if (++c_inter == 2) { c_inter = 0; ++p_inter; } last = val; } } else { i=0; if (c_inter == 1) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; outputs[c_inter][p_inter] += val; c_inter = 0; ++p_inter; ++i; } { float *z0 = outputs[0]; float *z1 = outputs[1]; for (; i+1 < effective;) { z0[p_inter] += CODEBOOK_ELEMENT_FAST(c,z+i) + last; z1[p_inter] += CODEBOOK_ELEMENT_FAST(c,z+i+1) + last; ++p_inter; i += 2; } } if (i < effective) { float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; outputs[c_inter][p_inter] += val; if (++c_inter == 2) { c_inter = 0; ++p_inter; } } } } total_decode -= effective; } *c_inter_p = c_inter; *p_inter_p = p_inter; return TRUE; } #endif #endif static int predict_point(int x, int x0, int x1, int y0, int y1) { int dy = y1 - y0; int adx = x1 - x0; // @OPTIMIZE: force int division to round in the right direction... is this necessary on x86? int err = abs(dy) * (x - x0); int off = err / adx; return dy < 0 ? y0 - off : y0 + off; } // the following table is block-copied from the specification static float inverse_db_table[256] = { 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, 0.82788260f, 0.88168307f, 0.9389798f, 1.0f }; // @OPTIMIZE: if you want to replace this bresenham line-drawing routine, // note that you must produce bit-identical output to decode correctly; // this specific sequence of operations is specified in the spec (it's // drawing integer-quantized frequency-space lines that the encoder // expects to be exactly the same) // ... also, isn't the whole point of Bresenham's algorithm to NOT // have to divide in the setup? sigh. #ifndef STB_VORBIS_NO_DEFER_FLOOR #define LINE_OP(a,b) a *= b #else #define LINE_OP(a,b) a = b #endif #ifdef STB_VORBIS_DIVIDE_TABLE #define DIVTAB_NUMER 32 #define DIVTAB_DENOM 64 int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB #endif static __forceinline int draw_line(float *output, int x0, int y0, int x1, int y1, int n) { int dy = y1 - y0; int adx = x1 - x0; int ady = abs(dy); int base; int x=x0,y=y0; int err = 0; int sy; /* Sanity check */ if (adx == 0) { return -1; } #ifdef STB_VORBIS_DIVIDE_TABLE if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) { if (dy < 0) { base = -integer_divide_table[ady][adx]; sy = base-1; } else { base = integer_divide_table[ady][adx]; sy = base+1; } } else { base = dy / adx; if (dy < 0) sy = base - 1; else sy = base+1; } #else base = dy / adx; if (dy < 0) sy = base - 1; else sy = base+1; #endif ady -= abs(base) * adx; if (x1 > n) x1 = n; /* Sanity check */ if (x >= n * 2 || y >= 256) { return -1; } LINE_OP(output[x], inverse_db_table[y]); for (++x; x < x1; ++x) { err += ady; if (err >= adx) { err -= adx; y += sy; } else { y += base; } /* Sanity check */ if (y >= 256) { return -1; } LINE_OP(output[x], inverse_db_table[y]); } return 0; } static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype) { int k; if (rtype == 0) { int step = n / book->dimensions; for (k=0; k < step; ++k) if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) return FALSE; } else { for (k=0; k < n; ) { if (!codebook_decode(f, book, target+offset, n-k)) return FALSE; k += book->dimensions; offset += book->dimensions; } } return TRUE; } static int decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) { int i,j,pass; Residue *r = f->residue_config + rn; int rtype = f->residue_types[rn]; int c = r->classbook; int classwords = f->codebooks[c].dimensions; int n_read = r->end - r->begin; int part_read = n_read / r->part_size; int temp_alloc_point = temp_alloc_save(f); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); #else int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); #endif stb_prof(2); for (i=0; i < ch; ++i) if (!do_not_decode[i]) memset(residue_buffers[i], 0, sizeof(float) * n); #if STB_VORBIS_MAX_CHANNELS > 1 if (rtype == 2 && ch != 1) { //int len = ch * n; for (j=0; j < ch; ++j) if (!do_not_decode[j]) break; if (j == ch) goto done; stb_prof(3); for (pass=0; pass < 8; ++pass) { int pcount = 0, class_set = 0; if (ch == 2) { stb_prof(13); while (pcount < part_read) { int z = r->begin + pcount*r->part_size; int c_inter = (z & 1), p_inter = z>>1; if (pass == 0) { Codebook *c = f->codebooks+r->classbook; int q; DECODE(q,f,c); if (q == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else for (i=classwords-1; i >= 0; --i) { classifications[0][i+pcount] = q % r->classifications; q /= r->classifications; } #endif } stb_prof(5); for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { int z = r->begin + pcount*r->part_size; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE int c = part_classdata[0][class_set][i]; #else int c = classifications[0][pcount]; #endif int b = r->residue_books[c][pass]; if (b >= 0) { Codebook *book = f->codebooks + b; stb_prof(20); // accounts for X time #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; #else // saves 1% if (!codebook_decode_deinterleave_repeat_2(f, book, residue_buffers, &c_inter, &p_inter, n, r->part_size)) goto done; #endif stb_prof(7); } else { z += r->part_size; c_inter = z & 1; p_inter = z >> 1; } } stb_prof(8); #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE ++class_set; #endif } } else if (ch == 1) { while (pcount < part_read) { int z = r->begin + pcount*r->part_size; int c_inter = 0, p_inter = z; if (pass == 0) { Codebook *c = f->codebooks+r->classbook; int q; DECODE(q,f,c); if (q == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else for (i=classwords-1; i >= 0; --i) { classifications[0][i+pcount] = q % r->classifications; q /= r->classifications; } #endif } for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { int z = r->begin + pcount*r->part_size; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE int c = part_classdata[0][class_set][i]; #else int c = classifications[0][pcount]; #endif int b = r->residue_books[c][pass]; if (b >= 0) { Codebook *book = f->codebooks + b; stb_prof(22); if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; stb_prof(3); } else { z += r->part_size; c_inter = 0; p_inter = z; } } #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE ++class_set; #endif } } else { while (pcount < part_read) { int z = r->begin + pcount*r->part_size; int c_inter = z % ch, p_inter = z/ch; if (pass == 0) { Codebook *c = f->codebooks+r->classbook; int q; DECODE(q,f,c); if (q == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[0][class_set] = r->classdata[q]; #else for (i=classwords-1; i >= 0; --i) { classifications[0][i+pcount] = q % r->classifications; q /= r->classifications; } #endif } for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { int z = r->begin + pcount*r->part_size; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE int c = part_classdata[0][class_set][i]; #else int c = classifications[0][pcount]; #endif int b = r->residue_books[c][pass]; if (b >= 0) { Codebook *book = f->codebooks + b; stb_prof(22); if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) goto done; stb_prof(3); } else { z += r->part_size; c_inter = z % ch; p_inter = z / ch; } } #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE ++class_set; #endif } } } goto done; } #endif stb_prof(9); for (pass=0; pass < 8; ++pass) { int pcount = 0, class_set=0; while (pcount < part_read) { if (pass == 0) { for (j=0; j < ch; ++j) { if (!do_not_decode[j]) { Codebook *c = f->codebooks+r->classbook; int temp; DECODE(temp,f,c); if (temp == EOP) goto done; #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE part_classdata[j][class_set] = r->classdata[temp]; #else for (i=classwords-1; i >= 0; --i) { classifications[j][i+pcount] = temp % r->classifications; temp /= r->classifications; } #endif } } } for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { for (j=0; j < ch; ++j) { if (!do_not_decode[j]) { #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE int c = part_classdata[j][class_set][i]; #else int c = classifications[j][pcount]; #endif int b = r->residue_books[c][pass]; if (b >= 0) { Codebook *book; float *target = residue_buffers[j]; int offset = r->begin + pcount * r->part_size; int n = r->part_size; /* Sanity check */ if (offset + n >= f->blocksize_1) { return FALSE; } book = f->codebooks + b; if (!residue_decode(f, book, target, offset, n, rtype)) goto done; } } } } #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE ++class_set; /* Sanity check */ if (class_set >= part_read) { return FALSE; } #endif } } done: stb_prof(0); temp_alloc_restore(f,temp_alloc_point); return TRUE; } #if 0 // slow way for debugging void inverse_mdct_slow(float *buffer, int n) { int i,j; int n2 = n >> 1; float *x = (float *) malloc(sizeof(*x) * n2); memcpy(x, buffer, sizeof(*x) * n2); for (i=0; i < n; ++i) { float acc = 0; for (j=0; j < n2; ++j) // formula from paper: //acc += n/4.0f * x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1)); // formula from wikipedia //acc += 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5)); // these are equivalent, except the formula from the paper inverts the multiplier! // however, what actually works is NO MULTIPLIER!?! //acc += 64 * 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5)); acc += x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1)); buffer[i] = acc; } free(x); } #elif 0 // same as above, but just barely able to run in real time on modern machines void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) { float mcos[16384]; int i,j; int n2 = n >> 1, nmask = (n << 2) -1; float *x = (float *) malloc(sizeof(*x) * n2); memcpy(x, buffer, sizeof(*x) * n2); for (i=0; i < 4*n; ++i) mcos[i] = (float) cos(M_PI / 2 * i / n); for (i=0; i < n; ++i) { float acc = 0; for (j=0; j < n2; ++j) acc += x[j] * mcos[(2 * i + 1 + n2)*(2*j+1) & nmask]; buffer[i] = acc; } free(x); } #else // transform to use a slow dct-iv; this is STILL basically trivial, // but only requires half as many ops #if 0 static void dct_iv_slow(float *buffer, int n) { float mcos[16384]; float x[2048]; int i,j; //int n2 = n >> 1; int nmask = (n << 3) - 1; memcpy(x, buffer, sizeof(*x) * n); for (i=0; i < 8*n; ++i) mcos[i] = (float) cos(M_PI / 4 * i / n); for (i=0; i < n; ++i) { float acc = 0; for (j=0; j < n; ++j) acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask]; //acc += x[j] * cos(M_PI / n * (i + 0.5) * (j + 0.5)); buffer[i] = acc; } //free(x); } #endif #if 0 static void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) { int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4; float temp[4096]; memcpy(temp, buffer, n2 * sizeof(float)); dct_iv_slow(temp, n2); // returns -c'-d, a-b' for (i=0; i < n4 ; ++i) buffer[i] = temp[i+n4]; // a-b' for ( ; i < n3_4; ++i) buffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d' for ( ; i < n ; ++i) buffer[i] = -temp[i - n3_4]; // c'+d } #endif #endif #ifndef LIBVORBIS_MDCT #define LIBVORBIS_MDCT 0 #endif #if LIBVORBIS_MDCT // directly call the vorbis MDCT using an interface documented // by Jeff Roberts... useful for performance comparison typedef struct { int n; int log2n; float *trig; int *bitrev; float scale; } mdct_lookup; extern void mdct_init(mdct_lookup *lookup, int n); extern void mdct_clear(mdct_lookup *l); extern void mdct_backward(mdct_lookup *init, float *in, float *out); mdct_lookup M1,M2; static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) { mdct_lookup *M; if (M1.n == n) M = &M1; else if (M2.n == n) M = &M2; else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; } else { if (M2.n) __asm int 3; mdct_init(&M2, n); M = &M2; } mdct_backward(M, buffer, buffer); } #endif // the following were split out into separate functions while optimizing; // they could be pushed back up but eh. __forceinline showed no change; // they're probably already being inlined. static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) { float *ee0 = e + i_off; float *ee2 = ee0 + k_off; int i; assert((n & 3) == 0); for (i=(n>>2); i > 0; --i) { float k00_20, k01_21; k00_20 = ee0[ 0] - ee2[ 0]; k01_21 = ee0[-1] - ee2[-1]; ee0[ 0] += ee2[ 0];//ee0[ 0] = ee0[ 0] + ee2[ 0]; ee0[-1] += ee2[-1];//ee0[-1] = ee0[-1] + ee2[-1]; ee2[ 0] = k00_20 * A[0] - k01_21 * A[1]; ee2[-1] = k01_21 * A[0] + k00_20 * A[1]; A += 8; k00_20 = ee0[-2] - ee2[-2]; k01_21 = ee0[-3] - ee2[-3]; ee0[-2] += ee2[-2];//ee0[-2] = ee0[-2] + ee2[-2]; ee0[-3] += ee2[-3];//ee0[-3] = ee0[-3] + ee2[-3]; ee2[-2] = k00_20 * A[0] - k01_21 * A[1]; ee2[-3] = k01_21 * A[0] + k00_20 * A[1]; A += 8; k00_20 = ee0[-4] - ee2[-4]; k01_21 = ee0[-5] - ee2[-5]; ee0[-4] += ee2[-4];//ee0[-4] = ee0[-4] + ee2[-4]; ee0[-5] += ee2[-5];//ee0[-5] = ee0[-5] + ee2[-5]; ee2[-4] = k00_20 * A[0] - k01_21 * A[1]; ee2[-5] = k01_21 * A[0] + k00_20 * A[1]; A += 8; k00_20 = ee0[-6] - ee2[-6]; k01_21 = ee0[-7] - ee2[-7]; ee0[-6] += ee2[-6];//ee0[-6] = ee0[-6] + ee2[-6]; ee0[-7] += ee2[-7];//ee0[-7] = ee0[-7] + ee2[-7]; ee2[-6] = k00_20 * A[0] - k01_21 * A[1]; ee2[-7] = k01_21 * A[0] + k00_20 * A[1]; A += 8; ee0 -= 8; ee2 -= 8; } } static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) { int i; float k00_20, k01_21; float *e0 = e + d0; float *e2 = e0 + k_off; for (i=lim >> 2; i > 0; --i) { k00_20 = e0[-0] - e2[-0]; k01_21 = e0[-1] - e2[-1]; e0[-0] += e2[-0];//e0[-0] = e0[-0] + e2[-0]; e0[-1] += e2[-1];//e0[-1] = e0[-1] + e2[-1]; e2[-0] = (k00_20)*A[0] - (k01_21) * A[1]; e2[-1] = (k01_21)*A[0] + (k00_20) * A[1]; A += k1; k00_20 = e0[-2] - e2[-2]; k01_21 = e0[-3] - e2[-3]; e0[-2] += e2[-2];//e0[-2] = e0[-2] + e2[-2]; e0[-3] += e2[-3];//e0[-3] = e0[-3] + e2[-3]; e2[-2] = (k00_20)*A[0] - (k01_21) * A[1]; e2[-3] = (k01_21)*A[0] + (k00_20) * A[1]; A += k1; k00_20 = e0[-4] - e2[-4]; k01_21 = e0[-5] - e2[-5]; e0[-4] += e2[-4];//e0[-4] = e0[-4] + e2[-4]; e0[-5] += e2[-5];//e0[-5] = e0[-5] + e2[-5]; e2[-4] = (k00_20)*A[0] - (k01_21) * A[1]; e2[-5] = (k01_21)*A[0] + (k00_20) * A[1]; A += k1; k00_20 = e0[-6] - e2[-6]; k01_21 = e0[-7] - e2[-7]; e0[-6] += e2[-6];//e0[-6] = e0[-6] + e2[-6]; e0[-7] += e2[-7];//e0[-7] = e0[-7] + e2[-7]; e2[-6] = (k00_20)*A[0] - (k01_21) * A[1]; e2[-7] = (k01_21)*A[0] + (k00_20) * A[1]; e0 -= 8; e2 -= 8; A += k1; } } static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) { int i; float A0 = A[0]; float A1 = A[0+1]; float A2 = A[0+a_off]; float A3 = A[0+a_off+1]; float A4 = A[0+a_off*2+0]; float A5 = A[0+a_off*2+1]; float A6 = A[0+a_off*3+0]; float A7 = A[0+a_off*3+1]; float k00,k11; float *ee0 = e +i_off; float *ee2 = ee0+k_off; for (i=n; i > 0; --i) { k00 = ee0[ 0] - ee2[ 0]; k11 = ee0[-1] - ee2[-1]; ee0[ 0] = ee0[ 0] + ee2[ 0]; ee0[-1] = ee0[-1] + ee2[-1]; ee2[ 0] = (k00) * A0 - (k11) * A1; ee2[-1] = (k11) * A0 + (k00) * A1; k00 = ee0[-2] - ee2[-2]; k11 = ee0[-3] - ee2[-3]; ee0[-2] = ee0[-2] + ee2[-2]; ee0[-3] = ee0[-3] + ee2[-3]; ee2[-2] = (k00) * A2 - (k11) * A3; ee2[-3] = (k11) * A2 + (k00) * A3; k00 = ee0[-4] - ee2[-4]; k11 = ee0[-5] - ee2[-5]; ee0[-4] = ee0[-4] + ee2[-4]; ee0[-5] = ee0[-5] + ee2[-5]; ee2[-4] = (k00) * A4 - (k11) * A5; ee2[-5] = (k11) * A4 + (k00) * A5; k00 = ee0[-6] - ee2[-6]; k11 = ee0[-7] - ee2[-7]; ee0[-6] = ee0[-6] + ee2[-6]; ee0[-7] = ee0[-7] + ee2[-7]; ee2[-6] = (k00) * A6 - (k11) * A7; ee2[-7] = (k11) * A6 + (k00) * A7; ee0 -= k0; ee2 -= k0; } } static __forceinline void iter_54(float *z) { float k00,k11,k22,k33; float y0,y1,y2,y3; k00 = z[ 0] - z[-4]; y0 = z[ 0] + z[-4]; y2 = z[-2] + z[-6]; k22 = z[-2] - z[-6]; z[-0] = y0 + y2; // z0 + z4 + z2 + z6 z[-2] = y0 - y2; // z0 + z4 - z2 - z6 // done with y0,y2 k33 = z[-3] - z[-7]; z[-4] = k00 + k33; // z0 - z4 + z3 - z7 z[-6] = k00 - k33; // z0 - z4 - z3 + z7 // done with k33 k11 = z[-1] - z[-5]; y1 = z[-1] + z[-5]; y3 = z[-3] + z[-7]; z[-1] = y1 + y3; // z1 + z5 + z3 + z7 z[-3] = y1 - y3; // z1 + z5 - z3 - z7 z[-5] = k11 - k22; // z1 - z5 + z2 - z6 z[-7] = k11 + k22; // z1 - z5 - z2 + z6 } static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) { //int k_off = -8; int a_off = base_n >> 3; float A2 = A[0+a_off]; float *z = e + i_off; float *base = z - 16 * n; while (z > base) { float k00,k11; k00 = z[-0] - z[-8]; k11 = z[-1] - z[-9]; z[-0] = z[-0] + z[-8]; z[-1] = z[-1] + z[-9]; z[-8] = k00; z[-9] = k11 ; k00 = z[ -2] - z[-10]; k11 = z[ -3] - z[-11]; z[ -2] = z[ -2] + z[-10]; z[ -3] = z[ -3] + z[-11]; z[-10] = (k00+k11) * A2; z[-11] = (k11-k00) * A2; k00 = z[-12] - z[ -4]; // reverse to avoid a unary negation k11 = z[ -5] - z[-13]; z[ -4] = z[ -4] + z[-12]; z[ -5] = z[ -5] + z[-13]; z[-12] = k11; z[-13] = k00; k00 = z[-14] - z[ -6]; // reverse to avoid a unary negation k11 = z[ -7] - z[-15]; z[ -6] = z[ -6] + z[-14]; z[ -7] = z[ -7] + z[-15]; z[-14] = (k00+k11) * A2; z[-15] = (k00-k11) * A2; iter_54(z); iter_54(z-8); z -= 16; } } static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) { int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; //int n3_4 = n - n4; int ld; // @OPTIMIZE: reduce register pressure by using fewer variables? int save_point = temp_alloc_save(f); float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2)); float *u=NULL,*v=NULL; // twiddle factors float *A = f->A[blocktype]; // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' after this function. // kernel from paper // merged: // copy and reflect spectral data // step 0 // note that it turns out that the items added together during // this step are, in fact, being added to themselves (as reflected // by step 0). inexplicable inefficiency! this became obvious // once I combined the passes. // so there's a missing 'times 2' here (for adding X to itself). // this propogates through linearly to the end, where the numbers // are 1/2 too small, and need to be compensated for. { float *d,*e, *AA, *e_stop; d = &buf2[n2-2]; AA = A; e = &buffer[0]; e_stop = &buffer[n2]; while (e != e_stop) { d[1] = (e[0] * AA[0] - e[2]*AA[1]); d[0] = (e[0] * AA[1] + e[2]*AA[0]); d -= 2; AA += 2; e += 4; } e = &buffer[n2-3]; while (d >= buf2) { d[1] = (-e[2] * AA[0] - -e[0]*AA[1]); d[0] = (-e[2] * AA[1] + -e[0]*AA[0]); d -= 2; AA += 2; e -= 4; } } // now we use symbolic names for these, so that we can // possibly swap their meaning as we change which operations // are in place u = buffer; v = buf2; // step 2 (paper output is w, now u) // this could be in place, but the data ends up in the wrong // place... _somebody_'s got to swap it, so this is nominated { float *AA = &A[n2-8]; float *d0,*d1, *e0, *e1; e0 = &v[n4]; e1 = &v[0]; d0 = &u[n4]; d1 = &u[0]; while (AA >= A) { float v40_20, v41_21; v41_21 = e0[1] - e1[1]; v40_20 = e0[0] - e1[0]; d0[1] = e0[1] + e1[1]; d0[0] = e0[0] + e1[0]; d1[1] = v41_21*AA[4] - v40_20*AA[5]; d1[0] = v40_20*AA[4] + v41_21*AA[5]; v41_21 = e0[3] - e1[3]; v40_20 = e0[2] - e1[2]; d0[3] = e0[3] + e1[3]; d0[2] = e0[2] + e1[2]; d1[3] = v41_21*AA[0] - v40_20*AA[1]; d1[2] = v40_20*AA[0] + v41_21*AA[1]; AA -= 8; d0 += 4; d1 += 4; e0 += 4; e1 += 4; } } // step 3 ld = ilog(n) - 1; // ilog is off-by-one from normal definitions // optimized step 3: // the original step3 loop can be nested r inside s or s inside r; // it's written originally as s inside r, but this is dumb when r // iterates many times, and s few. So I have two copies of it and // switch between them halfway. // this is iteration 0 of step 3 imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); // this is iteration 1 of step 3 imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); l=2; for (; l < (ld-3)>>1; ++l) { int k0 = n >> (l+2), k0_2 = k0>>1; int lim = 1 << (l+1); int i; for (i=0; i < lim; ++i) imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); } for (; l < ld-6; ++l) { int k0 = n >> (l+2), k1 = 1 << (l+3), k0_2 = k0>>1; int rlim = n >> (l+6), r; int lim = 1 << (l+1); int i_off; float *A0 = A; i_off = n2-1; for (r=rlim; r > 0; --r) { imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); A0 += k1*4; i_off -= 8; } } // iterations with count: // ld-6,-5,-4 all interleaved together // the big win comes from getting rid of needless flops // due to the constants on pass 5 & 4 being all 1 and 0; // combining them to be simultaneous to improve cache made little difference imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); // output is u // step 4, 5, and 6 // cannot be in-place because of step 5 { uint16 *bitrev = f->bit_reverse[blocktype]; // weirdly, I'd have thought reading sequentially and writing // erratically would have been better than vice-versa, but in // fact that's not what my testing showed. (That is, with // j = bitreverse(i), do you read i and write j, or read j and write i.) float *d0 = &v[n4-4]; float *d1 = &v[n2-4]; while (d0 >= v) { int k4; k4 = bitrev[0]; d1[3] = u[k4+0]; d1[2] = u[k4+1]; d0[3] = u[k4+2]; d0[2] = u[k4+3]; k4 = bitrev[1]; d1[1] = u[k4+0]; d1[0] = u[k4+1]; d0[1] = u[k4+2]; d0[0] = u[k4+3]; d0 -= 4; d1 -= 4; bitrev += 2; } } // (paper output is u, now v) // data must be in buf2 assert(v == buf2); // step 7 (paper output is v, now v) // this is now in place { float *C = f->C[blocktype]; float *d, *e; d = v; e = v + n2 - 4; while (d < e) { float a02,a11,b0,b1,b2,b3; a02 = d[0] - e[2]; a11 = d[1] + e[3]; b0 = C[1]*a02 + C[0]*a11; b1 = C[1]*a11 - C[0]*a02; b2 = d[0] + e[ 2]; b3 = d[1] - e[ 3]; d[0] = b2 + b0; d[1] = b3 + b1; e[2] = b2 - b0; e[3] = b1 - b3; a02 = d[2] - e[0]; a11 = d[3] + e[1]; b0 = C[3]*a02 + C[2]*a11; b1 = C[3]*a11 - C[2]*a02; b2 = d[2] + e[ 0]; b3 = d[3] - e[ 1]; d[2] = b2 + b0; d[3] = b3 + b1; e[0] = b2 - b0; e[1] = b1 - b3; C += 4; d += 4; e -= 4; } } // data must be in buf2 // step 8+decode (paper output is X, now buffer) // this generates pairs of data a la 8 and pushes them directly through // the decode kernel (pushing rather than pulling) to avoid having // to make another pass later // this cannot POSSIBLY be in place, so we refer to the buffers directly { float *d0,*d1,*d2,*d3; float *B = f->B[blocktype] + n2 - 8; float *e = buf2 + n2 - 8; d0 = &buffer[0]; d1 = &buffer[n2-4]; d2 = &buffer[n2]; d3 = &buffer[n-4]; while (e >= v) { float p0,p1,p2,p3; p3 = e[6]*B[7] - e[7]*B[6]; p2 = -e[6]*B[6] - e[7]*B[7]; d0[0] = p3; d1[3] = - p3; d2[0] = p2; d3[3] = p2; p1 = e[4]*B[5] - e[5]*B[4]; p0 = -e[4]*B[4] - e[5]*B[5]; d0[1] = p1; d1[2] = - p1; d2[1] = p0; d3[2] = p0; p3 = e[2]*B[3] - e[3]*B[2]; p2 = -e[2]*B[2] - e[3]*B[3]; d0[2] = p3; d1[1] = - p3; d2[2] = p2; d3[1] = p2; p1 = e[0]*B[1] - e[1]*B[0]; p0 = -e[0]*B[0] - e[1]*B[1]; d0[3] = p1; d1[0] = - p1; d2[3] = p0; d3[0] = p0; B -= 8; e -= 8; d0 += 4; d2 += 4; d1 -= 4; d3 -= 4; } } temp_alloc_restore(f,save_point); } #if 0 // this is the original version of the above code, if you want to optimize it from scratch void inverse_mdct_naive(float *buffer, int n) { float s; float A[1 << 12], B[1 << 12], C[1 << 11]; int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; int n3_4 = n - n4, ld; // how can they claim this only uses N words?! // oh, because they're only used sparsely, whoops float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13]; // set up twiddle factors for (k=k2=0; k < n4; ++k,k2+=2) { A[k2 ] = (float) cos(4*k*M_PI/n); A[k2+1] = (float) -sin(4*k*M_PI/n); B[k2 ] = (float) cos((k2+1)*M_PI/n/2); B[k2+1] = (float) sin((k2+1)*M_PI/n/2); } for (k=k2=0; k < n8; ++k,k2+=2) { C[k2 ] = (float) cos(2*(k2+1)*M_PI/n); C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n); } // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" // Note there are bugs in that pseudocode, presumably due to them attempting // to rename the arrays nicely rather than representing the way their actual // implementation bounces buffers back and forth. As a result, even in the // "some formulars corrected" version, a direct implementation fails. These // are noted below as "paper bug". // copy and reflect spectral data for (k=0; k < n2; ++k) u[k] = buffer[k]; for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1]; // kernel from paper // step 1 for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) { v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1]; v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2]; } // step 2 for (k=k4=0; k < n8; k+=1, k4+=4) { w[n2+3+k4] = v[n2+3+k4] + v[k4+3]; w[n2+1+k4] = v[n2+1+k4] + v[k4+1]; w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4]; w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4]; } // step 3 ld = ilog(n) - 1; // ilog is off-by-one from normal definitions for (l=0; l < ld-3; ++l) { int k0 = n >> (l+2), k1 = 1 << (l+3); int rlim = n >> (l+4), r4, r; int s2lim = 1 << (l+2), s2; for (r=r4=0; r < rlim; r4+=4,++r) { for (s2=0; s2 < s2lim; s2+=2) { u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4]; u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4]; u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1] - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1]; u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1] + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1]; } } if (l+1 < ld-3) { // paper bug: ping-ponging of u&w here is omitted memcpy(w, u, sizeof(u)); } } // step 4 for (i=0; i < n8; ++i) { int j = bit_reverse(i) >> (32-ld+3); assert(j < n8); if (i == j) { // paper bug: original code probably swapped in place; if copying, // need to directly copy in this case int i8 = i << 3; v[i8+1] = u[i8+1]; v[i8+3] = u[i8+3]; v[i8+5] = u[i8+5]; v[i8+7] = u[i8+7]; } else if (i < j) { int i8 = i << 3, j8 = j << 3; v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1]; v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3]; v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5]; v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7]; } } // step 5 for (k=0; k < n2; ++k) { w[k] = v[k*2+1]; } // step 6 for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) { u[n-1-k2] = w[k4]; u[n-2-k2] = w[k4+1]; u[n3_4 - 1 - k2] = w[k4+2]; u[n3_4 - 2 - k2] = w[k4+3]; } // step 7 for (k=k2=0; k < n8; ++k, k2 += 2) { v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2; v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2; v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2; v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2; } // step 8 for (k=k2=0; k < n4; ++k,k2 += 2) { X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1]; X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ]; } // decode kernel to output // determined the following value experimentally // (by first figuring out what made inverse_mdct_slow work); then matching that here // (probably vorbis encoder premultiplies by n or n/2, to save it on the decoder?) s = 0.5; // theoretically would be n4 // [[[ note! the s value of 0.5 is compensated for by the B[] in the current code, // so it needs to use the "old" B values to behave correctly, or else // set s to 1.0 ]]] for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4]; for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1]; for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4]; } #endif static float *get_window(vorb *f, int len) { len <<= 1; if (len == f->blocksize_0) return f->window[0]; if (len == f->blocksize_1) return f->window[1]; return NULL; } #ifndef STB_VORBIS_NO_DEFER_FLOOR typedef int16 YTYPE; #else typedef int YTYPE; #endif static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag) { int n2 = n >> 1; int s = map->chan[i].mux, floor; floor = map->submap_floor[s]; if (f->floor_types[floor] == 0) { return error(f, VORBIS_invalid_stream); } else { Floor1 *g = &f->floor_config[floor].floor1; int j,q; int lx = 0, ly = finalY[0] * g->floor1_multiplier; for (q=1; q < g->values; ++q) { j = g->sorted_order[q]; #ifndef STB_VORBIS_NO_DEFER_FLOOR if (finalY[j] >= 0) #else if (step2_flag[j]) #endif { int hy = finalY[j] * g->floor1_multiplier; int hx = g->Xlist[j]; if (draw_line(target, lx,ly, hx,hy, n2) < 0) return FALSE; lx = hx, ly = hy; } } if (lx < n2) // optimization of: draw_line(target, lx,ly, n,ly, n2); for (j=lx; j < n2; ++j) LINE_OP(target[j], inverse_db_table[ly]); } return TRUE; } static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) { Mode *m; int i, n, prev, next, window_center; f->channel_buffer_start = f->channel_buffer_end = 0; retry: if (f->eof) return FALSE; if (!maybe_start_packet(f)) return FALSE; // check packet type if (get_bits(f,1) != 0) { if (IS_PUSH_MODE(f)) return error(f,VORBIS_bad_packet_type); while (EOP != get8_packet(f)); goto retry; } #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); #endif i = get_bits(f, ilog(f->mode_count-1)); if (i == EOP) return FALSE; if (i >= f->mode_count) return FALSE; *mode = i; m = f->mode_config + i; if (m->blockflag) { n = f->blocksize_1; prev = get_bits(f,1); next = get_bits(f,1); } else { prev = next = 0; n = f->blocksize_0; } // WINDOWING window_center = n >> 1; if (m->blockflag && !prev) { *p_left_start = (n - f->blocksize_0) >> 2; *p_left_end = (n + f->blocksize_0) >> 2; } else { *p_left_start = 0; *p_left_end = window_center; } if (m->blockflag && !next) { *p_right_start = (n*3 - f->blocksize_0) >> 2; *p_right_end = (n*3 + f->blocksize_0) >> 2; } else { *p_right_start = window_center; *p_right_end = n; } return TRUE; } static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) { Mapping *map; int i,j,k,n,n2; int zero_channel[256]; int really_zero_channel[256]; int window_center; // WINDOWING n = f->blocksize[m->blockflag]; window_center = n >> 1; map = &f->mapping[m->mapping]; // FLOORS n2 = n >> 1; stb_prof(1); for (i=0; i < f->channels; ++i) { int s = map->chan[i].mux, floor; zero_channel[i] = FALSE; floor = map->submap_floor[s]; if (f->floor_types[floor] == 0) { return error(f, VORBIS_invalid_stream); } else { Floor1 *g = &f->floor_config[floor].floor1; if (get_bits(f, 1)) { short *finalY; uint8 step2_flag[256]; static int range_list[4] = { 256, 128, 86, 64 }; int range = range_list[g->floor1_multiplier-1]; int offset = 2; finalY = f->finalY[i]; finalY[0] = get_bits(f, ilog(range)-1); finalY[1] = get_bits(f, ilog(range)-1); for (j=0; j < g->partitions; ++j) { int pclass = g->partition_class_list[j]; int cdim = g->class_dimensions[pclass]; int cbits = g->class_subclasses[pclass]; int csub = (1 << cbits)-1; int cval = 0; if (cbits) { Codebook *c = f->codebooks + g->class_masterbooks[pclass]; DECODE(cval,f,c); } for (k=0; k < cdim; ++k) { int book = g->subclass_books[pclass][cval & csub]; cval = cval >> cbits; if (book >= 0) { int temp; Codebook *c = f->codebooks + book; DECODE(temp,f,c); finalY[offset++] = temp; } else finalY[offset++] = 0; } } if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec step2_flag[0] = step2_flag[1] = 1; for (j=2; j < g->values; ++j) { int low, high, pred, highroom, lowroom, room, val; low = g->neighbors[j][0]; high = g->neighbors[j][1]; //neighbors(g->Xlist, j, &low, &high); pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); val = finalY[j]; highroom = range - pred; lowroom = pred; if (highroom < lowroom) room = highroom * 2; else room = lowroom * 2; if (val) { step2_flag[low] = step2_flag[high] = 1; step2_flag[j] = 1; if (val >= room) if (highroom > lowroom) finalY[j] = val - lowroom + pred; else finalY[j] = pred - val + highroom - 1; else if (val & 1) finalY[j] = pred - ((val+1)>>1); else finalY[j] = pred + (val>>1); } else { step2_flag[j] = 0; finalY[j] = pred; } } #ifdef STB_VORBIS_NO_DEFER_FLOOR /* Sanity check */ if (n >= f->blocksize_1) return FALSE; do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); #else // defer final floor computation until _after_ residue for (j=0; j < g->values; ++j) { if (!step2_flag[j]) finalY[j] = -1; } #endif } else { error: zero_channel[i] = TRUE; } // So we just defer everything else to later // at this point we've decoded the floor into buffer } } stb_prof(0); // at this point we've decoded all floors #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); #endif // re-enable coupled channels if necessary memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels); for (i=0; i < map->coupling_steps; ++i) if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) { zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; } // RESIDUE DECODE for (i=0; i < map->submaps; ++i) { float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; int r,t; uint8 do_not_decode[256]; int ch = 0; memset(do_not_decode, 0, 256); for (j=0; j < f->channels; ++j) { if (map->chan[j].mux == i) { if (zero_channel[j]) { do_not_decode[ch] = TRUE; residue_buffers[ch] = NULL; } else { do_not_decode[ch] = FALSE; residue_buffers[ch] = f->channel_buffers[j]; } ++ch; } } r = map->submap_residue[i]; t = f->residue_types[r]; if (!decode_residue(f, residue_buffers, ch, n2, r, do_not_decode)) { return FALSE; } } #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); #endif // INVERSE COUPLING stb_prof(14); for (i = map->coupling_steps-1; i >= 0; --i) { int n2 = n >> 1; float *m = f->channel_buffers[map->chan[i].magnitude]; float *a = f->channel_buffers[map->chan[i].angle ]; for (j=0; j < n2; ++j) { float a2,m2; if (m[j] > 0) if (a[j] > 0) m2 = m[j], a2 = m[j] - a[j]; else a2 = m[j], m2 = m[j] + a[j]; else if (a[j] > 0) m2 = m[j], a2 = m[j] + a[j]; else a2 = m[j], m2 = m[j] - a[j]; m[j] = m2; a[j] = a2; } } // finish decoding the floors #ifndef STB_VORBIS_NO_DEFER_FLOOR stb_prof(15); for (i=0; i < f->channels; ++i) { if (really_zero_channel[i]) { memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); } else { do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); } } #else for (i=0; i < f->channels; ++i) { if (really_zero_channel[i]) { memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); } else { for (j=0; j < n2; ++j) f->channel_buffers[i][j] *= f->floor_buffers[i][j]; } } #endif // INVERSE MDCT stb_prof(16); for (i=0; i < f->channels; ++i) inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); stb_prof(0); // this shouldn't be necessary, unless we exited on an error // and want to flush to get to the next packet flush_packet(f); if (f->first_decode) { // assume we start so first non-discarded sample is sample 0 // this isn't to spec, but spec would require us to read ahead // and decode the size of all current frames--could be done, // but presumably it's not a commonly used feature f->current_loc = -n2; // start of first frame is positioned for discard // we might have to discard samples "from" the next frame too, // if we're lapping a large block then a small at the start? f->discard_samples_deferred = n - right_end; f->current_loc_valid = TRUE; f->first_decode = FALSE; } else if (f->discard_samples_deferred) { left_start += f->discard_samples_deferred; *p_left = left_start; f->discard_samples_deferred = 0; } else if (f->previous_length == 0 && f->current_loc_valid) { // we're recovering from a seek... that means we're going to discard // the samples from this packet even though we know our position from // the last page header, so we need to update the position based on // the discarded samples here // but wait, the code below is going to add this in itself even // on a discard, so we don't need to do it here... } // check if we have ogg information about the sample # for this packet if (f->last_seg_which == f->end_seg_with_known_loc) { // if we have a valid current loc, and this is final: if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { uint32 current_end = f->known_loc_for_packet - (n-right_end); // then let's infer the size of the (probably) short final frame if (current_end < f->current_loc + right_end) { if (current_end < f->current_loc) { // negative truncation, that's impossible! *len = 0; } else { *len = current_end - f->current_loc; } *len += left_start; f->current_loc += *len; return TRUE; } } // otherwise, just set our sample loc // guess that the ogg granule pos refers to the _middle_ of the // last frame? // set f->current_loc to the position of left_start f->current_loc = f->known_loc_for_packet - (n2-left_start); f->current_loc_valid = TRUE; } if (f->current_loc_valid) f->current_loc += (right_start - left_start); #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); #endif *len = right_end; // ignore samples after the window goes to 0 return TRUE; } static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right) { int mode, left_end, right_end; if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); } static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) { int prev,i,j; // we use right&left (the start of the right- and left-window sin()-regions) // to determine how much to return, rather than inferring from the rules // (same result, clearer code); 'left' indicates where our sin() window // starts, therefore where the previous window's right edge starts, and // therefore where to start mixing from the previous buffer. 'right' // indicates where our sin() ending-window starts, therefore that's where // we start saving, and where our returned-data ends. // mixin from previous window if (f->previous_length) { int i,j, n = f->previous_length; float *w = get_window(f, n); /* Sanity check */ if (w == NULL) { return -1; } for (i=0; i < f->channels; ++i) { for (j=0; j < n; ++j) f->channel_buffers[i][left+j] = f->channel_buffers[i][left+j]*w[ j] + f->previous_window[i][ j]*w[n-1-j]; } } prev = f->previous_length; // last half of this data becomes previous window f->previous_length = len - right; // @OPTIMIZE: could avoid this copy by double-buffering the // output (flipping previous_window with channel_buffers), but // then previous_window would have to be 2x as large, and // channel_buffers couldn't be temp mem (although they're NOT // currently temp mem, they could be (unless we want to level // performance by spreading out the computation)) for (i=0; i < f->channels; ++i) for (j=0; right+j < len; ++j) f->previous_window[i][j] = f->channel_buffers[i][right+j]; if (!prev) // there was no previous packet, so this data isn't valid... // this isn't entirely true, only the would-have-overlapped data // isn't valid, but this seems to be what the spec requires return 0; // truncate a short frame if (len < right) right = len; f->samples_output += right-left; return right - left; } static int vorbis_pump_first_frame(stb_vorbis *f) { int len, right, left; if (vorbis_decode_packet(f, &len, &left, &right)) { if (vorbis_finish_frame(f, len, left, right) < 0) return -1; } return 0; } #ifndef STB_VORBIS_NO_PUSHDATA_API static int is_whole_packet_present(stb_vorbis *f, int end_page) { // make sure that we have the packet available before continuing... // this requires a full ogg parse, but we know we can fetch from f->stream // instead of coding this out explicitly, we could save the current read state, // read the next packet with get8() until end-of-packet, check f->eof, then // reset the state? but that would be slower, esp. since we'd have over 256 bytes // of state to restore (primarily the page segment table) int s = f->next_seg, first = TRUE; uint8 *p = f->stream; if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag for (; s < f->segment_count; ++s) { p += f->segments[s]; if (f->segments[s] < 255) // stop at first short segment break; } // either this continues, or it ends it... if (end_page) if (s < f->segment_count-1) return error(f, VORBIS_invalid_stream); if (s == f->segment_count) s = -1; // set 'crosses page' flag if (p > f->stream_end) return error(f, VORBIS_need_more_data); first = FALSE; } for (; s == -1;) { uint8 *q; int n; // check that we have the page header ready if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data); // validate the page if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream); if (p[4] != 0) return error(f, VORBIS_invalid_stream); if (first) { // the first segment must NOT have 'continued_packet', later ones MUST if (f->previous_length) if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); // if no previous length, we're resynching, so we can come in on a continued-packet, // which we'll just drop } else { if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); } n = p[26]; // segment counts q = p+27; // q points to segment table p = q + n; // advance past header // make sure we've read the segment table if (p > f->stream_end) return error(f, VORBIS_need_more_data); for (s=0; s < n; ++s) { p += q[s]; if (q[s] < 255) break; } if (end_page) if (s < n-1) return error(f, VORBIS_invalid_stream); if (s == f->segment_count) s = -1; // set 'crosses page' flag if (p > f->stream_end) return error(f, VORBIS_need_more_data); first = FALSE; } return TRUE; } #endif // !STB_VORBIS_NO_PUSHDATA_API static int start_decoder(vorb *f) { uint8 header[6], x,y; int len,i,j,k, max_submaps = 0; int longest_floorlist=0; int val; // first page, first packet if (!start_page(f)) return FALSE; // validate page flag if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page); if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page); if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); // check for expected packet length if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); if (f->segments[0] != 30) return error(f, VORBIS_invalid_first_page); // read packet // check packet header if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof); if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page); // vorbis_version if (get32(f) != 0) return error(f, VORBIS_invalid_first_page); val = get8(f); if (val == 0) return error(f, VORBIS_invalid_first_page); if (val > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels); f->channels = val; f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page); get32(f); // bitrate_maximum get32(f); // bitrate_nominal get32(f); // bitrate_minimum x = get8(f); { int log0,log1; log0 = x & 15; log1 = x >> 4; f->blocksize_0 = 1 << log0; f->blocksize_1 = 1 << log1; if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); if (log0 > log1) return error(f, VORBIS_invalid_setup); } // framing_flag x = get8(f); if (!(x & 1)) return error(f, VORBIS_invalid_first_page); // second packet! if (!start_page(f)) return FALSE; if (!start_packet(f)) return FALSE; do { len = next_segment(f); skip(f, len); f->bytes_in_seg = 0; } while (len); // third packet! if (!start_packet(f)) return FALSE; #ifndef STB_VORBIS_NO_PUSHDATA_API if (IS_PUSH_MODE(f)) { if (!is_whole_packet_present(f, TRUE)) { // convert error in ogg header to write type if (f->error == VORBIS_invalid_stream) f->error = VORBIS_invalid_setup; return FALSE; } } #endif libxmp_crc32_init_A(); // always init it, to avoid multithread race conditions if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup); for (i=0; i < 6; ++i) header[i] = get8_packet(f); if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); // codebooks f->codebook_count = get_bits(f,8) + 1; f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); if (f->codebooks == NULL) return error(f, VORBIS_outofmem); memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count); for (i=0; i < f->codebook_count; ++i) { uint32 *values; int ordered, sorted_count; int total=0; uint8 *lengths; Codebook *c = f->codebooks+i; x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); x = get_bits(f, 8); c->dimensions = (get_bits(f, 8)<<8) + x; x = get_bits(f, 8); y = get_bits(f, 8); c->entries = (get_bits(f, 8)<<16) + (y<<8) + x; ordered = get_bits(f,1); c->sparse = ordered ? 0 : get_bits(f,1); if (c->sparse) lengths = (uint8 *) setup_temp_malloc(f, c->entries); else lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); if (!lengths) return error(f, VORBIS_outofmem); if (ordered) { int current_entry = 0; int current_length = get_bits(f,5) + 1; while (current_entry < c->entries) { int limit = c->entries - current_entry; int n = get_bits(f, ilog(limit)); if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } memset(lengths + current_entry, current_length, n); current_entry += n; ++current_length; } } else { for (j=0; j < c->entries; ++j) { int present = c->sparse ? get_bits(f,1) : 1; if (present) { lengths[j] = get_bits(f, 5) + 1; ++total; } else { lengths[j] = NO_CODE; } } } if (c->sparse && total >= c->entries >> 2) { // convert sparse items to non-sparse! if (c->entries > (int) f->setup_temp_memory_required) f->setup_temp_memory_required = c->entries; c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); memcpy(c->codeword_lengths, lengths, c->entries); setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! lengths = c->codeword_lengths; c->sparse = 0; } // compute the size of the sorted tables if (c->sparse) { sorted_count = total; //assert(total != 0); } else { sorted_count = 0; #ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH for (j=0; j < c->entries; ++j) if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE) ++sorted_count; #endif } c->sorted_entries = sorted_count; values = NULL; if (!c->sparse) { c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); if (!c->codewords) return error(f, VORBIS_outofmem); } else { unsigned int size; if (c->sorted_entries) { c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries); if (!c->codeword_lengths) return error(f, VORBIS_outofmem); c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); if (!c->codewords) return error(f, VORBIS_outofmem); values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); if (!values) return error(f, VORBIS_outofmem); } size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries; if (size > f->setup_temp_memory_required) f->setup_temp_memory_required = size; } if (!compute_codewords(c, lengths, c->entries, values)) { if (c->sparse) { setup_temp_free(f, values, 0); setup_temp_free(f, lengths, c->entries); } return error(f, VORBIS_invalid_setup); } if (c->sorted_entries) { // allocate an extra slot for sentinels c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); // allocate an extra slot at the front so that c->sorted_values[-1] is defined // so that we can catch that case without an extra if c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); if (c->sorted_values) { ++c->sorted_values; c->sorted_values[-1] = -1; } compute_sorted_huffman(c, lengths, values); } if (c->sparse) { setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); setup_temp_free(f, lengths, c->entries); c->codewords = NULL; } compute_accelerated_huffman(c); c->lookup_type = get_bits(f, 4); if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); if (c->lookup_type > 0) { uint16 *mults; c->minimum_value = float32_unpack(get_bits(f, 32)); c->delta_value = float32_unpack(get_bits(f, 32)); c->value_bits = get_bits(f, 4)+1; c->sequence_p = get_bits(f,1); if (c->lookup_type == 1) { c->lookup_values = lookup1_values(c->entries, c->dimensions); /* Sanity check */ if (c->lookup_values <= 0) { return FALSE; } } else { c->lookup_values = c->entries * c->dimensions; } mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); if (mults == NULL) return error(f, VORBIS_outofmem); for (j=0; j < (int) c->lookup_values; ++j) { int q = get_bits(f, c->value_bits); if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); } mults[j] = q; } #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK if (c->lookup_type == 1) { int len, sparse = c->sparse; // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop if (sparse) { if (c->sorted_entries == 0) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); goto skip; } c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); } else c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } len = sparse ? c->sorted_entries : c->entries; for (j=0; j < len; ++j) { int z = sparse ? c->sorted_values[j] : j, div=1; for (k=0; k < c->dimensions; ++k) { int off = (z / div) % c->lookup_values; c->multiplicands[j*c->dimensions + k] = #ifndef STB_VORBIS_CODEBOOK_FLOATS mults[off]; #else mults[off]*c->delta_value + c->minimum_value; // in this case (and this case only) we could pre-expand c->sequence_p, // and throw away the decode logic for it; have to ALSO do // it in the case below, but it can only be done if // STB_VORBIS_CODEBOOK_FLOATS // !STB_VORBIS_DIVIDES_IN_CODEBOOK #endif div *= c->lookup_values; /* Sanity check */ if (div == 0) { free(mults); return FALSE; } } } setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); c->lookup_type = 2; } else #endif { c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); #ifndef STB_VORBIS_CODEBOOK_FLOATS memcpy(c->multiplicands, mults, sizeof(c->multiplicands[0]) * c->lookup_values); #else for (j=0; j < (int) c->lookup_values; ++j) c->multiplicands[j] = mults[j] * c->delta_value + c->minimum_value; setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); #endif } skip:; #ifdef STB_VORBIS_CODEBOOK_FLOATS if (c->lookup_type == 2 && c->sequence_p) { /* Sanity check */ if (c->sparse) { if (c->lookup_values > c->sorted_entries * c->dimensions) { return FALSE; } } else { if (c->lookup_values > c->entries * c->dimensions) { return FALSE; } } for (j=1; j < (int) c->lookup_values; ++j) c->multiplicands[j] = c->multiplicands[j-1]; c->sequence_p = 0; } #endif } } // time domain transfers (notused) x = get_bits(f, 6) + 1; for (i=0; i < x; ++i) { uint32 z = get_bits(f, 16); if (z != 0) return error(f, VORBIS_invalid_setup); } // Floors f->floor_count = get_bits(f, 6)+1; f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); for (i=0; i < f->floor_count; ++i) { f->floor_types[i] = get_bits(f, 16); if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup); if (f->floor_types[i] == 0) { Floor0 *g = &f->floor_config[i].floor0; g->order = get_bits(f,8); g->rate = get_bits(f,16); g->bark_map_size = get_bits(f,16); g->amplitude_bits = get_bits(f,6); g->amplitude_offset = get_bits(f,8); g->number_of_books = get_bits(f,4) + 1; for (j=0; j < g->number_of_books; ++j) g->book_list[j] = get_bits(f,8); return error(f, VORBIS_feature_not_supported); } else { Point p[31*8+2]; Floor1 *g = &f->floor_config[i].floor1; int max_class = -1; g->partitions = get_bits(f, 5); for (j=0; j < g->partitions; ++j) { g->partition_class_list[j] = get_bits(f, 4); if (g->partition_class_list[j] > max_class) max_class = g->partition_class_list[j]; } for (j=0; j <= max_class; ++j) { g->class_dimensions[j] = get_bits(f, 3)+1; g->class_subclasses[j] = get_bits(f, 2); if (g->class_subclasses[j]) { g->class_masterbooks[j] = get_bits(f, 8); if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } for (k=0; k < 1 << g->class_subclasses[j]; ++k) { g->subclass_books[j][k] = get_bits(f,8)-1; if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } } g->floor1_multiplier = get_bits(f,2)+1; g->rangebits = get_bits(f,4); g->Xlist[0] = 0; g->Xlist[1] = 1 << g->rangebits; g->values = 2; for (j=0; j < g->partitions; ++j) { int c = g->partition_class_list[j]; for (k=0; k < g->class_dimensions[c]; ++k) { g->Xlist[g->values] = get_bits(f, g->rangebits); ++g->values; } } // precompute the sorting for (j=0; j < g->values; ++j) { p[j].x = g->Xlist[j]; p[j].y = j; } qsort(p, g->values, sizeof(p[0]), point_compare); for (j=0; j < g->values; ++j) g->sorted_order[j] = (uint8) p[j].y; // precompute the neighbors for (j=2; j < g->values; ++j) { int low=0,hi=0; neighbors(g->Xlist, j, &low,&hi); g->neighbors[j][0] = low; g->neighbors[j][1] = hi; } if (g->values > longest_floorlist) longest_floorlist = g->values; } } // Residue f->residue_count = get_bits(f, 6)+1; f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(*f->residue_config)); for (i=0; i < f->residue_count; ++i) { uint8 residue_cascade[64]; Residue *r = f->residue_config+i; f->residue_types[i] = get_bits(f, 16); if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); r->begin = get_bits(f, 24); r->end = get_bits(f, 24); /* Sanity check */ if (r->end - r->begin > 1024) { return FALSE; } r->part_size = get_bits(f,24)+1; r->classifications = get_bits(f,6)+1; r->classbook = get_bits(f,8); for (j=0; j < r->classifications; ++j) { uint8 high_bits=0; uint8 low_bits=get_bits(f,3); if (get_bits(f,1)) high_bits = get_bits(f,5); residue_cascade[j] = high_bits*8 + low_bits; } r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); for (j=0; j < r->classifications; ++j) { for (k=0; k < 8; ++k) { if (residue_cascade[j] & (1 << k)) { r->residue_books[j][k] = get_bits(f, 8); if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); } else { r->residue_books[j][k] = -1; } } } /* Sanity check */ if (r->classbook >= f->codebook_count) { return -1; } // precompute the classifications[] array to avoid inner-loop mod/divide // call it 'classdata' since we already have r->classifications r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); if (!r->classdata) return error(f, VORBIS_outofmem); memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); for (j=0; j < f->codebooks[r->classbook].entries; ++j) { int classwords = f->codebooks[r->classbook].dimensions; int temp = j; r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); for (k=classwords-1; k >= 0; --k) { r->classdata[j][k] = temp % r->classifications; temp /= r->classifications; } } } f->mapping_count = get_bits(f,6)+1; f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); for (i=0; i < f->mapping_count; ++i) { Mapping *m = f->mapping + i; int mapping_type = get_bits(f,16); if (mapping_type != 0) return error(f, VORBIS_invalid_setup); m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan)); if (get_bits(f,1)) m->submaps = get_bits(f,4); else m->submaps = 1; if (m->submaps > max_submaps) max_submaps = m->submaps; if (get_bits(f,1)) { m->coupling_steps = get_bits(f,8)+1; for (k=0; k < m->coupling_steps; ++k) { m->chan[k].magnitude = get_bits(f, ilog(f->channels)-1); m->chan[k].angle = get_bits(f, ilog(f->channels)-1); if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup); if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup); if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup); } } else m->coupling_steps = 0; // reserved field if (get_bits(f,2)) return error(f, VORBIS_invalid_setup); if (m->submaps > 1) { for (j=0; j < f->channels; ++j) { m->chan[j].mux = get_bits(f, 4); if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup); } } else // @SPECIFICATION: this case is missing from the spec for (j=0; j < f->channels; ++j) m->chan[j].mux = 0; for (j=0; j < m->submaps; ++j) { get_bits(f,8); // discard m->submap_floor[j] = get_bits(f,8); m->submap_residue[j] = get_bits(f,8); if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup); if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup); } } // Modes f->mode_count = get_bits(f, 6)+1; for (i=0; i < f->mode_count; ++i) { Mode *m = f->mode_config+i; m->blockflag = get_bits(f,1); m->windowtype = get_bits(f,16); m->transformtype = get_bits(f,16); m->mapping = get_bits(f,8); if (m->windowtype != 0) return error(f, VORBIS_invalid_setup); if (m->transformtype != 0) return error(f, VORBIS_invalid_setup); if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup); } flush_packet(f); f->previous_length = 0; for (i=0; i < f->channels; ++i) { f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1); f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); #ifdef STB_VORBIS_NO_DEFER_FLOOR f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); #endif } if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE; if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE; f->blocksize[0] = f->blocksize_0; f->blocksize[1] = f->blocksize_1; #ifdef STB_VORBIS_DIVIDE_TABLE if (integer_divide_table[1][1]==0) for (i=0; i < DIVTAB_NUMER; ++i) for (j=1; j < DIVTAB_DENOM; ++j) integer_divide_table[i][j] = i / j; #endif // compute how much temporary memory is needed // 1. { uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); uint32 classify_mem; int i,max_part_read=0; for (i=0; i < f->residue_count; ++i) { Residue *r = f->residue_config + i; int n_read = r->end - r->begin; int part_read = n_read / r->part_size; if (part_read > max_part_read) max_part_read = part_read; } #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *)); #else classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); #endif f->temp_memory_required = classify_mem; if (imdct_mem > f->temp_memory_required) f->temp_memory_required = imdct_mem; } f->first_decode = TRUE; #ifndef STB_VORBIS_NO_ALLOC_BUFFER if (f->alloc.alloc_buffer) { assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); // check if there's enough temp memory so we don't error later if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset) return error(f, VORBIS_outofmem); } #endif f->first_audio_page_offset = stb_vorbis_get_file_offset(f); return TRUE; } static void vorbis_deinit(stb_vorbis *p) { int i,j; for (i = 0; i < 2; i++) { setup_free(p, p->A[i]); setup_free(p, p->B[i]); setup_free(p, p->C[i]); setup_free(p, p->bit_reverse[i]); } for (i=0; i < p->residue_count; ++i) { Residue *r = p->residue_config+i; if (r->classdata) { for (j=0; j < p->codebooks[r->classbook].entries; ++j) setup_free(p, r->classdata[j]); setup_free(p, r->classdata); } setup_free(p, r->residue_books); } if (p->codebooks) { for (i=0; i < p->codebook_count; ++i) { Codebook *c = p->codebooks + i; setup_free(p, c->codeword_lengths); setup_free(p, c->multiplicands); setup_free(p, c->codewords); setup_free(p, c->sorted_codewords); // c->sorted_values[-1] is the first entry in the array setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); } setup_free(p, p->codebooks); } setup_free(p, p->floor_config); setup_free(p, p->residue_config); for (i=0; i < p->mapping_count; ++i) setup_free(p, p->mapping[i].chan); setup_free(p, p->mapping); for (i=0; i < p->channels; ++i) { setup_free(p, p->channel_buffers[i]); setup_free(p, p->previous_window[i]); #ifdef STB_VORBIS_NO_DEFER_FLOOR setup_free(p, p->floor_buffers[i]); #endif setup_free(p, p->finalY[i]); } for (i=0; i < 2; ++i) { setup_free(p, p->window[i]); } #ifndef STB_VORBIS_NO_STDIO if (p->close_on_free) fclose(p->f); #endif } void stb_vorbis_close(stb_vorbis *p) { if (p == NULL) return; vorbis_deinit(p); setup_free(p,p); } static void vorbis_init(stb_vorbis *p, stb_vorbis_alloc *z) { memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start if (z) { p->alloc = *z; p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3; p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; } p->eof = 0; p->error = VORBIS__no_error; p->stream = NULL; p->codebooks = NULL; p->page_crc_tests = -1; #ifndef STB_VORBIS_NO_STDIO p->close_on_free = FALSE; p->f = NULL; #endif } #if 0 int stb_vorbis_get_sample_offset(stb_vorbis *f) { if (f->current_loc_valid) return f->current_loc; else return -1; } stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) { stb_vorbis_info d; d.channels = f->channels; d.sample_rate = f->sample_rate; d.setup_memory_required = f->setup_memory_required; d.setup_temp_memory_required = f->setup_temp_memory_required; d.temp_memory_required = f->temp_memory_required; d.max_frame_size = f->blocksize_1 >> 1; return d; } int stb_vorbis_get_error(stb_vorbis *f) { int e = f->error; f->error = VORBIS__no_error; return e; } #endif static stb_vorbis * vorbis_alloc(stb_vorbis *f) { stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p)); return p; } #ifndef STB_VORBIS_NO_PUSHDATA_API void stb_vorbis_flush_pushdata(stb_vorbis *f) { f->previous_length = 0; f->page_crc_tests = 0; f->discard_samples_deferred = 0; f->current_loc_valid = FALSE; f->first_decode = FALSE; f->samples_output = 0; f->channel_buffer_start = 0; f->channel_buffer_end = 0; } static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) { int i,n; for (i=0; i < f->page_crc_tests; ++i) f->scan[i].bytes_done = 0; // if we have room for more scans, search for them first, because // they may cause us to stop early if their header is incomplete if (f->page_crc_tests < STB_VORBIS_PUSHDATA_CRC_COUNT) { if (data_len < 4) return 0; data_len -= 3; // need to look for 4-byte sequence, so don't miss // one that straddles a boundary for (i=0; i < data_len; ++i) { if (data[i] == 0x4f) { if (0==memcmp(data+i, ogg_page_header, 4)) { int j,len; uint32 crc; // make sure we have the whole page header if (i+26 >= data_len || i+27+data[i+26] >= data_len) { // only read up to this page start, so hopefully we'll // have the whole page header start next time data_len = i; break; } // ok, we have it all; compute the length of the page len = 27 + data[i+26]; for (j=0; j < data[i+26]; ++j) len += data[i+27+j]; // scan everything up to the embedded crc (which we must 0) crc = 0; for (j=0; j < 22; ++j) crc = libxmp_crc32_update(crc, data[i+j]); // now process 4 0-bytes for ( ; j < 26; ++j) crc = libxmp_crc32_update(crc, 0); // len is the total number of bytes we need to scan n = f->page_crc_tests++; f->scan[n].bytes_left = len-j; f->scan[n].crc_so_far = crc; f->scan[n].goal_crc = data[i+22] + (data[i+23] << 8) + (data[i+24]<<16) + (data[i+25]<<24); // if the last frame on a page is continued to the next, then // we can't recover the sample_loc immediately if (data[i+27+data[i+26]-1] == 255) f->scan[n].sample_loc = ~0; else f->scan[n].sample_loc = data[i+6] + (data[i+7] << 8) + (data[i+ 8]<<16) + (data[i+ 9]<<24); f->scan[n].bytes_done = i+j; if (f->page_crc_tests == STB_VORBIS_PUSHDATA_CRC_COUNT) break; // keep going if we still have room for more } } } } for (i=0; i < f->page_crc_tests;) { uint32 crc; int j; int n = f->scan[i].bytes_done; int m = f->scan[i].bytes_left; if (m > data_len - n) m = data_len - n; // m is the bytes to scan in the current chunk crc = f->scan[i].crc_so_far; for (j=0; j < m; ++j) crc = libxmp_crc32_update(crc, data[n+j]); f->scan[i].bytes_left -= m; f->scan[i].crc_so_far = crc; if (f->scan[i].bytes_left == 0) { // does it match? if (f->scan[i].crc_so_far == f->scan[i].goal_crc) { // Houston, we have page data_len = n+m; // consumption amount is wherever that scan ended f->page_crc_tests = -1; // drop out of page scan mode f->previous_length = 0; // decode-but-don't-output one frame f->next_seg = -1; // start a new page f->current_loc = f->scan[i].sample_loc; // set the current sample location // to the amount we'd have decoded had we decoded this page f->current_loc_valid = f->current_loc != ~0; return data_len; } // delete entry f->scan[i] = f->scan[--f->page_crc_tests]; } else { ++i; } } return data_len; } // return value: number of bytes we used int stb_vorbis_decode_frame_pushdata( stb_vorbis *f, // the file we're decoding uint8 *data, int data_len, // the memory available for decoding int *channels, // place to write number of float * buffers float ***output, // place to write float ** array of float * buffers int *samples // place to write number of output samples ) { int i; int len,right,left; if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); if (f->page_crc_tests >= 0) { *samples = 0; return vorbis_search_for_page_pushdata(f, data, data_len); } f->stream = data; f->stream_end = data + data_len; f->error = VORBIS__no_error; // check that we have the entire packet in memory if (!is_whole_packet_present(f, FALSE)) { *samples = 0; return 0; } if (!vorbis_decode_packet(f, &len, &left, &right)) { // save the actual error we encountered enum STBVorbisError error = f->error; if (error == VORBIS_bad_packet_type) { // flush and resynch f->error = VORBIS__no_error; while (get8_packet(f) != EOP) if (f->eof) break; *samples = 0; return f->stream - data; } if (error == VORBIS_continued_packet_flag_invalid) { if (f->previous_length == 0) { // we may be resynching, in which case it's ok to hit one // of these; just discard the packet f->error = VORBIS__no_error; while (get8_packet(f) != EOP) if (f->eof) break; *samples = 0; return f->stream - data; } } // if we get an error while parsing, what to do? // well, it DEFINITELY won't work to continue from where we are! stb_vorbis_flush_pushdata(f); // restore the error that actually made us bail f->error = error; *samples = 0; return 1; } // success! len = vorbis_finish_frame(f, len, left, right); /* Sanity check */ if (len < 0) { return -1; } for (i=0; i < f->channels; ++i) f->outputs[i] = f->channel_buffers[i] + left; if (channels) *channels = f->channels; *samples = len; *output = f->outputs; return f->stream - data; } stb_vorbis *stb_vorbis_open_pushdata( unsigned char *data, int data_len, // the memory available for decoding int *data_used, // only defined if result is not NULL int *error, stb_vorbis_alloc *alloc) { stb_vorbis *f, p; vorbis_init(&p, alloc); p.stream = data; p.stream_end = data + data_len; p.push_mode = TRUE; if (!start_decoder(&p)) { if (p.eof) *error = VORBIS_need_more_data; else *error = p.error; return NULL; } f = vorbis_alloc(&p); if (f) { *f = p; *data_used = f->stream - data; *error = 0; return f; } else { vorbis_deinit(&p); return NULL; } } #endif // STB_VORBIS_NO_PUSHDATA_API unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) { #ifndef STB_VORBIS_NO_PUSHDATA_API if (f->push_mode) return 0; #endif if (USE_MEMORY(f)) return f->stream - f->stream_start; #ifndef STB_VORBIS_NO_STDIO return ftell(f->f) - f->f_start; #endif } #ifndef STB_VORBIS_NO_PULLDATA_API // // DATA-PULLING API // #if 0 static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) { for(;;) { int n; if (f->eof) return 0; n = get8(f); if (n == 0x4f) { // page header unsigned int retry_loc = stb_vorbis_get_file_offset(f); int i; // check if we're off the end of a file_section stream if (retry_loc - 25 > f->stream_len) return 0; // check the rest of the header for (i=1; i < 4; ++i) if (get8(f) != ogg_page_header[i]) break; if (f->eof) return 0; if (i == 4) { uint8 header[27]; uint32 i, crc, goal, len; for (i=0; i < 4; ++i) header[i] = ogg_page_header[i]; for (; i < 27; ++i) header[i] = get8(f); if (f->eof) return 0; if (header[4] != 0) goto invalid; goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24); for (i=22; i < 26; ++i) header[i] = 0; crc = 0; for (i=0; i < 27; ++i) crc = libxmp_crc32_update(crc, header[i]); len = 0; for (i=0; i < header[26]; ++i) { int s = get8(f); crc = libxmp_crc32_update(crc, s); len += s; } if (len && f->eof) return 0; for (i=0; i < len; ++i) crc = libxmp_crc32_update(crc, get8(f)); // finished parsing probable page if (crc == goal) { // we could now check that it's either got the last // page flag set, OR it's followed by the capture // pattern, but I guess TECHNICALLY you could have // a file with garbage between each ogg page and recover // from it automatically? So even though that paranoia // might decrease the chance of an invalid decode by // another 2^32, not worth it since it would hose those // invalid-but-useful files? if (end) *end = stb_vorbis_get_file_offset(f); if (last) { if (header[5] & 0x04) *last = 1; else *last = 0; } set_file_offset(f, retry_loc-1); return 1; } } invalid: // not a valid page, so rewind and look for next one set_file_offset(f, retry_loc); } } } // seek is implemented with 'interpolation search'--this is like // binary search, but we use the data values to estimate the likely // location of the data item (plus a bit of a bias so when the // estimation is wrong we don't waste overly much time) #define SAMPLE_unknown 0xffffffff // ogg vorbis, in its insane infinite wisdom, only provides // information about the sample at the END of the page. // therefore we COULD have the data we need in the current // page, and not know it. we could just use the end location // as our only knowledge for bounds, seek back, and eventually // the binary search finds it. or we can try to be smart and // not waste time trying to locate more pages. we try to be // smart, since this data is already in memory anyway, so // doing needless I/O would be crazy! static int vorbis_analyze_page(stb_vorbis *f, ProbedPage *z) { uint8 header[27], lacing[255]; uint8 packet_type[255]; int num_packet, packet_start, previous =0; int i,len; uint32 samples; // record where the page starts z->page_start = stb_vorbis_get_file_offset(f); // parse the header getn(f, header, 27); assert(header[0] == 'O' && header[1] == 'g' && header[2] == 'g' && header[3] == 'S'); getn(f, lacing, header[26]); // determine the length of the payload len = 0; for (i=0; i < header[26]; ++i) len += lacing[i]; // this implies where the page ends z->page_end = z->page_start + 27 + header[26] + len; // read the last-decoded sample out of the data z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 16); if (header[5] & 4) { // if this is the last page, it's not possible to work // backwards to figure out the first sample! whoops! fuck. z->first_decoded_sample = SAMPLE_unknown; set_file_offset(f, z->page_start); return 1; } // scan through the frames to determine the sample-count of each one... // our goal is the sample # of the first fully-decoded sample on the // page, which is the first decoded sample of the 2nd page num_packet=0; packet_start = ((header[5] & 1) == 0); for (i=0; i < header[26]; ++i) { if (packet_start) { uint8 n,b,m; if (lacing[i] == 0) goto bail; // trying to read from zero-length packet n = get8(f); // if bottom bit is non-zero, we've got corruption if (n & 1) goto bail; n >>= 1; b = ilog(f->mode_count-1); m = n >> b; n &= (1 << b)-1; if (n >= f->mode_count) goto bail; if (num_packet == 0 && f->mode_config[n].blockflag) previous = (m & 1); packet_type[num_packet++] = f->mode_config[n].blockflag; skip(f, lacing[i]-1); } else skip(f, lacing[i]); packet_start = (lacing[i] < 255); } // now that we know the sizes of all the pages, we can start determining // how much sample data there is. samples = 0; // for the last packet, we step by its whole length, because the definition // is that we encoded the end sample loc of the 'last packet completed', // where 'completed' refers to packets being split, and we are left to guess // what 'end sample loc' means. we assume it means ignoring the fact that // the last half of the data is useless without windowing against the next // packet... (so it's not REALLY complete in that sense) if (num_packet > 1) samples += f->blocksize[packet_type[num_packet-1]]; for (i=num_packet-2; i >= 1; --i) { // now, for this packet, how many samples do we have that // do not overlap the following packet? if (packet_type[i] == 1) if (packet_type[i+1] == 1) samples += f->blocksize_1 >> 1; else samples += ((f->blocksize_1 - f->blocksize_0) >> 2) + (f->blocksize_0 >> 1); else samples += f->blocksize_0 >> 1; } // now, at this point, we've rewound to the very beginning of the // _second_ packet. if we entirely discard the first packet after // a seek, this will be exactly the right sample number. HOWEVER! // we can't as easily compute this number for the LAST page. The // only way to get the sample offset of the LAST page is to use // the end loc from the previous page. But what that returns us // is _exactly_ the place where we get our first non-overlapped // sample. (I think. Stupid spec for being ambiguous.) So for // consistency it's better to do that here, too. However, that // will then require us to NOT discard all of the first frame we // decode, in some cases, which means an even weirder frame size // and extra code. what a fucking pain. // we're going to discard the first packet if we // start the seek here, so we don't care about it. (we could actually // do better; if the first packet is long, and the previous packet // is short, there's actually data in the first half of the first // packet that doesn't need discarding... but not worth paying the // effort of tracking that of that here and in the seeking logic) // except crap, if we infer it from the _previous_ packet's end // location, we DO need to use that definition... and we HAVE to // infer the start loc of the LAST packet from the previous packet's // end location. fuck you, ogg vorbis. z->first_decoded_sample = z->last_decoded_sample - samples; // restore file state to where we were set_file_offset(f, z->page_start); return 1; // restore file state to where we were bail: set_file_offset(f, z->page_start); return 0; } static int vorbis_seek_frame_from_page(stb_vorbis *f, uint32 page_start, uint32 first_sample, uint32 target_sample, int fine) { int left_start, left_end, right_start, right_end, mode,i; int frame=0; uint32 frame_start; int frames_to_skip, data_to_skip; // first_sample is the sample # of the first sample that doesn't // overlap the previous page... note that this requires us to // _partially_ discard the first packet! bleh. set_file_offset(f, page_start); f->next_seg = -1; // force page resync frame_start = first_sample; // frame start is where the previous packet's last decoded sample // was, which corresponds to left_end... EXCEPT if the previous // packet was long and this packet is short? Probably a bug here. // now, we can start decoding frames... we'll only FAKE decode them, // until we find the frame that contains our sample; then we'll rewind, // and try again for (;;) { int start; if (!vorbis_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) return error(f, VORBIS_seek_failed); if (frame == 0) start = left_end; else start = left_start; // the window starts at left_start; the last valid sample we generate // before the next frame's window start is right_start-1 if (target_sample < frame_start + right_start-start) break; flush_packet(f); if (f->eof) return error(f, VORBIS_seek_failed); frame_start += right_start - start; ++frame; } // ok, at this point, the sample we want is contained in frame #'frame' // to decode frame #'frame' normally, we have to decode the // previous frame first... but if it's the FIRST frame of the page // we can't. if it's the first frame, it means it falls in the part // of the first frame that doesn't overlap either of the other frames. // so, if we have to handle that case for the first frame, we might // as well handle it for all of them, so: if (target_sample > frame_start + (left_end - left_start)) { // so what we want to do is go ahead and just immediately decode // this frame, but then make it so the next get_frame_float() uses // this already-decoded data? or do we want to go ahead and rewind, // and leave a flag saying to skip the first N data? let's do that frames_to_skip = frame; // if this is frame #1, skip 1 frame (#0) data_to_skip = left_end - left_start; } else { // otherwise, we want to skip frames 0, 1, 2, ... frame-2 // (which means frame-2+1 total frames) then decode frame-1, // then leave frame pending frames_to_skip = frame - 1; assert(frames_to_skip >= 0); data_to_skip = -1; } set_file_offset(f, page_start); f->next_seg = - 1; // force page resync for (i=0; i < frames_to_skip; ++i) { maybe_start_packet(f); flush_packet(f); } if (data_to_skip >= 0) { int i,j,n = f->blocksize_0 >> 1; f->discard_samples_deferred = data_to_skip; for (i=0; i < f->channels; ++i) for (j=0; j < n; ++j) f->previous_window[i][j] = 0; f->previous_length = n; frame_start += data_to_skip; } else { f->previous_length = 0; if (vorbis_pump_first_frame(f) < 0) return -1; } // at this point, the NEXT decoded frame will generate the desired sample if (fine) { // so if we're doing sample accurate streaming, we want to go ahead and decode it! if (target_sample != frame_start) { int n; stb_vorbis_get_frame_float(f, &n, NULL); assert(target_sample > frame_start); assert(f->channel_buffer_start + (int) (target_sample-frame_start) < f->channel_buffer_end); f->channel_buffer_start += (target_sample - frame_start); } } return 0; } static int vorbis_seek_base(stb_vorbis *f, unsigned int sample_number, int fine) { ProbedPage p[2],q; if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); // do we know the location of the last page? if (f->p_last.page_start == 0) { uint32 z = stb_vorbis_stream_length_in_samples(f); if (z == 0) return error(f, VORBIS_cant_find_last_page); } p[0] = f->p_first; p[1] = f->p_last; if (sample_number >= f->p_last.last_decoded_sample) sample_number = f->p_last.last_decoded_sample-1; if (sample_number < f->p_first.last_decoded_sample) { if (vorbis_seek_frame_from_page(f, p[0].page_start, 0, sample_number, fine) < 0) return -1; return 0; } else { int attempts=0; while (p[0].page_end < p[1].page_start) { uint32 probe; uint32 start_offset, end_offset; uint32 start_sample, end_sample; // copy these into local variables so we can tweak them // if any are unknown start_offset = p[0].page_end; end_offset = p[1].after_previous_page_start; // an address known to seek to page p[1] start_sample = p[0].last_decoded_sample; end_sample = p[1].last_decoded_sample; // currently there is no such tweaking logic needed/possible? if (start_sample == SAMPLE_unknown || end_sample == SAMPLE_unknown) return error(f, VORBIS_seek_failed); // now we want to lerp between these for the target samples... // step 1: we need to bias towards the page start... if (start_offset + 4000 < end_offset) end_offset -= 4000; // now compute an interpolated search loc probe = start_offset + (int) floor((float) (end_offset - start_offset) / (end_sample - start_sample) * (sample_number - start_sample)); // next we need to bias towards binary search... // code is a little wonky to allow for full 32-bit unsigned values if (attempts >= 4) { uint32 probe2 = start_offset + ((end_offset - start_offset) >> 1); if (attempts >= 8) probe = probe2; else if (probe < probe2) probe = probe + ((probe2 - probe) >> 1); else probe = probe2 + ((probe - probe2) >> 1); } ++attempts; set_file_offset(f, probe); if (!vorbis_find_page(f, NULL, NULL)) return error(f, VORBIS_seek_failed); if (!vorbis_analyze_page(f, &q)) return error(f, VORBIS_seek_failed); q.after_previous_page_start = probe; // it's possible we've just found the last page again if (q.page_start == p[1].page_start) { p[1] = q; continue; } if (sample_number < q.last_decoded_sample) p[1] = q; else p[0] = q; } if (p[0].last_decoded_sample <= sample_number && sample_number < p[1].last_decoded_sample) { if (vorbis_seek_frame_from_page(f, p[1].page_start, p[0].last_decoded_sample, sample_number, fine) < 0) return -1; return 0; } return error(f, VORBIS_seek_failed); } } #endif #if 0 int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) { return vorbis_seek_base(f, sample_number, FALSE); } int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) { return vorbis_seek_base(f, sample_number, TRUE); } void stb_vorbis_seek_start(stb_vorbis *f) { if (IS_PUSH_MODE(f)) { error(f, VORBIS_invalid_api_mixing); return; } set_file_offset(f, f->first_audio_page_offset); f->previous_length = 0; f->first_decode = TRUE; f->next_seg = -1; vorbis_pump_first_frame(f); } unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) { unsigned int restore_offset, previous_safe; unsigned int end, last_page_loc; if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); if (!f->total_samples) { int last; uint32 lo,hi; char header[6]; // first, store the current decode position so we can restore it restore_offset = stb_vorbis_get_file_offset(f); // now we want to seek back 64K from the end (the last page must // be at most a little less than 64K, but let's allow a little slop) if (f->stream_len >= 65536 && f->stream_len-65536 >= f->first_audio_page_offset) previous_safe = f->stream_len - 65536; else previous_safe = f->first_audio_page_offset; set_file_offset(f, previous_safe); // previous_safe is now our candidate 'earliest known place that seeking // to will lead to the final page' if (!vorbis_find_page(f, &end, (int unsigned *)&last)) { // if we can't find a page, we're hosed! f->error = VORBIS_cant_find_last_page; f->total_samples = 0xffffffff; goto done; } // check if there are more pages last_page_loc = stb_vorbis_get_file_offset(f); // stop when the last_page flag is set, not when we reach eof; // this allows us to stop short of a 'file_section' end without // explicitly checking the length of the section while (!last) { set_file_offset(f, end); if (!vorbis_find_page(f, &end, (int unsigned *)&last)) { // the last page we found didn't have the 'last page' flag // set. whoops! break; } previous_safe = last_page_loc+1; last_page_loc = stb_vorbis_get_file_offset(f); } set_file_offset(f, last_page_loc); // parse the header getn(f, (unsigned char *)header, 6); // extract the absolute granule position lo = get32(f); hi = get32(f); if (lo == 0xffffffff && hi == 0xffffffff) { f->error = VORBIS_cant_find_last_page; f->total_samples = SAMPLE_unknown; goto done; } if (hi) lo = 0xfffffffe; // saturate f->total_samples = lo; f->p_last.page_start = last_page_loc; f->p_last.page_end = end; f->p_last.last_decoded_sample = lo; f->p_last.first_decoded_sample = SAMPLE_unknown; f->p_last.after_previous_page_start = previous_safe; done: set_file_offset(f, restore_offset); } return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples; } float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) { return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate; } #endif int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) { int len, right,left,i; if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); if (!vorbis_decode_packet(f, &len, &left, &right)) { f->channel_buffer_start = f->channel_buffer_end = 0; return 0; } /* Sanity check */ if (len > f->blocksize_1) { return -1; } len = vorbis_finish_frame(f, len, left, right); /* Sanity check */ if (len < 0) { return -1; } for (i=0; i < f->channels; ++i) f->outputs[i] = f->channel_buffers[i] + left; f->channel_buffer_start = left; f->channel_buffer_end = left+len; if (channels) *channels = f->channels; if (output) *output = f->outputs; return len; } #ifndef STB_VORBIS_NO_STDIO stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc, unsigned int length) { stb_vorbis *f, p; vorbis_init(&p, alloc); p.f = file; p.f_start = ftell(file); p.stream_len = length; p.close_on_free = close_on_free; if (start_decoder(&p)) { f = vorbis_alloc(&p); if (f) { *f = p; if (vorbis_pump_first_frame(f) < 0) return NULL; return f; } } if (error) *error = p.error; vorbis_deinit(&p); return NULL; } #if 0 stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, stb_vorbis_alloc *alloc) { unsigned int len, start; start = ftell(file); fseek(file, 0, SEEK_END); len = ftell(file) - start; fseek(file, start, SEEK_SET); return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); } stb_vorbis * stb_vorbis_open_filename(char *filename, int *error, stb_vorbis_alloc *alloc) { FILE *f = fopen(filename, "rb"); if (f) return stb_vorbis_open_file(f, TRUE, error, alloc); if (error) *error = VORBIS_file_open_failure; return NULL; } #endif #endif // STB_VORBIS_NO_STDIO stb_vorbis * stb_vorbis_open_memory(unsigned char *data, int len, int *error, stb_vorbis_alloc *alloc) { stb_vorbis *f, p; if (data == NULL) return NULL; vorbis_init(&p, alloc); p.stream = data; p.stream_end = data + len; p.stream_start = p.stream; p.stream_len = len; p.push_mode = FALSE; if (start_decoder(&p)) { f = vorbis_alloc(&p); if (f) { *f = p; if (vorbis_pump_first_frame(f) < 0) return NULL; return f; } } if (error) *error = p.error; vorbis_deinit(&p); return NULL; } #ifndef STB_VORBIS_NO_INTEGER_CONVERSION #define PLAYBACK_MONO 1 #define PLAYBACK_LEFT 2 #define PLAYBACK_RIGHT 4 #if 0 #define L (PLAYBACK_LEFT | PLAYBACK_MONO) #define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO) #define R (PLAYBACK_RIGHT | PLAYBACK_MONO) static int8 channel_position[7][6] = { { 0 }, { C }, { L, R }, { L, C, R }, { L, R, L, R }, { L, C, R, L, R }, { L, C, R, L, R, C }, }; #endif #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT typedef union { float f; int i; } float_conv; typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4]; #define FASTDEF(x) float_conv x // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s)) #define check_endianness() #else #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) #define check_endianness() #define FASTDEF(x) #endif static void copy_samples(short *dest, float *src, int len) { int i; check_endianness(); for (i=0; i < len; ++i) { FASTDEF(temp); int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; dest[i] = v; } } #if STB_VORBIS_MAX_CHANNELS > 1 static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) { #define BUFFER_SIZE 32 float buffer[BUFFER_SIZE]; int i,j,o,n = BUFFER_SIZE; check_endianness(); for (o = 0; o < len; o += BUFFER_SIZE) { memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { if (channel_position[num_c][j] & mask) { for (i=0; i < n; ++i) buffer[i] += data[j][d_offset+o+i]; } } for (i=0; i < n; ++i) { FASTDEF(temp); int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; output[o+i] = v; } } } #endif #if STB_VORBIS_MAX_CHANNELS > 1 //static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} }; static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) { #define BUFFER_SIZE 32 float buffer[BUFFER_SIZE]; int i,j,o,n = BUFFER_SIZE >> 1; // o is the offset in the source data check_endianness(); for (o = 0; o < len; o += BUFFER_SIZE >> 1) { // o2 is the offset in the output data int o2 = o << 1; memset(buffer, 0, sizeof(buffer)); if (o + n > len) n = len - o; for (j=0; j < num_c; ++j) { int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT); if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) { for (i=0; i < n; ++i) { buffer[i*2+0] += data[j][d_offset+o+i]; buffer[i*2+1] += data[j][d_offset+o+i]; } } else if (m == PLAYBACK_LEFT) { for (i=0; i < n; ++i) { buffer[i*2+0] += data[j][d_offset+o+i]; } } else if (m == PLAYBACK_RIGHT) { for (i=0; i < n; ++i) { buffer[i*2+1] += data[j][d_offset+o+i]; } } } for (i=0; i < (n<<1); ++i) { FASTDEF(temp); int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; output[o2+i] = v; } } } #endif static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) { int i; #if STB_VORBIS_MAX_CHANNELS > 1 if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} }; for (i=0; i < buf_c; ++i) compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); } else #endif { int limit = buf_c < data_c ? buf_c : data_c; for (i=0; i < limit; ++i) copy_samples(buffer[i]+b_offset, data[i], samples); for ( ; i < buf_c; ++i) memset(buffer[i]+b_offset, 0, sizeof(short) * samples); } } int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) { float **output; int len = stb_vorbis_get_frame_float(f, NULL, &output); /* Sanity check */ if (len < 0) return -1; if (len > num_samples) len = num_samples; if (len) convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); return len; } #if STB_VORBIS_MAX_CHANNELS > 1 static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) { int i; check_endianness(); if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { assert(buf_c == 2); for (i=0; i < buf_c; ++i) compute_stereo_samples(buffer, data_c, data, d_offset, len); } else { int limit = buf_c < data_c ? buf_c : data_c; int j; for (j=0; j < len; ++j) { for (i=0; i < limit; ++i) { FASTDEF(temp); float f = data[i][d_offset+j]; int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); if ((unsigned int) (v + 32768) > 65535) v = v < 0 ? -32768 : 32767; *buffer++ = v; } for ( ; i < buf_c; ++i) *buffer++ = 0; } } } #endif int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) { #if STB_VORBIS_MAX_CHANNELS > 1 float **output; int len; #endif if (num_c == 1) return stb_vorbis_get_frame_short(f,num_c,&buffer, num_shorts); #if STB_VORBIS_MAX_CHANNELS > 1 len = stb_vorbis_get_frame_float(f, NULL, &output); if (len) { if (len*num_c > num_shorts) len = num_shorts / num_c; convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); } return len; #else return 0; #endif } #if 0 int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) { float **outputs; int len = num_shorts / channels; int n=0; int z = f->channels; if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; if (k) convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); buffer += k*channels; n += k; f->channel_buffer_start += k; if (n == len) break; if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; } return n; } #endif #if 0 int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) { float **outputs; int n=0; int z = f->channels; if (z > channels) z = channels; while (n < len) { int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; if (k) convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); n += k; f->channel_buffer_start += k; if (n == len) break; if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; } return n; } #endif #ifndef STB_VORBIS_NO_STDIO int stb_vorbis_decode_filename(char *filename, int *channels, short **output) { int data_len, offset, total, limit, error; short *data; stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL); if (v == NULL) return -1; limit = v->channels * 4096; *channels = v->channels; offset = data_len = 0; total = limit; data = (short *) malloc(total * sizeof(*data)); if (data == NULL) { stb_vorbis_close(v); return -2; } for (;;) { int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset); if (n == 0) break; data_len += n; offset += n * v->channels; if (offset + limit > total) { short *data2; total *= 2; data2 = (short *) realloc(data, total * sizeof(*data)); if (data2 == NULL) { free(data); stb_vorbis_close(v); return -2; } data = data2; } } *output = data; return data_len; } #endif // NO_STDIO int stb_vorbis_decode_memory(uint8 *mem, int len, int *channels, short **output) { int data_len, offset, total, limit, error; short *data; stb_vorbis *v; D_(D_INFO "vorbis_decode_memory (len=%d)", len); v = stb_vorbis_open_memory(mem, len, &error, NULL); if (v == NULL) return -1; limit = v->channels * 4096; *channels = v->channels; offset = data_len = 0; total = limit; D_(D_INFO "total=%d\n", total); data = (short *) malloc(total * sizeof(*data)); if (data == NULL) { stb_vorbis_close(v); return -2; } for (;;) { int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset); if (n == 0) break; data_len += n; offset += n * v->channels; D_(D_INFO "offset=%d, limit=%d, total=%d", offset, limit, total); if (offset + limit > total) { short *data2; total *= 2; data2 = (short *) realloc(data, total * sizeof(*data)); if (data2 == NULL) { free(data); stb_vorbis_close(v); return -2; } data = data2; } } stb_vorbis_close(v); *output = data; return data_len; } #endif #if 0 int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) { float **outputs; int len = num_floats / channels; int n=0; int z = f->channels; if (z > channels) z = channels; while (n < len) { int i,j; int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= len) k = len - n; for (j=0; j < k; ++j) { for (i=0; i < z; ++i) *buffer++ = f->channel_buffers[i][f->channel_buffer_start+j]; for ( ; i < channels; ++i) *buffer++ = 0; } n += k; f->channel_buffer_start += k; if (n == len) break; if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; } return n; } int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) { float **outputs; int n=0; int z = f->channels; if (z > channels) z = channels; while (n < num_samples) { int i; int k = f->channel_buffer_end - f->channel_buffer_start; if (n+k >= num_samples) k = num_samples - n; if (k) { for (i=0; i < z; ++i) memcpy(buffer[i]+n, f->channel_buffers+f->channel_buffer_start, sizeof(float)*k); for ( ; i < channels; ++i) memset(buffer[i]+n, 0, sizeof(float) * k); } n += k; f->channel_buffer_start += k; if (n == num_samples) break; if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; } return n; } #endif #endif // STB_VORBIS_NO_PULLDATA_API #endif // STB_VORBIS_HEADER_ONLY libxmp-4.4.1/src/depackers/xz_private.h0000664000175000017500000001067312641457214017750 0ustar claudioclaudio/* * Private includes and definitions * * Author: Lasse Collin * * This file has been put into the public domain. * You can do whatever you want with this file. */ #ifndef XZ_PRIVATE_H #define XZ_PRIVATE_H #ifdef __KERNEL__ # include # include # include /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ # ifndef XZ_PREBOOT # include # include # include # ifdef CONFIG_XZ_DEC_X86 # define XZ_DEC_X86 # endif # ifdef CONFIG_XZ_DEC_POWERPC # define XZ_DEC_POWERPC # endif # ifdef CONFIG_XZ_DEC_IA64 # define XZ_DEC_IA64 # endif # ifdef CONFIG_XZ_DEC_ARM # define XZ_DEC_ARM # endif # ifdef CONFIG_XZ_DEC_ARMTHUMB # define XZ_DEC_ARMTHUMB # endif # ifdef CONFIG_XZ_DEC_SPARC # define XZ_DEC_SPARC # endif # define memeq(a, b, size) (memcmp(a, b, size) == 0) # define memzero(buf, size) memset(buf, 0, size) # endif # define get_le32(p) le32_to_cpup((const uint32 *)(p)) #else /* * For userspace builds, use a separate header to define the required * macros and functions. This makes it easier to adapt the code into * different environments and avoids clutter in the Linux kernel tree. */ # include "xz_config.h" #endif /* If no specific decoding mode is requested, enable support for all modes. */ #if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ && !defined(XZ_DEC_DYNALLOC) # define XZ_DEC_SINGLE # define XZ_DEC_PREALLOC # define XZ_DEC_DYNALLOC #endif /* * The DEC_IS_foo(mode) macros are used in "if" statements. If only some * of the supported modes are enabled, these macros will evaluate to true or * false at compile time and thus allow the compiler to omit unneeded code. */ #ifdef XZ_DEC_SINGLE # define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) #else # define DEC_IS_SINGLE(mode) (false) #endif #ifdef XZ_DEC_PREALLOC # define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) #else # define DEC_IS_PREALLOC(mode) (false) #endif #ifdef XZ_DEC_DYNALLOC # define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) #else # define DEC_IS_DYNALLOC(mode) (false) #endif #if !defined(XZ_DEC_SINGLE) # define DEC_IS_MULTI(mode) (true) #elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) # define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) #else # define DEC_IS_MULTI(mode) (false) #endif /* * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. */ #ifndef XZ_DEC_BCJ # if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ || defined(XZ_DEC_SPARC) # define XZ_DEC_BCJ # endif #endif /* * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used * before calling xz_dec_lzma2_run(). */ XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, uint32 dict_max); /* * Decode the LZMA2 properties (one byte) and reset the decoder. Return * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not * big enough, and XZ_OPTIONS_ERROR if props indicates something that this * decoder doesn't support. */ XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8 props); /* Decode raw LZMA2 stream from b->in to b->out. */ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b); /* Free the memory allocated for the LZMA2 decoder. */ XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s); #ifdef XZ_DEC_BCJ /* * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before * calling xz_dec_bcj_run(). */ XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call); /* * Decode the Filter ID of a BCJ filter. This implementation doesn't * support custom start offsets, so no decoding of Filter Properties * is needed. Returns XZ_OK if the given Filter ID is supported. * Otherwise XZ_OPTIONS_ERROR is returned. */ XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8 id); /* * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() * must be called directly. */ XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, struct xz_dec_lzma2 *lzma2, struct xz_buf *b); /* Free the memory allocated for the BCJ filters. */ #define xz_dec_bcj_end(s) kfree(s) #endif #endif libxmp-4.4.1/src/depackers/inflate.h0000664000175000017500000000027212773453116017174 0ustar claudioclaudio#ifndef LIBXMP_INFLATE_H #define LIBXMP_INFLATE_H struct inflate_data { struct huffman_tree_t *huffman_tree_len_static; }; int libxmp_inflate (FILE *, FILE *, uint32 *, int); #endif libxmp-4.4.1/src/depackers/oxm.c0000664000175000017500000001435712774567167016376 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "vorbis.h" #include "common.h" #include "depacker.h" #define MAGIC_OGGS 0x4f676753 struct xm_instrument { uint32 len; uint8 buf[36]; }; int test_oxm(FILE *f) { int i, j; int hlen, npat, len, plen; int nins, nsmp; uint32 ilen; int slen[256]; uint8 buf[1024]; int error; if (fseek(f, 0, SEEK_SET) < 0) { return -1; } if (fread(buf, 1, 80, f) != 80) { return -1; } hlen = readmem32l(buf + 60); npat = readmem16l(buf + 70); nins = readmem16l(buf + 72); if (memcmp(buf, "Extended Module:", 16)) { return -1; } if (npat > 256 || nins > 128) { return -1; } if (fseek(f, 60 + hlen, SEEK_SET) < 0) { return -1; } for (i = 0; i < npat; i++) { if (fread(buf, 1, 9, f) != 9) { return -1; } len = readmem32l(buf); plen = readmem16l(buf + 7); if (fseek(f, len - 9 + plen, SEEK_CUR) < 0) { return -1; } } for (i = 0; i < nins; i++) { ilen = read32l(f, &error); if (error != 0) return -1; if (ilen > 263) { return -1; } if (fseek(f, -4, SEEK_CUR) < 0) { return -1; } if (fread(buf, 1, ilen, f) != ilen) { /* instrument header */ return -1; } nsmp = readmem16l(buf + 27); if (nsmp > 255) return -1; if (nsmp == 0) continue; /* Read instrument data */ for (j = 0; j < nsmp; j++) { slen[j] = read32l(f, &error); if (error != 0) { return -1; } if (fseek(f, 36, SEEK_CUR) < 0) { return -1; } } /* Read samples */ for (j = 0; j < nsmp; j++) { read32b(f, NULL); if (read32b(f, NULL) == MAGIC_OGGS) return 0; if (fseek(f, slen[j] - 8, SEEK_CUR) < 0) return -1; } } return -1; } static char *oggdec(FILE *f, int len, int res, int *newlen) { int i, n, ch; /*int size;*/ uint8 *data, *pcm; int16 *pcm16 = NULL; uint32 id; int error; /* Sanity check */ if (len < 4) { return NULL; } /*size =*/ read32l(f, &error); if (error != 0) return NULL; id = read32b(f, &error); if (error != 0 || fseek(f, -8, SEEK_CUR) < 0) return NULL; if ((data = calloc(1, len)) == NULL) return NULL; read32b(f, &error); if (error != 0 || fread(data, 1, len - 4, f) != len - 4) { free(data); return NULL; } if (id != MAGIC_OGGS) { /* copy input data if not Ogg file */ *newlen = len; return (char *)data; } n = stb_vorbis_decode_memory(data, len, &ch, &pcm16); free(data); if (n <= 0) { free(pcm16); return NULL; } pcm = (uint8 *)pcm16; if (res == 8) { for (i = 0; i < n; i++) { pcm[i] = pcm16[i] >> 8; } pcm = realloc(pcm16, n); if (pcm == NULL) { free(pcm16); return NULL; } pcm16 = (int16 *)pcm; } /* Convert to delta */ if (res == 8) { for (i = n - 1; i > 0; i--) pcm[i] -= pcm[i - 1]; *newlen = n; } else { for (i = n - 1; i > 0; i--) pcm16[i] -= pcm16[i - 1]; *newlen = n * 2; } return (char *)pcm; } static int decrunch_oxm(FILE *f, FILE *fo) { int i, j, pos; int hlen, npat, len, plen; int nins, nsmp, size; uint32 ilen; uint8 buf[1024]; struct xm_instrument xi[256]; char *pcm[256]; int newlen = 0; if (fread(buf, 1, 80, f) != 80) { return -1; } hlen = readmem32l(buf + 60); npat = readmem16l(buf + 70); nins = readmem16l(buf + 72); if (npat > 256 || nins > 128) { return -1; } if (fseek(f, 60 + hlen, SEEK_SET) < 0) { return -1; } for (i = 0; i < npat; i++) { if (fread(buf, 1, 9, f) != 9) { return -1; } len = readmem32l(buf); plen = readmem16l(buf + 7); if (fseek(f, len - 9 + plen, SEEK_CUR) < 0) { return -1; } } pos = ftell(f); if (pos < 0) { return -1; } if (fseek(f, 0, SEEK_SET) < 0) { return -1; } move_data(fo, f, pos); /* module header + patterns */ for (i = 0; i < nins; i++) { ilen = read32l(f, NULL); if (ilen > 1024) { D_(D_CRIT "ilen=%d\n", ilen); return -1; } if (fseek(f, -4, SEEK_CUR) < 0) { return -1; } if (fread(buf, ilen, 1, f) != 1) { /* instrument header */ return -1; } buf[26] = 0; fwrite(buf, ilen, 1, fo); nsmp = readmem16l(buf + 27); size = readmem32l(buf + 29); if (nsmp == 0) { continue; } /* Sanity check */ if (nsmp > 0x10 || (nsmp > 0 && size > 0x100)) { D_(D_CRIT "Sanity check: nsmp=%d size=%d", nsmp, size); return -1; } /* Read sample headers */ for (j = 0; j < nsmp; j++) { xi[j].len = read32l(f, NULL); if (xi[j].len > MAX_SAMPLE_SIZE) { D_(D_CRIT "sample %d len = %d", j, xi[j].len); return -1; } if (fread(xi[j].buf, 1, 36, f) != 36) { return -1; } } /* Read samples */ for (j = 0; j < nsmp; j++) { D_(D_INFO "sample=%d len=%d\n", j, xi[j].len); if (xi[j].len > 0) { int res = 8; if (xi[j].buf[10] & 0x10) res = 16; pcm[j] = oggdec(f, xi[j].len, res, &newlen); xi[j].len = newlen; if (pcm[j] == NULL) { return -1; } } } /* Write sample headers */ for (j = 0; j < nsmp; j++) { write32l(fo, xi[j].len); fwrite(xi[j].buf, 1, 36, fo); } /* Write samples */ for (j = 0; j < nsmp; j++) { if (xi[j].len > 0) { fwrite(pcm[j], 1, xi[j].len, fo); free(pcm[j]); } } } return 0; } struct depacker libxmp_depacker_oxm = { NULL, decrunch_oxm }; libxmp-4.4.1/src/depackers/arcfs.c0000664000175000017500000001107412774567167016662 0ustar claudioclaudio/* ArcFS depacker for xmp * Copyright (C) 2007 Claudio Matsuoka * * Based on the nomarch .arc depacker from nomarch * Copyright (C) 2001-2006 Russell Marks * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU Lesser General Public License. See COPYING.LIB * for more information. */ #include #include #include #include #include #include #include #include "common.h" #include "depacker.h" #include "readrle.h" #include "readhuff.h" #include "readlzw.h" struct archived_file_header_tag { unsigned char method; unsigned char bits; char name[13]; unsigned long compressed_size; unsigned int date, time, crc; unsigned long orig_size; unsigned long offset; }; static int read_file_header(FILE *in, struct archived_file_header_tag *hdrp) { int hlen, start /*, ver*/; int i; int error; if (fseek(in, 8, SEEK_CUR) < 0) /* skip magic */ return -1; hlen = read32l(in, &error) / 36; if (error != 0) return -1; start = read32l(in, &error); if (error != 0) return -1; /*ver =*/ read32l(in, &error); if (error != 0) return -1; read32l(in, &error); if (error != 0) return -1; /*ver =*/ read32l(in, &error); if (error != 0) return -1; if (fseek(in, 68, SEEK_CUR) < 0) /* reserved */ return -1; for (i = 0; i < hlen; i++) { int x = read8(in, &error); if (error != 0) return -1; if (x == 0) /* end? */ break; hdrp->method = x & 0x7f; if (fread(hdrp->name, 1, 11, in) != 11) { return -1; } hdrp->name[12] = 0; hdrp->orig_size = read32l(in, &error); if (error != 0) return -1; read32l(in, &error); if (error != 0) return -1; read32l(in, &error); if (error != 0) return -1; x = read32l(in, &error); if (error != 0) return -1; hdrp->compressed_size = read32l(in, &error); if (error != 0) return -1; hdrp->offset = read32l(in, &error); if (error != 0) return -1; if (x == 1) /* deleted */ continue; if (hdrp->offset & 0x80000000) /* directory */ continue; hdrp->crc = x >> 16; hdrp->bits = (x & 0xff00) >> 8; hdrp->offset &= 0x7fffffff; hdrp->offset += start; break; } return 0; } /* read file data, assuming header has just been read from in * and hdrp's data matches it. Caller is responsible for freeing * the memory allocated. * Returns NULL for file I/O error only; OOM is fatal (doesn't return). */ static unsigned char *read_file_data(FILE *in, struct archived_file_header_tag *hdrp) { unsigned char *data; int siz = hdrp->compressed_size; if ((data = malloc(siz)) == NULL) { goto err; } if (fseek(in, hdrp->offset, SEEK_SET) < 0) { goto err2; } if (fread(data, 1, siz, in) != siz) { goto err2; } return data; err2: free(data); err: return NULL; } static int arcfs_extract(FILE *in, FILE *out) { struct archived_file_header_tag hdr; unsigned char *data, *orig_data; int exitval = 0; if (read_file_header(in, &hdr) < 0) return -1; if (hdr.method == 0) return -1; /* error reading data (hit EOF) */ if ((data = read_file_data(in, &hdr)) == NULL) return -1; orig_data = NULL; /* FWIW, most common types are (by far) 8/9 and 2. * (127 is the most common in Spark archives, but only those.) * 3 and 4 crop up occasionally. 5 and 6 are very, very rare. * And I don't think I've seen a *single* file with 1 or 7 yet. */ switch (hdr.method) { case 2: /* no compression */ orig_data = data; break; case 8: /* "Crunched" [sic] * (RLE+9-to-12-bit dynamic LZW, a *bit* like GIF) */ orig_data = libxmp_convert_lzw_dynamic(data, hdr.bits, 1, hdr.compressed_size, hdr.orig_size, 0); break; case 9: /* "Squashed" (9-to-13-bit, no RLE) */ orig_data = libxmp_convert_lzw_dynamic(data, hdr.bits, 0, hdr.compressed_size, hdr.orig_size, 0); break; case 127: /* "Compress" (9-to-16-bit, no RLE) ("Spark" only) */ orig_data = libxmp_convert_lzw_dynamic(data, hdr.bits, 0, hdr.compressed_size, hdr.orig_size, 0); break; default: free(data); return -1; } if (orig_data == NULL) { free(data); return -1; } if (fwrite(orig_data, 1, hdr.orig_size, out) != hdr.orig_size) exitval = -1; if (orig_data != data) /* don't free uncompressed stuff twice :-) */ free(orig_data); free(data); return exitval; } static int test_arcfs(unsigned char *b) { return !memcmp(b, "Archive\0", 8); } static int decrunch_arcfs(FILE * f, FILE * fo) { int ret; if (fo == NULL) return -1; ret = arcfs_extract(f, fo); if (ret < 0) return -1; return 0; } struct depacker libxmp_depacker_arcfs = { test_arcfs, decrunch_arcfs }; libxmp-4.4.1/src/depackers/muse.c0000664000175000017500000000162512774567167016536 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU Lesser General Public License. See COPYING.LIB * for more information. */ #include #include #include "common.h" #include "depacker.h" #include "inflate.h" static int test_muse(unsigned char *b) { if (memcmp(b, "MUSE", 4) == 0) { uint32 r = readmem32b(b + 4); /* MOD2J2B uses 0xdeadbabe */ if (r == 0xdeadbeaf || r == 0xdeadbabe) { return 1; } } return 0; } static int decrunch_muse(FILE *f, FILE *fo) { uint32 checksum; if (fseek(f, 24, SEEK_SET) < 0) { return -1; } return libxmp_inflate(f, fo, &checksum, 0); } struct depacker libxmp_depacker_muse = { test_muse, decrunch_muse }; libxmp-4.4.1/src/depackers/unlzx.c0000664000175000017500000006711412775035311016730 0ustar claudioclaudio/* $Id: LZX.c,v 1.12 2005/06/23 14:54:41 stoecker Exp $ LZX file archiver client XAD library system for archive handling Copyright (C) 1998 and later by Dirk Stöcker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Modified for xmp by Claudio Matsuoka, 2014-01-04 */ #include #include #include #include "common.h" #include "depacker.h" #include "crc32.h" #if 0 #ifndef XADMASTERVERSION #define XADMASTERVERSION 10 #endif XADCLIENTVERSTR("LZX 1.10 (21.2.2004)") #define LZX_VERSION 1 #define LZX_REVISION 10 /* ---------------------------------------------------------------------- */ #define LZXINFO_DAMAGE_PROTECT 1 #define LZXINFO_FLAG_LOCKED 2 struct LZXInfo_Header { uint8 ID[3]; /* "LZX" */ uint8 Flags; /* LZXINFO_FLAG_#? */ uint8 Unknown[6]; }; #endif #define LZXHDR_FLAG_MERGED (1<<0) #define LZXHDR_PROT_READ (1<<0) #define LZXHDR_PROT_WRITE (1<<1) #define LZXHDR_PROT_DELETE (1<<2) #define LZXHDR_PROT_EXECUTE (1<<3) #define LZXHDR_PROT_ARCHIVE (1<<4) #define LZXHDR_PROT_HOLD (1<<5) #define LZXHDR_PROT_SCRIPT (1<<6) #define LZXHDR_PROT_PURE (1<<7) #define LZXHDR_TYPE_MSDOS 0 #define LZXHDR_TYPE_WINDOWS 1 #define LZXHDR_TYPE_OS2 2 #define LZXHDR_TYPE_AMIGA 10 #define LZXHDR_TYPE_UNIX 20 #define LZXHDR_PACK_STORE 0 #define LZXHDR_PACK_NORMAL 2 #define LZXHDR_PACK_EOF 32 struct LZXArc_Header { uint8 Attributes; /* 0 - LZXHDR_PROT_#? */ uint8 pad1; /* 1 */ uint8 FileSize[4]; /* 2 (little endian) */ uint8 CrSize[4]; /* 6 (little endian) */ uint8 MachineType; /* 10 - LZXHDR_TYPE_#? */ uint8 PackMode; /* 11 - LZXHDR_PACK_#? */ uint8 Flags; /* 12 - LZXHDR_FLAG_#? */ uint8 pad2; /* 13 */ uint8 CommentSize; /* 14 - length (0-79) */ uint8 ExtractVersion; /* 15 - version needed to extract */ uint8 pad3; /* 16 */ uint8 pad4; /* 17 */ uint8 Date[4]; /* 18 - Packed_Date */ uint8 DataCRC[4]; /* 22 (little endian) */ uint8 HeaderCRC[4]; /* 26 (little endian) */ uint8 FilenameSize; /* 30 - filename length */ }; /* SIZE = 31 */ /* Header CRC includes filename and comment. */ #define LZXHEADERSIZE 31 /* Packed date [4 BYTES, bit 0 is MSB, 31 is LSB] bit 0 - 4 Day 5 - 8 Month (January is 0) 9 - 14 Year (start 1970) 15 - 19 Hour 20 - 25 Minute 26 - 31 Second */ struct LZXEntryData { uint32 CRC; /* CRC of uncrunched data */ uint32 PackMode; /* CrunchMode */ uint32 ArchivePos; /* Position is src file */ uint32 DataStart; /* Position in merged buffer */ }; #define LZXPE(a) ((struct LZXEntryData *) ((a)->xfi_PrivateInfo)) #define LZXDD(a) ((struct LZXDecrData *) ((a)->xai_PrivateClient)) struct LZXDecrData { int mode; uint8 archive_header[31]; uint8 header_filename[256]; uint8 header_comment[256]; uint32 crc; uint8 pack_mode; uint32 sum; FILE *outfile; struct filename_node *filename_list; uint8 *src; uint8 *dest; uint8 *src_end; uint8 *dest_end; uint32 method; uint32 decrunch_length; uint32 pack_size; uint32 unpack_size; uint32 last_offset; uint32 control; int shift; uint8 offset_len[8]; uint16 offset_table[128]; uint8 huffman20_len[20]; uint16 huffman20_table[96]; uint8 literal_len[768]; uint16 literal_table[5120]; /* Was 16384, coverity scan reported overrun */ uint8 read_buffer[16385]; /* have a reasonable sized read buffer */ uint8 buffer[258 + 65536 + 258]; /* allow overrun for speed */ }; /* ---------------------------------------------------------------------- */ #if 0 XADRECOGDATA(LZX) { if (data[0] == 'L' && data[1] == 'Z' && data[2] == 'X') return 1; else return 0; } #define XADFIBF_DELETE (1<<0) #define XADFIBF_EXECUTE (1<<1) #define XADFIBF_WRITE (1<<2) #define XADFIBF_READ (1<<3) #define XADFIBF_PURE (1<<4) XADGETINFO(LZX) { int err; uint32 bufpos = 0; struct xadFileInfo *fi, *fig = 0; /* fig - first grouped ptr */ struct LZXArc_Header head; if (! (err = xadHookAccess(XADM XADAC_INPUTSEEK, sizeof(struct LZXInfo_Header), 0, ai))) { while (!err && ai->xai_InPos < ai->xai_InSize) { if (! (err = xadHookAccess(XADM XADAC_READ, LZXHEADERSIZE, &head, ai))) { uint32 i, j, k, l, crc; i = head.CommentSize; j = head.FilenameSize; k = EndGetI32(head.HeaderCRC); head.HeaderCRC[0] = head.HeaderCRC[1] = head.HeaderCRC[2] = head.HeaderCRC[3] = 0; /* clear for CRC check */ if (! (fi = (struct xadFileInfo *)xadAllocObject(XADM XADOBJ_FILEINFO, XAD_OBJNAMESIZE, j + 1, i ? XAD_OBJCOMMENTSIZE : TAG_IGNORE, i + 1, XAD_OBJPRIVINFOSIZE, sizeof(struct LZXEntryData), TAG_DONE))) err = XADERR_NOMEMORY; else if (! (err = xadHookAccess(XADM XADAC_READ, j, fi->xfi_FileName, ai)) && (!i || !(err = xadHookAccess(XADM XADAC_READ, i, fi-> xfi_Comment, ai)))) { l = EndGetI32(head.CrSize); if (!l || !(err = xadHookAccess(XADM XADAC_INPUTSEEK, l, 0, ai))) { crc = xadCalcCRC32(XADM XADCRC32_ID1, (uint32)~0, LZXHEADERSIZE, (uint8 *)&head); crc = xadCalcCRC32(XADM XADCRC32_ID1, crc, j, (uint8 *)fi->xfi_FileName); if (i) crc = xadCalcCRC32(XADM XADCRC32_ID1, crc, i, (uint8 *)fi->xfi_Comment); if (~crc != k) err = XADERR_CHECKSUM; else { if (!fig) { fig = fi; bufpos = 0; } fi->xfi_Size = EndGetI32(head.FileSize); if (!l && !fi->xfi_Size && fi->xfi_FileName[--j] == '/') { fi->xfi_FileName[j] = 0; fi->xfi_Flags |= XADFIF_DIRECTORY; } i = head.Attributes; j = 0; if (!(i & LZXHDR_PROT_READ)) j |= XADFIBF_READ; if (!(i & LZXHDR_PROT_WRITE)) j |= XADFIBF_WRITE; if (!(i & LZXHDR_PROT_DELETE)) j |= XADFIBF_DELETE; if (!(i & LZXHDR_PROT_EXECUTE)) j |= XADFIBF_EXECUTE; j |= (i & (LZXHDR_PROT_ARCHIVE | LZXHDR_PROT_SCRIPT)); if (i & LZXHDR_PROT_PURE) j |= XADFIBF_PURE; if (i & LZXHDR_PROT_HOLD) j |= (1 << 7); /* not defined in */ fi->xfi_Protection = j; { /* Make the date */ struct xadDate d; j = EndGetM32(head.Date); d.xd_Second = j & 63; j >>= 6; d.xd_Minute = j & 63; j >>= 6; d.xd_Hour = j & 31; j >>= 5; d.xd_Year = 1970 + (j & 63); if (d.xd_Year >= 2028) /* Original LZX */ d.xd_Year += 2000 - 2028; else if (d.xd_Year < 1978) /* Dr.Titus */ d.xd_Year += 2034 - 1970; /* Dates from 1978 to 1999 are correct */ /* Dates from 2000 to 2027 Mikolaj patch are correct */ /* Dates from 2000 to 2005 LZX/Dr.Titus patch are correct */ /* Dates from 2034 to 2041 Dr.Titus patch are correct */ j >>= 6; d.xd_Month = 1 + (j & 15); j >>= 4; d.xd_Day = j; d.xd_Micros = 0; xadConvertDates(XADM XAD_DATEXADDATE, &d, XAD_GETDATEXADDATE, &fi->xfi_Date, TAG_DONE); } LZXPE(fi)->CRC = EndGetI32(head.DataCRC); LZXPE(fi)->DataStart = bufpos; bufpos += fi->xfi_Size; if (head.Flags & LZXHDR_FLAG_MERGED) { fi->xfi_Flags |= XADFIF_GROUPED; if (l) { fi->xfi_Flags |= XADFIF_ENDOFGROUP; fi->xfi_GroupCrSize = l; } } else fi->xfi_CrunchSize = l; if (l) { LZXPE(fi)->ArchivePos = ai->xai_InPos - l; LZXPE(fi)->PackMode = head.PackMode; while (fig) { fig->xfi_GroupCrSize = l; LZXPE(fig)->ArchivePos = ai->xai_InPos - l; LZXPE(fig)->PackMode = head.PackMode; fig = fig->xfi_Next; } } err = xadAddFileEntryA(XADM fi, ai, 0); fi = 0; } /* skip crunched data */ } /* get filename and comment */ if (fi) xadFreeObjectA(XADM fi, 0); } /* xadFileInfo Allocation */ } /* READ header */ } /* while loop */ } /* INPUTSEEK 3 bytes */ if (err && ai->xai_FileInfo) { ai->xai_Flags |= XADAIF_FILECORRUPT; ai->xai_LastError = err; err = 0; } return err; } #endif struct filename_node { struct filename_node *next; uint32 length; uint32 crc; char filename[256]; }; /* ---------------------------------------------------------------------- */ static const uint8 table_one[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14 }; static const uint32 table_two[32] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152 }; static const uint32 table_three[16] = { 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767 }; static const uint8 table_four[34] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; /* ---------------------------------------------------------------------- */ /* Build a fast huffman decode table from the symbol bit lengths. */ /* There is an alternate algorithm which is faster but also more complex. */ static int make_decode_table(int number_symbols, int table_size, uint8 *length, uint16 *table) { register uint8 bit_num = 0; register int symbol; uint32 leaf; /* could be a register */ uint32 table_mask, bit_mask, pos, fill, next_symbol, reverse; pos = 0; /* current position in decode table */ bit_mask = table_mask = 1 << table_size; bit_mask >>= 1; /* don't do the first number */ bit_num++; while (bit_num <= table_size) { for (symbol = 0; symbol < number_symbols; symbol++) { if (length[symbol] == bit_num) { reverse = pos; /* reverse the order of the position's bits */ leaf = 0; fill = table_size; do { /* reverse the position */ leaf = (leaf << 1) + (reverse & 1); reverse >>= 1; } while (--fill); if ((pos += bit_mask) > table_mask) return -1; /* we will overrun the table! abort! */ fill = bit_mask; next_symbol = 1 << bit_num; do { table[leaf] = symbol; leaf += next_symbol; } while (--fill); } } bit_mask >>= 1; bit_num++; } if (pos != table_mask) { for (symbol = pos; symbol < table_mask; symbol++) { /* clear the rest of the table */ reverse = symbol; /* reverse the order of the position's bits */ leaf = 0; fill = table_size; do { /* reverse the position */ leaf = (leaf << 1) + (reverse & 1); reverse >>= 1; } while (--fill); table[leaf] = 0; } next_symbol = table_mask >> 1; pos <<= 16; table_mask <<= 16; bit_mask = 32768; while (bit_num <= 16) { for (symbol = 0; symbol < number_symbols; symbol++) { if (length[symbol] == bit_num) { reverse = pos >> 16; /* reverse the order of the position's bits */ leaf = 0; fill = table_size; do { /* reverse the position */ leaf = (leaf << 1) + (reverse & 1); reverse >>= 1; } while (--fill); for (fill = 0; fill < bit_num - table_size; fill++) { if (table[leaf] == 0) { table[next_symbol << 1] = 0; table[(next_symbol << 1) + 1] = 0; table[leaf] = next_symbol++; } leaf = table[leaf] << 1; leaf += (pos >> (15 - fill)) & 1; } table[leaf] = symbol; pos += bit_mask; if (pos > table_mask) return -1; /* we will overrun the table! abort! */ } } bit_mask >>= 1; bit_num++; } } if (pos != table_mask) return -1; /* the table is incomplete! */ return 0; } /* ---------------------------------------------------------------------- */ /* Read and build the decrunch tables. There better be enough data in the */ /* src buffer or it's stuffed. */ static int read_literal_table(struct LZXDecrData *decr) { register uint32 control; register int shift; uint32 temp; /* could be a register */ uint32 symbol, pos, count, fix, max_symbol; uint8 *src; int abort = 0; int x; control = decr->control; shift = decr->shift; src = decr->src; if (shift < 0) { /* fix the control word if necessary */ shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } /* read the decrunch method */ decr->method = control & 7; control >>= 3; shift -= 3; if (shift < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } /* Read and build the offset huffman table */ if (!abort && decr->method == 3) { for (temp = 0; temp < 8; temp++) { decr->offset_len[temp] = control & 7; control >>= 3; if ((shift -= 3) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } } abort = make_decode_table(8, 7, decr->offset_len, decr->offset_table); } /* read decrunch length */ if (!abort) { decr->decrunch_length = (control & 255) << 16; control >>= 8; shift -= 8; if (shift < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } decr->decrunch_length += (control & 255) << 8; control >>= 8; shift -= 8; if (shift < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } decr->decrunch_length += (control & 255); control >>= 8; shift -= 8; if (shift < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } } /* read and build the huffman literal table */ if (!abort && decr->method != 1) { pos = 0; fix = 1; max_symbol = 256; do { for (temp = 0; temp < 20; temp++) { decr->huffman20_len[temp] = control & 15; control >>= 4; if ((shift -= 4) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } } abort = make_decode_table(20, 6, decr->huffman20_len, decr->huffman20_table); if (abort) break; /* argh! table is corrupt! */ do { if ((symbol = decr->huffman20_table[control & 63]) >= 20) { do { /* symbol is longer than 6 bits */ symbol = decr->huffman20_table[((control >> 6) & 1) + (symbol << 1)]; if (!shift--) { shift += 16; control += *src++ << 24; control += *src++ << 16; } control >>= 1; } while (symbol >= 20); temp = 6; } else { temp = decr->huffman20_len[symbol]; } control >>= temp; if ((shift -= temp) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } switch (symbol) { case 17: case 18: if (symbol == 17) { temp = 4; count = 3; } else { /* symbol == 18 */ temp = 6 - fix; count = 19; } count += (control & table_three[temp]) + fix; control >>= temp; if ((shift -= temp) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } while ((pos < max_symbol) && (count--)) decr->literal_len[pos++] = 0; break; case 19: count = (control & 1) + 3 + fix; if (!shift--) { shift += 16; control += *src++ << 24; control += *src++ << 16; } control >>= 1; if ((symbol = decr->huffman20_table[control & 63]) >= 20) { do { /* symbol is longer than 6 bits */ symbol = decr->huffman20_table[((control >> 6) & 1) + (symbol << 1)]; if (!shift--) { shift += 16; control += *src++ << 24; control += *src++ << 16; } control >>= 1; } while (symbol >= 20); temp = 6; } else { temp = decr->huffman20_len[symbol]; } control >>= temp; if ((shift -= temp) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } /* Sanity check */ if (pos >= 768) return -1; x = decr->literal_len[pos] + 17 - symbol; /* Sanity check */ if (x >= 34) return -1; symbol = table_four[x]; while (pos < max_symbol && count--) decr->literal_len[pos++] = symbol; break; default: symbol = table_four[decr->literal_len[pos] + 17 - symbol]; decr->literal_len[pos++] = symbol; break; } } while (pos < max_symbol); fix--; max_symbol += 512; } while (max_symbol == 768); if (!abort) abort = make_decode_table(768, 12, decr->literal_len, decr->literal_table); } decr->control = control; decr->shift = shift; decr->src = src; return abort; } /* ---------------------------------------------------------------------- */ /* Fill up the decrunch buffer. Needs lots of overrun for both decr->dest */ /* and src buffers. Most of the time is spent in this routine so it's */ /* pretty damn optimized. */ static void decrunch(struct LZXDecrData *decr) { register uint32 control; register int shift; uint32 temp; /* could be a register */ uint32 symbol, count; uint8 *string, *src, *dest; control = decr->control; shift = decr->shift; src = decr->src; dest = decr->dest; do { if ((symbol = decr->literal_table[control & 4095]) >= 768) { control >>= 12; if ((shift -= 12) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } do { /* literal is longer than 12 bits */ symbol = decr->literal_table[(control & 1) + (symbol << 1)]; if (!shift--) { shift += 16; control += *src++ << 24; control += *src++ << 16; } control >>= 1; } while (symbol >= 768); } else { temp = decr->literal_len[symbol]; control >>= temp; if ((shift -= temp) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } } if (symbol < 256) { *dest++ = symbol; } else { symbol -= 256; count = table_two[temp = symbol & 31]; temp = table_one[temp]; if ((temp >= 3) && (decr->method == 3)) { temp -= 3; count += ((control & table_three[temp]) << 3); control >>= temp; if ((shift -= temp) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } count += (temp = decr->offset_table[control & 127]); temp = decr->offset_len[temp]; } else { count += control & table_three[temp]; if (!count) count = decr->last_offset; } control >>= temp; if ((shift -= temp) < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } decr->last_offset = count; count = table_two[temp = (symbol >> 5) & 15] + 3; temp = table_one[temp]; count += (control & table_three[temp]); control >>= temp; shift -= temp; if (shift < 0) { shift += 16; control += *src++ << (8 + shift); control += *src++ << shift; } string = (decr->buffer + decr->last_offset < dest) ? dest - decr->last_offset : dest + 65536 - decr->last_offset; do { *dest++ = *string++; } while (--count); } } while (dest < decr->dest_end && src < decr->src_end); decr->control = control; decr->shift = shift; decr->src = src; decr->dest = dest; } /* ---------------------------------------------------------------------- */ /* Trying to understand this function is hazardous. */ static int extract_normal(FILE * in_file, struct LZXDecrData *decr) { struct filename_node *node; FILE *out_file = 0; uint8 *pos; uint8 *temp; uint32 count; int abort = 0; decr->control = 0; /* initial control word */ decr->shift = -16; decr->last_offset = 1; decr->unpack_size = 0; decr->decrunch_length = 0; memset(decr->offset_len, 0, 8); memset(decr->literal_len, 0, 768); decr->src = decr->read_buffer + 16384; decr->src_end = decr->src - 1024; pos = decr->dest_end = decr->dest = decr->buffer + 258 + 65536; for (node = decr->filename_list; (!abort) && node; node = node->next) { /*printf("Extracting \"%s\"...", node->filename); fflush(stdout); */ if (libxmp_exclude_match(node->filename)) { out_file = NULL; } else { out_file = decr->outfile; } decr->sum = 0; /* reset CRC */ decr->unpack_size = node->length; while (decr->unpack_size > 0) { if (pos == decr->dest) { /* time to fill the buffer? */ /* check if we have enough data and read some if not */ if (decr->src >= decr->src_end) { /* have we exhausted the current read buffer? */ temp = decr->read_buffer; if ((count = temp - decr->src + 16384)) { do { /* copy the remaining overrun to the start of the buffer */ *temp++ = *decr->src++; } while (--count); } decr->src = decr->read_buffer; count = decr->src - temp + 16384; if (decr->pack_size < count) count = decr->pack_size; /* make sure we don't read too much */ if (fread(temp, 1, count, in_file) != count) { /* printf("\n"); if (ferror(in_file)) perror("FRead(Data)"); else fprintf(stderr, "EOF: Data\n"); */ abort = 1; break; /* fatal error */ } decr->pack_size -= count; temp += count; if (decr->src >= temp) break; /* argh! no more data! */ } /* if(src >= decr->src_end) */ /* check if we need to read the tables */ if (decr->decrunch_length <= 0) { if (read_literal_table(decr)) break; /* argh! can't make huffman tables! */ } /* unpack some data */ if (decr->dest >= decr->buffer + 258 + 65536) { if ((count = decr->dest - decr->buffer - 65536)) { temp = (decr->dest = decr->buffer) + 65536; do { /* copy the overrun to the start of the buffer */ *decr->dest++ = *temp++; } while (--count); } pos = decr->dest; } decr->dest_end = decr->dest + decr->decrunch_length; if (decr->dest_end > decr->buffer + 258 + 65536) decr->dest_end = decr->buffer + 258 + 65536; temp = decr->dest; decrunch(decr); decr->decrunch_length -= (decr->dest - temp); } /* calculate amount of data we can use before we need to * fill the buffer again */ count = decr->dest - pos; if (count > decr->unpack_size) count = decr->unpack_size; /* take only what we need */ decr->sum = libxmp_crc32_A1(pos, count, decr->sum); if (out_file) { /* Write the data to the file */ abort = 1; if (fwrite(pos, 1, count, out_file) != count) { #if 0 perror("FWrite"); /* argh! write error */ fclose(out_file); out_file = 0; #endif } } decr->unpack_size -= count; pos += count; } #if 0 if (out_file) { fclose(out_file); if (!abort) printf(" crc %s\n", (node->crc == sum) ? "good" : "bad"); } #endif } /* for */ return (abort); } /* ---------------------------------------------------------------------- */ static int extract_archive(FILE * in_file, struct LZXDecrData *decr) { uint32 temp; struct filename_node **filename_next; struct filename_node *node; struct filename_node *temp_node; int actual; int abort; int result = 1; /* assume an error */ decr->filename_list = 0; /* clear the list */ filename_next = &decr->filename_list; do { abort = 1; /* assume an error */ actual = fread(decr->archive_header, 1, 31, in_file); if (ferror(in_file)) { /* perror("FRead(Archive_Header)"); */ continue; } if (actual == 0) { /* 0 is normal and means EOF */ result = 0; /* normal termination */ continue; } if (actual != 31) { /* fprintf(stderr, "EOF: Archive_Header\n"); */ continue; } decr->sum = 0; /* reset CRC */ decr->crc = readmem32l(decr->archive_header + 26); /* Must set the field to 0 before calculating the crc */ memset(decr->archive_header + 26, 0, 4); decr->sum = libxmp_crc32_A1(decr->archive_header, 31, decr->sum); temp = decr->archive_header[30]; /* filename length */ actual = fread(decr->header_filename, 1, temp, in_file); if (ferror(in_file)) { /* perror("FRead(Header_Filename)"); */ continue; } if (actual != temp) { /* fprintf(stderr, "EOF: Header_Filename\n"); */ continue; } decr->header_filename[temp] = 0; decr->sum = libxmp_crc32_A1(decr->header_filename, temp, decr->sum); temp = decr->archive_header[14]; /* comment length */ actual = fread(decr->header_comment, 1, temp, in_file); if (ferror(in_file)) { /* perror("FRead(Header_Comment)"); */ continue; } if (actual != temp) { /* fprintf(stderr, "EOF: Header_Comment\n"); */ continue; } decr->header_comment[temp] = 0; decr->sum = libxmp_crc32_A1(decr->header_comment, temp, decr->sum); if (decr->sum != decr->crc) { /* fprintf(stderr, "CRC: Archive_Header\n"); */ continue; } decr->unpack_size = readmem32l(decr->archive_header + 2); decr->pack_size = readmem32l(decr->archive_header + 6); decr->pack_mode = decr->archive_header[11]; decr->crc = readmem32l(decr->archive_header + 22); /* allocate a filename node */ node = malloc(sizeof(struct filename_node)); if (node == NULL) { /* fprintf(stderr, "MAlloc(Filename_node)\n"); */ continue; } *filename_next = node; /* add this node to the list */ filename_next = &(node->next); node->next = 0; node->length = decr->unpack_size; node->crc = decr->crc; for (temp = 0; (node->filename[temp] = decr->header_filename[temp]); temp++) ; #if 0 if (decr->pack_size == 0) { abort = 0; /* continue */ continue; } #endif switch (decr->pack_mode) { #if 0 case 0: /* store */ /*abort =*/ extract_store(in_file, decr); abort = 1; /* for xmp */ break; #endif case 2: /* normal */ /*abort =*/ extract_normal(in_file, decr); abort = 1; /* for xmp */ break; default: /* unknown */ break; } #if 0 if (abort) break; /* a read error occured */ /* CID 129002 (#1 of 1): Logically dead code (DEADCODE) * dead_error_begin: Execution cannot reach this statement: */ temp_node = decr->filename_list; /* free the list now */ while ((node = temp_node)) { temp_node = node->next; free(node); } decr->filename_list = 0; /* clear the list */ filename_next = &decr->filename_list; if (fseek(in_file, decr->pack_size, SEEK_CUR)) { /* perror("FSeek(Data)"); */ break; } #endif } while (!abort); /* free the filename list in case an error occured */ temp_node = decr->filename_list; while ((node = temp_node)) { temp_node = node->next; free(node); } return result; } static int test_lzx(unsigned char *b) { return memcmp(b, "LZX", 3) == 0; } static int decrunch_lzx(FILE *f, FILE *fo) { struct LZXDecrData *decr; if (fo == NULL) goto err; decr = calloc(1, sizeof(struct LZXDecrData)); if (decr == NULL) goto err; if (fseek(f, 10, SEEK_CUR) < 0) /* skip header */ goto err2; libxmp_crc32_init_A(); decr->outfile = fo; extract_archive(f, decr); free(decr); return 0; err2: free(decr); err: return -1; } struct depacker libxmp_depacker_lzx = { test_lzx, decrunch_lzx }; libxmp-4.4.1/src/depackers/readrle.c0000664000175000017500000000314112773571316017164 0ustar claudioclaudio/* nomarch 1.0 - extract old `.arc' archives. * Copyright (C) 2001 Russell Marks. See unarc.c for license details. * * readrle.c - read RLE-compressed files. * * Also provides the generic outputrle() for the other RLE-using methods * to use. */ #include #include #include #include #include "readrle.h" #if 0 static void rawoutput(int byte, struct data_in_out *io) { if(io->data_out_pointdata_out_max) *io->data_out_point++=byte; } #endif /* call with -1 before starting, to make sure state is initialised */ void libxmp_outputrle(int chr,void (*outputfunc)(int, struct data_in_out *), struct rledata *rd, struct data_in_out *io) { int f; if(chr==-1) { rd->lastchr=rd->repeating=0; return; } if(rd->repeating) { if(chr==0) (*outputfunc)(0x90, io); else for(f=1;flastchr, io); rd->repeating=0; } else { if(chr==0x90) rd->repeating=1; else { (*outputfunc)(chr, io); rd->lastchr=chr; } } } #if 0 unsigned char *convert_rle(unsigned char *data_in, unsigned long in_len, unsigned long orig_len) { unsigned char *data_out; struct rledata rd; struct data_in_out io; if((data_out=malloc(orig_len))==NULL) fprintf(stderr,"nomarch: out of memory!\n"),exit(1); io.data_in_point=data_in; io.data_in_max=data_in+in_len; io.data_out_point=data_out; io.data_out_max=data_out+orig_len; outputrle(-1,NULL, &rd, &io); while(io.data_in_point * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. */ #include "xz_private.h" #include "xz_lzma2.h" /* * Range decoder initialization eats the first five bytes of each LZMA chunk. */ #define RC_INIT_BYTES 5 /* * Minimum number of usable input buffer to safely decode one LZMA symbol. * The worst case is that we decode 22 bits using probabilities and 26 * direct bits. This may decode at maximum of 20 bytes of input. However, * lzma_main() does an extra normalization before returning, thus we * need to put 21 here. */ #define LZMA_IN_REQUIRED 21 /* * Dictionary (history buffer) * * These are always true: * start <= pos <= full <= end * pos <= limit <= end * * In multi-call mode, also these are true: * end == size * size <= size_max * allocated <= size * * Most of these variables are size_t to support single-call mode, * in which the dictionary variables address the actual output * buffer directly. */ struct dictionary { /* Beginning of the history buffer */ uint8 *buf; /* Old position in buf (before decoding more data) */ size_t start; /* Position in buf */ size_t pos; /* * How full dictionary is. This is used to detect corrupt input that * would read beyond the beginning of the uncompressed stream. */ size_t full; /* Write limit; we don't write to buf[limit] or later bytes. */ size_t limit; /* * End of the dictionary buffer. In multi-call mode, this is * the same as the dictionary size. In single-call mode, this * indicates the size of the output buffer. */ size_t end; /* * Size of the dictionary as specified in Block Header. This is used * together with "full" to detect corrupt input that would make us * read beyond the beginning of the uncompressed stream. */ uint32 size; /* * Maximum allowed dictionary size in multi-call mode. * This is ignored in single-call mode. */ uint32 size_max; /* * Amount of memory currently allocated for the dictionary. * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, * size_max is always the same as the allocated size.) */ uint32 allocated; /* Operation mode */ enum xz_mode mode; }; /* Range decoder */ struct rc_dec { uint32 range; uint32 code; /* * Number of initializing bytes remaining to be read * by rc_read_init(). */ uint32 init_bytes_left; /* * Buffer from which we read our input. It can be either * temp.buf or the caller-provided input buffer. */ const uint8 *in; size_t in_pos; size_t in_limit; }; /* Probabilities for a length decoder. */ struct lzma_len_dec { /* Probability of match length being at least 10 */ uint16 choice; /* Probability of match length being at least 18 */ uint16 choice2; /* Probabilities for match lengths 2-9 */ uint16 low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; /* Probabilities for match lengths 10-17 */ uint16 mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; /* Probabilities for match lengths 18-273 */ uint16 high[LEN_HIGH_SYMBOLS]; }; struct lzma_dec { /* Distances of latest four matches */ uint32 rep0; uint32 rep1; uint32 rep2; uint32 rep3; /* Types of the most recently seen LZMA symbols */ enum lzma_state state; /* * Length of a match. This is updated so that dict_repeat can * be called again to finish repeating the whole match. */ uint32 len; /* * LZMA properties or related bit masks (number of literal * context bits, a mask dervied from the number of literal * position bits, and a mask dervied from the number * position bits) */ uint32 lc; uint32 literal_pos_mask; /* (1 << lp) - 1 */ uint32 pos_mask; /* (1 << pb) - 1 */ /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ uint16 is_match[STATES][POS_STATES_MAX]; /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ uint16 is_rep[STATES]; /* * If 0, distance of a repeated match is rep0. * Otherwise check is_rep1. */ uint16 is_rep0[STATES]; /* * If 0, distance of a repeated match is rep1. * Otherwise check is_rep2. */ uint16 is_rep1[STATES]; /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ uint16 is_rep2[STATES]; /* * If 1, the repeated match has length of one byte. Otherwise * the length is decoded from rep_len_decoder. */ uint16 is_rep0_long[STATES][POS_STATES_MAX]; /* * Probability tree for the highest two bits of the match * distance. There is a separate probability tree for match * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. */ uint16 dist_slot[DIST_STATES][DIST_SLOTS]; /* * Probility trees for additional bits for match distance * when the distance is in the range [4, 127]. */ uint16 dist_special[FULL_DISTANCES - DIST_MODEL_END]; /* * Probability tree for the lowest four bits of a match * distance that is equal to or greater than 128. */ uint16 dist_align[ALIGN_SIZE]; /* Length of a normal match */ struct lzma_len_dec match_len_dec; /* Length of a repeated match */ struct lzma_len_dec rep_len_dec; /* Probabilities of literals */ uint16 literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; }; struct lzma2_dec { /* Position in xz_dec_lzma2_run(). */ enum lzma2_seq { SEQ_CONTROL, SEQ_UNCOMPRESSED_1, SEQ_UNCOMPRESSED_2, SEQ_COMPRESSED_0, SEQ_COMPRESSED_1, SEQ_PROPERTIES, SEQ_LZMA_PREPARE, SEQ_LZMA_RUN, SEQ_COPY } sequence; /* Next position after decoding the compressed size of the chunk. */ enum lzma2_seq next_sequence; /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ uint32 uncompressed; /* * Compressed size of LZMA chunk or compressed/uncompressed * size of uncompressed chunk (64 KiB at maximum) */ uint32 compressed; /* * True if dictionary reset is needed. This is false before * the first chunk (LZMA or uncompressed). */ bool need_dict_reset; /* * True if new LZMA properties are needed. This is false * before the first LZMA chunk. */ bool need_props; }; struct xz_dec_lzma2 { /* * The order below is important on x86 to reduce code size and * it shouldn't hurt on other platforms. Everything up to and * including lzma.pos_mask are in the first 128 bytes on x86-32, * which allows using smaller instructions to access those * variables. On x86-64, fewer variables fit into the first 128 * bytes, but this is still the best order without sacrificing * the readability by splitting the structures. */ struct rc_dec rc; struct dictionary dict; struct lzma2_dec lzma2; struct lzma_dec lzma; /* * Temporary buffer which holds small number of input bytes between * decoder calls. See lzma2_lzma() for details. */ struct { uint32 size; uint8 buf[3 * LZMA_IN_REQUIRED]; } temp; }; /************** * Dictionary * **************/ /* * Reset the dictionary state. When in single-call mode, set up the beginning * of the dictionary to point to the actual output buffer. */ static void dict_reset(struct dictionary *dict, struct xz_buf *b) { if (DEC_IS_SINGLE(dict->mode)) { dict->buf = b->out + b->out_pos; dict->end = b->out_size - b->out_pos; } dict->start = 0; dict->pos = 0; dict->limit = 0; dict->full = 0; } /* Set dictionary write limit */ static void dict_limit(struct dictionary *dict, size_t out_max) { if (dict->end - dict->pos <= out_max) dict->limit = dict->end; else dict->limit = dict->pos + out_max; } /* Return true if at least one byte can be written into the dictionary. */ static inline bool dict_has_space(const struct dictionary *dict) { return dict->pos < dict->limit; } /* * Get a byte from the dictionary at the given distance. The distance is * assumed to valid, or as a special case, zero when the dictionary is * still empty. This special case is needed for single-call decoding to * avoid writing a '\0' to the end of the destination buffer. */ static inline uint32 dict_get(const struct dictionary *dict, uint32 dist) { size_t offset = dict->pos - dist - 1; if (dist >= dict->pos) offset += dict->end; return dict->full > 0 ? dict->buf[offset] : 0; } /* * Put one byte into the dictionary. It is assumed that there is space for it. */ static inline void dict_put(struct dictionary *dict, uint8 byte) { dict->buf[dict->pos++] = byte; if (dict->full < dict->pos) dict->full = dict->pos; } /* * Repeat given number of bytes from the given distance. If the distance is * invalid, false is returned. On success, true is returned and *len is * updated to indicate how many bytes were left to be repeated. */ static bool dict_repeat(struct dictionary *dict, uint32 *len, uint32 dist) { size_t back; uint32 left; if (dist >= dict->full || dist >= dict->size) return false; left = min_t(size_t, dict->limit - dict->pos, *len); *len -= left; back = dict->pos - dist - 1; if (dist >= dict->pos) back += dict->end; do { dict->buf[dict->pos++] = dict->buf[back++]; if (back == dict->end) back = 0; } while (--left > 0); if (dict->full < dict->pos) dict->full = dict->pos; return true; } /* Copy uncompressed data as is from input to dictionary and output buffers. */ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, uint32 *left) { size_t copy_size; while (*left > 0 && b->in_pos < b->in_size && b->out_pos < b->out_size) { copy_size = min(b->in_size - b->in_pos, b->out_size - b->out_pos); if (copy_size > dict->end - dict->pos) copy_size = dict->end - dict->pos; if (copy_size > *left) copy_size = *left; *left -= copy_size; memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); dict->pos += copy_size; if (dict->full < dict->pos) dict->full = dict->pos; if (DEC_IS_MULTI(dict->mode)) { if (dict->pos == dict->end) dict->pos = 0; memcpy(b->out + b->out_pos, b->in + b->in_pos, copy_size); } dict->start = dict->pos; b->out_pos += copy_size; b->in_pos += copy_size; } } /* * Flush pending data from dictionary to b->out. It is assumed that there is * enough space in b->out. This is guaranteed because caller uses dict_limit() * before decoding data into the dictionary. */ static uint32 dict_flush(struct dictionary *dict, struct xz_buf *b) { size_t copy_size = dict->pos - dict->start; if (DEC_IS_MULTI(dict->mode)) { if (dict->pos == dict->end) dict->pos = 0; memcpy(b->out + b->out_pos, dict->buf + dict->start, copy_size); } dict->start = dict->pos; b->out_pos += copy_size; return copy_size; } /***************** * Range decoder * *****************/ /* Reset the range decoder. */ static void rc_reset(struct rc_dec *rc) { rc->range = (uint32)-1; rc->code = 0; rc->init_bytes_left = RC_INIT_BYTES; } /* * Read the first five initial bytes into rc->code if they haven't been * read already. (Yes, the first byte gets completely ignored.) */ static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b) { while (rc->init_bytes_left > 0) { if (b->in_pos == b->in_size) return false; rc->code = (rc->code << 8) + b->in[b->in_pos++]; --rc->init_bytes_left; } return true; } /* Return true if there may not be enough input for the next decoding loop. */ static inline bool rc_limit_exceeded(const struct rc_dec *rc) { return rc->in_pos > rc->in_limit; } /* * Return true if it is possible (from point of view of range decoder) that * we have reached the end of the LZMA chunk. */ static inline bool rc_is_finished(const struct rc_dec *rc) { return rc->code == 0; } /* Read the next input byte if needed. */ static inline void rc_normalize(struct rc_dec *rc) { if (rc->range < RC_TOP_VALUE) { rc->range <<= RC_SHIFT_BITS; rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; } } /* * Decode one bit. In some versions, this function has been splitted in three * functions so that the compiler is supposed to be able to more easily avoid * an extra branch. In this particular version of the LZMA decoder, this * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 * on x86). Using a non-splitted version results in nicer looking code too. * * NOTE: This must return an int. Do not make it return a bool or the speed * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) */ static inline int rc_bit(struct rc_dec *rc, uint16 *prob) { uint32 bound; int bit; rc_normalize(rc); bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; if (rc->code < bound) { rc->range = bound; *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; bit = 0; } else { rc->range -= bound; rc->code -= bound; *prob -= *prob >> RC_MOVE_BITS; bit = 1; } return bit; } /* Decode a bittree starting from the most significant bit. */ static inline uint32 rc_bittree(struct rc_dec *rc, uint16 *probs, uint32 limit) { uint32 symbol = 1; do { if (rc_bit(rc, &probs[symbol])) symbol = (symbol << 1) + 1; else symbol <<= 1; } while (symbol < limit); return symbol; } /* Decode a bittree starting from the least significant bit. */ static inline void rc_bittree_reverse(struct rc_dec *rc, uint16 *probs, uint32 *dest, uint32 limit) { uint32 symbol = 1; uint32 i = 0; do { if (rc_bit(rc, &probs[symbol])) { symbol = (symbol << 1) + 1; *dest += 1 << i; } else { symbol <<= 1; } } while (++i < limit); } /* Decode direct bits (fixed fifty-fifty probability) */ static inline void rc_direct(struct rc_dec *rc, uint32 *dest, uint32 limit) { uint32 mask; do { rc_normalize(rc); rc->range >>= 1; rc->code -= rc->range; mask = (uint32)0 - (rc->code >> 31); rc->code += rc->range & mask; *dest = (*dest << 1) + (mask + 1); } while (--limit > 0); } /******** * LZMA * ********/ /* Get pointer to literal coder probability array. */ static uint16 *lzma_literal_probs(struct xz_dec_lzma2 *s) { uint32 prev_byte = dict_get(&s->dict, 0); uint32 low = prev_byte >> (8 - s->lzma.lc); uint32 high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; return s->lzma.literal[low + high]; } /* Decode a literal (one 8-bit byte) */ static void lzma_literal(struct xz_dec_lzma2 *s) { uint16 *probs; uint32 symbol; uint32 match_byte; uint32 match_bit; uint32 offset; uint32 i; probs = lzma_literal_probs(s); if (lzma_state_is_literal(s->lzma.state)) { symbol = rc_bittree(&s->rc, probs, 0x100); } else { symbol = 1; match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; offset = 0x100; do { match_bit = match_byte & offset; match_byte <<= 1; i = offset + match_bit + symbol; if (rc_bit(&s->rc, &probs[i])) { symbol = (symbol << 1) + 1; offset &= match_bit; } else { symbol <<= 1; offset &= ~match_bit; } } while (symbol < 0x100); } dict_put(&s->dict, (uint8)symbol); lzma_state_literal(&s->lzma.state); } /* Decode the length of the match into s->lzma.len. */ static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, uint32 pos_state) { uint16 *probs; uint32 limit; if (!rc_bit(&s->rc, &l->choice)) { probs = l->low[pos_state]; limit = LEN_LOW_SYMBOLS; s->lzma.len = MATCH_LEN_MIN; } else { if (!rc_bit(&s->rc, &l->choice2)) { probs = l->mid[pos_state]; limit = LEN_MID_SYMBOLS; s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; } else { probs = l->high; limit = LEN_HIGH_SYMBOLS; s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; } } s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; } /* Decode a match. The distance will be stored in s->lzma.rep0. */ static void lzma_match(struct xz_dec_lzma2 *s, uint32 pos_state) { uint16 *probs; uint32 dist_slot; uint32 limit; lzma_state_match(&s->lzma.state); s->lzma.rep3 = s->lzma.rep2; s->lzma.rep2 = s->lzma.rep1; s->lzma.rep1 = s->lzma.rep0; lzma_len(s, &s->lzma.match_len_dec, pos_state); probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; if (dist_slot < DIST_MODEL_START) { s->lzma.rep0 = dist_slot; } else { limit = (dist_slot >> 1) - 1; s->lzma.rep0 = 2 + (dist_slot & 1); if (dist_slot < DIST_MODEL_END) { s->lzma.rep0 <<= limit; probs = s->lzma.dist_special + s->lzma.rep0 - dist_slot - 1; rc_bittree_reverse(&s->rc, probs, &s->lzma.rep0, limit); } else { rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); s->lzma.rep0 <<= ALIGN_BITS; rc_bittree_reverse(&s->rc, s->lzma.dist_align, &s->lzma.rep0, ALIGN_BITS); } } } /* * Decode a repeated match. The distance is one of the four most recently * seen matches. The distance will be stored in s->lzma.rep0. */ static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32 pos_state) { uint32 tmp; if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ s->lzma.state][pos_state])) { lzma_state_short_rep(&s->lzma.state); s->lzma.len = 1; return; } } else { if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { tmp = s->lzma.rep1; } else { if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { tmp = s->lzma.rep2; } else { tmp = s->lzma.rep3; s->lzma.rep3 = s->lzma.rep2; } s->lzma.rep2 = s->lzma.rep1; } s->lzma.rep1 = s->lzma.rep0; s->lzma.rep0 = tmp; } lzma_state_long_rep(&s->lzma.state); lzma_len(s, &s->lzma.rep_len_dec, pos_state); } /* LZMA decoder core */ static bool lzma_main(struct xz_dec_lzma2 *s) { uint32 pos_state; /* * If the dictionary was reached during the previous call, try to * finish the possibly pending repeat in the dictionary. */ if (dict_has_space(&s->dict) && s->lzma.len > 0) dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); /* * Decode more LZMA symbols. One iteration may consume up to * LZMA_IN_REQUIRED - 1 bytes. */ while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { pos_state = s->dict.pos & s->lzma.pos_mask; if (!rc_bit(&s->rc, &s->lzma.is_match[ s->lzma.state][pos_state])) { lzma_literal(s); } else { if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) lzma_rep_match(s, pos_state); else lzma_match(s, pos_state); if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) return false; } } /* * Having the range decoder always normalized when we are outside * this function makes it easier to correctly handle end of the chunk. */ rc_normalize(&s->rc); return true; } /* * Reset the LZMA decoder and range decoder state. Dictionary is nore reset * here, because LZMA state may be reset without resetting the dictionary. */ static void lzma_reset(struct xz_dec_lzma2 *s) { uint16 *probs; size_t i; s->lzma.state = STATE_LIT_LIT; s->lzma.rep0 = 0; s->lzma.rep1 = 0; s->lzma.rep2 = 0; s->lzma.rep3 = 0; /* * All probabilities are initialized to the same value. This hack * makes the code smaller by avoiding a separate loop for each * probability array. * * This could be optimized so that only that part of literal * probabilities that are actually required. In the common case * we would write 12 KiB less. */ probs = s->lzma.is_match[0]; for (i = 0; i < PROBS_TOTAL; ++i) probs[i] = RC_BIT_MODEL_TOTAL / 2; rc_reset(&s->rc); } /* * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks * from the decoded lp and pb values. On success, the LZMA decoder state is * reset and true is returned. */ static bool lzma_props(struct xz_dec_lzma2 *s, uint8 props) { if (props > (4 * 5 + 4) * 9 + 8) return false; s->lzma.pos_mask = 0; while (props >= 9 * 5) { props -= 9 * 5; ++s->lzma.pos_mask; } s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; s->lzma.literal_pos_mask = 0; while (props >= 9) { props -= 9; ++s->lzma.literal_pos_mask; } s->lzma.lc = props; if (s->lzma.lc + s->lzma.literal_pos_mask > 4) return false; s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; lzma_reset(s); return true; } /********* * LZMA2 * *********/ /* * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This * wrapper function takes care of making the LZMA decoder's assumption safe. * * As long as there is plenty of input left to be decoded in the current LZMA * chunk, we decode directly from the caller-supplied input buffer until * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into * s->temp.buf, which (hopefully) gets filled on the next call to this * function. We decode a few bytes from the temporary buffer so that we can * continue decoding from the caller-supplied input buffer again. */ static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) { size_t in_avail; uint32 tmp; in_avail = b->in_size - b->in_pos; if (s->temp.size > 0 || s->lzma2.compressed == 0) { tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; if (tmp > s->lzma2.compressed - s->temp.size) tmp = s->lzma2.compressed - s->temp.size; if (tmp > in_avail) tmp = in_avail; memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); if (s->temp.size + tmp == s->lzma2.compressed) { memzero(s->temp.buf + s->temp.size + tmp, sizeof(s->temp.buf) - s->temp.size - tmp); s->rc.in_limit = s->temp.size + tmp; } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { s->temp.size += tmp; b->in_pos += tmp; return true; } else { s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; } s->rc.in = s->temp.buf; s->rc.in_pos = 0; if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) return false; s->lzma2.compressed -= s->rc.in_pos; if (s->rc.in_pos < s->temp.size) { s->temp.size -= s->rc.in_pos; memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, s->temp.size); return true; } b->in_pos += s->rc.in_pos - s->temp.size; s->temp.size = 0; } in_avail = b->in_size - b->in_pos; if (in_avail >= LZMA_IN_REQUIRED) { s->rc.in = b->in; s->rc.in_pos = b->in_pos; if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) s->rc.in_limit = b->in_pos + s->lzma2.compressed; else s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; if (!lzma_main(s)) return false; in_avail = s->rc.in_pos - b->in_pos; if (in_avail > s->lzma2.compressed) return false; s->lzma2.compressed -= in_avail; b->in_pos = s->rc.in_pos; } in_avail = b->in_size - b->in_pos; if (in_avail < LZMA_IN_REQUIRED) { if (in_avail > s->lzma2.compressed) in_avail = s->lzma2.compressed; memcpy(s->temp.buf, b->in + b->in_pos, in_avail); s->temp.size = in_avail; b->in_pos += in_avail; } return true; } /* * Take care of the LZMA2 control layer, and forward the job of actual LZMA * decoding or copying of uncompressed chunks to other functions. */ XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b) { uint32 tmp; while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { switch (s->lzma2.sequence) { case SEQ_CONTROL: /* * LZMA2 control byte * * Exact values: * 0x00 End marker * 0x01 Dictionary reset followed by * an uncompressed chunk * 0x02 Uncompressed chunk (no dictionary reset) * * Highest three bits (s->control & 0xE0): * 0xE0 Dictionary reset, new properties and state * reset, followed by LZMA compressed chunk * 0xC0 New properties and state reset, followed * by LZMA compressed chunk (no dictionary * reset) * 0xA0 State reset using old properties, * followed by LZMA compressed chunk (no * dictionary reset) * 0x80 LZMA chunk (no dictionary or state reset) * * For LZMA compressed chunks, the lowest five bits * (s->control & 1F) are the highest bits of the * uncompressed size (bits 16-20). * * A new LZMA2 stream must begin with a dictionary * reset. The first LZMA chunk must set new * properties and reset the LZMA state. * * Values that don't match anything described above * are invalid and we return XZ_DATA_ERROR. */ tmp = b->in[b->in_pos++]; if (tmp == 0x00) return XZ_STREAM_END; if (tmp >= 0xE0 || tmp == 0x01) { s->lzma2.need_props = true; s->lzma2.need_dict_reset = false; dict_reset(&s->dict, b); } else if (s->lzma2.need_dict_reset) { return XZ_DATA_ERROR; } if (tmp >= 0x80) { s->lzma2.uncompressed = (tmp & 0x1F) << 16; s->lzma2.sequence = SEQ_UNCOMPRESSED_1; if (tmp >= 0xC0) { /* * When there are new properties, * state reset is done at * SEQ_PROPERTIES. */ s->lzma2.need_props = false; s->lzma2.next_sequence = SEQ_PROPERTIES; } else if (s->lzma2.need_props) { return XZ_DATA_ERROR; } else { s->lzma2.next_sequence = SEQ_LZMA_PREPARE; if (tmp >= 0xA0) lzma_reset(s); } } else { if (tmp > 0x02) return XZ_DATA_ERROR; s->lzma2.sequence = SEQ_COMPRESSED_0; s->lzma2.next_sequence = SEQ_COPY; } break; case SEQ_UNCOMPRESSED_1: s->lzma2.uncompressed += (uint32)b->in[b->in_pos++] << 8; s->lzma2.sequence = SEQ_UNCOMPRESSED_2; break; case SEQ_UNCOMPRESSED_2: s->lzma2.uncompressed += (uint32)b->in[b->in_pos++] + 1; s->lzma2.sequence = SEQ_COMPRESSED_0; break; case SEQ_COMPRESSED_0: s->lzma2.compressed = (uint32)b->in[b->in_pos++] << 8; s->lzma2.sequence = SEQ_COMPRESSED_1; break; case SEQ_COMPRESSED_1: s->lzma2.compressed += (uint32)b->in[b->in_pos++] + 1; s->lzma2.sequence = s->lzma2.next_sequence; break; case SEQ_PROPERTIES: if (!lzma_props(s, b->in[b->in_pos++])) return XZ_DATA_ERROR; s->lzma2.sequence = SEQ_LZMA_PREPARE; case SEQ_LZMA_PREPARE: if (s->lzma2.compressed < RC_INIT_BYTES) return XZ_DATA_ERROR; if (!rc_read_init(&s->rc, b)) return XZ_OK; s->lzma2.compressed -= RC_INIT_BYTES; s->lzma2.sequence = SEQ_LZMA_RUN; case SEQ_LZMA_RUN: /* * Set dictionary limit to indicate how much we want * to be encoded at maximum. Decode new data into the * dictionary. Flush the new data from dictionary to * b->out. Check if we finished decoding this chunk. * In case the dictionary got full but we didn't fill * the output buffer yet, we may run this loop * multiple times without changing s->lzma2.sequence. */ dict_limit(&s->dict, min_t(size_t, b->out_size - b->out_pos, s->lzma2.uncompressed)); if (!lzma2_lzma(s, b)) return XZ_DATA_ERROR; s->lzma2.uncompressed -= dict_flush(&s->dict, b); if (s->lzma2.uncompressed == 0) { if (s->lzma2.compressed > 0 || s->lzma.len > 0 || !rc_is_finished(&s->rc)) return XZ_DATA_ERROR; rc_reset(&s->rc); s->lzma2.sequence = SEQ_CONTROL; } else if (b->out_pos == b->out_size || (b->in_pos == b->in_size && s->temp.size < s->lzma2.compressed)) { return XZ_OK; } break; case SEQ_COPY: dict_uncompressed(&s->dict, b, &s->lzma2.compressed); if (s->lzma2.compressed > 0) return XZ_OK; s->lzma2.sequence = SEQ_CONTROL; break; } } return XZ_OK; } XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, uint32 dict_max) { struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); if (s == NULL) return NULL; s->dict.mode = mode; s->dict.size_max = dict_max; if (DEC_IS_PREALLOC(mode)) { s->dict.buf = vmalloc(dict_max); if (s->dict.buf == NULL) { kfree(s); return NULL; } } else if (DEC_IS_DYNALLOC(mode)) { s->dict.buf = NULL; s->dict.allocated = 0; } return s; } XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8 props) { /* This limits dictionary size to 3 GiB to keep parsing simpler. */ if (props > 39) return XZ_OPTIONS_ERROR; s->dict.size = 2 + (props & 1); s->dict.size <<= (props >> 1) + 11; if (DEC_IS_MULTI(s->dict.mode)) { if (s->dict.size > s->dict.size_max) return XZ_MEMLIMIT_ERROR; s->dict.end = s->dict.size; if (DEC_IS_DYNALLOC(s->dict.mode)) { if (s->dict.allocated < s->dict.size) { vfree(s->dict.buf); s->dict.buf = vmalloc(s->dict.size); if (s->dict.buf == NULL) { s->dict.allocated = 0; return XZ_MEM_ERROR; } } } } s->lzma.len = 0; s->lzma2.sequence = SEQ_CONTROL; s->lzma2.need_dict_reset = true; s->temp.size = 0; return XZ_OK; } XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s) { if (DEC_IS_MULTI(s->dict.mode)) vfree(s->dict.buf); kfree(s); } libxmp-4.4.1/src/depackers/xfd.c0000664000175000017500000000612112774567167016342 0ustar claudioclaudio/* xfdmaster.library decruncher for XMP * Copyright (C) 2007 Chris Young * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU Lesser General Public License. See COPYING.LIB * for more information. */ #ifdef __SUNPRO_C #pragma error_messages (off,E_EMPTY_TRANSLATION_UNIT) #endif #ifdef AMIGA #define __USE_INLINE__ #include #include #include #include #include struct local_data { struct Library *xfdMasterBase; #ifdef __amigaos4__ struct xfdMasterIFace *IxfdMaster; struct ExecIFace *IExec; // = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface; #endif }; struct xfdBufferInfo *open_xfd(struct local_data *data) { #ifdef __amigaos4__ data->IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface; #endif if(data->xfdMasterBase = OpenLibrary("xfdmaster.library",38)) { #ifdef __amigaos4__ if(data->IxfdMaster = (struct xfdMasterIFace *)GetInterface(data->xfdMasterBase,"main",1,NULL)) { #endif return(struct xfdBufferInfo *)xfdAllocObject(XFDOBJ_BUFFERINFO); #ifdef __amigaos4__ } #endif } close_xfd(NULL); return NULL; } void close_xfd(struct xfdBufferInfo *xfdobj, struct local_data *data) { if(xfdobj) { xfdFreeObject((APTR)xfdobj); xfdobj=NULL; } #ifdef __amigaos4__ if(data->IxfdMaster) { DropInterface((struct Interface *)data->IxfdMaster); data->IxfdMaster=NULL; } #endif if(data->xfdMasterBase) { CloseLibrary(data->xfdMasterBase); data->xfdMasterBase=NULL; } } static char *_test_xfd(unsigned char *buffer, int length) { char *ret = NULL; struct xfdBufferInfo *xfdobj; struct local_data data; if(xfdobj=open_xfd(&data)) { xfdobj->xfdbi_SourceBuffer = buffer; xfdobj->xfdbi_SourceBufLen = length; xfdobj->xfdbi_Flags = XFDFB_RECOGTARGETLEN | XFDFB_RECOGEXTERN; if(xfdRecogBuffer(xfdobj)) { ret = xfdobj->xfdbi_PackerName; } close_xfd(xfdobj, &data); } return(ret); } static int test_xfd(unsigned char *b) { return _test_xfd(b, 1024) != NULL; } static int decrunch_xfd(FILE *f1, FILE *f2) { struct xfdBufferInfo *xfdobj; uint8 *packed; int plen,ret=-1; struct stat st; struct local_data data; if (f2 == NULL) return -1; fstat(fileno(f1), &st); plen = st.st_size; packed = AllocVec(plen,MEMF_CLEAR); if (!packed) return -1; fread(packed,plen,1,f1); if(xfdobj=open_xfd(&data)) { xfdobj->xfdbi_SourceBufLen = plen; xfdobj->xfdbi_SourceBuffer = packed; xfdobj->xfdbi_Flags = XFDFF_RECOGEXTERN | XFDFF_RECOGTARGETLEN; /* xfdobj->xfdbi_PackerFlags = XFDPFF_RECOGLEN; */ if(xfdRecogBuffer(xfdobj)) { xfdobj->xfdbi_TargetBufMemType = MEMF_ANY; if(xfdDecrunchBuffer(xfdobj)) { if(fwrite(xfdobj->xfdbi_TargetBuffer,1,xfdobj->xfdbi_TargetBufSaveLen,f2) == xfdobj->xfdbi_TargetBufSaveLen) ret=0; FreeMem(xfdobj->xfdbi_TargetBuffer,xfdobj->xfdbi_TargetBufLen); } else { ret=-1; } } close_xfd(xfdobj, &data); } FreeVec(packed); return(ret); } struct depacker libxmp_depacker_xfd = { test_xfd, decrunch_xfd }; #endif /* AMIGA */ libxmp-4.4.1/src/depackers/unxz.c0000664000175000017500000000270412774567167016570 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU Lesser General Public License. See COPYING.LIB * for more information. */ #include #include #include #include "depacker.h" #include "xz.h" #include "crc32.h" #define BUFFER_SIZE 4096 static int test_xz(unsigned char *b) { return b[0] == 0xfd && b[3] == 'X' && b[4] == 'Z' && b[5] == 0x00; } static int decrunch_xz(FILE *in, FILE *out) { struct xz_buf b; struct xz_dec *state; unsigned char *membuf; int ret = 0; libxmp_crc32_init_A(); memset(&b, 0, sizeof(b)); if ((membuf = malloc(2 * BUFFER_SIZE)) == NULL) return -1; b.in = membuf; b.out = membuf + BUFFER_SIZE; b.out_size = BUFFER_SIZE; /* Limit memory usage to 16M */ state = xz_dec_init(XZ_DYNALLOC, 16 * 1024 * 1024); while (1) { enum xz_ret r; if (b.in_pos == b.in_size) { int rd = fread(membuf, 1, BUFFER_SIZE, in); if (rd < 0) { ret = -1; break; } b.in_size = rd; b.in_pos = 0; } r = xz_dec_run(state, &b); if (b.out_pos) { fwrite(b.out, 1, b.out_pos, out); b.out_pos = 0; } if (r == XZ_STREAM_END) { break; } if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { ret = -1; break; } } xz_dec_end(state); free(membuf); return ret; } struct depacker libxmp_depacker_xz = { test_xz, decrunch_xz }; libxmp-4.4.1/src/depackers/vorbis.h0000664000175000017500000003475612641457214017071 0ustar claudioclaudio#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H #define STB_VORBIS_INCLUDE_STB_VORBIS_H #if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) #define STB_VORBIS_NO_STDIO 1 #endif #ifndef STB_VORBIS_NO_STDIO #include #endif #ifdef __cplusplus extern "C" { #endif /////////// THREAD SAFETY // Individual stb_vorbis* handles are not thread-safe; you cannot decode from // them from multiple threads at the same time. However, you can have multiple // stb_vorbis* handles and decode from them independently in multiple thrads. /////////// MEMORY ALLOCATION // normally stb_vorbis uses malloc() to allocate memory at startup, // and alloca() to allocate temporary memory during a frame on the // stack. (Memory consumption will depend on the amount of setup // data in the file and how you set the compile flags for speed // vs. size. In my test files the maximal-size usage is ~150KB.) // // You can modify the wrapper functions in the source (setup_malloc, // setup_temp_malloc, temp_malloc) to change this behavior, or you // can use a simpler allocation model: you pass in a buffer from // which stb_vorbis will allocate _all_ its memory (including the // temp memory). "open" may fail with a VORBIS_outofmem if you // do not pass in enough data; there is no way to determine how // much you do need except to succeed (at which point you can // query get_info to find the exact amount required. yes I know // this is lame). // // If you pass in a non-NULL buffer of the type below, allocation // will occur from it as described above. Otherwise just pass NULL // to use malloc()/alloca() #ifdef HAVE_ALLOCA_H #include #endif typedef struct { char *alloc_buffer; int alloc_buffer_length_in_bytes; } stb_vorbis_alloc; /////////// FUNCTIONS USEABLE WITH ALL INPUT MODES typedef struct stb_vorbis stb_vorbis; typedef struct { unsigned int sample_rate; int channels; unsigned int setup_memory_required; unsigned int setup_temp_memory_required; unsigned int temp_memory_required; int max_frame_size; } stb_vorbis_info; // get general information about the file extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); // get the last error detected (clears it, too) extern int stb_vorbis_get_error(stb_vorbis *f); // close an ogg vorbis file and free all memory in use extern void stb_vorbis_close(stb_vorbis *f); // this function returns the offset (in samples) from the beginning of the // file that will be returned by the next decode, if it is known, or -1 // otherwise. after a flush_pushdata() call, this may take a while before // it becomes valid again. // NOT WORKING YET after a seek with PULLDATA API extern int stb_vorbis_get_sample_offset(stb_vorbis *f); // returns the current seek point within the file, or offset from the beginning // of the memory buffer. In pushdata mode it returns 0. extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); /////////// PUSHDATA API #ifndef STB_VORBIS_NO_PUSHDATA_API // this API allows you to get blocks of data from any source and hand // them to stb_vorbis. you have to buffer them; stb_vorbis will tell // you how much it used, and you have to give it the rest next time; // and stb_vorbis may not have enough data to work with and you will // need to give it the same data again PLUS more. Note that the Vorbis // specification does not bound the size of an individual frame. extern stb_vorbis *stb_vorbis_open_pushdata( unsigned char *datablock, int datablock_length_in_bytes, int *datablock_memory_consumed_in_bytes, int *error, stb_vorbis_alloc *alloc_buffer); // create a vorbis decoder by passing in the initial data block containing // the ogg&vorbis headers (you don't need to do parse them, just provide // the first N bytes of the file--you're told if it's not enough, see below) // on success, returns an stb_vorbis *, does not set error, returns the amount of // data parsed/consumed on this call in *datablock_memory_consumed_in_bytes; // on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed // if returns NULL and *error is VORBIS_need_more_data, then the input block was // incomplete and you need to pass in a larger block from the start of the file extern int stb_vorbis_decode_frame_pushdata( stb_vorbis *f, unsigned char *datablock, int datablock_length_in_bytes, int *channels, // place to write number of float * buffers float ***output, // place to write float ** array of float * buffers int *samples // place to write number of output samples ); // decode a frame of audio sample data if possible from the passed-in data block // // return value: number of bytes we used from datablock // possible cases: // 0 bytes used, 0 samples output (need more data) // N bytes used, 0 samples output (resynching the stream, keep going) // N bytes used, M samples output (one frame of data) // note that after opening a file, you will ALWAYS get one N-bytes,0-sample // frame, because Vorbis always "discards" the first frame. // // Note that on resynch, stb_vorbis will rarely consume all of the buffer, // instead only datablock_length_in_bytes-3 or less. This is because it wants // to avoid missing parts of a page header if they cross a datablock boundary, // without writing state-machiney code to record a partial detection. // // The number of channels returned are stored in *channels (which can be // NULL--it is always the same as the number of channels reported by // get_info). *output will contain an array of float* buffers, one per // channel. In other words, (*output)[0][0] contains the first sample from // the first channel, and (*output)[1][0] contains the first sample from // the second channel. extern void stb_vorbis_flush_pushdata(stb_vorbis *f); // inform stb_vorbis that your next datablock will not be contiguous with // previous ones (e.g. you've seeked in the data); future attempts to decode // frames will cause stb_vorbis to resynchronize (as noted above), and // once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it // will begin decoding the _next_ frame. // // if you want to seek using pushdata, you need to seek in your file, then // call stb_vorbis_flush_pushdata(), then start calling decoding, then once // decoding is returning you data, call stb_vorbis_get_sample_offset, and // if you don't like the result, seek your file again and repeat. #endif ////////// PULLING INPUT API #ifndef STB_VORBIS_NO_PULLDATA_API // This API assumes stb_vorbis is allowed to pull data from a source-- // either a block of memory containing the _entire_ vorbis stream, or a // FILE * that you or it create, or possibly some other reading mechanism // if you go modify the source to replace the FILE * case with some kind // of callback to your code. (But if you don't support seeking, you may // just want to go ahead and use pushdata.) #if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION) extern int stb_vorbis_decode_filename(char *filename, int *channels, short **output); #endif extern int stb_vorbis_decode_memory(unsigned char *mem, int len, int *channels, short **output); // decode an entire file and output the data interleaved into a malloc()ed // buffer stored in *output. The return value is the number of samples // decoded, or -1 if the file could not be opened or was not an ogg vorbis file. // When you're done with it, just free() the pointer returned in *output. extern stb_vorbis * stb_vorbis_open_memory(unsigned char *data, int len, int *error, stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from an ogg vorbis stream in memory (note // this must be the entire stream!). on failure, returns NULL and sets *error #ifndef STB_VORBIS_NO_STDIO extern stb_vorbis * stb_vorbis_open_filename(char *filename, int *error, stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from a filename via fopen(). on failure, // returns NULL and sets *error (possibly to VORBIS_file_open_failure). extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, int *error, stb_vorbis_alloc *alloc_buffer); // create an ogg vorbis decoder from an open FILE *, looking for a stream at // the _current_ seek point (ftell). on failure, returns NULL and sets *error. // note that stb_vorbis must "own" this stream; if you seek it in between // calls to stb_vorbis, it will become confused. Morever, if you attempt to // perform stb_vorbis_seek_*() operations on this file, it will assume it // owns the _entire_ rest of the file after the start point. Use the next // function, stb_vorbis_open_file_section(), to limit it. extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, int *error, stb_vorbis_alloc *alloc_buffer, unsigned int len); // create an ogg vorbis decoder from an open FILE *, looking for a stream at // the _current_ seek point (ftell); the stream will be of length 'len' bytes. // on failure, returns NULL and sets *error. note that stb_vorbis must "own" // this stream; if you seek it in between calls to stb_vorbis, it will become // confused. #endif extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); // NOT WORKING YET // these functions seek in the Vorbis file to (approximately) 'sample_number'. // after calling seek_frame(), the next call to get_frame_*() will include // the specified sample. after calling stb_vorbis_seek(), the next call to // stb_vorbis_get_samples_* will start with the specified sample. If you // do not need to seek to EXACTLY the target sample when using get_samples_*, // you can also use seek_frame(). extern void stb_vorbis_seek_start(stb_vorbis *f); // this function is equivalent to stb_vorbis_seek(f,0), but it // actually works extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); // these functions return the total length of the vorbis stream extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); // decode the next frame and return the number of samples. the number of // channels returned are stored in *channels (which can be NULL--it is always // the same as the number of channels reported by get_info). *output will // contain an array of float* buffers, one per channel. These outputs will // be overwritten on the next call to stb_vorbis_get_frame_*. // // You generally should not intermix calls to stb_vorbis_get_frame_*() // and stb_vorbis_get_samples_*(), since the latter calls the former. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); #endif // decode the next frame and return the number of samples per channel. the // data is coerced to the number of channels you request according to the // channel coercion rules (see below). You must pass in the size of your // buffer(s) so that stb_vorbis will not overwrite the end of the buffer. // The maximum buffer size needed can be gotten from get_info(); however, // the Vorbis I specification implies an absolute maximum of 4096 samples // per channel. Note that for interleaved data, you pass in the number of // shorts (the size of your array), but the return value is the number of // samples per channel, not the total number of samples. // Channel coercion rules: // Let M be the number of channels requested, and N the number of channels present, // and Cn be the nth channel; let stereo L be the sum of all L and center channels, // and stereo R be the sum of all R and center channels (channel assignment from the // vorbis spec). // M N output // 1 k sum(Ck) for all k // 2 * stereo L, stereo R // k l k > l, the first l channels, then 0s // k l k <= l, the first k channels // Note that this is not _good_ surround etc. mixing at all! It's just so // you get something useful. extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); // gets num_samples samples, not necessarily on a frame boundary--this requires // buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES. // Returns the number of samples stored per channel; it may be less than requested // at the end of the file. If there are no more samples in the file, returns 0. #ifndef STB_VORBIS_NO_INTEGER_CONVERSION extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); #endif // gets num_samples samples, not necessarily on a frame boundary--this requires // buffering so you have to supply the buffers. Applies the coercion rules above // to produce 'channels' channels. Returns the number of samples stored per channel; // it may be less than requested at the end of the file. If there are no more // samples in the file, returns 0. #endif //////// ERROR CODES enum STBVorbisError { VORBIS__no_error, VORBIS_need_more_data=1, // not a real error VORBIS_invalid_api_mixing, // can't mix API modes VORBIS_outofmem, // not enough memory VORBIS_feature_not_supported, // uses floor 0 VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small VORBIS_file_open_failure, // fopen() failed VORBIS_seek_without_length, // can't seek in unknown-length file VORBIS_unexpected_eof=10, // file is truncated? VORBIS_seek_invalid, // seek past EOF // decoding errors (corrupt/invalid stream) -- you probably // don't care about the exact details of these // vorbis errors: VORBIS_invalid_setup=20, VORBIS_invalid_stream, // ogg errors: VORBIS_missing_capture_pattern=30, VORBIS_invalid_stream_structure_version, VORBIS_continued_packet_flag_invalid, VORBIS_incorrect_stream_serial_number, VORBIS_invalid_first_page, VORBIS_bad_packet_type, VORBIS_cant_find_last_page, VORBIS_seek_failed, }; #ifdef __cplusplus } #endif #endif // STB_VORBIS_INCLUDE_STB_VORBIS_H libxmp-4.4.1/src/depackers/README.unxz0000664000175000017500000001244012304451505017252 0ustar claudioclaudio XZ Embedded =========== XZ Embedded is a relatively small, limited implementation of the .xz file format. Currently only decoding is implemented. XZ Embedded was written for use in the Linux kernel, but the code can be easily used in other environments too, including regular userspace applications. This README contains information that is useful only when the copy of XZ Embedded isn't part of the Linux kernel tree. You should also read linux/Documentation/xz.txt even if you aren't using XZ Embedded as part of Linux; information in that file is not repeated in this README. Compiling the Linux kernel module The xz_dec module depends on crc32 module, so make sure that you have it enabled (CONFIG_CRC32). Building the xz_dec and xz_dec_test modules without support for BCJ filters: cd linux/lib/xz make -C /path/to/kernel/source \ KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m Building the xz_dec and xz_dec_test modules with support for BCJ filters: cd linux/lib/xz make -C /path/to/kernel/source \ KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \ CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \ CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \ CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y If you want only one or a few of the BCJ filters, omit the appropriate variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support code shared between all BCJ filters. Most people don't need the xz_dec_test module. You can skip building it by omitting CONFIG_XZ_DEC_TEST=m from the make command line. Compiler requirements XZ Embedded should compile as either GNU-C89 (used in the Linux kernel) or with any C99 compiler. Getting the code to compile with non-GNU C89 compiler or a C++ compiler should be quite easy as long as there is a data type for unsigned 64-bit integer (or the code is modified not to support large files, which needs some more care than just using 32-bit integer instead of 64-bit). If you use GCC, try to use a recent version. For example, on x86-32, xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when compiled with GCC 4.3.3. Embedding into userspace applications To embed the XZ decoder, copy the following files into a single directory in your source code tree: linux/include/linux/xz.h linux/lib/xz/xz_crc32.c linux/lib/xz/xz_dec_lzma2.c linux/lib/xz/xz_dec_stream.c linux/lib/xz/xz_lzma2.h linux/lib/xz/xz_private.h linux/lib/xz/xz_stream.h userspace/xz_config.h Alternatively, xz.h may be placed into a different directory but then that directory must be in the compiler include path when compiling the .c files. Your code should use only the functions declared in xz.h. The rest of the .h files are meant only for internal use in XZ Embedded. You may want to modify xz_config.h to be more suitable for your build environment. Probably you should at least skim through it even if the default file works as is. BCJ filter support If you want support for one or more BCJ filters, you need to copy also linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate #defines in xz_config.h or in compiler flags. You don't need these #defines in the code that just uses XZ Embedded via xz.h, but having them always #defined doesn't hurt either. #define Instruction set BCJ filter endianness XZ_DEC_X86 x86-32 or x86-64 Little endian only XZ_DEC_POWERPC PowerPC Big endian only XZ_DEC_IA64 Itanium (IA-64) Big or little endian XZ_DEC_ARM ARM Little endian only XZ_DEC_ARMTHUMB ARM-Thumb Little endian only XZ_DEC_SPARC SPARC Big or little endian While some architectures are (partially) bi-endian, the endianness setting doesn't change the endianness of the instructions on all architectures. That's why Itanium and SPARC filters work for both big and little endian executables (Itanium has little endian instructions and SPARC has big endian instructions). There currently is no filter for little endian PowerPC or big endian ARM or ARM-Thumb. Implementing filters for them can be considered if there is a need for such filters in real-world applications. Notes about shared libraries If you are including XZ Embedded into a shared library, you very probably should rename the xz_* functions to prevent symbol conflicts in case your library is linked against some other library or application that also has XZ Embedded in it (which may even be a different version of XZ Embedded). TODO: Provide an easy way to do this. Please don't create a shared library of XZ Embedded itself unless it is fine to rebuild everything depending on that shared library everytime you upgrade to a newer version of XZ Embedded. There are no API or ABI stability guarantees between different versions of XZ Embedded. libxmp-4.4.1/src/depackers/s404_dec.c0000664000175000017500000002236612774567167017077 0ustar claudioclaudio/* StoneCracker S404 algorithm data decompression routine (c) 2006 Jouni 'Mr.Spiv' Korhonen. The code is in public domain. from shd: Some portability notes. We are using int32_t as a file size, and that fits all Amiga file sizes. size_t is of course the right choice. Warning: Code is not re-entrant. modified for xmp by Claudio Matsuoka, Jan 2010 (couldn't keep stdint types, some platforms we build on didn't like them) */ #include #include #include #include #include #include #include "common.h" #include "depacker.h" /* #include "compat.h" #include "s404_dec.h" */ struct bitstream { /* bit buffer for rolling data bit by bit from the compressed file */ uint32 word; /* bits left in the bit buffer */ int left; /* compressed data source */ uint16 *src; uint8 *orgsrc; }; static int initGetb(struct bitstream *bs, uint8 *src, uint32 src_length) { int eff; bs->src = (uint16 *) (src + src_length); bs->orgsrc = src; bs->left = readmem16b((uint8 *)bs->src); /* bit counter */ /*if (bs->left & (~0xf)) fprintf(stderr, "Workarounded an ancient stc bug\n");*/ /* mask off any corrupt bits */ bs->left &= 0x000f; bs->src--; /* get the first 16-bits of the compressed stream */ bs->word = readmem16b((uint8 *)bs->src); bs->src--; eff = readmem16b((uint8 *)bs->src); /* efficiency */ bs->src--; return eff; } /* get nbits from the compressed stream */ static int getb(struct bitstream *bs, int nbits) { bs->word &= 0x0000ffff; /* If not enough bits in the bit buffer, get more */ if (bs->left < nbits) { bs->word <<= bs->left; /* assert((bs->word & 0x0000ffffU) == 0); */ /* Check that we don't go out of bounds */ /*assert((uint8 *)bs->src >= bs->orgsrc);*/ if (bs->orgsrc > (uint8 *)bs->src) { return -1; } bs->word |= readmem16b((uint8 *)bs->src); bs->src--; nbits -= bs->left; bs->left = 16; /* 16 unused (and some used) bits left in the word */ } /* Shift nbits off the word and return them */ bs->left -= nbits; bs->word <<= nbits; return bs->word >> 16; } /* Returns bytes still to read.. or < 0 if error. */ static int checkS404File(uint32 *buf, /*size_t len,*/ int32 *oLen, int32 *pLen, int32 *sLen ) { /*if (len < 16) return -1;*/ if (memcmp(buf, "S404", 4) != 0) return -1; *sLen = readmem32b((uint8 *)&buf[1]); /* Security length */ if (*sLen < 0) return -1; *oLen = readmem32b((uint8 *)&buf[2]); /* Depacked length */ if (*oLen < 0) return -1; *pLen = readmem32b((uint8 *)&buf[3]); /* Packed length */ if (*pLen < 0) return -1; return 0; } static int decompressS404(uint8 *src, uint8 *orgdst, int32 dst_length, int32 src_length) { uint16 w; int32 eff; int32 n; uint8 *dst; int32 oLen = dst_length; struct bitstream bs; int x; dst = orgdst + oLen; eff = initGetb(&bs, src, src_length); /*printf("_bl: %02X, _bb: %04X, eff: %d\n",_bl,_bb, eff);*/ while (oLen > 0) { x = getb(&bs, 9); /* Sanity check */ if (x < 0) { return -1; } w = x; /*printf("oLen: %d _bl: %02X, _bb: %04X, w: %04X\n",oLen,_bl,_bb,w);*/ if (w < 0x100) { /*assert(dst > orgdst);*/ if (orgdst >= dst) { return -1; } *--dst = w; /*printf("0+[8] -> %02X\n",w);*/ oLen--; } else if (w == 0x13e || w == 0x13f) { w <<= 4; x = getb(&bs, 4); /* Sanity check */ if (x < 0) { return -1; } w |= x; n = (w & 0x1f) + 14; oLen -= n; while (n-- > 0) { x = getb(&bs, 8); /* Sanity check */ if (x < 0) { return -1; } w = x; /*printf("1+001+1111+[4] -> [8] -> %02X\n",w);*/ /*assert(dst > orgdst);*/ if (orgdst >= dst) { return -1; } *--dst = w; } } else { if (w >= 0x180) { /* copy 2-3 */ n = w & 0x40 ? 3 : 2; if (w & 0x20) { /* dist 545 -> */ w = (w & 0x1f) << (eff - 5); x = getb(&bs, eff - 5); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 544; /* printf("1+1+[1]+1+[%d] -> ", eff); */ } else if (w & 0x30) { // dist 1 -> 32 w = (w & 0x0f) << 1; x = getb(&bs, 1); /* Sanity check */ if (x < 0) { return -1; } w |= x; /* printf("1+1+[1]+01+[5] %d %02X %d %04X-> ",n,w, _bl, _bb); */ } else { /* dist 33 -> 544 */ w = (w & 0x0f) << 5; x = getb(&bs, 5); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 32; /* printf("1+1+[1]+00+[9] -> "); */ } } else if (w >= 0x140) { /* copy 4-7 */ n = ((w & 0x30) >> 4) + 4; if (w & 0x08) { /* dist 545 -> */ w = (w & 0x07) << (eff - 3); x = getb(&bs, eff - 3); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 544; /* printf("1+01+[2]+1+[%d] -> ", eff); */ } else if (w & 0x0c) { /* dist 1 -> 32 */ w = (w & 0x03) << 3; x = getb(&bs, 3); /* Sanity check */ if (x < 0) { return -1; } w |= x; /* printf("1+01+[2]+01+[5] -> "); */ } else { /* dist 33 -> 544 */ w = (w & 0x03) << 7; x = getb(&bs, 7); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 32; /* printf("1+01+[2]+00+[9] -> "); */ } } else if (w >= 0x120) { /* copy 8-22 */ n = ((w & 0x1e) >> 1) + 8; if (w & 0x01) { /* dist 545 -> */ x = getb(&bs, eff); /* Sanity check */ if (x < 0) { return -1; } w = x; w += 544; /* printf("1+001+[4]+1+[%d] -> ", eff); */ } else { x = getb(&bs, 6); /* Sanity check */ if (x < 0) { return -1; } w = x; if (w & 0x20) { /* dist 1 -> 32 */ w &= 0x1f; /* printf("1+001+[4]+001+[5] -> "); */ } else { /* dist 33 -> 544 */ w <<= 4; x = getb(&bs, 4); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 32; /* printf("1+001+[4]+00+[9] -> "); */ } } } else { w = (w & 0x1f) << 3; x = getb(&bs, 3); /* Sanity check */ if (x < 0) { return -1; } w |= x; n = 23; while (w == 0xff) { n += w; x = getb(&bs, 8); /* Sanity check */ if (x < 0) { return -1; } w = x; } n += w; x = getb(&bs, 7); w = x; if (w & 0x40) { /* dist 545 -> */ w = (w & 0x3f) << (eff - 6); x = getb(&bs, eff - 6); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 544; } else if (w & 0x20) { /* dist 1 -> 32 */ w &= 0x1f; /* printf("1+000+[8]+01+[5] -> "); */ } else { /* dist 33 -> 544; */ w <<= 4; x = getb(&bs, 4); /* Sanity check */ if (x < 0) { return -1; } w |= x; w += 32; /* printf("1+000+[8]+00+[9] -> "); */ } } /* printf("<%d,%d>\n",n,w+1); fflush(stdout); */ oLen -= n; while (n-- > 0) { /* printf("Copying: %02X\n",dst[w]); */ dst--; if (dst < orgdst || (dst + w + 1) >= (orgdst + dst_length)) return -1; *dst = dst[w + 1]; } } } return 0; } static int test_s404(unsigned char *b) { return memcmp(b, "S404", 4) == 0; } static int decrunch_s404(FILE *in, /* size_t s, */ FILE *out) { int32 oLen, sLen, pLen; uint8 *dst = NULL; struct stat st; uint8 *buf, *src; if (fstat(fileno(in), &st)) return -1; src = buf = malloc(st.st_size); if (src == NULL) return -1; if (fread(buf, 1, st.st_size, in) != st.st_size) { goto error; } if (checkS404File((uint32 *) src, /*s,*/ &oLen, &pLen, &sLen)) { /*fprintf(stderr,"S404 Error: checkS404File() failed..\n");*/ goto error; } /* Sanity check */ if (oLen < 0 || pLen < 0 || pLen + 16 < 0 || pLen + 16 >= st.st_size) { goto error; } if ((dst = malloc(oLen)) == NULL) { /*fprintf(stderr,"S404 Error: malloc(%d) failed..\n", oLen);*/ goto error; } /* src + 16 skips S404 header */ if (decompressS404(src + 16, dst, oLen, pLen) < 0) { goto error1; } if (fwrite(dst, oLen, 1, out) == 0) { /*fprintf(stderr,"S404 Error: fwrite() failed..\n");*/ goto error1; } free(dst); free(src); return 0; error1: free(dst); error: free(src); return -1; } struct depacker libxmp_depacker_s404 = { test_s404, decrunch_s404 }; libxmp-4.4.1/src/depackers/crc32.c0000664000175000017500000000460612773571316016471 0ustar claudioclaudio/* * CRC functions for libxmp * Copyright (C) 2013 Claudio Matsuoka * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "common.h" #include "crc32.h" uint32 libxmp_crc32_table_A[256]; uint32 libxmp_crc32_table_B[256]; static void crc_table_init_A(uint32 poly, uint32 *table) { int i, j; uint32 k; for (i = 0; i < 256; i++) { k = i; for (j = 0; j < 8; j++) { k = k & 1 ? (k >> 1) ^ poly : k >> 1; } table[i] = k; } return; } static void crc_table_init_B(uint32 poly, uint32 *table) { int i, j; uint32 k; for (i = 0; i < 256; i++) { k = i << 24; for (j = 0; j < 8; j++) { k = k & 0x80000000 ? (k << 1) ^ poly : k << 1; } table[i] = k; } return; } void libxmp_crc32_init_A() { static int flag = 0; if (flag) return; crc_table_init_A(0xedb88320, libxmp_crc32_table_A); flag = 1; } void libxmp_crc32_init_B() { static int flag = 0; if (flag) return; crc_table_init_B(0x04c11db7, libxmp_crc32_table_B); flag = 1; } uint32 libxmp_crc32_A1(const uint8 *buf, size_t size, uint32 crc) { crc = ~crc; while (size--) { crc = libxmp_crc32_table_A[*buf++ ^ (crc & 0xff)] ^ (crc >> 8); } return ~crc; } uint32 libxmp_crc32_A2(const uint8 *buf, size_t size, uint32 crc) { while (size--) { crc = libxmp_crc32_table_A[*buf++ ^ (crc & 0xff)] ^ (crc >> 8); } return crc; } libxmp-4.4.1/src/depackers/crc32.h0000664000175000017500000000047312773453056016474 0ustar claudioclaudio#ifndef LIBXMP_CRC_H #define LIBXMP_CRC_H extern uint32 libxmp_crc32_table_A[256]; extern uint32 libxmp_crc32_table_B[256]; void libxmp_crc32_init_A (void); uint32 libxmp_crc32_A1 (const uint8 *, size_t, uint32); uint32 libxmp_crc32_A2 (const uint8 *, size_t, uint32); void libxmp_crc32_init_B (void); #endif libxmp-4.4.1/src/depackers/gunzip.c0000664000175000017500000000377512774567167017111 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU Lesser General Public License. See COPYING.LIB * for more information. */ #include #include "common.h" #include "inflate.h" #include "depacker.h" #include "crc32.h" /* See RFC1952 for further information */ /* The flag byte is divided into individual bits as follows: bit 0 FTEXT bit 1 FHCRC bit 2 FEXTRA bit 3 FNAME bit 4 FCOMMENT bit 5 reserved bit 6 reserved bit 7 reserved */ #define FLAG_FTEXT (1 << 0) #define FLAG_FHCRC (1 << 1) #define FLAG_FEXTRA (1 << 2) #define FLAG_FNAME (1 << 3) #define FLAG_FCOMMENT (1 << 4) struct member { uint8 id1; uint8 id2; uint8 cm; uint8 flg; uint32 mtime; uint8 xfl; uint8 os; }; static int test_gzip(unsigned char *b) { return b[0] == 31 && b[1] == 139; } static int decrunch_gzip(FILE *in, FILE *out) { struct member member; int val, c; uint32 crc; libxmp_crc32_init_A(); member.id1 = read8(in, NULL); member.id2 = read8(in, NULL); member.cm = read8(in, NULL); member.flg = read8(in, NULL); member.mtime = read32l(in, NULL); member.xfl = read8(in, NULL); member.os = read8(in, NULL); if (member.cm != 0x08) { return -1; } if (member.flg & FLAG_FEXTRA) { int xlen = read16l(in, NULL); if (fseek(in, xlen, SEEK_CUR) < 0) { return -1; } } if (member.flg & FLAG_FNAME) { do { c = read8(in, NULL); } while (c != 0); } if (member.flg & FLAG_FCOMMENT) { do { c = read8(in, NULL); } while (c != 0); } if (member.flg & FLAG_FHCRC) { read16l(in, NULL); } val = libxmp_inflate(in, out, &crc, 1); if (val != 0) { return -1; } /* Check CRC32 */ val = read32l(in, NULL); if (val != crc) { return -1; } /* Check file size */ val = read32l(in, NULL); if (val != ftell(out)) { return -1; } return 0; } struct depacker libxmp_depacker_gzip = { test_gzip, decrunch_gzip }; libxmp-4.4.1/src/depackers/readlzw.h0000664000175000017500000000245112773453554017231 0ustar claudioclaudio/* nomarch 1.3 - extract old `.arc' archives. * Copyright (C) 2001,2002 Russell Marks. See main.c for license details. * * Modified for xmp by Claudio Matsuoka, Aug 2007 * * readlzw.h */ #ifndef LIBXMP_READLZW_H #define LIBXMP_READLZW_H #define ALIGN4(x) (((x) + 3) & ~3L) /* Digital Symphony LZW quirk */ #define XMP_LZW_QUIRK_DSYM (NOMARCH_QUIRK_END101|NOMARCH_QUIRK_NOCHK| \ NOMARCH_QUIRK_NOSYNC|NOMARCH_QUIRK_START101| \ NOMARCH_QUIRK_ALIGN4) #define NOMARCH_QUIRK_END101 (1L << 0) /* code 0x101 is end mark */ #define NOMARCH_QUIRK_NOCHK (1L << 1) /* don't check input size */ #define NOMARCH_QUIRK_NOSYNC (1L << 2) /* don't resync */ #define NOMARCH_QUIRK_START101 (1L << 3) /* start at 0x101 not 0x100 */ #define NOMARCH_QUIRK_ALIGN4 (1L << 4) /* input buffer size aligned */ #define NOMARCH_QUIRK_SKIPMAX (1L << 5) /* skip max code size */ struct local_data; uint8 *libxmp_convert_lzw_dynamic(unsigned char *data_in, int bits,int use_rle, unsigned long in_len, unsigned long orig_len, int q); uint8 *libxmp_read_lzw_dynamic(FILE *f, uint8 *buf, int max_bits,int use_rle, unsigned long in_len, unsigned long orig_len, int q); #endif libxmp-4.4.1/src/depackers/xz_config.h0000664000175000017500000000516112641457214017537 0ustar claudioclaudio/* * Private includes and definitions for userspace use of XZ Embedded * * Author: Lasse Collin * * This file has been put into the public domain. * You can do whatever you want with this file. */ #ifndef XZ_CONFIG_H #define XZ_CONFIG_H /* Uncomment as needed to enable BCJ filter decoders. */ /* #define XZ_DEC_X86 */ /* #define XZ_DEC_POWERPC */ /* #define XZ_DEC_IA64 */ /* #define XZ_DEC_ARM */ /* #define XZ_DEC_ARMTHUMB */ /* #define XZ_DEC_SPARC */ #define XZ_DEC_ANY_CHECK 1 #include #include #include "xz.h" #define kmalloc(size, flags) malloc(size) #define kfree(ptr) free(ptr) #define vmalloc(size) malloc(size) #define vfree(ptr) free(ptr) #define memeq(a, b, size) (memcmp(a, b, size) == 0) #define memzero(buf, size) memset(buf, 0, size) #ifndef min # define min(x, y) ((x) < (y) ? (x) : (y)) #endif #define min_t(type, x, y) min(x, y) /* * Some functions have been marked with __always_inline to keep the * performance reasonable even when the compiler is optimizing for * small code size. You may be able to save a few bytes by #defining * __always_inline to plain inline, but don't complain if the code * becomes slow. * * NOTE: System headers on GNU/Linux may #define this macro already, * so if you want to change it, you need to #undef it first. */ #ifndef __always_inline # ifdef __GNUC__ # define __always_inline \ inline __attribute__((__always_inline__)) # else # define __always_inline inline # endif #endif /* Inline functions to access unaligned unsigned 32-bit integers */ #ifndef get_unaligned_le32 static inline uint32 get_unaligned_le32(const uint8 *buf) { return (uint32)buf[0] | ((uint32)buf[1] << 8) | ((uint32)buf[2] << 16) | ((uint32)buf[3] << 24); } #endif #ifndef get_unaligned_be32 static inline uint32 get_unaligned_be32(const uint8 *buf) { return (uint32)(buf[0] << 24) | ((uint32)buf[1] << 16) | ((uint32)buf[2] << 8) | (uint32)buf[3]; } #endif #ifndef put_unaligned_le32 static inline void put_unaligned_le32(uint32 val, uint8 *buf) { buf[0] = (uint8)val; buf[1] = (uint8)(val >> 8); buf[2] = (uint8)(val >> 16); buf[3] = (uint8)(val >> 24); } #endif #ifndef put_unaligned_be32 static inline void put_unaligned_be32(uint32 val, uint8 *buf) { buf[0] = (uint8)(val >> 24); buf[1] = (uint8)(val >> 16); buf[2] = (uint8)(val >> 8); buf[3] = (uint8)val; } #endif /* * Use get_unaligned_le32() also for aligned access for simplicity. On * little endian systems, #define get_le32(ptr) (*(const uint32 *)(ptr)) * could save a few bytes in code size. */ #ifndef get_le32 # define get_le32 get_unaligned_le32 #endif #endif libxmp-4.4.1/src/depackers/xz_lzma2.h0000664000175000017500000001373412641457214017324 0ustar claudioclaudio/* * LZMA2 definitions * * Authors: Lasse Collin * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. */ #ifndef XZ_LZMA2_H #define XZ_LZMA2_H /* Range coder constants */ #define RC_SHIFT_BITS 8 #define RC_TOP_BITS 24 #define RC_TOP_VALUE (1 << RC_TOP_BITS) #define RC_BIT_MODEL_TOTAL_BITS 11 #define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) #define RC_MOVE_BITS 5 /* * Maximum number of position states. A position state is the lowest pb * number of bits of the current uncompressed offset. In some places there * are different sets of probabilities for different position states. */ #define POS_STATES_MAX (1 << 4) /* * This enum is used to track which LZMA symbols have occurred most recently * and in which order. This information is used to predict the next symbol. * * Symbols: * - Literal: One 8-bit byte * - Match: Repeat a chunk of data at some distance * - Long repeat: Multi-byte match at a recently seen distance * - Short repeat: One-byte repeat at a recently seen distance * * The symbol names are in from STATE_oldest_older_previous. REP means * either short or long repeated match, and NONLIT means any non-literal. */ enum lzma_state { STATE_LIT_LIT, STATE_MATCH_LIT_LIT, STATE_REP_LIT_LIT, STATE_SHORTREP_LIT_LIT, STATE_MATCH_LIT, STATE_REP_LIT, STATE_SHORTREP_LIT, STATE_LIT_MATCH, STATE_LIT_LONGREP, STATE_LIT_SHORTREP, STATE_NONLIT_MATCH, STATE_NONLIT_REP }; /* Total number of states */ #define STATES 12 /* The lowest 7 states indicate that the previous state was a literal. */ #define LIT_STATES 7 /* Indicate that the latest symbol was a literal. */ static inline void lzma_state_literal(enum lzma_state *state) { if (*state <= STATE_SHORTREP_LIT_LIT) *state = STATE_LIT_LIT; else if (*state <= STATE_LIT_SHORTREP) *state -= 3; else *state -= 6; } /* Indicate that the latest symbol was a match. */ static inline void lzma_state_match(enum lzma_state *state) { *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; } /* Indicate that the latest state was a long repeated match. */ static inline void lzma_state_long_rep(enum lzma_state *state) { *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; } /* Indicate that the latest symbol was a short match. */ static inline void lzma_state_short_rep(enum lzma_state *state) { *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; } /* Test if the previous symbol was a literal. */ static inline bool lzma_state_is_literal(enum lzma_state state) { return state < LIT_STATES; } /* Each literal coder is divided in three sections: * - 0x001-0x0FF: Without match byte * - 0x101-0x1FF: With match byte; match bit is 0 * - 0x201-0x2FF: With match byte; match bit is 1 * * Match byte is used when the previous LZMA symbol was something else than * a literal (that is, it was some kind of match). */ #define LITERAL_CODER_SIZE 0x300 /* Maximum number of literal coders */ #define LITERAL_CODERS_MAX (1 << 4) /* Minimum length of a match is two bytes. */ #define MATCH_LEN_MIN 2 /* Match length is encoded with 4, 5, or 10 bits. * * Length Bits * 2-9 4 = Choice=0 + 3 bits * 10-17 5 = Choice=1 + Choice2=0 + 3 bits * 18-273 10 = Choice=1 + Choice2=1 + 8 bits */ #define LEN_LOW_BITS 3 #define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) #define LEN_MID_BITS 3 #define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) #define LEN_HIGH_BITS 8 #define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) #define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) /* * Maximum length of a match is 273 which is a result of the encoding * described above. */ #define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) /* * Different sets of probabilities are used for match distances that have * very short match length: Lengths of 2, 3, and 4 bytes have a separate * set of probabilities for each length. The matches with longer length * use a shared set of probabilities. */ #define DIST_STATES 4 /* * Get the index of the appropriate probability array for decoding * the distance slot. */ static inline uint32 lzma_get_dist_state(uint32 len) { return len < DIST_STATES + MATCH_LEN_MIN ? len - MATCH_LEN_MIN : DIST_STATES - 1; } /* * The highest two bits of a 32-bit match distance are encoded using six bits. * This six-bit value is called a distance slot. This way encoding a 32-bit * value takes 6-36 bits, larger values taking more bits. */ #define DIST_SLOT_BITS 6 #define DIST_SLOTS (1 << DIST_SLOT_BITS) /* Match distances up to 127 are fully encoded using probabilities. Since * the highest two bits (distance slot) are always encoded using six bits, * the distances 0-3 don't need any additional bits to encode, since the * distance slot itself is the same as the actual distance. DIST_MODEL_START * indicates the first distance slot where at least one additional bit is * needed. */ #define DIST_MODEL_START 4 /* * Match distances greater than 127 are encoded in three pieces: * - distance slot: the highest two bits * - direct bits: 2-26 bits below the highest two bits * - alignment bits: four lowest bits * * Direct bits don't use any probabilities. * * The distance slot value of 14 is for distances 128-191. */ #define DIST_MODEL_END 14 /* Distance slots that indicate a distance <= 127. */ #define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) #define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) /* * For match distances greater than 127, only the highest two bits and the * lowest four bits (alignment) is encoded using probabilities. */ #define ALIGN_BITS 4 #define ALIGN_SIZE (1 << ALIGN_BITS) #define ALIGN_MASK (ALIGN_SIZE - 1) /* Total number of all probability variables */ #define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) /* * LZMA remembers the four most recent match distances. Reusing these * distances tends to take less space than re-encoding the actual * distance value. */ #define REPS 4 #endif libxmp-4.4.1/src/depackers/xz.h0000664000175000017500000002651612641457214016221 0ustar claudioclaudio/* * XZ decompressor * * Authors: Lasse Collin * Igor Pavlov * * This file has been put into the public domain. * You can do whatever you want with this file. */ #ifndef XZ_H #define XZ_H #ifdef __KERNEL__ # include # include #else /* # include # include */ # include "common.h" # define false 0 # define true 1 #ifndef B_BEOS_VERSION typedef int bool; #endif #endif #ifdef __cplusplus extern "C" { #endif /* In Linux, this is used to make extern functions static when needed. */ #ifndef XZ_EXTERN # define XZ_EXTERN extern #endif /** * enum xz_mode - Operation mode * * @XZ_SINGLE: Single-call mode. This uses less RAM than * than multi-call modes, because the LZMA2 * dictionary doesn't need to be allocated as * part of the decoder state. All required data * structures are allocated at initialization, * so xz_dec_run() cannot return XZ_MEM_ERROR. * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 * dictionary buffer. All data structures are * allocated at initialization, so xz_dec_run() * cannot return XZ_MEM_ERROR. * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is * allocated once the required size has been * parsed from the stream headers. If the * allocation fails, xz_dec_run() will return * XZ_MEM_ERROR. * * It is possible to enable support only for a subset of the above * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled * with support for all operation modes, but the preboot code may * be built with fewer features to minimize code size. */ enum xz_mode { XZ_SINGLE, XZ_PREALLOC, XZ_DYNALLOC }; /** * enum xz_ret - Return codes * @XZ_OK: Everything is OK so far. More input or more * output space is required to continue. This * return code is possible only in multi-call mode * (XZ_PREALLOC or XZ_DYNALLOC). * @XZ_STREAM_END: Operation finished successfully. * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding * is still possible in multi-call mode by simply * calling xz_dec_run() again. * Note that this return value is used only if * XZ_DEC_ANY_CHECK was defined at build time, * which is not used in the kernel. Unsupported * check types return XZ_OPTIONS_ERROR if * XZ_DEC_ANY_CHECK was not defined at build time. * @XZ_MEM_ERROR: Allocating memory failed. This return code is * possible only if the decoder was initialized * with XZ_DYNALLOC. The amount of memory that was * tried to be allocated was no more than the * dict_max argument given to xz_dec_init(). * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than * allowed by the dict_max argument given to * xz_dec_init(). This return value is possible * only in multi-call mode (XZ_PREALLOC or * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) * ignores the dict_max argument. * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic * bytes). * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested * compression options. In the decoder this means * that the header CRC32 matches, but the header * itself specifies something that we don't support. * @XZ_DATA_ERROR: Compressed data is corrupt. * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly * different between multi-call and single-call * mode; more information below. * * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls * to XZ code cannot consume any input and cannot produce any new output. * This happens when there is no new input available, or the output buffer * is full while at least one output byte is still pending. Assuming your * code is not buggy, you can get this error only when decoding a compressed * stream that is truncated or otherwise corrupt. * * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer * is too small or the compressed input is corrupt in a way that makes the * decoder produce more output than the caller expected. When it is * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR * is used instead of XZ_BUF_ERROR. */ enum xz_ret { XZ_OK, XZ_STREAM_END, XZ_UNSUPPORTED_CHECK, XZ_MEM_ERROR, XZ_MEMLIMIT_ERROR, XZ_FORMAT_ERROR, XZ_OPTIONS_ERROR, XZ_DATA_ERROR, XZ_BUF_ERROR }; /** * struct xz_buf - Passing input and output buffers to XZ code * @in: Beginning of the input buffer. This may be NULL if and only * if in_pos is equal to in_size. * @in_pos: Current position in the input buffer. This must not exceed * in_size. * @in_size: Size of the input buffer * @out: Beginning of the output buffer. This may be NULL if and only * if out_pos is equal to out_size. * @out_pos: Current position in the output buffer. This must not exceed * out_size. * @out_size: Size of the output buffer * * Only the contents of the output buffer from out[out_pos] onward, and * the variables in_pos and out_pos are modified by the XZ code. */ struct xz_buf { const uint8 *in; size_t in_pos; size_t in_size; uint8 *out; size_t out_pos; size_t out_size; }; /** * struct xz_dec - Opaque type to hold the XZ decoder state */ struct xz_dec; /** * xz_dec_init() - Allocate and initialize a XZ decoder state * @mode: Operation mode * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for * multi-call decoding. This is ignored in single-call mode * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes * or 2^n + 2^(n-1) bytes (the latter sizes are less common * in practice), so other values for dict_max don't make sense. * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, * 512 KiB, and 1 MiB are probably the only reasonable values, * except for kernel and initramfs images where a bigger * dictionary can be fine and useful. * * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at * once. The caller must provide enough output space or the decoding will * fail. The output space is used as the dictionary buffer, which is why * there is no need to allocate the dictionary as part of the decoder's * internal state. * * Because the output buffer is used as the workspace, streams encoded using * a big dictionary are not a problem in single-call mode. It is enough that * the output buffer is big enough to hold the actual uncompressed data; it * can be smaller than the dictionary size stored in the stream headers. * * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes * of memory is preallocated for the LZMA2 dictionary. This way there is no * risk that xz_dec_run() could run out of memory, since xz_dec_run() will * never allocate any memory. Instead, if the preallocated dictionary is too * small for decoding the given input stream, xz_dec_run() will return * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be * decoded to avoid allocating excessive amount of memory for the dictionary. * * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): * dict_max specifies the maximum allowed dictionary size that xz_dec_run() * may allocate once it has parsed the dictionary size from the stream * headers. This way excessive allocations can be avoided while still * limiting the maximum memory usage to a sane value to prevent running the * system out of memory when decompressing streams from untrusted sources. * * On success, xz_dec_init() returns a pointer to struct xz_dec, which is * ready to be used with xz_dec_run(). If memory allocation fails, * xz_dec_init() returns NULL. */ XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32 dict_max); /** * xz_dec_run() - Run the XZ decoder * @s: Decoder state allocated using xz_dec_init() * @b: Input and output buffers * * The possible return values depend on build options and operation mode. * See enum xz_ret for details. * * Note that if an error occurs in single-call mode (return value is not * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the * contents of the output buffer from b->out[b->out_pos] onward are * undefined. This is true even after XZ_BUF_ERROR, because with some filter * chains, there may be a second pass over the output buffer, and this pass * cannot be properly done if the output buffer is truncated. Thus, you * cannot give the single-call decoder a too small buffer and then expect to * get that amount valid data from the beginning of the stream. You must use * the multi-call decoder if you don't want to uncompress the whole stream. */ XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b); /** * xz_dec_reset() - Reset an already allocated decoder state * @s: Decoder state allocated using xz_dec_init() * * This function can be used to reset the multi-call decoder state without * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). * * In single-call mode, xz_dec_reset() is always called in the beginning of * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in * multi-call mode. */ XZ_EXTERN void xz_dec_reset(struct xz_dec *s); /** * xz_dec_end() - Free the memory allocated for the decoder state * @s: Decoder state allocated using xz_dec_init(). If s is NULL, * this function does nothing. */ XZ_EXTERN void xz_dec_end(struct xz_dec *s); /* * Standalone build (userspace build or in-kernel build for boot time use) * needs a CRC32 implementation. For normal in-kernel use, kernel's own * CRC32 module is used instead, and users of this module don't need to * care about the functions below. */ #ifndef XZ_INTERNAL_CRC32 # ifdef __KERNEL__ # define XZ_INTERNAL_CRC32 0 # else # define XZ_INTERNAL_CRC32 1 # endif #endif #if XZ_INTERNAL_CRC32 /* * This must be called before any other xz_* function to initialize * the CRC32 lookup table. */ XZ_EXTERN void xz_crc32_init(void); /* * Update CRC32 value using the polynomial from IEEE-802.3. To start a new * calculation, the third argument must be zero. To continue the calculation, * the previously returned value is passed as the third argument. */ XZ_EXTERN uint32 xz_crc32(const uint8 *buf, size_t size, uint32 crc); #endif #ifdef __cplusplus } #endif #endif libxmp-4.4.1/src/depackers/ppdepack.c0000664000175000017500000001624712774567167017362 0ustar claudioclaudio/* PowerPacker decrunch * Based on code by Stuart Caie * This software is in the Public Domain */ /* Code from Heikki Orsila's amigadepack 0.02 to replace previous * PowerPack depacker with license issues. * * Modified for xmp by Claudio Matsuoka, 08/2007 * - merged mld's checks from the old depack sources. Original credits: * - corrupt file and data detection * (thanks to Don Adan and Dirk Stoecker for help and infos) * - implemeted "efficiency" checks * - further detection based on code by Georg Hoermann * * Modified for xmp by Claudio Matsuoka, 05/2013 * - decryption code removed */ #include #include #include #include #include #include #include "common.h" #include "depacker.h" /* #define val(p) ((p)[0]<<16 | (p)[1] << 8 | (p)[2]) */ static int savefile(FILE *fo, void *mem, size_t length) { int ok = fo && (fwrite(mem, 1, length, fo) == length); return ok; } #define PP_READ_BITS(nbits, var) do { \ bit_cnt = (nbits); \ while (bits_left < bit_cnt) { \ if (buf_src < src) return 0; /* out of source bits */ \ bit_buffer |= (*--buf_src << bits_left); \ bits_left += 8; \ } \ (var) = 0; \ bits_left -= bit_cnt; \ while (bit_cnt--) { \ (var) = ((var) << 1) | (bit_buffer & 1); \ bit_buffer >>= 1; \ } \ } while(0) #define PP_BYTE_OUT(byte) do { \ if (out <= dest) return 0; /* output overflow */ \ *--out = (byte); \ written++; \ } while (0) static int ppDecrunch(uint8 *src, uint8 *dest, uint8 *offset_lens, uint32 src_len, uint32 dest_len, uint8 skip_bits) { uint8 *buf_src, *out, *dest_end, bits_left = 0, bit_cnt; uint32 bit_buffer = 0, x, todo, offbits, offset, written=0; if (src == NULL || dest == NULL || offset_lens == NULL) return 0; /* set up input and output pointers */ buf_src = src + src_len; out = dest_end = dest + dest_len; /* skip the first few bits */ PP_READ_BITS(skip_bits, x); /* while there are input bits left */ while (written < dest_len) { PP_READ_BITS(1, x); if (x == 0) { /* 1bit==0: literal, then match. 1bit==1: just match */ todo = 1; do { PP_READ_BITS(2, x); todo += x; } while (x == 3); while (todo--) { PP_READ_BITS(8, x); PP_BYTE_OUT(x); } /* should we end decoding on a literal, break out of the main loop */ if (written == dest_len) break; } /* match: read 2 bits for initial offset bitlength / match length */ PP_READ_BITS(2, x); offbits = offset_lens[x]; todo = x+2; if (x == 3) { PP_READ_BITS(1, x); if (x==0) offbits = 7; PP_READ_BITS(offbits, offset); do { PP_READ_BITS(3, x); todo += x; } while (x == 7); } else { PP_READ_BITS(offbits, offset); } if ((out + offset) >= dest_end) return 0; /* match overflow */ while (todo--) { x = out[offset]; PP_BYTE_OUT(x); } } /* all output bytes written without error */ return 1; /* return (src == buf_src) ? 1 : 0; */ } static int ppdepack(uint8 *data, size_t len, FILE *fo) { /* PP FORMAT: * 1 longword identifier 'PP20' or 'PX20' * [1 word checksum (if 'PX20') $ssss] * 1 longword efficiency $eeeeeeee * X longwords crunched file $cccccccc,$cccccccc,... * 1 longword decrunch info 'decrlen' << 8 | '8 bits other info' */ int success=0; uint8 *output /*, crypted*/; uint32 outlen; if (len < 16) { /*fprintf(stderr, "File is too short to be a PP file (%u bytes)\n", len);*/ return -1; } if (data[0]=='P' && data[1]=='P' && data[2]=='2' && data[3]=='0') { if (len & 0x03) { /*fprintf(stderr, "File length is not a multiple of 4\n");*/ return -1; } /*crypted = 0;*/ } #if 0 else if (data[0]=='P' && data[1]=='X' && data[2]=='2' && data[3]=='0') { if ((len-2) & 0x03) { /*fprintf(stderr, "(file length - 2) is not a multiple of 4\n");*/ return -1; } crypted = 1; } #endif else { /*fprintf(stderr, "File does not have the PP signature\n");*/ return -1; } outlen = readmem24b(data + len - 4); /* fprintf(stderr, "decrunched length = %u bytes\n", outlen); */ output = (uint8 *) malloc(outlen); if (output == NULL) { /*fprintf(stderr, "out of memory!\n");*/ return -1; } /* if (crypted == 0) { */ /*fprintf(stderr, "not encrypted, decrunching anyway\n"); */ if (ppDecrunch(&data[8], output, &data[4], len-12, outlen, data[len-1])) { /* fprintf(stderr, "Decrunch successful! "); */ savefile(fo, (void *) output, outlen); } else { success=-1; } /*} else { success=-1; }*/ free(output); return success; } static int test_pp(unsigned char *b) { return memcmp(b, "PP20", 4) == 0; } static int decrunch_pp(FILE *f, FILE *fo) { uint8 *packed /*, *unpacked */; int plen, unplen; struct stat st; if (fo == NULL) goto err; if (fstat(fileno(f), &st) < 0) goto err; plen = st.st_size; //counter = 0; /* Amiga longwords are only on even addresses. * The pp20 data format has the length stored in a longword * after the packed data, so I guess a file that is not even * is probl not a valid pp20 file. Thanks for Don Adan for * reminding me on this! - mld */ if ((plen != (plen / 2) * 2)) { /*fprintf(stderr, "filesize not even\n");*/ goto err; } packed = malloc(plen); if (packed == NULL) { /*fprintf(stderr, "can't allocate memory for packed data\n");*/ goto err; } if (fread(packed, 1, plen, f) != plen) { goto err1; } /* Hmmh... original pp20 only support efficiency from 9 9 9 9 up to 9 10 12 13, afaik * but the xfd detection code says this... *sigh* * * move.l 4(a0),d0 * cmp.b #9,d0 * blo.b .Exit * and.l #$f0f0f0f0,d0 * bne.s .Exit */ if (((packed[4] < 9) || (packed[5] < 9) || (packed[6] < 9) || (packed[7] < 9))) { /*fprintf(stderr, "invalid efficiency\n");*/ goto err1; } if (((readmem24b(packed +4) * 256 + packed[7]) & 0xf0f0f0f0) != 0 ) { /*fprintf(stderr, "invalid efficiency(?)\n");*/ goto err1; } unplen = readmem24b(packed + plen - 4); if (!unplen) { /*fprintf(stderr, "not a powerpacked file\n");*/ goto err1; } if (ppdepack (packed, plen, fo) == -1) { /*fprintf(stderr, "error while decrunching data...");*/ goto err1; } free (packed); return 0; err1: free(packed); err: return -1; } struct depacker libxmp_depacker_pp = { test_pp, decrunch_pp }; libxmp-4.4.1/src/depackers/bunzip2.c0000664000175000017500000005263112774567167017161 0ustar claudioclaudio/* vi: set sw=4 ts=4: */ /* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), which also acknowledges contributions by Mike Burrows, David Wheeler, Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, Robert Sedgewick, and Jon L. Bentley. This code is licensed under the LGPLv2: LGPL (http://www.gnu.org/copyleft/lgpl.html */ /* Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org). More efficient reading of huffman codes, a streamlined read_bunzip() function, and various other tweaks. In (limited) tests, approximately 20% faster than bzcat on x86 and about 10% faster on arm. Note that about 2/3 of the time is spent in read_unzip() reversing the Burrows-Wheeler transformation. Much of that time is delay resulting from cache misses. I would ask that anyone benefiting from this work, especially those using it in commercial products, consider making a donation to my local non-profit hospice organization (see www.hospiceacadiana.com) in the name of the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003. Manuel */ /* Modified for xmp by Claudio Matsuoka, 20120809 */ #include #include #include #include #include #include #include "common.h" #include "depacker.h" #include "crc32.h" /* Constants for huffman coding */ #define MAX_GROUPS 6 #define GROUP_SIZE 50 /* 64 would have been more efficient */ #define MAX_HUFCODE_BITS 20 /* Longest huffman code allowed */ #define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */ #define SYMBOL_RUNA 0 #define SYMBOL_RUNB 1 /* Status return values */ #define RETVAL_OK 0 #define RETVAL_LAST_BLOCK (-1) #define RETVAL_NOT_BZIP_DATA (-2) #define RETVAL_UNEXPECTED_INPUT_EOF (-3) #define RETVAL_UNEXPECTED_OUTPUT_EOF (-4) #define RETVAL_DATA_ERROR (-5) #define RETVAL_OUT_OF_MEMORY (-6) #define RETVAL_OBSOLETE_INPUT (-7) /* Other housekeeping constants */ #define IOBUF_SIZE 4096 /* This is what we know about each huffman coding group */ struct group_data { /* We have an extra slot at the end of limit[] for a sentinal value. */ int limit[MAX_HUFCODE_BITS+1],base[MAX_HUFCODE_BITS],permute[MAX_SYMBOLS]; int minLen, maxLen; }; /* Structure holding all the housekeeping data, including IO buffers and memory that persists between calls to bunzip */ typedef struct { /* State for interrupting output loop */ int writeCopies,writePos,writeRunCountdown,writeCount,writeCurrent; /* I/O tracking data (file handles, buffers, positions, etc.) */ FILE *in,*out; int inbufCount,inbufPos /*,outbufPos*/; unsigned char *inbuf /*,*outbuf*/; unsigned int inbufBitCount, inbufBits; /* The CRC values stored in the block header and calculated from the data */ unsigned int headerCRC, totalCRC, writeCRC; /* Intermediate buffer and its size (in bytes) */ unsigned int *dbuf, dbufSize; /* These things are a bit too big to go on the stack */ unsigned char selectors[32768]; /* nSelectors=15 bits */ struct group_data groups[MAX_GROUPS]; /* huffman coding tables */ /* For I/O error handling */ jmp_buf jmpbuf; } bunzip_data; /* Return the next nnn bits of input. All reads from the compressed input are done through this function. All reads are big endian */ static unsigned int get_bits(bunzip_data *bd, char bits_wanted) { unsigned int bits=0; /* If we need to get more data from the byte buffer, do so. (Loop getting one byte at a time to enforce endianness and avoid unaligned access.) */ while (bd->inbufBitCountinbufPos==bd->inbufCount) { if((bd->inbufCount = fread(bd->inbuf, 1, IOBUF_SIZE, bd->in)) <= 0) longjmp(bd->jmpbuf,RETVAL_UNEXPECTED_INPUT_EOF); bd->inbufPos=0; } /* Avoid 32-bit overflow (dump bit buffer to top of output) */ if(bd->inbufBitCount>=24) { bits=bd->inbufBits&((1<inbufBitCount)-1); bits_wanted-=bd->inbufBitCount; bits<<=bits_wanted; bd->inbufBitCount=0; } /* Grab next 8 bits of input from buffer. */ bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++]; bd->inbufBitCount+=8; } /* Calculate result */ bd->inbufBitCount-=bits_wanted; bits|=(bd->inbufBits>>bd->inbufBitCount)&((1<dbuf; dbufSize=bd->dbufSize; selectors=bd->selectors; /* Reset longjmp I/O error handling */ i=setjmp(bd->jmpbuf); if(i) return i; /* Read in header signature and CRC, then validate signature. (last block signature means CRC is for whole file, return now) */ i = get_bits(bd,24); j = get_bits(bd,24); bd->headerCRC=get_bits(bd,32); if ((i == 0x177245) && (j == 0x385090)) return RETVAL_LAST_BLOCK; if ((i != 0x314159) || (j != 0x265359)) return RETVAL_NOT_BZIP_DATA; /* We can add support for blockRandomised if anybody complains. There was some code for this in busybox 1.0.0-pre3, but nobody ever noticed that it didn't actually work. */ if(get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT; if((origPtr=get_bits(bd,24)) > dbufSize) return RETVAL_DATA_ERROR; /* mapping table: if some byte values are never used (encoding things like ascii text), the compression code removes the gaps to have fewer symbols to deal with, and writes a sparse bitfield indicating which values were present. We make a translation table to convert the symbols back to the corresponding bytes. */ t=get_bits(bd, 16); symTotal=0; for (i=0;i<16;i++) { if(t&(1<<(15-i))) { k=get_bits(bd,16); for(j=0;j<16;j++) if(k&(1<<(15-j))) symToByte[symTotal++]=(16*i)+j; } } /* How many different huffman coding groups does this block use? */ groupCount=get_bits(bd,3); if (groupCount<2 || groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR; /* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding group. Read in the group selector list, which is stored as MTF encoded bit runs. (MTF=Move To Front, as each value is used it's moved to the start of the list.) */ if(!(nSelectors=get_bits(bd, 15))) return RETVAL_DATA_ERROR; for(i=0; i=groupCount) return RETVAL_DATA_ERROR; /* Decode MTF to get the next selector */ uc = mtfSymbol[j]; for(;j;j--) mtfSymbol[j] = mtfSymbol[j-1]; mtfSymbol[0]=selectors[i]=uc; } /* Read the huffman coding tables for each group, which code for symTotal literal symbols, plus two run symbols (RUNA, RUNB) */ symCount=symTotal+2; for (j=0; j (MAX_HUFCODE_BITS-1)) return RETVAL_DATA_ERROR; /* If first bit is 0, stop. Else second bit indicates whether to increment or decrement the value. Optimization: grab 2 bits and unget the second if the first was 0. */ k = get_bits(bd,2); if (k < 2) { bd->inbufBitCount++; break; } /* Add one if second bit 1, else subtract 1. Avoids if/else */ t+=(((k+1)&2)-1); } /* Correct for the initial -1, to get the final symbol length */ length[i]=t+1; } /* Find largest and smallest lengths in this group */ minLen=maxLen=length[0]; for(i = 1; i < symCount; i++) { if(length[i] > maxLen) maxLen = length[i]; else if(length[i] < minLen) minLen = length[i]; } /* Calculate permute[], base[], and limit[] tables from length[]. * * permute[] is the lookup table for converting huffman coded symbols * into decoded symbols. base[] is the amount to subtract from the * value of a huffman symbol of a given length when using permute[]. * * limit[] indicates the largest numerical value a symbol with a given * number of bits can have. This is how the huffman codes can vary in * length: each code with a value>limit[length] needs another bit. */ hufGroup=bd->groups+j; hufGroup->minLen = minLen; hufGroup->maxLen = maxLen; /* Note that minLen can't be smaller than 1, so we adjust the base and limit array pointers so we're not always wasting the first entry. We do this again when using them (during symbol decoding).*/ base=hufGroup->base-1; limit=hufGroup->limit-1; /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ pp=0; for(i=minLen;i<=maxLen;i++) { temp[i]=limit[i]=0; for(t=0;tpermute[pp++] = t; } /* Count symbols coded for at each bit length */ for (i=0;ilimit[length] comparison. */ limit[i]= (pp << (maxLen - i)) - 1; pp<<=1; base[i+1]=pp-(t+=temp[i]); } limit[maxLen+1] = INT_MAX; /* Sentinal value for reading next sym. */ limit[maxLen]=pp+temp[maxLen]-1; base[minLen]=0; } /* We've finished reading and digesting the block header. Now read this block's huffman coded symbols from the file and undo the huffman coding and run length encoding, saving the result into dbuf[dbufCount++]=uc */ /* Initialize symbol occurrence counters and symbol Move To Front table */ for(i=0;i<256;i++) { byteCount[i] = 0; mtfSymbol[i]=(unsigned char)i; } /* Loop through compressed symbols. */ runPos=dbufCount=symCount=selector=0; for(;;) { /* Determine which huffman coding group to use. */ if(!(symCount--)) { symCount=GROUP_SIZE-1; if(selector>=nSelectors) return RETVAL_DATA_ERROR; hufGroup=bd->groups+selectors[selector++]; base=hufGroup->base-1; limit=hufGroup->limit-1; } /* Read next huffman-coded symbol. */ /* Note: It is far cheaper to read maxLen bits and back up than it is to read minLen bits and then an additional bit at a time, testing as we go. Because there is a trailing last block (with file CRC), there is no danger of the overread causing an unexpected EOF for a valid compressed file. As a further optimization, we do the read inline (falling back to a call to get_bits if the buffer runs dry). The following (up to got_huff_bits:) is equivalent to j=get_bits(bd,hufGroup->maxLen); */ while (bd->inbufBitCountmaxLen) { if(bd->inbufPos==bd->inbufCount) { j = get_bits(bd,hufGroup->maxLen); goto got_huff_bits; } bd->inbufBits=(bd->inbufBits<<8)|bd->inbuf[bd->inbufPos++]; bd->inbufBitCount+=8; }; bd->inbufBitCount-=hufGroup->maxLen; j = (bd->inbufBits>>bd->inbufBitCount)&((1<maxLen)-1); got_huff_bits: /* Figure how how many bits are in next symbol and unget extras */ i=hufGroup->minLen; while(j>limit[i]) ++i; bd->inbufBitCount += (hufGroup->maxLen - i); /* Huffman decode value to get nextSym (with bounds checking) */ if ((i > hufGroup->maxLen) || (((unsigned)(j=(j>>(hufGroup->maxLen-i))-base[i])) >= MAX_SYMBOLS)) return RETVAL_DATA_ERROR; nextSym = hufGroup->permute[j]; /* We have now decoded the symbol, which indicates either a new literal byte, or a repeated run of the most recent literal byte. First, check if nextSym indicates a repeated run, and if so loop collecting how many times to repeat the last literal. */ if (((unsigned)nextSym) <= SYMBOL_RUNB) { /* RUNA or RUNB */ /* If this is the start of a new run, zero out counter */ if(!runPos) { runPos = 1; t = 0; } /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at each bit position, add 1 or 2 instead. For example, 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. You can make any bit pattern that way using 1 less symbol than the basic or 0/1 method (except all bits 0, which would use no symbols, but a run of length 0 doesn't mean anything in this context). Thus space is saved. */ t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ runPos <<= 1; continue; } /* When we hit the first non-run symbol after a run, we now know how many times to repeat the last literal, so append that many copies to our buffer of decoded symbols (dbuf) now. (The last literal used is the one at the head of the mtfSymbol array.) */ if(runPos) { runPos=0; if(t < 0 || t > dbufSize || dbufCount+t>=dbufSize) return RETVAL_DATA_ERROR; uc = symToByte[mtfSymbol[0]]; byteCount[uc] += t; while(t--) dbuf[dbufCount++]=uc; } /* Is this the terminating symbol? */ if(nextSym>symTotal) break; /* At this point, nextSym indicates a new literal character. Subtract one to get the position in the MTF array at which this literal is currently to be found. (Note that the result can't be -1 or 0, because 0 and 1 are RUNA and RUNB. But another instance of the first symbol in the mtf array, position 0, would have been handled as part of a run above. Therefore 1 unused mtf position minus 2 non-literal nextSym values equals -1.) */ if(dbufCount>=dbufSize) return RETVAL_DATA_ERROR; i = nextSym - 1; uc = mtfSymbol[i]; /* Adjust the MTF array. Since we typically expect to move only a * small number of symbols, and are bound by 256 in any case, using * memmove here would typically be bigger and slower due to function * call overhead and other assorted setup costs. */ do { mtfSymbol[i] = mtfSymbol[i-1]; } while (--i); mtfSymbol[0] = uc; uc=symToByte[uc]; /* We have our literal byte. Save it into dbuf. */ byteCount[uc]++; dbuf[dbufCount++] = (unsigned int)uc; } /* At this point, we've read all the huffman-coded symbols (and repeated runs) for this block from the input stream, and decoded them into the intermediate buffer. There are dbufCount many decoded bytes in dbuf[]. Now undo the Burrows-Wheeler transform on dbuf. See http://dogma.net/markn/articles/bwt/bwt.htm */ /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ j=0; for(i=0;i<256;i++) { k=j+byteCount[i]; byteCount[i] = j; j=k; } /* Figure out what order dbuf would be in if we sorted it. */ for (i=0;i=dbufCount) return RETVAL_DATA_ERROR; bd->writePos=dbuf[origPtr]; bd->writeCurrent=(unsigned char)(bd->writePos&0xff); bd->writePos>>=8; bd->writeRunCountdown=5; } bd->writeCount=dbufCount; return RETVAL_OK; } /* Undo burrows-wheeler transform on intermediate buffer to produce output. If start_bunzip was initialized with out_fd=-1, then up to len bytes of data are written to outbuf. Return value is number of bytes written or error (all errors are negative numbers). If out_fd!=-1, outbuf and len are ignored, data is written to out_fd and return is RETVAL_OK or error. */ static int read_bunzip(bunzip_data *bd, char *outbuf, int len) { const unsigned int *dbuf; int pos,current,previous,gotcount; /* If last read was short due to end of file, return last block now */ if(bd->writeCount<0) return bd->writeCount; gotcount = 0; dbuf=bd->dbuf; pos=bd->writePos; current=bd->writeCurrent; /* We will always have pending decoded data to write into the output buffer unless this is the very first call (in which case we haven't huffman-decoded a block into the intermediate buffer yet). */ if (bd->writeCopies) { /* Inside the loop, writeCopies means extra copies (beyond 1) */ --bd->writeCopies; /* Loop outputting bytes */ for(;;) { /* If the output buffer is full, snapshot state and return */ if(gotcount >= len) { bd->writePos=pos; bd->writeCurrent=current; bd->writeCopies++; return len; } /* Write next byte into output buffer, updating CRC */ outbuf[gotcount++] = current; bd->writeCRC=(((bd->writeCRC)<<8) ^libxmp_crc32_table_B[((bd->writeCRC)>>24)^current]); /* Loop now if we're outputting multiple copies of this byte */ if (bd->writeCopies) { --bd->writeCopies; continue; } decode_next_byte: if (!bd->writeCount--) break; /* Follow sequence vector to undo Burrows-Wheeler transform */ previous=current; pos=dbuf[pos]; current=pos&0xff; pos>>=8; /* After 3 consecutive copies of the same byte, the 4th is a repeat count. We count down from 4 instead * of counting up because testing for non-zero is faster */ if(--bd->writeRunCountdown) { if(current!=previous) bd->writeRunCountdown=4; } else { /* We have a repeated run, this byte indicates the count */ bd->writeCopies=current; current=previous; bd->writeRunCountdown=5; /* Sometimes there are just 3 bytes (run length 0) */ if(!bd->writeCopies) goto decode_next_byte; /* Subtract the 1 copy we'd output anyway to get extras */ --bd->writeCopies; } } /* Decompression of this block completed successfully */ bd->writeCRC=~bd->writeCRC; bd->totalCRC=((bd->totalCRC<<1) | (bd->totalCRC>>31)) ^ bd->writeCRC; /* If this block had a CRC error, force file level CRC error. */ if(bd->writeCRC!=bd->headerCRC) { bd->totalCRC=bd->headerCRC+1; return RETVAL_LAST_BLOCK; } } /* Refill the intermediate buffer by huffman-decoding next block of input */ /* (previous is just a convenient unused temp variable here) */ previous=get_next_block(bd); if(previous) { bd->writeCount=previous; return (previous!=RETVAL_LAST_BLOCK) ? previous : gotcount; } bd->writeCRC=0xffffffffUL; pos=bd->writePos; current=bd->writeCurrent; goto decode_next_byte; } /* Allocate the structure, read file header. If in_fd==-1, inbuf must contain a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are ignored, and data is read from file handle into temporary buffer. */ static int start_bunzip(bunzip_data **bdp, FILE *in, char *inbuf, int len) { bunzip_data *bd; unsigned int i; const unsigned int BZh0=(((unsigned int)'B')<<24)+(((unsigned int)'Z')<<16) +(((unsigned int)'h')<<8)+(unsigned int)'0'; /* Figure out how much data to allocate */ i=sizeof(bunzip_data); if(in!=NULL) i+=IOBUF_SIZE; /* Allocate bunzip_data. Most fields initialize to zero. */ if(!(bd=*bdp=malloc(i))) return RETVAL_OUT_OF_MEMORY; memset(bd,0,sizeof(bunzip_data)); /* Setup input buffer */ if(NULL==(bd->in=in)) { bd->inbuf=(unsigned char *)inbuf; bd->inbufCount=len; } else bd->inbuf=(unsigned char *)(bd+1); #if 0 /* Init the CRC32 table (big endian) */ for(i=0;i<256;i++) { c=i<<24; for(j=8;j;j--) c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); bd->crc32Table[i]=c; } #endif /* Setup for I/O error handling via longjmp */ i=setjmp(bd->jmpbuf); if(i) return i; /* Ensure that file starts with "BZh['1'-'9']." */ i = get_bits(bd,32); if (((unsigned int)(i-BZh0-1)) >= 9) return RETVAL_NOT_BZIP_DATA; /* Fourth byte (ascii '1'-'9'), indicates block size in units of 100k of uncompressed data. Allocate intermediate buffer for block. */ bd->dbufSize=100000*(i-BZh0); if(!(bd->dbuf=malloc(bd->dbufSize * sizeof(unsigned int)))) return RETVAL_OUT_OF_MEMORY; return RETVAL_OK; } static int test_bzip2(unsigned char *b) { return b[0] == 'B' && b[1] == 'Z' && b[2] == 'h'; } /* Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, not end of file.) */ static int decrunch_bzip2(FILE *src, FILE *dst) { char *outbuf; bunzip_data *bd; int i; libxmp_crc32_init_B(); if(!(outbuf=malloc(IOBUF_SIZE))) return RETVAL_OUT_OF_MEMORY; if(!(i=start_bunzip(&bd,src,0,0))) { for(;;) { if((i=read_bunzip(bd,outbuf,IOBUF_SIZE)) <= 0) break; if(i!=fwrite(outbuf,1,i,dst)) { i=RETVAL_UNEXPECTED_OUTPUT_EOF; break; } } } /* Check CRC and release memory */ if(i==RETVAL_LAST_BLOCK && bd->headerCRC==bd->totalCRC) i=RETVAL_OK; if(bd->dbuf) free(bd->dbuf); free(bd); free(outbuf); return i == 0 ? 0 : -1; } struct depacker libxmp_depacker_bzip2 = { test_bzip2, decrunch_bzip2 }; libxmp-4.4.1/src/depackers/unarc.c0000664000175000017500000002133112774567167016671 0ustar claudioclaudio/* nomarch 1.4 - extract old `.arc' archives. * Copyright (C) 2001-2006 Russell Marks. * * main.c - most of the non-extraction stuff. * * Modified by Claudio Matsuoka for xmp, 24-Aug-2007 * Relicensed under the LGPL for libxmp, 15-Aug-2012 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define NOMARCH_VER "1.4" #include #include #include #include #include "common.h" #include "depacker.h" #include "readrle.h" #include "readhuff.h" #include "readlzw.h" struct archived_file_header_tag { unsigned char method; char name[13]; unsigned long compressed_size; /* 4 bytes in file */ unsigned int date, time, crc; /* 2 bytes each in file */ unsigned long orig_size; /* 4 bytes in file */ int has_crc; }; /* there is no overall header for the archive, but there's a header * for each file stored in it. * returns zero if we couldn't get a header. * NB: a header with method zero marks EOF. */ static int read_file_header(FILE * in, struct archived_file_header_tag *hdrp) { unsigned char buf[4 + 2 + 2 + 2 + 4]; /* used to read size1/date/time/crc/size2 */ int bufsiz = sizeof(buf); int method_high; int c; hdrp->method = 0xff; if (fgetc(in) != 0x1a) return 0; if ((c = fgetc(in)) == EOF) return 0; /* allow for the spark archive variant's alternate method encoding */ method_high = (c >> 7); hdrp->method = (c & 127); /* zero if EOF, which also means no further `header' */ if (hdrp->method == 0) return 1; /* `old' version of uncompressed storage was weird */ if (hdrp->method == 1) bufsiz -= 4; /* no `orig_size' field */ if (fread(hdrp->name, 1, sizeof(hdrp->name), in) != sizeof(hdrp->name) || fread(buf, 1, bufsiz, in) != bufsiz) return 0; /* extract the bits from buf */ hdrp->compressed_size = readmem32l(buf); hdrp->date = readmem16l(buf + 4); hdrp->time = readmem16l(buf + 6); hdrp->crc = readmem16l(buf + 8); /* yes, only 16-bit CRC */ hdrp->has_crc = 1; if (hdrp->method == 1) hdrp->orig_size = hdrp->compressed_size; else hdrp->orig_size = readmem32l(buf + 10); /* make *sure* name is asciiz */ hdrp->name[12] = 0; #if 0 /* strip top bits, and lowercase the name */ for (f = 0; f < strlen(hdrp->name); f++) hdrp->name[f] = maybe_downcase(hdrp->name[f] & 127); #endif /* lose the possible extra bytes in spark archives */ if (method_high) { if (fread(buf, 1, 12, in) != 12) return 0; /* has a weird recursive-.arc file scheme for subdirs, * and since these are supposed to be dealt with inline * (though they aren't here) the CRCs could be junk. * So check for it being marked as a stored dir. */ if (hdrp->method == 2 && buf[3] == 0xff && buf[2] == 0xfd && buf[1] == 0xdc) hdrp->has_crc = 0; } return 1; } /* self-extracting archives, for both CP/M and MS-DOS, have up to * 3 bytes before the initial ^Z. This skips those if present. * Returns zero if there's an input error, or we fail to find ^Z in * the first 4 bytes. * * This should work with self-extracting archives for CP/M * (e.g. unarc16.ark), and those produced by `arc'. It won't work with * pkpak self-extracting archives, for two reasons: * * - they have 4 bytes before the ^Z. * - they have an EOF member (zero byte) right after that, giving you * an archive containing no files (grrr). * * So I thought it was better (and less confusing) to effectively stick * with the not-an-archive error for those. :-) */ static int skip_sfx_header(FILE * in) { int c, f, got = 0; for (f = 0; f < 4; f++) { if ((c = fgetc(in)) == EOF) return 0; if (c == 0x1a) { got = 1; ungetc(c, in); break; } } return got; } /* read file data, assuming header has just been read from in * and hdrp's data matches it. Caller is responsible for freeing * the memory allocated. * Returns NULL for file I/O error only; OOM is fatal (doesn't return). */ static unsigned char *read_file_data(FILE * in, struct archived_file_header_tag *hdrp) { unsigned char *data; int siz = hdrp->compressed_size; if ((data = malloc(siz)) == NULL) return NULL; if (fread(data, 1, siz, in) != siz) { free(data); data = NULL; } return data; } #if 0 /* variant which just skips past the data */ static int skip_file_data(FILE *in,struct archived_file_header_tag *hdrp) { int siz = hdrp->compressed_size; int f; for(f = 0; f < siz; f++) if (fgetc(in) == EOF) return 0; return 1; } #endif static int arc_extract(FILE *in, FILE *out) { struct archived_file_header_tag hdr; /* int done = 0; */ unsigned char *data, *orig_data; int exitval = 0; if (!skip_sfx_header(in) || !read_file_header(in, &hdr)) return -1; #if 0 /* We don't files named 'From?' */ while (!strcmp(hdr.name, "From?") || *hdr.name == '!') { if (!skip_file_data(in,&hdr)) return -1; if (!read_file_header(in, &hdr)) return -1; } #endif /* extract a single file */ /* do { */ if (hdr.method == 0) { /* EOF */ /* done = 1; continue; */ return -1; } /* error reading data (hit EOF) */ if ((data = read_file_data(in, &hdr)) == NULL) return -1; orig_data = NULL; /* FWIW, most common types are (by far) 8/9 and 2. * (127 is the most common in Spark archives, but only those.) * 3 and 4 crop up occasionally. 5 and 6 are very, very rare. * And I don't think I've seen a *single* file with 1 or 7 yet. */ switch (hdr.method) { case 2: /* no compression */ orig_data = data; hdr.orig_size = hdr.compressed_size; break; #if 0 case 3: /* "packed" (RLE) */ supported = 1; orig_data = convert_rle(data, hdr.compressed_size, hdr.orig_size); break; case 4: /* "squeezed" (Huffman, like CP/M `SQ') */ supported = 1; orig_data = convert_huff(data, hdr.compressed_size, hdr.orig_size); break; case 5: /* "crunched" (12-bit static LZW) */ orig_data = libxmp_convert_lzw_dynamic(data, 0, 0, hdr.compressed_size, hdr.orig_size, 0); break; case 6: /* "crunched" (RLE+12-bit static LZW) */ orig_data = libxmp_convert_lzw_dynamic(data, 0, 1, hdr.compressed_size, hdr.orig_size, 0); break; case 7: /* PKPAK docs call this one "internal to SEA" */ /* it looks like this one was only used by a development version * of SEA ARC, so chances are it can be safely ignored. * OTOH, it's just method 6 with a slightly different hash, * so I presume it wouldn't be *that* hard to add... :-) */ break; #endif case 8: /* "Crunched" [sic] * (RLE+9-to-12-bit dynamic LZW, a *bit* like GIF) */ orig_data = libxmp_convert_lzw_dynamic(data, 12, 1, hdr.compressed_size, hdr.orig_size, NOMARCH_QUIRK_SKIPMAX); break; case 9: /* "Squashed" (9-to-13-bit, no RLE) */ orig_data = libxmp_convert_lzw_dynamic(data, 13, 0, hdr.compressed_size, hdr.orig_size, 0); break; case 127: /* "Compress" (9-to-16-bit, no RLE) ("Spark" only) */ orig_data = libxmp_convert_lzw_dynamic(data, 16, 0, hdr.compressed_size, hdr.orig_size, 0); break; default: free(data); return -1; } /* there was a `pak 2.0' which added a type 10 ("distill"), but I don't * plan to support that unless there's some desperate need for it. */ if (orig_data == NULL) { free(data); return -1; } if (fwrite(orig_data, 1, hdr.orig_size, out) != hdr.orig_size) exitval = -1; if (orig_data != data) /* don't free uncompressed stuff twice :-) */ free(orig_data); free(data); return exitval; } static int test_arc(unsigned char *b) { if (b[0] == 0x1a) { int x = b[1] & 0x7f; int i, flag = 0; long size; /* check file name */ for (i = 0; i < 13; i++) { if (b[2 + i] == 0) { if (i == 0) /* name can't be empty */ flag = 1; break; } if (!isprint(b[2 + i])) { /* name must be printable */ flag = 1; break; } } size = readmem32l(b + 15); /* max file size is 512KB */ if (size < 0 || size > 512 * 1024) flag = 1; if (flag == 0) { if (x >= 1 && x <= 9 && x != 7) { /* Arc */ return 1; } else if (x == 0x7f) { /* !Spark */ return 1; } } } return 0; } static int decrunch_arc(FILE *f, FILE *fo) { return arc_extract(f, fo); } struct depacker libxmp_depacker_arc = { test_arc, decrunch_arc }; libxmp-4.4.1/src/depackers/uncompress.c0000664000175000017500000001461012774567167017761 0ustar claudioclaudio/* public domain decompress code */ #include #include #include "depacker.h" #define MAGIC_1 31 /* First byte of compressed file */ #define MAGIC_2 157 /* Second byte of compressed file */ #define BIT_MASK 0x1f /* Mask for 'number of compresssion bits */ /* Masks 0x20 and 0x40 are free. */ #define BITS 16 #define HSIZE 69001 /* 95% occupancy */ #define FIRST 257 /* first free entry */ #define CLEAR 256 /* table clear output code */ #define INIT_BITS 9 /* initial number of bits/code */ #define BLOCK_MODE 0x80 /* Block compresssion if table is full and */ #define MAXCODE(n) (1L << (n)) /* compression rate is dropping flush tables */ #define IBUFSIZ BUFSIZ /* Default input buffer size */ #define OBUFSIZ BUFSIZ /* Default output buffer size */ #define input(b,o,c,n,m) { \ char_type *p = &(b)[(o)>>3]; \ (c) = ((((long)(p[0]))|((long)(p[1])<<8)| \ ((long)(p[2])<<16))>>((o)&0x7))&(m); \ (o) += (n); \ } while (0) typedef unsigned char char_type; typedef long int code_int; typedef long int count_int; typedef long int cmp_code_int; #define htabof(i) htab[i] #define codetabof(i) codetab[i] #define tab_prefixof(i) codetabof(i) #define tab_suffixof(i) ((char_type *)(htab))[i] #define de_stack ((char_type *)&(htab[HSIZE-1])) #define clear_htab() memset(htab, -1, sizeof(htab)) #define clear_tab_prefixof() memset(codetab, 0, 256); static int test_compress(unsigned char *b) { return b[0] == 31 && b[1] == 157; } /* * Decompress stdin to stdout. This routine adapts to the codes in the * file building the "string" table on-the-fly; requiring no table to * be stored in the compressed file. The tables used herein are shared * with those of the compress() routine. See the definitions above. */ static int decrunch_compress(FILE * in, FILE * out) { char_type *stackp; code_int code; int finchar; code_int oldcode; code_int incode; int inbits; int posbits; int outpos; int insize; int bitmask; code_int free_ent; code_int maxcode; code_int maxmaxcode; int n_bits; int rsize; int maxbits; int block_mode; int i; long bytes_in; /* Total number of byte from input */ /*long bytes_out;*/ /* Total number of byte to output */ char_type inbuf[IBUFSIZ + 64]; /* Input buffer */ char_type outbuf[OBUFSIZ + 2048];/* Output buffer */ count_int htab[HSIZE]; unsigned short codetab[HSIZE]; insize = 0; rsize = fread(inbuf, 1, IBUFSIZ, in); insize += rsize; if (insize < 3 || inbuf[0] != MAGIC_1 || inbuf[1] != MAGIC_2) { return -1; } maxbits = inbuf[2] & BIT_MASK; block_mode = inbuf[2] & BLOCK_MODE; maxmaxcode = MAXCODE(maxbits); if (maxbits > BITS) { /*fprintf(stderr, "%s: compressed with %d bits, can only handle %d bits\n", (*ifname != '\0' ? ifname : "stdin"), maxbits, BITS); exit_code = 4; */ return -1; } bytes_in = insize; maxcode = MAXCODE(n_bits = INIT_BITS) - 1; bitmask = (1 << n_bits) - 1; oldcode = -1; finchar = 0; outpos = 0; posbits = 3 << 3; free_ent = ((block_mode) ? FIRST : 256); clear_tab_prefixof(); /* As above, initialize the first 256 entries in the table. */ for (code = 255; code >= 0; --code) tab_suffixof(code) = (char_type) code; do { resetbuf:; { int i; int e; int o; o = posbits >> 3; e = o <= insize ? insize - o : 0; for (i = 0; i < e; ++i) inbuf[i] = inbuf[i + o]; insize = e; posbits = 0; } if (insize < sizeof(inbuf) - IBUFSIZ) { if ((rsize = fread(inbuf + insize, 1, IBUFSIZ, in)) < 0) return -1; insize += rsize; } inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : (insize << 3) - (n_bits - 1)); while (inbits > posbits) { if (free_ent > maxcode) { posbits = ((posbits - 1) + ((n_bits << 3) - (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); ++n_bits; if (n_bits == maxbits) maxcode = maxmaxcode; else maxcode = MAXCODE(n_bits) - 1; bitmask = (1 << n_bits) - 1; goto resetbuf; } input(inbuf, posbits, code, n_bits, bitmask); if (oldcode == -1) { if (code >= 256) { fprintf(stderr, "oldcode:-1 code:%i\n", (int)(code)); fprintf(stderr, "uncompress: corrupt input\n"); /* abort_compress(); */ return -1; } outbuf[outpos++] = (char_type)(finchar = (int)(oldcode = code)); continue; } if (code == CLEAR && block_mode) { clear_tab_prefixof(); free_ent = FIRST - 1; posbits = ((posbits - 1) + ((n_bits << 3) - (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); maxcode = MAXCODE(n_bits = INIT_BITS) - 1; bitmask = (1 << n_bits) - 1; goto resetbuf; } incode = code; stackp = de_stack; if (code >= free_ent) { /* Special case for KwKwK string. */ if (code > free_ent) { /*char_type *p; posbits -= n_bits; p = &inbuf[posbits >> 3]; fprintf(stderr, "insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)\n", insize, posbits, p[-1], p[0], p[1], p[2], p[3], (posbits & 07));*/ fprintf(stderr, "uncompress: corrupt input\n"); /* abort_compress(); */ return -1; } *--stackp = (char_type) finchar; code = oldcode; } while ((cmp_code_int) code >= (cmp_code_int) 256) { /* Generate output characters in reverse order */ *--stackp = tab_suffixof(code); code = tab_prefixof(code); } *--stackp = (char_type) (finchar = tab_suffixof(code)); /* And put them out in forward order */ if (outpos + (i = (de_stack - stackp)) >= OBUFSIZ) { do { if (i > OBUFSIZ - outpos) i = OBUFSIZ - outpos; if (i > 0) { memcpy(outbuf + outpos, stackp, i); outpos += i; } if (outpos >= OBUFSIZ) { if (fwrite(outbuf, 1, outpos, out) != outpos) { return -1; /*write_error(); */ } outpos = 0; } stackp += i; } while ((i = (de_stack - stackp)) > 0); } else { memcpy(outbuf + outpos, stackp, i); outpos += i; } if ((code = free_ent) < maxmaxcode) { /* Generate the new entry. */ tab_prefixof(code) = (unsigned short)oldcode; tab_suffixof(code) = (char_type) finchar; free_ent = code + 1; } oldcode = incode; /* Remember previous code. */ } bytes_in += rsize; } while (rsize > 0); if (outpos > 0 && fwrite(outbuf, 1, outpos, out) != outpos) return -1; return 0; } struct depacker libxmp_depacker_compress = { test_compress, decrunch_compress }; libxmp-4.4.1/src/depackers/Makefile0000664000175000017500000000130412760420620017024 0ustar claudioclaudio DEPACKERS_OBJS = ppdepack.o unsqsh.o mmcmp.o readrle.o readlzw.o \ unarc.o arcfs.o xfd.o inflate.o muse.o unlzx.o s404_dec.o \ unzip.o gunzip.o uncompress.o unxz.o bunzip2.o unlha.o \ xz_dec_lzma2.o xz_dec_stream.o oxm.o vorbis.o crc32.o DEPACKERS_DFILES = Makefile $(DEPACKERS_OBJS:.o=.c) readhuff.h readlzw.h \ readrle.h inflate.h xz_lzma2.h README.unxz xz.h \ xz_private.h xz_stream.h xz_config.h vorbis.h crc32.h DEPACKERS_PATH = src/depackers OBJS += $(addprefix $(DEPACKERS_PATH)/,$(DEPACKERS_OBJS)) default-depackers:: $(MAKE) -C .. dist-depackers:: mkdir -p $(DIST)/$(DEPACKERS_PATH) cp -RPp $(addprefix $(DEPACKERS_PATH)/,$(DEPACKERS_DFILES)) $(DIST)/$(DEPACKERS_PATH) libxmp-4.4.1/src/tempfile.c0000664000175000017500000000605212777410253015412 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef __SUNPRO_C #pragma error_messages (off,E_EMPTY_TRANSLATION_UNIT) #endif #ifndef LIBXMP_CORE_PLAYER #include #include #include #include #include #ifdef HAVE_UMASK #include #endif #include "tempfile.h" #ifdef WIN32 int mkstemp(char *); static int get_temp_dir(char *buf, int size) { const char def[] = "C:\\WINDOWS\\TEMP"; char *tmp = getenv("TEMP"); strncpy(buf, tmp ? tmp : def, size); strncat(buf, "\\", size); return 0; } #elif defined __AMIGA__ static int get_temp_dir(char *buf, int size) { strncpy(buf, "T:", size); return 0; } #elif defined __ANDROID__ #include #include static int get_temp_dir(char *buf, int size) { #define APPDIR "/sdcard/Xmp for Android" struct stat st; if (stat(APPDIR, &st) < 0) { if (mkdir(APPDIR, 0777) < 0) return -1; } if (stat(APPDIR "/tmp", &st) < 0) { if (mkdir(APPDIR "/tmp", 0777) < 0) return -1; } strncpy(buf, APPDIR "/tmp/", size); return 0; } #else static int get_temp_dir(char *buf, int size) { char *tmp = getenv("TMPDIR"); if (tmp) { snprintf(buf, size, "%s/", tmp); } else { strncpy(buf, "/tmp/", size); } return 0; } #endif FILE *make_temp_file(char **filename) { char tmp[PATH_MAX]; FILE *temp; int fd; if (get_temp_dir(tmp, PATH_MAX) < 0) return NULL; strncat(tmp, "xmp_XXXXXX", PATH_MAX - 10); if ((*filename = strdup(tmp)) == NULL) goto err; #ifdef HAVE_UMASK umask(0177); #endif if ((fd = mkstemp(*filename)) < 0) goto err2; if ((temp = fdopen(fd, "w+b")) == NULL) goto err3; return temp; err3: close(fd); err2: free(*filename); err: return NULL; } /* * Windows doesn't allow you to unlink an open file, so we changed the * temp file cleanup system to remove temporary files after we close it */ void unlink_temp_file(char *temp) { if (temp) { unlink(temp); free(temp); } } #endif libxmp-4.4.1/src/control.c0000664000175000017500000002673712774567167015317 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "format.h" #include "virtual.h" #include "mixer.h" const char *xmp_version = XMP_VERSION; const unsigned int xmp_vercode = XMP_VERCODE; xmp_context xmp_create_context() { struct context_data *ctx; ctx = calloc(1, sizeof(struct context_data)); if (ctx == NULL) { return NULL; } ctx->state = XMP_STATE_UNLOADED; ctx->m.defpan = 100; ctx->s.numvoc = SMIX_NUMVOC; return (xmp_context)ctx; } void xmp_free_context(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; if (ctx->state > XMP_STATE_UNLOADED) xmp_release_module(opaque); free(opaque); } static void set_position(struct context_data *ctx, int pos, int dir) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct flow_control *f = &p->flow; int seq; int has_marker; /* If dir is 0, we can jump to a different sequence */ if (dir == 0) { seq = libxmp_get_sequence(ctx, pos); } else { seq = p->sequence; } if (seq == 0xff) { return; } has_marker = HAS_QUIRK(QUIRK_MARKER); if (seq >= 0) { int start = m->seq_data[seq].entry_point; p->sequence = seq; if (pos >= 0) { int pat; while (has_marker && mod->xxo[pos] == 0xfe) { if (dir < 0) { if (pos > start) { pos--; } } else { pos++; } } pat = mod->xxo[pos]; if (pat < mod->pat) { if (has_marker && pat == 0xff) { return; } if (pos > p->scan[seq].ord) { f->end_point = 0; } else { f->num_rows = mod->xxp[pat]->rows; f->end_point = p->scan[seq].num; f->jumpline = 0; } } } if (pos < mod->len) { if (pos == 0) { p->pos = -1; } else { p->pos = pos; } } } } int xmp_next_position(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; if (p->pos < m->mod.len) set_position(ctx, p->pos + 1, 1); return p->pos; } int xmp_prev_position(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; if (p->pos == m->seq_data[p->sequence].entry_point) { set_position(ctx, -1, -1); } else if (p->pos > m->seq_data[p->sequence].entry_point) { set_position(ctx, p->pos - 1, -1); } return p->pos < 0 ? 0 : p->pos; } int xmp_set_position(xmp_context opaque, int pos) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; if (pos >= m->mod.len) return -XMP_ERROR_INVALID; set_position(ctx, pos, 0); return p->pos; } void xmp_stop_module(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; if (ctx->state < XMP_STATE_PLAYING) return; p->pos = -2; } void xmp_restart_module(xmp_context opaque) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; if (ctx->state < XMP_STATE_PLAYING) return; p->loop_count = 0; p->pos = -1; } int xmp_seek_time(xmp_context opaque, int time) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; int i, t; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; for (i = m->mod.len - 1; i >= 0; i--) { int pat = m->mod.xxo[i]; if (pat >= m->mod.pat) { continue; } if (libxmp_get_sequence(ctx, i) != p->sequence) { continue; } t = m->xxo_info[i].time; if (time >= t) { set_position(ctx, i, 1); break; } } if (i < 0) { xmp_set_position(opaque, 0); } return p->pos < 0 ? 0 : p->pos; } int xmp_channel_mute(xmp_context opaque, int chn, int status) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; int ret; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; if (chn < 0 || chn >= XMP_MAX_CHANNELS) { return -XMP_ERROR_INVALID; } ret = p->channel_mute[chn]; if (status >= 2) { p->channel_mute[chn] = !p->channel_mute[chn]; } else if (status >= 0) { p->channel_mute[chn] = status; } return ret; } int xmp_channel_vol(xmp_context opaque, int chn, int vol) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; int ret; if (ctx->state < XMP_STATE_PLAYING) return -XMP_ERROR_STATE; if (chn < 0 || chn >= XMP_MAX_CHANNELS) { return -XMP_ERROR_INVALID; } ret = p->channel_vol[chn]; if (vol >= 0 && vol <= 100) { p->channel_vol[chn] = vol; } return ret; } #ifdef USE_VERSIONED_SYMBOLS extern int xmp_set_player_v41__(xmp_context, int, int) __attribute__((alias("xmp_set_player_v40__"))); extern int xmp_set_player_v43__(xmp_context, int, int) __attribute__((alias("xmp_set_player_v40__"))); extern int xmp_set_player_v44__(xmp_context, int, int) __attribute__((alias("xmp_set_player_v40__"))); asm(".symver xmp_set_player_v40__, xmp_set_player@XMP_4.0"); asm(".symver xmp_set_player_v41__, xmp_set_player@XMP_4.1"); asm(".symver xmp_set_player_v43__, xmp_set_player@XMP_4.3"); asm(".symver xmp_set_player_v44__, xmp_set_player@@XMP_4.4"); #define xmp_set_player__ xmp_set_player_v40__ #else #define xmp_set_player__ xmp_set_player #endif int xmp_set_player__(xmp_context opaque, int parm, int val) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct mixer_data *s = &ctx->s; int ret = -XMP_ERROR_INVALID; if (parm == XMP_PLAYER_SMPCTL || parm == XMP_PLAYER_DEFPAN) { /* these should be set before loading the module */ if (ctx->state >= XMP_STATE_LOADED) { return -XMP_ERROR_STATE; } } else if (parm == XMP_PLAYER_VOICES) { /* these should be set before start playing */ if (ctx->state >= XMP_STATE_PLAYING) { return -XMP_ERROR_STATE; } } else if (ctx->state < XMP_STATE_PLAYING) { return -XMP_ERROR_STATE; } switch (parm) { case XMP_PLAYER_AMP: if (val >= 0 && val <= 3) { s->amplify = val; ret = 0; } break; case XMP_PLAYER_MIX: if (val >= -100 && val <= 100) { s->mix = val; ret = 0; } break; case XMP_PLAYER_INTERP: if (val >= XMP_INTERP_NEAREST && val <= XMP_INTERP_SPLINE) { s->interp = val; ret = 0; } break; case XMP_PLAYER_DSP: s->dsp = val; ret = 0; break; case XMP_PLAYER_FLAGS: { p->player_flags = val; ret = 0; break; } /* 4.1 */ case XMP_PLAYER_CFLAGS: { int vblank = p->flags & XMP_FLAGS_VBLANK; p->flags = val; if (vblank != (p->flags & XMP_FLAGS_VBLANK)) libxmp_scan_sequences(ctx); ret = 0; break; } case XMP_PLAYER_SMPCTL: m->smpctl = val; ret = 0; break; case XMP_PLAYER_VOLUME: if (val >= 0 && val <= 200) { p->master_vol = val; ret = 0; } break; case XMP_PLAYER_SMIX_VOLUME: if (val >= 0 && val <= 200) { p->smix_vol = val; ret = 0; } break; /* 4.3 */ case XMP_PLAYER_DEFPAN: if (val >= 0 && val <= 100) { m->defpan = val; ret = 0; } break; /* 4.4 */ case XMP_PLAYER_MODE: p->mode = val; libxmp_set_player_mode(ctx); libxmp_scan_sequences(ctx); ret = 0; break; case XMP_PLAYER_VOICES: s->numvoc = val; break; } return ret; } #ifdef USE_VERSIONED_SYMBOLS extern int xmp_get_player_v41__(xmp_context, int) __attribute__((alias("xmp_get_player_v40__"))); extern int xmp_get_player_v42__(xmp_context, int) __attribute__((alias("xmp_get_player_v40__"))); extern int xmp_get_player_v43__(xmp_context, int) __attribute__((alias("xmp_get_player_v40__"))); extern int xmp_get_player_v44__(xmp_context, int) __attribute__((alias("xmp_get_player_v40__"))); asm(".symver xmp_get_player_v40__, xmp_get_player@XMP_4.0"); asm(".symver xmp_get_player_v41__, xmp_get_player@XMP_4.1"); asm(".symver xmp_get_player_v42__, xmp_get_player@XMP_4.2"); asm(".symver xmp_get_player_v43__, xmp_get_player@XMP_4.3"); asm(".symver xmp_get_player_v44__, xmp_get_player@@XMP_4.4"); #define xmp_get_player__ xmp_get_player_v40__ #else #define xmp_get_player__ xmp_get_player #endif int xmp_get_player__(xmp_context opaque, int parm) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct mixer_data *s = &ctx->s; int ret = -XMP_ERROR_INVALID; if (parm == XMP_PLAYER_SMPCTL || parm == XMP_PLAYER_DEFPAN) { // can read these at any time } else if (parm != XMP_PLAYER_STATE && ctx->state < XMP_STATE_PLAYING) { return -XMP_ERROR_STATE; } switch (parm) { case XMP_PLAYER_AMP: ret = s->amplify; break; case XMP_PLAYER_MIX: ret = s->mix; break; case XMP_PLAYER_INTERP: ret = s->interp; break; case XMP_PLAYER_DSP: ret = s->dsp; break; case XMP_PLAYER_FLAGS: ret = p->player_flags; break; /* 4.1 */ case XMP_PLAYER_CFLAGS: ret = p->flags; break; case XMP_PLAYER_SMPCTL: ret = m->smpctl; break; case XMP_PLAYER_VOLUME: ret = p->master_vol; break; case XMP_PLAYER_SMIX_VOLUME: ret = p->smix_vol; break; /* 4.2 */ case XMP_PLAYER_STATE: ret = ctx->state; break; /* 4.3 */ case XMP_PLAYER_DEFPAN: ret = m->defpan; break; /* 4.4 */ case XMP_PLAYER_MODE: ret = p->mode; break; case XMP_PLAYER_MIXER_TYPE: ret = XMP_MIXER_STANDARD; if (p->flags & XMP_FLAGS_A500) { if (IS_AMIGA_MOD()) { #ifdef LIBXMP_PAULA_SIMULATOR if (p->filter) { ret = XMP_MIXER_A500F; } else { ret = XMP_MIXER_A500; } #endif } } break; case XMP_PLAYER_VOICES: ret = s->numvoc; break; } return ret; } char **xmp_get_format_list() { return format_list(); } void xmp_inject_event(xmp_context opaque, int channel, struct xmp_event *e) { struct context_data *ctx = (struct context_data *)opaque; struct player_data *p = &ctx->p; if (ctx->state < XMP_STATE_PLAYING) return; memcpy(&p->inject_event[channel], e, sizeof(struct xmp_event)); p->inject_event[channel]._flag = 1; } int xmp_set_instrument_path(xmp_context opaque, char *path) { struct context_data *ctx = (struct context_data *)opaque; struct module_data *m = &ctx->m; if (m->instrument_path != NULL) free(m->instrument_path); m->instrument_path = strdup(path); if (m->instrument_path == NULL) { return -XMP_ERROR_SYSTEM; } return 0; } libxmp-4.4.1/src/memio.h0000664000175000017500000000077212773463510014723 0ustar claudioclaudio#ifndef LIBXMP_MEMIO_H #define LIBXMP_MEMIO_H #include typedef struct { unsigned char *start; ptrdiff_t pos; ptrdiff_t size; } MFILE; #ifdef __cplusplus extern "C" { #endif MFILE *mopen(void *, long); int mgetc(MFILE *stream); size_t mread(void *, size_t, size_t, MFILE *); int mseek(MFILE *, long, int); long mtell(MFILE *); int mclose(MFILE *); int meof(MFILE *); #ifndef LIBXMP_CORE_PLAYER int mstat(MFILE *, struct stat *); #endif #ifdef __cplusplus } #endif #endif libxmp-4.4.1/src/tempfile.h0000664000175000017500000000016512773463510015416 0ustar claudioclaudio#ifndef XMP_PLATFORM_H #define XMP_PLATFORM_H FILE *make_temp_file(char **); void unlink_temp_file(char *); #endif libxmp-4.4.1/src/load_helpers.c0000664000175000017500000002436512777410253016255 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "common.h" #include "loaders/loader.h" #ifndef LIBXMP_CORE_PLAYER #ifdef __ANDROID__ #include #include #include #endif #include /* * Handle special "module quirks" that can't be detected automatically * such as Protracker 2.x compatibility, vblank timing, etc. */ struct module_quirk { uint8 md5[16]; int flags; int mode; }; const struct module_quirk mq[] = { /* "No Mercy" by Alf/VTL (added by Martin Willers) */ { { 0x36, 0x6e, 0xc0, 0xfa, 0x96, 0x2a, 0xeb, 0xee, 0x03, 0x4a, 0xa2, 0xdb, 0xaa, 0x49, 0xaa, 0xea }, 0, XMP_MODE_PROTRACKER }, /* mod.souvenir of china */ { { 0x93, 0xf1, 0x46, 0xae, 0xb7, 0x58, 0xc3, 0x9d, 0x8b, 0x5f, 0xbc, 0x98, 0xbf, 0x23, 0x7a, 0x43 }, XMP_FLAGS_FIXLOOP, XMP_MODE_AUTO }, /* "siedler ii" (added by Daniel Åkerud) */ { { 0x70, 0xaa, 0x03, 0x4d, 0xfb, 0x2f, 0x1f, 0x73, 0xd9, 0xfd, 0xba, 0xfe, 0x13, 0x1b, 0xb7, 0x01 }, XMP_FLAGS_VBLANK, XMP_MODE_AUTO }, /* "Klisje paa klisje" (added by Kjetil Torgrim Homme) */ { { 0xe9, 0x98, 0x01, 0x2c, 0x70, 0x0e, 0xb4, 0x3a, 0xf0, 0x32, 0x17, 0x11, 0x30, 0x58, 0x29, 0xb2 }, 0, XMP_MODE_NOISETRACKER }, #if 0 /* -- Already covered by Noisetracker fingerprinting -- */ /* Another version of Klisje paa klisje sent by Steve Fernandez */ { { 0x12, 0x19, 0x1c, 0x90, 0x41, 0xe3, 0xfd, 0x70, 0xb7, 0xe6, 0xb3, 0x94, 0x8b, 0x21, 0x07, 0x63 }, XMP_FLAGS_VBLANK }, #endif /* "((((( nebulos )))))" sent by Tero Auvinen (AMP version) */ { { 0x51, 0x6e, 0x8d, 0xcc, 0x35, 0x7d, 0x50, 0xde, 0xa9, 0x85, 0xbe, 0xbf, 0x90, 0x2e, 0x42, 0xdc }, 0, XMP_MODE_NOISETRACKER }, /* Purple Motion's Sundance.mod, Music Channel BBS edit */ { { 0x5d, 0x3e, 0x1e, 0x08, 0x28, 0x52, 0x12, 0xc7, 0x17, 0x64, 0x95, 0x75, 0x98, 0xe6, 0x95, 0xc1 }, 0, XMP_MODE_ST3 }, /* Asle's Ode to Protracker */ { { 0x97, 0xa3, 0x7d, 0x30, 0xd7, 0xae, 0x6d, 0x50, 0xc9, 0x62, 0xe9, 0xd8, 0x87, 0x1b, 0x7e, 0x8a }, 0, XMP_MODE_PROTRACKER }, { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 0 } }; static void module_quirks(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; int i; for (i = 0; mq[i].flags != 0 || mq[i].mode != 0; i++) { if (!memcmp(m->md5, mq[i].md5, 16)) { p->flags |= mq[i].flags; p->mode = mq[i].mode; } } } /* * Check whether the given string matches one of the blacklisted glob * patterns. Used to filter file names stored in archive files. */ int libxmp_exclude_match(char *name) { int i; static const char *const exclude[] = { "README", "readme", "*.DIZ", "*.diz", "*.NFO", "*.nfo", "*.DOC", "*.Doc", "*.doc", "*.INFO", "*.info", "*.Info", "*.TXT", "*.txt", "*.EXE", "*.exe", "*.COM", "*.com", "*.README", "*.readme", "*.Readme", "*.ReadMe", NULL }; for (i = 0; exclude[i] != NULL; i++) { if (fnmatch(exclude[i], name, 0) == 0) { return 1; } } return 0; } #endif /* LIBXMP_CORE_PLAYER */ char *libxmp_adjust_string(char *s) { int i; for (i = 0; i < strlen(s); i++) { if (!isprint((int)s[i]) || ((uint8) s[i] > 127)) s[i] = ' '; } while (*s && (s[strlen(s) - 1] == ' ')) { s[strlen(s) - 1] = 0; } return s; } static void check_envelope(struct xmp_envelope *env) { /* Disable envelope if invalid number of points */ if (env->npt <= 0 || env->npt > XMP_MAX_ENV_POINTS) { env->flg &= ~XMP_ENVELOPE_ON; } /* Disable envelope loop if invalid loop parameters */ if (env->lps >= env->npt || env->lpe >= env->npt) { env->flg &= ~XMP_ENVELOPE_LOOP; } /* Disable envelope loop if invalid sustain */ if (env->sus >= env->npt) { env->flg &= ~XMP_ENVELOPE_ON; } } void libxmp_load_prologue(struct context_data *ctx) { struct module_data *m = &ctx->m; int i; /* Reset variables */ memset(&m->mod, 0, sizeof (struct xmp_module)); m->rrate = PAL_RATE; m->c4rate = C4_PAL_RATE; m->volbase = 0x40; m->gvol = m->gvolbase = 0x40; m->vol_table = NULL; m->quirk = 0; m->read_event_type = READ_EVENT_MOD; m->period_type = PERIOD_AMIGA; m->comment = NULL; m->scan_cnt = NULL; /* Set defaults */ m->mod.pat = 0; m->mod.trk = 0; m->mod.chn = 4; m->mod.ins = 0; m->mod.smp = 0; m->mod.spd = 6; m->mod.bpm = 125; m->mod.len = 0; m->mod.rst = 0; #ifndef LIBXMP_CORE_PLAYER m->extra = NULL; #endif #ifndef LIBXMP_CORE_DISABLE_IT m->xsmp = NULL; #endif m->time_factor = DEFAULT_TIME_FACTOR; for (i = 0; i < 64; i++) { int pan = (((i + 1) / 2) % 2) * 0xff; m->mod.xxc[i].pan = 0x80 + (pan - 0x80) * m->defpan / 100; m->mod.xxc[i].vol = 0x40; m->mod.xxc[i].flg = 0; } } void libxmp_load_epilogue(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int i, j; mod->gvl = m->gvol; /* Sanity check for module parameters */ CLAMP(mod->len, 0, XMP_MAX_MOD_LENGTH); CLAMP(mod->pat, 0, 257); /* some formats have an extra pattern */ CLAMP(mod->ins, 0, 255); CLAMP(mod->smp, 0, MAX_SAMPLES); CLAMP(mod->chn, 0, XMP_MAX_CHANNELS); /* Fix cases where the restart value is invalid e.g. kc_fall8.xm * from http://aminet.net/mods/mvp/mvp_0002.lha (reported by * Ralf Hoffmann ) */ if (mod->rst >= mod->len) { mod->rst = 0; } /* Sanity check for tempo and BPM */ if (mod->spd <= 0 || mod->spd > 255) { mod->spd = 6; } CLAMP(mod->bpm, XMP_MIN_BPM, 255); /* Set appropriate values for instrument volumes and subinstrument * global volumes when QUIRK_INSVOL is not set, to keep volume values * consistent if the user inspects struct xmp_module. We can later * set volumes in the loaders and eliminate the quirk. */ for (i = 0; i < mod->ins; i++) { if (~m->quirk & QUIRK_INSVOL) { mod->xxi[i].vol = m->volbase; } for (j = 0; j < mod->xxi[i].nsm; j++) { if (~m->quirk & QUIRK_INSVOL) { mod->xxi[i].sub[j].gvl = m->volbase; } } } /* Sanity check for envelopes */ for (i = 0; i < mod->ins; i++) { check_envelope(&mod->xxi[i].aei); check_envelope(&mod->xxi[i].fei); check_envelope(&mod->xxi[i].pei); } p->filter = 0; p->mode = XMP_MODE_AUTO; p->flags = p->player_flags; #ifndef LIBXMP_CORE_PLAYER module_quirks(ctx); #endif libxmp_set_player_mode(ctx); } int libxmp_prepare_scan(struct context_data *ctx) { struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; int i, ord; if (mod->xxp == NULL || mod->xxt == NULL) return -XMP_ERROR_LOAD; ord = 0; while (ord < mod->len && mod->xxo[ord] >= mod->pat) { ord++; } if (ord >= mod->len) { mod->len = 0; return 0; } m->scan_cnt = calloc(sizeof (char *), mod->len); if (m->scan_cnt == NULL) return -XMP_ERROR_SYSTEM; for (i = 0; i < mod->len; i++) { int pat_idx = mod->xxo[i]; struct xmp_pattern *pat; /* Add pattern if referenced in orders */ if (pat_idx < mod->pat && !mod->xxp[pat_idx]) { if (libxmp_alloc_pattern(mod, pat_idx) < 0) { return -XMP_ERROR_SYSTEM; } } pat = pat_idx >= mod->pat ? NULL : mod->xxp[pat_idx]; m->scan_cnt[i] = calloc(1, pat && pat->rows ? pat->rows : 1); if (m->scan_cnt[i] == NULL) return -XMP_ERROR_SYSTEM; } return 0; } /* Process player personality flags */ int libxmp_set_player_mode(struct context_data *ctx) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; int q; switch (p->mode) { case XMP_MODE_AUTO: break; case XMP_MODE_MOD: m->c4rate = C4_PAL_RATE; m->quirk = 0; m->read_event_type = READ_EVENT_MOD; m->period_type = PERIOD_AMIGA; break; case XMP_MODE_NOISETRACKER: m->c4rate = C4_PAL_RATE; m->quirk = QUIRK_NOBPM; m->read_event_type = READ_EVENT_MOD; m->period_type = PERIOD_MODRNG; break; case XMP_MODE_PROTRACKER: m->c4rate = C4_PAL_RATE; m->quirk = QUIRK_PROTRACK; m->read_event_type = READ_EVENT_MOD; m->period_type = PERIOD_MODRNG; break; case XMP_MODE_S3M: q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM); m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_ST3 | q; m->read_event_type = READ_EVENT_ST3; break; case XMP_MODE_ST3: q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM); m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_ST3 | QUIRK_ST3BUGS | q; m->read_event_type = READ_EVENT_ST3; break; case XMP_MODE_ST3GUS: q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM); m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_ST3 | QUIRK_ST3BUGS | q; m->quirk &= ~QUIRK_RSTCHN; m->read_event_type = READ_EVENT_ST3; break; case XMP_MODE_XM: m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_FT2; m->read_event_type = READ_EVENT_FT2; break; case XMP_MODE_FT2: m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_FT2 | QUIRK_FT2BUGS; m->read_event_type = READ_EVENT_FT2; break; case XMP_MODE_IT: m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_IT | QUIRK_VIBHALF | QUIRK_VIBINV; m->read_event_type = READ_EVENT_IT; break; case XMP_MODE_ITSMP: m->c4rate = C4_NTSC_RATE; m->quirk = QUIRKS_IT | QUIRK_VIBHALF | QUIRK_VIBINV; m->quirk &= ~(QUIRK_VIRTUAL | QUIRK_RSTCHN); m->read_event_type = READ_EVENT_IT; break; default: return -1; } return 0; } libxmp-4.4.1/src/depacker.h0000664000175000017500000000157112774567167015407 0ustar claudioclaudio#ifndef XMP_DEPACKER_H #define XMP_DEPACKER_H #include extern struct depacker libxmp_depacker_zip; extern struct depacker libxmp_depacker_lha; extern struct depacker libxmp_depacker_gzip; extern struct depacker libxmp_depacker_bzip2; extern struct depacker libxmp_depacker_xz; extern struct depacker libxmp_depacker_compress; extern struct depacker libxmp_depacker_pp; extern struct depacker libxmp_depacker_sqsh; extern struct depacker libxmp_depacker_arc; extern struct depacker libxmp_depacker_arcfs; extern struct depacker libxmp_depacker_mmcmp; extern struct depacker libxmp_depacker_muse; extern struct depacker libxmp_depacker_lzx; extern struct depacker libxmp_depacker_s404; extern struct depacker libxmp_depacker_xfd; extern struct depacker libxmp_depacker_oxm; struct depacker { int (*const test)(unsigned char *); int (*const depack)(FILE *, FILE *); }; #endif libxmp-4.4.1/src/lfo.c0000664000175000017500000000743312774567167014407 0ustar claudioclaudio/* Extended Module Player * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "lfo.h" #define WAVEFORM_SIZE 64 static const int sine_wave[WAVEFORM_SIZE] = { 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, 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 }; /* LFO */ static int get_lfo_mod(struct lfo *lfo) { int val; if (lfo->rate == 0) return 0; switch (lfo->type) { case 0: /* sine */ val = sine_wave[lfo->phase]; break; case 1: /* ramp down */ val = 255 - (lfo->phase << 3); break; case 2: /* square */ val = lfo->phase < WAVEFORM_SIZE / 2 ? 255 : -255; break; case 3: /* random */ val = ((rand() & 0x1ff) - 256); break; #ifndef LIBXMP_CORE_PLAYER case 669: /* 669 vibrato */ val = lfo->phase & 1; break; #endif default: return 0; } return val * lfo->depth; } static int get_lfo_st3(struct lfo *lfo) { if (lfo->rate == 0) { return 0; } /* S3M square */ if (lfo->type == 2) { int val = lfo->phase < WAVEFORM_SIZE / 2 ? 255 : 0; return val * lfo->depth; } return get_lfo_mod(lfo); } /* From OpenMPT VibratoWaveforms.xm: * "Generally the vibrato and tremolo tables are identical to those that * ProTracker uses, but the vibrato’s “ramp down” table is upside down." */ static int get_lfo_ft2(struct lfo *lfo) { if (lfo->rate == 0) return 0; /* FT2 ramp */ if (lfo->type == 1) { int phase = (lfo->phase + (WAVEFORM_SIZE >> 1)) % WAVEFORM_SIZE; int val = (phase << 3) - 255; return val * lfo->depth; } return get_lfo_mod(lfo); } #ifndef LIBXMP_CORE_DISABLE_IT static int get_lfo_it(struct lfo *lfo) { if (lfo->rate == 0) return 0; return get_lfo_st3(lfo); } #endif int libxmp_lfo_get(struct context_data *ctx, struct lfo *lfo, int is_vibrato) { struct module_data *m = &ctx->m; switch (m->read_event_type) { case READ_EVENT_ST3: return get_lfo_st3(lfo); case READ_EVENT_FT2: if (is_vibrato) { return get_lfo_ft2(lfo); } else { return get_lfo_mod(lfo); } #ifndef LIBXMP_CORE_DISABLE_IT case READ_EVENT_IT: return get_lfo_it(lfo); #endif default: return get_lfo_mod(lfo); } } void libxmp_lfo_update(struct lfo *lfo) { lfo->phase += lfo->rate; lfo->phase %= WAVEFORM_SIZE; } void libxmp_lfo_set_phase(struct lfo *lfo, int phase) { lfo->phase = phase; } void libxmp_lfo_set_depth(struct lfo *lfo, int depth) { lfo->depth = depth; } void libxmp_lfo_set_rate(struct lfo *lfo, int rate) { lfo->rate = rate; } void libxmp_lfo_set_waveform(struct lfo *lfo, int type) { lfo->type = type; } libxmp-4.4.1/src/effects.h0000664000175000017500000000750612774312011015224 0ustar claudioclaudio#ifndef LIBXMP_EFFECTS_H #define LIBXMP_EFFECTS_H /* Protracker effects */ #define FX_ARPEGGIO 0x00 #define FX_PORTA_UP 0x01 #define FX_PORTA_DN 0x02 #define FX_TONEPORTA 0x03 #define FX_VIBRATO 0x04 #define FX_TONE_VSLIDE 0x05 #define FX_VIBRA_VSLIDE 0x06 #define FX_TREMOLO 0x07 #define FX_OFFSET 0x09 #define FX_VOLSLIDE 0x0a #define FX_JUMP 0x0b #define FX_VOLSET 0x0c #define FX_BREAK 0x0d #define FX_EXTENDED 0x0e #define FX_SPEED 0x0f /* Fast tracker effects */ #define FX_SETPAN 0x08 /* Fast Tracker II effects */ #define FX_GLOBALVOL 0x10 #define FX_GVOL_SLIDE 0x11 #define FX_KEYOFF 0x14 #define FX_ENVPOS 0x15 #define FX_PANSLIDE 0x19 #define FX_MULTI_RETRIG 0x1b #define FX_TREMOR 0x1d #define FX_XF_PORTA 0x21 /* Protracker extended effects */ #define EX_FILTER 0x00 #define EX_F_PORTA_UP 0x01 #define EX_F_PORTA_DN 0x02 #define EX_GLISS 0x03 #define EX_VIBRATO_WF 0x04 #define EX_FINETUNE 0x05 #define EX_PATTERN_LOOP 0x06 #define EX_TREMOLO_WF 0x07 #define EX_SETPAN 0x08 #define EX_RETRIG 0x09 #define EX_F_VSLIDE_UP 0x0a #define EX_F_VSLIDE_DN 0x0b #define EX_CUT 0x0c #define EX_DELAY 0x0d #define EX_PATT_DELAY 0x0e #define EX_INVLOOP 0x0f #ifndef LIBXMP_CORE_PLAYER /* Oktalyzer effects */ #define FX_OKT_ARP3 0x70 #define FX_OKT_ARP4 0x71 #define FX_OKT_ARP5 0x72 #define FX_NSLIDE2_DN 0x73 #define FX_NSLIDE2_UP 0x74 #define FX_F_NSLIDE_DN 0x75 #define FX_F_NSLIDE_UP 0x76 /* Persistent effects -- for FNK and FAR */ #define FX_PER_PORTA_DN 0x78 #define FX_PER_PORTA_UP 0x79 #define FX_PER_TPORTA 0x7a #define FX_PER_VIBRATO 0x7b #define FX_PER_VSLD_UP 0x7c #define FX_PER_VSLD_DN 0x7d #define FX_SPEED_CP 0x7e #define FX_PER_CANCEL 0x7f /* 669 frequency based effects */ #define FX_669_PORTA_UP 0x60 #define FX_669_PORTA_DN 0x61 #define FX_669_TPORTA 0x62 #define FX_669_FINETUNE 0x63 #define FX_669_VIBRATO 0x64 #endif #ifndef LIBXMP_CORE_DISABLE_IT /* IT effects */ #define FX_TRK_VOL 0x80 #define FX_TRK_VSLIDE 0x81 #define FX_TRK_FVSLIDE 0x82 #define FX_IT_INSTFUNC 0x83 #define FX_FLT_CUTOFF 0x84 #define FX_FLT_RESN 0x85 #define FX_IT_BPM 0x87 #define FX_IT_ROWDELAY 0x88 #define FX_IT_PANSLIDE 0x89 #define FX_PANBRELLO 0x8a #define FX_PANBRELLO_WF 0x8b #define FX_HIOFFSET 0x8c #define FX_IT_BREAK 0x8e /* like FX_BREAK with hex parameter */ #endif #ifndef LIBXMP_CORE_PLAYER /* MED effects */ #define FX_HOLD_DECAY 0x90 #define FX_SETPITCH 0x91 #define FX_VIBRATO2 0x92 /* PTM effects */ #define FX_NSLIDE_DN 0x9c /* IMF/PTM note slide down */ #define FX_NSLIDE_UP 0x9d /* IMF/PTM note slide up */ #define FX_NSLIDE_R_UP 0x9e /* PTM note slide down with retrigger */ #define FX_NSLIDE_R_DN 0x9f /* PTM note slide up with retrigger */ /* Extra effects */ #define FX_VOLSLIDE_UP 0xa0 /* SFX, MDL */ #define FX_VOLSLIDE_DN 0xa1 #define FX_F_VSLIDE 0xa5 /* IMF/MDL */ #define FX_CHORUS 0xa9 /* IMF */ #define FX_ICE_SPEED 0xa2 #define FX_REVERB 0xaa /* IMF */ #define FX_MED_HOLD 0xb1 /* MMD hold/decay */ #define FX_MEGAARP 0xb2 /* Smaksak effect 7: MegaArp */ #define FX_VOL_ADD 0xb6 /* SFX change volume up */ #define FX_VOL_SUB 0xb7 /* SFX change volume down */ #define FX_PITCH_ADD 0xb8 /* SFX add steps to current note */ #define FX_PITCH_SUB 0xb9 /* SFX add steps to current note */ #endif #define FX_SURROUND 0x8d /* S3M/IT */ #define FX_S3M_SPEED 0xa3 /* S3M */ #define FX_VOLSLIDE_2 0xa4 #define FX_FINETUNE 0xa6 #define FX_S3M_BPM 0xab /* S3M */ #define FX_FINE_VIBRATO 0xac /* S3M/PTM/IMF/LIQ */ #define FX_F_VSLIDE_UP 0xad /* MMD */ #define FX_F_VSLIDE_DN 0xae /* MMD */ #define FX_F_PORTA_UP 0xaf /* MMD */ #define FX_F_PORTA_DN 0xb0 /* MMD */ #define FX_PATT_DELAY 0xb3 /* MMD */ #define FX_S3M_ARPEGGIO 0xb4 #define FX_PANSL_NOMEM 0xb5 /* XM volume column */ #define FX_VSLIDE_UP_2 0xc0 /* IT volume column volume slide */ #define FX_VSLIDE_DN_2 0xc1 #define FX_F_VSLIDE_UP_2 0xc2 #define FX_F_VSLIDE_DN_2 0xc3 #endif /* LIBXMP_EFFECTS_H */ libxmp-4.4.1/src/Makefile0000664000175000017500000000137312774567167015120 0ustar claudioclaudio SRC_OBJS = virtual.o format.o period.o player.o read_event.o dataio.o \ mkstemp.o fnmatch.o md5.o lfo.o scan.o control.o \ med_extras.o filter.o effects.o mixer.o mix_all.o \ load_helpers.o load.o hio.o hmn_extras.o extras.o smix.o \ memio.o tempfile.o mix_paula.o SRC_DFILES = Makefile $(SRC_OBJS:.o=.c) common.h effects.h \ format.h lfo.h list.h mixer.h period.h player.h virtual.h \ fnmatch.h md5.h precomp_lut.h tempfile.h med_extras.h hio.h \ hmn_extras.h extras.h memio.h mdataio.h depacker.h paula.h \ precomp_blep.h SRC_PATH = src OBJS += $(addprefix $(SRC_PATH)/,$(SRC_OBJS)) default-src:: $(MAKE) -C .. dist-src:: mkdir -p $(DIST)/$(SRC_PATH) cp -RPp $(addprefix $(SRC_PATH)/,$(SRC_DFILES)) $(DIST)/$(SRC_PATH) libxmp-4.4.1/docs/0000775000175000017500000000000012777546220013603 5ustar claudioclaudiolibxmp-4.4.1/docs/CREDITS0000664000175000017500000002034612742415254014622 0ustar claudioclaudioThe Authors - Mirko Buffoni * Windows port fixes * random hacks and improvements - Frederic Bujon * XM pan fix - Hipolito Carraro Jr * main player coding * software mixer * virtual channel system design and implementation - Rudolf Cejka * MED loader alignment and endianism fixes * XM loader endianism fixes * S3M loader fixes - Sylvain Chipaux * Prowizard loaders - Chris Cox * S3M loader fixes - Michael Doering * RAR unpacking support * PP20 decrunching fixes - Rune Elvemo * fixes for endianism problems in Linux/PPC - Mike Gorchak * misc hacks - Tom Hargreaves * Digital Symphony and Archimedes Tracker loader fixes - Kevin Langman * OS/2 port - Antti S. Lankila * Amiga sound model and processing algorithm - Stephen Leary * AMOS Music Bank format loader - Claudio Matsuoka * main player coding * module loaders - Dominik Mierzejewski * fixes for gcc 2.96/glibc 2.2 - Francis Russell * OctaMED tempo fixes - Adam Sampson * buildsystem and configuration file location fixes - Johan Samuelsson * Amiga port and fixes - Attila Sipos * SQSH decruncher checksum - Miodrag Vallat * 669 loader fixes * XM loader endianism fixes - Chris Young * Amiga port and fixes Other contributors: Antti Huovilainen, Michael Janson, Matthias Leonhardt, Andy Eltsov, Davi Lima, Geoff Reedy, Sipos Attila, Bjoern Fisher, Matus Telgarsky, Bernhard März, Cyke O'Path, Rudolf Cejka, Igor Krpanic, Chris Cox, Rudá Moura, Paul Wise, Henrik Pauli, Zbigniew Luszpinski, Jon Rafkind, Reynir Stefansson, Ralf Hoffmann, Douglas Carmichael, Adric Riedel, Gürkan Sengün, Lorence Lombardo, Martin Willers, Laurent Clevy, Michael Doering, Bert Jahn, Adi Sapir, Jools Smyth, Martin Jeppesen, Stuart Caie, Bernhard März, Matthias Arndt. Third-party code licenses: MD5 digest This code implements the MD5 message-digest algorithm. The algorithm is due to Ron Rivest. This code was written by Colin Plumb in 1993, no copyright is claimed. This code is in the public domain; do with it what you wish. Equivalent code is available from RSA Data Security, Inc. This code has been tested against that, and is equivalent, except that you don't need to include two pages of legalese with every copy. Powerpack depacker Based on code by Stuart Caie Modified by Michael Doering and Claudio Matsuoka This software is in the Public Domain YM3812 emulator fmopl.c -- software implementation of FM sound generator This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. XZ decompressor XZ Embedded is a relatively small, limited implementation of the .xz file format. Currently only decoding is implemented. Authors: Lasse Collin Igor Pavlov This file has been put into the public domain. You can do whatever you want with this file. Zip decompressor This code is Copyright 2005-2006 by Michael Kohn This package is licensed under the LGPL. You are free to use this library in both commercial and non-commercial applications as long as you dynamically link to it. If you statically link this library you must also release your software under the LGPL. If you need more flexibility in the license email and we can work something out. Stonecracker decompressor StoneCracker S404 algorithm data decompression routine (c) 2006 Jouni 'Mr.Spiv' Korhonen. The code is in public domain. Bzip2 decompressor Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), which also acknowledges contributions by Mike Burrows, David Wheeler, Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, Robert Sedgewick, and Jon L. Bentley. This code is licensed under the LGPLv2: LGPL (http://www.gnu.org/copyleft/lgpl.html) Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org) Arc decompressor nomarch 1.4 - extract old `.arc' archives. Copyright (C) 2001-2006 Russell Marks. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. LHA decompressor LhA file archiver client XAD library system for archive handling Copyright (C) 1998 and later by Dirk Stoecker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. LZX decompressor LZX file archiver client XAD library system for archive handling Copyright (C) 1998 and later by Dirk Stöcker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. DMF sample decompressor IT resonant filters IT sample decompressor Modplug Plugin for XMMS v2.0 / libmodplug v0.8.5 Based on the ModPlug sound engine by Olivier Lapicque This source code is public domain. Authors: Olivier Lapicque MED2 module loading code V2.00 file loading/saving routines by T. Kinnunen 1990 MED2.00 by Teijo Kinnunen, 1990 MED is in Public Domain Vorbis decoder Ogg Vorbis I audio decoder -- version 0.99996 Written in April 2007 by Sean Barrett, sponsored by RAD Game Tools. Placed in the public domain April 2007 by the author: no copyright is claimed, and you may use it for any purpose you like. ptpopen - A Windows replacement for popen() pt_popen/pt_pclose functions Written somewhere in the 90s by Kurt Keller This piece of code is in the public domain. I do not claim any rights on it. Do whatever you want to do with it and I hope it will be still useful. mkstemp implementation Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden). All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Institute nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libxmp-4.4.1/docs/libxmp.pdf0000664000175000017500000021751512742416220015570 0ustar claudioclaudio%PDF-1.4 % ReportLab Generated PDF document http://www.reportlab.com 1 0 obj << /F1 2 0 R /F2 3 0 R /F3 106 0 R /F4 107 0 R >> endobj 2 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >> endobj 3 0 obj << /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >> endobj 4 0 obj << /Contents 199 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 5 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 108 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 40.01575 760.0394 98.34575 769.0394 ] /Subtype /Link /Type /Annot >> endobj 6 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 108 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 549.6998 757.7894 555.2598 766.7894 ] /Subtype /Link /Type /Annot >> endobj 7 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 108 0 R /XYZ 40.01575 658.0394 0 ] /Rect [ 60.01575 745.0394 102.2557 754.0394 ] /Subtype /Link /Type /Annot >> endobj 8 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 108 0 R /XYZ 40.01575 658.0394 0 ] /Rect [ 549.6998 742.7894 555.2598 751.7894 ] /Subtype /Link /Type /Annot >> endobj 9 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 108 0 R /XYZ 40.01575 382.0394 0 ] /Rect [ 60.01575 730.0394 138.9257 739.0394 ] /Subtype /Link /Type /Annot >> endobj 10 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 108 0 R /XYZ 40.01575 382.0394 0 ] /Rect [ 549.6998 727.7894 555.2598 736.7894 ] /Subtype /Link /Type /Annot >> endobj 11 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 119 0 R /XYZ 40.01575 184.6394 0 ] /Rect [ 60.01575 715.0394 120.0357 724.0394 ] /Subtype /Link /Type /Annot >> endobj 12 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 119 0 R /XYZ 40.01575 184.6394 0 ] /Rect [ 549.6998 712.7894 555.2598 721.7894 ] /Subtype /Link /Type /Annot >> endobj 13 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 40.01575 700.0394 104.4857 709.0394 ] /Subtype /Link /Type /Annot >> endobj 14 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 549.6998 697.7894 555.2598 706.7894 ] /Subtype /Link /Type /Annot >> endobj 15 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 758.0394 0 ] /Rect [ 60.01575 685.0394 195.6257 694.0394 ] /Subtype /Link /Type /Annot >> endobj 16 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 758.0394 0 ] /Rect [ 549.6998 682.7894 555.2598 691.7894 ] /Subtype /Link /Type /Annot >> endobj 17 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 724.0394 0 ] /Rect [ 80.01575 672.0394 178.5477 679.0394 ] /Subtype /Link /Type /Annot >> endobj 18 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 724.0394 0 ] /Rect [ 550.2558 668.9144 555.2598 675.9144 ] /Subtype /Link /Type /Annot >> endobj 19 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 667.0394 0 ] /Rect [ 80.01575 659.0394 209.0757 666.0394 ] /Subtype /Link /Type /Annot >> endobj 20 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 667.0394 0 ] /Rect [ 550.2558 655.9144 555.2598 662.9144 ] /Subtype /Link /Type /Annot >> endobj 21 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 598.0394 0 ] /Rect [ 80.01575 646.0394 194.0457 653.0394 ] /Subtype /Link /Type /Annot >> endobj 22 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 598.0394 0 ] /Rect [ 550.2558 642.9144 555.2598 649.9144 ] /Subtype /Link /Type /Annot >> endobj 23 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 506.0394 0 ] /Rect [ 60.01575 631.0394 132.8257 640.0394 ] /Subtype /Link /Type /Annot >> endobj 24 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 506.0394 0 ] /Rect [ 549.6998 628.7894 555.2598 637.7894 ] /Subtype /Link /Type /Annot >> endobj 25 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 472.0394 0 ] /Rect [ 80.01575 618.0394 220.5687 625.0394 ] /Subtype /Link /Type /Annot >> endobj 26 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 472.0394 0 ] /Rect [ 550.2558 614.9144 555.2598 621.9144 ] /Subtype /Link /Type /Annot >> endobj 27 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 384.0394 0 ] /Rect [ 80.01575 605.0394 234.5727 612.0394 ] /Subtype /Link /Type /Annot >> endobj 28 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 384.0394 0 ] /Rect [ 550.2558 601.9144 555.2598 608.9144 ] /Subtype /Link /Type /Annot >> endobj 29 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 283.0394 0 ] /Rect [ 60.01575 590.0394 127.8257 599.0394 ] /Subtype /Link /Type /Annot >> endobj 30 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 283.0394 0 ] /Rect [ 549.6998 587.7894 555.2598 596.7894 ] /Subtype /Link /Type /Annot >> endobj 31 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 249.0394 0 ] /Rect [ 80.01575 577.0394 335.6247 584.0394 ] /Subtype /Link /Type /Annot >> endobj 32 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 249.0394 0 ] /Rect [ 550.2558 573.9144 555.2598 580.9144 ] /Subtype /Link /Type /Annot >> endobj 33 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 720.0394 0 ] /Rect [ 80.01575 564.0394 275.5947 571.0394 ] /Subtype /Link /Type /Annot >> endobj 34 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 720.0394 0 ] /Rect [ 550.2558 560.9144 555.2598 567.9144 ] /Subtype /Link /Type /Annot >> endobj 35 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 529.0394 0 ] /Rect [ 80.01575 551.0394 378.1047 558.0394 ] /Subtype /Link /Type /Annot >> endobj 36 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 529.0394 0 ] /Rect [ 550.2558 547.9144 555.2598 554.9144 ] /Subtype /Link /Type /Annot >> endobj 37 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 311.0394 0 ] /Rect [ 80.01575 538.0394 342.1137 545.0394 ] /Subtype /Link /Type /Annot >> endobj 38 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 311.0394 0 ] /Rect [ 550.2558 534.9144 555.2598 541.9144 ] /Subtype /Link /Type /Annot >> endobj 39 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 105.0394 0 ] /Rect [ 80.01575 525.0394 249.0717 532.0394 ] /Subtype /Link /Type /Annot >> endobj 40 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 105.0394 0 ] /Rect [ 550.2558 521.9144 555.2598 528.9144 ] /Subtype /Link /Type /Annot >> endobj 41 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 127 0 R /XYZ 40.01575 747.0394 0 ] /Rect [ 80.01575 512.0394 238.5687 519.0394 ] /Subtype /Link /Type /Annot >> endobj 42 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 127 0 R /XYZ 40.01575 747.0394 0 ] /Rect [ 550.2558 508.9144 555.2598 515.9144 ] /Subtype /Link /Type /Annot >> endobj 43 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 127 0 R /XYZ 40.01575 626.0394 0 ] /Rect [ 80.01575 499.0394 372.6327 506.0394 ] /Subtype /Link /Type /Annot >> endobj 44 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 127 0 R /XYZ 40.01575 626.0394 0 ] /Rect [ 550.2558 495.9144 555.2598 502.9144 ] /Subtype /Link /Type /Annot >> endobj 45 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 60.01575 484.0394 127.2657 493.0394 ] /Subtype /Link /Type /Annot >> endobj 46 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 549.6998 481.7894 555.2598 490.7894 ] /Subtype /Link /Type /Annot >> endobj 47 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 765.0394 0 ] /Rect [ 80.01575 471.0394 300.0927 478.0394 ] /Subtype /Link /Type /Annot >> endobj 48 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 765.0394 0 ] /Rect [ 550.2558 467.9144 555.2598 474.9144 ] /Subtype /Link /Type /Annot >> endobj 49 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 534.2394 0 ] /Rect [ 80.01575 458.0394 222.5577 465.0394 ] /Subtype /Link /Type /Annot >> endobj 50 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 534.2394 0 ] /Rect [ 550.2558 454.9144 555.2598 461.9144 ] /Subtype /Link /Type /Annot >> endobj 51 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 382.2394 0 ] /Rect [ 80.01575 445.0394 340.1247 452.0394 ] /Subtype /Link /Type /Annot >> endobj 52 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 382.2394 0 ] /Rect [ 550.2558 441.9144 555.2598 448.9144 ] /Subtype /Link /Type /Annot >> endobj 53 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 149.2394 0 ] /Rect [ 80.01575 432.0394 359.6187 439.0394 ] /Subtype /Link /Type /Annot >> endobj 54 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 149.2394 0 ] /Rect [ 550.2558 428.9144 555.2598 435.9144 ] /Subtype /Link /Type /Annot >> endobj 55 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 133 0 R /XYZ 40.01575 292.2394 0 ] /Rect [ 80.01575 419.0394 229.5687 426.0394 ] /Subtype /Link /Type /Annot >> endobj 56 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 133 0 R /XYZ 40.01575 292.2394 0 ] /Rect [ 545.2518 415.9144 555.2598 422.9144 ] /Subtype /Link /Type /Annot >> endobj 57 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 60.01575 404.0394 121.1457 413.0394 ] /Subtype /Link /Type /Annot >> endobj 58 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 544.1398 401.7894 555.2598 410.7894 ] /Subtype /Link /Type /Annot >> endobj 59 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 765.0394 0 ] /Rect [ 80.01575 391.0394 231.0717 398.0394 ] /Subtype /Link /Type /Annot >> endobj 60 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 765.0394 0 ] /Rect [ 545.2518 387.9144 555.2598 394.9144 ] /Subtype /Link /Type /Annot >> endobj 61 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 637.0394 0 ] /Rect [ 80.01575 378.0394 231.5667 385.0394 ] /Subtype /Link /Type /Annot >> endobj 62 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 637.0394 0 ] /Rect [ 545.2518 374.9144 555.2598 381.9144 ] /Subtype /Link /Type /Annot >> endobj 63 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 509.0394 0 ] /Rect [ 80.01575 365.0394 257.5857 372.0394 ] /Subtype /Link /Type /Annot >> endobj 64 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 509.0394 0 ] /Rect [ 545.2518 361.9144 555.2598 368.9144 ] /Subtype /Link /Type /Annot >> endobj 65 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 354.0394 0 ] /Rect [ 80.01575 352.0394 236.5707 359.0394 ] /Subtype /Link /Type /Annot >> endobj 66 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 354.0394 0 ] /Rect [ 545.2518 348.9144 555.2598 355.9144 ] /Subtype /Link /Type /Annot >> endobj 67 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 257.0394 0 ] /Rect [ 80.01575 339.0394 245.0667 346.0394 ] /Subtype /Link /Type /Annot >> endobj 68 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 257.0394 0 ] /Rect [ 545.2518 335.9144 555.2598 342.9144 ] /Subtype /Link /Type /Annot >> endobj 69 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 160.0394 0 ] /Rect [ 80.01575 326.0394 253.0677 333.0394 ] /Subtype /Link /Type /Annot >> endobj 70 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 134 0 R /XYZ 40.01575 160.0394 0 ] /Rect [ 545.2518 322.9144 555.2598 329.9144 ] /Subtype /Link /Type /Annot >> endobj 71 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 135 0 R /XYZ 40.01575 756.0394 0 ] /Rect [ 80.01575 313.0394 307.1127 320.0394 ] /Subtype /Link /Type /Annot >> endobj 72 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 135 0 R /XYZ 40.01575 756.0394 0 ] /Rect [ 545.2518 309.9144 555.2598 316.9144 ] /Subtype /Link /Type /Annot >> endobj 73 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 135 0 R /XYZ 40.01575 598.0394 0 ] /Rect [ 80.01575 300.0394 286.0977 307.0394 ] /Subtype /Link /Type /Annot >> endobj 74 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 135 0 R /XYZ 40.01575 598.0394 0 ] /Rect [ 545.2518 296.9144 555.2598 303.9144 ] /Subtype /Link /Type /Annot >> endobj 75 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 135 0 R /XYZ 40.01575 440.0394 0 ] /Rect [ 80.01575 287.0394 366.1347 294.0394 ] /Subtype /Link /Type /Annot >> endobj 76 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 135 0 R /XYZ 40.01575 440.0394 0 ] /Rect [ 545.2518 283.9144 555.2598 290.9144 ] /Subtype /Link /Type /Annot >> endobj 77 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 136 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 60.01575 272.0394 168.9457 281.0394 ] /Subtype /Link /Type /Annot >> endobj 78 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 136 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 544.1398 269.7894 555.2598 278.7894 ] /Subtype /Link /Type /Annot >> endobj 79 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 136 0 R /XYZ 40.01575 765.0394 0 ] /Rect [ 80.01575 259.0394 305.6097 266.0394 ] /Subtype /Link /Type /Annot >> endobj 80 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 136 0 R /XYZ 40.01575 765.0394 0 ] /Rect [ 545.2518 255.9144 555.2598 262.9144 ] /Subtype /Link /Type /Annot >> endobj 81 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 136 0 R /XYZ 40.01575 598.0394 0 ] /Rect [ 80.01575 246.0394 262.5807 253.0394 ] /Subtype /Link /Type /Annot >> endobj 82 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 136 0 R /XYZ 40.01575 598.0394 0 ] /Rect [ 545.2518 242.9144 555.2598 249.9144 ] /Subtype /Link /Type /Annot >> endobj 83 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 137 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 80.01575 233.0394 290.5887 240.0394 ] /Subtype /Link /Type /Annot >> endobj 84 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 137 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 545.2518 229.9144 555.2598 236.9144 ] /Subtype /Link /Type /Annot >> endobj 85 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 139 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 40.01575 218.0394 165.6257 227.0394 ] /Subtype /Link /Type /Annot >> endobj 86 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 139 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 544.1398 215.7894 555.2598 224.7894 ] /Subtype /Link /Type /Annot >> endobj 87 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 139 0 R /XYZ 40.01575 714.0394 0 ] /Rect [ 60.01575 203.0394 98.91575 212.0394 ] /Subtype /Link /Type /Annot >> endobj 88 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 139 0 R /XYZ 40.01575 714.0394 0 ] /Rect [ 544.1398 200.7894 555.2598 209.7894 ] /Subtype /Link /Type /Annot >> endobj 89 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 426.2394 0 ] /Rect [ 60.01575 188.0394 148.3857 197.0394 ] /Subtype /Link /Type /Annot >> endobj 90 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 426.2394 0 ] /Rect [ 544.1398 185.7894 555.2598 194.7894 ] /Subtype /Link /Type /Annot >> endobj 91 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 392.2394 0 ] /Rect [ 80.01575 175.0394 289.5807 182.0394 ] /Subtype /Link /Type /Annot >> endobj 92 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 392.2394 0 ] /Rect [ 545.2518 171.9144 555.2598 178.9144 ] /Subtype /Link /Type /Annot >> endobj 93 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 210.2394 0 ] /Rect [ 80.01575 162.0394 388.1307 169.0394 ] /Subtype /Link /Type /Annot >> endobj 94 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 210.2394 0 ] /Rect [ 545.2518 158.9144 555.2598 165.9144 ] /Subtype /Link /Type /Annot >> endobj 95 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 722.0394 0 ] /Rect [ 80.01575 149.0394 340.6017 156.0394 ] /Subtype /Link /Type /Annot >> endobj 96 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 722.0394 0 ] /Rect [ 545.2518 145.9144 555.2598 152.9144 ] /Subtype /Link /Type /Annot >> endobj 97 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 525.0394 0 ] /Rect [ 80.01575 136.0394 316.6167 143.0394 ] /Subtype /Link /Type /Annot >> endobj 98 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 525.0394 0 ] /Rect [ 545.2518 132.9144 555.2598 139.9144 ] /Subtype /Link /Type /Annot >> endobj 99 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 367.0394 0 ] /Rect [ 80.01575 123.0394 333.1047 130.0394 ] /Subtype /Link /Type /Annot >> endobj 100 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 367.0394 0 ] /Rect [ 545.2518 119.9144 555.2598 126.9144 ] /Subtype /Link /Type /Annot >> endobj 101 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 185.0394 0 ] /Rect [ 80.01575 110.0394 299.5797 117.0394 ] /Subtype /Link /Type /Annot >> endobj 102 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 185.0394 0 ] /Rect [ 545.2518 106.9144 555.2598 113.9144 ] /Subtype /Link /Type /Annot >> endobj 103 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 144 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 80.01575 97.03937 223.5567 104.0394 ] /Subtype /Link /Type /Annot >> endobj 104 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 144 0 R /XYZ 40.01575 799.0394 0 ] /Rect [ 545.2518 93.91437 555.2598 100.9144 ] /Subtype /Link /Type /Annot >> endobj 105 0 obj << /Annots [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R 52 0 R 53 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 66 0 R 67 0 R 68 0 R 69 0 R 70 0 R 71 0 R 72 0 R 73 0 R 74 0 R 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R 81 0 R 82 0 R 83 0 R 84 0 R 85 0 R 86 0 R 87 0 R 88 0 R 89 0 R 90 0 R 91 0 R 92 0 R 93 0 R 94 0 R 95 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R ] /Contents 200 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 106 0 obj << /BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >> endobj 107 0 obj << /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font >> endobj 108 0 obj << /Contents 201 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 109 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 251.5394 0 ] /Rect [ 63.44875 502.2394 151.9018 514.2394 ] /Subtype /Link /Type /Annot >> endobj 110 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 722.5394 0 ] /Rect [ 40.01575 490.2394 128.5865 502.2394 ] /Subtype /Link /Type /Annot >> endobj 111 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 767.5394 0 ] /Rect [ 106.1221 353.4394 189.7353 365.4394 ] /Subtype /Link /Type /Annot >> endobj 112 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 767.5394 0 ] /Rect [ 70.76222 248.6394 160.9587 260.6394 ] /Subtype /Link /Type /Annot >> endobj 113 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 536.7394 0 ] /Rect [ 293.011 248.6394 380.4275 260.6394 ] /Subtype /Link /Type /Annot >> endobj 114 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 151.7394 0 ] /Rect [ 40.01575 236.6394 138.1066 248.6394 ] /Subtype /Link /Type /Annot >> endobj 115 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 536.7394 0 ] /Rect [ 316.2728 236.6394 397.1237 248.6394 ] /Subtype /Link /Type /Annot >> endobj 116 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 133 0 R /XYZ 40.01575 294.7394 0 ] /Rect [ 60.57575 204.6394 141.1557 216.6394 ] /Subtype /Link /Type /Annot >> endobj 117 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 107.5394 0 ] /Rect [ 146.7157 204.6394 248.9657 216.6394 ] /Subtype /Link /Type /Annot >> endobj 118 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 386.5394 0 ] /Rect [ 271.2057 204.6394 357.3457 216.6394 ] /Subtype /Link /Type /Annot >> endobj 119 0 obj << /Annots [ 109 0 R 110 0 R 111 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 117 0 R 118 0 R ] /Contents 202 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 120 0 obj << /Contents 203 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 121 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 122 0 R /XYZ 40.01575 474.5394 0 ] /Rect [ 281.2157 343.0394 377.9157 355.0394 ] /Subtype /Link /Type /Annot >> endobj 122 0 obj << /Annots [ 121 0 R ] /Contents 204 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 123 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 137 0 R /XYZ 40.01575 801.5394 0 ] /Rect [ 362.1257 667.0394 439.3657 679.0394 ] /Subtype /Link /Type /Annot >> endobj 124 0 obj << /Annots [ 123 0 R ] /Contents 205 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 125 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 124 0 R /XYZ 40.01575 722.5394 0 ] /Rect [ 466.8998 706.0394 555.1295 718.0394 ] /Subtype /Link /Type /Annot >> endobj 126 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 137 0 R /XYZ 40.01575 801.5394 0 ] /Rect [ 252.3578 694.0394 331.1981 706.0394 ] /Subtype /Link /Type /Annot >> endobj 127 0 obj << /Annots [ 125 0 R 126 0 R ] /Contents 206 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 128 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 151.7394 0 ] /Rect [ 445.0427 493.2394 544.1398 505.2394 ] /Subtype /Link /Type /Annot >> endobj 129 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 536.7394 0 ] /Rect [ 85.62942 329.2394 169.0331 341.2394 ] /Subtype /Link /Type /Annot >> endobj 130 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 536.7394 0 ] /Rect [ 474.6898 317.2394 554.4224 329.2394 ] /Subtype /Link /Type /Annot >> endobj 131 0 obj << /Annots [ 128 0 R 129 0 R 130 0 R ] /Contents 207 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 132 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 131 0 R /XYZ 40.01575 536.7394 0 ] /Rect [ 430.8053 335.2394 513.0776 347.2394 ] /Subtype /Link /Type /Annot >> endobj 133 0 obj << /Annots [ 132 0 R ] /Contents 208 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 134 0 obj << /Contents 209 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 135 0 obj << /Contents 210 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 136 0 obj << /Contents 211 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 137 0 obj << /Contents 212 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 138 0 obj << /Contents 213 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 139 0 obj << /Contents 214 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 140 0 obj << /Contents 215 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 141 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 143 0 R /XYZ 40.01575 369.5394 0 ] /Rect [ 119.4957 669.0394 233.4057 681.0394 ] /Subtype /Link /Type /Annot >> endobj 142 0 obj << /Border [ 0 0 0 ] /Contents () /Dest [ 140 0 R /XYZ 40.01575 394.7394 0 ] /Rect [ 160.8046 213.0394 237.4746 225.0394 ] /Subtype /Link /Type /Annot >> endobj 143 0 obj << /Annots [ 141 0 R 142 0 R ] /Contents 216 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 144 0 obj << /Contents 217 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 198 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >> /Type /Page >> endobj 145 0 obj << /Outlines 147 0 R /PageLabels 218 0 R /PageMode /UseNone /Pages 198 0 R /Type /Catalog >> endobj 146 0 obj << /Author () /CreationDate (D:20160716083750+03'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20160716083750+03'00') /Producer (ReportLab PDF Library - www.reportlab.com) /Subject (\(unspecified\)) /Title (Libxmp 4.4 API documentation) /Trapped /False >> endobj 147 0 obj << /Count 60 /First 148 0 R /Last 188 0 R /Type /Outlines >> endobj 148 0 obj << /Count 3 /Dest [ 108 0 R /XYZ 40.01575 799.0394 0 ] /First 149 0 R /Last 151 0 R /Next 152 0 R /Parent 147 0 R /Title (Introduction) >> endobj 149 0 obj << /Dest [ 108 0 R /XYZ 40.01575 658.0394 0 ] /Next 150 0 R /Parent 148 0 R /Title (Concepts) >> endobj 150 0 obj << /Dest [ 108 0 R /XYZ 40.01575 382.0394 0 ] /Next 151 0 R /Parent 148 0 R /Prev 149 0 R /Title (A simple example) >> endobj 151 0 obj << /Dest [ 119 0 R /XYZ 40.01575 184.6394 0 ] /Parent 148 0 R /Prev 150 0 R /Title (SDL example) >> endobj 152 0 obj << /Count 35 /Dest [ 122 0 R /XYZ 40.01575 799.0394 0 ] /First 153 0 R /Last 184 0 R /Next 188 0 R /Parent 147 0 R /Prev 148 0 R /Title (API reference) >> endobj 153 0 obj << /Count 3 /Dest [ 122 0 R /XYZ 40.01575 758.0394 0 ] /First 154 0 R /Last 156 0 R /Next 157 0 R /Parent 152 0 R /Title (Version and player information) >> endobj 154 0 obj << /Dest [ 122 0 R /XYZ 40.01575 724.0394 0 ] /Next 155 0 R /Parent 153 0 R /Title (const char *xmp_version) >> endobj 155 0 obj << /Dest [ 122 0 R /XYZ 40.01575 667.0394 0 ] /Next 156 0 R /Parent 153 0 R /Prev 154 0 R /Title (const unsigned int xmp_vercode) >> endobj 156 0 obj << /Dest [ 122 0 R /XYZ 40.01575 598.0394 0 ] /Parent 153 0 R /Prev 155 0 R /Title (char **xmp_get_format_list\(\)) >> endobj 157 0 obj << /Count 2 /Dest [ 122 0 R /XYZ 40.01575 506.0394 0 ] /First 158 0 R /Last 159 0 R /Next 160 0 R /Parent 152 0 R /Prev 153 0 R /Title (Context creation) >> endobj 158 0 obj << /Dest [ 122 0 R /XYZ 40.01575 472.0394 0 ] /Next 159 0 R /Parent 157 0 R /Title (xmp_context xmp_create_context\(\)) >> endobj 159 0 obj << /Dest [ 122 0 R /XYZ 40.01575 384.0394 0 ] /Parent 157 0 R /Prev 158 0 R /Title (void xmp_free_context\(xmp_context c\)) >> endobj 160 0 obj << /Count 7 /Dest [ 122 0 R /XYZ 40.01575 283.0394 0 ] /First 161 0 R /Last 167 0 R /Next 168 0 R /Parent 152 0 R /Prev 157 0 R /Title (Module loading) >> endobj 161 0 obj << /Dest [ 122 0 R /XYZ 40.01575 249.0394 0 ] /Next 162 0 R /Parent 160 0 R /Title (int xmp_test_module\(char *path, struct xmp_test_info *test_info\)) >> endobj 162 0 obj << /Dest [ 124 0 R /XYZ 40.01575 720.0394 0 ] /Next 163 0 R /Parent 160 0 R /Prev 161 0 R /Title (int xmp_load_module\(xmp_context c, char *path\)) >> endobj 163 0 obj << /Dest [ 124 0 R /XYZ 40.01575 529.0394 0 ] /Next 164 0 R /Parent 160 0 R /Prev 162 0 R /Title (int xmp_load_module_from_memory\(xmp_context c, void *mem, long size\)) >> endobj 164 0 obj << /Dest [ 124 0 R /XYZ 40.01575 311.0394 0 ] /Next 165 0 R /Parent 160 0 R /Prev 163 0 R /Title (int xmp_load_module_from_file\(xmp_context c, FILE *f, long size\)) >> endobj 165 0 obj << /Dest [ 124 0 R /XYZ 40.01575 105.0394 0 ] /Next 166 0 R /Parent 160 0 R /Prev 164 0 R /Title (void xmp_release_module\(xmp_context c\)) >> endobj 166 0 obj << /Dest [ 127 0 R /XYZ 40.01575 747.0394 0 ] /Next 167 0 R /Parent 160 0 R /Prev 165 0 R /Title (void xmp_scan_module\(xmp_context c\)) >> endobj 167 0 obj << /Dest [ 127 0 R /XYZ 40.01575 626.0394 0 ] /Parent 160 0 R /Prev 166 0 R /Title (void xmp_get_module_info\(xmp_context c, struct xmp_module_info *info\)) >> endobj 168 0 obj << /Count 5 /Dest [ 131 0 R /XYZ 40.01575 799.0394 0 ] /First 169 0 R /Last 173 0 R /Next 174 0 R /Parent 152 0 R /Prev 160 0 R /Title (Module playing) >> endobj 169 0 obj << /Dest [ 131 0 R /XYZ 40.01575 765.0394 0 ] /Next 170 0 R /Parent 168 0 R /Title (int xmp_start_player\(xmp_context c, int rate, int format\)) >> endobj 170 0 obj << /Dest [ 131 0 R /XYZ 40.01575 534.2394 0 ] /Next 171 0 R /Parent 168 0 R /Prev 169 0 R /Title (int xmp_play_frame\(xmp_context c\)) >> endobj 171 0 obj << /Dest [ 131 0 R /XYZ 40.01575 382.2394 0 ] /Next 172 0 R /Parent 168 0 R /Prev 170 0 R /Title (int xmp_play_buffer\(xmp_context c, void *buffer, int size, int loop\)) >> endobj 172 0 obj << /Dest [ 131 0 R /XYZ 40.01575 149.2394 0 ] /Next 173 0 R /Parent 168 0 R /Prev 171 0 R /Title (void xmp_get_frame_info\(xmp_context c, struct xmp_frame_info *info\)) >> endobj 173 0 obj << /Dest [ 133 0 R /XYZ 40.01575 292.2394 0 ] /Parent 168 0 R /Prev 172 0 R /Title (void xmp_end_player\(xmp_context c\)) >> endobj 174 0 obj << /Count 9 /Dest [ 134 0 R /XYZ 40.01575 799.0394 0 ] /First 175 0 R /Last 183 0 R /Next 184 0 R /Parent 152 0 R /Prev 168 0 R /Title (Player control) >> endobj 175 0 obj << /Dest [ 134 0 R /XYZ 40.01575 765.0394 0 ] /Next 176 0 R /Parent 174 0 R /Title (int xmp_next_position\(xmp_context c\)) >> endobj 176 0 obj << /Dest [ 134 0 R /XYZ 40.01575 637.0394 0 ] /Next 177 0 R /Parent 174 0 R /Prev 175 0 R /Title (int xmp_prev_position\(xmp_context c\)) >> endobj 177 0 obj << /Dest [ 134 0 R /XYZ 40.01575 509.0394 0 ] /Next 178 0 R /Parent 174 0 R /Prev 176 0 R /Title (int xmp_set_position\(xmp_context c, int pos\)) >> endobj 178 0 obj << /Dest [ 134 0 R /XYZ 40.01575 354.0394 0 ] /Next 179 0 R /Parent 174 0 R /Prev 177 0 R /Title (void xmp_stop_module\(xmp_context c\)) >> endobj 179 0 obj << /Dest [ 134 0 R /XYZ 40.01575 257.0394 0 ] /Next 180 0 R /Parent 174 0 R /Prev 178 0 R /Title (void xmp_restart_module\(xmp_context c\)) >> endobj 180 0 obj << /Dest [ 134 0 R /XYZ 40.01575 160.0394 0 ] /Next 181 0 R /Parent 174 0 R /Prev 179 0 R /Title (int xmp_seek_time\(xmp_context c, int time\)) >> endobj 181 0 obj << /Dest [ 135 0 R /XYZ 40.01575 756.0394 0 ] /Next 182 0 R /Parent 174 0 R /Prev 180 0 R /Title (int xmp_channel_mute\(xmp_context c, int chn, int status\)) >> endobj 182 0 obj << /Dest [ 135 0 R /XYZ 40.01575 598.0394 0 ] /Next 183 0 R /Parent 174 0 R /Prev 181 0 R /Title (int xmp_channel_vol\(xmp_context c, int chn, int vol\)) >> endobj 183 0 obj << /Dest [ 135 0 R /XYZ 40.01575 440.0394 0 ] /Parent 174 0 R /Prev 182 0 R /Title (void xmp_inject_event\(xmp_context c, int chn, struct xmp_event *event\)) >> endobj 184 0 obj << /Count 3 /Dest [ 136 0 R /XYZ 40.01575 799.0394 0 ] /First 185 0 R /Last 187 0 R /Parent 152 0 R /Prev 174 0 R /Title (Player parameter setting) >> endobj 185 0 obj << /Dest [ 136 0 R /XYZ 40.01575 765.0394 0 ] /Next 186 0 R /Parent 184 0 R /Title (int xmp_set_instrument_path\(xmp_context c, char *path\)) >> endobj 186 0 obj << /Dest [ 136 0 R /XYZ 40.01575 598.0394 0 ] /Next 187 0 R /Parent 184 0 R /Prev 185 0 R /Title (int xmp_get_player\(xmp_context c, int param\)) >> endobj 187 0 obj << /Dest [ 137 0 R /XYZ 40.01575 799.0394 0 ] /Parent 184 0 R /Prev 186 0 R /Title (int xmp_set_player\(xmp_context c, int param, int val\)) >> endobj 188 0 obj << /Count 9 /Dest [ 139 0 R /XYZ 40.01575 799.0394 0 ] /First 189 0 R /Last 190 0 R /Parent 147 0 R /Prev 152 0 R /Title (External sample mixer API) >> endobj 189 0 obj << /Dest [ 139 0 R /XYZ 40.01575 714.0394 0 ] /Next 190 0 R /Parent 188 0 R /Title (Example) >> endobj 190 0 obj << /Count 7 /Dest [ 140 0 R /XYZ 40.01575 426.2394 0 ] /First 191 0 R /Last 197 0 R /Parent 188 0 R /Prev 189 0 R /Title (SMIX API reference) >> endobj 191 0 obj << /Dest [ 140 0 R /XYZ 40.01575 392.2394 0 ] /Next 192 0 R /Parent 190 0 R /Title (int xmp_start_smix\(xmp_context c, int nch, int nsmp\)) >> endobj 192 0 obj << /Dest [ 140 0 R /XYZ 40.01575 210.2394 0 ] /Next 193 0 R /Parent 190 0 R /Prev 191 0 R /Title (int xmp_smix_play_instrument\(xmp_context c, int ins, int note, int vol, int chn\)) >> endobj 193 0 obj << /Dest [ 143 0 R /XYZ 40.01575 722.0394 0 ] /Next 194 0 R /Parent 190 0 R /Prev 192 0 R /Title (int xmp_smix_play_sample\(xmp_context c, int ins, int vol, int chn\)) >> endobj 194 0 obj << /Dest [ 143 0 R /XYZ 40.01575 525.0394 0 ] /Next 195 0 R /Parent 190 0 R /Prev 193 0 R /Title (int xmp_smix_channel_pan\(xmp_context c, int chn, int pan\)) >> endobj 195 0 obj << /Dest [ 143 0 R /XYZ 40.01575 367.0394 0 ] /Next 196 0 R /Parent 190 0 R /Prev 194 0 R /Title (int xmp_smix_load_sample\(xmp_context c, int num, char *path\)) >> endobj 196 0 obj << /Dest [ 143 0 R /XYZ 40.01575 185.0394 0 ] /Next 197 0 R /Parent 190 0 R /Prev 195 0 R /Title (int xmp_smix_release_sample\(xmp_context c, int num\)) >> endobj 197 0 obj << /Dest [ 144 0 R /XYZ 40.01575 799.0394 0 ] /Parent 190 0 R /Prev 196 0 R /Title (void xmp_end_smix\(xmp_context c\)) >> endobj 198 0 obj << /Count 19 /Kids [ 4 0 R 105 0 R 108 0 R 119 0 R 120 0 R 122 0 R 124 0 R 127 0 R 131 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R 138 0 R 139 0 R 140 0 R 143 0 R 144 0 R ] /Type /Pages >> endobj 199 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 254 >> stream Gar?,b6l*?&4Q>Irki$Ai0]p-R^uHp&@t]Z&#`K*W%Sk_I+.j['!dn[R<'4"$&@QQXF['8Dp2U??\=UX^;S*jaXKsZR8lV/Xg;ulP0*P=3b*\BXS+rCMc1#+EoRMGH'9R`0#(7lBH8c.0b$SrKUGC>$/`H`X5#=Fob!2!?ogSr=C1=Dr\D6)&,S9_%_dS`:J2omMt]k%e#02Ojj(,XWL=\!1R!Ss=?n]Yeke\R6\W7upl5endstream endobj 200 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1931 >> stream Gb!$J>Ar7S'S,'Cj?N,g2,[MOW7tgj,t!1sa>RP\6NBK;Bh+^?H'0/CrUhD7)kG=c.8oZ^TMZt<4Qkb`\WAWN%fHY.s%*F1:CH[R%K_I%@LXHOA$C1X[u8FfIkNH_gD2kl#C:q+JfpRFDM77%Gm!nOfY>b'HXMs:"PFa.g`ZY"G%V9H&:$5:F6'(rHXQ:<:(Ul2DSXfK7:)1jY!.EU2mA\>Ndp(RZL/s]H?TJJ]u-J.)_M:q_;QjdM#n1VI:"JrB?4VDHBJ"b*%GHOBU?@6E-7f)A[0r:F^!k(-,o9l@1:-C%UXDSp[>jh`>Kr[K),BcA,:/L!`s9ks(C;n<#2L?#:2F+2bLt49%0J*aR5gsknP99)Po-pU9H-eA6">%5a>rn/HOoiB"o&qGKiV2NoJ,jV#U5O5uVDQd9pH)SK3>#IIh[o9!TciTgl2`Znp*op,/*.,*RTWPEZf)@3Eis@(2-1P7j\e\gXmeh6RD#fH#;j$pc;XJ8$Zmob)?`+rQ*1aK$4)cZ'8'YM!ghdSNe?J*:$2IFP7BAI;W.UWAe$hqpVp^[ITU^X&s&PEQ`hJ/Yd3P%(7I)$BucM8;O`(q9Tc$eUPefh@%[2Qc8BX/AaN(^:#dM4r1M7`Y=n][@*`&finboQ`nbJ7P(HiqTj2:KlTM2:J1>[kqo/&E93u9lRu6i6kJpZ((rUhW0i;2W",]J2&OC`K,I(_$RX4%j2n%;GVIXH'\P5d=]'Wt#Dmf!)1?a(B3W*D("a%kN6<.XK'_L6"u5;09B6%p\D;0o0G)_n?<>7t"*54+Sc\._:[4Wr+EN9Pmm8XpaJJ.iYTTb\*XTW%*hY["o58N\E7SO>dU':OK?&;+YPSk,Kj=iBcE:kL>,L7_#YL$cNCInGeu]3US)e[?lLb.,GDU"dQJg5&=J7>7/TLJE)-V<=HN)c%tH)_m!&Z%Z1e+O6DQI$R$ss,JMqJQH>;bdsMX>+GXFVjnZ,[.:npuq>:-n>adek%Ul6U^!q:kilJWPu\o9Ne8HpEg]+R3*d8^AAi-F^USPrgk:U>`ac??h$2:E=hMk.2IF/i5S2+Jpl-c:fFW2R)9>,N`2Xd,oV,!ul6fCrGC"6:Zj^c6lYi\-XU*Z$AUNJ;\1d@T'Cr:]44,^bCHf4+R)H%`PZN$YLK9,nJ5+%$m3R==6a12*q'gUN'4s!4kM)B(LP4n3&2.EFg&88`tsH4/:1;9Kr(]GQ&fa1^&JJ!35cZ%%J=_c!tELB)q?XGE@P_g;J2(=cg=/d.5/Jk;\d9&N[sT.C>tfpjjL55&#!%HM*>f;(#=>^;#<4VVCpl>LM0$gD6PFHq53D?@.-VPY%bnM'D1g3j%g".qBK2[b^6^NH%l9F3lX,Go+h3_Y..[u;&$gf1MuNdI^DW^~>endstream endobj 201 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2481 >> stream Gb!Sl>AkH>(4HdUs)9mnYd,EJjt8*p=WmAu>6@Wied>6H.L^'H,B5NKOrV[%`W#V'6dA5kO^-XT+,VP.1nkK+NSh:o!uLu_juk-n^7)t*pE"QCbVS`T-\V:1>g-Qhq"a"ZYGD\6a7Z/u"I$sWEJ%DM3t24.p9sl#-\?UE^.0/L^\>R6cq4M&k==J>*'a-E@0B=:]9?q7EWr5];TgP,&hU-S"Qo`8q5Fu*SbY@IK(&G5E".A'%@*?E0#fZu=QYfJT&\()f:B^)"/@BO]IR_.$5aJU7*_LOffb[`MkstT*`Q(iQ.2O56,C]jHkW@)P-Y3lR6n;\8L&Mi3NH],ZiX)OH'?[RO0[2s-(ha7Ci`1R1C`=dQl.26I/C*%>UP9hgsX($jX".:+,l0%U2G"jGJDBCBGJiDQ7C8IXTCmDH'r\eQW;So$<(V6ak8q7R5afpaQW-`qu\?Je2\o8u'+ITZcX`:"KSqp)0'UJJ_7\dI56WKlVOqjM\0[Kln(*fYq-^/8FT0hOljnX=#OV.DZ[RI?1TqFm.MC2Dl/l%q7TctNXo)VhcnM+#<:-=HPfH/,S8h%"jDq9%`&k9rAA3Q^(i5HZhHC(]p@l`6!K9$o]i)Jma9!h8AFILttp,q:qZQR1r0l"'86tm[&8cZUN0^4Gt/.i=AC!O2$PXtFn=,b4s@leB$CRV:4j+=(arBoFJjVa4S1Mnl4f$dt:eS4AJAR3T76%E*ee9YI/\NBKt@1r[ftp?<62PsJ\)@Bk>?Jkiq@WMu-g(B]E)WbM^f/M7C4Gb0nGjf3pYA[Ntd$nZkaVON]_QDuE9p'WL.p;m=:?On>_Z*E:aK"[tY&;%A>^22/c>AR0k)igVUa&`Il`Coq0JAfD8sI&KPtpBP&lLGgR9ORX54g%C.datGrfJ!5+m:Z%XWsS.Hr,3=P]`p#%?deJ_Tm^H^:$%&"R$-EF>3kPm]rs2JZXeRWRWDZE*%p/'69'U,mZg8I5>A,p@;@Ib3jKN9cB`ar;mMVZJ9b*LFMWcED(SDPn./o9/:k.PEdl'Xu-e]@n$B4,hE.C_UB*hJ)p=XX'ocK*[Y:7\L!DdGe]8bg'aPS/F`'I5fGs9n?#qU6skeLL::QY6ip[RUf-1&XmVC8lK5A241mcTkh%XeZuc_g2PEYUDgQnD+B<:(kQ4-2qN&>d?7d^A?eqU7i0`Ib_HOaphaXS9l7[^C\QUtGsVrGs!0H%#=IBcRu`?"j]s$1lo2jRGSh[gD$SEn.27S34>UZ_)(SAm=F!Y9KLr,N-PMk5=[!+]8Ml>-c[]D_"8R\_O;=T,p9`EY)hSKT9(!rEcqmn>Wbg8#[@iKJ.=NePNpA?/a9HZ.E!e$/oRjt]XYMaG)&?iS_O@N-bppu2g?&dFM9=p1LjgTK^:XeWu-K39nm[,.R_(QeT?F@,T6?$9\'9u)Uj)h[VZN@P$Gn9l)!$bB-[\=nR3TDg%G`!f#o2F[Xbq!,68D@kbR`4N5`&&S1Hh*mCll2T.+/ij`4ZaO6?Bg0TG%oZu*5FEM__',qS(H#uU)OmD)`o1MskBH2QNk4Zdit0b,?-b7`AfO/(-sggCc!l@h:'^cnpCk.%05n[TQD]O=.rO:@>o8'8,bBXmNFs>+iah%C^*F*F,je8m^TGu>MoW0\qG%QGq;N2K3e2D~>endstream endobj 202 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2029 >> stream Gb!#\D/\E'&H3_"s'_]q'o@`V)e5DH=,BSk'fBn7Nc^PJcsj1e0=KJh5.IMqF[(BM0miV_C0_ZVmu_pU)TDd_KE+8pV8A;C1Sq,8n][X@a5ZU&Y?oDr#SYf,E8*VkoNp#pSZ&%+4Yi(q3uBQ_>kbp`XN,_JYC8;FS-sBd":gW?W]4#%6b6Wl#hK#o/IX^:4>>,pG9=WL"*Tsdq\"B'HTU3$JC"t`;MfoE-bj>H&7\uRLtZV',76Oddl+B?L)nVoM#G2"iD?-/ZC#7Vh#s&7?tt$]R)$fiG2/]Z7r1Z+Zj7T^m,?TfD<%&MqFJtRPkQ#?Gs44o47.V4O-RDhhsF)["q[.#\GpOQu"4siq[2neS?K[H"o5S/-X4qZ8p*\J;Q7drg]kP$Z1ODL&h0P7[5flgh.USP*&IshmTgbA,e.4Ri.LnJqfMcFBTYd+]N`B(@sNH`8>X+JY3]U'kd.bX(s56T;J%7784JF5Uj@SfkSF?$[IV)"AK-.Pba`&\=&_5et%l9O0>,e&Bobk_Z"Y?Ob/AmiQTDI8b:ee2s4f9&g4T\iB?trH?U[)3)QRh\I>NgQ1Bi4@\BUoME2_Q8oPKrYG=(QtC-j;-WN.\U4hNRSO;qR=oBV68CiYAqJEC]$;!Ei`/.c?5(NpH;__b9:n)jd!LKD9tna)n+TPIcC-n$MJ0rIWs8!D@bfWL"!D$>9)!?1O9ul@gZq_ZX.bFEigV-n>`FGG#8]!nc.Vlm.f5DZ$Oh,hqR.-2J$l_gfB(sop)^N_ZAlgN0ZV\r4bCj9p5siF?r])CQHo\l6:kl.Bufb!J,LWFMZ;oT\bbQo;jjGGhROOYUeF^k27B_a;c7.5/Y(to:toojdp!CM2L'5>,\kO%"X/juGg"pW*nH+NI]GZ.ftF!)qjtF.C$XEG9Nb1U[&hF@=`+,^%lccL#FCkbd/~>endstream endobj 203 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1011 >> stream GasIe?#Q2d'Rc%,s):tP'8]VE*C]:NkQ&I'\ij'gU+ef_kl,V4na55K=*;[,*V6oW8j7eHu.i0-(oggm'W--)Un`2ZK^R-"k*Kn#!]80AIM@Z59B+koojo2p3QiNWW#W!:UWu*18Z0SS.GM1S'i@(rc7debeQqF)KR07"0j[+X1[L+%)B,C1-^]M?iRiB/@b>2,%QRj+BO`4A-=V',I"hsaT1,Ri"!SJY%Qj#,S]u6Z)WR]OsW:`?LBRsK)hU`V]-$RZ`6,pt1JT:L/2kPF!W89a=%ila*X&k?N-;j/aBB1Q';NB\n6gf6Z?rZE<`RUfL.7W,4m#"[Oa]0K=o146*q2Kbm=j"'RGZFfsfg3iA,8T]I[h$FB96+Eh'G^:XZJ'q$*t#r?T.h^q!oPPpN<.X(f1K%'ufP[pam$q%;ZP.u>^krMPFi2BD'6PiVAA'T,O'W)7m7GA)O)q=HEF.@.Hg,65DUt*kXFJ$9]s#Sp.fP\+a(:N(qRunsYS,7~>endstream endobj 204 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1704 >> stream Gb"/'>Ar7S'RgRSs)9%8+Ap(8DX16MV*fg0831Z+[LaF8N[m-iu=+&G$pf!3Z0;q1/O>clW;I(5Mku>k_#i^7LpX;O6('9cVI[cgr`X"WUS^!F/KPN0SPd[2ORYMOf.6LGLN$ir,6@4S[*9>)&[FIo'\?#%T>qumQ7Y((iNQ/4C@`DtU`]6_I*F[k]^Kkito+C$Be?cbb]4hU$F@?);6.o+nFA/HOC.7UdX=RSG?Qr!s5+MO!NP/_m@W!q-iQ43AaKYe>cp))@;5\G;hJ2T:[/@/U#kmqXcgYWg0gYF16dkE\[4_Yq_'fLY:T\Ad5q(4/$4u<./2Ne%Z=0S/.aOOJXe7d'IA#c>ngh(aN.<)g;XX]3\[4?9tALV,dTP4'f2*CKpb#rY_li93=]j2g$SDEjnkWJ>NB7qfu&&lf5$^/L@b?e2JGep>Vp*%3lE0WF0nKYUCRh6(LUd_(EVj&LF_/h7DgiS`"8-F)qHIuLF&\[es7I-#=T$m;"i^dO\O,D':">1)?""FcBaMs8W(r>Q?@V6Z@I4U,q2/DbMVosk:Z4LBJ2d+1;YHVQsii-qH=\8D5.8<6??-U0heg%`sGfh0c<9qN"CQ^Z5m@]4Ap!EOkoC6[3tKl&i!a%B31D2U^ro3(#K)C<"B%Xgi02b8RHU>O-Bm8d)i>HZ+<*659h=-7lnNb$/QZgnK1?F5.+3%i6jm6Y;mJ;aCVlG&@r_*A%U6+8G[S(462:?kN\G^tmssX5<<%eHQP]h*IlY?gV'#JW)+K+meQJa!Nm(s]O]f>RLTRE9YKGWAi5\eHNL<"[]=f/2H?X^!q"`t=f71Lendstream endobj 205 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1856 >> stream Gb"/i;/_pp&BEZQjZC\])`_,G@2F!'\]0c39:B,NLT<$TMqEs*'nZlRC$sI-liP2Z`[3N[X3,0W=hDlFm*'rkI\9Rmn.4(LNhufk&)cgY"j162!O[^eK1kD=NfUmo+45JH4O'CJAZJK)NNfkK9Oj!R/riCrP#@L\ao+A$W]9]F">^b*%&G6J\f+?`dd9gea8>3esa9uF,e&j%8U*Ei!qP&%%d$lbG,CPTOWN@62D_?o)f;J!\QUHJNnm'1nFrX$W2jMTq&Wls!U1Q0b0/:0s1soj>=]G?KHXX%EEr+D&qS:g:QA1Q&'9==+@.i.b_uWYk6#&3LaN+)>dQZ0C;HO+[F3U\cFb8LgW`@.$(ue82'mBkKGF#p_9+nZ+MN=,0Z?l$%'e7\R$cfUfKnCCFOP=k,DT>`"s@9[K/^HGfnP)7LS.9JG5\5YPV=4Y-8-$=B^;@1^!0@A`A&NZ&a'@4K$h0^?O=_2[Dak,&Z5Dmj9J_G&q8SQFbchaUhEWZgO]H`_P9\uV;8]`UI?mJ[g-l.@ohNN+MlOm3]YL'`>tF+Q#B5lQ/La]W>b6B/UTCY:hP!*?_SWsbW-64)kP^=.ZOaIUF^[=,;QN2gme7?PJcqnN5Fgr\(*tSq1:,(fff0BbQg^S(K$Oq5)rI@YMfluV\0l/-.h?5L#Et_F:lpR-+^4Q,)`Mr<16qCt<[6rhU(d4"1Q;i9=*NWJ%U+0NJD')]%$n&WYB)TEJIabe&D(E0PH&BIsV.4=um6mA:WuXn9JR(^N>4q,L7iD@O>Pm@4$.?5u[p;i+fWH&VkI,CK)C_9"N0YiO304O-Qk]G^L65FmE@]/CX4C:$:Ku0R=)V>Ss;K+XHR6>:`Z((W29Ib[-qm&Rr\_CggO/>(nF_=![8LXbTsi>mVHUD9^TkLTs(+pp0eX#D"cZHgC'62TiHkc)hpb(%Pr(a.M\DEbD^D?0LD"T',pq7.&`8D`:UAY+&dRg+eeE_//_nY^IV'>ZKtupicM?5]_VqCXt10Hm`T.+^.7qMt`Qd3:U/P1[D<:Q_TN-".1\'Q%7P("O&JDBe8*)CETt:MAc/Kb_"HY><&+7R5YQ?!L_[bF#ul8(-A@f]Hp'JB(k=7h$()p+`JH2UJNe/@8HCg&obEOS443#Gh=W86[7KRPg-)P%r^SL:$fhXod3W"qj),q0rE%"]nnZR9-^a=A*F9%:"lnNV,3AFRe2<%>&9SVFmf5/"l`Z1gT^9Bbbm=Lp1aMY]\A/$o($_~>endstream endobj 206 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1760 >> stream Gb"/'>>s9G'Rj\Ls)9#":F^Hh8ToB2E+u17#^A+=Japh0g>5:XU_T9]oY:.eb-E9s'!B]j0,QC7e[_=@41f8;<;b/)],L_iO5Sqi"&4Qu'JuNq(gXrABRfJjIns:k&lhdddl,%N$q3%."?#rJ<;AA=mI(cJ<,"]Q/E!hBnqO4/D:Dq%XlH23hW('H2;Nm@^#l#4m3GFl3DIqohneN;_Y.X<>PFfY&?r%>8$&-,i3%MY8er8U,d1^Q/7KIkI,mT>>ufg\qNJpNR$qKO6=`a@o`TSg:*K>%(RfjnKq'bTbam,PWRBFRNXst@C6LCE;W_s^@`9$9@t-11=Z!ZE"\$m71'C%TFISYj(m\nI#c8$DVhfW&#i]jh3oN&S]Zd;J4g@hZkMEu>6s(=r2L%*.Ms*BU6UYdoLF#n6btnjHPNSe(dSg_XoPQC1&A@`]a.j^:Kn*m%5Y<+S)S.a/ln`SrY]-Ii:^HS)0O2qK'KDVnNpj_J9G:A5d)b8OAE?dlpe]$/Qd/!AKqDAUb6k:*9Z9n0h6b,`1.:ATNp`cIk].GmONsWF7lM-8B64uEkatT(]r%$TF7]g;Kjpi?A/:GX@sTBK^N1S36?[ti:'PK9ek5G;/6DdYGI\!Nd]CFhUCfLn'V"U2Ea[;<%8gRU-Y+,<-XtCgjEiIpl'PcHlnPJ/k.1>ZNi2!b$^Gh."5C.d4?6t>J6Q$S,Wign4BHfE7T0fqK:3Bg2`sP.GiGO+U0BMG-1\Bm!ZoptlYGc)JO1IY+'-pq91W'EZYi=rd!)6-^hMU9#TEQ$56O:;pYs9YKJ-'aKNU!8*M$\G(1NM@eFdYB_A'%Jp)3e[$16;,#/%,-6XU"0%!*-M).'5Y8aU.7C@;6:)W`@S,N\4,J[i^)a>u=Ad/_B$ADc0$(o9]5pF`E[f)OVL*:#'E42@:W\_[T9I,Zdn2mIR7%p"0j]6O<,"euc0M"W[VPW]\r8q@1--J0D-O>j8QN<"AUsYFIMs;m(ROE5)*R?Tr=,X$O%9~>endstream endobj 207 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2265 >> stream Gb"/(gMYb*&:H4YJ!`_b8/RK#mp!@t\cHiPUDCJo/-887D/Ek+'r@_jf69bWZ"2%d@`6(ah)#p8,fQ0-[kgqi)ZHMsG;'2Fn%mrh"j4V"!B#Z6hAI;[Dr5qhqhA-u%?5&NZq[bF8i5?]n>+cgL[!:bFRZ.m*I7YRKE3sl)[U)QiESecIOf!gg!)cG$.:*^hfB(s6#OjCSYURs."AeucL$/,#@/'s%(BC,Hq\jcjI9AK"SgVQI2S\<`lZDMGoBSN&K'Xg]o&?bBog/]"@p"8RU;:h1G>o(WgVe.6g1;e8(s('?"_?"07,!9^j?fLkMc)S2cgCo:IiG[9@"Ku("t#RnVu13=Pg]atCa'+tQ;Ptk^\8p"!Ll$;rR%nNafi;e!G9`-/@Ab.Od=Sh>L74GL33E.b;k@h7>GD2@PVmBJ0N4^/$'FLNh#5munD?fps/.2:l,KMR;VVSm0nAUH`&FTM,huXE8@h,7bSV$GJ:Z-LcIcq3kAbgp?P(@3'mJ2CX&q;V8Cj2LPDKbkG[LrKaQYIkqT\,5gnji(fOp!Y`hS%%F5N2MYZbY@Z-bNldq?[&uZ1II`M=gGTZoSfp_o5n%NXdd2+'?"IN_d)[PW]/7BWWdp("q^o<"C-a[&ar@OpEAL*5EG4mn174DjpnrG5_1SQs/W%#Nh7'j/gYJW6)d(mV"lkQd[J4oiT9S&oYN[2?6#NdS!R]DOr?ea$?$O*d<1etc\#C*?]lh/-%9+>Wfh,3V[-Xic;$U*Oe<-RFtSdXhK^c\Xb#JapdH$r&GirPOm?MbgG.)7oIVUel'`C0lmDP_:oRfViHJFZD.i`O(>gl2T2U-\'81,'Aa7Sl^)Lh=`TE%X-3N1_m&mTu4SW#.nl-6,!%c4&0NY4rFaMr"t*7f2lje_PY^6&pN'=DTU8:pY?9)/#LOr_]`:Aj^mdm/-'7=6me8i#GS4EG/!;$9dKGX+D6IFP8YTdc'haKqZ+@Y,BuG%/X,/.R:m>frbE%'rFs)Y[1-u\\e:uK"b^.o,oh'chb'ag!=qhM"Ht&*.e`a+f,!.PSOGPX*6ZrBI+0ddn_eKJYQ>C150[Y;NrJ.L6e-,mY/u_\sUl;g0_D<;SEf;5Rt"[PfUpiTcp[(W@m>lk(t=orI9raQtq"69C&Gu7aJp5YK9/#^&P,F2G,O01&*5H\hRo8/aj%K.['':f1O8E/6mQd4-Ri)^q>WCVk1Lr?!h3bYCS7DdQVk@RG(gXgrA?6EKsV+V"^6tZ.o*?<_,6hV%"N2R<"mY)8n8;C-MW+I>FS6Ps'lHGuOCnb10Uqf9D+0];BdV7K!0QVB$,6Q3>'4/_ujM@bE[,RJtr]0hWaO_(%k.3?ZT0F33A-S"C4*.@1~>endstream endobj 208 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1565 >> stream Gatm;D,91]&H7^.J!c8tl&=Mj1nQal[$:W2i(Bo5.WXkb\@'"YD25`(pYS'=IWt.3iu16,47g\N5!,@d5fFg>Ieke77i*eD)JD1A)ph9t"SWfMmchj:l%rI+R]<)sQ=GK>:)2TPR>9FkZ>%j(<00Nu%Mi4FgZ(u)k4YmNLj_b'^0\PrfcG9C:6Mo+EP1*4th/[@HMIDX)BcBbL*P\%7N`",jc(#Z]YGLP3W@D;CCjDCY9L-T@bs^u4\R=@e,kJku9V0&GKj[IV)r\aE!\a-ZOPsLsbroQj"Y$#W>*CW0FsXCDb-Zcg`t>0[YYCLh!5,\=LJ"gI2EZllCKag(E*4`mW_#iem;[L1OhCP?6^opL>XN>rSp2bZHNQ+-n7-*8[jW^_\g4uOnZ91(kSp"nQ='b)F@tC-b_J_k!:%CWBo4WkocR1?F4IK+F]I4="hGsbA\C.@hn8I=N\eY_"jT!*=oC\l[6$IU:!d@XmX$s,_/3kYZt)39#H,ckD9*hAMo(ja)eC\"ES;A(iIBh]NsoJXhBs./i8:1T5,`f_.mYakEOQP?)M80PTK*LoZE@SI%gftqZmiYD^G#5`EOU4Z$[NsG,TZs4jpiN2U>VN0[0IX2+r7.qALG,ScBD]+lG)V]p(h"1Nk/ZbZdW7J\otBW-tfB8[31^9W6l(,?D2\29TpHPfdabq]Q]tDmn(X+Y>4^a'p.)o`cKNFL2l4l#@AgV+g4_b+jgjo'>6%2I'fTnfpB^?/M(>r4`V2ho7Tg;uD^&2g;2fcoDL]0e"M?1(nAEa]9pDSUN#Zs"ZE=:kZ$J@5+s8$_&?T[qj]=KG,JnnfGRj#n/!\T)Yc]-O1MQ"r0LWC-)A/SN**cOQ;jo+;cio/MH(SahXq]pJJps7pRdtj$EpR58uO+E07.;0I/_cqq%fmog]Q8o%9[ro`uO>aQ49MHD5I*Bc$Q3<@69KYood4VXVpaCAL4#hsRU#GD"B_Zi.q>W+(VY[`:=kCQ%J[?l(Y]:X++pf#>lL[Ls+D*>E?\^SL'nU>;k@Q]aoB<+s_2mAohK]L[[.0l)f"abgo4i*S-[FNI9Y7hNqot\A.li"QH_]o`f#uWBCiI@7C]cuAIf'n(./s0+L0A?<1**S'&/C9oendstream endobj 209 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1112 >> stream Gb"/'hbVu\&:R./J%3NS61E3rh&Fg.6=LladBj.SWbP8M8e@d-(\Eo(ST)4Y*p:A\'9DZ3n09<(I.+MA*\#.j;jc>]20=kI\T8KD-E"B`d\Gbpa.]hiF;@E9K49'T\C?GE[0ZmBVgoJIgmG^a6gs0R#p9q59E`9t`:j>-GT=`]hs#V).$0$i4:?a_K(ESLOJ3E?j)@*sYm@+cFZWFT!]H"b$(DGQrbaWNPlNg(a)YsGoUBt3h*p/Qj"S:`,cntF$T,iXq=T'cnJ>8-!l`WpIqWH^N056UBQkloh1F7SqGp#pc_r&,PNfOso'C:V$hP;$m>%jqG)O6$lJJ`Fuh0B3irVHe8DC^B8p>(]X&?Rr6*lIQ6U$%G1fW^(S%7C8E5]tEdpops9A6$XqrfRS)hYE>c2EBOM;,R9g]/F0(b5cBAtOP)q7':GCO9Aqb[fKSP'@i9-9Rop1?7HGH"P)R)qQ?)e.'I1_6_K)1-U!/WKNcg(U6!G(4Uj06p8&T^pjTr2ZetZc1_(CC9q%!"o7;Zd;QnH/Q34ld">[m0N]"#^fW*Kjs+mU@0=bNL<@eV=pA-,/9fd!TaZIau^qp(q2cD(1)(CkVR%GUDA5t9^-ka/d1nX#@6Wrd+*Dhl*F,jIOHpCuHfKaVP*b(fGhRSiT/MOjPiH';!&%lC(:VRZWJ;Rb0*g+A;R?F2S'70>8amMmt3Ok4W@%c/CbpW_n$d!Q<90^oDsFWPV&MM%Hb-21(/:%=l[NOe)\:*_*$e#9\8;3mJp_mCuMYU_<:7_!hO0ZaYendstream endobj 210 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1429 >> stream Gb"/'>ArLj'Rl+]IlNJl-,qaT61`T+PH%N)RjD+c#:/@fA+0hdM*5I'WrD`6O)8\8"p]i19T8;4HCrQ;-m]89rNc,.Dgo&%&4-4(9CjGl6#Jf\[(Q?fe15,_D#fE[Bdu]a/Rq+=2'k4St:&RDe.OKAfWF9Wb'bR@"IsLj#&j$hq5imUnp1NL,DDQB.kM7;)BLDBrQFEe15fM"?mn"FE&k&GK];6!/5\moa4N:?:%ZL3u:kA*e4M>W9$[!\DAg='Z37M8Ied%^.Q&fg@dPr;E$#cW8/RN0'*6@Tt?Ti5:8!cbBi1q;8d"ibtu]%IViTjs)e0M`)_>S`*7cj2qi__q_c_;"7g&f&(V7U%+P,_'+HhUFr4>8r_uVp56&o50u8\+U3R`77?k=8p`M#ZQSGie%s1-u\k%RQ6Jm/QTINqG-fseMC[M>>lRWfe`$&`T!(Xb9aoF\?6Pdo&n=L2,i3JMac&Y.f6"\XEi.l"MS?=ddr.V_g?nDjDFW/.$[$MhMdaajTB#O&F/5]"L-fIXd^D(^VWdS0?WPDCZ9U,Fi>DNN.iS?$qbTp=./jj)5TFi*rTM0teA6*S0O`.6n>TKVeSpm$oe<[q!U?VgH(/`Or`RcDXf99:32)NDNm:=/;R4P=p&QBQ7a,e>8f3c(=)8AMYIY(EQ"COiY=2lQ5,l5

'q0=*e%DD7+BFoe`,/dnm'3Q:7lRMC^UhMJCSP:_?kh_s0_U.s.rn"olSNpA~>endstream endobj 211 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1819 >> stream Gb"/'>>O!E'Rm7(IlNJi[=dpkp+7Sf66_LV1S]s((ZeL&dhd35:\D^5uKZp^*h".U/EbZP/''*E\laC7\BQMBg7!Q)[9L^$ZVQ9pO(dVor*Peabm/`F_SdPtdq`CWU?_o!U&]2([jR+Pp1iA=V-Q\ANJW$K[^HrL5T&r/_\l$FIEn.bdN@;Zi.)a%7XcVa%;0BULkL%N^%#"*2fqJnl-Q4Q=ekU?,,LZ%taWa(iD^lP_nW9`CC+fK@W-6(cMU"=X%`$YMT4/iV1Gb?!PNZu$oVAB2DmdWDe63W.#pLN!ZH9FGY.6Tm1]R^mpn#PW2=(IK0:93'38rOdJ>,orH0iH5HekC/@!1h`/bR`Fksqi(GuAlcSp`m?B'[1]=Z;'?0/>A?Tak)on#am(+VF+?8=u0pmB.+"&t`mB(>^:KB#S$4o\>:K>H*:QKURK>Z,))!*oISfR[it5^;P3j?hdb#6(oSScVX=I`L;K,?l'@8o&/\C6`Lk31?sKVA"T39L*T,_<_On;;h\nLFWRO^/9S(ZlnJL[fC*Y]_&Yan,Wh/p1E,HmWi09K`s*FP2Z"hYeb=\bPJ:.V&>e&:@d5TK?*]IFECGY_`YL?G[ZW:A)U92\F&dYgT_3+#[1XJ`].l4fr!NqnCtLGg5X:Ml`m8;/amS\0'nJY$%;KaFU6AUr.,cj\E9f_A)Cj??`DJif=cGq2laO[Xt5hc,=0qn&s6];l^p^9Ra`huj[3s%)A8(Bpi^_,3uZl6HIRa/&%Tog^"K)6(TN>Q1lA4G+k@sVq7jN:Z7Ef0U`#F\R5Ti]d#46=7-AI-'An/h`_uW9UcK#j,iWDuRZ2*:"'ZS1P\BFQQ4&[o8_R3q]MA9`'_p/&rKlpK?[SC4!d"tnP-`/R4ZQTuLE&&.FAA9G`k"[LnqCV:XZM:t?@mFfQ`r=,=mB-LOdHFFqS]?0FD(mRYIjj#c^-0b8%QBP!$(MUVsIBRmd>&))$5)Q[aeSiTUVeQVWY.OLiT^\Q4'L1;`2,R,/*rd/mnb`'Z>-URpLgc`m:BtYrKq_d>16c6sOO\*qW\7=1K9Hg1!G:6/=o~>endstream endobj 212 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 2196 >> stream Gb!Sm>>sNP'Rl[Sq%)Y"CDgmrl-9`c6cCKi:`3\H\(3.3+Ur&.Kh9.Ss*daf/gQN,A?-\c&J^HmIJM/KhmnDjMEaN.SU(:V@q_JH+;DgO+M+;bGQ@^4`t(BuIN[lW>uaj5=9_kJ>uA#4NfnD_$Boj$WYdG`J/DaMp)1h0`K_;hKGo.Q'P^N=2aGba'dnTP%P>_^iQ5cjZ-/H,XL(>nlFu.[[*!5ua:o6[3[/eqi?h,n.nXH&S@r:Ab+^",CR+Vp37I>1Ya=A8:3?0,OgT#gU,c8sQe&t#3?4?:XKAN7!lhfPX&@,C7!.*M=7A#sQfElqmZ"Y22E6un7-q[g9h\IM.#TOAjF.OA$?6aK>3UU5bF-1MhV/R$Va^Xf3K%J)7N_5cT?hnNXV_QD#2NMUKc3Cs8UUAT*dJccO-O#W,M&?@L?%sLmde!Tfl14+"7MirU`&O7H"IV1W>_j4@bJ=XT?'!=Ve_pnIs%F:$n4;C=>j^H1c"(9e0gSA7WjMP"[FGCItI_gB4k*,k(m^[rj$+3]E.aFcNP?<#>+"2>RUZ&1bgoZJS_[UXP21E%u&&do1?-k1gMRaB4OG,155a@nuU)7MM+9O_*;;uiLUc!3m/tCfPr=O+[KX7!CP1J.]kj/$un,!7en$24OV0(4K4]JiCi63M_%41Ip3KhUW.OI$0AJCPbC`2*/bkYdbV;19=4`EXcP#4%i;;jpr^M2UXQ>oe:M(Vmc`a1""Ar.n^0;qW>+ur"QaU!u0CbB>8\fm5ppiaBEbJJNGBP\Hjcgit0XilOHQ>X"ACaJ]mUba\&*0giQk?PN_i4Jn(nH4\XQ#.W%l;j^FG[:r?=&aq.Y&]N*kC2&%8+^,h?P.iV^GiEG(D"^l:NDXQP*e2%B50NiN15"586q'+IM]>#@SC$5=f-[UK'R+rYokp%O\g/%;Hg=Saen'"(]riNddA=mo'>KNiLRWk`5*pCAA>SIU)Hp";NJ/k\D0MNdq7_;colK*ja(Tc[L*@XB(>84DCtT/od8endstream endobj 213 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1615 >> stream GauHK=``R^&:RDTr^/o5Cgqd#6f,n;9Ml`1!G>\sf^pCn!@H*aOOL/,2F[`CU`&&+&Yl3T.%mWdRILrC\T0K$+qo?ViW*5(sfLi7T!$*=Y(rj/!i+`HsG#<^_i$Fj,+$/pt`3n#KjeNSco^2Rc9sq_O/t6HI[&_5e'!2.IG4o_j!/kf5dbY1`3n7L,Zf4m\;^oo$]^VDO/:r;fX8$F(7]&,R`&`1H9<=hPe`[(MoZZE<_$/K*@5_a05jV).aPurNJNNH/n>%hg=B@5aJWf!V\6,$i;;PF+2Df(mfCT3>oVeWf"-Ui*erWH@((UArEOKafMKSq`7E[&X'V==,u)aMW@5IcDk('J:Pc1a5`DLZQ:ZZI't.85+a8I/XbR^I=9FnE-03k99(>263)s7u"*mpQPa:DK?RZ4TueS%FQ_ZTmO`:/dJDOo;P!flko(FeNJ`uTMX=1_YG:?XoK,BT:ak09m'?:c[F<)[dKY1b%%qp4s'b%r=8V*sD4C3"SY,X>\nbnj$7/gXdKP7BCZd\.uY*nTFaSaI"-DUgV:fnQ(,;R4>fWe3fK+PjAM2O"]"?)ShZ`8([kcB*+2lrFi.sP+I/PEd-PoA/f[fjr/g%>/3'BAXs-*$O10uu$>A?@t,3F'sF0_1GD&@&TZ_*%I+bh7U,n571M;3TjJO'1eI7m6gC9R=_Y46BP7=*-XNcqW3Zrp>M#+;7\^@X0+UOs2i*-4j"*3?aK3,)Ve;+MEHA;><%qX;=KpO9MB8'K6#r"J+'AHIh:!8Yb"+c]t&Do2lZk).M04APCR38'-m]oufq-GS-l]8c!usKW3oElfcW+Jf-WVVMkGZ,+O>p,Toc"4C@a53umE%9V-Ct514Q%Jgd,[N`q$N7@fCaFpBr';.#EpWp;c-e/6+#2g`E%1.bBDmFIWYU<)9\=$VPuSYHh9L'2Cl,aeo\rsrQ8fU]2`^CZ4'K(IK@`84]_~>endstream endobj 214 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1347 >> stream Gau`R;/`3h&:Uh4s"N0USOeuClju^jf9MV`Sj;UbT[$A2dlIm_L.P9(WPT+".\-pWUH#[-%q7VB5Ed*nXcEnbXr["^&[Mi_lu`$C9f\LGW=Y$!3`h/XZG81^DX0&;r4k,@1@;1a5+N0VF_*6-'2Q30XT-5\7a*#`>\t&b,UdLT8^l$^U(?fNH.,S1k7#c]^>!.aCH0JQuff39!g&StfAr*BN\\ScN;$g12K\fnq#-,^Y&p.5&K^G-tdX.%]-H;SWom>sOiI-,qPQKp$#i"[^R1qfGQWkh-Z"DFU7L@6NhEq&[o$V'MH.r.U^95D[U:';Of<)R#sJR-5BbE*gU'hjPT_:&5%tiTE9U-1(7HXFpDa9/?hf<]8W+d*@O>g0*LE)\AVWi@tJ]dFtbul,[:JSRK`#tXp'(.W`)XWFB2jfOFag1Xr`X645^7DMqt>(Fiuo3q2Lc==FjGE]pOPB:mf]CWc\K\a92)pPuo-./jq,k:Pr5)@HaRig<[C$LVPM\X(h`KcR&T$Qd+2:)O$ggKk]=POk;Ft+t:rhrfRfEhdc5:s-aO%X5emk\SX&i0ak8qT`7&g.!agnp]33EDS>BN;>5(+H4K2to2RNH34Y+\9Jl2BglG]T[9s38/74_qjGj6BtJoiDq!_"(a.")]26I?P^kH!+);^VE8!YNmn!QIn6cYUPK!?s65VYd.=VUQ#ebKD@LV4)21,2Sn`kr@?;+/:<642qD);'X%aA^-;hlO:o\,fpdS/6@2n+9L6OImiZQ@M.(IL\p\"VdU-p)S"eF+n8$6tlT=O2c'n@qS(+3Zc]#X`?G68>j2E5S3'I'Rm!n-9~>endstream endobj 215 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1670 >> stream Gb!;dD/\-!&H3_"s'_-&-W26SYMX&Z%lE7FW2-,?CE!Qd3VF)5[F^pUP&R>upR>HI?bcla*Dt-j+M4sA1XF?/1CaF'?UT9&!PnRUr;%?5U;1^L7$BGEp7OK055OmGLh*f[/BL:=FjMs4;Ui.0.tp5[B!G]S8AWRGSIJ3r^J'^tO=V5r^_%CleEg],G=\DmK+t,Yk>N5*&/Y,RU7>TI"K2#Y?YqI\5#IW)>!f1\bMnG;Z.%FGq$'/V9'.o:(DjriO59]6gTR4fQ`Vh;:?VP8kCJ;1[`QR0p[5?9muC-^\)>k*7.'I3)Fa5Wk8:BC^VOijk%'e0O1!C#aH*I$6CIt61:MZ#Fg2NUT@u"OLL6V),bfDIKIifM8YZhuQ`!GS3*lAhDYWKD&P^]0JR"/rc?#$A>^b4%Nbh]DVjd9&kH.1u.mS3Jo+FoBXUUG&.&NkoU`-OQBn?KUDQ^`?Vgj\L9kZq_6eAH>1I#AmYr)!#36Bs]8(9a`O>r+/(Cu>,J68GBf!76PT4tJH"&02ZTS3Fm_32$@8Hc]4m5'k9Q^s_-AkJIUtC.tBMl@Lh")5DWh2KQ31@VI'5gj6NES+TD(qS"!'!C`44\(amGqAt/sm;#*pdq_\ra&RCD7AWugB%%gh.p/AP%EgYi\^5A;%*kn0[?0T?;KXUtU[",SiA%QE6WbZF*k^gfqQm=foGp`ghZJS6TP+L*R+_^Ce[\%4C^qoGpT:s;sE,0Y(Ub'a1B+7e*/cN@>bDCX+j`eVfYe*3o_YoFt4=j5k[\5>J;@Im<&[3?JkS]'$D@5k$L>A=nc;pHN/NqFaVGW#(7Y4)[6VciCDBM,TE8qj26"q)mC>[/Vbq2Vc4_^!$D>c^_=l/t$/5Dor&5P8Ch&/t#h-%f0NW4;3rP]:[b'*1(Ldea5X)!lpb8FmhBDn:,?b=lZCqpfm"$Y7Ef\-`@XC)ZpJI$BG`C+<#Onf)6QCPoM$'2'IM+H]*)[k*FY0AqNe$]dNl5Q,?OR%6OmF>C&s*;raHHe%h-/C,&nk+'!]K16bW(LcXDÐBC'IeWD1N`))=P[<-@b.5RB?k)RKo%/8^bi(W\!W`YVnZPV)8pLg^=0m1;XM(gn>j2!4i2Mer)Xhr57giU_X!iWX&#Pf'@Ijh-Y-r@fnRI)bTdQi/dS<%Yendstream endobj 216 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 1719 >> stream Gb"/(D,91]&H7^.J!c;U"NJ'&9Cd&1\[\rY@;U)TmlTj%`"#OY>b'hX"9Qb.hV!=#AtI%Q!\422oWK26r*mS>QiNgf07`8D%e_bbg;c\oa%%DaeQ#$aL1Pn3%2Dk^l1j?0Od_;fDoYAe*,7M>/S;fQAF0ipU,Vtup=rUN?0a2:Z$S[Bh/oKK9ZWOhYk?Z"o$>@`1(0c_eTFU(EI//tG8Yin!W-fGWjCuXo_3_/>OlM?75L`29BXhW%,rQ8_'13Ifc8eD'8F_dQpVK@q/>@VcQI);0T&:3YV9+8eQ%q,ntLd`[CQ>oR'8O^@J%+]iTlQ)ifWG!8,lE_KVf;Zdmc=]pO)7cX'u5d:r-@P_$8ef#[AtbF(>51"d[D/+l1oK=FW'Efq144ZcgJOb@GehgXhALX'Z7hQgVKt>R(du0@8[Qj*PiL3Pl))bX?O[>SIIDEnLoYmd(>YEf[D?A*NgnGS,Tk7^)%c0Dl#Om)87u0iD?tG1ihF`b,+4W06:"0s[RJ1;++,",0Q=++ZaQC?YpNR]0IX4bk\FVdMB?!q0hMpG%Sr@-+`Z5i-X/(pg+Wgf';hGbWm1,PSMPbh21%hABNOh&L-ggGoe7"^?CnKEMk(7m0(*I*s+@&9Ye4:0Vn,uVOu_>LP\M.0RJNstFo_Z1>9dGmgZ5?FS%i,`Ok'.&d"Y&m4Rdi2-e.ppp)m%inBm.)sc/AF@sb8B3h]@al`;5AQF`*XJWWfH_j??mhHdM*pCmPblR&l@<@Lu(r:CBKf&@^`W.=C4ndM3mg[H]6%^JnYT;XKdQ##[JW](D:D=<0!;c+E3pb+:/AWUtLDmRlT8:'$3k0glW*K5#5JuJKILjU,92!rI:kA>sXT.dTVOP4KUgNAda/m;-1AGLt\W>bX6lgEl)"2M.rA`8;!5>;BMrSZ9LHMkRR'i3'E?g*kR-7c.rT,9=SJadsi5;6SO\-UN9&[<=e]o)?]c9S.UT`h%$PjiSUceoLf.1R_V#[hoo:$`eYgMr/4TBeq&=O<^Oc&3Tfj3^M#5n#Pc_Skp_u,-+]*N+?p16Q#Y8CJ_1QSb1\_F"/[I5Fu91R\[ep`2j?d:7V-Tf8JibS'c4+XmZma5^[CI3Ro[e$kW+N'!)*YtCt#JCP]+*[cK&`9,0%ZHDATEB^=2','m.,ufjR7L52.Z@q$bYc:i'uK)DR["/Oh5N2!]!Yg1\/E_]VO'BZ44piLsD>^DfV1V=q%=3q[%W'i/\e(UV(OO.T[Pr@!Zq,:(u9ej>L]Q^Egl_bOp.=.cLoaC1RQBtL'9>BKmc:bM'6)bi!LN[go;Od7)`W[C*/"-_l`9no,]:`e8j)NKmX!LM`nZ2~>endstream endobj 217 0 obj << /Filter [ /ASCII85Decode /FlateDecode ] /Length 485 >> stream Gat='_/=ii&A=S.&+>%8ZXQoAs?]\-_dp0u9&d_KpSiIlc%":HnL"G/SF#6!C[^W1M"5m_,NQgdLs:j4I,Aco9ZCsU.Y7%hA,bqPZ,b?=jJJ1rUp(kd7k(D=[ZW$OdEK_)lP@[)0p;cu4=3[pt%r=uH@6Bq_Kl!T&"'>[$\l(bf8$M3LJfHgqF*AFjWk0'WW`W4^0^t\RpXjrE=.ZV#![IgR=*QjT$dgFBY9!Y6`_DM'c#dYAY1+G*f>3U09@;Ai$H%f_(@%C,>(8`dZhP:pMPU_IAc:qjWV9)_qX@+[YPK:?KhnqS+b*Fq]s&G_9GfnZM;sbJ!4361B*$olLmqJBJ7IYurg3=1HM=qEAFsCW/Oc6fUL>5o-jCm$fhkX[lBADpkb+=\oSKIKhQg60K`OKB4iLG/,chr-sF(tG5^2o9n&$?oX%eA$9r;m\!q2Y~>endstream endobj 218 0 obj << /Nums [ 0 219 0 R 1 220 0 R 2 221 0 R 3 222 0 R 4 223 0 R 5 224 0 R 6 225 0 R 7 226 0 R 8 227 0 R 9 228 0 R 10 229 0 R 11 230 0 R 12 231 0 R 13 232 0 R 14 233 0 R 15 234 0 R 16 235 0 R 17 236 0 R 18 237 0 R ] >> endobj 219 0 obj << /S /D /St 1 >> endobj 220 0 obj << /S /D /St 2 >> endobj 221 0 obj << /S /D /St 3 >> endobj 222 0 obj << /S /D /St 4 >> endobj 223 0 obj << /S /D /St 5 >> endobj 224 0 obj << /S /D /St 6 >> endobj 225 0 obj << /S /D /St 7 >> endobj 226 0 obj << /S /D /St 8 >> endobj 227 0 obj << /S /D /St 9 >> endobj 228 0 obj << /S /D /St 10 >> endobj 229 0 obj << /S /D /St 11 >> endobj 230 0 obj << /S /D /St 12 >> endobj 231 0 obj << /S /D /St 13 >> endobj 232 0 obj << /S /D /St 14 >> endobj 233 0 obj << /S /D /St 15 >> endobj 234 0 obj << /S /D /St 16 >> endobj 235 0 obj << /S /D /St 17 >> endobj 236 0 obj << /S /D /St 18 >> endobj 237 0 obj << /S /D /St 19 >> endobj xref 0 238 0000000000 65535 f 0000000075 00000 n 0000000143 00000 n 0000000253 00000 n 0000000368 00000 n 0000000579 00000 n 0000000751 00000 n 0000000923 00000 n 0000001095 00000 n 0000001267 00000 n 0000001439 00000 n 0000001612 00000 n 0000001785 00000 n 0000001958 00000 n 0000002131 00000 n 0000002304 00000 n 0000002477 00000 n 0000002650 00000 n 0000002823 00000 n 0000002996 00000 n 0000003169 00000 n 0000003342 00000 n 0000003515 00000 n 0000003688 00000 n 0000003861 00000 n 0000004034 00000 n 0000004207 00000 n 0000004380 00000 n 0000004553 00000 n 0000004726 00000 n 0000004899 00000 n 0000005072 00000 n 0000005245 00000 n 0000005418 00000 n 0000005591 00000 n 0000005764 00000 n 0000005937 00000 n 0000006110 00000 n 0000006283 00000 n 0000006456 00000 n 0000006629 00000 n 0000006802 00000 n 0000006975 00000 n 0000007148 00000 n 0000007321 00000 n 0000007494 00000 n 0000007667 00000 n 0000007840 00000 n 0000008013 00000 n 0000008186 00000 n 0000008359 00000 n 0000008532 00000 n 0000008705 00000 n 0000008878 00000 n 0000009051 00000 n 0000009224 00000 n 0000009397 00000 n 0000009570 00000 n 0000009743 00000 n 0000009916 00000 n 0000010089 00000 n 0000010262 00000 n 0000010435 00000 n 0000010608 00000 n 0000010781 00000 n 0000010954 00000 n 0000011127 00000 n 0000011300 00000 n 0000011473 00000 n 0000011646 00000 n 0000011819 00000 n 0000011992 00000 n 0000012165 00000 n 0000012338 00000 n 0000012511 00000 n 0000012684 00000 n 0000012857 00000 n 0000013030 00000 n 0000013203 00000 n 0000013376 00000 n 0000013549 00000 n 0000013722 00000 n 0000013895 00000 n 0000014068 00000 n 0000014241 00000 n 0000014414 00000 n 0000014587 00000 n 0000014760 00000 n 0000014933 00000 n 0000015106 00000 n 0000015279 00000 n 0000015452 00000 n 0000015625 00000 n 0000015798 00000 n 0000015971 00000 n 0000016144 00000 n 0000016317 00000 n 0000016490 00000 n 0000016663 00000 n 0000016836 00000 n 0000017009 00000 n 0000017183 00000 n 0000017357 00000 n 0000017531 00000 n 0000017705 00000 n 0000017879 00000 n 0000018840 00000 n 0000018960 00000 n 0000019070 00000 n 0000019283 00000 n 0000019457 00000 n 0000019631 00000 n 0000019805 00000 n 0000019979 00000 n 0000020152 00000 n 0000020326 00000 n 0000020500 00000 n 0000020674 00000 n 0000020848 00000 n 0000021022 00000 n 0000021327 00000 n 0000021540 00000 n 0000021714 00000 n 0000021947 00000 n 0000022121 00000 n 0000022354 00000 n 0000022528 00000 n 0000022702 00000 n 0000022943 00000 n 0000023117 00000 n 0000023291 00000 n 0000023465 00000 n 0000023714 00000 n 0000023888 00000 n 0000024121 00000 n 0000024334 00000 n 0000024547 00000 n 0000024760 00000 n 0000024973 00000 n 0000025186 00000 n 0000025399 00000 n 0000025612 00000 n 0000025786 00000 n 0000025960 00000 n 0000026201 00000 n 0000026414 00000 n 0000026527 00000 n 0000026818 00000 n 0000026899 00000 n 0000027062 00000 n 0000027179 00000 n 0000027318 00000 n 0000027438 00000 n 0000027617 00000 n 0000027798 00000 n 0000027930 00000 n 0000028083 00000 n 0000028222 00000 n 0000028403 00000 n 0000028546 00000 n 0000028693 00000 n 0000028872 00000 n 0000029047 00000 n 0000029218 00000 n 0000029411 00000 n 0000029600 00000 n 0000029763 00000 n 0000029923 00000 n 0000030103 00000 n 0000030282 00000 n 0000030450 00000 n 0000030608 00000 n 0000030801 00000 n 0000030993 00000 n 0000031138 00000 n 0000031317 00000 n 0000031464 00000 n 0000031625 00000 n 0000031794 00000 n 0000031954 00000 n 0000032117 00000 n 0000032284 00000 n 0000032465 00000 n 0000032642 00000 n 0000032823 00000 n 0000032998 00000 n 0000033163 00000 n 0000033332 00000 n 0000033496 00000 n 0000033672 00000 n 0000033788 00000 n 0000033957 00000 n 0000034120 00000 n 0000034325 00000 n 0000034516 00000 n 0000034698 00000 n 0000034883 00000 n 0000035059 00000 n 0000035202 00000 n 0000035415 00000 n 0000035766 00000 n 0000037795 00000 n 0000040374 00000 n 0000042501 00000 n 0000043610 00000 n 0000045412 00000 n 0000047366 00000 n 0000049224 00000 n 0000051587 00000 n 0000053250 00000 n 0000054460 00000 n 0000055987 00000 n 0000057904 00000 n 0000060198 00000 n 0000061911 00000 n 0000063356 00000 n 0000065124 00000 n 0000066941 00000 n 0000067523 00000 n 0000067770 00000 n 0000067808 00000 n 0000067846 00000 n 0000067884 00000 n 0000067922 00000 n 0000067960 00000 n 0000067998 00000 n 0000068036 00000 n 0000068074 00000 n 0000068112 00000 n 0000068151 00000 n 0000068190 00000 n 0000068229 00000 n 0000068268 00000 n 0000068307 00000 n 0000068346 00000 n 0000068385 00000 n 0000068424 00000 n 0000068463 00000 n trailer << /ID % ReportLab generated PDF document -- digest (http://www.reportlab.com) [(\327\003N\350\276\300\306\212g\332\374,L\000\035\245) (\327\003N\350\276\300\306\212g\332\374,L\000\035\245)] /Info 146 0 R /Root 145 0 R /Size 238 >> startxref 68502 %%EOF libxmp-4.4.1/docs/Changelog0000664000175000017500000023003412777411660015416 0ustar claudioclaudioStable versions --------------- 4.4.1 (20161012): Fix issues reported by Saga Musix: - fix MDL c5spd to preserve base periods - fix MDL sample decoder loop with corrupted data - fix MASI loader OPLH and PPAN subchunks parsing Other changes: - fix MacOS Tiger build issues (reported by Misty De Meo) - fix sample loop corner case (reported by knight-ryu12) - fix set pan effect in multichannel MODs (reported by Leilei) - fix global volume on module loop (reported by Travis Evans) - fix IT pan right value (by NoSuck) - fix MASI effects based on OpenMPT PSM loader - fix memory leak in XMs with 256 patterns - fix anticlick when rendering only one sample - fix anticlick in His Master's Noise instruments - fix anticlick in MED synth instruments 4.4.0 (20160719): Fix bugs caught in the OpenMPT test cases: - fix XM arpeggio in FastTracker 2 compatible mode - fix IT bidirectional loop sample length - fix MOD vibrato and tremolo in Protracker compatible mode Fix multichannel MOD issues reported by Leilei: - fix XM replayer note delay and retrig quirk - fix XM replayer channel pan - fix MOD loader period to note conversion Fix issues reported by Lionel Debroux: - fix virtual channel deallocation error handling - fix S3M global volume effect - fix IT envelope reset on tone portamento - fix IT voice leak caused by disabled envelope - fix IT volume column tone portamento - fix XM envelope position setting - fix FT2 arpeggio+portamento quirk with finetunes - fix mixer anticlick routines - accept S3M modules with invalid effects Fix issues reported by Saga Musix: - fix 669 effects when no instrument number is specified - fix 669 effects to be frequency-based - fix 669 initial tempo Other changes: - fix S3M channel reset on sample end (reported by Alexander Null) - fix Noisetracker MOD speed setting (reported by Tero Auvinen) - fix IT loader DCA sanity check (reported by Paul Gomez Givera) - fix IT envelope reset after offset with portamento - fix bidirectional sample interpolation - fix mixer resampling and tuning issues - add Antti Lankila's Amiga 500 modeling mixer - add support to filter effect E0 in Amiga mods - add flags to configure player mode - add option to set the maximum number of virtual channels - add frequency-based "period" mode - add support to IT sample sustain loop - limit Oktalyzer modules to MOD note range - remove broken synth chip and Adlib emulation suport - code refactoring and cleanup 4.3.13 (20160417): Fix bugs caught in the OpenMPT test cases: - fix IT volume column fine volume slide with row delay Other changes: - fix MOD vs XM set finetune effect - fix IT old instrument volume - fix IT panbrello speed - fix IT random pan variation left bias - fix IT default pan in sample mode (reported by Hai Shalom) - fix S3M set pan effect (reported by Hai Shalom and Johannes Schultz) - code refactoring and cleanup 4.3.12 (20160305): Fix bugs caught in the OpenMPT test cases: - fix IT note off with instrument - fix IT note recover after cut - fix IT instrument without note after note cut event - fix IT pan reset on new note instead of new instrument - fix IT volume swing problems - fix XM glissando effect - fix Scream Tracker 3 period limits - fix Scream Tracker 3 tremolo memory Other changes: - fix IT pattern break in hexadecimal (reported by StarFox008) - fix S3M subsong detection (reported by knight-ryu12) - fix S3M/IT special marker handling (reported by knight-ryu12) - fix Galaxy Music System 4.0 song length (reported by AntonZab) - fix tone portamento memory without note (reported by NoSuck) - fix IT pan swing limits - Add TrackerPacker v1 format converter - Add TrackerPacker v2 format converter - Add ProPacker 1.0 format converter 4.3.11 (20160212): Fix bugs caught in the OpenMPT test cases: - fix FT2 XM arpeggio clamp - fix FT2 XM arpeggio + pitch slide - fix XM tremor effect handling - fix XM tremor recover after volume setting - fix IT instrument after keyoff - fix S3M first frame test in pattern delay - fix Protracker tone portamento target setting - fix Protracker arpeggio wraparound - fix Protracker finetune setting Other changes: - fix range of MMD effect 9 (reported by Lamar McLouth) - fix Visual C++ build (reported by Jochen Goernitz) - fix invalid sample offset handling in Skale Tracker XM (reported by Vladislav Suschikh) - fix Protracker sample loop to use full repeat only if start is 0 - fix Scream Tracker 4-channel MOD fingerprinting - fix lite build with IT support disabled - fix build with gcc 2.95 in Haiku 4.3.10 (20151231): Fix bugs reported by Coverity Scan: - fix out of bounds access in IT/XM/MDL/IMF envelopes - fix out of bounds read in STX effect decoding - fix RTM maximum sample name length - fix AC1D converter number of patterns underflow - fix PRU2 usage of uninitialized data - fix Vorbis depacker usage of uninitialized data - fix negative array index read when setting position - fix resource leak in MFP loader - fix resource leak in Chiptracker loader - fix resource leak in Startrekker loader - fix resource leak in module load error handling - fix event decoding in LIQ loader - fix JVS command parameter in MED synth - fix 669 effect decoding - fix memory violation in LZX decompressor - fix sanity check in PTM orders loading - add sanity check to smix sample loading - add sanity check to PP21 format converter - add sanity check to P40 and P61A format converters - add sanity check to Zen Packer format converter - add sanity check to TP3 format converter - add error handling to many decompressors - add error handling to many I/O operations - remove dead code from NO loader - remove dead code from Soundtracker loader - remove dead code from GMC format converter - remove dead code from LZX decompressor - remove dead code in virtual channel manager reset - remove unnecessary seeks in format loaders - prevent division by zero in memory I/O - change IFF info ID from string to binary buffer - better IFF error handling Fix problems caused by fuzz files (reported by Jonathan Neuschfer): - add sanity checks to LHA depacker - add sanity checks to MED3 loader - add sanity checks to ABK loader - add sanity checks to Fuchs converter - add sanity checks to GMC converter Other changes: - fix IT envelope release + fadeout (reported by NoSuck) - fix SFX effects 5, 6, 7, and 8 (reported by Lamar McLouth) - fix pattern loading in Galaxy 4 and 5 (reported by AntonZab) - fix memory leak in LZW decompressor (by Chris Spiegel) - fix tone portamento target setting (reported by Georgy Lomsadze) - fix IT autovibrato depth (reported by Travis Evans) - disable ST3 sample size limit (reported by Jochen Goernitz) - fix crash in Prowizard error handling - fix IMS sample loop start - fix LIQ pan setting and surround channel - add sanity check for IFF chunk size - refactor ProRunner2 event decoding 4.3.9 (20150623): Fix bugs caught in the OpenMPT test cases: - fix IT tone portamento on sample change and NNA - fix IT tone portamento with offset Fix problems caused by fuzz files (reported by Lionel Debroux): - add sanity check to RTM/MMD/MDL/DBM/SFX/MASI/DT loaders - add sanity check to Starpack/Fuzzac converter - add sanity check to Oxm/vorbis depacker - add sanity check to lha/MMCMP/s404 depacker - fix memory leak in vorbis decoder Fix problems caused by fuzz files (reported by Jonathan Neuschfer): - add sanity check to IT instrument name loader - add sanity check to IT loader instrument mapping - add sanity check to AMF module parameters and event loading - initialize IT loader last event data Other changes: - detect Amiga frequency limits in MOD (reported by Mirko Buffoni) - fix problems in Amiga split channels (reported by Gabriele Orioli) - fix global volume on restart to invalid row (reported by Adam Purkrt) - fix Oktalyzer note slide effect (by Dennis Lindroos) - fix Oktalyzer volume setting in split channels (by Dennis Lindroos) - fix external sample mixer for IT files (reported by honguito98) - allow short sample reads (reported by Adam Purkrt) - address problems reported by clang sanitizer 4.3.8 (20150404): Fix bugs caught in the OpenMPT test cases: - fix pre-increment of envelope indexes - fix IT note release at end of envelope sustain loop - reset channel flags in case of delay effect Other changes: - fix MMD3 16-bit samples (reported by jbb666) - refactor XM envelopes - refactor IT envelopes 4.3.7 (20150329): Fix bugs caught in the OpenMPT test cases: - fix IT sample mode note cut on invalid sample - fix IT sample mode note end detection - fix IT envelope handling with carry and fadeout - fix IT tone portamento with sample changes - fix IT initial global volume setting - fix IT keyoff with instrument in old effects mode - fix IT filter maximum values with resonance Other changes: - fix IT random volume variation - fix pattern initialization sanity check - fix ++ pattern handling in IT loader (reported by honguito98) - fix Soundtracker short rip loading (reported by Shlomi Fish) - add IT high offset command (SAx) - add IT surround command (S9x) - add IT surround channel support - add IT sample pan setting support 4.3.6 (20150322): Fix bugs caught in the OpenMPT test cases: - fix IT volume column volume slide effect memory - fix IT default filter cutoff on new note - fix IT filter envelope memory Fix crashes with fuzzed files (reported by Lionel Debroux): - add sanity check to MED2/3/4 loader - add sanity check to STIM/GDM/DBM/LIQ/ICE/PSM/PTM/MGT loader - add sanity check to MDL/RAD/MGT/IMF/RTM/DT/LIQ/DTM pattern loader - add sanity check to OKT/IMF/MMD/MDL sample loader - add sanity check to Archimedes Tracker format test - add sanity check to Digital Symphony track loader - add sanity checks to SQSH, bzip2, arc, lha, lzx and S404 depackers - add sanity check for AMD/STX number of patterns - add sanity check for DSYM/MMD1/MMD3 number of channels - add sanity check for MMD1/MMD3 instrument type - add sanity check for IT old instrument loading - add sanity checks and fix memory leaks in the Vorbis decoder Other changes: - fix instrument number in channel initialization - fix sample size limit (reported by Jochen Goernitz) - fix loading of OpenMPT 1.17 IT modules (reported by Dane Bush) - fix sample number limit (reported by Lionel Debroux) - fix Oktalyzer split channel replay (reported by Dennis Lindroos) - fix Oktalyzer sample loop (by Dennis Lindroos) - fix Oktalyzer note slide up/down effect - fix ThePlayer pattern decoding - fix XM loading for MED2XM modules (reported by Lorence Lombardo) - add support to Amiga split channel loop and volume setting - add IT random volume variation - add IT random pan variation 4.3.5 (20150207): Fix crashes with fuzzed files (reported by Lionel Debroux): - add sanity check for ST3 S3M maximum sample size - add sanity check for sample loop start - add sanity check for speed 0 - add sanity check for invalid XM effects - add sanity check for maximum number of channels - add sanity check for number of points in IT envelope - add sanity check for S3M file format information - add sanity check for maximum sample size - add sanity check for invalid envelope points - add sanity check for basic module parameters - add sanity check for instrument release after load error - add sanity check for XM header size - add sanity check for XM/IT/S3M/MTM/RTM parameters and sample size - add sanity checks to inflate and lha decompressors - add more tests to 669 and NO file detection - fix mixer index overflow with large samples - fix prowizard data request response - fix EU/NP1/NP2/NP3 prowizard depackers - fix crash on attempt to play invalid sample - fix infinite loop in break+delay quirk - reset module data before loading module Other changes: - fix loop processing error in scan (reported by Lionel Debroux) - fix minimum BPM value for MED (reported by cspiegel) - fix sample loop adjustment (by Emmanuel Julien) 4.3.4 (20150111): Fix bugs caught in the OpenMPT test cases: - fix XM keyoff+delay combinations - fix XM fine pitch slide with pattern delay - fix XM vibrato rampdown waveform - fix XM volume column pan with keyoff and delay - fix XM pan envelope position setting - fix channel volume and instrument initialization - fix end of module detection inside a loop Fix bugs reported by Francisco Pareja-Lecaros: - fix MASI (PSM) volume command - fix MASI (PSM) note number parsing - fix Noisetracker note limit detection Other changes: - fix overflow in linear interpolator (reported by Jochen Goernitz) - fix MTM invalid track load (reported by Douglas Carmichael) - add ProPacker 3.0 loader 4.3.3 (20141231): Fix bugs caught in the OpenMPT test cases: - fix XM note delay volume with no note or instrument set - fix XM out-of-range note delays with pattern delays Other changes: - fix XM envelope loop length (reported by Per Trner) - fix big-endian detection in configuration (by Andreas Schwab) 4.3.2 (20141130): Fix bugs caught in the OpenMPT test cases: - fix IT invalid instrument number recovery - fix IT note retrig on portamento with same sample - fix XM portamento target reset on new instrument - fix XM portamento with offset - fix XM pan slide memory - fix XM tremolo and vibrato waveforms - fix MOD pattern break with pattern delay - fix MOD Protracker offset bug emulation - fix tremolo rate Other changes: - fix IT portamento after keyoff and note end - fix IT fadeout reset on new note - fix IT pattern row delay scan - fix MOD/XM volume up+down priority (reported by Jason Gibson) - fix MOD fine volume slide memory (reported by Dennis Lindroos) - fix set sample offset effect (by Dennis Lindroos) - fix Windows temp file (reported by Andreas Argirakis & Eric Lvesque) - add emulation of the FT2 pattern loop bug (by Eugene Toder) - allow loading of packed formats from memory - allow loading of OpenMPT MOD files with large samples - enable offset bug emulation by default for Protracker MODs - code cleanup 4.3.1 (20141111): Fix bugs caught in the OpenMPT test cases: - fix IT filter envelope range - fix IT envelope carry after envelope end - fix XM note off with volume command - fix XM K00 effect handling - fix XM portamento with volume column portamento - fix XM keyoff with instrument - fix XM note limits Fix bugs reported by Andreas Argirakis: - fix MOD false positive for UNIC Tracker modules - fix EMOD instrument finetune - fix UNIC Tracker instrument finetune test - fix NoisePacker1 loader Other changes: - fix IT tone portamento in first note (reported by Jan Engelhardt) - fix XM invalid memory access in event reader - fix STM empty note event read - fix ABK loader test in Win32 - fix MOD period range enforcing (reported by Jason Gibson) - fix ST2.6 speed effect (reported by Saga Musix) - fix corner case memory leak in S3M loader - fix retrig of single-shot samples after the end of the sample - fix crash in envelope reset with invalid instrument - fix module titles and instrument names in Mac OS X - fix row delay initialization on new module - refactor depacking code - code cleanup 4.3.0 (20140926): Fix bugs reported by Sami Jumppanen: - fix MED4 instrument numbering - fix MED effect FFF (turn note off) - fix MED synth finetune effect Fix bugs reported by Alexander Null: - fix fine volume slide memory - fix IT portamento after note end in sample mode - fix S3M portamento after note end Fix bugs caught in the OpenMPT test cases: - add XM and IT envelope loop and sustain point quirk - fix Amiga limits for notes with finetune - fix XM invalid offset handling - fix XM note release reset on new volume - fix XM pattern loader to honor header size - fix XM fine volume slide effect memory - fix XM fine pitch slide effect memory - fix XM finetune effect - fix IT portamento if offset effect is used - fix IT NNA on invalid sample mapping - fix IT filter envelope index reset - fix IT envelope carry on note cut events - fix IT envelope reset on new instrument - fix IT instrument change on portamento in compatible GXX mode - fix IT unmapped sample parsing - fix IT filter cutoff reset Other changes: - add API call to load a module from a file handle - add API call to set default pan separation value - add OpenMPT test cases to regression test suite - add AMOS Music Bank loader (by Stephen Leary) - refactor memory I/O calls - read OctaMED annotation and song info text - fix segfault in mixer caused by sample position overflow - fix MED synth pitch slide reset on new note - fix MED synth volume change during wait command - fix MED synth envelope loop handling (reported by Stefan Martens) - fix OctaMED SS default pitch transpose (reported by Karl Churchill) - fix OctaMED instrument name loading - fix XM, S3M, IT and MED offset effect handling - fix IT fadeout and envelope reset on new virtual channel - fix S3M shared effect parameter memory - fix S3M default pan positions - fix S3M set BPM effect with values < 32 (reported by Kyu S.) - fix incorrect Noisetracker effect filtering (reported by Kyu S.) - fix period limits for (possibly non-Amiga) Protracker clones - fix loop counter reset on play buffer reset - fix finetune effect 4.2.8 (20140714): Fix bugs reported by Sami Jumppanen: - fix OctaMED decimal volume decoding - fix MED4 sampled instrument octave range - fix mishandling of MED4 effect FFD - fix MED synth waveform command CHD Other changes: - fix sequence number reset on player start - fix stray notes in XM (reported by Andreas Argirakis) - limit note number to avoid crash (reported by Bastian Pflieger) - disable recursive file decompression 4.2.7 (20140412): - add support for XM with ADPCM samples (reported by mk.bikash) - add OctaMED effect 2E (reported by Andreas Argirakis) - fix MMD2/3 note event mapping (reported by Andreas Argirakis) - fix XM set pan effect - fix IT disabled instrument pan 4.2.6 (20140407): Fix bugs reported by Andreas Argirakis: - add OctaMED 2 to 7 octave IFFOCT sample loader - fix volume in MED synth instruments - fix OctaMED V5 MMD2 sample transpose Other changes: - fix double free in module loaded from memory (by Arnaud Trol) - fix old Soundtracker sample loops (reported by Dennis Lindroos) - fix Win64 portability issues (reported by Ozkan Sezer) - fix OctaMED 3 octave limit for sampled instruments - fix OctaMED hold/decay event support - fix OctaMED vibrato effect depth - fix IT tempo slide effect - fix Visual C++ nmake build issues - refactor OctaMED event reader - generate Android NDK static libraries 4.2.5 (20140302): - fix Oktalyzer sample numbering (reported by Andreas Argirakis) - fix XM delay effect with invalid instrument - disable incomplete Graoumf Tracker loader - disable incomplete TCB Tracker loader - code refactor for core mod player library subset 4.2.4 (20140222): Fix bugs reported by Justin Crawford: - fix XM note and envelope retrig on delay effect - fix XM keyoff reset on new note event - fix retrig effect frame counter - fix envelope update after manually set point Other changes: - fix Chiptracker pattern decoding (reported by Andreas Argirakis) - fix AMF sample loop end - fix false positives in Slamtilt format test - refactor S3M arpeggio effect memory - disable incomplete DMF loader - disable incomplete DTT loader - address clang-analyzer warnings 4.2.3 (20140118): - remove limit of samples in RTM loader - fix S3M length bug introduced in 4.2.1 (reported by Misty De Meo) - fix MDL effect decoding - fix MDL envelope decoding - fix MDL fadeout setting when envelopes are disabled - fix MDL instrument vibrato depth - fix MDL sample loop size - fix MDL fine volume slide effect - fix MacOS X dylib versioning 4.2.2 (20140111): - re-enable Falcon MegaTracker loader - fix DIGI Booster finetune (reported by Andreas Argirakis) - fix tempo in BPM mode MMD modules (reported by Andreas Argirakis) - fix crash in zip depacker - fix MED4 large (>64KB) sample loading - fix MED4 sample loop flag setting - fix MMD Protracker-compatible volume slide effect - fix number of channels in GDM loader - fix number of channels in MED4 loader - fix instrument name setting in MDL loader - replace LZX decompressor code with LGPL version from XAD 4.2.1 (20131229): Many fixes by Vitamin/CAIG: - fixes in memory I/O layer - improve loading of many module formats including XM and S3M - fix resource leak in case of invalid module structure - portability fixes Other changes: - disable YM2149 emulator - disable poorly implemented and rarely used module formats - fix mod loop setting in very small loops (reported by Misty De Meo) - fix linear period mode vibrato handling - refactor vibrato effect processing - code cleanup 4.2.0 (20131109): - ignore invalid Noisetracker effects - add API call to load a module from a buffer in memory - add API call to read the player state (loaded, playing, etc) - add API call to set the player master volume - add API calls to reserve channels and play instruments on them - add loader for His Master's Noise modules - fix loop parameter in xmp_play_buffer() - fix MED synth volume slide reset on new note - fix instrument mapping in IT old instrument format - fix number of tracks in IT loader - fix LHA depacker header parsing - fix thread-unsafe Archimedes Tracker loader - fix thread-unsafe Digital Tracker loader - fix handling of loader errors - fix S3M 16-bit sample replay - refactor handling of format-specific instrument and channel data - refactor MED synth command interpreter - rewrite SQSH depacker code - disable rarely used ZOO depacker - disable rarely used ALM loader - code cleanup 4.1.5 (20130527): Fix bugs reported by Andreas Falkenhahn: - fix OctaMED decay event and effect decoding - fix The Player 6.0A pattern depacking - fix Oktalyzer instrument to sample mapping 4.1.4 (20130519): - fix array initialization in IT loader (reported by Jacques Philippe) - remove regression tests from the distribution package - address license issues in md5 digest code - address Visual C++ portability issues - code cleanup 4.1.3 (20130511): - fix envelope reset on new instrument (reported by ArtRemix) - fix JMP END sequences in MED synth wave table - fix IT portamento after note cut - fix IT and XM envelope resets - refactor virtual channel code - code cleanup 4.1.2 (20130504): - fix Graoumf Tracker arpeggio, set linear volume and set number of frames effects (reported by Misty De Meo) - fix MTM sample fine tuning - fix unsigned conversion sample range when downmixing - fix memory leaks when attempting to load corrupted modules - refactor note slide effect code 4.1.1 (20130428): - add XM set envelope position effect - fix XM note with no instrument after keyoff - fix detection of compiler flags - fix library symbol versioning in OS X (by Douglas Carmichael) - fix loss of precision in portamento (reported by Misty De Meo) - fix OS X, Solaris and BeOS/Haiku build issues 4.1.0 (20130420): - add API call to fill equally-sized data chunks with PCM data - add configurable player parameter to disable sample loading - add configurable player parameter to set/get current module flags - changed maximum sampling rate to 49170 Hz - fix floating point values in lowpass filter - fix buffer overflow in MASI loader (reported by Douglas Carmichael) - fix simultaneous volume slide up and down - fix IT vs XM vibrato rate using quirk - fix IT portamento after note cut (reported by Benjamin Shadwick) - fix segfault in AMD module loader (reported by Jacques Philippe) - fix memory leak in AMD module loader - fix sequence scanner to prevent listing empty sequences - fix build issues in Cygwin (reported by Benjamin Shadwick) - fix pkg-config library definition - fix loop count reset when restarting module - fix MMD0-3 pitch slides (reported by Simon Spiers) - fix MED4 pattern reading (reported by Simon Spiers) - fix MED2/3/4 portamento effect - fix Stonecracker depacker - fix IT envelopes with no envelope points - fix XM invalid instrument event (reported by Banjamin Shadwick) 4.0.4 (20130406): - fix IT volume column slide to note - fix IT pan setting effect - fix IT vibrato effect depth - fix IT portamento after fadeout - fix IT panbrello waveform setting - fix tremolo effect depth - fix random waveform generator 4.0.3 (20130331): - add module quirks for well-known cases - add built-in zoo depacker - add IT pan slide effect - add IT panbrello effect - fix IT pan setting effect (reported by Jan Engelhardt) - fix IT fine vibrato effect - fix MED BPM mode tempo setting - fix global volume slides - fix bidirectional sample loops - fix sequence entry points - rescan sequences if timing flag is changed 4.0.2 (20130223): - add IT volume column vibrato - add IT pattern row delay effect - add fine global volume slide effect - fix IT instrument vibrato depth and sweep - fix IT past note effects - fix IT fadeout values - fix IT fadeout event loading - fix period range for values lower than 8 - fix global volume slides - fix channel volume setting - fix multi-retrig effect counter - fix invalid sample number access - fix memory access violation in MMCMP depacker - fix global volume setting in module scan - reset virtual channel flags on creation - change maximum number of mixer voices to 128 4.0.1 (20130216): - fix license issues reported by Jan Engelhardt - minor documentation updates 4.0.0 (20130213): - split library and application in different packages - remove OSS sequencer support - remove platform-specific device drivers - remove all global data, make library code fully thread-safe - remove configuration files (moved to front-end) - remove support to uLaw-encoded output - remove bogus lzma file detection (by Bodo Thiesen) - extend note range to full 10-octave range - extensive code refactoring - rewrite MMCMP decompressor to be endian-safe - replaced IT sample decompressor with public domain version - add cubic spline sample interpolation - add built-in zip file decompressor - add built-in gzip file decompressor - add built-in compress file decompressor - add built-in bzip2 file decompressor - add built-in xz file decompressor - add built-in lha file decompressor - add built-in vorbis sample decoder - add support to IT envelope carry - add support to IT sample vibrato - add ASYLUM Music Format V1.0 loader - add regression tests - fix interpolation and sample loop processing - fix S404 depacker integration - fix note delay effect - fix FT2 old instrument volume quirk - fix XM tone portamento with finetune (reported by Rakesh Sewgolam) - fix instrument envelope loops (Storlek test #24) - fix IT tremor effect (Storlek tests #12 and #13) - fix IT global volume (Storlek test #16) - fix IT stray tone portamento handling (Storlek test #23) - fix IT unified pitch slide memory (Storlek test #25) - fix IT retrigger effect (Storlek test #15) - fix IT filters - fix IT fadeout event handling - fix persistent slide down effect 3.5.0 (20120127): - fix AMF 1.0 module loading (reported by Andre Timmermans), probe for sample loop size - fix AMF 1.1+ sample loops when loop start is zero - fix AMF track index including track 0 as empty track (reported by Andre Timmermans) - fix AMF tremolo effect (reported by Andre Timmermans) - fix AMF pitchbend effects (reported by Andre Timmermans) - fix AMF volume slide effect - fix AMF track allocation - fix OpenBSD driver configuration - fix patern delay + pattern break command (reported by The Welder) - fix memory leaks found by cppcheck (reported by Paul Wise) - fix XM note cut on invalid instrument (reported by Benjamin Shadwick) - fix invalid memory access in case of mismatched track/pattern lengths - fix uninitialized values when loading BoobieSqueezer XM modules - fix subinstrument mapping for certain parameters - fix invalid memory access in The Player loader - fix plugin for Audacious 2.5.4 - add support to DSMS mod files - add YM2149 emulator and improved chip sound support - add support to ZX Spectrum AY-3-8192 chiptunes - add ZX Spectrum Soundtracker module loader 3.4.1 (20110813): - test for unused but set variable warning in gcc (needed to build on MacOS X, reported by Misty De Meo) - fix format specifiers in CoreAudio driver messages (reported by Misty De Meo) - build audacious3 driver if system has Audacious 2.5 - change dependency generation flags for clang (reported by Misty De Meo) - fix OXM module loading 3.4.0 (20110808): - fix reported elapsed time with looped modules - fix portamento of mapped instruments (reported by Null Vista) - add MED2 (MED 1.12) module support - add Noiserunner module support - add support for MED4 synth instruments (reported by Tim Newsham) - fix MED4 Soundtracker-compatible tempo setting (Song2.med) - fix Audacious plugin crash if module is invalid (reported by Dominik Mierzejewski) - fix Audacious plugin seek widget position setting - remove nonexistent Modplug Tracker IT quirk (reported by Johannes Schultz, voice samples shouldn't play in Deep in Her Eyes remake) - fix Startrekker Packer loader - fix IT215 compressed sample loader (reported by Ben "GreaseMonkey" Russell) - use start/stoptimer also for pause in OSS driver (by Test Rat) - identify modules created with munch.py in IT loader - OctaMED MMD0/1/2/3 tempo fixes (by Francis Russell) - MMD0/1 note limit fix (by Francis Russell) - improve latency in ALSA driver output - Audacious 2.4 API 17 plugin fixes - add Audacious 3.0 plugin (by Michael Schwendt) 3.3.0 (20101202): - change MED BPM mode tempo setting (reported by Lorence Lombardo) - fix OSS driver fragment setting - add interactive loop toggle (requested by Emanuel Haupt) - add filter to prevent loading NoiseRunner modules as Protracker - add NoiseRunner loader (requested by Johan Samuelsson) - add improved Impulse Tracker fingerprinting (from Schism Tracker) - add Archimedes Tracker StasisMod effects support (Tom Hargreaves) - add tarball decompressor (Tom Hargreaves) - limit uncompression recursion (Tom Hargreaves) - fix Tracker Packer 3 loader (Tom Hargreaves) - fix load issue with BoobieSqueezer XMs (reported by Null Vista) - fix modinfo tempo/bpm setting - fix Zip file detection (Tom Hargreaves) - fix Archimedes Tracker effects (Tom Hargreaves) - update Audacious plugin to API 16 - code cleanup 3.2.0 (20100530): - Digital Symphony fixes by Tom Hargreaves - Archimedes Tracker fixes by Tom Hargreaves - add shared logarithmic volume table for Archimedes formats - fix default Archimedes formats pan (RLLR instead of LRRL) - add Coconizer file loader - portability fixes for BeOS and Haiku - code cleanup and optimizations - Android port using NDK - fix time echoback event for MED - fix module time count not reseting at new module - make zipfile detection stricter (by Solomon Peachy) - fix DSMI loader volume event (by Solomon Peachy) - initialize formats only once - fix build with Audacious plugin API 13 - fix seek in Audacious plugin 3.1.0 (20100107): - implement MED4 instrument transposition - fix build with MSVC++ 2008 - fix bogus information in winamp plugin file info display - fix Audacious plugin dialog stacking order (by Michael Schwendt) - add Titanics Player prowizard loader - add SKYT Packer prowizard loader - add Novotrade Packer prowizard loader - add Hornet Packer prowizard loader - fix empty instruments in Digital Illusions loader - fix silent Liquid Tracker module bug - add Magnetic Fields Packer loader - add The Player 6.1a prowizard loader - add StoneCracker S404 decompressor (from amigadepacker) - add extra Funktracker file tests to prevent false positives - add Polly Tracker module loader - code cleanup and optimizations 3.0.1 (20091221): - better handling of corrupted modules - load Real Tracker RTMM 1.12 modules (tested with odyssey.rtm) - fix tuning of Real Tracker modules - fix Real Tracker patern decoding - fix segfault in modules with 0 orders or 0 channels - fix loading of MED4 module patterns with less than 32 lines - fix memory leak when loading corrupt MED4 files 3.0.0 (20091210): 13 years after the 0.09b release - allow parallel build (R.I.P. 1996 buildsystem) - implement the long postponed open player loop - generate win32 project files when packaging distfile - remove callback driver - split unified flags/quirks into separate variables - add elapsed time echoback event - add option to display elapsed and remaining time - implement IT volume column fine effects quirk (Storlek test #6) - fix bmp plugin build - fix FreeBSD build (by swell k) - fix terminal handling in Cygwin (by daniel kerud) - add OpenMPT id to S3M loader - add Epic MegaGames MUSE data decompression - add Galaxy Music System (Jazz Jackrabbit 2 J2B) module loader - fix parsing of driver-specific parameters - fix GDM length, number of patterns and number of samples - fix memory access error in MDL sample depacker - fix ProRunner1 samples size - OSS driver resets the DSP device on exit (by Andrew Church) - fix handling of PT portamento+vslide effect (by Andrew Church) - move driver init from player core to main application or plugin - Epic MegaGames MASI loader fixes - add Amiga TuneNet plugin (by Chris Young) - fix Module Protector loader - fix lha depacking in Amiga (reported by Chris Young) - fix clang build (by swell k) - add support for xz decompressor (by swell k) - add built-in LZX decompressor - remove pause-related functions from player core - fix build in Solaris 10 and Sun Studio 12 Update 1 C++ compiler (reported by Douglas Carmichael) - fix plugin to work with Audacious 2.2 (reported by Gtz Waschk) - fix invalid and uninitialized data accesses reported by Valgrind - fix memory leaks reported by Valgrind 2.7.1 (20090718): - fix -l option in manpage (debian bug #442147) - fix endianism in MDL sample depacking (reported by Grkan Sengn) - fix loading of MOD2XM 1.0 modules (reported by Grkan Sengn) - add some sanity checks in XM module loading - fix IT note cut and delay (Storlek test #22) - increase period resolution for better tuning (reported by Mirko Buffoni and Grkan Sengn) - allow lower BPM settings (fixes Lemmings 2 circus music) 2.7.0 (20090711): - add StarTrekker packer loader (untested, need samples) - extended key range to IT octave 9 (fixes beek-my_eleventh_year.it, reported by Mirko Buffoni) - ignore tempo/bpm settings to 0 in module scan (fixes albacore.it, reported by Storlek) - implement IT T0x and T1x tempo slides - process effects in IT muted channels (Storlek test #10) - generalized delayed event support (Storlek test #8) - emulate "always store instrument" IT bug (Storlek test #8) - add extra click removal step in mixer routines - fix loop size in GMC loader (reported by Mirko Buffoni) - GMC loader code cleanup - store in-file comments - apply amplification in the final downmix - set sample format to unsigned on 8-bit wav file output - attempt to handle BPM-based MED tempos a bit better - add option to use the IT LPF as a click/noise filter - deprecate $HOME/.xmprc, use $HOME/.xmp/xmp.conf instead - reintroduce modules.conf, move SYSCONFDIR back to /etc/xmp - display checksum for platforms where cksum(1) not readily available - add filter quirk for rn-alone.it - reintroduce manual setting for vblank timing in Amiga modules - add vblank quirk for mod.siedler ii (by Daniel kerud) - don't crash if SoundSmith instruments not found 2.6.2 (20090630): - Promizer 1.8a loader code cleanup - fix portamento to skip first frame of each row - fix periods in instruments with finetune 2.6.1 (20090627): - fix XMMS plugin build (reported by Gtz Waschk) - add Chibi Tracker fingerprint to IT loader (info by Storlek) - add Schism Tracker fingerprint to S3M loader (info by Storlek) - fix Modplug Tracker/OpenMPT identification in IT loader - IT instrument and sample modes use same quirks (Storlek test #9) - transposed period scale base down one semitone (Storlek test #1) - remove previous portamento in SpaceDebris.mod fix - add unified pitch slide/portamento memory (Storlek test #3) - no Amiga limits for multichannel mods (fixes Bending CD61) 2.6.0 (20090625): - cleanup: remove rarely used Unix IPC code that difficults porting - cleanup: remove per-module configuration that nobody uses - cleanup: moved Prowizard depacking to loader section - don't abort loading if IT sample magic not found (fixes loading of use-brdg.it and use-funk.it, reported by Mirko Buffoni) - multichannel mods written with Scream Tracker don't use Amiga note limits (fixes Earth Mountains, reported by Samuli Sorvakko) - fix start option in DeusEx's .umx files (by erlk ozlr) - add OpenBSD sndio driver (by Thomas Pfaff) - fix memory leak: free extra pattern allocated by the XM loader - fix memory leak: free temporary pointer arrays in the IT loader - fix memory leak: free temporary pointer arrays in the S3M loader - fix memory leak: free header and filename when file is invalid - fix memory leak: free temporary buffer in MDL loader - fix memory leak: move UNIC check to test section of mod loader - fix memory leak: free Digital Symphony extra empty track - fix memory leak: free Music Module Compressor buffers - fix memory access violation freeing list nodes using list_for_each - fix memory access violation in MDL track allocation - fix memory access violation in MDL sample decompression - fix memory access violation in LIQ pattern loading - fix memory access violation in P18A format test - fix free of unallocated block in IT sample-only mode - fix buffer overflow in OXM/DTT loaders (reported by Luigi Auriemma) - rename oss_mix driver to oss and alsa_mix to alsa - restrict MMD0/MMD1 non-synth instrument note range to 3 octaves (reported by Daniel kerud and Mirko Buffoni) - assume wav driver if output filename ends in .wav - fix volume slides with 00 parameter (by Mirko Buffoni) - fix crash when S3M C2spd is zero (by Mirko Buffoni) - merged Mirko Buffoni's Windows Visual C++ port - don't process tone portamento in first frame of each row, fixes Space Debris.mod (by Mirko Buffoni) - add amplification factor option (by Mirko Buffoni) - improved Winamp plugin (by Mirko Buffoni) - don't unlink open files (for Windows port, by Mirko Buffoni) - add experimental DxF/DFx handling with volume slides in all frames - add better Archimedes .arc compressed file test - reverted to older YM3812 emulator for license compliance - fix byte swap error in HSC to SBI Adlib OPL2 instrument conversion - fix Reality Adlib tracker loader - implement Adlib OPL2 synth volume setting - improve tempo, tuning and envelope of HSC modules - fix scanning of patterns containing short tracks - don't play notes outside the valid 8 octave note range - enable The Player 5.0A loader (tested with Full Moon mods) - enable ProPacker 2.1 loader (tested with Cool World mods) - fix endianism issues in The Player 5.0 and 6.0 loaders - fix AMF track remapping error - enable instrument retriggering quirk in IT loader - configuration file moved back to /etc - fix estimated tempo for S3M/IT modules with BPM changes 2.5.1 (20071207): 11 years after xmp 0.09a, the first public release! - fix Winamp plugin default sampling rate (reported by Mirko Buffoni) - Winamp plugin number of channels fixed by Mirko Buffoni - recognize TakeTracker TDZ4 modules (reported by Lorence Lombardo) - fix crash in anticlick when pan amplitude is set to 100% (reported by Mirko Buffoni) - extend playable octave range (fixes replay of octave 9 notes in beek-my_eleventh_year.it, reported by Mirko Buffoni) - Protracker-style sample loops only valid with loop start 0 (fixes M.K. Amegas conversion and others, reported by Mirko Buffoni) - reset fadeout on new instrument fetch (fixes echo in "pain of lace" pat 0 ch 2-3, reported by Mirko Buffoni) - add quirk for simultaneous volume slide up and down (M.K. allows it but S3M doesn't, fixes Red Dream.mod reported by Ralf Hoffmann) - Impulse Tracker in sample mode has instrument priority quirk - fix IT far right (64) stereo channel panning - merge Amiga port improvements by Johan Samuelsson - merge Amiga xfdmaster.library support by Chris Young - Amiga port also buildable for AROS (AHI driver not tested) - fix global track parsing in DMF loader (fixes mok-trea.dmf, reported by Lorence Lombardo) - fix Winamp plugin to use the equalizer (reported by Mirko Buffoni) - skip 0xfe and 0xff S3M/IT control patterns at load time - fix scan of pattern break in the last pattern of the module - add BPM quirk for XMs converted with MED2XM (fixes Fascinated.xm, reported by Lorence Lombardo) - merge Windows patch for decompression by Mirko Buffoni 2.5.0 (20071127): - remove DMP-specific effect from MOD loader - extend Protracker sample loops to Noisetracker and Startrekker - FLT loader recognizes Startrekker FLTM modules (only PCM channels) - implement support for Startrekker/ADSC AM synth instruments - fixed cast to signed type in finetune display - fixed Protracker 3 IFFMODL loader (process VERS chunk manually) - added support to Protracker sample loops in the Protracker 3 loader - added PulseAudio driver (using the simple API) - remove restrictive tests for Soundtracker modules (fixes 99redballoons.mod and atmosfer4.mod, reported by Adric Riedel) - fixed infinite loop control (allows full replay time of 11:04 for Gryzor's extended Global Trash 3.mod, reported by Adric Riedel) - use floating point period generation for the software mixer - fix S3M tempo/bpm setting effect (fixes seaside_hotel.s3m) - MinGW32 build fixes and new Windows driver (based on MikMod) - merged Amiga AHI driver written by Lorence Lombardo - don't read commands from terminal in Windows and Amiga - reset parameter in case of MDL "no effect" (saa.mdl pos 13 ch 9 plays correctly, reported by Grkan Sengn) - fixed wav and file drivers binary file creation for win32 - add support for Octamed V6 16bit samples (fixes instruments in LaEsperanza.mmd3, reported by Lorence Lombardo) - enforce minimum allowed BPM to prevent large frames (fix crash with MED2XM modules such as Fascinated.xm, reported by Lorence Lombardo) - fixed conversion of big-endian 16-bit samples in big-endian machines - fixed decompression of 16-bit IT samples in big-endian machines - added experimental Winamp plugin - added handler for Ultra Tracker sample type 20 (fixes seasons.ult, reported by Lorence Lombardo) - fixed instrument parameter handling in MED4 loader - added Generic Digital Music (GDM) loader - plugin code cleanup, remove mode button and hold buffer - merged AmigaOS4 patches by Chris Young 2.4.1 (20071029): - fixed portamento after keyoff problem in metamorph_part_ii.xm where new note is not recognized (reported by Adric Riedel) - implement Protracker-style sample loops: first play entire sample, then play the loop (needed to play MeNoWantMiseria.mod correctly, reported by Adric Riedel) - fixed finetune test in UNIC Tracker detection to prevent false positive with all that she wants.mod (reported by Adric Riedel) - fixed test for ?CHN and ??CH TakeTracker/FastTracker2 modules - fixed data type in the XM loader to work in 64-bit systems - don't ignore effect on event with invalid instrument (fixes tempo in 39.mod pos 11, reported by Adric Riedel) - removed restrictive tests for Ultimate Soundtracker (false negative in Karsten Obarski's sleepwalk and others, reported by Adric Riedel) - minimum sample size changed from 5 to 4 bytes, childhood.it actually has 4 byte samples (reported by Adric Riedel) - cut effect doesn't retrigger sample (fixes Comic Bakery Remix pos 1 ch 3, reported by Adric Riedel) - allow period 162 in ST mods (for blueberry.mod UST, reported by AR) - fixed period interpolation using real log function instead of table 2.4.0 (20071025): - added Oktalyzer note slide and fine note slide effects - added Oktalyzer arpeggio 3, arpeggio 4 and arpeggio 5 effects - added MED synth programmable arpeggio commands ARP and ARE - added MED synth vibrato commands VBS, VBD and VWF - added module probe method without loading (Audacious plugin can test for files while a module is playing) - added persistent effects for 669, FNK and FAR - fixed MED synth volume slide commands CHD and CHU - fixed detuning in short samples with bidirectional loop by adjusting the loop size to match forward loop size - fixed sound cut bug when changing samples in the MED synth (don't reset channel on attempt to set invalid sample position) - fixed identification of IIgs MegaTracker modules - fixed 669 persistent vibrato and portamento effects - fixed FAR persistent vibrato/portamento and pattern break effects - fixed sample loading in FAR modules - fixed multi-retrig effect processing (see cyberculosis.xm ch 7) - fixed segfault when output file is specified but driver isn't - fixed XM sample loop size in XMs made with Digitrakker - revert CoreAudio driver pause patch (fix memory management problem) - reset MED synth program at each new note event - removed filesize-based module format detection - replaced XANN loader with Prowizard XANN depacker - reorganized internal data to remove lots of global variables - changed all loaders to load module from relative offset - changed UMX depacker to be a real loader (using relative offsets) - ported Audacious plugin to the Audacious 1.4.0 API - fixed sample offset on portamento after keyoff (Decibeter - Cosmic 'Wegian Mamas.xm plays correctly now) - fixed length of XM loops (jt_xmas.xm no longer out of tune) - fixed Audacious plugin to display duration when adding to playlist - fixed memory access violations reported by Valgrind - split XMMS/BMP/Audacious plugin source - invalid patterns in sequence ignored instead of aborting replay - fixed load of DBM 16-bit samples (reported by Ralf Hoffmann) - fixed DBM envelope offset error (reported by Ralf Hoffmann) - disabled AMF volslide effect (problems with CannonFodder2-Done.AMF) - fixed MMD1/MMD3 loaders to skip invalid synth instruments (reported by Ralf Hoffmann, Misanthropy.MED loads correctly) - fixed number of patterns in Funktracker modules - added Funktracker persistent portamento and volume slide effects - fixed offset effect with parameter 00 (reported by Adric Riedel) - changed volume dynamic range to fix steps in volume ramps (tested with departure soundtrack.xm, reported by Adric Riedel) - set priority to slide down when volume slide up and down is used, fixes Skaven's 2nd Reality blast (reported by Douglas Carmichael) 2.3.2 (20071009): - added ModPlug Tracker IT quirk: ignore sample global volume (fixes speech in "Deep In Her Eyes Remake", reported by Douglas Carmichael) - added PTM/IMF note slide effects and PTM note slide + retrig effect - added partial support to MED synth sounds (ported from xmp 2.1.0) - added experimental BeOS driver based on the CoreAudio driver - fixed copy of overlapping memory areas in IT loader - fixed initialization of channel flags before loading module - fixed PTM sample loop size (tested with abnormality.ptm) - fixed PTM effects translation (PTM-specific effects were ignored) - fixed effects settings in AIX and OSX CoreAudio drivers (reported by Douglas Carmichael and Chris Cox) - fixed pause in OSX CoreAudio driver - fixed Fuchs Tracker prowizard loader format detection - fixed --time option time counter for MED files - decoupled PT3 PTDT and MOD loader 2.3.1 (20071005): - added PTM global volume effect - fixed output filename setting in wav output - fixed size field setting in wav driver - fixed configure option --sysconfdir (reported by Douglas Carmichael) - fixed major bug in anticlick routine generating clicks in the right audio channel (reported by Douglas Carmichael) - changed rampdown time in Hipolito's anticlick algorithm (removes clicks from PM's 2nd Reality, reported by Douglas Carmichael) - changed default file name when writing to WAV to .wav 2.3.0 (20071002): - added runtime endianism detection - added extractor for Epic Games' Unreal UMX files - added workaround for S3M "Return of Litmus" 0x87 quirk (reported by Ralf Hoffmann) - added DigiBooster Pro module loader - added Fmod OXM depacker (depends on oggdec) - enabled Tracker Packer 3 prowizard loader - enabled The Player 4.x prowizard loader - removed reverse-endian sample reading options and XMP_CTL_BIGEND - fixed semantics of big/little endian options, moved to file driver - fixed memory corruption in Quadra Composer module loader - fixed Quadra Composer vibrato, offset and jump effects - fixed endianism problem in KSM and Zen Packer loaders - fixed transposition of Digital Tracker module notes - fixed build for QNX Neutrino 6.3.2 - fixed OSS sequencer driver timing (reported by Reynir Stefansson) - fixed BMP/Audacious plugin to build also as XMMS plugin - fixed Impulse Tracker identification in S3M loader - fixed Module Protector test to recognize mods from "Made In Croatia" - fixed crash when scanning modules with length zero (bug #1800766) - fixed driver detection in NetBSD (don't try to build OSS driver) - fixed crash when restart value is invalid (reported by Ralf Hoffmann) - fixed handling of S3M pattern 0xfe (reported by Ralf Hoffmann) - fixed data size in MMD3 pattern sequence loading - fixed MMD1/MMD3 invalid/unhandled effect translation - fixed MMD1/MMD3 mixing buffer size setting (for PrivInv.med) - fixed Soundtracker 15-instrument module tracker fingerprinting - format management code cleanup - prowizard code cleanup 2.2.1 (20070917): - added IT tracker fingerprinting - enabled track volumes (fixes znm-believe.it, reported by Jon Rafkind) - fixed DESTDIR and config file location (by Adam Sampson) - fixed volume overdrive in the Megatracker loader - fixed probing order of PW-packed and Arc - raised sample number limit from 255 to 1024 (fixes megaman.xm tempo and missing instruments reported by Jon Rafkind) - build plugin files as PIC 2.2.0 (20070915): - added more module format specs - added CD61 Octalyser module support - added Flextrax FLX module detection - added TCB Tracker module loader - added Digital Tracker DTM module loader - added Digital Tracker FA04/6/8 module support - added Real Tracker module loader - added X-Tracker module loader - added portable, 64bit-safe MMD0/1/2/3 MED loader - added Graoumf Tracker GTK module loader - added old Liquid Tracker "NO" module loader - added OSX CoreAudio driver - added S3M/PTM/IMF/LIQ/IT fine vibrato effect - added Archimedes Tracker loader - added Arc/!Spark depacker - added ArcFS depacker - added Archimedes VIDC sample converter - added Digital Symphony module loader - added Megatracker module loader - added Desktop Tracker module loader - added Zoo depacker - added MED3 module loader - added MED4 module loader - added IIgs ASIF sample converter - added IIgs SoundSmith/MegaTracker loader - added Audacious plugin - enabled WAV writer - enabled IMF filter effects - enabled Game Music Creator prowizard converter - removed broken shared lib generation - removed packed structures - replaced non-free PowerPack depacker with Kyzer's PD version - replaced list management in IFF loader with kernel list helpers - replaced XMMS plugin with Beep Media Player plugin - fixed long-standing bug in S3M BPM handling, "Panic" plays correctly - fixed MDL effects translation - fixed MDL pattern order loading missing first pattern - fixed MDL memory corruption in envelope initialization - fixed MDL 16-bit sample depacking (reported by Paul Wise) - fixed MDL multisampled instrument mapping - fixed MDL note event keyoff (gothlord.mdl plays better) - fixed XM and MDL sample loop size - fixed XM BPM setting (speedup.xm plays correctly) - fixed LIQ effects and 16-bit sample loading - fixed S3M pan settings - fixed IT old instrument volume mode setting - fixed IT 16-bit sample loading (reported by Henrik Pauli) - fixed IT effect S00 and delta sample loading (fixes O4UFRDMX.IT) - fixed multi-retrig effect (reported by Henrik Pauli) - fixed infinite loop scan (reported by Zbigniew Luszpinski) - fixed Sinaria sample size and finetune - fixed issues with OpenBSD - fixed issues with 64-bit machines - fixed loading of big-endian 16-bit samples - using Asle's Prowizard to handle packed MODs 2.1.1 (unreleased): - added more module format specs - added MO3 unpacking support - added file detection to the XMMS plugin - added Beep Media Player support to the XMMS plugin - added Epic Megagames PSM module support - added Epic Megagames old PSM (Silverball) module support - added DSMI/DMP Advanced Module Format support - added support to Ultimate Soundtracker modules - added ALSA 0.9/1.0 sound output support - fixed recursive decrunching of module files - fixed QNX6 portability issues (by Mike Gorchak) - fixed heavy memory leak in the XMMS plugin - fixed --time command-line parameter - fixed portamento-after-keyoff bug (Jeronen Tel's "Nine One One" now plays correctly) - fixed IFF file loading to avoid data alignment errors - fixed endianism issues in MDL loader - updated OPL emulation (by Mike Gorchak) - default verbosity level changed to 1 - default sound mode set to stereo - disabled MED loader (nonportable, didn't work well) 2.1.0 (unreleased): - Added Takuya Ooura's FFT code - Added scope/spectrum analyser modes to xxmp - Fixed dynamic driver loading to honour the configuration prefix - Added --with-esd option to the configuration script for esd in FreeBSD (reported by Nate Dannenberg ) - Added xxmp panel and module info to XMMS info box - Fixed YM3812 emulator output in mono and stereo modes - Reordered extra libraries in Makefile.rules to build correctly in IRIX 6.5.10/gcc 2.95.2 (reported by Johan Hattne ) - Added aRts driver - Added NAS driver (based on Martin Denn's mpg123 NAS driver) - Added experimental QNX4 driver based on Mike Gorchak's nspmod port - Added experimental win32 driver based on Tony Million's mpg123 driver - Added NEO Software/Electronic Rats HSC module loader - Added Liquid Tracker module 0.0 and 1.0 support - Added callback driver for plugins - XMMS plugin changed to use the callback driver - Added Images Music System support 2.0.4 (20010119): - Added driver for synthesized sounds - Added Tatsuyuki Satoh's YM3812 emulator - Added support to The Player 6.0a modules (using Sylvain "Asle" Chipaux's P60A loader) - Added seek capability to XMMS plugin - Added (very) experimental AIX driver - Added envelope point sanity checks (fixed "Beautiful Ones" IT envelope bug reported by Chris Cox) - Added support to dynamic linked drivers (for better packaging) - Added option to package only DFSG-compliant code - Fixed audioio.h detection in OpenBSD 2.8 (by Chris Cox ) - Max. filter cutoff value changed from 254 to 253 to avoid problems in "Beautiful Ones") - Fixed external drivers problem with the XMMS plugin (reported by greg ) - Fixed xmp_ord_set() bug (was calling XMP_ORD_PREV) - Fixed period calculation algorithm (that was an OLD bug!) - Started adding support to MED 1.11, 1.12, 2.00 and 3.22 - Replaced RPM spec with Dominik Mierzejewski's version 2.0.3 (20001229): - Fixes for enabling/disabling features in configure.in - gcc 2.96/glibc 2.2 related fixes by Dominik Mierzejewski - Support for RAR packed files by Michael Doering - Improved powerpacker decrunching by Michael Doering - IT lowpass filters for the software mixer - Fixed "yes/no" switch in xmp-modules.conf - XMMS plugin in big-endian machines fixed by Griff Miller II - Updated RPM specfile 2.0.2 (20000506): - Fixes in the NetBSD driver (by Michael ) - Fixed sample size for MED synth instruments - Fixed the set offset effect for (offset > sample length) bug reported by Igor Krpanic - Fixed configuration file loading in OS/2 (by Kevin Langman ) - Fixed S3M tone portamento bug introduced in 2.0.1 - Fixed option --fix-sample-loops - Improved Noisetracker and Octalyser module detection - Fixed UNIC tracker and Mod's Grave module detection - Fixed Protracker song detection - Event loading in S3M fixed by Rudolf Cejka - ALSA 0.5 driver fixed by Rob Adamson - Added experimental XMMS plugin - Removed calls to tempnam(3) - Big-endian sound output finally fixed? 2.0.1 (20000223): - Endianism problems in Linux/PPC (Amiga) fixed by Rune Elvemo - Added enhanced NetBSD/OpenBSD drivers written by Michael - Fixed sample loop detection bug in the MOD loader - ALSA 0.5 support fixes by Tijs van Bakel - Moved the YM3128 emulator sources to the 2.1 branch (shouldn't be in the 2.0.0 package) - Added extra sanity tests for 15 instrument MODs (based on sample size/loop info), relaxed file size test, added check for NT mods - Fixed pathname for Protracker song sample loading - Fixed XM loader for nonstandard mods sent by Cyke O'Path - Added workaround for IT fine global volume slides - Added support for EXO4/EXO8 Startrekker/Audio Sculpture modules - Added support for Soundtracker 2.6/Ice Tracker modules - MED synth instruments MUCH better now (but still far from perfection) - Fixed S3M instrument retriggering on portamento bug reported by Igor Krpanic 2.0.0 (20000202): - Allocations checked with Electric Fence - Fixed powerpack decruncher counter initialization - Number of tracks fixed in the XM loader - 0 byte allocation fixed in the XM loader - Vibrato depth fixed (>>1) - Independent effect memory for XM volume slide effect and volume column effect - Disable sample loop when loop end < loop start - Continue S3M fine effects (e.g. x00 after xF5) - Loader for Startrekker FLT8 modules - Pattern loop fixed - Set offset effect bug fixed (reported by Martin Willers ) - Sample length in the software mixer - 669 effects fixed by Miod Vallat - Fixed S3M/IT continue arpeggio effect - Fixed S3M/IT set tempo effect - Fixed set finetune effect (<<4) - Fixed S3M and XM global volume settings - Fixed STX memory leaks - Added support for XM 1.03 modules in the XM loader - Speed 0x20 correctly recognized - STM loader accepts BMOD2STM stms (reported by Bernhard Mrz) - Fixed wrong number of patterns in FAR loader (reported by Bernhard Mrz ) - Fixed IFF chunk buffer allocation for MDL samples - Fixed sample buffer size for MDL 16 bit samples - SMIX_C4NOTE changed to from 6947 to 6864 in mixer.h (reported by Christoph Groth -- fixes Cannon Fodder replaying) - Ignore garbage in the order list (reported by Spirilis -- fixes dragnet.mod) - Event fetch now emulates ST3, FT2 and Protracker - Added virtual channel system (for IT NNAs etc) - Added loaders for Protracker 3.59 IFFMODL, STMIK 0.2, Promizer 0.1/ 2.0/4.0, SoundFX 1.3/2.0, Slamtilt, MED/OctaMED, DIGIBooster, Quadra Composer, Digital Illusions, Module Protector, Zen Packer, Kefrens Sound Machine, Heatseeker, Imago Orpheus and Impulse Tracker modules - Added support for MED synth sounds (incomplete) - Added support for MED BPM tempos (incomplete) - S3M loader recognizes Imago Orpheus - xmprc renamed to xmp.conf - Configuration for specific mods using xmp-modules.conf - User configuration stored in $HOME/.xmp - Protracker effect 9 bug emulation - Support for Protracker song files - AWE support for IT filter envelopes - Filename in the xxmp window title (added by Geoff Reedy ) - Sample crunching for soundcards with limited memory (requested by janne ) - Bidirectional loop expansion and 16-bit conversion for AWE - Added anti-click routines in the mixer (requested by Teemu Kiviniemi ) - Zirconia's MMCMP decrunching support - Old volume mode set for awedrv 0.4.3 - Added option --loadonly - Changed finalvol formula - MOD loader split in M.K./xCHN, FLT and ST loaders - xmp_options changed to xmp_control - Removed redundant code from loaders - Dropped options -p (period mode), --disable-envelopes, --modrange and --ntsc - UNIC and LAX collapsed in a single loader - Added test for AWE_MD_NEW_VOLUME_CALC definition in oss_seq.c - Fixed buffer write() after EINTR on SIGSTOP (reported by Ruda Moura ) - Title line in xxmp fixed by Geoff Reedy - Tweak configure.in to honour predefined CPPFLAGS in environment since awe_voice.h moves around in FreeBSD. At the time it is in /usr/src/sys/gnu/i386/isa/sound/ (by Bjoern Fisher ) - Added missing #include "config.h" in main.c (by Bjoern Fisher ) - Default mixing rate raised to 44.1 kHz - Fixed OSS sequencer timing in Linux/Alpha (by Nils Faerber , reported by Andrew Hobgood -- improved using Miodrag Vallat's HZ checking) - Added native ALSA PCM driver - Fixed xxmp title wrap - Fixed 4-bit ADPCM sample decompression - Solaris driver fixed by Keith Hargrove - IRIX driver fixed by Brian Downing - Merged OS/2 DART port by Kevin Langman - Added BMOD2STM support in STX mods (reported by Miod Vallat) 1.2.0 (Unreleased): - Added support for 16-bit samples in S3M (reported by Geoff Reedy and Chris Jantzen ) - Status display in main.c changed from curr_row/num_rows to curr_row/max_rows. - esd driver fixed by Terry Glass - (Yet another scanner bugfix) scanner ignores tempo 0 - (Yet another scanner bugfix) estimated time limit extended from 15 min. to approx. 4 hours (should be sufficient) - (Yet another scanner bugfix) scanner sets global volume - (Yet another scanner bugfix) S3M_END test fixed - Skip to previous module fixed - Loop start set in bytes in 15 instrument MOD files - Added return status for failure in decompression - Temporary file unlink after failed decompression - Fixed S_ISDIR using wrong argument - Fixed clear chunk ID buffer in the IFF loader - Fixed chunk ID test fixed in the IFF loader - Release the IFF loader linked list after loading - Init default options in load.c - Volume echo event normalized to 0x40 - Fixed sample loop in UNIC/LAX modules - Fixed FAR number of patterns - Fixed FAR tempo effect - Fixed FAR effect parameter setting - STM loader now rejects STX files - Fixed XM note fadeout value - Option --fix-sample-loop sets sample loop start in bytes - Added support for NoisePacker 1/2/3, Digitrakker 0.0/1.0/1.1 and Promizer 1.0/1.8 module formats - SIGUSR1 and SIGUSR2 handlers for skipping to next/previous module (requested by Geoff Reedy ) - Recursive module unpacking - drv_solaris renamed to drv_bsd_sparc - Other cosmetic changes 1.1.6 (19981019): - xxmp compilation in FreeBSD fixed by Adam Hodson - Makefile fixed for bash 2 - S3M global volume setting removed (reported by John v/d Kamp ) - S3M tempo/BPM effect fixed (reported by Joel Jordan ) - XM loader checks module version - XM loader fixed for DEC UNIX by Andrew Leahy - finalvol shifted right one bit to prevent volume overflow with dh-pofot.xm (Party On Funk-o-tron) - File uncompression based on magic instead of file suffix - Loop detection and time estimation improved; --noback option removed (reported by Scott Scriven ) - Invalid values for module restart are ignored (reported by John v/d Kamp ) - Don't play invalid samples and instruments - Fine effect processing changed to the Protracker standard instead of FT2 (i.e. effects EB1-EE5 play fine vol slide five times) - OSS audio driver fragment setting fixed - Added test for file type before loading - MOD/XM tempo/BPM setting fixed (reported by Gabor Lenart ) - XM loader limits number of samples (needed to play Jeronen Tel's "Pools of Poison") - Invalid sample number in instrument map is set to 0xff and ignored by the player (needed to play Jeronen Tel's "Pools of Poison") - Jump to previous order in order zero ignored. - Channel 1 to 10 mute/unmute keys changed - cfg.mode -1 bias removed - --ignoreff option removed - Reserved & unsed fields removed from structures - S3M tremor effect implemented - XM keyoff effect implemented - Experimental (untested) SGI driver - Experimental (untested) OpenBSD driver - --nocmd option added by Mark R. Boyns - Added support for XM 1.02, Ultra Tracker, ProRunner, Propacker, Tracker, Unic Tracker, Laxity, FC-M, XANN and AC1D modules - Added built-in uncompressors for Powerpacker and XPK-SQSH - Option for realtime priority in FreeBSD added by Douglas Carmichael - Support for 15 bpp in xxmp added by John v/d Kamp 1.1.5 (19980321): - Bidirectional sample loop fixed (reported by Andy Eltsov) - Set pan effect bug fixed by Frederic Bujon - Solaris/Sparclinux driver for the AMD 7930 audio chip (tested in Solaris 2.5.1 and Linux 2.0.33) - Support for the Enlightened Sound Daemon - Better SIGSTOP/SIGCONT handling 1.1.4.1 (19980330): - New URL updated in docs 1.1.4 (19980204): - Added missing error check in Solaris and HP-UX drivers - Fixed includes for FreeBSD - Fixed X setup in the configure script - Fixed X include path in Makefile.rules and src/main/Makefile - scan.c replaced by a new version from 1.2.0 development tree - HP-UX driver works (tested in a 9000/710 with HP-UX 9.05) - Misc doc updates 1.1.3 (19980128): - xxmp color #000000 changed to #020202 (needed in Solaris) - `cmd' type changed to char - Interactive commands to unmute channels 6, 7 and 8 - MTM loader works in big-endian machines - Experimental HP-UX support added (not tested) - Panel background colors changed - New INSTALL file - Misc doc updates 1.1.2 (19980105): - Fixed xxmp palette corruption - Fixed xxmp error messages - Misc doc updates 1.1.1 (19980103): - Fixed coredump in Oktalyzer loader (resetting pattern and sample counters) - Fixed coredump with Adlib instruments - Fixed xxmp window update (added missing XSync, xxmp shows current pattern and row) - Fixed color palette in 16 bpp True Color - Fixed command line arguments -S and -M 1.1.0 (19971224): "The Nightmare Before Christmas" release - Package license changed to GPL - Configuration made by GNU autoconf - Software mixer and /dev/dsp support - Compiles on FreeBSD 2.2 and Solaris 2.4 - Command line options changed, long options added - Random play mode added - AWE reverb and chorus options added - Support for OPL2 FM synthesizer - New formats supported: Elyssis Adlib Tracker (AMD), Reality Adlib Tracker (RAD), Aley's Modules (ALM) - Support for multiple output devices - Support for Scream Tracker 3.00 modules (volslides in every frame) - Support for S3M Adlib instruments - Support for S3M (very old) signed samples - Support for S3M pan ("The Crossing" plays correctly) - Support for S3M global volume - Support for Oktalyzer 7 bit samples - Support for IFF modules and variations - S3M arpeggio kludge removed - S3M module length adjusted discarding 0xff paterns - S3M set tempo/BPM effect adjusted - XM envelope loop bug fixed ("Shooting Star" plays correctly) - XM 16 bit sample conversion bug fixed ("Hyperdrive" plays correctly) - Support for XM instruments with 29 byte headers (for "Braintomb") - AWE32 pan setting fixed - Glissando in linear period mod bug fixed - Volume overflow bug fixed (again) - Tone portamento update bug fixed - Period setting workaround for panic.s3m - Pattern jump effect bug fixed - Oktalyzer loader bugs fixed - period_to_bend precision loss bug fixed - Option -s fixed to play with correct tempo/BPM/volume - Added support for bzip, compress, zip and lha compressed modules - Added Protracker and Soundtracker wrappers to the MOD loader - Support for MDZ modules with ADPCM samples - IPC stuff removed, player engine built as a library - Fixed memory leak in MOD loader - Fixed memory leak in oss_seq - X11 version (xxmp) - Interactive commands - xmprc file 1.0.1 (19970419): - IPC global volume setting bug fixed - FAR number of patterns bug fixed - S3M volume setting effect correctly handled (fixes Skaven's 2nd Reality) - Option to disable dynamic panning to prevent AWE-32 clicking 1.0.0 (19970330): First non-experimental release - Added option -t (maximum playing time) - Added option -K to enable IPC - Test module removed from package Experimental versions --------------------- 0.99c (19970320): Fixed more bugs reported by Michael Janson - S3M loader changed to recognize fine and extra fine volume slides only when the slide nibble is not zero (fixes PM's 2nd Reality) - XM patterns with 0 (==0xff) rows are being correctly handled (Wave's Home Vist should play better) - Tone portamento effect does not reset envelopes (fixes Wave's Home Visit pattern 0, channels 0 to 5) - Loop click removal fixed & improved - chipsamples sound smoother using gmod's method to prevent clicking - Continue vibrato effect bug fixed 0.99b (19970318): Fixed bugs reported by Antti Huovilainen and Michael Janson - Extra fine portamento bug fixed (ascent.s3m should play better) - Volume column tone portamento in XM shifted left 4 bits (fixes guitar in Zodiak's Status Mooh order 7, channel 7) - Note delay bug fixed (fixes bass in Jogeir Liljedahl's Guitar Slinger) - delay was working as note retrig - Sample offset effect bug fixed (fixes snare drum in Zodiak's Status Mooh order 0D channel 5) - offset 00 uses previous offset - New instrument event with same instrument does not retrig the sample (fixes pad in Romeo Knight's Wir Happy Hippos) - Global volume limited to 0x40 (fixes fadeout in Zodiak's Reflecter) - Sample loop adjusted for click removal - 669 loader changed to use secondary effects for tempo/break - S3M loader changed to use generic pattern loops (S3M-specific pattern loop kluge removed from xm_play.c) - MOD loader fixed - the module may have unused patterns stored and this situation was confusing the loader - Effect F changed to recognize 32 frames per row 0.99a (19970313): - General code review - Internal module format changed to XXM - Added endianism correction - Volume overdrive bug fixed - Verbosity levels adjusted - Vibrato implementation bug fixed - Instrument vibrato sweep implemented - New module formats supported: STM, 669, WOW, MTM, PTM, OKT, FAR - Added mute/solo channel command line options - Tempo 0 ignored - Lots of cosmetic changes - Option to reduce sample resolution to 8 bits - Envelope sustain bug ("Zodiak bug") fixed (reported by Beta) - Infinite loop in pattern jump bug fixed 0.09e (19970105): Improved S3M support and general bugfixes - Yet another pattern loop bug fixed - S3M J00 (arpeggio) effect workaround - S3M stereo enable/disable implemented - S3M sample pan bug fixed - Added warning for S3M Adlib channels - Improved S3M channel pan handling - Incremental verbosity option - Tone portamento behaviour fixed (for "Elimination Part I") - Added parameter -i to ignore S3M end of module markers - S3M FFx/F00 (continue fine period slide) effect bug fixed (bug was audible in the Second Reality opening theme) - Global volume slide bug fixed - installbin target fixed in the Makefile - Volume reset with no instrument for new note bug fixed (bug was audible in "Knulla Kuk" by Moby) 0.09d (19970101): - Pattern jump bug fixed - Added support for ??CH mods - thanks to Toru Egashira - Fine pitchbending effect bug fixed - Signal handling fixed (again) - USR1 and USR2 signals changed to ABRT and HUP - Command line parameter to force MOD octave range - NTSC timing for MOD files - Glissando effect implemented - Retrig and multi-retrig effects bug fixed - S3M fine volume slide effect translation bug fixed - S3M C2SPD translation to relnote/finetune bug fixed - S3M pattern loop fixed - S3M module loop bug fixed - Pattern loop (for restart order>=0x7f) bug fixed - version.o dependencies fixed in the Makefile 0.09c (19970101): broken version (unreleased) 0.09b (19961210): - Note release and fadeout bug fixed - Module restart (SIGUSR2) bug fixed - Octave shift bug fixed ("Move to da beat" plays OK) - "Squeak" bug fixed (the bug was caused by a tone portamento with no destination note) - Pitchbending effect bug fixed ("Crystal Dragon" plays OK) 0.09a (19961207): First public release. - Panel signal handling fixed - base_note set with C4 frequency of 130.812 Hz (actually C3) - GUS_VOICE_POS enabled for AWE_DEVICE (Iwai's patch) - Envelope fadeout (release) fixed - Note skip bug corrected after some shotgun debugging - GUS panning fixed (bypassing sequencer.h) - Added panning amplitude command line option - Added a channel pan parameter - Changed the XM loader to always unpack the patterns - S3M pan positions fixed - Timing variables changed to floating point - I really don't like FP, maybe I've been hacking in assembly language too much - Added 15-instrument MOD loader - Added XM finetune interpolation - Arpeggio bug fixed: pitchbend increments between semitones is 100 and not 128 (why don't they use ROUND numbers?) - Changed period2bend to prevent lossage in higher octaves - Pattern loop effect implemented (running_lamer.mod plays OK) - Auto-detector (?) for 15-instrument MODs (option -f removed) - Added linear period support - All source files checked into RCS Development (unreleased) versions --------------------------------- 0.08 (19961031): - Increased code mess - Included Iwai's AWE support - devices.c created to wrap output devices - sequencer.c, awe.c and gus.c included in devices.c - Portability macros set in the Makefile (but not used) - Manpage draft included in the package - Added command-line device selector - Finally got rid of those ridiculous fread()s in xm_load.c - xm_instrument_header split into xm_instrument_header and xm_instrument - Removed OSS macros from xm_play.c - Volume overflow bug fixed ("Thematic Hymn" plays OK) - Scream Tracker S3M loader - Fixed the song length bug - XM relnotes are working again! - Added a garbage character filter to the MOD loader - Floating point stuff removed - Sequencer sync message support added - Multiple file entry point bug fixed - Song loop bug fixed, added a loop-enable option - Tremolo and extra fine portamento effects fixed - Player doesn't try to play invalid instruments (and dump core) - SIGUSR1 and SIGUSR2 handlers added (abort/restart module) - MOD effects with parameter 0 filtered in the loader (nasty bug) - Finetunes partially fixed ("Ooo-uh-uh-uh" does not work) - Started X11 panel (VERY experimental) - Volume column effect fxp bug fixed - Envelope retrig on tone portamento bug fixed - MOD sample loop length fixed - Finetune in tone portamento bug fixed 0.07 (19961011): We've screwed up XM relnotes in this version. Yuck! - Sample loop bug fixed - Extra fine portamento effect implemented - Global volume set/slide effects implemented - Pan slide effect implemented - Delay pattern effect implemented - Retriggered tremolo/vibrato implemented - Added tremolo/vibrato waveforms 4, 5 and 6 (no retrigger) - Stereo reverse/mono command line options are now functional - Pan slide effect implemented (but does it work?) - Arpeggio effect implemented - "Official" Amiga (exponential) periods implemented - Multi-retrig and delay effects implemented - Retrig and cut implemented as special cases of multi retrig - Fixed vibrato/tremolo waveforms - Added some macros to reduce the code mess - Finetunes/relnotes processed by the player (and not by the loader) 0.06 (19960924): This version can play most MODs - Changed a lot of variable names - Fixed envelope processing - Fixed pitchbending (SEQ_BENDER vs SEQ_PITCHBEND) bug - Fixed panning (SEQ_CONTROL vs SEQ_PANNING) bug - Fixed multisample struct definition bug - Fixed note number "obi-wan" bug ("Neverending Story" plays OK) - Fixed tone portamento behavior ("Art of Chrome" plays OK) - Added MOD finetune support ("Elimination Part I" plays OK) - Added offset, cut, delay and retrig effects 0.05 and before: - Lots of changes. libxmp-4.4.1/docs/COPYING.LIB0000664000175000017500000006364212304451505015241 0ustar claudioclaudio GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libxmp-4.4.1/docs/formats.txt0000664000175000017500000000560012706551122016005 0ustar claudioclaudio SUPPORTED MODULE FORMATS Common suffix Tracker/packer Recognized variants Soundtracker and variants: MOD Sound/Noise/Protracker M.K., M!K!, M&K!, N.T., CD81 MOD, M15 Soundtracker 2.2, UST MOD/NT Startrekker/ADSC FLT4/8/M, EXO4/8 MOD Digital Tracker FA04, FA06, FA08 MOD Fast/Taketracker xCHN, xxCH MOD His Master's Noise - FLX Flextrax M.K., xCHN (no dsp effects) WOW Mod's Grave M.K. Amiga packed formats: - AC1D Packer - - FC-M Packer 1.0 - Fuchs Tracker - - Heatseeker mc1.0 - Hornet Packer HRT! - Images Music System ? - Kefrens Sound Machine - - Module Protector - - NoisePacker 1.0, 2.0, 3.0 - NoiseRunner - - Pha Packer - - Power Music - - ProPacker 2.1 - ProRunner 1.0, 2.0 - Promizer 0.1, 1.0c, 1.8a, 2.0, 4.0 - SKYT Packer - - StarTrekker Packer - - The Player 4.x, 5.0a, 6.0a, 6.1a - Titanics Player - - Tracker Packer 3 MOD Unic Tracker 1.0, 2.0 - Wanton Packer - - XANN Packer - - Zen Packer - Other Amiga tracker formats: DBM DigiBooster Pro DBM0 DIGI DIGI Booster 1.4, 1.5, 1.6, 1.7 EMOD Quadra Composer 0001 MOD ChipTracker KRIS MOD Protracker 3.59 PTDT MED MED 1.12/2.10/3.00 MED2, MED3, MED4 MED MED 3.00/OctaMED MMD0, MMD1, MMD2, MMD3 MOD, MTN ST 2.6, Ice Tracker MTN, IT10 OKT Oktalyzer - SFX SoundFX 1.3, 2.0? Atari tracker formats: MOD Octalyser CD61, CD81 DTM Digital Tracker 1.9 MGT Megatracker - Acorn tracker formats: - Archimedes Tracker V1.0+++ - Digital Symphony 0 PC tracker formats: 669 Composer 669/UNIS 669 if, JN FAR Farandole Composer 1.0 FNK Funktracker R0, R1, R2 IMF Imago Orpheus 1.0 IT Impulse Tracker 1.00, 2.00, 2.14, 2.15 LIQ Liquid Tracker 0.0, 1.0 MDL Digitrakker 0.0, 1.0, 1.1 MTM Multitracker 1.0 PTM Poly Tracker 2.03 RTM Real Tracker 1.00 S3M Scream Tracker 3 3.00, 3.01+ STM Scream Tracker 2 !Scream!, BMOD2STM ULT Ultra Tracker V0001, V0002, V0003, V0004 XM Fast Tracker II 1.02, 1.03, 1.04 PC packed formats: AMF DSMI (DMP) 0.9, 1.0, 1.1, 1.2, 1.3, 1.4 GDM Generic Digital Music 1.0 STX ST Music Interface Kit 1.0, 1.1 Game formats: ABK AMOS Sound Bank - AMF Asylum Music Format 1.0 - Digital Illusions - - Game Music Creator - PSM Epic Megagames MASI epic, sinaria J2B Galaxy Music System 5.0 - - Galaxy Music System 4.0 - MFP/SMP Magnetic Fields Packer - - Novotrade Packer - PSM Protracker Studio 0.01, 1.00 STIM Slamtilt - UMX Epic Games Unreal/UT IT, S3M, MOD, XM YM3812 (Adlib) formats: AMD Amusic Adlib Tracker - RAD Reality Adlib Tracker - HSC NEO soft/HSC-Tracker 1.5 S3M Scream Tracker 3 3.00, 3.01+ Formats marked with (*) are experimental and are known to have replay errors and unimplemented effects. Format descriptions of packed modules sent by Sylvain "Asle" Chipaux. PTM specs and info by Kilian Hekhuis. AMF specs by Miod Vallat. Soundtracker format details by Michael Schwendt and Sylvain Chipaux. libxmp-4.4.1/docs/fixloop.txt0000664000175000017500000000424512304451505016014 0ustar claudioclaudio The flag XMP_FLAGS_FIXLOOP halves sample loop start values. You may need to use it with modules where autodetection is either impossible or unreliable. Case 1: Bad conversion from Soundtracker to M.K. In Soundtracker and derivatives using 15 instrument modules the loop start is given in bytes instead of 16 bit words [1]. Many modules have been converted from 15 instrument to 31 instrument format assuming that the loop start was in 16 bit words instead of bytes, resulting in broken loops [2]. In this case, use XMP_FLAGS_FIXLOOP to play the module correctly. An example of damaged module is "mod.souvenir of china" Case 2: NoisePacker v1 modules According to Asle [3], the only difference between NoisePacker 1.0 and 2.0 is the loop start value. This situation is very hard to detect, and XMP_FLAGS_FIXLOOP is needed to play NoisePacker 2.0 modules correctly. Case 3: Laxity/UNIC modules UNIC modules can have loop start specified in 16 bit words or in 32 bit words [4]. Use XMP_FLAGS_FIXLOOP to set this value to 16 bit words. References: [1] Michael Schwendt (Sat, 24 Oct 1998 22:41:21 +0000) "(...) all Soundtracker derivatives, including Ultimate Soundtracker, Soundtracker v1.0 to v4.0 and V to IX, Master Soundtracker 1.0, D.O.C-Soundtracker v2.0 to v2.3, use repeat_start in bytes (!). Hence MOD players should default to repeat_start in bytes. The first Soundtrackers to use repeat_start in words were Soundtracker v2.4 (Spreadpoint), Noisetracker, and Protracker." [2] "Ultimate Soundtracker module format description", v0.1, by Michael Schwendt, lines 28--31: "Years later people without knowledge of the incompatibility between the original Soundtracker module format and successors like Soundtracker 2.4 or Protracker damaged modules by converting them to Protracker format." [3] "Amiga MOD packers described", version 4.1 (13/06/98), written by Sylvain Chipaux (Asle/ReDoX). [4] "Amiga MOD packers described", version 4.1 (13/06/98), written by Sylvain Chipaux (Asle/ReDoX). "About this loop start /4 or /2, I cannot tell for sure because I've encountered both cases: 'Guardian dragon' (/2) and 'Guardian dragon II' (/4). libxmp-4.4.1/docs/libxmp.rst0000664000175000017500000011173312742415254015630 0ustar claudioclaudio Libxmp 4.4 API documentation ============================ .. contents:: `Contents` :depth: 3 .. raw:: pdf PageBreak Introduction ------------ Libxmp is a module player library supporting many mainstream and obscure module formats including Protracker MOD, Scream Tracker III S3M and Impulse Tracker IT. Libxmp loads the module and renders the sound as linear PCM samples in a buffer at rate and format specified by the user, one frame at a time (standard modules usually play at 50 frames per second). Possible applications for libxmp include stand-alone module players, module player plugins for other players, module information extractors, background music replayers for games and other applications, module-to-mp3 renderers, etc. Concepts ~~~~~~~~ * **Player context:** Most libxmp functions require a handle that identifies the module player context. Each context is independent and multiple contexts can be defined simultaneously. * **Sequence:** Each group of positions in the order list that loops over itself, also known as "subsong". Most modules have only one sequence, but some modules, especially modules used in games can have multiple sequences. "Hidden patterns" outside the main song are also listed as extra sequences, certain module authors such as Skaven commonly place extra patterns at the end of the module. * **State:** *[Added in libxmp 4.2]* The player can be in one of three possible states: *unloaded*, *loaded*, or *playing*. The player is in unloaded state after context creation, changing to other states when a module is loaded or played. * **External sample mixer:** *[Added in libxmp 4.2]* Special sound channels can be reserved using `xmp_start_smix()` to play module instruments or external samples. This is useful when libxmp is used to provide background music to games or other applications where sound effects can be played in response to events or user actions * **Amiga mixer:** *[Added in libxmp 4.4]* Certain formats may use special mixers modeled after the original hardware used to play the format, providing more realistic sound at the expense of CPU usage. Currently Amiga formats such as Protracker can use a mixer modeled after the Amiga 500, with or without the led filter. A simple example ~~~~~~~~~~~~~~~~ This example loads a module, plays it at 44.1kHz and writes it to a raw sound file:: #include #include #include int main(int argc, char **argv) { xmp_context c; struct xmp_frame_info mi; FILE *f; /* The output raw file */ f = fopen("out.raw", "wb"); if (f == NULL) { fprintf(stderr, "can't open output file\n"); exit(EXIT_FAILURE); } /* Create the player context */ c = xmp_create_context(); /* Load our module */ if (xmp_load_module(c, argv[1]) != 0) { fprintf(stderr, "can't load module\n"); exit(EXIT_FAILURE); } /* Play the module */ xmp_start_player(c, 44100, 0); while (xmp_play_frame(c) == 0) { xmp_get_frame_info(c, &mi); if (mi.loop_count > 0) /* exit before looping */ break; fwrite(mi.buffer, mi.buffer_size, 1, f); /* write audio data */ } xmp_end_player(c); xmp_release_module(c); /* unload module */ xmp_free_context(c); /* destroy the player context */ fclose(f); exit(EXIT_SUCCESS); } A player context can load and play a single module at a time. Multiple contexts can be defined if needed. Use `xmp_test_module()`_ to check if the file is a valid module and retrieve the module name and type. Use `xmp_load_module()`_ to load the module to memory. These two calls return 0 on success or <0 in case of error. Error codes are:: -XMP_ERROR_INTERNAL /* Internal error */ -XMP_ERROR_FORMAT /* Unsupported module format */ -XMP_ERROR_LOAD /* Error loading file */ -XMP_ERROR_DEPACK /* Error depacking file */ -XMP_ERROR_SYSTEM /* System error */ -XMP_ERROR_STATE /* Incorrect player state */ If a system error occurs, the specific error is set in ``errno``. Parameters to `xmp_start_player()`_ are the sampling rate (up to 48kHz) and a bitmapped integer holding one or more of the following mixer flags:: XMP_MIX_8BIT /* Mix to 8-bit instead of 16 */ XMP_MIX_UNSIGNED /* Mix to unsigned samples */ XMP_MIX_MONO /* Mix to mono instead of stereo */ XMP_MIX_NEAREST /* Mix using nearest neighbor interpolation */ XMP_MIX_NOFILTER /* Disable lowpass filter */ After `xmp_start_player()`_ is called, each call to `xmp_play_frame()`_ will render an audio frame. Call `xmp_get_frame_info()`_ to retrieve the buffer address and size. `xmp_play_frame()`_ returns 0 on success or -1 if replay should stop. Use `xmp_end_player()`_, `xmp_release_module()`_ and `xmp_free_context()`_ to release memory and end replay. SDL example ~~~~~~~~~~~ To use libxmp with SDL, just provide a callback function that renders module data. The module will play when ``SDL_PauseAudio(0)`` is called:: #include #include static void fill_audio(void *udata, unsigned char *stream, int len) { xmp_play_buffer(udata, stream, len, 0); } int sound_init(xmp_context ctx, int sampling_rate, int channels) { SDL_AudioSpec a; a.freq = sampling_rate; a.format = (AUDIO_S16); a.channels = channels; a.samples = 2048; a.callback = fill_audio; a.userdata = ctx; if (SDL_OpenAudio(&a, NULL) < 0) { fprintf(stderr, "%s\n", SDL_GetError()); return -1; } } int main(int argc, char **argv) { xmp_context ctx; if ((ctx = xmp_create_context()) == NULL) return 1; sound_init(ctx, 44100, 2); xmp_load_module(ctx, argv[1]); xmp_start_player(ctx, 44100, 0); SDL_PauseAudio(0); sleep(10); // Do something important here SDL_PauseAudio(1); xmp_end_player(ctx); xmp_release_module(ctx); xmp_free_context(ctx); SDL_CloseAudio(); return 0; } SDL callbacks run in a separate thread, so don't forget to protect sections that manipulate module data with ``SDL_LockAudio()`` and ``SDL_UnlockAudio()``. .. raw:: pdf PageBreak API reference ------------- Version and player information ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _xmp_version: const char \*xmp_version ```````````````````````` A string containing the library version, such as "4.0.0". .. _xmp_vercode: const unsigned int xmp_vercode `````````````````````````````` The library version encoded in a integer value. Bits 23-16 contain the major version number, bits 15-8 contain the minor version number, and bits 7-0 contain the release number. .. _xmp_get_format_list(): char \*\*xmp_get_format_list() `````````````````````````````` Query the list of supported module formats. **Returns:** a NULL-terminated array of strings containing the names of all supported module formats. Context creation ~~~~~~~~~~~~~~~~ .. _xmp_create_context(): xmp_context xmp_create_context() ```````````````````````````````` Create a new player context and return an opaque handle to be used in subsequent accesses to this context. **Returns:** the player context handle. .. _xmp_free_context(): void xmp_free_context(xmp_context c) ```````````````````````````````````` Destroy a player context previously created using `xmp_create_context()`_. **Parameters:** :c: the player context handle. Module loading ~~~~~~~~~~~~~~ .. _xmp_test_module(): int xmp_test_module(char \*path, struct xmp_test_info \*test_info) `````````````````````````````````````````````````````````````````` Test if a file is a valid module. Testing a file does not affect the current player context or any currently loaded module. **Parameters:** :path: pathname of the module to test. :test_info: NULL, or a pointer to a structure used to retrieve the module title and format if the file is a valid module. ``struct xmp_test_info`` is defined as:: struct xmp_test_info { char name[XMP_NAME_SIZE]; /* Module title */ char type[XMP_NAME_SIZE]; /* Module format */ }; **Returns:** 0 if the file is a valid module, or a negative error code in case of error. Error codes can be ``-XMP_ERROR_FORMAT`` in case of an unrecognized file format, ``-XMP_ERROR_DEPACK`` if the file is compressed and uncompression failed, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_load_module(): int xmp_load_module(xmp_context c, char \*path) ``````````````````````````````````````````````` Load a module into the specified player context. (Certain player flags, such as ``XMP_PLAYER_SMPCTL`` and ``XMP_PLAYER_DEFPAN``, must be set before loading the module, see `xmp_set_player()`_ for more information.) **Parameters:** :c: the player context handle. :path: pathname of the module to load. **Returns:** 0 if sucessful, or a negative error code in case of error. Error codes can be ``-XMP_ERROR_FORMAT`` in case of an unrecognized file format, ``-XMP_ERROR_DEPACK`` if the file is compressed and uncompression failed, ``-XMP_ERROR_LOAD`` if the file format was recognized but the file loading failed, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_load_module_from_memory(): int xmp_load_module_from_memory(xmp_context c, void \*mem, long size) ````````````````````````````````````````````````````````````````````` *[Added in libxmp 4.2]* Load a module from memory into the specified player context. **Parameters:** :c: the player context handle. :mem: a pointer to the module file image in memory. Multi-file modules or compressed modules can't be loaded from memory. :size: the size of the module, or 0 if the size is unknown or not specified. If size is set to 0 certain module formats won't be recognized, the MD5 digest will not be set, and module-specific quirks won't be applied. **Returns:** 0 if sucessful, or a negative error code in case of error. Error codes can be ``-XMP_ERROR_FORMAT`` in case of an unrecognized file format, ``-XMP_ERROR_LOAD`` if the file format was recognized but the file loading failed, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_load_module_from_file(): int xmp_load_module_from_file(xmp_context c, FILE \*f, long size) ````````````````````````````````````````````````````````````````` *[Added in libxmp 4.3]* Load a module from a stream into the specified player context. **Parameters:** :c: the player context handle. :f: the file stream. On return, the stream position is undefined. :size: the size of the module, or 0 if the size is unknown or not specified. If size is set to 0 certain module formats won't be recognized, the MD5 digest will not be set, and module-specific quirks won't be applied. **Returns:** 0 if sucessful, or a negative error code in case of error. Error codes can be ``-XMP_ERROR_FORMAT`` in case of an unrecognized file format, ``-XMP_ERROR_LOAD`` if the file format was recognized but the file loading failed, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_release_module(): void xmp_release_module(xmp_context c) `````````````````````````````````````` Release memory allocated by a module from the specified player context. **Parameters:** :c: the player context handle. .. _xmp_scan_module(): void xmp_scan_module(xmp_context c) ``````````````````````````````````` Scan the loaded module for sequences and timing. Scanning is automatically performed by `xmp_load_module()`_ and this function should be called only if `xmp_set_player()`_ is used to change player timing (with parameter ``XMP_PLAYER_VBLANK``) in libxmp 4.0.2 or older. **Parameters:** :c: the player context handle. .. _xmp_get_module_info(): void xmp_get_module_info(xmp_context c, struct xmp_module_info \*info) `````````````````````````````````````````````````````````````````````` Retrieve current module data. **Parameters:** :c: the player context handle. :info: pointer to structure containing the module data. ``struct xmp_module_info`` is defined as follows:: struct xmp_module_info { unsigned char md5[16]; /* MD5 message digest */ int vol_base; /* Volume scale */ struct xmp_module *mod; /* Pointer to module data */ char *comment; /* Comment text, if any */ int num_sequences; /* Number of valid sequences */ struct xmp_sequence *seq_data; /* Pointer to sequence data */ }; Detailed module data is exposed in the ``mod`` field:: struct xmp_module { char name[XMP_NAME_SIZE]; /* Module title */ char type[XMP_NAME_SIZE]; /* Module format */ int pat; /* Number of patterns */ int trk; /* Number of tracks */ int chn; /* Tracks per pattern */ int ins; /* Number of instruments */ int smp; /* Number of samples */ int spd; /* Initial speed */ int bpm; /* Initial BPM */ int len; /* Module length in patterns */ int rst; /* Restart position */ int gvl; /* Global volume */ struct xmp_pattern **xxp; /* Patterns */ struct xmp_track **xxt; /* Tracks */ struct xmp_instrument *xxi; /* Instruments */ struct xmp_sample *xxs; /* Samples */ struct xmp_channel xxc[64]; /* Channel info */ unsigned char xxo[XMP_MAX_MOD_LENGTH]; /* Orders */ }; See the header file for more information about pattern and instrument data. Module playing ~~~~~~~~~~~~~~ .. _xmp_start_player(): int xmp_start_player(xmp_context c, int rate, int format) ````````````````````````````````````````````````````````` Start playing the currently loaded module. **Parameters:** :c: the player context handle. :rate: the sampling rate to use, in Hz (typically 44100). Valid values range from 8kHz to 48kHz. :flags: bitmapped configurable player flags, one or more of the following:: XMP_FORMAT_8BIT /* Mix to 8-bit instead of 16 */ XMP_FORMAT_UNSIGNED /* Mix to unsigned samples */ XMP_FORMAT_MONO /* Mix to mono instead of stereo */ **Returns:** 0 if sucessful, or a negative error code in case of error. Error codes can be ``-XMP_ERROR_INTERNAL`` in case of a internal player error, ``-XMP_ERROR_INVALID`` if the sampling rate is invalid, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_play_frame(): int xmp_play_frame(xmp_context c) ````````````````````````````````` Play one frame of the module. Modules usually play at 50 frames per second. Use `xmp_get_frame_info()`_ to retrieve the buffer containing audio data. **Parameters:** :c: the player context handle. **Returns:** 0 if sucessful, ``-XMP_END`` if the module ended or was stopped, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_play_buffer(): int xmp_play_buffer(xmp_context c, void \*buffer, int size, int loop) ````````````````````````````````````````````````````````````````````` *[Added in libxmp 4.1]* Fill the buffer with PCM data up to the specified size. This is a convenience function that calls `xmp_play_frame()`_ internally to fill the user-supplied buffer. **Don't call both xmp_play_frame() and xmp_play_buffer() in the same replay loop.** If you don't need equally sized data chunks, `xmp_play_frame()`_ may result in better performance. Also note that silence is added at the end of a buffer if the module ends and no loop is to be performed. **Parameters:** :c: the player context handle. :buffer: the buffer to fill with PCM data, or NULL to reset the internal state. :size: the buffer size in bytes. :loop: stop replay when the loop counter reaches the specified value, or 0 to disable loop checking. **Returns:** 0 if sucessful, ``-XMP_END`` if module was stopped or the loop counter was reached, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_get_frame_info(): void xmp_get_frame_info(xmp_context c, struct xmp_frame_info \*info) ```````````````````````````````````````````````````````````````````` Retrieve the current frame data. **Parameters:** :c: the player context handle. :info: pointer to structure containing current frame data. ``struct xmp_frame_info`` is defined as follows:: struct xmp_frame_info { /* Current frame information */ int pos; /* Current position */ int pattern; /* Current pattern */ int row; /* Current row in pattern */ int num_rows; /* Number of rows in current pattern */ int frame; /* Current frame */ int speed; /* Current replay speed */ int bpm; /* Current bpm */ int time; /* Current module time in ms */ int total_time; /* Estimated replay time in ms*/ int frame_time; /* Frame replay time in us */ void *buffer; /* Pointer to sound buffer */ int buffer_size; /* Used buffer size */ int total_size; /* Total buffer size */ int volume; /* Current master volume */ int loop_count; /* Loop counter */ int virt_channels; /* Number of virtual channels */ int virt_used; /* Used virtual channels */ int sequence; /* Current sequence */ struct xmp_channel_info { /* Current channel information */ unsigned int period; /* Sample period */ unsigned int position; /* Sample position */ short pitchbend; /* Linear bend from base note*/ unsigned char note; /* Current base note number */ unsigned char instrument; /* Current instrument number */ unsigned char sample; /* Current sample number */ unsigned char volume; /* Current volume */ unsigned char pan; /* Current stereo pan */ unsigned char reserved; /* Reserved */ struct xmp_event event; /* Current track event */ } channel_info[XMP_MAX_CHANNELS]; }; This function should be used to retrieve sound buffer data after `xmp_play_frame()`_ is called. Fields ``buffer`` and ``buffer_size`` contain the pointer to the sound buffer PCM data and its size. The buffer size will be no larger than ``XMP_MAX_FRAMESIZE``. .. _xmp_end_player(): void xmp_end_player(xmp_context c) `````````````````````````````````` End module replay and release player memory. **Parameters:** :c: the player context handle. .. raw:: pdf PageBreak Player control ~~~~~~~~~~~~~~ .. _xmp_next_position(): int xmp_next_position(xmp_context c) ```````````````````````````````````` Skip replay to the start of the next position. **Parameters:** :c: the player context handle. **Returns:** The new position index, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_prev_position(): int xmp_prev_position(xmp_context c) ```````````````````````````````````` Skip replay to the start of the previous position. **Parameters:** :c: the player context handle. **Returns:** The new position index, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_set_position(): int xmp_set_position(xmp_context c, int pos) ```````````````````````````````````````````` Skip replay to the start of the given position. **Parameters:** :c: the player context handle. :pos: the position index to set. **Returns:** The new position index, ``-XMP_ERROR_INVALID`` of the new position is invalid or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_stop_module(): void xmp_stop_module(xmp_context c) ``````````````````````````````````` Stop the currently playing module. **Parameters:** :c: the player context handle. .. _xmp_restart_module(): void xmp_restart_module(xmp_context c) `````````````````````````````````````` Restart the currently playing module. **Parameters:** :c: the player context handle. .. _xmp_seek_time(): int xmp_seek_time(xmp_context c, int time) `````````````````````````````````````````` Skip replay to the specified time. **Parameters:** :c: the player context handle. :time: time to seek in milliseconds. **Returns:** The new position index, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_channel_mute(): int xmp_channel_mute(xmp_context c, int chn, int status) ```````````````````````````````````````````````````````````` Mute or unmute the specified channel. **Parameters:** :c: the player context handle. :chn: the channel to mute or unmute. :status: 0 to mute channel, 1 to unmute or -1 to query the current channel status. **Returns:** The previous channel status, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_channel_vol(): int xmp_channel_vol(xmp_context c, int chn, int vol) ```````````````````````````````````````````````````````` Set or retrieve the volume of the specified channel. **Parameters:** :c: the player context handle. :chn: the channel to set or get volume. :vol: a value from 0-100 to set the channel volume, or -1 to retrieve the current volume. **Returns:** The previous channel volume, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_inject_event(): void xmp_inject_event(xmp_context c, int chn, struct xmp_event \*event) ``````````````````````````````````````````````````````````````````````````` Dynamically insert a new event into a playing module. **Parameters:** :c: the player context handle. :chn: the channel to insert the new event. :event: the event to insert. ``struct xmp_event`` is defined as:: struct xmp_event { unsigned char note; /* Note number (0 means no note) */ unsigned char ins; /* Patch number */ unsigned char vol; /* Volume (0 to basevol) */ unsigned char fxt; /* Effect type */ unsigned char fxp; /* Effect parameter */ unsigned char f2t; /* Secondary effect type */ unsigned char f2p; /* Secondary effect parameter */ unsigned char _flag; /* Internal (reserved) flags */ }; .. raw:: pdf PageBreak Player parameter setting ~~~~~~~~~~~~~~~~~~~~~~~~ .. _xmp_set_instrument_path(): int xmp_set_instrument_path(xmp_context c, char \*path) ``````````````````````````````````````````````````````` Set the path to retrieve external instruments or samples. Used by some formats (such as MED2) to read sample files from a different directory in the filesystem. **Parameters:** :c: the player context handle. :path: the path to retrieve instrument files. **Returns:** 0 if the instrument path was correctly set, or ``-XMP_ERROR_SYSTEM`` in case of error (the system error code is set in ``errno``). .. _xmp_get_player(): int xmp_get_player(xmp_context c, int param) ```````````````````````````````````````````` Retrieve current value of the specified player parameter. **Parameters:** :c: the player context handle. :param: player parameter to get. Valid parameters are:: XMP_PLAYER_AMP /* Amplification factor */ XMP_PLAYER_MIX /* Stereo mixing */ XMP_PLAYER_INTERP /* Interpolation type */ XMP_PLAYER_DSP /* DSP effect flags */ XMP_PLAYER_FLAGS /* Player flags */ XMP_PLAYER_CFLAGS /* Player flags for current module*/ XMP_PLAYER_SMPCTL /* Control sample loading */ XMP_PLAYER_VOLUME /* Player master volume */ XMP_PLAYER_STATE /* Current player state (read only) */ XMP_PLAYER_SMIX_VOLUME /* SMIX Volume */ XMP_PLAYER_DEFPAN /* Default pan separation */ XMP_PLAYER_MODE /* Player personality */ XMP_PLAYER_MIXER_TYPE /* Current mixer (read only) */ XMP_PLAYER_VOICES /* Maximum number of mixer voices */ Valid states are:: XMP_STATE_UNLOADED /* Context created */ XMP_STATE_LOADED /* Module loaded */ XMP_STATE_PLAYING /* Module playing */ Valid mixer types are:: XMP_MIXER_STANDARD /* Standard mixer */ XMP_MIXER_A500 /* Amiga 500 */ XMP_MIXER_A500F /* Amiga 500 with led filter */ See ``xmp_set_player`` for the rest of valid values for each parameter. **Returns:** The parameter value, or ``-XMP_ERROR_STATE`` if the parameter is not ``XMP_PLAYER_STATE`` and the player is not in playing state. .. raw:: pdf PageBreak .. _xmp_set_player(): int xmp_set_player(xmp_context c, int param, int val) ````````````````````````````````````````````````````` Set player parameter with the specified value. **Parameters:** :param: player parameter to set. Valid parameters are:: XMP_PLAYER_AMP /* Amplification factor */ XMP_PLAYER_MIX /* Stereo mixing */ XMP_PLAYER_INTERP /* Interpolation type */ XMP_PLAYER_DSP /* DSP effect flags */ XMP_PLAYER_FLAGS /* Player flags */ XMP_PLAYER_CFLAGS /* Player flags for current module*/ XMP_PLAYER_SMPCTL /* Control sample loading */ XMP_PLAYER_VOLUME /* Player master volume */ XMP_PLAYER_SMIX_VOLUME /* SMIX Volume */ XMP_PLAYER_DEFPAN /* Default pan separation */ XMP_PLAYER_MODE /* Player personality */ XMP_PLAYER_VOICES /* Maximum number of mixer voices */ :val: the value to set. Valid values depend on the parameter being set. **Valid values:** * Amplification factor: ranges from 0 to 3. Default value is 1. * Stereo mixing: percentual left/right channel separation. Default is 70. * Interpolation type: can be one of the following values:: XMP_INTERP_NEAREST /* Nearest neighbor */ XMP_INTERP_LINEAR /* Linear (default) */ XMP_INTERP_SPLINE /* Cubic spline */ * DSP effects flags: enable or disable DSP effects. Valid effects are:: XMP_DSP_LOWPASS /* Lowpass filter effect */ XMP_DSP_ALL /* All effects */ * Player flags: tweakable player parameters. Valid flags are:: XMP_FLAGS_VBLANK /* Use vblank timing */ XMP_FLAGS_FX9BUG /* Emulate Protracker 2.x FX9 bug */ XMP_FLAGS_FIXLOOP /* Make sample loop value / 2 */ XMP_FLAGS_A500 /* Use Paula mixer in Amiga modules */ * *[Added in libxmp 4.1]* Player flags for current module: same flags as above but after applying module-specific quirks (if any). * *[Added in libxmp 4.1]* Sample control: Valid values are:: XMP_SMPCTL_SKIP /* Don't load samples */ * Disabling sample loading when loading a module allows allows computation of module duration without decompressing and loading large sample data, and is useful when duration information is needed for a module that won't be played immediately. * *[Added in libxmp 4.2]* Player volumes: Set the player master volume or the external sample mixer master volume. Valid values are 0 to 100. * *[Added in libxmp 4.3]* Default pan separation: percentual left/right pan separation in formats with only left and right channels. Default is 100%. .. raw:: pdf PageBreak .. * *[Added in libxmp 4.4]* Player personality: The player can be forced to emulate a specific tracker in cases where the module relies on a format quirk and tracker detection fails. Valid modes are:: XMP_MODE_AUTO /* Autodetect mode (default) */ XMP_MODE_MOD /* Play as a generic MOD player */ XMP_MODE_NOISETRACKER /* Play using Noisetracker quirks */ XMP_MODE_PROTRACKER /* Play using Protracker 1/2 quirks */ XMP_MODE_S3M /* Play as a generic S3M player */ XMP_MODE_ST3 /* Play using ST3 bug emulation */ XMP_MODE_ST3GUS /* Play using ST3+GUS quirks */ XMP_MODE_XM /* Play as a generic XM player */ XMP_MODE_FT2 /* Play using FT2 bug emulation */ XMP_MODE_IT /* Play using IT quirks */ XMP_MODE_ITSMP /* Play using IT sample mode quirks */ By default, formats similar to S3M such as PTM or IMF will use S3M replayer (without Scream Tracker 3 quirks/bug emulation), and formats similar to XM such as RTM and MDL will use the XM replayer (without FT2 quirks/bug emulation). Multichannel MOD files will use the XM replayer, and Scream Tracker 3 MOD files will use S3M replayer with ST3 quirks. S3M files will use the most appropriate replayer according to the tracker used to create the file, and enable Scream Tracker 3 quirks and bugs only if created using ST3. XM files will be played with FT2 bugs and quirks only if created using Fast Tracker II. Modules created with OpenMPT will be played with all bugs and quirks of the original trackers. * *[Added in libxmp 4.4]* Maximum number of mixer voices: the maximum number of virtual channels that can be used to play the module. If set too high, modules with voice leaks can cause excessive CPU usage. Default is 128. **Returns:** 0 if parameter was correctly set, ``-XMP_ERROR_INVALID`` if parameter or values are out of the valid ranges, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. raw:: pdf PageBreak External sample mixer API ------------------------- Libxmp 4.2 includes a mini-API that can be used to add sound effects to games and similar applications, provided that you have a low latency sound system. It allows module instruments or external sample files in WAV format to be played in response to arbitrary events. Example ~~~~~~~ This example using SDL loads a module and a sound sample, plays the module as background music, and plays the sample when a key is pressed:: #include #include static void fill_audio(void *udata, unsigned char *stream, int len) { xmp_play_buffer(udata, stream, len, 0); } int sound_init(xmp_context ctx, int sampling_rate, int channels) { SDL_AudioSpec a; a.freq = sampling_rate; a.format = (AUDIO_S16); a.channels = channels; a.samples = 2048; a.callback = fill_audio; a.userdata = ctx; if (SDL_OpenAudio(&a, NULL) < 0) { fprintf(stderr, "%s\n", SDL_GetError()); return -1; } } int video_init() { if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "%s\n", SDL_GetError()); return -1; } if (SDL_SetVideoMode(640, 480, 8, 0) == NULL) { fprintf(stderr, "%s\n", SDL_GetError()); return -1; } atexit(SDL_Quit); } int main(int argc, char **argv) { SDL_Event event; xmp_context ctx; if ((ctx = xmp_create_context()) == NULL) return 1; video_init(); sound_init(ctx, 44100, 2); xmp_start_smix(ctx, 1, 1); xmp_smix_load_sample(ctx, 0, "blip.wav"); xmp_load_module(ctx, "music.mod"); xmp_start_player(ctx, 44100, 0); xmp_set_player(ctx, XMP_PLAYER_VOLUME, 40); SDL_PauseAudio(0); while (1) { if (SDL_WaitEvent(&event)) { if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_ESCAPE) break; xmp_smix_play_sample(ctx, 0, 60, 64, 0); } } } SDL_PauseAudio(1); xmp_end_player(ctx); xmp_release_module(ctx); xmp_free_context(ctx); xmp_end_smix(ctx); SDL_CloseAudio(); return 0; } SMIX API reference ~~~~~~~~~~~~~~~~~~ .. _xmp_start_smix(): int xmp_start_smix(xmp_context c, int nch, int nsmp) ```````````````````````````````````````````````````` Initialize the external sample mixer subsystem with the given number of reserved channels and samples. **Parameters:** :c: the player context handle. :nch: number of reserved sound mixer channels (1 to 64). :nsmp: number of external samples. **Returns:** 0 if the external sample mixer system was correctly initialized, ``-XMP_ERROR_INVALID`` in case of invalid parameters, ``-XMP_ERROR_STATE`` if the player is already in playing state, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_smix_play_instrument(): int xmp_smix_play_instrument(xmp_context c, int ins, int note, int vol, int chn) ```````````````````````````````````````````````````````````````````````````````` Play a note using an instrument from the currently loaded module in one of the reserved sound mixer channels. **Parameters:** :c: the player context handle. :ins: the instrument to play. :note: the note number to play (60 = middle C). :vol: the volume to use (range: 0 to the maximum volume value used by the current module). :chn: the reserved channel to use to play the instrument. **Returns:** 0 if the instrument was correctly played, ``-XMP_ERROR_INVALID`` in case of invalid parameters, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_smix_play_sample(): int xmp_smix_play_sample(xmp_context c, int ins, int vol, int chn) `````````````````````````````````````````````````````````````````` Play an external sample file in one of the reserved sound channels. The sample must have been previously loaded using `xmp_smix_load_sample()`_. **Parameters:** :c: the player context handle. :ins: the sample to play. :vol: the volume to use (0 to the maximum volume value used by the current module. :chn: the reserved channel to use to play the sample. **Returns:** 0 if the sample was correctly played, ``-XMP_ERROR_INVALID`` in case of invalid parameters, or ``-XMP_ERROR_STATE`` if the player is not in playing state. .. _xmp_smix_channel_pan(): int xmp_smix_channel_pan(xmp_context c, int chn, int pan) ````````````````````````````````````````````````````````` Set the reserved channel pan value. **Parameters:** :c: the player context handle. :chn: the reserved channel number. :pan: the pan value to set (0 to 255). **Returns:** 0 if the pan value was set, or ``-XMP_ERROR_INVALID`` if parameters are invalid. .. _xmp_smix_load_sample(): int xmp_smix_load_sample(xmp_context c, int num, char \*path) ````````````````````````````````````````````````````````````` Load a sound sample from a file. Samples should be in mono WAV (RIFF) format. **Parameters:** :c: the player context handle. :num: the slot number of the external sample to load. :path: pathname of the file to load. **Returns:** 0 if the sample was correctly loaded, ``-XMP_ERROR_INVALID`` if the sample slot number is invalid (not reserved using `xmp_start_smix()`_), ``-XMP_ERROR_FORMAT`` if the file format is unsupported, or ``-XMP_ERROR_SYSTEM`` in case of system error (the system error code is set in ``errno``). .. _xmp_smix_release_sample(): int xmp_smix_release_sample(xmp_context c, int num) ``````````````````````````````````````````````````` Release memory allocated by an external sample in the specified player context. **Parameters:** :c: the player context handle. :num: the sample slot number to release. **Returns:** 0 if memory was correctly released, or ``-XMP_ERROR_INVALID`` if the sample slot number is invalid. .. _xmp_end_smix(): void xmp_end_smix(xmp_context c) ```````````````````````````````` Deinitialize and resease memory used by the external sample mixer subsystem. **Parameters:** :c: the player context handle. libxmp-4.4.1/docs/libxmp.html0000664000175000017500000022151712742416215015764 0ustar claudioclaudio Libxmp 4.4 API documentation

Libxmp 4.4 API documentation

Contents

Introduction

Libxmp is a module player library supporting many mainstream and obscure module formats including Protracker MOD, Scream Tracker III S3M and Impulse Tracker IT. Libxmp loads the module and renders the sound as linear PCM samples in a buffer at rate and format specified by the user, one frame at a time (standard modules usually play at 50 frames per second).

Possible applications for libxmp include stand-alone module players, module player plugins for other players, module information extractors, background music replayers for games and other applications, module-to-mp3 renderers, etc.

Concepts

  • Player context: Most libxmp functions require a handle that identifies the module player context. Each context is independent and multiple contexts can be defined simultaneously.
  • Sequence: Each group of positions in the order list that loops over itself, also known as "subsong". Most modules have only one sequence, but some modules, especially modules used in games can have multiple sequences. "Hidden patterns" outside the main song are also listed as extra sequences, certain module authors such as Skaven commonly place extra patterns at the end of the module.
  • State: [Added in libxmp 4.2] The player can be in one of three possible states: unloaded, loaded, or playing. The player is in unloaded state after context creation, changing to other states when a module is loaded or played.
  • External sample mixer: [Added in libxmp 4.2] Special sound channels can be reserved using xmp_start_smix() to play module instruments or external samples. This is useful when libxmp is used to provide background music to games or other applications where sound effects can be played in response to events or user actions
  • Amiga mixer: [Added in libxmp 4.4] Certain formats may use special mixers modeled after the original hardware used to play the format, providing more realistic sound at the expense of CPU usage. Currently Amiga formats such as Protracker can use a mixer modeled after the Amiga 500, with or without the led filter.

A simple example

This example loads a module, plays it at 44.1kHz and writes it to a raw sound file:

#include <stdio.h>
#include <stdlib.h>
#include <xmp.h>

int main(int argc, char **argv)
{
    xmp_context c;
    struct xmp_frame_info mi;
    FILE *f;

    /* The output raw file */
    f = fopen("out.raw", "wb");
    if (f == NULL) {
        fprintf(stderr, "can't open output file\n");
        exit(EXIT_FAILURE);
    }

    /* Create the player context */
    c = xmp_create_context();

    /* Load our module */
    if (xmp_load_module(c, argv[1]) != 0) {
        fprintf(stderr, "can't load module\n");
        exit(EXIT_FAILURE);
    }

    /* Play the module */
    xmp_start_player(c, 44100, 0);
    while (xmp_play_frame(c) == 0) {
        xmp_get_frame_info(c, &mi);

        if (mi.loop_count > 0)    /* exit before looping */
            break;

        fwrite(mi.buffer, mi.buffer_size, 1, f);  /* write audio data */
    }
    xmp_end_player(c);
    xmp_release_module(c);        /* unload module */
    xmp_free_context(c);          /* destroy the player context */

    fclose(f);

    exit(EXIT_SUCCESS);
}

A player context can load and play a single module at a time. Multiple contexts can be defined if needed.

Use xmp_test_module() to check if the file is a valid module and retrieve the module name and type. Use xmp_load_module() to load the module to memory. These two calls return 0 on success or <0 in case of error. Error codes are:

-XMP_ERROR_INTERNAL   /* Internal error */
-XMP_ERROR_FORMAT     /* Unsupported module format */
-XMP_ERROR_LOAD       /* Error loading file */
-XMP_ERROR_DEPACK     /* Error depacking file */
-XMP_ERROR_SYSTEM     /* System error */
-XMP_ERROR_STATE      /* Incorrect player state */

If a system error occurs, the specific error is set in errno.

Parameters to xmp_start_player() are the sampling rate (up to 48kHz) and a bitmapped integer holding one or more of the following mixer flags:

XMP_MIX_8BIT          /* Mix to 8-bit instead of 16 */
XMP_MIX_UNSIGNED      /* Mix to unsigned samples */
XMP_MIX_MONO          /* Mix to mono instead of stereo */
XMP_MIX_NEAREST       /* Mix using nearest neighbor interpolation */
XMP_MIX_NOFILTER      /* Disable lowpass filter */

After xmp_start_player() is called, each call to xmp_play_frame() will render an audio frame. Call xmp_get_frame_info() to retrieve the buffer address and size. xmp_play_frame() returns 0 on success or -1 if replay should stop.

Use xmp_end_player(), xmp_release_module() and xmp_free_context() to release memory and end replay.

SDL example

To use libxmp with SDL, just provide a callback function that renders module data. The module will play when SDL_PauseAudio(0) is called:

#include <SDL/SDL.h>
#include <xmp.h>

static void fill_audio(void *udata, unsigned char *stream, int len)
{
    xmp_play_buffer(udata, stream, len, 0);
}

int sound_init(xmp_context ctx, int sampling_rate, int channels)
{
    SDL_AudioSpec a;

    a.freq = sampling_rate;
    a.format = (AUDIO_S16);
    a.channels = channels;
    a.samples = 2048;
    a.callback = fill_audio;
    a.userdata = ctx;

    if (SDL_OpenAudio(&a, NULL) < 0) {
            fprintf(stderr, "%s\n", SDL_GetError());
            return -1;
    }
}

int main(int argc, char **argv)
{
    xmp_context ctx;

    if ((ctx = xmp_create_context()) == NULL)
            return 1;

    sound_init(ctx, 44100, 2);
    xmp_load_module(ctx, argv[1]);
    xmp_start_player(ctx, 44100, 0);

    SDL_PauseAudio(0);

    sleep(10);              // Do something important here

    SDL_PauseAudio(1);

    xmp_end_player(ctx);
    xmp_release_module(ctx);
    xmp_free_context(ctx);

    SDL_CloseAudio();
    return 0;
}

SDL callbacks run in a separate thread, so don't forget to protect sections that manipulate module data with SDL_LockAudio() and SDL_UnlockAudio().

API reference

Version and player information

const char *xmp_version

A string containing the library version, such as "4.0.0".

const unsigned int xmp_vercode

The library version encoded in a integer value. Bits 23-16 contain the major version number, bits 15-8 contain the minor version number, and bits 7-0 contain the release number.

char **xmp_get_format_list()

Query the list of supported module formats.

Returns:
a NULL-terminated array of strings containing the names of all supported module formats.

Context creation

xmp_context xmp_create_context()

Create a new player context and return an opaque handle to be used in subsequent accesses to this context.

Returns:
the player context handle.

void xmp_free_context(xmp_context c)

Destroy a player context previously created using xmp_create_context().

Parameters:
c:the player context handle.

Module loading

int xmp_test_module(char *path, struct xmp_test_info *test_info)

Test if a file is a valid module. Testing a file does not affect the current player context or any currently loaded module.

Parameters:
path:

pathname of the module to test.

test_info:

NULL, or a pointer to a structure used to retrieve the module title and format if the file is a valid module. struct xmp_test_info is defined as:

struct xmp_test_info {
    char name[XMP_NAME_SIZE];      /* Module title */
    char type[XMP_NAME_SIZE];      /* Module format */
};
Returns:
0 if the file is a valid module, or a negative error code in case of error. Error codes can be -XMP_ERROR_FORMAT in case of an unrecognized file format, -XMP_ERROR_DEPACK if the file is compressed and uncompression failed, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

int xmp_load_module(xmp_context c, char *path)

Load a module into the specified player context. (Certain player flags, such as XMP_PLAYER_SMPCTL and XMP_PLAYER_DEFPAN, must be set before loading the module, see xmp_set_player() for more information.)

Parameters:
c:the player context handle.
path:pathname of the module to load.
Returns:
0 if sucessful, or a negative error code in case of error. Error codes can be -XMP_ERROR_FORMAT in case of an unrecognized file format, -XMP_ERROR_DEPACK if the file is compressed and uncompression failed, -XMP_ERROR_LOAD if the file format was recognized but the file loading failed, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

int xmp_load_module_from_memory(xmp_context c, void *mem, long size)

[Added in libxmp 4.2] Load a module from memory into the specified player context.

Parameters:
c:the player context handle.
mem:a pointer to the module file image in memory. Multi-file modules or compressed modules can't be loaded from memory.
size:the size of the module, or 0 if the size is unknown or not specified. If size is set to 0 certain module formats won't be recognized, the MD5 digest will not be set, and module-specific quirks won't be applied.
Returns:
0 if sucessful, or a negative error code in case of error. Error codes can be -XMP_ERROR_FORMAT in case of an unrecognized file format, -XMP_ERROR_LOAD if the file format was recognized but the file loading failed, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

int xmp_load_module_from_file(xmp_context c, FILE *f, long size)

[Added in libxmp 4.3] Load a module from a stream into the specified player context.

Parameters:
c:the player context handle.
f:the file stream. On return, the stream position is undefined.
size:the size of the module, or 0 if the size is unknown or not specified. If size is set to 0 certain module formats won't be recognized, the MD5 digest will not be set, and module-specific quirks won't be applied.
Returns:
0 if sucessful, or a negative error code in case of error. Error codes can be -XMP_ERROR_FORMAT in case of an unrecognized file format, -XMP_ERROR_LOAD if the file format was recognized but the file loading failed, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

void xmp_release_module(xmp_context c)

Release memory allocated by a module from the specified player context.

Parameters:
c:the player context handle.

void xmp_scan_module(xmp_context c)

Scan the loaded module for sequences and timing. Scanning is automatically performed by xmp_load_module() and this function should be called only if xmp_set_player() is used to change player timing (with parameter XMP_PLAYER_VBLANK) in libxmp 4.0.2 or older.

Parameters:
c:the player context handle.

void xmp_get_module_info(xmp_context c, struct xmp_module_info *info)

Retrieve current module data.

Parameters:
c:

the player context handle.

info:

pointer to structure containing the module data. struct xmp_module_info is defined as follows:

struct xmp_module_info {
    unsigned char md5[16];          /* MD5 message digest */
    int vol_base;                   /* Volume scale */
    struct xmp_module *mod;         /* Pointer to module data */
    char *comment;                  /* Comment text, if any */
    int num_sequences;              /* Number of valid sequences */
    struct xmp_sequence *seq_data;  /* Pointer to sequence data */
};

Detailed module data is exposed in the mod field:

struct xmp_module {
    char name[XMP_NAME_SIZE];       /* Module title */
    char type[XMP_NAME_SIZE];       /* Module format */
    int pat;                        /* Number of patterns */
    int trk;                        /* Number of tracks */
    int chn;                        /* Tracks per pattern */
    int ins;                        /* Number of instruments */
    int smp;                        /* Number of samples */
    int spd;                        /* Initial speed */
    int bpm;                        /* Initial BPM */
    int len;                        /* Module length in patterns */
    int rst;                        /* Restart position */
    int gvl;                        /* Global volume */

    struct xmp_pattern **xxp;       /* Patterns */
    struct xmp_track **xxt;         /* Tracks */
    struct xmp_instrument *xxi;     /* Instruments */
    struct xmp_sample *xxs;         /* Samples */
    struct xmp_channel xxc[64];     /* Channel info */
    unsigned char xxo[XMP_MAX_MOD_LENGTH];  /* Orders */
};

See the header file for more information about pattern and instrument data.

Module playing

int xmp_start_player(xmp_context c, int rate, int format)

Start playing the currently loaded module.

Parameters:
c:

the player context handle.

rate:

the sampling rate to use, in Hz (typically 44100). Valid values range from 8kHz to 48kHz.

flags:

bitmapped configurable player flags, one or more of the following:

XMP_FORMAT_8BIT         /* Mix to 8-bit instead of 16 */
XMP_FORMAT_UNSIGNED     /* Mix to unsigned samples */
XMP_FORMAT_MONO         /* Mix to mono instead of stereo */
Returns:
0 if sucessful, or a negative error code in case of error. Error codes can be -XMP_ERROR_INTERNAL in case of a internal player error, -XMP_ERROR_INVALID if the sampling rate is invalid, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

int xmp_play_frame(xmp_context c)

Play one frame of the module. Modules usually play at 50 frames per second. Use xmp_get_frame_info() to retrieve the buffer containing audio data.

Parameters:
c:the player context handle.
Returns:
0 if sucessful, -XMP_END if the module ended or was stopped, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_play_buffer(xmp_context c, void *buffer, int size, int loop)

[Added in libxmp 4.1] Fill the buffer with PCM data up to the specified size. This is a convenience function that calls xmp_play_frame() internally to fill the user-supplied buffer. Don't call both xmp_play_frame() and xmp_play_buffer() in the same replay loop. If you don't need equally sized data chunks, xmp_play_frame() may result in better performance. Also note that silence is added at the end of a buffer if the module ends and no loop is to be performed.

Parameters:
c:the player context handle.
buffer:the buffer to fill with PCM data, or NULL to reset the internal state.
size:the buffer size in bytes.
loop:stop replay when the loop counter reaches the specified value, or 0 to disable loop checking.
Returns:
0 if sucessful, -XMP_END if module was stopped or the loop counter was reached, or -XMP_ERROR_STATE if the player is not in playing state.

void xmp_get_frame_info(xmp_context c, struct xmp_frame_info *info)

Retrieve the current frame data.

Parameters:
c:

the player context handle.

info:

pointer to structure containing current frame data. struct xmp_frame_info is defined as follows:

struct xmp_frame_info {           /* Current frame information */
    int pos;            /* Current position */
    int pattern;        /* Current pattern */
    int row;            /* Current row in pattern */
    int num_rows;       /* Number of rows in current pattern */
    int frame;          /* Current frame */
    int speed;          /* Current replay speed */
    int bpm;            /* Current bpm */
    int time;           /* Current module time in ms */
    int total_time;     /* Estimated replay time in ms*/
    int frame_time;     /* Frame replay time in us */
    void *buffer;       /* Pointer to sound buffer */
    int buffer_size;    /* Used buffer size */
    int total_size;     /* Total buffer size */
    int volume;         /* Current master volume */
    int loop_count;     /* Loop counter */
    int virt_channels;  /* Number of virtual channels */
    int virt_used;      /* Used virtual channels */
    int sequence;       /* Current sequence */

    struct xmp_channel_info {     /* Current channel information */
        unsigned int period;      /* Sample period */
        unsigned int position;    /* Sample position */
        short pitchbend;          /* Linear bend from base note*/
        unsigned char note;       /* Current base note number */
        unsigned char instrument; /* Current instrument number */
        unsigned char sample;     /* Current sample number */
        unsigned char volume;     /* Current volume */
        unsigned char pan;        /* Current stereo pan */
        unsigned char reserved;   /* Reserved */
        struct xmp_event event;   /* Current track event */
    } channel_info[XMP_MAX_CHANNELS];
};

This function should be used to retrieve sound buffer data after xmp_play_frame() is called. Fields buffer and buffer_size contain the pointer to the sound buffer PCM data and its size. The buffer size will be no larger than XMP_MAX_FRAMESIZE.

void xmp_end_player(xmp_context c)

End module replay and release player memory.

Parameters:
c:the player context handle.

Player control

int xmp_next_position(xmp_context c)

Skip replay to the start of the next position.

Parameters:
c:the player context handle.
Returns:
The new position index, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_prev_position(xmp_context c)

Skip replay to the start of the previous position.

Parameters:
c:the player context handle.
Returns:
The new position index, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_set_position(xmp_context c, int pos)

Skip replay to the start of the given position.

Parameters:
c:the player context handle.
pos:the position index to set.
Returns:
The new position index, -XMP_ERROR_INVALID of the new position is invalid or -XMP_ERROR_STATE if the player is not in playing state.

void xmp_stop_module(xmp_context c)

Stop the currently playing module.

Parameters:
c:the player context handle.

void xmp_restart_module(xmp_context c)

Restart the currently playing module.

Parameters:
c:the player context handle.

int xmp_seek_time(xmp_context c, int time)

Skip replay to the specified time.

Parameters:
c:the player context handle.
time:time to seek in milliseconds.
Returns:
The new position index, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_channel_mute(xmp_context c, int chn, int status)

Mute or unmute the specified channel.

Parameters:
c:the player context handle.
chn:the channel to mute or unmute.
status:0 to mute channel, 1 to unmute or -1 to query the current channel status.
Returns:
The previous channel status, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_channel_vol(xmp_context c, int chn, int vol)

Set or retrieve the volume of the specified channel.

Parameters:
c:the player context handle.
chn:the channel to set or get volume.
vol:a value from 0-100 to set the channel volume, or -1 to retrieve the current volume.
Returns:
The previous channel volume, or -XMP_ERROR_STATE if the player is not in playing state.

void xmp_inject_event(xmp_context c, int chn, struct xmp_event *event)

Dynamically insert a new event into a playing module.

Parameters:
c:

the player context handle.

chn:

the channel to insert the new event.

event:

the event to insert. struct xmp_event is defined as:

struct xmp_event {
    unsigned char note;   /* Note number (0 means no note) */
    unsigned char ins;    /* Patch number */
    unsigned char vol;    /* Volume (0 to basevol) */
    unsigned char fxt;    /* Effect type */
    unsigned char fxp;    /* Effect parameter */
    unsigned char f2t;    /* Secondary effect type */
    unsigned char f2p;    /* Secondary effect parameter */
    unsigned char _flag;  /* Internal (reserved) flags */
};

Player parameter setting

int xmp_set_instrument_path(xmp_context c, char *path)

Set the path to retrieve external instruments or samples. Used by some formats (such as MED2) to read sample files from a different directory in the filesystem.

Parameters:
c:the player context handle.
path:the path to retrieve instrument files.
Returns:
0 if the instrument path was correctly set, or -XMP_ERROR_SYSTEM in case of error (the system error code is set in errno).

int xmp_get_player(xmp_context c, int param)

Retrieve current value of the specified player parameter.

Parameters:
c:

the player context handle.

param:

player parameter to get. Valid parameters are:

XMP_PLAYER_AMP         /* Amplification factor */
XMP_PLAYER_MIX         /* Stereo mixing */
XMP_PLAYER_INTERP      /* Interpolation type */
XMP_PLAYER_DSP         /* DSP effect flags */
XMP_PLAYER_FLAGS       /* Player flags */
XMP_PLAYER_CFLAGS      /* Player flags for current module*/
XMP_PLAYER_SMPCTL      /* Control sample loading */
XMP_PLAYER_VOLUME      /* Player master volume */
XMP_PLAYER_STATE       /* Current player state (read only) */
XMP_PLAYER_SMIX_VOLUME /* SMIX Volume */
XMP_PLAYER_DEFPAN      /* Default pan separation */
XMP_PLAYER_MODE        /* Player personality */
XMP_PLAYER_MIXER_TYPE  /* Current mixer (read only) */
XMP_PLAYER_VOICES      /* Maximum number of mixer voices */

Valid states are:

XMP_STATE_UNLOADED     /* Context created */
XMP_STATE_LOADED       /* Module loaded */
XMP_STATE_PLAYING      /* Module playing */

Valid mixer types are:

XMP_MIXER_STANDARD      /* Standard mixer */
XMP_MIXER_A500          /* Amiga 500 */
XMP_MIXER_A500F         /* Amiga 500 with led filter */

See xmp_set_player for the rest of valid values for each parameter.

Returns:
The parameter value, or -XMP_ERROR_STATE if the parameter is not XMP_PLAYER_STATE and the player is not in playing state.

int xmp_set_player(xmp_context c, int param, int val)

Set player parameter with the specified value.

Parameters:
param:

player parameter to set. Valid parameters are:

XMP_PLAYER_AMP         /* Amplification factor */
XMP_PLAYER_MIX         /* Stereo mixing */
XMP_PLAYER_INTERP      /* Interpolation type */
XMP_PLAYER_DSP         /* DSP effect flags */
XMP_PLAYER_FLAGS       /* Player flags */
XMP_PLAYER_CFLAGS      /* Player flags for current module*/
XMP_PLAYER_SMPCTL      /* Control sample loading */
XMP_PLAYER_VOLUME      /* Player master volume */
XMP_PLAYER_SMIX_VOLUME /* SMIX Volume */
XMP_PLAYER_DEFPAN      /* Default pan separation */
XMP_PLAYER_MODE        /* Player personality */
XMP_PLAYER_VOICES      /* Maximum number of mixer voices */
val:

the value to set. Valid values depend on the parameter being set.

Valid values:

  • Amplification factor: ranges from 0 to 3. Default value is 1.

  • Stereo mixing: percentual left/right channel separation. Default is 70.

  • Interpolation type: can be one of the following values:

    XMP_INTERP_NEAREST  /* Nearest neighbor */
    XMP_INTERP_LINEAR   /* Linear (default) */
    XMP_INTERP_SPLINE   /* Cubic spline */
    
  • DSP effects flags: enable or disable DSP effects. Valid effects are:

    XMP_DSP_LOWPASS     /* Lowpass filter effect */
    XMP_DSP_ALL         /* All effects */
    
  • Player flags: tweakable player parameters. Valid flags are:

    XMP_FLAGS_VBLANK    /* Use vblank timing */
    XMP_FLAGS_FX9BUG    /* Emulate Protracker 2.x FX9 bug */
    XMP_FLAGS_FIXLOOP   /* Make sample loop value / 2 */
    XMP_FLAGS_A500      /* Use Paula mixer in Amiga modules */
    
  • [Added in libxmp 4.1] Player flags for current module: same flags as above but after applying module-specific quirks (if any).

  • [Added in libxmp 4.1] Sample control: Valid values are:

    XMP_SMPCTL_SKIP     /* Don't load samples */
    
  • Disabling sample loading when loading a module allows allows computation of module duration without decompressing and loading large sample data, and is useful when duration information is needed for a module that won't be played immediately.

  • [Added in libxmp 4.2] Player volumes: Set the player master volume or the external sample mixer master volume. Valid values are 0 to 100.

  • [Added in libxmp 4.3] Default pan separation: percentual left/right pan separation in formats with only left and right channels. Default is 100%.

  • [Added in libxmp 4.4] Player personality: The player can be forced to emulate a specific tracker in cases where the module relies on a format quirk and tracker detection fails. Valid modes are:

    XMP_MODE_AUTO         /* Autodetect mode (default) */
    XMP_MODE_MOD          /* Play as a generic MOD player */
    XMP_MODE_NOISETRACKER /* Play using Noisetracker quirks */
    XMP_MODE_PROTRACKER   /* Play using Protracker 1/2 quirks */
    XMP_MODE_S3M          /* Play as a generic S3M player */
    XMP_MODE_ST3          /* Play using ST3 bug emulation */
    XMP_MODE_ST3GUS       /* Play using ST3+GUS quirks */
    XMP_MODE_XM           /* Play as a generic XM player */
    XMP_MODE_FT2          /* Play using FT2 bug emulation */
    XMP_MODE_IT           /* Play using IT quirks */
    XMP_MODE_ITSMP        /* Play using IT sample mode quirks */
    

    By default, formats similar to S3M such as PTM or IMF will use S3M replayer (without Scream Tracker 3 quirks/bug emulation), and formats similar to XM such as RTM and MDL will use the XM replayer (without FT2 quirks/bug emulation).

    Multichannel MOD files will use the XM replayer, and Scream Tracker 3 MOD files will use S3M replayer with ST3 quirks. S3M files will use the most appropriate replayer according to the tracker used to create the file, and enable Scream Tracker 3 quirks and bugs only if created using ST3. XM files will be played with FT2 bugs and quirks only if created using Fast Tracker II.

    Modules created with OpenMPT will be played with all bugs and quirks of the original trackers.

  • [Added in libxmp 4.4] Maximum number of mixer voices: the maximum number of virtual channels that can be used to play the module. If set too high, modules with voice leaks can cause excessive CPU usage. Default is 128.

Returns:
0 if parameter was correctly set, -XMP_ERROR_INVALID if parameter or values are out of the valid ranges, or -XMP_ERROR_STATE if the player is not in playing state.

External sample mixer API

Libxmp 4.2 includes a mini-API that can be used to add sound effects to games and similar applications, provided that you have a low latency sound system. It allows module instruments or external sample files in WAV format to be played in response to arbitrary events.

Example

This example using SDL loads a module and a sound sample, plays the module as background music, and plays the sample when a key is pressed:

#include <SDL/SDL.h>
#include <xmp.h>

static void fill_audio(void *udata, unsigned char *stream, int len)
{
    xmp_play_buffer(udata, stream, len, 0);
}

int sound_init(xmp_context ctx, int sampling_rate, int channels)
{
    SDL_AudioSpec a;

    a.freq = sampling_rate;
    a.format = (AUDIO_S16);
    a.channels = channels;
    a.samples = 2048;
    a.callback = fill_audio;
    a.userdata = ctx;

    if (SDL_OpenAudio(&a, NULL) < 0) {
            fprintf(stderr, "%s\n", SDL_GetError());
            return -1;
    }
}

int video_init()
{
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "%s\n", SDL_GetError());
        return -1;
    }
    if (SDL_SetVideoMode(640, 480, 8, 0) == NULL) {
        fprintf(stderr, "%s\n", SDL_GetError());
        return -1;
    }
    atexit(SDL_Quit);
}

int main(int argc, char **argv)
{
    SDL_Event event;
    xmp_context ctx;

    if ((ctx = xmp_create_context()) == NULL)
            return 1;

    video_init();
    sound_init(ctx, 44100, 2);

    xmp_start_smix(ctx, 1, 1);
    xmp_smix_load_sample(ctx, 0, "blip.wav");

    xmp_load_module(ctx, "music.mod");
    xmp_start_player(ctx, 44100, 0);
    xmp_set_player(ctx, XMP_PLAYER_VOLUME, 40);

    SDL_PauseAudio(0);

    while (1) {
        if (SDL_WaitEvent(&event)) {
            if (event.type == SDL_KEYDOWN) {
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    break;
                xmp_smix_play_sample(ctx, 0, 60, 64, 0);
            }
        }
    }

    SDL_PauseAudio(1);

    xmp_end_player(ctx);
    xmp_release_module(ctx);
    xmp_free_context(ctx);
    xmp_end_smix(ctx);

    SDL_CloseAudio();
    return 0;
}

SMIX API reference

int xmp_start_smix(xmp_context c, int nch, int nsmp)

Initialize the external sample mixer subsystem with the given number of reserved channels and samples.

Parameters:
c:the player context handle.
nch:number of reserved sound mixer channels (1 to 64).
nsmp:number of external samples.
Returns:
0 if the external sample mixer system was correctly initialized, -XMP_ERROR_INVALID in case of invalid parameters, -XMP_ERROR_STATE if the player is already in playing state, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

int xmp_smix_play_instrument(xmp_context c, int ins, int note, int vol, int chn)

Play a note using an instrument from the currently loaded module in one of the reserved sound mixer channels.

Parameters:
c:the player context handle.
ins:the instrument to play.
note:the note number to play (60 = middle C).
vol:the volume to use (range: 0 to the maximum volume value used by the current module).
chn:the reserved channel to use to play the instrument.
Returns:
0 if the instrument was correctly played, -XMP_ERROR_INVALID in case of invalid parameters, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_smix_play_sample(xmp_context c, int ins, int vol, int chn)

Play an external sample file in one of the reserved sound channels. The sample must have been previously loaded using xmp_smix_load_sample().

Parameters:
c:the player context handle.
ins:the sample to play.
vol:the volume to use (0 to the maximum volume value used by the current module.
chn:the reserved channel to use to play the sample.
Returns:
0 if the sample was correctly played, -XMP_ERROR_INVALID in case of invalid parameters, or -XMP_ERROR_STATE if the player is not in playing state.

int xmp_smix_channel_pan(xmp_context c, int chn, int pan)

Set the reserved channel pan value.

Parameters:
c:the player context handle.
chn:the reserved channel number.
pan:the pan value to set (0 to 255).
Returns:
0 if the pan value was set, or -XMP_ERROR_INVALID if parameters are invalid.

int xmp_smix_load_sample(xmp_context c, int num, char *path)

Load a sound sample from a file. Samples should be in mono WAV (RIFF) format.

Parameters:
c:the player context handle.
num:the slot number of the external sample to load.
path:pathname of the file to load.
Returns:
0 if the sample was correctly loaded, -XMP_ERROR_INVALID if the sample slot number is invalid (not reserved using xmp_start_smix()), -XMP_ERROR_FORMAT if the file format is unsupported, or -XMP_ERROR_SYSTEM in case of system error (the system error code is set in errno).

int xmp_smix_release_sample(xmp_context c, int num)

Release memory allocated by an external sample in the specified player context.

Parameters:
c:the player context handle.
num:the sample slot number to release.
Returns:
0 if memory was correctly released, or -XMP_ERROR_INVALID if the sample slot number is invalid.

void xmp_end_smix(xmp_context c)

Deinitialize and resease memory used by the external sample mixer subsystem.

Parameters:
c:the player context handle.
libxmp-4.4.1/docs/custom.style0000664000175000017500000003014512742415254016174 0ustar claudioclaudio # List any fonts you would like to embed in the PDF here embeddedFonts: [] # Default page setup. Can be overridden by including other # stylesheets with -s pageSetup: size: A4 # firstTemplate: coverPage margin-bottom: 8mm margin-left: 12mm margin-right: 12mm margin-top: 8mm margin-gutter: 0cm spacing-header: 5mm spacing-footer: 5mm # The first template is one of the 'pageTemplates" # (See next section) firstTemplate: oneColumn # pageTemplates can be accessed with the .. raw:: pdf PageBreak command pageTemplates: coverPage: frames: [] [0cm, 0cm, 100%, 100%] showHeader : false showFooter : false emptyPage: frames: [] [0cm, 0cm, 100%, 100%] showHeader : false showFooter : false oneColumn: frames: [] [0cm, 0cm, 100%, 100%] showHeader : true showFooter : true twoColumn: frames: [] [0cm, 0cm, 49%, 100%] [51%, 0cm, 49%, 100%] showHeader : true showFooter : true threeColumn: frames: [] [2%, 0cm, 29.333%, 100%] [35.333%, 0cm, 29.333%, 100%] [68.666%, 0cm, 29.333%, 100%] showHeader : true showFooter : true cutePage: frames: [] [0%, 0%, 100%, 100%] showHeader : true showFooter : true defaultFooter : ###Page### defaultHeader : ###Section### fontsAlias: stdFont: Helvetica stdBold: Helvetica-Bold stdItalic: Helvetica-Oblique stdBoldItalic: Helvetica-BoldOblique stdSans: Helvetica stdSansBold: Helvetica-Bold stdSansItalic: Helvetica-Oblique stdSansBoldItalic: Helvetica-BoldOblique stdMono: Courier stdMonoItalic: Courier-Oblique stdMonoBold: Courier-Bold stdMonoBoldItalic: Courier-BoldOblique stdSerif: Times-Roman linkColor: darkgreen styles: base: parent: null fontName: stdFont fontSize: 10 leading: 12 leftIndent: 0 rightIndent: 0 firstLineIndent: 0 alignment: TA_LEFT spaceBefore: 0 spaceAfter: 0 bulletFontName: stdFont bulletFontSize: 10 bulletIndent: 0 textColor: black backColor: null wordWrap: null borderWidth: 0 borderPadding: 0 borderColor: null borderRadius: null allowWidows: 3 allowOrphans: 3 hyphenation: false kerning: false underline: false strike: false commands: [] normal: parent: base title-reference: parent: heading fontName: stdBold bodytext: parent: normal spaceBefore: 8 alignment: TA_JUSTIFY hyphenation: true toc: parent: normal leading: 9 blockquote: parent: bodytext leftIndent: 20 lineblock: parent: bodytext line: parent: lineblock spaceBefore: 0 toc1: parent: toc fontName: stdBold toc2: parent: toc leftIndent: 20 toc3: parent: toc leading: 7 leftIndent: 40 fontSize: 90% spaceAfter: 0 spaceBefore: 0 toc4: parent: toc leftIndent: 60 toc5: parent: toc leftIndent: 80 toc6: parent: toc leftIndent: 100 toc7: parent: toc leftIndent: 100 toc8: parent: toc leftIndent: 100 toc9: parent: toc leftIndent: 100 toc10: parent: toc leftIndent: 100 toc11: parent: toc leftIndent: 100 toc12: parent: toc leftIndent: 100 toc13: parent: toc leftIndent: 100 toc14: parent: toc leftIndent: 100 toc15: parent: toc leftIndent: 100 footer: parent: normal alignment: TA_CENTER header: parent: normal alignment: TA_CENTER attribution: parent: bodytext alignment: TA_RIGHT figure: parent: bodytext alignment: TA_CENTER commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [ALIGN, [ 0, 0 ], [ -1, -1 ], CENTER ] colWidths: [100%] figure-caption: parent: bodytext fontName: stdItalic alignment: TA_CENTER figure-legend: parent: bodytext bullet-list: parent: bodytext commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [RIGHTPADDING, [ 0, 0 ], [ 1, -1 ], 0 ] colWidths: ["20", null] bullet-list-item: parent: bodytext item-list: parent: bodytext commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [RIGHTPADDING, [ 0, 0 ], [ 1, -1 ], 0 ] colWidths: [20pt,null] item-list-item: parent: bodytext definition-list-term: parent: normal fontName: stdBold spaceBefore: 4 spaceAfter: 0 keepWithNext: false definition-list-classifier: parent: normal fontName: stdItalic definition: parent: bodytext firstLineIndent: 0 bulletIndent: 0 spaceBefore: 0 colWidths: [20pt,null] commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [LEFTPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] [BOTTOMPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] [RIGHTPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] fieldname: parent: bodytext alignment: TA_RIGHT fontName: stdBold fieldvalue: parent: bodytext rubric: parent: bodytext textColor: darkred alignment: TA_CENTER italic: parent: bodytext fontName: stdItalic heading: parent: normal keepWithNext: true spaceBefore: 12 spaceAfter: 6 textColor: #20435C title: parent: heading fontName: stdBold fontSize: 200% alignment: TA_CENTER keepWithNext: false spaceAfter: 10 subtitle: parent: title spaceBefore: 12 fontSize: 75% heading1: parent: heading fontName: stdBold fontSize: 175% spaceBefore: 24 heading2: parent: heading fontName: stdBold fontSize: 150% spaceBefore: 20 heading3: parent: heading fontName: stdBold fontSize: 125% spaceBefore: 16 heading4: parent: heading fontName: stdBold heading5: parent: heading fontName: stdBold heading6: parent: heading fontName: stdBold topic-title: parent: heading3 sidebar-title: parent: heading3 sidebar-subtitle: parent: heading4 sidebar: float: none width: 100% parent: normal backColor: beige borderColor: darkgray borderPadding: 8 borderWidth: 0.5 admonition: parent: normal spaceBefore: 12 spaceAfter: 6 borderPadding: [16,16,16,16] backColor: beige borderColor: darkgray borderWidth: 0.5 commands:[] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] attention: parent: admonition caution: parent: admonition danger: parent: admonition error: parent: admonition hint: parent: admonition important: parent: admonition note: parent: admonition tip: parent: admonition warning: parent: admonition admonition-title: parent: heading3 admonition-heading: parent: heading3 attention-heading: parent: admonition-heading caution-heading: parent: admonition-heading danger-heading: parent: admonition-heading error-heading: parent: admonition-heading hint-heading: parent: admonition-heading important-heading: parent: admonition-heading note-heading: parent: admonition-heading tip-heading: parent: admonition-heading warning-heading: parent: admonition-heading literal: parent: normal fontName: stdMono firstLineIndent: 0 hyphenation: false wordWrap: null aafigure: parent: literal table: spaceBefore:6 spaceAfter:0 alignment: TA_CENTER commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [INNERGRID, [ 0, 0 ], [ -1, -1 ], 0.25, black ] [ROWBACKGROUNDS, [0, 0], [-1, -1], [white,#E0E0E0]] [BOX, [ 0, 0 ], [ -1, -1 ], 0.25, black ] table-title: parent : heading4 keepWithNext: false alignment : TA_CENTER table-heading: parent : heading backColor : beige alignment : TA_CENTER valign : BOTTOM borderPadding : 0 table-body: parent : normal dedication: parent : normal abstract: parent : normal contents: parent : normal tableofcontents: parent : normal code: parent: literal leftIndent: 0 spaceBefore: 8 spaceAfter: 8 borderWidth: 0.5 borderPadding: 6 allowOrphans: 4 allowWidows: 4 backColor: #EEEEFF borderColor: #AA99CC borderPadding: [2, 2, 2, 2] borderWidth: 0.3 linenumber: parent: code right: parent: bodytext alignment: right center: parent: bodytext alignment: center pygments-n: parent: code pygments-nx: parent: code pygments-p: parent: code pygments-hll: {parent: code, backColor: #ffffcc} pygments-c: {textColor: #008800, parent: code} pygments-err: {parent: code} pygments-k: {textColor: #AA22FF, parent: code} pygments-o: {textColor: #666666, parent: code} pygments-cm: {textColor: #008800, parent: code} pygments-cp: {textColor: #008800, parent: code} pygments-c1: {textColor: #008800, parent: code} pygments-cs: {textColor: #008800, parent: code} pygments-gd: {textColor: #A00000, parent: code} pygments-ge: {parent: code} pygments-gr: {textColor: #FF0000, parent: code} pygments-gh: {textColor: #000080, parent: code} pygments-gi: {textColor: #00A000, parent: code} pygments-go: {textColor: #808080, parent: code} pygments-gp: {textColor: #000080, parent: code} pygments-gs: {parent: code} pygments-gu: {textColor: #800080, parent: code} pygments-gt: {textColor: #0040D0, parent: code} pygments-kc: {textColor: #AA22FF, parent: code} pygments-kd: {textColor: #AA22FF, parent: code} pygments-kn: {textColor: #AA22FF, parent: code} pygments-kp: {textColor: #AA22FF, parent: code} pygments-kr: {textColor: #AA22FF, parent: code} pygments-kt: {textColor: #00BB00, parent: code} pygments-m: {textColor: #666666, parent: code} pygments-s: {textColor: #BB4444, parent: code} pygments-na: {textColor: #BB4444, parent: code} pygments-nb: {textColor: #AA22FF, parent: code} pygments-nc: {textColor: #0000FF, parent: code} pygments-no: {textColor: #880000, parent: code} pygments-nd: {textColor: #AA22FF, parent: code} pygments-ni: {textColor: #999999, parent: code} pygments-ne: {textColor: #D2413A, parent: code} pygments-nf: {textColor: #00A000, parent: code} pygments-nl: {textColor: #A0A000, parent: code} pygments-nn: {textColor: #0000FF, parent: code} pygments-nt: {textColor: #008000, parent: code} pygments-nv: {textColor: #B8860B, parent: code} pygments-ow: {textColor: #AA22FF, parent: code} pygments-w: {textColor: #bbbbbb, parent: code} pygments-mf: {textColor: #666666, parent: code} pygments-mh: {textColor: #666666, parent: code} pygments-mi: {textColor: #666666, parent: code} pygments-mo: {textColor: #666666, parent: code} pygments-sb: {textColor: #BB4444, parent: code} pygments-sc: {textColor: #BB4444, parent: code} pygments-sd: {textColor: #BB4444, parent: code} pygments-s2: {textColor: #BB4444, parent: code} pygments-se: {textColor: #BB6622, parent: code} pygments-sh: {textColor: #BB4444, parent: code} pygments-si: {textColor: #BB6688, parent: code} pygments-sx: {textColor: #008000, parent: code} pygments-sr: {textColor: #BB6688, parent: code} pygments-s1: {textColor: #BB4444, parent: code} pygments-ss: {textColor: #B8860B, parent: code} pygments-bp: {textColor: #AA22FF, parent: code} pygments-vc: {textColor: #B8860B, parent: code} pygments-vg: {textColor: #B8860B, parent: code} pygments-vi: {textColor: #B8860B, parent: code} pygments-il: {textColor: #666666, parent: code} endnote: parent: bodytext commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [TOPPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] [BOTTOMPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] [RIGHTPADDING, [ 0, 0 ], [ 1, -1 ], 0 ] colWidths: [3cm, null] field-list: parent: bodytext commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [TOPPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] colWidths: [1.6cm, null] spaceBefore: 6 option-list: commands: [] [VALIGN, [ 0, 0 ], [ -1, -1 ], TOP ] [TOPPADDING, [ 0, 0 ], [ -1, -1 ], 0 ] colWidths: [null,null] libxmp-4.4.1/docs/Makefile0000664000175000017500000000200012742415254015225 0ustar claudioclaudio DOCS_DFILES = Makefile COPYING.LIB CREDITS Changelog formats.txt \ fixloop.txt libxmp.rst custom.style $(DOCS_FILES) DOCS_PATH = docs DOCS_FILES = libxmp.html libxmp.3 libxmp.pdf DOCS += $(addprefix $(DOCS_PATH)/,$(DOCS_FILES)) all-docs: $(DOCS) $(DOCS): docs/Makefile install-docs: $(DOCS) @echo "Installing manpages in $(DESTDIR)$(MANDIR)" @[ -d $(DESTDIR)$(MANDIR) ] || mkdir -p $(DESTDIR)$(MANDIR) @$(INSTALL_DATA) docs/libxmp.3 $(DESTDIR)$(MANDIR) dist-docs: mkdir -p $(DIST)/$(DOCS_PATH) cp -RPp $(addprefix $(DOCS_PATH)/,$(DOCS_DFILES)) $(DIST)/$(DOCS_PATH) docs/libxmp.3: docs/libxmp.man.rst rst2man docs/libxmp.man.rst > $@ docs/libxmp.man.rst: docs/libxmp.rst docs/manpage-header.rst docs/Makefile cp docs/manpage-header.rst $@ sed -n '/^Introduction/,$$p' docs/libxmp.rst >> $@ docs/libxmp.html: docs/libxmp.rst rst2html docs/libxmp.rst > $@ docs/libxmp.pdf: docs/libxmp.rst docs/custom.style rst2pdf docs/libxmp.rst -c --smart-quotes=1 -s docs/custom.style --footer="###Page###" -o $@ libxmp-4.4.1/docs/libxmp.30000664000175000017500000011323512742416215015157 0ustar claudioclaudio.\" Man page generated from reStructuredText. . .TH LIBXMP 3 "Nov 2013" "4.2" "Extended Module Player" .SH NAME libxmp \- A tracker module player library . .nr rst2man-indent-level 0 . .de1 rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de1 INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH INTRODUCTION .sp Libxmp is a module player library supporting many mainstream and obscure module formats including Protracker MOD, Scream Tracker III S3M and Impulse Tracker IT. Libxmp loads the module and renders the sound as linear PCM samples in a buffer at rate and format specified by the user, one frame at a time (standard modules usually play at 50 frames per second). .sp Possible applications for libxmp include stand\-alone module players, module player plugins for other players, module information extractors, background music replayers for games and other applications, module\-to\-mp3 renderers, etc. .SS Concepts .INDENT 0.0 .IP \(bu 2 \fBPlayer context:\fP Most libxmp functions require a handle that identifies the module player context. Each context is independent and multiple contexts can be defined simultaneously. .IP \(bu 2 \fBSequence:\fP Each group of positions in the order list that loops over itself, also known as "subsong". Most modules have only one sequence, but some modules, especially modules used in games can have multiple sequences. "Hidden patterns" outside the main song are also listed as extra sequences, certain module authors such as Skaven commonly place extra patterns at the end of the module. .IP \(bu 2 \fBState:\fP \fI[Added in libxmp 4.2]\fP The player can be in one of three possible states: \fIunloaded\fP, \fIloaded\fP, or \fIplaying\fP\&. The player is in unloaded state after context creation, changing to other states when a module is loaded or played. .IP \(bu 2 \fBExternal sample mixer:\fP \fI[Added in libxmp 4.2]\fP Special sound channels can be reserved using \fIxmp_start_smix()\fP to play module instruments or external samples. This is useful when libxmp is used to provide background music to games or other applications where sound effects can be played in response to events or user actions .IP \(bu 2 \fBAmiga mixer:\fP \fI[Added in libxmp 4.4]\fP Certain formats may use special mixers modeled after the original hardware used to play the format, providing more realistic sound at the expense of CPU usage. Currently Amiga formats such as Protracker can use a mixer modeled after the Amiga 500, with or without the led filter. .UNINDENT .SS A simple example .sp This example loads a module, plays it at 44.1kHz and writes it to a raw sound file: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C #include #include #include int main(int argc, char **argv) { xmp_context c; struct xmp_frame_info mi; FILE *f; /* The output raw file */ f = fopen("out.raw", "wb"); if (f == NULL) { fprintf(stderr, "can\(aqt open output file\en"); exit(EXIT_FAILURE); } /* Create the player context */ c = xmp_create_context(); /* Load our module */ if (xmp_load_module(c, argv[1]) != 0) { fprintf(stderr, "can\(aqt load module\en"); exit(EXIT_FAILURE); } /* Play the module */ xmp_start_player(c, 44100, 0); while (xmp_play_frame(c) == 0) { xmp_get_frame_info(c, &mi); if (mi.loop_count > 0) /* exit before looping */ break; fwrite(mi.buffer, mi.buffer_size, 1, f); /* write audio data */ } xmp_end_player(c); xmp_release_module(c); /* unload module */ xmp_free_context(c); /* destroy the player context */ fclose(f); exit(EXIT_SUCCESS); } .ft P .fi .UNINDENT .UNINDENT .sp A player context can load and play a single module at a time. Multiple contexts can be defined if needed. .sp Use \fI\%xmp_test_module()\fP to check if the file is a valid module and retrieve the module name and type. Use \fI\%xmp_load_module()\fP to load the module to memory. These two calls return 0 on success or <0 in case of error. Error codes are: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C \-XMP_ERROR_INTERNAL /* Internal error */ \-XMP_ERROR_FORMAT /* Unsupported module format */ \-XMP_ERROR_LOAD /* Error loading file */ \-XMP_ERROR_DEPACK /* Error depacking file */ \-XMP_ERROR_SYSTEM /* System error */ \-XMP_ERROR_STATE /* Incorrect player state */ .ft P .fi .UNINDENT .UNINDENT .sp If a system error occurs, the specific error is set in \fBerrno\fP\&. .sp Parameters to \fI\%xmp_start_player()\fP are the sampling rate (up to 48kHz) and a bitmapped integer holding one or more of the following mixer flags: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C XMP_MIX_8BIT /* Mix to 8\-bit instead of 16 */ XMP_MIX_UNSIGNED /* Mix to unsigned samples */ XMP_MIX_MONO /* Mix to mono instead of stereo */ XMP_MIX_NEAREST /* Mix using nearest neighbor interpolation */ XMP_MIX_NOFILTER /* Disable lowpass filter */ .ft P .fi .UNINDENT .UNINDENT .sp After \fI\%xmp_start_player()\fP is called, each call to \fI\%xmp_play_frame()\fP will render an audio frame. Call \fI\%xmp_get_frame_info()\fP to retrieve the buffer address and size. \fI\%xmp_play_frame()\fP returns 0 on success or \-1 if replay should stop. .sp Use \fI\%xmp_end_player()\fP, \fI\%xmp_release_module()\fP and \fI\%xmp_free_context()\fP to release memory and end replay. .SS SDL example .sp To use libxmp with SDL, just provide a callback function that renders module data. The module will play when \fBSDL_PauseAudio(0)\fP is called: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C #include #include static void fill_audio(void *udata, unsigned char *stream, int len) { xmp_play_buffer(udata, stream, len, 0); } int sound_init(xmp_context ctx, int sampling_rate, int channels) { SDL_AudioSpec a; a.freq = sampling_rate; a.format = (AUDIO_S16); a.channels = channels; a.samples = 2048; a.callback = fill_audio; a.userdata = ctx; if (SDL_OpenAudio(&a, NULL) < 0) { fprintf(stderr, "%s\en", SDL_GetError()); return \-1; } } int main(int argc, char **argv) { xmp_context ctx; if ((ctx = xmp_create_context()) == NULL) return 1; sound_init(ctx, 44100, 2); xmp_load_module(ctx, argv[1]); xmp_start_player(ctx, 44100, 0); SDL_PauseAudio(0); sleep(10); // Do something important here SDL_PauseAudio(1); xmp_end_player(ctx); xmp_release_module(ctx); xmp_free_context(ctx); SDL_CloseAudio(); return 0; } .ft P .fi .UNINDENT .UNINDENT .sp SDL callbacks run in a separate thread, so don\(aqt forget to protect sections that manipulate module data with \fBSDL_LockAudio()\fP and \fBSDL_UnlockAudio()\fP\&. .SH API REFERENCE .SS Version and player information .SS const char *xmp_version .INDENT 0.0 .INDENT 3.5 A string containing the library version, such as "4.0.0". .UNINDENT .UNINDENT .SS const unsigned int xmp_vercode .INDENT 0.0 .INDENT 3.5 The library version encoded in a integer value. Bits 23\-16 contain the major version number, bits 15\-8 contain the minor version number, and bits 7\-0 contain the release number. .UNINDENT .UNINDENT .SS char **xmp_get_format_list() .INDENT 0.0 .INDENT 3.5 Query the list of supported module formats. .INDENT 0.0 .TP .B \fBReturns:\fP a NULL\-terminated array of strings containing the names of all supported module formats. .UNINDENT .UNINDENT .UNINDENT .SS Context creation .SS xmp_context xmp_create_context() .INDENT 0.0 .INDENT 3.5 Create a new player context and return an opaque handle to be used in subsequent accesses to this context. .INDENT 0.0 .TP .B \fBReturns:\fP the player context handle. .UNINDENT .UNINDENT .UNINDENT .SS void xmp_free_context(xmp_context c) .INDENT 0.0 .INDENT 3.5 Destroy a player context previously created using \fI\%xmp_create_context()\fP\&. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS Module loading .SS int xmp_test_module(char *path, struct xmp_test_info *test_info) .INDENT 0.0 .INDENT 3.5 Test if a file is a valid module. Testing a file does not affect the current player context or any currently loaded module. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B path pathname of the module to test. .TP .B test_info NULL, or a pointer to a structure used to retrieve the module title and format if the file is a valid module. \fBstruct xmp_test_info\fP is defined as: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C struct xmp_test_info { char name[XMP_NAME_SIZE]; /* Module title */ char type[XMP_NAME_SIZE]; /* Module format */ }; .ft P .fi .UNINDENT .UNINDENT .UNINDENT .TP .B \fBReturns:\fP 0 if the file is a valid module, or a negative error code in case of error. Error codes can be \fB\-XMP_ERROR_FORMAT\fP in case of an unrecognized file format, \fB\-XMP_ERROR_DEPACK\fP if the file is compressed and uncompression failed, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_load_module(xmp_context c, char *path) .INDENT 0.0 .INDENT 3.5 Load a module into the specified player context. (Certain player flags, such as \fBXMP_PLAYER_SMPCTL\fP and \fBXMP_PLAYER_DEFPAN\fP, must be set before loading the module, see \fI\%xmp_set_player()\fP for more information.) .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B path pathname of the module to load. .UNINDENT .TP .B \fBReturns:\fP 0 if sucessful, or a negative error code in case of error. Error codes can be \fB\-XMP_ERROR_FORMAT\fP in case of an unrecognized file format, \fB\-XMP_ERROR_DEPACK\fP if the file is compressed and uncompression failed, \fB\-XMP_ERROR_LOAD\fP if the file format was recognized but the file loading failed, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_load_module_from_memory(xmp_context c, void *mem, long size) .INDENT 0.0 .INDENT 3.5 \fI[Added in libxmp 4.2]\fP Load a module from memory into the specified player context. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B mem a pointer to the module file image in memory. Multi\-file modules or compressed modules can\(aqt be loaded from memory. .TP .B size the size of the module, or 0 if the size is unknown or not specified. If size is set to 0 certain module formats won\(aqt be recognized, the MD5 digest will not be set, and module\-specific quirks won\(aqt be applied. .UNINDENT .TP .B \fBReturns:\fP 0 if sucessful, or a negative error code in case of error. Error codes can be \fB\-XMP_ERROR_FORMAT\fP in case of an unrecognized file format, \fB\-XMP_ERROR_LOAD\fP if the file format was recognized but the file loading failed, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_load_module_from_file(xmp_context c, FILE *f, long size) .INDENT 0.0 .INDENT 3.5 \fI[Added in libxmp 4.3]\fP Load a module from a stream into the specified player context. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B f the file stream. On return, the stream position is undefined. .TP .B size the size of the module, or 0 if the size is unknown or not specified. If size is set to 0 certain module formats won\(aqt be recognized, the MD5 digest will not be set, and module\-specific quirks won\(aqt be applied. .UNINDENT .TP .B \fBReturns:\fP 0 if sucessful, or a negative error code in case of error. Error codes can be \fB\-XMP_ERROR_FORMAT\fP in case of an unrecognized file format, \fB\-XMP_ERROR_LOAD\fP if the file format was recognized but the file loading failed, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS void xmp_release_module(xmp_context c) .INDENT 0.0 .INDENT 3.5 Release memory allocated by a module from the specified player context. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS void xmp_scan_module(xmp_context c) .INDENT 0.0 .INDENT 3.5 Scan the loaded module for sequences and timing. Scanning is automatically performed by \fI\%xmp_load_module()\fP and this function should be called only if \fI\%xmp_set_player()\fP is used to change player timing (with parameter \fBXMP_PLAYER_VBLANK\fP) in libxmp 4.0.2 or older. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS void xmp_get_module_info(xmp_context c, struct xmp_module_info *info) .INDENT 0.0 .INDENT 3.5 Retrieve current module data. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B info pointer to structure containing the module data. \fBstruct xmp_module_info\fP is defined as follows: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C struct xmp_module_info { unsigned char md5[16]; /* MD5 message digest */ int vol_base; /* Volume scale */ struct xmp_module *mod; /* Pointer to module data */ char *comment; /* Comment text, if any */ int num_sequences; /* Number of valid sequences */ struct xmp_sequence *seq_data; /* Pointer to sequence data */ }; .ft P .fi .UNINDENT .UNINDENT .sp Detailed module data is exposed in the \fBmod\fP field: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C struct xmp_module { char name[XMP_NAME_SIZE]; /* Module title */ char type[XMP_NAME_SIZE]; /* Module format */ int pat; /* Number of patterns */ int trk; /* Number of tracks */ int chn; /* Tracks per pattern */ int ins; /* Number of instruments */ int smp; /* Number of samples */ int spd; /* Initial speed */ int bpm; /* Initial BPM */ int len; /* Module length in patterns */ int rst; /* Restart position */ int gvl; /* Global volume */ struct xmp_pattern **xxp; /* Patterns */ struct xmp_track **xxt; /* Tracks */ struct xmp_instrument *xxi; /* Instruments */ struct xmp_sample *xxs; /* Samples */ struct xmp_channel xxc[64]; /* Channel info */ unsigned char xxo[XMP_MAX_MOD_LENGTH]; /* Orders */ }; .ft P .fi .UNINDENT .UNINDENT .sp See the header file for more information about pattern and instrument data. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS Module playing .SS int xmp_start_player(xmp_context c, int rate, int format) .INDENT 0.0 .INDENT 3.5 Start playing the currently loaded module. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B rate the sampling rate to use, in Hz (typically 44100). Valid values range from 8kHz to 48kHz. .TP .B flags bitmapped configurable player flags, one or more of the following: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C XMP_FORMAT_8BIT /* Mix to 8\-bit instead of 16 */ XMP_FORMAT_UNSIGNED /* Mix to unsigned samples */ XMP_FORMAT_MONO /* Mix to mono instead of stereo */ .ft P .fi .UNINDENT .UNINDENT .UNINDENT .TP .B \fBReturns:\fP 0 if sucessful, or a negative error code in case of error. Error codes can be \fB\-XMP_ERROR_INTERNAL\fP in case of a internal player error, \fB\-XMP_ERROR_INVALID\fP if the sampling rate is invalid, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_play_frame(xmp_context c) .INDENT 0.0 .INDENT 3.5 Play one frame of the module. Modules usually play at 50 frames per second. Use \fI\%xmp_get_frame_info()\fP to retrieve the buffer containing audio data. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .TP .B \fBReturns:\fP 0 if sucessful, \fB\-XMP_END\fP if the module ended or was stopped, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_play_buffer(xmp_context c, void *buffer, int size, int loop) .INDENT 0.0 .INDENT 3.5 \fI[Added in libxmp 4.1]\fP Fill the buffer with PCM data up to the specified size. This is a convenience function that calls \fI\%xmp_play_frame()\fP internally to fill the user\-supplied buffer. \fBDon\(aqt call both xmp_play_frame() and xmp_play_buffer() in the same replay loop.\fP If you don\(aqt need equally sized data chunks, \fI\%xmp_play_frame()\fP may result in better performance. Also note that silence is added at the end of a buffer if the module ends and no loop is to be performed. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B buffer the buffer to fill with PCM data, or NULL to reset the internal state. .TP .B size the buffer size in bytes. .TP .B loop stop replay when the loop counter reaches the specified value, or 0 to disable loop checking. .UNINDENT .TP .B \fBReturns:\fP 0 if sucessful, \fB\-XMP_END\fP if module was stopped or the loop counter was reached, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS void xmp_get_frame_info(xmp_context c, struct xmp_frame_info *info) .INDENT 0.0 .INDENT 3.5 Retrieve the current frame data. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B info pointer to structure containing current frame data. \fBstruct xmp_frame_info\fP is defined as follows: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C struct xmp_frame_info { /* Current frame information */ int pos; /* Current position */ int pattern; /* Current pattern */ int row; /* Current row in pattern */ int num_rows; /* Number of rows in current pattern */ int frame; /* Current frame */ int speed; /* Current replay speed */ int bpm; /* Current bpm */ int time; /* Current module time in ms */ int total_time; /* Estimated replay time in ms*/ int frame_time; /* Frame replay time in us */ void *buffer; /* Pointer to sound buffer */ int buffer_size; /* Used buffer size */ int total_size; /* Total buffer size */ int volume; /* Current master volume */ int loop_count; /* Loop counter */ int virt_channels; /* Number of virtual channels */ int virt_used; /* Used virtual channels */ int sequence; /* Current sequence */ struct xmp_channel_info { /* Current channel information */ unsigned int period; /* Sample period */ unsigned int position; /* Sample position */ short pitchbend; /* Linear bend from base note*/ unsigned char note; /* Current base note number */ unsigned char instrument; /* Current instrument number */ unsigned char sample; /* Current sample number */ unsigned char volume; /* Current volume */ unsigned char pan; /* Current stereo pan */ unsigned char reserved; /* Reserved */ struct xmp_event event; /* Current track event */ } channel_info[XMP_MAX_CHANNELS]; }; .ft P .fi .UNINDENT .UNINDENT .sp This function should be used to retrieve sound buffer data after \fI\%xmp_play_frame()\fP is called. Fields \fBbuffer\fP and \fBbuffer_size\fP contain the pointer to the sound buffer PCM data and its size. The buffer size will be no larger than \fBXMP_MAX_FRAMESIZE\fP\&. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS void xmp_end_player(xmp_context c) .INDENT 0.0 .INDENT 3.5 End module replay and release player memory. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS Player control .SS int xmp_next_position(xmp_context c) .INDENT 0.0 .INDENT 3.5 Skip replay to the start of the next position. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .TP .B \fBReturns:\fP The new position index, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_prev_position(xmp_context c) .INDENT 0.0 .INDENT 3.5 Skip replay to the start of the previous position. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .TP .B \fBReturns:\fP The new position index, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_set_position(xmp_context c, int pos) .INDENT 0.0 .INDENT 3.5 Skip replay to the start of the given position. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B pos the position index to set. .UNINDENT .TP .B \fBReturns:\fP The new position index, \fB\-XMP_ERROR_INVALID\fP of the new position is invalid or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS void xmp_stop_module(xmp_context c) .INDENT 0.0 .INDENT 3.5 Stop the currently playing module. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS void xmp_restart_module(xmp_context c) .INDENT 0.0 .INDENT 3.5 Restart the currently playing module. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS int xmp_seek_time(xmp_context c, int time) .INDENT 0.0 .INDENT 3.5 Skip replay to the specified time. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B time time to seek in milliseconds. .UNINDENT .TP .B \fBReturns:\fP The new position index, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_channel_mute(xmp_context c, int chn, int status) .INDENT 0.0 .INDENT 3.5 Mute or unmute the specified channel. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B chn the channel to mute or unmute. .TP .B status 0 to mute channel, 1 to unmute or \-1 to query the current channel status. .UNINDENT .TP .B \fBReturns:\fP The previous channel status, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_channel_vol(xmp_context c, int chn, int vol) .INDENT 0.0 .INDENT 3.5 Set or retrieve the volume of the specified channel. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B chn the channel to set or get volume. .TP .B vol a value from 0\-100 to set the channel volume, or \-1 to retrieve the current volume. .UNINDENT .TP .B \fBReturns:\fP The previous channel volume, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS void xmp_inject_event(xmp_context c, int chn, struct xmp_event *event) .INDENT 0.0 .INDENT 3.5 Dynamically insert a new event into a playing module. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B chn the channel to insert the new event. .TP .B event the event to insert. \fBstruct xmp_event\fP is defined as: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C struct xmp_event { unsigned char note; /* Note number (0 means no note) */ unsigned char ins; /* Patch number */ unsigned char vol; /* Volume (0 to basevol) */ unsigned char fxt; /* Effect type */ unsigned char fxp; /* Effect parameter */ unsigned char f2t; /* Secondary effect type */ unsigned char f2p; /* Secondary effect parameter */ unsigned char _flag; /* Internal (reserved) flags */ }; .ft P .fi .UNINDENT .UNINDENT .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SS Player parameter setting .SS int xmp_set_instrument_path(xmp_context c, char *path) .INDENT 0.0 .INDENT 3.5 Set the path to retrieve external instruments or samples. Used by some formats (such as MED2) to read sample files from a different directory in the filesystem. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B path the path to retrieve instrument files. .UNINDENT .TP .B \fBReturns:\fP 0 if the instrument path was correctly set, or \fB\-XMP_ERROR_SYSTEM\fP in case of error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_get_player(xmp_context c, int param) .INDENT 0.0 .INDENT 3.5 Retrieve current value of the specified player parameter. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B param player parameter to get. Valid parameters are: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C XMP_PLAYER_AMP /* Amplification factor */ XMP_PLAYER_MIX /* Stereo mixing */ XMP_PLAYER_INTERP /* Interpolation type */ XMP_PLAYER_DSP /* DSP effect flags */ XMP_PLAYER_FLAGS /* Player flags */ XMP_PLAYER_CFLAGS /* Player flags for current module*/ XMP_PLAYER_SMPCTL /* Control sample loading */ XMP_PLAYER_VOLUME /* Player master volume */ XMP_PLAYER_STATE /* Current player state (read only) */ XMP_PLAYER_SMIX_VOLUME /* SMIX Volume */ XMP_PLAYER_DEFPAN /* Default pan separation */ XMP_PLAYER_MODE /* Player personality */ XMP_PLAYER_MIXER_TYPE /* Current mixer (read only) */ XMP_PLAYER_VOICES /* Maximum number of mixer voices */ .ft P .fi .UNINDENT .UNINDENT .sp Valid states are: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C XMP_STATE_UNLOADED /* Context created */ XMP_STATE_LOADED /* Module loaded */ XMP_STATE_PLAYING /* Module playing */ .ft P .fi .UNINDENT .UNINDENT .sp Valid mixer types are: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C XMP_MIXER_STANDARD /* Standard mixer */ XMP_MIXER_A500 /* Amiga 500 */ XMP_MIXER_A500F /* Amiga 500 with led filter */ .ft P .fi .UNINDENT .UNINDENT .sp See \fBxmp_set_player\fP for the rest of valid values for each parameter. .UNINDENT .TP .B \fBReturns:\fP The parameter value, or \fB\-XMP_ERROR_STATE\fP if the parameter is not \fBXMP_PLAYER_STATE\fP and the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_set_player(xmp_context c, int param, int val) .INDENT 0.0 .INDENT 3.5 Set player parameter with the specified value. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B param player parameter to set. Valid parameters are: .INDENT 7.0 .INDENT 3.5 .sp .nf .ft C XMP_PLAYER_AMP /* Amplification factor */ XMP_PLAYER_MIX /* Stereo mixing */ XMP_PLAYER_INTERP /* Interpolation type */ XMP_PLAYER_DSP /* DSP effect flags */ XMP_PLAYER_FLAGS /* Player flags */ XMP_PLAYER_CFLAGS /* Player flags for current module*/ XMP_PLAYER_SMPCTL /* Control sample loading */ XMP_PLAYER_VOLUME /* Player master volume */ XMP_PLAYER_SMIX_VOLUME /* SMIX Volume */ XMP_PLAYER_DEFPAN /* Default pan separation */ XMP_PLAYER_MODE /* Player personality */ XMP_PLAYER_VOICES /* Maximum number of mixer voices */ .ft P .fi .UNINDENT .UNINDENT .TP .B val the value to set. Valid values depend on the parameter being set. .UNINDENT .sp \fBValid values:\fP .INDENT 7.0 .IP \(bu 2 Amplification factor: ranges from 0 to 3. Default value is 1. .IP \(bu 2 Stereo mixing: percentual left/right channel separation. Default is 70. .IP \(bu 2 Interpolation type: can be one of the following values: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C XMP_INTERP_NEAREST /* Nearest neighbor */ XMP_INTERP_LINEAR /* Linear (default) */ XMP_INTERP_SPLINE /* Cubic spline */ .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 DSP effects flags: enable or disable DSP effects. Valid effects are: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C XMP_DSP_LOWPASS /* Lowpass filter effect */ XMP_DSP_ALL /* All effects */ .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Player flags: tweakable player parameters. Valid flags are: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C XMP_FLAGS_VBLANK /* Use vblank timing */ XMP_FLAGS_FX9BUG /* Emulate Protracker 2.x FX9 bug */ XMP_FLAGS_FIXLOOP /* Make sample loop value / 2 */ XMP_FLAGS_A500 /* Use Paula mixer in Amiga modules */ .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 \fI[Added in libxmp 4.1]\fP Player flags for current module: same flags as above but after applying module\-specific quirks (if any). .IP \(bu 2 \fI[Added in libxmp 4.1]\fP Sample control: Valid values are: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C XMP_SMPCTL_SKIP /* Don\(aqt load samples */ .ft P .fi .UNINDENT .UNINDENT .IP \(bu 2 Disabling sample loading when loading a module allows allows computation of module duration without decompressing and loading large sample data, and is useful when duration information is needed for a module that won\(aqt be played immediately. .IP \(bu 2 \fI[Added in libxmp 4.2]\fP Player volumes: Set the player master volume or the external sample mixer master volume. Valid values are 0 to 100. .IP \(bu 2 \fI[Added in libxmp 4.3]\fP Default pan separation: percentual left/right pan separation in formats with only left and right channels. Default is 100%. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .\" . .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .INDENT 3.5 .INDENT 0.0 .IP \(bu 2 \fI[Added in libxmp 4.4]\fP Player personality: The player can be forced to emulate a specific tracker in cases where the module relies on a format quirk and tracker detection fails. Valid modes are: .INDENT 2.0 .INDENT 3.5 .sp .nf .ft C XMP_MODE_AUTO /* Autodetect mode (default) */ XMP_MODE_MOD /* Play as a generic MOD player */ XMP_MODE_NOISETRACKER /* Play using Noisetracker quirks */ XMP_MODE_PROTRACKER /* Play using Protracker 1/2 quirks */ XMP_MODE_S3M /* Play as a generic S3M player */ XMP_MODE_ST3 /* Play using ST3 bug emulation */ XMP_MODE_ST3GUS /* Play using ST3+GUS quirks */ XMP_MODE_XM /* Play as a generic XM player */ XMP_MODE_FT2 /* Play using FT2 bug emulation */ XMP_MODE_IT /* Play using IT quirks */ XMP_MODE_ITSMP /* Play using IT sample mode quirks */ .ft P .fi .UNINDENT .UNINDENT .sp By default, formats similar to S3M such as PTM or IMF will use S3M replayer (without Scream Tracker 3 quirks/bug emulation), and formats similar to XM such as RTM and MDL will use the XM replayer (without FT2 quirks/bug emulation). .sp Multichannel MOD files will use the XM replayer, and Scream Tracker 3 MOD files will use S3M replayer with ST3 quirks. S3M files will use the most appropriate replayer according to the tracker used to create the file, and enable Scream Tracker 3 quirks and bugs only if created using ST3. XM files will be played with FT2 bugs and quirks only if created using Fast Tracker II. .sp Modules created with OpenMPT will be played with all bugs and quirks of the original trackers. .IP \(bu 2 \fI[Added in libxmp 4.4]\fP Maximum number of mixer voices: the maximum number of virtual channels that can be used to play the module. If set too high, modules with voice leaks can cause excessive CPU usage. Default is 128. .UNINDENT .UNINDENT .UNINDENT .INDENT 0.0 .TP .B \fBReturns:\fP 0 if parameter was correctly set, \fB\-XMP_ERROR_INVALID\fP if parameter or values are out of the valid ranges, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SH EXTERNAL SAMPLE MIXER API .sp Libxmp 4.2 includes a mini\-API that can be used to add sound effects to games and similar applications, provided that you have a low latency sound system. It allows module instruments or external sample files in WAV format to be played in response to arbitrary events. .SS Example .sp This example using SDL loads a module and a sound sample, plays the module as background music, and plays the sample when a key is pressed: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C #include #include static void fill_audio(void *udata, unsigned char *stream, int len) { xmp_play_buffer(udata, stream, len, 0); } int sound_init(xmp_context ctx, int sampling_rate, int channels) { SDL_AudioSpec a; a.freq = sampling_rate; a.format = (AUDIO_S16); a.channels = channels; a.samples = 2048; a.callback = fill_audio; a.userdata = ctx; if (SDL_OpenAudio(&a, NULL) < 0) { fprintf(stderr, "%s\en", SDL_GetError()); return \-1; } } int video_init() { if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "%s\en", SDL_GetError()); return \-1; } if (SDL_SetVideoMode(640, 480, 8, 0) == NULL) { fprintf(stderr, "%s\en", SDL_GetError()); return \-1; } atexit(SDL_Quit); } int main(int argc, char **argv) { SDL_Event event; xmp_context ctx; if ((ctx = xmp_create_context()) == NULL) return 1; video_init(); sound_init(ctx, 44100, 2); xmp_start_smix(ctx, 1, 1); xmp_smix_load_sample(ctx, 0, "blip.wav"); xmp_load_module(ctx, "music.mod"); xmp_start_player(ctx, 44100, 0); xmp_set_player(ctx, XMP_PLAYER_VOLUME, 40); SDL_PauseAudio(0); while (1) { if (SDL_WaitEvent(&event)) { if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_ESCAPE) break; xmp_smix_play_sample(ctx, 0, 60, 64, 0); } } } SDL_PauseAudio(1); xmp_end_player(ctx); xmp_release_module(ctx); xmp_free_context(ctx); xmp_end_smix(ctx); SDL_CloseAudio(); return 0; } .ft P .fi .UNINDENT .UNINDENT .SS SMIX API reference .SS int xmp_start_smix(xmp_context c, int nch, int nsmp) .INDENT 0.0 .INDENT 3.5 Initialize the external sample mixer subsystem with the given number of reserved channels and samples. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B nch number of reserved sound mixer channels (1 to 64). .TP .B nsmp number of external samples. .UNINDENT .TP .B \fBReturns:\fP 0 if the external sample mixer system was correctly initialized, \fB\-XMP_ERROR_INVALID\fP in case of invalid parameters, \fB\-XMP_ERROR_STATE\fP if the player is already in playing state, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_smix_play_instrument(xmp_context c, int ins, int note, int vol, int chn) .INDENT 0.0 .INDENT 3.5 Play a note using an instrument from the currently loaded module in one of the reserved sound mixer channels. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B ins the instrument to play. .TP .B note the note number to play (60 = middle C). .TP .B vol the volume to use (range: 0 to the maximum volume value used by the current module). .TP .B chn the reserved channel to use to play the instrument. .UNINDENT .TP .B \fBReturns:\fP 0 if the instrument was correctly played, \fB\-XMP_ERROR_INVALID\fP in case of invalid parameters, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_smix_play_sample(xmp_context c, int ins, int vol, int chn) .INDENT 0.0 .INDENT 3.5 Play an external sample file in one of the reserved sound channels. The sample must have been previously loaded using \fI\%xmp_smix_load_sample()\fP\&. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B ins the sample to play. .TP .B vol the volume to use (0 to the maximum volume value used by the current module. .TP .B chn the reserved channel to use to play the sample. .UNINDENT .TP .B \fBReturns:\fP 0 if the sample was correctly played, \fB\-XMP_ERROR_INVALID\fP in case of invalid parameters, or \fB\-XMP_ERROR_STATE\fP if the player is not in playing state. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_smix_channel_pan(xmp_context c, int chn, int pan) .INDENT 0.0 .INDENT 3.5 Set the reserved channel pan value. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B chn the reserved channel number. .TP .B pan the pan value to set (0 to 255). .UNINDENT .TP .B \fBReturns:\fP 0 if the pan value was set, or \fB\-XMP_ERROR_INVALID\fP if parameters are invalid. .UNINDENT .UNINDENT .UNINDENT .SS int xmp_smix_load_sample(xmp_context c, int num, char *path) .INDENT 0.0 .INDENT 3.5 Load a sound sample from a file. Samples should be in mono WAV (RIFF) format. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B num the slot number of the external sample to load. .TP .B path pathname of the file to load. .UNINDENT .TP .B \fBReturns:\fP 0 if the sample was correctly loaded, \fB\-XMP_ERROR_INVALID\fP if the sample slot number is invalid (not reserved using \fI\%xmp_start_smix()\fP), \fB\-XMP_ERROR_FORMAT\fP if the file format is unsupported, or \fB\-XMP_ERROR_SYSTEM\fP in case of system error (the system error code is set in \fBerrno\fP). .UNINDENT .UNINDENT .UNINDENT .SS int xmp_smix_release_sample(xmp_context c, int num) .INDENT 0.0 .INDENT 3.5 Release memory allocated by an external sample in the specified player context. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .TP .B num the sample slot number to release. .UNINDENT .TP .B \fBReturns:\fP 0 if memory was correctly released, or \fB\-XMP_ERROR_INVALID\fP if the sample slot number is invalid. .UNINDENT .UNINDENT .UNINDENT .SS void xmp_end_smix(xmp_context c) .INDENT 0.0 .INDENT 3.5 Deinitialize and resease memory used by the external sample mixer subsystem. .INDENT 0.0 .TP .B \fBParameters:\fP .INDENT 7.0 .TP .B c the player context handle. .UNINDENT .UNINDENT .UNINDENT .UNINDENT .SH AUTHOR Claudio Matsuoka and Hipolito Carraro Jr. .\" Generated by docutils manpage writer. . libxmp-4.4.1/Makefile.vc0000664000175000017500000001017112777430671014724 0ustar claudioclaudioCC = cl CFLAGS = /O2 /Iinclude /Isrc /Isrc\win32 /DBUILDING_DLL /DWIN32 \ /Dinline=__inline /DPATH_MAX=1024 /D_USE_MATH_DEFINES LD = link LDFLAGS = /DLL /RELEASE /OUT:$(DLL) DLL = libxmp.dll OBJS = src\virtual.obj src\format.obj src\period.obj src\player.obj src\read_event.obj src\dataio.obj src\mkstemp.obj src\fnmatch.obj src\md5.obj src\lfo.obj src\scan.obj src\control.obj src\med_extras.obj src\filter.obj src\effects.obj src\mixer.obj src\mix_all.obj src\load_helpers.obj src\load.obj src\hio.obj src\hmn_extras.obj src\extras.obj src\smix.obj src\memio.obj src\tempfile.obj src\mix_paula.obj src\loaders\common.obj src\loaders\iff.obj src\loaders\itsex.obj src\loaders\asif.obj src\loaders\voltable.obj src\loaders\sample.obj src\loaders\xm_load.obj src\loaders\mod_load.obj src\loaders\s3m_load.obj src\loaders\stm_load.obj src\loaders\669_load.obj src\loaders\far_load.obj src\loaders\mtm_load.obj src\loaders\ptm_load.obj src\loaders\okt_load.obj src\loaders\ult_load.obj src\loaders\mdl_load.obj src\loaders\it_load.obj src\loaders\stx_load.obj src\loaders\pt3_load.obj src\loaders\sfx_load.obj src\loaders\flt_load.obj src\loaders\st_load.obj src\loaders\emod_load.obj src\loaders\imf_load.obj src\loaders\digi_load.obj src\loaders\fnk_load.obj src\loaders\ice_load.obj src\loaders\liq_load.obj src\loaders\ims_load.obj src\loaders\masi_load.obj src\loaders\amf_load.obj src\loaders\psm_load.obj src\loaders\stim_load.obj src\loaders\mmd_common.obj src\loaders\mmd1_load.obj src\loaders\mmd3_load.obj src\loaders\rtm_load.obj src\loaders\dt_load.obj src\loaders\no_load.obj src\loaders\arch_load.obj src\loaders\sym_load.obj src\loaders\med2_load.obj src\loaders\med3_load.obj src\loaders\med4_load.obj src\loaders\dbm_load.obj src\loaders\umx_load.obj src\loaders\gdm_load.obj src\loaders\pw_load.obj src\loaders\gal5_load.obj src\loaders\gal4_load.obj src\loaders\mfp_load.obj src\loaders\asylum_load.obj src\loaders\hmn_load.obj src\loaders\mgt_load.obj src\loaders\chip_load.obj src\loaders\abk_load.obj src\loaders\prowizard\prowiz.obj src\loaders\prowizard\ptktable.obj src\loaders\prowizard\tuning.obj src\loaders\prowizard\ac1d.obj src\loaders\prowizard\di.obj src\loaders\prowizard\eureka.obj src\loaders\prowizard\fc-m.obj src\loaders\prowizard\fuchs.obj src\loaders\prowizard\fuzzac.obj src\loaders\prowizard\gmc.obj src\loaders\prowizard\heatseek.obj src\loaders\prowizard\ksm.obj src\loaders\prowizard\mp.obj src\loaders\prowizard\np1.obj src\loaders\prowizard\np2.obj src\loaders\prowizard\np3.obj src\loaders\prowizard\p61a.obj src\loaders\prowizard\pm10c.obj src\loaders\prowizard\pm18a.obj src\loaders\prowizard\pha.obj src\loaders\prowizard\prun1.obj src\loaders\prowizard\prun2.obj src\loaders\prowizard\tdd.obj src\loaders\prowizard\unic.obj src\loaders\prowizard\unic2.obj src\loaders\prowizard\wn.obj src\loaders\prowizard\zen.obj src\loaders\prowizard\tp1.obj src\loaders\prowizard\tp3.obj src\loaders\prowizard\p40.obj src\loaders\prowizard\xann.obj src\loaders\prowizard\theplayer.obj src\loaders\prowizard\pp10.obj src\loaders\prowizard\pp21.obj src\loaders\prowizard\starpack.obj src\loaders\prowizard\titanics.obj src\loaders\prowizard\skyt.obj src\loaders\prowizard\novotrade.obj src\loaders\prowizard\hrt.obj src\loaders\prowizard\noiserun.obj src\depackers\ppdepack.obj src\depackers\unsqsh.obj src\depackers\mmcmp.obj src\depackers\readrle.obj src\depackers\readlzw.obj src\depackers\unarc.obj src\depackers\arcfs.obj src\depackers\xfd.obj src\depackers\inflate.obj src\depackers\muse.obj src\depackers\unlzx.obj src\depackers\s404_dec.obj src\depackers\unzip.obj src\depackers\gunzip.obj src\depackers\uncompress.obj src\depackers\unxz.obj src\depackers\bunzip2.obj src\depackers\unlha.obj src\depackers\xz_dec_lzma2.obj src\depackers\xz_dec_stream.obj src\depackers\oxm.obj src\depackers\vorbis.obj src\depackers\crc32.obj src\win32\ptpopen.obj TEST = test\md5.obj test\test.obj .c.obj: $(CC) /c $(CFLAGS) /Fo$*.obj $< all: $(DLL) $(DLL): $(OBJS) $(LD) $(LDFLAGS) $(OBJS) clean: del $(OBJS) $(DLL) *.lib *.exp check: $(TEST) $(LD) /RELEASE /OUT:test\libxmp-test.exe $(TEST) libxmp.lib copy libxmp.dll test cd test & libxmp-test