mirror of
https://github.com/love2d/megasource.git
synced 2026-08-12 00:20:55 +02:00
Add libmodplug 0.8.8.4.
This commit is contained in:
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
ModPlug-XMMS and libmodplug are now in the public domain.
|
||||
@@ -0,0 +1,296 @@
|
||||
changes:
|
||||
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 seperate 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)
|
||||
BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitFirFilterRampMix)
|
||||
BEGIN_MIX_INTERFACE(Stereo8BitFirFilterMix)
|
||||
@@ -0,0 +1,365 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
SUBDIRS = src
|
||||
|
||||
EXTRA_DIST = \
|
||||
AUTHORS COPYING ChangeLog \
|
||||
INSTALL README TODO
|
||||
|
||||
pkgconfigdir=${libdir}/pkgconfig
|
||||
pkgconfig_DATA=libmodplug.pc
|
||||
|
||||
@@ -0,0 +1,767 @@
|
||||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
|
||||
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 = .
|
||||
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(srcdir)/libmodplug.pc.in \
|
||||
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
|
||||
TODO config.guess config.sub depcomp install-sh ltmain.sh \
|
||||
missing
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
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_GEN = $(am__v_GEN_$(V))
|
||||
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
AM_V_at = $(am__v_at_$(V))
|
||||
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_at_0 = @
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-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 uninstall-recursive
|
||||
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__installdirs = "$(DESTDIR)$(pkgconfigdir)"
|
||||
DATA = $(pkgconfig_DATA)
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
|
||||
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
|
||||
distdir dist dist-all distcheck
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
{ test ! -d "$(distdir)" \
|
||||
|| { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -fr "$(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
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
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@
|
||||
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@
|
||||
SUBDIRS = src
|
||||
EXTRA_DIST = \
|
||||
AUTHORS COPYING ChangeLog \
|
||||
INSTALL README TODO
|
||||
|
||||
pkgconfigdir = ${libdir}/pkgconfig
|
||||
pkgconfig_DATA = libmodplug.pc
|
||||
all: all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh:
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(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
|
||||
.PRECIOUS: 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: $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(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)
|
||||
test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
|
||||
@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
|
||||
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|^.*/||'`; \
|
||||
test -n "$$files" || exit 0; \
|
||||
echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \
|
||||
cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files
|
||||
|
||||
# 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.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(SUBDIRS)'; 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"
|
||||
|
||||
$(RECURSIVE_CLEAN_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
rev=''; for subdir in $$list; do \
|
||||
if test "$$subdir" = "."; then :; else \
|
||||
rev="$$subdir $$rev"; \
|
||||
fi; \
|
||||
done; \
|
||||
rev="$$rev ."; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
for subdir in $$rev; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done && test -z "$$fail"
|
||||
tags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
|
||||
done
|
||||
ctags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
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; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
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
|
||||
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
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"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
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 \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
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) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzma: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist dist-all: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__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*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lzma*) \
|
||||
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(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 \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(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__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:
|
||||
@$(am__cd) '$(distuninstallcheck_dir)' \
|
||||
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|
||||
|| { 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:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
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: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
|
||||
install-am install-strip tags-recursive
|
||||
|
||||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am am--refresh check check-am clean clean-generic \
|
||||
clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-lzma 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-recursive uninstall uninstall-am \
|
||||
uninstall-pkgconfigDATA
|
||||
|
||||
|
||||
# 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:
|
||||
@@ -0,0 +1,6 @@
|
||||
Konstanty Bialkowski <konstanty@ieee.org> Tue Apr 7 15:00:00 AEST 2009
|
||||
New release of small fixes from contributers 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.
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
Modplug Plugin for XMMS v2.0 / libmodplug v0.8.5
|
||||
Based on the ModPlug sound engine by Olivier Lapicque <olivierl@jps.net>
|
||||
XMMS plugin by Kenton Varda <temporal@gauge3d.org>
|
||||
Maintainer is now Konstanty Bialkowski <konstanty@ieee.org>
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
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:
|
||||
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 exept 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:
|
||||
None of the config options seem to have any affect on the sound quality.
|
||||
|
||||
Possible cause:
|
||||
You did not disable MikMod, so mods are being played by it rather than
|
||||
by ModPlug.
|
||||
|
||||
Solution:
|
||||
Disable MikMod in the XMMS input plugins configuration dialog.
|
||||
|
||||
Alternative cause:
|
||||
You are not playing a mod-like file. ModPlug only plays mod-like file
|
||||
formats, and has no affect on mp3's or other non-mod formats. (Note:
|
||||
Yes, I have actually had people e-mail me with this problem.)
|
||||
|
||||
Solution:
|
||||
Download some mods. You can start at <http://www.traxinspace.org>.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Fix and check endian-ness issues.
|
||||
Add looping flag to sound file / API function for this.
|
||||
Vendored
+9409
File diff suppressed because it is too large
Load Diff
Vendored
+1501
File diff suppressed because it is too large
Load Diff
Vendored
+1705
File diff suppressed because it is too large
Load Diff
Vendored
+18287
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_INIT
|
||||
AC_PREREQ(2.63)
|
||||
AC_CONFIG_SRCDIR([Makefile.am])
|
||||
|
||||
AM_INIT_AUTOMAKE(libmodplug, 0.8.8.4)
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
|
||||
AC_CONFIG_HEADERS([src/config.h])
|
||||
|
||||
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 #this will cause problems when cross-compiling...
|
||||
#AC_REQUIRE([AC_CANONICAL_HOST])_LT_SET_OPTION([LT_INIT],[win32-dll])
|
||||
#AC_DIAGNOSE([obsolete],[AC_LIBTOOL_WIN32_DLL: Remove this warning and the call to _LT_SET_OPTION when you
|
||||
#put the `win32-dll' option into LT_INIT's first parameter.])
|
||||
|
||||
LT_INIT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([inttypes.h stdint.h malloc.h])
|
||||
AC_CHECK_FUNCS(setenv sinf)
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -fno-exceptions -Wall -ffast-math -D_REENTRANT"
|
||||
# CXXFLAGS="-fno-exceptions -g -Wall -ffast-math -D_REENTRANT `glib-config --cflags`"
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
case "$host" in
|
||||
*mingw* | *cygwin*)
|
||||
LT_LDFLAGS="-no-undefined"
|
||||
;;
|
||||
*)
|
||||
LT_LDFLAGS=""
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(LT_LDFLAGS)
|
||||
|
||||
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
|
||||
@@ -0,0 +1,630 @@
|
||||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 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 outputing dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
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"
|
||||
|
||||
# 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
|
||||
|
||||
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 -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## 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).
|
||||
## - 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 -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
## 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.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## 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.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -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 -eq 0; then :
|
||||
else
|
||||
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 ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
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.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
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 -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
icc)
|
||||
# Intel's C compiler understands `-MD -MF file'. However on
|
||||
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||
# ICC 7.0 will fill foo.d with something like
|
||||
# foo.o: sub/foo.c
|
||||
# foo.o: sub/foo.h
|
||||
# which is wrong. We want:
|
||||
# sub/foo.o: sub/foo.c
|
||||
# sub/foo.o: sub/foo.h
|
||||
# sub/foo.c:
|
||||
# sub/foo.h:
|
||||
# ICC 7.1 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using \ :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
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.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
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 -eq 0; then :
|
||||
else
|
||||
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,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add `dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#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.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# With Tru64 cc, shared objects can also be used to make a
|
||||
# static library. This mechanism is used in libtool 1.4 series to
|
||||
# handle both shared and static libraries in a single compilation.
|
||||
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
|
||||
#
|
||||
# With libtool 1.5 this exception was removed, and libtool now
|
||||
# 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.libs/$base.lo.d # libtool 1.4
|
||||
tmpdepfile2=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
|
||||
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.o.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
tmpdepfile4=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
#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:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
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"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
sed '1,2d' "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
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:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$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:
|
||||
@@ -0,0 +1,520 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names starting with `-'.
|
||||
case $src in
|
||||
-*) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dst=$dst_arg
|
||||
# Protect names starting with `-'.
|
||||
case $dst in
|
||||
-*) dst=./$dst;;
|
||||
esac
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
-*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test -z "$d" && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
@@ -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} -I${includedir}/libmodplug
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,376 @@
|
||||
#! /bin/sh
|
||||
# Common stub for a few missing GNU programs while installing.
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
|
||||
# 2008, 2009 Free Software Foundation, Inc.
|
||||
# Originally 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
|
||||
|
||||
run=:
|
||||
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
|
||||
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
|
||||
|
||||
# In the cases where this matters, `missing' is being run in the
|
||||
# srcdir already.
|
||||
if test -f configure.ac; then
|
||||
configure_ac=configure.ac
|
||||
else
|
||||
configure_ac=configure.in
|
||||
fi
|
||||
|
||||
msg="missing on your system"
|
||||
|
||||
case $1 in
|
||||
--run)
|
||||
# Try to run requested program, and just exit if it succeeds.
|
||||
run=
|
||||
shift
|
||||
"$@" && exit 0
|
||||
# Exit code 63 means version mismatch. This often happens
|
||||
# when the user try to use an ancient version of a tool on
|
||||
# a file that requires a minimum version. In this case we
|
||||
# we should proceed has if the program had been absent, or
|
||||
# if --run hadn't been passed.
|
||||
if test $? = 63; then
|
||||
run=:
|
||||
msg="probably too old"
|
||||
fi
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
|
||||
error status if there is no known handling for PROGRAM.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
--run try to run the given command, and emulate it if it fails
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal touch file \`aclocal.m4'
|
||||
autoconf touch file \`configure'
|
||||
autoheader touch file \`config.h.in'
|
||||
autom4te touch the output file, or create a stub one
|
||||
automake touch all \`Makefile.in' files
|
||||
bison create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
flex create \`lex.yy.c', if possible, from existing .c
|
||||
help2man touch the output file
|
||||
lex create \`lex.yy.c', if possible, from existing .c
|
||||
makeinfo touch the output file
|
||||
tar try tar, gnutar, gtar, then tar without non-portable flags
|
||||
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
|
||||
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
|
||||
|
||||
# normalize program name to check for.
|
||||
program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
# Now exit if we have it, but it failed. Also exit now if we
|
||||
# don't have it and --version was passed (most likely to detect
|
||||
# the program). This is about non-GNU programs, so use $1 not
|
||||
# $program.
|
||||
case $1 in
|
||||
lex*|yacc*)
|
||||
# Not GNU programs, they don't have --version.
|
||||
;;
|
||||
|
||||
tar*)
|
||||
if test -n "$run"; then
|
||||
echo 1>&2 "ERROR: \`tar' requires --run"
|
||||
exit 1
|
||||
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||
# Could not run --version or --help. This is probably someone
|
||||
# running `$TOOL --version' or `$TOOL --help' to check whether
|
||||
# $TOOL exists and not knowing $TOOL uses missing.
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# If it does not exist, or fails to run (possibly an outdated version),
|
||||
# try to emulate it.
|
||||
case $program in
|
||||
aclocal*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
|
||||
to install the \`Automake' and \`Perl' packages. Grab them from
|
||||
any GNU archive site."
|
||||
touch aclocal.m4
|
||||
;;
|
||||
|
||||
autoconf*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`${configure_ac}'. You might want to install the
|
||||
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
|
||||
archive site."
|
||||
touch configure
|
||||
;;
|
||||
|
||||
autoheader*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`acconfig.h' or \`${configure_ac}'. You might want
|
||||
to install the \`Autoconf' and \`GNU m4' packages. Grab them
|
||||
from any GNU archive site."
|
||||
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
|
||||
test -z "$files" && files="config.h"
|
||||
touch_files=
|
||||
for f in $files; do
|
||||
case $f in
|
||||
*:*) touch_files="$touch_files "`echo "$f" |
|
||||
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
|
||||
*) touch_files="$touch_files $f.in";;
|
||||
esac
|
||||
done
|
||||
touch $touch_files
|
||||
;;
|
||||
|
||||
automake*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
|
||||
You might want to install the \`Automake' and \`Perl' packages.
|
||||
Grab them from any GNU archive site."
|
||||
find . -type f -name Makefile.am -print |
|
||||
sed 's/\.am$/.in/' |
|
||||
while read f; do touch "$f"; done
|
||||
;;
|
||||
|
||||
autom4te*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, but is $msg.
|
||||
You might have modified some files without having the
|
||||
proper tools for further handling them.
|
||||
You can get \`$1' as part of \`Autoconf' from any GNU
|
||||
archive site."
|
||||
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo "#! /bin/sh"
|
||||
echo "# Created by GNU Automake missing as a replacement of"
|
||||
echo "# $ $@"
|
||||
echo "exit 0"
|
||||
chmod +x $file
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
bison*|yacc*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' $msg. You should only need it if
|
||||
you modified a \`.y' file. You may need the \`Bison' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Bison' from any GNU archive site."
|
||||
rm -f y.tab.c y.tab.h
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG="\${$#}"
|
||||
case $LASTARG in
|
||||
*.y)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" y.tab.c
|
||||
fi
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" y.tab.h
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test ! -f y.tab.h; then
|
||||
echo >y.tab.h
|
||||
fi
|
||||
if test ! -f y.tab.c; then
|
||||
echo 'main() { return 0; }' >y.tab.c
|
||||
fi
|
||||
;;
|
||||
|
||||
lex*|flex*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a \`.l' file. You may need the \`Flex' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Flex' from any GNU archive site."
|
||||
rm -f lex.yy.c
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG="\${$#}"
|
||||
case $LASTARG in
|
||||
*.l)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" lex.yy.c
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test ! -f lex.yy.c; then
|
||||
echo 'main() { return 0; }' >lex.yy.c
|
||||
fi
|
||||
;;
|
||||
|
||||
help2man*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a dependency of a manual page. You may need the
|
||||
\`Help2man' package in order for those modifications to take
|
||||
effect. You can get \`Help2man' from any GNU archive site."
|
||||
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo ".ab help2man is required to generate this page"
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
|
||||
makeinfo*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a \`.texi' or \`.texinfo' file, or any other file
|
||||
indirectly affecting the aspect of the manual. The spurious
|
||||
call might also be the consequence of using a buggy \`make' (AIX,
|
||||
DU, IRIX). You might want to install the \`Texinfo' package or
|
||||
the \`GNU make' package. Grab either from any GNU archive site."
|
||||
# The file to touch is that specified with -o ...
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -z "$file"; then
|
||||
# ... or it is the one specified with @setfilename ...
|
||||
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
|
||||
file=`sed -n '
|
||||
/^@setfilename/{
|
||||
s/.* \([^ ]*\) *$/\1/
|
||||
p
|
||||
q
|
||||
}' $infile`
|
||||
# ... or it is derived from the source name (dir/f.texi becomes f.info)
|
||||
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
|
||||
fi
|
||||
# If the file does not exist, the user really needs makeinfo;
|
||||
# let's fail without touching anything.
|
||||
test -f $file || exit 1
|
||||
touch $file
|
||||
;;
|
||||
|
||||
tar*)
|
||||
shift
|
||||
|
||||
# We have already tried tar in the generic part.
|
||||
# Look for gnutar/gtar before invocation to avoid ugly error
|
||||
# messages.
|
||||
if (gnutar --version > /dev/null 2>&1); then
|
||||
gnutar "$@" && exit 0
|
||||
fi
|
||||
if (gtar --version > /dev/null 2>&1); then
|
||||
gtar "$@" && exit 0
|
||||
fi
|
||||
firstarg="$1"
|
||||
if shift; then
|
||||
case $firstarg in
|
||||
*o*)
|
||||
firstarg=`echo "$firstarg" | sed s/o//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
case $firstarg in
|
||||
*h*)
|
||||
firstarg=`echo "$firstarg" | sed s/h//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: I can't seem to be able to run \`tar' with the given arguments.
|
||||
You may want to install GNU tar or Free paxutils, or check the
|
||||
command line arguments."
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and is $msg.
|
||||
You might have modified some files without having the
|
||||
proper tools for further handling them. Check the \`README' file,
|
||||
it often tells you about the needed prerequisites for installing
|
||||
this package. You may also peek at any GNU archive site, in case
|
||||
some other package would contain this missing \`$1' program."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# 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:
|
||||
@@ -0,0 +1,46 @@
|
||||
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
|
||||
@@ -0,0 +1,685 @@
|
||||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
|
||||
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
|
||||
DIST_COMMON = $(libmodpluginclude_HEADERS) $(noinst_HEADERS) \
|
||||
$(srcdir)/Makefile.am $(srcdir)/Makefile.in \
|
||||
$(srcdir)/config.h.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.in
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
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__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_$(V))
|
||||
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_lt_0 = --silent
|
||||
libmodplug_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
|
||||
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
|
||||
$(AM_CXXFLAGS) $(CXXFLAGS) $(libmodplug_la_LDFLAGS) $(LDFLAGS) \
|
||||
-o $@
|
||||
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_$(V))
|
||||
am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CXX_0 = @echo " CXX " $@;
|
||||
AM_V_at = $(am__v_at_$(V))
|
||||
am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_at_0 = @
|
||||
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_$(V))
|
||||
am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CXXLD_0 = @echo " CXXLD " $@;
|
||||
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_$(V))
|
||||
am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
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_$(V))
|
||||
am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
AM_V_GEN = $(am__v_GEN_$(V))
|
||||
am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
SOURCES = $(libmodplug_la_SOURCES)
|
||||
DIST_SOURCES = $(libmodplug_la_SOURCES)
|
||||
HEADERS = $(libmodpluginclude_HEADERS) $(noinst_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
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@
|
||||
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@
|
||||
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: $(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
|
||||
.PRECIOUS: 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: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@if test ! -f $@; then \
|
||||
rm -f stamp-h1; \
|
||||
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
|
||||
else :; fi
|
||||
|
||||
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: $(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)
|
||||
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
|
||||
@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 " $(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)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libmodplug.la: $(libmodplug_la_OBJECTS) $(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
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(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
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(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
|
||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-libmodplugincludeHEADERS: $(libmodpluginclude_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(libmodplugincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libmodplugincludedir)"
|
||||
@list='$(libmodpluginclude_HEADERS)'; test -n "$(libmodplugincludedir)" || list=; \
|
||||
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|^.*/||'`; \
|
||||
test -n "$$files" || exit 0; \
|
||||
echo " ( cd '$(DESTDIR)$(libmodplugincludedir)' && rm -f" $$files ")"; \
|
||||
cd "$(DESTDIR)$(libmodplugincludedir)" && rm -f $$files
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
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
|
||||
CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
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"
|
||||
|
||||
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:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
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 all all-am check check-am clean clean-generic \
|
||||
clean-libLTLIBRARIES clean-libtool ctags 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 uninstall uninstall-am uninstall-libLTLIBRARIES \
|
||||
uninstall-libmodplugincludeHEADERS
|
||||
|
||||
|
||||
# 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:
|
||||
@@ -0,0 +1,133 @@
|
||||
/* src/config.h.in. Generated from configure.in 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 `setenv' function. */
|
||||
#undef HAVE_SETENV
|
||||
|
||||
/* 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 in which 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
@@ -0,0 +1,134 @@
|
||||
#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()
|
||||
|
||||
extern BYTE autovibit2xm[8];
|
||||
extern BYTE autovibxm2it[8];
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
#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) {}
|
||||
|
||||
#define strncasecmp(a,b,c) strncmp(a,b,c)
|
||||
#define strcasecmp(a,b) strcmp(a,b)
|
||||
#define strnicmp(a,b,c) strncasecmp(a,b,c)
|
||||
#define HAVE_SINF 1
|
||||
|
||||
#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;
|
||||
|
||||
inline LONG MulDiv (long a, long b, long c)
|
||||
{
|
||||
// if (!c) return 0;
|
||||
return ((uint64_t) a * (uint64_t) b ) / c;
|
||||
}
|
||||
|
||||
#define MODPLUG_NO_FILESAVE
|
||||
#define NO_AGC
|
||||
#define LPCTSTR LPCSTR
|
||||
#define lstrcpyn strncpy
|
||||
#define lstrcpy strcpy
|
||||
#define lstrcmp strcmp
|
||||
#define WAVE_FORMAT_PCM 1
|
||||
//#define ENABLE_EQ
|
||||
|
||||
#define GHND 0
|
||||
|
||||
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) {}
|
||||
|
||||
#define GlobalFreePtr(p) free((void *)(p))
|
||||
|
||||
#define strnicmp(a,b,c) strncasecmp(a,b,c)
|
||||
#define wsprintf sprintf
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE true
|
||||
#endif
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
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; }
|
||||
// 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);
|
||||
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(pTrackData));
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
* 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];
|
||||
|
||||
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 + 7 < dwMemLength)
|
||||
{
|
||||
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:
|
||||
{
|
||||
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 (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
|
||||
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
|
||||
//
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<MAX_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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks)
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
{
|
||||
MODCOMMAND cmd, *m = pat;
|
||||
UINT len = *((WORD *)lpTracks);
|
||||
UINT pos = 0, row = 0, i;
|
||||
lpTracks += 2;
|
||||
for (UINT ntrk=1; ntrk<nTrack; ntrk++)
|
||||
{
|
||||
lpTracks += len;
|
||||
len = *((WORD *)lpTracks);
|
||||
lpTracks += 2;
|
||||
}
|
||||
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;
|
||||
const MDLPATTERNDATA *pmpd;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
block = *((WORD *)(lpStream+dwMemPos));
|
||||
blocklen = *((DWORD *)(lpStream+dwMemPos+2));
|
||||
dwMemPos += 6;
|
||||
if (dwMemPos + blocklen > dwMemLength)
|
||||
{
|
||||
if (dwMemPos == 11) return FALSE;
|
||||
break;
|
||||
}
|
||||
switch(block)
|
||||
{
|
||||
// IN: infoblock
|
||||
case 0x4E49:
|
||||
pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos);
|
||||
memcpy(m_szNames[0], pmib->songname, 32);
|
||||
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++)
|
||||
{
|
||||
if (dwPos+18 >= dwMemLength) break;
|
||||
pmpd = (MDLPATTERNDATA *)(lpStream + dwPos);
|
||||
if (pmpd->channels > 32) break;
|
||||
PatternSize[i] = pmpd->lastrow+1;
|
||||
if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels;
|
||||
dwPos += 18 + 2*pmpd->channels;
|
||||
for (j=0; j<pmpd->channels; j++)
|
||||
{
|
||||
patterntracks[i*32+j] = pmpd->data[j];
|
||||
}
|
||||
}
|
||||
break;
|
||||
// TR: Track Data
|
||||
case 0x5254:
|
||||
if (dwTrackPos) break;
|
||||
ntracks = *((WORD *)(lpStream+dwMemPos));
|
||||
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];
|
||||
dwPos = dwMemPos+1;
|
||||
for (i=0; i<nsamples; i++, dwPos += 59)
|
||||
{
|
||||
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);
|
||||
memcpy(pins->name, lpStream+dwPos+33, 8);
|
||||
pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41));
|
||||
pins->nLength = *((DWORD *)(lpStream+dwPos+45));
|
||||
pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49));
|
||||
pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53));
|
||||
if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP;
|
||||
pins->nGlobalVol = 64;
|
||||
if (lpStream[dwPos+58] & 0x01)
|
||||
{
|
||||
pins->uFlags |= CHN_16BIT;
|
||||
pins->nLength >>= 1;
|
||||
pins->nLoopStart >>= 1;
|
||||
pins->nLoopEnd >>= 1;
|
||||
}
|
||||
if (lpStream[dwPos+58] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP;
|
||||
smpinfo[nins] = (lpStream[dwPos+58] >> 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))
|
||||
{
|
||||
MODINSTRUMENT *pins = &Ins[i];
|
||||
UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
|
||||
if (!smpinfo[i])
|
||||
{
|
||||
dwPos += ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwMemLength - dwPos);
|
||||
} else
|
||||
{
|
||||
DWORD dwLen = *((DWORD *)(lpStream+dwPos));
|
||||
dwPos += 4;
|
||||
if ((dwLen < dwMemLength) && (dwLen <= dwMemLength - dwPos) && (dwLen > 4))
|
||||
{
|
||||
flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8;
|
||||
ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), 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))
|
||||
{
|
||||
MODCOMMAND *m = Patterns[ipat] + chn;
|
||||
UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], patterntracks[ipat*32+chn], lpStream+dwTrackPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) && (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) || (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
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
#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()
|
||||
|
||||
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 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;
|
||||
|
||||
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)
|
||||
{
|
||||
UINT derr = 0;
|
||||
if (psmp->nLoopStart >= psmp->nLength) { psmp->nLoopStart = psmp->nLength-1; derr|=1; }
|
||||
if (psmp->nLoopEnd > psmp->nLength) { psmp->nLoopEnd = psmp->nLength; derr |= 1; }
|
||||
if (psmp->nLoopStart > psmp->nLoopEnd) derr |= 1;
|
||||
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;
|
||||
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 (!strnicmp(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
|
||||
@@ -0,0 +1,635 @@
|
||||
#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;
|
||||
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)
|
||||
{
|
||||
#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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -0,0 +1,27 @@
|
||||
#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);
|
||||
//#ifdef NEWMIKMOD
|
||||
BOOL PAT_Load_Instruments(void *c);
|
||||
//#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength)
|
||||
//-----------------------------------------------------------
|
||||
{
|
||||
PSMCHUNK *pfh = (PSMCHUNK *)lpStream;
|
||||
DWORD dwMemPos, dwSongPos;
|
||||
DWORD smpnames[MAX_SAMPLES];
|
||||
DWORD patptrs[MAX_PATTERNS];
|
||||
BYTE samplemap[MAX_SAMPLES];
|
||||
UINT nPatterns;
|
||||
|
||||
// Swap chunk
|
||||
swap_PSMCHUNK(pfh);
|
||||
|
||||
// Chunk0: "PSM ",filesize,"FILE"
|
||||
if (dwMemLength < 256) return FALSE;
|
||||
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 = (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
|
||||
PSMSONGHDR *pSong = (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 = (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 = ((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 = ((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 = (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;
|
||||
UINT pos = 0;
|
||||
UINT row = 0;
|
||||
UINT oldch = 0;
|
||||
BOOL bNewRow = FALSE;
|
||||
#ifdef PSM_LOG
|
||||
Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream));
|
||||
#endif
|
||||
while ((row < nRows) && (pos+1 < len))
|
||||
{
|
||||
UINT flags = p[pos++];
|
||||
UINT ch = p[pos++];
|
||||
|
||||
#ifdef PSM_LOG
|
||||
//Log("flags+ch: %02X.%02X\n", flags, ch);
|
||||
#endif
|
||||
if (((flags & 0xf0) == 0x10) && (ch <= oldch) /*&& (!bNewRow)*/)
|
||||
{
|
||||
if ((pos+1<len) && (!(p[pos] & 0x0f)) && (p[pos+1] < m_nChannels))
|
||||
{
|
||||
#ifdef PSM_LOG
|
||||
//if (!nPat) Log("Continuing on new row\n");
|
||||
#endif
|
||||
row++;
|
||||
m += m_nChannels;
|
||||
oldch = ch;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((pos >= len) || (row >= nRows)) break;
|
||||
if (!(flags & 0xf0))
|
||||
{
|
||||
#ifdef PSM_LOG
|
||||
//if (!nPat) Log("EOR(%d): %02X.%02X\n", row, p[pos], p[pos+1]);
|
||||
#endif
|
||||
row++;
|
||||
m += m_nChannels;
|
||||
bNewRow = TRUE;
|
||||
oldch = ch;
|
||||
continue;
|
||||
}
|
||||
bNewRow = FALSE;
|
||||
if (ch >= m_nChannels)
|
||||
{
|
||||
#ifdef PSM_LOG
|
||||
if (!nPat) Log("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch);
|
||||
#endif
|
||||
ch = 0;
|
||||
}
|
||||
// Note + Instr
|
||||
if ((flags & 0x40) && (pos+1 < len))
|
||||
{
|
||||
UINT note = p[pos++];
|
||||
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
|
||||
if ((note) && (note < 0x80)) note = (note>>4)*12+(note&0x0f)+12+1;
|
||||
m[ch].instr = samplemap[nins];
|
||||
m[ch].note = note;
|
||||
}
|
||||
// Volume
|
||||
if ((flags & 0x20) && (pos < len))
|
||||
{
|
||||
m[ch].volcmd = VOLCMD_VOLUME;
|
||||
m[ch].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; 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;
|
||||
// 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;
|
||||
}
|
||||
m[ch].command = (BYTE)command;
|
||||
m[ch].param = (BYTE)param;
|
||||
}
|
||||
oldch = ch;
|
||||
}
|
||||
#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;
|
||||
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
if (b & 0x20)
|
||||
{
|
||||
if (dwMemPos + 2 > dwMemLength) break;
|
||||
m[nChn].note = lpStream[dwMemPos++];
|
||||
m[nChn].instr = lpStream[dwMemPos++];
|
||||
}
|
||||
if (b & 0x40)
|
||||
{
|
||||
if (dwMemPos + 2 > dwMemLength) break;
|
||||
m[nChn].command = lpStream[dwMemPos++];
|
||||
m[nChn].param = lpStream[dwMemPos++];
|
||||
if ((m[nChn].command == 0x0E) && ((m[nChn].param & 0xF0) == 0x80))
|
||||
{
|
||||
m[nChn].command = CMD_S3MCMDEX;
|
||||
} else
|
||||
if (m[nChn].command < 0x10)
|
||||
{
|
||||
ConvertModCommand(&m[nChn]);
|
||||
} else
|
||||
{
|
||||
switch(m[nChn].command)
|
||||
{
|
||||
case 16:
|
||||
m[nChn].command = CMD_GLOBALVOLUME;
|
||||
break;
|
||||
case 17:
|
||||
m[nChn].command = CMD_RETRIG;
|
||||
break;
|
||||
case 18:
|
||||
m[nChn].command = CMD_FINEVIBRATO;
|
||||
break;
|
||||
default:
|
||||
m[nChn].command = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (b & 0x80)
|
||||
{
|
||||
if (dwMemPos >= dwMemLength) break;
|
||||
m[nChn].volcmd = VOLCMD_VOLUME;
|
||||
m[nChn].vol = lpStream[dwMemPos++];
|
||||
}
|
||||
} else
|
||||
{
|
||||
row++;
|
||||
m += m_nChannels;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)) 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)
|
||||
dwMemPos += 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, ¶m, 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
|
||||
|
||||
@@ -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)
|
||||
|| ((strnicmp(phdr->trackername, "!SCREAM!", 8))
|
||||
&& (strnicmp(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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Olivier Lapicque <olivierl@jps.net>
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "sndfile.h"
|
||||
|
||||
#define MODMAGIC_OFFSET (20+31*30+130)
|
||||
|
||||
|
||||
BOOL CSoundFile::ReadUMX(const BYTE *lpStream, DWORD dwMemLength)
|
||||
//---------------------------------------------------------------
|
||||
{
|
||||
if ((!lpStream) || (dwMemLength < 0x800)) return FALSE;
|
||||
// Rip Mods from UMX
|
||||
if ((bswapLE32(*((DWORD *)(lpStream+0x20))) < dwMemLength)
|
||||
&& (bswapLE32(*((DWORD *)(lpStream+0x18))) <= dwMemLength - 0x10)
|
||||
&& (bswapLE32(*((DWORD *)(lpStream+0x18))) >= dwMemLength - 0x200))
|
||||
{
|
||||
for (UINT uscan=0x40; uscan<0x500; uscan++)
|
||||
{
|
||||
DWORD dwScan = bswapLE32(*((DWORD *)(lpStream+uscan)));
|
||||
// IT
|
||||
if (dwScan == 0x4D504D49)
|
||||
{
|
||||
DWORD dwRipOfs = uscan;
|
||||
return ReadIT(lpStream + dwRipOfs, dwMemLength - dwRipOfs);
|
||||
}
|
||||
// S3M
|
||||
if (dwScan == 0x4D524353)
|
||||
{
|
||||
DWORD dwRipOfs = uscan - 44;
|
||||
return ReadS3M(lpStream + dwRipOfs, dwMemLength - dwRipOfs);
|
||||
}
|
||||
// XM
|
||||
if (!strnicmp((LPCSTR)(lpStream+uscan), "Extended Module", 15))
|
||||
{
|
||||
DWORD dwRipOfs = uscan;
|
||||
return ReadXM(lpStream + dwRipOfs, dwMemLength - dwRipOfs);
|
||||
}
|
||||
// MOD
|
||||
if ((uscan > MODMAGIC_OFFSET) && (dwScan == 0x2e4b2e4d))
|
||||
{
|
||||
DWORD dwRipOfs = uscan - MODMAGIC_OFFSET;
|
||||
return ReadMod(lpStream+dwRipOfs, dwMemLength-dwRipOfs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Olivier Lapicque <olivierl@jps.net>
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "sndfile.h"
|
||||
|
||||
#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 + 8 >= dwMemLength)
|
||||
|| ((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 + 8 >= dwMemLength) 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
* 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 (strnicmp((LPCSTR)lpStream, "Extended Module", 15)) return FALSE;
|
||||
|
||||
memcpy(m_szNames[0], lpStream+17, 20);
|
||||
xmhead = *(tagXMFILEHEADER *)(lpStream+60);
|
||||
dwHdrSize = bswapLE32(xmhead.size);
|
||||
norders = bswapLE16(xmhead.norder);
|
||||
if ((!norders) || (norders > MAX_ORDERS)) return FALSE;
|
||||
restartpos = bswapLE16(xmhead.restartpos);
|
||||
channels = bswapLE16(xmhead.channels);
|
||||
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)));
|
||||
}
|
||||
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
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Olivier Lapicque <olivierl@jps.net>
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "sndfile.h"
|
||||
|
||||
BOOL PP20_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
|
||||
|
||||
typedef struct MMCMPFILEHEADER
|
||||
{
|
||||
DWORD id_ziRC; // "ziRC"
|
||||
DWORD id_ONia; // "ONia"
|
||||
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;
|
||||
WORD num_bits;
|
||||
} MMCMPBLOCK, *LPMMCMPBLOCK;
|
||||
|
||||
typedef struct MMCMPSUBBLOCK
|
||||
{
|
||||
DWORD unpk_pos;
|
||||
DWORD unpk_size;
|
||||
} MMCMPSUBBLOCK, *LPMMCMPSUBBLOCK;
|
||||
|
||||
#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
|
||||
|
||||
const DWORD MMCMP8BitCommands[8] =
|
||||
{
|
||||
0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF8
|
||||
};
|
||||
|
||||
const UINT MMCMP8BitFetch[8] =
|
||||
{
|
||||
3, 3, 3, 3, 2, 1, 0, 0
|
||||
};
|
||||
|
||||
const DWORD MMCMP16BitCommands[16] =
|
||||
{
|
||||
0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF0,
|
||||
0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
|
||||
};
|
||||
|
||||
const UINT MMCMP16BitFetch[16] =
|
||||
{
|
||||
4, 4, 4, 4, 3, 2, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
|
||||
BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength)
|
||||
//---------------------------------------------------------
|
||||
{
|
||||
DWORD dwMemLength = *pdwMemLength;
|
||||
LPCBYTE lpMemFile = *ppMemFile;
|
||||
LPBYTE pBuffer;
|
||||
LPMMCMPFILEHEADER pmfh = (LPMMCMPFILEHEADER)(lpMemFile);
|
||||
LPMMCMPHEADER pmmh = (LPMMCMPHEADER)(lpMemFile+10);
|
||||
LPDWORD pblk_table;
|
||||
DWORD dwFileSize;
|
||||
|
||||
if (PP20_Unpack(ppMemFile, pdwMemLength))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if ((dwMemLength < 256) || (!pmfh) || (pmfh->id_ziRC != 0x4352697A) || (pmfh->id_ONia != 0x61694e4f) || (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 = (LPDWORD)(lpMemFile+pmmh->blktable);
|
||||
for (UINT nBlock=0; nBlock<pmmh->nblocks; nBlock++)
|
||||
{
|
||||
DWORD dwMemPos = pblk_table[nBlock];
|
||||
LPMMCMPBLOCK pblk = (LPMMCMPBLOCK)(lpMemFile+dwMemPos);
|
||||
LPMMCMPSUBBLOCK psubblk = (LPMMCMPSUBBLOCK)(lpMemFile+dwMemPos+20);
|
||||
|
||||
if ((dwMemPos + 20 >= dwMemLength) || (dwMemPos + 20 + pblk->sub_blk*8 >= dwMemLength)) break;
|
||||
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_pos + psubblk->unpk_size > dwFileSize)) 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;
|
||||
psubblk++;
|
||||
}
|
||||
} else
|
||||
// Data is 16-bit packed
|
||||
if (pblk->flags & MMCMP_16BIT)
|
||||
{
|
||||
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;
|
||||
|
||||
#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;
|
||||
while (subblk < pblk->sub_blk)
|
||||
{
|
||||
UINT newval = 0x10000;
|
||||
DWORD d = bb.GetBits(numbits+1);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
pDest[dwPos++] = (WORD)newval;
|
||||
}
|
||||
if (dwPos >= dwSize)
|
||||
{
|
||||
subblk++;
|
||||
dwPos = 0;
|
||||
dwSize = psubblk[subblk].unpk_size >> 1;
|
||||
pDest = (LPWORD)(pBuffer + psubblk[subblk].unpk_pos);
|
||||
}
|
||||
}
|
||||
} else
|
||||
// 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;
|
||||
|
||||
bb.bitcount = 0;
|
||||
bb.bitbuffer = 0;
|
||||
bb.pSrc = lpMemFile+dwMemPos+pblk->tt_entries;
|
||||
bb.pEnd = lpMemFile+dwMemPos+pblk->pk_size;
|
||||
while (subblk < pblk->sub_blk)
|
||||
{
|
||||
UINT newval = 0x100;
|
||||
DWORD d = bb.GetBits(numbits+1);
|
||||
|
||||
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)
|
||||
{
|
||||
int n = ptable[newval];
|
||||
if (pblk->flags & MMCMP_DELTA)
|
||||
{
|
||||
n += oldval;
|
||||
oldval = n;
|
||||
}
|
||||
pDest[dwPos++] = (BYTE)n;
|
||||
}
|
||||
if (dwPos >= dwSize)
|
||||
{
|
||||
subblk++;
|
||||
dwPos = 0;
|
||||
dwSize = psubblk[subblk].unpk_size;
|
||||
pDest = pBuffer + psubblk[subblk].unpk_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*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;
|
||||
}
|
||||
|
||||
|
||||
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] = (BYTE)BitBuffer.GetBits(8);
|
||||
}
|
||||
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) || (*(DWORD *)lpMemFile != 0x30325050)) 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
|
||||
*/
|
||||
|
||||
#include "modplug.h"
|
||||
#include "stdafx.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 ) {
|
||||
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 = (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.
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
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. */
|
||||
ModPlugFile* ModPlug_Load(const void* data, int size);
|
||||
/* Unload a mod file. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
void ModPlug_GetSettings(ModPlug_Settings* settings);
|
||||
void ModPlug_SetSettings(const ModPlug_Settings* settings);
|
||||
|
||||
/* New ModPlug API Functions */
|
||||
/* NOTE: Master Volume (1-512) */
|
||||
unsigned int ModPlug_GetMasterVolume(ModPlugFile* file) ;
|
||||
void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol) ;
|
||||
|
||||
int ModPlug_GetCurrentSpeed(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentTempo(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentOrder(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentPattern(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentRow(ModPlugFile* file);
|
||||
int ModPlug_GetPlayingChannels(ModPlugFile* file);
|
||||
|
||||
void ModPlug_SeekOrder(ModPlugFile* file,int order);
|
||||
int ModPlug_GetModuleType(ModPlugFile* file);
|
||||
char* ModPlug_GetMessage(ModPlugFile* file);
|
||||
|
||||
|
||||
#ifndef MODPLUG_NO_FILESAVE
|
||||
/*
|
||||
* EXPERIMENTAL Export Functions
|
||||
*/
|
||||
/*Export to a Scream Tracker 3 S3M module. EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Extended Module (XM). EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
char ModPlug_ExportXM(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Amiga MOD file. EXPERIMENTAL.*/
|
||||
char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Impulse Tracker IT file. Should work OK in Little-Endian & Big-Endian platforms :-) */
|
||||
char ModPlug_ExportIT(ModPlugFile* file, const char* filepath);
|
||||
#endif // MODPLUG_NO_FILESAVE
|
||||
|
||||
unsigned int ModPlug_NumInstruments(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumSamples(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumPatterns(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumChannels(ModPlugFile* file);
|
||||
unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
|
||||
/*
|
||||
* Retrieve pattern note-data
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc) ;
|
||||
void ModPlug_UnloadMixerCallback(ModPlugFile* file) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user