Built SDL2_image and _mixer static

This commit is contained in:
2022-09-30 15:49:16 -04:00
parent e2605bf6c1
commit 1dec4347e0
4473 changed files with 1964551 additions and 9 deletions

View File

@ -0,0 +1,22 @@
XMMS plugin:
Kenton Varda <temporal@gauge3d.org>
Konstanty Bialkowski <konstanty@ieee.org>
General Maintainence:
Konstanty Bialkowski <konstanty@ieee.org>
Sound Engine:
Olivier Lapicque <olivierl@jps.net>
BZip2 support:
Colin DeVilbiss <crdevilb@mtu.edu>
Spline and Fir resamplers:
Markus Fick <marf@gmx.net>
Endianness Fixes:
Adam Goode <adam@evdebs.org>
Endianness Fixes + Implementation of C 24bit,32bit functions:
Marco Trillo <toad@arsystel.com>
Fixes to AGC/Clipping, Frequency Limit, Other Fixes:
Alistair John Strachan <s0348365@sms.ed.ac.uk>
AMD64 Fix (long long vs long vs int)
Tyler Montbriand <tsm@accesscomm.ca>

View File

@ -0,0 +1,47 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := modplug
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src $(LOCAL_PATH)/src/libmodplug
LOCAL_CFLAGS += -DHAVE_SETENV -DHAVE_SINF
LOCAL_SRC_FILES += \
src/fastmix.cpp \
src/load_669.cpp \
src/load_abc.cpp \
src/load_amf.cpp \
src/load_ams.cpp \
src/load_dbm.cpp \
src/load_dmf.cpp \
src/load_dsm.cpp \
src/load_far.cpp \
src/load_it.cpp \
src/load_j2b.cpp \
src/load_mdl.cpp \
src/load_med.cpp \
src/load_mid.cpp \
src/load_mod.cpp \
src/load_mt2.cpp \
src/load_mtm.cpp \
src/load_okt.cpp \
src/load_pat.cpp \
src/load_psm.cpp \
src/load_ptm.cpp \
src/load_s3m.cpp \
src/load_stm.cpp \
src/load_ult.cpp \
src/load_umx.cpp \
src/load_wav.cpp \
src/load_xm.cpp \
src/mmcmp.cpp \
src/modplug.cpp \
src/snd_dsp.cpp \
src/snd_flt.cpp \
src/snd_fx.cpp \
src/sndfile.cpp \
src/sndmix.cpp
include $(BUILD_STATIC_LIBRARY)

View File

@ -0,0 +1 @@
ModPlug-XMMS and libmodplug are now in the public domain.

View File

@ -0,0 +1,299 @@
changes:
date = 24-apr-2017 [Konstanty Bialkowski/Lionel Debroux/SEZERO]
Version 0.8.9.0
OOB Write and Read fixes + a number of divide by zero fixes.
(ABC, PAT, AMF, MDL, PSM, XM, IT, MMCMP, MID)
There were some patches 2010-2016 which were recorded here.
date = 21-apr-2009 [Konstanty Bialkowski/OpenMPT/Novell (Stanislav Brabec)]
->file: src/load_amf.cpp
where: whole file
what: added const declarations to read only variables
what: fixed delete function
->file: src/fastmix.cpp
where: X86_Convert32To24
what: conversion to 24bit was incorrect
->file: src/load_mdl.cpp
where: init of m_lpszSongComments
what: fixed delete function to be array version (Reported by
David Binderman / Stanislav Brabec)
->file: src/load_pat.cpp
where: memcpy to .reserved
what: changed fixed valid of 36 to sizeof(reserved)
(Reported by Manfred Tremmel / Stanislav Brabec)
date = 20-apr-2009 [Konstanty Bialkowski]
->file: src/load_meb.cpp
where: LoadMED
what: fixed integer boundary condition checking code (fixing
exploit)
Details of exploit (and creator of test.s3m for exploit)
http://www.securityfocus.com/bid/30801/info
http://www.15897.com/blog/post/QianQianJingTing-mod-buffer-overflow-POC.html
->file: src/load_abc.cpp
where: TestABC
what: Made ABC detection code more robust
->file: src/load_abc.cpp, sndfile.cpp, snd_fx.cpp
where: various
what: change constant variables to explicitly use const
definition
(Thanks to Leandro Nini/Diego "Flameeyes" Pettenò)
->file: src/table.cpp -> src/table.h
where: rename of file
what: moved tables to separate file
(Thanks to Leandro Nini/Diego "Flameeyes" Pettenò)
date = 15-apr-2009 [Konstanty Bialkowski]
->file: src/load_abc.cpp
where: TestABC
what: made sure obviously binary files do not try to get
loaded as ABC
where: abc_addchordname
what: made sure first argument was const char * (not just char
*)
->file: src/sndfile.cpp
where: format conversion routines
what: made sure (*a++) = func(*a), is executed properly, by
splitting into two lines
-file: src/libmodplug/sndfile.h
where: IMixPlugin
what: made sure there is a virtual destructor (to avoid
warnings)
->file: src/load_ptm.cpp
where: mixing routine
what: bswap32 was used on a uint16_t [2] array, and when gcc
uses -O2 (or greater) optimization, this may not do what is
intended.
date = 7-apr-2009 [Konstanty Bialkowski/Anthony Ramine]
-> file: src/load_abc.cpp,load_mid.cpp,load_pat.cpp
where: whole file(s)
what: removed use of ULONG, and changed to uint32_t
where: few functions
what: removed uint, and replaced with uint32_t
date = 7-apr-2009 [Zed Pobre/Debian]
-> file: src/libmodplug.pc
where: file.
what: split Libs into Libs.private
date = 2-nov-2006 [Alec Berryman/CVE-2006-4192]
-> file: src/sndfile.cpp
where: ReadSample
what: prevent buffer overflow [as reported in CVE-2006-4192]
date = 2-nov-2006 [Konstanty Bialkowski/Macro Trillo]
-> file: configure.in,config.h,load_abc.cpp,fastmix.cpp
where: Automake 2.60 used
what: In order to properly use stdint.h we should make use of the new macros for its detection, on systems with automake 2.59 but where stdint.h is available, this can be removed. (Patch by Macro Trillo)
-> file: src/load_amf.cpp, src/fastmix.cpp
where: Licensing
what: all old code was relicensed for public domain, and somehow an old version was included with GPL notices
date = 20-jul-2006 [Peter Grootswagers]
-> file: src/load_abc.cpp
where: instrument loader functions
what: replaced with correspondig functions in load_pat.cpp
-> file: src/load_mid.cpp
where: whole source
what: new loader for midi files
-> file: src/load_pat.cpp
where: whole source
what: new loader for GUS instrument patch files (pat)
-> file: src/load_pat.h
where: whole source
what: new header declaring reuseable GUS instrument patch functions (pat)
-> file: README
where: 2. Features
what: added description of load_mid.cpp and load_pat.cpp
-> file: src/Makefile.am
where: libmodplug_la_SOURCES
what: added load_mid.cpp and load_pat.cpp
where: libmodpluginclude_HEADERS
what: added load_pat.h
-> file: src/sndfile.cpp
where: function CSoundFile::Create()
what: added call to ReadMID and ReadPAT
-> file: src/libmodplug/sndfile.h
where: #define
what: added MOD_TYPE_PAT (MOD_TYPE_MID already there...)
where: class CSoundFile
what: added public function members ReadMID, TestMID, ReadPat, TestPAT and PATsample
date = 24-jun-2006 [Peter Grootswagers]
-> file: src/load_abc.cpp
where: whole source
what: new loader for abc files
-> file: README
where: 2. Features
what: added description of load_abc.cpp
-> file: src/Makefile.am
where: libmodplug_la_SOURCES
what: added load_abc.cpp
-> file: src/sndfile.cpp
where: function CSoundFile::Create()
what: added call to ReadABC
-> file: src/libmodplug/sndfile.h
where: #define
what: added MOD_TYPE_ABC
where: class CSoundFile
what: added public function members ReadABC and TestABC
date = 20-mar-2006 [Macro Trillo / "Custom libmodplug project"]
-> file : src/load_s3m.cpp
-> file : src/load_far.cpp
what: fixed endianness
date = 20-mar-2006 [Alistair John Strachan]
....
Many other changes need to be documented here...
GCC3 fixes, GCC4 fixes, More Archive Types.
date = 09-feb-2001 [Markus Fick]
-> file: fastmix.cpp
where: spline creation, spline macros
what: added unity gain clamp code, added Quantizer_Bits(shift) preprocessor constants
where: fir creation, fir macros
what: - removed x<pi/2 condition in coef creation
- added quantizer_bits(shift) preprocessor constants
- set default quantizer bits to 15 instead 14 (scale now 32768 instead 16384)
there should not occure any overflows during fir response calculation because
of the symmetric form of filter and the position of the negative fir coefs
- changed final volume calculation for 16bit samples (quality enhancement)
date = 08-feb-2001 [Markus Fick]
-> file: sndmix.cpp
where: function ReadNote()
what: modified behaviour of modplug so that interpolation is only deactivated if
a) the user selects "no interpolation"
b) linear interpolation is set and speed incr. > 0xff00
=> if spline or fir is active then we use always interpolation
-> file: fastmix.cpp
where: spline macros
what: changed spline macros to use precalculated tables (way faster)
where: file
what: - implemented spline table precalculator
- changed fir precalculator + macros (for higher quality and clearer source)
- added some comments and documentation
comment:
- preprocessor constant: SPLINE_FRACBITS
) controls quality/memory usage
range is [4..14] inclusive
4 = low quality, low memory usage
14 = highest quality, highest memory usage (1L<<14)*4*2 bytes
- preprocessor constant: WFIR_FRACBITS
) controls quality/memory usage
range is [4..12] inclusive
4 = low quality, low mu
12 = highest quality, highest memory usage ((1L<<(12+1))+1)*8*2 bytes
date = 07-feb-2001 [Markus Fick]
-> file: fastmix.cpp
where: spline macros
what: fixed error in coef calculation
date = 07-feb-2001 [Markus Fick]
-> file: sndfile.h
where: class definition of soundfile
what: removed InitFIR + DoneFIR function prototypes
-> file: sndfile.cpp
function:CSoundFile::CSoundFile()
what: [modify] removed call to CSoundFile::InitFIRMixer( )
function:CSoundFile::~CSoundFile()
what: [modify] removed call to CSoundFile::DoneFIRMixer( )
-> file: fastmix.cpp
where: spline macros
what: changed formula + added some guard bits to calculation
where: fir macros + implementation
what: - moved CSoundfile::FIR funtions to CzFIR (single instance sfir)
- changed fir macros to support CzFIR class
date = 06-feb-2001 [Markus Fick]
-> file: fastmix.cpp
where: macros
what: - removed fir filter with coef interpolation
- add spline interpolation
RM: now modplug->select( SPLINE ) selects spline and
modplug->select( POLYPHASE ) selects 8tap fir filter
date = 05-feb-2001 [Markus Fick]
-> file: fastmix.cpp
where: macros + filter order
what: [modify] changed filter order to 8 instead of 10
-> file: fastmix.cpp
what: new macros+switch for fir-interpolator with coef interpolation
date = 04-feb-2001 [Markus Fick]
-> file: sndfile.h
where: class CSoundFile (bottom)
what: [add] methods for FIR mixer support
1. int InitFIRInterpolator( );
2. int DoneFIRInterpolator( );
-> file: sndfile.cpp
function:CSoundFile::CSoundFile()
what: [modify] add call to CSoundFile::InitFIRMixer( )
function:CSoundFile::~CSoundFile()
what: [modify] add call to CSoundFile::DoneFIRMixer( )
-> file: fastmix.cpp
new include: <math.h>
why: need it for fir-coef calculation
new function: CSoundFile::InitFIRMixer( ) // initializes fir filter lookup (if necessary)
new function: CSoundFile::DoneFIRMixer( ) // decrements ReferenceCounter (for static vars) and deinitializes fir struct (if possible).
new defs:
#define FIRCPWBN 10 // log2 of number of precalculated wings (-(1L<<FIRCPWBN)..(1L<<FIRCPWBN))
#define FIRLOPOSSHIFT (16-(FIRCPWBN+1)) // shift for lopos of sampleposition -> (16 - FIRCPWBN - 1)
#define FIRLEN 9 // number(-1) of multiplications per sample
#define FIRCUT 0.90f // cutoff of filter
#define MIXNDX_FIRMIXERSRC 0x20 // src-type for firfilter
new vars:
static signed short *cFirLut; // lulines
static int bFirInitialized = 0; // initialized?
static int nFirOrder = FIRLEN; // order (modplug has 4smps pre/post extension, so limit this to 9)
static float nFirFC = FIRCUT; // cutoff (normalized to pi/2)
static int nFirCpw = (1L<<FIRCPWBN); // number of precalculted filter lines
static int nFirUsers = 0; // reference counter
new macros:
#define SNDMIX_GETMONOVOL8FIRFILTER
#define SNDMIX_GETMONOVOL16FIRFILTER
#define SNDMIX_GETSTEREOVOL8FIRFILTER
#define SNDMIX_GETSTEREOVOL16FIRFILTER
new mixer interface macros:
BEGIN_MIX_INTERFACE(Mono8BitFirFilterMix)
BEGIN_MIX_INTERFACE(Mono16BitFirFilterMix)
BEGIN_RAMPMIX_INTERFACE(Mono8BitFirFilterRampMix)
BEGIN_RAMPMIX_INTERFACE(Mono16BitFirFilterRampMix)
BEGIN_MIX_INTERFACE(FastMono8BitFirFilterMix)
BEGIN_MIX_INTERFACE(FastMono16BitFirFilterMix)
BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitFirFilterRampMix)

View File

@ -0,0 +1,3 @@
(1) ./configure
(2) make
(3) su -c "make install"

View File

@ -0,0 +1,11 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
EXTRA_DIST = \
AUTHORS COPYING ChangeLog \
INSTALL README TODO
pkgconfigdir=${libdir}/pkgconfig
pkgconfig_DATA=libmodplug.pc

View File

@ -0,0 +1,863 @@
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
$(am__configure_deps) $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/src/config.h
CONFIG_CLEAN_FILES = libmodplug.pc
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
install-data-recursive install-dvi-recursive \
install-exec-recursive install-html-recursive \
install-info-recursive install-pdf-recursive \
install-ps-recursive install-recursive installcheck-recursive \
installdirs-recursive pdf-recursive ps-recursive \
tags-recursive uninstall-recursive
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
DATA = $(pkgconfig_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
$(RECURSIVE_TARGETS) \
$(RECURSIVE_CLEAN_TARGETS) \
$(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
cscope distdir dist dist-all distcheck
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
CSCOPE = cscope
DIST_SUBDIRS = $(SUBDIRS)
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/libmodplug.pc.in \
AUTHORS COPYING ChangeLog INSTALL NEWS README TODO compile \
config.guess config.sub depcomp install-sh ltmain.sh missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
if test -d "$(distdir)"; then \
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -rf "$(distdir)" \
|| { sleep 5 && rm -rf "$(distdir)"; }; \
else :; fi
am__post_remove_distdir = $(am__remove_distdir)
am__relativize = \
dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
sed_rest='s,^[^/]*/*,,'; \
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
sed_butlast='s,/*[^/]*$$,,'; \
while test -n "$$dir1"; do \
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
if test "$$first" != "."; then \
if test "$$first" = ".."; then \
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
else \
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
if test "$$first2" = "$$first"; then \
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
else \
dir2="../$$dir2"; \
fi; \
dir0="$$dir0"/"$$first"; \
fi; \
fi; \
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
done; \
reldir="$$dir2"
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
DIST_TARGETS = dist-gzip
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_LDFLAGS = @LT_LDFLAGS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODPLUG_LIBRARY_VERSION = @MODPLUG_LIBRARY_VERSION@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
EXTRA_DIST = \
AUTHORS COPYING ChangeLog \
INSTALL README TODO
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = libmodplug.pc
all: all-recursive
.SUFFIXES:
am--refresh: Makefile
@:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
$(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
$(am__cd) $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
$(am__aclocal_m4_deps):
libmodplug.pc: $(top_builddir)/config.status $(srcdir)/libmodplug.pc.in
cd $(top_builddir) && $(SHELL) ./config.status $@
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool config.lt
install-pkgconfigDATA: $(pkgconfig_DATA)
@$(NORMAL_INSTALL)
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
done
uninstall-pkgconfigDATA:
@$(NORMAL_UNINSTALL)
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
# (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.
$(am__recursive_targets):
@fail=; \
if $(am__make_keepgoing); then \
failcom='fail=yes'; \
else \
failcom='exit 1'; \
fi; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-recursive
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
include_option=--etags-include; \
empty_fix=.; \
else \
include_option=--include; \
empty_fix=; \
fi; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test ! -f $$subdir/TAGS || \
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-recursive
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscope: cscope.files
test ! -s cscope.files \
|| $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
clean-cscope:
-rm -f cscope.files
cscope.files: clean-cscope cscopelist
cscopelist: cscopelist-recursive
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
distdir: $(DISTFILES)
$(am__remove_distdir)
test -d "$(distdir)" || mkdir "$(distdir)"
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
$(am__make_dryrun) \
|| test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \
new_distdir=$$reldir; \
dir1=$$subdir; dir2="$(top_distdir)"; \
$(am__relativize); \
new_top_distdir=$$reldir; \
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
($(am__cd) $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$new_top_distdir" \
distdir="$$new_distdir" \
am__remove_distdir=: \
am__skip_length_check=: \
am__skip_mode_fix=: \
distdir) \
|| exit 1; \
fi; \
done
-test -n "$(am__skip_mode_fix)" \
|| find "$(distdir)" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
$(am__post_remove_distdir)
dist-lzip: distdir
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
$(am__post_remove_distdir)
dist-xz: distdir
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
$(am__post_remove_distdir)
dist-tarZ: distdir
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__post_remove_distdir)
dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__post_remove_distdir)
dist dist-all:
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
$(am__post_remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
*.tar.xz*) \
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
chmod a-w $(distdir)
test -d $(distdir)/_build || exit 0; \
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& am__cwd=`pwd` \
&& $(am__cd) $(distdir)/_build/sub \
&& ../../configure \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
&& cd "$$am__cwd" \
|| exit 1
$(am__post_remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@test -n '$(distuninstallcheck_dir)' || { \
echo 'ERROR: trying to run $@ with an empty' \
'$$(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
$(am__cd) '$(distuninstallcheck_dir)' || { \
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
check: check-recursive
all-am: Makefile $(DATA)
installdirs: installdirs-recursive
installdirs-am:
for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-recursive
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -f Makefile
distclean-am: clean-am distclean-generic distclean-libtool \
distclean-tags
dvi: dvi-recursive
dvi-am:
html: html-recursive
html-am:
info: info-recursive
info-am:
install-data-am: install-pkgconfigDATA
install-dvi: install-dvi-recursive
install-dvi-am:
install-exec-am:
install-html: install-html-recursive
install-html-am:
install-info: install-info-recursive
install-info-am:
install-man:
install-pdf: install-pdf-recursive
install-pdf-am:
install-ps: install-ps-recursive
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-recursive
pdf-am:
ps: ps-recursive
ps-am:
uninstall-am: uninstall-pkgconfigDATA
.MAKE: $(am__recursive_targets) install-am install-strip
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
am--refresh check check-am clean clean-cscope clean-generic \
clean-libtool cscope cscopelist-am ctags ctags-am dist \
dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \
dist-xz dist-zip distcheck distclean distclean-generic \
distclean-libtool distclean-tags distcleancheck distdir \
distuninstallcheck dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-pkgconfigDATA install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs installdirs-am maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-pkgconfigDATA
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,6 @@
Konstanty Bialkowski <konstanty@ieee.org> Tue Apr 7 15:00:00 AEST 2009
New release of small fixes from contributors and downstream distributions. (Package config Libs.private addin (from Debian)), usage of uint32_t vs uint for load_abc.cpp,load_mid.cpp,load_pat.cpp.
Konstanty Bialkowski <konstanty@ieee.org> Mon Mar 20 10:00:00 AEST 2006
New Release based on fixes contributed since last release.

View File

@ -0,0 +1,224 @@
libmodplug - the library which was part of the Modplug-xmms project
Web page: http://modplug-xmms.sf.net/
Based on the ModPlug sound engine by Olivier Lapicque <olivierl@jps.net>
XMMS plugin by Kenton Varda <temporal@gauge3d.org> (~2002)
Maintainer is now Konstanty Bialkowski <konstanty@ieee.org> (~2006)
On Wed 14 Aug 2013 the repository was forked / cloned to GitHub.
The current release is libmodplug v0.8.9.0.
History
-------
Olivier Lapicque, author of Modplug, which is arguably the best quality
MOD-playing software available, has placed his sound rendering code in the
public domain. This library and plugin is based on that code.
This code was originally part of modplug-xmms, and was split into a library - libmodplug
and the modplug-xmms code. Also since then an example rendering project called modplugplay and
modplug123 were introduced. They are still available on the sourceforge website.
For more information on libmodplug, the library for decoding mod-like music
formats, see libmodplug/README.
Contents
--------
1. Requirements
2. Features
3. Options
4. Troubleshooting
---------------
1. Requirements
---------------
- POSIX OS (Linux or other unix*)
- XMMS 1.0.0 or higher (only for modplug-xmms plugin).
* This library is only guaranteed to work on Linux. I have received
conflicting reports on whether or not it will work on Solaris x86.
One person reported that the plugin compiled fine with the
"-fpermissive" compiler flag, which I have added. Others had far
more trouble. Note that a recent change to the library should allow
it to work on PPC and other big-endian systems.
* Under linux there is also modplugplay contributed, which allows command
line playing of mod files under Linux. (Available at http://modplug-xmms.sf.net/)
-----------
2. Features
-----------
- Plays 22 different mod formats, including:
MOD, S3M, XM, IT, 669, AMF (both of them), AMS, DBM, DMF, DSM, FAR,
MDL, MED, MTM, OKT, PTM, STM, ULT, UMX, MT2, PSM
- Plays zip, rar, gzip, and bzip2 compressed mods. The following
extensions are recognized: (Only in modplug-xmms)
zip: MDZ, S3Z, XMZ, ITZ
rar: MDR, S3R, XMR, ITR
gzip: MDGZ, S3GZ, XMGZ, ITGZ
You can also load plain old ZIP, RAR, and GZ files. If ModPlug finds
a mod in them, it will play it.
Note: To play these formats, you need to have the associated
decompression utilities (unzip, gunzip, unrar) installed.
Note(2): The format of the mod is NOT determined from the extension on
compressed mods. For example, if you zipped a UMX mod and gave it the
extension MDZ, it would work fine.
- plays timidity's GUS patch files (*.pat):
a multi sample pat file with n samples can be played with a Frere Jacques
canon with n voices.
- plays all types of MIDI files (*.mid):
uses the timidity .pat files for samples (when available)
recognizes environment variables:
MMPAT_PATH_TO_CFG set to the directory where the file "timidity.cfg" and
the subdirectory "instruments" can be found,
default: "/usr/local/share/timidity".
MMMID_SPEED for experimenting with the mod speed (1 thru 9)
MMMID_VERBOSE for feedback on the conversion process
MMMID_DEBUG for sake of completeness, only useful for maintainers
- plays textfiles written in the ABC music notation (*.abc):
uses the timidity .pat files for samples (when available)
recognizes environment variables:
MMPAT_PATH_TO_CFG set to the directory where the file "timidity.cfg" and
the subdirectory "instruments" can be found,
default: "/usr/local/share/timidity".
MMABC_NO_RANDOM_PICK when not set and the abc file contains multiple songs
(X:n) the first song to be played will be picked at random another click
on the play button advances to the next
song in the file (or the first when the last song has been
played), when set it can be 0 (zero) or not numeric
to let it play all songs in the file, a positive number n to
let it play the n-th song in the file, a negative number -n to
let it play the n-th song in the file and advancing to the next
song when the play button is clicked.
MMABC_DUMPTRACKS when set it gives diagnostic information on stdout,
values can be:
all - every event is printed
nonotes - only the control events (looping, breaks etc.) are printed
any other value prints the control events and every note event
immediately succeeding the control events.
- Slightly better sound quality than Mikmod. Vastly superior quality
over Winamp.
- All XMMS calls are supported except for the band gains on the
equalizer. The preamp is supported, but MOD music is not anywhere
near as cheap to equalize as MP3. Thus, equalization does is not
supported in this version. However, a variable bass boost option
is available in the configuration dialog (see below).
- Tons of playback options (see below).
----------
3. Options
----------
All of the following items are configurable from the plugin
configuration dialog box.
Sampling rate: Higher is better. Note that the sound is rendered at a
higher sampling rate and converted down to increase quality.
Bits per sample: 8-bit or 16-bit sound. Note that all computations are
done at 32-bit and converted down to the sampling rate you specify.
Channels: mono/stereo. Note that all computations are done in stereo.
If you choose mono, the channels will be mixed.
Resampling: Method used to convert samples to different sampling rates.
"Nearest" is the fastest setting (but sounds terrible), while
"8-tap fir" is the best-quality setting.
Noise Reduction: Reduces noise. :)
Fast Playlist Info: When this option is on, names of songs in your
playlist will load considerably faster, but song lengths will not be
shown and only MOD, S3M, XM, and IT formats will have their names shown.
Don't worry, though, because all the data which is skipped will still be
loaded when you actually play the song. This should probably always be
on.
Reverb: A nice reverb effect. The depth and delay of the reverb can be
tuned to your liking using the sliders.
Bass boost: Variable bass boost effect. The "range" slider controls the
frequency range of the bass boost. If you increase this value, higher
frequencies will be boosted, but the overall volume increase will be
less. (you can compensate by using the volume slider:)
Surround: Dolby Pro-Logic surround effect. Depth and delay can be fine
tuned.
Preamp: A global volume boost. Note that setting the preamp too high
will cause clipping (nasty clicks and pops).
Looping: Some mods have loops built-in. Normally, these loops are
ignored because otherwise the same mod would play forever. However,
you can choose to respect the loops, or even set a number of times to
follow a loop.
------------------
4. Troubleshooting
------------------
Problem:
Some of my files load up, but show garbled info in the playlist and/or
don't play correctly.
Possible cause:
The mod is in a different format than its file format suggests.
Modplug-XMMS uses a combination of file extension and contents to figure
out what format a mod is in, and can be thrown off if a mod is
incorrectly labeled.
Solution:
Turning off "fast info" in the configuration may fix the problem. This
will cause Modplug-XMMS to detect all basic mod types by content, but
archive types will still be detected by extension. If this doesn't
solve the problem, then you probably have files which are actually
compressed archives but are not labeled as such. For example, you may
have a file "aws_anew.xm" which is actually a ZIP archive. You will
have to either unzip these files or rename them to have an extension
associated with their type. In the case of a ZIP, you can use any of
the extensions "ZIP, MDZ, S3Z, XMZ, ITZ". (Note that these five types
are all treated exactly the same -- the actual format of the mod is
detected by contents.)
Problem:
Everything appears to be working, but no sound is being generated.
MP3's play just fine.
Possible cause:
Modplug has a relatively low default volume, and you may just not be
hearing it. (Note: Yes, more that one person has e-mailed me with
this problem.)
Solution:
Turn up your volume. You may wish to do this via the "preamp"
setting in the ModPlug configuration. This way, you won't have to
turn down your volume again when you play an MP3.
Problem:
You have a mod which is rendered incorrectly by ModPlug-XMMS.
Possible cause:
This could be our fault. :)
Solution:
First, test the mod using the Windows version of ModPlug, if you can.
If it sounds wrong there, then send the mod and a bug report to
Olivier Lapicque <olivierl@jps.net>. If the mod plays correctly in
Windows, however, then the bug is my fault. In that case, e-mail
me (Konstanty) <konstanty@ieee.org>. (previously Kenton Varda at
<temporal@gauge3d.org>).
Problem:
I have a problem which is not listed here, or an idea for a cool
feature.
Solution:
E-mail me (Konstanty) at <konstanty@ieee.org>. I would be
happy to hear any suggestions or problems you have.

View File

@ -0,0 +1,2 @@
Fix and check endian-ness issues.
Add looping flag to sound file / API function for this.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,347 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program 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, 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 <http://www.gnu.org/licenses/>.
# 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 file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# 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:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.63)
AC_INIT([libmodplug], [0.8.9.0])
AC_CONFIG_SRCDIR([Makefile.am])
AM_INIT_AUTOMAKE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
AC_CONFIG_HEADERS([src/config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_MAINTAINER_MODE([enable])
dnl Checks for programs.
dnl I am disabling static libraries here because otherwise libtool insists on
dnl compiling everything twice -- once with and once without -fPIC. Pisses me
dnl off. Just do everything with -fPIC, damnit! Compiling everything twice
dnl probably wastes more cycles than not using -fPIC saves.
AC_DISABLE_STATIC
AC_DISABLE_STATIC([])
AC_PROG_CC
AC_PROG_CXX
AC_LANG([C++])
AC_C_BIGENDIAN
#AC_LIBTOOL_WIN32_DLL
#AC_PROG_LIBTOOL
LT_INIT([win32-dll])
AC_HEADER_STDC
AC_CHECK_HEADERS([inttypes.h stdint.h malloc.h])
AC_CHECK_FUNCS(sinf)
CXXFLAGS="$CXXFLAGS -fno-exceptions -Wall -ffast-math -fno-common -D_REENTRANT"
AC_CANONICAL_HOST
case "$host" in
*mingw* | *cygwin*)
LT_LDFLAGS="-no-undefined"
;;
*)
LT_LDFLAGS=""
;;
esac
AC_SUBST(LT_LDFLAGS)
# require 10.5+ for osx/x86_64 builds
case "$host" in
x86_64-*-darwin*)
CXXFLAGS="$CXXFLAGS -mmacosx-version-min=10.5"
LDFLAGS="$LDFLAGS -mmacosx-version-min=10.5" ;;
esac
# symbol visibility
ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS -fvisibility=hidden -Werror"
AC_CACHE_CHECK([if compiler supports visibility attributes],[libmodplug_cv_gcc_visibility],
AC_TRY_COMPILE([void foo(void);
__attribute__((visibility("default"))) void foo(void) {}],
[],
[libmodplug_cv_gcc_visibility=yes],
[libmodplug_cv_gcc_visibility=no])
)
# we want symbol -fvisibility for elf targets, however it works
# with darwin/macho too. other than that, windows, dos and os2
# do not need it: for any such targets, the -Werror switch is
# supposed to fail the above check. (I'm adding the manual test
# below nonetheless, just in case.)
case $host_os in
mingw*|cygwin*|emx*|*djgpp)
libmodplug_cv_gcc_visibility=no
;;
esac
CXXFLAGS="$ac_save_CXXFLAGS"
if test $libmodplug_cv_gcc_visibility = yes ;then
CXXFLAGS="$CXXFLAGS -DSYM_VISIBILITY -fvisibility=hidden"
fi
case ${target_os} in
*sun* | *solaris*)
CXXFLAGS="$CXXFLAGS -fpermissive"
;;
esac
# portable types. requires autoconf 2.60
# `configure' will check if these are defined in system headers.
# if not, it will auto-detect and define them in `config.h'
AC_TYPE_INT8_T
AC_TYPE_UINT8_T
AC_TYPE_INT16_T
AC_TYPE_UINT16_T
AC_TYPE_INT32_T
AC_TYPE_UINT32_T
AC_TYPE_INT64_T
AC_TYPE_UINT64_T
MODPLUG_LIBRARY_VERSION=1:0:0
AC_SUBST(MODPLUG_LIBRARY_VERSION)
AC_CONFIG_FILES([Makefile
src/Makefile
libmodplug.pc])
AC_OUTPUT

View File

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program 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, 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 <http://www.gnu.org/licenses/>.
# 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 Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# 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:

View File

@ -0,0 +1,501 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2013-12-25.23; # 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.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# 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_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
is_target_a_directory=possibly
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
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
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
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
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
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 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 problematic for 'test' and other utilities.
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
# 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 "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
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-writable 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
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && 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` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
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:

View File

@ -0,0 +1,905 @@
- disable wav formats handling: SDL_mixer has its own code for it.
- disable midi formats handling: SDL_mixer has timidity or native midi for it.
- disable experimental file save support: no one uses it, ever.
- don't export cplusplus interface from shared libs. SDL_mixer doesn't use it.
- disable mmcmp unpacking. disable broken pp20 unpacking.
- merge https://github.com/Konstanty/libmodplug/pull/36 (fix PSM loader overwrites const data)
- merge https://github.com/Konstanty/libmodplug/pull/39 (case-sensitive STM signature checks)
- merge https://github.com/Konstanty/libmodplug/pull/40 (big-endian-friendly MDL track length read)
- merge https://github.com/Konstanty/libmodplug/pull/24 (make some stuff static)
- merge https://github.com/Konstanty/libmodplug/pull/14 (NO_PACKING / MODPLUG_NO_FILESAVE ifdefs)
- merge https://github.com/Konstanty/libmodplug/pull/32 (replace setenv)
- merge https://github.com/Konstanty/libmodplug/pull/41 (timidity paths update)
diff -u libmodplug-0.8.9.0/configure.ac~ libmodplug-0.8.9.0/configure.ac
--- libmodplug-0.8.9.0/configure.ac~
+++ libmodplug-0.8.9.0/configure.ac
@@ -29,7 +29,7 @@ LT_INIT([win32-dll])
AC_HEADER_STDC
AC_CHECK_HEADERS([inttypes.h stdint.h malloc.h])
-AC_CHECK_FUNCS(setenv sinf)
+AC_CHECK_FUNCS(sinf)
CXXFLAGS="$CXXFLAGS -fno-exceptions -Wall -ffast-math -fno-common -D_REENTRANT"
@@ -99,6 +99,6 @@ MODPLUG_LIBRARY_VERSION=1:0:0
AC_SUBST(MODPLUG_LIBRARY_VERSION)
AC_CONFIG_FILES([Makefile
- src/Makefile
+ src/Makefile
libmodplug.pc])
AC_OUTPUT
diff -u libmodplug-0.8.9.0/configure~ libmodplug-0.8.9.0/configure
--- libmodplug-0.8.9.0/configure~
+++ libmodplug-0.8.9.0/configure
@@ -16702,13 +16702,12 @@ fi
done
-for ac_func in setenv sinf
+for ac_func in sinf
do :
- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
-ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ ac_fn_cxx_check_func "$LINENO" "sinf" "ac_cv_func_sinf"
+if test "x$ac_cv_func_sinf" = xyes; then :
cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_SINF 1
_ACEOF
fi
diff -u libmodplug-0.8.9.0/src/config.h.in~ libmodplug-0.8.9.0/src/config.h.in
--- libmodplug-0.8.9.0/src/config.h.in~
+++ libmodplug-0.8.9.0/src/config.h.in
@@ -15,9 +15,6 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
-/* Define to 1 if you have the `setenv' function. */
-#undef HAVE_SETENV
-
/* Define to 1 if you have the `sinf' function. */
#undef HAVE_SINF
diff -up libmodplug-0.8.9.0/src/libmodplug/it_defs.h~ libmodplug-0.8.9.0/src/libmodplug/it_defs.h
--- libmodplug-0.8.9.0/src/libmodplug/it_defs.h~
+++ libmodplug-0.8.9.0/src/libmodplug/it_defs.h
@@ -128,7 +128,9 @@ typedef struct ITSAMPLESTRUCT
#pragma pack()
-extern BYTE autovibit2xm[8];
-extern BYTE autovibxm2it[8];
+#if 0/* made these two static to load_it.cpp */
+extern const BYTE autovibit2xm[8];
+extern const BYTE autovibxm2it[8];
+#endif
#endif
diff -up libmodplug-0.8.9.0/src/libmodplug/sndfile.h~ libmodplug-0.8.9.0/src/libmodplug/sndfile.h
--- libmodplug-0.8.9.0/src/libmodplug/sndfile.h~
+++ libmodplug-0.8.9.0/src/libmodplug/sndfile.h
@@ -456,7 +456,7 @@ typedef struct _MODCOMMAND
// Mix Plugins
#define MIXPLUG_MIXREADY 0x01 // Set when cleared
-class MODPLUG_EXPORT IMixPlugin
+class /*MODPLUG_EXPORT*/ IMixPlugin
{
public:
virtual ~IMixPlugin() {};
@@ -535,7 +535,7 @@ typedef VOID (* LPSNDMIXHOOKPROC)(int *,
//==============
-class MODPLUG_EXPORT CSoundFile
+class /*MODPLUG_EXPORT*/ CSoundFile
//==============
{
public: // Static Members
@@ -638,7 +638,9 @@ public:
BOOL ReadIT(LPCBYTE lpStream, DWORD dwMemLength);
BOOL Read669(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadUlt(LPCBYTE lpStream, DWORD dwMemLength);
+#ifndef NO_WAVFORMAT
BOOL ReadWav(LPCBYTE lpStream, DWORD dwMemLength);
+#endif
BOOL ReadDSM(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadFAR(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadAMS(LPCBYTE lpStream, DWORD dwMemLength);
@@ -653,12 +655,14 @@ public:
BOOL ReadPSM(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadJ2B(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadUMX(LPCBYTE lpStream, DWORD dwMemLength);
+#ifndef NO_MIDIFORMATS
BOOL ReadABC(LPCBYTE lpStream, DWORD dwMemLength);
BOOL TestABC(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadMID(LPCBYTE lpStream, DWORD dwMemLength);
BOOL TestMID(LPCBYTE lpStream, DWORD dwMemLength);
BOOL ReadPAT(LPCBYTE lpStream, DWORD dwMemLength);
BOOL TestPAT(LPCBYTE lpStream, DWORD dwMemLength);
+#endif
// Save Functions
#ifndef MODPLUG_NO_FILESAVE
UINT WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen=0);
@@ -666,14 +670,16 @@ public:
BOOL SaveS3M(LPCSTR lpszFileName, UINT nPacking=0);
BOOL SaveMod(LPCSTR lpszFileName, UINT nPacking=0);
BOOL SaveIT(LPCSTR lpszFileName, UINT nPacking=0);
-#endif // MODPLUG_NO_FILESAVE
- // MOD Convert function
UINT GetBestSaveFormat() const;
UINT GetSaveFormats() const;
+#endif
+ // MOD Convert function
void ConvertModCommand(MODCOMMAND *) const;
void S3MConvert(MODCOMMAND *m, BOOL bIT) const;
+#ifndef MODPLUG_NO_FILESAVE
void S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const;
WORD ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const;
+#endif
public:
// Real-time sound functions
@@ -759,8 +765,11 @@ public:
BOOL IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const;
// Read/Write sample functions
signed char GetDeltaValue(signed char prev, UINT n) const { return (signed char)(prev + CompressionTable[n & 0x0F]); }
+#if !(defined(MODPLUG_NO_FILESAVE)||defined(NO_PACKING))
UINT PackSample(int &sample, int next);
BOOL CanPackSample(LPSTR pSample, UINT nLen, UINT nPacking, BYTE *result=NULL);
+#endif // NO_FILESAVE, NO_PACKING
+
UINT ReadSample(MODINSTRUMENT *pIns, UINT nFlags, LPCSTR pMemFile, DWORD dwMemLength);
BOOL DestroySample(UINT nSample);
BOOL DestroyInstrument(UINT nInstr);
diff -up libmodplug-0.8.9.0/src/libmodplug/stdafx.h~ libmodplug-0.8.9.0/src/libmodplug/stdafx.h
--- libmodplug-0.8.9.0/src/libmodplug/stdafx.h~
+++ libmodplug-0.8.9.0/src/libmodplug/stdafx.h
@@ -21,9 +21,15 @@
# include <stdint.h>
#endif
+/*#define MMCMP_SUPPORT*/
+
/* disable AGC and FILESAVE for all targets for uniformity. */
#define NO_AGC
#define MODPLUG_NO_FILESAVE
+/*#define NO_PACKING*/
+/*#define NO_FILTER */
+#define NO_MIDIFORMATS
+#define NO_WAVFORMAT
#ifdef _WIN32
@@ -88,12 +94,6 @@ typedef const char* LPCSTR;
typedef void* PVOID;
typedef void VOID;
-inline LONG MulDiv (long a, long b, long c)
-{
-/*if (!c) return 0;*/
- return ((uint64_t) a * (uint64_t) b ) / c;
-}
-
#define LPCTSTR LPCSTR
#define lstrcpyn strncpy
#define lstrcpy strcpy
diff -up libmodplug-0.8.9.0/src/load_669.cpp~ libmodplug-0.8.9.0/src/load_669.cpp
--- libmodplug-0.8.9.0/src/load_669.cpp~
+++ libmodplug-0.8.9.0/src/load_669.cpp
@@ -17,7 +17,7 @@
typedef struct tagFILEHEADER669
{
WORD sig; // 'if' or 'JN'
- signed char songmessage[108]; // Song Message
+ signed char songmessage[108]; // Song Message
BYTE samples; // number of samples (1-64)
BYTE patterns; // number of patterns (1-128)
BYTE restartpos;
@@ -35,7 +35,7 @@ typedef struct tagSAMPLE669
BYTE loopend[4];
} SAMPLE669;
-DWORD lengthArrayToDWORD(const BYTE length[4]) {
+static DWORD lengthArrayToDWORD(const BYTE length[4]) {
DWORD len = (length[3] << 24) +
(length[2] << 16) +
(length[1] << 8) +
diff -up libmodplug-0.8.9.0/src/load_abc.cpp~ libmodplug-0.8.9.0/src/load_abc.cpp
--- libmodplug-0.8.9.0/src/load_abc.cpp~
+++ libmodplug-0.8.9.0/src/load_abc.cpp
@@ -37,9 +37,11 @@
#include "stdafx.h"
#include "sndfile.h"
+#ifndef NO_MIDIFORMATS
+
#include "load_pat.h"
-#if _MSC_VER >= 1600
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
#define putenv _putenv
#define strdup _strdup
#endif
@@ -256,16 +258,6 @@ static void abc_add_setjumploop(ABCHANDL
static uint32_t abc_pattracktime(ABCHANDLE *h, uint32_t tracktime);
static int abc_patno(ABCHANDLE *h, uint32_t tracktime);
-#ifndef HAVE_SETENV
-static void setenv(const char *name, const char *value, int overwrite)
-{
- int len = strlen(name)+1+strlen(value)+1;
- char *str = (char *)malloc(len);
- sprintf(str, "%s=%s", name, value);
- putenv(str);
- free(str);
-}
-#endif
static int abc_isvalidchar(char c) {
return(isalpha(c) || isdigit(c) || isspace(c) || c == '%' || c == ':');
@@ -2345,9 +2337,9 @@ BOOL CSoundFile::TestABC(const BYTE *lpS
// =====================================================================================
static ABCHANDLE *ABC_Init(void)
{
+ static char buf[40];
ABCHANDLE *retval;
char *p;
- char buf[10];
retval = (ABCHANDLE *)calloc(1,sizeof(ABCHANDLE));
if( !retval ) return NULL;
retval->track = NULL;
@@ -2365,16 +2357,16 @@ static ABCHANDLE *ABC_Init(void)
retval->pickrandom = atoi(p);
if( *p == '-' ) {
retval->pickrandom = atoi(p+1)-1; // xmms preloads the file
- sprintf(buf,"-%ld",retval->pickrandom+2);
- setenv(ABC_ENV_NORANDOMPICK, buf, 1);
+ sprintf(buf,"%s=-%ld",ABC_ENV_NORANDOMPICK,retval->pickrandom+2);
+ putenv(buf);
}
}
else {
srandom((uint32_t)time(0)); // initialize random generator with seed
retval->pickrandom = 1+(int)(10000.0*random()/(RAND_MAX+1.0));
// can handle pickin' from songbooks with 10.000 songs
- sprintf(buf,"-%ld",retval->pickrandom); // xmms preloads the file
- setenv(ABC_ENV_NORANDOMPICK, buf, 1);
+ sprintf(buf,"%s=-%ld",ABC_ENV_NORANDOMPICK,retval->pickrandom); // xmms preloads the file
+ putenv(buf);
}
return retval;
}
@@ -4878,3 +4870,4 @@ BOOL CSoundFile::ReadABC(const uint8_t *
ABC_Cleanup(h); // we dont need it anymore
return 1;
}
+#endif // NO_MIDIFORMATS
diff -up libmodplug-0.8.9.0/src/load_amf.cpp~ libmodplug-0.8.9.0/src/load_amf.cpp
--- libmodplug-0.8.9.0/src/load_amf.cpp~
+++ libmodplug-0.8.9.0/src/load_amf.cpp
@@ -44,7 +44,6 @@ typedef struct _AMFSAMPLE
UCHAR volume;
} AMFSAMPLE;
-
#pragma pack()
@@ -52,7 +51,7 @@ typedef struct _AMFSAMPLE
extern void Log(LPCSTR, ...);
#endif
-VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
+static VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
//-------------------------------------------------------------------------------
{
UINT lastinstr = 0;
@@ -163,7 +162,6 @@ VOID AMF_Unpack(MODCOMMAND *pPat, const
}
-
BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, const DWORD dwMemLength)
//-----------------------------------------------------------
{
diff -up libmodplug-0.8.9.0/src/load_dmf.cpp~ libmodplug-0.8.9.0/src/load_dmf.cpp
--- libmodplug-0.8.9.0/src/load_dmf.cpp~
+++ libmodplug-0.8.9.0/src/load_dmf.cpp
@@ -509,7 +509,7 @@ typedef struct DMF_HTREE
// DMF Huffman ReadBits
-BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits)
+static BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits)
//-------------------------------------------
{
BYTE x = 0, bitv = 1;
@@ -534,7 +534,7 @@ BYTE DMFReadBits(DMF_HTREE *tree, UINT n
// tree: [8-bit value][12-bit index][12-bit index] = 32-bit
//
-void DMFNewNode(DMF_HTREE *tree)
+static void DMFNewNode(DMF_HTREE *tree)
//------------------------------
{
BYTE isleft, isright;
diff -up libmodplug-0.8.9.0/src/load_it.cpp~ libmodplug-0.8.9.0/src/load_it.cpp
--- libmodplug-0.8.9.0/src/load_it.cpp~
+++ libmodplug-0.8.9.0/src/load_it.cpp
@@ -15,19 +15,18 @@
#pragma warning(disable:4244)
#endif
+static const
BYTE autovibit2xm[8] =
{ 0, 3, 1, 4, 2, 0, 0, 0 };
-
+#ifndef MODPLUG_NO_FILESAVE
+static const
BYTE autovibxm2it[8] =
{ 0, 2, 4, 1, 3, 0, 0, 0 };
+#endif
//////////////////////////////////////////////////////////
// Impulse Tracker IT file support
-// for conversion of XM samples
-extern WORD XMPeriodTable[96+8];
-extern UINT XMLinearTable[768];
-
static inline UINT ConvertVolParam(UINT value)
//--------------------------------------------
{
diff -up libmodplug-0.8.9.0/src/load_mdl.cpp~ libmodplug-0.8.9.0/src/load_mdl.cpp
--- libmodplug-0.8.9.0/src/load_mdl.cpp~
+++ libmodplug-0.8.9.0/src/load_mdl.cpp
@@ -42,7 +42,7 @@ typedef struct MDLPATTERNDATA
} MDLPATTERNDATA;
-void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data)
+static void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data)
//--------------------------------------------------------
{
UINT command = 0, param = data;
@@ -91,7 +91,7 @@ void ConvertMDLCommand(MODCOMMAND *m, UI
}
-void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks, UINT len)
+static void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks, UINT len)
//-------------------------------------------------------------------------------------------------
{
MODCOMMAND cmd, *m = pat;
@@ -168,7 +168,6 @@ void UnpackMDLTrack(MODCOMMAND *pat, UIN
}
-
BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
@@ -429,12 +428,13 @@ BOOL CSoundFile::ReadMDL(const BYTE *lpS
for (UINT ipat=0; ipat<npatterns; ipat++)
{
if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break;
- for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks) && (*(WORD *)lpStream+dwTrackPos) < dwMemLength-dwTrackPos)
+ for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks))
{
+ const BYTE *lpTracks = lpStream + dwTrackPos;
+ UINT len = lpTracks[0] | (lpTracks[1] << 8);
+ if (len < dwMemLength-dwTrackPos) {
MODCOMMAND *m = Patterns[ipat] + chn;
UINT nTrack = patterntracks[ipat*32+chn];
- const BYTE *lpTracks = lpStream + dwTrackPos;
- UINT len = lpTracks[0] | (lpTracks[1] << 8);
lpTracks += 2;
for (UINT ntrk=1; ntrk<nTrack && lpTracks < (dwMemLength + lpStream - len); ntrk++)
@@ -447,6 +447,7 @@ BOOL CSoundFile::ReadMDL(const BYTE *lpS
if ( len > dwMemLength - dwTrackPos ) len = 0;
UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], nTrack, lpTracks, len);
+ }
}
}
}
diff -up libmodplug-0.8.9.0/src/load_mid.cpp~ libmodplug-0.8.9.0/src/load_mid.cpp
--- libmodplug-0.8.9.0/src/load_mid.cpp~
+++ libmodplug-0.8.9.0/src/load_mid.cpp
@@ -35,6 +35,9 @@
#include "stdafx.h"
#include "sndfile.h"
+
+#ifndef NO_MIDIFORMATS
+
#define PAN_LEFT 0x30
#define PAN_RIGHT 0xD0
#define MAX_POLYPHONY 16 // max notes in one midi channel
@@ -92,7 +95,7 @@ typedef struct _MIDTRACK
#undef _mm_free
#endif
-#define MMSTREAM FILE
+#define MMSTREAM FILE
#define _mm_fseek(f,pos,whence) fseek(f,pos,whence)
#define _mm_read_UBYTES(buf,sz,f) fread(buf,sz,1,f)
#define _mm_read_SBYTES(buf,sz,f) fread(buf,sz,1,f)
@@ -1582,3 +1585,4 @@ BOOL CSoundFile::ReadMID(const BYTE *lpS
avoid_reentry = 0; // it is safe now, I'm finished
return TRUE;
}
+#endif // NO_MIDIFORMATS
diff -up libmodplug-0.8.9.0/src/load_mod.cpp~ libmodplug-0.8.9.0/src/load_mod.cpp
--- libmodplug-0.8.9.0/src/load_mod.cpp~
+++ libmodplug-0.8.9.0/src/load_mod.cpp
@@ -60,6 +60,7 @@ void CSoundFile::ConvertModCommand(MODCO
}
+#ifndef MODPLUG_NO_FILESAVE
WORD CSoundFile::ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const
//------------------------------------------------------------------
{
@@ -144,6 +145,7 @@ WORD CSoundFile::ModSaveCommand(const MO
}
return (WORD)((command << 8) | (param));
}
+#endif // MODPLUG_NO_FILESAVE
#pragma pack(1)
@@ -184,7 +186,7 @@ static BOOL IsValidName(LPCSTR s, int le
return TRUE;
}
-BOOL IsMagic(LPCSTR s1, LPCSTR s2)
+static BOOL IsMagic(LPCSTR s1, LPCSTR s2)
{
return ((*(DWORD *)s1) == (*(DWORD *)s2)) ? TRUE : FALSE;
}
diff -up libmodplug-0.8.9.0/src/load_pat.cpp~ libmodplug-0.8.9.0/src/load_pat.cpp
--- libmodplug-0.8.9.0/src/load_pat.cpp~
+++ libmodplug-0.8.9.0/src/load_pat.cpp
@@ -44,16 +44,18 @@
#include "stdafx.h"
#include "sndfile.h"
+#ifndef NO_MIDIFORMATS
+
#include "load_pat.h"
-#ifdef MSC_VER
+#ifdef _WIN32
#define DIRDELIM '\\'
#define TIMIDITYCFG "C:\\TIMIDITY\\TIMIDITY.CFG"
#define PATHFORPAT "C:\\TIMIDITY\\INSTRUMENTS"
#else
#define DIRDELIM '/'
-#define TIMIDITYCFG "/usr/local/share/timidity/timidity.cfg"
-#define PATHFORPAT "/usr/local/share/timidity/instruments"
+#define TIMIDITYCFG "/etc/timidity.cfg" /*"/usr/share/timidity/timidity.cfg"*/
+#define PATHFORPAT "/usr/share/timidity/instruments"
#endif
#define PAT_ENV_PATH2CFG "MMPAT_PATH_TO_CFG"
@@ -764,10 +766,7 @@ BOOL CSoundFile::TestPAT(const BYTE *lpS
// =====================================================================================
static PATHANDLE *PAT_Init(void)
{
- PATHANDLE *retval;
- retval = (PATHANDLE *)calloc(1,sizeof(PATHANDLE));
- if( !retval ) return NULL;
- return retval;
+ return (PATHANDLE *)calloc(1,sizeof(PATHANDLE));
}
// =====================================================================================
@@ -1259,3 +1258,4 @@ BOOL CSoundFile::ReadPAT(const BYTE *lpS
PAT_Cleanup(h); // we dont need it anymore
return 1;
}
+#endif // NO_MIDIFORMATS
diff -up libmodplug-0.8.9.0/src/load_psm.cpp~ libmodplug-0.8.9.0/src/load_psm.cpp
--- libmodplug-0.8.9.0/src/load_psm.cpp~
+++ libmodplug-0.8.9.0/src/load_psm.cpp
@@ -84,7 +84,9 @@ typedef struct _PSMSAMPLE
BYTE reserved6[19];
} PSMSAMPLE;
-void swap_PSMSAMPLE(PSMSAMPLE* p){
+#pragma pack()
+
+static void swap_PSMSAMPLE(PSMSAMPLE* p){
p->smpid = bswapLE32(p->smpid);
p->length = bswapLE32(p->length);
p->loopstart = bswapLE32(p->loopstart);
@@ -92,13 +94,11 @@ void swap_PSMSAMPLE(PSMSAMPLE* p){
p->samplerate = bswapLE32(p->samplerate);
}
-#pragma pack()
-
BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
- PSMCHUNK *pfh = (PSMCHUNK *)lpStream;
+ PSMCHUNK pfh = *(const PSMCHUNK *)lpStream;
DWORD dwMemPos, dwSongPos;
DWORD smpnames[MAX_SAMPLES];
DWORD patptrs[MAX_PATTERNS];
@@ -108,17 +108,17 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
if (dwMemLength < 256) return FALSE;
// Swap chunk
- swap_PSMCHUNK(pfh);
+ swap_PSMCHUNK(&pfh);
// Chunk0: "PSM ",filesize,"FILE"
- if (pfh->id == PSM_ID_OLD)
+ if (pfh.id == PSM_ID_OLD)
{
#ifdef PSM_LOG
Log("Old PSM format not supported\n");
#endif
return FALSE;
}
- if ((pfh->id != PSM_ID_NEW) || (pfh->len+12 > dwMemLength) || (pfh->listid != IFFID_FILE)) return FALSE;
+ if ((pfh.id != PSM_ID_NEW) || (pfh.len+12 > dwMemLength) || (pfh.listid != IFFID_FILE)) return FALSE;
m_nType = MOD_TYPE_PSM;
m_nChannels = 16;
m_nSamples = 0;
@@ -132,13 +132,13 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
}
while (dwMemPos+8 < dwMemLength)
{
- PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos);
- swap_PSMCHUNK(pchunk);
- if ((pchunk->len >= dwMemLength - 8) || (dwMemPos + pchunk->len + 8 > dwMemLength)) break;
+ PSMCHUNK pchunk = *(const PSMCHUNK *)(lpStream+dwMemPos);
+ swap_PSMCHUNK(&pchunk);
+ if ((pchunk.len >= dwMemLength - 8) || (dwMemPos + pchunk.len + 8 > dwMemLength)) break;
dwMemPos += 8;
PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
- ULONG len = pchunk->len;
- if (len) switch(pchunk->id)
+ ULONG len = pchunk.len;
+ if (len) switch(pchunk.id)
{
// "TITL": Song title
case IFFID_TITL:
@@ -166,21 +166,21 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
{
m_nSamples++;
MODINSTRUMENT *pins = &Ins[m_nSamples];
- PSMSAMPLE *psmp = (PSMSAMPLE *)pdata;
- swap_PSMSAMPLE(psmp);
- smpnames[m_nSamples] = psmp->smpid;
- memcpy(m_szNames[m_nSamples], psmp->samplename, 31);
+ PSMSAMPLE psmp = *(PSMSAMPLE *)pdata;
+ swap_PSMSAMPLE(&psmp);
+ smpnames[m_nSamples] = psmp.smpid;
+ memcpy(m_szNames[m_nSamples], psmp.samplename, 31);
m_szNames[m_nSamples][31] = 0;
samplemap[m_nSamples-1] = (BYTE)m_nSamples;
// Init sample
pins->nGlobalVol = 0x40;
- pins->nC4Speed = psmp->samplerate;
- pins->nLength = psmp->length;
- pins->nLoopStart = psmp->loopstart;
- pins->nLoopEnd = psmp->loopend;
+ pins->nC4Speed = psmp.samplerate;
+ pins->nLength = psmp.length;
+ pins->nLoopStart = psmp.loopstart;
+ pins->nLoopEnd = psmp.loopend;
pins->nPan = 128;
- pins->nVolume = (psmp->defvol+1) * 2;
- pins->uFlags = (psmp->flags & 0x80) ? CHN_LOOP : 0;
+ pins->nVolume = (psmp.defvol+1) * 2;
+ pins->uFlags = (psmp.flags & 0x80) ? CHN_LOOP : 0;
if (pins->nLoopStart > 0) pins->nLoopStart--;
// Point to sample data
pdata += 0x60;
@@ -199,17 +199,17 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
default:
{
CHAR s[8], s2[64];
- *(DWORD *)s = pchunk->id;
+ *(DWORD *)s = pchunk.id;
s[4] = 0;
- wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk->len, dwMemPos);
+ wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk.len, dwMemPos);
OutputDebugString(s2);
}
#endif
}
- dwMemPos += pchunk->len;
+ dwMemPos += pchunk.len;
}
// Step #1: convert song structure
- PSMSONGHDR *pSong = (PSMSONGHDR *)(lpStream+dwSongPos+8);
+ const PSMSONGHDR *pSong = (const PSMSONGHDR *)(lpStream+dwSongPos+8);
if ((!dwSongPos) || (pSong->channels < 2) || (pSong->channels > 32)) return TRUE;
m_nChannels = pSong->channels;
// Valid song header -> convert attached chunks
@@ -218,13 +218,13 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
dwMemPos = dwSongPos + 8 + 11; // sizeof(PSMCHUNK)+sizeof(PSMSONGHDR)
while (dwMemPos + 8 < dwSongEnd)
{
- PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos);
- swap_PSMCHUNK(pchunk);
+ PSMCHUNK pchunk = *(const PSMCHUNK *)(lpStream+dwMemPos);
+ swap_PSMCHUNK(&pchunk);
dwMemPos += 8;
- if ((pchunk->len > dwSongEnd) || (dwMemPos + pchunk->len > dwSongEnd)) break;
+ if ((pchunk.len > dwSongEnd) || (dwMemPos + pchunk.len > dwSongEnd)) break;
PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
- ULONG len = pchunk->len;
- switch(pchunk->id)
+ ULONG len = pchunk.len;
+ switch(pchunk.id)
{
case IFFID_OPLH:
if (len >= 0x20)
@@ -237,7 +237,7 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
DWORD dwName = *(DWORD *)(pdata+pos);
for (UINT i=0; i<nPatterns; i++)
{
- DWORD dwPatName = ((PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
+ DWORD dwPatName = ((const PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
if (dwName == dwPatName)
{
bFound = TRUE;
@@ -258,7 +258,7 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
DWORD dwName = *(DWORD *)(pdata+pos);
for (UINT i=0; i<nPatterns; i++)
{
- DWORD dwPatName = ((PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
+ DWORD dwPatName = ((const PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
if (dwName == dwPatName)
{
Order[iOrd++] = i;
@@ -270,23 +270,23 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
}
break;
}
- dwMemPos += pchunk->len;
+ dwMemPos += pchunk.len;
}
}
// Step #2: convert patterns
for (UINT nPat=0; nPat<nPatterns; nPat++)
{
- PSMPATTERN *pPsmPat = (PSMPATTERN *)(lpStream+patptrs[nPat]+8);
- swap_PSMPATTERN(pPsmPat);
+ PSMPATTERN pPsmPat = *(const PSMPATTERN *)(lpStream+patptrs[nPat]+8);
+ swap_PSMPATTERN(&pPsmPat);
ULONG len = *(DWORD *)(lpStream+patptrs[nPat]+4) - 12;
- UINT nRows = pPsmPat->rows;
- if (len > pPsmPat->size) len = pPsmPat->size;
+ UINT nRows = pPsmPat.rows;
+ if (len > pPsmPat.size) len = pPsmPat.size;
if ((nRows < 64) || (nRows > 256)) nRows = 64;
PatternSize[nPat] = nRows;
if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break;
MODCOMMAND *m = Patterns[nPat];
- BYTE *p = pPsmPat->data;
+ BYTE *p = pPsmPat.data;
MODCOMMAND *sp, dummy;
UINT pos = 0;
UINT row = 0;
@@ -295,7 +295,7 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream));
#endif
UINT flags, ch;
- rowlim = bswapLE16(pPsmPat->reserved1)-2;
+ rowlim = bswapLE16(pPsmPat.reserved1)-2;
while ((row < nRows) && (pos+3 < len))
{
if ((pos+1) >= rowlim) {
@@ -393,7 +393,7 @@ BOOL CSoundFile::ReadPSM(LPCBYTE lpStrea
#ifdef PSM_LOG
if (pos < len)
{
- Log("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat->rows, pPsmPat->size, len-pos);
+ Log("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat.rows, pPsmPat.size, len-pos);
}
#endif
}
diff -up libmodplug-0.8.9.0/src/load_s3m.cpp~ libmodplug-0.8.9.0/src/load_s3m.cpp
--- libmodplug-0.8.9.0/src/load_s3m.cpp~
+++ libmodplug-0.8.9.0/src/load_s3m.cpp
@@ -105,6 +105,7 @@ void CSoundFile::S3MConvert(MODCOMMAND *
}
+#ifndef MODPLUG_NO_FILESAVE
void CSoundFile::S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const
//---------------------------------------------------------------------
{
@@ -182,6 +183,7 @@ void CSoundFile::S3MSaveConvert(UINT *pc
*pcmd = command;
*pprm = param;
}
+#endif // MODPLUG_NO_FILESAVE
static DWORD boundInput(DWORD input, DWORD smin, DWORD smax)
{
diff -up libmodplug-0.8.9.0/src/load_stm.cpp~ libmodplug-0.8.9.0/src/load_stm.cpp
--- libmodplug-0.8.9.0/src/load_stm.cpp~
+++ libmodplug-0.8.9.0/src/load_stm.cpp
@@ -64,8 +64,8 @@ BOOL CSoundFile::ReadSTM(const BYTE *lpS
if ((!lpStream) || (dwMemLength < sizeof(STMHEADER))) return FALSE;
if ((phdr->filetype != 2) || (phdr->unused != 0x1A)
- || ((strncasecmp(phdr->trackername, "!SCREAM!", 8))
- && (strncasecmp(phdr->trackername, "BMOD2STM", 8)))) return FALSE;
+ || ((strncmp(phdr->trackername, "!Scream!", 8))
+ && (strncmp(phdr->trackername, "BMOD2STM", 8)))) return FALSE;
memcpy(m_szNames[0], phdr->songname, 20);
// Read STM header
m_nType = MOD_TYPE_STM;
diff -up libmodplug-0.8.9.0/src/load_wav.cpp~ libmodplug-0.8.9.0/src/load_wav.cpp
--- libmodplug-0.8.9.0/src/load_wav.cpp~
+++ libmodplug-0.8.9.0/src/load_wav.cpp
@@ -7,6 +7,8 @@
#include "stdafx.h"
#include "sndfile.h"
+#ifndef NO_WAVFORMAT
+
#ifndef WAVE_FORMAT_EXTENSIBLE
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
@@ -170,7 +172,6 @@ static const int gIMAUnpackTable[90] =
32767, 0
};
-
BOOL IMAADPCMUnpack16(signed short *pdest, UINT nLen, LPBYTE psrc, DWORD dwBytes, UINT pkBlkAlign)
//------------------------------------------------------------------------------------------------
{
@@ -215,3 +216,4 @@ BOOL IMAADPCMUnpack16(signed short *pdes
}
return TRUE;
}
+#endif // NO_WAVFORMAT
diff -up libmodplug-0.8.9.0/src/mmcmp.cpp~ libmodplug-0.8.9.0/src/mmcmp.cpp
--- libmodplug-0.8.9.0/src/mmcmp.cpp~
+++ libmodplug-0.8.9.0/src/mmcmp.cpp
@@ -8,6 +8,7 @@
#include "stdafx.h"
#include "sndfile.h"
+#ifdef MMCMP_SUPPORT
BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
#pragma pack(1)
@@ -501,3 +502,4 @@ BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPD
*pdwMemLength = dwDstLen;
return TRUE;
}
+#endif /* MMCMP_SUPPORT */
diff -up libmodplug-0.8.9.0/src/sndfile.cpp~ libmodplug-0.8.9.0/src/sndfile.cpp
--- libmodplug-0.8.9.0/src/sndfile.cpp~
+++ libmodplug-0.8.9.0/src/sndfile.cpp
@@ -9,8 +9,6 @@
#include "libmodplug/stdafx.h"
#include "libmodplug/sndfile.h"
-#define MMCMP_SUPPORT
-
#ifdef MMCMP_SUPPORT
extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
#endif
@@ -24,9 +22,11 @@ extern void ITUnpack8Bit(signed char *pS
extern void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215);
+#ifndef MODPLUG_NO_FILESAVE
+#ifndef NO_PACKING
+
#define MAX_PACK_TABLES 3
-
// Compression table
static const signed char UnpackTable[MAX_PACK_TABLES][16] =
//--------------------------------------------
@@ -40,6 +40,8 @@ static const signed char UnpackTable[MAX
{0, 1, 2, 3, 5, 7, 12, 19,
-1, -2, -3, -5, -7, -12, -19, -31}
};
+#endif
+#endif
//////////////////////////////////////////////////////////
@@ -140,12 +142,16 @@ BOOL CSoundFile::Create(LPCBYTE lpStream
if ((!ReadXM(lpStream, dwMemLength))
&& (!ReadS3M(lpStream, dwMemLength))
&& (!ReadIT(lpStream, dwMemLength))
+#ifndef NO_WAVFORMAT
&& (!ReadWav(lpStream, dwMemLength))
+#endif
#ifndef MODPLUG_BASIC_SUPPORT
+#ifndef NO_MIDIFORMATS
/* Sequencer File Format Support */
&& (!ReadABC(lpStream, dwMemLength))
&& (!ReadMID(lpStream, dwMemLength))
&& (!ReadPAT(lpStream, dwMemLength))
+#endif
&& (!ReadSTM(lpStream, dwMemLength))
&& (!ReadMed(lpStream, dwMemLength))
&& (!ReadMTM(lpStream, dwMemLength))
@@ -753,6 +759,7 @@ void CSoundFile::LoopPattern(int nPat, i
}
+#ifndef MODPLUG_NO_FILESAVE
UINT CSoundFile::GetBestSaveFormat() const
//----------------------------------------
{
@@ -767,7 +774,6 @@ UINT CSoundFile::GetBestSaveFormat() con
return MOD_TYPE_IT;
}
-
UINT CSoundFile::GetSaveFormats() const
//-------------------------------------
{
@@ -786,6 +792,7 @@ UINT CSoundFile::GetSaveFormats() const
}
return n;
}
+#endif // MODPLUG_NO_FILESAVE
UINT CSoundFile::GetSampleName(UINT nSample,LPSTR s) const
@@ -817,6 +824,8 @@ UINT CSoundFile::GetInstrumentName(UINT
}
+#ifndef MODPLUG_NO_FILESAVE
+
#ifndef NO_PACKING
UINT CSoundFile::PackSample(int &sample, int next)
//------------------------------------------------
@@ -877,8 +886,6 @@ BOOL CSoundFile::CanPackSample(LPSTR pSa
}
#endif // NO_PACKING
-#ifndef MODPLUG_NO_FILESAVE
-
UINT CSoundFile::WriteSample(FILE *f, MODINSTRUMENT *pins, UINT nFlags, UINT nMaxLen)
//-----------------------------------------------------------------------------------
{
diff -up libmodplug-0.8.9.0/src/sndmix.cpp~ libmodplug-0.8.9.0/src/sndmix.cpp
--- libmodplug-0.8.9.0/src/sndmix.cpp~
+++ libmodplug-0.8.9.0/src/sndmix.cpp
@@ -60,7 +60,7 @@ UINT gnReverbSend;
// Log tables for pre-amp
// We don't want the tracker to get too loud
-const UINT PreAmpTable[16] =
+static const UINT PreAmpTable[16] =
{
0x60, 0x60, 0x60, 0x70, // 0-7
0x80, 0x88, 0x90, 0x98, // 8-15
@@ -68,7 +68,7 @@ const UINT PreAmpTable[16] =
0xB4, 0xB8, 0xBC, 0xC0, // 24-31
};
-const UINT PreAmpAGCTable[16] =
+static const UINT PreAmpAGCTable[16] =
{
0x60, 0x60, 0x60, 0x60,
0x68, 0x70, 0x78, 0x80,

View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=${prefix}/include
Name: libmodplug
Description: The ModPlug mod file playing library.
Version: @VERSION@
Requires:
Libs: -L${libdir} -lmodplug
Libs.private: -lstdc++ -lm
Cflags: -I${includedir}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,437 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option '$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
[_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the 'shared' and
# 'disable-shared' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the 'static' and
# 'disable-static' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the 'fast-install'
# and 'disable-fast-install' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_AIX_SONAME([DEFAULT])
# ----------------------------------
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
m4_define([_LT_WITH_AIX_SONAME],
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
shared_archive_member_spec=
case $host,$enable_shared in
power*-*-aix[[5-9]]*,yes)
AC_MSG_CHECKING([which variant of shared library versioning to provide])
AC_ARG_WITH([aix-soname],
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
[case $withval in
aix|svr4|both)
;;
*)
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
;;
esac
lt_cv_with_aix_soname=$with_aix_soname],
[AC_CACHE_VAL([lt_cv_with_aix_soname],
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
with_aix_soname=$lt_cv_with_aix_soname])
AC_MSG_RESULT([$with_aix_soname])
if test aix != "$with_aix_soname"; then
# For the AIX way of multilib, we name the shared archive member
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
# the AIX toolchain works better with OBJECT_MODE set (default 32).
if test 64 = "${OBJECT_MODE-32}"; then
shared_archive_member_spec=shr_64
else
shared_archive_member_spec=shr
fi
fi
;;
*)
with_aix_soname=aix
;;
esac
_LT_DECL([], [shared_archive_member_spec], [0],
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
])# _LT_WITH_AIX_SONAME
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

View File

@ -0,0 +1,124 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59, which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

View File

@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 4179 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.6])
m4_define([LT_PACKAGE_REVISION], [2.4.6])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.6'
macro_revision='2.4.6'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

View File

@ -0,0 +1,99 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])

View File

@ -0,0 +1,215 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program 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, 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 <http://www.gnu.org/licenses/>.
# 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.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# 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:

View File

@ -0,0 +1,50 @@
# always define MODPLUG_BUILD when building libmodplug
# regardless of static build or shared library build..
AM_CXXFLAGS = -DMODPLUG_BUILD=1
AM_CPPFLAGS = -I$(top_srcdir)/src/libmodplug
lib_LTLIBRARIES = libmodplug.la
libmodplug_la_LDFLAGS = -version-info $(MODPLUG_LIBRARY_VERSION) $(LT_LDFLAGS)
libmodplug_la_LIBADD = -lm
libmodplug_la_SOURCES = tables.h \
sndmix.cpp \
sndfile.cpp \
snd_fx.cpp \
snd_flt.cpp \
snd_dsp.cpp \
fastmix.cpp \
mmcmp.cpp \
load_xm.cpp \
load_wav.cpp \
load_umx.cpp \
load_ult.cpp \
load_stm.cpp \
load_s3m.cpp \
load_ptm.cpp \
load_okt.cpp \
load_mtm.cpp \
load_mod.cpp \
load_med.cpp \
load_mdl.cpp \
load_it.cpp \
load_far.cpp \
load_dsm.cpp \
load_dmf.cpp \
load_dbm.cpp \
load_ams.cpp \
load_amf.cpp \
load_669.cpp \
load_j2b.cpp \
load_mt2.cpp \
load_psm.cpp \
load_abc.cpp \
load_mid.cpp \
load_pat.cpp \
modplug.cpp
libmodplugincludedir = $(includedir)/libmodplug
libmodpluginclude_HEADERS = libmodplug/stdafx.h libmodplug/sndfile.h libmodplug/it_defs.h modplug.h
noinst_HEADERS = load_pat.h

View File

@ -0,0 +1,797 @@
# Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(libmodpluginclude_HEADERS) \
$(noinst_HEADERS) $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(libdir)" \
"$(DESTDIR)$(libmodplugincludedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libmodplug_la_DEPENDENCIES =
am_libmodplug_la_OBJECTS = sndmix.lo sndfile.lo snd_fx.lo snd_flt.lo \
snd_dsp.lo fastmix.lo mmcmp.lo load_xm.lo load_wav.lo \
load_umx.lo load_ult.lo load_stm.lo load_s3m.lo load_ptm.lo \
load_okt.lo load_mtm.lo load_mod.lo load_med.lo load_mdl.lo \
load_it.lo load_far.lo load_dsm.lo load_dmf.lo load_dbm.lo \
load_ams.lo load_amf.lo load_669.lo load_j2b.lo load_mt2.lo \
load_psm.lo load_abc.lo load_mid.lo load_pat.lo modplug.lo
libmodplug_la_OBJECTS = $(am_libmodplug_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
libmodplug_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
$(AM_CXXFLAGS) $(CXXFLAGS) $(libmodplug_la_LDFLAGS) $(LDFLAGS) \
-o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
am__v_CXX_1 =
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libmodplug_la_SOURCES)
DIST_SOURCES = $(libmodplug_la_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
HEADERS = $(libmodpluginclude_HEADERS) $(noinst_HEADERS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
$(LISP)config.h.in
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_LDFLAGS = @LT_LDFLAGS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MODPLUG_LIBRARY_VERSION = @MODPLUG_LIBRARY_VERSION@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
# always define MODPLUG_BUILD when building libmodplug
# regardless of static build or shared library build..
AM_CXXFLAGS = -DMODPLUG_BUILD=1
AM_CPPFLAGS = -I$(top_srcdir)/src/libmodplug
lib_LTLIBRARIES = libmodplug.la
libmodplug_la_LDFLAGS = -version-info $(MODPLUG_LIBRARY_VERSION) $(LT_LDFLAGS)
libmodplug_la_LIBADD = -lm
libmodplug_la_SOURCES = tables.h \
sndmix.cpp \
sndfile.cpp \
snd_fx.cpp \
snd_flt.cpp \
snd_dsp.cpp \
fastmix.cpp \
mmcmp.cpp \
load_xm.cpp \
load_wav.cpp \
load_umx.cpp \
load_ult.cpp \
load_stm.cpp \
load_s3m.cpp \
load_ptm.cpp \
load_okt.cpp \
load_mtm.cpp \
load_mod.cpp \
load_med.cpp \
load_mdl.cpp \
load_it.cpp \
load_far.cpp \
load_dsm.cpp \
load_dmf.cpp \
load_dbm.cpp \
load_ams.cpp \
load_amf.cpp \
load_669.cpp \
load_j2b.cpp \
load_mt2.cpp \
load_psm.cpp \
load_abc.cpp \
load_mid.cpp \
load_pat.cpp \
modplug.cpp
libmodplugincludedir = $(includedir)/libmodplug
libmodpluginclude_HEADERS = libmodplug/stdafx.h libmodplug/sndfile.h libmodplug/it_defs.h modplug.h
noinst_HEADERS = load_pat.h
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .cpp .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
config.h: stamp-h1
@test -f $@ || rm -f stamp-h1
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status src/config.h
$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f config.h stamp-h1
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libmodplug.la: $(libmodplug_la_OBJECTS) $(libmodplug_la_DEPENDENCIES) $(EXTRA_libmodplug_la_DEPENDENCIES)
$(AM_V_CXXLD)$(libmodplug_la_LINK) -rpath $(libdir) $(libmodplug_la_OBJECTS) $(libmodplug_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fastmix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_669.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_abc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_amf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_ams.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_dbm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_dmf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_dsm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_far.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_it.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_j2b.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_mdl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_med.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_mid.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_mod.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_mt2.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_mtm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_okt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_pat.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_psm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_ptm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_s3m.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_stm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_ult.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_umx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_wav.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/load_xm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmcmp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modplug.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snd_dsp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snd_flt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snd_fx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sndfile.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sndmix.Plo@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-libmodplugincludeHEADERS: $(libmodpluginclude_HEADERS)
@$(NORMAL_INSTALL)
@list='$(libmodpluginclude_HEADERS)'; test -n "$(libmodplugincludedir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(libmodplugincludedir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libmodplugincludedir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libmodplugincludedir)'"; \
$(INSTALL_HEADER) $$files "$(DESTDIR)$(libmodplugincludedir)" || exit $$?; \
done
uninstall-libmodplugincludeHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(libmodpluginclude_HEADERS)'; test -n "$(libmodplugincludedir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(libmodplugincludedir)'; $(am__uninstall_files_from_dir)
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h
installdirs:
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libmodplugincludedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-libmodplugincludeHEADERS
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-libLTLIBRARIES
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-libLTLIBRARIES \
uninstall-libmodplugincludeHEADERS
.MAKE: all install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
ctags-am distclean distclean-compile distclean-generic \
distclean-hdr distclean-libtool distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-libLTLIBRARIES \
install-libmodplugincludeHEADERS install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \
uninstall-libmodplugincludeHEADERS
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,129 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <malloc.h> header file. */
#undef HAVE_MALLOC_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `sinf' function. */
#undef HAVE_SINF
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT32_T
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT64_T
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
#define below would cause a syntax error. */
#undef _UINT8_T
/* Define to the type of a signed integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
#undef int16_t
/* Define to the type of a signed integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef int32_t
/* Define to the type of a signed integer type of width exactly 64 bits if
such a type exists and the standard includes do not define it. */
#undef int64_t
/* Define to the type of a signed integer type of width exactly 8 bits if such
a type exists and the standard includes do not define it. */
#undef int8_t
/* Define to the type of an unsigned integer type of width exactly 16 bits if
such a type exists and the standard includes do not define it. */
#undef uint16_t
/* Define to the type of an unsigned integer type of width exactly 32 bits if
such a type exists and the standard includes do not define it. */
#undef uint32_t
/* Define to the type of an unsigned integer type of width exactly 64 bits if
such a type exists and the standard includes do not define it. */
#undef uint64_t
/* Define to the type of an unsigned integer type of width exactly 8 bits if
such a type exists and the standard includes do not define it. */
#undef uint8_t

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
#ifndef _ITDEFS_H_
#define _ITDEFS_H_
#pragma pack(1)
typedef struct tagITFILEHEADER
{
DWORD id; // 0x4D504D49
CHAR songname[26];
WORD reserved1; // 0x1004
WORD ordnum;
WORD insnum;
WORD smpnum;
WORD patnum;
WORD cwtv;
WORD cmwt;
WORD flags;
WORD special;
BYTE globalvol;
BYTE mv;
BYTE speed;
BYTE tempo;
BYTE sep;
BYTE zero;
WORD msglength;
DWORD msgoffset;
DWORD reserved2;
BYTE chnpan[64];
BYTE chnvol[64];
} ITFILEHEADER;
typedef struct tagITENVELOPE
{
BYTE flags;
BYTE num;
BYTE lpb;
BYTE lpe;
BYTE slb;
BYTE sle;
BYTE data[25*3];
BYTE reserved;
} ITENVELOPE;
// Old Impulse Instrument Format (cmwt < 0x200)
typedef struct tagITOLDINSTRUMENT
{
DWORD id; // IMPI = 0x49504D49
CHAR filename[12]; // DOS file name
BYTE zero;
BYTE flags;
BYTE vls;
BYTE vle;
BYTE sls;
BYTE sle;
WORD reserved1;
WORD fadeout;
BYTE nna;
BYTE dnc;
WORD trkvers;
BYTE nos;
BYTE reserved2;
CHAR name[26];
WORD reserved3[3];
BYTE keyboard[240];
BYTE volenv[200];
BYTE nodes[50];
} ITOLDINSTRUMENT;
// Impulse Instrument Format
typedef struct tagITINSTRUMENT
{
DWORD id;
CHAR filename[12];
BYTE zero;
BYTE nna;
BYTE dct;
BYTE dca;
WORD fadeout;
signed char pps;
BYTE ppc;
BYTE gbv;
BYTE dfp;
BYTE rv;
BYTE rp;
WORD trkvers;
BYTE nos;
BYTE reserved1;
CHAR name[26];
BYTE ifc;
BYTE ifr;
BYTE mch;
BYTE mpr;
WORD mbank;
BYTE keyboard[240];
ITENVELOPE volenv;
ITENVELOPE panenv;
ITENVELOPE pitchenv;
BYTE dummy[4]; // was 7, but IT v2.17 saves 554 bytes
} ITINSTRUMENT;
// IT Sample Format
typedef struct ITSAMPLESTRUCT
{
DWORD id; // 0x53504D49
CHAR filename[12];
BYTE zero;
BYTE gvl;
BYTE flags;
BYTE vol;
CHAR name[26];
BYTE cvt;
BYTE dfp;
DWORD length;
DWORD loopbegin;
DWORD loopend;
DWORD C5Speed;
DWORD susloopbegin;
DWORD susloopend;
DWORD samplepointer;
BYTE vis;
BYTE vid;
BYTE vir;
BYTE vit;
} ITSAMPLESTRUCT;
#pragma pack()
#if 0/* made these two static to load_it.cpp */
extern const BYTE autovibit2xm[8];
extern const BYTE autovibxm2it[8];
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,141 @@
/*
* This source code is public domain.
*
* Authors: Rani Assaf <rani@magic.metawire.com>,
* Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
#ifndef _STDAFX_H_
#define _STDAFX_H_
/* Autoconf detection of stdint/inttypes */
#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED)
# include "config.h"
# define CONFIG_H_INCLUDED 1
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
/*#define MMCMP_SUPPORT*/
/* disable AGC and FILESAVE for all targets for uniformity. */
#define NO_AGC
#define MODPLUG_NO_FILESAVE
/*#define NO_PACKING*/
/*#define NO_FILTER */
#define NO_MIDIFORMATS
#define NO_WAVFORMAT
#ifdef _WIN32
#ifdef MSC_VER
#pragma warning (disable:4201)
#pragma warning (disable:4514)
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdio.h>
#include <malloc.h>
#include <stdint.h>
#define srandom(_seed) srand(_seed)
#define random() rand()
#define sleep(_ms) Sleep(_ms)
inline void ProcessPlugins(int n) {}
#undef strcasecmp
#undef strncasecmp
#define strcasecmp(a,b) _stricmp(a,b)
#define strncasecmp(a,b,c) _strnicmp(a,b,c)
#define HAVE_SINF 1
#ifndef isblank
#define isblank(c) ((c) == ' ' || (c) == '\t')
#endif
#else
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
typedef int8_t CHAR;
typedef uint8_t UCHAR;
typedef uint8_t* PUCHAR;
typedef uint16_t USHORT;
typedef uint32_t ULONG;
typedef uint32_t UINT;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef int64_t LONGLONG;
typedef int32_t* LPLONG;
typedef uint32_t* LPDWORD;
typedef uint16_t WORD;
typedef uint8_t BYTE;
typedef uint8_t* LPBYTE;
typedef bool BOOL;
typedef char* LPSTR;
typedef void* LPVOID;
typedef uint16_t* LPWORD;
typedef const char* LPCSTR;
typedef void* PVOID;
typedef void VOID;
#define LPCTSTR LPCSTR
#define lstrcpyn strncpy
#define lstrcpy strcpy
#define lstrcmp strcmp
#define wsprintf sprintf
#define WAVE_FORMAT_PCM 1
#define GHND 0
#define GlobalFreePtr(p) free((void *)(p))
inline int8_t * GlobalAllocPtr(unsigned int, size_t size)
{
int8_t * p = (int8_t *) malloc(size);
if (p != NULL) memset(p, 0, size);
return p;
}
inline void ProcessPlugins(int n) {}
#ifndef FALSE
#define FALSE false
#endif
#ifndef TRUE
#define TRUE true
#endif
#endif /* _WIN32 */
#if defined(_WIN32) || defined(__CYGWIN__)
# if defined(MODPLUG_BUILD) && defined(DLL_EXPORT) /* building libmodplug as a dll for windows */
# define MODPLUG_EXPORT __declspec(dllexport)
# elif defined(MODPLUG_BUILD) || defined(MODPLUG_STATIC) /* building or using static libmodplug for windows */
# define MODPLUG_EXPORT
# else
# define MODPLUG_EXPORT __declspec(dllimport) /* using libmodplug dll for windows */
# endif
#elif defined(MODPLUG_BUILD) && defined(SYM_VISIBILITY)
# define MODPLUG_EXPORT __attribute__((visibility("default")))
#else
#define MODPLUG_EXPORT
#endif
#endif

View File

@ -0,0 +1,193 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
////////////////////////////////////////////////////////////
// 669 Composer / UNIS 669 module loader
////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
typedef struct tagFILEHEADER669
{
WORD sig; // 'if' or 'JN'
signed char songmessage[108]; // Song Message
BYTE samples; // number of samples (1-64)
BYTE patterns; // number of patterns (1-128)
BYTE restartpos;
BYTE orders[128];
BYTE tempolist[128];
BYTE breaks[128];
} FILEHEADER669;
typedef struct tagSAMPLE669
{
BYTE filename[13];
BYTE length[4]; // when will somebody think about DWORD align ???
BYTE loopstart[4];
BYTE loopend[4];
} SAMPLE669;
static DWORD lengthArrayToDWORD(const BYTE length[4]) {
DWORD len = (length[3] << 24) +
(length[2] << 16) +
(length[1] << 8) +
(length[0]);
return(len);
}
BOOL CSoundFile::Read669(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
BOOL b669Ext;
const FILEHEADER669 *pfh = (const FILEHEADER669 *)lpStream;
const SAMPLE669 *psmp = (const SAMPLE669 *)(lpStream + 0x1F1);
DWORD dwMemPos = 0;
if ((!lpStream) || (dwMemLength < sizeof(FILEHEADER669))) return FALSE;
if ((bswapLE16(pfh->sig) != 0x6669) && (bswapLE16(pfh->sig) != 0x4E4A)) return FALSE;
b669Ext = (bswapLE16(pfh->sig) == 0x4E4A) ? TRUE : FALSE;
if ((!pfh->samples) || (pfh->samples > 64) || (pfh->restartpos >= 128)
|| (!pfh->patterns) || (pfh->patterns > 128)) return FALSE;
DWORD dontfuckwithme = 0x1F1 + pfh->samples * sizeof(SAMPLE669) + pfh->patterns * 0x600;
if (dontfuckwithme > dwMemLength) return FALSE;
for (UINT ichk=0; ichk<pfh->samples; ichk++)
{
DWORD len = lengthArrayToDWORD(psmp[ichk].length);
dontfuckwithme += len;
}
if (dontfuckwithme > dwMemLength) return FALSE;
// That should be enough checking: this must be a 669 module.
m_nType = MOD_TYPE_669;
m_dwSongFlags |= SONG_LINEARSLIDES;
m_nMinPeriod = 28 << 2;
m_nMaxPeriod = 1712 << 3;
m_nDefaultTempo = 125;
m_nDefaultSpeed = 6;
m_nChannels = 8;
memcpy(m_szNames[0], pfh->songmessage, 16);
m_nSamples = pfh->samples;
for (UINT nins=1; nins<=m_nSamples; nins++, psmp++)
{
DWORD len = lengthArrayToDWORD(psmp->length);
DWORD loopstart = lengthArrayToDWORD(psmp->loopstart);
DWORD loopend = lengthArrayToDWORD(psmp->loopend);
if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
if ((loopend > len) && (!loopstart)) loopend = 0;
if (loopend > len) loopend = len;
if (loopstart + 4 >= loopend) loopstart = loopend = 0;
Ins[nins].nLength = len;
Ins[nins].nLoopStart = loopstart;
Ins[nins].nLoopEnd = loopend;
if (loopend) Ins[nins].uFlags |= CHN_LOOP;
memcpy(m_szNames[nins], psmp->filename, 13);
Ins[nins].nVolume = 256;
Ins[nins].nGlobalVol = 64;
Ins[nins].nPan = 128;
}
// Song Message
m_lpszSongComments = new char[109];
memcpy(m_lpszSongComments, pfh->songmessage, 108);
m_lpszSongComments[108] = 0;
// Reading Orders
memcpy(Order, pfh->orders, 128);
m_nRestartPos = pfh->restartpos;
if (Order[m_nRestartPos] >= pfh->patterns) m_nRestartPos = 0;
// Reading Pattern Break Locations
for (UINT npan=0; npan<8; npan++)
{
ChnSettings[npan].nPan = (npan & 1) ? 0x30 : 0xD0;
ChnSettings[npan].nVolume = 64;
}
// Reading Patterns
dwMemPos = 0x1F1 + pfh->samples * 25;
for (UINT npat=0; npat<pfh->patterns; npat++)
{
Patterns[npat] = AllocatePattern(64, m_nChannels);
if (!Patterns[npat]) break;
PatternSize[npat] = 64;
MODCOMMAND *m = Patterns[npat];
const BYTE *p = lpStream + dwMemPos;
for (UINT row=0; row<64; row++)
{
MODCOMMAND *mspeed = m;
if ((row == pfh->breaks[npat]) && (row != 63))
{
for (UINT i=0; i<8; i++)
{
m[i].command = CMD_PATTERNBREAK;
m[i].param = 0;
}
}
for (UINT n=0; n<8; n++, m++, p+=3)
{
UINT note = p[0] >> 2;
UINT instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
UINT vol = p[1] & 0x0F;
if (p[0] < 0xFE)
{
m->note = note + 37;
m->instr = instr + 1;
}
if (p[0] <= 0xFE)
{
m->volcmd = VOLCMD_VOLUME;
m->vol = (vol << 2) + 2;
}
if (p[2] != 0xFF)
{
UINT command = p[2] >> 4;
UINT param = p[2] & 0x0F;
switch(command)
{
case 0x00: command = CMD_PORTAMENTOUP; break;
case 0x01: command = CMD_PORTAMENTODOWN; break;
case 0x02: command = CMD_TONEPORTAMENTO; break;
case 0x03: command = CMD_MODCMDEX; param |= 0x50; break;
case 0x04: command = CMD_VIBRATO; param |= 0x40; break;
case 0x05: if (param) command = CMD_SPEED; else command = 0; param += 2; break;
case 0x06: if (param == 0) { command = CMD_PANNINGSLIDE; param = 0xFE; }
else if (param == 1) { command = CMD_PANNINGSLIDE; param = 0xEF; }
else command = 0;
break;
default: command = 0;
}
if (command)
{
if (command == CMD_SPEED) mspeed = NULL;
m->command = command;
m->param = param;
}
}
}
if ((!row) && (mspeed))
{
for (UINT i=0; i<8; i++) if (!mspeed[i].command)
{
mspeed[i].command = CMD_SPEED;
mspeed[i].param = pfh->tempolist[npat] + 2;
break;
}
}
}
dwMemPos += 0x600;
}
// Reading Samples
for (UINT n=1; n<=m_nSamples; n++)
{
UINT len = Ins[n].nLength;
if (dwMemPos >= dwMemLength) break;
if (len > 4) ReadSample(&Ins[n], RS_PCM8U, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
dwMemPos += len;
}
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,423 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
///////////////////////////////////////////////////
//
// AMF module loader
//
// There is 2 types of AMF files:
// - ASYLUM Music Format
// - Advanced Music Format(DSM)
//
///////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#define AMFLOG
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct _AMFFILEHEADER
{
UCHAR szAMF[3];
UCHAR version;
CHAR title[32];
UCHAR numsamples;
UCHAR numorders;
USHORT numtracks;
UCHAR numchannels;
} AMFFILEHEADER;
typedef struct _AMFSAMPLE
{
UCHAR type;
CHAR samplename[32];
CHAR filename[13];
ULONG offset;
ULONG length;
USHORT c2spd;
UCHAR volume;
} AMFSAMPLE;
#pragma pack()
#ifdef AMFLOG
extern void Log(LPCSTR, ...);
#endif
static VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
//-------------------------------------------------------------------------------
{
UINT lastinstr = 0;
UINT nTrkSize = bswapLE16(*(USHORT *)pTrack);
nTrkSize += (UINT)pTrack[2] << 16;
pTrack += 3;
while (nTrkSize--)
{
UINT row = pTrack[0];
UINT cmd = pTrack[1];
UINT arg = pTrack[2];
if (row >= nRows) break;
MODCOMMAND *m = pPat + row * nChannels;
if (cmd < 0x7F) // note+vol
{
m->note = cmd+1;
if (!m->instr) m->instr = lastinstr;
m->volcmd = VOLCMD_VOLUME;
m->vol = arg;
} else
if (cmd == 0x7F) // duplicate row
{
signed char rdelta = (signed char)arg;
int rowsrc = (int)row + (int)rdelta;
if ((rowsrc >= 0) && (rowsrc < (int)nRows)) memcpy(m, &pPat[rowsrc*nChannels],sizeof(pPat[rowsrc*nChannels]));
} else
if (cmd == 0x80) // instrument
{
m->instr = arg+1;
lastinstr = m->instr;
} else
if (cmd == 0x83) // volume
{
m->volcmd = VOLCMD_VOLUME;
m->vol = arg;
} else
// effect
{
UINT command = cmd & 0x7F;
UINT param = arg;
switch(command)
{
// 0x01: Set Speed
case 0x01: command = CMD_SPEED; break;
// 0x02: Volume Slide
// 0x0A: Tone Porta + Vol Slide
// 0x0B: Vibrato + Vol Slide
case 0x02: command = CMD_VOLUMESLIDE;
case 0x0A: if (command == 0x0A) command = CMD_TONEPORTAVOL;
case 0x0B: if (command == 0x0B) command = CMD_VIBRATOVOL;
if (param & 0x80) param = (-(signed char)param)&0x0F;
else param = (param&0x0F)<<4;
break;
// 0x04: Porta Up/Down
case 0x04: if (param & 0x80) { command = CMD_PORTAMENTOUP; param = (-(signed char)param)&0x7F; }
else { command = CMD_PORTAMENTODOWN; } break;
// 0x06: Tone Portamento
case 0x06: command = CMD_TONEPORTAMENTO; break;
// 0x07: Tremor
case 0x07: command = CMD_TREMOR; break;
// 0x08: Arpeggio
case 0x08: command = CMD_ARPEGGIO; break;
// 0x09: Vibrato
case 0x09: command = CMD_VIBRATO; break;
// 0x0C: Pattern Break
case 0x0C: command = CMD_PATTERNBREAK; break;
// 0x0D: Position Jump
case 0x0D: command = CMD_POSITIONJUMP; break;
// 0x0F: Retrig
case 0x0F: command = CMD_RETRIG; break;
// 0x10: Offset
case 0x10: command = CMD_OFFSET; break;
// 0x11: Fine Volume Slide
case 0x11: if (param) { command = CMD_VOLUMESLIDE;
if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F);
else param = 0x0F|((param&0x0F)<<4);
} else command = 0; break;
// 0x12: Fine Portamento
// 0x16: Extra Fine Portamento
case 0x12:
case 0x16: if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0;
command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
if (param & 0x80) param = mask|((-(signed char)param)&0x0F);
else param |= mask;
} else command = 0; break;
// 0x13: Note Delay
case 0x13: command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break;
// 0x14: Note Cut
case 0x14: command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break;
// 0x15: Set Tempo
case 0x15: command = CMD_TEMPO; break;
// 0x17: Panning
case 0x17: param = (param+64)&0x7F;
if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING; m->vol = param/2; } command = 0; }
else { command = CMD_PANNING8; }
break;
// Unknown effects
default: command = param = 0;
}
if (command)
{
m->command = command;
m->param = param;
}
}
pTrack += 3;
}
}
BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, const DWORD dwMemLength)
//-----------------------------------------------------------
{
const AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream;
DWORD dwMemPos;
if ((!lpStream) || (dwMemLength < 2048)) return FALSE;
if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096))
{
UINT numorders, numpats, numsamples;
dwMemPos = 32;
numpats = lpStream[dwMemPos+3];
numorders = lpStream[dwMemPos+4];
numsamples = 64;
dwMemPos += 6;
if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders)
|| (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE;
m_nType = MOD_TYPE_AMF0;
m_nChannels = 8;
m_nInstruments = 0;
m_nSamples = 31;
m_nDefaultTempo = 125;
m_nDefaultSpeed = 6;
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
{
Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF;
}
dwMemPos = 294; // ???
for (UINT iSmp=0; iSmp<numsamples; iSmp++)
{
MODINSTRUMENT *psmp = &Ins[iSmp+1];
memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22);
m_szNames[iSmp+1][21] = '\0';
psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]);
psmp->nVolume = lpStream[dwMemPos+23];
psmp->nGlobalVol = 64;
if (psmp->nVolume > 0x40) psmp->nVolume = 0x40;
psmp->nVolume <<= 2;
psmp->nLength = bswapLE32(*((LPDWORD)(lpStream+dwMemPos+25)));
psmp->nLoopStart = bswapLE32(*((LPDWORD)(lpStream+dwMemPos+29)));
psmp->nLoopEnd = psmp->nLoopStart + bswapLE32(*((LPDWORD)(lpStream+dwMemPos+33)));
if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength))
{
psmp->uFlags = CHN_LOOP;
} else
{
psmp->nLoopStart = psmp->nLoopEnd = 0;
}
if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1;
dwMemPos += 37;
}
for (UINT iPat=0; iPat<numpats; iPat++)
{
MODCOMMAND *p = AllocatePattern(64, m_nChannels);
if (!p) break;
Patterns[iPat] = p;
PatternSize[iPat] = 64;
const UCHAR *pin = lpStream + dwMemPos;
for (UINT i=0; i<8*64; i++)
{
p->note = 0;
if (pin[0])
{
p->note = pin[0] + 13;
}
p->instr = pin[1];
p->command = pin[2];
p->param = pin[3];
if (p->command > 0x0F)
{
#ifdef AMFLOG
Log("0x%02X.0x%02X ?", p->command, p->param);
#endif
p->command = 0;
}
ConvertModCommand(p);
pin += 4;
p++;
}
dwMemPos += 64*32;
}
// Read samples
for (UINT iData=0; iData<m_nSamples; iData++)
{
MODINSTRUMENT *psmp = &Ins[iData+1];
if (psmp->nLength)
{
if (dwMemPos > dwMemLength) return FALSE;
dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
}
return TRUE;
}
////////////////////////////
// DSM/AMF
USHORT *ptracks[MAX_PATTERNS];
DWORD sampleseekpos[MAX_SAMPLES];
if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F')
|| (pfh->version < 10) || (pfh->version > 14) || (!bswapLE16(pfh->numtracks))
|| (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS)
|| (!pfh->numsamples) || (pfh->numsamples >= MAX_SAMPLES)
|| (pfh->numchannels < 4) || (pfh->numchannels > 32))
return FALSE;
memcpy(m_szNames[0], pfh->title, 32);
m_szNames[0][31] = '\0';
dwMemPos = sizeof(AMFFILEHEADER);
m_nType = MOD_TYPE_AMF;
m_nChannels = pfh->numchannels;
m_nSamples = pfh->numsamples;
m_nInstruments = 0;
// Setup Channel Pan Positions
if (pfh->version >= 11)
{
signed char *panpos = (signed char *)(lpStream + dwMemPos);
UINT nchannels = (pfh->version >= 13) ? 32 : 16;
for (UINT i=0; i<nchannels; i++)
{
int pan = (panpos[i] + 64) * 2;
if (pan < 0) pan = 0;
if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; }
ChnSettings[i].nPan = pan;
}
dwMemPos += nchannels;
} else
{
for (UINT i=0; i<16; i++)
{
ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0;
}
dwMemPos += 16;
}
// Get Tempo/Speed
m_nDefaultTempo = 125;
m_nDefaultSpeed = 6;
if (pfh->version >= 13)
{
if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos];
if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1];
dwMemPos += 2;
}
// Setup sequence list
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
{
Order[iOrd] = 0xFF;
if (iOrd < pfh->numorders)
{
Order[iOrd] = iOrd;
PatternSize[iOrd] = 64;
if (pfh->version >= 14)
{
PatternSize[iOrd] = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
dwMemPos += 2;
}
ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
dwMemPos += m_nChannels * sizeof(USHORT);
}
}
if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE;
// Read Samples
UINT maxsampleseekpos = 0;
for (UINT iIns=0; iIns<m_nSamples; iIns++)
{
MODINSTRUMENT *pins = &Ins[iIns+1];
const AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos);
dwMemPos += sizeof(AMFSAMPLE);
memcpy(m_szNames[iIns+1], psh->samplename, 32);
m_szNames[iIns+1][31] = '\0';
memcpy(pins->name, psh->filename, 13);
pins->name[12] = '\0';
pins->nLength = bswapLE32(psh->length);
pins->nC4Speed = bswapLE16(psh->c2spd);
pins->nGlobalVol = 64;
pins->nVolume = psh->volume * 4;
if (pfh->version >= 11)
{
pins->nLoopStart = bswapLE32(*(DWORD *)(lpStream+dwMemPos));
pins->nLoopEnd = bswapLE32(*(DWORD *)(lpStream+dwMemPos+4));
dwMemPos += 8;
} else
{
pins->nLoopStart = bswapLE16(*(WORD *)(lpStream+dwMemPos));
pins->nLoopEnd = pins->nLength;
dwMemPos += 2;
}
sampleseekpos[iIns] = 0;
if ((psh->type) && (bswapLE32(psh->offset) < dwMemLength-1))
{
sampleseekpos[iIns] = bswapLE32(psh->offset);
if (bswapLE32(psh->offset) > maxsampleseekpos)
maxsampleseekpos = bswapLE32(psh->offset);
if ((pins->nLoopEnd > pins->nLoopStart + 2)
&& (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP;
}
}
// Read Track Mapping Table
USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos);
UINT realtrackcnt = 0;
dwMemPos += pfh->numtracks * sizeof(USHORT);
if (dwMemPos >= dwMemLength)
return TRUE;
for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++)
{
if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap];
}
// Store tracks positions
BYTE **pTrackData = new BYTE *[realtrackcnt];
memset(pTrackData, 0, sizeof(BYTE *) * realtrackcnt);
for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos <= dwMemLength - 3)
{
UINT nTrkSize = bswapLE16(*(USHORT *)(lpStream+dwMemPos));
nTrkSize += (UINT)lpStream[dwMemPos+2] << 16;
if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength)
{
pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos);
}
dwMemPos += nTrkSize * 3 + 3;
}
// Create the patterns from the list of tracks
for (UINT iPat=0; iPat<pfh->numorders; iPat++)
{
MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels);
if (!p) break;
Patterns[iPat] = p;
for (UINT iChn=0; iChn<m_nChannels; iChn++)
{
UINT nTrack = bswapLE16(ptracks[iPat][iChn]);
if ((nTrack) && (nTrack <= pfh->numtracks))
{
UINT realtrk = bswapLE16(pTrackMap[nTrack-1]);
if (realtrk)
{
realtrk--;
if ((realtrk < realtrackcnt) && (pTrackData[realtrk]))
{
AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels);
}
}
}
}
}
delete[] pTrackData;
// Read Sample Data
for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++)
{
if (dwMemPos >= dwMemLength) break;
for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp])
{
MODINSTRUMENT *pins = &Ins[iSmp+1];
dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
break;
}
}
return TRUE;
}

View File

@ -0,0 +1,628 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
//////////////////////////////////////////////
// AMS module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct AMSFILEHEADER
{
char szHeader[7]; // "Extreme" // changed from CHAR
BYTE verlo, verhi; // 0x??,0x01
BYTE chncfg;
BYTE samples;
WORD patterns;
WORD orders;
BYTE vmidi;
WORD extra;
} AMSFILEHEADER;
typedef struct AMSSAMPLEHEADER
{
DWORD length;
DWORD loopstart;
DWORD loopend;
BYTE finetune_and_pan;
WORD samplerate; // C-2 = 8363
BYTE volume; // 0-127
BYTE infobyte;
} AMSSAMPLEHEADER;
#pragma pack()
BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
BYTE pkinf[MAX_SAMPLES];
AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
DWORD dwMemPos;
UINT tmp, tmp2;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7))
|| (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples >= MAX_SAMPLES)
|| (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS))
{
return ReadAMS2(lpStream, dwMemLength);
}
dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra;
if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE;
m_nType = MOD_TYPE_AMS;
m_nInstruments = 0;
m_nChannels = (pfh->chncfg & 0x1F) + 1;
m_nSamples = pfh->samples;
for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER))
{
AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
MODINSTRUMENT *pins = &Ins[nSmp];
pins->nLength = psh->length;
pins->nLoopStart = psh->loopstart;
pins->nLoopEnd = psh->loopend;
pins->nGlobalVol = 64;
pins->nVolume = psh->volume << 1;
pins->nC4Speed = psh->samplerate;
pins->nPan = (psh->finetune_and_pan & 0xF0);
if (pins->nPan < 0x80) pins->nPan += 0x10;
pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F);
pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0;
if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP;
pkinf[nSmp] = psh->infobyte;
}
// Read Song Name
tmp = lpStream[dwMemPos++];
if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE;
tmp2 = (tmp < 32) ? tmp : 31;
if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2);
m_szNames[0][tmp2] = 0;
dwMemPos += tmp;
// Read sample names
for (UINT sNam=1; sNam<=m_nSamples; sNam++)
{
if (dwMemPos + 32 >= dwMemLength) return TRUE;
tmp = lpStream[dwMemPos++];
tmp2 = (tmp < 32) ? tmp : 31;
if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2);
dwMemPos += tmp;
}
// Skip Channel names
for (UINT cNam=0; cNam<m_nChannels; cNam++)
{
if (dwMemPos + 32 >= dwMemLength) return TRUE;
tmp = lpStream[dwMemPos++];
dwMemPos += tmp;
}
// Read Pattern Names
m_lpszPatternNames = new char[pfh->patterns * 32]; // changed from CHAR
if (!m_lpszPatternNames) return TRUE;
m_nPatternNames = pfh->patterns;
memset(m_lpszPatternNames, 0, m_nPatternNames * 32);
for (UINT pNam=0; pNam < m_nPatternNames; pNam++)
{
if (dwMemPos + 32 >= dwMemLength) return TRUE;
tmp = lpStream[dwMemPos++];
tmp2 = (tmp < 32) ? tmp : 31;
if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2);
dwMemPos += tmp;
}
// Read Song Comments
tmp = *((WORD *)(lpStream+dwMemPos));
dwMemPos += 2;
if (dwMemPos + tmp >= dwMemLength) return TRUE;
if (tmp)
{
m_lpszSongComments = new char[tmp+1]; // changed from CHAR
if (!m_lpszSongComments) return TRUE;
memset(m_lpszSongComments, 0, tmp+1);
memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp);
dwMemPos += tmp;
}
// Read Order List
for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2)
{
UINT n = *((WORD *)(lpStream+dwMemPos));
Order[iOrd] = (BYTE)n;
}
// Read Patterns
for (UINT iPat=0; iPat<pfh->patterns; iPat++)
{
if (dwMemPos + 4 >= dwMemLength) return TRUE;
UINT len = *((DWORD *)(lpStream + dwMemPos));
dwMemPos += 4;
if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
PatternSize[iPat] = 64;
MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
if (!m) return TRUE;
Patterns[iPat] = m;
const BYTE *p = lpStream + dwMemPos;
UINT row = 0, i = 0;
while ((row < PatternSize[iPat]) && (i+2 < len))
{
BYTE b0 = p[i++];
BYTE b1 = p[i++];
BYTE b2 = 0;
UINT ch = b0 & 0x3F;
// Note+Instr
if (!(b0 & 0x40))
{
b2 = p[i++];
if (ch < m_nChannels)
{
if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25;
m[ch].instr = b2;
}
if (b1 & 0x80)
{
b0 |= 0x40;
b1 = p[i++];
}
}
// Effect
if (b0 & 0x40)
{
anothercommand:
if (b1 & 0x40)
{
if (ch < m_nChannels)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = b1 & 0x3F;
}
} else
{
b2 = p[i++];
if (ch < m_nChannels)
{
UINT cmd = b1 & 0x3F;
if (cmd == 0x0C)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = b2 >> 1;
} else
if (cmd == 0x0E)
{
if (!m[ch].command)
{
UINT command = CMD_S3MCMDEX;
UINT param = b2;
switch(param & 0xF0)
{
case 0x00: if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break;
case 0x10: command = CMD_PORTAMENTOUP; param |= 0xF0; break;
case 0x20: command = CMD_PORTAMENTODOWN; param |= 0xF0; break;
case 0x30: param = (param & 0x0F) | 0x10; break;
case 0x40: param = (param & 0x0F) | 0x30; break;
case 0x50: param = (param & 0x0F) | 0x20; break;
case 0x60: param = (param & 0x0F) | 0xB0; break;
case 0x70: param = (param & 0x0F) | 0x40; break;
case 0x90: command = CMD_RETRIG; param &= 0x0F; break;
case 0xA0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break;
case 0xB0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break;
}
m[ch].command = command;
m[ch].param = param;
}
} else
{
m[ch].command = cmd;
m[ch].param = b2;
ConvertModCommand(&m[ch]);
}
}
}
if (b1 & 0x80)
{
b1 = p[i++];
if (i <= len) goto anothercommand;
}
}
if (b0 & 0x80)
{
row++;
m += m_nChannels;
}
}
dwMemPos += len;
}
// Read Samples
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
{
if (dwMemPos >= dwMemLength - 9) return TRUE;
UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////
// AMS 2.2 loader
#pragma pack(1)
typedef struct AMS2FILEHEADER
{
DWORD dwHdr1; // AMShdr
WORD wHdr2;
BYTE b1A; // 0x1A
BYTE titlelen; // 30-bytes max
CHAR szTitle[30]; // [titlelen]
} AMS2FILEHEADER;
typedef struct AMS2SONGHEADER
{
WORD version;
BYTE instruments;
WORD patterns;
WORD orders;
WORD bpm;
BYTE speed;
BYTE channels;
BYTE commands;
BYTE rows;
WORD flags;
} AMS2SONGHEADER;
typedef struct AMS2INSTRUMENT
{
BYTE samples;
BYTE notemap[NOTE_MAX];
} AMS2INSTRUMENT;
typedef struct AMS2ENVELOPE
{
BYTE speed;
BYTE sustain;
BYTE loopbegin;
BYTE loopend;
BYTE points;
BYTE info[3];
} AMS2ENVELOPE;
typedef struct AMS2SAMPLE
{
DWORD length;
DWORD loopstart;
DWORD loopend;
WORD frequency;
BYTE finetune;
WORD c4speed;
CHAR transpose;
BYTE volume;
BYTE flags;
} AMS2SAMPLE;
#pragma pack()
BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
//------------------------------------------------------------
{
const AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream;
AMS2SONGHEADER *psh;
DWORD dwMemPos;
BYTE smpmap[16];
BYTE packedsamples[MAX_SAMPLES];
if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264)
|| (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE;
dwMemPos = pfh->titlelen + 8;
psh = (AMS2SONGHEADER *)(lpStream + dwMemPos);
if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments)
|| (psh->instruments >= MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE;
dwMemPos += sizeof(AMS2SONGHEADER);
if (pfh->titlelen)
{
memcpy(m_szNames, pfh->szTitle, pfh->titlelen);
m_szNames[0][pfh->titlelen] = 0;
}
m_nType = MOD_TYPE_AMS;
m_nChannels = 32;
m_nDefaultTempo = psh->bpm >> 8;
m_nDefaultSpeed = psh->speed;
m_nInstruments = psh->instruments;
m_nSamples = 0;
if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
{
UINT insnamelen = lpStream[dwMemPos];
CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
dwMemPos += insnamelen + 1;
AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
dwMemPos += sizeof(AMS2INSTRUMENT);
if (dwMemPos + 1024 >= dwMemLength) return TRUE;
AMS2ENVELOPE *volenv, *panenv, *pitchenv;
volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + volenv->points*3;
panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + panenv->points*3;
pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + pitchenv->points*3;
INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
if (!penv) return TRUE;
memset(smpmap, 0, sizeof(smpmap));
memset(penv, 0, sizeof(INSTRUMENTHEADER));
for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++)
{
if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break;
m_nSamples++;
smpmap[ismpmap] = m_nSamples;
}
penv->nGlobalVol = 64;
penv->nPan = 128;
penv->nPPC = 60;
Headers[nIns] = penv;
if (insnamelen)
{
if (insnamelen > 31) insnamelen = 31;
memcpy(penv->name, pinsname, insnamelen);
penv->name[insnamelen] = 0;
}
for (UINT inotemap=0; inotemap<NOTE_MAX; inotemap++)
{
penv->NoteMap[inotemap] = inotemap+1;
penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F];
}
// Volume Envelope
{
UINT pos = 0;
penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points;
penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain;
penv->nVolLoopStart = volenv->loopbegin;
penv->nVolLoopEnd = volenv->loopend;
for (UINT i=0; i<penv->nVolEnv; i++)
{
penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8);
penv->VolPoints[i] = (WORD)pos;
}
}
penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
UINT envflags = lpStream[dwMemPos+3];
if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP;
if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN;
if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME;
dwMemPos += 5;
// Read Samples
for (UINT ismp=0; ismp<pins->samples; ismp++)
{
MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL;
UINT smpnamelen = lpStream[dwMemPos];
if ((psmp) && (smpnamelen) && (smpnamelen <= 22))
{
memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen);
}
dwMemPos += smpnamelen + 1;
if (psmp)
{
AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
psmp->nGlobalVol = 64;
psmp->nPan = 128;
psmp->nLength = pams->length;
psmp->nLoopStart = pams->loopstart;
psmp->nLoopEnd = pams->loopend;
psmp->nC4Speed = pams->c4speed;
psmp->RelativeTone = pams->transpose;
psmp->nVolume = pams->volume / 2;
packedsamples[smpmap[ismp]] = pams->flags;
if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT;
if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP;
if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP;
}
dwMemPos += sizeof(AMS2SAMPLE);
}
}
if (dwMemPos + 256 >= dwMemLength) return TRUE;
// Comments
{
UINT composernamelen = lpStream[dwMemPos];
if (composernamelen)
{
m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen);
m_lpszSongComments[composernamelen] = 0;
}
}
dwMemPos += composernamelen + 1;
// channel names
for (UINT i=0; i<32; i++)
{
UINT chnnamlen = lpStream[dwMemPos];
if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME))
{
memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen);
}
dwMemPos += chnnamlen + 1;
if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE;
}
// packed comments (ignored)
UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos));
dwMemPos += songtextlen;
if (dwMemPos + 256 >= dwMemLength) return TRUE;
}
// Order List
{
for (UINT i=0; i<MAX_ORDERS; i++)
{
Order[i] = 0xFF;
if (dwMemPos + 2 >= dwMemLength) return TRUE;
if (i < psh->orders)
{
Order[i] = lpStream[dwMemPos];
dwMemPos += 2;
}
}
}
// Pattern Data
for (UINT ipat=0; ipat<psh->patterns; ipat++)
{
if (dwMemPos+8 >= dwMemLength) return TRUE;
UINT packedlen = *((LPDWORD)(lpStream+dwMemPos));
UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]);
//UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F);
//UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5);
UINT patnamlen = lpStream[dwMemPos+6];
dwMemPos += 4;
if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8))
{
if ((patnamlen) && (patnamlen < MAX_PATTERNNAME))
{
char s[MAX_PATTERNNAME]; // changed from CHAR
memcpy(s, lpStream+dwMemPos+3, patnamlen);
s[patnamlen] = 0;
SetPatternName(ipat, s);
}
PatternSize[ipat] = numrows;
Patterns[ipat] = AllocatePattern(numrows, m_nChannels);
if (!Patterns[ipat]) return TRUE;
// Unpack Pattern Data
LPCBYTE psrc = lpStream + dwMemPos;
UINT pos = 3 + patnamlen;
UINT row = 0;
while ((pos < packedlen) && (row < numrows))
{
MODCOMMAND *m = Patterns[ipat] + row * m_nChannels;
UINT byte1 = psrc[pos++];
UINT ch = byte1 & 0x1F;
// Read Note + Instr
if (!(byte1 & 0x40))
{
UINT byte2 = psrc[pos++];
UINT note = byte2 & 0x7F;
if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF;
m[ch].instr = psrc[pos++];
// Read Effect
while (byte2 & 0x80)
{
byte2 = psrc[pos++];
if (byte2 & 0x40)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = byte2 & 0x3F;
} else
{
UINT command = byte2 & 0x3F;
UINT param = psrc[pos++];
if (command == 0x0C)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = param / 2;
} else
if (command < 0x10)
{
m[ch].command = command;
m[ch].param = param;
ConvertModCommand(&m[ch]);
} else
{
// TODO: AMS effects
}
}
}
}
if (byte1 & 0x80) row++;
}
}
dwMemPos += packedlen;
}
// Read Samples
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
{
if (dwMemPos >= dwMemLength - 9) return TRUE;
UINT flags;
if (packedsamples[iSmp] & 0x03)
{
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
} else
{
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
}
dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////
// AMS Sample unpacking
void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter)
{
UINT tmplen = dmax;
signed char *amstmp = new signed char[tmplen];
if (!amstmp) return;
// Unpack Loop
{
signed char *p = amstmp;
UINT i=0, j=0;
while ((i < inputlen) && (j < tmplen))
{
signed char ch = psrc[i++];
if (ch == packcharacter)
{
BYTE ch2 = psrc[i++];
if (ch2)
{
ch = psrc[i++];
while (ch2--)
{
p[j++] = ch;
if (j >= tmplen) break;
}
} else p[j++] = packcharacter;
} else p[j++] = ch;
}
}
// Bit Unpack Loop
{
signed char *p = amstmp;
UINT bitcount = 0x80, dh;
UINT k=0;
for (UINT i=0; i<dmax; i++)
{
BYTE al = *p++;
dh = 0;
for (UINT count=0; count<8; count++)
{
UINT bl = al & bitcount;
bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF;
bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF;
pdest[k++] |= bl;
if (k >= dmax)
{
k = 0;
dh++;
}
}
bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF;
}
}
// Delta Unpack
{
signed char old = 0;
for (UINT i=0; i<dmax; i++)
{
int pos = ((LPBYTE)pdest)[i];
if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F);
old -= (signed char)pos;
pdest[i] = old;
}
}
delete[] amstmp;
}

View File

@ -0,0 +1,368 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
///////////////////////////////////////////////////////////////
//
// DigiBooster Pro Module Loader (*.dbm)
//
// Note: this loader doesn't handle multiple songs
//
///////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#define DBM_FILE_MAGIC 0x304d4244
#define DBM_ID_NAME 0x454d414e
#define DBM_NAMELEN 0x2c000000
#define DBM_ID_INFO 0x4f464e49
#define DBM_INFOLEN 0x0a000000
#define DBM_ID_SONG 0x474e4f53
#define DBM_ID_INST 0x54534e49
#define DBM_ID_VENV 0x564e4556
#define DBM_ID_PATT 0x54544150
#define DBM_ID_SMPL 0x4c504d53
#pragma pack(1)
typedef struct DBMFILEHEADER
{
DWORD dbm_id; // "DBM0" = 0x304d4244
WORD trkver; // Tracker version: 02.15
WORD reserved;
DWORD name_id; // "NAME" = 0x454d414e
DWORD name_len; // name length: always 44
CHAR songname[44];
DWORD info_id; // "INFO" = 0x4f464e49
DWORD info_len; // 0x0a000000
WORD instruments;
WORD samples;
WORD songs;
WORD patterns;
WORD channels;
DWORD song_id; // "SONG" = 0x474e4f53
DWORD song_len;
CHAR songname2[44];
WORD orders;
// WORD orderlist[0]; // orderlist[orders] in words
} DBMFILEHEADER;
typedef struct DBMINSTRUMENT
{
CHAR name[30];
WORD sampleno;
WORD volume;
DWORD finetune;
DWORD loopstart;
DWORD looplen;
WORD panning;
WORD flags;
} DBMINSTRUMENT;
typedef struct DBMENVELOPE
{
WORD instrument;
BYTE flags;
BYTE numpoints;
BYTE sustain1;
BYTE loopbegin;
BYTE loopend;
BYTE sustain2;
WORD volenv[2*32];
} DBMENVELOPE;
typedef struct DBMPATTERN
{
WORD rows;
DWORD packedsize;
BYTE patterndata[2]; // [packedsize]
} DBMPATTERN;
typedef struct DBMSAMPLE
{
DWORD flags;
DWORD samplesize;
BYTE sampledata[2]; // [samplesize]
} DBMSAMPLE;
#pragma pack()
BOOL CSoundFile::ReadDBM(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const DBMFILEHEADER *pfh = (DBMFILEHEADER *)lpStream;
DWORD dwMemPos;
UINT nOrders, nSamples, nInstruments, nPatterns;
if ((!lpStream) || (dwMemLength <= sizeof(DBMFILEHEADER)) || (!pfh->channels)
|| (pfh->dbm_id != bswapLE32(DBM_FILE_MAGIC)) || (!pfh->songs) || (pfh->song_id != bswapLE32(DBM_ID_SONG))
|| (pfh->name_id != bswapLE32(DBM_ID_NAME)) || (pfh->name_len != bswapLE32(DBM_NAMELEN))
|| (pfh->info_id != bswapLE32(DBM_ID_INFO)) || (pfh->info_len != bswapLE32(DBM_INFOLEN))) return FALSE;
dwMemPos = sizeof(DBMFILEHEADER);
nOrders = bswapBE16(pfh->orders);
if (dwMemPos + 2 * nOrders + 8*3 >= dwMemLength) return FALSE;
nInstruments = bswapBE16(pfh->instruments);
nSamples = bswapBE16(pfh->samples);
nPatterns = bswapBE16(pfh->patterns);
m_nType = MOD_TYPE_DBM;
m_nChannels = bswapBE16(pfh->channels);
if (m_nChannels < 4) m_nChannels = 4;
if (m_nChannels > 64) m_nChannels = 64;
memcpy(m_szNames[0], (pfh->songname[0]) ? pfh->songname : pfh->songname2, 32);
m_szNames[0][31] = 0;
for (UINT iOrd=0; iOrd < nOrders; iOrd++)
{
Order[iOrd] = lpStream[dwMemPos+iOrd*2+1];
if (iOrd >= MAX_ORDERS-2) break;
}
dwMemPos += 2*nOrders;
while (dwMemPos + 10 < dwMemLength)
{
DWORD chunk_id = ((LPDWORD)(lpStream+dwMemPos))[0];
DWORD chunk_size = bswapBE32(((LPDWORD)(lpStream+dwMemPos))[1]);
DWORD chunk_pos;
dwMemPos += 8;
chunk_pos = dwMemPos;
if ((dwMemPos + chunk_size > dwMemLength) || (chunk_size > dwMemLength)) break;
dwMemPos += chunk_size;
// Instruments
if (chunk_id == bswapLE32(DBM_ID_INST))
{
if (nInstruments >= MAX_INSTRUMENTS) nInstruments = MAX_INSTRUMENTS-1;
for (UINT iIns=0; iIns<nInstruments; iIns++)
{
MODINSTRUMENT *psmp;
INSTRUMENTHEADER *penv;
DBMINSTRUMENT *pih;
UINT nsmp;
if (chunk_pos + sizeof(DBMINSTRUMENT) > dwMemPos) break;
if ((penv = new INSTRUMENTHEADER) == NULL) break;
pih = (DBMINSTRUMENT *)(lpStream+chunk_pos);
nsmp = bswapBE16(pih->sampleno);
psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Ins[nsmp] : NULL;
memset(penv, 0, sizeof(INSTRUMENTHEADER));
memcpy(penv->name, pih->name, 30);
if (psmp)
{
memcpy(m_szNames[nsmp], pih->name, 30);
m_szNames[nsmp][30] = 0;
}
Headers[iIns+1] = penv;
penv->nFadeOut = 1024; // ???
penv->nGlobalVol = 64;
penv->nPan = bswapBE16(pih->panning);
if ((penv->nPan) && (penv->nPan < 256))
penv->dwFlags = ENV_SETPANNING;
else
penv->nPan = 128;
penv->nPPC = 5*12;
for (UINT i=0; i<NOTE_MAX; i++)
{
penv->Keyboard[i] = nsmp;
penv->NoteMap[i] = i+1;
}
// Sample Info
if (psmp)
{
DWORD sflags = bswapBE16(pih->flags);
psmp->nVolume = bswapBE16(pih->volume) * 4;
if ((!psmp->nVolume) || (psmp->nVolume > 256)) psmp->nVolume = 256;
psmp->nGlobalVol = 64;
psmp->nC4Speed = bswapBE32(pih->finetune);
int f2t = FrequencyToTranspose(psmp->nC4Speed);
psmp->RelativeTone = f2t >> 7;
psmp->nFineTune = f2t & 0x7F;
if ((pih->looplen) && (sflags & 3))
{
psmp->nLoopStart = bswapBE32(pih->loopstart);
psmp->nLoopEnd = psmp->nLoopStart + bswapBE32(pih->looplen);
psmp->uFlags |= CHN_LOOP;
psmp->uFlags &= ~CHN_PINGPONGLOOP;
if (sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP;
}
}
chunk_pos += sizeof(DBMINSTRUMENT);
m_nInstruments = iIns+1;
}
} else
// Volume Envelopes
if (chunk_id == bswapLE32(DBM_ID_VENV))
{
UINT nEnvelopes = lpStream[chunk_pos+1];
chunk_pos += 2;
for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++)
{
DBMENVELOPE *peh;
UINT nins;
if (chunk_pos + sizeof(DBMENVELOPE) > dwMemPos) break;
peh = (DBMENVELOPE *)(lpStream+chunk_pos);
nins = bswapBE16(peh->instrument);
if ((nins) && (nins < MAX_INSTRUMENTS) && (Headers[nins]) && (peh->numpoints))
{
INSTRUMENTHEADER *penv = Headers[nins];
if (peh->flags & 1) penv->dwFlags |= ENV_VOLUME;
if (peh->flags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
if (peh->flags & 4) penv->dwFlags |= ENV_VOLLOOP;
penv->nVolEnv = peh->numpoints + 1;
if (penv->nVolEnv > MAX_ENVPOINTS) penv->nVolEnv = MAX_ENVPOINTS;
penv->nVolLoopStart = peh->loopbegin;
penv->nVolLoopEnd = peh->loopend;
penv->nVolSustainBegin = penv->nVolSustainEnd = peh->sustain1;
for (UINT i=0; i<penv->nVolEnv; i++)
{
penv->VolPoints[i] = bswapBE16(peh->volenv[i*2]);
penv->VolEnv[i] = (BYTE)bswapBE16(peh->volenv[i*2+1]);
}
}
chunk_pos += sizeof(DBMENVELOPE);
}
} else
// Packed Pattern Data
if (chunk_id == bswapLE32(DBM_ID_PATT))
{
if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS;
for (UINT iPat=0; iPat<nPatterns; iPat++)
{
DBMPATTERN *pph;
DWORD pksize;
UINT nRows;
if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break;
pph = (DBMPATTERN *)(lpStream+chunk_pos);
pksize = bswapBE32(pph->packedsize);
if ((chunk_pos + pksize + 6 > dwMemPos) || (pksize > dwMemPos)) break;
nRows = bswapBE16(pph->rows);
if ((nRows >= 4) && (nRows <= 256))
{
MODCOMMAND *m = AllocatePattern(nRows, m_nChannels);
if (m)
{
LPBYTE pkdata = (LPBYTE)&pph->patterndata;
UINT row = 0;
UINT i = 0;
PatternSize[iPat] = nRows;
Patterns[iPat] = m;
while ((i+3<pksize) && (row < nRows))
{
UINT ch = pkdata[i++];
if (ch)
{
BYTE b = pkdata[i++];
ch--;
if (ch < m_nChannels)
{
if (b & 0x01)
{
UINT note = pkdata[i++];
if (note == 0x1F) note = 0xFF; else
if ((note) && (note < 0xFE))
{
note = ((note >> 4)*12) + (note & 0x0F) + 13;
}
m[ch].note = note;
}
if (b & 0x02) m[ch].instr = pkdata[i++];
if (b & 0x3C)
{
UINT cmd1 = 0xFF, param1 = 0, cmd2 = 0xFF, param2 = 0;
if (b & 0x04) cmd1 = (UINT)pkdata[i++];
if (b & 0x08) param1 = pkdata[i++];
if (b & 0x10) cmd2 = (UINT)pkdata[i++];
if (b & 0x20) param2 = pkdata[i++];
if (cmd1 == 0x0C)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = param1;
cmd1 = 0xFF;
} else
if (cmd2 == 0x0C)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = param2;
cmd2 = 0xFF;
}
if ((cmd1 > 0x13) || ((cmd1 >= 0x10) && (cmd2 < 0x10)))
{
cmd1 = cmd2;
param1 = param2;
cmd2 = 0xFF;
}
if (cmd1 <= 0x13)
{
m[ch].command = cmd1;
m[ch].param = param1;
ConvertModCommand(&m[ch]);
}
}
} else
{
if (b & 0x01) i++;
if (b & 0x02) i++;
if (b & 0x04) i++;
if (b & 0x08) i++;
if (b & 0x10) i++;
if (b & 0x20) i++;
}
} else
{
row++;
m += m_nChannels;
}
}
}
}
chunk_pos += 6 + pksize;
}
} else
// Reading Sample Data
if (chunk_id == bswapLE32(DBM_ID_SMPL))
{
if (nSamples >= MAX_SAMPLES) nSamples = MAX_SAMPLES-1;
m_nSamples = nSamples;
for (UINT iSmp=1; iSmp<=nSamples; iSmp++)
{
MODINSTRUMENT *pins;
DBMSAMPLE *psh;
DWORD samplesize;
DWORD sampleflags;
if (chunk_pos + sizeof(DBMSAMPLE) >= dwMemPos) break;
psh = (DBMSAMPLE *)(lpStream+chunk_pos);
chunk_pos += 8;
samplesize = bswapBE32(psh->samplesize);
sampleflags = bswapBE32(psh->flags);
pins = &Ins[iSmp];
pins->nLength = samplesize;
if (sampleflags & 2)
{
pins->uFlags |= CHN_16BIT;
samplesize <<= 1;
}
if ((chunk_pos+samplesize > dwMemPos) || (samplesize > dwMemLength)) break;
if (sampleflags & 3)
{
ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16M : RS_PCM8S,
(LPSTR)(psh->sampledata), samplesize);
}
chunk_pos += samplesize;
}
}
}
return TRUE;
}

View File

@ -0,0 +1,608 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
///////////////////////////////////////////////////////
// DMF DELUSION DIGITAL MUSIC FILEFORMAT (X-Tracker) //
///////////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#define DMFLOG
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct DMFHEADER
{
DWORD id; // "DDMF" = 0x464d4444
BYTE version; // 4
CHAR trackername[8]; // "XTRACKER"
CHAR songname[30];
CHAR composer[20];
BYTE date[3];
} DMFHEADER;
typedef struct DMFINFO
{
DWORD id; // "INFO"
DWORD infosize;
} DMFINFO;
typedef struct DMFSEQU
{
DWORD id; // "SEQU"
DWORD seqsize;
WORD loopstart;
WORD loopend;
WORD sequ[2];
} DMFSEQU;
typedef struct DMFPATT
{
DWORD id; // "PATT"
DWORD patsize;
WORD numpat; // 1-1024
BYTE tracks;
BYTE firstpatinfo;
} DMFPATT;
typedef struct DMFTRACK
{
BYTE tracks;
BYTE beat; // [hi|lo] -> hi=ticks per beat, lo=beats per measure
WORD ticks; // max 512
DWORD jmpsize;
} DMFTRACK;
typedef struct DMFSMPI
{
DWORD id;
DWORD size;
BYTE samples;
} DMFSMPI;
typedef struct DMFSAMPLE
{
DWORD len;
DWORD loopstart;
DWORD loopend;
WORD c3speed;
BYTE volume;
BYTE flags;
} DMFSAMPLE;
#pragma pack()
#ifdef DMFLOG
extern void Log(LPCSTR s, ...);
#endif
BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const DMFHEADER *pfh = (DMFHEADER *)lpStream;
DMFINFO *psi;
DMFSEQU *sequ;
DWORD dwMemPos;
BYTE infobyte[32];
BYTE smplflags[MAX_SAMPLES], hasSMPI = 0;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pfh->id != 0x464d4444) || (!pfh->version) || (pfh->version & 0xF0)) return FALSE;
dwMemPos = 66;
memcpy(m_szNames[0], pfh->songname, 30);
m_szNames[0][30] = 0;
m_nType = MOD_TYPE_DMF;
m_nChannels = 0;
#ifdef DMFLOG
Log("DMF version %d: \"%s\": %d bytes (0x%04X)\n", pfh->version, m_szNames[0], dwMemLength, dwMemLength);
#endif
while (dwMemPos < dwMemLength - 7)
{
DWORD id = *((LPDWORD)(lpStream+dwMemPos));
switch(id)
{
// "INFO"
case 0x4f464e49:
// "CMSG"
case 0x47534d43:
psi = (DMFINFO *)(lpStream+dwMemPos);
if (id == 0x47534d43) dwMemPos++;
if ((psi->infosize > dwMemLength) || (psi->infosize + dwMemPos + 8 > dwMemLength)) goto dmfexit;
if ((psi->infosize >= 8) && (!m_lpszSongComments))
{
m_lpszSongComments = new char[psi->infosize]; // changed from CHAR
if (m_lpszSongComments)
{
for (UINT i=0; i<psi->infosize-1; i++)
{
CHAR c = lpStream[dwMemPos+8+i];
if ((i % 40) == 39)
m_lpszSongComments[i] = 0x0d;
else
m_lpszSongComments[i] = (c < ' ') ? ' ' : c;
}
m_lpszSongComments[psi->infosize-1] = 0;
}
}
dwMemPos += psi->infosize + 8 - 1;
break;
// "SEQU"
case 0x55514553:
sequ = (DMFSEQU *)(lpStream+dwMemPos);
if ((sequ->seqsize >= dwMemLength) || (dwMemPos + sequ->seqsize + 12 > dwMemLength)) goto dmfexit;
{
UINT nseq = sequ->seqsize >> 1;
if (nseq >= MAX_ORDERS-1) nseq = MAX_ORDERS-1;
if (sequ->loopstart < nseq) m_nRestartPos = sequ->loopstart;
for (UINT i=0; i<nseq; i++) Order[i] = (BYTE)sequ->sequ[i];
}
dwMemPos += sequ->seqsize + 8;
break;
// "PATT"
case 0x54544150:
if (!m_nChannels)
{
DMFPATT *patt = (DMFPATT *)(lpStream+dwMemPos);
UINT numpat;
DWORD dwPos = dwMemPos + 11;
if ((patt->patsize >= dwMemLength) || (dwMemPos + patt->patsize + 8 > dwMemLength)) goto dmfexit;
numpat = patt->numpat;
if (numpat > MAX_PATTERNS) numpat = MAX_PATTERNS;
m_nChannels = patt->tracks;
if (m_nChannels < patt->firstpatinfo) m_nChannels = patt->firstpatinfo;
if (m_nChannels > 32) m_nChannels = 32;
if (m_nChannels < 4) m_nChannels = 4;
for (UINT npat=0; npat<numpat; npat++)
{
DMFTRACK *pt = (DMFTRACK *)(lpStream+dwPos);
#ifdef DMFLOG
Log("Pattern #%d: %d tracks, %d rows\n", npat, pt->tracks, pt->ticks);
#endif
UINT tracks = pt->tracks;
if (tracks > 32) tracks = 32;
UINT ticks = pt->ticks;
if (ticks > 256) ticks = 256;
if (ticks < 16) ticks = 16;
dwPos += 8;
if ((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break;
PatternSize[npat] = (WORD)ticks;
MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels);
if (!m) goto dmfexit;
Patterns[npat] = m;
DWORD d = dwPos;
dwPos += pt->jmpsize;
UINT ttype = 1;
UINT tempo = 125;
UINT glbinfobyte = 0;
UINT pbeat = (pt->beat & 0xf0) ? pt->beat>>4 : 8;
BOOL tempochange = (pt->beat & 0xf0) ? TRUE : FALSE;
memset(infobyte, 0, sizeof(infobyte));
for (UINT row=0; row<ticks; row++)
{
MODCOMMAND *p = &m[row*m_nChannels];
// Parse track global effects
if (!glbinfobyte)
{
BYTE info = lpStream[d++];
BYTE infoval = 0;
if ((info & 0x80) && (d < dwPos)) glbinfobyte = lpStream[d++];
info &= 0x7f;
if ((info) && (d < dwPos)) infoval = lpStream[d++];
switch(info)
{
case 1: ttype = 0; tempo = infoval; tempochange = TRUE; break;
case 2: ttype = 1; tempo = infoval; tempochange = TRUE; break;
case 3: pbeat = infoval>>4; tempochange = ttype; break;
#ifdef DMFLOG
default: if (info) Log("GLB: %02X.%02X\n", info, infoval);
#endif
}
} else
{
glbinfobyte--;
}
// Parse channels
for (UINT i=0; i<tracks; i++) if (!infobyte[i])
{
MODCOMMAND cmd = {0,0,0,0,0,0};
BYTE info = lpStream[d++];
if (info & 0x80) infobyte[i] = lpStream[d++];
// Instrument
if (info & 0x40)
{
cmd.instr = lpStream[d++];
}
// Note
if (info & 0x20)
{
cmd.note = lpStream[d++];
if ((cmd.note) && (cmd.note < 0xfe)) cmd.note &= 0x7f;
if ((cmd.note) && (cmd.note < 128)) cmd.note += 24;
}
// Volume
if (info & 0x10)
{
cmd.volcmd = VOLCMD_VOLUME;
cmd.vol = (lpStream[d++]+3)>>2;
}
// Effect 1
if (info & 0x08)
{
BYTE efx = lpStream[d++];
BYTE eval = lpStream[d++];
switch(efx)
{
// 1: Key Off
case 1: if (!cmd.note) cmd.note = 0xFE; break;
// 2: Set Loop
// 4: Sample Delay
case 4: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break;
// 5: Retrig
case 5: if (eval&0xe0) { cmd.command = CMD_RETRIG; cmd.param = (eval>>5); } break;
// 6: Offset
case 6: cmd.command = CMD_OFFSET; cmd.param = eval; break;
#ifdef DMFLOG
default: Log("FX1: %02X.%02X\n", efx, eval);
#endif
}
}
// Effect 2
if (info & 0x04)
{
BYTE efx = lpStream[d++];
BYTE eval = lpStream[d++];
switch(efx)
{
// 1: Finetune
case 1: if (eval&0xf0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>4)|0x20; } break;
// 2: Note Delay
case 2: if (eval&0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xD0; } break;
// 3: Arpeggio
case 3: if (eval) { cmd.command = CMD_ARPEGGIO; cmd.param = eval; } break;
// 4: Portamento Up
case 4: cmd.command = CMD_PORTAMENTOUP; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break;
// 5: Portamento Down
case 5: cmd.command = CMD_PORTAMENTODOWN; cmd.param = (eval >= 0xe0) ? 0xdf : eval; break;
// 6: Tone Portamento
case 6: cmd.command = CMD_TONEPORTAMENTO; cmd.param = eval; break;
// 8: Vibrato
case 8: cmd.command = CMD_VIBRATO; cmd.param = eval; break;
// 12: Note cut
case 12: if (eval & 0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval>>5)|0xc0; }
else if (!cmd.note) { cmd.note = 0xfe; } break;
#ifdef DMFLOG
default: Log("FX2: %02X.%02X\n", efx, eval);
#endif
}
}
// Effect 3
if (info & 0x02)
{
BYTE efx = lpStream[d++];
BYTE eval = lpStream[d++];
switch(efx)
{
// 1: Vol Slide Up
case 1: if (eval == 0xff) break;
eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
cmd.command = CMD_VOLUMESLIDE; cmd.param = eval<<4; break;
// 2: Vol Slide Down
case 2: if (eval == 0xff) break;
eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
cmd.command = CMD_VOLUMESLIDE; cmd.param = eval; break;
// 7: Set Pan
case 7: if (!cmd.volcmd) { cmd.volcmd = VOLCMD_PANNING; cmd.vol = (eval+3)>>2; }
else { cmd.command = CMD_PANNING8; cmd.param = eval; } break;
// 8: Pan Slide Left
case 8: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
cmd.command = CMD_PANNINGSLIDE; cmd.param = eval<<4; break;
// 9: Pan Slide Right
case 9: eval = (eval+3)>>2; if (eval > 0x0f) eval = 0x0f;
cmd.command = CMD_PANNINGSLIDE; cmd.param = eval; break;
#ifdef DMFLOG
default: Log("FX3: %02X.%02X\n", efx, eval);
#endif
}
}
// Store effect
if (i < m_nChannels) p[i] = cmd;
if (d > dwPos)
{
#ifdef DMFLOG
Log("Unexpected EOP: row=%d\n", row);
#endif
break;
}
} else
{
infobyte[i]--;
}
// Find free channel for tempo change
if (tempochange)
{
tempochange = FALSE;
UINT speed=6, modtempo=tempo;
UINT rpm = ((ttype) && (pbeat)) ? tempo*pbeat : (tempo+1)*15;
for (speed=30; speed>1; speed--)
{
modtempo = rpm*speed/24;
if (modtempo <= 200) break;
if ((speed < 6) && (modtempo < 256)) break;
}
#ifdef DMFLOG
Log("Tempo change: ttype=%d pbeat=%d tempo=%3d -> speed=%d tempo=%d\n",
ttype, pbeat, tempo, speed, modtempo);
#endif
for (UINT ich=0; ich<m_nChannels; ich++) if (!p[ich].command)
{
if (speed)
{
p[ich].command = CMD_SPEED;
p[ich].param = (BYTE)speed;
speed = 0;
} else
if ((modtempo >= 32) && (modtempo < 256))
{
p[ich].command = CMD_TEMPO;
p[ich].param = (BYTE)modtempo;
modtempo = 0;
} else
{
break;
}
}
}
if (d >= dwPos) break;
}
#ifdef DMFLOG
Log(" %d/%d bytes remaining\n", dwPos-d, pt->jmpsize);
#endif
if (dwPos + 8 >= dwMemLength) break;
}
dwMemPos += patt->patsize + 8;
}
break;
// "SMPI": Sample Info
case 0x49504d53:
{
hasSMPI = 1;
DMFSMPI *pds = (DMFSMPI *)(lpStream+dwMemPos);
if (pds->size <= dwMemLength - dwMemPos)
{
DWORD dwPos = dwMemPos + 9;
m_nSamples = pds->samples;
if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
{
UINT namelen = lpStream[dwPos];
smplflags[iSmp] = 0;
if (dwPos+namelen+1+sizeof(DMFSAMPLE) > dwMemPos+pds->size+8) break;
if (namelen)
{
UINT rlen = (namelen < 32) ? namelen : 31;
memcpy(m_szNames[iSmp], lpStream+dwPos+1, rlen);
m_szNames[iSmp][rlen] = 0;
}
dwPos += namelen + 1;
DMFSAMPLE *psh = (DMFSAMPLE *)(lpStream+dwPos);
MODINSTRUMENT *psmp = &Ins[iSmp];
psmp->nLength = psh->len;
psmp->nLoopStart = psh->loopstart;
psmp->nLoopEnd = psh->loopend;
psmp->nC4Speed = psh->c3speed;
psmp->nGlobalVol = 64;
psmp->nVolume = (psh->volume) ? ((WORD)psh->volume)+1 : (WORD)256;
psmp->uFlags = (psh->flags & 2) ? CHN_16BIT : 0;
if (psmp->uFlags & CHN_16BIT) psmp->nLength >>= 1;
if (psh->flags & 1) psmp->uFlags |= CHN_LOOP;
smplflags[iSmp] = psh->flags;
dwPos += (pfh->version < 8) ? 22 : 30;
#ifdef DMFLOG
Log("SMPI %d/%d: len=%d flags=0x%02X\n", iSmp, m_nSamples, psmp->nLength, psh->flags);
#endif
}
}
dwMemPos += pds->size + 8;
}
break;
// "SMPD": Sample Data
case 0x44504d53:
{
DWORD dwPos = dwMemPos + 8;
UINT ismpd = 0;
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++)
{
ismpd++;
DWORD pksize;
if (dwPos + 4 >= dwMemLength)
{
#ifdef DMFLOG
Log("Unexpected EOF at sample %d/%d! (pos=%d)\n", iSmp, m_nSamples, dwPos);
#endif
break;
}
pksize = *((LPDWORD)(lpStream+dwPos));
#ifdef DMFLOG
Log("sample %d: pos=0x%X pksize=%d ", iSmp, dwPos, pksize);
Log("len=%d flags=0x%X [%08X]\n", Ins[iSmp].nLength, smplflags[ismpd], *((LPDWORD)(lpStream+dwPos+4)));
#endif
dwPos += 4;
if (pksize > dwMemLength - dwPos)
{
#ifdef DMFLOG
Log("WARNING: pksize=%d, but only %d bytes left\n", pksize, dwMemLength-dwPos);
#endif
pksize = dwMemLength - dwPos;
}
if ((pksize) && (iSmp <= m_nSamples))
{
UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
if (hasSMPI && smplflags[ismpd] & 4)
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_DMF16 : RS_DMF8;
ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwPos), pksize);
}
dwPos += pksize;
}
dwMemPos = dwPos;
}
break;
// "ENDE": end of file
case 0x45444e45:
goto dmfexit;
// Unrecognized id, or "ENDE" field
default:
dwMemPos += 4;
break;
}
}
dmfexit:
if (!m_nChannels)
{
if (!m_nSamples)
{
m_nType = MOD_TYPE_NONE;
return FALSE;
}
m_nChannels = 4;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////
// DMF Compression
#pragma pack(1)
typedef struct DMF_HNODE
{
short int left, right;
BYTE value;
} DMF_HNODE;
typedef struct DMF_HTREE
{
LPBYTE ibuf, ibufmax;
DWORD bitbuf;
UINT bitnum;
UINT lastnode, nodecount;
DMF_HNODE nodes[256];
} DMF_HTREE;
#pragma pack()
// DMF Huffman ReadBits
static BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits)
//-------------------------------------------
{
BYTE x = 0, bitv = 1;
while (nbits--)
{
if (tree->bitnum)
{
tree->bitnum--;
} else
{
tree->bitbuf = (tree->ibuf < tree->ibufmax) ? *(tree->ibuf++) : 0;
tree->bitnum = 7;
}
if (tree->bitbuf & 1) x |= bitv;
bitv <<= 1;
tree->bitbuf >>= 1;
}
return x;
}
//
// tree: [8-bit value][12-bit index][12-bit index] = 32-bit
//
static void DMFNewNode(DMF_HTREE *tree)
//------------------------------
{
BYTE isleft, isright;
UINT actnode;
actnode = tree->nodecount;
if (actnode > 255) return;
tree->nodes[actnode].value = DMFReadBits(tree, 7);
isleft = DMFReadBits(tree, 1);
isright = DMFReadBits(tree, 1);
actnode = tree->lastnode;
if (actnode > 255) return;
tree->nodecount++;
tree->lastnode = tree->nodecount;
if (isleft)
{
tree->nodes[actnode].left = tree->lastnode;
DMFNewNode(tree);
} else
{
tree->nodes[actnode].left = -1;
}
tree->lastnode = tree->nodecount;
if (isright)
{
tree->nodes[actnode].right = tree->lastnode;
DMFNewNode(tree);
} else
{
tree->nodes[actnode].right = -1;
}
}
int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen)
//----------------------------------------------------------------------
{
DMF_HTREE tree;
UINT actnode;
BYTE value, sign, delta = 0;
memset(&tree, 0, sizeof(tree));
tree.ibuf = ibuf;
tree.ibufmax = ibufmax;
DMFNewNode(&tree);
value = 0;
for (UINT i=0; i<maxlen; i++)
{
actnode = 0;
sign = DMFReadBits(&tree, 1);
do
{
if (DMFReadBits(&tree, 1))
actnode = tree.nodes[actnode].right;
else
actnode = tree.nodes[actnode].left;
if (actnode > 255) break;
delta = tree.nodes[actnode].value;
if ((tree.ibuf >= tree.ibufmax) && (!tree.bitnum)) break;
} while ((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0));
if (sign) delta ^= 0xFF;
value += delta;
psample[i] = (i) ? value : 0;
}
#ifdef DMFLOG
// Log("DMFUnpack: %d remaining bytes\n", tree.ibufmax-tree.ibuf);
#endif
return tree.ibuf - ibuf;
}

View File

@ -0,0 +1,236 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
//////////////////////////////////////////////
// DSIK Internal Format (DSM) module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
#pragma pack(1)
#define DSMID_RIFF 0x46464952 // "RIFF"
#define DSMID_DSMF 0x464d5344 // "DSMF"
#define DSMID_SONG 0x474e4f53 // "SONG"
#define DSMID_INST 0x54534e49 // "INST"
#define DSMID_PATT 0x54544150 // "PATT"
typedef struct DSMNOTE
{
BYTE note,ins,vol,cmd,inf;
} DSMNOTE;
typedef struct DSMINST
{
DWORD id_INST;
DWORD inst_len;
CHAR filename[13];
BYTE flags;
BYTE flags2;
BYTE volume;
DWORD length;
DWORD loopstart;
DWORD loopend;
DWORD reserved1;
WORD c2spd;
WORD reserved2;
CHAR samplename[28];
} DSMINST;
typedef struct DSMFILEHEADER
{
DWORD id_RIFF; // "RIFF"
DWORD riff_len;
DWORD id_DSMF; // "DSMF"
DWORD id_SONG; // "SONG"
DWORD song_len;
} DSMFILEHEADER;
typedef struct DSMSONG
{
CHAR songname[28];
WORD reserved1;
WORD flags;
DWORD reserved2;
WORD numord;
WORD numsmp;
WORD numpat;
WORD numtrk;
BYTE globalvol;
BYTE mastervol;
BYTE speed;
BYTE bpm;
BYTE panpos[16];
BYTE orders[128];
} DSMSONG;
typedef struct DSMPATT
{
DWORD id_PATT;
DWORD patt_len;
BYTE dummy1;
BYTE dummy2;
} DSMPATT;
#pragma pack()
BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream;
DSMSONG *psong;
DWORD dwMemPos;
UINT nPat, nSmp;
if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF)
|| (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024)
|| (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG)
|| (pfh->song_len > dwMemLength)) return FALSE;
psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER));
dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len;
m_nType = MOD_TYPE_DSM;
m_nChannels = psong->numtrk;
if (m_nChannels < 4) m_nChannels = 4;
if (m_nChannels > 16) m_nChannels = 16;
m_nSamples = psong->numsmp;
if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES - 1;
m_nDefaultSpeed = psong->speed;
m_nDefaultTempo = psong->bpm;
m_nDefaultGlobalVolume = psong->globalvol << 2;
if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
m_nSongPreAmp = psong->mastervol & 0x7F;
for (UINT iOrd=0; iOrd<sizeof(psong->orders); iOrd++)
{
Order[iOrd] = (BYTE)((iOrd < psong->numord) ? psong->orders[iOrd] : 0xFF);
}
for (UINT iPan=0; iPan<16; iPan++)
{
ChnSettings[iPan].nPan = 0x80;
if (psong->panpos[iPan] <= 0x80)
{
ChnSettings[iPan].nPan = psong->panpos[iPan] << 1;
}
}
memcpy(m_szNames[0], psong->songname, 28);
nPat = 0;
nSmp = 1;
while (dwMemPos < dwMemLength - 8)
{
DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos);
DSMINST *pins = (DSMINST *)(lpStream+dwMemPos);
// Reading Patterns
if (ppatt->id_PATT == DSMID_PATT)
{
dwMemPos += 8;
if (dwMemPos + ppatt->patt_len >= dwMemLength) break;
DWORD dwPos = dwMemPos;
dwMemPos += ppatt->patt_len;
MODCOMMAND *m = AllocatePattern(64, m_nChannels);
if (!m) break;
PatternSize[nPat] = 64;
Patterns[nPat] = m;
UINT row = 0;
while ((row < 64) && (dwPos + 2 <= dwMemPos))
{
UINT flag = lpStream[dwPos++];
if (flag)
{
UINT ch = (flag & 0x0F) % m_nChannels;
if (flag & 0x80)
{
UINT note = lpStream[dwPos++];
if (note)
{
if (note <= 12*9) note += 12;
m[ch].note = (BYTE)note;
}
}
if (flag & 0x40)
{
m[ch].instr = lpStream[dwPos++];
}
if (flag & 0x20)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = lpStream[dwPos++];
}
if (flag & 0x10)
{
UINT command = lpStream[dwPos++];
UINT param = lpStream[dwPos++];
switch(command)
{
// 4-bit Panning
case 0x08:
switch(param & 0xF0)
{
case 0x00: param <<= 4; break;
case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break;
case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break;
case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break;
case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break;
default: command = 0;
}
break;
// Portamentos
case 0x11:
case 0x12:
command &= 0x0F;
break;
// 3D Sound (?)
case 0x13:
command = 'X' - 55;
param = 0x91;
break;
default:
// Volume + Offset (?)
command = ((command & 0xF0) == 0x20) ? 0x09 : 0;
}
m[ch].command = (BYTE)command;
m[ch].param = (BYTE)param;
if (command) ConvertModCommand(&m[ch]);
}
} else
{
m += m_nChannels;
row++;
}
}
nPat++;
} else
// Reading Samples
if ((nSmp <= m_nSamples) && (pins->id_INST == DSMID_INST))
{
if (dwMemPos + pins->inst_len >= dwMemLength - 8) break;
DWORD dwPos = dwMemPos + sizeof(DSMINST);
dwMemPos += 8 + pins->inst_len;
memcpy(m_szNames[nSmp], pins->samplename, 28);
MODINSTRUMENT *psmp = &Ins[nSmp];
memcpy(psmp->name, pins->filename, 13);
psmp->nGlobalVol = 64;
psmp->nC4Speed = pins->c2spd;
psmp->uFlags = (WORD)((pins->flags & 1) ? CHN_LOOP : 0);
psmp->nLength = pins->length;
psmp->nLoopStart = pins->loopstart;
psmp->nLoopEnd = pins->loopend;
psmp->nVolume = (WORD)(pins->volume << 2);
if (psmp->nVolume > 256) psmp->nVolume = 256;
UINT smptype = (pins->flags & 2) ? RS_PCM8S : RS_PCM8U;
ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos);
nSmp++;
} else
{
break;
}
}
return TRUE;
}

View File

@ -0,0 +1,265 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
////////////////////////////////////////
// Farandole (FAR) module loader //
////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#define FARFILEMAGIC 0xFE524146 // "FAR"
#pragma pack(1)
typedef struct FARHEADER1
{
DWORD id; // file magic FAR=
CHAR songname[40]; // songname
CHAR magic2[3]; // 13,10,26
WORD headerlen; // remaining length of header in bytes
BYTE version; // 0xD1
BYTE onoff[16];
BYTE edit1[9];
BYTE speed;
BYTE panning[16];
BYTE edit2[4];
WORD stlen;
} FARHEADER1;
typedef struct FARHEADER2
{
BYTE orders[256];
BYTE numpat;
BYTE snglen;
BYTE loopto;
WORD patsiz[256];
} FARHEADER2;
typedef struct FARSAMPLE
{
CHAR samplename[32];
DWORD length;
BYTE finetune;
BYTE volume;
DWORD reppos;
DWORD repend;
BYTE type;
BYTE loop;
} FARSAMPLE;
#pragma pack()
BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const FARHEADER1 *pmh1 = (const FARHEADER1 *)lpStream;
const FARHEADER2 *pmh2;
DWORD dwMemPos = sizeof(FARHEADER1);
UINT headerlen, stlen;
BYTE samplemap[8];
if ((!lpStream) || (dwMemLength < 1024) || (bswapLE32(pmh1->id) != FARFILEMAGIC)
|| (pmh1->magic2[0] != 13) || (pmh1->magic2[1] != 10) || (pmh1->magic2[2] != 26)) return FALSE;
headerlen = bswapLE16(pmh1->headerlen);
stlen = bswapLE16( pmh1->stlen );
if ((headerlen >= dwMemLength) || (dwMemPos + stlen + sizeof(FARHEADER2) >= dwMemLength)) return FALSE;
// Globals
m_nType = MOD_TYPE_FAR;
m_nChannels = 16;
m_nInstruments = 0;
m_nSamples = 0;
m_nSongPreAmp = 0x20;
m_nDefaultSpeed = pmh1->speed;
m_nDefaultTempo = 80;
m_nDefaultGlobalVolume = 256;
memcpy(m_szNames[0], pmh1->songname, 32);
// Channel Setting
for (UINT nchpan=0; nchpan<16; nchpan++)
{
ChnSettings[nchpan].dwFlags = 0;
ChnSettings[nchpan].nPan = ((pmh1->panning[nchpan] & 0x0F) << 4) + 8;
ChnSettings[nchpan].nVolume = 64;
}
// Reading comment
if (stlen)
{
UINT szLen = stlen;
if (szLen > dwMemLength - dwMemPos) szLen = dwMemLength - dwMemPos;
if ((m_lpszSongComments = new char[szLen + 1]) != NULL)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos, szLen);
m_lpszSongComments[szLen] = 0;
}
dwMemPos += stlen;
}
// Reading orders
if (sizeof(FARHEADER2) > dwMemLength - dwMemPos) return TRUE;
pmh2 = (const FARHEADER2 *)(lpStream + dwMemPos);
dwMemPos += sizeof(FARHEADER2);
if (dwMemPos >= dwMemLength) return TRUE;
for (UINT iorder=0; iorder<MAX_ORDERS; iorder++)
{
Order[iorder] = (iorder <= pmh2->snglen) ? pmh2->orders[iorder] : 0xFF;
}
m_nRestartPos = pmh2->loopto;
// Reading Patterns
dwMemPos += headerlen - (869 + stlen);
if (dwMemPos >= dwMemLength) return TRUE;
// end byteswap of pattern data
WORD *patsiz = (WORD *)pmh2->patsiz;
for (UINT ipat=0; ipat<256; ipat++) if (patsiz[ipat])
{
UINT patlen = bswapLE16(patsiz[ipat]);
if ((ipat >= MAX_PATTERNS) || (patlen < 2))
{
dwMemPos += patlen;
continue;
}
if (dwMemPos + patlen >= dwMemLength) return TRUE;
UINT rows = (patlen - 2) >> 6;
if (!rows)
{
dwMemPos += patlen;
continue;
}
if (rows > 256) rows = 256;
if (rows < 16) rows = 16;
PatternSize[ipat] = rows;
if ((Patterns[ipat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
MODCOMMAND *m = Patterns[ipat];
UINT patbrk = lpStream[dwMemPos];
const BYTE *p = lpStream + dwMemPos + 2;
UINT max = rows*16*4;
if (max > patlen-2) max = patlen-2;
for (UINT len=0; len<max; len += 4, m++)
{
BYTE note = p[len];
BYTE ins = p[len+1];
BYTE vol = p[len+2];
BYTE eff = p[len+3];
if (note)
{
m->instr = ins + 1;
m->note = note + 36;
}
if (vol & 0x0F)
{
m->volcmd = VOLCMD_VOLUME;
m->vol = (vol & 0x0F) << 2;
if (m->vol <= 4) m->vol = 0;
}
switch(eff & 0xF0)
{
// 1.x: Portamento Up
case 0x10:
m->command = CMD_PORTAMENTOUP;
m->param = eff & 0x0F;
break;
// 2.x: Portamento Down
case 0x20:
m->command = CMD_PORTAMENTODOWN;
m->param = eff & 0x0F;
break;
// 3.x: Tone-Portamento
case 0x30:
m->command = CMD_TONEPORTAMENTO;
m->param = (eff & 0x0F) << 2;
break;
// 4.x: Retrigger
case 0x40:
m->command = CMD_RETRIG;
m->param = 6 / (1+(eff&0x0F)) + 1;
break;
// 5.x: Set Vibrato Depth
case 0x50:
m->command = CMD_VIBRATO;
m->param = (eff & 0x0F);
break;
// 6.x: Set Vibrato Speed
case 0x60:
m->command = CMD_VIBRATO;
m->param = (eff & 0x0F) << 4;
break;
// 7.x: Vol Slide Up
case 0x70:
m->command = CMD_VOLUMESLIDE;
m->param = (eff & 0x0F) << 4;
break;
// 8.x: Vol Slide Down
case 0x80:
m->command = CMD_VOLUMESLIDE;
m->param = (eff & 0x0F);
break;
// A.x: Port to vol
case 0xA0:
m->volcmd = VOLCMD_VOLUME;
m->vol = ((eff & 0x0F) << 2) + 4;
break;
// B.x: Set Balance
case 0xB0:
m->command = CMD_PANNING8;
m->param = (eff & 0x0F) << 4;
break;
// F.x: Set Speed
case 0xF0:
m->command = CMD_SPEED;
m->param = eff & 0x0F;
break;
default:
if ((patbrk) && (patbrk+1 == (len >> 6)) && (patbrk+1 != rows-1))
{
m->command = CMD_PATTERNBREAK;
patbrk = 0;
}
}
}
dwMemPos += patlen;
}
// Reading samples
if (dwMemPos + 8 >= dwMemLength) return TRUE;
memcpy(samplemap, lpStream+dwMemPos, 8);
dwMemPos += 8;
MODINSTRUMENT *pins = &Ins[1];
for (UINT ismp=0; ismp<64; ismp++, pins++) if (samplemap[ismp >> 3] & (1 << (ismp & 7)))
{
if (dwMemPos + sizeof(FARSAMPLE) > dwMemLength) return TRUE;
const FARSAMPLE *pfs = reinterpret_cast<const FARSAMPLE*>(lpStream + dwMemPos);
dwMemPos += sizeof(FARSAMPLE);
m_nSamples = ismp + 1;
memcpy(m_szNames[ismp+1], pfs->samplename, 32);
const DWORD length = bswapLE32( pfs->length ) ; /* endian fix - Toad */
pins->nLength = length ;
pins->nLoopStart = bswapLE32(pfs->reppos) ;
pins->nLoopEnd = bswapLE32(pfs->repend) ;
pins->nFineTune = 0;
pins->nC4Speed = 8363*2;
pins->nGlobalVol = 64;
pins->nVolume = pfs->volume << 4;
pins->uFlags = 0;
if ((pins->nLength > 3) && (dwMemPos + 4 < dwMemLength))
{
if (pfs->type & 1)
{
pins->uFlags |= CHN_16BIT;
pins->nLength >>= 1;
pins->nLoopStart >>= 1;
pins->nLoopEnd >>= 1;
}
if ((pfs->loop & 8) && (pins->nLoopEnd > 4)) pins->uFlags |= CHN_LOOP;
ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S,
(LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
}
dwMemPos += length;
}
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
///////////////////////////////////////////////////
//
// J2B module loader
//
///////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"

View File

@ -0,0 +1,532 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
//////////////////////////////////////////////
// DigiTracker (MDL) module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
typedef struct MDLSONGHEADER
{
DWORD id; // "DMDL" = 0x4C444D44
BYTE version;
} MDLSONGHEADER;
typedef struct MDLINFOBLOCK
{
CHAR songname[32];
CHAR composer[20];
WORD norders;
WORD repeatpos;
BYTE globalvol;
BYTE speed;
BYTE tempo;
BYTE channelinfo[32];
BYTE seq[256];
} MDLINFOBLOCK;
typedef struct MDLPATTERNDATA
{
BYTE channels;
BYTE lastrow; // nrows = lastrow+1
CHAR name[16];
WORD data[1];
} MDLPATTERNDATA;
static void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data)
//--------------------------------------------------------
{
UINT command = 0, param = data;
switch(eff)
{
case 0x01: command = CMD_PORTAMENTOUP; break;
case 0x02: command = CMD_PORTAMENTODOWN; break;
case 0x03: command = CMD_TONEPORTAMENTO; break;
case 0x04: command = CMD_VIBRATO; break;
case 0x05: command = CMD_ARPEGGIO; break;
case 0x07: command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break;
case 0x08: command = CMD_PANNING8; param <<= 1; break;
case 0x0B: command = CMD_POSITIONJUMP; break;
case 0x0C: command = CMD_GLOBALVOLUME; break;
case 0x0D: command = CMD_PATTERNBREAK; param = (data & 0x0F) + (data>>4)*10; break;
case 0x0E:
command = CMD_S3MCMDEX;
switch(data & 0xF0)
{
case 0x00: command = 0; break; // What is E0x in MDL (there is a bunch) ?
case 0x10: if (param & 0x0F) { param |= 0xF0; command = CMD_PANNINGSLIDE; } else command = 0; break;
case 0x20: if (param & 0x0F) { param = (param << 4) | 0x0F; command = CMD_PANNINGSLIDE; } else command = 0; break;
case 0x30: param = (data & 0x0F) | 0x10; break; // glissando
case 0x40: param = (data & 0x0F) | 0x30; break; // vibrato waveform
case 0x60: param = (data & 0x0F) | 0xB0; break;
case 0x70: param = (data & 0x0F) | 0x40; break; // tremolo waveform
case 0x90: command = CMD_RETRIG; param &= 0x0F; break;
case 0xA0: param = (data & 0x0F) << 4; command = CMD_GLOBALVOLSLIDE; break;
case 0xB0: param = data & 0x0F; command = CMD_GLOBALVOLSLIDE; break;
case 0xF0: param = ((data >> 8) & 0x0F) | 0xA0; break;
}
break;
case 0x0F: command = CMD_SPEED; break;
case 0x10: if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break;
case 0x20: if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break;
case 0x30: command = CMD_RETRIG; break;
case 0x40: command = CMD_TREMOLO; break;
case 0x50: command = CMD_TREMOR; break;
case 0xEF: if (param > 0xFF) param = 0xFF; command = CMD_OFFSET; break;
}
if (command)
{
m->command = command;
m->param = param;
}
}
static void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks, UINT len)
//-------------------------------------------------------------------------------------------------
{
MODCOMMAND cmd, *m = pat;
UINT pos = 0, row = 0, i;
cmd.note = cmd.instr = 0;
cmd.volcmd = cmd.vol = 0;
cmd.command = cmd.param = 0;
while ((row < nRows) && (pos < len))
{
UINT xx;
BYTE b = lpTracks[pos++];
xx = b >> 2;
switch(b & 0x03)
{
case 0x01:
for (i=0; i<=xx; i++)
{
if (row) *m = *(m-nChannels);
m += nChannels;
row++;
if (row >= nRows) break;
}
break;
case 0x02:
if (xx < row) *m = pat[nChannels*xx];
m += nChannels;
row++;
break;
case 0x03:
{
cmd.note = (xx & 0x01) ? lpTracks[pos++] : 0;
cmd.instr = (xx & 0x02) ? lpTracks[pos++] : 0;
cmd.volcmd = cmd.vol = 0;
cmd.command = cmd.param = 0;
if ((cmd.note < NOTE_MAX-12) && (cmd.note)) cmd.note += 12;
UINT volume = (xx & 0x04) ? lpTracks[pos++] : 0;
UINT commands = (xx & 0x08) ? lpTracks[pos++] : 0;
UINT command1 = commands & 0x0F;
UINT command2 = commands & 0xF0;
UINT param1 = (xx & 0x10) ? lpTracks[pos++] : 0;
UINT param2 = (xx & 0x20) ? lpTracks[pos++] : 0;
if ((command1 == 0x0E) && ((param1 & 0xF0) == 0xF0) && (!command2))
{
param1 = ((param1 & 0x0F) << 8) | param2;
command1 = 0xEF;
command2 = param2 = 0;
}
if (volume)
{
cmd.volcmd = VOLCMD_VOLUME;
cmd.vol = (volume+1) >> 2;
}
ConvertMDLCommand(&cmd, command1, param1);
if ((cmd.command != CMD_SPEED)
&& (cmd.command != CMD_TEMPO)
&& (cmd.command != CMD_PATTERNBREAK))
ConvertMDLCommand(&cmd, command2, param2);
*m = cmd;
m += nChannels;
row++;
}
break;
// Empty Slots
default:
row += xx+1;
m += (xx+1)*nChannels;
if (row >= nRows) break;
}
}
}
BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
DWORD dwMemPos, dwPos, blocklen, dwTrackPos;
const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream;
const MDLINFOBLOCK *pmib;
UINT i,j, norders = 0, npatterns = 0, ntracks = 0;
UINT ninstruments = 0, nsamples = 0;
WORD block;
WORD patterntracks[MAX_PATTERNS*32];
BYTE smpinfo[MAX_SAMPLES];
BYTE insvolenv[MAX_INSTRUMENTS];
BYTE inspanenv[MAX_INSTRUMENTS];
LPCBYTE pvolenv, ppanenv, ppitchenv;
UINT nvolenv, npanenv, npitchenv;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE;
const UINT hdrLen = (pmsh->version>0)? 59 : 57;
memset(patterntracks, 0, sizeof(patterntracks));
memset(smpinfo, 0, sizeof(smpinfo));
memset(insvolenv, 0, sizeof(insvolenv));
memset(inspanenv, 0, sizeof(inspanenv));
dwMemPos = 5;
dwTrackPos = 0;
pvolenv = ppanenv = ppitchenv = NULL;
nvolenv = npanenv = npitchenv = 0;
m_nSamples = m_nInstruments = 0;
while (dwMemPos+6 < dwMemLength)
{
const BYTE *pp = lpStream + dwMemPos;
block = pp[0] | (pp[1] << 8);
blocklen = pp[2] | (pp[3] << 8) | (pp[4] << 16) | (pp[5] << 24);
dwMemPos += 6;
if (blocklen > dwMemLength - dwMemPos)
{
if (dwMemPos == 11) return FALSE;
break;
}
switch(block)
{
// IN: infoblock
case 0x4E49:
pmib = (const MDLINFOBLOCK *)(lpStream+dwMemPos);
memcpy(m_szNames[0], pmib->songname, 32);
m_szNames[0][31] = 0;
norders = pmib->norders;
if (norders > MAX_ORDERS) norders = MAX_ORDERS;
m_nRestartPos = pmib->repeatpos;
m_nDefaultGlobalVolume = pmib->globalvol;
m_nDefaultTempo = pmib->tempo;
m_nDefaultSpeed = pmib->speed;
m_nChannels = 4;
for (i=0; i<32; i++)
{
ChnSettings[i].nVolume = 64;
ChnSettings[i].nPan = (pmib->channelinfo[i] & 0x7F) << 1;
if (pmib->channelinfo[i] & 0x80)
ChnSettings[i].dwFlags |= CHN_MUTE;
else
m_nChannels = i+1;
}
for (j=0; j<norders; j++) Order[j] = pmib->seq[j];
break;
// ME: song message
case 0x454D:
if (blocklen)
{
if (m_lpszSongComments) delete [] m_lpszSongComments;
m_lpszSongComments = new char[blocklen];
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos, blocklen);
m_lpszSongComments[blocklen-1] = 0;
}
}
break;
// PA: Pattern Data
case 0x4150:
npatterns = lpStream[dwMemPos];
if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS;
dwPos = dwMemPos + 1;
for (i=0; i<npatterns; i++)
{
const BYTE *data;
UINT ch;
if (pmsh->version == 0) {
if (m_nChannels < 32) m_nChannels = 32;
ch = 32;
} else {
if (dwPos+18 >= dwMemLength) break;
const MDLPATTERNDATA *pmpd = (const MDLPATTERNDATA *)(lpStream + dwPos);
if (pmpd->channels > 32) break;
PatternSize[i] = pmpd->lastrow+1;
if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels;
ch = pmpd->channels;
}
if (2 * ch >= dwMemLength - dwPos) break;
data = lpStream + dwPos;
dwPos += 2 * ch;
for (j=0; j<ch && j<m_nChannels; j++, data+=2)
{
patterntracks[i*32+j] = data[0] | (data[1] << 8);
}
}
break;
// TR: Track Data
case 0x5254:
if (dwTrackPos) break;
pp = lpStream + dwMemPos;
ntracks = pp[0] | (pp[1] << 8);
dwTrackPos = dwMemPos+2;
break;
// II: Instruments
case 0x4949:
ninstruments = lpStream[dwMemPos];
dwPos = dwMemPos+1;
for (i=0; i<ninstruments; i++)
{
UINT nins = lpStream[dwPos];
if ((nins >= MAX_INSTRUMENTS) || (!nins)) break;
if (m_nInstruments < nins) m_nInstruments = nins;
if (!Headers[nins])
{
UINT note = 12;
if ((Headers[nins] = new INSTRUMENTHEADER) == NULL) break;
INSTRUMENTHEADER *penv = Headers[nins];
memset(penv, 0, sizeof(INSTRUMENTHEADER));
memcpy(penv->name, lpStream+dwPos+2, 32);
penv->nGlobalVol = 64;
penv->nPPC = 5*12;
for (j=0; j<lpStream[dwPos+1]; j++)
{
const BYTE *ps = lpStream+dwPos+34+14*j;
while ((note < (UINT)(ps[1]+12)) && (note < NOTE_MAX))
{
penv->NoteMap[note] = note+1;
if (ps[0] < MAX_SAMPLES)
{
int ismp = ps[0];
penv->Keyboard[note] = ps[0];
Ins[ismp].nVolume = ps[2];
Ins[ismp].nPan = ps[4] << 1;
Ins[ismp].nVibType = ps[11];
Ins[ismp].nVibSweep = ps[10];
Ins[ismp].nVibDepth = ps[9];
Ins[ismp].nVibRate = ps[8];
}
penv->nFadeOut = (ps[7] << 8) | ps[6];
if (penv->nFadeOut == 0xFFFF) penv->nFadeOut = 0;
note++;
}
// Use volume envelope ?
if (ps[3] & 0x80)
{
penv->dwFlags |= ENV_VOLUME;
insvolenv[nins] = (ps[3] & 0x3F) + 1;
}
// Use panning envelope ?
if (ps[5] & 0x80)
{
penv->dwFlags |= ENV_PANNING;
inspanenv[nins] = (ps[5] & 0x3F) + 1;
}
}
}
dwPos += 34 + 14*lpStream[dwPos+1];
}
for (j=1; j<=m_nInstruments; j++) if (!Headers[j])
{
Headers[j] = new INSTRUMENTHEADER;
if (Headers[j]) memset(Headers[j], 0, sizeof(INSTRUMENTHEADER));
}
break;
// VE: Volume Envelope
case 0x4556:
if ((nvolenv = lpStream[dwMemPos]) == 0) break;
if (dwMemPos + nvolenv*32 + 1 <= dwMemLength) pvolenv = lpStream + dwMemPos + 1;
break;
// PE: Panning Envelope
case 0x4550:
if ((npanenv = lpStream[dwMemPos]) == 0) break;
if (dwMemPos + npanenv*32 + 1 <= dwMemLength) ppanenv = lpStream + dwMemPos + 1;
break;
// FE: Pitch Envelope
case 0x4546:
if ((npitchenv = lpStream[dwMemPos]) == 0) break;
if (dwMemPos + npitchenv*32 + 1 <= dwMemLength) ppitchenv = lpStream + dwMemPos + 1;
break;
// IS: Sample Infoblock
case 0x5349:
nsamples = lpStream[dwMemPos];
i = blocklen / hdrLen;
if (i< nsamples) nsamples = i;
dwPos = dwMemPos+1;
for (i=0; i<nsamples; i++, dwPos += hdrLen)
{
UINT nins = lpStream[dwPos];
if ((nins >= MAX_SAMPLES) || (!nins)) continue;
if (m_nSamples < nins) m_nSamples = nins;
MODINSTRUMENT *pins = &Ins[nins];
memcpy(m_szNames[nins], lpStream+dwPos+1, 32);
m_szNames[nins][31] = 0;
memcpy(pins->name, lpStream+dwPos+33, 8);
pp = lpStream + dwPos + 41;
pins->nC4Speed = pp[0] | (pp[1] << 8); pp += 2;
if (pmsh->version > 0) {
pins->nC4Speed |= (pp[0] << 16) | (pp[1] << 24); pp += 2;
}
pins->nLength = pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24); pp += 4;
pins->nLoopStart = pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24); pp += 4;
pins->nLoopEnd = pins->nLoopStart + (pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24));
if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP;
pins->nGlobalVol = 64;
if (pmsh->version == 0) pins->nVolume = pp[4];
if (lpStream[dwPos+hdrLen-1] & 0x01)
{
pins->uFlags |= CHN_16BIT;
pins->nLength >>= 1;
pins->nLoopStart >>= 1;
pins->nLoopEnd >>= 1;
}
if (lpStream[dwPos+hdrLen-1] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP;
smpinfo[nins] = (lpStream[dwPos+hdrLen-1] >> 2) & 3;
}
break;
// SA: Sample Data
case 0x4153:
dwPos = dwMemPos;
for (i=1; i<=m_nSamples; i++) if ((Ins[i].nLength) && (!Ins[i].pSample) && (smpinfo[i] != 3) && (dwPos < dwMemLength))
{
const BYTE *pp = lpStream + dwPos;
MODINSTRUMENT *pins = &Ins[i];
UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
if (!smpinfo[i])
{
dwPos += ReadSample(pins, flags, (LPSTR)pp, dwMemLength - dwPos);
} else
{
DWORD dwLen = pp[0] | (pp[1] << 8) | (pp[2] << 16) | (pp[3] << 24); pp += 4;
dwPos += 4;
if ((dwLen <= dwMemLength) && (dwPos <= dwMemLength - dwLen) && (dwLen > 4))
{
flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8;
ReadSample(pins, flags, (LPSTR)pp, dwLen);
}
dwPos += dwLen;
}
}
break;
}
dwMemPos += blocklen;
}
// Unpack Patterns
if ((dwTrackPos) && (npatterns) && (m_nChannels) && (ntracks))
{
for (UINT ipat=0; ipat<npatterns; ipat++)
{
if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break;
for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks))
{
const BYTE *lpTracks = lpStream + dwTrackPos;
UINT len = lpTracks[0] | (lpTracks[1] << 8);
if (len < dwMemLength-dwTrackPos) {
MODCOMMAND *m = Patterns[ipat] + chn;
UINT nTrack = patterntracks[ipat*32+chn];
lpTracks += 2;
for (UINT ntrk=1; ntrk<nTrack && lpTracks < (dwMemLength + lpStream - len); ntrk++)
{
lpTracks += len;
len = lpTracks[0] | (lpTracks[1] << 8);
lpTracks += 2;
}
if ( len > dwMemLength - dwTrackPos ) len = 0;
UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], nTrack, lpTracks, len);
}
}
}
}
// Set up envelopes
for (UINT iIns=1; iIns<=m_nInstruments; iIns++) if (Headers[iIns])
{
INSTRUMENTHEADER *penv = Headers[iIns];
// Setup volume envelope
if ((nvolenv) && (pvolenv) && (insvolenv[iIns]))
{
LPCBYTE pve = pvolenv;
for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns])
{
WORD vtick = 1;
penv->nVolEnv = 15;
for (UINT iv=0; iv<15; iv++)
{
if (iv) vtick += pve[iv*2+1];
penv->VolPoints[iv] = vtick;
penv->VolEnv[iv] = pve[iv*2+2];
if (!pve[iv*2+1])
{
penv->nVolEnv = iv+1;
break;
}
}
penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F;
if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN;
if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP;
penv->nVolLoopStart = pve[32] & 0x0F;
penv->nVolLoopEnd = pve[32] >> 4;
}
}
// Setup panning envelope
if ((npanenv) && (ppanenv) && (inspanenv[iIns]))
{
LPCBYTE ppe = ppanenv;
for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns])
{
WORD vtick = 1;
penv->nPanEnv = 15;
for (UINT iv=0; iv<15; iv++)
{
if (iv) vtick += ppe[iv*2+1];
penv->PanPoints[iv] = vtick;
penv->PanEnv[iv] = ppe[iv*2+2];
if (!ppe[iv*2+1])
{
penv->nPanEnv = iv+1;
break;
}
}
if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN;
if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP;
penv->nPanLoopStart = ppe[32] & 0x0F;
penv->nPanLoopEnd = ppe[32] >> 4;
}
}
}
m_dwSongFlags |= SONG_LINEARSLIDES;
m_nType = MOD_TYPE_MDL;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// MDL Sample Unpacking
// MDL Huffman ReadBits compression
WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
//-----------------------------------------------------------------
{
WORD v = (WORD)(bitbuf & ((1 << n) - 1) );
bitbuf >>= n;
bitnum -= n;
if (bitnum <= 24)
{
bitbuf |= (((DWORD)(*ibuf++)) << bitnum);
bitnum += 8;
}
return v;
}

View File

@ -0,0 +1,931 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
#include "stdafx.h"
#include "sndfile.h"
//#define MED_LOG
#ifdef MED_LOG
extern void Log(LPCSTR s, ...);
#endif
//////////////////////////////////////////////////////////
// OctaMed MED file support (import only)
//
// Lookup table for bpm values.
static const BYTE bpmvals[10] = { 179,164,152,141,131,123,116,110,104,99 };
// flags
#define MMD_FLAG_FILTERON 0x1
#define MMD_FLAG_JUMPINGON 0x2
#define MMD_FLAG_JUMP8TH 0x4
#define MMD_FLAG_INSTRSATT 0x8 // instruments are attached (this is a module)
#define MMD_FLAG_VOLHEX 0x10
#define MMD_FLAG_STSLIDE 0x20 // SoundTracker mode for slides
#define MMD_FLAG_8CHANNEL 0x40 // OctaMED 8 channel song
#define MMD_FLAG_SLOWHQ 0x80 // HQ slows playing speed (V2-V4 compatibility)
// flags2
#define MMD_FLAG2_BMASK 0x1F
#define MMD_FLAG2_BPM 0x20
#define MMD_FLAG2_MIX 0x80 // uses Mixing (V7+)
// flags3:
#define MMD_FLAG3_STEREO 0x1 // mixing in Stereo mode
#define MMD_FLAG3_FREEPAN 0x2 // free panning
#define MMD_FLAG3_GM 0x4 // module designed for GM/XG compatibility
// generic MMD tags
#define MMDTAG_END 0
#define MMDTAG_PTR 0x80000000 // data needs relocation
#define MMDTAG_MUSTKNOW 0x40000000 // loader must fail if this isn't recognized
#define MMDTAG_MUSTWARN 0x20000000 // loader must warn if this isn't recognized
// ExpData tags
// # of effect groups, including the global group (will
// override settings in MMDSong struct), default = 1
#define MMDTAG_EXP_NUMFXGROUPS 1
#define MMDTAG_TRK_NAME (MMDTAG_PTR|1) // trackinfo tags
#define MMDTAG_TRK_NAMELEN 2 // namelen includes zero term.
#define MMDTAG_TRK_FXGROUP 3
// effectinfo tags
#define MMDTAG_FX_ECHOTYPE 1
#define MMDTAG_FX_ECHOLEN 2
#define MMDTAG_FX_ECHODEPTH 3
#define MMDTAG_FX_STEREOSEP 4
#define MMDTAG_FX_GROUPNAME (MMDTAG_PTR|5) // the Global Effects group shouldn't have name saved!
#define MMDTAG_FX_GRPNAMELEN 6 // namelen includes zero term.
#pragma pack(1)
typedef struct tagMEDMODULEHEADER
{
DWORD id; // MMD1-MMD3
DWORD modlen; // Size of file
DWORD song; // Position in file for this song
WORD psecnum;
WORD pseq;
DWORD blockarr; // Position in file for blocks
DWORD mmdflags;
DWORD smplarr; // Position in file for samples
DWORD reserved;
DWORD expdata; // Absolute offset in file for ExpData (0 if not present)
DWORD reserved2;
WORD pstate;
WORD pblock;
WORD pline;
WORD pseqnum;
WORD actplayline;
BYTE counter;
BYTE extra_songs; // # of songs - 1
} MEDMODULEHEADER;
typedef struct tagMMD0SAMPLE
{
WORD rep, replen;
BYTE midich;
BYTE midipreset;
BYTE svol;
signed char strans;
} MMD0SAMPLE;
// Sample header is immediately followed by sample data...
typedef struct tagMMDSAMPLEHEADER
{
DWORD length; // length of *one* *unpacked* channel in *bytes*
WORD type;
// if non-negative
// bits 0-3 reserved for multi-octave instruments, not supported on the PC
// 0x10: 16 bit (otherwise 8 bit)
// 0x20: Stereo (otherwise mono)
// 0x40: Uses DeltaCode
// 0x80: Packed data
// -1: Synth
// -2: Hybrid
// if type indicates packed data, these fields follow, otherwise we go right to the data
WORD packtype; // Only 1 = ADPCM is supported
WORD subtype; // Packing subtype
// ADPCM subtype
// 1: g723_40
// 2: g721
// 3: g723_24
BYTE commonflags; // flags common to all packtypes (none defined so far)
BYTE packerflags; // flags for the specific packtype
ULONG leftchlen; // packed length of left channel in bytes
ULONG rightchlen; // packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES)
BYTE SampleData[1]; // Sample Data
} MMDSAMPLEHEADER;
// MMD0/MMD1 song header
typedef struct tagMMD0SONGHEADER
{
MMD0SAMPLE sample[63];
WORD numblocks; // # of blocks
WORD songlen; // # of entries used in playseq
BYTE playseq[256]; // Play sequence
WORD deftempo; // BPM tempo
signed char playtransp; // Play transpose
BYTE flags; // 0x10: Hex Volumes | 0x20: ST/NT/PT Slides | 0x40: 8 Channels song
BYTE flags2; // [b4-b0]+1: Tempo LPB, 0x20: tempo mode, 0x80: mix_conv=on
BYTE tempo2; // tempo TPL
BYTE trkvol[16]; // track volumes
BYTE mastervol; // master volume
BYTE numsamples; // # of samples (max=63)
} MMD0SONGHEADER;
// MMD2/MMD3 song header
typedef struct tagMMD2SONGHEADER
{
MMD0SAMPLE sample[63];
WORD numblocks; // # of blocks
WORD numsections; // # of sections
DWORD playseqtable; // filepos of play sequence
DWORD sectiontable; // filepos of sections table (WORD array)
DWORD trackvols; // filepos of tracks volume (BYTE array)
WORD numtracks; // # of tracks (max 64)
WORD numpseqs; // # of play sequences
DWORD trackpans; // filepos of tracks pan values (BYTE array)
LONG flags3; // 0x1:stereo_mix, 0x2:free_panning, 0x4:GM/XG compatibility
WORD voladj; // vol_adjust (set to 100 if 0)
WORD channels; // # of channels (4 if =0)
BYTE mix_echotype; // 1:normal,2:xecho
BYTE mix_echodepth; // 1..6
WORD mix_echolen; // > 0
signed char mix_stereosep; // -4..4
BYTE pad0[223];
WORD deftempo; // BPM tempo
signed char playtransp; // play transpose
BYTE flags; // 0x1:filteron, 0x2:jumpingon, 0x4:jump8th, 0x8:instr_attached, 0x10:hex_vol, 0x20:PT_slides, 0x40:8ch_conv,0x80:hq slows playing speed
BYTE flags2; // 0x80:mix_conv=on, [b4-b0]+1:tempo LPB, 0x20:tempo_mode
BYTE tempo2; // tempo TPL
BYTE pad1[16];
BYTE mastervol; // master volume
BYTE numsamples; // # of samples (max 63)
} MMD2SONGHEADER;
// For MMD0 the note information is held in 3 bytes, byte0, byte1, byte2. For reference we
// number the bits in each byte 0..7, where 0 is the low bit.
// The note is held as bits 5..0 of byte0
// The instrument is encoded in 6 bits, bits 7 and 6 of byte0 and bits 7,6,5,4 of byte1
// The command number is bits 3,2,1,0 of byte1, command data is in byte2:
// For command 0, byte2 represents the second data byte, otherwise byte2
// represents the first data byte.
typedef struct tagMMD0BLOCK
{
BYTE numtracks;
BYTE lines; // File value is 1 less than actual, so 0 -> 1 line
} MMD0BLOCK; // BYTE data[lines+1][tracks][3];
// For MMD1,MMD2,MMD3 the note information is carried in 4 bytes, byte0, byte1,
// byte2 and byte3
// The note is held as byte0 (values above 0x84 are ignored)
// The instrument is held as byte1
// The command number is held as byte2, command data is in byte3
// For commands 0 and 0x19 byte3 represents the second data byte,
// otherwise byte2 represents the first data byte.
typedef struct tagMMD1BLOCK
{
WORD numtracks; // Number of tracks, may be > 64, but then that data is skipped.
WORD lines; // Stored value is 1 less than actual, so 0 -> 1 line
DWORD info; // Offset of BlockInfo (if 0, no block_info is present)
} MMD1BLOCK;
typedef struct tagMMD1BLOCKINFO
{
DWORD hlmask; // Unimplemented - ignore
DWORD blockname; // file offset of block name
DWORD blocknamelen; // length of block name (including term. 0)
DWORD pagetable; // file offset of command page table
DWORD cmdexttable; // file offset of command extension table
DWORD reserved[4]; // future expansion
} MMD1BLOCKINFO;
// A set of play sequences is stored as an array of ULONG files offsets
// Each offset points to the play sequence itself.
typedef struct tagMMD2PLAYSEQ
{
CHAR name[32];
DWORD command_offs; // filepos of command table
DWORD reserved;
WORD length;
WORD seq[512]; // skip if > 0x8000
} MMD2PLAYSEQ;
// A command table contains commands that effect a particular play sequence
// entry. The only commands read in are STOP or POSJUMP, all others are ignored
// POSJUMP is presumed to have extra bytes containing a WORD for the position
typedef struct tagMMDCOMMAND
{
WORD offset; // Offset within current sequence entry
BYTE cmdnumber; // STOP (537) or POSJUMP (538) (others skipped)
BYTE extra_count;
BYTE extra_bytes[4];// [extra_count];
} MMDCOMMAND; // Last entry has offset == 0xFFFF, cmd_number == 0 and 0 extrabytes
typedef struct tagMMD0EXP
{
DWORD nextmod; // File offset of next Hdr
DWORD exp_smp; // Pointer to extra instrument data
WORD s_ext_entries; // Number of extra instrument entries
WORD s_ext_entrsz; // Size of extra instrument data
DWORD annotxt;
DWORD annolen;
DWORD iinfo; // Instrument names
WORD i_ext_entries;
WORD i_ext_entrsz;
DWORD jumpmask;
DWORD rgbtable;
BYTE channelsplit[4]; // Only used if 8ch_conv (extra channel for every nonzero entry)
DWORD n_info;
DWORD songname; // Song name
DWORD songnamelen;
DWORD dumps;
DWORD mmdinfo;
DWORD mmdrexx;
DWORD mmdcmd3x;
DWORD trackinfo_ofs; // ptr to song->numtracks ptrs to tag lists
DWORD effectinfo_ofs; // ptr to group ptrs
DWORD tag_end;
} MMD0EXP;
#pragma pack()
static void MedConvert(MODCOMMAND *p, const MMD0SONGHEADER *pmsh)
//---------------------------------------------------------------
{
UINT command = p->command;
UINT param = p->param;
switch(command)
{
case 0x00: if (param) command = CMD_ARPEGGIO; else command = 0; break;
case 0x01: command = CMD_PORTAMENTOUP; break;
case 0x02: command = CMD_PORTAMENTODOWN; break;
case 0x03: command = CMD_TONEPORTAMENTO; break;
case 0x04: command = CMD_VIBRATO; break;
case 0x05: command = CMD_TONEPORTAVOL; break;
case 0x06: command = CMD_VIBRATOVOL; break;
case 0x07: command = CMD_TREMOLO; break;
case 0x0A: if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
case 0x0B: command = CMD_POSITIONJUMP; break;
case 0x0C: command = CMD_VOLUME;
if (pmsh->flags & MMD_FLAG_VOLHEX)
{
if (param < 0x80)
{
param = (param+1) / 2;
} else command = 0;
} else
{
if (param <= 0x99)
{
param = (param >> 4)*10+((param & 0x0F) % 10);
if (param > 64) param = 64;
} else command = 0;
}
break;
case 0x09: command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break;
case 0x0D: if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
case 0x0F: // Set Tempo / Special
// F.00 = Pattern Break
if (!param) command = CMD_PATTERNBREAK; else
// F.01 - F.F0: Set tempo/speed
if (param <= 0xF0)
{
if (pmsh->flags & MMD_FLAG_8CHANNEL)
{
param = (param > 10) ? 99 : bpmvals[param-1];
} else
// F.01 - F.0A: Set Speed
if (param <= 0x0A)
{
command = CMD_SPEED;
} else
// Old tempo
if (!(pmsh->flags2 & MMD_FLAG2_BPM))
{
param = _muldiv(param, 5*715909, 2*474326);
}
// F.0B - F.F0: Set Tempo (assumes LPB=4)
if (param > 0x0A)
{
command = CMD_TEMPO;
if (param < 0x21) param = 0x21;
if (param > 240) param = 240;
}
} else
switch(param)
{
// F.F1: Retrig 2x
case 0xF1:
command = CMD_MODCMDEX;
param = 0x93;
break;
// F.F2: Note Delay 2x
case 0xF2:
command = CMD_MODCMDEX;
param = 0xD3;
break;
// F.F3: Retrig 3x
case 0xF3:
command = CMD_MODCMDEX;
param = 0x92;
break;
// F.F4: Note Delay 1/3
case 0xF4:
command = CMD_MODCMDEX;
param = 0xD2;
break;
// F.F5: Note Delay 2/3
case 0xF5:
command = CMD_MODCMDEX;
param = 0xD4;
break;
// F.F8: Filter Off
case 0xF8:
command = CMD_MODCMDEX;
param = 0x00;
break;
// F.F9: Filter On
case 0xF9:
command = CMD_MODCMDEX;
param = 0x01;
break;
// F.FD: Very fast tone-portamento
case 0xFD:
command = CMD_TONEPORTAMENTO;
param = 0xFF;
break;
// F.FE: End Song
case 0xFE:
command = CMD_SPEED;
param = 0;
break;
// F.FF: Note Cut
case 0xFF:
command = CMD_MODCMDEX;
param = 0xC0;
break;
default:
#ifdef MED_LOG
Log("Unknown Fxx command: cmd=0x%02X param=0x%02X\n", command, param);
#endif
param = command = 0;
}
break;
// 11.0x: Fine Slide Up
case 0x11:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0x10;
break;
// 12.0x: Fine Slide Down
case 0x12:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0x20;
break;
// 14.xx: Vibrato
case 0x14:
command = CMD_VIBRATO;
break;
// 15.xx: FineTune
case 0x15:
command = CMD_MODCMDEX;
param &= 0x0F;
param |= 0x50;
break;
// 16.xx: Pattern Loop
case 0x16:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0x60;
break;
// 18.xx: Note Cut
case 0x18:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0xC0;
break;
// 19.xx: Sample Offset
case 0x19:
command = CMD_OFFSET;
break;
// 1A.0x: Fine Volume Up
case 0x1A:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0xA0;
break;
// 1B.0x: Fine Volume Down
case 0x1B:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0xB0;
break;
// 1D.xx: Pattern Break
case 0x1D:
command = CMD_PATTERNBREAK;
break;
// 1E.0x: Pattern Delay
case 0x1E:
command = CMD_MODCMDEX;
if (param > 0x0F) param = 0x0F;
param |= 0xE0;
break;
// 1F.xy: Retrig
case 0x1F:
command = CMD_RETRIG;
param &= 0x0F;
break;
// 2E.xx: set panning
case 0x2E:
command = CMD_MODCMDEX;
param = ((param + 0x10) & 0xFF) >> 1;
if (param > 0x0F) param = 0x0F;
param |= 0x80;
break;
default:
#ifdef MED_LOG
// 0x2E ?
Log("Unknown command: cmd=0x%02X param=0x%02X\n", command, param);
#endif
command = param = 0;
}
p->command = command;
p->param = param;
}
BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const MEDMODULEHEADER *pmmh;
const MMD0SONGHEADER *pmsh;
const MMD2SONGHEADER *pmsh2;
const MMD0EXP *pmex;
DWORD dwBlockArr, dwSmplArr, dwExpData, wNumBlocks;
LPDWORD pdwTable;
CHAR version;
UINT deftempo;
int playtransp = 0;
if ((!lpStream) || (dwMemLength < 0x200)) return FALSE;
pmmh = (MEDMODULEHEADER *)lpStream;
if (((pmmh->id & 0x00FFFFFF) != 0x444D4D) || (!pmmh->song)) return FALSE;
// Check for 'MMDx'
DWORD dwSong = bswapBE32(pmmh->song);
if ((dwSong >= dwMemLength) || (dwSong + sizeof(MMD0SONGHEADER) >= dwMemLength)) return FALSE;
version = (signed char)((pmmh->id >> 24) & 0xFF);
if ((version < '0') || (version > '3')) return FALSE;
#ifdef MED_LOG
Log("\nLoading MMD%c module (flags=0x%02X)...\n", version, bswapBE32(pmmh->mmdflags));
Log(" modlen = %d\n", bswapBE32(pmmh->modlen));
Log(" song = 0x%08X\n", bswapBE32(pmmh->song));
Log(" psecnum = %d\n", bswapBE16(pmmh->psecnum));
Log(" pseq = %d\n", bswapBE16(pmmh->pseq));
Log(" blockarr = 0x%08X\n", bswapBE32(pmmh->blockarr));
Log(" mmdflags = 0x%08X\n", bswapBE32(pmmh->mmdflags));
Log(" smplarr = 0x%08X\n", bswapBE32(pmmh->smplarr));
Log(" reserved = 0x%08X\n", bswapBE32(pmmh->reserved));
Log(" expdata = 0x%08X\n", bswapBE32(pmmh->expdata));
Log(" reserved2= 0x%08X\n", bswapBE32(pmmh->reserved2));
Log(" pstate = %d\n", bswapBE16(pmmh->pstate));
Log(" pblock = %d\n", bswapBE16(pmmh->pblock));
Log(" pline = %d\n", bswapBE16(pmmh->pline));
Log(" pseqnum = %d\n", bswapBE16(pmmh->pseqnum));
Log(" actplayline=%d\n", bswapBE16(pmmh->actplayline));
Log(" counter = %d\n", pmmh->counter);
Log(" extra_songs = %d\n", pmmh->extra_songs);
Log("\n");
#endif
m_nType = MOD_TYPE_MED;
m_nSongPreAmp = 0x20;
dwBlockArr = bswapBE32(pmmh->blockarr);
dwSmplArr = bswapBE32(pmmh->smplarr);
dwExpData = bswapBE32(pmmh->expdata);
if ((dwExpData) && (dwExpData < dwMemLength - sizeof(MMD0EXP)))
pmex = (MMD0EXP *)(lpStream+dwExpData);
else
pmex = NULL;
pmsh = (MMD0SONGHEADER *)(lpStream + dwSong);
pmsh2 = (MMD2SONGHEADER *)pmsh;
#ifdef MED_LOG
if (version < '2')
{
Log("MMD0 Header:\n");
Log(" numblocks = %d\n", bswapBE16(pmsh->numblocks));
Log(" songlen = %d\n", bswapBE16(pmsh->songlen));
Log(" playseq = ");
for (UINT idbg1=0; idbg1<16; idbg1++) Log("%2d, ", pmsh->playseq[idbg1]);
Log("...\n");
Log(" deftempo = 0x%04X\n", bswapBE16(pmsh->deftempo));
Log(" playtransp = %d\n", (signed char)pmsh->playtransp);
Log(" flags(1,2) = 0x%02X, 0x%02X\n", pmsh->flags, pmsh->flags2);
Log(" tempo2 = %d\n", pmsh->tempo2);
Log(" trkvol = ");
for (UINT idbg2=0; idbg2<16; idbg2++) Log("0x%02X, ", pmsh->trkvol[idbg2]);
Log("...\n");
Log(" mastervol = 0x%02X\n", pmsh->mastervol);
Log(" numsamples = %d\n", pmsh->numsamples);
} else
{
Log("MMD2 Header:\n");
Log(" numblocks = %d\n", bswapBE16(pmsh2->numblocks));
Log(" numsections= %d\n", bswapBE16(pmsh2->numsections));
Log(" playseqptr = 0x%04X\n", bswapBE32(pmsh2->playseqtable));
Log(" sectionptr = 0x%04X\n", bswapBE32(pmsh2->sectiontable));
Log(" trackvols = 0x%04X\n", bswapBE32(pmsh2->trackvols));
Log(" numtracks = %d\n", bswapBE16(pmsh2->numtracks));
Log(" numpseqs = %d\n", bswapBE16(pmsh2->numpseqs));
Log(" trackpans = 0x%04X\n", bswapBE32(pmsh2->trackpans));
Log(" flags3 = 0x%08X\n", bswapBE32(pmsh2->flags3));
Log(" voladj = %d\n", bswapBE16(pmsh2->voladj));
Log(" channels = %d\n", bswapBE16(pmsh2->channels));
Log(" echotype = %d\n", pmsh2->mix_echotype);
Log(" echodepth = %d\n", pmsh2->mix_echodepth);
Log(" echolen = %d\n", bswapBE16(pmsh2->mix_echolen));
Log(" stereosep = %d\n", (signed char)pmsh2->mix_stereosep);
Log(" deftempo = 0x%04X\n", bswapBE16(pmsh2->deftempo));
Log(" playtransp = %d\n", (signed char)pmsh2->playtransp);
Log(" flags(1,2) = 0x%02X, 0x%02X\n", pmsh2->flags, pmsh2->flags2);
Log(" tempo2 = %d\n", pmsh2->tempo2);
Log(" mastervol = 0x%02X\n", pmsh2->mastervol);
Log(" numsamples = %d\n", pmsh->numsamples);
}
Log("\n");
#endif
wNumBlocks = bswapBE16(pmsh->numblocks);
m_nChannels = 4;
m_nSamples = pmsh->numsamples;
if (m_nSamples > 63) m_nSamples = 63;
// Tempo
m_nDefaultTempo = 125;
deftempo = bswapBE16(pmsh->deftempo);
if (!deftempo) deftempo = 125;
if (pmsh->flags2 & MMD_FLAG2_BPM)
{
UINT tempo_tpl = (pmsh->flags2 & MMD_FLAG2_BMASK) + 1;
if (!tempo_tpl) tempo_tpl = 4;
deftempo *= tempo_tpl;
deftempo /= 4;
#ifdef MED_LOG
Log("newtempo: %3d bpm (bpm=%3d lpb=%2d)\n", deftempo, bswapBE16(pmsh->deftempo), (pmsh->flags2 & MMD_FLAG2_BMASK)+1);
#endif
} else
{
if (pmsh->flags & MMD_FLAG_8CHANNEL && deftempo > 0 && deftempo <= 10)
{
deftempo = bpmvals[deftempo-1];
} else {
deftempo = _muldiv(deftempo, 5*715909, 2*474326);
}
#ifdef MED_LOG
Log("oldtempo: %3d bpm (bpm=%3d)\n", deftempo, bswapBE16(pmsh->deftempo));
#endif
}
// Speed
m_nDefaultSpeed = pmsh->tempo2;
if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
if (deftempo < 0x21) deftempo = 0x21;
if (deftempo > 255)
{
while ((m_nDefaultSpeed > 3) && (deftempo > 260))
{
deftempo = (deftempo * (m_nDefaultSpeed - 1)) / m_nDefaultSpeed;
m_nDefaultSpeed--;
}
if (deftempo > 255) deftempo = 255;
}
m_nDefaultTempo = deftempo;
// Reading Samples
for (UINT iSHdr=0; iSHdr<m_nSamples; iSHdr++)
{
MODINSTRUMENT *pins = &Ins[iSHdr+1];
pins->nLoopStart = bswapBE16(pmsh->sample[iSHdr].rep) << 1;
pins->nLoopEnd = pins->nLoopStart + (bswapBE16(pmsh->sample[iSHdr].replen) << 1);
pins->nVolume = (pmsh->sample[iSHdr].svol << 2);
pins->nGlobalVol = 64;
if (pins->nVolume > 256) pins->nVolume = 256;
pins->RelativeTone = -12 * pmsh->sample[iSHdr].strans;
pins->nPan = 128;
if (pins->nLoopEnd) pins->uFlags |= CHN_LOOP;
}
// Common Flags
if (!(pmsh->flags & 0x20)) m_dwSongFlags |= SONG_FASTVOLSLIDES;
// Reading play sequence
if (version < '2')
{
UINT nbo = pmsh->songlen >> 8;
if (nbo >= MAX_ORDERS) nbo = MAX_ORDERS-1;
if (!nbo) nbo = 1;
memcpy(Order, pmsh->playseq, nbo);
playtransp = pmsh->playtransp;
} else
{
UINT nOrders, nSections;
UINT nTrks = bswapBE16(pmsh2->numtracks);
if ((nTrks >= 4) && (nTrks <= 32)) m_nChannels = nTrks;
DWORD playseqtable = bswapBE32(pmsh2->playseqtable);
UINT numplayseqs = bswapBE16(pmsh2->numpseqs);
if (!numplayseqs) numplayseqs = 1;
nOrders = 0;
nSections = bswapBE16(pmsh2->numsections);
DWORD sectiontable = bswapBE32(pmsh2->sectiontable);
if ((!nSections) || (!sectiontable) || (sectiontable >= dwMemLength-2)) nSections = 1;
nOrders = 0;
for (UINT iSection=0; iSection<nSections; iSection++)
{
UINT nplayseq = 0;
if ((sectiontable) && (sectiontable < dwMemLength-2))
{
nplayseq = lpStream[sectiontable+1];
sectiontable += 2; // WORDs
} else
{
nSections = 0;
}
UINT pseq = 0;
if ((playseqtable) && (playseqtable < dwMemLength) && (nplayseq*4 < dwMemLength - playseqtable))
{
pseq = bswapBE32(((LPDWORD)(lpStream+playseqtable))[nplayseq]);
}
if ((pseq) && dwMemLength > sizeof(MMD2PLAYSEQ) &&
(pseq < dwMemLength - sizeof(MMD2PLAYSEQ)))
{
const MMD2PLAYSEQ *pmps = (MMD2PLAYSEQ *)(lpStream + pseq);
if (!m_szNames[0][0]) memcpy(m_szNames[0], pmps->name, 31);
UINT n = bswapBE16(pmps->length);
if (n < (dwMemLength - (pseq + sizeof(*pmps)) + sizeof(pmps->seq)) / sizeof(pmps->seq[0]))
{
for (UINT i=0; i<n; i++)
{
UINT seqval = pmps->seq[i] >> 8;
if ((seqval < wNumBlocks) && (nOrders < MAX_ORDERS-1))
{
Order[nOrders++] = seqval;
}
}
}
}
}
playtransp = pmsh2->playtransp;
while (nOrders < MAX_ORDERS) Order[nOrders++] = 0xFF;
}
// Reading Expansion structure
if (pmex)
{
// Channel Split
if ((m_nChannels == 4) && (pmsh->flags & MMD_FLAG_8CHANNEL))
{
for (UINT i8ch=0; i8ch<4; i8ch++)
{
if (pmex->channelsplit[i8ch]) m_nChannels++;
}
}
// Song Comments
uint32_t annotxt = bswapBE32(pmex->annotxt);
uint32_t annolen = bswapBE32(pmex->annolen);
if ((annotxt) && (annolen) && (annotxt + annolen > annotxt) // overflow checks.
&& (annotxt+annolen <= dwMemLength))
{
m_lpszSongComments = new char[annolen+1];
memcpy(m_lpszSongComments, lpStream+annotxt, annolen);
m_lpszSongComments[annolen] = 0;
}
// Song Name
uint32_t songname = bswapBE32(pmex->songname);
uint32_t songnamelen = bswapBE32(pmex->songnamelen);
if ((songname) && (songnamelen) && (songname+songnamelen > songname)
&& (songname+songnamelen <= dwMemLength))
{
if (songnamelen > 31) songnamelen = 31;
memcpy(m_szNames[0], lpStream+songname, songnamelen);
m_szNames[0][31] = '\0';
}
// Sample Names
DWORD smpinfoex = bswapBE32(pmex->iinfo);
if (smpinfoex)
{
DWORD iinfoptr = bswapBE32(pmex->iinfo);
UINT ientries = bswapBE16(pmex->i_ext_entries);
UINT ientrysz = bswapBE16(pmex->i_ext_entrsz);
if ((iinfoptr) && (ientrysz < 256) &&
(ientries*ientrysz < dwMemLength) &&
(iinfoptr < dwMemLength - (ientries*ientrysz)))
{
LPCSTR psznames = (LPCSTR)(lpStream + iinfoptr);
UINT maxnamelen = ientrysz;
// copy a max of 32 bytes.
if (maxnamelen > 32) maxnamelen = 32;
for (UINT i=0; i<ientries; i++) if (i < m_nSamples)
{
lstrcpyn(m_szNames[i+1], psznames + i*ientrysz, maxnamelen);
m_szNames[i+1][31] = '\0';
}
}
}
// Track Names
DWORD trackinfo_ofs = bswapBE32(pmex->trackinfo_ofs);
if ((trackinfo_ofs) && (trackinfo_ofs < dwMemLength) && (m_nChannels * 4 < dwMemLength - trackinfo_ofs))
{
DWORD *ptrktags = (DWORD *)(lpStream + trackinfo_ofs);
for (UINT i=0; i<m_nChannels; i++)
{
DWORD trknameofs = 0, trknamelen = 0;
DWORD trktagofs = bswapBE32(ptrktags[i]);
if (trktagofs)
{
while (trktagofs < dwMemLength - 8)
{
DWORD ntag = bswapBE32(*(DWORD *)(lpStream + trktagofs));
if (ntag == MMDTAG_END) break;
DWORD tagdata = bswapBE32(*(DWORD *)(lpStream + trktagofs + 4));
switch(ntag)
{
case MMDTAG_TRK_NAMELEN: trknamelen = tagdata; break;
case MMDTAG_TRK_NAME: trknameofs = tagdata; break;
}
trktagofs += 8;
}
if (trknamelen > MAX_CHANNELNAME) trknamelen = MAX_CHANNELNAME;
if ((trknameofs) && (trknamelen < dwMemLength) && (trknameofs < dwMemLength - trknamelen))
{
lstrcpyn(ChnSettings[i].szName, (LPCSTR)(lpStream+trknameofs), MAX_CHANNELNAME);
ChnSettings[i].szName[MAX_CHANNELNAME-1] = '\0';
}
}
}
}
}
// Reading samples
if (dwSmplArr > dwMemLength - 4*m_nSamples) return TRUE;
pdwTable = (LPDWORD)(lpStream + dwSmplArr);
for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (pdwTable[iSmp])
{
UINT dwPos = bswapBE32(pdwTable[iSmp]);
if ((dwPos >= dwMemLength) || (dwPos + sizeof(MMDSAMPLEHEADER) >= dwMemLength)) continue;
MMDSAMPLEHEADER *psdh = (MMDSAMPLEHEADER *)(lpStream + dwPos);
UINT len = bswapBE32(psdh->length);
#ifdef MED_LOG
Log("SampleData %d: stype=0x%02X len=%d\n", iSmp, bswapBE16(psdh->type), len);
#endif
if ((len > MAX_SAMPLE_LENGTH) || (dwPos + len + 6 > dwMemLength)) len = 0;
UINT flags = RS_PCM8S, stype = bswapBE16(psdh->type);
LPSTR psdata = (LPSTR)(lpStream + dwPos + 6);
if (stype & 0x80)
{
psdata += (stype & 0x20) ? 14 : 6;
} else
{
if (stype & 0x10)
{
Ins[iSmp+1].uFlags |= CHN_16BIT;
len /= 2;
flags = (stype & 0x20) ? RS_STPCM16M : RS_PCM16M;
} else
{
flags = (stype & 0x20) ? RS_STPCM8S : RS_PCM8S;
}
if (stype & 0x20) len /= 2;
}
Ins[iSmp+1].nLength = len;
ReadSample(&Ins[iSmp+1], flags, psdata, dwMemLength - dwPos - 6);
}
// Reading patterns (blocks)
if (wNumBlocks > MAX_PATTERNS) wNumBlocks = MAX_PATTERNS;
if ((!dwBlockArr) || (dwMemLength < 4*wNumBlocks) ||
(dwBlockArr > dwMemLength - 4*wNumBlocks)) return TRUE;
pdwTable = (LPDWORD)(lpStream + dwBlockArr);
playtransp += (version == '3') ? 24 : 48;
for (UINT iBlk=0; iBlk<wNumBlocks; iBlk++)
{
UINT dwPos = bswapBE32(pdwTable[iBlk]);
if ((!dwPos) || (dwPos >= dwMemLength) || (dwPos >= dwMemLength - 8)) continue;
UINT lines = 64, tracks = 4;
if (version == '0')
{
const MMD0BLOCK *pmb = (const MMD0BLOCK *)(lpStream + dwPos);
lines = pmb->lines + 1;
tracks = pmb->numtracks;
if (!tracks) tracks = m_nChannels;
if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
PatternSize[iBlk] = lines;
MODCOMMAND *p = Patterns[iBlk];
LPBYTE s = (LPBYTE)(lpStream + dwPos + 2);
UINT maxlen = tracks*lines*3;
if (maxlen + dwPos > dwMemLength - 2) break;
for (UINT y=0; y<lines; y++)
{
for (UINT x=0; x<tracks; x++, s+=3) if (x < m_nChannels)
{
BYTE note = s[0] & 0x3F;
BYTE instr = s[1] >> 4;
if (s[0] & 0x80) instr |= 0x10;
if (s[0] & 0x40) instr |= 0x20;
if ((note) && (note <= 132)) p->note = note + playtransp;
p->instr = instr;
p->command = s[1] & 0x0F;
p->param = s[2];
// if (!iBlk) Log("%02X.%02X.%02X | ", s[0], s[1], s[2]);
MedConvert(p, pmsh);
p++;
}
//if (!iBlk) Log("\n");
}
} else
{
const MMD1BLOCK *pmb = (MMD1BLOCK *)(lpStream + dwPos);
#ifdef MED_LOG
Log("MMD1BLOCK: lines=%2d, tracks=%2d, offset=0x%04X\n",
bswapBE16(pmb->lines), bswapBE16(pmb->numtracks), bswapBE32(pmb->info));
#endif
const MMD1BLOCKINFO *pbi = NULL;
BYTE *pcmdext = NULL;
lines = (pmb->lines >> 8) + 1;
tracks = pmb->numtracks >> 8;
if (!tracks) tracks = m_nChannels;
if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
PatternSize[iBlk] = (WORD)lines;
DWORD dwBlockInfo = bswapBE32(pmb->info);
if ((dwBlockInfo) && (dwBlockInfo < dwMemLength - sizeof(MMD1BLOCKINFO)))
{
pbi = (MMD1BLOCKINFO *)(lpStream + dwBlockInfo);
#ifdef MED_LOG
Log(" BLOCKINFO: blockname=0x%04X namelen=%d pagetable=0x%04X &cmdexttable=0x%04X\n",
bswapBE32(pbi->blockname), bswapBE32(pbi->blocknamelen), bswapBE32(pbi->pagetable), bswapBE32(pbi->cmdexttable));
#endif
if ((pbi->blockname) && (pbi->blocknamelen))
{
DWORD nameofs = bswapBE32(pbi->blockname);
UINT namelen = bswapBE32(pbi->blocknamelen);
if ((nameofs < dwMemLength) && (namelen < dwMemLength + nameofs))
{
SetPatternName(iBlk, (LPCSTR)(lpStream+nameofs));
}
}
if (pbi->cmdexttable)
{
DWORD cmdexttable = bswapBE32(pbi->cmdexttable);
if (cmdexttable < dwMemLength - 4)
{
cmdexttable = bswapBE32(*(DWORD *)(lpStream + cmdexttable));
if ((cmdexttable) && (cmdexttable <= dwMemLength - lines*tracks))
{
pcmdext = (BYTE *)(lpStream + cmdexttable);
}
}
}
}
MODCOMMAND *p = Patterns[iBlk];
LPBYTE s = (LPBYTE)(lpStream + dwPos + 8);
UINT maxlen = tracks*lines*4;
if (maxlen + dwPos > dwMemLength - 8) break;
for (UINT y=0; y<lines; y++)
{
for (UINT x=0; x<tracks; x++, s+=4) if (x < m_nChannels)
{
BYTE note = s[0];
if ((note) && (note <= 132))
{
int rnote = note + playtransp;
if (rnote < 1) rnote = 1;
if (rnote > NOTE_MAX) rnote = NOTE_MAX;
p->note = (BYTE)rnote;
}
p->instr = s[1];
p->command = s[2];
p->param = s[3];
if (pcmdext) p->vol = pcmdext[x];
MedConvert(p, pmsh);
p++;
}
if (pcmdext) pcmdext += tracks;
}
}
}
// Setup channel pan positions
for (UINT iCh=0; iCh<m_nChannels; iCh++)
{
ChnSettings[iCh].nPan = (((iCh&3) == 1) || ((iCh&3) == 2)) ? 0xC0 : 0x40;
ChnSettings[iCh].nVolume = 64;
}
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,538 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
#include "stdafx.h"
#include "sndfile.h"
#include "tables.h"
#ifdef _MSC_VER
//#pragma warning(disable:4244)
#endif
//////////////////////////////////////////////////////////
// ProTracker / NoiseTracker MOD/NST file support
void CSoundFile::ConvertModCommand(MODCOMMAND *m) const
//-----------------------------------------------------
{
UINT command = m->command, param = m->param;
switch(command)
{
case 0x00: if (param) command = CMD_ARPEGGIO; break;
case 0x01: command = CMD_PORTAMENTOUP; break;
case 0x02: command = CMD_PORTAMENTODOWN; break;
case 0x03: command = CMD_TONEPORTAMENTO; break;
case 0x04: command = CMD_VIBRATO; break;
case 0x05: command = CMD_TONEPORTAVOL; if (param & 0xF0) param &= 0xF0; break;
case 0x06: command = CMD_VIBRATOVOL; if (param & 0xF0) param &= 0xF0; break;
case 0x07: command = CMD_TREMOLO; break;
case 0x08: command = CMD_PANNING8; break;
case 0x09: command = CMD_OFFSET; break;
case 0x0A: command = CMD_VOLUMESLIDE; if (param & 0xF0) param &= 0xF0; break;
case 0x0B: command = CMD_POSITIONJUMP; break;
case 0x0C: command = CMD_VOLUME; break;
case 0x0D: command = CMD_PATTERNBREAK; param = ((param >> 4) * 10) + (param & 0x0F); break;
case 0x0E: command = CMD_MODCMDEX; break;
case 0x0F: command = (param <= (UINT)((m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) ? 0x1F : 0x20)) ? CMD_SPEED : CMD_TEMPO;
if ((param == 0xFF) && (m_nSamples == 15)) command = 0; break;
// Extension for XM extended effects
case 'G' - 55: command = CMD_GLOBALVOLUME; break;
case 'H' - 55: command = CMD_GLOBALVOLSLIDE; if (param & 0xF0) param &= 0xF0; break;
case 'K' - 55: command = CMD_KEYOFF; break;
case 'L' - 55: command = CMD_SETENVPOSITION; break;
case 'M' - 55: command = CMD_CHANNELVOLUME; break;
case 'N' - 55: command = CMD_CHANNELVOLSLIDE; break;
case 'P' - 55: command = CMD_PANNINGSLIDE; if (param & 0xF0) param &= 0xF0; break;
case 'R' - 55: command = CMD_RETRIG; break;
case 'T' - 55: command = CMD_TREMOR; break;
case 'X' - 55: command = CMD_XFINEPORTAUPDOWN; break;
case 'Y' - 55: command = CMD_PANBRELLO; break;
case 'Z' - 55: command = CMD_MIDI; break;
default: command = 0;
}
m->command = command;
m->param = param;
}
#ifndef MODPLUG_NO_FILESAVE
WORD CSoundFile::ModSaveCommand(const MODCOMMAND *m, BOOL bXM) const
//------------------------------------------------------------------
{
UINT command = m->command & 0x3F, param = m->param;
switch(command)
{
case 0: command = param = 0; break;
case CMD_ARPEGGIO: command = 0; break;
case CMD_PORTAMENTOUP:
if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
{
if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x10; break; }
else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x10; break; }
}
command = 0x01;
break;
case CMD_PORTAMENTODOWN:
if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_STM))
{
if ((param & 0xF0) == 0xE0) { command=0x0E; param=((param & 0x0F) >> 2)|0x20; break; }
else if ((param & 0xF0) == 0xF0) { command=0x0E; param &= 0x0F; param|=0x20; break; }
}
command = 0x02;
break;
case CMD_TONEPORTAMENTO: command = 0x03; break;
case CMD_VIBRATO: command = 0x04; break;
case CMD_TONEPORTAVOL: command = 0x05; break;
case CMD_VIBRATOVOL: command = 0x06; break;
case CMD_TREMOLO: command = 0x07; break;
case CMD_PANNING8:
command = 0x08;
if (bXM)
{
if ((m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM) && (param <= 0x80))
{
param <<= 1;
if (param > 255) param = 255;
}
} else
{
if ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)) param >>= 1;
}
break;
case CMD_OFFSET: command = 0x09; break;
case CMD_VOLUMESLIDE: command = 0x0A; break;
case CMD_POSITIONJUMP: command = 0x0B; break;
case CMD_VOLUME: command = 0x0C; break;
case CMD_PATTERNBREAK: command = 0x0D; param = ((param / 10) << 4) | (param % 10); break;
case CMD_MODCMDEX: command = 0x0E; break;
case CMD_SPEED: command = 0x0F; if (param > 0x20) param = 0x20; break;
case CMD_TEMPO: if (param > 0x20) { command = 0x0F; break; }
case CMD_GLOBALVOLUME: command = 'G' - 55; break;
case CMD_GLOBALVOLSLIDE: command = 'H' - 55; break;
case CMD_KEYOFF: command = 'K' - 55; break;
case CMD_SETENVPOSITION: command = 'L' - 55; break;
case CMD_CHANNELVOLUME: command = 'M' - 55; break;
case CMD_CHANNELVOLSLIDE: command = 'N' - 55; break;
case CMD_PANNINGSLIDE: command = 'P' - 55; break;
case CMD_RETRIG: command = 'R' - 55; break;
case CMD_TREMOR: command = 'T' - 55; break;
case CMD_XFINEPORTAUPDOWN: command = 'X' - 55; break;
case CMD_PANBRELLO: command = 'Y' - 55; break;
case CMD_MIDI: command = 'Z' - 55; break;
case CMD_S3MCMDEX:
switch(param & 0xF0)
{
case 0x10: command = 0x0E; param = (param & 0x0F) | 0x30; break;
case 0x20: command = 0x0E; param = (param & 0x0F) | 0x50; break;
case 0x30: command = 0x0E; param = (param & 0x0F) | 0x40; break;
case 0x40: command = 0x0E; param = (param & 0x0F) | 0x70; break;
case 0x90: command = 'X' - 55; break;
case 0xB0: command = 0x0E; param = (param & 0x0F) | 0x60; break;
case 0xA0:
case 0x50:
case 0x70:
case 0x60: command = param = 0; break;
default: command = 0x0E; break;
}
break;
default: command = param = 0;
}
return (WORD)((command << 8) | (param));
}
#endif // MODPLUG_NO_FILESAVE
#pragma pack(1)
typedef struct _MODSAMPLE
{
CHAR name[22];
WORD length;
BYTE finetune;
BYTE volume;
WORD loopstart;
WORD looplen;
} MODSAMPLE, *PMODSAMPLE;
typedef struct _MODMAGIC
{
BYTE nOrders;
BYTE nRestartPos;
BYTE Orders[128];
char Magic[4]; // changed from CHAR
} MODMAGIC, *PMODMAGIC;
#pragma pack()
static BOOL IsValidName(LPCSTR s, int length, CHAR minChar)
//-----------------------------------------------------------------
{
int i, nt;
for (i = 0, nt = 0; i < length; i++)
{
if(s[i])
{
if (nt) return FALSE;// garbage after null
if (s[i] < minChar) return FALSE;// caller says it's garbage
}
else if (!nt) nt = i;// found null terminator
}
return TRUE;
}
static BOOL IsMagic(LPCSTR s1, LPCSTR s2)
{
return ((*(DWORD *)s1) == (*(DWORD *)s2)) ? TRUE : FALSE;
}
BOOL CSoundFile::ReadMod(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
char s[1024]; // changed from CHAR
DWORD dwMemPos, dwTotalSampleLen;
PMODMAGIC pMagic;
UINT nErr;
if ((!lpStream) || (dwMemLength < 0x600)) return FALSE;
dwMemPos = 20;
m_nSamples = 31;
m_nChannels = 4;
pMagic = (PMODMAGIC)(lpStream+dwMemPos+sizeof(MODSAMPLE)*31);
// Check Mod Magic
memcpy(s, pMagic->Magic, 4);
if ((IsMagic(s, "M.K.")) || (IsMagic(s, "M!K!"))
|| (IsMagic(s, "M&K!")) || (IsMagic(s, "N.T."))) m_nChannels = 4; else
if ((IsMagic(s, "CD81")) || (IsMagic(s, "OKTA"))) m_nChannels = 8; else
if ((s[0]=='F') && (s[1]=='L') && (s[2]=='T') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
if ((s[0]>='2') && (s[0]<='9') && (s[1]=='C') && (s[2]=='H') && (s[3]=='N')) m_nChannels = s[0] - '0'; else
if ((s[0]=='1') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 10; else
if ((s[0]=='2') && (s[1]>='0') && (s[1]<='9') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 20; else
if ((s[0]=='3') && (s[1]>='0') && (s[1]<='2') && (s[2]=='C') && (s[3]=='H')) m_nChannels = s[1] - '0' + 30; else
if ((s[0]=='T') && (s[1]=='D') && (s[2]=='Z') && (s[3]>='4') && (s[3]<='9')) m_nChannels = s[3] - '0'; else
if (IsMagic(s,"16CN")) m_nChannels = 16; else
if (IsMagic(s,"32CN")) m_nChannels = 32;
else {
if (!IsValidName((LPCSTR)lpStream, 20, ' '))
return FALSE;
m_nSamples = 15;
}
// Load Samples
nErr = 0;
dwTotalSampleLen = 0;
for (UINT i=1; i<=m_nSamples; i++)
{
PMODSAMPLE pms = (PMODSAMPLE)(lpStream+dwMemPos);
MODINSTRUMENT *psmp = &Ins[i];
UINT loopstart, looplen;
if (m_nSamples == 15)
{
if (!IsValidName((LPCSTR)pms->name, 22, 14)) return FALSE;
if (pms->finetune>>4) return FALSE;
if (pms->volume > 64) return FALSE;
if (bswapBE16(pms->length) > 32768) return FALSE;
}
memcpy(m_szNames[i], pms->name, 22);
m_szNames[i][22] = 0;
psmp->uFlags = 0;
psmp->nLength = bswapBE16(pms->length)*2;
dwTotalSampleLen += psmp->nLength;
psmp->nFineTune = MOD2XMFineTune(pms->finetune & 0x0F);
psmp->nVolume = 4*pms->volume;
if (psmp->nVolume > 256) { psmp->nVolume = 256; nErr++; }
psmp->nGlobalVol = 64;
psmp->nPan = 128;
loopstart = bswapBE16(pms->loopstart)*2;
looplen = bswapBE16(pms->looplen)*2;
// Fix loops
if ((looplen > 2) && (loopstart+looplen > psmp->nLength)
&& (loopstart/2+looplen <= psmp->nLength))
{
loopstart /= 2;
}
psmp->nLoopStart = loopstart;
psmp->nLoopEnd = loopstart + looplen;
if (psmp->nLength < 4) psmp->nLength = 0;
if (psmp->nLength)
{
if (psmp->nLoopStart >= psmp->nLength) { psmp->nLoopStart = psmp->nLength-1; }
if (psmp->nLoopEnd > psmp->nLength) { psmp->nLoopEnd = psmp->nLength; }
if ((psmp->nLoopStart > psmp->nLoopEnd) || (psmp->nLoopEnd <= 8)
|| (psmp->nLoopEnd - psmp->nLoopStart <= 4))
{
psmp->nLoopStart = 0;
psmp->nLoopEnd = 0;
}
if (psmp->nLoopEnd > psmp->nLoopStart)
{
psmp->uFlags |= CHN_LOOP;
}
}
dwMemPos += sizeof(MODSAMPLE);
}
if ((m_nSamples == 15) && (dwTotalSampleLen > dwMemLength * 4)) return FALSE;
pMagic = (PMODMAGIC)(lpStream+dwMemPos);
dwMemPos += sizeof(MODMAGIC);
if (m_nSamples == 15) {
dwMemPos -= 4;
if (pMagic->nOrders > 128) return FALSE;
}
memset(Order, 0,sizeof(Order));
memcpy(Order, pMagic->Orders, 128);
UINT nbp, nbpbuggy, nbpbuggy2, norders;
norders = pMagic->nOrders;
if ((!norders) || (norders > 0x80))
{
norders = 0x80;
while ((norders > 1) && (!Order[norders-1])) norders--;
}
nbpbuggy = 0;
nbpbuggy2 = 0;
nbp = 0;
for (UINT iord=0; iord<128; iord++)
{
UINT i = Order[iord];
if ((i < 0x80) && (nbp <= i))
{
nbp = i+1;
if (iord<norders) nbpbuggy = nbp;
}
if (i >= nbpbuggy2) nbpbuggy2 = i+1;
}
for (UINT iend=norders; iend<MAX_ORDERS; iend++) Order[iend] = 0xFF;
norders--;
m_nRestartPos = pMagic->nRestartPos;
if (m_nRestartPos >= 0x78) m_nRestartPos = 0;
if (m_nRestartPos + 1 >= (UINT)norders) m_nRestartPos = 0;
if (!nbp) return FALSE;
DWORD dwWowTest = dwTotalSampleLen+dwMemPos;
if ((IsMagic(pMagic->Magic, "M.K.")) && (dwWowTest + nbp*8*256 == dwMemLength)) m_nChannels = 8;
if ((nbp != nbpbuggy) && (dwWowTest + nbp*m_nChannels*256 != dwMemLength))
{
if (dwWowTest + nbpbuggy*m_nChannels*256 == dwMemLength) nbp = nbpbuggy;
else nErr += 8;
} else
if ((nbpbuggy2 > nbp) && (dwWowTest + nbpbuggy2*m_nChannels*256 == dwMemLength))
{
nbp = nbpbuggy2;
}
if ((dwWowTest < 0x600) || (dwWowTest > dwMemLength)) nErr += 8;
if ((m_nSamples == 15) && (nErr >= 16)) return FALSE;
// Default settings
m_nType = MOD_TYPE_MOD;
m_nDefaultSpeed = 6;
m_nDefaultTempo = 125;
m_nMinPeriod = 14 << 2;
m_nMaxPeriod = 3424 << 2;
memcpy(m_szNames, lpStream, 20);
// Setting channels pan
for (UINT ich=0; ich<m_nChannels; ich++)
{
ChnSettings[ich].nVolume = 64;
if (gdwSoundSetup & SNDMIX_MAXDEFAULTPAN)
ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 256 : 0;
else
ChnSettings[ich].nPan = (((ich&3)==1) || ((ich&3)==2)) ? 0xC0 : 0x40;
}
// Reading channels
for (UINT ipat=0; ipat<nbp; ipat++)
{
if (ipat < MAX_PATTERNS)
{
if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
PatternSize[ipat] = 64;
if (dwMemPos + m_nChannels*256 >= dwMemLength) break;
MODCOMMAND *m = Patterns[ipat];
LPCBYTE p = lpStream + dwMemPos;
for (UINT j=m_nChannels*64; j; m++,p+=4,j--)
{
BYTE A0=p[0], A1=p[1], A2=p[2], A3=p[3];
UINT n = ((((UINT)A0 & 0x0F) << 8) | (A1));
if ((n) && (n != 0xFFF)) m->note = GetNoteFromPeriod(n << 2);
m->instr = ((UINT)A2 >> 4) | (A0 & 0x10);
m->command = A2 & 0x0F;
m->param = A3;
if ((m->command) || (m->param)) ConvertModCommand(m);
}
}
dwMemPos += m_nChannels*256;
}
// Reading instruments
DWORD dwErrCheck = 0;
for (UINT ismp=1; ismp<=m_nSamples; ismp++) if (Ins[ismp].nLength)
{
LPSTR p = (LPSTR)(lpStream+dwMemPos);
UINT flags = 0;
if (dwMemPos + 5 >= dwMemLength) break;
if (! strncmp(p, "ADPCM", 5))
{
flags = 3;
p += 5;
dwMemPos += 5;
}
DWORD dwSize = ReadSample(&Ins[ismp], flags, p, dwMemLength - dwMemPos);
if (dwSize)
{
dwMemPos += dwSize;
dwErrCheck++;
}
}
#ifdef MODPLUG_TRACKER
return TRUE;
#else
return (dwErrCheck) ? TRUE : FALSE;
#endif
}
#ifndef MODPLUG_NO_FILESAVE
#ifdef _MSC_VER
#pragma warning(disable:4100)
#endif
BOOL CSoundFile::SaveMod(LPCSTR lpszFileName, UINT nPacking)
//----------------------------------------------------------
{
BYTE insmap[32];
UINT inslen[32];
BYTE bTab[32];
BYTE ord[128];
FILE *f;
if ((!m_nChannels) || (!lpszFileName)) return FALSE;
if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
memset(ord, 0, sizeof(ord));
memset(inslen, 0, sizeof(inslen));
if (m_nInstruments)
{
memset(insmap, 0, sizeof(insmap));
for (UINT i=1; i<32; i++) if (Headers[i])
{
for (UINT j=0; j<128; j++) if (Headers[i]->Keyboard[j])
{
insmap[i] = Headers[i]->Keyboard[j];
break;
}
}
} else
{
for (UINT i=0; i<32; i++) insmap[i] = (BYTE)i;
}
// Writing song name
fwrite(m_szNames, 20, 1, f);
// Writing instrument definition
for (UINT iins=1; iins<=31; iins++)
{
MODINSTRUMENT *pins = &Ins[insmap[iins]];
memcpy(bTab, m_szNames[iins],22);
inslen[iins] = pins->nLength;
if (inslen[iins] > 0x1fff0) inslen[iins] = 0x1fff0;
bTab[22] = inslen[iins] >> 9;
bTab[23] = inslen[iins] >> 1;
if (pins->RelativeTone < 0) bTab[24] = 0x08; else
if (pins->RelativeTone > 0) bTab[24] = 0x07; else
bTab[24] = (BYTE)XM2MODFineTune(pins->nFineTune);
bTab[25] = pins->nVolume >> 2;
bTab[26] = pins->nLoopStart >> 9;
bTab[27] = pins->nLoopStart >> 1;
bTab[28] = (pins->nLoopEnd - pins->nLoopStart) >> 9;
bTab[29] = (pins->nLoopEnd - pins->nLoopStart) >> 1;
fwrite(bTab, 30, 1, f);
}
// Writing number of patterns
UINT nbp=0, norders=128;
for (UINT iord=0; iord<128; iord++)
{
if (Order[iord] == 0xFF)
{
norders = iord;
break;
}
if ((Order[iord] < 0x80) && (nbp<=Order[iord])) nbp = Order[iord]+1;
}
bTab[0] = norders;
bTab[1] = m_nRestartPos;
fwrite(bTab, 2, 1, f);
// Writing pattern list
if (norders) memcpy(ord, Order, norders);
fwrite(ord, 128, 1, f);
// Writing signature
if (m_nChannels == 4)
lstrcpy((LPSTR)&bTab, "M.K.");
else
wsprintf((LPSTR)&bTab, "%luCHN", m_nChannels);
fwrite(bTab, 4, 1, f);
// Writing patterns
for (UINT ipat=0; ipat<nbp; ipat++) if (Patterns[ipat])
{
BYTE s[64*4];
MODCOMMAND *m = Patterns[ipat];
for (UINT i=0; i<64; i++) if (i < PatternSize[ipat])
{
LPBYTE p=s;
for (UINT c=0; c<m_nChannels; c++,p+=4,m++)
{
UINT param = ModSaveCommand(m, FALSE);
UINT command = param >> 8;
param &= 0xFF;
if (command > 0x0F) command = param = 0;
if ((m->vol >= 0x10) && (m->vol <= 0x50) && (!command) && (!param)) { command = 0x0C; param = m->vol - 0x10; }
UINT period = m->note;
if (period)
{
if (period < 37) period = 37;
period -= 37;
if (period >= 6*12) period = 6*12-1;
period = ProTrackerPeriodTable[period];
}
UINT instr = (m->instr > 31) ? 0 : m->instr;
p[0] = ((period >> 8) & 0x0F) | (instr & 0x10);
p[1] = period & 0xFF;
p[2] = ((instr & 0x0F) << 4) | (command & 0x0F);
p[3] = param;
}
fwrite(s, m_nChannels, 4, f);
} else
{
memset(s, 0, m_nChannels*4);
fwrite(s, m_nChannels, 4, f);
}
}
// Writing instruments
for (UINT ismpd=1; ismpd<=31; ismpd++) if (inslen[ismpd])
{
MODINSTRUMENT *pins = &Ins[insmap[ismpd]];
UINT flags = RS_PCM8S;
#ifndef NO_PACKING
if (!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
{
if ((nPacking) && (CanPackSample((char *)pins->pSample, inslen[ismpd], nPacking)))
{
fwrite("ADPCM", 1, 5, f);
flags = RS_ADPCM4;
}
}
#endif
WriteSample(f, pins, flags, inslen[ismpd]);
}
fclose(f);
return TRUE;
}
#ifdef _MSC_VER
#pragma warning(default:4100)
#endif
#endif // MODPLUG_NO_FILESAVE

View File

@ -0,0 +1,636 @@
#include "stdafx.h"
#include "sndfile.h"
//#define MT2DEBUG
#pragma pack(1)
typedef struct _MT2FILEHEADER
{
DWORD dwMT20; // 0x3032544D "MT20"
DWORD dwSpecial;
WORD wVersion;
CHAR szTrackerName[32]; // "MadTracker 2.0"
CHAR szSongName[64];
WORD nOrders;
WORD wRestart;
WORD wPatterns;
WORD wChannels;
WORD wSamplesPerTick;
BYTE bTicksPerLine;
BYTE bLinesPerBeat;
DWORD fulFlags; // b0=packed patterns
WORD wInstruments;
WORD wSamples;
BYTE Orders[256];
} MT2FILEHEADER;
typedef struct _MT2PATTERN
{
WORD wLines;
DWORD wDataLen;
} MT2PATTERN;
typedef struct _MT2COMMAND
{
BYTE note; // 0=nothing, 97=note off
BYTE instr;
BYTE vol;
BYTE pan;
BYTE fxcmd;
BYTE fxparam1;
BYTE fxparam2;
} MT2COMMAND;
typedef struct _MT2DRUMSDATA
{
WORD wDrumPatterns;
WORD wDrumSamples[8];
BYTE DrumPatternOrder[256];
} MT2DRUMSDATA;
typedef struct _MT2AUTOMATION
{
DWORD dwFlags;
DWORD dwEffectId;
DWORD nEnvPoints;
} MT2AUTOMATION;
typedef struct _MT2INSTRUMENT
{
CHAR szName[32];
DWORD dwDataLen;
WORD wSamples;
BYTE GroupsMapping[96];
BYTE bVibType;
BYTE bVibSweep;
BYTE bVibDepth;
BYTE bVibRate;
WORD wFadeOut;
WORD wNNA;
WORD wInstrFlags;
WORD wEnvFlags1;
WORD wEnvFlags2;
} MT2INSTRUMENT;
typedef struct _MT2ENVELOPE
{
BYTE nFlags;
BYTE nPoints;
BYTE nSustainPos;
BYTE nLoopStart;
BYTE nLoopEnd;
BYTE bReserved[3];
BYTE EnvData[64];
} MT2ENVELOPE;
typedef struct _MT2SYNTH
{
BYTE nSynthId;
BYTE nFxId;
WORD wCutOff;
BYTE nResonance;
BYTE nAttack;
BYTE nDecay;
BYTE bReserved[25];
} MT2SYNTH;
typedef struct _MT2SAMPLE
{
CHAR szName[32];
DWORD dwDataLen;
DWORD dwLength;
DWORD dwFrequency;
BYTE nQuality;
BYTE nChannels;
BYTE nFlags;
BYTE nLoop;
DWORD dwLoopStart;
DWORD dwLoopEnd;
WORD wVolume;
BYTE nPan;
BYTE nBaseNote;
WORD wSamplesPerBeat;
} MT2SAMPLE;
typedef struct _MT2GROUP
{
BYTE nSmpNo;
BYTE nVolume; // 0-128
BYTE nFinePitch;
BYTE Reserved[5];
} MT2GROUP;
#pragma pack()
static VOID ConvertMT2Command(CSoundFile *that, MODCOMMAND *m, const MT2COMMAND *p)
//---------------------------------------------------------------------------
{
// Note
m->note = 0;
if (p->note) m->note = (p->note > 96) ? 0xFF : p->note+12;
// Instrument
m->instr = p->instr;
// Volume Column
if ((p->vol >= 0x10) && (p->vol <= 0x90))
{
m->volcmd = VOLCMD_VOLUME;
m->vol = (p->vol - 0x10) >> 1;
} else
if ((p->vol >= 0xA0) && (p->vol <= 0xAF))
{
m->volcmd = VOLCMD_VOLSLIDEDOWN;
m->vol = (p->vol & 0x0f);
} else
if ((p->vol >= 0xB0) && (p->vol <= 0xBF))
{
m->volcmd = VOLCMD_VOLSLIDEUP;
m->vol = (p->vol & 0x0f);
} else
if ((p->vol >= 0xC0) && (p->vol <= 0xCF))
{
m->volcmd = VOLCMD_FINEVOLDOWN;
m->vol = (p->vol & 0x0f);
} else
if ((p->vol >= 0xD0) && (p->vol <= 0xDF))
{
m->volcmd = VOLCMD_FINEVOLUP;
m->vol = (p->vol & 0x0f);
} else
{
m->volcmd = 0;
m->vol = 0;
}
// Effects
m->command = 0;
m->param = 0;
if ((p->fxcmd) || (p->fxparam1) || (p->fxparam2))
{
if (!p->fxcmd)
{
m->command = p->fxparam2;
m->param = p->fxparam1;
that->ConvertModCommand(m);
} else
{
// TODO: MT2 Effects
}
}
}
BOOL CSoundFile::ReadMT2(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
const MT2FILEHEADER *pfh = (MT2FILEHEADER *)lpStream;
DWORD dwMemPos, dwDrumDataPos, dwExtraDataPos;
UINT nDrumDataLen, nExtraDataLen;
const MT2DRUMSDATA *pdd;
const MT2INSTRUMENT *InstrMap[255];
const MT2SAMPLE *SampleMap[256];
if ((!lpStream) || (dwMemLength < sizeof(MT2FILEHEADER))
|| (pfh->dwMT20 != 0x3032544D)
|| (pfh->wVersion < 0x0200) || (pfh->wVersion >= 0x0300)
|| (pfh->wChannels < 4) || (pfh->wChannels > 64)) return FALSE;
pdd = NULL;
m_nType = MOD_TYPE_MT2;
m_nChannels = pfh->wChannels;
m_nRestartPos = pfh->wRestart;
m_nDefaultSpeed = pfh->bTicksPerLine;
m_nDefaultTempo = 125;
if ((pfh->wSamplesPerTick > 100) && (pfh->wSamplesPerTick < 5000))
{
m_nDefaultTempo = 110250 / pfh->wSamplesPerTick;
}
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
{
Order[iOrd] = (BYTE)((iOrd < pfh->nOrders) ? pfh->Orders[iOrd] : 0xFF);
}
memcpy(m_szNames[0], pfh->szSongName, 32);
m_szNames[0][31] = 0;
dwMemPos = sizeof(MT2FILEHEADER);
nDrumDataLen = *(WORD *)(lpStream + dwMemPos);
dwDrumDataPos = dwMemPos + 2;
if (nDrumDataLen >= 2) pdd = (MT2DRUMSDATA *)(lpStream+dwDrumDataPos);
dwMemPos += 2 + nDrumDataLen;
#ifdef MT2DEBUG
Log("MT2 v%03X: \"%s\" (flags=%04X)\n", pfh->wVersion, m_szNames[0], pfh->fulFlags);
Log("%d Channels, %d Patterns, %d Instruments, %d Samples\n", pfh->wChannels, pfh->wPatterns, pfh->wInstruments, pfh->wSamples);
Log("Drum Data: %d bytes @%04X\n", nDrumDataLen, dwDrumDataPos);
#endif
if (dwMemPos >= dwMemLength-12) return TRUE;
if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4;
nExtraDataLen = *(DWORD *)(lpStream+dwMemPos);
dwExtraDataPos = dwMemPos + 4;
dwMemPos += 4;
#ifdef MT2DEBUG
Log("Extra Data: %d bytes @%04X\n", nExtraDataLen, dwExtraDataPos);
#endif
if (dwMemPos + nExtraDataLen >= dwMemLength) return TRUE;
while (dwMemPos+8 < dwExtraDataPos + nExtraDataLen)
{
DWORD dwId = *(DWORD *)(lpStream+dwMemPos);
DWORD dwLen = *(DWORD *)(lpStream+dwMemPos+4);
dwMemPos += 8;
if (dwMemPos + dwLen > dwMemLength) return TRUE;
#ifdef MT2DEBUG
CHAR s[5];
memcpy(s, &dwId, 4);
s[4] = 0;
Log("pos=0x%04X: %s: %d bytes\n", dwMemPos-8, s, dwLen);
#endif
switch(dwId)
{
// MSG
case 0x0047534D:
if ((dwLen > 3) && (!m_lpszSongComments))
{
DWORD nTxtLen = dwLen;
if (nTxtLen > 32000) nTxtLen = 32000;
m_lpszSongComments = new char[nTxtLen]; // changed from CHAR
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos+1, nTxtLen-1);
m_lpszSongComments[nTxtLen-1] = 0;
}
}
break;
// SUM -> author name (or "Unregistered")
// TMAP
// TRKS
case 0x534b5254:
break;
}
dwMemPos += dwLen;
}
// Load Patterns
dwMemPos = dwExtraDataPos + nExtraDataLen;
for (UINT iPat=0; iPat<pfh->wPatterns; iPat++) if (dwMemPos < dwMemLength-6)
{
const MT2PATTERN *pmp = (MT2PATTERN *)(lpStream+dwMemPos);
UINT wDataLen = (pmp->wDataLen + 1) & ~1;
dwMemPos += 6;
if (dwMemPos + wDataLen > dwMemLength) break;
UINT nLines = pmp->wLines;
if ((iPat < MAX_PATTERNS) && (nLines > 0) && (nLines <= 256))
{
#ifdef MT2DEBUG
Log("Pattern #%d @%04X: %d lines, %d bytes\n", iPat, dwMemPos-6, nLines, pmp->wDataLen);
#endif
PatternSize[iPat] = nLines;
Patterns[iPat] = AllocatePattern(nLines, m_nChannels);
if (!Patterns[iPat]) return TRUE;
MODCOMMAND *m = Patterns[iPat];
UINT len = wDataLen;
if (pfh->fulFlags & 1) // Packed Patterns
{
BYTE *p = (BYTE *)(lpStream+dwMemPos);
UINT pos = 0, row=0, ch=0;
while (pos < len)
{
MT2COMMAND cmd;
UINT infobyte = p[pos++];
UINT rptcount = 0;
if (infobyte == 0xff)
{
rptcount = p[pos++];
infobyte = p[pos++];
#if 0
Log("(%d.%d) FF(%02X).%02X\n", row, ch, rptcount, infobyte);
} else
{
Log("(%d.%d) %02X\n", row, ch, infobyte);
#endif
}
if (infobyte & 0x7f)
{
UINT patpos = row*m_nChannels+ch;
cmd.note = cmd.instr = cmd.vol = cmd.pan = cmd.fxcmd = cmd.fxparam1 = cmd.fxparam2 = 0;
if (infobyte & 1) cmd.note = p[pos++];
if (infobyte & 2) cmd.instr = p[pos++];
if (infobyte & 4) cmd.vol = p[pos++];
if (infobyte & 8) cmd.pan = p[pos++];
if (infobyte & 16) cmd.fxcmd = p[pos++];
if (infobyte & 32) cmd.fxparam1 = p[pos++];
if (infobyte & 64) cmd.fxparam2 = p[pos++];
#ifdef MT2DEBUG
if (cmd.fxcmd)
{
Log("(%d.%d) MT2 FX=%02X.%02X.%02X\n", row, ch, cmd.fxcmd, cmd.fxparam1, cmd.fxparam2);
}
#endif
ConvertMT2Command(this, &m[patpos], &cmd);
}
row += rptcount+1;
while (row >= nLines) { row-=nLines; ch++; }
if (ch >= m_nChannels) break;
}
} else
{
const MT2COMMAND *p = (MT2COMMAND *)(lpStream+dwMemPos);
UINT n = 0;
while ((len > sizeof(MT2COMMAND)) && (n < m_nChannels*nLines))
{
ConvertMT2Command(this, m, p);
len -= sizeof(MT2COMMAND);
n++;
p++;
m++;
}
}
}
dwMemPos += wDataLen;
}
// Skip Drum Patterns
if (pdd)
{
#ifdef MT2DEBUG
Log("%d Drum Patterns at offset 0x%08X\n", pdd->wDrumPatterns, dwMemPos);
#endif
for (UINT iDrm=0; iDrm<pdd->wDrumPatterns; iDrm++)
{
if (dwMemPos > dwMemLength-2) return TRUE;
UINT nLines = *(WORD *)(lpStream+dwMemPos);
#ifdef MT2DEBUG
if (nLines != 64) Log("Drum Pattern %d: %d Lines @%04X\n", iDrm, nLines, dwMemPos);
#endif
dwMemPos += 2 + nLines * 32;
}
}
// Automation
if (pfh->fulFlags & 2)
{
#ifdef MT2DEBUG
Log("Automation at offset 0x%08X\n", dwMemPos);
#endif
UINT nAutoCount = m_nChannels;
if (pfh->fulFlags & 0x10) nAutoCount++; // Master Automation
if ((pfh->fulFlags & 0x08) && (pdd)) nAutoCount += 8; // Drums Automation
nAutoCount *= pfh->wPatterns;
for (UINT iAuto=0; iAuto<nAutoCount; iAuto++)
{
if (dwMemPos+12 >= dwMemLength) return TRUE;
const MT2AUTOMATION *pma = (MT2AUTOMATION *)(lpStream+dwMemPos);
dwMemPos += (pfh->wVersion <= 0x201) ? 4 : 8;
for (UINT iEnv=0; iEnv<14; iEnv++)
{
if (pma->dwFlags & (1 << iEnv))
{
#ifdef MT2DEBUG
UINT nPoints = *(DWORD *)(lpStream+dwMemPos);
Log(" Env[%d/%d] %04X @%04X: %d points\n", iAuto, nAutoCount, 1 << iEnv, dwMemPos-8, nPoints);
#endif
dwMemPos += 260;
}
}
}
}
// Load Instruments
#ifdef MT2DEBUG
Log("Loading instruments at offset 0x%08X\n", dwMemPos);
#endif
memset(InstrMap, 0, sizeof(InstrMap));
m_nInstruments = (pfh->wInstruments < MAX_INSTRUMENTS) ? pfh->wInstruments : MAX_INSTRUMENTS-1;
for (UINT iIns=1; iIns<=255; iIns++)
{
if (dwMemPos+36 > dwMemLength) return TRUE;
const MT2INSTRUMENT *pmi = (MT2INSTRUMENT *)(lpStream+dwMemPos);
INSTRUMENTHEADER *penv = NULL;
if (iIns <= m_nInstruments)
{
penv = new INSTRUMENTHEADER;
Headers[iIns] = penv;
if (penv)
{
memset(penv, 0, sizeof(INSTRUMENTHEADER));
memcpy(penv->name, pmi->szName, 32);
penv->nGlobalVol = 64;
penv->nPan = 128;
for (UINT i=0; i<NOTE_MAX; i++)
{
penv->NoteMap[i] = i+1;
}
}
}
#ifdef MT2DEBUG
if (iIns <= pfh->wInstruments) Log(" Instrument #%d at offset %04X: %d bytes\n", iIns, dwMemPos, pmi->dwDataLen);
#endif
if (((LONG)pmi->dwDataLen > 0) && (dwMemPos <= dwMemLength - 40) && (pmi->dwDataLen <= dwMemLength - (dwMemPos + 40)))
{
InstrMap[iIns-1] = pmi;
if (penv)
{
penv->nFadeOut = pmi->wFadeOut;
penv->nNNA = pmi->wNNA & 3;
penv->nDCT = (pmi->wNNA>>8) & 3;
penv->nDNA = (pmi->wNNA>>12) & 3;
MT2ENVELOPE *pehdr[4];
WORD *pedata[4];
if (pfh->wVersion <= 0x201)
{
DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT) - 4;
pehdr[0] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
pehdr[1] = (MT2ENVELOPE *)(lpStream+dwEnvPos+8);
pehdr[2] = pehdr[3] = NULL;
pedata[0] = (WORD *)(lpStream+dwEnvPos+16);
pedata[1] = (WORD *)(lpStream+dwEnvPos+16+64);
pedata[2] = pedata[3] = NULL;
} else
{
DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT);
for (UINT i=0; i<4; i++)
{
if (pmi->wEnvFlags1 & (1<<i))
{
pehdr[i] = (MT2ENVELOPE *)(lpStream+dwEnvPos);
pedata[i] = (WORD *)pehdr[i]->EnvData;
dwEnvPos += sizeof(MT2ENVELOPE);
} else
{
pehdr[i] = NULL;
pedata[i] = NULL;
}
}
}
// Load envelopes
for (UINT iEnv=0; iEnv<4; iEnv++) if (pehdr[iEnv])
{
const MT2ENVELOPE *pme = pehdr[iEnv];
WORD *pEnvPoints = NULL;
BYTE *pEnvData = NULL;
#ifdef MT2DEBUG
Log(" Env %d.%d @%04X: %d points\n", iIns, iEnv, (UINT)(((BYTE *)pme)-lpStream), pme->nPoints);
#endif
switch(iEnv)
{
// Volume Envelope
case 0:
if (pme->nFlags & 1) penv->dwFlags |= ENV_VOLUME;
if (pme->nFlags & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
if (pme->nFlags & 4) penv->dwFlags |= ENV_VOLLOOP;
penv->nVolEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
penv->nVolSustainBegin = penv->nVolSustainEnd = pme->nSustainPos;
penv->nVolLoopStart = pme->nLoopStart;
penv->nVolLoopEnd = pme->nLoopEnd;
pEnvPoints = penv->VolPoints;
pEnvData = penv->VolEnv;
break;
// Panning Envelope
case 1:
if (pme->nFlags & 1) penv->dwFlags |= ENV_PANNING;
if (pme->nFlags & 2) penv->dwFlags |= ENV_PANSUSTAIN;
if (pme->nFlags & 4) penv->dwFlags |= ENV_PANLOOP;
penv->nPanEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
penv->nPanSustainBegin = penv->nPanSustainEnd = pme->nSustainPos;
penv->nPanLoopStart = pme->nLoopStart;
penv->nPanLoopEnd = pme->nLoopEnd;
pEnvPoints = penv->PanPoints;
pEnvData = penv->PanEnv;
break;
// Pitch/Filter envelope
default:
if (pme->nFlags & 1) penv->dwFlags |= (iEnv==3) ? (ENV_PITCH|ENV_FILTER) : ENV_PITCH;
if (pme->nFlags & 2) penv->dwFlags |= ENV_PITCHSUSTAIN;
if (pme->nFlags & 4) penv->dwFlags |= ENV_PITCHLOOP;
penv->nPitchEnv = (pme->nPoints > 16) ? 16 : pme->nPoints;
penv->nPitchSustainBegin = penv->nPitchSustainEnd = pme->nSustainPos;
penv->nPitchLoopStart = pme->nLoopStart;
penv->nPitchLoopEnd = pme->nLoopEnd;
pEnvPoints = penv->PitchPoints;
pEnvData = penv->PitchEnv;
}
// Envelope data
if ((pEnvPoints) && (pEnvData) && (pedata[iEnv]))
{
WORD *psrc = pedata[iEnv];
for (UINT i=0; i<16; i++)
{
pEnvPoints[i] = psrc[i*2];
pEnvData[i] = (BYTE)psrc[i*2+1];
}
}
}
}
dwMemPos += pmi->dwDataLen + 36;
if (pfh->wVersion > 0x201) dwMemPos += 4; // ?
} else
{
dwMemPos += 36;
}
}
#ifdef MT2DEBUG
Log("Loading samples at offset 0x%08X\n", dwMemPos);
#endif
memset(SampleMap, 0, sizeof(SampleMap));
m_nSamples = (pfh->wSamples < MAX_SAMPLES) ? pfh->wSamples : MAX_SAMPLES-1;
for (UINT iSmp=1; iSmp<=256; iSmp++)
{
if (dwMemPos+36 > dwMemLength) return TRUE;
const MT2SAMPLE *pms = (MT2SAMPLE *)(lpStream+dwMemPos);
#ifdef MT2DEBUG
if (iSmp <= m_nSamples) Log(" Sample #%d at offset %04X: %d bytes\n", iSmp, dwMemPos, pms->dwDataLen);
#endif
if (iSmp < MAX_SAMPLES)
{
memcpy(m_szNames[iSmp], pms->szName, 32);
}
if (pms->dwDataLen > 0)
{
SampleMap[iSmp-1] = pms;
if (iSmp < MAX_SAMPLES)
{
MODINSTRUMENT *psmp = &Ins[iSmp];
psmp->nGlobalVol = 64;
if (dwMemPos+sizeof(MT2SAMPLE) > dwMemLength) return TRUE;
psmp->nVolume = (pms->wVolume >> 7);
psmp->nPan = (pms->nPan == 0x80) ? 128 : (pms->nPan^0x80);
psmp->nLength = pms->dwLength;
psmp->nC4Speed = pms->dwFrequency;
psmp->nLoopStart = pms->dwLoopStart;
psmp->nLoopEnd = pms->dwLoopEnd;
FrequencyToTranspose(psmp);
psmp->RelativeTone -= pms->nBaseNote - 49;
psmp->nC4Speed = TransposeToFrequency(psmp->RelativeTone, psmp->nFineTune);
if (pms->nQuality == 2) { psmp->uFlags |= CHN_16BIT; psmp->nLength >>= 1; }
if (pms->nChannels == 2) { psmp->nLength >>= 1; }
if (pms->nLoop == 1) psmp->uFlags |= CHN_LOOP;
if (pms->nLoop == 2) psmp->uFlags |= CHN_LOOP|CHN_PINGPONGLOOP;
}
dwMemPos += pms->dwDataLen + 36;
} else
{
dwMemPos += 36;
}
}
#ifdef MT2DEBUG
Log("Loading groups at offset 0x%08X\n", dwMemPos);
#endif
for (UINT iMap=0; iMap<255; iMap++) if (InstrMap[iMap])
{
if (dwMemPos+8 > dwMemLength) return TRUE;
const MT2INSTRUMENT *pmi = InstrMap[iMap];
INSTRUMENTHEADER *penv = NULL;
if (iMap<m_nInstruments) penv = Headers[iMap+1];
for (UINT iGrp=0; iGrp<pmi->wSamples; iGrp++)
{
if (penv)
{
const MT2GROUP *pmg = (MT2GROUP *)(lpStream+dwMemPos);
for (UINT i=0; i<96; i++)
{
if (pmi->GroupsMapping[i] == iGrp)
{
UINT nSmp = pmg->nSmpNo+1;
penv->Keyboard[i+12] = (BYTE)nSmp;
if (nSmp <= m_nSamples)
{
Ins[nSmp].nVibType = pmi->bVibType;
Ins[nSmp].nVibSweep = pmi->bVibSweep;
Ins[nSmp].nVibDepth = pmi->bVibDepth;
Ins[nSmp].nVibRate = pmi->bVibRate;
}
}
}
}
dwMemPos += 8;
}
}
#ifdef MT2DEBUG
Log("Loading sample data at offset 0x%08X\n", dwMemPos);
#endif
for (UINT iData=0; iData<256; iData++) if ((iData < m_nSamples) && (SampleMap[iData]))
{
const MT2SAMPLE *pms = SampleMap[iData];
MODINSTRUMENT *psmp = &Ins[iData+1];
if (!(pms->nFlags & 5))
{
if (psmp->nLength > 0 && dwMemPos < dwMemLength)
{
#ifdef MT2DEBUG
Log(" Reading sample #%d at offset 0x%04X (len=%d)\n", iData+1, dwMemPos, psmp->nLength);
#endif
UINT rsflags;
if (pms->nChannels == 2)
rsflags = (psmp->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
else
rsflags = (psmp->uFlags & CHN_16BIT) ? RS_PCM16D : RS_PCM8D;
dwMemPos += ReadSample(psmp, rsflags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
} else
if (dwMemPos+4 < dwMemLength)
{
UINT nNameLen = *(DWORD *)(lpStream+dwMemPos);
dwMemPos += nNameLen + 16;
}
if (dwMemPos+4 >= dwMemLength) break;
}
return TRUE;
}

View File

@ -0,0 +1,168 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
//////////////////////////////////////////////////////////
// MTM file support (import only)
#pragma pack(1)
typedef struct tagMTMSAMPLE
{
char samplename[22]; // changed from CHAR
DWORD length;
DWORD reppos;
DWORD repend;
CHAR finetune;
BYTE volume;
BYTE attribute;
} MTMSAMPLE;
typedef struct tagMTMHEADER
{
char id[4]; // MTM file marker + version // changed from CHAR
char songname[20]; // ASCIIZ songname // changed from CHAR
WORD numtracks; // number of tracks saved
BYTE lastpattern; // last pattern number saved
BYTE lastorder; // last order number to play (songlength-1)
WORD commentsize; // length of comment field
BYTE numsamples; // number of samples saved
BYTE attribute; // attribute byte (unused)
BYTE beatspertrack;
BYTE numchannels; // number of channels used
BYTE panpos[32]; // voice pan positions
} MTMHEADER;
#pragma pack()
BOOL CSoundFile::ReadMTM(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
MTMHEADER *pmh = (MTMHEADER *)lpStream;
DWORD dwMemPos = 66;
if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
if ((strncmp(pmh->id, "MTM", 3)) || (pmh->numchannels > 32)
|| (pmh->numsamples >= MAX_SAMPLES) || (!pmh->numsamples)
|| (!pmh->numtracks) || (!pmh->numchannels)
|| (!pmh->lastpattern) || (pmh->lastpattern >= MAX_PATTERNS))
return FALSE;
strncpy(m_szNames[0], pmh->songname, 20);
m_szNames[0][20] = 0;
if (dwMemPos + 37*pmh->numsamples + 128 + 192*pmh->numtracks
+ 64 * (pmh->lastpattern+1) + pmh->commentsize >= dwMemLength)
return FALSE;
m_nType = MOD_TYPE_MTM;
m_nSamples = pmh->numsamples;
m_nChannels = pmh->numchannels;
// Reading instruments
for (UINT i=1; i<=m_nSamples; i++)
{
MTMSAMPLE *pms = (MTMSAMPLE *)(lpStream + dwMemPos);
strncpy(m_szNames[i], pms->samplename, 22);
m_szNames[i][22] = 0;
Ins[i].nVolume = pms->volume << 2;
Ins[i].nGlobalVol = 64;
DWORD len = pms->length;
if ((len > 4) && (len <= MAX_SAMPLE_LENGTH))
{
Ins[i].nLength = len;
Ins[i].nLoopStart = pms->reppos;
Ins[i].nLoopEnd = pms->repend;
if (Ins[i].nLoopEnd > Ins[i].nLength)
Ins[i].nLoopEnd = Ins[i].nLength;
if (Ins[i].nLoopStart + 4 >= Ins[i].nLoopEnd)
Ins[i].nLoopStart = Ins[i].nLoopEnd = 0;
if (Ins[i].nLoopEnd) Ins[i].uFlags |= CHN_LOOP;
Ins[i].nFineTune = MOD2XMFineTune(pms->finetune);
if (pms->attribute & 0x01)
{
Ins[i].uFlags |= CHN_16BIT;
Ins[i].nLength >>= 1;
Ins[i].nLoopStart >>= 1;
Ins[i].nLoopEnd >>= 1;
}
Ins[i].nPan = 128;
}
dwMemPos += 37;
}
// Setting Channel Pan Position
for (UINT ich=0; ich<m_nChannels; ich++)
{
ChnSettings[ich].nPan = ((pmh->panpos[ich] & 0x0F) << 4) + 8;
ChnSettings[ich].nVolume = 64;
}
// Reading pattern order
memcpy(Order, lpStream + dwMemPos, pmh->lastorder+1);
dwMemPos += 128;
// Reading Patterns
LPCBYTE pTracks = lpStream + dwMemPos;
dwMemPos += 192 * pmh->numtracks;
LPWORD pSeq = (LPWORD)(lpStream + dwMemPos);
for (UINT pat=0; pat<=pmh->lastpattern; pat++)
{
PatternSize[pat] = 64;
if ((Patterns[pat] = AllocatePattern(64, m_nChannels)) == NULL) break;
for (UINT n=0; n<32; n++) if ((pSeq[n]) && (pSeq[n] <= pmh->numtracks) && (n < m_nChannels))
{
LPCBYTE p = pTracks + 192 * (pSeq[n]-1);
MODCOMMAND *m = Patterns[pat] + n;
for (UINT i=0; i<64; i++, m+=m_nChannels, p+=3)
{
if (p[0] & 0xFC) m->note = (p[0] >> 2) + 37;
m->instr = ((p[0] & 0x03) << 4) | (p[1] >> 4);
UINT cmd = p[1] & 0x0F;
UINT param = p[2];
if (cmd == 0x0A)
{
if (param & 0xF0) param &= 0xF0; else param &= 0x0F;
}
m->command = cmd;
m->param = param;
if ((cmd) || (param)) ConvertModCommand(m);
}
}
pSeq += 32;
}
dwMemPos += 64*(pmh->lastpattern+1);
if ((pmh->commentsize) && (dwMemPos + pmh->commentsize < dwMemLength))
{
UINT n = pmh->commentsize;
m_lpszSongComments = new char[n+1];
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos, n);
m_lpszSongComments[n] = 0;
for (UINT i=0; i<n; i++)
{
if (!m_lpszSongComments[i])
{
m_lpszSongComments[i] = ((i+1) % 40) ? 0x20 : 0x0D;
}
}
}
}
dwMemPos += pmh->commentsize;
// Reading Samples
for (UINT ismp=1; ismp<=m_nSamples; ismp++)
{
if (dwMemPos >= dwMemLength) break;
dwMemPos += ReadSample(&Ins[ismp], (Ins[ismp].uFlags & CHN_16BIT) ? RS_PCM16U : RS_PCM8U,
(LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
}
m_nMinPeriod = 64;
m_nMaxPeriod = 32767;
return TRUE;
}

View File

@ -0,0 +1,197 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
//////////////////////////////////////////////
// Oktalyzer (OKT) module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
typedef struct OKTFILEHEADER
{
DWORD okta; // "OKTA"
DWORD song; // "SONG"
DWORD cmod; // "CMOD"
DWORD fixed8;
BYTE chnsetup[8];
DWORD samp; // "SAMP"
DWORD samplen;
} OKTFILEHEADER;
typedef struct OKTSAMPLE
{
CHAR name[20];
DWORD length;
WORD loopstart;
WORD looplen;
BYTE pad1;
BYTE volume;
BYTE pad2;
BYTE pad3;
} OKTSAMPLE;
BOOL CSoundFile::ReadOKT(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const OKTFILEHEADER *pfh = (OKTFILEHEADER *)lpStream;
DWORD dwMemPos = sizeof(OKTFILEHEADER);
UINT nsamples = 0, npatterns = 0, norders = 0;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pfh->okta != 0x41544B4F) || (pfh->song != 0x474E4F53)
|| (pfh->cmod != 0x444F4D43) || (pfh->chnsetup[0]) || (pfh->chnsetup[2])
|| (pfh->chnsetup[4]) || (pfh->chnsetup[6]) || (pfh->fixed8 != 0x08000000)
|| (pfh->samp != 0x504D4153)) return FALSE;
m_nType = MOD_TYPE_OKT;
m_nChannels = 4 + pfh->chnsetup[1] + pfh->chnsetup[3] + pfh->chnsetup[5] + pfh->chnsetup[7];
if (m_nChannels > MAX_CHANNELS) m_nChannels = MAX_CHANNELS;
nsamples = bswapBE32(pfh->samplen) >> 5;
m_nSamples = nsamples;
if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
// Reading samples
for (UINT smp=1; smp <= nsamples; smp++)
{
if (dwMemPos >= dwMemLength) return TRUE;
if (smp < MAX_SAMPLES)
{
OKTSAMPLE *psmp = (OKTSAMPLE *)(lpStream + dwMemPos);
MODINSTRUMENT *pins = &Ins[smp];
memcpy(m_szNames[smp], psmp->name, 20);
pins->uFlags = 0;
pins->nLength = bswapBE32(psmp->length) & ~1;
pins->nLoopStart = bswapBE16(psmp->loopstart);
pins->nLoopEnd = pins->nLoopStart + bswapBE16(psmp->looplen);
if (pins->nLoopStart + 2 < pins->nLoopEnd) pins->uFlags |= CHN_LOOP;
pins->nGlobalVol = 64;
pins->nVolume = psmp->volume << 2;
pins->nC4Speed = 8363;
}
dwMemPos += sizeof(OKTSAMPLE);
}
// SPEE
if (dwMemPos >= dwMemLength) return TRUE;
if (*((DWORD *)(lpStream + dwMemPos)) == 0x45455053)
{
m_nDefaultSpeed = lpStream[dwMemPos+9];
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
}
// SLEN
if (dwMemPos >= dwMemLength) return TRUE;
if (*((DWORD *)(lpStream + dwMemPos)) == 0x4E454C53)
{
npatterns = lpStream[dwMemPos+9];
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
}
// PLEN
if (dwMemPos >= dwMemLength) return TRUE;
if (*((DWORD *)(lpStream + dwMemPos)) == 0x4E454C50)
{
norders = lpStream[dwMemPos+9];
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
}
// PATT
if (dwMemPos >= dwMemLength) return TRUE;
if (*((DWORD *)(lpStream + dwMemPos)) == 0x54544150)
{
UINT orderlen = norders;
if (orderlen >= MAX_ORDERS) orderlen = MAX_ORDERS-1;
for (UINT i=0; i<orderlen; i++) Order[i] = lpStream[dwMemPos+10+i];
for (UINT j=orderlen; j>1; j--) { if (Order[j-1]) break; Order[j-1] = 0xFF; }
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
}
// PBOD
UINT npat = 0;
while ((dwMemPos+10 < dwMemLength) && (*((DWORD *)(lpStream + dwMemPos)) == 0x444F4250))
{
DWORD dwPos = dwMemPos + 10;
UINT rows = lpStream[dwMemPos+9];
if (!rows) rows = 64;
if (npat < MAX_PATTERNS)
{
if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
MODCOMMAND *m = Patterns[npat];
PatternSize[npat] = rows;
UINT imax = m_nChannels*rows;
for (UINT i=0; i<imax; i++, m++, dwPos+=4)
{
if (dwPos+4 > dwMemLength) break;
const BYTE *p = lpStream+dwPos;
UINT note = p[0];
if (note)
{
m->note = note + 48;
m->instr = p[1] + 1;
}
UINT command = p[2];
UINT param = p[3];
m->param = param;
switch(command)
{
// 0: no effect
case 0:
break;
// 1: Portamento Up
case 1:
case 17:
case 30:
if (param) m->command = CMD_PORTAMENTOUP;
break;
// 2: Portamento Down
case 2:
case 13:
case 21:
if (param) m->command = CMD_PORTAMENTODOWN;
break;
// 10: Arpeggio
case 10:
case 11:
case 12:
m->command = CMD_ARPEGGIO;
break;
// 15: Filter
case 15:
m->command = CMD_MODCMDEX;
m->param = param & 0x0F;
break;
// 25: Position Jump
case 25:
m->command = CMD_POSITIONJUMP;
break;
// 28: Set Speed
case 28:
m->command = CMD_SPEED;
break;
// 31: Volume Control
case 31:
if (param <= 0x40) m->command = CMD_VOLUME; else
if (param <= 0x50) { m->command = CMD_VOLUMESLIDE; m->param &= 0x0F; if (!m->param) m->param = 0x0F; } else
if (param <= 0x60) { m->command = CMD_VOLUMESLIDE; m->param = (param & 0x0F) << 4; if (!m->param) m->param = 0xF0; } else
if (param <= 0x70) { m->command = CMD_MODCMDEX; m->param = 0xB0 | (param & 0x0F); if (!(param & 0x0F)) m->param = 0xBF; } else
if (param <= 0x80) { m->command = CMD_MODCMDEX; m->param = 0xA0 | (param & 0x0F); if (!(param & 0x0F)) m->param = 0xAF; }
break;
}
}
}
npat++;
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
}
// SBOD
UINT nsmp = 1;
while ((dwMemPos+10 < dwMemLength) && (*((DWORD *)(lpStream + dwMemPos)) == 0x444F4253))
{
if (nsmp < MAX_SAMPLES) ReadSample(&Ins[nsmp], RS_PCM8S, (LPSTR)(lpStream+dwMemPos+8), dwMemLength-dwMemPos-8);
dwMemPos += bswapBE32(*((DWORD *)(lpStream + dwMemPos + 4))) + 8;
nsmp++;
}
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
#ifndef LOAD_PAT_H
#define LOAD_PAT_H
#ifdef __cplusplus
extern "C" {
#endif
void pat_init_patnames(void);
void pat_resetsmp(void);
int pat_numinstr(void);
int pat_numsmp(void);
int pat_smptogm(int smp);
int pat_gmtosmp(int gm);
int pat_gm_drumnr(int n);
int pat_gm_drumnote(int n);
const char *pat_gm_name(int gm);
int pat_modnote(int midinote);
int pat_smplooped(int smp);
BOOL PAT_Load_Instruments(void *c);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,866 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
///////////////////////////////////////////////////
//
// PSM module loader
//
///////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#define PSM_LOG
#define PSM_ID_NEW 0x204d5350
#define PSM_ID_OLD 0xfe4d5350
#define IFFID_FILE 0x454c4946
#define IFFID_TITL 0x4c544954
#define IFFID_SDFT 0x54464453
#define IFFID_PBOD 0x444f4250
#define IFFID_SONG 0x474e4f53
#define IFFID_PATT 0x54544150
#define IFFID_DSMP 0x504d5344
#define IFFID_OPLH 0x484c504f
#pragma pack(1)
typedef struct _PSMCHUNK
{
DWORD id;
DWORD len;
DWORD listid;
} PSMCHUNK;
void swap_PSMCHUNK(PSMCHUNK* p){
p->id = bswapLE32(p->id);
p->len = bswapLE32(p->len);
p->listid = bswapLE32(p->listid);
}
typedef struct _PSMSONGHDR
{
CHAR songname[8]; // "MAINSONG"
BYTE reserved1;
BYTE reserved2;
BYTE channels;
} PSMSONGHDR;
typedef struct _PSMPATTERN
{
DWORD size;
DWORD name;
WORD rows;
WORD reserved1;
BYTE data[4];
} PSMPATTERN;
void swap_PSMPATTERN(PSMPATTERN* p){
p->size = bswapLE32(p->size);
p->name = bswapLE32(p->name);
p->rows = bswapLE16(p->rows);
}
typedef struct _PSMSAMPLE
{
BYTE flags;
CHAR songname[8];
DWORD smpid;
CHAR samplename[34];
DWORD reserved1;
BYTE reserved2;
BYTE insno;
BYTE reserved3;
DWORD length;
DWORD loopstart;
DWORD loopend;
WORD reserved4;
BYTE defvol;
DWORD reserved5;
DWORD samplerate;
BYTE reserved6[19];
} PSMSAMPLE;
#pragma pack()
static void swap_PSMSAMPLE(PSMSAMPLE* p){
p->smpid = bswapLE32(p->smpid);
p->length = bswapLE32(p->length);
p->loopstart = bswapLE32(p->loopstart);
p->loopend = bswapLE32(p->loopend);
p->samplerate = bswapLE32(p->samplerate);
}
BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
PSMCHUNK pfh = *(const PSMCHUNK *)lpStream;
DWORD dwMemPos, dwSongPos;
DWORD smpnames[MAX_SAMPLES];
DWORD patptrs[MAX_PATTERNS];
BYTE samplemap[MAX_SAMPLES];
UINT nPatterns;
if (dwMemLength < 256) return FALSE;
// Swap chunk
swap_PSMCHUNK(&pfh);
// Chunk0: "PSM ",filesize,"FILE"
if (pfh.id == PSM_ID_OLD)
{
#ifdef PSM_LOG
Log("Old PSM format not supported\n");
#endif
return FALSE;
}
if ((pfh.id != PSM_ID_NEW) || (pfh.len+12 > dwMemLength) || (pfh.listid != IFFID_FILE)) return FALSE;
m_nType = MOD_TYPE_PSM;
m_nChannels = 16;
m_nSamples = 0;
nPatterns = 0;
dwMemPos = 12;
dwSongPos = 0;
for (UINT iChPan=0; iChPan<16; iChPan++)
{
UINT pan = (((iChPan & 3) == 1) || ((iChPan&3)==2)) ? 0xC0 : 0x40;
ChnSettings[iChPan].nPan = pan;
}
while (dwMemPos+8 < dwMemLength)
{
PSMCHUNK pchunk = *(const PSMCHUNK *)(lpStream+dwMemPos);
swap_PSMCHUNK(&pchunk);
if ((pchunk.len >= dwMemLength - 8) || (dwMemPos + pchunk.len + 8 > dwMemLength)) break;
dwMemPos += 8;
PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
ULONG len = pchunk.len;
if (len) switch(pchunk.id)
{
// "TITL": Song title
case IFFID_TITL:
if (!pdata[0]) { pdata++; len--; }
memcpy(m_szNames[0], pdata, (len>31) ? 31 : len);
m_szNames[0][31] = 0;
break;
// "PBOD": Pattern
case IFFID_PBOD:
if ((len >= 12) && (nPatterns < MAX_PATTERNS))
{
patptrs[nPatterns++] = dwMemPos-8;
}
break;
// "SONG": Song description
case IFFID_SONG:
if ((len >= sizeof(PSMSONGHDR)+8) && (!dwSongPos))
{
dwSongPos = dwMemPos - 8;
}
break;
// "DSMP": Sample Data
case IFFID_DSMP:
if ((len >= sizeof(PSMSAMPLE)) && (m_nSamples+1 < MAX_SAMPLES))
{
m_nSamples++;
MODINSTRUMENT *pins = &Ins[m_nSamples];
PSMSAMPLE psmp = *(PSMSAMPLE *)pdata;
swap_PSMSAMPLE(&psmp);
smpnames[m_nSamples] = psmp.smpid;
memcpy(m_szNames[m_nSamples], psmp.samplename, 31);
m_szNames[m_nSamples][31] = 0;
samplemap[m_nSamples-1] = (BYTE)m_nSamples;
// Init sample
pins->nGlobalVol = 0x40;
pins->nC4Speed = psmp.samplerate;
pins->nLength = psmp.length;
pins->nLoopStart = psmp.loopstart;
pins->nLoopEnd = psmp.loopend;
pins->nPan = 128;
pins->nVolume = (psmp.defvol+1) * 2;
pins->uFlags = (psmp.flags & 0x80) ? CHN_LOOP : 0;
if (pins->nLoopStart > 0) pins->nLoopStart--;
// Point to sample data
pdata += 0x60;
len -= 0x60;
// Load sample data
if ((pins->nLength > 3) && (len > 3))
{
ReadSample(pins, RS_PCM8D, (LPCSTR)pdata, len);
} else
{
pins->nLength = 0;
}
}
break;
#if 0
default:
{
CHAR s[8], s2[64];
*(DWORD *)s = pchunk.id;
s[4] = 0;
wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk.len, dwMemPos);
OutputDebugString(s2);
}
#endif
}
dwMemPos += pchunk.len;
}
// Step #1: convert song structure
const PSMSONGHDR *pSong = (const PSMSONGHDR *)(lpStream+dwSongPos+8);
if ((!dwSongPos) || (pSong->channels < 2) || (pSong->channels > 32)) return TRUE;
m_nChannels = pSong->channels;
// Valid song header -> convert attached chunks
{
DWORD dwSongEnd = dwSongPos + 8 + *(DWORD *)(lpStream+dwSongPos+4);
dwMemPos = dwSongPos + 8 + 11; // sizeof(PSMCHUNK)+sizeof(PSMSONGHDR)
while (dwMemPos + 8 < dwSongEnd)
{
PSMCHUNK pchunk = *(const PSMCHUNK *)(lpStream+dwMemPos);
swap_PSMCHUNK(&pchunk);
dwMemPos += 8;
if ((pchunk.len > dwSongEnd) || (dwMemPos + pchunk.len > dwSongEnd)) break;
PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos);
ULONG len = pchunk.len;
switch(pchunk.id)
{
case IFFID_OPLH:
if (len >= 0x20)
{
UINT pos = len - 3;
while (pos > 5)
{
BOOL bFound = FALSE;
pos -= 5;
DWORD dwName = *(DWORD *)(pdata+pos);
for (UINT i=0; i<nPatterns; i++)
{
DWORD dwPatName = ((const PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
if (dwName == dwPatName)
{
bFound = TRUE;
break;
}
}
if ((!bFound) && (pdata[pos+1] > 0) && (pdata[pos+1] <= 0x10)
&& (pdata[pos+3] > 0x40) && (pdata[pos+3] < 0xC0))
{
m_nDefaultSpeed = pdata[pos+1];
m_nDefaultTempo = pdata[pos+3];
break;
}
}
UINT iOrd = 0;
while ((pos+5<len) && (iOrd < MAX_ORDERS))
{
DWORD dwName = *(DWORD *)(pdata+pos);
for (UINT i=0; i<nPatterns; i++)
{
DWORD dwPatName = ((const PSMPATTERN *)(lpStream+patptrs[i]+8))->name;
if (dwName == dwPatName)
{
Order[iOrd++] = i;
break;
}
}
pos += 5;
}
}
break;
}
dwMemPos += pchunk.len;
}
}
// Step #2: convert patterns
for (UINT nPat=0; nPat<nPatterns; nPat++)
{
PSMPATTERN pPsmPat = *(const PSMPATTERN *)(lpStream+patptrs[nPat]+8);
swap_PSMPATTERN(&pPsmPat);
ULONG len = *(DWORD *)(lpStream+patptrs[nPat]+4) - 12;
UINT nRows = pPsmPat.rows;
if (len > pPsmPat.size) len = pPsmPat.size;
if ((nRows < 64) || (nRows > 256)) nRows = 64;
PatternSize[nPat] = nRows;
if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break;
MODCOMMAND *m = Patterns[nPat];
BYTE *p = pPsmPat.data;
MODCOMMAND *sp, dummy;
UINT pos = 0;
UINT row = 0;
UINT rowlim;
#ifdef PSM_LOG
Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream));
#endif
UINT flags, ch;
rowlim = bswapLE16(pPsmPat.reserved1)-2;
while ((row < nRows) && (pos+3 < len))
{
if ((pos+1) >= rowlim) {
pos = rowlim;
rowlim = (((int)p[pos+1])<<8)
| ((int)p[pos+0]);
m += m_nChannels;
row++;
rowlim += pos;
pos += 2;
}
if (row >= nRows) continue;
flags = p[pos++];
ch = p[pos++];
if (ch >= m_nChannels) {
sp = &dummy;
} else {
sp = &m[ch];
}
// Note + Instr
if ((flags & 0x80) && (pos+1 < len))
{
UINT note = p[pos++];
note = (note>>4)*12+(note&0x0f)+12+1;
if (note > 0x80) note = 0;
sp->note = note;
}
if ((flags & 0x40) && (pos+1 < len))
{
UINT nins = p[pos++];
#ifdef PSM_LOG
//if (!nPat) Log("note+ins: %02X.%02X\n", note, nins);
if ((!nPat) && (nins >= m_nSamples)) Log("WARNING: invalid instrument number (%d)\n", nins);
#endif
sp->instr = samplemap[nins];
}
// Volume
if ((flags & 0x20) && (pos < len))
{
sp->volcmd = VOLCMD_VOLUME;
sp->vol = p[pos++] / 2;
}
// Effect
if ((flags & 0x10) && (pos+1 < len))
{
UINT command = p[pos++];
UINT param = p[pos++];
// Convert effects
switch(command)
{
// 01: fine volslide up
case 0x01: command = CMD_VOLUMESLIDE; param |= 0x0f;
if (param == 15) param=31;
break;
// 02: volslide up
case 0x02: command = CMD_VOLUMESLIDE; param>>=1; param<<=4; break;
// 03: fine volslide down
case 0x03: command = CMD_VOLUMESLIDE; param>>=4; param |= 0xf0;
if (param == 240) param=241;
break;
// 04: fine volslide down
case 0x04: command = CMD_VOLUMESLIDE; param>>=4; param |= 0xf0; break;
// 0C: portamento up
case 0x0C: command = CMD_PORTAMENTOUP; param = (param+1)/2; break;
// 0E: portamento down
case 0x0E: command = CMD_PORTAMENTODOWN; param = (param+1)/2; break;
// 0F: tone portamento
case 0x0F: command = CMD_TONEPORTAMENTO; param = param/4; break;
// 15: vibrato
case 0x15: command = CMD_VIBRATO; break;
// 29: sample offset
case 0x29: pos += 2; break;
// 2A: retrigger note
case 0x2A: command = CMD_RETRIG; break;
// 33: Position Jump
case 0x33: command = CMD_POSITIONJUMP; break;
// 34: Pattern break
case 0x34: command = CMD_PATTERNBREAK; break;
// 3D: speed
case 0x3D: command = CMD_SPEED; break;
// 3E: tempo
case 0x3E: command = CMD_TEMPO; break;
// Unknown
default:
#ifdef PSM_LOG
Log("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param);
#endif
command = param = 0;
}
sp->command = (BYTE)command;
sp->param = (BYTE)param;
}
}
#ifdef PSM_LOG
if (pos < len)
{
Log("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat.rows, pPsmPat.size, len-pos);
}
#endif
}
// Done (finally!)
return TRUE;
}
//////////////////////////////////////////////////////////////
//
// PSM Old Format
//
/*
CONST
c_PSM_MaxOrder = $FF;
c_PSM_MaxSample = $FF;
c_PSM_MaxChannel = $0F;
TYPE
PPSM_Header = ^TPSM_Header;
TPSM_Header = RECORD
PSM_Sign : ARRAY[01..04] OF CHAR; { PSM + #254 }
PSM_SongName : ARRAY[01..58] OF CHAR;
PSM_Byte00 : BYTE;
PSM_Byte1A : BYTE;
PSM_Unknown00 : BYTE;
PSM_Unknown01 : BYTE;
PSM_Unknown02 : BYTE;
PSM_Speed : BYTE;
PSM_Tempo : BYTE;
PSM_Unknown03 : BYTE;
PSM_Unknown04 : WORD;
PSM_OrderLength : WORD;
PSM_PatternNumber : WORD;
PSM_SampleNumber : WORD;
PSM_ChannelNumber : WORD;
PSM_ChannelUsed : WORD;
PSM_OrderPosition : LONGINT;
PSM_ChannelSettingPosition : LONGINT;
PSM_PatternPosition : LONGINT;
PSM_SamplePosition : LONGINT;
{ *** perhaps there are some more infos in a larger header,
but i have not decoded it and so it apears here NOT }
END;
PPSM_Sample = ^TPSM_Sample;
TPSM_Sample = RECORD
PSM_SampleFileName : ARRAY[01..12] OF CHAR;
PSM_SampleByte00 : BYTE;
PSM_SampleName : ARRAY[01..22] OF CHAR;
PSM_SampleUnknown00 : ARRAY[01..02] OF BYTE;
PSM_SamplePosition : LONGINT;
PSM_SampleUnknown01 : ARRAY[01..04] OF BYTE;
PSM_SampleNumber : BYTE;
PSM_SampleFlags : WORD;
PSM_SampleLength : LONGINT;
PSM_SampleLoopBegin : LONGINT;
PSM_SampleLoopEnd : LONGINT;
PSM_Unknown03 : BYTE;
PSM_SampleVolume : BYTE;
PSM_SampleC5Speed : WORD;
END;
PPSM_SampleList = ^TPSM_SampleList;
TPSM_SampleList = ARRAY[01..c_PSM_MaxSample] OF TPSM_Sample;
PPSM_Order = ^TPSM_Order;
TPSM_Order = ARRAY[00..c_PSM_MaxOrder] OF BYTE;
PPSM_ChannelSettings = ^TPSM_ChannelSettings;
TPSM_ChannelSettings = ARRAY[00..c_PSM_MaxChannel] OF BYTE;
CONST
PSM_NotesInPattern : BYTE = $00;
PSM_ChannelInPattern : BYTE = $00;
CONST
c_PSM_SetSpeed = 60;
FUNCTION PSM_Size(FileName : STRING;FilePosition : LONGINT) : LONGINT;
BEGIN
END;
PROCEDURE PSM_UnpackPattern(VAR Source,Destination;PatternLength : WORD);
VAR
Witz : ARRAY[00..04] OF WORD;
I1,I2 : WORD;
I3,I4 : WORD;
TopicalByte : ^BYTE;
Pattern : PUnpackedPattern;
ChannelP : BYTE;
NoteP : BYTE;
InfoByte : BYTE;
CodeByte : BYTE;
InfoWord : WORD;
Effect : BYTE;
Opperand : BYTE;
Panning : BYTE;
Volume : BYTE;
PrevInfo : BYTE;
InfoIndex : BYTE;
BEGIN
Pattern := @Destination;
TopicalByte := @Source;
{ *** Initialize patttern }
FOR I2 := 0 TO c_Maximum_NoteIndex DO
FOR I3 := 0 TO c_Maximum_ChannelIndex DO
BEGIN
Pattern^[I2,I3,c_Pattern_NoteIndex] := $FF;
Pattern^[I2,I3,c_Pattern_SampleIndex] := $00;
Pattern^[I2,I3,c_Pattern_VolumeIndex] := $FF;
Pattern^[I2,I3,c_Pattern_PanningIndex] := $FF;
Pattern^[I2,I3,c_Pattern_EffectIndex] := $00;
Pattern^[I2,I3,c_Pattern_OpperandIndex] := $00;
END;
{ *** Byte-pointer on first pattern-entry }
ChannelP := $00;
NoteP := $00;
InfoByte := $00;
PrevInfo := $00;
InfoIndex := $02;
{ *** read notes in pattern }
PSM_NotesInPattern := TopicalByte^; INC(TopicalByte); DEC(PatternLength); INC(InfoIndex);
PSM_ChannelInPattern := TopicalByte^; INC(TopicalByte); DEC(PatternLength); INC(InfoIndex);
{ *** unpack pattern }
WHILE (INTEGER(PatternLength) > 0) AND (NoteP < c_Maximum_NoteIndex) DO
BEGIN
{ *** Read info-byte }
InfoByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength); INC(InfoIndex);
IF InfoByte <> $00 THEN
BEGIN
ChannelP := InfoByte AND $0F;
IF InfoByte AND 128 = 128 THEN { note and sample }
BEGIN
{ *** read note }
CodeByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
DEC(CodeByte);
CodeByte := CodeByte MOD 12 * 16 + CodeByte DIV 12 + 2;
Pattern^[NoteP,ChannelP,c_Pattern_NoteIndex] := CodeByte;
{ *** read sample }
CodeByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
Pattern^[NoteP,ChannelP,c_Pattern_SampleIndex] := CodeByte;
END;
IF InfoByte AND 64 = 64 THEN { Volume }
BEGIN
CodeByte := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
Pattern^[NoteP,ChannelP,c_Pattern_VolumeIndex] := CodeByte;
END;
IF InfoByte AND 32 = 32 THEN { effect AND opperand }
BEGIN
Effect := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
Opperand := TopicalByte^; INC(TopicalByte); DEC(PatternLength);
CASE Effect OF
c_PSM_SetSpeed:
BEGIN
Effect := c_I_Set_Speed;
END;
ELSE
BEGIN
Effect := c_I_NoEffect;
Opperand := $00;
END;
END;
Pattern^[NoteP,ChannelP,c_Pattern_EffectIndex] := Effect;
Pattern^[NoteP,ChannelP,c_Pattern_OpperandIndex] := Opperand;
END;
END ELSE INC(NoteP);
END;
END;
PROCEDURE PSM_Load(FileName : STRING;FilePosition : LONGINT;VAR Module : PModule;VAR ErrorCode : WORD);
{ *** caution : Module has to be inited before!!!! }
VAR
Header : PPSM_Header;
Sample : PPSM_SampleList;
Order : PPSM_Order;
ChannelSettings : PPSM_ChannelSettings;
MultiPurposeBuffer : PByteArray;
PatternBuffer : PUnpackedPattern;
TopicalParaPointer : WORD;
InFile : FILE;
I1,I2 : WORD;
I3,I4 : WORD;
TempW : WORD;
TempB : BYTE;
TempP : PByteArray;
TempI : INTEGER;
{ *** copy-vars for loop-extension }
CopySource : LONGINT;
CopyDestination : LONGINT;
CopyLength : LONGINT;
BEGIN
{ *** try to open file }
ASSIGN(InFile,FileName);
{$I-}
RESET(InFile,1);
{$I+}
IF IORESULT <> $00 THEN
BEGIN
EXIT;
END;
{$I-}
{ *** seek start of module }
IF FILESIZE(InFile) < FilePosition THEN
BEGIN
EXIT;
END;
SEEK(InFile,FilePosition);
{ *** look for enough memory for temporary variables }
IF MEMAVAIL < SIZEOF(TPSM_Header) + SIZEOF(TPSM_SampleList) +
SIZEOF(TPSM_Order) + SIZEOF(TPSM_ChannelSettings) +
SIZEOF(TByteArray) + SIZEOF(TUnpackedPattern)
THEN
BEGIN
EXIT;
END;
{ *** init dynamic variables }
NEW(Header);
NEW(Sample);
NEW(Order);
NEW(ChannelSettings);
NEW(MultiPurposeBuffer);
NEW(PatternBuffer);
{ *** read header }
BLOCKREAD(InFile,Header^,SIZEOF(TPSM_Header));
{ *** test if this is a DSM-file }
IF NOT ((Header^.PSM_Sign[1] = 'P') AND (Header^.PSM_Sign[2] = 'S') AND
(Header^.PSM_Sign[3] = 'M') AND (Header^.PSM_Sign[4] = #254)) THEN
BEGIN
ErrorCode := c_NoValidFileFormat;
CLOSE(InFile);
EXIT;
END;
{ *** read order }
SEEK(InFile,FilePosition + Header^.PSM_OrderPosition);
BLOCKREAD(InFile,Order^,Header^.PSM_OrderLength);
{ *** read channelsettings }
SEEK(InFile,FilePosition + Header^.PSM_ChannelSettingPosition);
BLOCKREAD(InFile,ChannelSettings^,SIZEOF(TPSM_ChannelSettings));
{ *** read samplelist }
SEEK(InFile,FilePosition + Header^.PSM_SamplePosition);
BLOCKREAD(InFile,Sample^,Header^.PSM_SampleNumber * SIZEOF(TPSM_Sample));
{ *** copy header to intern NTMIK-structure }
Module^.Module_Sign := 'MF';
Module^.Module_FileFormatVersion := $0100;
Module^.Module_SampleNumber := Header^.PSM_SampleNumber;
Module^.Module_PatternNumber := Header^.PSM_PatternNumber;
Module^.Module_OrderLength := Header^.PSM_OrderLength;
Module^.Module_ChannelNumber := Header^.PSM_ChannelNumber+1;
Module^.Module_Initial_GlobalVolume := 64;
Module^.Module_Initial_MasterVolume := $C0;
Module^.Module_Initial_Speed := Header^.PSM_Speed;
Module^.Module_Initial_Tempo := Header^.PSM_Tempo;
{ *** paragraph 01 start }
Module^.Module_Flags := c_Module_Flags_ZeroVolume * BYTE(1) +
c_Module_Flags_Stereo * BYTE(1) +
c_Module_Flags_ForceAmigaLimits * BYTE(0) +
c_Module_Flags_Panning * BYTE(1) +
c_Module_Flags_Surround * BYTE(1) +
c_Module_Flags_QualityMixing * BYTE(1) +
c_Module_Flags_FastVolumeSlides * BYTE(0) +
c_Module_Flags_SpecialCustomData * BYTE(0) +
c_Module_Flags_SongName * BYTE(1);
I1 := $01;
WHILE (Header^.PSM_SongName[I1] > #00) AND (I1 < c_Module_SongNameLength) DO
BEGIN
Module^.Module_Name[I1] := Header^.PSM_SongName[I1];
INC(I1);
END;
Module^.Module_Name[c_Module_SongNameLength] := #00;
{ *** Init channelsettings }
FOR I1 := 0 TO c_Maximum_ChannelIndex DO
BEGIN
IF I1 < Header^.PSM_ChannelUsed THEN
BEGIN
{ *** channel enabled }
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_GlobalVolume := 64;
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Panning := (ChannelSettings^[I1]) * $08;
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Code := I1 + $10 * BYTE(ChannelSettings^[I1] > $08) +
c_ChannelSettings_Code_ChannelEnabled * BYTE(1) +
c_ChannelSettings_Code_ChannelDigital * BYTE(1);
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Controls :=
c_ChannelSettings_Controls_EnhancedMode * BYTE(1) +
c_ChannelSettings_Controls_SurroundMode * BYTE(0);
END
ELSE
BEGIN
{ *** channel disabled }
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_GlobalVolume := $00;
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Panning := $00;
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Code := $00;
Module^.Module_ChannelSettingPointer^[I1].ChannelSettings_Controls := $00;
END;
END;
{ *** init and copy order }
FILLCHAR(Module^.Module_OrderPointer^,c_Maximum_OrderIndex+1,$FF);
MOVE(Order^,Module^.Module_OrderPointer^,Header^.PSM_OrderLength);
{ *** read pattern }
SEEK(InFile,FilePosition + Header^.PSM_PatternPosition);
NTMIK_LoaderPatternNumber := Header^.PSM_PatternNumber-1;
FOR I1 := 0 TO Header^.PSM_PatternNumber-1 DO
BEGIN
NTMIK_LoadPatternProcedure;
{ *** read length }
BLOCKREAD(InFile,TempW,2);
{ *** read pattern }
BLOCKREAD(InFile,MultiPurposeBuffer^,TempW-2);
{ *** unpack pattern and set notes per channel to 64 }
PSM_UnpackPattern(MultiPurposeBuffer^,PatternBuffer^,TempW);
NTMIK_PackPattern(MultiPurposeBuffer^,PatternBuffer^,PSM_NotesInPattern);
TempW := WORD(256) * MultiPurposeBuffer^[01] + MultiPurposeBuffer^[00];
GETMEM(Module^.Module_PatternPointer^[I1],TempW);
MOVE(MultiPurposeBuffer^,Module^.Module_PatternPointer^[I1]^,TempW);
{ *** next pattern }
END;
{ *** read samples }
NTMIK_LoaderSampleNumber := Header^.PSM_SampleNumber;
FOR I1 := 1 TO Header^.PSM_SampleNumber DO
BEGIN
NTMIK_LoadSampleProcedure;
{ *** get index for sample }
I3 := Sample^[I1].PSM_SampleNumber;
{ *** clip PSM-sample }
IF Sample^[I1].PSM_SampleLoopEnd > Sample^[I1].PSM_SampleLength
THEN Sample^[I1].PSM_SampleLoopEnd := Sample^[I1].PSM_SampleLength;
{ *** init intern sample }
NEW(Module^.Module_SamplePointer^[I3]);
FILLCHAR(Module^.Module_SamplePointer^[I3]^,SIZEOF(TSample),$00);
FILLCHAR(Module^.Module_SamplePointer^[I3]^.Sample_SampleName,c_Sample_SampleNameLength,#32);
FILLCHAR(Module^.Module_SamplePointer^[I3]^.Sample_FileName,c_Sample_FileNameLength,#32);
{ *** copy informations to intern sample }
I2 := $01;
WHILE (Sample^[I1].PSM_SampleName[I2] > #00) AND (I2 < c_Sample_SampleNameLength) DO
BEGIN
Module^.Module_SamplePointer^[I3]^.Sample_SampleName[I2] := Sample^[I1].PSM_SampleName[I2];
INC(I2);
END;
Module^.Module_SamplePointer^[I3]^.Sample_Sign := 'DF';
Module^.Module_SamplePointer^[I3]^.Sample_FileFormatVersion := $00100;
Module^.Module_SamplePointer^[I3]^.Sample_Position := $00000000;
Module^.Module_SamplePointer^[I3]^.Sample_Selector := $0000;
Module^.Module_SamplePointer^[I3]^.Sample_Volume := Sample^[I1].PSM_SampleVolume;
Module^.Module_SamplePointer^[I3]^.Sample_LoopCounter := $00;
Module^.Module_SamplePointer^[I3]^.Sample_C5Speed := Sample^[I1].PSM_SampleC5Speed;
Module^.Module_SamplePointer^[I3]^.Sample_Length := Sample^[I1].PSM_SampleLength;
Module^.Module_SamplePointer^[I3]^.Sample_LoopBegin := Sample^[I1].PSM_SampleLoopBegin;
Module^.Module_SamplePointer^[I3]^.Sample_LoopEnd := Sample^[I1].PSM_SampleLoopEnd;
{ *** now it's time for the flags }
Module^.Module_SamplePointer^[I3]^.Sample_Flags :=
c_Sample_Flags_DigitalSample * BYTE(1) +
c_Sample_Flags_8BitSample * BYTE(1) +
c_Sample_Flags_UnsignedSampleData * BYTE(1) +
c_Sample_Flags_Packed * BYTE(0) +
c_Sample_Flags_LoopCounter * BYTE(0) +
c_Sample_Flags_SampleName * BYTE(1) +
c_Sample_Flags_LoopActive *
BYTE(Sample^[I1].PSM_SampleFlags AND (LONGINT(1) SHL 15) = (LONGINT(1) SHL 15));
{ *** alloc memory for sample-data }
E_Getmem(Module^.Module_SamplePointer^[I3]^.Sample_Selector,
Module^.Module_SamplePointer^[I3]^.Sample_Position,
Module^.Module_SamplePointer^[I3]^.Sample_Length + c_LoopExtensionSize);
{ *** read out data }
EPT(TempP).p_Selector := Module^.Module_SamplePointer^[I3]^.Sample_Selector;
EPT(TempP).p_Offset := $0000;
SEEK(InFile,Sample^[I1].PSM_SamplePosition);
E_BLOCKREAD(InFile,TempP^,Module^.Module_SamplePointer^[I3]^.Sample_Length);
{ *** 'coz the samples are signed in a DSM-file -> PC-fy them }
IF Module^.Module_SamplePointer^[I3]^.Sample_Length > 4 THEN
BEGIN
CopyLength := Module^.Module_SamplePointer^[I3]^.Sample_Length;
{ *** decode sample }
ASM
DB 066h; MOV CX,WORD PTR CopyLength
{ *** load sample selector }
MOV ES,WORD PTR TempP[00002h]
DB 066h; XOR SI,SI
DB 066h; XOR DI,DI
XOR AH,AH
{ *** conert all bytes }
@@MainLoop:
DB 026h; DB 067h; LODSB
ADD AL,AH
MOV AH,AL
DB 067h; STOSB
DB 066h; LOOP @@MainLoop
END;
{ *** make samples unsigned }
ASM
DB 066h; MOV CX,WORD PTR CopyLength
{ *** load sample selector }
MOV ES,WORD PTR TempP[00002h]
DB 066h; XOR SI,SI
DB 066h; XOR DI,DI
{ *** conert all bytes }
@@MainLoop:
DB 026h; DB 067h; LODSB
SUB AL,080h
DB 067h; STOSB
DB 066h; LOOP @@MainLoop
END;
{ *** Create Loop-Extension }
IF Module^.Module_SamplePointer^[I3]^.Sample_Flags AND c_Sample_Flags_LoopActive = c_Sample_Flags_LoopActive THEN
BEGIN
CopySource := Module^.Module_SamplePointer^[I3]^.Sample_LoopBegin;
CopyDestination := Module^.Module_SamplePointer^[I3]^.Sample_LoopEnd;
CopyLength := CopyDestination - CopySource;
ASM
{ *** load sample-selector }
MOV ES,WORD PTR TempP[00002h]
DB 066h; MOV DI,WORD PTR CopyDestination
{ *** calculate number of full sample-loops to copy }
XOR DX,DX
MOV AX,c_LoopExtensionSize
MOV BX,WORD PTR CopyLength
DIV BX
OR AX,AX
JE @@NoFullLoop
{ *** copy some full-loops (size=bx) }
MOV CX,AX
@@InnerLoop:
PUSH CX
DB 066h; MOV SI,WORD PTR CopySource
MOV CX,BX
DB 0F3h; DB 026h,067h,0A4h { REP MOVS BYTE PTR ES:[EDI],ES:[ESI] }
POP CX
LOOP @@InnerLoop
@@NoFullLoop:
{ *** calculate number of rest-bytes to copy }
DB 066h; MOV SI,WORD PTR CopySource
MOV CX,DX
DB 0F3h; DB 026h,067h,0A4h { REP MOVS BYTE PTR ES:[EDI],ES:[ESI] }
END;
END
ELSE
BEGIN
CopyDestination := Module^.Module_SamplePointer^[I3]^.Sample_Length;
ASM
{ *** load sample-selector }
MOV ES,WORD PTR TempP[00002h]
DB 066h; MOV DI,WORD PTR CopyDestination
{ *** clear extension }
MOV CX,c_LoopExtensionSize
MOV AL,080h
DB 0F3h; DB 067h,0AAh { REP STOS BYTE PTR ES:[EDI] }
END;
END;
END;
{ *** next sample }
END;
{ *** init period-ranges }
NTMIK_MaximumPeriod := $0000D600 SHR 1;
NTMIK_MinimumPeriod := $0000D600 SHR 8;
{ *** close file }
CLOSE(InFile);
{ *** dispose all dynamic variables }
DISPOSE(Header);
DISPOSE(Sample);
DISPOSE(Order);
DISPOSE(ChannelSettings);
DISPOSE(MultiPurposeBuffer);
DISPOSE(PatternBuffer);
{ *** set errorcode to noerror }
ErrorCode := c_NoError;
END;
*/

View File

@ -0,0 +1,212 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
//////////////////////////////////////////////
// PTM PolyTracker module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct PTMFILEHEADER
{
CHAR songname[28]; // name of song, asciiz string
CHAR eof; // 26
BYTE version_lo; // 03 version of file, currently 0203h
BYTE version_hi; // 02
BYTE reserved1; // reserved, set to 0
WORD norders; // number of orders (0..256)
WORD nsamples; // number of instruments (1..255)
WORD npatterns; // number of patterns (1..128)
WORD nchannels; // number of channels (voices) used (1..32)
WORD fileflags; // set to 0
WORD reserved2; // reserved, set to 0
DWORD ptmf_id; // song identification, 'PTMF' or 0x464d5450
BYTE reserved3[16]; // reserved, set to 0
BYTE chnpan[32]; // channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
BYTE orders[256]; // order list, valid entries 0..nOrders-1
WORD patseg[128]; // pattern offsets (*16)
} PTMFILEHEADER, *LPPTMFILEHEADER;
#define SIZEOF_PTMFILEHEADER 608
typedef struct PTMSAMPLE
{
BYTE sampletype; // sample type (bit array)
CHAR filename[12]; // name of external sample file
BYTE volume; // default volume
WORD nC4Spd; // C4 speed
WORD sampleseg; // sample segment (used internally)
WORD fileofs[2]; // offset of sample data
WORD length[2]; // sample size (in bytes)
WORD loopbeg[2]; // start of loop
WORD loopend[2]; // end of loop
WORD gusdata[8];
char samplename[28]; // name of sample, asciiz // changed from CHAR
DWORD ptms_id; // sample identification, 'PTMS' or 0x534d5450
} PTMSAMPLE;
#define SIZEOF_PTMSAMPLE 80
#pragma pack()
static uint32_t BS2WORD(uint16_t w[2]) {
uint32_t u32 = (w[1] << 16) + w[0];
return(bswapLE32(u32));
}
BOOL CSoundFile::ReadPTM(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
DWORD dwMemPos;
UINT nOrders;
if ((!lpStream) || (dwMemLength < sizeof(PTMFILEHEADER))) return FALSE;
PTMFILEHEADER pfh = *(LPPTMFILEHEADER)lpStream;
pfh.norders = bswapLE16(pfh.norders);
pfh.nsamples = bswapLE16(pfh.nsamples);
pfh.npatterns = bswapLE16(pfh.npatterns);
pfh.nchannels = bswapLE16(pfh.nchannels);
pfh.fileflags = bswapLE16(pfh.fileflags);
pfh.reserved2 = bswapLE16(pfh.reserved2);
pfh.ptmf_id = bswapLE32(pfh.ptmf_id);
for (UINT j=0; j<128; j++)
{
pfh.patseg[j] = bswapLE16(pfh.patseg[j]);
}
if ((pfh.ptmf_id != 0x464d5450) || (!pfh.nchannels)
|| (pfh.nchannels > 32)
|| (pfh.norders > 256) || (!pfh.norders)
|| (!pfh.nsamples) || (pfh.nsamples > 255)
|| (!pfh.npatterns) || (pfh.npatterns > 128)
|| (SIZEOF_PTMFILEHEADER+pfh.nsamples*SIZEOF_PTMSAMPLE >= (int)dwMemLength)) return FALSE;
memcpy(m_szNames[0], pfh.songname, 28);
m_szNames[0][28] = 0;
m_nType = MOD_TYPE_PTM;
m_nChannels = pfh.nchannels;
m_nSamples = (pfh.nsamples < MAX_SAMPLES) ? pfh.nsamples : MAX_SAMPLES-1;
dwMemPos = SIZEOF_PTMFILEHEADER;
nOrders = (pfh.norders < MAX_ORDERS) ? pfh.norders : MAX_ORDERS-1;
memcpy(Order, pfh.orders, nOrders);
for (UINT ipan=0; ipan<m_nChannels; ipan++)
{
ChnSettings[ipan].nVolume = 64;
ChnSettings[ipan].nPan = ((pfh.chnpan[ipan] & 0x0F) << 4) + 4;
}
for (UINT ismp=0; ismp<m_nSamples; ismp++, dwMemPos += SIZEOF_PTMSAMPLE)
{
MODINSTRUMENT *pins = &Ins[ismp+1];
PTMSAMPLE *psmp = (PTMSAMPLE *)(lpStream+dwMemPos);
lstrcpyn(m_szNames[ismp+1], psmp->samplename, 28);
memcpy(pins->name, psmp->filename, 12);
pins->name[12] = 0;
pins->nGlobalVol = 64;
pins->nPan = 128;
pins->nVolume = psmp->volume << 2;
pins->nC4Speed = bswapLE16(psmp->nC4Spd) << 1;
pins->uFlags = 0;
if ((psmp->sampletype & 3) == 1)
{
UINT smpflg = RS_PCM8D;
pins->nLength = BS2WORD(psmp->length);
pins->nLoopStart = BS2WORD(psmp->loopbeg);
pins->nLoopEnd = BS2WORD(psmp->loopend);
DWORD samplepos = BS2WORD(psmp->fileofs);
if (psmp->sampletype & 4) pins->uFlags |= CHN_LOOP;
if (psmp->sampletype & 8) pins->uFlags |= CHN_PINGPONGLOOP;
if (psmp->sampletype & 16)
{
pins->uFlags |= CHN_16BIT;
pins->nLength >>= 1;
pins->nLoopStart >>= 1;
pins->nLoopEnd >>= 1;
smpflg = RS_PTM8DTO16;
}
if ((pins->nLength) && (samplepos) && (samplepos < dwMemLength))
{
ReadSample(pins, smpflg, (LPSTR)(lpStream+samplepos), dwMemLength-samplepos);
}
}
}
// Reading Patterns
for (UINT ipat=0; ipat<pfh.npatterns; ipat++)
{
dwMemPos = ((UINT)pfh.patseg[ipat]) << 4;
if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue;
PatternSize[ipat] = 64;
if ((Patterns[ipat] = AllocatePattern(64, m_nChannels)) == NULL) break;
//
MODCOMMAND *m = Patterns[ipat];
for (UINT row=0; ((row < 64) && (dwMemPos < dwMemLength)); )
{
UINT b = lpStream[dwMemPos++];
if (dwMemPos >= dwMemLength) break;
if (b)
{
UINT nChn = b & 0x1F;
MODCOMMAND &selm = m[nChn < m_nChannels ? nChn : 0];
if (b & 0x20)
{
if (dwMemPos + 2 > dwMemLength) break;
selm.note = lpStream[dwMemPos++];
selm.instr = lpStream[dwMemPos++];
}
if (b & 0x40)
{
if (dwMemPos + 2 > dwMemLength) break;
selm.command = lpStream[dwMemPos++];
selm.param = lpStream[dwMemPos++];
if ((selm.command == 0x0E) && ((selm.param & 0xF0) == 0x80))
{
selm.command = CMD_S3MCMDEX;
} else
if (selm.command < 0x10)
{
ConvertModCommand(&selm);
} else
{
switch(selm.command)
{
case 16:
selm.command = CMD_GLOBALVOLUME;
break;
case 17:
selm.command = CMD_RETRIG;
break;
case 18:
selm.command = CMD_FINEVIBRATO;
break;
default:
selm.command = 0;
}
}
}
if (b & 0x80)
{
if (dwMemPos >= dwMemLength) break;
selm.volcmd = VOLCMD_VOLUME;
selm.vol = lpStream[dwMemPos++];
}
} else
{
row++;
m += m_nChannels;
}
}
}
return TRUE;
}

View File

@ -0,0 +1,672 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
#include "stdafx.h"
#include "sndfile.h"
#include "tables.h"
#ifdef _MSC_VER
//#pragma warning(disable:4244)
#endif
//////////////////////////////////////////////////////
// ScreamTracker S3M file support
#pragma pack(1)
typedef struct tagS3MSAMPLESTRUCT
{
BYTE type;
CHAR dosname[12];
BYTE hmem;
WORD memseg;
DWORD length;
DWORD loopbegin;
DWORD loopend;
BYTE vol;
BYTE bReserved;
BYTE pack;
BYTE flags;
DWORD finetune;
DWORD dwReserved;
WORD intgp;
WORD int512;
DWORD lastused;
CHAR name[28];
CHAR scrs[4];
} S3MSAMPLESTRUCT;
typedef struct tagS3MFILEHEADER
{
CHAR name[28];
BYTE b1A;
BYTE type;
WORD reserved1;
WORD ordnum;
WORD insnum;
WORD patnum;
WORD flags;
WORD cwtv;
WORD version;
DWORD scrm; // "SCRM" = 0x4D524353
BYTE globalvol;
BYTE speed;
BYTE tempo;
BYTE mastervol;
BYTE ultraclicks;
BYTE panning_present;
BYTE reserved2[8];
WORD special;
BYTE channels[32];
} S3MFILEHEADER;
void CSoundFile::S3MConvert(MODCOMMAND *m, BOOL bIT) const
//--------------------------------------------------------
{
UINT command = m->command;
UINT param = m->param;
switch (command + 0x40)
{
case 'A': command = CMD_SPEED; break;
case 'B': command = CMD_POSITIONJUMP; break;
case 'C': command = CMD_PATTERNBREAK; if (!bIT) param = (param >> 4) * 10 + (param & 0x0F); break;
case 'D': command = CMD_VOLUMESLIDE; break;
case 'E': command = CMD_PORTAMENTODOWN; break;
case 'F': command = CMD_PORTAMENTOUP; break;
case 'G': command = CMD_TONEPORTAMENTO; break;
case 'H': command = CMD_VIBRATO; break;
case 'I': command = CMD_TREMOR; break;
case 'J': command = CMD_ARPEGGIO; break;
case 'K': command = CMD_VIBRATOVOL; break;
case 'L': command = CMD_TONEPORTAVOL; break;
case 'M': command = CMD_CHANNELVOLUME; break;
case 'N': command = CMD_CHANNELVOLSLIDE; break;
case 'O': command = CMD_OFFSET; break;
case 'P': command = CMD_PANNINGSLIDE; break;
case 'Q': command = CMD_RETRIG; break;
case 'R': command = CMD_TREMOLO; break;
case 'S': command = CMD_S3MCMDEX; break;
case 'T': command = CMD_TEMPO; break;
case 'U': command = CMD_FINEVIBRATO; break;
case 'V': command = CMD_GLOBALVOLUME; break;
case 'W': command = CMD_GLOBALVOLSLIDE; break;
case 'X': command = CMD_PANNING8; break;
case 'Y': command = CMD_PANBRELLO; break;
case 'Z': command = CMD_MIDI; break;
default: command = 0;
}
m->command = command;
m->param = param;
}
#ifndef MODPLUG_NO_FILESAVE
void CSoundFile::S3MSaveConvert(UINT *pcmd, UINT *pprm, BOOL bIT) const
//---------------------------------------------------------------------
{
UINT command = *pcmd;
UINT param = *pprm;
switch(command)
{
case CMD_SPEED: command = 'A'; break;
case CMD_POSITIONJUMP: command = 'B'; break;
case CMD_PATTERNBREAK: command = 'C'; if (!bIT) param = ((param / 10) << 4) + (param % 10); break;
case CMD_VOLUMESLIDE: command = 'D'; break;
case CMD_PORTAMENTODOWN: command = 'E'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break;
case CMD_PORTAMENTOUP: command = 'F'; if ((param >= 0xE0) && (m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM))) param = 0xDF; break;
case CMD_TONEPORTAMENTO: command = 'G'; break;
case CMD_VIBRATO: command = 'H'; break;
case CMD_TREMOR: command = 'I'; break;
case CMD_ARPEGGIO: command = 'J'; break;
case CMD_VIBRATOVOL: command = 'K'; break;
case CMD_TONEPORTAVOL: command = 'L'; break;
case CMD_CHANNELVOLUME: command = 'M'; break;
case CMD_CHANNELVOLSLIDE: command = 'N'; break;
case CMD_OFFSET: command = 'O'; break;
case CMD_PANNINGSLIDE: command = 'P'; break;
case CMD_RETRIG: command = 'Q'; break;
case CMD_TREMOLO: command = 'R'; break;
case CMD_S3MCMDEX: command = 'S'; break;
case CMD_TEMPO: command = 'T'; break;
case CMD_FINEVIBRATO: command = 'U'; break;
case CMD_GLOBALVOLUME: command = 'V'; break;
case CMD_GLOBALVOLSLIDE: command = 'W'; break;
case CMD_PANNING8:
command = 'X';
if ((bIT) && (m_nType != MOD_TYPE_IT) && (m_nType != MOD_TYPE_XM))
{
if (param == 0xA4) { command = 'S'; param = 0x91; } else
if (param <= 0x80) { param <<= 1; if (param > 255) param = 255; } else
command = param = 0;
} else
if ((!bIT) && ((m_nType == MOD_TYPE_IT) || (m_nType == MOD_TYPE_XM)))
{
param >>= 1;
}
break;
case CMD_PANBRELLO: command = 'Y'; break;
case CMD_MIDI: command = 'Z'; break;
case CMD_XFINEPORTAUPDOWN:
if (param & 0x0F) switch(param & 0xF0)
{
case 0x10: command = 'F'; param = (param & 0x0F) | 0xE0; break;
case 0x20: command = 'E'; param = (param & 0x0F) | 0xE0; break;
case 0x90: command = 'S'; break;
default: command = param = 0;
} else command = param = 0;
break;
case CMD_MODCMDEX:
command = 'S';
switch(param & 0xF0)
{
case 0x00: command = param = 0; break;
case 0x10: command = 'F'; param |= 0xF0; break;
case 0x20: command = 'E'; param |= 0xF0; break;
case 0x30: param = (param & 0x0F) | 0x10; break;
case 0x40: param = (param & 0x0F) | 0x30; break;
case 0x50: param = (param & 0x0F) | 0x20; break;
case 0x60: param = (param & 0x0F) | 0xB0; break;
case 0x70: param = (param & 0x0F) | 0x40; break;
case 0x90: command = 'Q'; param &= 0x0F; break;
case 0xA0: if (param & 0x0F) { command = 'D'; param = (param << 4) | 0x0F; } else command=param=0; break;
case 0xB0: if (param & 0x0F) { command = 'D'; param |= 0xF0; } else command=param=0; break;
}
break;
default: command = param = 0;
}
command &= ~0x40;
*pcmd = command;
*pprm = param;
}
#endif // MODPLUG_NO_FILESAVE
static DWORD boundInput(DWORD input, DWORD smin, DWORD smax)
{
if (input > smax) input = smax;
else if (input < smin) input = 0;
return(input);
}
BOOL CSoundFile::ReadS3M(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
UINT insnum,patnum,nins,npat;
DWORD insfile[MAX_SAMPLES];
WORD ptr[256];
DWORD dwMemPos;
BYTE insflags[MAX_SAMPLES], inspack[MAX_SAMPLES];
if ((!lpStream) || (dwMemLength <= sizeof(S3MFILEHEADER)+sizeof(S3MSAMPLESTRUCT)+64)) return FALSE;
S3MFILEHEADER psfh = *(S3MFILEHEADER *)lpStream;
psfh.reserved1 = bswapLE16(psfh.reserved1);
psfh.ordnum = bswapLE16(psfh.ordnum);
psfh.insnum = bswapLE16(psfh.insnum);
psfh.patnum = bswapLE16(psfh.patnum);
psfh.flags = bswapLE16(psfh.flags);
psfh.cwtv = bswapLE16(psfh.cwtv);
psfh.version = bswapLE16(psfh.version);
psfh.scrm = bswapLE32(psfh.scrm);
psfh.special = bswapLE16(psfh.special);
if (psfh.scrm != 0x4D524353) return FALSE;
dwMemPos = 0x60;
m_nType = MOD_TYPE_S3M;
memset(m_szNames,0,sizeof(m_szNames));
memcpy(m_szNames[0], psfh.name, 28);
// Speed
m_nDefaultSpeed = psfh.speed;
if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 6;
if (m_nDefaultSpeed > 0x1F) m_nDefaultSpeed = 0x1F;
// Tempo
m_nDefaultTempo = psfh.tempo;
if (m_nDefaultTempo < 40) m_nDefaultTempo = 40;
if (m_nDefaultTempo > 240) m_nDefaultTempo = 240;
// Global Volume
m_nDefaultGlobalVolume = psfh.globalvol << 2;
if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256;
m_nSongPreAmp = psfh.mastervol & 0x7F;
// Channels
m_nChannels = 4;
for (UINT ich=0; ich<32; ich++)
{
ChnSettings[ich].nPan = 128;
ChnSettings[ich].nVolume = 64;
ChnSettings[ich].dwFlags = CHN_MUTE;
if (psfh.channels[ich] != 0xFF)
{
m_nChannels = ich+1;
UINT b = psfh.channels[ich] & 0x0F;
ChnSettings[ich].nPan = (b & 8) ? 0xC0 : 0x40;
ChnSettings[ich].dwFlags = 0;
}
}
if (m_nChannels < 4) m_nChannels = 4;
if ((psfh.cwtv < 0x1320) || (psfh.flags & 0x40)) m_dwSongFlags |= SONG_FASTVOLSLIDES;
// Reading pattern order
UINT iord = psfh.ordnum;
if (iord<1) iord = 1;
if (iord > MAX_ORDERS) iord = MAX_ORDERS;
if (iord)
{
memcpy(Order, lpStream+dwMemPos, iord);
dwMemPos += iord;
}
if ((iord & 1) && (lpStream[dwMemPos] == 0xFF)) dwMemPos++;
// Reading file pointers
insnum = nins = psfh.insnum;
if (insnum >= MAX_SAMPLES) insnum = MAX_SAMPLES-1;
m_nSamples = insnum;
patnum = npat = psfh.patnum;
if (patnum > MAX_PATTERNS) patnum = MAX_PATTERNS;
memset(ptr, 0, sizeof(ptr));
// Ignore file if it has a corrupted header.
if (nins+npat > 256) return FALSE;
if (nins+npat)
{
memcpy(ptr, lpStream+dwMemPos, 2*(nins+npat));
dwMemPos += 2*(nins+npat);
for (UINT j = 0; j < (nins+npat); ++j) {
ptr[j] = bswapLE16(ptr[j]);
}
if (psfh.panning_present == 252)
{
const BYTE *chnpan = lpStream+dwMemPos;
for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20)
{
ChnSettings[i].nPan = ((chnpan[i] & 0x0F) << 4) + 8;
}
}
}
if (!m_nChannels) return TRUE;
// Reading instrument headers
memset(insfile, 0, sizeof(insfile));
for (UINT iSmp=1; iSmp<=insnum; iSmp++)
{
UINT nInd = ((DWORD)ptr[iSmp-1])*16;
if ((!nInd) || (nInd + 0x50 > dwMemLength)) {
// initialize basic variables.
insflags[iSmp-1] = 0;
inspack[iSmp-1] = 0;
continue;
}
S3MSAMPLESTRUCT pSmp;
memcpy(&pSmp, lpStream+nInd, 0x50);
memcpy(Ins[iSmp].name, &pSmp.dosname, 12);
insflags[iSmp-1] = pSmp.flags;
inspack[iSmp-1] = pSmp.pack;
memcpy(m_szNames[iSmp], pSmp.name, 28);
m_szNames[iSmp][28] = 0;
if ((pSmp.type==1) && (pSmp.scrs[2]=='R') && (pSmp.scrs[3]=='S'))
{
Ins[iSmp].nLength = boundInput(bswapLE32(pSmp.length), 4, MAX_SAMPLE_LENGTH);
Ins[iSmp].nLoopStart = boundInput(bswapLE32(pSmp.loopbegin), 4, Ins[iSmp].nLength - 1);
Ins[iSmp].nLoopEnd = boundInput(bswapLE32(pSmp.loopend), 4, Ins[iSmp].nLength);
Ins[iSmp].nVolume = boundInput(pSmp.vol, 0, 64) << 2;
Ins[iSmp].nGlobalVol = 64;
if (pSmp.flags&1) Ins[iSmp].uFlags |= CHN_LOOP;
UINT j = bswapLE32(pSmp.finetune);
if (!j) j = 8363;
if (j < 1024) j = 1024;
Ins[iSmp].nC4Speed = j;
insfile[iSmp] = (pSmp.hmem << 20) + (bswapLE16(pSmp.memseg) << 4);
// offset is invalid - ignore this sample.
if (insfile[iSmp] > dwMemLength) insfile[iSmp] = 0;
else if (insfile[iSmp]) {
// ignore duplicate samples.
for (int z=iSmp-1; z>=0; z--)
if (insfile[iSmp] == insfile[z])
insfile[iSmp] = 0;
}
if ((Ins[iSmp].nLoopStart >= Ins[iSmp].nLoopEnd) || (Ins[iSmp].nLoopEnd - Ins[iSmp].nLoopStart < 8))
Ins[iSmp].nLoopStart = Ins[iSmp].nLoopEnd = 0;
Ins[iSmp].nPan = 0x80;
}
}
// Reading patterns
for (UINT iPat=0; iPat<patnum; iPat++)
{
UINT nInd = ((DWORD)ptr[nins+iPat]) << 4;
if (nInd + 0x40 > dwMemLength) continue;
WORD len = bswapLE16(*((WORD *)(lpStream+nInd)));
nInd += 2;
PatternSize[iPat] = 64;
if ((!len) || (nInd + len > dwMemLength - 6)
|| ((Patterns[iPat] = AllocatePattern(64, m_nChannels)) == NULL)) continue;
LPBYTE src = (LPBYTE)(lpStream+nInd);
// Unpacking pattern
MODCOMMAND *p = Patterns[iPat];
UINT row = 0;
UINT j = 0;
while (j < len)
{
BYTE b = src[j++];
if (!b)
{
if (++row >= 64) break;
} else
{
UINT chn = b & 0x1F;
if (chn < m_nChannels)
{
MODCOMMAND *m = &p[row*m_nChannels+chn];
if (b & 0x20)
{
m->note = src[j++];
if (m->note < 0xF0) m->note = (m->note & 0x0F) + 12*(m->note >> 4) + 13;
else if (m->note == 0xFF) m->note = 0;
m->instr = src[j++];
}
if (b & 0x40)
{
UINT vol = src[j++];
if ((vol >= 128) && (vol <= 192))
{
vol -= 128;
m->volcmd = VOLCMD_PANNING;
} else
{
if (vol > 64) vol = 64;
m->volcmd = VOLCMD_VOLUME;
}
m->vol = vol;
}
if (b & 0x80)
{
m->command = src[j++];
m->param = src[j++];
if (m->command) S3MConvert(m, FALSE);
}
} else
{
if (b & 0x20) j += 2;
if (b & 0x40) j++;
if (b & 0x80) j += 2;
}
if (j >= len) break;
}
}
}
// Reading samples
for (UINT iRaw=1; iRaw<=insnum; iRaw++) if ((Ins[iRaw].nLength) && (insfile[iRaw]))
{
UINT flags = (psfh.version == 1) ? RS_PCM8S : RS_PCM8U;
if (insflags[iRaw-1] & 4) flags += 5;
if (insflags[iRaw-1] & 2) flags |= RSF_STEREO;
if (inspack[iRaw-1] == 4) flags = RS_ADPCM4;
dwMemPos = insfile[iRaw];
if (dwMemPos < dwMemLength)
ReadSample(&Ins[iRaw], flags, (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
}
m_nMinPeriod = 64;
m_nMaxPeriod = 32767;
if (psfh.flags & 0x10) m_dwSongFlags |= SONG_AMIGALIMITS;
return TRUE;
}
#ifndef MODPLUG_NO_FILESAVE
#ifdef _MSC_VER
#pragma warning(disable:4100)
#endif
static BYTE S3MFiller[16] =
{
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
};
BOOL CSoundFile::SaveS3M(LPCSTR lpszFileName, UINT nPacking)
//----------------------------------------------------------
{
FILE *f;
BYTE header[0x60];
UINT nbo,nbi,nbp,i;
WORD patptr[128];
WORD insptr[128];
BYTE buffer[5*1024];
S3MSAMPLESTRUCT insex[128];
if ((!m_nChannels) || (!lpszFileName)) return FALSE;
if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
// Writing S3M header
memset(header, 0, sizeof(header));
memset(insex, 0, sizeof(insex));
memcpy(header, m_szNames[0], 0x1C);
header[0x1B] = 0;
header[0x1C] = 0x1A;
header[0x1D] = 0x10;
nbo = (GetNumPatterns() + 15) & 0xF0;
if (!nbo) nbo = 16;
header[0x20] = nbo & 0xFF;
header[0x21] = nbo >> 8;
nbi = m_nInstruments;
if (!nbi) nbi = m_nSamples;
if (nbi > 99) nbi = 99;
header[0x22] = nbi & 0xFF;
header[0x23] = nbi >> 8;
nbp = 0;
for (i=0; Patterns[i]; i++) { nbp = i+1; if (nbp >= MAX_PATTERNS) break; }
for (i=0; i<MAX_ORDERS; i++) if ((Order[i] < MAX_PATTERNS) && (Order[i] >= nbp)) nbp = Order[i] + 1;
header[0x24] = nbp & 0xFF;
header[0x25] = nbp >> 8;
if (m_dwSongFlags & SONG_FASTVOLSLIDES) header[0x26] |= 0x40;
if ((m_nMaxPeriod < 20000) || (m_dwSongFlags & SONG_AMIGALIMITS)) header[0x26] |= 0x10;
header[0x28] = 0x20;
header[0x29] = 0x13;
header[0x2A] = 0x02; // Version = 1 => Signed samples
header[0x2B] = 0x00;
header[0x2C] = 'S';
header[0x2D] = 'C';
header[0x2E] = 'R';
header[0x2F] = 'M';
header[0x30] = m_nDefaultGlobalVolume >> 2;
header[0x31] = m_nDefaultSpeed;
header[0x32] = m_nDefaultTempo;
header[0x33] = ((m_nSongPreAmp < 0x20) ? 0x20 : m_nSongPreAmp) | 0x80; // Stereo
header[0x35] = 0xFC;
for (i=0; i<32; i++)
{
if (i < m_nChannels)
{
UINT tmp = (i & 0x0F) >> 1;
header[0x40+i] = (i & 0x10) | ((i & 1) ? 8+tmp : tmp);
} else header[0x40+i] = 0xFF;
}
fwrite(header, 0x60, 1, f);
fwrite(Order, nbo, 1, f);
memset(patptr, 0, sizeof(patptr));
memset(insptr, 0, sizeof(insptr));
UINT ofs0 = 0x60 + nbo;
UINT ofs1 = ((0x60 + nbo + nbi*2 + nbp*2 + 15) & 0xFFF0) + 0x20;
UINT ofs = ofs1;
for (i=0; i<nbi; i++) insptr[i] = (WORD)((ofs + i*0x50) / 16);
for (i=0; i<nbp; i++) patptr[i] = (WORD)((ofs + nbi*0x50) / 16);
fwrite(insptr, nbi, 2, f);
fwrite(patptr, nbp, 2, f);
if (header[0x35] == 0xFC)
{
BYTE chnpan[32];
for (i=0; i<32; i++)
{
chnpan[i] = 0x20 | (ChnSettings[i].nPan >> 4);
}
fwrite(chnpan, 0x20, 1, f);
}
if ((nbi*2+nbp*2) & 0x0F)
{
fwrite(S3MFiller, 0x10 - ((nbi*2+nbp*2) & 0x0F), 1, f);
}
ofs1 = ftell(f);
fwrite(insex, nbi, 0x50, f);
// Packing patterns
ofs += nbi*0x50;
for (i=0; i<nbp; i++)
{
WORD len = 64;
memset(buffer, 0, sizeof(buffer));
patptr[i] = ofs / 16;
if (Patterns[i])
{
len = 2;
MODCOMMAND *p = Patterns[i];
for (int row=0; row<64; row++) if (row < PatternSize[i])
{
for (UINT j=0; j<m_nChannels; j++)
{
UINT b = j;
MODCOMMAND *m = &p[row*m_nChannels+j];
UINT note = m->note;
UINT volcmd = m->volcmd;
UINT vol = m->vol;
UINT command = m->command;
UINT param = m->param;
if ((note) || (m->instr)) b |= 0x20;
if (!note) note = 0xFF; else
if (note >= 0xFE) note = 0xFE; else
if (note < 13) note = 0; else note -= 13;
if (note < 0xFE) note = (note % 12) + ((note / 12) << 4);
if (command == CMD_VOLUME)
{
command = 0;
if (param > 64) param = 64;
volcmd = VOLCMD_VOLUME;
vol = param;
}
if (volcmd == VOLCMD_VOLUME) b |= 0x40; else
if (volcmd == VOLCMD_PANNING) { vol |= 0x80; b |= 0x40; }
if (command)
{
S3MSaveConvert(&command, &param, FALSE);
if (command) b |= 0x80;
}
if (b & 0xE0)
{
buffer[len++] = b;
if (b & 0x20)
{
buffer[len++] = note;
buffer[len++] = m->instr;
}
if (b & 0x40)
{
buffer[len++] = vol;
}
if (b & 0x80)
{
buffer[len++] = command;
buffer[len++] = param;
}
if (len > sizeof(buffer) - 20) break;
}
}
buffer[len++] = 0;
if (len > sizeof(buffer) - 20) break;
}
}
buffer[0] = (len - 2) & 0xFF;
buffer[1] = (len - 2) >> 8;
len = (len+15) & (~0x0F);
fwrite(buffer, len, 1, f);
ofs += len;
}
// Writing samples
for (i=1; i<=nbi; i++)
{
MODINSTRUMENT *pins = &Ins[i];
if (m_nInstruments)
{
pins = Ins;
if (Headers[i])
{
for (UINT j=0; j<128; j++)
{
UINT n = Headers[i]->Keyboard[j];
if ((n) && (n < MAX_INSTRUMENTS))
{
pins = &Ins[n];
break;
}
}
}
}
memcpy(insex[i-1].dosname, pins->name, 12);
memcpy(insex[i-1].name, m_szNames[i], 28);
memcpy(insex[i-1].scrs, "SCRS", 4);
insex[i-1].hmem = (BYTE)((DWORD)ofs >> 20);
insex[i-1].memseg = (WORD)((DWORD)ofs >> 4);
if (pins->pSample)
{
insex[i-1].type = 1;
insex[i-1].length = pins->nLength;
insex[i-1].loopbegin = pins->nLoopStart;
insex[i-1].loopend = pins->nLoopEnd;
insex[i-1].vol = pins->nVolume / 4;
insex[i-1].flags = (pins->uFlags & CHN_LOOP) ? 1 : 0;
if (pins->nC4Speed)
insex[i-1].finetune = pins->nC4Speed;
else
insex[i-1].finetune = TransposeToFrequency(pins->RelativeTone, pins->nFineTune);
UINT flags = RS_PCM8U;
#ifndef NO_PACKING
if (nPacking)
{
if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
&& (CanPackSample((char *)pins->pSample, pins->nLength, nPacking)))
{
insex[i-1].pack = 4;
flags = RS_ADPCM4;
}
} else
#endif // NO_PACKING
{
if (pins->uFlags & CHN_16BIT)
{
insex[i-1].flags |= 4;
flags = RS_PCM16U;
}
if (pins->uFlags & CHN_STEREO)
{
insex[i-1].flags |= 2;
flags = (pins->uFlags & CHN_16BIT) ? RS_STPCM16U : RS_STPCM8U;
}
}
DWORD len = WriteSample(f, pins, flags);
if (len & 0x0F)
{
fwrite(S3MFiller, 0x10 - (len & 0x0F), 1, f);
}
ofs += (len + 15) & (~0x0F);
} else
{
insex[i-1].length = 0;
}
}
// Updating parapointers
fseek(f, ofs0, SEEK_SET);
fwrite(insptr, nbi, 2, f);
fwrite(patptr, nbp, 2, f);
fseek(f, ofs1, SEEK_SET);
fwrite(insex, 0x50, nbi, f);
fclose(f);
return TRUE;
}
#ifdef _MSC_VER
#pragma warning(default:4100)
#endif
#endif // MODPLUG_NO_FILESAVE

View File

@ -0,0 +1,186 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct tagSTMNOTE
{
BYTE note;
BYTE insvol;
BYTE volcmd;
BYTE cmdinf;
} STMNOTE;
// Raw STM sampleinfo struct:
typedef struct tagSTMSAMPLE
{
CHAR filename[14]; // Can't have long comments - just filename comments :)
WORD reserved; // ISA in memory when in ST 2
WORD length; // Sample length
WORD loopbeg; // Loop start point
WORD loopend; // Loop end point
BYTE volume; // Volume
BYTE reserved2; // More reserved crap
WORD c2spd; // Good old c2spd
BYTE reserved3[6]; // Yet more of PSi's reserved crap
} STMSAMPLE;
// Raw STM header struct:
typedef struct tagSTMHEADER
{
char songname[20]; // changed from CHAR
char trackername[8]; // !SCREAM! for ST 2.xx // changed from CHAR
CHAR unused; // 0x1A
CHAR filetype; // 1=song, 2=module (only 2 is supported, of course) :)
CHAR ver_major; // Like 2
CHAR ver_minor; // "ditto"
BYTE inittempo; // initspeed= stm inittempo>>4
BYTE numpat; // number of patterns
BYTE globalvol; // <- WoW! a RiGHT TRiANGLE =8*)
BYTE reserved[13]; // More of PSi's internal crap
STMSAMPLE sample[31]; // STM sample data
BYTE patorder[128]; // Docs say 64 - actually 128
} STMHEADER;
#pragma pack()
BOOL CSoundFile::ReadSTM(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
const STMHEADER *phdr = (STMHEADER *)lpStream;
DWORD dwMemPos = 0;
if ((!lpStream) || (dwMemLength < sizeof(STMHEADER))) return FALSE;
if ((phdr->filetype != 2) || (phdr->unused != 0x1A)
|| ((strncmp(phdr->trackername, "!Scream!", 8))
&& (strncmp(phdr->trackername, "BMOD2STM", 8)))) return FALSE;
memcpy(m_szNames[0], phdr->songname, 20);
// Read STM header
m_nType = MOD_TYPE_STM;
m_nSamples = 31;
m_nChannels = 4;
m_nInstruments = 0;
m_nMinPeriod = 64;
m_nMaxPeriod = 0x7FFF;
m_nDefaultSpeed = phdr->inittempo >> 4;
if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 1;
m_nDefaultTempo = 125;
m_nDefaultGlobalVolume = phdr->globalvol << 2;
if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256;
memcpy(Order, phdr->patorder, 128);
// Setting up channels
for (UINT nSet=0; nSet<4; nSet++)
{
ChnSettings[nSet].dwFlags = 0;
ChnSettings[nSet].nVolume = 64;
ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0;
}
// Reading samples
for (UINT nIns=0; nIns<31; nIns++)
{
MODINSTRUMENT *pIns = &Ins[nIns+1];
const STMSAMPLE *pStm = &phdr->sample[nIns]; // STM sample data
memcpy(pIns->name, pStm->filename, 13);
memcpy(m_szNames[nIns+1], pStm->filename, 12);
pIns->nC4Speed = bswapLE16(pStm->c2spd);
pIns->nGlobalVol = 64;
pIns->nVolume = pStm->volume << 2;
if (pIns->nVolume > 256) pIns->nVolume = 256;
pIns->nLength = bswapLE16(pStm->length);
if ((pIns->nLength < 4) || (!pIns->nVolume)) pIns->nLength = 0;
pIns->nLoopStart = bswapLE16(pStm->loopbeg);
pIns->nLoopEnd = bswapLE16(pStm->loopend);
if ((pIns->nLoopEnd > pIns->nLoopStart) && (pIns->nLoopEnd != 0xFFFF)) pIns->uFlags |= CHN_LOOP;
}
dwMemPos = sizeof(STMHEADER);
for (UINT nOrd=0; nOrd<MAX_ORDERS; nOrd++) if (Order[nOrd] >= 99) Order[nOrd] = 0xFF;
UINT nPatterns = phdr->numpat;
for (UINT nPat=0; nPat<nPatterns; nPat++)
{
if (dwMemPos + 64*4*4 > dwMemLength) return TRUE;
PatternSize[nPat] = 64;
if ((Patterns[nPat] = AllocatePattern(64, m_nChannels)) == NULL) return TRUE;
MODCOMMAND *m = Patterns[nPat];
const STMNOTE *p = (const STMNOTE *)(lpStream + dwMemPos);
for (UINT n=0; n<64*4; n++, p++, m++)
{
UINT note,ins,vol,cmd;
// extract the various information from the 4 bytes that
// make up a single note
note = p->note;
ins = p->insvol >> 3;
vol = (p->insvol & 0x07) + (p->volcmd >> 1);
cmd = p->volcmd & 0x0F;
if ((ins) && (ins < 32)) m->instr = ins;
// special values of [SBYTE0] are handled here ->
// we have no idea if these strange values will ever be encountered
// but it appears as though stms sound correct.
if ((note == 0xFE) || (note == 0xFC)) m->note = 0xFE; else
// if note < 251, then all three bytes are stored in the file
if (note < 0xFC) m->note = (note >> 4)*12 + (note&0xf) + 37;
if (vol <= 64) { m->volcmd = VOLCMD_VOLUME; m->vol = vol; }
m->param = p->cmdinf;
switch(cmd)
{
// Axx set speed to xx
case 1: m->command = CMD_SPEED; m->param >>= 4; break;
// Bxx position jump
case 2: m->command = CMD_POSITIONJUMP; break;
// Cxx patternbreak to row xx
case 3: m->command = CMD_PATTERNBREAK; m->param = (m->param & 0xF0) * 10 + (m->param & 0x0F); break;
// Dxy volumeslide
case 4: m->command = CMD_VOLUMESLIDE; break;
// Exy toneslide down
case 5: m->command = CMD_PORTAMENTODOWN; break;
// Fxy toneslide up
case 6: m->command = CMD_PORTAMENTOUP; break;
// Gxx Tone portamento,speed xx
case 7: m->command = CMD_TONEPORTAMENTO; break;
// Hxy vibrato
case 8: m->command = CMD_VIBRATO; break;
// Ixy tremor, ontime x, offtime y
case 9: m->command = CMD_TREMOR; break;
// Jxy arpeggio
case 10: m->command = CMD_ARPEGGIO; break;
// Kxy Dual command H00 & Dxy
case 11: m->command = CMD_VIBRATOVOL; break;
// Lxy Dual command G00 & Dxy
case 12: m->command = CMD_TONEPORTAVOL; break;
// Xxx amiga command 8xx
case 0x18: m->command = CMD_PANNING8; break;
default:
m->command = m->param = 0;
}
}
dwMemPos += 64*4*4;
}
// Reading Samples
for (UINT nSmp=1; nSmp<=31; nSmp++)
{
MODINSTRUMENT *pIns = &Ins[nSmp];
dwMemPos = (dwMemPos + 15) & (~15);
if (pIns->nLength)
{
UINT nPos = ((UINT)phdr->sample[nSmp-1].reserved) << 4;
if ((nPos >= sizeof(STMHEADER)) && (nPos+pIns->nLength <= dwMemLength)) dwMemPos = nPos;
if (dwMemPos < dwMemLength)
{
dwMemPos += ReadSample(pIns, RS_PCM8S, (LPSTR)(lpStream+dwMemPos),dwMemLength-dwMemPos);
}
}
}
return TRUE;
}

View File

@ -0,0 +1,224 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#define ULT_16BIT 0x04
#define ULT_LOOP 0x08
#define ULT_BIDI 0x10
#pragma pack(1)
// Raw ULT header struct:
typedef struct tagULTHEADER
{
char id[15]; // changed from CHAR
char songtitle[32]; // changed from CHAR
BYTE reserved;
} ULTHEADER;
// Raw ULT sampleinfo struct:
typedef struct tagULTSAMPLE
{
CHAR samplename[32];
CHAR dosname[12];
LONG loopstart;
LONG loopend;
LONG sizestart;
LONG sizeend;
BYTE volume;
BYTE flags;
WORD finetune;
} ULTSAMPLE;
#pragma pack()
BOOL CSoundFile::ReadUlt(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
ULTHEADER *pmh = (ULTHEADER *)lpStream;
ULTSAMPLE *pus;
UINT nos, nop;
DWORD dwMemPos = 0;
// try to read module header
if ((!lpStream) || (dwMemLength < 0x100)) return FALSE;
if (strncmp(pmh->id,"MAS_UTrack_V00",14)) return FALSE;
// Warning! Not supported ULT format, trying anyway
// if ((pmh->id[14] < '1') || (pmh->id[14] > '4')) return FALSE;
m_nType = MOD_TYPE_ULT;
m_nDefaultSpeed = 6;
m_nDefaultTempo = 125;
memcpy(m_szNames[0], pmh->songtitle, 32);
m_szNames[0][31] = '\0';
// read songtext
dwMemPos = sizeof(ULTHEADER);
if ((pmh->reserved) && (dwMemPos + pmh->reserved * 32 < dwMemLength))
{
UINT len = pmh->reserved * 32;
m_lpszSongComments = new char[len + 1 + pmh->reserved];
if (m_lpszSongComments)
{
for (UINT l=0; l<pmh->reserved; l++)
{
memcpy(m_lpszSongComments+l*33, lpStream+dwMemPos+l*32, 32);
m_lpszSongComments[l*33+32] = 0x0D;
}
m_lpszSongComments[len] = 0;
}
dwMemPos += len;
}
if (dwMemPos >= dwMemLength) return TRUE;
nos = lpStream[dwMemPos++];
m_nSamples = nos;
if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1;
UINT smpsize = 64;
if (pmh->id[14] >= '4') smpsize += 2;
if (dwMemPos + nos*smpsize + 256 + 2 > dwMemLength) return TRUE;
for (UINT ins=1; ins<=nos; ins++, dwMemPos+=smpsize) if (ins<=m_nSamples)
{
pus = (ULTSAMPLE *)(lpStream+dwMemPos);
MODINSTRUMENT *pins = &Ins[ins];
memcpy(m_szNames[ins], pus->samplename, 32);
m_szNames[ins][31] = '\0';
memcpy(pins->name, pus->dosname, 12);
pins->nLoopStart = pus->loopstart;
pins->nLoopEnd = pus->loopend;
pins->nLength = pus->sizeend - pus->sizestart;
pins->nVolume = pus->volume;
pins->nGlobalVol = 64;
pins->nC4Speed = 8363;
if (pmh->id[14] >= '4')
{
pins->nC4Speed = pus->finetune;
}
if (pus->flags & ULT_LOOP) pins->uFlags |= CHN_LOOP;
if (pus->flags & ULT_BIDI) pins->uFlags |= CHN_PINGPONGLOOP;
if (pus->flags & ULT_16BIT)
{
pins->uFlags |= CHN_16BIT;
pins->nLoopStart >>= 1;
pins->nLoopEnd >>= 1;
}
}
memcpy(Order, lpStream+dwMemPos, 256);
dwMemPos += 256;
m_nChannels = lpStream[dwMemPos] + 1;
nop = lpStream[dwMemPos+1] + 1;
dwMemPos += 2;
if (m_nChannels > 32) m_nChannels = 32;
// Default channel settings
for (UINT nSet=0; nSet<m_nChannels; nSet++)
{
ChnSettings[nSet].nVolume = 64;
ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0;
}
// read pan position table for v1.5 and higher
if(pmh->id[14]>='3')
{
if (dwMemPos + m_nChannels > dwMemLength) return TRUE;
for(UINT t=0; t<m_nChannels; t++)
{
ChnSettings[t].nPan = (lpStream[dwMemPos++] << 4) + 8;
if (ChnSettings[t].nPan > 256) ChnSettings[t].nPan = 256;
}
}
// Allocating Patterns
for (UINT nAllocPat=0; nAllocPat<nop; nAllocPat++)
{
if (nAllocPat < MAX_PATTERNS)
{
PatternSize[nAllocPat] = 64;
Patterns[nAllocPat] = AllocatePattern(64, m_nChannels);
}
}
// Reading Patterns
for (UINT nChn=0; nChn<m_nChannels; nChn++)
{
for (UINT nPat=0; nPat<nop; nPat++)
{
MODCOMMAND *pat = NULL;
if (nPat < MAX_PATTERNS)
{
pat = Patterns[nPat];
if (pat) pat += nChn;
}
UINT row = 0;
while (row < 64)
{
if (dwMemPos + 6 > dwMemLength) return TRUE;
UINT rep = 1;
UINT note = lpStream[dwMemPos++];
if (note == 0xFC)
{
rep = lpStream[dwMemPos];
note = lpStream[dwMemPos+1];
dwMemPos += 2;
}
UINT instr = lpStream[dwMemPos++];
UINT eff = lpStream[dwMemPos++];
UINT dat1 = lpStream[dwMemPos++];
UINT dat2 = lpStream[dwMemPos++];
UINT cmd1 = eff & 0x0F;
UINT cmd2 = eff >> 4;
if (cmd1 == 0x0C) dat1 >>= 2; else
if (cmd1 == 0x0B) { cmd1 = dat1 = 0; }
if (cmd2 == 0x0C) dat2 >>= 2; else
if (cmd2 == 0x0B) { cmd2 = dat2 = 0; }
while ((rep != 0) && (row < 64))
{
if (pat)
{
pat->instr = instr;
if (note) pat->note = note + 36;
if (cmd1 | dat1)
{
if (cmd1 == 0x0C)
{
pat->volcmd = VOLCMD_VOLUME;
pat->vol = dat1;
} else
{
pat->command = cmd1;
pat->param = dat1;
ConvertModCommand(pat);
}
}
if (cmd2 == 0x0C)
{
pat->volcmd = VOLCMD_VOLUME;
pat->vol = dat2;
} else
if ((cmd2 | dat2) && (!pat->command))
{
pat->command = cmd2;
pat->param = dat2;
ConvertModCommand(pat);
}
pat += m_nChannels;
}
row++;
rep--;
}
}
}
}
// Reading Instruments
for (UINT smp=1; smp<=m_nSamples; smp++) if (Ins[smp].nLength)
{
if (dwMemPos >= dwMemLength) return TRUE;
UINT flags = (Ins[smp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
dwMemPos += ReadSample(&Ins[smp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
}
return TRUE;
}

View File

@ -0,0 +1,312 @@
/*
* This source code is public domain.
*
* Epic Games Unreal UMX container loading for libmodplug
* Written by O. Sezer <sezero@users.sourceforge.net>
* UPKG parsing partially based on Unreal Media Ripper (UMR) v0.3
* by Andy Ward <wardwh@swbell.net>, with additional updates
* by O. Sezer - see git repo at https://github.com/sezero/umr/
* Retrieves the offset, size and object type directly from umx.
*/
#include "stdafx.h"
#include "sndfile.h"
typedef LONG fci_t; /* FCompactIndex */
#define UPKG_HDR_TAG 0x9e2a83c1
struct _genhist { /* for upkg versions >= 68 */
LONG export_count;
LONG name_count;
};
struct upkg_hdr {
DWORD tag; /* UPKG_HDR_TAG */
LONG file_version;
DWORD pkg_flags;
LONG name_count; /* number of names in name table (>= 0) */
LONG name_offset; /* offset to name table (>= 0) */
LONG export_count; /* num. exports in export table (>= 0) */
LONG export_offset; /* offset to export table (>= 0) */
LONG import_count; /* num. imports in export table (>= 0) */
LONG import_offset; /* offset to import table (>= 0) */
/* number of GUIDs in heritage table (>= 1) and table's offset:
* only with versions < 68. */
LONG heritage_count;
LONG heritage_offset;
/* with versions >= 68: a GUID, a dword for generation count
* and export_count and name_count dwords for each generation: */
DWORD guid[4];
LONG generation_count;
#define UPKG_HDR_SIZE 64 /* 64 bytes up until here */
/*struct _genhist *gen;*/
};
#define UMUSIC_IT 0
#define UMUSIC_S3M 1
#define UMUSIC_XM 2
#define UMUSIC_MOD 3
#define UMUSIC_WAV 4
#define UMUSIC_MP2 5
static const char *mustype[] = {
"IT", "S3M", "XM", "MOD",
NULL
};
/* decode an FCompactIndex.
* original documentation by Tim Sweeney was at
* http://unreal.epicgames.com/Packages.htm
* also see Unreal Wiki:
* http://wiki.beyondunreal.com/Legacy:Package_File_Format/Data_Details
*/
static fci_t get_fci (const char *in, int *pos)
{
LONG a;
int size;
size = 1;
a = in[0] & 0x3f;
if (in[0] & 0x40) {
size++;
a |= (in[1] & 0x7f) << 6;
if (in[1] & 0x80) {
size++;
a |= (in[2] & 0x7f) << 13;
if (in[2] & 0x80) {
size++;
a |= (in[3] & 0x7f) << 20;
if (in[3] & 0x80) {
size++;
a |= (in[4] & 0x3f) << 27;
}
}
}
}
if (in[0] & 0x80)
a = -a;
*pos += size;
return a;
}
static int get_objtype (const BYTE *membase, LONG memlen,
LONG ofs, int type)
{
if (type == UMUSIC_IT) {
_retry:
if (memcmp(membase + ofs, "IMPM", 4) == 0)
return UMUSIC_IT;
return -1;
}
if (type == UMUSIC_XM) {
if (memcmp(membase + ofs, "Extended Module: ", 17) != 0)
return -1;
if (*(membase + ofs + 37) != 0x1a) return -1;
return UMUSIC_XM;
}
if (type == UMUSIC_S3M) {
if (memcmp(membase + ofs + 44, "SCRM", 4) == 0)
return UMUSIC_S3M;
/*return -1;*/
/* SpaceMarines.umx and Starseek.umx from Return to NaPali
* report as "s3m" whereas the actual music format is "it" */
goto _retry;
}
if (type == UMUSIC_MOD) {
membase += ofs + 1080;
if (memcmp(membase, "M.K.", 4) == 0 || memcmp(membase, "M!K!", 4) == 0)
return UMUSIC_MOD;
return -1;
}
return -1;
}
static int read_export (const BYTE *membase, LONG memlen,
const struct upkg_hdr *hdr,
LONG *ofs, LONG *objsize)
{
char buf[40];
int idx = 0, t;
memcpy(buf, membase + *ofs, 40);
if (hdr->file_version < 40) idx += 8; /* 00 00 00 00 00 00 00 00 */
if (hdr->file_version < 60) idx += 16; /* 81 00 00 00 00 00 FF FF FF FF FF FF FF FF 00 00 */
get_fci(&buf[idx], &idx); /* skip junk */
t = get_fci(&buf[idx], &idx); /* type_name */
if (hdr->file_version > 61) idx += 4; /* skip export size */
*objsize = get_fci(&buf[idx], &idx);
*ofs += idx; /* offset for real data */
return t; /* return type_name index */
}
static int read_typname(const BYTE *membase, LONG memlen,
const struct upkg_hdr *hdr,
int idx, char *out)
{
int i, s;
long l;
char buf[64];
if (idx >= hdr->name_count) return -1;
buf[63] = '\0';
for (i = 0, l = 0; i <= idx; i++) {
memcpy(buf, membase + hdr->name_offset + l, 63);
if (hdr->file_version >= 64) {
s = *(signed char *)buf; /* numchars *including* terminator */
if (s <= 0 || s > 64) return -1;
l += s + 5; /* 1 for buf[0], 4 for int32_t name_flags */
} else {
l += (long)strlen(buf);
l += 5; /* 1 for terminator, 4 for int32_t name_flags */
}
}
strcpy(out, (hdr->file_version >= 64)? &buf[1] : buf);
return 0;
}
static int probe_umx (const BYTE *membase, LONG memlen,
const struct upkg_hdr *hdr,
LONG *ofs, LONG *objsize)
{
int i, idx, t;
LONG s, pos;
char buf[64];
/* Find the offset and size of the first IT, S3M or XM
* by parsing the exports table. The umx files should
* have only one export. Kran32.umx from Unreal has two,
* but both pointing to the same music. */
s = memlen - hdr->export_offset;
if (s <= 0) return -1;
if (s > 64) s = 64;
memcpy(buf, membase + hdr->export_offset, s);
for (; s < 64; ++s) buf[s] = 0x0; /* really? */
idx = 0;
get_fci(&buf[idx], &idx); /* skip class_index */
get_fci(&buf[idx], &idx); /* skip super_index */
if (hdr->file_version >= 60) idx += 4; /* skip int32 package_index */
get_fci(&buf[idx], &idx); /* skip object_name */
idx += 4; /* skip int32 object_flags */
s = get_fci(&buf[idx], &idx); /* get serial_size */
if (s <= 0) return -1;
pos = get_fci(&buf[idx],&idx); /* get serial_offset */
if (pos < 0 || pos > memlen - 40) return -1;
if ((t = read_export(membase, memlen, hdr, &pos, &s)) < 0) return -1;
if (s <= 0 || s > memlen - pos) return -1;
if (read_typname(membase, memlen, hdr, t, buf) < 0) return -1;
for (i = 0; mustype[i] != NULL; i++) {
if (!strcasecmp(buf, mustype[i])) {
t = i;
break;
}
}
if (mustype[i] == NULL) return -1;
if ((t = get_objtype(membase, memlen, pos, t)) < 0) return -1;
*ofs = pos;
*objsize = s;
return t;
}
static int probe_header (void *header)
{
struct upkg_hdr *hdr;
unsigned char *p;
DWORD *swp;
int i;
/* byte swap the header - all members are 32 bit LE values */
p = (unsigned char *) header;
swp = (DWORD *) header;
for (i = 0; i < UPKG_HDR_SIZE/4; i++, p += 4) {
swp[i] = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
hdr = (struct upkg_hdr *) header;
if (hdr->tag != UPKG_HDR_TAG) {
return -1;
}
if (hdr->name_count < 0 ||
hdr->name_offset < 0 ||
hdr->export_count < 0 ||
hdr->export_offset < 0 ||
hdr->import_count < 0 ||
hdr->import_offset < 0 ) {
return -1;
}
#if 0
return 0;
#else
switch (hdr->file_version) {
case 35: case 37: /* Unreal beta - */
case 40: case 41: /* 1998 */
case 61:/* Unreal */
case 62:/* Unreal Tournament */
case 63:/* Return to NaPali */
case 64:/* Unreal Tournament */
case 66:/* Unreal Tournament */
case 68:/* Unreal Tournament */
case 69:/* Tactical Ops */
case 83:/* Mobile Forces */
return 0;
}
return -1;/* Unknown upkg version for an UMX */
#endif
}
static int process_upkg (const BYTE *membase, LONG memlen,
LONG *ofs, LONG *objsize)
{
char header[UPKG_HDR_SIZE];
memcpy(header, membase, UPKG_HDR_SIZE);
if (probe_header(header) < 0)
return -1;
return probe_umx(membase, memlen, (struct upkg_hdr *)header, ofs, objsize);
}
BOOL CSoundFile::ReadUMX(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
int type;
LONG ofs = 0, size = 0;
if (!lpStream || dwMemLength < 0x800 || dwMemLength > 0x7fffffff)
return FALSE;
type = process_upkg(lpStream, (LONG)dwMemLength, &ofs, &size);
if (type < 0) return FALSE;
// Rip Mods from UMX
switch (type) {
case UMUSIC_IT: return ReadIT(lpStream + ofs, size);
case UMUSIC_S3M: return ReadS3M(lpStream + ofs, size);
case UMUSIC_XM: return ReadXM(lpStream + ofs, size);
case UMUSIC_MOD: return ReadMod(lpStream + ofs, size);
}
return FALSE;
}

View File

@ -0,0 +1,219 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
#ifndef NO_WAVFORMAT
#ifndef WAVE_FORMAT_EXTENSIBLE
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
#endif
/////////////////////////////////////////////////////////////
// WAV file support
BOOL CSoundFile::ReadWav(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
DWORD dwMemPos = 0;
WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream;
WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER));
if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE;
if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE)
|| (pfmt->id_fmt != IFFID_fmt)) return FALSE;
dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen;
if ((dwMemPos >= dwMemLength - 8)
|| ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE))
|| (pfmt->channels > 4)
|| (!pfmt->channels)
|| (!pfmt->freqHz)
|| (pfmt->bitspersample & 7)
|| (pfmt->bitspersample < 8)
|| (pfmt->bitspersample > 32)) return FALSE;
WAVEDATAHEADER *pdata;
for (;;)
{
pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos);
if (pdata->id_data == IFFID_data) break;
dwMemPos += pdata->length + 8;
if (dwMemPos >= dwMemLength - 8) return FALSE;
}
m_nType = MOD_TYPE_WAV;
m_nSamples = 0;
m_nInstruments = 0;
m_nChannels = 4;
m_nDefaultSpeed = 8;
m_nDefaultTempo = 125;
m_dwSongFlags |= SONG_LINEARSLIDES; // For no resampling
Order[0] = 0;
Order[1] = 0xFF;
PatternSize[0] = PatternSize[1] = 64;
if ((Patterns[0] = AllocatePattern(64, 4)) == NULL) return TRUE;
if ((Patterns[1] = AllocatePattern(64, 4)) == NULL) return TRUE;
UINT samplesize = (pfmt->channels * pfmt->bitspersample) >> 3;
UINT len = pdata->length, bytelen;
if (len > dwMemLength - 8 - dwMemPos) len = dwMemLength - dwMemPos - 8;
len /= samplesize;
bytelen = len;
if (pfmt->bitspersample >= 16) bytelen *= 2;
if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
if (!len) return TRUE;
// Setting up module length
DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1;
DWORD framesperrow = (dwTime + 63) / 63;
if (framesperrow < 4) framesperrow = 4;
UINT norders = 1;
while (framesperrow >= 0x20)
{
Order[norders++] = 1;
Order[norders] = 0xFF;
framesperrow = (dwTime + (64 * norders - 1)) / (64 * norders);
if (norders >= MAX_ORDERS-1) break;
}
m_nDefaultSpeed = framesperrow;
for (UINT iChn=0; iChn<4; iChn++)
{
ChnSettings[iChn].nPan = (iChn & 1) ? 256 : 0;
ChnSettings[iChn].nVolume = 64;
ChnSettings[iChn].dwFlags = 0;
}
// Setting up speed command
MODCOMMAND *pcmd = Patterns[0];
pcmd[0].command = CMD_SPEED;
pcmd[0].param = (BYTE)m_nDefaultSpeed;
pcmd[0].note = 5*12+1;
pcmd[0].instr = 1;
pcmd[1].note = pcmd[0].note;
pcmd[1].instr = pcmd[0].instr;
m_nSamples = pfmt->channels;
// Support for Multichannel Wave
for (UINT nChn=0; nChn<m_nSamples; nChn++)
{
MODINSTRUMENT *pins = &Ins[nChn+1];
pcmd[nChn].note = pcmd[0].note;
pcmd[nChn].instr = (BYTE)(nChn+1);
pins->nLength = len;
pins->nC4Speed = pfmt->freqHz;
pins->nVolume = 256;
pins->nPan = 128;
pins->nGlobalVol = 64;
pins->uFlags = (WORD)((pfmt->bitspersample >= 16) ? CHN_16BIT : 0);
pins->uFlags |= CHN_PANNING;
if (m_nSamples > 1)
{
switch(nChn)
{
case 0: pins->nPan = 0; break;
case 1: pins->nPan = 256; break;
case 2: pins->nPan = (WORD)((m_nSamples == 3) ? 128 : 64); pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break;
case 3: pins->nPan = 192; pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break;
default: pins->nPan = 128; break;
}
}
if ((pins->pSample = AllocateSample(bytelen+8)) == NULL) return TRUE;
if (pfmt->bitspersample >= 16)
{
int slsize = pfmt->bitspersample >> 3;
signed short *p = (signed short *)pins->pSample;
signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn*slsize+slsize-2);
for (UINT i=0; i<len; i++)
{
p[i] = *((signed short *)psrc);
psrc += samplesize;
}
p[len+1] = p[len] = p[len-1];
} else
{
signed char *p = (signed char *)pins->pSample;
signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn);
for (UINT i=0; i<len; i++)
{
p[i] = (signed char)((*psrc) + 0x80);
psrc += samplesize;
}
p[len+1] = p[len] = p[len-1];
}
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////
// IMA ADPCM Support
#pragma pack(1)
typedef struct IMAADPCMBLOCK
{
WORD sample;
BYTE index;
BYTE Reserved;
} DVI_ADPCMBLOCKHEADER;
#pragma pack()
static const int gIMAUnpackTable[90] =
{
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411,
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
32767, 0
};
BOOL IMAADPCMUnpack16(signed short *pdest, UINT nLen, LPBYTE psrc, DWORD dwBytes, UINT pkBlkAlign)
//------------------------------------------------------------------------------------------------
{
static const int gIMAIndexTab[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
UINT nPos;
int value;
if ((nLen < 4) || (!pdest) || (!psrc)
|| (pkBlkAlign < 5) || (pkBlkAlign > dwBytes)) return FALSE;
nPos = 0;
while ((nPos < nLen) && (dwBytes > 4))
{
int nIndex;
value = *((short int *)psrc);
nIndex = psrc[2];
psrc += 4;
dwBytes -= 4;
pdest[nPos++] = (short int)value;
for (UINT i=0; ((i<(pkBlkAlign-4)*2) && (nPos < nLen) && (dwBytes)); i++)
{
BYTE delta;
if (i & 1)
{
delta = (BYTE)(((*(psrc++)) >> 4) & 0x0F);
dwBytes--;
} else
{
delta = (BYTE)((*psrc) & 0x0F);
}
int v = gIMAUnpackTable[nIndex] >> 3;
if (delta & 1) v += gIMAUnpackTable[nIndex] >> 2;
if (delta & 2) v += gIMAUnpackTable[nIndex] >> 1;
if (delta & 4) v += gIMAUnpackTable[nIndex];
if (delta & 8) value -= v; else value += v;
nIndex += gIMAIndexTab[delta & 7];
if (nIndex < 0) nIndex = 0; else
if (nIndex > 88) nIndex = 88;
if (value > 32767) value = 32767; else
if (value < -32768) value = -32768;
pdest[nPos++] = (short int)value;
}
}
return TRUE;
}
#endif // NO_WAVFORMAT

View File

@ -0,0 +1,896 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>,
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
*/
#include "stdafx.h"
#include "sndfile.h"
////////////////////////////////////////////////////////
// FastTracker II XM file support
#ifdef MSC_VER
#pragma warning(disable:4244)
#endif
#pragma pack(1)
typedef struct tagXMFILEHEADER
{
DWORD size;
WORD norder;
WORD restartpos;
WORD channels;
WORD patterns;
WORD instruments;
WORD flags;
WORD speed;
WORD tempo;
BYTE order[256];
} XMFILEHEADER;
typedef struct tagXMINSTRUMENTHEADER
{
DWORD size;
CHAR name[22];
BYTE type;
BYTE samples;
BYTE samplesh;
} XMINSTRUMENTHEADER;
typedef struct tagXMSAMPLEHEADER
{
DWORD shsize;
BYTE snum[96];
WORD venv[24];
WORD penv[24];
BYTE vnum, pnum;
BYTE vsustain, vloops, vloope, psustain, ploops, ploope;
BYTE vtype, ptype;
BYTE vibtype, vibsweep, vibdepth, vibrate;
WORD volfade;
WORD res;
BYTE reserved1[20];
} XMSAMPLEHEADER;
typedef struct tagXMSAMPLESTRUCT
{
DWORD samplen;
DWORD loopstart;
DWORD looplen;
BYTE vol;
signed char finetune;
BYTE type;
BYTE pan;
signed char relnote;
BYTE res;
char name[22];
} XMSAMPLESTRUCT;
#pragma pack()
BOOL CSoundFile::ReadXM(const BYTE *lpStream, DWORD dwMemLength)
//--------------------------------------------------------------
{
XMSAMPLEHEADER xmsh;
XMSAMPLESTRUCT xmss;
DWORD dwMemPos, dwHdrSize;
WORD norders=0, restartpos=0, channels=0, patterns=0, instruments=0;
WORD xmflags=0, deftempo=125, defspeed=6;
BOOL InstUsed[256];
BYTE channels_used[MAX_CHANNELS];
BYTE pattern_map[256];
BOOL samples_used[MAX_SAMPLES];
UINT unused_samples;
tagXMFILEHEADER xmhead;
m_nChannels = 0;
if ((!lpStream) || (dwMemLength < 0x200)) return FALSE;
if (strncmp((LPCSTR)lpStream, "Extended Module:", 16)) return FALSE;
memcpy(m_szNames[0], lpStream+17, 20);
xmhead = *(tagXMFILEHEADER *)(lpStream+60);
dwHdrSize = bswapLE32(xmhead.size);
norders = bswapLE16(xmhead.norder);
restartpos = bswapLE16(xmhead.restartpos);
channels = bswapLE16(xmhead.channels);
if ((!dwHdrSize) || dwHdrSize > dwMemLength - 60) return FALSE;
if ((!norders) || (norders > MAX_ORDERS)) return FALSE;
if ((!channels) || (channels > 64)) return FALSE;
m_nType = MOD_TYPE_XM;
m_nMinPeriod = 27;
m_nMaxPeriod = 54784;
m_nChannels = channels;
if (restartpos < norders) m_nRestartPos = restartpos;
patterns = bswapLE16(xmhead.patterns);
if (patterns > 256) patterns = 256;
instruments = bswapLE16(xmhead.instruments);
if (instruments >= MAX_INSTRUMENTS) instruments = MAX_INSTRUMENTS-1;
m_nInstruments = instruments;
m_nSamples = 0;
xmflags = bswapLE16(xmhead.flags);
if (xmflags & 1) m_dwSongFlags |= SONG_LINEARSLIDES;
if (xmflags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE;
defspeed = bswapLE16(xmhead.speed);
deftempo = bswapLE16(xmhead.tempo);
if ((deftempo >= 32) && (deftempo < 256)) m_nDefaultTempo = deftempo;
if ((defspeed > 0) && (defspeed < 40)) m_nDefaultSpeed = defspeed;
memcpy(Order, lpStream+80, norders);
memset(InstUsed, 0, sizeof(InstUsed));
if (patterns > MAX_PATTERNS)
{
UINT i, j;
for (i=0; i<norders; i++)
{
if (Order[i] < patterns) InstUsed[Order[i]] = TRUE;
}
j = 0;
for (i=0; i<256; i++)
{
if (InstUsed[i]) pattern_map[i] = j++;
}
for (i=0; i<256; i++)
{
if (!InstUsed[i])
{
pattern_map[i] = (j < MAX_PATTERNS) ? j : 0xFE;
j++;
}
}
for (i=0; i<norders; i++)
{
Order[i] = pattern_map[Order[i]];
}
} else
{
for (UINT i=0; i<256; i++) pattern_map[i] = i;
}
memset(InstUsed, 0, sizeof(InstUsed));
dwMemPos = dwHdrSize + 60;
if (dwMemPos + 8 >= dwMemLength) return TRUE;
// Reading patterns
memset(channels_used, 0, sizeof(channels_used));
for (UINT ipat=0; ipat<patterns; ipat++)
{
UINT ipatmap = pattern_map[ipat];
DWORD dwSize = 0;
WORD rows=64, packsize=0;
dwSize = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
while ((dwMemPos + dwSize >= dwMemLength) || (dwSize & 0xFFFFFF00))
{
if (dwMemPos + 4 >= dwMemLength) break;
dwMemPos++;
dwSize = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
}
if (dwMemPos + 9 > dwMemLength) return TRUE;
rows = bswapLE16(*((WORD *)(lpStream+dwMemPos+5)));
if ((!rows) || (rows > 256)) rows = 64;
packsize = bswapLE16(*((WORD *)(lpStream+dwMemPos+7)));
if (dwMemPos + dwSize + 4 > dwMemLength) return TRUE;
dwMemPos += dwSize;
if (dwMemPos + packsize + 4 > dwMemLength) return TRUE;
MODCOMMAND *p;
if (ipatmap < MAX_PATTERNS)
{
PatternSize[ipatmap] = rows;
if ((Patterns[ipatmap] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
if (!packsize) continue;
p = Patterns[ipatmap];
} else p = NULL;
const BYTE *src = lpStream+dwMemPos;
UINT j=0;
for (UINT row=0; row<rows; row++)
{
for (UINT chn=0; chn<m_nChannels; chn++)
{
if ((p) && (j < packsize))
{
BYTE b = src[j++];
UINT vol = 0;
if (b & 0x80)
{
if (b & 1) p->note = src[j++];
if (b & 2) p->instr = src[j++];
if (b & 4) vol = src[j++];
if (b & 8) p->command = src[j++];
if (b & 16) p->param = src[j++];
} else
{
p->note = b;
p->instr = src[j++];
vol = src[j++];
p->command = src[j++];
p->param = src[j++];
}
if (p->note == 97) p->note = 0xFF; else
if ((p->note) && (p->note < 97)) p->note += 12;
if (p->note) channels_used[chn] = 1;
if (p->command | p->param) ConvertModCommand(p);
if (p->instr == 0xff) p->instr = 0;
if (p->instr) InstUsed[p->instr] = TRUE;
if ((vol >= 0x10) && (vol <= 0x50))
{
p->volcmd = VOLCMD_VOLUME;
p->vol = vol - 0x10;
} else
if (vol >= 0x60)
{
UINT v = vol & 0xF0;
vol &= 0x0F;
p->vol = vol;
switch(v)
{
// 60-6F: Volume Slide Down
case 0x60: p->volcmd = VOLCMD_VOLSLIDEDOWN; break;
// 70-7F: Volume Slide Up:
case 0x70: p->volcmd = VOLCMD_VOLSLIDEUP; break;
// 80-8F: Fine Volume Slide Down
case 0x80: p->volcmd = VOLCMD_FINEVOLDOWN; break;
// 90-9F: Fine Volume Slide Up
case 0x90: p->volcmd = VOLCMD_FINEVOLUP; break;
// A0-AF: Set Vibrato Speed
case 0xA0: p->volcmd = VOLCMD_VIBRATOSPEED; break;
// B0-BF: Vibrato
case 0xB0: p->volcmd = VOLCMD_VIBRATO; break;
// C0-CF: Set Panning
case 0xC0: p->volcmd = VOLCMD_PANNING; p->vol = (vol << 2) + 2; break;
// D0-DF: Panning Slide Left
case 0xD0: p->volcmd = VOLCMD_PANSLIDELEFT; break;
// E0-EF: Panning Slide Right
case 0xE0: p->volcmd = VOLCMD_PANSLIDERIGHT; break;
// F0-FF: Tone Portamento
case 0xF0: p->volcmd = VOLCMD_TONEPORTAMENTO; break;
}
}
p++;
} else
if (j < packsize)
{
BYTE b = src[j++];
if (b & 0x80)
{
if (b & 1) j++;
if (b & 2) j++;
if (b & 4) j++;
if (b & 8) j++;
if (b & 16) j++;
} else j += 4;
} else break;
}
}
dwMemPos += packsize;
}
// Wrong offset check
while (dwMemPos + 4 < dwMemLength)
{
DWORD d = bswapLE32(*((DWORD *)(lpStream+dwMemPos)));
if (d < 0x300) break;
dwMemPos++;
}
memset(samples_used, 0, sizeof(samples_used));
unused_samples = 0;
// Reading instruments
for (UINT iIns=1; iIns<=instruments; iIns++)
{
XMINSTRUMENTHEADER *pih;
BYTE flags[32];
DWORD samplesize[32];
UINT samplemap[32];
WORD nsamples;
if (dwMemPos + sizeof(XMINSTRUMENTHEADER) >= dwMemLength) return TRUE;
pih = (XMINSTRUMENTHEADER *)(lpStream+dwMemPos);
if (dwMemPos + bswapLE32(pih->size) > dwMemLength) return TRUE;
if ((Headers[iIns] = new INSTRUMENTHEADER) == NULL) continue;
memset(Headers[iIns], 0, sizeof(INSTRUMENTHEADER));
memcpy(Headers[iIns]->name, pih->name, 22);
if ((nsamples = pih->samples) > 0)
{
if (dwMemPos + sizeof(XMSAMPLEHEADER) > dwMemLength) return TRUE;
memcpy(&xmsh, lpStream+dwMemPos+sizeof(XMINSTRUMENTHEADER), sizeof(XMSAMPLEHEADER));
xmsh.shsize = bswapLE32(xmsh.shsize);
for (int i = 0; i < 24; ++i) {
xmsh.venv[i] = bswapLE16(xmsh.venv[i]);
xmsh.penv[i] = bswapLE16(xmsh.penv[i]);
}
xmsh.volfade = bswapLE16(xmsh.volfade);
xmsh.res = bswapLE16(xmsh.res);
dwMemPos += bswapLE32(pih->size);
} else
{
if (bswapLE32(pih->size)) dwMemPos += bswapLE32(pih->size);
else dwMemPos += sizeof(XMINSTRUMENTHEADER);
continue;
}
memset(samplemap, 0, sizeof(samplemap));
if (nsamples > 32) return TRUE;
UINT newsamples = m_nSamples;
for (UINT nmap=0; nmap<nsamples; nmap++)
{
UINT n = m_nSamples+nmap+1;
if (n >= MAX_SAMPLES)
{
n = m_nSamples;
while (n > 0)
{
if (!Ins[n].pSample)
{
for (UINT xmapchk=0; xmapchk < nmap; xmapchk++)
{
if (samplemap[xmapchk] == n) goto alreadymapped;
}
for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs])
{
INSTRUMENTHEADER *pks = Headers[clrs];
for (UINT ks=0; ks<128; ks++)
{
if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
}
}
break;
}
alreadymapped:
n--;
}
#ifndef MODPLUG_FASTSOUNDLIB
// Damn! more than 200 samples: look for duplicates
if (!n)
{
if (!unused_samples)
{
unused_samples = DetectUnusedSamples(samples_used);
if (!unused_samples) unused_samples = 0xFFFF;
}
if ((unused_samples) && (unused_samples != 0xFFFF))
{
for (UINT iext=m_nSamples; iext>=1; iext--) if (!samples_used[iext])
{
unused_samples--;
samples_used[iext] = TRUE;
DestroySample(iext);
n = iext;
for (UINT mapchk=0; mapchk<nmap; mapchk++)
{
if (samplemap[mapchk] == n) samplemap[mapchk] = 0;
}
for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs])
{
INSTRUMENTHEADER *pks = Headers[clrs];
for (UINT ks=0; ks<128; ks++)
{
if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0;
}
}
memset(&Ins[n], 0, sizeof(Ins[0]));
break;
}
}
}
#endif // MODPLUG_FASTSOUNDLIB
}
if (newsamples < n) newsamples = n;
samplemap[nmap] = n;
}
m_nSamples = newsamples;
// Reading Volume Envelope
INSTRUMENTHEADER *penv = Headers[iIns];
penv->nMidiProgram = pih->type;
penv->nFadeOut = xmsh.volfade;
penv->nPan = 128;
penv->nPPC = 5*12;
if (xmsh.vtype & 1) penv->dwFlags |= ENV_VOLUME;
if (xmsh.vtype & 2) penv->dwFlags |= ENV_VOLSUSTAIN;
if (xmsh.vtype & 4) penv->dwFlags |= ENV_VOLLOOP;
if (xmsh.ptype & 1) penv->dwFlags |= ENV_PANNING;
if (xmsh.ptype & 2) penv->dwFlags |= ENV_PANSUSTAIN;
if (xmsh.ptype & 4) penv->dwFlags |= ENV_PANLOOP;
if (xmsh.vnum > 12) xmsh.vnum = 12;
if (xmsh.pnum > 12) xmsh.pnum = 12;
penv->nVolEnv = xmsh.vnum;
if (!xmsh.vnum) penv->dwFlags &= ~ENV_VOLUME;
if (!xmsh.pnum) penv->dwFlags &= ~ENV_PANNING;
penv->nPanEnv = xmsh.pnum;
penv->nVolSustainBegin = penv->nVolSustainEnd = xmsh.vsustain;
if (xmsh.vsustain >= 12) penv->dwFlags &= ~ENV_VOLSUSTAIN;
penv->nVolLoopStart = xmsh.vloops;
penv->nVolLoopEnd = xmsh.vloope;
if (penv->nVolLoopEnd >= 12) penv->nVolLoopEnd = 0;
if (penv->nVolLoopStart >= penv->nVolLoopEnd) penv->dwFlags &= ~ENV_VOLLOOP;
penv->nPanSustainBegin = penv->nPanSustainEnd = xmsh.psustain;
if (xmsh.psustain >= 12) penv->dwFlags &= ~ENV_PANSUSTAIN;
penv->nPanLoopStart = xmsh.ploops;
penv->nPanLoopEnd = xmsh.ploope;
if (penv->nPanLoopEnd >= 12) penv->nPanLoopEnd = 0;
if (penv->nPanLoopStart >= penv->nPanLoopEnd) penv->dwFlags &= ~ENV_PANLOOP;
penv->nGlobalVol = 64;
for (UINT ienv=0; ienv<12; ienv++)
{
penv->VolPoints[ienv] = (WORD)xmsh.venv[ienv*2];
penv->VolEnv[ienv] = (BYTE)xmsh.venv[ienv*2+1];
penv->PanPoints[ienv] = (WORD)xmsh.penv[ienv*2];
penv->PanEnv[ienv] = (BYTE)xmsh.penv[ienv*2+1];
if (ienv)
{
if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1])
{
penv->VolPoints[ienv] &= 0xFF;
penv->VolPoints[ienv] += penv->VolPoints[ienv-1] & 0xFF00;
if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1]) penv->VolPoints[ienv] += 0x100;
}
if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1])
{
penv->PanPoints[ienv] &= 0xFF;
penv->PanPoints[ienv] += penv->PanPoints[ienv-1] & 0xFF00;
if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1]) penv->PanPoints[ienv] += 0x100;
}
}
}
for (UINT j=0; j<96; j++)
{
penv->NoteMap[j+12] = j+1+12;
if (xmsh.snum[j] < nsamples)
penv->Keyboard[j+12] = samplemap[xmsh.snum[j]];
}
// Reading samples
for (UINT ins=0; ins<nsamples; ins++)
{
if ((dwMemPos + sizeof(xmss) > dwMemLength)
|| (dwMemPos + xmsh.shsize > dwMemLength)) return TRUE;
memcpy(&xmss, lpStream+dwMemPos, sizeof(xmss));
xmss.samplen = bswapLE32(xmss.samplen);
xmss.loopstart = bswapLE32(xmss.loopstart);
xmss.looplen = bswapLE32(xmss.looplen);
dwMemPos += xmsh.shsize;
flags[ins] = (xmss.type & 0x10) ? RS_PCM16D : RS_PCM8D;
if (xmss.type & 0x20) flags[ins] = (xmss.type & 0x10) ? RS_STPCM16D : RS_STPCM8D;
samplesize[ins] = xmss.samplen;
if (!samplemap[ins]) continue;
if (xmss.type & 0x10)
{
xmss.looplen >>= 1;
xmss.loopstart >>= 1;
xmss.samplen >>= 1;
}
if (xmss.type & 0x20)
{
xmss.looplen >>= 1;
xmss.loopstart >>= 1;
xmss.samplen >>= 1;
}
if (xmss.samplen > MAX_SAMPLE_LENGTH) xmss.samplen = MAX_SAMPLE_LENGTH;
if (xmss.loopstart >= xmss.samplen) xmss.type &= ~3;
xmss.looplen += xmss.loopstart;
if (xmss.looplen > xmss.samplen) xmss.looplen = xmss.samplen;
if (!xmss.looplen) xmss.type &= ~3;
UINT imapsmp = samplemap[ins];
memcpy(m_szNames[imapsmp], xmss.name, 22);
m_szNames[imapsmp][22] = 0;
MODINSTRUMENT *pins = &Ins[imapsmp];
pins->nLength = (xmss.samplen > MAX_SAMPLE_LENGTH) ? MAX_SAMPLE_LENGTH : xmss.samplen;
pins->nLoopStart = xmss.loopstart;
pins->nLoopEnd = xmss.looplen;
if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength;
if (pins->nLoopStart >= pins->nLoopEnd)
{
pins->nLoopStart = pins->nLoopEnd = 0;
}
if (xmss.type & 3) pins->uFlags |= CHN_LOOP;
if (xmss.type & 2) pins->uFlags |= CHN_PINGPONGLOOP;
pins->nVolume = xmss.vol << 2;
if (pins->nVolume > 256) pins->nVolume = 256;
pins->nGlobalVol = 64;
if ((xmss.res == 0xAD) && (!(xmss.type & 0x30)))
{
flags[ins] = RS_ADPCM4;
samplesize[ins] = (samplesize[ins]+1)/2 + 16;
}
pins->nFineTune = xmss.finetune;
pins->RelativeTone = (int)xmss.relnote;
pins->nPan = xmss.pan;
pins->uFlags |= CHN_PANNING;
pins->nVibType = xmsh.vibtype;
pins->nVibSweep = xmsh.vibsweep;
pins->nVibDepth = xmsh.vibdepth;
pins->nVibRate = xmsh.vibrate;
memcpy(pins->name, xmss.name, 22);
pins->name[21] = 0;
}
#if 0
if ((xmsh.reserved2 > nsamples) && (xmsh.reserved2 <= 16))
{
dwMemPos += (((UINT)xmsh.reserved2) - nsamples) * xmsh.shsize;
}
#endif
for (UINT ismpd=0; ismpd<nsamples; ismpd++)
{
if ((samplemap[ismpd]) && (samplesize[ismpd]) && (dwMemPos < dwMemLength))
{
ReadSample(&Ins[samplemap[ismpd]], flags[ismpd], (LPSTR)(lpStream + dwMemPos), dwMemLength - dwMemPos);
}
dwMemPos += samplesize[ismpd];
if (dwMemPos >= dwMemLength) break;
}
}
// Read song comments: "TEXT"
if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x74786574))
{
UINT len = *((DWORD *)(lpStream+dwMemPos+4));
dwMemPos += 8;
if ((dwMemPos + len <= dwMemLength) && (len < 16384))
{
m_lpszSongComments = new char[len+1];
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos, len);
m_lpszSongComments[len] = 0;
}
dwMemPos += len;
}
}
// Read midi config: "MIDI"
if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4944494D))
{
UINT len = *((DWORD *)(lpStream+dwMemPos+4));
dwMemPos += 8;
if (len == sizeof(MODMIDICFG))
{
memcpy(&m_MidiCfg, lpStream+dwMemPos, len);
m_dwSongFlags |= SONG_EMBEDMIDICFG;
}
}
// Read pattern names: "PNAM"
if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50))
{
UINT len = *((DWORD *)(lpStream+dwMemPos+4));
dwMemPos += 8;
if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME))
{
m_lpszPatternNames = new char[len];
if (m_lpszPatternNames)
{
m_nPatternNames = len / MAX_PATTERNNAME;
memcpy(m_lpszPatternNames, lpStream+dwMemPos, len);
}
dwMemPos += len;
}
}
// Read channel names: "CNAM"
if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43))
{
UINT len = *((DWORD *)(lpStream+dwMemPos+4));
dwMemPos += 8;
if ((dwMemPos + len <= dwMemLength) && (len <= MAX_BASECHANNELS*MAX_CHANNELNAME))
{
UINT n = len / MAX_CHANNELNAME;
for (UINT i=0; i<n; i++)
{
memcpy(ChnSettings[i].szName, (lpStream+dwMemPos+i*MAX_CHANNELNAME), MAX_CHANNELNAME);
ChnSettings[i].szName[MAX_CHANNELNAME-1] = 0;
}
dwMemPos += len;
}
}
// Read mix plugins information
if (dwMemPos + 8 < dwMemLength)
{
dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos);
}
return TRUE;
}
#ifndef MODPLUG_NO_FILESAVE
BOOL CSoundFile::SaveXM(LPCSTR lpszFileName, UINT nPacking)
//---------------------------------------------------------
{
BYTE s[64*64*5];
XMFILEHEADER header;
XMINSTRUMENTHEADER xmih;
XMSAMPLEHEADER xmsh;
XMSAMPLESTRUCT xmss;
BYTE smptable[32];
BYTE xmph[9];
FILE *f;
int i;
if ((!m_nChannels) || (!lpszFileName)) return FALSE;
if ((f = fopen(lpszFileName, "wb")) == NULL) return FALSE;
fwrite("Extended Module: ", 17, 1, f);
fwrite(m_szNames[0], 20, 1, f);
s[0] = 0x1A;
lstrcpy((LPSTR)&s[1], (nPacking) ? "MOD Plugin packed " : "FastTracker v2.00 ");
s[21] = 0x04;
s[22] = 0x01;
fwrite(s, 23, 1, f);
// Writing song header
memset(&header, 0, sizeof(header));
header.size = sizeof(XMFILEHEADER);
header.norder = 0;
header.restartpos = m_nRestartPos;
header.channels = m_nChannels;
header.patterns = 0;
for (i=0; i<MAX_ORDERS; i++)
{
if (Order[i] == 0xFF) break;
header.norder++;
if ((Order[i] >= header.patterns) && (Order[i] < MAX_PATTERNS)) header.patterns = Order[i]+1;
}
header.instruments = m_nInstruments;
if (!header.instruments) header.instruments = m_nSamples;
header.flags = (m_dwSongFlags & SONG_LINEARSLIDES) ? 0x01 : 0x00;
if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000;
header.tempo = m_nDefaultTempo;
header.speed = m_nDefaultSpeed;
memcpy(header.order, Order, header.norder);
fwrite(&header, 1, sizeof(header), f);
// Writing patterns
for (i=0; i<header.patterns; i++) if (Patterns[i])
{
MODCOMMAND *p = Patterns[i];
UINT len = 0;
memset(&xmph, 0, sizeof(xmph));
xmph[0] = 9;
xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
xmph[6] = (BYTE)(PatternSize[i] >> 8);
for (UINT j=m_nChannels*PatternSize[i]; j; j--,p++)
{
UINT note = p->note;
UINT param = ModSaveCommand(p, TRUE);
UINT command = param >> 8;
param &= 0xFF;
if (note >= 0xFE) note = 97; else
if ((note <= 12) || (note > 96+12)) note = 0; else
note -= 12;
UINT vol = 0;
if (p->volcmd)
{
UINT volcmd = p->volcmd;
switch(volcmd)
{
case VOLCMD_VOLUME: vol = 0x10 + p->vol; break;
case VOLCMD_VOLSLIDEDOWN: vol = 0x60 + (p->vol & 0x0F); break;
case VOLCMD_VOLSLIDEUP: vol = 0x70 + (p->vol & 0x0F); break;
case VOLCMD_FINEVOLDOWN: vol = 0x80 + (p->vol & 0x0F); break;
case VOLCMD_FINEVOLUP: vol = 0x90 + (p->vol & 0x0F); break;
case VOLCMD_VIBRATOSPEED: vol = 0xA0 + (p->vol & 0x0F); break;
case VOLCMD_VIBRATO: vol = 0xB0 + (p->vol & 0x0F); break;
case VOLCMD_PANNING: vol = 0xC0 + (p->vol >> 2); if (vol > 0xCF) vol = 0xCF; break;
case VOLCMD_PANSLIDELEFT: vol = 0xD0 + (p->vol & 0x0F); break;
case VOLCMD_PANSLIDERIGHT: vol = 0xE0 + (p->vol & 0x0F); break;
case VOLCMD_TONEPORTAMENTO: vol = 0xF0 + (p->vol & 0x0F); break;
}
}
if ((note) && (p->instr) && (vol > 0x0F) && (command) && (param))
{
s[len++] = note;
s[len++] = p->instr;
s[len++] = vol;
s[len++] = command;
s[len++] = param;
} else
{
BYTE b = 0x80;
if (note) b |= 0x01;
if (p->instr) b |= 0x02;
if (vol >= 0x10) b |= 0x04;
if (command) b |= 0x08;
if (param) b |= 0x10;
s[len++] = b;
if (b & 1) s[len++] = note;
if (b & 2) s[len++] = p->instr;
if (b & 4) s[len++] = vol;
if (b & 8) s[len++] = command;
if (b & 16) s[len++] = param;
}
if (len > sizeof(s) - 5) break;
}
xmph[7] = (BYTE)(len & 0xFF);
xmph[8] = (BYTE)(len >> 8);
fwrite(xmph, 1, 9, f);
fwrite(s, 1, len, f);
} else
{
memset(&xmph, 0, sizeof(xmph));
xmph[0] = 9;
xmph[5] = (BYTE)(PatternSize[i] & 0xFF);
xmph[6] = (BYTE)(PatternSize[i] >> 8);
fwrite(xmph, 1, 9, f);
}
// Writing instruments
for (i=1; i<=header.instruments; i++)
{
MODINSTRUMENT *pins;
BYTE flags[32];
memset(&xmih, 0, sizeof(xmih));
memset(&xmsh, 0, sizeof(xmsh));
xmih.size = sizeof(xmih) + sizeof(xmsh);
memcpy(xmih.name, m_szNames[i], 22);
xmih.type = 0;
xmih.samples = 0;
if (m_nInstruments)
{
INSTRUMENTHEADER *penv = Headers[i];
if (penv)
{
memcpy(xmih.name, penv->name, 22);
xmih.type = penv->nMidiProgram;
xmsh.volfade = penv->nFadeOut;
xmsh.vnum = (BYTE)penv->nVolEnv;
xmsh.pnum = (BYTE)penv->nPanEnv;
if (xmsh.vnum > 12) xmsh.vnum = 12;
if (xmsh.pnum > 12) xmsh.pnum = 12;
for (UINT ienv=0; ienv<12; ienv++)
{
xmsh.venv[ienv*2] = penv->VolPoints[ienv];
xmsh.venv[ienv*2+1] = penv->VolEnv[ienv];
xmsh.penv[ienv*2] = penv->PanPoints[ienv];
xmsh.penv[ienv*2+1] = penv->PanEnv[ienv];
}
if (penv->dwFlags & ENV_VOLUME) xmsh.vtype |= 1;
if (penv->dwFlags & ENV_VOLSUSTAIN) xmsh.vtype |= 2;
if (penv->dwFlags & ENV_VOLLOOP) xmsh.vtype |= 4;
if (penv->dwFlags & ENV_PANNING) xmsh.ptype |= 1;
if (penv->dwFlags & ENV_PANSUSTAIN) xmsh.ptype |= 2;
if (penv->dwFlags & ENV_PANLOOP) xmsh.ptype |= 4;
xmsh.vsustain = (BYTE)penv->nVolSustainBegin;
xmsh.vloops = (BYTE)penv->nVolLoopStart;
xmsh.vloope = (BYTE)penv->nVolLoopEnd;
xmsh.psustain = (BYTE)penv->nPanSustainBegin;
xmsh.ploops = (BYTE)penv->nPanLoopStart;
xmsh.ploope = (BYTE)penv->nPanLoopEnd;
for (UINT j=0; j<96; j++) if (penv->Keyboard[j+12])
{
UINT k;
for (k=0; k<xmih.samples; k++) if (smptable[k] == penv->Keyboard[j+12]) break;
if (k == xmih.samples)
{
smptable[xmih.samples++] = penv->Keyboard[j+12];
}
if (xmih.samples >= 32) break;
xmsh.snum[j] = k;
}
// xmsh.reserved2 = xmih.samples;
}
} else
{
xmih.samples = 1;
// xmsh.reserved2 = 1;
smptable[0] = i;
}
xmsh.shsize = (xmih.samples) ? 40 : 0;
fwrite(&xmih, 1, sizeof(xmih), f);
if (smptable[0])
{
MODINSTRUMENT *pvib = &Ins[smptable[0]];
xmsh.vibtype = pvib->nVibType;
xmsh.vibsweep = pvib->nVibSweep;
xmsh.vibdepth = pvib->nVibDepth;
xmsh.vibrate = pvib->nVibRate;
}
fwrite(&xmsh, 1, xmih.size - sizeof(xmih), f);
if (!xmih.samples) continue;
for (UINT ins=0; ins<xmih.samples; ins++)
{
memset(&xmss, 0, sizeof(xmss));
if (smptable[ins]) memcpy(xmss.name, m_szNames[smptable[ins]], 22);
pins = &Ins[smptable[ins]];
xmss.samplen = pins->nLength;
xmss.loopstart = pins->nLoopStart;
xmss.looplen = pins->nLoopEnd - pins->nLoopStart;
xmss.vol = pins->nVolume / 4;
xmss.finetune = (char)pins->nFineTune;
xmss.type = 0;
if (pins->uFlags & CHN_LOOP) xmss.type = (pins->uFlags & CHN_PINGPONGLOOP) ? 2 : 1;
flags[ins] = RS_PCM8D;
#ifndef NO_PACKING
if (nPacking)
{
if ((!(pins->uFlags & (CHN_16BIT|CHN_STEREO)))
&& (CanPackSample((char *)pins->pSample, pins->nLength, nPacking)))
{
flags[ins] = RS_ADPCM4;
xmss.res = 0xAD;
}
} else
#endif
{
if (pins->uFlags & CHN_16BIT)
{
flags[ins] = RS_PCM16D;
xmss.type |= 0x10;
xmss.looplen *= 2;
xmss.loopstart *= 2;
xmss.samplen *= 2;
}
if (pins->uFlags & CHN_STEREO)
{
flags[ins] = (pins->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D;
xmss.type |= 0x20;
xmss.looplen *= 2;
xmss.loopstart *= 2;
xmss.samplen *= 2;
}
}
xmss.pan = 255;
if (pins->nPan < 256) xmss.pan = (BYTE)pins->nPan;
xmss.relnote = (signed char)pins->RelativeTone;
fwrite(&xmss, 1, xmsh.shsize, f);
}
for (UINT ismpd=0; ismpd<xmih.samples; ismpd++)
{
pins = &Ins[smptable[ismpd]];
if (pins->pSample)
{
#ifndef NO_PACKING
if ((flags[ismpd] == RS_ADPCM4) && (xmih.samples>1)) CanPackSample((char *)pins->pSample, pins->nLength, nPacking);
#endif // NO_PACKING
WriteSample(f, pins, flags[ismpd]);
}
}
}
// Writing song comments
if ((m_lpszSongComments) && (m_lpszSongComments[0]))
{
DWORD d = 0x74786574;
fwrite(&d, 1, 4, f);
d = strlen(m_lpszSongComments);
fwrite(&d, 1, 4, f);
fwrite(m_lpszSongComments, 1, d, f);
}
// Writing midi cfg
if (m_dwSongFlags & SONG_EMBEDMIDICFG)
{
DWORD d = 0x4944494D;
fwrite(&d, 1, 4, f);
d = sizeof(MODMIDICFG);
fwrite(&d, 1, 4, f);
fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f);
}
// Writing Pattern Names
if ((m_nPatternNames) && (m_lpszPatternNames))
{
DWORD dwLen = m_nPatternNames * MAX_PATTERNNAME;
while ((dwLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwLen-MAX_PATTERNNAME])) dwLen -= MAX_PATTERNNAME;
if (dwLen >= MAX_PATTERNNAME)
{
DWORD d = 0x4d414e50;
fwrite(&d, 1, 4, f);
fwrite(&dwLen, 1, 4, f);
fwrite(m_lpszPatternNames, 1, dwLen, f);
}
}
// Writing Channel Names
{
UINT nChnNames = 0;
for (UINT inam=0; inam<m_nChannels; inam++)
{
if (ChnSettings[inam].szName[0]) nChnNames = inam+1;
}
// Do it!
if (nChnNames)
{
DWORD dwLen = nChnNames * MAX_CHANNELNAME;
DWORD d = 0x4d414e43;
fwrite(&d, 1, 4, f);
fwrite(&dwLen, 1, 4, f);
for (UINT inam=0; inam<nChnNames; inam++)
{
fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f);
}
}
}
// Save mix plugins information
SaveMixPlugins(f);
fclose(f);
return TRUE;
}
#endif // MODPLUG_NO_FILESAVE

View File

@ -0,0 +1,505 @@
/*
* This source code is public domain.
*
* Handles unpacking of Powerpack PP20
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
#ifdef MMCMP_SUPPORT
BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
#pragma pack(1)
typedef struct MMCMPFILEHEADER
{
char id[8]; // "ziRCONia"
WORD hdrsize;
} MMCMPFILEHEADER, *LPMMCMPFILEHEADER;
typedef struct MMCMPHEADER
{
WORD version;
WORD nblocks;
DWORD filesize;
DWORD blktable;
BYTE glb_comp;
BYTE fmt_comp;
} MMCMPHEADER, *LPMMCMPHEADER;
typedef struct MMCMPBLOCK
{
DWORD unpk_size;
DWORD pk_size;
DWORD xor_chk;
WORD sub_blk;
WORD flags;
WORD tt_entries;
USHORT num_bits;
} MMCMPBLOCK, *LPMMCMPBLOCK;
typedef struct MMCMPSUBBLOCK
{
DWORD unpk_pos;
DWORD unpk_size;
} MMCMPSUBBLOCK, *LPMMCMPSUBBLOCK;
#pragma pack()
// make sure of structure sizes
typedef int chk_MMCMPFILEHEADER[(sizeof(struct MMCMPFILEHEADER) == 10) * 2 - 1];
typedef int chk_MMCMPHEADER[(sizeof(struct MMCMPHEADER) == 14) * 2 - 1];
typedef int chk_MMCMPBLOCK[(sizeof(struct MMCMPBLOCK) == 20) * 2 - 1];
typedef int chk_MMCMPSUBBLOCK[(sizeof(struct MMCMPSUBBLOCK) == 8) * 2 - 1];
#define MMCMP_COMP 0x0001
#define MMCMP_DELTA 0x0002
#define MMCMP_16BIT 0x0004
#define MMCMP_STEREO 0x0100
#define MMCMP_ABS16 0x0200
#define MMCMP_ENDIAN 0x0400
typedef struct MMCMPBITBUFFER
{
UINT bitcount;
DWORD bitbuffer;
LPCBYTE pSrc;
LPCBYTE pEnd;
DWORD GetBits(UINT nBits);
} MMCMPBITBUFFER;
DWORD MMCMPBITBUFFER::GetBits(UINT nBits)
//---------------------------------------
{
DWORD d;
if (!nBits) return 0;
while (bitcount < 24)
{
bitbuffer |= ((pSrc < pEnd) ? *pSrc++ : 0) << bitcount;
bitcount += 8;
}
d = bitbuffer & ((1 << nBits) - 1);
bitbuffer >>= nBits;
bitcount -= nBits;
return d;
}
//#define MMCMP_LOG
#ifdef MMCMP_LOG
extern void Log(LPCSTR s, ...);
#endif
static const DWORD MMCMP8BitCommands[8] =
{
0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF8
};
static const UINT MMCMP8BitFetch[8] =
{
3, 3, 3, 3, 2, 1, 0, 0
};
static const DWORD MMCMP16BitCommands[16] =
{
0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
};
static const UINT MMCMP16BitFetch[16] =
{
4, 4, 4, 4, 3, 2, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static void swap_mfh(LPMMCMPFILEHEADER fh)
{
fh->hdrsize = bswapLE16(fh->hdrsize);
}
static void swap_mmh(LPMMCMPHEADER mh)
{
mh->version = bswapLE16(mh->version);
mh->nblocks = bswapLE16(mh->nblocks);
mh->filesize = bswapLE32(mh->filesize);
mh->blktable = bswapLE32(mh->blktable);
}
static void swap_block (LPMMCMPBLOCK blk)
{
blk->unpk_size = bswapLE32(blk->unpk_size);
blk->pk_size = bswapLE32(blk->pk_size);
blk->xor_chk = bswapLE32(blk->xor_chk);
blk->sub_blk = bswapLE16(blk->sub_blk);
blk->flags = bswapLE16(blk->flags);
blk->tt_entries = bswapLE16(blk->tt_entries);
blk->num_bits = bswapLE16(blk->num_bits);
}
static void swap_subblock (LPMMCMPSUBBLOCK sblk)
{
sblk->unpk_pos = bswapLE32(sblk->unpk_pos);
sblk->unpk_size = bswapLE32(sblk->unpk_size);
}
BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
//---------------------------------------------------------
{
DWORD dwMemLength;
LPCBYTE lpMemFile;
LPBYTE pBuffer;
LPMMCMPFILEHEADER pmfh;
LPMMCMPHEADER pmmh;
const DWORD *pblk_table;
DWORD dwFileSize;
BYTE tmp0[32], tmp1[32];
if (PP20_Unpack(ppMemFile, pdwMemLength))
{
return TRUE;
}
dwMemLength = *pdwMemLength;
lpMemFile = *ppMemFile;
if ((dwMemLength < 256) || (!lpMemFile)) return FALSE;
memcpy(tmp0, lpMemFile, 24);
pmfh = (LPMMCMPFILEHEADER)(tmp0);
pmmh = (LPMMCMPHEADER)(tmp0+10);
swap_mfh(pmfh);
swap_mmh(pmmh);
if ((memcmp(pmfh->id,"ziRCONia",8) != 0) || (pmfh->hdrsize < 14)
|| (!pmmh->nblocks) || (pmmh->filesize < 16) || (pmmh->filesize > 0x8000000)
|| (pmmh->blktable >= dwMemLength) || (pmmh->blktable + 4*pmmh->nblocks > dwMemLength)) return FALSE;
dwFileSize = pmmh->filesize;
if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwFileSize + 31) & ~15)) == NULL) return FALSE;
pblk_table = (const DWORD *)(lpMemFile+pmmh->blktable);
for (UINT nBlock=0; nBlock<pmmh->nblocks; nBlock++)
{
DWORD dwMemPos = bswapLE32(pblk_table[nBlock]);
DWORD dwSubPos;
LPMMCMPBLOCK pblk;
LPMMCMPSUBBLOCK psubblk;
if (dwMemPos >= dwMemLength - 20) break;
memcpy(tmp1, lpMemFile+dwMemPos, 28);
pblk = (LPMMCMPBLOCK)(tmp1);
psubblk = (LPMMCMPSUBBLOCK)(tmp1+20);
swap_block(pblk);
swap_subblock(psubblk);
if (dwMemPos + 20 + pblk->sub_blk*8 >= dwMemLength) break;
dwSubPos = dwMemPos + 20;
dwMemPos += 20 + pblk->sub_blk*8;
#ifdef MMCMP_LOG
Log("block %d: flags=%04X sub_blocks=%d", nBlock, (UINT)pblk->flags, (UINT)pblk->sub_blk);
Log(" pksize=%d unpksize=%d", pblk->pk_size, pblk->unpk_size);
Log(" tt_entries=%d num_bits=%d\n", pblk->tt_entries, pblk->num_bits);
#endif
// Data is not packed
if (!(pblk->flags & MMCMP_COMP))
{
for (UINT i=0; i<pblk->sub_blk; i++)
{
if ((psubblk->unpk_pos >= dwFileSize) ||
(psubblk->unpk_size >= dwFileSize) ||
(psubblk->unpk_size > dwFileSize - psubblk->unpk_pos) ||
psubblk->unpk_size > dwMemLength - dwMemPos) break;
#ifdef MMCMP_LOG
Log(" Unpacked sub-block %d: offset %d, size=%d\n", i, psubblk->unpk_pos, psubblk->unpk_size);
#endif
memcpy(pBuffer+psubblk->unpk_pos, lpMemFile+dwMemPos, psubblk->unpk_size);
dwMemPos += psubblk->unpk_size;
memcpy(tmp1+20,lpMemFile+dwSubPos+i*8,8);
swap_subblock(psubblk);
}
} else
// Data is 16-bit packed
if (pblk->flags & MMCMP_16BIT && pblk->num_bits < 16)
{
MMCMPBITBUFFER bb;
LPWORD pDest = (LPWORD)(pBuffer + psubblk->unpk_pos);
DWORD dwSize = psubblk->unpk_size >> 1;
DWORD dwPos = 0;
UINT numbits = pblk->num_bits;
UINT subblk = 0, oldval = 0;
if (dwSize * 2 > dwFileSize-psubblk->unpk_pos ||
psubblk->unpk_pos > dwMemLength-dwMemPos)
break;
#ifdef MMCMP_LOG
Log(" 16-bit block: pos=%d size=%d ", psubblk->unpk_pos, psubblk->unpk_size);
if (pblk->flags & MMCMP_DELTA) Log("DELTA ");
if (pblk->flags & MMCMP_ABS16) Log("ABS16 ");
Log("\n");
#endif
bb.bitcount = 0;
bb.bitbuffer = 0;
bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
if (bb.pEnd > lpMemFile+dwMemLength)
bb.pEnd = lpMemFile+dwMemLength;
while (subblk < pblk->sub_blk)
{
UINT newval = 0x10000;
DWORD d = bb.GetBits(numbits+1);
if ((psubblk->unpk_pos >= dwFileSize) ||
(psubblk->unpk_size >= dwFileSize) ||
(psubblk->unpk_size > dwFileSize - psubblk->unpk_pos))
dwPos = dwSize;
if (d >= MMCMP16BitCommands[numbits])
{
UINT nFetch = MMCMP16BitFetch[numbits];
UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch);
if (newbits != numbits)
{
numbits = newbits & 0x0F;
} else
{
if ((d = bb.GetBits(4)) == 0x0F)
{
if (bb.GetBits(1)) break;
newval = 0xFFFF;
} else
{
newval = 0xFFF0 + d;
}
}
} else
{
newval = d;
}
if (newval < 0x10000 && dwPos < dwSize)
{
newval = (newval & 1) ? (UINT)(-(LONG)((newval+1) >> 1)) : (UINT)(newval >> 1);
if (pblk->flags & MMCMP_DELTA)
{
newval += oldval;
oldval = newval;
} else
if (!(pblk->flags & MMCMP_ABS16))
{
newval ^= 0x8000;
}
WORD swapped = (WORD)newval;
pDest[dwPos++] = bswapLE16(swapped);
}
if (dwPos >= dwSize)
{
subblk++;
memcpy(tmp1+20,lpMemFile+dwSubPos+subblk*8,8);
swap_subblock(psubblk);
dwPos = 0;
dwSize = psubblk->unpk_size >> 1;
if ( psubblk->unpk_pos >= dwFileSize ||
dwSize * 2 > dwFileSize ) {
break;
}
pDest = (LPWORD)(pBuffer + psubblk->unpk_pos);
}
}
} else if (pblk->num_bits < 8)
// Data is 8-bit packed
{
MMCMPBITBUFFER bb;
LPBYTE pDest = pBuffer + psubblk->unpk_pos;
DWORD dwSize = psubblk->unpk_size;
DWORD dwPos = 0;
UINT numbits = pblk->num_bits;
UINT subblk = 0, oldval = 0;
LPCBYTE ptable = lpMemFile+dwMemPos;
if (dwSize > dwFileSize-psubblk->unpk_pos ||
psubblk->unpk_pos > dwMemLength-dwMemPos)
break;
bb.bitcount = 0;
bb.bitbuffer = 0;
bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
if (bb.pEnd > lpMemFile+dwMemLength)
bb.pEnd = lpMemFile+dwMemLength;
while (subblk < pblk->sub_blk)
{
UINT newval = 0x100;
DWORD d = bb.GetBits(numbits+1);
if ((psubblk->unpk_pos >= dwFileSize) ||
(psubblk->unpk_size >= dwFileSize) ||
(psubblk->unpk_size > dwFileSize - (psubblk->unpk_pos)))
dwPos = dwSize;
if (d >= MMCMP8BitCommands[numbits])
{
UINT nFetch = MMCMP8BitFetch[numbits];
UINT newbits = bb.GetBits(nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch);
if (newbits != numbits)
{
numbits = newbits & 0x07;
} else
{
if ((d = bb.GetBits(3)) == 7)
{
if (bb.GetBits(1)) break;
newval = 0xFF;
} else
{
newval = 0xF8 + d;
}
}
} else
{
newval = d;
}
if (newval < 0x100 && dwPos < dwSize && dwMemPos < dwMemLength - newval)
{
int n = ptable[newval];
if (pblk->flags & MMCMP_DELTA)
{
n += oldval;
oldval = n;
}
pDest[dwPos++] = (BYTE)n;
}
if (dwPos >= dwSize)
{
subblk++;
memcpy(tmp1+20,lpMemFile+dwSubPos+subblk*8,8);
swap_subblock(psubblk);
dwPos = 0;
dwSize = psubblk->unpk_size;
if ( psubblk->unpk_pos >= dwFileSize ||
dwSize > dwFileSize )
break;
pDest = pBuffer + psubblk->unpk_pos;
}
}
} else
{
GlobalFreePtr(pBuffer);
return FALSE;
}
}
*ppMemFile = pBuffer;
*pdwMemLength = dwFileSize;
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
// PowerPack PP20 Unpacker
//
typedef struct _PPBITBUFFER
{
UINT bitcount;
ULONG bitbuffer;
LPCBYTE pStart;
LPCBYTE pSrc;
ULONG GetBits(UINT n);
} PPBITBUFFER;
ULONG PPBITBUFFER::GetBits(UINT n)
{
ULONG result = 0;
for (UINT i=0; i<n; i++)
{
if (!bitcount)
{
bitcount = 8;
if (pSrc != pStart) pSrc--;
bitbuffer = *pSrc;
}
result = (result<<1) | (bitbuffer&1);
bitbuffer >>= 1;
bitcount--;
}
return result;
}
static VOID PP20_DoUnpack(const BYTE *pSrc, UINT nSrcLen, BYTE *pDst, UINT nDstLen)
{
PPBITBUFFER BitBuffer;
ULONG nBytesLeft;
BitBuffer.pStart = pSrc;
BitBuffer.pSrc = pSrc + nSrcLen - 4;
BitBuffer.bitbuffer = 0;
BitBuffer.bitcount = 0;
BitBuffer.GetBits(pSrc[nSrcLen-1]);
nBytesLeft = nDstLen;
while (nBytesLeft > 0)
{
if (!BitBuffer.GetBits(1))
{
UINT n = 1;
while (n < nBytesLeft)
{
UINT code = BitBuffer.GetBits(2);
n += code;
if (code != 3) break;
}
for (UINT i=0; i<n; i++)
{
pDst[nBytesLeft - 1] = (BYTE)BitBuffer.GetBits(8);
if (!--nBytesLeft) break;
}
if (!nBytesLeft) break;
}
{
UINT n = BitBuffer.GetBits(2)+1;
UINT nbits = pSrc[n-1];
UINT nofs;
if (n==4)
{
nofs = BitBuffer.GetBits( (BitBuffer.GetBits(1)) ? nbits : 7 );
while (n < nBytesLeft)
{
UINT code = BitBuffer.GetBits(3);
n += code;
if (code != 7) break;
}
} else
{
nofs = BitBuffer.GetBits(nbits);
}
for (UINT i=0; i<=n; i++)
{
pDst[nBytesLeft-1] = (nBytesLeft+nofs < nDstLen) ? pDst[nBytesLeft+nofs] : 0;
if (!--nBytesLeft) break;
}
}
}
}
BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
{
DWORD dwMemLength = *pdwMemLength;
LPCBYTE lpMemFile = *ppMemFile;
DWORD dwDstLen;
LPBYTE pBuffer;
if ((!lpMemFile) || (dwMemLength < 256) || (memcmp(lpMemFile,"PP20",4) != 0)) return FALSE;
dwDstLen = (lpMemFile[dwMemLength-4]<<16) | (lpMemFile[dwMemLength-3]<<8) | (lpMemFile[dwMemLength-2]);
//Log("PP20 detected: Packed length=%d, Unpacked length=%d\n", dwMemLength, dwDstLen);
if ((dwDstLen < 512) || (dwDstLen > 0x400000) || (dwDstLen > 16*dwMemLength)) return FALSE;
if ((pBuffer = (LPBYTE)GlobalAllocPtr(GHND, (dwDstLen + 31) & ~15)) == NULL) return FALSE;
PP20_DoUnpack(lpMemFile+4, dwMemLength-4, pBuffer, dwDstLen);
*ppMemFile = pBuffer;
*pdwMemLength = dwDstLen;
return TRUE;
}
#endif /* MMCMP_SUPPORT */

View File

@ -0,0 +1,277 @@
/*
* This source code is public domain.
*
* Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
*/
#include "stdafx.h"
#include "modplug.h"
#include "sndfile.h"
struct _ModPlugFile
{
CSoundFile mSoundFile;
};
namespace ModPlug
{
ModPlug_Settings gSettings =
{
MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION,
2, // mChannels
16, // mBits
44100, // mFrequency
MODPLUG_RESAMPLE_LINEAR, //mResamplingMode
128, // mStereoSeparation
32, // mMaxMixChannels
0,
0,
0,
0,
0,
0,
0
};
int gSampleSize;
void UpdateSettings(bool updateBasicConfig)
{
if(gSettings.mFlags & MODPLUG_ENABLE_REVERB)
{
CSoundFile::SetReverbParameters(gSettings.mReverbDepth,
gSettings.mReverbDelay);
}
if(gSettings.mFlags & MODPLUG_ENABLE_MEGABASS)
{
CSoundFile::SetXBassParameters(gSettings.mBassAmount,
gSettings.mBassRange);
}
else // modplug seems to ignore the SetWaveConfigEx() setting for bass boost
CSoundFile::SetXBassParameters(0, 0);
if(gSettings.mFlags & MODPLUG_ENABLE_SURROUND)
{
CSoundFile::SetSurroundParameters(gSettings.mSurroundDepth,
gSettings.mSurroundDelay);
}
if(updateBasicConfig)
{
CSoundFile::SetWaveConfig(gSettings.mFrequency,
gSettings.mBits,
gSettings.mChannels);
CSoundFile::SetMixConfig(gSettings.mStereoSeparation,
gSettings.mMaxMixChannels);
gSampleSize = gSettings.mBits / 8 * gSettings.mChannels;
}
CSoundFile::SetWaveConfigEx(gSettings.mFlags & MODPLUG_ENABLE_SURROUND,
!(gSettings.mFlags & MODPLUG_ENABLE_OVERSAMPLING),
gSettings.mFlags & MODPLUG_ENABLE_REVERB,
true,
gSettings.mFlags & MODPLUG_ENABLE_MEGABASS,
gSettings.mFlags & MODPLUG_ENABLE_NOISE_REDUCTION,
false);
CSoundFile::SetResamplingMode(gSettings.mResamplingMode);
}
}
ModPlugFile* ModPlug_Load(const void* data, int size)
{
ModPlugFile* result = new ModPlugFile;
ModPlug::UpdateSettings(true);
if(result->mSoundFile.Create((const BYTE*)data, size))
{
result->mSoundFile.SetRepeatCount(ModPlug::gSettings.mLoopCount);
return result;
}
else
{
delete result;
return NULL;
}
}
void ModPlug_Unload(ModPlugFile* file)
{
file->mSoundFile.Destroy();
delete file;
}
int ModPlug_Read(ModPlugFile* file, void* buffer, int size)
{
return file->mSoundFile.Read(buffer, size) * ModPlug::gSampleSize;
}
const char* ModPlug_GetName(ModPlugFile* file)
{
return file->mSoundFile.GetTitle();
}
int ModPlug_GetLength(ModPlugFile* file)
{
return file->mSoundFile.GetSongTime() * 1000;
}
void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc)
{
file->mSoundFile.gpSndMixHook = (LPSNDMIXHOOKPROC)proc ;
return;
}
void ModPlug_UnloadMixerCallback(ModPlugFile* file)
{
file->mSoundFile.gpSndMixHook = NULL;
return ;
}
unsigned int ModPlug_GetMasterVolume(ModPlugFile* file)
{
return (unsigned int)file->mSoundFile.m_nMasterVolume;
}
void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol)
{
(void)file->mSoundFile.SetMasterVolume( (UINT)cvol,
FALSE );
return ;
}
int ModPlug_GetCurrentSpeed(ModPlugFile* file)
{
return file->mSoundFile.m_nMusicSpeed;
}
int ModPlug_GetCurrentTempo(ModPlugFile* file)
{
return file->mSoundFile.m_nMusicTempo;
}
int ModPlug_GetCurrentOrder(ModPlugFile* file)
{
return file->mSoundFile.GetCurrentOrder();
}
int ModPlug_GetCurrentPattern(ModPlugFile* file)
{
return file->mSoundFile.GetCurrentPattern();
}
int ModPlug_GetCurrentRow(ModPlugFile* file)
{
return file->mSoundFile.m_nRow;
}
int ModPlug_GetPlayingChannels(ModPlugFile* file)
{
return ( file->mSoundFile.m_nMixChannels < file->mSoundFile.m_nMaxMixChannels ? file->mSoundFile.m_nMixChannels : file->mSoundFile.m_nMaxMixChannels );
}
void ModPlug_SeekOrder(ModPlugFile* file,int order)
{
file->mSoundFile.SetCurrentOrder(order);
}
int ModPlug_GetModuleType(ModPlugFile* file)
{
return file->mSoundFile.m_nType;
}
char* ModPlug_GetMessage(ModPlugFile* file)
{
return file->mSoundFile.m_lpszSongComments;
}
#ifndef MODPLUG_NO_FILESAVE
char ModPlug_ExportS3M(ModPlugFile* file,const char* filepath)
{
return (char)file->mSoundFile.SaveS3M(filepath,0);
}
char ModPlug_ExportXM(ModPlugFile* file,const char* filepath)
{
return (char)file->mSoundFile.SaveXM(filepath,0);
}
char ModPlug_ExportMOD(ModPlugFile* file,const char* filepath)
{
return (char)file->mSoundFile.SaveMod(filepath,0);
}
char ModPlug_ExportIT(ModPlugFile* file,const char* filepath)
{
return (char)file->mSoundFile.SaveIT(filepath,0);
}
#endif // MODPLUG_NO_FILESAVE
unsigned int ModPlug_NumInstruments(ModPlugFile* file)
{
return file->mSoundFile.m_nInstruments;
}
unsigned int ModPlug_NumSamples(ModPlugFile* file)
{
return file->mSoundFile.m_nSamples;
}
unsigned int ModPlug_NumPatterns(ModPlugFile* file)
{
return file->mSoundFile.GetNumPatterns();
}
unsigned int ModPlug_NumChannels(ModPlugFile* file)
{
return file->mSoundFile.GetNumChannels();
}
unsigned int ModPlug_SampleName(ModPlugFile* file,unsigned int qual,char* buff)
{
return file->mSoundFile.GetSampleName(qual,buff);
}
unsigned int ModPlug_InstrumentName(ModPlugFile* file,unsigned int qual,char* buff)
{
return file->mSoundFile.GetInstrumentName(qual,buff);
}
ModPlugNote* ModPlug_GetPattern(ModPlugFile* file,int pattern,unsigned int* numrows) {
if ( pattern<MAX_PATTERNS && pattern >= 0) {
if (file->mSoundFile.Patterns[pattern]) {
if (numrows) *numrows=(unsigned int)file->mSoundFile.PatternSize[pattern];
return (ModPlugNote*)file->mSoundFile.Patterns[pattern];
}
}
return NULL;
}
void ModPlug_Seek(ModPlugFile* file, int millisecond)
{
int maxpos;
int maxtime = file->mSoundFile.GetSongTime() * 1000;
float postime;
if(millisecond > maxtime)
millisecond = maxtime;
maxpos = file->mSoundFile.GetMaxPosition();
postime = 0.0f;
if (maxtime != 0)
postime = (float)maxpos / (float)maxtime;
file->mSoundFile.SetCurrentPos((int)(millisecond * postime));
}
void ModPlug_GetSettings(ModPlug_Settings* settings)
{
memcpy(settings, &ModPlug::gSettings, sizeof(ModPlug_Settings));
}
void ModPlug_SetSettings(const ModPlug_Settings* settings)
{
memcpy(&ModPlug::gSettings, settings, sizeof(ModPlug_Settings));
ModPlug::UpdateSettings(false); // do not update basic config.
}

View File

@ -0,0 +1,185 @@
/*
* This source code is public domain.
*
* Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
*/
#ifndef MODPLUG_H__INCLUDED
#define MODPLUG_H__INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
# if defined(MODPLUG_BUILD) && defined(DLL_EXPORT) /* building libmodplug as a dll for windows */
# define MODPLUG_EXPORT __declspec(dllexport)
# elif defined(MODPLUG_BUILD) || defined(MODPLUG_STATIC) /* building or using static libmodplug for windows */
# define MODPLUG_EXPORT
# else
# define MODPLUG_EXPORT __declspec(dllimport) /* using libmodplug dll for windows */
# endif
#elif defined(MODPLUG_BUILD) && defined(SYM_VISIBILITY)
# define MODPLUG_EXPORT __attribute__((visibility("default")))
#else
#define MODPLUG_EXPORT
#endif
struct _ModPlugFile;
typedef struct _ModPlugFile ModPlugFile;
struct _ModPlugNote {
unsigned char Note;
unsigned char Instrument;
unsigned char VolumeEffect;
unsigned char Effect;
unsigned char Volume;
unsigned char Parameter;
};
typedef struct _ModPlugNote ModPlugNote;
typedef void (*ModPlugMixerProc)(int*, unsigned long, unsigned long);
/* Load a mod file. [data] should point to a block of memory containing the complete
* file, and [size] should be the size of that block.
* Return the loaded mod file on success, or NULL on failure. */
MODPLUG_EXPORT ModPlugFile* ModPlug_Load(const void* data, int size);
/* Unload a mod file. */
MODPLUG_EXPORT void ModPlug_Unload(ModPlugFile* file);
/* Read sample data into the buffer. Returns the number of bytes read. If the end
* of the mod has been reached, zero is returned. */
MODPLUG_EXPORT int ModPlug_Read(ModPlugFile* file, void* buffer, int size);
/* Get the name of the mod. The returned buffer is stored within the ModPlugFile
* structure and will remain valid until you unload the file. */
MODPLUG_EXPORT const char* ModPlug_GetName(ModPlugFile* file);
/* Get the length of the mod, in milliseconds. Note that this result is not always
* accurate, especially in the case of mods with loops. */
MODPLUG_EXPORT int ModPlug_GetLength(ModPlugFile* file);
/* Seek to a particular position in the song. Note that seeking and MODs don't mix very
* well. Some mods will be missing instruments for a short time after a seek, as ModPlug
* does not scan the sequence backwards to find out which instruments were supposed to be
* playing at that time. (Doing so would be difficult and not very reliable.) Also,
* note that seeking is not very exact in some mods -- especially those for which
* ModPlug_GetLength() does not report the full length. */
MODPLUG_EXPORT void ModPlug_Seek(ModPlugFile* file, int millisecond);
enum _ModPlug_Flags
{
MODPLUG_ENABLE_OVERSAMPLING = 1 << 0, /* Enable oversampling (*highly* recommended) */
MODPLUG_ENABLE_NOISE_REDUCTION = 1 << 1, /* Enable noise reduction */
MODPLUG_ENABLE_REVERB = 1 << 2, /* Enable reverb */
MODPLUG_ENABLE_MEGABASS = 1 << 3, /* Enable megabass */
MODPLUG_ENABLE_SURROUND = 1 << 4 /* Enable surround sound. */
};
enum _ModPlug_ResamplingMode
{
MODPLUG_RESAMPLE_NEAREST = 0, /* No interpolation (very fast, extremely bad sound quality) */
MODPLUG_RESAMPLE_LINEAR = 1, /* Linear interpolation (fast, good quality) */
MODPLUG_RESAMPLE_SPLINE = 2, /* Cubic spline interpolation (high quality) */
MODPLUG_RESAMPLE_FIR = 3 /* 8-tap fir filter (extremely high quality) */
};
typedef struct _ModPlug_Settings
{
int mFlags; /* One or more of the MODPLUG_ENABLE_* flags above, bitwise-OR'ed */
/* Note that ModPlug always decodes sound at 44100kHz, 32 bit, stereo and then
* down-mixes to the settings you choose. */
int mChannels; /* Number of channels - 1 for mono or 2 for stereo */
int mBits; /* Bits per sample - 8, 16, or 32 */
int mFrequency; /* Sampling rate - 11025, 22050, or 44100 */
int mResamplingMode; /* One of MODPLUG_RESAMPLE_*, above */
int mStereoSeparation; /* Stereo separation, 1 - 256 */
int mMaxMixChannels; /* Maximum number of mixing channels (polyphony), 32 - 256 */
int mReverbDepth; /* Reverb level 0(quiet)-100(loud) */
int mReverbDelay; /* Reverb delay in ms, usually 40-200ms */
int mBassAmount; /* XBass level 0(quiet)-100(loud) */
int mBassRange; /* XBass cutoff in Hz 10-100 */
int mSurroundDepth; /* Surround level 0(quiet)-100(heavy) */
int mSurroundDelay; /* Surround delay in ms, usually 5-40ms */
int mLoopCount; /* Number of times to loop. Zero prevents looping.
* -1 loops forever. */
} ModPlug_Settings;
/* Get and set the mod decoder settings. All options, except for channels, bits-per-sample,
* sampling rate, and loop count, will take effect immediately. Those options which don't
* take effect immediately will take effect the next time you load a mod. */
MODPLUG_EXPORT void ModPlug_GetSettings(ModPlug_Settings* settings);
MODPLUG_EXPORT void ModPlug_SetSettings(const ModPlug_Settings* settings);
/* New ModPlug API Functions */
/* NOTE: Master Volume (1-512) */
MODPLUG_EXPORT unsigned int ModPlug_GetMasterVolume(ModPlugFile* file) ;
MODPLUG_EXPORT void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol) ;
MODPLUG_EXPORT int ModPlug_GetCurrentSpeed(ModPlugFile* file);
MODPLUG_EXPORT int ModPlug_GetCurrentTempo(ModPlugFile* file);
MODPLUG_EXPORT int ModPlug_GetCurrentOrder(ModPlugFile* file);
MODPLUG_EXPORT int ModPlug_GetCurrentPattern(ModPlugFile* file);
MODPLUG_EXPORT int ModPlug_GetCurrentRow(ModPlugFile* file);
MODPLUG_EXPORT int ModPlug_GetPlayingChannels(ModPlugFile* file);
MODPLUG_EXPORT void ModPlug_SeekOrder(ModPlugFile* file,int order);
MODPLUG_EXPORT int ModPlug_GetModuleType(ModPlugFile* file);
MODPLUG_EXPORT char* ModPlug_GetMessage(ModPlugFile* file);
#define MODPLUG_NO_FILESAVE /* experimental yet. must match stdafx.h. */
#ifndef MODPLUG_NO_FILESAVE
/*
* EXPERIMENTAL Export Functions
*/
/*Export to a Scream Tracker 3 S3M module. EXPERIMENTAL (only works on Little-Endian platforms)*/
MODPLUG_EXPORT char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath);
/*Export to a Extended Module (XM). EXPERIMENTAL (only works on Little-Endian platforms)*/
MODPLUG_EXPORT char ModPlug_ExportXM(ModPlugFile* file, const char* filepath);
/*Export to a Amiga MOD file. EXPERIMENTAL.*/
MODPLUG_EXPORT char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath);
/*Export to a Impulse Tracker IT file. Should work OK in Little-Endian & Big-Endian platforms :-) */
MODPLUG_EXPORT char ModPlug_ExportIT(ModPlugFile* file, const char* filepath);
#endif /* MODPLUG_NO_FILESAVE */
MODPLUG_EXPORT unsigned int ModPlug_NumInstruments(ModPlugFile* file);
MODPLUG_EXPORT unsigned int ModPlug_NumSamples(ModPlugFile* file);
MODPLUG_EXPORT unsigned int ModPlug_NumPatterns(ModPlugFile* file);
MODPLUG_EXPORT unsigned int ModPlug_NumChannels(ModPlugFile* file);
MODPLUG_EXPORT unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff);
MODPLUG_EXPORT unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff);
/*
* Retrieve pattern note-data
*/
MODPLUG_EXPORT ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows);
/*
* =================
* Mixer callback
* =================
*
* Use this callback if you want to 'modify' the mixed data of LibModPlug.
*
* void proc(int* buffer,unsigned long channels,unsigned long nsamples) ;
*
* 'buffer': A buffer of mixed samples
* 'channels': N. of channels in the buffer
* 'nsamples': N. of samples in the buffeer (without taking care of n.channels)
*
* (Samples are signed 32-bit integers)
*/
MODPLUG_EXPORT void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc) ;
MODPLUG_EXPORT void ModPlug_UnloadMixerCallback(ModPlugFile* file) ;
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -0,0 +1,485 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
#ifdef MODPLUG_FASTSOUNDLIB
#define MODPLUG_NO_REVERB
#endif
// Delayed Surround Filters
#ifndef MODPLUG_FASTSOUNDLIB
#define nDolbyHiFltAttn 6
#define nDolbyHiFltMask 3
#define DOLBYATTNROUNDUP 31
#else
#define nDolbyHiFltAttn 3
#define nDolbyHiFltMask 3
#define DOLBYATTNROUNDUP 3
#endif
// Bass Expansion
#define XBASS_DELAY 14 // 2.5 ms
// Buffer Sizes
#define XBASSBUFFERSIZE 64 // 2 ms at 50KHz
#define FILTERBUFFERSIZE 64 // 1.25 ms
#define SURROUNDBUFFERSIZE ((MAX_SAMPLE_RATE * 50) / 1000)
#define REVERBBUFFERSIZE ((MAX_SAMPLE_RATE * 200) / 1000)
#define REVERBBUFFERSIZE2 ((REVERBBUFFERSIZE*13) / 17)
#define REVERBBUFFERSIZE3 ((REVERBBUFFERSIZE*7) / 13)
#define REVERBBUFFERSIZE4 ((REVERBBUFFERSIZE*7) / 19)
// DSP Effects: PUBLIC members
UINT CSoundFile::m_nXBassDepth = 6;
UINT CSoundFile::m_nXBassRange = XBASS_DELAY;
UINT CSoundFile::m_nReverbDepth = 1;
UINT CSoundFile::m_nReverbDelay = 100;
UINT CSoundFile::m_nProLogicDepth = 12;
UINT CSoundFile::m_nProLogicDelay = 20;
////////////////////////////////////////////////////////////////////
// DSP Effects internal state
// Bass Expansion: low-pass filter
static LONG nXBassSum = 0;
static LONG nXBassBufferPos = 0;
static LONG nXBassDlyPos = 0;
static LONG nXBassMask = 0;
// Noise Reduction: simple low-pass filter
static LONG nLeftNR = 0;
static LONG nRightNR = 0;
// Surround Encoding: 1 delay line + low-pass filter + high-pass filter
static LONG nSurroundSize = 0;
static LONG nSurroundPos = 0;
static LONG nDolbyDepth = 0;
static LONG nDolbyLoDlyPos = 0;
static LONG nDolbyLoFltPos = 0;
static LONG nDolbyLoFltSum = 0;
static LONG nDolbyHiFltPos = 0;
static LONG nDolbyHiFltSum = 0;
// Reverb: 4 delay lines + high-pass filter + low-pass filter
#ifndef MODPLUG_NO_REVERB
static LONG nReverbSize = 0;
static LONG nReverbBufferPos = 0;
static LONG nReverbSize2 = 0;
static LONG nReverbBufferPos2 = 0;
static LONG nReverbSize3 = 0;
static LONG nReverbBufferPos3 = 0;
static LONG nReverbSize4 = 0;
static LONG nReverbBufferPos4 = 0;
static LONG nReverbLoFltSum = 0;
static LONG nReverbLoFltPos = 0;
static LONG nReverbLoDlyPos = 0;
static LONG nFilterAttn = 0;
static LONG gRvbLowPass[8];
static LONG gRvbLPPos = 0;
static LONG gRvbLPSum = 0;
static LONG ReverbLoFilterBuffer[XBASSBUFFERSIZE];
static LONG ReverbLoFilterDelay[XBASSBUFFERSIZE];
static LONG ReverbBuffer[REVERBBUFFERSIZE];
static LONG ReverbBuffer2[REVERBBUFFERSIZE2];
static LONG ReverbBuffer3[REVERBBUFFERSIZE3];
static LONG ReverbBuffer4[REVERBBUFFERSIZE4];
#endif
static LONG XBassBuffer[XBASSBUFFERSIZE];
static LONG XBassDelay[XBASSBUFFERSIZE];
static LONG DolbyLoFilterBuffer[XBASSBUFFERSIZE];
static LONG DolbyLoFilterDelay[XBASSBUFFERSIZE];
static LONG DolbyHiFilterBuffer[FILTERBUFFERSIZE];
static LONG SurroundBuffer[SURROUNDBUFFERSIZE];
// Access the main temporary mix buffer directly: avoids an extra pointer
extern int MixSoundBuffer[MIXBUFFERSIZE*2];
//cextern int MixReverbBuffer[MIXBUFFERSIZE*2];
extern int MixReverbBuffer[MIXBUFFERSIZE*2];
static UINT GetMaskFromSize(UINT len)
//-----------------------------------
{
UINT n = 2;
while (n <= len) n <<= 1;
return ((n >> 1) - 1);
}
void CSoundFile::InitializeDSP(BOOL bReset)
//-----------------------------------------
{
if (!m_nReverbDelay) m_nReverbDelay = 100;
if (!m_nXBassRange) m_nXBassRange = XBASS_DELAY;
if (!m_nProLogicDelay) m_nProLogicDelay = 20;
if (m_nXBassDepth > 8) m_nXBassDepth = 8;
if (m_nXBassDepth < 2) m_nXBassDepth = 2;
if (bReset)
{
// Noise Reduction
nLeftNR = nRightNR = 0;
}
// Pro-Logic Surround
nSurroundPos = nSurroundSize = 0;
nDolbyLoFltPos = nDolbyLoFltSum = nDolbyLoDlyPos = 0;
nDolbyHiFltPos = nDolbyHiFltSum = 0;
if (gdwSoundSetup & SNDMIX_SURROUND)
{
memset(DolbyLoFilterBuffer, 0, sizeof(DolbyLoFilterBuffer));
memset(DolbyHiFilterBuffer, 0, sizeof(DolbyHiFilterBuffer));
memset(DolbyLoFilterDelay, 0, sizeof(DolbyLoFilterDelay));
memset(SurroundBuffer, 0, sizeof(SurroundBuffer));
nSurroundSize = (gdwMixingFreq * m_nProLogicDelay) / 1000;
if (nSurroundSize > SURROUNDBUFFERSIZE) nSurroundSize = SURROUNDBUFFERSIZE;
if (m_nProLogicDepth < 8) nDolbyDepth = (32 >> m_nProLogicDepth) + 32;
else nDolbyDepth = (m_nProLogicDepth < 16) ? (8 + (m_nProLogicDepth - 8) * 7) : 64;
nDolbyDepth >>= 2;
}
// Reverb Setup
#ifndef MODPLUG_NO_REVERB
if (gdwSoundSetup & SNDMIX_REVERB)
{
UINT nrs = (gdwMixingFreq * m_nReverbDelay) / 1000;
UINT nfa = m_nReverbDepth+1;
if (nrs > REVERBBUFFERSIZE) nrs = REVERBBUFFERSIZE;
if ((bReset) || (nrs != (UINT)nReverbSize) || (nfa != (UINT)nFilterAttn))
{
nFilterAttn = nfa;
nReverbSize = nrs;
nReverbBufferPos = nReverbBufferPos2 = nReverbBufferPos3 = nReverbBufferPos4 = 0;
nReverbLoFltSum = nReverbLoFltPos = nReverbLoDlyPos = 0;
gRvbLPSum = gRvbLPPos = 0;
nReverbSize2 = (nReverbSize * 13) / 17;
if (nReverbSize2 > REVERBBUFFERSIZE2) nReverbSize2 = REVERBBUFFERSIZE2;
nReverbSize3 = (nReverbSize * 7) / 13;
if (nReverbSize3 > REVERBBUFFERSIZE3) nReverbSize3 = REVERBBUFFERSIZE3;
nReverbSize4 = (nReverbSize * 7) / 19;
if (nReverbSize4 > REVERBBUFFERSIZE4) nReverbSize4 = REVERBBUFFERSIZE4;
memset(ReverbLoFilterBuffer, 0, sizeof(ReverbLoFilterBuffer));
memset(ReverbLoFilterDelay, 0, sizeof(ReverbLoFilterDelay));
memset(ReverbBuffer, 0, sizeof(ReverbBuffer));
memset(ReverbBuffer2, 0, sizeof(ReverbBuffer2));
memset(ReverbBuffer3, 0, sizeof(ReverbBuffer3));
memset(ReverbBuffer4, 0, sizeof(ReverbBuffer4));
memset(gRvbLowPass, 0, sizeof(gRvbLowPass));
}
} else nReverbSize = 0;
#endif
BOOL bResetBass = FALSE;
// Bass Expansion Reset
if (gdwSoundSetup & SNDMIX_MEGABASS)
{
UINT nXBassSamples = (gdwMixingFreq * m_nXBassRange) / 10000;
if (nXBassSamples > XBASSBUFFERSIZE) nXBassSamples = XBASSBUFFERSIZE;
UINT mask = GetMaskFromSize(nXBassSamples);
if ((bReset) || (mask != (UINT)nXBassMask))
{
nXBassMask = mask;
bResetBass = TRUE;
}
} else
{
nXBassMask = 0;
bResetBass = TRUE;
}
if (bResetBass)
{
nXBassSum = nXBassBufferPos = nXBassDlyPos = 0;
memset(XBassBuffer, 0, sizeof(XBassBuffer));
memset(XBassDelay, 0, sizeof(XBassDelay));
}
}
void CSoundFile::ProcessStereoDSP(int count)
//------------------------------------------
{
#ifndef MODPLUG_NO_REVERB
// Reverb
if (gdwSoundSetup & SNDMIX_REVERB)
{
int *pr = MixSoundBuffer, *pin = MixReverbBuffer, rvbcount = count;
do
{
int echo = ReverbBuffer[nReverbBufferPos] + ReverbBuffer2[nReverbBufferPos2]
+ ReverbBuffer3[nReverbBufferPos3] + ReverbBuffer4[nReverbBufferPos4]; // echo = reverb signal
// Delay line and remove Low Frequencies // v = original signal
int echodly = ReverbLoFilterDelay[nReverbLoDlyPos]; // echodly = delayed signal
ReverbLoFilterDelay[nReverbLoDlyPos] = echo >> 1;
nReverbLoDlyPos++;
nReverbLoDlyPos &= 0x1F;
int n = nReverbLoFltPos;
nReverbLoFltSum -= ReverbLoFilterBuffer[n];
int tmp = echo / 128;
ReverbLoFilterBuffer[n] = tmp;
nReverbLoFltSum += tmp;
echodly -= nReverbLoFltSum;
nReverbLoFltPos = (n + 1) & 0x3F;
// Reverb
int v = (pin[0]+pin[1]) >> nFilterAttn;
pr[0] += pin[0] + echodly;
pr[1] += pin[1] + echodly;
v += echodly >> 2;
ReverbBuffer3[nReverbBufferPos3] = v;
ReverbBuffer4[nReverbBufferPos4] = v;
v += echodly >> 4;
v >>= 1;
gRvbLPSum -= gRvbLowPass[gRvbLPPos];
gRvbLPSum += v;
gRvbLowPass[gRvbLPPos] = v;
gRvbLPPos++;
gRvbLPPos &= 7;
int vlp = gRvbLPSum >> 2;
ReverbBuffer[nReverbBufferPos] = vlp;
ReverbBuffer2[nReverbBufferPos2] = vlp;
if (++nReverbBufferPos >= nReverbSize) nReverbBufferPos = 0;
if (++nReverbBufferPos2 >= nReverbSize2) nReverbBufferPos2 = 0;
if (++nReverbBufferPos3 >= nReverbSize3) nReverbBufferPos3 = 0;
if (++nReverbBufferPos4 >= nReverbSize4) nReverbBufferPos4 = 0;
pr += 2;
pin += 2;
} while (--rvbcount);
}
#endif
// Dolby Pro-Logic Surround
if (gdwSoundSetup & SNDMIX_SURROUND)
{
int *pr = MixSoundBuffer, n = nDolbyLoFltPos;
for (int r=count; r; r--)
{
int v = (pr[0]+pr[1]+DOLBYATTNROUNDUP) >> (nDolbyHiFltAttn+1);
#ifndef MODPLUG_FASTSOUNDLIB
v *= (int)nDolbyDepth;
#endif
// Low-Pass Filter
nDolbyHiFltSum -= DolbyHiFilterBuffer[nDolbyHiFltPos];
DolbyHiFilterBuffer[nDolbyHiFltPos] = v;
nDolbyHiFltSum += v;
v = nDolbyHiFltSum;
nDolbyHiFltPos++;
nDolbyHiFltPos &= nDolbyHiFltMask;
// Surround
int secho = SurroundBuffer[nSurroundPos];
SurroundBuffer[nSurroundPos] = v;
// Delay line and remove low frequencies
v = DolbyLoFilterDelay[nDolbyLoDlyPos]; // v = delayed signal
DolbyLoFilterDelay[nDolbyLoDlyPos] = secho; // secho = signal
nDolbyLoDlyPos++;
nDolbyLoDlyPos &= 0x1F;
nDolbyLoFltSum -= DolbyLoFilterBuffer[n];
int tmp = secho / 64;
DolbyLoFilterBuffer[n] = tmp;
nDolbyLoFltSum += tmp;
v -= nDolbyLoFltSum;
n++;
n &= 0x3F;
// Add echo
pr[0] += v;
pr[1] -= v;
if (++nSurroundPos >= nSurroundSize) nSurroundPos = 0;
pr += 2;
}
nDolbyLoFltPos = n;
}
// Bass Expansion
if (gdwSoundSetup & SNDMIX_MEGABASS)
{
int *px = MixSoundBuffer;
int xba = m_nXBassDepth+1, xbamask = (1 << xba) - 1;
int n = nXBassBufferPos;
for (int x=count; x; x--)
{
nXBassSum -= XBassBuffer[n];
int tmp0 = px[0] + px[1];
int tmp = (tmp0 + ((tmp0 >> 31) & xbamask)) >> xba;
XBassBuffer[n] = tmp;
nXBassSum += tmp;
int v = XBassDelay[nXBassDlyPos];
XBassDelay[nXBassDlyPos] = px[0];
px[0] = v + nXBassSum;
v = XBassDelay[nXBassDlyPos+1];
XBassDelay[nXBassDlyPos+1] = px[1];
px[1] = v + nXBassSum;
nXBassDlyPos = (nXBassDlyPos + 2) & nXBassMask;
px += 2;
n++;
n &= nXBassMask;
}
nXBassBufferPos = n;
}
// Noise Reduction
if (gdwSoundSetup & SNDMIX_NOISEREDUCTION)
{
int n1 = nLeftNR, n2 = nRightNR;
int *pnr = MixSoundBuffer;
for (int nr=count; nr; nr--)
{
int vnr = pnr[0] >> 1;
pnr[0] = vnr + n1;
n1 = vnr;
vnr = pnr[1] >> 1;
pnr[1] = vnr + n2;
n2 = vnr;
pnr += 2;
}
nLeftNR = n1;
nRightNR = n2;
}
}
void CSoundFile::ProcessMonoDSP(int count)
//----------------------------------------
{
#ifndef MODPLUG_NO_REVERB
// Reverb
if (gdwSoundSetup & SNDMIX_REVERB)
{
int *pr = MixSoundBuffer, rvbcount = count, *pin = MixReverbBuffer;
do
{
int echo = ReverbBuffer[nReverbBufferPos] + ReverbBuffer2[nReverbBufferPos2]
+ ReverbBuffer3[nReverbBufferPos3] + ReverbBuffer4[nReverbBufferPos4]; // echo = reverb signal
// Delay line and remove Low Frequencies // v = original signal
int echodly = ReverbLoFilterDelay[nReverbLoDlyPos]; // echodly = delayed signal
ReverbLoFilterDelay[nReverbLoDlyPos] = echo >> 1;
nReverbLoDlyPos++;
nReverbLoDlyPos &= 0x1F;
int n = nReverbLoFltPos;
nReverbLoFltSum -= ReverbLoFilterBuffer[n];
int tmp = echo / 128;
ReverbLoFilterBuffer[n] = tmp;
nReverbLoFltSum += tmp;
echodly -= nReverbLoFltSum;
nReverbLoFltPos = (n + 1) & 0x3F;
// Reverb
int v = pin[0] >> (nFilterAttn-1);
*pr++ += pin[0] + echodly;
pin++;
v += echodly >> 2;
ReverbBuffer3[nReverbBufferPos3] = v;
ReverbBuffer4[nReverbBufferPos4] = v;
v += echodly >> 4;
v >>= 1;
gRvbLPSum -= gRvbLowPass[gRvbLPPos];
gRvbLPSum += v;
gRvbLowPass[gRvbLPPos] = v;
gRvbLPPos++;
gRvbLPPos &= 7;
int vlp = gRvbLPSum >> 2;
ReverbBuffer[nReverbBufferPos] = vlp;
ReverbBuffer2[nReverbBufferPos2] = vlp;
if (++nReverbBufferPos >= nReverbSize) nReverbBufferPos = 0;
if (++nReverbBufferPos2 >= nReverbSize2) nReverbBufferPos2 = 0;
if (++nReverbBufferPos3 >= nReverbSize3) nReverbBufferPos3 = 0;
if (++nReverbBufferPos4 >= nReverbSize4) nReverbBufferPos4 = 0;
} while (--rvbcount);
}
#endif
// Bass Expansion
if (gdwSoundSetup & SNDMIX_MEGABASS)
{
int *px = MixSoundBuffer;
int xba = m_nXBassDepth, xbamask = (1 << xba)-1;
int n = nXBassBufferPos;
for (int x=count; x; x--)
{
nXBassSum -= XBassBuffer[n];
int tmp0 = *px;
int tmp = (tmp0 + ((tmp0 >> 31) & xbamask)) >> xba;
XBassBuffer[n] = tmp;
nXBassSum += tmp;
int v = XBassDelay[nXBassDlyPos];
XBassDelay[nXBassDlyPos] = *px;
*px++ = v + nXBassSum;
nXBassDlyPos = (nXBassDlyPos + 2) & nXBassMask;
n++;
n &= nXBassMask;
}
nXBassBufferPos = n;
}
// Noise Reduction
if (gdwSoundSetup & SNDMIX_NOISEREDUCTION)
{
int n = nLeftNR;
int *pnr = MixSoundBuffer;
for (int nr=count; nr; pnr++, nr--)
{
int vnr = *pnr >> 1;
*pnr = vnr + n;
n = vnr;
}
nLeftNR = n;
}
}
/////////////////////////////////////////////////////////////////
// Clean DSP Effects interface
// [Reverb level 0(quiet)-100(loud)], [delay in ms, usually 40-200ms]
BOOL CSoundFile::SetReverbParameters(UINT nDepth, UINT nDelay)
//------------------------------------------------------------
{
if (nDepth > 100) nDepth = 100;
UINT gain = nDepth / 20;
if (gain > 4) gain = 4;
m_nReverbDepth = 4 - gain;
if (nDelay < 40) nDelay = 40;
if (nDelay > 250) nDelay = 250;
m_nReverbDelay = nDelay;
return TRUE;
}
// [XBass level 0(quiet)-100(loud)], [cutoff in Hz 20-100]
BOOL CSoundFile::SetXBassParameters(UINT nDepth, UINT nRange)
//-----------------------------------------------------------
{
if (nDepth > 100) nDepth = 100;
UINT gain = nDepth / 20;
if (gain > 4) gain = 4;
m_nXBassDepth = 8 - gain; // filter attenuation 1/256 .. 1/16
UINT range = nRange / 5;
if (range > 5) range -= 5; else range = 0;
if (nRange > 16) nRange = 16;
m_nXBassRange = 21 - range; // filter average on 0.5-1.6ms
return TRUE;
}
// [Surround level 0(quiet)-100(heavy)] [delay in ms, usually 5-50ms]
BOOL CSoundFile::SetSurroundParameters(UINT nDepth, UINT nDelay)
//--------------------------------------------------------------
{
UINT gain = (nDepth * 16) / 100;
if (gain > 16) gain = 16;
if (gain < 1) gain = 1;
m_nProLogicDepth = gain;
if (nDelay < 4) nDelay = 4;
if (nDelay > 50) nDelay = 50;
m_nProLogicDelay = nDelay;
return TRUE;
}
BOOL CSoundFile::SetWaveConfigEx(BOOL bSurround,BOOL bNoOverSampling,BOOL bReverb,BOOL hqido,BOOL bMegaBass,BOOL bNR,BOOL bEQ)
//----------------------------------------------------------------------------------------------------------------------------
{
DWORD d = gdwSoundSetup & ~(SNDMIX_SURROUND | SNDMIX_NORESAMPLING | SNDMIX_REVERB | SNDMIX_HQRESAMPLER | SNDMIX_MEGABASS | SNDMIX_NOISEREDUCTION | SNDMIX_EQ);
if (bSurround) d |= SNDMIX_SURROUND;
if (bNoOverSampling) d |= SNDMIX_NORESAMPLING;
if (bReverb) d |= SNDMIX_REVERB;
if (hqido) d |= SNDMIX_HQRESAMPLER;
if (bMegaBass) d |= SNDMIX_MEGABASS;
if (bNR) d |= SNDMIX_NOISEREDUCTION;
if (bEQ) d |= SNDMIX_EQ;
gdwSoundSetup = d;
InitPlayer(FALSE);
return TRUE;
}

View File

@ -0,0 +1,101 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "stdafx.h"
#include "sndfile.h"
// AWE32: cutoff = reg[0-255] * 31.25 + 100 -> [100Hz-8060Hz]
// EMU10K1 docs: cutoff = reg[0-127]*62+100
#define FILTER_PRECISION 8192
#ifndef NO_FILTER
#ifdef MSC_VER
#define _ASM_MATH
#endif
#ifdef _ASM_MATH
// pow(a,b) returns a^^b -> 2^^(b.log2(a))
static float pow(float a, float b)
{
long tmpint;
float result;
_asm {
fld b // Load b
fld a // Load a
fyl2x // ST(0) = b.log2(a)
fist tmpint // Store integer exponent
fisub tmpint // ST(0) = -1 <= (b*log2(a)) <= 1
f2xm1 // ST(0) = 2^(x)-1
fild tmpint // load integer exponent
fld1 // Load 1
fscale // ST(0) = 2^ST(1)
fstp ST(1) // Remove the integer from the stack
fmul ST(1), ST(0) // multiply with fractional part
faddp ST(1), ST(0) // add integer_part
fstp result // Store the result
}
return result;
}
#else
#include <math.h>
#endif // _ASM_MATH
DWORD CSoundFile::CutOffToFrequency(UINT nCutOff, int flt_modifier) const
//-----------------------------------------------------------------------
{
float Fc;
if (m_dwSongFlags & SONG_EXFILTERRANGE)
Fc = 110.0f * pow(2.0f, 0.25f + ((float)(nCutOff*(flt_modifier+256)))/(21.0f*512.0f));
else
Fc = 110.0f * pow(2.0f, 0.25f + ((float)(nCutOff*(flt_modifier+256)))/(24.0f*512.0f));
LONG freq = (LONG)Fc;
if (freq < 120) return 120;
if (freq > 10000) return 10000;
if (freq*2 > (LONG)gdwMixingFreq) freq = gdwMixingFreq>>1;
return (DWORD)freq;
}
// Simple 2-poles resonant filter
void CSoundFile::SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier) const
//----------------------------------------------------------------------------------------
{
float fc = (float)CutOffToFrequency(pChn->nCutOff, flt_modifier);
float fs = (float)gdwMixingFreq;
float fg, fb0, fb1;
fc *= (float)(2.0*3.14159265358/fs);
float dmpfac = pow(10.0f, -((24.0f / 128.0f)*(float)pChn->nResonance) / 20.0f);
float d = (1.0f-2.0f*dmpfac)* fc;
if (d>2.0) d = 2.0;
d = (2.0f*dmpfac - d)/fc;
float e = pow(1.0f/fc,2.0f);
fg=1/(1+d+e);
fb0=(d+e+e)/(1+d+e);
fb1=-e/(1+d+e);
pChn->nFilter_A0 = (int)(fg * FILTER_PRECISION);
pChn->nFilter_B0 = (int)(fb0 * FILTER_PRECISION);
pChn->nFilter_B1 = (int)(fb1 * FILTER_PRECISION);
if (bReset)
{
pChn->nFilter_Y1 = pChn->nFilter_Y2 = 0;
pChn->nFilter_Y3 = pChn->nFilter_Y4 = 0;
}
pChn->dwFlags |= CHN_FILTER;
}
#endif // NO_FILTER

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,376 @@
/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
#include "libmodplug/stdafx.h"
#include "libmodplug/sndfile.h"
#ifndef MODPLUG_FASTSOUNDLIB
//#pragma data_seg(".tables")
#endif
static const BYTE ImpulseTrackerPortaVolCmd[16] =
{
0x00, 0x01, 0x04, 0x08, 0x10, 0x20, 0x40, 0x60,
0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
// Period table for Protracker octaves 0-5:
static const WORD ProTrackerPeriodTable[6*12] =
{
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,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,113,
107,101,95,90,85,80,75,71,67,63,60,56,
53,50,47,45,42,40,37,35,33,31,30,28
};
static const WORD ProTrackerTunedPeriods[16*12] =
{
1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907,
1700,1604,1514,1430,1348,1274,1202,1134,1070,1010,954,900,
1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,894,
1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,888,
1664,1570,1482,1398,1320,1246,1176,1110,1048,990,934,882,
1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,874,
1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,868,
1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914,862,
1814,1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,
1800,1700,1604,1514,1430,1350,1272,1202,1134,1070,1010,954,
1788,1688,1592,1504,1418,1340,1264,1194,1126,1064,1004,948,
1774,1676,1582,1492,1408,1330,1256,1184,1118,1056,996,940,
1762,1664,1570,1482,1398,1320,1246,1176,1110,1048,988,934,
1750,1652,1558,1472,1388,1310,1238,1168,1102,1040,982,926,
1736,1640,1548,1460,1378,1302,1228,1160,1094,1032,974,920,
1724,1628,1536,1450,1368,1292,1220,1150,1086,1026,968,914
};
// S3M C-4 periods
static const WORD FreqS3MTable[16] =
{
1712,1616,1524,1440,1356,1280,
1208,1140,1076,1016,960,907,
0,0,0,0
};
// S3M FineTune frequencies
static const WORD S3MFineTuneTable[16] =
{
7895,7941,7985,8046,8107,8169,8232,8280,
8363,8413,8463,8529,8581,8651,8723,8757, // 8363*2^((i-8)/(12*8))
};
// Sinus table
static const int16_t ModSinusTable[64] =
{
0,12,25,37,49,60,71,81,90,98,106,112,117,122,125,126,
127,126,125,122,117,112,106,98,90,81,71,60,49,37,25,12,
0,-12,-25,-37,-49,-60,-71,-81,-90,-98,-106,-112,-117,-122,-125,-126,
-127,-126,-125,-122,-117,-112,-106,-98,-90,-81,-71,-60,-49,-37,-25,-12
};
// Triangle wave table (ramp down)
static const int16_t ModRampDownTable[64] =
{
0,-4,-8,-12,-16,-20,-24,-28,-32,-36,-40,-44,-48,-52,-56,-60,
-64,-68,-72,-76,-80,-84,-88,-92,-96,-100,-104,-108,-112,-116,-120,-124,
127,123,119,115,111,107,103,99,95,91,87,83,79,75,71,67,
63,59,55,51,47,43,39,35,31,27,23,19,15,11,7,3
};
// Square wave table
static const int16_t ModSquareTable[64] =
{
127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,
127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,
-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127
};
// Random wave table
static const int16_t ModRandomTable[64] =
{
98,-127,-43,88,102,41,-65,-94,125,20,-71,-86,-70,-32,-16,-96,
17,72,107,-5,116,-69,-62,-40,10,-61,65,109,-18,-38,-13,-76,
-23,88,21,-94,8,106,21,-112,6,109,20,-88,-30,9,-127,118,
42,-34,89,-4,-51,-72,21,-29,112,123,84,-101,-92,98,-54,-95
};
// volume fade tables for Retrig Note:
static const int8_t retrigTable1[16] =
{ 0, 0, 0, 0, 0, 0, 10, 8, 0, 0, 0, 0, 0, 0, 24, 32 };
static const int8_t retrigTable2[16] =
{ 0, -1, -2, -4, -8, -16, 0, 0, 0, 1, 2, 4, 8, 16, 0, 0 };
static const WORD XMPeriodTable[104] =
{
907,900,894,887,881,875,868,862,856,850,844,838,832,826,820,814,
808,802,796,791,785,779,774,768,762,757,752,746,741,736,730,725,
720,715,709,704,699,694,689,684,678,675,670,665,660,655,651,646,
640,636,632,628,623,619,614,610,604,601,597,592,588,584,580,575,
570,567,563,559,555,551,547,543,538,535,532,528,524,520,516,513,
508,505,502,498,494,491,487,484,480,477,474,470,467,463,460,457,
453,450,447,443,440,437,434,431
};
static const uint32_t XMLinearTable[768] =
{
535232,534749,534266,533784,533303,532822,532341,531861,
531381,530902,530423,529944,529466,528988,528511,528034,
527558,527082,526607,526131,525657,525183,524709,524236,
523763,523290,522818,522346,521875,521404,520934,520464,
519994,519525,519057,518588,518121,517653,517186,516720,
516253,515788,515322,514858,514393,513929,513465,513002,
512539,512077,511615,511154,510692,510232,509771,509312,
508852,508393,507934,507476,507018,506561,506104,505647,
505191,504735,504280,503825,503371,502917,502463,502010,
501557,501104,500652,500201,499749,499298,498848,498398,
497948,497499,497050,496602,496154,495706,495259,494812,
494366,493920,493474,493029,492585,492140,491696,491253,
490809,490367,489924,489482,489041,488600,488159,487718,
487278,486839,486400,485961,485522,485084,484647,484210,
483773,483336,482900,482465,482029,481595,481160,480726,
480292,479859,479426,478994,478562,478130,477699,477268,
476837,476407,475977,475548,475119,474690,474262,473834,
473407,472979,472553,472126,471701,471275,470850,470425,
470001,469577,469153,468730,468307,467884,467462,467041,
466619,466198,465778,465358,464938,464518,464099,463681,
463262,462844,462427,462010,461593,461177,460760,460345,
459930,459515,459100,458686,458272,457859,457446,457033,
456621,456209,455797,455386,454975,454565,454155,453745,
453336,452927,452518,452110,451702,451294,450887,450481,
450074,449668,449262,448857,448452,448048,447644,447240,
446836,446433,446030,445628,445226,444824,444423,444022,
443622,443221,442821,442422,442023,441624,441226,440828,
440430,440033,439636,439239,438843,438447,438051,437656,
437261,436867,436473,436079,435686,435293,434900,434508,
434116,433724,433333,432942,432551,432161,431771,431382,
430992,430604,430215,429827,429439,429052,428665,428278,
427892,427506,427120,426735,426350,425965,425581,425197,
424813,424430,424047,423665,423283,422901,422519,422138,
421757,421377,420997,420617,420237,419858,419479,419101,
418723,418345,417968,417591,417214,416838,416462,416086,
415711,415336,414961,414586,414212,413839,413465,413092,
412720,412347,411975,411604,411232,410862,410491,410121,
409751,409381,409012,408643,408274,407906,407538,407170,
406803,406436,406069,405703,405337,404971,404606,404241,
403876,403512,403148,402784,402421,402058,401695,401333,
400970,400609,400247,399886,399525,399165,398805,398445,
398086,397727,397368,397009,396651,396293,395936,395579,
395222,394865,394509,394153,393798,393442,393087,392733,
392378,392024,391671,391317,390964,390612,390259,389907,
389556,389204,388853,388502,388152,387802,387452,387102,
386753,386404,386056,385707,385359,385012,384664,384317,
383971,383624,383278,382932,382587,382242,381897,381552,
381208,380864,380521,380177,379834,379492,379149,378807,
378466,378124,377783,377442,377102,376762,376422,376082,
375743,375404,375065,374727,374389,374051,373714,373377,
373040,372703,372367,372031,371695,371360,371025,370690,
370356,370022,369688,369355,369021,368688,368356,368023,
367691,367360,367028,366697,366366,366036,365706,365376,
365046,364717,364388,364059,363731,363403,363075,362747,
362420,362093,361766,361440,361114,360788,360463,360137,
359813,359488,359164,358840,358516,358193,357869,357547,
357224,356902,356580,356258,355937,355616,355295,354974,
354654,354334,354014,353695,353376,353057,352739,352420,
352103,351785,351468,351150,350834,350517,350201,349885,
349569,349254,348939,348624,348310,347995,347682,347368,
347055,346741,346429,346116,345804,345492,345180,344869,
344558,344247,343936,343626,343316,343006,342697,342388,
342079,341770,341462,341154,340846,340539,340231,339924,
339618,339311,339005,338700,338394,338089,337784,337479,
337175,336870,336566,336263,335959,335656,335354,335051,
334749,334447,334145,333844,333542,333242,332941,332641,
332341,332041,331741,331442,331143,330844,330546,330247,
329950,329652,329355,329057,328761,328464,328168,327872,
327576,327280,326985,326690,326395,326101,325807,325513,
325219,324926,324633,324340,324047,323755,323463,323171,
322879,322588,322297,322006,321716,321426,321136,320846,
320557,320267,319978,319690,319401,319113,318825,318538,
318250,317963,317676,317390,317103,316817,316532,316246,
315961,315676,315391,315106,314822,314538,314254,313971,
313688,313405,313122,312839,312557,312275,311994,311712,
311431,311150,310869,310589,310309,310029,309749,309470,
309190,308911,308633,308354,308076,307798,307521,307243,
306966,306689,306412,306136,305860,305584,305308,305033,
304758,304483,304208,303934,303659,303385,303112,302838,
302565,302292,302019,301747,301475,301203,300931,300660,
300388,300117,299847,299576,299306,299036,298766,298497,
298227,297958,297689,297421,297153,296884,296617,296349,
296082,295815,295548,295281,295015,294749,294483,294217,
293952,293686,293421,293157,292892,292628,292364,292100,
291837,291574,291311,291048,290785,290523,290261,289999,
289737,289476,289215,288954,288693,288433,288173,287913,
287653,287393,287134,286875,286616,286358,286099,285841,
285583,285326,285068,284811,284554,284298,284041,283785,
283529,283273,283017,282762,282507,282252,281998,281743,
281489,281235,280981,280728,280475,280222,279969,279716,
279464,279212,278960,278708,278457,278206,277955,277704,
277453,277203,276953,276703,276453,276204,275955,275706,
275457,275209,274960,274712,274465,274217,273970,273722,
273476,273229,272982,272736,272490,272244,271999,271753,
271508,271263,271018,270774,270530,270286,270042,269798,
269555,269312,269069,268826,268583,268341,268099,267857
};
static const int8_t ft2VibratoTable[256] =
{
0,-2,-3,-5,-6,-8,-9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
-24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,
-43,-44,-45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,
-56,-57,-58,-59,-59,-60,-60,-61,-61,-62,-62,-62,-63,-63,
-63,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-63,-63,
-63,-62,-62,-62,-61,-61,-60,-60,-59,-59,-58,-57,-56,-56,
-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-45,-44,-43,-42,
-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,-24,-23,
-22,-20,-19,-17,-16,-14,-12,-11,-9,-8,-6,-5,-3,-2,0,
2,3,5,6,8,9,11,12,14,16,17,19,20,22,23,24,26,27,29,30,
32,33,34,36,37,38,39,41,42,43,44,45,46,47,48,49,50,51,
52,53,54,55,56,56,57,58,59,59,60,60,61,61,62,62,62,63,
63,63,64,64,64,64,64,64,64,64,64,64,64,63,63,63,62,62,
62,61,61,60,60,59,59,58,57,56,56,55,54,53,52,51,50,49,
48,47,46,45,44,43,42,41,39,38,37,36,34,33,32,30,29,27,
26,24,23,22,20,19,17,16,14,12,11,9,8,6,5,3,2
};
static const DWORD FineLinearSlideUpTable[16] =
{
65536, 65595, 65654, 65714, 65773, 65832, 65892, 65951,
66011, 66071, 66130, 66190, 66250, 66309, 66369, 66429
};
static const DWORD FineLinearSlideDownTable[16] =
{
65535, 65477, 65418, 65359, 65300, 65241, 65182, 65123,
65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645
};
static const DWORD LinearSlideUpTable[256] =
{
65536, 65773, 66010, 66249, 66489, 66729, 66971, 67213,
67456, 67700, 67945, 68190, 68437, 68685, 68933, 69182,
69432, 69684, 69936, 70189, 70442, 70697, 70953, 71209,
71467, 71725, 71985, 72245, 72507, 72769, 73032, 73296,
73561, 73827, 74094, 74362, 74631, 74901, 75172, 75444,
75717, 75991, 76265, 76541, 76818, 77096, 77375, 77655,
77935, 78217, 78500, 78784, 79069, 79355, 79642, 79930,
80219, 80509, 80800, 81093, 81386, 81680, 81976, 82272,
82570, 82868, 83168, 83469, 83771, 84074, 84378, 84683,
84989, 85297, 85605, 85915, 86225, 86537, 86850, 87164,
87480, 87796, 88113, 88432, 88752, 89073, 89395, 89718,
90043, 90369, 90695, 91023, 91353, 91683, 92015, 92347,
92681, 93017, 93353, 93691, 94029, 94370, 94711, 95053,
95397, 95742, 96088, 96436, 96785, 97135, 97486, 97839,
98193, 98548, 98904, 99262, 99621, 99981, 100343, 100706,
101070, 101435, 101802, 102170, 102540, 102911, 103283, 103657,
104031, 104408, 104785, 105164, 105545, 105926, 106309, 106694,
107080, 107467, 107856, 108246, 108637, 109030, 109425, 109820,
110217, 110616, 111016, 111418, 111821, 112225, 112631, 113038,
113447, 113857, 114269, 114682, 115097, 115514, 115931, 116351,
116771, 117194, 117618, 118043, 118470, 118898, 119328, 119760,
120193, 120628, 121064, 121502, 121941, 122382, 122825, 123269,
123715, 124162, 124611, 125062, 125514, 125968, 126424, 126881,
127340, 127801, 128263, 128727, 129192, 129660, 130129, 130599,
131072, 131546, 132021, 132499, 132978, 133459, 133942, 134426,
134912, 135400, 135890, 136381, 136875, 137370, 137866, 138365,
138865, 139368, 139872, 140378, 140885, 141395, 141906, 142419,
142935, 143451, 143970, 144491, 145014, 145538, 146064, 146593,
147123, 147655, 148189, 148725, 149263, 149803, 150344, 150888,
151434, 151982, 152531, 153083, 153637, 154192, 154750, 155310,
155871, 156435, 157001, 157569, 158138, 158710, 159284, 159860,
160439, 161019, 161601, 162186, 162772, 163361, 163952, 164545,
};
static const DWORD LinearSlideDownTable[256] =
{
65536, 65299, 65064, 64830, 64596, 64363, 64131, 63900,
63670, 63440, 63212, 62984, 62757, 62531, 62305, 62081,
61857, 61634, 61412, 61191, 60970, 60751, 60532, 60314,
60096, 59880, 59664, 59449, 59235, 59021, 58809, 58597,
58385, 58175, 57965, 57757, 57548, 57341, 57134, 56928,
56723, 56519, 56315, 56112, 55910, 55709, 55508, 55308,
55108, 54910, 54712, 54515, 54318, 54123, 53928, 53733,
53540, 53347, 53154, 52963, 52772, 52582, 52392, 52204,
52015, 51828, 51641, 51455, 51270, 51085, 50901, 50717,
50535, 50353, 50171, 49990, 49810, 49631, 49452, 49274,
49096, 48919, 48743, 48567, 48392, 48218, 48044, 47871,
47698, 47526, 47355, 47185, 47014, 46845, 46676, 46508,
46340, 46173, 46007, 45841, 45676, 45511, 45347, 45184,
45021, 44859, 44697, 44536, 44376, 44216, 44056, 43898,
43740, 43582, 43425, 43268, 43112, 42957, 42802, 42648,
42494, 42341, 42189, 42037, 41885, 41734, 41584, 41434,
41285, 41136, 40988, 40840, 40693, 40546, 40400, 40254,
40109, 39965, 39821, 39677, 39534, 39392, 39250, 39108,
38967, 38827, 38687, 38548, 38409, 38270, 38132, 37995,
37858, 37722, 37586, 37450, 37315, 37181, 37047, 36913,
36780, 36648, 36516, 36384, 36253, 36122, 35992, 35862,
35733, 35604, 35476, 35348, 35221, 35094, 34968, 34842,
34716, 34591, 34466, 34342, 34218, 34095, 33972, 33850,
33728, 33606, 33485, 33364, 33244, 33124, 33005, 32886,
32768, 32649, 32532, 32415, 32298, 32181, 32065, 31950,
31835, 31720, 31606, 31492, 31378, 31265, 31152, 31040,
30928, 30817, 30706, 30595, 30485, 30375, 30266, 30157,
30048, 29940, 29832, 29724, 29617, 29510, 29404, 29298,
29192, 29087, 28982, 28878, 28774, 28670, 28567, 28464,
28361, 28259, 28157, 28056, 27955, 27854, 27754, 27654,
27554, 27455, 27356, 27257, 27159, 27061, 26964, 26866,
26770, 26673, 26577, 26481, 26386, 26291, 26196, 26102,
};
static const int SpectrumSinusTable[256*2] =
{
0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11,
12, 13, 14, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23,
24, 25, 25, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 34,
35, 36, 36, 37, 38, 38, 39, 39, 40, 41, 41, 42, 42, 43, 44, 44,
45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52,
53, 53, 53, 54, 54, 55, 55, 55, 56, 56, 57, 57, 57, 58, 58, 58,
59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 61, 62, 62, 62,
62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62,
62, 62, 62, 62, 61, 61, 61, 61, 61, 60, 60, 60, 60, 59, 59, 59,
59, 58, 58, 58, 57, 57, 57, 56, 56, 55, 55, 55, 54, 54, 53, 53,
53, 52, 52, 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45,
45, 44, 44, 43, 42, 42, 41, 41, 40, 39, 39, 38, 38, 37, 36, 36,
35, 34, 34, 33, 32, 32, 31, 30, 30, 29, 28, 28, 27, 26, 25, 25,
24, 23, 22, 22, 21, 20, 20, 19, 18, 17, 17, 16, 15, 14, 14, 13,
12, 11, 10, 10, 9, 8, 7, 7, 6, 5, 4, 3, 3, 2, 1, 0,
0, -1, -1, -2, -3, -3, -4, -5, -6, -7, -7, -8, -9, -10, -10, -11,
-12, -13, -14, -14, -15, -16, -17, -17, -18, -19, -20, -20, -21, -22, -22, -23,
-24, -25, -25, -26, -27, -28, -28, -29, -30, -30, -31, -32, -32, -33, -34, -34,
-35, -36, -36, -37, -38, -38, -39, -39, -40, -41, -41, -42, -42, -43, -44, -44,
-45, -45, -46, -46, -47, -47, -48, -48, -49, -49, -50, -50, -51, -51, -52, -52,
-53, -53, -53, -54, -54, -55, -55, -55, -56, -56, -57, -57, -57, -58, -58, -58,
-59, -59, -59, -59, -60, -60, -60, -60, -61, -61, -61, -61, -61, -62, -62, -62,
-62, -62, -62, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63,
-63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, -62, -62,
-62, -62, -62, -62, -61, -61, -61, -61, -61, -60, -60, -60, -60, -59, -59, -59,
-59, -58, -58, -58, -57, -57, -57, -56, -56, -55, -55, -55, -54, -54, -53, -53,
-53, -52, -52, -51, -51, -50, -50, -49, -49, -48, -48, -47, -47, -46, -46, -45,
-45, -44, -44, -43, -42, -42, -41, -41, -40, -39, -39, -38, -38, -37, -36, -36,
-35, -34, -34, -33, -32, -32, -31, -30, -30, -29, -28, -28, -27, -26, -25, -25,
-24, -23, -22, -22, -21, -20, -20, -19, -18, -17, -17, -16, -15, -14, -14, -13,
-12, -11, -10, -10, -9, -8, -7, -7, -6, -5, -4, -3, -3, -2, -1, 0,
};