Added mikmod library, also added it to SDL_mixer

This commit is contained in:
pelya
2010-11-12 11:58:53 +02:00
parent 48c1f1aa0a
commit b9e424ea10
55 changed files with 27358 additions and 4 deletions

View File

@@ -1 +1 @@
REminiscence
pachi

130
project/jni/mikmod/AUTHORS Normal file
View File

@@ -0,0 +1,130 @@
libmikmod main authors
----------------------
* Jean-Paul Mikkers (MikMak) <mikmak@via.nl>
wrote MikMod and maintained it until version 3.
* Jake Stine (Air Richter) <dracoirs@epix.net>
[email doesn't work anymore...]
made decisive contributions to the code (esp. IT support) and
maintained MikMod version 3 until it was discontinued. He still works
on the WinAmp module plugin, roughly based on MikMod.
* Miod Vallat <miod@mikmod.org>
maintainer MikMod'Unix (since version 3.0.4), made
an audit of the code resulting in many bugs fixed.
* Raphael Assenat <raph@raphnet.net>
Revived the project after many years of inactivity, in 2004. Is
the current maintainer.
Previous Unix maintainers
-------------------------
* Steve McIntyre <steven@chiark.greenend.org.uk>
maintained MikMod'Unix version 2. Used to maintain the Debian package
for MikMod.
* Peter Amstutz <tetron@student.umass.edu>
maintained MikMod'Unix version 3 up to version 3.0.3.
General contributors
--------------------
* Arne de Bruijn <arne@knoware.nl>
wrote the compressed IT sample support.
* Shlomi Fish <shlomif@vipe.technion.ac.il>
wrote the Java port, bug fixes.
* Juan Linietsky <coding@reduz.com.ar>
overall bug fixes.
* Claudio Matsuoka <claudio@helllabs.org>
wrote the STX loader and submitted bug fixes.
* Sebastiaan A. Megens <samegens@xs4all.nl>
fixed various bugs (memory leaks, endianness issues, etc).
* ``UFO'' <ufo303@poczta.onet.pl>
wrote the OKT loader.
* Kev Vance <kvance@zeux.org>
wrote the GDM loader.
* Paul Fisher made decisive contributions and improvements.
* Alexander Kerkhove fixed an ULT panning effect bug.
* ``Kodiak'' helped on the interfaces of libmikmod.
* Sylvain Marchand make MikMod more portable and GCC compilable.
Contributors on the Unix side
-----------------------------
* Axel "awe" Wefers <awe@fruitz-of-dojo.de>
wrote the OSX CoreAudio driver, the AIFF driver and
updated the Mac Audio Carbon driver
* Douglas Carmichael <dcarmich@mcs.com>
ported MikMod to FreeBSD.
* Chris Conn <cconn@tohs.abacom.com>
wrote the OSS driver.
* Roine Gustaffson <e93_rog@e.kth.se>
wrote the Digital AudioFile driver.
* Stephan Kanthak <kanthak@informatik.rwth-aachen.de>
wrote the SGI driver.
* Lutz Vieweg <lkv@mania.robin.de>
wrote the AIX and HP-UX drivers.
* Valtteri Vuorikoski <vuori@sci.fi>
wrote the Sun driver.
* Andy Lo A Foe <andy@alsa-project.org>
wrote the Ultra driver (for the Gravis Ultrasound sound card).
* C Ray C <crayc@pyro.net>
updated the Ultra driver to work with libmikmod 3.
* ``MenTaLguY'' <mental@kludge.org>
autoconfized the Unix libmikmod distribution.
* Tobias Gloth <gloth@geomagic.com>
created the new I/O interface, made the code MT-safe and submitted bug fixes.
* Simon Hosie <gumboot@clear.net.nz>
wrote the piped output driver, and submitted speed optimizations and bugfixes
for the software mixer.
* Gerd Rausch <gerd@alf.gun.de>
wrote the sam9407 driver.
* Joseph Carter <knghtbrd@debian.org>
maintains the Debian package for MikMod and libmikmod, submitted
bugfixes.
Contributors on the Windows side
--------------------------------
* Brian McKinney <Brian.McKinney@colorado.edu>
created the DirectSound driver.
* Bjornar Henden <bhenden@online.no>
created the Multimedia API windows driver.
Contributors on the Dos side
----------------------------
Their code isn't there anymore, but they contributed to the success of
libmikmod...
* Jean-Philippe Ajirent wrote the EMS memory routines.
* Peter Breitling ported MikMod to DJGPP.
* Arnout Cosman wrote the PAS driver.
* Mario Koeppen wrote the WSS driver.
* Mike Leibow wrote the GUS driver.
* Jeremy McDonald wrote a fast assembly-language mixer.
* Steffen Rusitschka and Vince Vu wrote the AWE driver.
Contributors on the Macintosh side
----------------------------------
* Anders Bjoerklund <afb@algonet.se>
ported libmikmod to the Macintosh.
Contributors on the OS/2 side
-----------------------------
* Stefan Tibus <Stefan_Tibus@ThePentagon.com>
ported libmikmod to OS/2.
* Andrew Zabolotny <bit@eltech.ru>
improved the existing OS/2 drivers.
Contributors on the BeOS side
-----------------------------
* Thomas Neumann <tneumann@polycode.dk>
integrated libmikmod into his BeOS APlayer, and contributed many bug fixes.
--
If your name is missing, don't hesitate to remind me at
<mikmod@mikmod.raphnet.net>

View File

@@ -0,0 +1,24 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mikmod
APP_SUBDIRS := $(patsubst $(LOCAL_PATH)/%, %, $(shell find $(LOCAL_PATH) -type d))
LOCAL_CFLAGS := -O3 $(foreach D, $(APP_SUBDIRS), -I$(LOCAL_PATH)/$(D)) \
-I$(LOCAL_PATH)/include -I$(LOCAL_PATH) -DHAVE_CONFIG_H
LOCAL_CPP_EXTENSION := .cpp
LOCAL_SRC_FILES := $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.cpp))))
LOCAL_SRC_FILES += $(foreach F, $(APP_SUBDIRS), $(addprefix $(F)/,$(notdir $(wildcard $(LOCAL_PATH)/$(F)/*.c))))
LOCAL_SHARED_LIBRARIES :=
LOCAL_STATIC_LIBRARIES :=
LOCAL_LDLIBS :=
include $(BUILD_STATIC_LIBRARY)

View File

@@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We this
license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
Another cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does insure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -0,0 +1,482 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

183
project/jni/mikmod/INSTALL Normal file
View File

@@ -0,0 +1,183 @@
Basic Installation
==================
These are generic installation instructions.
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, a file
`config.cache' that saves the results of its tests to speed up
reconfiguring, and a file `config.log' containing compiler output
(useful mainly for debugging `configure').
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 at some point `config.cache'
contains results you don't want to keep, you may remove or edit it.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need `configure.in' 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. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. 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.
4. Type `make install' to install the programs and any data files and
documentation.
5. 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.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. You can give `configure'
initial values for variables by setting them in the environment. Using
a Bourne-compatible shell, you can do that on the command line like
this:
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
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 must use a version of `make' that
supports the `VPATH' variable, such as 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 `..'.
If you have to use a `make' that does not supports the `VPATH'
variable, you have 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.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' 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.
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'.
Optional Features
=================
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.
Specifying the System Type
==========================
There may be some features `configure' can not figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
a message saying it can not guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
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 host type.
If you are building compiler tools for cross-compiling, you can also
use the `--target=TYPE' option to select the type of system they will
produce code for and the `--build=TYPE' option to select the type of
system on which you are compiling the package.
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.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--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.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

590
project/jni/mikmod/NEWS Normal file
View File

@@ -0,0 +1,590 @@
Summary of changes between libmikmod 3.1.11 and libmikmod 3.2.0 ():
==========================================================================
THANKS
- Axel "awe" Wefers <awe@fruitz-of-dojo.de>,
for creating the CoreAudio driver, the new
AIFF driver and updating the Carbon driver.
- Frank Loemker, for sending me his collection of patches
for libmikmod.
- Anders F Björklund <afb@algonet.se>, for updates, fixes and tests on
Mac Platforms.
NEW FEATURES
- MacOS X CoreAudio driver
- Carbon support
- Loader for ASYLUM Music Format v1.0 (.amf) modules,
as used in crusader games.
- New function 'Player_QueryVoices' added, which is used to return
dynamic channel information about the module player. (Mikmod 3.2.2 uses
it for it's dynamic panels).
- Mixing with floating point output. The MacOSX CoreAudio driver uses it.
Thanks goes to Anders F Björklund for implementing this.
- AIFF disk writer driver.
BUGFIXES
- The sun driver now compiles on solaris (Thanks to Nicolas Gros d'Aillon
for sending me Jonathan Perkin's fix)
Summary of changes between libmikmod 3.1.10 and libmikmod 3.1.11 (Thiers):
==========================================================================
libmikmod 3.1.11 was released on 01/21/2004.
This is a small maintenance release. I know there are not many changes,
but since it has been a very long time since the last one, and meanwhile
libmikmod changed maintaner, I think it is justified.
THANKS
- Ingo Saitz, the maintainer of the mikmod packages for debian, for
bugfixes.
- Frank Loemker, for the lcc-win32 stuff and fixes for the direct sound
driver.
BUGFIXES
- Playback problems in MODs of length >128. This fixes the file beatwave.mod. Thanks
to Emmanuel Coirier for pointing this out.
- Applied debian patches:
- Fix for broken volume fadeouts of IT instruments
- Fixed configure test for pthread
- devfs support for Linux OSS
- Makefile for lcc-win32. To compile libmikmod with lcc-win32 a rather new
version is needed. I currently use version 3.7 compiled on Jan 20 2002.
A version half a year old did not work.
To compile
- check that you have the lcc bin directory in the PATH
(and no other compiler bin dirs),
- change to libmikmod-3.1.11/win32,
- check Makefile.lcc for any needed changes, and
- use make -f Makefile.lcc.
- Different fixes for the direct sound driver:
- Pausing did only work for half of the buffer.
- Restarting the player did not work as the output thread was removed
in DS_PlayStop().
- Removed busy waiting for end of thread.
- Sound output is started immediately on the first call to DS_Update()
to be consistent with other non threaded drivers.
- Different small clean ups.
- In MikMod_Reset() the raw output driver driver did not use the
filename set via the cmdline.
Summary of changes between libmikmod 3.1.9 and libmikmod 3.1.10 (Arlanc):
=========================================================================
libmikmod 3.1.10 was released on 01/24/2002.
This version is yet another bugfix release. I have more contributions coming,
especially a native MacOS X driver, that will not be present in 3.1.10 but
will be in 3.1.11.
THANKS
- Most of the bugs mentioned below have been squished by ``UFO'',
Holger Jakob, Thomas Neumann, Mark Page and Juan Linietsky.
BUGFIXES
- Systematic coredumps on library initialization and calls to
MikMod_InfoDriver have been eliminated. Sorry, and thanks to Shlomi
Fish for the best fix.
- The fix for spurious effect memory for portamentos in MOD files shouldn't
have been applied to the ``porta to note'' (effect 3) effect. Fixed in this
release. In the process, the aforementioned fix was perfected, as it
broke a few modules by accident.
- IT Panbrello effect with random wave did not work.
- IT Tempo slide (T0x, T1x) was not updated accurately, and the effect memory
was not implemented. The only tempo slide command which worked accurately
was T10, which is a no-op (-:
- IT effect SC0 (cut note with no delay) is now correctly interpreted as SC1.
- XM effect 6 (porta + volume slide) didn't have memory.
- ProTracker effect F (change speed or bpm) should now be correctly handled
when its value is 32, depending on the module type (some formats will use
it as a speed value, others as a bpm value).
- XM playback stopped when reaching pattern 255 in the order list.
- Corrupted envelopes in XM instruments are detected and some repair is
attempted.
- Some valid AMF, IMF and IT modules refused to load.
- Fine volume slide effects in volume column of IT modules, when using the
effect memory (i.e. A0 and B0) were misinterpreted as AF and BF, thus
causing unwanted large slides.
- Portamento to note effect in volume column of IT modules was not rendered
correctly.
- S3M files marked as created by ScreamTracker will honour the limit of 64000
bytes (not 64KB!) for sample length and sample offset effect position.
- Loops in instrument envelopes were processed one tick too fast.
- In-song message in FAR modules were not displayed correctly.
- ProTracker effect E9 (Retrig) was not played correctly.
NEW FEATURES
- Modules which are not panning-aware (not using any panning effects and
with the tracker's default panning) use a recentered panning, so as to
sound better with headphones. Suggested by Urpo Lankinen.
- Retrigger and panning effects are now recognized in FAR modules.
- All arpeggio effects are now played in OKT modules.
- FLT8 modules (8 channel StarTrekker) are now recognized and played.
PLATFORM SPECIFIC
- The Windows DirectSound driver has been improved and will use less
resources during playback.
- The native audio driver for NetBSD and OpenBSD should work better with
recent versions of these systems, as well as with old sound cards such
as the SoundBlaster Pro.
- Mac OS X is supported, although no native sound driver is available for
it yet, thanks to Juha Kaunisto.
- Dynamically loading drivers is now supported on HP-PA systems running
under HP-UX, as well on systems using the a.out binary file format.
Summary of changes between libmikmod 3.1.8 and libmikmod 3.1.9 (Vorey):
=======================================================================
libmikmod 3.1.9 was released on 02/14/2000.
This version is a bugfix release, and was primarily considered as a public
patch for 3.1.8 (namely, version 3.1.8-a). However, due to the very important
bug fix in XM playback, among other things, it's worth being 3.1.9...
THANKS
- Many thanks to ``UFO'', Thomas Neumann, James Kehl and Vito Caputo for their
help, code and feedback.
- Special thanks to Gerd Rausch, for writing both the Linux sam9407 driver and
the associated Mikmod driver. Nice work !
- Thanks to Bastien Nocera for letting me do some tests under Linux/PPC.
BUGFIXES
- Envelopes weren't loaded correctly for IMF and XM modules. In the average
case, the first envelope point was correct, the remaining half points were
bogus, and the other half completely random. This fix is definitely worth
the upgrade.
- In MOD files, effect 0xc (set channel volume) with effect parameter 0xff was
misplayed as a note cut.
- In MOD files too, effects 0x1, 0x2 and 0x3 (portamentos) with effect
parameter 0x00 were using the command memory, but these commands do not have
effect memory for MOD files.
- The Wuzamod check for STM modules wasn't present in 3.1.8, despite what the
release notes said )-:
- Enabling the envelope (with an effect) for a sample with no associated
envelope would cause immediate coredumps. Now fixed.
- Panning was ignored in GDM modules.
- Sample rate was incorrect for STM and STX modules.
- Arpeggio memory (for IT modules) was ignored.
- Tempo slide for IT modules was not processed correctly.
- Toggling surround sound didn't have effect until the driver was reset.
NEW FEATURES
- New loader for Amiga Oktalyzer (.OKT) modules.
- UNI loader recognizes recent APlayer modules (.APUN format level 0x104).
- Due to popular request, the function Player_LoadTitleFP() has been added to
the library.
- Under Unix systems, make targets "check" and "uninstall" have been added.
However, due to a bug in automake, "make uninstall" will only work correctly
with the next release of automake (or the current CVS tree).
- New output driver for sam9407-based soundcards under Linux, featuring
hardware playback.
PLATFORM SPECIFIC
- Support for the latest Linux Ultra driver development versions (2.99) has
been added. Also, a few bugs in this driver have been fixed.
- The DirectSound driver (win32) shipped with the previous release didn't
compile. It should now - at least things are better !
- The OSS driver from 3.1.8 didn't work very well with some versions of the
Linux kernel, as well as under Linux/PPC. The problems should be gone now.
Also, the OSS driver now handles multi-soundcard configurations.
Summary of changes between libmikmod 3.1.7 and libmikmod 3.1.8 (Tence):
=======================================================================
libmikmod 3.1.8 was released on 10/25/1999.
THANKS
- Many thanks (in no particular order) to Frank Loemker, Bjornar Henden, Joshua
Shagam, Vito Caputo, Thomas Neumann, Zach Metzinger, and Kevin Langman for
their help, code and feedback.
- Special thanks to Andrew Zabolotny for his huge work on the OS/2 drivers.
The rest of your code is not lost, it will go into 3.2...
BUGFIXES (more details can be found in file ``PROBLEMS'')
- IT global volume slide effect was played too fast.
- IT effect S6x (pattern delay for x ticks) was misunderstood as SEx (pattern
delay for x rows).
- Finetune effect was not handled correctly for some XM modules.
- Software mixer incorrectly produced extra clicks in interpolated mode (fix by
Frank Loemker).
- Under Unix systems, the piped output driver (drv_pipe), as well as the output
to file drivers (drv_raw, drv_wav) had security issues if the libmikmod
application is setuid root.
- Trying to read data from a file, with the data not located at offset 0,
didn't work correctly since 3.1.5.
- Almost any text file beginning with "if" was considered as a valid module by
Player_LoadTitle(), yet hopefully rejected when trying to load it.
- AMF effect 4 and variants lacked memory.
- IT modules featuring patterns with less than 32 rows could not be loaded.
- Some samples and effects in APlayer converted modules (.apun) were not played
correctly.
- Linefeeds in the song message in IT modules weren't loaded correctly.
NEW FEATURES
- IMF effect XE (ignore envelope) implemented.
- Support for uLaw output with the OSS driver, for Linux/sparc.
- Started to modularize semaphore usage when possible. The Player_LoadTitle()
function can be used while a module is playing without causing a short pause
in playback.
- STM modules with the Wuzamod signature can now be loaded.
- More ``slightly corrupted'' XM modules can be loaded.
PLATFORM SPECIFIC
- libmikmod 3.1.7 didn't compile out of the box under IRIX (sorry !)
- The EsounD driver didn't compile under Solaris
- Solaris driver forced playback to either headphone or speaker, instead of
using the current output setting as default. This is now fixed.
- Under SunOS 4, libmikmod should compile with the non-ansi C compiler bundled
by default.
- The ALSA driver now works with ALSA 0.4.
- The OSS driver should now work with Linux/ppc.
- Under OS/2, the MMPM/2 and DART driver have been almost rewritten by Andrew
Zabolotny and work much better. And they are now somewhat configurable, too.
- libmikmod 3.1.8 should work as a DLL under win32 environments. And the
non-directX driver is now registered in MikMod_RegisterAllDrivers().
Summary of changes between libmikmod 3.1.6 and libmikmod 3.1.7 (Sauxillanges):
==============================================================================
libmikmod 3.1.7 was released on 06/28/1999.
THANKS
- Anders Bjoerklund did a terrific job of creating a Macintosh driver !
I'm proud to add the MacOS to the list of supported systems.
- Bjornar Henden provided a non-directX driver for Windows NT users. This
makes libmikmod more portable than ever. Thanks a lot !
- Simon Hosie contributed speed optimizations and bug fixes to the software
mixer. Thanks for your work !
- Timo Taipalus pointed out several severe problems and helped me to get rid
of them. Thanks for your efforts !
BUGFIXES (more details can be found in file ``PROBLEMS'')
- Very long samples were truncated when played with the normal software
mixer.
- Invalid notes using non-existent instruments caused the current note to
be retrigged instead of being ignored.
- Porta to note effects did not restart the sample envelopes.
- Note cut with non empty volume column on the same row resulted in the note
cut being ignored.
- Disabling/enabling envelopes had no effect.
- 15 instrument modules embedding a ``Music Channel BBS'' ad were rejected.
- Huge (>64Kb) sample offsets were ignored with the hiqh quality mixer.
- Delay note effect was incorrectly converted to pattern jump, and porta to
note was incorrectly converted to tremor, for GDM modules.
- Dual effect Lxx in S3M and IT was misconverted to L00 (this bug was
introduced in 3.1.5-beta2, thanks to Timo Taipalus for noticing it)
- Pitch envelope was not played accurately (IT).
- XM modules in format 1.03 couldn't be loaded.
- XM modules with the tracker name empty made the library coredump on some
platforms.
- Set finetune effect (E5x) wasn't handled correctly for XM modules.
- Fine slides (X1x,X2x) didn't play correctly for XM modules (thanks to Frank
Loemker for reporting it).
- If the MikMod_InitThreads() function was called more than once, the library
did not behave correctly.
- Sample loops were not computed correctly for Oktalyzer modules.
NEW FEATURES
- Modules can be played with a speed shift (suggested by Roope Anttinnen).
- MikMod_Init() and MikMod_Reset() have been extended to pass specific
parameters to the drivers. This makes libmikmod 3.1.7 incompatible with the
previous versions, but updated libmikmod-based players will be released soon.
The shared library version has increased (now 2.0). This number scheme is
going to be as crazy as ncurses' one...
PLATFORM SPECIFIC
- It was not possible to create a multithreaded library on FreeBSD (fix by
Roope Anttinnen).
- HP-UX driver used to reset mixer settings at initialization.
- Added MacOS support, thanks to Anders Bjoerklund.
- Solaris driver now works on Solaris/Intel edition.
Summary of changes between libmikmod 3.1.5 and libmikmod 3.1.6 (Romegier):
==========================================================================
libmikmod 3.1.6 was released on 03/24/1999.
BUGFIXES
- When the library was built thread-safe, calls to Player_SetPosition
resulted in a deadlock.
- The OSS driver was too strict and didn't allow OSS to select a different
playback frequency.
- A volume bug has been removed from the module player (thanks to Thomas
Neumann for the report).
NEW FEATURES
- Volume ramping has been ported from the high quality mixer to the regular
mixer, and is enabled when interpolated mixing is requested. You should hear
less clicks in interpolated mode from now ! (Suggested by Bjornar Henden)
- The UNI loader recognizes APlayer format 1.3 modules.
PLATFORM SPECIFIC
- The NetBSD and OpenBSD driver should work with recent NetBSD and OpenBSD
versions.
- Some Windows code has been merged. Feedback will be appreciated. Note that,
as I don't have a windows development system (and no plan to have one in the
near future), I can't test or debug the Windows part myself.
Summary of changes between libmikmod 3.1.2 and libmikmod 3.1.5 (Pradelles):
===========================================================================
libmikmod 3.1.5 was released on 03/01/1999.
THANKS
- Many thanks to Lutz Roeder and Uwe Thoma, who send me the description of
the Imago Orpheus file format (IMF), as well as some of Imago's code, which
made the creation of the IMF loader a pure C exercise (-:
- Many thanks to Claudio Matsuoka, Tobias Gloth, C. Ray C. and Ben Collver for
their contributions and bug reports.
- Also big thanks to Jan Havelka for his help in tracking and fixing bugs.
- I almost forgot to thank Cedric Hebert for pointing out the gcc 2.x
optimization options bug !
- And as a last-minute add-on, Kev Vance submitted a GDM loader.
BUGFIXES
- The OSS driver used much more memory than necessary without reason.
- Samples longer than 1 Mb were not played correctly. However, the fix now
requires that your C compiler provides a 64 bit integer type. As a result,
libmikmod will not compile anymore on AIX with old versions of xlC.
- Samples with ping pong loops could make the library segfault on some rare
conditions. This bug was also present in MikIT and in the module plugin
of winamp, which are also based on old MikMod 3 sources...
- The sample loaders will now load samples with extra information blocks in
them, and has been made more robust.
- More checks to detect empty song messages.
- The song message loading routine was bugged and could make the library
coredump.
- AMF modules in formats 1.0, 1.2 and 1.3 couldn't be loaded.
- MED loader now loads instrument names and song message if they exist.
- More check have been added to the 15 instrument MOD loader to prevent it
from hanging on non-mod files ; let me know if you still experience
problems with it.
- STM loader rejected STM created by MOD2STM ; the last pattern was never
played ; also, in some STM modules the samples were not loaded correctly.
- XM modules in format 1.02 couldn't be loaded.
- Envelope sustain loops in XM modules were not processed correctly.
- Porta to note using the command memory used sometimes an incorrect value
when playing AMF, IT, S3M and ULT modules.
- Volume slides for IT (Dxx) and XM (Axx) modules didn't continue in the
background.
- Porta down effect in the volume column of IT modules was not played
correctly.
- Problems occuring when compiling libmikmod when an older version of libmikmod
is installed are now fixed.
DOCUMENTATION FIXES
- The documentation incorrectly referred to PAN_MIDDLE instead of PAN_CENTER.
NEW FEATURES
- On platforms that support POSIX.4 threads, the library is now thread-safe.
- Depending on your system's capabilities, ALSA and EsounD driver can now
be dynamically loaded when a libmikmod application is run, so if you built
your binary with the shared ALSA or EsounD libraries (which is the default),
it will run on other systems lacking those libraries.
- New loaders for GDM (General Digital Music), IMF (Imago Orpheus) and STX
(STMIK 0.2) modules.
- UNI loader is back, for those who need to play the ``Acid Tetris'' songs.
- S3M loader correctly identifies S3M modules created by Impulse Tracker
an Imago Orpheus.
- IT effect T (slide tempo) is now implemented.
- The driver for the Linux Ultrasound project (the ancestor of ALSA) is back,
too.
- The selection of the standard or high-quality software mixer is now made at
runtime.
- New interfaces Voice_Get{Frequency,Panning,Volume} and
Player_GetChannelPeriod (this one is for x11amp's MikMod plugin).
- Due to the addition of the new driver and loaders, library version has
increased.
PLATFORM SPECIFIC
- Compiling with gcc 2.x under Linux on x86 platforms performed aggressive
optimizations which had nasty interferences with the channel volumes on
some modules. Hopefully this is now fixed, so gcc users will get the same
sound quality as egcs users.
I apologize to everyone told me of this volume problem for the time it took
me to figure out where it came from.
Previous versions of libmikmod were bundled with the MikMod player ; refer to
its ``NEWS'' file for older changes information.

449
project/jni/mikmod/README Normal file
View File

@@ -0,0 +1,449 @@
Hello folks!
This is libmikmod, version 3.2.0-beta1, a portable sound library for Unix
and other systems. Check out the file 'NEWS' for more history information.
>> BETA WARNING
---------------
This is a *beta* version of libmikmod. Although it should work fine on
almost all systems, there are likely a few last-minute errors or typos
in the source, and some parts have not received enough hours of testing yet.
Also, please note that all features planned for the final 3.2.0 release are not
available yet. Some structures or functions may change. This release is mainly
intended to the libmikmod developers to share a common base for adding new
features...
The library programming documentation (in docs/) is mostly up-to-date... It
lacks the Player_QueryVoices documentation, though.
If you're not scared, then you can proceed and enjoy fewer bugs than in the
previous version (-;
>> BUILDING LIBMIKMOD
---------------------
- If you're building libmikmod under MacOS, please refer to the 'README'
file located in the 'macintosh' subdirectory.
- If you're building libmikmod under OS/2, please refer to the 'README'
file located in the 'os2' subdirectory.
- If you're building libmikmod under Windows, please refer to the
'README' file located in the 'win32' subdirectory.
- If you're building libmikmod under any other system which is not a
Unix flavour, then be warned that this your platform is not supported
and that libmikmod will probably not build out of the box; don't
hesitate to drop me a note, and I'll see what I can do for this situation.
So you're on a good old Unix workstation, aren't you ?
You'll need an ANSI C compiler to build libmikmod. If your system does not
come with an ANSI C compiler, you might want to try the GUN C compiler, gcc.
If you're building on a 32 bit architecture, your compiler must provide a
64 bit integer type (usually 'long long').
To prevent clobbering the sources, I recommend building libmikmod in an
alternate directory, for example 'build':
mkdir build
cd build
In this directory, run libmikmod's configure script:
../configure
The configure script will attempt to guess correct values for various
system-dependent variables used during the build process, and will
create appropriate Makefiles for proper compilation.
If you're not familiar with configure scripts and their standard
options, you can find more general information about them in the file
INSTALL.
The default behaviour of the configure script is to create both a static
and a shared library, with as many drivers as possible, which are
dynamically loaded whenever possible. However, it can be given several
options to tweak your configuration of libmikmod:
The --enable-af, --enable-alsa, --enable-esd, --enable-oss,
--enable-sam9407 and --enable-ultra options will compile respectively
the Digital AudioFile, Advanced Linux Sound Architecture (ALSA),
Enlightened Sound Daemon, Open Sound System (OSS), sam9407 and Linux
Ultrasound drivers.
Since the configure script will search for the appropriate include files
and libraries, to compile as much drivers as possible, these options are
mostly useful in their negative form:
../configure --disable-esd
will configure libmikmod without the Enlightened Sound Daemon driver,
even if all the necessary files for compiling are present on the
system.
The --enable-dl option enables the dynamic load of the alsa, esd and
ultra drivers at runtime, if your systems support it. This option is
enabled by default if the build system supports it, so it is more useful
in its negative form:
../configure --disable-dl
will configure libmikmod without the dynamic loading facility.
The --enable-threads option enables the creation of a thread-safe
libmikmod library, if your system provides POSIX threads. This option is
enabled by default, so it is more useful in its negative form:
../configure --disable-threads
will configure for a non thread-safe version of libmikmod.
The --enable-shared and --enable-static options control whether a static
library, a shared library or both should be built.
The --enable-debug option creates a debug version of libmikmod.
After you've successfully run configure, simply run
make
to get all things build. Then, run
make install
to have the library installed. Depending on where you choose to install
it (using the --prefix= option to configure), you may need root
privileges for this operation.
>> DRIVER PARAMETERS
--------------------
Until a good place to put this information is found, here is the list of
parameters recognized by the drivers, as well as the driver alias list.
When specifying multiple parameters, use a comma (,) to separate the
different parameters, for example: somevalue=1,someothervalue=2
- AudioFile (alias "audiofile")
machine= same syntax as the AUDIOFILE environment variable.
- AIX ("AIX") [AIX only]
buffer= logarithmic size of the buffer, in the range 12-19. Default
is 15.
- ALSA ("alsa") [Linux only]
card= card number. Default is first pcm-capable card. Replaces the
ALSA_CARD environment variable, which is now deprecated.
pcm= pcm interface number. Default is first adequate interface.
Replaces the ALSA_PCM environment variable, which is now
deprecated.
buffer= logarithmic fragment size, in the range 2-16. Default is 4.
Replaces the MM_NUMFRAGS environment variable, which is now
deprecated.
- DART ("dart") [OS/2 only]
buffer= logarithmic fragment size, in the range 12-16. Default is
computed to a bit more than 1/4" of playback.
count= fragment count, in the range 2-8. Default is 2.
device= waveaudio device number, in the range 0-8. Default is 0 (use
default waveaudio device).
- DirectX ("ds") [Win32 only]
buffer= logarithmic size of the buffer, in the range 12-19. Default
is 16.
globalfocus
always play music, even if the application has not the
focus. Required for full-screen applications.
- EsounD ("esd") [Unix only]
machine= same syntax as the ESPEAKER environment variable.
- HP ("hp") [HP-UX only]
buffer= logarithmic size of the buffer, in the range 12-19. Default
is 15.
headphone redirects the output to the headphone port.
- MacOS ("mac") [MacOS only]
buffer= logarithmic size of the buffer, in the range 10-16. Default
is 12.
- OS/2 MMPM ("os2") [OS/2 only]
buffer= logarithmic size of the buffer, in the range 12-16. Default
is computed to a bit more than 1/4" of playback.
device= waveaudio device number, in the range 0-8. Default is 0 (use
default waveaudio device).
- OSS ("oss") [Unix only]
card= card number. Default is the card whose driver was loaded
first.
buffer= logarithmic fragment size, in the range 7-17. Default is 14.
Replaces the MM_FRAGSIZE environment variable, which is now
deprecated.
count= fragment count, in the range 2-255. Default is 16.
Replaces the MM_NUMFRAGS environment variable, which is now
deprecated.
- Piped output ("pipe") [Unix only]
pipe= Pipe command (mandatory).
- SGI audio library ("sgi") [IRIX only]
fragsize= buffer size for libmikmod internal use.
Replaces the MM_SGI_FRAGSIZE environment variable, which is
now deprecated.
bufsize= buffer size for the audio library.
Replaces the MM_SGI_BUFSIZE environment variable, which is
now deprecated.
- Disk writers in raw and wav formats ("raw" and "wav")
file= Output file name. Default is music.raw for the raw driver
and music.wav for the wav driver.
- Sun/Solaris/NetBSD/OpenBSD audio ("audio")
[SunOS, Solaris, NetBSD, OpenBSD only]
buffer= logarithmic fragment size, in the range 7-17. Default is 12.
Replaces the MM_FRAGSIZE environment variable, which is now
deprecated.
headphone on SunOS/Solaris only, redirects the output to the headphone
port.
speaker on SunOS/Solaris only, redirects the output to the speaker.
- Linux sam9407-based soundcards ("sam9407") [Linux only]
card= card number. Default is first card.
- NoSound ("nosound"), Standard output ("stdout"), Ultrasound ("ultra"),
Windows Multimedia ("winmm")
These driver have no options.
>> ALSA DRIVER SPECIFIC INFORMATION (Linux specific)
-----------------------------------
The Advanced Linux Sound Architecture (ALSA) project aims to provide
better sound facilities than the current OSS drivers. Although it is
still in beta, it appears to be very stable and very easy to program
compared to the OSS.
Besides, it works much better than OSS for Gravis-type soundcards.
You can find more information on ALSA, including an HOWTO, on the web:
http://www.alsa-project.org
The Advanced Linux Sound Architecture (ALSA) is still in beta, but its
API is stable, so this libmikmod version should work with future
versions of ALSA.
This version of the libmikmod ALSA driver works with either ALSA
versions 0.3.x (for Linux kernels 2.0.x) and 0.4.x (for Linux kernels
2.2.x and later).
The latest versions, 0.5.x and 0.9.x, are currently not supported natively,
although you can use the OSS emulation without problems.
If the sound comes out jerky, you can pass the "buffer=xx" option to the
driver, to tweak the ALSA settings. The default value (if this option is
not used) is 4; the slower your machine is, the greater this value has
to be, but the allowed range is 2 to 16. However, the ALSA generally
finds good settings for your configuration, so I doubt you'll have to
use this option.
>> ENLIGHTENED SOUND DAEMON SPECIFIC INFORMATION (Unix specific)
------------------------------------------------
The Enlightened Sound Daemon (EsounD) is still experimental and may
change a lot until it reaches the 1.0 release. Thus, this libmikmod
version might not work with future versions of EsounD.
You can find more information on EsounD on the web:
http://www.tux.org/~ricdude/EsounD.html
However, this page is getting very out of date. Recent EsounD work can
be found on the GNOME project:
http://www.gnome.org/applist/view.php3?name=esound
which not kept up-to-date either...
The version of the libmikmod EsounD driver coincides with the latest
EsounD release available when this version of libmikmod was released;
for the 3.1.10 release, this is EsounD v0.2.23, but libmikmod should
work with any version starting from 0.2.6, although the latest version
is recommended.
Please note that between 0.2.8 and 0.2.12 the server port and the
protocol have changed, thus clients compiled with libesd from 0.2.8 can
not communicate with 0.2.12 (and later) esd, and vice versa.
If the esd daemon dies, libmikmod will try to reconnect every 5 seconds
and every new module, if a module ends. So, you can safely restart esd
and wait 5 seconds, and voila! Sound is back...
If you run esd and a libmikmod application on the same machine,
everything should work fine. However, if there is a real network
connection, synchronization problems can occur.
If sound clicks or gets chopped, then you've likely got a
synchronization problem. Pausing the player for a second should cause
the problem to disappear. If there's still problems, perhaps your
network is not fast enough. Lowering the playback rate will hopefully
solve the problem.
Also, the performance of the esd is really abominable if the esd
playback frequency can't be divided by the libmikmod playback rate. For
example, runinng a libmikmod application at 42000 Hz with esd at 44100
Hz will sound horrible, and take a lot of CPU time due to resampling.
>> SGI DRIVER SPECIFIC INFORMATION (IRIX specific)
----------------------------------
The SGI audio driver was written by Stephan Kanthak in 1996 and its
author grants to distribute it with the libmikmod package under the same
restrictions as the library.
If you encounter any problems concerning crackles or short stops while
playing, feel free to experiment with the values of the fragsize and
bufsize options of the driver. The default values are 20000 for fragsize
and 40000 for bufsize. Increasing bufsize might result in nonstop sound
on slow machines, but increases latency of interactive applications. The
value of fragsize should be set to about half of bufsize in most cases
and needs to be increased only if you own a very slow SGI.
Common problems
- libmikmod does not compile on my SGI?
First check out whether you have the SGI audio library (libaudio) or
not. If the audio library is missing you should upgrade to IRIX 5.3 or
newer and you will obtain the media development package automatically
with it. If you have the audio library installed, check out if it is
in the linker path.
Also, the audio API has been extended in recent IRIX releases (6.4 and
later). The older API used by libmikmod is supposed to be still supported,
please drop me a note if it is not on your IRIX release.
- Sound is _very_ noisy?
Change sample size to 16 bits.
- Sound crackles or stops temporarily?
Try to increase the value of the fragsize driver option (default value
is 20000). Switch to mono mode if necessary.
- libmikmod applications only react very slowly?
This is a typical effect on SGI machines because the audio library
sets up an internal buffer that seems to be quite large on many
installations. Try to decrease the bufsize driver option (default
value is 40000).
How to contact the driver author:
Stephan Kanthak <kanthak@i6.informatik.rwth-aachen.de>
Please cc: me (miod), just in case.
>> SUNOS, SOLARIS, NETBSD AND OPENBSD DRIVER SPECIFIC INFORMATION
-----------------------------------------------------------------
The above mentioned systems use the same interface to the audio device.
The libmikmod driver for this interface is the Sun driver. It was coded
by Valtteri Vuorikoski <vuori@sci.fi> and updated to libmikmod 3 by Tor
Norbye <tor@cs.stanford.edu>, and has been modified to work under NetBSD
and OpenBSD by the current maintainer.
This driver works with old sound hardware using 8 KHz mono ulaw, and
with modern hardware using pcm mono or stereo at any frequency. If your
settings aren't supported by the audio device, sound initialization will
fail. Refer to the audio(7) man page under SunOS/Solaris and the
audio(4) man page under NetBSD/OpenBSD for more details on your audio
hardware and its capabilities.
On Sun workstations, you might be interested in passing the "headphone"
option to the driver to force output on the headphones, since plugging
the headphones is not enough.
If you run NetBSD or OpenBSD, the driver does not support the headphone
and speaker parameters, but you can achieve the same effect with
audioctl(1), for example:
audioctl -w play.port=1
will select the speaker, while a value of 2 would have selected the
headphone.
If sound is jerky, you can pass the "buffer=xx" option to the driver to
increase its internal buffer size. The default value (when this option
is not used) is 12; the slower your machine, the greater this value has
to be, in the range 7-17.
If you can't get libmikmod to work with your hardware, you can use its
raw disk writer driver, in 8 bit mono 8 kHz, and send the music.raw file
to /dev/audio with sox, using the following command line:
sox -t raw -c 1 -r 8000 -u -b music.raw -t raw -U -r 8000 \
-c 1 -b /dev/audio
(or use the piped output driver with this command line)
Or if you played in 16 bit stereo, you can convert the file to a .au
file:
audioconvert -o music.au -f sun \
-i rate=44.1k,channels=stereo,encoding=linear16 music.raw
and play the file:
audioplay -p headphone -v 10 music.au
>> SAM9407 DRIVER SPECIFIC INFORMATION (Linux specific)
--------------------------------------
The SAM9407 driver provides an OSS-compatible driver for the soundcards
based on the sam9407 audio chip (MaxiSound 64 and Terratec EWS, among
others), and provides advanced features such as hardware module
playback.
You can find more information on this driver on the web:
http://www.anime.net/~sam9407
The version of the libmikmod sam9407 driver coincides with the latest sam9407
driver release available when this version of libmikmod was released; for the
3.1.10 release, this is sam9407 driver v1.0.0.
>> THANKS
---------
I would like to thank everyone who contributed to libmikmod. Their names
are in the AUTHORS file for the significative contributions, but some
other names can be found in the NEWS file. Thanks a lot! Keeping
libmikmod alive wouldn't be much fun without you.
>> LICENSE
----------
The libmikmod sound library is covered by the GNU Library General Public
License as published by the Free Software Fundation (you'll find it in
the file COPYING.LIB); either version 2 of the licence, or (at your
option) any later version.
The GNU Lesser General Public License, version 2.1, in file
COPYING.LESSER, can be considered as a later version of the LGPL, and is
strongly recommended for people who will embed libmikmod in their
application as a shared library.
Parts of the library (in playercode/mdulaw.c) are derived from the files
libst.h and raw.c from an old version of the sox (SOund eXchange)
package written by Lance Norskog and Jef Poskanzer. The following
copyright notice applies to these parts:
Copyright (C) 1989 by Jef Poskanzer.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. This software is provided "as is" without express or
implied warranty.
>> CONTACT AND DOWNLOAD INFO
----------------------------
* email:
Please send all your libmikmod related e-mail to me, at:
mikmod@raphnet.net
* web:
libmikmod home page is located at:
http://mikmod.raphnet.net

45
project/jni/mikmod/TODO Normal file
View File

@@ -0,0 +1,45 @@
TODO list for future versions (or ROADMAP if you prefer)
=============================
**** for the next major release, libmikmod 3.2:
- bugfixes
- ability to have several modules in memory (it doesn't work in all cases in
the current version)
- integration of the LINA (LINA Is Not A3D) companion library written by
David Banz.
- total module length computation
- ability to seek in modules in smaller chunks than patterns
**** during 3.2.x maintenance releases:
- a NAS (Network Audio System) driver
- DMF and PSM loaders
- loading of stereo and ADPCM wave files
**** hopefully in 3.x.x releases:
- bugfixes
- use of glib or Pth for better thread support (i.e. more portability)
- LIQ loader (see with Claudio Matsuoka)
- MED improvements (at least I hope so)
- software mixer improvements
- an OSS sequencer driver
- an ALSA sequencer driver
**** Will hopefully occur in 4.x
- bugfixes
- a TFMX loader (see with Claudio, too)
**** Plans for the 4.x series and later:
- bugfixes
- a well-defined module loader interface, allowing both libmikmod and xmp to
share the same loader code (in cooperation with Claudio, of course)
- extending the feature list, at the request of the users: midi support ?
mp3 support ? cdda support ? suggestions welcome.
Want something else ? Drop me a note at <miod@mikmod.org> and I'll
see what I can do for you...

159
project/jni/mikmod/config.h Normal file
View File

@@ -0,0 +1,159 @@
/* config.h. Generated automatically by configure. */
/* config.h.in. Generated automatically from configure.in by autoheader 2.13. */
/* Define if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* #undef _ALL_SOURCE */
#endif
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
#define HAVE_SYS_WAIT_H 1
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef pid_t */
/* Define to `unsigned' if <sys/types.h> doesn't define. */
/* #undef size_t */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS
/* Define if your system supports binary pipes (i.e. Unix) */
#define DRV_PIPE 1
/* Define if you want a .aiff file writer driver */
#define DRV_AIFF 1
/* Define if the AudioFile driver is compiled */
/* #undef DRV_AF */
/* Define if the AIX audio driver is compiled */
/* #undef DRV_AIX */
/* Define if the Linux ALSA driver is compiled */
/* #undef DRV_ALSA */
/* Define if the Enlightened Sound Daemon driver is compiled */
/* #undef DRV_ESD */
/* Define if the HP-UX audio driver is compiled */
/* #undef DRV_HP */
/* Define if the Open Sound System driver is compiled */
/* #undef DRV_OSS */
/* Define if the Linux SAM9407 driver is compiled */
/* #undef DRV_SAM9407 */
/* Define if the SGI audio driver is compiled */
/* #undef DRV_SGI */
/* Define if the Sun audio driver or compatible (NetBSD, OpenBSD)
is compiled */
/* #undef DRV_SUN */
/* Define if the Linux Ultra driver is compiled */
/* #undef DRV_ULTRA */
/* Define this if you want the MacOS X CoreAudio driver */
/* #undef DRV_OSX */
/* Define this if you want the Carbon Mac Audio driver */
/* #undef DRV_MAC */
/* Define if you want a debug version of the library */
/* #undef MIKMOD_DEBUG */
/* Define if you want runtime dynamic linking of ALSA and EsounD drivers */
/* #undef MIKMOD_DYNAMIC */
/* Define if your system provides POSIX.4 threads */
#define HAVE_PTHREAD 1
/* Define if your system is SunOS 4.* */
/* #undef SUNOS */
/* Define if your system is AIX 3.* - might be needed for 4.* too */
/* #undef AIX */
/* Define if your system defines random(3) and srandom(3) in math.h instead
of stdlib.h */
/* #undef SRANDOM_IN_MATH_H */
/* Define if EsounD driver depends on ALSA */
/* #undef MIKMOD_DYNAMIC_ESD_NEEDS_ALSA */
/* Define if your system has RTLD_GLOBAL defined in <dlfcn.h> */
/* #undef HAVE_RTLD_GLOBAL */
/* Define if your system needs leading underscore to function names in dlsym() calls */
/* #undef DLSYM_NEEDS_UNDERSCORE */
/* Define if you have the setenv function. */
#define HAVE_SETENV 1
/* Define if you have the snprintf function. */
#define HAVE_SNPRINTF 1
/* Define if you have the srandom function. */
/* #undef HAVE_SRANDOM */
/* Define if you have the strcasecmp function. */
#define HAVE_STRCASECMP 1
/* Define if you have the strdup function. */
#define HAVE_STRDUP 1
/* Define if you have the strstr function. */
#define HAVE_STRSTR 1
/* Define if you have the <AF/AFlib.h> header file. */
/* #undef HAVE_AF_AFLIB_H */
/* Define if you have the <dl.h> header file. */
/* #undef HAVE_DL_H */
/* Define if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
/* Define if you have the <dmedia/audio.h> header file. */
/* #undef HAVE_DMEDIA_AUDIO_H */
/* Define if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the <libgus.h> header file. */
/* #undef HAVE_LIBGUS_H */
/* Define if you have the <machine/soundcard.h> header file. */
/* #undef HAVE_MACHINE_SOUNDCARD_H */
/* Define if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1
/* Define if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define if you have the <sun/audioio.h> header file. */
/* #undef HAVE_SUN_AUDIOIO_H */
/* Define if you have the <sys/acpa.h> header file. */
/* #undef HAVE_SYS_ACPA_H */
/* Define if you have the <sys/asoundlib.h> header file. */
/* #undef HAVE_SYS_ASOUNDLIB_H */
/* Define if you have the <sys/audio.h> header file. */
/* #undef HAVE_SYS_AUDIO_H */
/* Define if you have the <sys/audioio.h> header file. */
/* #undef HAVE_SYS_AUDIOIO_H */
/* Define if you have the <sys/ioctl.h> header file. */
/* #undef HAVE_SYS_IOCTL_H */
/* Define if you have the <sys/sam9407.h> header file. */
/* #undef HAVE_SYS_SAM9407_H */
/* Define if you have the <sys/soundcard.h> header file. */
/* #undef HAVE_SYS_SOUNDCARD_H */
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Name of package */
#define PACKAGE "libmikmod"
/* Version number of package */
#define VERSION "3.2.0b2"

View File

@@ -0,0 +1,379 @@
/* MikMod sound library
(c) 2004, Raphael Assenat
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: drv_aiff.c,v 1.4 2004/02/20 22:08:33 raph Exp $
Driver for output to a file called MUSIC.AIFF [or .AIF on Windows].
==============================================================================*/
/*
Written by Axel "awe" Wefers <awe@fruitz-of-dojo.de>
Raphael Assenat: 19 Feb 2004: Command line options documented in the MDRIVER structure,
and I added #if 0 's around pragmas, since gcc complaines about them.
Hopefully, the IDE which uses them wont care about that?
*/
/*_______________________________________________________________________________________________iNCLUDES
*/
#if 0
#pragma mark INCLUDES
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
#ifdef DRV_AIFF
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <math.h> /* required for IEEE extended conversion */
#if 0
#pragma mark -
#endif
/*________________________________________________________________________________________________dEFINES
*/
#if 0
#pragma mark DEFINES
#endif
#define AIFF_BUFFERSIZE 32768
#if defined(WIN32) || defined(DJGPP)
#define AIFF_FILENAME "music.aif"
#else
#define AIFF_FILENAME "music.aiff"
#endif /* WIN32 */
#if 0
#pragma mark -
#endif
/*_________________________________________________________________________________________________mACROS
*/
#if 0
#pragma mark MACROS
#endif
#define AIFF_FLOAT_TO_UNSIGNED(f) ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L + 1))
#if 0
#pragma mark -
#endif
/*___________________________________________________________________________________________________vARS
*/
#if 0
#pragma mark VARIABLES
#endif
static MWRITER *gAiffOut = NULL;
static FILE *gAiffFile = NULL;
static SBYTE *gAiffAudioBuffer = NULL;
static CHAR *gAiffFileName = NULL;
static ULONG gAiffDumpSize = 0;
#if 0
#pragma mark -
#endif
/*____________________________________________________________________________________fUNCTION_pROTOTYPES
*/
#if 0
#pragma mark FUNCTION PROTOTYPES
#endif
#ifdef SUNOS
extern int fclose(FILE *);
#endif
static void AIFF_ConvertToIeeeExtended (double theValue, char *theBytes);
static void AIFF_PutHeader (void);
static void AIFF_CommandLine (CHAR *theCmdLine);
static BOOL AIFF_IsThere (void);
static BOOL AIFF_Init (void);
static void AIFF_Exit (void);
static void AIFF_Update (void);
#if 0
#pragma mark -
#endif
/*___________________________________________________________________________AIFF_ConvertToIeeeExtended()
*/
void AIFF_ConvertToIeeeExtended (double theValue, char *theBytes)
{
int mySign;
int myExponent;
double myFMant, myFsMant;
unsigned long myHiMant, myLoMant;
if (theValue < 0)
{
mySign = 0x8000;
theValue *= -1;
} else
{
mySign = 0;
}
if (theValue == 0)
{
myExponent = 0;
myHiMant = 0;
myLoMant = 0;
}
else
{
myFMant = frexp (theValue, &myExponent);
if ((myExponent > 16384) || !(myFMant < 1))
{
myExponent = mySign | 0x7FFF;
myHiMant = 0;
myLoMant = 0;
}
else
{
myExponent += 16382;
if (myExponent < 0)
{
myFMant = ldexp (myFMant, myExponent);
myExponent = 0;
}
myExponent |= mySign;
myFMant = ldexp (myFMant, 32);
myFsMant = floor (myFMant);
myHiMant = AIFF_FLOAT_TO_UNSIGNED (myFsMant);
myFMant = ldexp (myFMant - myFsMant, 32);
myFsMant = floor (myFMant);
myLoMant = AIFF_FLOAT_TO_UNSIGNED (myFsMant);
}
}
theBytes[0] = myExponent >> 8;
theBytes[1] = myExponent;
theBytes[2] = myHiMant >> 24;
theBytes[3] = myHiMant >> 16;
theBytes[4] = myHiMant >> 8;
theBytes[5] = myHiMant;
theBytes[6] = myLoMant >> 24;
theBytes[7] = myLoMant >> 16;
theBytes[8] = myLoMant >> 8;
theBytes[9] = myLoMant;
}
/*_______________________________________________________________________________________AIFF_PutHeader()
*/
static void AIFF_PutHeader(void)
{
ULONG myFrames;
UBYTE myIEEE[10];
myFrames = gAiffDumpSize / (((md_mode&DMODE_STEREO) ? 2 : 1) * ((md_mode & DMODE_16BITS) ? 2 : 1));
AIFF_ConvertToIeeeExtended ((double) md_mixfreq, myIEEE);
_mm_fseek (gAiffOut, 0, SEEK_SET);
_mm_write_string ("FORM", gAiffOut); /* chunk 'FORM' */
_mm_write_M_ULONG (gAiffDumpSize + 36, gAiffOut); /* length of the file */
_mm_write_string ("AIFFCOMM", gAiffOut); /* chunk 'AIFF', 'COMM' */
_mm_write_M_ULONG (18, gAiffOut); /* length of this AIFF block */
_mm_write_M_UWORD ((md_mode & DMODE_STEREO) ? 2 : 1, gAiffOut); /* channels */
_mm_write_M_ULONG (myFrames, gAiffOut); /* frames = freq * secs */
_mm_write_M_UWORD ((md_mode & DMODE_16BITS) ? 16 : 8, gAiffOut); /* bits per sample */
_mm_write_UBYTES (myIEEE, 10, gAiffOut); /* frequency [IEEE extended] */
_mm_write_string ("SSND", gAiffOut); /* data chunk 'SSND' */
_mm_write_M_ULONG (gAiffDumpSize, gAiffOut); /* data length */
_mm_write_M_ULONG (0, gAiffOut); /* data offset, always zero */
_mm_write_M_ULONG (0, gAiffOut); /* data blocksize, always zero */
}
/*_____________________________________________________________________________________AIFF_CommandLine()
*/
static void AIFF_CommandLine (CHAR *theCmdLine)
{
CHAR *myFileName = MD_GetAtom ("file", theCmdLine,0);
if (myFileName != NULL)
{
_mm_free (gAiffFileName);
gAiffFileName = myFileName;
}
}
/*_________________________________________________________________________________________AIFF_isThere()
*/
static BOOL AIFF_IsThere (void)
{
return (1);
}
/*____________________________________________________________________________________________AIFF_Init()
*/
static BOOL AIFF_Init (void)
{
#if defined unix || (defined __APPLE__ && defined __MACH__)
if (!MD_Access (gAiffFileName ? gAiffFileName : AIFF_FILENAME))
{
_mm_errno=MMERR_OPENING_FILE;
return (1);
}
#endif
if (!(gAiffFile = fopen (gAiffFileName ? gAiffFileName : AIFF_FILENAME, "wb")))
{
_mm_errno = MMERR_OPENING_FILE;
return (1);
}
if (!(gAiffOut =_mm_new_file_writer (gAiffFile)))
{
fclose (gAiffFile);
unlink(gAiffFileName ? gAiffFileName : AIFF_FILENAME);
gAiffFile = NULL;
return (1);
}
if (!(gAiffAudioBuffer = (SBYTE*) _mm_malloc (AIFF_BUFFERSIZE)))
{
_mm_delete_file_writer (gAiffOut);
fclose (gAiffFile);
unlink (gAiffFileName ? gAiffFileName : AIFF_FILENAME);
gAiffFile = NULL;
gAiffOut = NULL;
return 1;
}
md_mode|=DMODE_SOFT_MUSIC|DMODE_SOFT_SNDFX;
if (VC_Init ())
{
_mm_delete_file_writer (gAiffOut);
fclose (gAiffFile);
unlink (gAiffFileName ? gAiffFileName : AIFF_FILENAME);
gAiffFile = NULL;
gAiffOut = NULL;
return 1;
}
gAiffDumpSize = 0;
AIFF_PutHeader ();
return (0);
}
/*____________________________________________________________________________________________AIFF_Exit()
*/
static void AIFF_Exit (void)
{
VC_Exit ();
/* write in the actual sizes now */
if (gAiffOut != NULL)
{
AIFF_PutHeader ();
_mm_delete_file_writer (gAiffOut);
fclose (gAiffFile);
gAiffFile = NULL;
gAiffOut = NULL;
}
if (gAiffAudioBuffer != NULL)
{
free (gAiffAudioBuffer);
gAiffAudioBuffer = NULL;
}
}
/*__________________________________________________________________________________________AIFF_Update()
*/
static void AIFF_Update (void)
{
ULONG myByteCount;
myByteCount = VC_WriteBytes (gAiffAudioBuffer, AIFF_BUFFERSIZE);
if (md_mode & DMODE_16BITS)
{
_mm_write_M_UWORDS ((UWORD *) gAiffAudioBuffer, myByteCount >> 1, gAiffOut);
}
else
{
ULONG i;
for (i = 0; i < myByteCount; i++)
{
gAiffAudioBuffer[i] -= 0x80; /* convert to signed PCM */
}
_mm_write_UBYTES (gAiffAudioBuffer, myByteCount, gAiffOut);
}
gAiffDumpSize += myByteCount;
}
/*________________________________________________________________________________________________drv_osx
*/
MIKMODAPI MDRIVER drv_aiff = {
NULL,
"Disk writer (aiff)",
"AIFF disk writer (music.aiff) v1.1",
0,255,
"aif",
"file:t:music.aiff:Output file name\n",
AIFF_CommandLine,
AIFF_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
AIFF_Init,
AIFF_Exit,
NULL,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
AIFF_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
#else
MISSING(drv_aiff);
#endif
/*____________________________________________________________________________________________________eOF
*/

View File

@@ -0,0 +1,107 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: drv_nos.c,v 1.3 2004/01/31 22:39:40 raph Exp $
Driver for no output
==============================================================================*/
/*
Written by Jean-Paul Mikkers <mikmak@via.nl>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "mikmod_internals.h"
#define ZEROLEN 32768
static SBYTE *zerobuf=NULL;
static BOOL NS_IsThere(void)
{
return 1;
}
static BOOL NS_Init(void)
{
zerobuf=(SBYTE*)_mm_malloc(ZEROLEN);
return VC_Init();
}
static void NS_Exit(void)
{
VC_Exit();
_mm_free(zerobuf);
}
static void NS_Update(void)
{
if (zerobuf)
VC_WriteBytes(zerobuf,ZEROLEN);
}
MIKMODAPI MDRIVER drv_nos={
NULL,
"No Sound",
"Nosound Driver v3.0",
255,255,
"nosound",
NULL,
NULL,
NS_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
NS_Init,
NS_Exit,
NULL,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
NS_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,220 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: drv_pipe.c,v 1.3 2004/01/31 22:39:40 raph Exp $
Driver for output via a pipe to another command
==============================================================================*/
/*
Written by Simon Hosie <gumboot@clear.net.nz>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
#ifdef DRV_PIPE
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#if defined unix || (defined __APPLE__ && defined __MACH__)
#include <errno.h>
#include <sys/wait.h>
#endif
#ifdef SUNOS
extern int fclose(FILE *);
#endif
#define BUFFERSIZE 32768
static MWRITER *pipeout=NULL;
static FILE *pipefile=NULL;
#if defined unix || (defined __APPLE__ && defined __MACH__)
static int pipefd[2]={-1,-1};
static pid_t pid;
#endif
static SBYTE *audiobuffer=NULL;
static CHAR *target=NULL;
static void pipe_CommandLine(CHAR *cmdline)
{
CHAR *ptr=MD_GetAtom("pipe",cmdline,0);
if(ptr) {
_mm_free(target);
target=ptr;
}
}
static BOOL pipe_IsThere(void)
{
return 1;
}
static BOOL pipe_Init(void)
{
if(!target) {
_mm_errno=MMERR_OPENING_FILE;
return 1;
}
#if !defined unix && (!defined __APPLE__ || !defined __MACH__)
#ifdef __EMX__
_fsetmode(stdout, "b");
#endif
#ifdef __WATCOMC__
pipefile = _popen(target, "wb");
#else
pipefile = popen(target, "wb");
#endif
if (!pipefile) {
_mm_errno=MMERR_OPENING_FILE;
return 1;
}
#else
/* poor man's popen() */
if (pipe(pipefd)) {
_mm_errno = MMERR_OPENING_FILE;
return 1;
}
switch (pid=fork()) {
case -1:
close(pipefd[0]);
close(pipefd[1]);
pipefd[0]=pipefd[1]=-1;
_mm_errno=MMERR_OPENING_FILE;
return 1;
case 0:
if (pipefd[0]) {
dup2(pipefd[0],0);
close(pipefd[0]);
}
close(pipefd[1]);
if (!MD_DropPrivileges())
execl("/bin/sh","sh","-c",target,NULL);
exit(127);
}
close(pipefd[0]);
if (!(pipefile=fdopen(pipefd[1],"wb"))) {
_mm_errno=MMERR_OPENING_FILE;
return 1;
}
#endif
if(!(pipeout=_mm_new_file_writer(pipefile)))
return 1;
if(!(audiobuffer=(SBYTE*)_mm_malloc(BUFFERSIZE)))
return 1;
md_mode|=DMODE_SOFT_MUSIC|DMODE_SOFT_SNDFX;
return VC_Init();
}
static void pipe_Exit(void)
{
#if defined unix || (defined __APPLE__ && defined __MACH__)
int pstat;
pid_t pid2;
#endif
VC_Exit();
_mm_free(audiobuffer);
if(pipeout) {
_mm_delete_file_writer(pipeout);
pipeout=NULL;
}
if(pipefile) {
#if !defined unix && (!defined __APPLE__ || !defined __MACH__)
#ifdef __WATCOMC__
_pclose(pipefile);
#else
pclose(pipefile);
#endif
#ifdef __EMX__
_fsetmode(stdout,"t");
#endif
#else
fclose(pipefile);
do {
pid2=waitpid(pid,&pstat,0);
} while (pid2==-1 && errno==EINTR);
#endif
pipefile=NULL;
}
}
static void pipe_Update(void)
{
_mm_write_UBYTES(audiobuffer,VC_WriteBytes(audiobuffer,BUFFERSIZE),pipeout);
}
MIKMODAPI MDRIVER drv_pipe={
NULL,
"Piped writer",
"Piped Output driver v0.2",
0,255,
"pipe",
"pipe:t::Pipe command\n",
pipe_CommandLine,
pipe_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
pipe_Init,
pipe_Exit,
NULL,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
pipe_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
#else
MISSING(drv_pipe);
#endif
/* ex:set ts=4: */

View File

@@ -0,0 +1,121 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: drv_stdout.c,v 1.3 2004/01/31 22:39:40 raph Exp $
Output data to stdout
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include "mikmod_internals.h"
#define BUFFERSIZE 32768
static SBYTE *audiobuffer=NULL;
static BOOL stdout_IsThere(void)
{
/* only allow this driver on pipes */
return 1-isatty(1);
}
static BOOL stdout_Init(void)
{
if(!(audiobuffer=(SBYTE*)_mm_malloc(BUFFERSIZE))) return 1;
#ifdef __EMX__
_fsetmode(stdout,"b");
#endif
return VC_Init();
}
static void stdout_Exit(void)
{
VC_Exit();
#ifdef __EMX__
_fsetmode(stdout,"t");
#endif
if (audiobuffer) {
free(audiobuffer);
audiobuffer=NULL;
}
}
static void stdout_Update(void)
{
#ifdef WIN32
_write
#else
write
#endif
(1,audiobuffer,VC_WriteBytes((SBYTE*)audiobuffer,BUFFERSIZE));
}
static BOOL stdout_Reset(void)
{
VC_Exit();
return VC_Init();
}
MIKMODAPI MDRIVER drv_stdout={
NULL,
"stdout",
"Standard output driver v1.1",
0,255,
"stdout",
NULL,
NULL,
stdout_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
stdout_Init,
stdout_Exit,
stdout_Reset,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
stdout_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,189 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: drv_wav.c,v 1.3 2004/01/31 22:39:40 raph Exp $
Driver for output to a file called MUSIC.WAV
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef SUNOS
extern int fclose(FILE *);
#endif
#define BUFFERSIZE 32768
#define FILENAME "music.wav"
static MWRITER *wavout=NULL;
static FILE *wavfile=NULL;
static SBYTE *audiobuffer=NULL;
static ULONG dumpsize;
static CHAR *filename=NULL;
static void putheader(void)
{
_mm_fseek(wavout,0,SEEK_SET);
_mm_write_string("RIFF",wavout);
_mm_write_I_ULONG(dumpsize+44,wavout);
_mm_write_string("WAVEfmt ",wavout);
_mm_write_I_ULONG(16,wavout); /* length of this RIFF block crap */
_mm_write_I_UWORD(1, wavout); /* microsoft format type */
_mm_write_I_UWORD((md_mode&DMODE_STEREO)?2:1,wavout);
_mm_write_I_ULONG(md_mixfreq,wavout);
_mm_write_I_ULONG(md_mixfreq*((md_mode&DMODE_STEREO)?2:1)*
((md_mode&DMODE_16BITS)?2:1),wavout);
/* block alignment (8/16 bit) */
_mm_write_I_UWORD(((md_mode&DMODE_16BITS)?2:1)*
((md_mode&DMODE_STEREO)?2:1),wavout);
_mm_write_I_UWORD((md_mode&DMODE_16BITS)?16:8,wavout);
_mm_write_string("data",wavout);
_mm_write_I_ULONG(dumpsize,wavout);
}
static void WAV_CommandLine(CHAR *cmdline)
{
CHAR *ptr=MD_GetAtom("file",cmdline,0);
if(ptr) {
_mm_free(filename);
filename=ptr;
}
}
static BOOL WAV_IsThere(void)
{
return 1;
}
static BOOL WAV_Init(void)
{
#if defined unix || (defined __APPLE__ && defined __MACH__)
if (!MD_Access(filename?filename:FILENAME)) {
_mm_errno=MMERR_OPENING_FILE;
return 1;
}
#endif
if(!(wavfile=fopen(filename?filename:FILENAME,"wb"))) {
_mm_errno=MMERR_OPENING_FILE;
return 1;
}
if(!(wavout=_mm_new_file_writer (wavfile))) {
fclose(wavfile);unlink(filename?filename:FILENAME);
wavfile=NULL;
return 1;
}
if(!(audiobuffer=(SBYTE*)_mm_malloc(BUFFERSIZE))) {
_mm_delete_file_writer(wavout);
fclose(wavfile);unlink(filename?filename:FILENAME);
wavfile=NULL;wavout=NULL;
return 1;
}
md_mode|=DMODE_SOFT_MUSIC|DMODE_SOFT_SNDFX;
if (VC_Init()) {
_mm_delete_file_writer(wavout);
fclose(wavfile);unlink(filename?filename:FILENAME);
wavfile=NULL;wavout=NULL;
return 1;
}
dumpsize=0;
putheader();
return 0;
}
static void WAV_Exit(void)
{
VC_Exit();
/* write in the actual sizes now */
if(wavout) {
putheader();
_mm_delete_file_writer(wavout);
fclose(wavfile);
wavfile=NULL;wavout=NULL;
}
if(audiobuffer) {
free(audiobuffer);
audiobuffer=NULL;
}
}
static void WAV_Update(void)
{
ULONG done;
done=VC_WriteBytes(audiobuffer,BUFFERSIZE);
_mm_write_UBYTES(audiobuffer,done,wavout);
dumpsize+=done;
}
MIKMODAPI MDRIVER drv_wav={
NULL,
"Disk writer (wav)",
"Wav disk writer (music.wav) v1.2",
0,255,
"wav",
"file:t:music.wav:Output file name\n",
WAV_CommandLine,
WAV_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
WAV_Init,
WAV_Exit,
NULL,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
WAV_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,747 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mikmod.h.in,v 1.11 2004/02/18 14:10:39 raph Exp $
MikMod sound library include file
==============================================================================*/
#ifndef _MIKMOD_H_
#define _MIKMOD_H_
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* ========== Compiler magic for shared libraries
*/
#if defined WIN32 && defined _DLL
#ifdef DLL_EXPORTS
#define MIKMODAPI __declspec(dllexport)
#else
#define MIKMODAPI __declspec(dllimport)
#endif
#else
#define MIKMODAPI
#endif
/*
* ========== Library version
*/
#define LIBMIKMOD_VERSION_MAJOR 3L
#define LIBMIKMOD_VERSION_MINOR 2L
#define LIBMIKMOD_REVISION 0L
#define LIBMIKMOD_VERSION \
((LIBMIKMOD_VERSION_MAJOR<<16)| \
(LIBMIKMOD_VERSION_MINOR<< 8)| \
(LIBMIKMOD_REVISION))
MIKMODAPI extern long MikMod_GetVersion(void);
/*
* ========== Platform independent-type definitions
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <mmsystem.h>
#endif
#if defined(__OS2__)||defined(__EMX__)
#define INCL_DOSSEMAPHORES
#include <os2.h>
#else
typedef char CHAR;
#endif
#if defined(__arch64__) || defined(__alpha)
/* 64 bit architectures */
typedef signed char SBYTE; /* 1 byte, signed */
typedef unsigned char UBYTE; /* 1 byte, unsigned */
typedef signed short SWORD; /* 2 bytes, signed */
typedef unsigned short UWORD; /* 2 bytes, unsigned */
typedef signed int SLONG; /* 4 bytes, signed */
typedef unsigned int ULONG; /* 4 bytes, unsigned */
typedef int BOOL; /* 0=false, <>0 true */
#else
/* 32 bit architectures */
typedef signed char SBYTE; /* 1 byte, signed */
typedef unsigned char UBYTE; /* 1 byte, unsigned */
typedef signed short SWORD; /* 2 bytes, signed */
typedef unsigned short UWORD; /* 2 bytes, unsigned */
typedef signed long SLONG; /* 4 bytes, signed */
#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32)
typedef unsigned long ULONG; /* 4 bytes, unsigned */
typedef int BOOL; /* 0=false, <>0 true */
#endif
#endif
/*
* ========== Error codes
*/
enum {
MMERR_OPENING_FILE = 1,
MMERR_OUT_OF_MEMORY,
MMERR_DYNAMIC_LINKING,
MMERR_SAMPLE_TOO_BIG,
MMERR_OUT_OF_HANDLES,
MMERR_UNKNOWN_WAVE_TYPE,
MMERR_LOADING_PATTERN,
MMERR_LOADING_TRACK,
MMERR_LOADING_HEADER,
MMERR_LOADING_SAMPLEINFO,
MMERR_NOT_A_MODULE,
MMERR_NOT_A_STREAM,
MMERR_MED_SYNTHSAMPLES,
MMERR_ITPACK_INVALID_DATA,
MMERR_DETECTING_DEVICE,
MMERR_INVALID_DEVICE,
MMERR_INITIALIZING_MIXER,
MMERR_OPENING_AUDIO,
MMERR_8BIT_ONLY,
MMERR_16BIT_ONLY,
MMERR_STEREO_ONLY,
MMERR_ULAW,
MMERR_NON_BLOCK,
MMERR_AF_AUDIO_PORT,
MMERR_AIX_CONFIG_INIT,
MMERR_AIX_CONFIG_CONTROL,
MMERR_AIX_CONFIG_START,
MMERR_GUS_SETTINGS,
MMERR_GUS_RESET,
MMERR_GUS_TIMER,
MMERR_HP_SETSAMPLESIZE,
MMERR_HP_SETSPEED,
MMERR_HP_CHANNELS,
MMERR_HP_AUDIO_OUTPUT,
MMERR_HP_AUDIO_DESC,
MMERR_HP_BUFFERSIZE,
MMERR_OSS_SETFRAGMENT,
MMERR_OSS_SETSAMPLESIZE,
MMERR_OSS_SETSTEREO,
MMERR_OSS_SETSPEED,
MMERR_SGI_SPEED,
MMERR_SGI_16BIT,
MMERR_SGI_8BIT,
MMERR_SGI_STEREO,
MMERR_SGI_MONO,
MMERR_SUN_INIT,
MMERR_OS2_MIXSETUP,
MMERR_OS2_SEMAPHORE,
MMERR_OS2_TIMER,
MMERR_OS2_THREAD,
MMERR_DS_PRIORITY,
MMERR_DS_BUFFER,
MMERR_DS_FORMAT,
MMERR_DS_NOTIFY,
MMERR_DS_EVENT,
MMERR_DS_THREAD,
MMERR_DS_UPDATE,
MMERR_WINMM_HANDLE,
MMERR_WINMM_ALLOCATED,
MMERR_WINMM_DEVICEID,
MMERR_WINMM_FORMAT,
MMERR_WINMM_UNKNOWN,
MMERR_MAC_SPEED,
MMERR_MAC_START,
MMERR_OSX_UNKNOWN_DEVICE,
MMERR_OSX_BAD_PROPERTY,
MMERR_OSX_UNSUPPORTED_FORMAT,
MMERR_OSX_SET_STEREO,
MMERR_OSX_BUFFER_ALLOC,
MMERR_OSX_ADD_IO_PROC,
MMERR_OSX_DEVICE_START,
MMERR_OSX_PTHREAD,
MMERR_DOSWSS_STARTDMA,
MMERR_DOSSB_STARTDMA,
MMERR_MAX
};
/*
* ========== Error handling
*/
typedef void (MikMod_handler)(void);
typedef MikMod_handler *MikMod_handler_t;
MIKMODAPI extern int MikMod_errno;
MIKMODAPI extern BOOL MikMod_critical;
MIKMODAPI extern char *MikMod_strerror(int);
MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t);
/*
* ========== Library initialization and core functions
*/
struct MDRIVER;
MIKMODAPI extern void MikMod_RegisterAllDrivers(void);
MIKMODAPI extern CHAR* MikMod_InfoDriver(void);
MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*);
MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*);
MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int);
MIKMODAPI extern BOOL MikMod_Init(CHAR*);
MIKMODAPI extern void MikMod_Exit(void);
MIKMODAPI extern BOOL MikMod_Reset(CHAR*);
MIKMODAPI extern BOOL MikMod_SetNumVoices(int,int);
MIKMODAPI extern BOOL MikMod_Active(void);
MIKMODAPI extern BOOL MikMod_EnableOutput(void);
MIKMODAPI extern void MikMod_DisableOutput(void);
MIKMODAPI extern void MikMod_Update(void);
MIKMODAPI extern BOOL MikMod_InitThreads(void);
MIKMODAPI extern void MikMod_Lock(void);
MIKMODAPI extern void MikMod_Unlock(void);
/*
* ========== Reader, Writer
*/
typedef struct MREADER {
BOOL (*Seek)(struct MREADER*,long,int);
long (*Tell)(struct MREADER*);
BOOL (*Read)(struct MREADER*,void*,size_t);
int (*Get)(struct MREADER*);
BOOL (*Eof)(struct MREADER*);
} MREADER;
typedef struct MWRITER {
BOOL (*Seek)(struct MWRITER*,long,int);
long (*Tell)(struct MWRITER*);
BOOL (*Write)(struct MWRITER*,void*,size_t);
BOOL (*Put)(struct MWRITER*,int);
} MWRITER;
/*
* ========== Samples
*/
/* Sample playback should not be interrupted */
#define SFX_CRITICAL 1
/* Sample format [loading and in-memory] flags: */
#define SF_16BITS 0x0001
#define SF_STEREO 0x0002
#define SF_SIGNED 0x0004
#define SF_BIG_ENDIAN 0x0008
#define SF_DELTA 0x0010
#define SF_ITPACKED 0x0020
#define SF_FORMATMASK 0x003F
/* General Playback flags */
#define SF_LOOP 0x0100
#define SF_BIDI 0x0200
#define SF_REVERSE 0x0400
#define SF_SUSTAIN 0x0800
#define SF_PLAYBACKMASK 0x0C00
/* Module-only Playback Flags */
#define SF_OWNPAN 0x1000
#define SF_UST_LOOP 0x2000
#define SF_EXTRAPLAYBACKMASK 0x3000
/* Panning constants */
#define PAN_LEFT 0
#define PAN_HALFLEFT 64
#define PAN_CENTER 128
#define PAN_HALFRIGHT 192
#define PAN_RIGHT 255
#define PAN_SURROUND 512 /* panning value for Dolby Surround */
typedef struct SAMPLE {
SWORD panning; /* panning (0-255 or PAN_SURROUND) */
ULONG speed; /* Base playing speed/frequency of note */
UBYTE volume; /* volume 0-64 */
UWORD inflags; /* sample format on disk */
UWORD flags; /* sample format in memory */
ULONG length; /* length of sample (in samples!) */
ULONG loopstart; /* repeat position (relative to start, in samples) */
ULONG loopend; /* repeat end */
ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */
ULONG susend; /* sustain loop end / Yet! */
/* Variables used by the module player only! (ignored for sound effects) */
UBYTE globvol; /* global volume */
UBYTE vibflags; /* autovibrato flag stuffs */
UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */
UBYTE vibsweep;
UBYTE vibdepth;
UBYTE vibrate;
CHAR* samplename; /* name of the sample */
/* Values used internally only */
UWORD avibpos; /* autovibrato pos [player use] */
UBYTE divfactor; /* for sample scaling, maintains proper period slides */
ULONG seekpos; /* seek position in file */
SWORD handle; /* sample handle used by individual drivers */
} SAMPLE;
/* Sample functions */
MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);
MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*);
MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
MIKMODAPI extern void Sample_Free(SAMPLE*);
MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE);
MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD);
MIKMODAPI extern UWORD Voice_GetVolume(SBYTE);
MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG);
MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE);
MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG);
MIKMODAPI extern ULONG Voice_GetPanning(SBYTE);
MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG);
MIKMODAPI extern void Voice_Stop(SBYTE);
MIKMODAPI extern BOOL Voice_Stopped(SBYTE);
MIKMODAPI extern SLONG Voice_GetPosition(SBYTE);
MIKMODAPI extern ULONG Voice_RealVolume(SBYTE);
/*
* ========== Internal module representation (UniMod)
*/
/*
Instrument definition - for information only, the only field which may be
of use in user programs is the name field
*/
/* Instrument note count */
#define INSTNOTES 120
/* Envelope point */
typedef struct ENVPT {
SWORD pos;
SWORD val;
} ENVPT;
/* Envelope point count */
#define ENVPOINTS 32
/* Instrument structure */
typedef struct INSTRUMENT {
CHAR* insname;
UBYTE flags;
UWORD samplenumber[INSTNOTES];
UBYTE samplenote[INSTNOTES];
UBYTE nnatype;
UBYTE dca; /* duplicate check action */
UBYTE dct; /* duplicate check type */
UBYTE globvol;
UWORD volfade;
SWORD panning; /* instrument-based panning var */
UBYTE pitpansep; /* pitch pan separation (0 to 255) */
UBYTE pitpancenter; /* pitch pan center (0 to 119) */
UBYTE rvolvar; /* random volume varations (0 - 100%) */
UBYTE rpanvar; /* random panning varations (0 - 100%) */
/* volume envelope */
UBYTE volflg; /* bit 0: on 1: sustain 2: loop */
UBYTE volpts;
UBYTE volsusbeg;
UBYTE volsusend;
UBYTE volbeg;
UBYTE volend;
ENVPT volenv[ENVPOINTS];
/* panning envelope */
UBYTE panflg; /* bit 0: on 1: sustain 2: loop */
UBYTE panpts;
UBYTE pansusbeg;
UBYTE pansusend;
UBYTE panbeg;
UBYTE panend;
ENVPT panenv[ENVPOINTS];
/* pitch envelope */
UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */
UBYTE pitpts;
UBYTE pitsusbeg;
UBYTE pitsusend;
UBYTE pitbeg;
UBYTE pitend;
ENVPT pitenv[ENVPOINTS];
} INSTRUMENT;
struct MP_CONTROL;
struct MP_VOICE;
/*
Module definition
*/
/* maximum master channels supported */
#define UF_MAXCHAN 64
/* Module flags */
#define UF_XMPERIODS 0x0001 /* XM periods / finetuning */
#define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */
#define UF_INST 0x0004 /* Instruments are used */
#define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather
than numchn */
#define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */
#define UF_BGSLIDES 0x0020 /* continue volume slides in the background */
#define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */
#define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern break
semantics */
#define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */
#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
#define UF_PANNING 0x0400 /* module uses panning effects or have
non-tracker default initial panning */
typedef struct MODULE {
/* general module information */
CHAR* songname; /* name of the song */
CHAR* modtype; /* string type of module loaded */
CHAR* comment; /* module comments */
UWORD flags; /* See module flags above */
UBYTE numchn; /* number of module channels */
UBYTE numvoices; /* max # voices used for full NNA playback */
UWORD numpos; /* number of positions in this song */
UWORD numpat; /* number of patterns in this song */
UWORD numins; /* number of instruments */
UWORD numsmp; /* number of samples */
struct INSTRUMENT* instruments; /* all instruments */
struct SAMPLE* samples; /* all samples */
UBYTE realchn; /* real number of channels used */
UBYTE totalchn; /* total number of channels used (incl NNAs) */
/* playback settings */
UWORD reppos; /* restart position */
UBYTE initspeed; /* initial song speed */
UWORD inittempo; /* initial song tempo */
UBYTE initvolume; /* initial global volume (0 - 128) */
UWORD panning[UF_MAXCHAN]; /* panning positions */
UBYTE chanvol[UF_MAXCHAN]; /* channel positions */
UWORD bpm; /* current beats-per-minute speed */
UWORD sngspd; /* current song speed */
SWORD volume; /* song volume (0-128) (or user volume) */
BOOL extspd; /* extended speed flag (default enabled) */
BOOL panflag; /* panning flag (default enabled) */
BOOL wrap; /* wrap module ? (default disabled) */
BOOL loop; /* allow module to loop ? (default enabled) */
BOOL fadeout; /* volume fade out during last pattern */
UWORD patpos; /* current row number */
SWORD sngpos; /* current song position */
ULONG sngtime; /* current song time in 2^-10 seconds */
SWORD relspd; /* relative speed factor */
/* internal module representation */
UWORD numtrk; /* number of tracks */
UBYTE** tracks; /* array of numtrk pointers to tracks */
UWORD* patterns; /* array of Patterns */
UWORD* pattrows; /* array of number of rows for each pattern */
UWORD* positions; /* all positions */
BOOL forbid; /* if true, no player update! */
UWORD numrow; /* number of rows on current pattern */
UWORD vbtick; /* tick counter (counts from 0 to sngspd) */
UWORD sngremainder;/* used for song time computation */
struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */
struct MP_VOICE* voice; /* Audio Voice information (size md_numchn) */
UBYTE globalslide; /* global volume slide rate */
UBYTE pat_repcrazy;/* module has just looped to position -1 */
UWORD patbrk; /* position where to start a new pattern */
UBYTE patdly; /* patterndelay counter (command memory) */
UBYTE patdly2; /* patterndelay counter (real one) */
SWORD posjmp; /* flag to indicate a jump is needed... */
UWORD bpmlimit; /* threshold to detect bpm or speed values */
} MODULE;
/* This structure is used to query current playing voices status */
typedef struct VOICEINFO {
INSTRUMENT* i; /* Current channel instrument */
SAMPLE* s; /* Current channel sample */
SWORD panning; /* panning position */
SBYTE volume; /* channel's "global" volume (0..64) */
UWORD period; /* period to play the sample at */
UBYTE kick; /* if true = sample has been restarted */
} VOICEINFO;
/*
* ========== Module loaders
*/
struct MLOADER;
MIKMODAPI extern CHAR* MikMod_InfoLoader(void);
MIKMODAPI extern void MikMod_RegisterAllLoaders(void);
MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*);
MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */
MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */
MIKMODAPI extern struct MLOADER load_asy; /* ASYLUM Music Format 1.0 */
MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */
MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */
MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */
MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */
MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */
MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */
MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */
MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */
MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */
MIKMODAPI extern struct MLOADER load_okt; /* Amiga Oktalyzer */
MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */
MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */
MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */
/*
* ========== Module player
*/
MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL);
MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*);
MIKMODAPI extern CHAR* Player_LoadTitleFP(FILE*);
MIKMODAPI extern void Player_Free(MODULE*);
MIKMODAPI extern void Player_Start(MODULE*);
MIKMODAPI extern BOOL Player_Active(void);
MIKMODAPI extern void Player_Stop(void);
MIKMODAPI extern void Player_TogglePause(void);
MIKMODAPI extern BOOL Player_Paused(void);
MIKMODAPI extern void Player_NextPosition(void);
MIKMODAPI extern void Player_PrevPosition(void);
MIKMODAPI extern void Player_SetPosition(UWORD);
MIKMODAPI extern BOOL Player_Muted(UBYTE);
MIKMODAPI extern void Player_SetVolume(SWORD);
MIKMODAPI extern MODULE* Player_GetModule(void);
MIKMODAPI extern void Player_SetSpeed(UWORD);
MIKMODAPI extern void Player_SetTempo(UWORD);
MIKMODAPI extern void Player_Unmute(SLONG,...);
MIKMODAPI extern void Player_Mute(SLONG,...);
MIKMODAPI extern void Player_ToggleMute(SLONG,...);
MIKMODAPI extern int Player_GetChannelVoice(UBYTE);
MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE);
MIKMODAPI extern int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo);
typedef void (MikMod_player)(void);
typedef MikMod_player *MikMod_player_t;
MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t);
#define MUTE_EXCLUSIVE 32000
#define MUTE_INCLUSIVE 32001
/*
* ========== Drivers
*/
enum {
MD_MUSIC = 0,
MD_SNDFX
};
enum {
MD_HARDWARE = 0,
MD_SOFTWARE
};
/* Mixing flags */
/* These ones take effect only after MikMod_Init or MikMod_Reset */
#define DMODE_16BITS 0x0001 /* enable 16 bit output */
#define DMODE_STEREO 0x0002 /* enable stereo output */
#define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */
#define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */
#define DMODE_HQMIXER 0x0010 /* Use high-quality (slower) software mixer */
#define DMODE_FLOAT 0x0020 /* enable float output */
/* These take effect immediately. */
#define DMODE_SURROUND 0x0100 /* enable surround sound */
#define DMODE_INTERP 0x0200 /* enable interpolation */
#define DMODE_REVERSE 0x0400 /* reverse stereo */
struct SAMPLOAD;
typedef struct MDRIVER {
struct MDRIVER* next;
CHAR* Name;
CHAR* Version;
UBYTE HardVoiceLimit; /* Limit of hardware mixer voices */
UBYTE SoftVoiceLimit; /* Limit of software mixer voices */
CHAR *Alias;
CHAR *CmdLineHelp;
void (*CommandLine) (CHAR*);
BOOL (*IsPresent) (void);
SWORD (*SampleLoad) (struct SAMPLOAD*,int);
void (*SampleUnload) (SWORD);
ULONG (*FreeSampleSpace) (int);
ULONG (*RealSampleLength) (int,struct SAMPLE*);
BOOL (*Init) (void);
void (*Exit) (void);
BOOL (*Reset) (void);
BOOL (*SetNumVoices) (void);
BOOL (*PlayStart) (void);
void (*PlayStop) (void);
void (*Update) (void);
void (*Pause) (void);
void (*VoiceSetVolume) (UBYTE,UWORD);
UWORD (*VoiceGetVolume) (UBYTE);
void (*VoiceSetFrequency)(UBYTE,ULONG);
ULONG (*VoiceGetFrequency)(UBYTE);
void (*VoiceSetPanning) (UBYTE,ULONG);
ULONG (*VoiceGetPanning) (UBYTE);
void (*VoicePlay) (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
void (*VoiceStop) (UBYTE);
BOOL (*VoiceStopped) (UBYTE);
SLONG (*VoiceGetPosition) (UBYTE);
ULONG (*VoiceRealVolume) (UBYTE);
} MDRIVER;
/* These variables can be changed at ANY time and results will be immediate */
MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */
MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */
MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */
MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */
MIKMODAPI extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */
/* The variables below can be changed at any time, but changes will not be
implemented until MikMod_Reset is called. A call to MikMod_Reset may result
in a skip or pop in audio (depending on the soundcard driver and the settings
changed). */
MIKMODAPI extern UWORD md_device; /* device */
MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */
MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */
/* The following variable should not be changed! */
MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */
/* Known drivers list */
MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */
MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */
MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */
MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */
MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */
MIKMODAPI extern struct MDRIVER drv_aiff; /* AIFF file disk writer [music.aiff] */
MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */
MIKMODAPI extern struct MDRIVER drv_sam9407; /* Linux sam9407 driver */
MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */
MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */
MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */
MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */
MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */
MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */
MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */
MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */
MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */
MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */
MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */
MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */
MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */
MIKMODAPI extern struct MDRIVER drv_osx; /* MacOS X CoreAudio Driver */
/*========== Virtual channel mixer interface (for user-supplied drivers only) */
MIKMODAPI extern BOOL VC_Init(void);
MIKMODAPI extern void VC_Exit(void);
MIKMODAPI extern BOOL VC_SetNumVoices(void);
MIKMODAPI extern ULONG VC_SampleSpace(int);
MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);
MIKMODAPI extern BOOL VC_PlayStart(void);
MIKMODAPI extern void VC_PlayStop(void);
MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);
MIKMODAPI extern void VC_SampleUnload(SWORD);
MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);
MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);
MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD);
MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);
MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG);
MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);
MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG);
MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);
MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
MIKMODAPI extern void VC_VoiceStop(UBYTE);
MIKMODAPI extern BOOL VC_VoiceStopped(UBYTE);
MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);
MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE);
#ifdef __cplusplus
}
#endif
#endif
/* ex:set ts=4: */

View File

@@ -0,0 +1,747 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mikmod.h.in,v 1.11 2004/02/18 14:10:39 raph Exp $
MikMod sound library include file
==============================================================================*/
#ifndef _MIKMOD_H_
#define _MIKMOD_H_
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* ========== Compiler magic for shared libraries
*/
#if defined WIN32 && defined _DLL
#ifdef DLL_EXPORTS
#define MIKMODAPI __declspec(dllexport)
#else
#define MIKMODAPI __declspec(dllimport)
#endif
#else
#define MIKMODAPI
#endif
/*
* ========== Library version
*/
#define LIBMIKMOD_VERSION_MAJOR 3L
#define LIBMIKMOD_VERSION_MINOR 2L
#define LIBMIKMOD_REVISION 0L
#define LIBMIKMOD_VERSION \
((LIBMIKMOD_VERSION_MAJOR<<16)| \
(LIBMIKMOD_VERSION_MINOR<< 8)| \
(LIBMIKMOD_REVISION))
MIKMODAPI extern long MikMod_GetVersion(void);
/*
* ========== Platform independent-type definitions
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#include <mmsystem.h>
#endif
#if defined(__OS2__)||defined(__EMX__)
#define INCL_DOSSEMAPHORES
#include <os2.h>
#else
typedef char CHAR;
#endif
#if defined(__arch64__) || defined(__alpha)
/* 64 bit architectures */
typedef signed char SBYTE; /* 1 byte, signed */
typedef unsigned char UBYTE; /* 1 byte, unsigned */
typedef signed short SWORD; /* 2 bytes, signed */
typedef unsigned short UWORD; /* 2 bytes, unsigned */
typedef signed int SLONG; /* 4 bytes, signed */
typedef unsigned int ULONG; /* 4 bytes, unsigned */
typedef int BOOL; /* 0=false, <>0 true */
#else
/* 32 bit architectures */
typedef signed char SBYTE; /* 1 byte, signed */
typedef unsigned char UBYTE; /* 1 byte, unsigned */
typedef signed short SWORD; /* 2 bytes, signed */
typedef unsigned short UWORD; /* 2 bytes, unsigned */
typedef signed long SLONG; /* 4 bytes, signed */
#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32)
typedef unsigned long ULONG; /* 4 bytes, unsigned */
typedef int BOOL; /* 0=false, <>0 true */
#endif
#endif
/*
* ========== Error codes
*/
enum {
MMERR_OPENING_FILE = 1,
MMERR_OUT_OF_MEMORY,
MMERR_DYNAMIC_LINKING,
MMERR_SAMPLE_TOO_BIG,
MMERR_OUT_OF_HANDLES,
MMERR_UNKNOWN_WAVE_TYPE,
MMERR_LOADING_PATTERN,
MMERR_LOADING_TRACK,
MMERR_LOADING_HEADER,
MMERR_LOADING_SAMPLEINFO,
MMERR_NOT_A_MODULE,
MMERR_NOT_A_STREAM,
MMERR_MED_SYNTHSAMPLES,
MMERR_ITPACK_INVALID_DATA,
MMERR_DETECTING_DEVICE,
MMERR_INVALID_DEVICE,
MMERR_INITIALIZING_MIXER,
MMERR_OPENING_AUDIO,
MMERR_8BIT_ONLY,
MMERR_16BIT_ONLY,
MMERR_STEREO_ONLY,
MMERR_ULAW,
MMERR_NON_BLOCK,
MMERR_AF_AUDIO_PORT,
MMERR_AIX_CONFIG_INIT,
MMERR_AIX_CONFIG_CONTROL,
MMERR_AIX_CONFIG_START,
MMERR_GUS_SETTINGS,
MMERR_GUS_RESET,
MMERR_GUS_TIMER,
MMERR_HP_SETSAMPLESIZE,
MMERR_HP_SETSPEED,
MMERR_HP_CHANNELS,
MMERR_HP_AUDIO_OUTPUT,
MMERR_HP_AUDIO_DESC,
MMERR_HP_BUFFERSIZE,
MMERR_OSS_SETFRAGMENT,
MMERR_OSS_SETSAMPLESIZE,
MMERR_OSS_SETSTEREO,
MMERR_OSS_SETSPEED,
MMERR_SGI_SPEED,
MMERR_SGI_16BIT,
MMERR_SGI_8BIT,
MMERR_SGI_STEREO,
MMERR_SGI_MONO,
MMERR_SUN_INIT,
MMERR_OS2_MIXSETUP,
MMERR_OS2_SEMAPHORE,
MMERR_OS2_TIMER,
MMERR_OS2_THREAD,
MMERR_DS_PRIORITY,
MMERR_DS_BUFFER,
MMERR_DS_FORMAT,
MMERR_DS_NOTIFY,
MMERR_DS_EVENT,
MMERR_DS_THREAD,
MMERR_DS_UPDATE,
MMERR_WINMM_HANDLE,
MMERR_WINMM_ALLOCATED,
MMERR_WINMM_DEVICEID,
MMERR_WINMM_FORMAT,
MMERR_WINMM_UNKNOWN,
MMERR_MAC_SPEED,
MMERR_MAC_START,
MMERR_OSX_UNKNOWN_DEVICE,
MMERR_OSX_BAD_PROPERTY,
MMERR_OSX_UNSUPPORTED_FORMAT,
MMERR_OSX_SET_STEREO,
MMERR_OSX_BUFFER_ALLOC,
MMERR_OSX_ADD_IO_PROC,
MMERR_OSX_DEVICE_START,
MMERR_OSX_PTHREAD,
MMERR_DOSWSS_STARTDMA,
MMERR_DOSSB_STARTDMA,
MMERR_MAX
};
/*
* ========== Error handling
*/
typedef void (MikMod_handler)(void);
typedef MikMod_handler *MikMod_handler_t;
MIKMODAPI extern int MikMod_errno;
MIKMODAPI extern BOOL MikMod_critical;
MIKMODAPI extern char *MikMod_strerror(int);
MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t);
/*
* ========== Library initialization and core functions
*/
struct MDRIVER;
MIKMODAPI extern void MikMod_RegisterAllDrivers(void);
MIKMODAPI extern CHAR* MikMod_InfoDriver(void);
MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*);
MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*);
MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int);
MIKMODAPI extern BOOL MikMod_Init(CHAR*);
MIKMODAPI extern void MikMod_Exit(void);
MIKMODAPI extern BOOL MikMod_Reset(CHAR*);
MIKMODAPI extern BOOL MikMod_SetNumVoices(int,int);
MIKMODAPI extern BOOL MikMod_Active(void);
MIKMODAPI extern BOOL MikMod_EnableOutput(void);
MIKMODAPI extern void MikMod_DisableOutput(void);
MIKMODAPI extern void MikMod_Update(void);
MIKMODAPI extern BOOL MikMod_InitThreads(void);
MIKMODAPI extern void MikMod_Lock(void);
MIKMODAPI extern void MikMod_Unlock(void);
/*
* ========== Reader, Writer
*/
typedef struct MREADER {
BOOL (*Seek)(struct MREADER*,long,int);
long (*Tell)(struct MREADER*);
BOOL (*Read)(struct MREADER*,void*,size_t);
int (*Get)(struct MREADER*);
BOOL (*Eof)(struct MREADER*);
} MREADER;
typedef struct MWRITER {
BOOL (*Seek)(struct MWRITER*,long,int);
long (*Tell)(struct MWRITER*);
BOOL (*Write)(struct MWRITER*,void*,size_t);
BOOL (*Put)(struct MWRITER*,int);
} MWRITER;
/*
* ========== Samples
*/
/* Sample playback should not be interrupted */
#define SFX_CRITICAL 1
/* Sample format [loading and in-memory] flags: */
#define SF_16BITS 0x0001
#define SF_STEREO 0x0002
#define SF_SIGNED 0x0004
#define SF_BIG_ENDIAN 0x0008
#define SF_DELTA 0x0010
#define SF_ITPACKED 0x0020
#define SF_FORMATMASK 0x003F
/* General Playback flags */
#define SF_LOOP 0x0100
#define SF_BIDI 0x0200
#define SF_REVERSE 0x0400
#define SF_SUSTAIN 0x0800
#define SF_PLAYBACKMASK 0x0C00
/* Module-only Playback Flags */
#define SF_OWNPAN 0x1000
#define SF_UST_LOOP 0x2000
#define SF_EXTRAPLAYBACKMASK 0x3000
/* Panning constants */
#define PAN_LEFT 0
#define PAN_HALFLEFT 64
#define PAN_CENTER 128
#define PAN_HALFRIGHT 192
#define PAN_RIGHT 255
#define PAN_SURROUND 512 /* panning value for Dolby Surround */
typedef struct SAMPLE {
SWORD panning; /* panning (0-255 or PAN_SURROUND) */
ULONG speed; /* Base playing speed/frequency of note */
UBYTE volume; /* volume 0-64 */
UWORD inflags; /* sample format on disk */
UWORD flags; /* sample format in memory */
ULONG length; /* length of sample (in samples!) */
ULONG loopstart; /* repeat position (relative to start, in samples) */
ULONG loopend; /* repeat end */
ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */
ULONG susend; /* sustain loop end / Yet! */
/* Variables used by the module player only! (ignored for sound effects) */
UBYTE globvol; /* global volume */
UBYTE vibflags; /* autovibrato flag stuffs */
UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */
UBYTE vibsweep;
UBYTE vibdepth;
UBYTE vibrate;
CHAR* samplename; /* name of the sample */
/* Values used internally only */
UWORD avibpos; /* autovibrato pos [player use] */
UBYTE divfactor; /* for sample scaling, maintains proper period slides */
ULONG seekpos; /* seek position in file */
SWORD handle; /* sample handle used by individual drivers */
} SAMPLE;
/* Sample functions */
MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);
MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*);
MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
MIKMODAPI extern void Sample_Free(SAMPLE*);
MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE);
MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD);
MIKMODAPI extern UWORD Voice_GetVolume(SBYTE);
MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG);
MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE);
MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG);
MIKMODAPI extern ULONG Voice_GetPanning(SBYTE);
MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG);
MIKMODAPI extern void Voice_Stop(SBYTE);
MIKMODAPI extern BOOL Voice_Stopped(SBYTE);
MIKMODAPI extern SLONG Voice_GetPosition(SBYTE);
MIKMODAPI extern ULONG Voice_RealVolume(SBYTE);
/*
* ========== Internal module representation (UniMod)
*/
/*
Instrument definition - for information only, the only field which may be
of use in user programs is the name field
*/
/* Instrument note count */
#define INSTNOTES 120
/* Envelope point */
typedef struct ENVPT {
SWORD pos;
SWORD val;
} ENVPT;
/* Envelope point count */
#define ENVPOINTS 32
/* Instrument structure */
typedef struct INSTRUMENT {
CHAR* insname;
UBYTE flags;
UWORD samplenumber[INSTNOTES];
UBYTE samplenote[INSTNOTES];
UBYTE nnatype;
UBYTE dca; /* duplicate check action */
UBYTE dct; /* duplicate check type */
UBYTE globvol;
UWORD volfade;
SWORD panning; /* instrument-based panning var */
UBYTE pitpansep; /* pitch pan separation (0 to 255) */
UBYTE pitpancenter; /* pitch pan center (0 to 119) */
UBYTE rvolvar; /* random volume varations (0 - 100%) */
UBYTE rpanvar; /* random panning varations (0 - 100%) */
/* volume envelope */
UBYTE volflg; /* bit 0: on 1: sustain 2: loop */
UBYTE volpts;
UBYTE volsusbeg;
UBYTE volsusend;
UBYTE volbeg;
UBYTE volend;
ENVPT volenv[ENVPOINTS];
/* panning envelope */
UBYTE panflg; /* bit 0: on 1: sustain 2: loop */
UBYTE panpts;
UBYTE pansusbeg;
UBYTE pansusend;
UBYTE panbeg;
UBYTE panend;
ENVPT panenv[ENVPOINTS];
/* pitch envelope */
UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */
UBYTE pitpts;
UBYTE pitsusbeg;
UBYTE pitsusend;
UBYTE pitbeg;
UBYTE pitend;
ENVPT pitenv[ENVPOINTS];
} INSTRUMENT;
struct MP_CONTROL;
struct MP_VOICE;
/*
Module definition
*/
/* maximum master channels supported */
#define UF_MAXCHAN 64
/* Module flags */
#define UF_XMPERIODS 0x0001 /* XM periods / finetuning */
#define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */
#define UF_INST 0x0004 /* Instruments are used */
#define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather
than numchn */
#define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */
#define UF_BGSLIDES 0x0020 /* continue volume slides in the background */
#define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */
#define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern break
semantics */
#define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */
#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
#define UF_PANNING 0x0400 /* module uses panning effects or have
non-tracker default initial panning */
typedef struct MODULE {
/* general module information */
CHAR* songname; /* name of the song */
CHAR* modtype; /* string type of module loaded */
CHAR* comment; /* module comments */
UWORD flags; /* See module flags above */
UBYTE numchn; /* number of module channels */
UBYTE numvoices; /* max # voices used for full NNA playback */
UWORD numpos; /* number of positions in this song */
UWORD numpat; /* number of patterns in this song */
UWORD numins; /* number of instruments */
UWORD numsmp; /* number of samples */
struct INSTRUMENT* instruments; /* all instruments */
struct SAMPLE* samples; /* all samples */
UBYTE realchn; /* real number of channels used */
UBYTE totalchn; /* total number of channels used (incl NNAs) */
/* playback settings */
UWORD reppos; /* restart position */
UBYTE initspeed; /* initial song speed */
UWORD inittempo; /* initial song tempo */
UBYTE initvolume; /* initial global volume (0 - 128) */
UWORD panning[UF_MAXCHAN]; /* panning positions */
UBYTE chanvol[UF_MAXCHAN]; /* channel positions */
UWORD bpm; /* current beats-per-minute speed */
UWORD sngspd; /* current song speed */
SWORD volume; /* song volume (0-128) (or user volume) */
BOOL extspd; /* extended speed flag (default enabled) */
BOOL panflag; /* panning flag (default enabled) */
BOOL wrap; /* wrap module ? (default disabled) */
BOOL loop; /* allow module to loop ? (default enabled) */
BOOL fadeout; /* volume fade out during last pattern */
UWORD patpos; /* current row number */
SWORD sngpos; /* current song position */
ULONG sngtime; /* current song time in 2^-10 seconds */
SWORD relspd; /* relative speed factor */
/* internal module representation */
UWORD numtrk; /* number of tracks */
UBYTE** tracks; /* array of numtrk pointers to tracks */
UWORD* patterns; /* array of Patterns */
UWORD* pattrows; /* array of number of rows for each pattern */
UWORD* positions; /* all positions */
BOOL forbid; /* if true, no player update! */
UWORD numrow; /* number of rows on current pattern */
UWORD vbtick; /* tick counter (counts from 0 to sngspd) */
UWORD sngremainder;/* used for song time computation */
struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */
struct MP_VOICE* voice; /* Audio Voice information (size md_numchn) */
UBYTE globalslide; /* global volume slide rate */
UBYTE pat_repcrazy;/* module has just looped to position -1 */
UWORD patbrk; /* position where to start a new pattern */
UBYTE patdly; /* patterndelay counter (command memory) */
UBYTE patdly2; /* patterndelay counter (real one) */
SWORD posjmp; /* flag to indicate a jump is needed... */
UWORD bpmlimit; /* threshold to detect bpm or speed values */
} MODULE;
/* This structure is used to query current playing voices status */
typedef struct VOICEINFO {
INSTRUMENT* i; /* Current channel instrument */
SAMPLE* s; /* Current channel sample */
SWORD panning; /* panning position */
SBYTE volume; /* channel's "global" volume (0..64) */
UWORD period; /* period to play the sample at */
UBYTE kick; /* if true = sample has been restarted */
} VOICEINFO;
/*
* ========== Module loaders
*/
struct MLOADER;
MIKMODAPI extern CHAR* MikMod_InfoLoader(void);
MIKMODAPI extern void MikMod_RegisterAllLoaders(void);
MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*);
MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */
MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */
MIKMODAPI extern struct MLOADER load_asy; /* ASYLUM Music Format 1.0 */
MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */
MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */
MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */
MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */
MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */
MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */
MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */
MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */
MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */
MIKMODAPI extern struct MLOADER load_okt; /* Amiga Oktalyzer */
MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */
MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */
MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */
MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */
/*
* ========== Module player
*/
MIKMODAPI extern MODULE* Player_Load(CHAR*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL);
MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL);
MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*);
MIKMODAPI extern CHAR* Player_LoadTitleFP(FILE*);
MIKMODAPI extern void Player_Free(MODULE*);
MIKMODAPI extern void Player_Start(MODULE*);
MIKMODAPI extern BOOL Player_Active(void);
MIKMODAPI extern void Player_Stop(void);
MIKMODAPI extern void Player_TogglePause(void);
MIKMODAPI extern BOOL Player_Paused(void);
MIKMODAPI extern void Player_NextPosition(void);
MIKMODAPI extern void Player_PrevPosition(void);
MIKMODAPI extern void Player_SetPosition(UWORD);
MIKMODAPI extern BOOL Player_Muted(UBYTE);
MIKMODAPI extern void Player_SetVolume(SWORD);
MIKMODAPI extern MODULE* Player_GetModule(void);
MIKMODAPI extern void Player_SetSpeed(UWORD);
MIKMODAPI extern void Player_SetTempo(UWORD);
MIKMODAPI extern void Player_Unmute(SLONG,...);
MIKMODAPI extern void Player_Mute(SLONG,...);
MIKMODAPI extern void Player_ToggleMute(SLONG,...);
MIKMODAPI extern int Player_GetChannelVoice(UBYTE);
MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE);
MIKMODAPI extern int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo);
typedef void (MikMod_player)(void);
typedef MikMod_player *MikMod_player_t;
MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t);
#define MUTE_EXCLUSIVE 32000
#define MUTE_INCLUSIVE 32001
/*
* ========== Drivers
*/
enum {
MD_MUSIC = 0,
MD_SNDFX
};
enum {
MD_HARDWARE = 0,
MD_SOFTWARE
};
/* Mixing flags */
/* These ones take effect only after MikMod_Init or MikMod_Reset */
#define DMODE_16BITS 0x0001 /* enable 16 bit output */
#define DMODE_STEREO 0x0002 /* enable stereo output */
#define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */
#define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */
#define DMODE_HQMIXER 0x0010 /* Use high-quality (slower) software mixer */
#define DMODE_FLOAT 0x0020 /* enable float output */
/* These take effect immediately. */
#define DMODE_SURROUND 0x0100 /* enable surround sound */
#define DMODE_INTERP 0x0200 /* enable interpolation */
#define DMODE_REVERSE 0x0400 /* reverse stereo */
struct SAMPLOAD;
typedef struct MDRIVER {
struct MDRIVER* next;
CHAR* Name;
CHAR* Version;
UBYTE HardVoiceLimit; /* Limit of hardware mixer voices */
UBYTE SoftVoiceLimit; /* Limit of software mixer voices */
CHAR *Alias;
CHAR *CmdLineHelp;
void (*CommandLine) (CHAR*);
BOOL (*IsPresent) (void);
SWORD (*SampleLoad) (struct SAMPLOAD*,int);
void (*SampleUnload) (SWORD);
ULONG (*FreeSampleSpace) (int);
ULONG (*RealSampleLength) (int,struct SAMPLE*);
BOOL (*Init) (void);
void (*Exit) (void);
BOOL (*Reset) (void);
BOOL (*SetNumVoices) (void);
BOOL (*PlayStart) (void);
void (*PlayStop) (void);
void (*Update) (void);
void (*Pause) (void);
void (*VoiceSetVolume) (UBYTE,UWORD);
UWORD (*VoiceGetVolume) (UBYTE);
void (*VoiceSetFrequency)(UBYTE,ULONG);
ULONG (*VoiceGetFrequency)(UBYTE);
void (*VoiceSetPanning) (UBYTE,ULONG);
ULONG (*VoiceGetPanning) (UBYTE);
void (*VoicePlay) (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
void (*VoiceStop) (UBYTE);
BOOL (*VoiceStopped) (UBYTE);
SLONG (*VoiceGetPosition) (UBYTE);
ULONG (*VoiceRealVolume) (UBYTE);
} MDRIVER;
/* These variables can be changed at ANY time and results will be immediate */
MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */
MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */
MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */
MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */
MIKMODAPI extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */
/* The variables below can be changed at any time, but changes will not be
implemented until MikMod_Reset is called. A call to MikMod_Reset may result
in a skip or pop in audio (depending on the soundcard driver and the settings
changed). */
MIKMODAPI extern UWORD md_device; /* device */
MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */
MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */
/* The following variable should not be changed! */
MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */
/* Known drivers list */
MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */
MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */
MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */
MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */
MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */
MIKMODAPI extern struct MDRIVER drv_aiff; /* AIFF file disk writer [music.aiff] */
MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */
MIKMODAPI extern struct MDRIVER drv_sam9407; /* Linux sam9407 driver */
MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */
MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */
MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */
MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */
MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */
MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */
MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */
MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */
MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */
MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */
MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */
MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */
MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */
MIKMODAPI extern struct MDRIVER drv_osx; /* MacOS X CoreAudio Driver */
/*========== Virtual channel mixer interface (for user-supplied drivers only) */
MIKMODAPI extern BOOL VC_Init(void);
MIKMODAPI extern void VC_Exit(void);
MIKMODAPI extern BOOL VC_SetNumVoices(void);
MIKMODAPI extern ULONG VC_SampleSpace(int);
MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);
MIKMODAPI extern BOOL VC_PlayStart(void);
MIKMODAPI extern void VC_PlayStop(void);
MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);
MIKMODAPI extern void VC_SampleUnload(SWORD);
MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);
MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);
MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD);
MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);
MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG);
MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);
MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG);
MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);
MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
MIKMODAPI extern void VC_VoiceStop(UBYTE);
MIKMODAPI extern BOOL VC_VoiceStopped(UBYTE);
MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);
MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE);
#ifdef __cplusplus
}
#endif
#endif
/* ex:set ts=4: */

View File

@@ -0,0 +1,685 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mikmod_internals.h,v 1.4 2004/02/18 13:29:17 raph Exp $
MikMod sound library internal definitions
==============================================================================*/
#ifndef _MIKMOD_INTERNALS_H
#define _MIKMOD_INTERNALS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <stdarg.h>
#if defined(__OS2__)||defined(__EMX__)||defined(WIN32)
#define strcasecmp(s,t) stricmp(s,t)
#endif
#include <mikmod_build.h>
#ifdef WIN32
#pragma warning(disable:4761)
#endif
/*========== More type definitions */
/* SLONGLONG: 64bit, signed */
#if defined (__arch64__) || defined(__alpha)
typedef long SLONGLONG;
#define NATIVE_64BIT_INT
#elif defined(__WATCOMC__)
typedef __int64 SLONGLONG;
#elif defined(WIN32) && !defined(__MWERKS__)
typedef LONGLONG SLONGLONG;
#elif macintosh && !TYPE_LONGLONG
#include <Types.h>
typedef SInt64 SLONGLONG;
#else
typedef long long SLONGLONG;
#endif
/*========== Error handling */
#define _mm_errno MikMod_errno
#define _mm_critical MikMod_critical
extern MikMod_handler_t _mm_errorhandler;
/*========== Memory allocation */
extern void* _mm_malloc(size_t);
extern void* _mm_calloc(size_t,size_t);
#define _mm_free(p) do { if (p) free(p); p = NULL; } while(0)
/*========== MT stuff */
#ifdef HAVE_PTHREAD
#include <pthread.h>
#define DECLARE_MUTEX(name) \
extern pthread_mutex_t _mm_mutex_##name
#define MUTEX_LOCK(name) \
pthread_mutex_lock(&_mm_mutex_##name)
#define MUTEX_UNLOCK(name) \
pthread_mutex_unlock(&_mm_mutex_##name)
#elif defined(__OS2__)||defined(__EMX__)
#define DECLARE_MUTEX(name) \
extern HMTX _mm_mutex_##name
#define MUTEX_LOCK(name) \
if(_mm_mutex_##name) \
DosRequestMutexSem(_mm_mutex_##name,SEM_INDEFINITE_WAIT)
#define MUTEX_UNLOCK(name) \
if(_mm_mutex_##name) \
DosReleaseMutexSem(_mm_mutex_##name)
#elif defined(WIN32)
#include <windows.h>
#define DECLARE_MUTEX(name) \
extern HANDLE _mm_mutex_##name
#define MUTEX_LOCK(name) \
if(_mm_mutex_##name) \
WaitForSingleObject(_mm_mutex_##name,INFINITE)
#define MUTEX_UNLOCK(name) \
if(_mm_mutex_##name) \
ReleaseMutex(_mm_mutex_##name)
#else
#define DECLARE_MUTEX(name) \
extern void *_mm_mutex_##name
#define MUTEX_LOCK(name)
#define MUTEX_UNLOCK(name)
#endif
DECLARE_MUTEX(lists);
DECLARE_MUTEX(vars);
/*========== Portable file I/O */
extern MREADER* _mm_new_file_reader(FILE* fp);
extern void _mm_delete_file_reader(MREADER*);
extern MWRITER* _mm_new_file_writer(FILE *fp);
extern void _mm_delete_file_writer(MWRITER*);
extern BOOL _mm_FileExists(CHAR *fname);
#define _mm_write_SBYTE(x,y) y->Put(y,(int)x)
#define _mm_write_UBYTE(x,y) y->Put(y,(int)x)
#define _mm_read_SBYTE(x) (SBYTE)x->Get(x)
#define _mm_read_UBYTE(x) (UBYTE)x->Get(x)
#define _mm_write_SBYTES(x,y,z) z->Write(z,(void *)x,y)
#define _mm_write_UBYTES(x,y,z) z->Write(z,(void *)x,y)
#define _mm_read_SBYTES(x,y,z) z->Read(z,(void *)x,y)
#define _mm_read_UBYTES(x,y,z) z->Read(z,(void *)x,y)
#define _mm_fseek(x,y,z) x->Seek(x,y,z)
#define _mm_ftell(x) x->Tell(x)
#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET)
#define _mm_eof(x) x->Eof(x)
extern void _mm_iobase_setcur(MREADER*);
extern void _mm_iobase_revert(void);
extern FILE *_mm_fopen(CHAR*,CHAR*);
extern int _mm_fclose(FILE *);
extern void _mm_write_string(CHAR*,MWRITER*);
extern int _mm_read_string (CHAR*,int,MREADER*);
extern SWORD _mm_read_M_SWORD(MREADER*);
extern SWORD _mm_read_I_SWORD(MREADER*);
extern UWORD _mm_read_M_UWORD(MREADER*);
extern UWORD _mm_read_I_UWORD(MREADER*);
extern SLONG _mm_read_M_SLONG(MREADER*);
extern SLONG _mm_read_I_SLONG(MREADER*);
extern ULONG _mm_read_M_ULONG(MREADER*);
extern ULONG _mm_read_I_ULONG(MREADER*);
extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*);
extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*);
extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*);
extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*);
extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*);
extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*);
extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*);
extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*);
extern void _mm_write_M_SWORD(SWORD,MWRITER*);
extern void _mm_write_I_SWORD(SWORD,MWRITER*);
extern void _mm_write_M_UWORD(UWORD,MWRITER*);
extern void _mm_write_I_UWORD(UWORD,MWRITER*);
extern void _mm_write_M_SLONG(SLONG,MWRITER*);
extern void _mm_write_I_SLONG(SLONG,MWRITER*);
extern void _mm_write_M_ULONG(ULONG,MWRITER*);
extern void _mm_write_I_ULONG(ULONG,MWRITER*);
extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*);
extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*);
extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*);
extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*);
extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*);
extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*);
extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*);
extern void _mm_write_I_ULONGS(ULONG*,int,MWRITER*);
/*========== Samples */
/* This is a handle of sorts attached to any sample registered with
SL_RegisterSample. Generally, this only need be used or changed by the
loaders and drivers of mikmod. */
typedef struct SAMPLOAD {
struct SAMPLOAD *next;
ULONG length; /* length of sample (in samples!) */
ULONG loopstart; /* repeat position (relative to start, in samples) */
ULONG loopend; /* repeat end */
UWORD infmt,outfmt;
int scalefactor;
SAMPLE* sample;
MREADER* reader;
} SAMPLOAD;
/*========== Sample and waves loading interface */
extern void SL_HalveSample(SAMPLOAD*,int);
extern void SL_Sample8to16(SAMPLOAD*);
extern void SL_Sample16to8(SAMPLOAD*);
extern void SL_SampleSigned(SAMPLOAD*);
extern void SL_SampleUnsigned(SAMPLOAD*);
extern BOOL SL_LoadSamples(void);
extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);
extern BOOL SL_Load(void*,SAMPLOAD*,ULONG);
extern BOOL SL_Init(SAMPLOAD*);
extern void SL_Exit(SAMPLOAD*);
/*========== Internal module representation (UniMod) interface */
/* number of notes in an octave */
#define OCTAVE 12
extern void UniSetRow(UBYTE*);
extern UBYTE UniGetByte(void);
extern UWORD UniGetWord(void);
extern UBYTE* UniFindRow(UBYTE*,UWORD);
extern void UniSkipOpcode(void);
extern void UniReset(void);
extern void UniWriteByte(UBYTE);
extern void UniWriteWord(UWORD);
extern void UniNewline(void);
extern UBYTE* UniDup(void);
extern BOOL UniInit(void);
extern void UniCleanup(void);
extern void UniEffect(UWORD,UWORD);
#define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x)
#define UniNote(x) UniEffect(UNI_NOTE,x)
extern void UniPTEffect(UBYTE,UBYTE);
extern void UniVolEffect(UWORD,UBYTE);
/*========== Module Commands */
enum {
/* Simple note */
UNI_NOTE = 1,
/* Instrument change */
UNI_INSTRUMENT,
/* Protracker effects */
UNI_PTEFFECT0, /* arpeggio */
UNI_PTEFFECT1, /* porta up */
UNI_PTEFFECT2, /* porta down */
UNI_PTEFFECT3, /* porta to note */
UNI_PTEFFECT4, /* vibrato */
UNI_PTEFFECT5, /* dual effect 3+A */
UNI_PTEFFECT6, /* dual effect 4+A */
UNI_PTEFFECT7, /* tremolo */
UNI_PTEFFECT8, /* pan */
UNI_PTEFFECT9, /* sample offset */
UNI_PTEFFECTA, /* volume slide */
UNI_PTEFFECTB, /* pattern jump */
UNI_PTEFFECTC, /* set volume */
UNI_PTEFFECTD, /* pattern break */
UNI_PTEFFECTE, /* extended effects */
UNI_PTEFFECTF, /* set speed */
/* Scream Tracker effects */
UNI_S3MEFFECTA, /* set speed */
UNI_S3MEFFECTD, /* volume slide */
UNI_S3MEFFECTE, /* porta down */
UNI_S3MEFFECTF, /* porta up */
UNI_S3MEFFECTI, /* tremor */
UNI_S3MEFFECTQ, /* retrig */
UNI_S3MEFFECTR, /* tremolo */
UNI_S3MEFFECTT, /* set tempo */
UNI_S3MEFFECTU, /* fine vibrato */
UNI_KEYOFF, /* note off */
/* Fast Tracker effects */
UNI_KEYFADE, /* note fade */
UNI_VOLEFFECTS, /* volume column effects */
UNI_XMEFFECT4, /* vibrato */
UNI_XMEFFECT6, /* dual effect 4+A */
UNI_XMEFFECTA, /* volume slide */
UNI_XMEFFECTE1, /* fine porta up */
UNI_XMEFFECTE2, /* fine porta down */
UNI_XMEFFECTEA, /* fine volume slide up */
UNI_XMEFFECTEB, /* fine volume slide down */
UNI_XMEFFECTG, /* set global volume */
UNI_XMEFFECTH, /* global volume slide */
UNI_XMEFFECTL, /* set envelope position */
UNI_XMEFFECTP, /* pan slide */
UNI_XMEFFECTX1, /* extra fine porta up */
UNI_XMEFFECTX2, /* extra fine porta down */
/* Impulse Tracker effects */
UNI_ITEFFECTG, /* porta to note */
UNI_ITEFFECTH, /* vibrato */
UNI_ITEFFECTI, /* tremor (xy not incremented) */
UNI_ITEFFECTM, /* set channel volume */
UNI_ITEFFECTN, /* slide / fineslide channel volume */
UNI_ITEFFECTP, /* slide / fineslide channel panning */
UNI_ITEFFECTT, /* slide tempo */
UNI_ITEFFECTU, /* fine vibrato */
UNI_ITEFFECTW, /* slide / fineslide global volume */
UNI_ITEFFECTY, /* panbrello */
UNI_ITEFFECTZ, /* resonant filters */
UNI_ITEFFECTS0,
/* UltraTracker effects */
UNI_ULTEFFECT9, /* Sample fine offset */
/* OctaMED effects */
UNI_MEDSPEED,
UNI_MEDEFFECTF1, /* play note twice */
UNI_MEDEFFECTF2, /* delay note */
UNI_MEDEFFECTF3, /* play note three times */
/* Oktalyzer effects */
UNI_OKTARP, /* arpeggio */
UNI_LAST
};
extern UWORD unioperands[UNI_LAST];
/* IT / S3M Extended SS effects: */
enum {
SS_GLISSANDO = 1,
SS_FINETUNE,
SS_VIBWAVE,
SS_TREMWAVE,
SS_PANWAVE,
SS_FRAMEDELAY,
SS_S7EFFECTS,
SS_PANNING,
SS_SURROUND,
SS_HIOFFSET,
SS_PATLOOP,
SS_NOTECUT,
SS_NOTEDELAY,
SS_PATDELAY
};
/* IT Volume column effects */
enum {
VOL_VOLUME = 1,
VOL_PANNING,
VOL_VOLSLIDE,
VOL_PITCHSLIDEDN,
VOL_PITCHSLIDEUP,
VOL_PORTAMENTO,
VOL_VIBRATO
};
/* IT resonant filter information */
#define UF_MAXMACRO 0x10
#define UF_MAXFILTER 0x100
#define FILT_CUT 0x80
#define FILT_RESONANT 0x81
typedef struct FILTER {
UBYTE filter,inf;
} FILTER;
/*========== Instruments */
/* Instrument format flags */
#define IF_OWNPAN 1
#define IF_PITCHPAN 2
/* Envelope flags: */
#define EF_ON 1
#define EF_SUSTAIN 2
#define EF_LOOP 4
#define EF_VOLENV 8
/* New Note Action Flags */
#define NNA_CUT 0
#define NNA_CONTINUE 1
#define NNA_OFF 2
#define NNA_FADE 3
#define NNA_MASK 3
#define DCT_OFF 0
#define DCT_NOTE 1
#define DCT_SAMPLE 2
#define DCT_INST 3
#define DCA_CUT 0
#define DCA_OFF 1
#define DCA_FADE 2
#define KEY_KICK 0
#define KEY_OFF 1
#define KEY_FADE 2
#define KEY_KILL (KEY_OFF|KEY_FADE)
#define KICK_ABSENT 0
#define KICK_NOTE 1
#define KICK_KEYOFF 2
#define KICK_ENV 4
#define AV_IT 1 /* IT vs. XM vibrato info */
/*========== Playing */
#define POS_NONE (-2) /* no loop position defined */
#define LAST_PATTERN (UWORD)(-1) /* special ``end of song'' pattern */
typedef struct ENVPR {
UBYTE flg; /* envelope flag */
UBYTE pts; /* number of envelope points */
UBYTE susbeg; /* envelope sustain index begin */
UBYTE susend; /* envelope sustain index end */
UBYTE beg; /* envelope loop begin */
UBYTE end; /* envelope loop end */
SWORD p; /* current envelope counter */
UWORD a; /* envelope index a */
UWORD b; /* envelope index b */
ENVPT* env; /* envelope points */
} ENVPR;
typedef struct MP_CHANNEL {
INSTRUMENT* i;
SAMPLE* s;
UBYTE sample; /* which sample number */
UBYTE note; /* the audible note as heard, direct rep of period */
SWORD outvolume; /* output volume (vol + sampcol + instvol) */
SBYTE chanvol; /* channel's "global" volume */
UWORD fadevol; /* fading volume rate */
SWORD panning; /* panning position */
UBYTE kick; /* if true = sample has to be restarted */
UBYTE kick_flag; /* kick has been true */
UWORD period; /* period to play the sample at */
UBYTE nna; /* New note action type + master/slave flags */
UBYTE volflg; /* volume envelope settings */
UBYTE panflg; /* panning envelope settings */
UBYTE pitflg; /* pitch envelope settings */
UBYTE keyoff; /* if true = fade out and stuff */
SWORD handle; /* which sample-handle */
UBYTE notedelay; /* (used for note delay) */
SLONG start; /* The starting byte index in the sample */
} MP_CHANNEL;
typedef struct MP_CONTROL {
struct MP_CHANNEL main;
struct MP_VOICE *slave; /* Audio Slave of current effects control channel */
UBYTE slavechn; /* Audio Slave of current effects control channel */
UBYTE muted; /* if set, channel not played */
UWORD ultoffset; /* fine sample offset memory */
UBYTE anote; /* the note that indexes the audible */
UBYTE oldnote;
SWORD ownper;
SWORD ownvol;
UBYTE dca; /* duplicate check action */
UBYTE dct; /* duplicate check type */
UBYTE* row; /* row currently playing on this channel */
SBYTE retrig; /* retrig value (0 means don't retrig) */
ULONG speed; /* what finetune to use */
SWORD volume; /* amiga volume (0 t/m 64) to play the sample at */
SWORD tmpvolume; /* tmp volume */
UWORD tmpperiod; /* tmp period */
UWORD wantedperiod; /* period to slide to (with effect 3 or 5) */
UBYTE arpmem; /* arpeggio command memory */
UBYTE pansspd; /* panslide speed */
UWORD slidespeed;
UWORD portspeed; /* noteslide speed (toneportamento) */
UBYTE s3mtremor; /* s3m tremor (effect I) counter */
UBYTE s3mtronof; /* s3m tremor ontime/offtime */
UBYTE s3mvolslide; /* last used volslide */
SBYTE sliding;
UBYTE s3mrtgspeed; /* last used retrig speed */
UBYTE s3mrtgslide; /* last used retrig slide */
UBYTE glissando; /* glissando (0 means off) */
UBYTE wavecontrol;
SBYTE vibpos; /* current vibrato position */
UBYTE vibspd; /* "" speed */
UBYTE vibdepth; /* "" depth */
SBYTE trmpos; /* current tremolo position */
UBYTE trmspd; /* "" speed */
UBYTE trmdepth; /* "" depth */
UBYTE fslideupspd;
UBYTE fslidednspd;
UBYTE fportupspd; /* fx E1 (extra fine portamento up) data */
UBYTE fportdnspd; /* fx E2 (extra fine portamento dn) data */
UBYTE ffportupspd; /* fx X1 (extra fine portamento up) data */
UBYTE ffportdnspd; /* fx X2 (extra fine portamento dn) data */
ULONG hioffset; /* last used high order of sample offset */
UWORD soffset; /* last used low order of sample-offset (effect 9) */
UBYTE sseffect; /* last used Sxx effect */
UBYTE ssdata; /* last used Sxx data info */
UBYTE chanvolslide; /* last used channel volume slide */
UBYTE panbwave; /* current panbrello waveform */
UBYTE panbpos; /* current panbrello position */
SBYTE panbspd; /* "" speed */
UBYTE panbdepth; /* "" depth */
UWORD newsamp; /* set to 1 upon a sample / inst change */
UBYTE voleffect; /* Volume Column Effect Memory as used by IT */
UBYTE voldata; /* Volume Column Data Memory */
SWORD pat_reppos; /* patternloop position */
UWORD pat_repcnt; /* times to loop */
} MP_CONTROL;
/* Used by NNA only player (audio control. AUDTMP is used for full effects
control). */
typedef struct MP_VOICE {
struct MP_CHANNEL main;
ENVPR venv;
ENVPR penv;
ENVPR cenv;
UWORD avibpos; /* autovibrato pos */
UWORD aswppos; /* autovibrato sweep pos */
ULONG totalvol; /* total volume of channel (before global mixings) */
BOOL mflag;
SWORD masterchn;
UWORD masterperiod;
MP_CONTROL* master; /* index of "master" effects channel */
} MP_VOICE;
/*========== Loaders */
typedef struct MLOADER {
struct MLOADER* next;
CHAR* type;
CHAR* version;
BOOL (*Init)(void);
BOOL (*Test)(void);
BOOL (*Load)(BOOL);
void (*Cleanup)(void);
CHAR* (*LoadTitle)(void);
} MLOADER;
/* internal loader variables */
extern MREADER* modreader;
extern UWORD finetune[16];
extern MODULE of; /* static unimod loading space */
extern UWORD npertab[7*OCTAVE]; /* used by the original MOD loaders */
extern SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
extern UBYTE* poslookup; /* lookup table for pattern jumps after
blank pattern removal */
extern UBYTE poslookupcnt;
extern UWORD* origpositions;
extern BOOL filters; /* resonant filters in use */
extern UBYTE activemacro; /* active midi macro number for Sxx */
extern UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */
extern FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */
extern int* noteindex;
/*========== Internal loader interface */
extern BOOL ReadComment(UWORD);
extern BOOL ReadLinedComment(UWORD,UWORD);
extern BOOL AllocPositions(int);
extern BOOL AllocPatterns(void);
extern BOOL AllocTracks(void);
extern BOOL AllocInstruments(void);
extern BOOL AllocSamples(void);
extern CHAR* DupStr(CHAR*,UWORD,BOOL);
/* loader utility functions */
extern int* AllocLinear(void);
extern void FreeLinear(void);
extern int speed_to_finetune(ULONG,int);
extern void S3MIT_ProcessCmd(UBYTE,UBYTE,unsigned int);
extern void S3MIT_CreateOrders(BOOL);
/* flags for S3MIT_ProcessCmd */
#define S3MIT_OLDSTYLE 1 /* behave as old scream tracker */
#define S3MIT_IT 2 /* behave as impulse tracker */
#define S3MIT_SCREAM 4 /* enforce scream tracker specific limits */
/* used to convert c4spd to linear XM periods (IT and IMF loaders). */
extern UWORD getlinearperiod(UWORD,ULONG);
extern ULONG getfrequency(UWORD,ULONG);
/* loader shared data */
#define STM_NTRACKERS 3
extern CHAR *STM_Signatures[STM_NTRACKERS];
/*========== Player interface */
extern BOOL Player_Init(MODULE*);
extern void Player_Exit(MODULE*);
extern void Player_HandleTick(void);
/*========== Drivers */
/* max. number of handles a driver has to provide. (not strict) */
#define MAXSAMPLEHANDLES 384
/* These variables can be changed at ANY time and results will be immediate */
extern UWORD md_bpm; /* current song / hardware BPM rate */
/* Variables below can be changed via MD_SetNumVoices at any time. However, a
call to MD_SetNumVoicess while the driver is active will cause the sound to
skip slightly. */
extern UBYTE md_numchn; /* number of song + sound effects voices */
extern UBYTE md_sngchn; /* number of song voices */
extern UBYTE md_sfxchn; /* number of sound effects voices */
extern UBYTE md_hardchn; /* number of hardware mixed voices */
extern UBYTE md_softchn; /* number of software mixed voices */
/* This is for use by the hardware drivers only. It points to the registered
tickhandler function. */
extern void (*md_player)(void);
extern SWORD MD_SampleLoad(SAMPLOAD*,int);
extern void MD_SampleUnload(SWORD);
extern ULONG MD_SampleSpace(int);
extern ULONG MD_SampleLength(int,SAMPLE*);
/* uLaw conversion */
extern void unsignedtoulaw(char *,int);
/* Parameter extraction helper */
extern CHAR *MD_GetAtom(CHAR*,CHAR*,BOOL);
/* Internal software mixer stuff */
extern void VC_SetupPointers(void);
extern BOOL VC1_Init(void);
extern BOOL VC2_Init(void);
#if defined(unix) || defined(__APPLE__) && defined(__MACH__)
/* POSIX helper functions */
extern BOOL MD_Access(CHAR *);
extern BOOL MD_DropPrivileges(void);
#endif
/* Macro to define a missing driver, yet allowing binaries to dynamically link
with the library without missing symbol errors */
#define MISSING(a) MDRIVER a = { NULL, NULL, NULL, 0, 0 }
/*========== Prototypes for non-MT safe versions of some public functions */
extern void _mm_registerdriver(struct MDRIVER*);
extern void _mm_registerloader(struct MLOADER*);
extern BOOL MikMod_Active_internal(void);
extern void MikMod_DisableOutput_internal(void);
extern BOOL MikMod_EnableOutput_internal(void);
extern void MikMod_Exit_internal(void);
extern BOOL MikMod_SetNumVoices_internal(int,int);
extern void Player_Exit_internal(MODULE*);
extern void Player_Stop_internal(void);
extern BOOL Player_Paused_internal(void);
extern void Sample_Free_internal(SAMPLE*);
extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG);
extern void Voice_SetFrequency_internal(SBYTE,ULONG);
extern void Voice_SetPanning_internal(SBYTE,ULONG);
extern void Voice_SetVolume_internal(SBYTE,UWORD);
extern void Voice_Stop_internal(SBYTE);
extern BOOL Voice_Stopped_internal(SBYTE);
#ifdef __cplusplus
}
#endif
#endif
/* ex:set ts=4: */

View File

@@ -0,0 +1,368 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_669.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Composer 669 module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
/* header */
typedef struct S69HEADER {
UBYTE marker[2];
CHAR message[108];
UBYTE nos;
UBYTE nop;
UBYTE looporder;
UBYTE orders[0x80];
UBYTE tempos[0x80];
UBYTE breaks[0x80];
} S69HEADER;
/* sample information */
typedef struct S69SAMPLE {
CHAR filename[13];
SLONG length;
SLONG loopbeg;
SLONG loopend;
} S69SAMPLE;
/* encoded note */
typedef struct S69NOTE {
UBYTE a,b,c;
} S69NOTE;
/*========== Loader variables */
/* current pattern */
static S69NOTE* s69pat=NULL;
/* Module header */
static S69HEADER* mh=NULL;
/* file type identification */
static CHAR* S69_Version[]={
"Composer 669",
"Extended 669"
};
/*========== Loader code */
BOOL S69_Test(void)
{
UBYTE buf[0x80];
if(!_mm_read_UBYTES(buf,2,modreader))
return 0;
/* look for id */
if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {
int i;
/* skip song message */
_mm_fseek(modreader,108,SEEK_CUR);
/* sanity checks */
if(_mm_read_UBYTE(modreader) > 64) return 0;
if(_mm_read_UBYTE(modreader) > 128) return 0;
if(_mm_read_UBYTE(modreader) > 127) return 0;
/* check order table */
if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;
for(i=0;i<0x80;i++)
if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0;
/* check tempos table */
if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;
for(i=0;i<0x80;i++)
if((!buf[i])||(buf[i]>32)) return 0;
/* check pattern length table */
if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;
for(i=0;i<0x80;i++)
if(buf[i]>0x3f) return 0;
} else
return 0;
return 1;
}
BOOL S69_Init(void)
{
if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0;
if(!(mh=(S69HEADER *)_mm_malloc(sizeof(S69HEADER)))) return 0;
return 1;
}
void S69_Cleanup(void)
{
_mm_free(s69pat);
_mm_free(mh);
}
static BOOL S69_LoadPatterns(void)
{
int track,row,channel;
UBYTE note,inst,vol,effect,lastfx,lastval;
S69NOTE *cur;
int tracks=0;
if(!AllocPatterns()) return 0;
if(!AllocTracks()) return 0;
for(track=0;track<of.numpat;track++) {
/* set pattern break locations */
of.pattrows[track]=mh->breaks[track]+1;
/* load the 669 pattern */
cur=s69pat;
for(row=0;row<64;row++) {
for(channel=0;channel<8;channel++,cur++) {
cur->a = _mm_read_UBYTE(modreader);
cur->b = _mm_read_UBYTE(modreader);
cur->c = _mm_read_UBYTE(modreader);
}
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
/* translate the pattern */
for(channel=0;channel<8;channel++) {
UniReset();
/* set pattern tempo */
UniPTEffect(0xf,78);
UniPTEffect(0xf,mh->tempos[track]);
lastfx=0xff,lastval=0;
for(row=0;row<=mh->breaks[track];row++) {
int a,b,c;
/* fetch the encoded note */
a=s69pat[(row*8)+channel].a;
b=s69pat[(row*8)+channel].b;
c=s69pat[(row*8)+channel].c;
/* decode it */
note=a>>2;
inst=((a&0x3)<<4)|((b&0xf0)>>4);
vol=b&0xf;
if (a<0xff) {
if (a<0xfe) {
UniInstrument(inst);
UniNote(note+2*OCTAVE);
lastfx=0xff; /* reset background effect memory */
}
UniPTEffect(0xc,vol<<2);
}
if ((c!=0xff)||(lastfx!=0xff)) {
if(c==0xff)
c=lastfx,effect=lastval;
else
effect=c&0xf;
switch(c>>4) {
case 0: /* porta up */
UniPTEffect(0x1,effect);
lastfx=c,lastval=effect;
break;
case 1: /* porta down */
UniPTEffect(0x2,effect);
lastfx=c,lastval=effect;
break;
case 2: /* porta to note */
UniPTEffect(0x3,effect);
lastfx=c,lastval=effect;
break;
case 3: /* frequency adjust */
/* DMP converts this effect to S3M FF1. Why not ? */
UniEffect(UNI_S3MEFFECTF,0xf0|effect);
break;
case 4: /* vibrato */
UniPTEffect(0x4,effect);
lastfx=c,lastval=effect;
break;
case 5: /* set speed */
if (effect)
UniPTEffect(0xf,effect);
else
if(mh->marker[0]!=0x69) {
#ifdef MIKMOD_DEBUG
fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",
track,row,channel);
#endif
}
break;
}
}
UniNewline();
}
if(!(of.tracks[tracks++]=UniDup())) return 0;
}
}
return 1;
}
BOOL S69_Load(BOOL curious)
{
int i;
SAMPLE *current;
S69SAMPLE sample;
/* module header */
_mm_read_UBYTES(mh->marker,2,modreader);
_mm_read_UBYTES(mh->message,108,modreader);
mh->nos=_mm_read_UBYTE(modreader);
mh->nop=_mm_read_UBYTE(modreader);
mh->looporder=_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->orders,0x80,modreader);
for(i=0;i<0x80;i++)
if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) {
_mm_errno=MMERR_NOT_A_MODULE;
return 1;
}
_mm_read_UBYTES(mh->tempos,0x80,modreader);
for(i=0;i<0x80;i++)
if ((!mh->tempos[i])||(mh->tempos[i]>32)) {
_mm_errno=MMERR_NOT_A_MODULE;
return 1;
}
_mm_read_UBYTES(mh->breaks,0x80,modreader);
for(i=0;i<0x80;i++)
if (mh->breaks[i]>0x3f) {
_mm_errno=MMERR_NOT_A_MODULE;
return 1;
}
/* set module variables */
of.initspeed=4;
of.inittempo=78;
of.songname=DupStr(mh->message,36,1);
of.modtype=strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);
of.numchn=8;
of.numpat=mh->nop;
of.numins=of.numsmp=mh->nos;
of.numtrk=of.numchn*of.numpat;
of.flags=UF_XMPERIODS|UF_LINEAR;
for(i= 35;(i>= 0)&&(mh->message[i]==' ');i--) mh->message[i]=0;
for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;
for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;
if((mh->message[0])||(mh->message[36])||(mh->message[72]))
if((of.comment=(CHAR*)_mm_malloc(3*(36+1)+1))) {
strncpy(of.comment,mh->message,36);
strcat(of.comment,"\r");
if (mh->message[36]) strncat(of.comment,mh->message+36,36);
strcat(of.comment,"\r");
if (mh->message[72]) strncat(of.comment,mh->message+72,36);
strcat(of.comment,"\r");
of.comment[3*(36+1)]=0;
}
if(!AllocPositions(0x80)) return 0;
for(i=0;i<0x80;i++) {
if(mh->orders[i]>=mh->nop) break;
of.positions[i]=mh->orders[i];
}
of.numpos=i;
of.reppos=mh->looporder<of.numpos?mh->looporder:0;
if(!AllocSamples()) return 0;
current=of.samples;
for(i=0;i<of.numins;i++) {
/* sample information */
_mm_read_UBYTES((UBYTE*)sample.filename,13,modreader);
sample.length=_mm_read_I_SLONG(modreader);
sample.loopbeg=_mm_read_I_SLONG(modreader);
sample.loopend=_mm_read_I_SLONG(modreader);
if (sample.loopend==0xfffff) sample.loopend=0;
if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
current->samplename=DupStr(sample.filename,13,1);
current->seekpos=0;
current->speed=0;
current->length=sample.length;
current->loopstart=sample.loopbeg;
current->loopend=sample.loopend;
current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0;
current->volume=64;
current++;
}
if(!S69_LoadPatterns()) return 0;
return 1;
}
CHAR *S69_LoadTitle(void)
{
CHAR s[36];
_mm_fseek(modreader,2,SEEK_SET);
if(!_mm_read_UBYTES(s,36,modreader)) return NULL;
return(DupStr(s,36,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_669={
NULL,
"669",
"669 (Composer 669, Unis 669)",
S69_Init,
S69_Test,
S69_Load,
S69_Cleanup,
S69_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,569 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_amf.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
DMP Advanced Module Format loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
typedef struct AMFHEADER {
UBYTE id[3]; /* AMF file marker */
UBYTE version; /* upper major, lower nibble minor version number */
CHAR songname[32]; /* ASCIIZ songname */
UBYTE numsamples; /* number of samples saved */
UBYTE numorders;
UWORD numtracks; /* number of tracks saved */
UBYTE numchannels; /* number of channels used */
SBYTE panpos[32]; /* voice pan positions */
UBYTE songbpm;
UBYTE songspd;
} AMFHEADER;
typedef struct AMFSAMPLE {
UBYTE type;
CHAR samplename[32];
CHAR filename[13];
ULONG offset;
ULONG length;
UWORD c2spd;
UBYTE volume;
ULONG reppos;
ULONG repend;
} AMFSAMPLE;
typedef struct AMFNOTE {
UBYTE note,instr,volume,fxcnt;
UBYTE effect[3];
SBYTE parameter[3];
} AMFNOTE;
/*========== Loader variables */
static AMFHEADER *mh = NULL;
#define AMFTEXTLEN 22
static CHAR AMF_Version[AMFTEXTLEN+1] = "DSMI Module Format 0.0";
static AMFNOTE *track = NULL;
/*========== Loader code */
BOOL AMF_Test(void)
{
UBYTE id[3],ver;
if(!_mm_read_UBYTES(id,3,modreader)) return 0;
if(memcmp(id,"AMF",3)) return 0;
ver=_mm_read_UBYTE(modreader);
if((ver>=10)&&(ver<=14)) return 1;
return 0;
}
BOOL AMF_Init(void)
{
if(!(mh=(AMFHEADER*)_mm_malloc(sizeof(AMFHEADER)))) return 0;
if(!(track=(AMFNOTE*)_mm_calloc(64,sizeof(AMFNOTE)))) return 0;
return 1;
}
void AMF_Cleanup(void)
{
_mm_free(mh);
_mm_free(track);
}
static BOOL AMF_UnpackTrack(MREADER* modreader)
{
ULONG tracksize;
UBYTE row,cmd;
SBYTE arg;
/* empty track */
memset(track,0,64*sizeof(AMFNOTE));
/* read packed track */
if (modreader) {
tracksize=_mm_read_I_UWORD(modreader);
tracksize+=((ULONG)_mm_read_UBYTE(modreader))<<16;
if (tracksize)
while(tracksize--) {
row=_mm_read_UBYTE(modreader);
cmd=_mm_read_UBYTE(modreader);
arg=_mm_read_SBYTE(modreader);
/* unexpected end of track */
if(!tracksize) {
if((row==0xff)&&(cmd==0xff)&&(arg==-1))
break;
/* the last triplet should be FF FF FF, but this is not
always the case... maybe a bug in m2amf ?
else
return 0;
*/
}
/* invalid row (probably unexpected end of row) */
if (row>=64)
return 0;
if (cmd<0x7f) {
/* note, vol */
track[row].note=cmd;
track[row].volume=(UBYTE)arg+1;
} else
if (cmd==0x7f) {
/* duplicate row */
if ((arg<0)&&(row+arg>=0)) {
memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));
}
} else
if (cmd==0x80) {
/* instr */
track[row].instr=arg+1;
} else
if (cmd==0x83) {
/* volume without note */
track[row].volume=(UBYTE)arg+1;
} else
if (cmd==0xff) {
/* apparently, some M2AMF version fail to estimate the
size of the compressed patterns correctly, and end
up with blanks, i.e. dead triplets. Those are marked
with cmd == 0xff. Let's ignore them. */
} else
if(track[row].fxcnt<3) {
/* effect, param */
if(cmd>0x97)
return 0;
track[row].effect[track[row].fxcnt]=cmd&0x7f;
track[row].parameter[track[row].fxcnt]=arg;
track[row].fxcnt++;
} else
return 0;
}
}
return 1;
}
static UBYTE* AMF_ConvertTrack(void)
{
int row,fx4memory=0;
/* convert track */
UniReset();
for (row=0;row<64;row++) {
if (track[row].instr) UniInstrument(track[row].instr-1);
if (track[row].note>OCTAVE) UniNote(track[row].note-OCTAVE);
/* AMF effects */
while(track[row].fxcnt--) {
SBYTE inf=track[row].parameter[track[row].fxcnt];
switch(track[row].effect[track[row].fxcnt]) {
case 1: /* Set speed */
UniEffect(UNI_S3MEFFECTA,inf);
break;
case 2: /* Volume slide */
if(inf) {
UniWriteByte(UNI_S3MEFFECTD);
if (inf>=0)
UniWriteByte((inf&0xf)<<4);
else
UniWriteByte((-inf)&0xf);
}
break;
/* effect 3, set channel volume, done in UnpackTrack */
case 4: /* Porta up/down */
if(inf) {
if(inf>0) {
UniEffect(UNI_S3MEFFECTE,inf);
fx4memory=UNI_S3MEFFECTE;
} else {
UniEffect(UNI_S3MEFFECTF,-inf);
fx4memory=UNI_S3MEFFECTF;
}
} else if(fx4memory)
UniEffect(fx4memory,0);
break;
/* effect 5, "Porta abs", not supported */
case 6: /* Porta to note */
UniEffect(UNI_ITEFFECTG,inf);
break;
case 7: /* Tremor */
UniEffect(UNI_S3MEFFECTI,inf);
break;
case 8: /* Arpeggio */
UniPTEffect(0x0,inf);
break;
case 9: /* Vibrato */
UniPTEffect(0x4,inf);
break;
case 0xa: /* Porta + Volume slide */
UniPTEffect(0x3,0);
if(inf) {
UniWriteByte(UNI_S3MEFFECTD);
if (inf>=0)
UniWriteByte((inf&0xf)<<4);
else
UniWriteByte((-inf)&0xf);
}
break;
case 0xb: /* Vibrato + Volume slide */
UniPTEffect(0x4,0);
if(inf) {
UniWriteByte(UNI_S3MEFFECTD);
if (inf>=0)
UniWriteByte((inf&0xf)<<4);
else
UniWriteByte((-inf)&0xf);
}
break;
case 0xc: /* Pattern break (in hex) */
UniPTEffect(0xd,inf);
break;
case 0xd: /* Pattern jump */
UniPTEffect(0xb,inf);
break;
/* effect 0xe, "Sync", not supported */
case 0xf: /* Retrig */
UniEffect(UNI_S3MEFFECTQ,inf&0xf);
break;
case 0x10: /* Sample offset */
UniPTEffect(0x9,inf);
break;
case 0x11: /* Fine volume slide */
if(inf) {
UniWriteByte(UNI_S3MEFFECTD);
if (inf>=0)
UniWriteByte((inf&0xf)<<4|0xf);
else
UniWriteByte(0xf0|((-inf)&0xf));
}
break;
case 0x12: /* Fine portamento */
if(inf) {
if(inf>0) {
UniEffect(UNI_S3MEFFECTE,0xf0|(inf&0xf));
fx4memory=UNI_S3MEFFECTE;
} else {
UniEffect(UNI_S3MEFFECTF,0xf0|((-inf)&0xf));
fx4memory=UNI_S3MEFFECTF;
}
} else if(fx4memory)
UniEffect(fx4memory,0);
break;
case 0x13: /* Delay note */
UniPTEffect(0xe,0xd0|(inf&0xf));
break;
case 0x14: /* Note cut */
UniPTEffect(0xc,0);
track[row].volume=0;
break;
case 0x15: /* Set tempo */
UniEffect(UNI_S3MEFFECTT,inf);
break;
case 0x16: /* Extra fine portamento */
if(inf) {
if(inf>0) {
UniEffect(UNI_S3MEFFECTE,0xe0|((inf>>2)&0xf));
fx4memory=UNI_S3MEFFECTE;
} else {
UniEffect(UNI_S3MEFFECTF,0xe0|(((-inf)>>2)&0xf));
fx4memory=UNI_S3MEFFECTF;
}
} else if(fx4memory)
UniEffect(fx4memory,0);
break;
case 0x17: /* Panning */
if (inf>64)
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
else
UniPTEffect(0x8,(inf==64)?255:(inf+64)<<1);
of.flags |= UF_PANNING;
break;
}
}
if (track[row].volume) UniVolEffect(VOL_VOLUME,track[row].volume-1);
UniNewline();
}
return UniDup();
}
BOOL AMF_Load(BOOL curious)
{
int t,u,realtrackcnt,realsmpcnt,defaultpanning;
AMFSAMPLE s;
SAMPLE *q;
UWORD *track_remap;
ULONG samplepos;
int channel_remap[16];
/* try to read module header */
_mm_read_UBYTES(mh->id,3,modreader);
mh->version =_mm_read_UBYTE(modreader);
_mm_read_string(mh->songname,32,modreader);
mh->numsamples =_mm_read_UBYTE(modreader);
mh->numorders =_mm_read_UBYTE(modreader);
mh->numtracks =_mm_read_I_UWORD(modreader);
mh->numchannels =_mm_read_UBYTE(modreader);
if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(mh->version>=11) {
memset(mh->panpos,0,32);
_mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
} else
_mm_read_UBYTES(channel_remap,16,modreader);
if (mh->version>=13) {
mh->songbpm=_mm_read_UBYTE(modreader);
if(mh->songbpm<32) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
mh->songspd=_mm_read_UBYTE(modreader);
if(mh->songspd>32) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
} else {
mh->songbpm=125;
mh->songspd=6;
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = mh->songspd;
of.inittempo = mh->songbpm;
AMF_Version[AMFTEXTLEN-3]='0'+(mh->version/10);
AMF_Version[AMFTEXTLEN-1]='0'+(mh->version%10);
of.modtype = strdup(AMF_Version);
of.numchn = mh->numchannels;
of.numtrk = mh->numorders*mh->numchannels;
if (mh->numtracks>of.numtrk)
of.numtrk=mh->numtracks;
of.numtrk++; /* add room for extra, empty track */
of.songname = DupStr(mh->songname,32,1);
of.numpos = mh->numorders;
of.numpat = mh->numorders;
of.reppos = 0;
of.flags |= UF_S3MSLIDES;
/* XXX whenever possible, we should try to determine the original format.
Here we assume it was S3M-style wrt bpmlimit... */
of.bpmlimit = 32;
/*
* Play with the panning table. Although the AMF format embeds a
* panning table, if the module was a MOD or an S3M with default
* panning and didn't use any panning commands, don't flag
* UF_PANNING, to use our preferred panning table for this case.
*/
defaultpanning = 1;
for (t = 0; t < 32; t++) {
if (mh->panpos[t] > 64) {
of.panning[t] = PAN_SURROUND;
defaultpanning = 0;
} else
if (mh->panpos[t] == 64)
of.panning[t] = PAN_RIGHT;
else
of.panning[t] = (mh->panpos[t] + 64) << 1;
}
if (defaultpanning) {
for (t = 0; t < of.numchn; t++)
if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {
defaultpanning = 0; /* not MOD canonical panning */
break;
}
}
if (defaultpanning)
of.flags |= UF_PANNING;
of.numins=of.numsmp=mh->numsamples;
if(!AllocPositions(of.numpos)) return 0;
for(t=0;t<of.numpos;t++)
of.positions[t]=t;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
/* read AMF order table */
for (t=0;t<of.numpat;t++) {
if (mh->version>=14)
/* track size */
of.pattrows[t]=_mm_read_I_UWORD(modreader);
if (mh->version>=10)
_mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);
else
for(u=0;u<of.numchn;u++)
of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* read sample information */
if(!AllocSamples()) return 0;
q=of.samples;
for(t=0;t<of.numins;t++) {
/* try to read sample info */
s.type=_mm_read_UBYTE(modreader);
_mm_read_string(s.samplename,32,modreader);
_mm_read_string(s.filename,13,modreader);
s.offset =_mm_read_I_ULONG(modreader);
s.length =_mm_read_I_ULONG(modreader);
s.c2spd =_mm_read_I_UWORD(modreader);
if(s.c2spd==8368) s.c2spd=8363;
s.volume =_mm_read_UBYTE(modreader);
if(mh->version>=11) {
s.reppos =_mm_read_I_ULONG(modreader);
s.repend =_mm_read_I_ULONG(modreader);
} else {
s.reppos =_mm_read_I_UWORD(modreader);
s.repend =s.length;
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->samplename = DupStr(s.samplename,32,1);
q->speed = s.c2spd;
q->volume = s.volume;
if (s.type) {
q->seekpos = s.offset;
q->length = s.length;
q->loopstart = s.reppos;
q->loopend = s.repend;
if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;
}
q++;
}
/* read track table */
if(!(track_remap=_mm_calloc(mh->numtracks+1,sizeof(UWORD))))
return 0;
_mm_read_I_UWORDS(track_remap+1,mh->numtracks,modreader);
if(_mm_eof(modreader)) {
free(track_remap);
_mm_errno=MMERR_LOADING_TRACK;
return 0;
}
for(realtrackcnt=t=0;t<=mh->numtracks;t++)
if (realtrackcnt<track_remap[t])
realtrackcnt=track_remap[t];
for(t=0;t<of.numpat*of.numchn;t++)
of.patterns[t]=(of.patterns[t]<=mh->numtracks)?
track_remap[of.patterns[t]]-1:realtrackcnt;
free(track_remap);
/* unpack tracks */
for(t=0;t<realtrackcnt;t++) {
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_TRACK;
return 0;
}
if (!AMF_UnpackTrack(modreader)) {
_mm_errno = MMERR_LOADING_TRACK;
return 0;
}
if(!(of.tracks[t]=AMF_ConvertTrack()))
return 0;
}
/* add an extra void track */
UniReset();
for(t=0;t<64;t++) UniNewline();
of.tracks[realtrackcnt++]=UniDup();
for(t=realtrackcnt;t<of.numtrk;t++) of.tracks[t]=NULL;
/* compute sample offsets */
samplepos=_mm_ftell(modreader);
for(realsmpcnt=t=0;t<of.numsmp;t++)
if(realsmpcnt<of.samples[t].seekpos)
realsmpcnt=of.samples[t].seekpos;
for(t=1;t<=realsmpcnt;t++) {
q=of.samples;
while(q->seekpos!=t) q++;
q->seekpos=samplepos;
samplepos+=q->length;
}
return 1;
}
CHAR *AMF_LoadTitle(void)
{
CHAR s[32];
_mm_fseek(modreader,4,SEEK_SET);
if(!_mm_read_UBYTES(s,32,modreader)) return NULL;
return(DupStr(s,32,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_amf={
NULL,
"AMF",
"AMF (DSMI Advanced Module Format)",
AMF_Init,
AMF_Test,
AMF_Load,
AMF_Cleanup,
AMF_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,398 @@
/* MikMod sound library
(c) 2004, Raphael Assenat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_asy.c,v 1.3 2004/01/28 01:18:22 raph Exp $
ASYLUM Music Format v1.0 (.amf) loader
adapted from load_mod.c by Raphael Assenat <raph@raphnet.net>,
with the help of the AMF2MOD utility sourcecode,
written to convert crusader's amf files into 8
channels mod file in 1995 by Mr. P / Powersource
mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#include <string.h>
#include "mikmod_internals.h"
/*========== Module structure */
typedef struct MSAMPINFO {
CHAR samplename[24];
UBYTE finetune;
UBYTE volume;
ULONG length;
ULONG reppos;
ULONG replen;
} MSAMPINFO;
typedef struct MODULEHEADER {
CHAR songname[21];
UBYTE num_patterns; /* number of patterns used */
UBYTE num_orders;
UBYTE positions[256]; /* which pattern to play at pos */
MSAMPINFO samples[64]; /* all sampleinfo */
} MODULEHEADER;
typedef struct MODTYPE {
CHAR id[5];
UBYTE channels;
CHAR *name;
} MODTYPE;
typedef struct MODNOTE {
UBYTE a, b, c, d;
} MODNOTE;
/* This table is taken from AMF2MOD.C
* written in 1995 by Mr. P / Powersource
* mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca */
UWORD periodtable[]={6848,6464,6096,5760,5424,5120,4832,4560,4304,
4064,3840,3628,3424,3232,3048,2880,2712,2560,
2416,2280,2152,2032,1920,1814,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};
/*========== Loader variables */
static CHAR asylum[] = "Asylum 1.0";
static MODULEHEADER *mh = NULL;
static MODNOTE *patbuf = NULL;
static int modtype = 0;
/*========== Loader code */
static BOOL ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
{
if (!memcmp(id, "ASYLUM Music Format V1.0", 24))
{
*descr = asylum;
*numchn = 8;
modtype = 1;
return 1;
}
return 0;
}
static BOOL ASY_Test(void)
{
UBYTE namestring[24], numchn;
CHAR *descr;
/* Read the magic string */
_mm_fseek(modreader, 0, SEEK_SET);
if (!_mm_read_UBYTES(namestring, 24, modreader))
return 0;
/* Test if the string is what we expect */
if (ASY_CheckType(namestring, &numchn, &descr))
return 1;
return 0;
}
static BOOL ASY_Init(void)
{
if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))
return 0;
return 1;
}
static void ASY_Cleanup(void)
{
_mm_free(mh);
_mm_free(patbuf);
}
static void ConvertNote(MODNOTE *n)
{
UBYTE instrument, effect, effdat, note;
UWORD period;
UBYTE lastnote = 0;
instrument = n->b&0x1f;
effect = n->c;
effdat = n->d;
/* convert amf note to mod period */
if (n->a) {
period = periodtable[n->a];
} else {
period = 0;
}
/* Convert the period to a note number */
note = 0;
if (period)
{
for (note = 0; note < 7 * OCTAVE; note++)
if (period >= npertab[note])
break;
if (note == 7 * OCTAVE)
note = 0;
else
note++;
}
if (instrument) {
/* if instrument does not exist, note cut */
if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
UniPTEffect(0xc, 0);
if (effect == 0xc)
effect = effdat = 0;
} else {
/* Protracker handling */
if (!modtype) {
/* if we had a note, then change instrument...*/
if (note)
UniInstrument(instrument - 1);
/* ...otherwise, only adjust volume... */
else {
/* ...unless an effect was specified,
* which forces a new note to be
* played */
if (effect || effdat) {
UniInstrument(instrument - 1);
note = lastnote;
} else
UniPTEffect(0xc,
mh->samples[instrument -
1].volume & 0x7f);
}
} else {
/* Fasttracker handling */
UniInstrument(instrument - 1);
if (!note)
note = lastnote;
}
}
}
if (note) {
UniNote(note + 2 * OCTAVE - 1);
lastnote = note;
}
/* Convert pattern jump from Dec to Hex */
if (effect == 0xd)
effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);
/* Volume slide, up has priority */
if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
effdat &= 0xf0;
UniPTEffect(effect, effdat);
}
static UBYTE *ConvertTrack(MODNOTE *n)
{
int t;
UniReset();
for (t = 0; t < 64; t++) {
ConvertNote(n);
UniNewline();
n += of.numchn;
}
return UniDup();
}
/* Loads all patterns of a modfile and converts them into the 3 byte format. */
static BOOL ML_LoadPatterns(void)
{
int t, s, tracks = 0;
if (!AllocPatterns()) {
return 0;
}
if (!AllocTracks()) {
return 0;
}
/* Allocate temporary buffer for loading and converting the patterns */
if (!(patbuf = (MODNOTE *)_mm_calloc(64U * of.numchn, sizeof(MODNOTE))))
return 0;
/* patterns start here */
_mm_fseek(modreader, 0xA66, SEEK_SET);
for (t = 0; t < of.numpat; t++) {
/* Load the pattern into the temp buffer and convert it */
for (s = 0; s < (64U * of.numchn); s++) {
patbuf[s].a = _mm_read_UBYTE(modreader);
patbuf[s].b = _mm_read_UBYTE(modreader);
patbuf[s].c = _mm_read_UBYTE(modreader);
patbuf[s].d = _mm_read_UBYTE(modreader);
}
for (s = 0; s < of.numchn; s++) {
if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) {
return 0;
}
}
}
return 1;
}
static BOOL ASY_Load(BOOL curious)
{
int t;
SAMPLE *q;
MSAMPINFO *s;
CHAR *descr=asylum;
ULONG seekpos;
// no title in asylum amf files :(
strcpy(mh->songname, "");
_mm_fseek(modreader, 0x23, SEEK_SET);
mh->num_patterns = _mm_read_UBYTE(modreader);
mh->num_orders = _mm_read_UBYTE(modreader);
// skip unknown byte
_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->positions, 256, modreader);
/* read samples headers*/
for (t = 0; t < 64; t++) {
s = &mh->samples[t];
_mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
_mm_read_string(s->samplename, 22, modreader);
s->samplename[21] = 0; /* just in case */
s->finetune = _mm_read_UBYTE(modreader);
s->volume = _mm_read_UBYTE(modreader);
_mm_read_UBYTE(modreader); // skip unknown byte
s->length = _mm_read_I_ULONG(modreader);
s->reppos = _mm_read_I_ULONG(modreader);
s->replen = _mm_read_I_ULONG(modreader);
}
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = 6;
of.inittempo = 125;
of.numchn = 8;
modtype = 0;
of.songname = DupStr(mh->songname, 21, 1);
of.numpos = mh->num_orders;
of.reppos = 0;
of.numpat = mh->num_patterns;
of.numtrk = of.numpat * of.numchn;
/* Copy positions (orders) */
if (!AllocPositions(of.numpos))
return 0;
for (t = 0; t < of.numpos; t++) {
of.positions[t] = mh->positions[t];
}
/* Finally, init the sampleinfo structures */
of.numins = 31;
of.numsmp = 31;
if (!AllocSamples())
return 0;
s = mh->samples;
q = of.samples;
seekpos = 2662+(2048*(of.numpat));
for (t = 0; t < of.numins; t++) {
/* convert the samplename */
q->samplename = DupStr(s->samplename, 23, 1);
/* init the sampleinfo variables */
q->speed = finetune[s->finetune & 0xf];
q->volume = s->volume & 0x7f;
q->loopstart = (ULONG)s->reppos;
q->loopend = (ULONG)q->loopstart + (s->replen);
q->length = (ULONG)s->length;
q->flags = SF_SIGNED;
q->seekpos = seekpos;
seekpos += q->length;
if ((s->replen) > 2) {
q->flags |= SF_LOOP;
}
/* fix replen if repend > length */
if (q->loopend > q->length)
q->loopend = q->length;
s++;
q++;
}
of.modtype = strdup(descr);
if (!ML_LoadPatterns())
return 0;
return 1;
}
static CHAR *ASY_LoadTitle(void)
{
CHAR *s = ""; // no titles
return (DupStr(s, 21, 1));
}
/*========== Loader information */
MLOADER load_asy = {
NULL,
"AMF",
"AMF (ASYLUM Music Format V1.0)",
ASY_Init,
ASY_Test,
ASY_Load,
ASY_Cleanup,
ASY_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,364 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_dsm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
DSIK internal format (DSM) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
#define DSM_MAXCHAN (16)
#define DSM_MAXORDERS (128)
typedef struct DSMSONG {
CHAR songname[28];
UWORD version;
UWORD flags;
ULONG reserved2;
UWORD numord;
UWORD numsmp;
UWORD numpat;
UWORD numtrk;
UBYTE globalvol;
UBYTE mastervol;
UBYTE speed;
UBYTE bpm;
UBYTE panpos[DSM_MAXCHAN];
UBYTE orders[DSM_MAXORDERS];
} DSMSONG;
typedef struct DSMINST {
CHAR filename[13];
UWORD flags;
UBYTE volume;
ULONG length;
ULONG loopstart;
ULONG loopend;
ULONG reserved1;
UWORD c2spd;
UWORD period;
CHAR samplename[28];
} DSMINST;
typedef struct DSMNOTE {
UBYTE note,ins,vol,cmd,inf;
} DSMNOTE;
#define DSM_SURROUND (0xa4)
/*========== Loader variables */
static CHAR* SONGID="SONG";
static CHAR* INSTID="INST";
static CHAR* PATTID="PATT";
static UBYTE blockid[4];
static ULONG blockln;
static ULONG blocklp;
static DSMSONG* mh=NULL;
static DSMNOTE* dsmbuf=NULL;
static CHAR DSM_Version[]="DSIK DSM-format";
static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};
/*========== Loader code */
BOOL DSM_Test(void)
{
UBYTE id[12];
if(!_mm_read_UBYTES(id,12,modreader)) return 0;
if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1;
return 0;
}
BOOL DSM_Init(void)
{
if(!(dsmbuf=(DSMNOTE *)_mm_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0;
if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0;
return 1;
}
void DSM_Cleanup(void)
{
_mm_free(dsmbuf);
_mm_free(mh);
}
static BOOL GetBlockHeader(void)
{
/* make sure we're at the right position for reading the
next riff block, no matter how many bytes read */
_mm_fseek(modreader, blocklp+blockln, SEEK_SET);
while(1) {
_mm_read_UBYTES(blockid,4,modreader);
blockln=_mm_read_I_ULONG(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) &&
memcmp(blockid,PATTID,4)) {
#ifdef MIKMOD_DEBUG
fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid);
#endif
_mm_fseek(modreader, blockln, SEEK_CUR);
} else
break;
}
blocklp = _mm_ftell(modreader);
return 1;
}
static BOOL DSM_ReadPattern(void)
{
int flag,row=0;
SWORD length;
DSMNOTE *n;
/* clear pattern data */
memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE));
length=_mm_read_I_SWORD(modreader);
while(row<64) {
flag=_mm_read_UBYTE(modreader);
if((_mm_eof(modreader))||(--length<0)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
if(flag) {
n=&dsmbuf[((flag&0xf)*64)+row];
if(flag&0x80) n->note=_mm_read_UBYTE(modreader);
if(flag&0x40) n->ins=_mm_read_UBYTE(modreader);
if(flag&0x20) n->vol=_mm_read_UBYTE(modreader);
if(flag&0x10) {
n->cmd=_mm_read_UBYTE(modreader);
n->inf=_mm_read_UBYTE(modreader);
}
} else
row++;
}
return 1;
}
static UBYTE *DSM_ConvertTrack(DSMNOTE *tr)
{
int t;
UBYTE note,ins,vol,cmd,inf;
UniReset();
for(t=0;t<64;t++) {
note=tr[t].note;
ins=tr[t].ins;
vol=tr[t].vol;
cmd=tr[t].cmd;
inf=tr[t].inf;
if(ins!=0 && ins!=255) UniInstrument(ins-1);
if(note!=255) UniNote(note-1); /* normal note */
if(vol<65) UniPTEffect(0xc,vol);
if(cmd!=255) {
if(cmd==0x8) {
if(inf==DSM_SURROUND)
UniEffect(UNI_ITEFFECTS0,0x91);
else
if(inf<=0x80) {
inf=(inf<0x80)?inf<<1:255;
UniPTEffect(cmd,inf);
}
} else
if(cmd==0xb) {
if(inf<=0x7f) UniPTEffect(cmd,inf);
} else {
/* Convert pattern jump from Dec to Hex */
if(cmd == 0xd)
inf = (((inf&0xf0)>>4)*10)+(inf&0xf);
UniPTEffect(cmd,inf);
}
}
UniNewline();
}
return UniDup();
}
BOOL DSM_Load(BOOL curious)
{
int t;
DSMINST s;
SAMPLE *q;
int cursmp=0,curpat=0,track=0;
blocklp=0;
blockln=12;
if(!GetBlockHeader()) return 0;
if(memcmp(blockid,SONGID,4)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
_mm_read_UBYTES(mh->songname,28,modreader);
mh->version=_mm_read_I_UWORD(modreader);
mh->flags=_mm_read_I_UWORD(modreader);
mh->reserved2=_mm_read_I_ULONG(modreader);
mh->numord=_mm_read_I_UWORD(modreader);
mh->numsmp=_mm_read_I_UWORD(modreader);
mh->numpat=_mm_read_I_UWORD(modreader);
mh->numtrk=_mm_read_I_UWORD(modreader);
mh->globalvol=_mm_read_UBYTE(modreader);
mh->mastervol=_mm_read_UBYTE(modreader);
mh->speed=_mm_read_UBYTE(modreader);
mh->bpm=_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader);
_mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader);
/* set module variables */
of.initspeed=mh->speed;
of.inittempo=mh->bpm;
of.modtype=strdup(DSM_Version);
of.numchn=mh->numtrk;
of.numpat=mh->numpat;
of.numtrk=of.numchn*of.numpat;
of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */
of.reppos=0;
of.flags |= UF_PANNING;
/* XXX whenever possible, we should try to determine the original format.
Here we assume it was S3M-style wrt bpmlimit... */
of.bpmlimit = 32;
for(t=0;t<DSM_MAXCHAN;t++)
of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND:
mh->panpos[t]<0x80?(mh->panpos[t]<<1):255;
if(!AllocPositions(mh->numord)) return 0;
of.numpos=0;
for(t=0;t<mh->numord;t++) {
int order=mh->orders[t];
if(order==255) order=LAST_PATTERN;
of.positions[of.numpos]=order;
if(mh->orders[t]<254) of.numpos++;
}
of.numins=of.numsmp=mh->numsmp;
if(!AllocSamples()) return 0;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
while(cursmp<of.numins||curpat<of.numpat) {
if(!GetBlockHeader()) return 0;
if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) {
q=&of.samples[cursmp];
/* try to read sample info */
_mm_read_UBYTES(s.filename,13,modreader);
s.flags=_mm_read_I_UWORD(modreader);
s.volume=_mm_read_UBYTE(modreader);
s.length=_mm_read_I_ULONG(modreader);
s.loopstart=_mm_read_I_ULONG(modreader);
s.loopend=_mm_read_I_ULONG(modreader);
s.reserved1=_mm_read_I_ULONG(modreader);
s.c2spd=_mm_read_I_UWORD(modreader);
s.period=_mm_read_I_UWORD(modreader);
_mm_read_UBYTES(s.samplename,28,modreader);
q->samplename=DupStr(s.samplename,28,1);
q->seekpos=_mm_ftell(modreader);
q->speed=s.c2spd;
q->length=s.length;
q->loopstart=s.loopstart;
q->loopend=s.loopend;
q->volume=s.volume;
if(s.flags&1) q->flags|=SF_LOOP;
if(s.flags&2) q->flags|=SF_SIGNED;
/* (s.flags&4) means packed sample,
but did they really exist in dsm ?*/
cursmp++;
} else
if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) {
DSM_ReadPattern();
for(t=0;t<of.numchn;t++)
if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0;
curpat++;
}
}
return 1;
}
CHAR *DSM_LoadTitle(void)
{
CHAR s[28];
_mm_fseek(modreader,12,SEEK_SET);
if(!_mm_read_UBYTES(s,28,modreader)) return NULL;
return(DupStr(s,28,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_dsm={
NULL,
"DSM",
"DSM (DSIK internal format)",
DSM_Init,
DSM_Test,
DSM_Load,
DSM_Cleanup,
DSM_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,346 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_far.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Farandole (FAR) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
typedef struct FARHEADER1 {
UBYTE id[4]; /* file magic */
CHAR songname[40]; /* songname */
CHAR blah[3]; /* 13,10,26 */
UWORD headerlen; /* remaining length of header in bytes */
UBYTE version;
UBYTE onoff[16];
UBYTE edit1[9];
UBYTE speed;
UBYTE panning[16];
UBYTE edit2[4];
UWORD stlen;
} FARHEADER1;
typedef struct FARHEADER2 {
UBYTE orders[256];
UBYTE numpat;
UBYTE snglen;
UBYTE loopto;
UWORD patsiz[256];
} FARHEADER2;
typedef struct FARSAMPLE {
CHAR samplename[32];
ULONG length;
UBYTE finetune;
UBYTE volume;
ULONG reppos;
ULONG repend;
UBYTE type;
UBYTE loop;
} FARSAMPLE;
typedef struct FARNOTE {
UBYTE note,ins,vol,eff;
} FARNOTE;
/*========== Loader variables */
static CHAR FAR_Version[] = "Farandole";
static FARHEADER1 *mh1 = NULL;
static FARHEADER2 *mh2 = NULL;
static FARNOTE *pat = NULL;
static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};
/*========== Loader code */
BOOL FAR_Test(void)
{
UBYTE id[47];
if(!_mm_read_UBYTES(id,47,modreader)) return 0;
if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0;
return 1;
}
BOOL FAR_Init(void)
{
if(!(mh1 = (FARHEADER1*)_mm_malloc(sizeof(FARHEADER1)))) return 0;
if(!(mh2 = (FARHEADER2*)_mm_malloc(sizeof(FARHEADER2)))) return 0;
if(!(pat = (FARNOTE*)_mm_malloc(256*16*4*sizeof(FARNOTE)))) return 0;
return 1;
}
void FAR_Cleanup(void)
{
_mm_free(mh1);
_mm_free(mh2);
_mm_free(pat);
}
static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
{
int t,vibdepth=1;
UniReset();
for(t=0;t<rows;t++) {
if(n->note) {
UniInstrument(n->ins);
UniNote(n->note+3*OCTAVE-1);
}
if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);
if (n->eff)
switch(n->eff>>4) {
case 0x3: /* porta to note */
UniPTEffect(0x3,(n->eff&0xf)<<4);
break;
case 0x4: /* retrigger */
UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));
break;
case 0x5: /* set vibrato depth */
vibdepth=n->eff&0xf;
break;
case 0x6: /* vibrato */
UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);
break;
case 0x7: /* volume slide up */
UniPTEffect(0xa,(n->eff&0xf)<<4);
break;
case 0x8: /* volume slide down */
UniPTEffect(0xa,n->eff&0xf);
break;
case 0xb: /* panning */
UniPTEffect(0xe,0x80|(n->eff&0xf));
break;
case 0xf: /* set speed */
UniPTEffect(0xf,n->eff&0xf);
break;
/* others not yet implemented */
default:
#ifdef MIKMOD_DEBUG
fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff);
#endif
break;
}
UniNewline();
n+=16;
}
return UniDup();
}
BOOL FAR_Load(BOOL curious)
{
int t,u,tracks=0;
SAMPLE *q;
FARSAMPLE s;
FARNOTE *crow;
UBYTE smap[8];
/* try to read module header (first part) */
_mm_read_UBYTES(mh1->id,4,modreader);
_mm_read_SBYTES(mh1->songname,40,modreader);
_mm_read_SBYTES(mh1->blah,3,modreader);
mh1->headerlen = _mm_read_I_UWORD (modreader);
mh1->version = _mm_read_UBYTE (modreader);
_mm_read_UBYTES(mh1->onoff,16,modreader);
_mm_read_UBYTES(mh1->edit1,9,modreader);
mh1->speed = _mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh1->panning,16,modreader);
_mm_read_UBYTES(mh1->edit2,4,modreader);
mh1->stlen = _mm_read_I_UWORD (modreader);
/* init modfile data */
of.modtype = strdup(FAR_Version);
of.songname = DupStr(mh1->songname,40,1);
of.numchn = 16;
of.initspeed = mh1->speed;
of.inittempo = 80;
of.reppos = 0;
of.flags |= UF_PANNING;
for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;
/* read songtext into comment field */
if(mh1->stlen)
if (!ReadLinedComment(mh1->stlen, 66)) return 0;
/* try to read module header (second part) */
_mm_read_UBYTES(mh2->orders,256,modreader);
mh2->numpat = _mm_read_UBYTE(modreader);
mh2->snglen = _mm_read_UBYTE(modreader);
mh2->loopto = _mm_read_UBYTE(modreader);
_mm_read_I_UWORDS(mh2->patsiz,256,modreader);
of.numpos = mh2->snglen;
if(!AllocPositions(of.numpos)) return 0;
for(t=0;t<of.numpos;t++) {
if(mh2->orders[t]==0xff) break;
of.positions[t] = mh2->orders[t];
}
/* count number of patterns stored in file */
of.numpat = 0;
for(t=0;t<256;t++)
if(mh2->patsiz[t])
if((t+1)>of.numpat) of.numpat=t+1;
of.numtrk = of.numpat*of.numchn;
/* seek across eventual new data */
_mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR);
/* alloc track and pattern structures */
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
for(t=0;t<of.numpat;t++) {
UBYTE rows=0,tempo;
memset(pat,0,256*16*4*sizeof(FARNOTE));
if(mh2->patsiz[t]) {
rows = _mm_read_UBYTE(modreader);
tempo = _mm_read_UBYTE(modreader);
crow = pat;
/* file often allocates 64 rows even if there are less in pattern */
if (mh2->patsiz[t]<2+(rows*16*4)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) {
crow->note = _mm_read_UBYTE(modreader);
crow->ins = _mm_read_UBYTE(modreader);
crow->vol = _mm_read_UBYTE(modreader);
crow->eff = _mm_read_UBYTE(modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
crow=pat;
of.pattrows[t] = rows;
for(u=16;u;u--,crow++)
if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
} else
tracks+=16;
}
/* read sample map */
if(!_mm_read_UBYTES(smap,8,modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* count number of samples used */
of.numins = 0;
for(t=0;t<64;t++)
if(smap[t>>3]&(1<<(t&7))) of.numins=t+1;
of.numsmp = of.numins;
/* alloc sample structs */
if(!AllocSamples()) return 0;
q = of.samples;
for(t=0;t<of.numsmp;t++) {
q->speed = 8363;
q->flags = SF_SIGNED;
if(smap[t>>3]&(1<<(t&7))) {
_mm_read_SBYTES(s.samplename,32,modreader);
s.length = _mm_read_I_ULONG(modreader);
s.finetune = _mm_read_UBYTE(modreader);
s.volume = _mm_read_UBYTE(modreader);
s.reppos = _mm_read_I_ULONG(modreader);
s.repend = _mm_read_I_ULONG(modreader);
s.type = _mm_read_UBYTE(modreader);
s.loop = _mm_read_UBYTE(modreader);
q->samplename = DupStr(s.samplename,32,1);
q->length = s.length;
q->loopstart = s.reppos;
q->loopend = s.repend;
q->volume = s.volume<<2;
if(s.type&1) q->flags|=SF_16BITS;
if(s.loop&8) q->flags|=SF_LOOP;
q->seekpos = _mm_ftell(modreader);
_mm_fseek(modreader,q->length,SEEK_CUR);
} else
q->samplename = DupStr(NULL,0,0);
q++;
}
return 1;
}
CHAR *FAR_LoadTitle(void)
{
CHAR s[40];
_mm_fseek(modreader,4,SEEK_SET);
if(!_mm_read_UBYTES(s,40,modreader)) return NULL;
return(DupStr(s,40,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_far={
NULL,
"FAR",
"FAR (Farandole Composer)",
FAR_Init,
FAR_Test,
FAR_Load,
FAR_Cleanup,
FAR_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,558 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software;you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation;either version 2 of
the License,or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY;without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library;if not,write to the Free Software
Foundation,Inc.,59 Temple Place - Suite 330,Boston,MA
02111-1307,USA.
*/
/*==============================================================================
$Id: load_gdm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
General DigiMusic (GDM) module loader
==============================================================================*/
/*
Written by Kev Vance<kvance@zeux.org>
based on the file format description written by 'MenTaLguY'
<mental@kludge.org>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
typedef struct GDMNOTE {
UBYTE note;
UBYTE samp;
struct {
UBYTE effect;
UBYTE param;
} effect[4];
} GDMNOTE;
typedef GDMNOTE GDMTRACK[64];
typedef struct GDMHEADER {
CHAR id1[4];
CHAR songname[32];
CHAR author[32];
CHAR eofmarker[3];
CHAR id2[4];
UBYTE majorver;
UBYTE minorver;
UWORD trackerid;
UBYTE t_majorver;
UBYTE t_minorver;
UBYTE pantable[32];
UBYTE mastervol;
UBYTE mastertempo;
UBYTE masterbpm;
UWORD flags;
ULONG orderloc;
UBYTE ordernum;
ULONG patternloc;
UBYTE patternnum;
ULONG samhead;
ULONG samdata;
UBYTE samnum;
ULONG messageloc;
ULONG messagelen;
ULONG scrollyloc;
UWORD scrollylen;
ULONG graphicloc;
UWORD graphiclen;
} GDMHEADER;
typedef struct GDMSAMPLE {
CHAR sampname[32];
CHAR filename[13];
UBYTE ems;
ULONG length;
ULONG loopbeg;
ULONG loopend;
UBYTE flags;
UWORD c4spd;
UBYTE vol;
UBYTE pan;
} GDMSAMPLE;
static GDMHEADER *mh=NULL; /* pointer to GDM header */
static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */
CHAR GDM_Version[]="General DigiMusic 1.xx";
BOOL GDM_Test(void)
{
/* test for gdm magic numbers */
UBYTE id[4];
_mm_fseek(modreader,0x00,SEEK_SET);
if (!_mm_read_UBYTES(id,4,modreader))
return 0;
if (!memcmp(id,"GDM\xfe",4)) {
_mm_fseek(modreader,71,SEEK_SET);
if (!_mm_read_UBYTES(id,4,modreader))
return 0;
if (!memcmp(id,"GMFS",4))
return 1;
}
return 0;
}
BOOL GDM_Init(void)
{
if (!(gdmbuf=(GDMNOTE*)_mm_malloc(32*64*sizeof(GDMNOTE)))) return 0;
if (!(mh=(GDMHEADER*)_mm_malloc(sizeof(GDMHEADER)))) return 0;
return 1;
}
void GDM_Cleanup(void)
{
_mm_free(mh);
_mm_free(gdmbuf);
}
BOOL GDM_ReadPattern(void)
{
int pos,flag,ch,i,maxch;
GDMNOTE n;
UWORD length,x=0;
/* get pattern length */
length=_mm_read_I_UWORD(modreader)-2;
/* clear pattern data */
memset(gdmbuf,255,32*64*sizeof(GDMNOTE));
pos=0;
maxch=0;
while (x<length) {
memset(&n,255,sizeof(GDMNOTE));
flag=_mm_read_UBYTE(modreader);
x++;
if (_mm_eof(modreader)) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
ch=flag&31;
if (ch>maxch) maxch=ch;
if (!flag) {
pos++;
continue;
}
if (flag&0x60) {
if (flag&0x20) {
/* new note */
n.note=_mm_read_UBYTE(modreader)&127;
n.samp=_mm_read_UBYTE(modreader);
x +=2;
}
if (flag&0x40) {
do {
/* effect channel set */
i=_mm_read_UBYTE(modreader);
n.effect[i>>6].effect=i&31;
n.effect[i>>6].param=_mm_read_UBYTE(modreader);
x +=2;
} while (i&32);
}
memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE));
}
}
return 1;
}
UBYTE *GDM_ConvertTrack(GDMNOTE*tr)
{
int t,i=0;
UBYTE note,ins,inf;
UniReset();
for (t=0;t<64;t++) {
note=tr[t].note;
ins=tr[t].samp;
if ((ins)&&(ins!=255))
UniInstrument(ins-1);
if (note!=255) {
UniNote(((note>>4)*OCTAVE)+(note&0xf)-1);
}
for (i=0;i<4;i++) {
inf = tr[t].effect[i].param;
switch (tr[t].effect[i].effect) {
case 1: /* toneslide up */
UniEffect(UNI_S3MEFFECTF,inf);
break;
case 2: /* toneslide down */
UniEffect(UNI_S3MEFFECTE,inf);
break;
case 3: /* glissando to note */
UniEffect(UNI_ITEFFECTG,inf);
break;
case 4: /* vibrato */
UniEffect(UNI_ITEFFECTH,inf);
break;
case 5: /* portamento+volslide */
UniEffect(UNI_ITEFFECTG,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 6: /* vibrato+volslide */
UniEffect(UNI_ITEFFECTH,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 7: /* tremolo */
UniEffect(UNI_S3MEFFECTR,inf);
break;
case 8: /* tremor */
UniEffect(UNI_S3MEFFECTI,inf);
break;
case 9: /* offset */
UniPTEffect(0x09,inf);
break;
case 0x0a: /* volslide */
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0x0b: /* jump to order */
UniPTEffect(0x0b,inf);
break;
case 0x0c: /* volume set */
UniPTEffect(0x0c,inf);
break;
case 0x0d: /* pattern break */
UniPTEffect(0x0d,inf);
break;
case 0x0e: /* extended */
switch (inf&0xf0) {
case 0x10: /* fine portamento up */
UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f));
break;
case 0x20: /* fine portamento down */
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
break;
case 0x30: /* glissando control */
UniEffect(SS_GLISSANDO, inf&0x0f);
break;
case 0x40: /* vibrato waveform */
UniEffect(SS_VIBWAVE, inf&0x0f);
break;
case 0x50: /* set c4spd */
UniEffect(SS_FINETUNE, inf&0x0f);
break;
case 0x60: /* loop fun */
UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0);
break;
case 0x70: /* tremolo waveform */
UniEffect(SS_TREMWAVE, inf&0x0f);
break;
case 0x80: /* extra fine porta up */
UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f));
break;
case 0x90: /* extra fine porta down */
UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f));
break;
case 0xa0: /* fine volslide up */
UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f));
break;
case 0xb0: /* fine volslide down */
UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f));
break;
case 0xc0: /* note cut */
case 0xd0: /* note delay */
case 0xe0: /* extend row */
UniPTEffect(0xe,inf);
break;
}
break;
case 0x0f: /* set tempo */
UniEffect(UNI_S3MEFFECTA,inf);
break;
case 0x10: /* arpeggio */
UniPTEffect(0x0,inf);
break;
case 0x12: /* retrigger */
UniEffect(UNI_S3MEFFECTQ,inf);
break;
case 0x13: /* set global volume */
UniEffect(UNI_XMEFFECTG,inf<<1);
break;
case 0x14: /* fine vibrato */
UniEffect(UNI_ITEFFECTU,inf);
break;
case 0x1e: /* special */
switch (inf&0xf0) {
case 8: /* set pan position */
if (inf >=128)
UniPTEffect(0x08,255);
else
UniPTEffect(0x08,inf<<1);
break;
}
break;
case 0x1f: /* set bpm */
if (inf >=0x20)
UniEffect(UNI_S3MEFFECTT,inf);
break;
}
}
UniNewline();
}
return UniDup();
}
BOOL GDM_Load(BOOL curious)
{
int i,x,u,track;
SAMPLE *q;
GDMSAMPLE s;
ULONG position;
/* read header */
_mm_read_string(mh->id1,4,modreader);
_mm_read_string(mh->songname,32,modreader);
_mm_read_string(mh->author,32,modreader);
_mm_read_string(mh->eofmarker,3,modreader);
_mm_read_string(mh->id2,4,modreader);
mh->majorver=_mm_read_UBYTE(modreader);
mh->minorver=_mm_read_UBYTE(modreader);
mh->trackerid=_mm_read_I_UWORD(modreader);
mh->t_majorver=_mm_read_UBYTE(modreader);
mh->t_minorver=_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->pantable,32,modreader);
mh->mastervol=_mm_read_UBYTE(modreader);
mh->mastertempo=_mm_read_UBYTE(modreader);
mh->masterbpm=_mm_read_UBYTE(modreader);
mh->flags=_mm_read_I_UWORD(modreader);
mh->orderloc=_mm_read_I_ULONG(modreader);
mh->ordernum=_mm_read_UBYTE(modreader);
mh->patternloc=_mm_read_I_ULONG(modreader);
mh->patternnum=_mm_read_UBYTE(modreader);
mh->samhead=_mm_read_I_ULONG(modreader);
mh->samdata=_mm_read_I_ULONG(modreader);
mh->samnum=_mm_read_UBYTE(modreader);
mh->messageloc=_mm_read_I_ULONG(modreader);
mh->messagelen=_mm_read_I_ULONG(modreader);
mh->scrollyloc=_mm_read_I_ULONG(modreader);
mh->scrollylen=_mm_read_I_UWORD(modreader);
mh->graphicloc=_mm_read_I_ULONG(modreader);
mh->graphiclen=_mm_read_I_UWORD(modreader);
/* have we ended abruptly? */
if (_mm_eof(modreader)) {
_mm_errno=MMERR_LOADING_HEADER;
return 0;
}
/* any orders? */
if(mh->ordernum==255) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
/* now we fill */
of.modtype=strdup(GDM_Version);
of.modtype[18]=mh->majorver+'0';
of.modtype[20]=mh->minorver/10+'0';
of.modtype[21]=mh->minorver%10+'0';
of.songname=DupStr(mh->songname,32,0);
of.numpat=mh->patternnum+1;
of.reppos=0;
of.numins=of.numsmp=mh->samnum+1;
of.initspeed=mh->mastertempo;
of.inittempo=mh->masterbpm;
of.initvolume=mh->mastervol<<1;
of.flags|=UF_S3MSLIDES | UF_PANNING;
/* XXX whenever possible, we should try to determine the original format.
Here we assume it was S3M-style wrt bpmlimit... */
of.bpmlimit = 32;
/* read the order data */
if (!AllocPositions(mh->ordernum+1)) {
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
_mm_fseek(modreader,mh->orderloc,SEEK_SET);
for (i=0;i<mh->ordernum+1;i++)
of.positions[i]=_mm_read_UBYTE(modreader);
of.numpos=0;
for (i=0;i<mh->ordernum+1;i++) {
int order=of.positions[i];
if(order==255) order=LAST_PATTERN;
of.positions[of.numpos]=order;
if (of.positions[i]<254) of.numpos++;
}
/* have we ended abruptly yet? */
if (_mm_eof(modreader)) {
_mm_errno=MMERR_LOADING_HEADER;
return 0;
}
/* time to load the samples */
if (!AllocSamples()) {
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
q=of.samples;
position=mh->samdata;
/* seek to instrument position */
_mm_fseek(modreader,mh->samhead,SEEK_SET);
for (i=0;i<of.numins;i++) {
/* load sample info */
_mm_read_UBYTES(s.sampname,32,modreader);
_mm_read_UBYTES(s.filename,12,modreader);
s.ems=_mm_read_UBYTE(modreader);
s.length=_mm_read_I_ULONG(modreader);
s.loopbeg=_mm_read_I_ULONG(modreader);
s.loopend=_mm_read_I_ULONG(modreader);
s.flags=_mm_read_UBYTE(modreader);
s.c4spd=_mm_read_I_UWORD(modreader);
s.vol=_mm_read_UBYTE(modreader);
s.pan=_mm_read_UBYTE(modreader);
if (_mm_eof(modreader)) {
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->samplename=DupStr(s.sampname,32,0);
q->speed=s.c4spd;
q->length=s.length;
q->loopstart=s.loopbeg;
q->loopend=s.loopend;
q->volume=s.vol;
q->panning=s.pan;
q->seekpos=position;
position +=s.length;
if (s.flags&1)
q->flags |=SF_LOOP;
if (s.flags&2)
q->flags |=SF_16BITS;
if (s.flags&16)
q->flags |=SF_STEREO;
q++;
}
/* set the panning */
for (i=x=0;i<32;i++) {
of.panning[i]=mh->pantable[i];
if (!of.panning[i])
of.panning[i]=PAN_LEFT;
else if (of.panning[i]==8)
of.panning[i]=PAN_CENTER;
else if (of.panning[i]==15)
of.panning[i]=PAN_RIGHT;
else if (of.panning[i]==16)
of.panning[i]=PAN_SURROUND;
else if (of.panning[i]==255)
of.panning[i]=128;
else
of.panning[i]<<=3;
if (mh->pantable[i]!=255)
x=i;
}
of.numchn=x+1;
if (of.numchn<1)
of.numchn=1; /* for broken counts */
/* load the pattern info */
of.numtrk=of.numpat*of.numchn;
/* jump to patterns */
_mm_fseek(modreader,mh->patternloc,SEEK_SET);
if (!AllocTracks()) {
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
if (!AllocPatterns()) {
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
for (i=track=0;i<of.numpat;i++) {
if (!GDM_ReadPattern()) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
for (u=0;u<of.numchn;u++,track++) {
of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]);
if (!of.tracks[track]) {
_mm_errno=MMERR_LOADING_TRACK;
return 0;
}
}
}
return 1;
}
CHAR *GDM_LoadTitle(void)
{
CHAR s[32];
_mm_fseek(modreader,4,SEEK_SET);
if (!_mm_read_UBYTES(s,32,modreader)) return NULL;
return DupStr(s,28,0);
}
MIKMODAPI MLOADER load_gdm=
{
NULL,
"GDM",
"GDM (General DigiMusic)",
GDM_Init,
GDM_Test,
GDM_Load,
GDM_Cleanup,
GDM_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,738 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_imf.c,v 1.2 2004/02/06 19:29:03 raph Exp $
Imago Orpheus (IMF) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
/* module header */
typedef struct IMFHEADER {
CHAR songname[32];
UWORD ordnum;
UWORD patnum;
UWORD insnum;
UWORD flags;
UBYTE initspeed;
UBYTE inittempo;
UBYTE mastervol;
UBYTE mastermult;
UBYTE orders[256];
} IMFHEADER;
/* channel settings */
typedef struct IMFCHANNEL {
CHAR name[12];
UBYTE chorus;
UBYTE reverb;
UBYTE pan;
UBYTE status;
} IMFCHANNEL;
/* instrument header */
#define IMFNOTECNT (10*OCTAVE)
#define IMFENVCNT (16*2)
typedef struct IMFINSTHEADER {
CHAR name[32];
UBYTE what[IMFNOTECNT];
UWORD volenv[IMFENVCNT];
UWORD panenv[IMFENVCNT];
UWORD pitenv[IMFENVCNT];
UBYTE volpts;
UBYTE volsus;
UBYTE volbeg;
UBYTE volend;
UBYTE volflg;
UBYTE panpts;
UBYTE pansus;
UBYTE panbeg;
UBYTE panend;
UBYTE panflg;
UBYTE pitpts;
UBYTE pitsus;
UBYTE pitbeg;
UBYTE pitend;
UBYTE pitflg;
UWORD volfade;
UWORD numsmp;
ULONG signature;
} IMFINSTHEADER;
/* sample header */
typedef struct IMFWAVHEADER {
CHAR samplename[13];
ULONG length;
ULONG loopstart;
ULONG loopend;
ULONG samplerate;
UBYTE volume;
UBYTE pan;
UBYTE flags;
} IMFWAVHEADER;
typedef struct IMFNOTE {
UBYTE note,ins,eff1,dat1,eff2,dat2;
} IMFNOTE;
/*========== Loader variables */
static CHAR IMF_Version[]="Imago Orpheus";
static IMFNOTE *imfpat=NULL;
static IMFHEADER *mh=NULL;
/*========== Loader code */
BOOL IMF_Test(void)
{
UBYTE id[4];
_mm_fseek(modreader,0x3c,SEEK_SET);
if(!_mm_read_UBYTES(id,4,modreader)) return 0;
if(!memcmp(id,"IM10",4)) return 1;
return 0;
}
BOOL IMF_Init(void)
{
if(!(imfpat=(IMFNOTE*)_mm_malloc(32*256*sizeof(IMFNOTE)))) return 0;
if(!(mh=(IMFHEADER*)_mm_malloc(sizeof(IMFHEADER)))) return 0;
return 1;
}
void IMF_Cleanup(void)
{
FreeLinear();
_mm_free(imfpat);
_mm_free(mh);
}
static BOOL IMF_ReadPattern(SLONG size,UWORD rows)
{
int row=0,flag,ch;
IMFNOTE *n,dummy;
/* clear pattern data */
memset(imfpat,255,32*256*sizeof(IMFNOTE));
while((size>0)&&(row<rows)) {
flag=_mm_read_UBYTE(modreader);size--;
if(_mm_eof(modreader)) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
if(flag) {
ch=remap[flag&31];
if(ch!=-1)
n=&imfpat[256*ch+row];
else
n=&dummy;
if(flag&32) {
n->note=_mm_read_UBYTE(modreader);
if(n->note>=0xa0) n->note=0xa0; /* note off */
n->ins =_mm_read_UBYTE(modreader);
size-=2;
}
if(flag&64) {
size-=2;
n->eff2=_mm_read_UBYTE(modreader);
n->dat2=_mm_read_UBYTE(modreader);
}
if(flag&128) {
n->eff1=_mm_read_UBYTE(modreader);
n->dat1=_mm_read_UBYTE(modreader);
size-=2;
}
} else row++;
}
if((size)||(row!=rows)) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
return 1;
}
static void IMF_ProcessCmd(UBYTE eff,UBYTE inf)
{
if((eff)&&(eff!=255))
switch (eff) {
case 0x01: /* set tempo */
UniEffect(UNI_S3MEFFECTA,inf);
break;
case 0x02: /* set BPM */
if(inf>=0x20) UniEffect(UNI_S3MEFFECTT,inf);
break;
case 0x03: /* tone portamento */
UniEffect(UNI_ITEFFECTG,inf);
break;
case 0x04: /* porta + volslide */
UniEffect(UNI_ITEFFECTG,inf);
UniEffect(UNI_S3MEFFECTD,0);
break;
case 0x05: /* vibrato */
UniEffect(UNI_XMEFFECT4,inf);
break;
case 0x06: /* vibrato + volslide */
UniEffect(UNI_XMEFFECT6,inf);
break;
case 0x07: /* fine vibrato */
UniEffect(UNI_ITEFFECTU,inf);
break;
case 0x08: /* tremolo */
UniEffect(UNI_S3MEFFECTR,inf);
break;
case 0x09: /* arpeggio */
UniPTEffect(0x0,inf);
break;
case 0x0a: /* panning */
UniPTEffect(0x8,(inf>=128)?255:(inf<<1));
break;
case 0x0b: /* pan slide */
UniEffect(UNI_XMEFFECTP,inf);
break;
case 0x0c: /* set channel volume */
if(inf<=64) UniPTEffect(0xc,inf);
break;
case 0x0d: /* volume slide */
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0x0e: /* fine volume slide */
if(inf) {
if(inf>>4)
UniEffect(UNI_S3MEFFECTD,0x0f|inf);
else
UniEffect(UNI_S3MEFFECTD,0xf0|inf);
} else
UniEffect(UNI_S3MEFFECTD,0);
break;
case 0x0f: /* set finetune */
UniPTEffect(0xe,0x50|(inf>>4));
break;
#ifdef MIKMOD_DEBUG
case 0x10: /* note slide up */
case 0x11: /* not slide down */
fprintf(stderr,"\rIMF effect 0x10/0x11 (note slide)"
" not implemented (eff=%2X inf=%2X)\n",eff,inf);
break;
#endif
case 0x12: /* slide up */
UniEffect(UNI_S3MEFFECTF,inf);
break;
case 0x13: /* slide down */
UniEffect(UNI_S3MEFFECTE,inf);
break;
case 0x14: /* fine slide up */
if (inf) {
if (inf<0x40)
UniEffect(UNI_S3MEFFECTF,0xe0|(inf>>2));
else
UniEffect(UNI_S3MEFFECTF,0xf0|(inf>>4));
} else
UniEffect(UNI_S3MEFFECTF,0);
break;
case 0x15: /* fine slide down */
if (inf) {
if (inf<0x40)
UniEffect(UNI_S3MEFFECTE,0xe0|(inf>>2));
else
UniEffect(UNI_S3MEFFECTE,0xf0|(inf>>4));
} else
UniEffect(UNI_S3MEFFECTE,0);
break;
/* 0x16 set filter cutoff (awe32) */
/* 0x17 filter side + resonance (awe32) */
case 0x18: /* sample offset */
UniPTEffect(0x9,inf);
break;
#ifdef MIKMOD_DEBUG
case 0x19: /* set fine sample offset */
fprintf(stderr,"\rIMF effect 0x19 (fine sample offset)"
" not implemented (inf=%2X)\n",inf);
break;
#endif
case 0x1a: /* keyoff */
UniWriteByte(UNI_KEYOFF);
break;
case 0x1b: /* retrig */
UniEffect(UNI_S3MEFFECTQ,inf);
break;
case 0x1c: /* tremor */
UniEffect(UNI_S3MEFFECTI,inf);
break;
case 0x1d: /* position jump */
UniPTEffect(0xb,inf);
break;
case 0x1e: /* pattern break */
UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));
break;
case 0x1f: /* set master volume */
if(inf<=64) UniEffect(UNI_XMEFFECTG,inf<<1);
break;
case 0x20: /* master volume slide */
UniEffect(UNI_XMEFFECTH,inf);
break;
case 0x21: /* extended effects */
switch(inf>>4) {
case 0x1: /* set filter */
case 0x5: /* vibrato waveform */
case 0x8: /* tremolo waveform */
UniPTEffect(0xe,inf-0x10);
break;
case 0xa: /* pattern loop */
UniPTEffect(0xe,0x60|(inf&0xf));
break;
case 0xb: /* pattern delay */
UniPTEffect(0xe,0xe0|(inf&0xf));
break;
case 0x3: /* glissando */
case 0xc: /* note cut */
case 0xd: /* note delay */
case 0xf: /* invert loop */
UniPTEffect(0xe,inf);
break;
case 0xe: /* ignore envelope */
UniEffect(UNI_ITEFFECTS0, 0x77); /* vol */
UniEffect(UNI_ITEFFECTS0, 0x79); /* pan */
UniEffect(UNI_ITEFFECTS0, 0x7b); /* pit */
break;
}
break;
/* 0x22 chorus (awe32) */
/* 0x23 reverb (awe32) */
}
}
static UBYTE* IMF_ConvertTrack(IMFNOTE* tr,UWORD rows)
{
int t;
UBYTE note,ins;
UniReset();
for(t=0;t<rows;t++) {
note=tr[t].note;
ins=tr[t].ins;
if((ins)&&(ins!=255)) UniInstrument(ins-1);
if(note!=255) {
if(note==0xa0) {
UniPTEffect(0xc,0); /* Note cut */
if(tr[t].eff1==0x0c) tr[t].eff1=0;
if(tr[t].eff2==0x0c) tr[t].eff2=0;
} else
UniNote(((note>>4)*OCTAVE)+(note&0xf));
}
IMF_ProcessCmd(tr[t].eff1,tr[t].dat1);
IMF_ProcessCmd(tr[t].eff2,tr[t].dat2);
UniNewline();
}
return UniDup();
}
BOOL IMF_Load(BOOL curious)
{
#define IMF_SMPINCR 64
int t,u,track=0,oldnumsmp;
IMFCHANNEL channels[32];
INSTRUMENT *d;
SAMPLE *q;
IMFWAVHEADER *wh=NULL,*s=NULL;
ULONG *nextwav=NULL;
UWORD wavcnt=0;
UBYTE id[4];
/* try to read the module header */
_mm_read_string(mh->songname,32,modreader);
mh->ordnum=_mm_read_I_UWORD(modreader);
mh->patnum=_mm_read_I_UWORD(modreader);
mh->insnum=_mm_read_I_UWORD(modreader);
mh->flags =_mm_read_I_UWORD(modreader);
_mm_fseek(modreader,8,SEEK_CUR);
mh->initspeed =_mm_read_UBYTE(modreader);
mh->inittempo =_mm_read_UBYTE(modreader);
mh->mastervol =_mm_read_UBYTE(modreader);
mh->mastermult=_mm_read_UBYTE(modreader);
_mm_fseek(modreader,64,SEEK_SET);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.songname=DupStr(mh->songname,31,1);
of.modtype=strdup(IMF_Version);
of.numpat=mh->patnum;
of.numins=mh->insnum;
of.reppos=0;
of.initspeed=mh->initspeed;
of.inittempo=mh->inittempo;
of.initvolume=mh->mastervol<<1;
of.flags |= UF_INST | UF_ARPMEM | UF_PANNING;
if(mh->flags&1) of.flags |= UF_LINEAR;
of.bpmlimit=32;
/* read channel information */
of.numchn=0;
memset(remap,-1,32*sizeof(UBYTE));
for(t=0;t<32;t++) {
_mm_read_string(channels[t].name,12,modreader);
channels[t].chorus=_mm_read_UBYTE(modreader);
channels[t].reverb=_mm_read_UBYTE(modreader);
channels[t].pan =_mm_read_UBYTE(modreader);
channels[t].status=_mm_read_UBYTE(modreader);
}
/* bug in Imago Orpheus ? If only channel 1 is enabled, in fact we have to
enable 16 channels */
if(!channels[0].status) {
for(t=1;t<16;t++) if(channels[t].status!=1) break;
if(t==16) for(t=1;t<16;t++) channels[t].status=0;
}
for(t=0;t<32;t++) {
if(channels[t].status!=2)
remap[t]=of.numchn++;
else
remap[t]=-1;
}
for(t=0;t<32;t++)
if(remap[t]!=-1) {
of.panning[remap[t]]=channels[t].pan;
of.chanvol[remap[t]]=channels[t].status?0:64;
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* read order list */
_mm_read_UBYTES(mh->orders,256,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
of.numpos=0;
for(t=0;t<mh->ordnum;t++)
if(mh->orders[t]!=0xff) of.numpos++;
if(!AllocPositions(of.numpos)) return 0;
for(t=u=0;t<mh->ordnum;t++)
if(mh->orders[t]!=0xff) of.positions[u++]=mh->orders[t];
/* load pattern info */
of.numtrk=of.numpat*of.numchn;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
for(t=0;t<of.numpat;t++) {
SLONG size;
UWORD rows;
size=(SLONG)_mm_read_I_UWORD(modreader);
rows=_mm_read_I_UWORD(modreader);
if((rows>256)||(size<4)) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
of.pattrows[t]=rows;
if(!IMF_ReadPattern(size-4,rows)) return 0;
for(u=0;u<of.numchn;u++)
if(!(of.tracks[track++]=IMF_ConvertTrack(&imfpat[u*256],rows)))
return 0;
}
/* load instruments */
if(!AllocInstruments()) return 0;
d=of.instruments;
for(oldnumsmp=t=0;t<of.numins;t++) {
IMFINSTHEADER ih;
memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
/* read instrument header */
_mm_read_string(ih.name,32,modreader);
d->insname=DupStr(ih.name,31,1);
_mm_read_UBYTES(ih.what,IMFNOTECNT,modreader);
_mm_fseek(modreader,8,SEEK_CUR);
_mm_read_I_UWORDS(ih.volenv,IMFENVCNT,modreader);
_mm_read_I_UWORDS(ih.panenv,IMFENVCNT,modreader);
_mm_read_I_UWORDS(ih.pitenv,IMFENVCNT,modreader);
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define IMF_FinishLoadingEnvelope(name) \
ih. name##pts=_mm_read_UBYTE(modreader); \
ih. name##sus=_mm_read_UBYTE(modreader); \
ih. name##beg=_mm_read_UBYTE(modreader); \
ih. name##end=_mm_read_UBYTE(modreader); \
ih. name##flg=_mm_read_UBYTE(modreader); \
_mm_read_UBYTE(modreader); \
_mm_read_UBYTE(modreader); \
_mm_read_UBYTE(modreader)
#else
#define IMF_FinishLoadingEnvelope(name) \
ih. name/**/pts=_mm_read_UBYTE(modreader); \
ih. name/**/sus=_mm_read_UBYTE(modreader); \
ih. name/**/beg=_mm_read_UBYTE(modreader); \
ih. name/**/end=_mm_read_UBYTE(modreader); \
ih. name/**/flg=_mm_read_UBYTE(modreader); \
_mm_read_UBYTE(modreader); \
_mm_read_UBYTE(modreader); \
_mm_read_UBYTE(modreader)
#endif
IMF_FinishLoadingEnvelope(vol);
IMF_FinishLoadingEnvelope(pan);
IMF_FinishLoadingEnvelope(pit);
ih.volfade=_mm_read_I_UWORD(modreader);
ih.numsmp =_mm_read_I_UWORD(modreader);
_mm_read_UBYTES(id,4,modreader);
/* Looks like Imago Orpheus forgets the signature for empty
instruments following a multi-sample instrument... */
if(memcmp(id,"II10",4) &&
(oldnumsmp && memcmp(id,"\x0\x0\x0\x0",4))) {
if(nextwav) free(nextwav);
if(wh) free(wh);
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
oldnumsmp=ih.numsmp;
if((ih.numsmp>16)||(ih.volpts>IMFENVCNT/2)||(ih.panpts>IMFENVCNT/2)||
(ih.pitpts>IMFENVCNT/2)||(_mm_eof(modreader))) {
if(nextwav) free(nextwav);
if(wh) free(wh);
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
for(u=0;u<IMFNOTECNT;u++)
d->samplenumber[u]=ih.what[u]>ih.numsmp?0xffff:ih.what[u]+of.numsmp;
d->volfade=ih.volfade;
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define IMF_ProcessEnvelope(name) \
for (u = 0; u < (IMFENVCNT >> 1); u++) { \
d-> name##env[u].pos = ih. name##env[u << 1]; \
d-> name##env[u].val = ih. name##env[(u << 1)+ 1]; \
} \
if (ih. name##flg&1) d-> name##flg|=EF_ON; \
if (ih. name##flg&2) d-> name##flg|=EF_SUSTAIN; \
if (ih. name##flg&4) d-> name##flg|=EF_LOOP; \
d-> name##susbeg=d-> name##susend=ih. name##sus; \
d-> name##beg=ih. name##beg; \
d-> name##end=ih. name##end; \
d-> name##pts=ih. name##pts; \
\
if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
d-> name##flg&=~EF_ON
#else
#define IMF_ProcessEnvelope(name) \
for (u = 0; u < (IMFENVCNT >> 1); u++) { \
d-> name/**/env[u].pos = ih. name/**/env[u << 1]; \
d-> name/**/env[u].val = ih. name/**/env[(u << 1)+ 1]; \
} \
if (ih. name/**/flg&1) d-> name/**/flg|=EF_ON; \
if (ih. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \
if (ih. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \
d-> name/**/susbeg=d-> name/**/susend=ih. name/**/sus; \
d-> name/**/beg=ih. name/**/beg; \
d-> name/**/end=ih. name/**/end; \
d-> name/**/pts=ih. name/**/pts; \
\
if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
d-> name/**/flg&=~EF_ON
#endif
IMF_ProcessEnvelope(vol);
IMF_ProcessEnvelope(pan);
IMF_ProcessEnvelope(pit);
#undef IMF_ProcessEnvelope
if(ih.pitflg&1) {
d->pitflg&=~EF_ON;
#ifdef MIKMOD_DEBUG
fprintf(stderr, "\rFilter envelopes not supported yet\n");
#endif
}
/* gather sample information */
for(u=0;u<ih.numsmp;u++,s++) {
/* allocate more room for sample information if necessary */
if(of.numsmp+u==wavcnt) {
wavcnt+=IMF_SMPINCR;
if(!(nextwav=realloc(nextwav,wavcnt*sizeof(ULONG)))) {
if(wh) free(wh);
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
if(!(wh=realloc(wh,wavcnt*sizeof(IMFWAVHEADER)))) {
free(nextwav);
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
s=wh+(wavcnt-IMF_SMPINCR);
}
_mm_read_string(s->samplename,13,modreader);
_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);
s->length =_mm_read_I_ULONG(modreader);
s->loopstart =_mm_read_I_ULONG(modreader);
s->loopend =_mm_read_I_ULONG(modreader);
s->samplerate=_mm_read_I_ULONG(modreader);
s->volume =_mm_read_UBYTE(modreader)&0x7f;
s->pan =_mm_read_UBYTE(modreader);
_mm_fseek(modreader,14,SEEK_CUR);
s->flags =_mm_read_UBYTE(modreader);
_mm_fseek(modreader,11,SEEK_CUR);
_mm_read_UBYTES(id,4,modreader);
if(((memcmp(id,"IS10",4))&&(memcmp(id,"IW10",4)))||
(_mm_eof(modreader))) {
free(nextwav);free(wh);
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
nextwav[of.numsmp+u]=_mm_ftell(modreader);
_mm_fseek(modreader,s->length,SEEK_CUR);
}
of.numsmp+=ih.numsmp;
d++;
}
/* sanity check */
if(!of.numsmp) {
if(nextwav) free(nextwav);
if(wh) free(wh);
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
/* load samples */
if(!AllocSamples()) {
free(nextwav);free(wh);
return 0;
}
if(!AllocLinear()) {
free(nextwav);free(wh);
return 0;
}
q=of.samples;
s=wh;
for(u=0;u<of.numsmp;u++,s++,q++) {
q->samplename=DupStr(s->samplename,12,1);
q->length =s->length;
q->loopstart=s->loopstart;
q->loopend =s->loopend;
q->volume =s->volume;
q->speed =s->samplerate;
if(of.flags&UF_LINEAR)
q->speed=speed_to_finetune(s->samplerate<<1,u);
q->panning =s->pan;
q->seekpos =nextwav[u];
q->flags|=SF_SIGNED;
if(s->flags&0x1) q->flags|=SF_LOOP;
if(s->flags&0x2) q->flags|=SF_BIDI;
if(s->flags&0x8) q->flags|=SF_OWNPAN;
if(s->flags&0x4) {
q->flags|=SF_16BITS;
q->length >>=1;
q->loopstart>>=1;
q->loopend >>=1;
}
}
d=of.instruments;
s=wh;
for(u=0;u<of.numins;u++,d++) {
for(t=0;t<IMFNOTECNT;t++) {
if(d->samplenumber[t]>=of.numsmp)
d->samplenote[t]=255;
else if (of.flags&UF_LINEAR) {
int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];
d->samplenote[u]=(note<0)?0:(note>255?255:note);
} else
d->samplenote[t]=t;
}
}
free(wh);free(nextwav);
return 1;
}
CHAR *IMF_LoadTitle(void)
{
CHAR s[31];
_mm_fseek(modreader,0,SEEK_SET);
if(!_mm_read_UBYTES(s,31,modreader)) return NULL;
return(DupStr(s,31,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_imf={
NULL,
"IMF",
"IMF (Imago Orpheus)",
IMF_Init,
IMF_Test,
IMF_Load,
IMF_Cleanup,
IMF_LoadTitle
};
/* ex:set ts=4: */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,505 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_m15.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
15 instrument MOD loader
Also supports Ultimate Sound Tracker (old M15 format)
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module Structure */
typedef struct MSAMPINFO {
CHAR samplename[23]; /* 22 in module, 23 in memory */
UWORD length;
UBYTE finetune;
UBYTE volume;
UWORD reppos;
UWORD replen;
} MSAMPINFO;
typedef struct MODULEHEADER {
CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */
MSAMPINFO samples[15]; /* all sampleinfo */
UBYTE songlength; /* number of patterns used */
UBYTE magic1; /* should be 127 */
UBYTE positions[128]; /* which pattern to play at pos */
} MODULEHEADER;
typedef struct MODNOTE {
UBYTE a,b,c,d;
} MODNOTE;
/*========== Loader variables */
static MODULEHEADER *mh = NULL;
static MODNOTE *patbuf = NULL;
static BOOL ust_loader = 0; /* if TRUE, load as an ust module. */
/* known file formats which can confuse the loader */
#define REJECT 2
static char *signatures[REJECT]={
"CAKEWALK", /* cakewalk midi files */
"SZDD" /* Microsoft compressed files */
};
static int siglen[REJECT]={8,4};
/*========== Loader code */
static BOOL LoadModuleHeader(MODULEHEADER *mh)
{
int t,u;
_mm_read_string(mh->songname,20,modreader);
mh->songname[20]=0; /* just in case */
/* sanity check : title should contain printable characters and a bunch
of null chars */
for(t=0;t<20;t++)
if((mh->songname[t])&&(mh->songname[t]<32)) return 0;
for(t=0;(mh->songname[t])&&(t<20);t++);
if(t<20) for(;t<20;t++) if(mh->songname[t]) return 0;
for(t=0;t<15;t++) {
MSAMPINFO *s=&mh->samples[t];
_mm_read_string(s->samplename,22,modreader);
s->samplename[22]=0; /* just in case */
s->length =_mm_read_M_UWORD(modreader);
s->finetune =_mm_read_UBYTE(modreader);
s->volume =_mm_read_UBYTE(modreader);
s->reppos =_mm_read_M_UWORD(modreader);
s->replen =_mm_read_M_UWORD(modreader);
/* sanity check : sample title should contain printable characters and
a bunch of null chars */
for(u=0;u<20;u++)
if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0;
for(u=0;(s->samplename[u])&&(u<20);u++);
if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0;
/* sanity check : finetune values */
if(s->finetune>>4) return 0;
}
mh->songlength =_mm_read_UBYTE(modreader);
mh->magic1 =_mm_read_UBYTE(modreader); /* should be 127 */
/* sanity check : no more than 128 positions, restart position in range */
if((!mh->songlength)||(mh->songlength>128)) return 0;
/* values encountered so far are 0x6a and 0x78 */
if(((mh->magic1&0xf8)!=0x78)&&(mh->magic1!=0x6a)&&(mh->magic1>mh->songlength)) return 0;
_mm_read_UBYTES(mh->positions,128,modreader);
/* sanity check : pattern range is 0..63 */
for(t=0;t<128;t++)
if(mh->positions[t]>63) return 0;
return(!_mm_eof(modreader));
}
/* Checks the patterns in the modfile for UST / 15-inst indications.
For example, if an effect 3xx is found, it is assumed that the song
is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST.
Returns: 0 indecisive; 1 = UST; 2 = 15-inst */
static int CheckPatternType(int numpat)
{
int t;
UBYTE eff, dat;
for(t=0;t<numpat*(64U*4);t++) {
/* Load the pattern into the temp buffer and scan it */
_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);
eff = _mm_read_UBYTE(modreader);
dat = _mm_read_UBYTE(modreader);
switch(eff) {
case 1:
if(dat>0x1f) return 1;
if(dat<0x3) return 2;
break;
case 2:
if(dat>0x1f) return 1;
return 2;
case 3:
if (dat) return 2;
break;
default:
return 2;
}
}
return 0;
}
static BOOL M15_Test(void)
{
int t, numpat;
MODULEHEADER mh;
ust_loader = 0;
if(!LoadModuleHeader(&mh)) return 0;
/* reject other file types */
for(t=0;t<REJECT;t++)
if(!memcmp(mh.songname,signatures[t],siglen[t])) return 0;
if(mh.magic1>127) return 0;
if((!mh.songlength)||(mh.songlength>mh.magic1)) return 0;
for(t=0;t<15;t++) {
/* all finetunes should be zero */
if(mh.samples[t].finetune) return 0;
/* all volumes should be <= 64 */
if(mh.samples[t].volume>64) return 0;
/* all instrument names should begin with s, st-, or a number */
if((mh.samples[t].samplename[0]=='s')||
(mh.samples[t].samplename[0]=='S')) {
if((memcmp(mh.samples[t].samplename,"st-",3)) &&
(memcmp(mh.samples[t].samplename,"ST-",3)) &&
(*mh.samples[t].samplename))
ust_loader = 1;
} else
if(!isdigit((int)mh.samples[t].samplename[0]))
ust_loader = 1;
if(mh.samples[t].length>4999||mh.samples[t].reppos>9999) {
ust_loader = 0;
if(mh.samples[t].length>32768) return 0;
}
/* if loop information is incorrect as words, but correct as bytes,
this is likely to be an ust-style module */
if((mh.samples[t].reppos+mh.samples[t].replen>mh.samples[t].length)&&
(mh.samples[t].reppos+mh.samples[t].replen<(mh.samples[t].length<<1))){
ust_loader = 1;
return 1;
}
if(!ust_loader) return 1;
}
for(numpat=0,t=0;t<mh.songlength;t++)
if(mh.positions[t]>numpat)
numpat = mh.positions[t];
numpat++;
switch(CheckPatternType(numpat)) {
case 0: /* indecisive, so check more clues... */
break;
case 1:
ust_loader = 1;
break;
case 2:
ust_loader = 0;
break;
}
return 1;
}
static BOOL M15_Init(void)
{
if(!(mh=(MODULEHEADER*)_mm_malloc(sizeof(MODULEHEADER)))) return 0;
return 1;
}
static void M15_Cleanup(void)
{
_mm_free(mh);
_mm_free(patbuf);
}
/*
Old (amiga) noteinfo:
_____byte 1_____ byte2_ _____byte 3_____ byte4_
/ \ / \ / \ / \
0000 0000-00000000 0000 0000-00000000
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
*/
static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect)
{
UBYTE instrument,effect,effdat,note;
UWORD period;
UBYTE lastnote=0;
/* decode the 4 bytes that make up a single note */
instrument = n->c>>4;
period = (((UWORD)n->a&0xf)<<8)+n->b;
effect = n->c&0xf;
effdat = n->d;
/* Convert the period to a note number */
note=0;
if(period) {
for(note=0;note<7*OCTAVE;note++)
if(period>=npertab[note]) break;
if(note==7*OCTAVE) note=0;
else note++;
}
if(instrument) {
/* if instrument does not exist, note cut */
if((instrument>15)||(!mh->samples[instrument-1].length)) {
UniPTEffect(0xc,0);
if(effect==0xc) effect=effdat=0;
} else {
/* if we had a note, then change instrument... */
if(note)
UniInstrument(instrument-1);
/* ...otherwise, only adjust volume... */
else {
/* ...unless an effect was specified, which forces a new note
to be played */
if(effect||effdat) {
UniInstrument(instrument-1);
note=lastnote;
} else
UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f);
}
}
}
if(note) {
UniNote(note+2*OCTAVE-1);
lastnote=note;
}
/* Convert pattern jump from Dec to Hex */
if(effect == 0xd)
effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf);
/* Volume slide, up has priority */
if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0))
effdat&=0xf0;
/* Handle ``heavy'' volumes correctly */
if ((effect == 0xc) && (effdat > 0x40))
effdat = 0x40;
if(ust_loader) {
switch(effect) {
case 0:
case 3:
break;
case 1:
UniPTEffect(0,effdat);
break;
case 2:
if(effdat&0xf) UniPTEffect(1,effdat&0xf);
else if(effdat>>2) UniPTEffect(2,effdat>>2);
break;
default:
UniPTEffect(effect,effdat);
break;
}
} else {
/* An isolated 100, 200 or 300 effect should be ignored (no
"standalone" porta memory in mod files). However, a sequence
such as 1XX, 100, 100, 100 is fine. */
if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&
(lasteffect < 0x10) && (effect != lasteffect))
effect = 0;
UniPTEffect(effect,effdat);
}
if (effect == 8)
of.flags |= UF_PANNING;
return effect;
}
static UBYTE *M15_ConvertTrack(MODNOTE* n)
{
int t;
UBYTE lasteffect = 0x10; /* non existant effect */
UniReset();
for(t=0;t<64;t++) {
lasteffect = M15_ConvertNote(n,lasteffect);
UniNewline();
n+=4;
}
return UniDup();
}
/* Loads all patterns of a modfile and converts them into the 3 byte format. */
static BOOL M15_LoadPatterns(void)
{
int t,s,tracks=0;
if(!AllocPatterns()) return 0;
if(!AllocTracks()) return 0;
/* Allocate temporary buffer for loading and converting the patterns */
if(!(patbuf=(MODNOTE*)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0;
for(t=0;t<of.numpat;t++) {
/* Load the pattern into the temp buffer and convert it */
for(s=0;s<(64U*4);s++) {
patbuf[s].a=_mm_read_UBYTE(modreader);
patbuf[s].b=_mm_read_UBYTE(modreader);
patbuf[s].c=_mm_read_UBYTE(modreader);
patbuf[s].d=_mm_read_UBYTE(modreader);
}
for(s=0;s<4;s++)
if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
}
return 1;
}
static BOOL M15_Load(BOOL curious)
{
int t,scan;
SAMPLE *q;
MSAMPINFO *s;
/* try to read module header */
if(!LoadModuleHeader(mh)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
if(ust_loader)
of.modtype = strdup("Ultimate Soundtracker");
else
of.modtype = strdup("Soundtracker");
/* set module variables */
of.initspeed = 6;
of.inittempo = 125;
of.numchn = 4;
of.songname = DupStr(mh->songname,21,1);
of.numpos = mh->songlength;
of.reppos = 0;
/* Count the number of patterns */
of.numpat = 0;
for(t=0;t<of.numpos;t++)
if(mh->positions[t]>of.numpat)
of.numpat=mh->positions[t];
/* since some old modules embed extra patterns, we have to check the
whole list to get the samples' file offsets right - however we can find
garbage here, so check carefully */
scan=1;
for(t=of.numpos;t<128;t++)
if(mh->positions[t]>=0x80) scan=0;
if (scan)
for(t=of.numpos;t<128;t++) {
if(mh->positions[t]>of.numpat)
of.numpat=mh->positions[t];
if((curious)&&(mh->positions[t])) of.numpos=t+1;
}
of.numpat++;
of.numtrk = of.numpat*of.numchn;
if(!AllocPositions(of.numpos)) return 0;
for(t=0;t<of.numpos;t++)
of.positions[t]=mh->positions[t];
/* Finally, init the sampleinfo structures */
of.numins=of.numsmp=15;
if(!AllocSamples()) return 0;
s = mh->samples;
q = of.samples;
for(t=0;t<of.numins;t++) {
/* convert the samplename */
q->samplename = DupStr(s->samplename,23,1);
/* init the sampleinfo variables and convert the size pointers */
q->speed = finetune[s->finetune&0xf];
q->volume = s->volume;
if(ust_loader)
q->loopstart = s->reppos;
else
q->loopstart = s->reppos<<1;
q->loopend = q->loopstart+(s->replen<<1);
q->length = s->length<<1;
q->flags = SF_SIGNED;
if(ust_loader) q->flags |= SF_UST_LOOP;
if(s->replen>2) q->flags |= SF_LOOP;
s++;
q++;
}
if(!M15_LoadPatterns()) return 0;
ust_loader = 0;
return 1;
}
static CHAR *M15_LoadTitle(void)
{
CHAR s[21];
_mm_fseek(modreader,0,SEEK_SET);
if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
s[20]=0; /* just in case */
return(DupStr(s,21,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_m15={
NULL,
"15-instrument module",
"MOD (15 instrument)",
M15_Init,
M15_Test,
M15_Load,
M15_Cleanup,
M15_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,719 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_med.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Amiga MED module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module information */
typedef struct MEDHEADER {
ULONG id;
ULONG modlen;
ULONG MEDSONGP; /* struct MEDSONG *song; */
UWORD psecnum; /* for the player routine, MMD2 only */
UWORD pseq; /* " " " " */
ULONG MEDBlockPP; /* struct MEDBlock **blockarr; */
ULONG reserved1;
ULONG MEDINSTHEADERPP; /* struct MEDINSTHEADER **smplarr; */
ULONG reserved2;
ULONG MEDEXPP; /* struct MEDEXP *expdata; */
ULONG reserved3;
UWORD pstate; /* some data for the player routine */
UWORD pblock;
UWORD pline;
UWORD pseqnum;
SWORD actplayline;
UBYTE counter;
UBYTE extra_songs; /* number of songs - 1 */
} MEDHEADER;
typedef struct MEDSAMPLE {
UWORD rep, replen; /* offs: 0(s), 2(s) */
UBYTE midich; /* offs: 4(s) */
UBYTE midipreset; /* offs: 5(s) */
UBYTE svol; /* offs: 6(s) */
SBYTE strans; /* offs: 7(s) */
} MEDSAMPLE;
typedef struct MEDSONG {
MEDSAMPLE sample[63]; /* 63 * 8 bytes = 504 bytes */
UWORD numblocks; /* offs: 504 */
UWORD songlen; /* offs: 506 */
UBYTE playseq[256]; /* offs: 508 */
UWORD deftempo; /* offs: 764 */
SBYTE playtransp; /* offs: 766 */
UBYTE flags; /* offs: 767 */
UBYTE flags2; /* offs: 768 */
UBYTE tempo2; /* offs: 769 */
UBYTE trkvol[16]; /* offs: 770 */
UBYTE mastervol; /* offs: 786 */
UBYTE numsamples; /* offs: 787 */
} MEDSONG;
typedef struct MEDEXP {
ULONG nextmod; /* pointer to next module */
ULONG exp_smp; /* pointer to MEDINSTEXT array */
UWORD s_ext_entries;
UWORD s_ext_entrsz;
ULONG annotxt; /* pointer to annotation text */
ULONG annolen;
ULONG iinfo; /* pointer to MEDINSTINFO array */
UWORD i_ext_entries;
UWORD i_ext_entrsz;
ULONG jumpmask;
ULONG rgbtable;
ULONG channelsplit;
ULONG n_info;
ULONG songname; /* pointer to songname */
ULONG songnamelen;
ULONG dumps;
ULONG reserved2[7];
} MEDEXP;
typedef struct MMD0NOTE {
UBYTE a, b, c;
} MMD0NOTE;
typedef struct MMD1NOTE {
UBYTE a, b, c, d;
} MMD1NOTE;
typedef struct MEDINSTHEADER {
ULONG length;
SWORD type;
/* Followed by actual data */
} MEDINSTHEADER;
typedef struct MEDINSTEXT {
UBYTE hold;
UBYTE decay;
UBYTE suppress_midi_off;
SBYTE finetune;
} MEDINSTEXT;
typedef struct MEDINSTINFO {
UBYTE name[40];
} MEDINSTINFO;
/*========== Loader variables */
#define MMD0_string 0x4D4D4430
#define MMD1_string 0x4D4D4431
static MEDHEADER *mh = NULL;
static MEDSONG *ms = NULL;
static MEDEXP *me = NULL;
static ULONG *ba = NULL;
static MMD0NOTE *mmd0pat = NULL;
static MMD1NOTE *mmd1pat = NULL;
static BOOL decimalvolumes;
static BOOL bpmtempos;
#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]
#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]
static CHAR MED_Version[] = "OctaMED (MMDx)";
/*========== Loader code */
BOOL MED_Test(void)
{
UBYTE id[4];
if (!_mm_read_UBYTES(id, 4, modreader))
return 0;
if ((!memcmp(id, "MMD0", 4)) || (!memcmp(id, "MMD1", 4)))
return 1;
return 0;
}
BOOL MED_Init(void)
{
if (!(me = (MEDEXP *)_mm_malloc(sizeof(MEDEXP))))
return 0;
if (!(mh = (MEDHEADER *)_mm_malloc(sizeof(MEDHEADER))))
return 0;
if (!(ms = (MEDSONG *)_mm_malloc(sizeof(MEDSONG))))
return 0;
return 1;
}
void MED_Cleanup(void)
{
_mm_free(me);
_mm_free(mh);
_mm_free(ms);
_mm_free(ba);
_mm_free(mmd0pat);
_mm_free(mmd1pat);
}
static void EffectCvt(UBYTE eff, UBYTE dat)
{
switch (eff) {
/* 0x0 0x1 0x2 0x3 0x4 PT effects */
case 0x5: /* PT vibrato with speed/depth nibbles swapped */
UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));
break;
/* 0x6 0x7 not used */
case 0x6:
case 0x7:
break;
case 0x8: /* midi hold/decay */
break;
case 0x9:
if (bpmtempos) {
if (!dat)
dat = of.initspeed;
UniEffect(UNI_S3MEFFECTA, dat);
} else {
if (dat <= 0x20) {
if (!dat)
dat = of.initspeed;
else
dat /= 4;
UniPTEffect(0xf, dat);
} else
UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4));
}
break;
/* 0xa 0xb PT effects */
case 0xc:
if (decimalvolumes)
dat = (dat >> 4) * 10 + (dat & 0xf);
UniPTEffect(0xc, dat);
break;
case 0xd: /* same as PT volslide */
UniPTEffect(0xa, dat);
break;
case 0xe: /* synth jmp - midi */
break;
case 0xf:
switch (dat) {
case 0: /* patternbreak */
UniPTEffect(0xd, 0);
break;
case 0xf1: /* play note twice */
UniWriteByte(UNI_MEDEFFECTF1);
break;
case 0xf2: /* delay note */
UniWriteByte(UNI_MEDEFFECTF2);
break;
case 0xf3: /* play note three times */
UniWriteByte(UNI_MEDEFFECTF3);
break;
case 0xfe: /* stop playing */
UniPTEffect(0xb, of.numpat);
break;
case 0xff: /* note cut */
UniPTEffect(0xc, 0);
break;
default:
if (dat <= 10)
UniPTEffect(0xf, dat);
else if (dat <= 240) {
if (bpmtempos)
UniPTEffect(0xf, (dat < 32) ? 32 : dat);
else
UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);
}
}
break;
default: /* all normal PT effects are handled here */
UniPTEffect(eff, dat);
break;
}
}
static UBYTE *MED_Convert1(int count, int col)
{
int t;
UBYTE inst, note, eff, dat;
MMD1NOTE *n;
UniReset();
for (t = 0; t < count; t++) {
n = &d1note(t, col);
note = n->a & 0x7f;
inst = n->b & 0x3f;
eff = n->c & 0xf;
dat = n->d;
if (inst)
UniInstrument(inst - 1);
if (note)
UniNote(note + 3 * OCTAVE - 1);
EffectCvt(eff, dat);
UniNewline();
}
return UniDup();
}
static UBYTE *MED_Convert0(int count, int col)
{
int t;
UBYTE a, b, inst, note, eff, dat;
MMD0NOTE *n;
UniReset();
for (t = 0; t < count; t++) {
n = &d0note(t, col);
a = n->a;
b = n->b;
note = a & 0x3f;
a >>= 6;
a = ((a & 1) << 1) | (a >> 1);
inst = (b >> 4) | (a << 4);
eff = b & 0xf;
dat = n->c;
if (inst)
UniInstrument(inst - 1);
if (note)
UniNote(note + 3 * OCTAVE - 1);
EffectCvt(eff, dat);
UniNewline();
}
return UniDup();
}
static BOOL LoadMEDPatterns(void)
{
int t, row, col;
UWORD numtracks, numlines, maxlines = 0, track = 0;
MMD0NOTE *mmdp;
/* first, scan patterns to see how many channels are used */
for (t = 0; t < of.numpat; t++) {
_mm_fseek(modreader, ba[t], SEEK_SET);
numtracks = _mm_read_UBYTE(modreader);
numlines = _mm_read_UBYTE(modreader);
if (numtracks > of.numchn)
of.numchn = numtracks;
if (numlines > maxlines)
maxlines = numlines;
}
of.numtrk = of.numpat * of.numchn;
if (!AllocTracks())
return 0;
if (!AllocPatterns())
return 0;
if (!
(mmd0pat =
(MMD0NOTE *)_mm_calloc(of.numchn * (maxlines + 1),
sizeof(MMD0NOTE)))) return 0;
/* second read: read and convert patterns */
for (t = 0; t < of.numpat; t++) {
_mm_fseek(modreader, ba[t], SEEK_SET);
numtracks = _mm_read_UBYTE(modreader);
numlines = _mm_read_UBYTE(modreader);
of.pattrows[t] = ++numlines;
memset(mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof(MMD0NOTE));
for (row = numlines; row; row--) {
for (col = numtracks; col; col--, mmdp++) {
mmdp->a = _mm_read_UBYTE(modreader);
mmdp->b = _mm_read_UBYTE(modreader);
mmdp->c = _mm_read_UBYTE(modreader);
}
}
for (col = 0; col < of.numchn; col++)
of.tracks[track++] = MED_Convert0(numlines, col);
}
return 1;
}
static BOOL LoadMMD1Patterns(void)
{
int t, row, col;
UWORD numtracks, numlines, maxlines = 0, track = 0;
MMD1NOTE *mmdp;
/* first, scan patterns to see how many channels are used */
for (t = 0; t < of.numpat; t++) {
_mm_fseek(modreader, ba[t], SEEK_SET);
numtracks = _mm_read_M_UWORD(modreader);
numlines = _mm_read_M_UWORD(modreader);
if (numtracks > of.numchn)
of.numchn = numtracks;
if (numlines > maxlines)
maxlines = numlines;
}
of.numtrk = of.numpat * of.numchn;
if (!AllocTracks())
return 0;
if (!AllocPatterns())
return 0;
if (!
(mmd1pat =
(MMD1NOTE *)_mm_calloc(of.numchn * (maxlines + 1),
sizeof(MMD1NOTE)))) return 0;
/* second read: really read and convert patterns */
for (t = 0; t < of.numpat; t++) {
_mm_fseek(modreader, ba[t], SEEK_SET);
numtracks = _mm_read_M_UWORD(modreader);
numlines = _mm_read_M_UWORD(modreader);
_mm_fseek(modreader, sizeof(ULONG), SEEK_CUR);
of.pattrows[t] = ++numlines;
memset(mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof(MMD1NOTE));
for (row = numlines; row; row--) {
for (col = numtracks; col; col--, mmdp++) {
mmdp->a = _mm_read_UBYTE(modreader);
mmdp->b = _mm_read_UBYTE(modreader);
mmdp->c = _mm_read_UBYTE(modreader);
mmdp->d = _mm_read_UBYTE(modreader);
}
}
for (col = 0; col < of.numchn; col++)
of.tracks[track++] = MED_Convert1(numlines, col);
}
return 1;
}
BOOL MED_Load(BOOL curious)
{
int t;
ULONG sa[64];
MEDINSTHEADER s;
SAMPLE *q;
MEDSAMPLE *mss;
/* try to read module header */
mh->id = _mm_read_M_ULONG(modreader);
mh->modlen = _mm_read_M_ULONG(modreader);
mh->MEDSONGP = _mm_read_M_ULONG(modreader);
mh->psecnum = _mm_read_M_UWORD(modreader);
mh->pseq = _mm_read_M_UWORD(modreader);
mh->MEDBlockPP = _mm_read_M_ULONG(modreader);
mh->reserved1 = _mm_read_M_ULONG(modreader);
mh->MEDINSTHEADERPP = _mm_read_M_ULONG(modreader);
mh->reserved2 = _mm_read_M_ULONG(modreader);
mh->MEDEXPP = _mm_read_M_ULONG(modreader);
mh->reserved3 = _mm_read_M_ULONG(modreader);
mh->pstate = _mm_read_M_UWORD(modreader);
mh->pblock = _mm_read_M_UWORD(modreader);
mh->pline = _mm_read_M_UWORD(modreader);
mh->pseqnum = _mm_read_M_UWORD(modreader);
mh->actplayline = _mm_read_M_SWORD(modreader);
mh->counter = _mm_read_UBYTE(modreader);
mh->extra_songs = _mm_read_UBYTE(modreader);
/* Seek to MEDSONG struct */
_mm_fseek(modreader, mh->MEDSONGP, SEEK_SET);
/* Load the MED Song Header */
mss = ms->sample; /* load the sample data first */
for (t = 63; t; t--, mss++) {
mss->rep = _mm_read_M_UWORD(modreader);
mss->replen = _mm_read_M_UWORD(modreader);
mss->midich = _mm_read_UBYTE(modreader);
mss->midipreset = _mm_read_UBYTE(modreader);
mss->svol = _mm_read_UBYTE(modreader);
mss->strans = _mm_read_SBYTE(modreader);
}
ms->numblocks = _mm_read_M_UWORD(modreader);
ms->songlen = _mm_read_M_UWORD(modreader);
_mm_read_UBYTES(ms->playseq, 256, modreader);
ms->deftempo = _mm_read_M_UWORD(modreader);
ms->playtransp = _mm_read_SBYTE(modreader);
ms->flags = _mm_read_UBYTE(modreader);
ms->flags2 = _mm_read_UBYTE(modreader);
ms->tempo2 = _mm_read_UBYTE(modreader);
_mm_read_UBYTES(ms->trkvol, 16, modreader);
ms->mastervol = _mm_read_UBYTE(modreader);
ms->numsamples = _mm_read_UBYTE(modreader);
/* check for a bad header */
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* load extension structure */
if (mh->MEDEXPP) {
_mm_fseek(modreader, mh->MEDEXPP, SEEK_SET);
me->nextmod = _mm_read_M_ULONG(modreader);
me->exp_smp = _mm_read_M_ULONG(modreader);
me->s_ext_entries = _mm_read_M_UWORD(modreader);
me->s_ext_entrsz = _mm_read_M_UWORD(modreader);
me->annotxt = _mm_read_M_ULONG(modreader);
me->annolen = _mm_read_M_ULONG(modreader);
me->iinfo = _mm_read_M_ULONG(modreader);
me->i_ext_entries = _mm_read_M_UWORD(modreader);
me->i_ext_entrsz = _mm_read_M_UWORD(modreader);
me->jumpmask = _mm_read_M_ULONG(modreader);
me->rgbtable = _mm_read_M_ULONG(modreader);
me->channelsplit = _mm_read_M_ULONG(modreader);
me->n_info = _mm_read_M_ULONG(modreader);
me->songname = _mm_read_M_ULONG(modreader);
me->songnamelen = _mm_read_M_ULONG(modreader);
me->dumps = _mm_read_M_ULONG(modreader);
}
/* seek to and read the samplepointer array */
_mm_fseek(modreader, mh->MEDINSTHEADERPP, SEEK_SET);
if (!_mm_read_M_ULONGS(sa, ms->numsamples, modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* alloc and read the blockpointer array */
if (!(ba = (ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG))))
return 0;
_mm_fseek(modreader, mh->MEDBlockPP, SEEK_SET);
if (!_mm_read_M_ULONGS(ba, ms->numblocks, modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* copy song positions */
if (!AllocPositions(ms->songlen))
return 0;
for (t = 0; t < ms->songlen; t++)
of.positions[t] = ms->playseq[t];
decimalvolumes = (ms->flags & 0x10) ? 0 : 1;
bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;
if (bpmtempos) {
int bpmlen = (ms->flags2 & 0x1f) + 1;
of.initspeed = ms->tempo2;
of.inittempo = ms->deftempo * bpmlen / 4;
if (bpmlen != 4) {
/* Let's do some math : compute GCD of BPM beat length and speed */
int a, b;
a = bpmlen;
b = ms->tempo2;
if (a > b) {
t = b;
b = a;
a = t;
}
while ((a != b) && (a)) {
t = a;
a = b - a;
b = t;
if (a > b) {
t = b;
b = a;
a = t;
}
}
of.initspeed /= b;
of.inittempo = ms->deftempo * bpmlen / (4 * b);
}
} else {
of.initspeed = ms->tempo2;
of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;
if ((ms->deftempo <= 10) && (ms->deftempo))
of.inittempo = (of.inittempo * 33) / 6;
of.flags |= UF_HIGHBPM;
}
MED_Version[12] = mh->id;
of.modtype = strdup(MED_Version);
of.numchn = 0; /* will be counted later */
of.numpat = ms->numblocks;
of.numpos = ms->songlen;
of.numins = ms->numsamples;
of.numsmp = of.numins;
of.reppos = 0;
if ((mh->MEDEXPP) && (me->songname) && (me->songnamelen)) {
char *name;
_mm_fseek(modreader, me->songname, SEEK_SET);
name = _mm_malloc(me->songnamelen);
_mm_read_UBYTES(name, me->songnamelen, modreader);
of.songname = DupStr(name, me->songnamelen, 1);
free(name);
} else
of.songname = DupStr(NULL, 0, 0);
if ((mh->MEDEXPP) && (me->annotxt) && (me->annolen)) {
_mm_fseek(modreader, me->annotxt, SEEK_SET);
ReadComment(me->annolen);
}
if (!AllocSamples())
return 0;
q = of.samples;
for (t = 0; t < of.numins; t++) {
q->flags = SF_SIGNED;
q->volume = 64;
if (sa[t]) {
_mm_fseek(modreader, sa[t], SEEK_SET);
s.length = _mm_read_M_ULONG(modreader);
s.type = _mm_read_M_SWORD(modreader);
if (s.type) {
#ifdef MIKMOD_DEBUG
fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");
#endif
if (!curious) {
_mm_errno = MMERR_MED_SYNTHSAMPLES;
return 0;
}
s.length = 0;
}
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->length = s.length;
q->seekpos = _mm_ftell(modreader);
q->loopstart = ms->sample[t].rep << 1;
q->loopend = q->loopstart + (ms->sample[t].replen << 1);
if (ms->sample[t].replen > 1)
q->flags |= SF_LOOP;
/* don't load sample if length>='MMD0'...
such kluges make libmikmod's code unique !!! */
if (q->length >= MMD0_string)
q->length = 0;
} else
q->length = 0;
if ((mh->MEDEXPP) && (me->exp_smp) &&
(t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) {
MEDINSTEXT ie;
_mm_fseek(modreader, me->exp_smp + t * me->s_ext_entrsz,
SEEK_SET);
ie.hold = _mm_read_UBYTE(modreader);
ie.decay = _mm_read_UBYTE(modreader);
ie.suppress_midi_off = _mm_read_UBYTE(modreader);
ie.finetune = _mm_read_SBYTE(modreader);
q->speed = finetune[ie.finetune & 0xf];
} else
q->speed = 8363;
if ((mh->MEDEXPP) && (me->iinfo) &&
(t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) {
MEDINSTINFO ii;
_mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);
_mm_read_UBYTES(ii.name, 40, modreader);
q->samplename = DupStr((char*)ii.name, 40, 1);
} else
q->samplename = NULL;
q++;
}
if (mh->id == MMD0_string) {
if (!LoadMEDPatterns()) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
} else if (mh->id == MMD1_string) {
if (!LoadMMD1Patterns()) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
} else {
_mm_errno = MMERR_NOT_A_MODULE;
return 0;
}
return 1;
}
CHAR *MED_LoadTitle(void)
{
ULONG posit, namelen;
CHAR *name, *retvalue = NULL;
_mm_fseek(modreader, 0x20, SEEK_SET);
posit = _mm_read_M_ULONG(modreader);
if (posit) {
_mm_fseek(modreader, posit + 0x2C, SEEK_SET);
posit = _mm_read_M_ULONG(modreader);
namelen = _mm_read_M_ULONG(modreader);
_mm_fseek(modreader, posit, SEEK_SET);
name = _mm_malloc(namelen);
_mm_read_UBYTES(name, namelen, modreader);
retvalue = DupStr(name, namelen, 1);
free(name);
}
return retvalue;
}
/*========== Loader information */
MIKMODAPI MLOADER load_med = {
NULL,
"MED",
"MED (OctaMED)",
MED_Init,
MED_Test,
MED_Load,
MED_Cleanup,
MED_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,512 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_mod.c,v 1.2 2004/01/21 13:33:11 raph Exp $
Generic MOD loader (Protracker, StarTracker, FastTracker, etc)
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
typedef struct MSAMPINFO {
CHAR samplename[23]; /* 22 in module, 23 in memory */
UWORD length;
UBYTE finetune;
UBYTE volume;
UWORD reppos;
UWORD replen;
} MSAMPINFO;
typedef struct MODULEHEADER {
CHAR songname[21]; /* the songname.. 20 in module, 21 in memory */
MSAMPINFO samples[31]; /* all sampleinfo */
UBYTE songlength; /* number of patterns used */
UBYTE magic1; /* should be 127 */
UBYTE positions[128]; /* which pattern to play at pos */
UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */
} MODULEHEADER;
typedef struct MODTYPE {
CHAR id[5];
UBYTE channels;
CHAR *name;
} MODTYPE;
typedef struct MODNOTE {
UBYTE a, b, c, d;
} MODNOTE;
/*========== Loader variables */
#define MODULEHEADERSIZE 0x438
static CHAR protracker[] = "Protracker";
static CHAR startrekker[] = "Startrekker";
static CHAR fasttracker[] = "Fasttracker";
static CHAR oktalyser[] = "Oktalyser";
static CHAR oktalyzer[] = "Oktalyzer";
static CHAR taketracker[] = "TakeTracker";
static CHAR orpheus[] = "Imago Orpheus (MOD format)";
static MODULEHEADER *mh = NULL;
static MODNOTE *patbuf = NULL;
static int modtype, trekker;
/*========== Loader code */
/* given the module ID, determine the number of channels and the tracker
description ; also alters modtype */
static BOOL MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
{
modtype = trekker = 0;
/* Protracker and variants */
if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {
*descr = protracker;
modtype = 0;
*numchn = 4;
return 1;
}
/* Star Tracker */
if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) &&
(isdigit(id[3]))) {
*descr = startrekker;
modtype = trekker = 1;
*numchn = id[3] - '0';
if (*numchn == 4 || *numchn == 8)
return 1;
#ifdef MIKMOD_DEBUG
else
fprintf(stderr, "\rUnknown FLT%d module type\n", *numchn);
#endif
return 0;
}
/* Oktalyzer (Amiga) */
if (!memcmp(id, "OKTA", 4)) {
*descr = oktalyzer;
modtype = 1;
*numchn = 8;
return 1;
}
/* Oktalyser (Atari) */
if (!memcmp(id, "CD81", 4)) {
*descr = oktalyser;
modtype = 1;
*numchn = 8;
return 1;
}
/* Fasttracker */
if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) {
*descr = fasttracker;
modtype = 1;
*numchn = id[0] - '0';
return 1;
}
/* Fasttracker or Taketracker */
if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2)))
&& (isdigit(id[0])) && (isdigit(id[1]))) {
if (id[3] == 'H') {
*descr = fasttracker;
modtype = 2; /* this can also be Imago Orpheus */
} else {
*descr = taketracker;
modtype = 1;
}
*numchn = (id[0] - '0') * 10 + (id[1] - '0');
return 1;
}
return 0;
}
static BOOL MOD_Test(void)
{
UBYTE id[4], numchn;
CHAR *descr;
_mm_fseek(modreader, MODULEHEADERSIZE, SEEK_SET);
if (!_mm_read_UBYTES(id, 4, modreader))
return 0;
if (MOD_CheckType(id, &numchn, &descr))
return 1;
return 0;
}
static BOOL MOD_Init(void)
{
if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))
return 0;
return 1;
}
static void MOD_Cleanup(void)
{
_mm_free(mh);
_mm_free(patbuf);
}
/*
Old (amiga) noteinfo:
_____byte 1_____ byte2_ _____byte 3_____ byte4_
/ \ / \ / \ / \
0000 0000-00000000 0000 0000-00000000
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
*/
static UBYTE ConvertNote(MODNOTE *n, UBYTE lasteffect)
{
UBYTE instrument, effect, effdat, note;
UWORD period;
UBYTE lastnote = 0;
/* extract the various information from the 4 bytes that make up a note */
instrument = (n->a & 0x10) | (n->c >> 4);
period = (((UWORD)n->a & 0xf) << 8) + n->b;
effect = n->c & 0xf;
effdat = n->d;
/* Convert the period to a note number */
note = 0;
if (period) {
for (note = 0; note < 7 * OCTAVE; note++)
if (period >= npertab[note])
break;
if (note == 7 * OCTAVE)
note = 0;
else
note++;
}
if (instrument) {
/* if instrument does not exist, note cut */
if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
UniPTEffect(0xc, 0);
if (effect == 0xc)
effect = effdat = 0;
} else {
/* Protracker handling */
if (!modtype) {
/* if we had a note, then change instrument... */
if (note)
UniInstrument(instrument - 1);
/* ...otherwise, only adjust volume... */
else {
/* ...unless an effect was specified, which forces a new
note to be played */
if (effect || effdat) {
UniInstrument(instrument - 1);
note = lastnote;
} else
UniPTEffect(0xc,
mh->samples[instrument -
1].volume & 0x7f);
}
} else {
/* Fasttracker handling */
UniInstrument(instrument - 1);
if (!note)
note = lastnote;
}
}
}
if (note) {
UniNote(note + 2 * OCTAVE - 1);
lastnote = note;
}
/* Convert pattern jump from Dec to Hex */
if (effect == 0xd)
effdat = (((effdat & 0xf0) >> 4) * 10) + (effdat & 0xf);
/* Volume slide, up has priority */
if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
effdat &= 0xf0;
/* Handle ``heavy'' volumes correctly */
if ((effect == 0xc) && (effdat > 0x40))
effdat = 0x40;
/* An isolated 100, 200 or 300 effect should be ignored (no
"standalone" porta memory in mod files). However, a sequence such
as 1XX, 100, 100, 100 is fine. */
if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&
(lasteffect < 0x10) && (effect != lasteffect))
effect = 0;
UniPTEffect(effect, effdat);
if (effect == 8)
of.flags |= UF_PANNING;
return effect;
}
static UBYTE *ConvertTrack(MODNOTE *n, int numchn)
{
int t;
UBYTE lasteffect = 0x10; /* non existant effect */
UniReset();
for (t = 0; t < 64; t++) {
lasteffect = ConvertNote(n,lasteffect);
UniNewline();
n += numchn;
}
return UniDup();
}
/* Loads all patterns of a modfile and converts them into the 3 byte format. */
static BOOL ML_LoadPatterns(void)
{
int t, s, tracks = 0;
if (!AllocPatterns())
return 0;
if (!AllocTracks())
return 0;
/* Allocate temporary buffer for loading and converting the patterns */
if (!(patbuf = (MODNOTE *)_mm_calloc(64U * of.numchn, sizeof(MODNOTE))))
return 0;
if (trekker && of.numchn == 8) {
/* Startrekker module dual pattern */
for (t = 0; t < of.numpat; t++) {
for (s = 0; s < (64U * 4); s++) {
patbuf[s].a = _mm_read_UBYTE(modreader);
patbuf[s].b = _mm_read_UBYTE(modreader);
patbuf[s].c = _mm_read_UBYTE(modreader);
patbuf[s].d = _mm_read_UBYTE(modreader);
}
for (s = 0; s < 4; s++)
if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4)))
return 0;
for (s = 0; s < (64U * 4); s++) {
patbuf[s].a = _mm_read_UBYTE(modreader);
patbuf[s].b = _mm_read_UBYTE(modreader);
patbuf[s].c = _mm_read_UBYTE(modreader);
patbuf[s].d = _mm_read_UBYTE(modreader);
}
for (s = 0; s < 4; s++)
if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4)))
return 0;
}
} else {
/* Generic module pattern */
for (t = 0; t < of.numpat; t++) {
/* Load the pattern into the temp buffer and convert it */
for (s = 0; s < (64U * of.numchn); s++) {
patbuf[s].a = _mm_read_UBYTE(modreader);
patbuf[s].b = _mm_read_UBYTE(modreader);
patbuf[s].c = _mm_read_UBYTE(modreader);
patbuf[s].d = _mm_read_UBYTE(modreader);
}
for (s = 0; s < of.numchn; s++)
if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, of.numchn)))
return 0;
}
}
return 1;
}
static BOOL MOD_Load(BOOL curious)
{
int t, scan;
SAMPLE *q;
MSAMPINFO *s;
CHAR *descr;
/* try to read module header */
_mm_read_string((CHAR *)mh->songname, 20, modreader);
mh->songname[20] = 0; /* just in case */
for (t = 0; t < 31; t++) {
s = &mh->samples[t];
_mm_read_string(s->samplename, 22, modreader);
s->samplename[22] = 0; /* just in case */
s->length = _mm_read_M_UWORD(modreader);
s->finetune = _mm_read_UBYTE(modreader);
s->volume = _mm_read_UBYTE(modreader);
s->reppos = _mm_read_M_UWORD(modreader);
s->replen = _mm_read_M_UWORD(modreader);
}
mh->songlength = _mm_read_UBYTE(modreader);
/* this fixes mods which declare more than 128 positions.
* eg: beatwave.mod */
if (mh->songlength > 128) { mh->songlength = 128; }
mh->magic1 = _mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->positions, 128, modreader);
_mm_read_UBYTES(mh->magic2, 4, modreader);
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = 6;
of.inittempo = 125;
if (!(MOD_CheckType(mh->magic2, &of.numchn, &descr))) {
_mm_errno = MMERR_NOT_A_MODULE;
return 0;
}
if (trekker && of.numchn == 8)
for (t = 0; t < 128; t++)
/* if module pretends to be FLT8, yet the order table
contains odd numbers, chances are it's a lying FLT4... */
if (mh->positions[t] & 1) {
of.numchn = 4;
break;
}
if (trekker && of.numchn == 8)
for (t = 0; t < 128; t++)
mh->positions[t] >>= 1;
of.songname = DupStr(mh->songname, 21, 1);
of.numpos = mh->songlength;
of.reppos = 0;
/* Count the number of patterns */
of.numpat = 0;
for (t = 0; t < of.numpos; t++)
if (mh->positions[t] > of.numpat)
of.numpat = mh->positions[t];
/* since some old modules embed extra patterns, we have to check the
whole list to get the samples' file offsets right - however we can find
garbage here, so check carefully */
scan = 1;
for (t = of.numpos; t < 128; t++)
if (mh->positions[t] >= 0x80)
scan = 0;
if (scan)
for (t = of.numpos; t < 128; t++) {
if (mh->positions[t] > of.numpat)
of.numpat = mh->positions[t];
if ((curious) && (mh->positions[t]))
of.numpos = t + 1;
}
of.numpat++;
of.numtrk = of.numpat * of.numchn;
if (!AllocPositions(of.numpos))
return 0;
for (t = 0; t < of.numpos; t++)
of.positions[t] = mh->positions[t];
/* Finally, init the sampleinfo structures */
of.numins = of.numsmp = 31;
if (!AllocSamples())
return 0;
s = mh->samples;
q = of.samples;
for (t = 0; t < of.numins; t++) {
/* convert the samplename */
q->samplename = DupStr(s->samplename, 23, 1);
/* init the sampleinfo variables and convert the size pointers */
q->speed = finetune[s->finetune & 0xf];
q->volume = s->volume & 0x7f;
q->loopstart = (ULONG)s->reppos << 1;
q->loopend = q->loopstart + ((ULONG)s->replen << 1);
q->length = (ULONG)s->length << 1;
q->flags = SF_SIGNED;
/* Imago Orpheus creates MODs with 16 bit samples, check */
if ((modtype == 2) && (s->volume & 0x80)) {
q->flags |= SF_16BITS;
descr = orpheus;
}
if (s->replen > 2)
q->flags |= SF_LOOP;
s++;
q++;
}
of.modtype = strdup(descr);
if (!ML_LoadPatterns())
return 0;
return 1;
}
static CHAR *MOD_LoadTitle(void)
{
CHAR s[21];
_mm_fseek(modreader, 0, SEEK_SET);
if (!_mm_read_UBYTES(s, 20, modreader))
return NULL;
s[20] = 0; /* just in case */
return (DupStr(s, 21, 1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_mod = {
NULL,
"Standard module",
"MOD (31 instruments)",
MOD_Init,
MOD_Test,
MOD_Load,
MOD_Cleanup,
MOD_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,285 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_mtm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
MTM module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
typedef struct MTMHEADER {
UBYTE id[3]; /* MTM file marker */
UBYTE version; /* upper major, lower nibble minor version number */
CHAR songname[20]; /* ASCIIZ songname */
UWORD numtracks; /* number of tracks saved */
UBYTE lastpattern; /* last pattern number saved */
UBYTE lastorder; /* last order number to play (songlength-1) */
UWORD commentsize; /* length of comment field */
UBYTE numsamples; /* number of samples saved */
UBYTE attribute; /* attribute byte (unused) */
UBYTE beatspertrack;
UBYTE numchannels; /* number of channels used */
UBYTE panpos[32]; /* voice pan positions */
} MTMHEADER;
typedef struct MTMSAMPLE {
CHAR samplename[22];
ULONG length;
ULONG reppos;
ULONG repend;
UBYTE finetune;
UBYTE volume;
UBYTE attribute;
} MTMSAMPLE;
typedef struct MTMNOTE {
UBYTE a,b,c;
} MTMNOTE;
/*========== Loader variables */
static MTMHEADER *mh = NULL;
static MTMNOTE *mtmtrk = NULL;
static UWORD pat[32];
static CHAR MTM_Version[] = "MTM";
/*========== Loader code */
BOOL MTM_Test(void)
{
UBYTE id[3];
if(!_mm_read_UBYTES(id,3,modreader)) return 0;
if(!memcmp(id,"MTM",3)) return 1;
return 0;
}
BOOL MTM_Init(void)
{
if(!(mtmtrk=(MTMNOTE*)_mm_calloc(64,sizeof(MTMNOTE)))) return 0;
if(!(mh=(MTMHEADER*)_mm_malloc(sizeof(MTMHEADER)))) return 0;
return 1;
}
void MTM_Cleanup(void)
{
_mm_free(mtmtrk);
_mm_free(mh);
}
static UBYTE* MTM_Convert(void)
{
int t;
UBYTE a,b,inst,note,eff,dat;
UniReset();
for(t=0;t<64;t++) {
a=mtmtrk[t].a;
b=mtmtrk[t].b;
inst=((a&0x3)<<4)|(b>>4);
note=a>>2;
eff=b&0xf;
dat=mtmtrk[t].c;
if(inst) UniInstrument(inst-1);
if(note) UniNote(note+2*OCTAVE);
/* MTM bug workaround : when the effect is volslide, slide-up *always*
overrides slide-down. */
if(eff==0xa && (dat&0xf0)) dat&=0xf0;
/* Convert pattern jump from Dec to Hex */
if(eff==0xd)
dat=(((dat&0xf0)>>4)*10)+(dat&0xf);
UniPTEffect(eff,dat);
UniNewline();
}
return UniDup();
}
BOOL MTM_Load(BOOL curious)
{
int t,u;
MTMSAMPLE s;
SAMPLE *q;
/* try to read module header */
_mm_read_UBYTES(mh->id,3,modreader);
mh->version =_mm_read_UBYTE(modreader);
_mm_read_string(mh->songname,20,modreader);
mh->numtracks =_mm_read_I_UWORD(modreader);
mh->lastpattern =_mm_read_UBYTE(modreader);
mh->lastorder =_mm_read_UBYTE(modreader);
mh->commentsize =_mm_read_I_UWORD(modreader);
mh->numsamples =_mm_read_UBYTE(modreader);
mh->attribute =_mm_read_UBYTE(modreader);
mh->beatspertrack=_mm_read_UBYTE(modreader);
mh->numchannels =_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->panpos,32,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = 6;
of.inittempo = 125;
of.modtype = strdup(MTM_Version);
of.numchn = mh->numchannels;
of.numtrk = mh->numtracks+1; /* get number of channels */
of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */
of.numpos = mh->lastorder+1; /* copy the songlength */
of.numpat = mh->lastpattern+1;
of.reppos = 0;
of.flags |= UF_PANNING;
for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<< 4;
of.numins=of.numsmp=mh->numsamples;
if(!AllocSamples()) return 0;
q=of.samples;
for(t=0;t<of.numins;t++) {
/* try to read sample info */
_mm_read_string(s.samplename,22,modreader);
s.length =_mm_read_I_ULONG(modreader);
s.reppos =_mm_read_I_ULONG(modreader);
s.repend =_mm_read_I_ULONG(modreader);
s.finetune =_mm_read_UBYTE(modreader);
s.volume =_mm_read_UBYTE(modreader);
s.attribute =_mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->samplename = DupStr(s.samplename,22,1);
q->seekpos = 0;
q->speed = finetune[s.finetune];
q->length = s.length;
q->loopstart = s.reppos;
q->loopend = s.repend;
q->volume = s.volume;
if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;
if(s.attribute&1) {
/* If the sample is 16-bits, convert the length and replen
byte-values into sample-values */
q->flags|=SF_16BITS;
q->length>>=1;
q->loopstart>>=1;
q->loopend>>=1;
}
q++;
}
if(!AllocPositions(of.numpos)) return 0;
for(t=0;t<of.numpos;t++)
of.positions[t]=_mm_read_UBYTE(modreader);
for(;t<128;t++) _mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
of.tracks[0]=MTM_Convert(); /* track 0 is empty */
for(t=1;t<of.numtrk;t++) {
int s;
for(s=0;s<64;s++) {
mtmtrk[s].a=_mm_read_UBYTE(modreader);
mtmtrk[s].b=_mm_read_UBYTE(modreader);
mtmtrk[s].c=_mm_read_UBYTE(modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_TRACK;
return 0;
}
if(!(of.tracks[t]=MTM_Convert())) return 0;
}
for(t=0;t<of.numpat;t++) {
_mm_read_I_UWORDS(pat,32,modreader);
for(u=0;u<of.numchn;u++)
of.patterns[((long)t*of.numchn)+u]=pat[u];
}
/* read comment field */
if(mh->commentsize)
if(!ReadLinedComment(mh->commentsize, 40)) return 0;
return 1;
}
CHAR *MTM_LoadTitle(void)
{
CHAR s[20];
_mm_fseek(modreader,4,SEEK_SET);
if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
return(DupStr(s,20,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_mtm={
NULL,
"MTM",
"MTM (MultiTracker Module editor)",
MTM_Init,
MTM_Test,
MTM_Load,
MTM_Cleanup,
MTM_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,460 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_okt.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Oktalyzer (OKT) module loader
==============================================================================*/
/*
Written by UFO <ufo303@poczta.onet.pl>
based on the file description compiled by Harald Zappe
<zappe@gaea.sietec.de>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module blocks */
/* sample information */
typedef struct OKTSAMPLE {
CHAR sampname[20];
ULONG len;
UWORD loopbeg;
UWORD looplen;
UBYTE volume;
} OKTSAMPLE;
typedef struct OKTNOTE {
UBYTE note, ins, eff, dat;
} OKTNOTE;
/*========== Loader variables */
static OKTNOTE *okttrk = NULL;
/*========== Loader code */
BOOL OKT_Test(void)
{
CHAR id[8];
if (!_mm_read_UBYTES(id, 8, modreader))
return 0;
if (!memcmp(id, "OKTASONG", 8))
return 1;
return 0;
}
/* Pattern analysis routine.
Effects not implemented (yet) : (in decimal)
11 Arpeggio 4: Change note every 50Hz tick between N,H,N,L
12 Arpeggio 5: Change note every 50Hz tick between H,H,N
N = normal note being played in this channel (1-36)
L = normal note number minus upper four bits of 'data'.
H = normal note number plus lower four bits of 'data'.
13 Decrease note number by 'data' once per tick.
17 Increase note number by 'data' once per tick.
21 Decrease note number by 'data' once per line.
30 Increase note number by 'data' once per line.
*/
static UBYTE *OKT_ConvertTrack(UBYTE patrows)
{
int t;
UBYTE ins, note, eff, dat;
UniReset();
for (t = 0; t < patrows; t++) {
note = okttrk[t].note;
ins = okttrk[t].ins;
eff = okttrk[t].eff;
dat = okttrk[t].dat;
if (note) {
UniNote(note + 3 * OCTAVE - 1);
UniInstrument(ins);
}
if (eff)
switch (eff) {
case 1: /* Porta Up */
UniPTEffect(0x1, dat);
break;
case 2: /* Portamento Down */
UniPTEffect(0x2, dat);
break;
/* case 9: what is this? */
case 10: /* Arpeggio 3 */
case 11: /* Arpeggio 4 */
case 12: /* Arpeggio 5 */
UniWriteByte(UNI_OKTARP);
UniWriteByte(eff + 3 - 10);
UniWriteByte(dat);
break;
case 15: /* Amiga filter toggle, ignored */
break;
case 25: /* Pattern Jump */
dat = (dat >> 4) * 10 + (dat & 0x0f);
UniPTEffect(0xb, dat);
break;
case 27: /* Release - similar to Keyoff */
UniWriteByte(UNI_KEYOFF);
break;
case 28: /* Set Tempo */
UniPTEffect(0xf, dat & 0x0f);
break;
case 31: /* volume Control */
if (dat <= 0x40)
UniPTEffect(0xc, dat);
else if (dat <= 0x50)
UniEffect(UNI_XMEFFECTA, (dat - 0x40)); /* fast fade out */
else if (dat <= 0x60)
UniEffect(UNI_XMEFFECTA, (dat - 0x50) << 4); /* fast fade in */
else if (dat <= 0x70)
UniEffect(UNI_XMEFFECTEB, (dat - 0x60)); /* slow fade out */
else if (dat <= 0x80)
UniEffect(UNI_XMEFFECTEA, (dat - 0x70)); /* slow fade in */
break;
#ifdef MIKMOD_DEBUG
default:
fprintf(stderr, "\rUnimplemented effect (%02d,%02x)\n",
eff, dat);
#endif
}
UniNewline();
}
return UniDup();
}
/* Read "channel modes" i.e. channel number and panning information */
static void OKT_doCMOD(void)
{
/* amiga channel panning table */
UBYTE amigapan[4] = { 0x00, 0xff, 0xff, 0x00 };
int t;
of.numchn = 0;
of.flags |= UF_PANNING;
for (t = 0; t < 4; t++)
if (_mm_read_M_UWORD(modreader)) {
/* two channels tied to the same Amiga hardware voice */
of.panning[of.numchn++] = amigapan[t];
of.panning[of.numchn++] = amigapan[t];
} else
/* one channel tied to the Amiga hardware voice */
of.panning[of.numchn++] = amigapan[t];
}
/* Read sample information */
static BOOL OKT_doSAMP(int len)
{
int t;
SAMPLE *q;
OKTSAMPLE s;
of.numins = of.numsmp = (len / 0x20);
if (!AllocSamples())
return 0;
for (t = 0, q = of.samples; t < of.numins; t++, q++) {
_mm_read_UBYTES(s.sampname, 20, modreader);
s.len = _mm_read_M_ULONG(modreader);
s.loopbeg = _mm_read_M_UWORD(modreader) * 2;
s.looplen = _mm_read_M_UWORD(modreader) * 2;
_mm_read_UBYTE(modreader);
s.volume = _mm_read_UBYTE(modreader);
_mm_read_M_UWORD(modreader);
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
if (!s.len)
q->seekpos = q->length = q->loopstart = q->loopend = q->flags = 0;
else {
s.len--;
/* sanity checks */
if (s.loopbeg > s.len)
s.loopbeg = s.len;
if (s.loopbeg + s.looplen > s.len)
s.looplen = s.len - s.loopbeg;
if (s.looplen < 2)
s.looplen = 0;
q->length = s.len;
q->loopstart = s.loopbeg;
q->loopend = s.looplen + q->loopstart;
q->volume = s.volume;
q->flags = SF_SIGNED;
if (s.looplen)
q->flags |= SF_LOOP;
}
q->samplename = DupStr(s.sampname, 20, 1);
q->speed = 8287;
}
return 1;
}
/* Read speed information */
static void OKT_doSPEE(void)
{
int tempo = _mm_read_M_UWORD(modreader);
of.initspeed = tempo;
}
/* Read song length information */
static void OKT_doSLEN(void)
{
of.numpat = _mm_read_M_UWORD(modreader);
}
/* Read pattern length information */
static void OKT_doPLEN(void)
{
of.numpos = _mm_read_M_UWORD(modreader);
}
/* Read order table */
static BOOL OKT_doPATT(void)
{
int t;
if (!of.numpos || !AllocPositions(of.numpos))
return 0;
for (t = 0; t < 128; t++)
if (t < of.numpos)
of.positions[t] = _mm_read_UBYTE(modreader);
else
break;
return 1;
}
static BOOL OKT_doPBOD(int patnum)
{
char *patbuf;
int rows, i;
int u;
if (!patnum) {
of.numtrk = of.numpat * of.numchn;
if (!AllocTracks() || !AllocPatterns())
return 0;
}
/* Read pattern */
of.pattrows[patnum] = rows = _mm_read_M_UWORD(modreader);
if (!(okttrk = (OKTNOTE *) _mm_calloc(rows, sizeof(OKTNOTE))) ||
!(patbuf = (char *)_mm_calloc(rows * of.numchn, sizeof(OKTNOTE))))
return 0;
_mm_read_UBYTES(patbuf, rows * of.numchn * sizeof(OKTNOTE), modreader);
if (_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
for (i = 0; i < of.numchn; i++) {
for (u = 0; u < rows; u++) {
okttrk[u].note = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE)];
okttrk[u].ins = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 1];
okttrk[u].eff = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 2];
okttrk[u].dat = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 3];
}
if (!(of.tracks[patnum * of.numchn + i] = OKT_ConvertTrack(rows)))
return 0;
}
_mm_free(patbuf);
_mm_free(okttrk);
return 1;
}
static void OKT_doSBOD(int insnum)
{
of.samples[insnum].seekpos = _mm_ftell(modreader);
}
BOOL OKT_Load(BOOL curious)
{
UBYTE id[4];
ULONG len;
ULONG fp;
BOOL seen_cmod = 0, seen_samp = 0, seen_slen = 0, seen_plen = 0, seen_patt
= 0, seen_spee = 0;
int patnum = 0, insnum = 0;
/* skip OKTALYZER header */
_mm_fseek(modreader, 8, SEEK_SET);
of.songname = strdup("");
of.modtype = strdup("Amiga Oktalyzer");
of.numpos = of.reppos = 0;
/* default values */
of.initspeed = 6;
of.inittempo = 125;
while (1) {
/* read block header */
_mm_read_UBYTES(id, 4, modreader);
len = _mm_read_M_ULONG(modreader);
if (_mm_eof(modreader))
break;
fp = _mm_ftell(modreader);
if (!memcmp(id, "CMOD", 4)) {
if (!seen_cmod) {
OKT_doCMOD();
seen_cmod = 1;
} else {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
} else if (!memcmp(id, "SAMP", 4)) {
if (!seen_samp && OKT_doSAMP(len))
seen_samp = 1;
else {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
} else if (!memcmp(id, "SPEE", 4)) {
if (!seen_spee) {
OKT_doSPEE();
seen_spee = 1;
} else {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
} else if (!memcmp(id, "SLEN", 4)) {
if (!seen_slen) {
OKT_doSLEN();
seen_slen = 1;
} else {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
} else if (!memcmp(id, "PLEN", 4)) {
if (!seen_plen) {
OKT_doPLEN();
seen_plen = 1;
} else {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
} else if (!memcmp(id, "PATT", 4)) {
if (!seen_plen) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
if (!seen_patt && OKT_doPATT())
seen_patt = 1;
else {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
} else if (!memcmp(id,"PBOD", 4)) {
/* need to know numpat and numchn */
if (!seen_slen || !seen_cmod || (patnum >= of.numpat)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
if (!OKT_doPBOD(patnum++)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
} else if (!memcmp(id,"SBOD",4)) {
/* need to know numsmp */
if (!seen_samp) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
while ((insnum < of.numins) && !of.samples[insnum].length)
insnum++;
if (insnum >= of.numins) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
OKT_doSBOD(insnum++);
}
/* goto next block start position */
_mm_fseek(modreader, fp + len, SEEK_SET);
}
if (!seen_cmod || !seen_samp || !seen_patt ||
!seen_slen || !seen_plen || (patnum != of.numpat)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
return 1;
}
CHAR *OKT_LoadTitle(void)
{
return strdup("");
}
/*========== Loader information */
MIKMODAPI MLOADER load_okt = {
NULL,
"OKT",
"OKT (Amiga Oktalyzer)",
NULL,
OKT_Test,
OKT_Load,
NULL,
OKT_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,470 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_s3m.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Screamtracker (S3M) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
/* header */
typedef struct S3MHEADER {
CHAR songname[28];
UBYTE t1a;
UBYTE type;
UBYTE unused1[2];
UWORD ordnum;
UWORD insnum;
UWORD patnum;
UWORD flags;
UWORD tracker;
UWORD fileformat;
CHAR scrm[4];
UBYTE mastervol;
UBYTE initspeed;
UBYTE inittempo;
UBYTE mastermult;
UBYTE ultraclick;
UBYTE pantable;
UBYTE unused2[8];
UWORD special;
UBYTE channels[32];
} S3MHEADER;
/* sample information */
typedef struct S3MSAMPLE {
UBYTE type;
CHAR filename[12];
UBYTE memsegh;
UWORD memsegl;
ULONG length;
ULONG loopbeg;
ULONG loopend;
UBYTE volume;
UBYTE dsk;
UBYTE pack;
UBYTE flags;
ULONG c2spd;
UBYTE unused[12];
CHAR sampname[28];
CHAR scrs[4];
} S3MSAMPLE;
typedef struct S3MNOTE {
UBYTE note,ins,vol,cmd,inf;
} S3MNOTE;
/*========== Loader variables */
static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */
static S3MHEADER *mh = NULL;
static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */
static unsigned int tracker; /* tracker id */
/* tracker identifiers */
#define NUMTRACKERS 4
static CHAR* S3M_Version[] = {
"Screamtracker x.xx",
"Imago Orpheus x.xx (S3M format)",
"Impulse Tracker x.xx (S3M format)",
"Unknown tracker x.xx (S3M format)",
"Impulse Tracker 2.14p3 (S3M format)",
"Impulse Tracker 2.14p4 (S3M format)"
};
/* version number position in above array */
static int numeric[NUMTRACKERS]={14,14,16,16};
/*========== Loader code */
BOOL S3M_Test(void)
{
UBYTE id[4];
_mm_fseek(modreader,0x2c,SEEK_SET);
if(!_mm_read_UBYTES(id,4,modreader)) return 0;
if(!memcmp(id,"SCRM",4)) return 1;
return 0;
}
BOOL S3M_Init(void)
{
if(!(s3mbuf=(S3MNOTE*)_mm_malloc(32*64*sizeof(S3MNOTE)))) return 0;
if(!(mh=(S3MHEADER*)_mm_malloc(sizeof(S3MHEADER)))) return 0;
if(!(poslookup=(UBYTE*)_mm_malloc(sizeof(UBYTE)*256))) return 0;
memset(poslookup,-1,256);
return 1;
}
void S3M_Cleanup(void)
{
_mm_free(s3mbuf);
_mm_free(paraptr);
_mm_free(poslookup);
_mm_free(mh);
_mm_free(origpositions);
}
/* Because so many s3m files have 16 channels as the set number used, but really
only use far less (usually 8 to 12 still), I had to make this function, which
determines the number of channels that are actually USED by a pattern.
For every channel that's used, it sets the appropriate array entry of the
global variable 'remap'
NOTE: You must first seek to the file location of the pattern before calling
this procedure.
Returns 1 on fail. */
static BOOL S3M_GetNumChannels(void)
{
int row=0,flag,ch;
while(row<64) {
flag=_mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 1;
}
if(flag) {
ch=flag&31;
if(mh->channels[ch]<32) remap[ch] = 0;
if(flag&32) {_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}
if(flag&64) _mm_read_UBYTE(modreader);
if(flag&128){_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}
} else row++;
}
return 0;
}
static BOOL S3M_ReadPattern(void)
{
int row=0,flag,ch;
S3MNOTE *n,dummy;
/* clear pattern data */
memset(s3mbuf,255,32*64*sizeof(S3MNOTE));
while(row<64) {
flag=_mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
if(flag) {
ch=remap[flag&31];
if(ch!=-1)
n=&s3mbuf[(64U*ch)+row];
else
n=&dummy;
if(flag&32) {
n->note=_mm_read_UBYTE(modreader);
n->ins=_mm_read_UBYTE(modreader);
}
if(flag&64) {
n->vol=_mm_read_UBYTE(modreader);
if (n->vol>64) n->vol=64;
}
if(flag&128) {
n->cmd=_mm_read_UBYTE(modreader);
n->inf=_mm_read_UBYTE(modreader);
}
} else row++;
}
return 1;
}
static UBYTE* S3M_ConvertTrack(S3MNOTE* tr)
{
int t;
UniReset();
for(t=0;t<64;t++) {
UBYTE note,ins,vol;
note=tr[t].note;
ins=tr[t].ins;
vol=tr[t].vol;
if((ins)&&(ins!=255)) UniInstrument(ins-1);
if(note!=255) {
if(note==254) {
UniPTEffect(0xc,0); /* note cut command */
vol=255;
} else
UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */
}
if(vol<255) UniPTEffect(0xc,vol);
S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,
tracker == 1 ? S3MIT_OLDSTYLE | S3MIT_SCREAM : S3MIT_OLDSTYLE);
UniNewline();
}
return UniDup();
}
BOOL S3M_Load(BOOL curious)
{
int t,u,track = 0;
SAMPLE *q;
UBYTE pan[32];
/* try to read module header */
_mm_read_string(mh->songname,28,modreader);
mh->t1a =_mm_read_UBYTE(modreader);
mh->type =_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->unused1,2,modreader);
mh->ordnum =_mm_read_I_UWORD(modreader);
mh->insnum =_mm_read_I_UWORD(modreader);
mh->patnum =_mm_read_I_UWORD(modreader);
mh->flags =_mm_read_I_UWORD(modreader);
mh->tracker =_mm_read_I_UWORD(modreader);
mh->fileformat =_mm_read_I_UWORD(modreader);
_mm_read_string(mh->scrm,4,modreader);
mh->mastervol =_mm_read_UBYTE(modreader);
mh->initspeed =_mm_read_UBYTE(modreader);
mh->inittempo =_mm_read_UBYTE(modreader);
mh->mastermult =_mm_read_UBYTE(modreader);
mh->ultraclick =_mm_read_UBYTE(modreader);
mh->pantable =_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->unused2,8,modreader);
mh->special =_mm_read_I_UWORD(modreader);
_mm_read_UBYTES(mh->channels,32,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* then we can decide the module type */
tracker=mh->tracker>>12;
if((!tracker)||(tracker>=NUMTRACKERS))
tracker=NUMTRACKERS-1; /* unknown tracker */
else {
if(mh->tracker>=0x3217)
tracker=NUMTRACKERS+1; /* IT 2.14p4 */
else if(mh->tracker>=0x3216)
tracker=NUMTRACKERS; /* IT 2.14p3 */
else tracker--;
}
of.modtype = strdup(S3M_Version[tracker]);
if(tracker<NUMTRACKERS) {
of.modtype[numeric[tracker]] = ((mh->tracker>>8) &0xf)+'0';
of.modtype[numeric[tracker]+2] = ((mh->tracker>>4)&0xf)+'0';
of.modtype[numeric[tracker]+3] = ((mh->tracker)&0xf)+'0';
}
/* set module variables */
of.songname = DupStr(mh->songname,28,0);
of.numpat = mh->patnum;
of.reppos = 0;
of.numins = of.numsmp = mh->insnum;
of.initspeed = mh->initspeed;
of.inittempo = mh->inittempo;
of.initvolume = mh->mastervol<<1;
of.flags |= UF_ARPMEM | UF_PANNING;
if((mh->tracker==0x1300)||(mh->flags&64))
of.flags|=UF_S3MSLIDES;
of.bpmlimit = 32;
/* read the order data */
if(!AllocPositions(mh->ordnum)) return 0;
if(!(origpositions=_mm_calloc(mh->ordnum,sizeof(UWORD)))) return 0;
for(t=0;t<mh->ordnum;t++) {
origpositions[t]=_mm_read_UBYTE(modreader);
if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254))
origpositions[t]=255/*mh->patnum-1*/;
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
poslookupcnt=mh->ordnum;
S3MIT_CreateOrders(curious);
if(!(paraptr=(UWORD*)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD))))
return 0;
/* read the instrument+pattern parapointers */
_mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader);
if(mh->pantable==252) {
/* read the panning table (ST 3.2 addition. See below for further
portions of channel panning [past reampper]). */
_mm_read_UBYTES(pan,32,modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* load samples */
if(!AllocSamples()) return 0;
q = of.samples;
for(t=0;t<of.numins;t++) {
S3MSAMPLE s;
/* seek to instrument position */
_mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);
/* and load sample info */
s.type =_mm_read_UBYTE(modreader);
_mm_read_string(s.filename,12,modreader);
s.memsegh =_mm_read_UBYTE(modreader);
s.memsegl =_mm_read_I_UWORD(modreader);
s.length =_mm_read_I_ULONG(modreader);
s.loopbeg =_mm_read_I_ULONG(modreader);
s.loopend =_mm_read_I_ULONG(modreader);
s.volume =_mm_read_UBYTE(modreader);
s.dsk =_mm_read_UBYTE(modreader);
s.pack =_mm_read_UBYTE(modreader);
s.flags =_mm_read_UBYTE(modreader);
s.c2spd =_mm_read_I_ULONG(modreader);
_mm_read_UBYTES(s.unused,12,modreader);
_mm_read_string(s.sampname,28,modreader);
_mm_read_string(s.scrs,4,modreader);
/* ScreamTracker imposes a 64000 bytes (not 64k !) limit */
if (s.length > 64000)
s.length = 64000;
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->samplename = DupStr(s.sampname,28,0);
q->speed = s.c2spd;
q->length = s.length;
q->loopstart = s.loopbeg;
q->loopend = s.loopend;
q->volume = s.volume;
q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4;
if(s.flags&1) q->flags |= SF_LOOP;
if(s.flags&4) q->flags |= SF_16BITS;
if(mh->fileformat==1) q->flags |= SF_SIGNED;
/* don't load sample if it doesn't have the SCRS tag */
if(memcmp(s.scrs,"SCRS",4)) q->length = 0;
q++;
}
/* determine the number of channels actually used. */
of.numchn = 0;
memset(remap,-1,32*sizeof(UBYTE));
for(t=0;t<of.numpat;t++) {
/* seek to pattern position (+2 skip pattern length) */
_mm_fseek(modreader,(long)((paraptr[of.numins+t])<<4)+2,SEEK_SET);
if(S3M_GetNumChannels()) return 0;
}
/* build the remap array */
for(t=0;t<32;t++)
if(!remap[t])
remap[t]=of.numchn++;
/* set panning positions after building remap chart! */
for(t=0;t<32;t++)
if((mh->channels[t]<32)&&(remap[t]!=-1)) {
if(mh->channels[t]<8)
of.panning[remap[t]]=0x30;
else
of.panning[remap[t]]=0xc0;
}
if(mh->pantable==252)
/* set panning positions according to panning table (new for st3.2) */
for(t=0;t<32;t++)
if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1))
of.panning[remap[t]]=(pan[t]&0xf)<<4;
/* load pattern info */
of.numtrk=of.numpat*of.numchn;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
for(t=0;t<of.numpat;t++) {
/* seek to pattern position (+2 skip pattern length) */
_mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);
if(!S3M_ReadPattern()) return 0;
for(u=0;u<of.numchn;u++)
if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;
}
return 1;
}
CHAR *S3M_LoadTitle(void)
{
CHAR s[28];
_mm_fseek(modreader,0,SEEK_SET);
if(!_mm_read_UBYTES(s,28,modreader)) return NULL;
return(DupStr(s,28,0));
}
/*========== Loader information */
MIKMODAPI MLOADER load_s3m={
NULL,
"S3M",
"S3M (Scream Tracker 3)",
S3M_Init,
S3M_Test,
S3M_Load,
S3M_Cleanup,
S3M_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,374 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_stm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Screamtracker 2 (STM) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
/* sample information */
typedef struct STMSAMPLE {
CHAR filename[12];
UBYTE unused; /* 0x00 */
UBYTE instdisk; /* Instrument disk */
UWORD reserved;
UWORD length; /* Sample length */
UWORD loopbeg; /* Loop start point */
UWORD loopend; /* Loop end point */
UBYTE volume; /* Volume */
UBYTE reserved2;
UWORD c2spd; /* Good old c2spd */
ULONG reserved3;
UWORD isa;
} STMSAMPLE;
/* header */
typedef struct STMHEADER {
CHAR songname[20];
CHAR trackername[8]; /* !Scream! for ST 2.xx */
UBYTE unused; /* 0x1A */
UBYTE filetype; /* 1=song, 2=module */
UBYTE ver_major;
UBYTE ver_minor;
UBYTE inittempo; /* initspeed= stm inittempo>>4 */
UBYTE numpat; /* number of patterns */
UBYTE globalvol;
UBYTE reserved[13];
STMSAMPLE sample[31]; /* STM sample data */
UBYTE patorder[128]; /* Docs say 64 - actually 128 */
} STMHEADER;
typedef struct STMNOTE {
UBYTE note,insvol,volcmd,cmdinf;
} STMNOTE;
/*========== Loader variables */
static STMNOTE *stmbuf = NULL;
static STMHEADER *mh = NULL;
/* tracker identifiers */
static CHAR* STM_Version[STM_NTRACKERS] = {
"Screamtracker 2",
"Converted by MOD2STM (STM format)",
"Wuzamod (STM format)"
};
/*========== Loader code */
BOOL STM_Test(void)
{
UBYTE str[44];
int t;
_mm_fseek(modreader,20,SEEK_SET);
_mm_read_UBYTES(str,44,modreader);
if(str[9]!=2) return 0; /* STM Module = filetype 2 */
/* Prevent false positives for S3M files */
if(!memcmp(str+40,"SCRM",4))
return 0;
for (t=0;t<STM_NTRACKERS;t++)
if(!memcmp(str,STM_Signatures[t],8))
return 1;
return 0;
}
BOOL STM_Init(void)
{
if(!(mh=(STMHEADER*)_mm_malloc(sizeof(STMHEADER)))) return 0;
if(!(stmbuf=(STMNOTE*)_mm_calloc(64U*4,sizeof(STMNOTE)))) return 0;
return 1;
}
static void STM_Cleanup(void)
{
_mm_free(mh);
_mm_free(stmbuf);
}
static void STM_ConvertNote(STMNOTE *n)
{
UBYTE note,ins,vol,cmd,inf;
/* extract the various information from the 4 bytes that make up a note */
note = n->note;
ins = n->insvol>>3;
vol = (n->insvol&7)+((n->volcmd&0x70)>>1);
cmd = n->volcmd&15;
inf = n->cmdinf;
if((ins)&&(ins<32)) UniInstrument(ins-1);
/* special values of [SBYTE0] are handled here
we have no idea if these strange values will ever be encountered.
but it appears as those stms sound correct. */
if((note==254)||(note==252)) {
UniPTEffect(0xc,0); /* note cut */
n->volcmd|=0x80;
} else
/* if note < 251, then all three bytes are stored in the file */
if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf));
if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol);
if(cmd!=255)
switch(cmd) {
case 1: /* Axx set speed to xx */
UniPTEffect(0xf,inf>>4);
break;
case 2: /* Bxx position jump */
UniPTEffect(0xb,inf);
break;
case 3: /* Cxx patternbreak to row xx */
UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));
break;
case 4: /* Dxy volumeslide */
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 5: /* Exy toneslide down */
UniEffect(UNI_S3MEFFECTE,inf);
break;
case 6: /* Fxy toneslide up */
UniEffect(UNI_S3MEFFECTF,inf);
break;
case 7: /* Gxx Tone portamento,speed xx */
UniPTEffect(0x3,inf);
break;
case 8: /* Hxy vibrato */
UniPTEffect(0x4,inf);
break;
case 9: /* Ixy tremor, ontime x, offtime y */
UniEffect(UNI_S3MEFFECTI,inf);
break;
case 0: /* protracker arpeggio */
if(!inf) break;
/* fall through */
case 0xa: /* Jxy arpeggio */
UniPTEffect(0x0,inf);
break;
case 0xb: /* Kxy Dual command H00 & Dxy */
UniPTEffect(0x4,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xc: /* Lxy Dual command G00 & Dxy */
UniPTEffect(0x3,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
/* Support all these above, since ST2 can LOAD these values but can
actually only play up to J - and J is only half-way implemented
in ST2 */
case 0x18: /* Xxx amiga panning command 8xx */
UniPTEffect(0x8,inf);
of.flags |= UF_PANNING;
break;
}
}
static UBYTE *STM_ConvertTrack(STMNOTE *n)
{
int t;
UniReset();
for(t=0;t<64;t++) {
STM_ConvertNote(n);
UniNewline();
n+=of.numchn;
}
return UniDup();
}
static BOOL STM_LoadPatterns(void)
{
int t,s,tracks=0;
if(!AllocPatterns()) return 0;
if(!AllocTracks()) return 0;
/* Allocate temporary buffer for loading and converting the patterns */
for(t=0;t<of.numpat;t++) {
for(s=0;s<(64U*of.numchn);s++) {
stmbuf[s].note = _mm_read_UBYTE(modreader);
stmbuf[s].insvol = _mm_read_UBYTE(modreader);
stmbuf[s].volcmd = _mm_read_UBYTE(modreader);
stmbuf[s].cmdinf = _mm_read_UBYTE(modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
for(s=0;s<of.numchn;s++)
if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
}
return 1;
}
BOOL STM_Load(BOOL curious)
{
int t;
ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */
SAMPLE *q;
/* try to read stm header */
_mm_read_string(mh->songname,20,modreader);
_mm_read_string(mh->trackername,8,modreader);
mh->unused =_mm_read_UBYTE(modreader);
mh->filetype =_mm_read_UBYTE(modreader);
mh->ver_major =_mm_read_UBYTE(modreader);
mh->ver_minor =_mm_read_UBYTE(modreader);
mh->inittempo =_mm_read_UBYTE(modreader);
if(!mh->inittempo) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
mh->numpat =_mm_read_UBYTE(modreader);
mh->globalvol =_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh->reserved,13,modreader);
for(t=0;t<31;t++) {
STMSAMPLE *s=&mh->sample[t]; /* STM sample data */
_mm_read_string(s->filename,12,modreader);
s->unused =_mm_read_UBYTE(modreader);
s->instdisk =_mm_read_UBYTE(modreader);
s->reserved =_mm_read_I_UWORD(modreader);
s->length =_mm_read_I_UWORD(modreader);
s->loopbeg =_mm_read_I_UWORD(modreader);
s->loopend =_mm_read_I_UWORD(modreader);
s->volume =_mm_read_UBYTE(modreader);
s->reserved2=_mm_read_UBYTE(modreader);
s->c2spd =_mm_read_I_UWORD(modreader);
s->reserved3=_mm_read_I_ULONG(modreader);
s->isa =_mm_read_I_UWORD(modreader);
}
_mm_read_UBYTES(mh->patorder,128,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
for(t=0;t<STM_NTRACKERS;t++)
if(!memcmp(mh->trackername,STM_Signatures[t],8)) break;
of.modtype = strdup(STM_Version[t]);
of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */
of.numpat = mh->numpat;
of.inittempo = 125; /* mh->inittempo+0x1c; */
of.initspeed = mh->inittempo>>4;
of.numchn = 4; /* get number of channels */
of.reppos = 0;
of.flags |= UF_S3MSLIDES;
of.bpmlimit = 32;
t=0;
if(!AllocPositions(0x80)) return 0;
/* 99 terminates the patorder list */
while((mh->patorder[t]<=99)&&(mh->patorder[t]<mh->numpat)) {
of.positions[t]=mh->patorder[t];
t++;
}
if(mh->patorder[t]<=99) t++;
of.numpos=t;
of.numtrk=of.numpat*of.numchn;
of.numins=of.numsmp=31;
if(!AllocSamples()) return 0;
if(!STM_LoadPatterns()) return 0;
MikMod_ISA=_mm_ftell(modreader);
MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
for(q=of.samples,t=0;t<of.numsmp;t++,q++) {
/* load sample info */
q->samplename = DupStr(mh->sample[t].filename,12,1);
q->speed = (mh->sample[t].c2spd * 8363) / 8448;
q->volume = mh->sample[t].volume;
q->length = mh->sample[t].length;
if (/*(!mh->sample[t].volume)||*/(q->length==1)) q->length=0;
q->loopstart = mh->sample[t].loopbeg;
q->loopend = mh->sample[t].loopend;
q->seekpos = MikMod_ISA;
MikMod_ISA+=q->length;
MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */
/* contrary to the STM specs, sample data is signed */
q->flags = SF_SIGNED;
if(q->loopend && q->loopend != 0xffff)
q->flags|=SF_LOOP;
}
return 1;
}
CHAR *STM_LoadTitle(void)
{
CHAR s[20];
_mm_fseek(modreader,0,SEEK_SET);
if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
return(DupStr(s,20,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_stm={
NULL,
"STM",
"STM (Scream Tracker)",
STM_Init,
STM_Test,
STM_Load,
STM_Cleanup,
STM_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,439 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_stx.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
STMIK 0.2 (STX) module loader
==============================================================================*/
/*
Written by Claudio Matsuoka <claudio@helllabs.org>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
/* header */
typedef struct STXHEADER {
CHAR songname[20];
CHAR trackername[8];
UWORD patsize;
UWORD unknown1;
UWORD patptr;
UWORD insptr;
UWORD chnptr; /* not sure */
UWORD unknown2;
UWORD unknown3;
UBYTE mastermult;
UBYTE initspeed;
UWORD unknown4;
UWORD unknown5;
UWORD patnum;
UWORD insnum;
UWORD ordnum;
UWORD unknown6;
UWORD unknown7;
UWORD unknown8;
CHAR scrm[4];
} STXHEADER;
/* sample information */
typedef struct STXSAMPLE {
UBYTE type;
CHAR filename[12];
UBYTE memsegh;
UWORD memsegl;
ULONG length;
ULONG loopbeg;
ULONG loopend;
UBYTE volume;
UBYTE dsk;
UBYTE pack;
UBYTE flags;
ULONG c2spd;
UBYTE unused[12];
CHAR sampname[28];
CHAR scrs[4];
} STXSAMPLE;
typedef struct STXNOTE {
UBYTE note,ins,vol,cmd,inf;
} STXNOTE;
/*========== Loader variables */
static STXNOTE *stxbuf = NULL; /* pointer to a complete STX pattern */
static STXHEADER *mh = NULL;
static UWORD *paraptr = NULL; /* parapointer array (see STX docs) */
/*========== Loader code */
static BOOL STX_Test(void)
{
UBYTE id[8];
int t;
_mm_fseek(modreader,0x3C,SEEK_SET);
if(!_mm_read_UBYTES(id,4,modreader)) return 0;
if(memcmp(id,"SCRM",4)) return 0;
_mm_fseek(modreader,0x14,SEEK_SET);
if(!_mm_read_UBYTES(id,8,modreader)) return 0;
for(t=0;t<STM_NTRACKERS;t++)
if(!memcmp(id,STM_Signatures[t],8)) return 1;
return 0;
}
static BOOL STX_Init(void)
{
if(!(stxbuf=(STXNOTE*)_mm_malloc(4*64*sizeof(STXNOTE)))) return 0;
if(!(mh=(STXHEADER*)_mm_malloc(sizeof(STXHEADER)))) return 0;
if(!(poslookup=(UBYTE*)_mm_malloc(sizeof(UBYTE)*256))) return 0;
memset(poslookup,-1,256);
return 1;
}
static void STX_Cleanup(void)
{
_mm_free(stxbuf);
_mm_free(paraptr);
_mm_free(poslookup);
_mm_free(mh);
}
static BOOL STX_ReadPattern(void)
{
int row=0,flag,ch;
STXNOTE *n,dummy;
/* clear pattern data */
memset(stxbuf,255,4*64*sizeof(STXNOTE));
while(row<64) {
flag=_mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_PATTERN;
return 0;
}
if(flag) {
ch=flag&31;
if((ch>=0)&&(ch<4))
n=&stxbuf[(64U*ch)+row];
else
n=&dummy;
if(flag&32) {
n->note=_mm_read_UBYTE(modreader);
n->ins=_mm_read_UBYTE(modreader);
}
if(flag&64) {
n->vol=_mm_read_UBYTE(modreader);
if(n->vol>64) n->vol=64;
}
if(flag&128) {
n->cmd=_mm_read_UBYTE(modreader);
n->inf=_mm_read_UBYTE(modreader);
}
} else row++;
}
return 1;
}
static UBYTE* STX_ConvertTrack(STXNOTE* tr)
{
int t;
UniReset();
for(t=0;t<64;t++) {
UBYTE note,ins,vol,cmd,inf;
note=tr[t].note;
ins=tr[t].ins;
vol=tr[t].vol;
cmd=tr[t].cmd;
inf=tr[t].inf;
if((ins)&&(ins!=255)) UniInstrument(ins-1);
if((note)&&(note!=255)) {
if(note==254) {
UniPTEffect(0xc,0); /* note cut command */
vol=255;
} else UniNote(24+((note>>4)*OCTAVE)+(note&0xf)); /* normal note */
}
if(vol<255) UniPTEffect(0xc,vol);
if(cmd<255) switch(cmd) {
case 1: /* Axx set speed to xx */
UniPTEffect(0xf,inf>>4);
break;
case 2: /* Bxx position jump */
UniPTEffect(0xb,inf);
break;
case 3: /* Cxx patternbreak to row xx */
UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf));
break;
case 4: /* Dxy volumeslide */
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 5: /* Exy toneslide down */
UniEffect(UNI_S3MEFFECTE,inf);
break;
case 6: /* Fxy toneslide up */
UniEffect(UNI_S3MEFFECTF,inf);
break;
case 7: /* Gxx Tone portamento,speed xx */
UniPTEffect(0x3,inf);
break;
case 8: /* Hxy vibrato */
UniPTEffect(0x4,inf);
break;
case 9: /* Ixy tremor, ontime x, offtime y */
UniEffect(UNI_S3MEFFECTI,inf);
break;
case 0: /* protracker arpeggio */
if(!inf) break;
/* fall through */
case 0xa: /* Jxy arpeggio */
UniPTEffect(0x0,inf);
break;
case 0xb: /* Kxy Dual command H00 & Dxy */
UniPTEffect(0x4,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xc: /* Lxy Dual command G00 & Dxy */
UniPTEffect(0x3,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
/* Support all these above, since ST2 can LOAD these values but can
actually only play up to J - and J is only half-way implemented
in ST2 */
case 0x18: /* Xxx amiga panning command 8xx */
UniPTEffect(0x8,inf);
of.flags |= UF_PANNING;
break;
}
UniNewline();
}
return UniDup();
}
static BOOL STX_Load(BOOL curious)
{
int t,u,track = 0;
int version = 0;
SAMPLE *q;
/* try to read module header */
_mm_read_string(mh->songname,20,modreader);
_mm_read_string(mh->trackername,8,modreader);
mh->patsize =_mm_read_I_UWORD(modreader);
mh->unknown1 =_mm_read_I_UWORD(modreader);
mh->patptr =_mm_read_I_UWORD(modreader);
mh->insptr =_mm_read_I_UWORD(modreader);
mh->chnptr =_mm_read_I_UWORD(modreader);
mh->unknown2 =_mm_read_I_UWORD(modreader);
mh->unknown3 =_mm_read_I_UWORD(modreader);
mh->mastermult =_mm_read_UBYTE(modreader);
mh->initspeed =_mm_read_UBYTE(modreader)>>4;
mh->unknown4 =_mm_read_I_UWORD(modreader);
mh->unknown5 =_mm_read_I_UWORD(modreader);
mh->patnum =_mm_read_I_UWORD(modreader);
mh->insnum =_mm_read_I_UWORD(modreader);
mh->ordnum =_mm_read_I_UWORD(modreader);
mh->unknown6 =_mm_read_I_UWORD(modreader);
mh->unknown7 =_mm_read_I_UWORD(modreader);
mh->unknown8 =_mm_read_I_UWORD(modreader);
_mm_read_string(mh->scrm,4,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.songname = DupStr(mh->songname,20,1);
of.numpat = mh->patnum;
of.reppos = 0;
of.numins = of.numsmp = mh->insnum;
of.initspeed = mh->initspeed;
of.inittempo = 125;
of.numchn = 4;
of.flags |= UF_S3MSLIDES;
of.bpmlimit = 32;
if(!(paraptr=(UWORD*)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD))))
return 0;
/* read the instrument+pattern parapointers */
_mm_fseek(modreader,mh->insptr<<4,SEEK_SET);
_mm_read_I_UWORDS(paraptr,of.numins,modreader);
_mm_fseek(modreader,mh->patptr<<4,SEEK_SET);
_mm_read_I_UWORDS(paraptr+of.numins,of.numpat,modreader);
/* check module version */
_mm_fseek(modreader,paraptr[of.numins]<<4,SEEK_SET);
version=_mm_read_I_UWORD(modreader);
if(version==mh->patsize) {
version = 0x10;
of.modtype = strdup("STMIK 0.2 (STM2STX 1.0)");
} else {
version = 0x11;
of.modtype = strdup("STMIK 0.2 (STM2STX 1.1)");
}
/* read the order data */
_mm_fseek(modreader,(mh->chnptr<<4)+32,SEEK_SET);
if(!AllocPositions(mh->ordnum)) return 0;
for(t=0;t<mh->ordnum;t++) {
of.positions[t]=_mm_read_UBYTE(modreader);
_mm_fseek(modreader,4,SEEK_CUR);
}
of.numpos=0;poslookupcnt=mh->ordnum;
for(t=0;t<mh->ordnum;t++) {
int order=of.positions[t];
if(order==255) order=LAST_PATTERN;
of.positions[of.numpos]=order;
poslookup[t]=of.numpos; /* bug fix for freaky S3Ms */
if(of.positions[t]<254) of.numpos++;
else
/* special end of song pattern */
if((order==LAST_PATTERN)&&(!curious)) break;
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* load samples */
if(!AllocSamples()) return 0;
for(q=of.samples,t=0;t<of.numins;t++,q++) {
STXSAMPLE s;
/* seek to instrument position */
_mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);
/* and load sample info */
s.type =_mm_read_UBYTE(modreader);
_mm_read_string(s.filename,12,modreader);
s.memsegh =_mm_read_UBYTE(modreader);
s.memsegl =_mm_read_I_UWORD(modreader);
s.length =_mm_read_I_ULONG(modreader);
s.loopbeg =_mm_read_I_ULONG(modreader);
s.loopend =_mm_read_I_ULONG(modreader);
s.volume =_mm_read_UBYTE(modreader);
s.dsk =_mm_read_UBYTE(modreader);
s.pack =_mm_read_UBYTE(modreader);
s.flags =_mm_read_UBYTE(modreader);
s.c2spd =_mm_read_I_ULONG(modreader);
_mm_read_UBYTES(s.unused,12,modreader);
_mm_read_string(s.sampname,28,modreader);
_mm_read_string(s.scrs,4,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->samplename = DupStr(s.sampname,28,1);
q->speed = (s.c2spd * 8363) / 8448;
q->length = s.length;
q->loopstart = s.loopbeg;
q->loopend = s.loopend;
q->volume = s.volume;
q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4;
q->flags |= SF_SIGNED;
if(s.flags&1) q->flags |= SF_LOOP;
if(s.flags&4) q->flags |= SF_16BITS;
}
/* load pattern info */
of.numtrk=of.numpat*of.numchn;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
for(t=0;t<of.numpat;t++) {
/* seek to pattern position (+2 skip pattern length) */
_mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+
(version==0x10?2:0),SEEK_SET);
if(!STX_ReadPattern()) return 0;
for(u=0;u<of.numchn;u++)
if(!(of.tracks[track++]=STX_ConvertTrack(&stxbuf[u*64]))) return 0;
}
return 1;
}
static CHAR *STX_LoadTitle(void)
{
CHAR s[28];
_mm_fseek(modreader,0,SEEK_SET);
if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
return(DupStr(s,28,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_stx={
NULL,
"STX",
"STX (Scream Tracker Music Interface Kit)",
STX_Init,
STX_Test,
STX_Load,
STX_Cleanup,
STX_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,335 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_ult.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Ultratracker (ULT) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
/* header */
typedef struct ULTHEADER {
CHAR id[16];
CHAR songtitle[32];
UBYTE reserved;
} ULTHEADER;
/* sample information */
typedef struct ULTSAMPLE {
CHAR samplename[32];
CHAR dosname[12];
SLONG loopstart;
SLONG loopend;
SLONG sizestart;
SLONG sizeend;
UBYTE volume;
UBYTE flags;
UWORD speed;
SWORD finetune;
} ULTSAMPLE;
typedef struct ULTEVENT {
UBYTE note,sample,eff,dat1,dat2;
} ULTEVENT;
/*========== Loader variables */
#define ULTS_16BITS 4
#define ULTS_LOOP 8
#define ULTS_REVERSE 16
#define ULT_VERSION_LEN 18
static CHAR ULT_Version[ULT_VERSION_LEN]="Ultra Tracker v1.x";
static ULTEVENT ev;
/*========== Loader code */
BOOL ULT_Test(void)
{
CHAR id[16];
if(!_mm_read_string(id,15,modreader)) return 0;
if(strncmp(id,"MAS_UTrack_V00",14)) return 0;
if((id[14]<'1')||(id[14]>'4')) return 0;
return 1;
}
BOOL ULT_Init(void)
{
return 1;
}
void ULT_Cleanup(void)
{
}
static UBYTE ReadUltEvent(ULTEVENT* event)
{
UBYTE flag,rep=1;
flag = _mm_read_UBYTE(modreader);
if(flag==0xfc) {
rep = _mm_read_UBYTE(modreader);
event->note =_mm_read_UBYTE(modreader);
} else
event->note = flag;
event->sample =_mm_read_UBYTE(modreader);
event->eff =_mm_read_UBYTE(modreader);
event->dat1 =_mm_read_UBYTE(modreader);
event->dat2 =_mm_read_UBYTE(modreader);
return rep;
}
BOOL ULT_Load(BOOL curious)
{
int t,u,tracks=0;
SAMPLE *q;
ULTSAMPLE s;
ULTHEADER mh;
UBYTE nos,noc,nop;
/* try to read module header */
_mm_read_string(mh.id,15,modreader);
_mm_read_string(mh.songtitle,32,modreader);
mh.reserved=_mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
ULT_Version[ULT_VERSION_LEN-1]='3'+(mh.id[14]-'1');
of.modtype = DupStr(ULT_Version,ULT_VERSION_LEN,1);
of.initspeed = 6;
of.inittempo = 125;
of.reppos = 0;
/* read songtext */
if ((mh.id[14]>'1')&&(mh.reserved))
if(!ReadLinedComment(mh.reserved * 32, 32)) return 0;
nos=_mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
of.songname=DupStr(mh.songtitle,32,1);
of.numins=of.numsmp=nos;
if(!AllocSamples()) return 0;
q = of.samples;
for(t=0;t<nos;t++) {
/* try to read sample info */
_mm_read_string(s.samplename,32,modreader);
_mm_read_string(s.dosname,12,modreader);
s.loopstart =_mm_read_I_ULONG(modreader);
s.loopend =_mm_read_I_ULONG(modreader);
s.sizestart =_mm_read_I_ULONG(modreader);
s.sizeend =_mm_read_I_ULONG(modreader);
s.volume =_mm_read_UBYTE(modreader);
s.flags =_mm_read_UBYTE(modreader);
s.speed =(mh.id[14]>='4')?_mm_read_I_UWORD(modreader):8363;
s.finetune =_mm_read_I_SWORD(modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
q->samplename=DupStr(s.samplename,32,1);
/* The correct formula for the coefficient would be
pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
here, we'll use a first order approximation here.
1/567290 == Ln(2)/OCTAVE/32768 */
q->speed=s.speed+s.speed*(((SLONG)s.speed*(SLONG)s.finetune)/567290);
q->length = s.sizeend-s.sizestart;
q->volume = s.volume>>2;
q->loopstart = s.loopstart;
q->loopend = s.loopend;
q->flags = SF_SIGNED;
if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;
if(s.flags&ULTS_16BITS) {
s.sizeend+=(s.sizeend-s.sizestart);
s.sizestart<<=1;
q->flags|=SF_16BITS;
q->loopstart>>=1;
q->loopend>>=1;
}
q++;
}
if(!AllocPositions(256)) return 0;
for(t=0;t<256;t++)
of.positions[t]=_mm_read_UBYTE(modreader);
for(t=0;t<256;t++)
if(of.positions[t]==255) {
of.positions[t]=LAST_PATTERN;
break;
}
of.numpos=t;
noc=_mm_read_UBYTE(modreader);
nop=_mm_read_UBYTE(modreader);
of.numchn=++noc;
of.numpat=++nop;
of.numtrk=of.numchn*of.numpat;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
for(u=0;u<of.numchn;u++)
for(t=0;t<of.numpat;t++)
of.patterns[(t*of.numchn)+u]=tracks++;
/* read pan position table for v1.5 and higher */
if(mh.id[14]>='3') {
for(t=0;t<of.numchn;t++) of.panning[t]=_mm_read_UBYTE(modreader)<<4;
of.flags |= UF_PANNING;
}
for(t=0;t<of.numtrk;t++) {
int rep,row=0;
UniReset();
while(row<64) {
rep=ReadUltEvent(&ev);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_TRACK;
return 0;
}
while(rep--) {
UBYTE eff;
int offset;
if(ev.sample) UniInstrument(ev.sample-1);
if(ev.note) UniNote(ev.note+2*OCTAVE-1);
/* first effect - various fixes by Alexander Kerkhove and
Thomas Neumann */
eff = ev.eff>>4;
switch(eff) {
case 0x3: /* tone portamento */
UniEffect(UNI_ITEFFECTG,ev.dat2);
break;
case 0x5:
break;
case 0x9: /* sample offset */
offset=(ev.dat2<<8)|((ev.eff&0xf)==9?ev.dat1:0);
UniEffect(UNI_ULTEFFECT9,offset);
break;
case 0xb: /* panning */
UniPTEffect(8,ev.dat2*0xf);
of.flags |= UF_PANNING;
break;
case 0xc: /* volume */
UniPTEffect(eff,ev.dat2>>2);
break;
default:
UniPTEffect(eff,ev.dat2);
break;
}
/* second effect */
eff=ev.eff&0xf;
switch(eff) {
case 0x3: /* tone portamento */
UniEffect(UNI_ITEFFECTG,ev.dat1);
break;
case 0x5:
break;
case 0x9: /* sample offset */
if((ev.eff>>4)!=9)
UniEffect(UNI_ULTEFFECT9,((UWORD)ev.dat1)<<8);
break;
case 0xb: /* panning */
UniPTEffect(8,ev.dat1*0xf);
of.flags |= UF_PANNING;
break;
case 0xc: /* volume */
UniPTEffect(eff,ev.dat1>>2);
break;
default:
UniPTEffect(eff,ev.dat1);
break;
}
UniNewline();
row++;
}
}
if(!(of.tracks[t]=UniDup())) return 0;
}
return 1;
}
CHAR *ULT_LoadTitle(void)
{
CHAR s[32];
_mm_fseek(modreader,15,SEEK_SET);
if(!_mm_read_UBYTES(s,32,modreader)) return NULL;
return(DupStr(s,32,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_ult={
NULL,
"ULT",
"ULT (UltraTracker)",
ULT_Init,
ULT_Test,
ULT_Load,
ULT_Cleanup,
ULT_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,717 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_uni.c,v 1.2 2004/02/06 19:29:03 raph Exp $
UNIMOD (libmikmod's and APlayer's internal module format) loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
typedef struct UNIHEADER {
CHAR id[4];
UBYTE numchn;
UWORD numpos;
UWORD reppos;
UWORD numpat;
UWORD numtrk;
UWORD numins;
UWORD numsmp;
UBYTE initspeed;
UBYTE inittempo;
UBYTE initvolume;
UWORD flags;
UBYTE numvoices;
UWORD bpmlimit;
UBYTE positions[256];
UBYTE panning[32];
} UNIHEADER;
typedef struct UNISMP05 {
UWORD c2spd;
UWORD transpose;
UBYTE volume;
UBYTE panning;
ULONG length;
ULONG loopstart;
ULONG loopend;
UWORD flags;
CHAR* samplename;
UBYTE vibtype;
UBYTE vibsweep;
UBYTE vibdepth;
UBYTE vibrate;
} UNISMP05;
/*========== Loader variables */
static UWORD universion;
static UNIHEADER mh;
#define UNI_SMPINCR 64
static UNISMP05 *wh=NULL,*s=NULL;
/*========== Loader code */
static char* readstring(void)
{
char *s=NULL;
UWORD len;
len=_mm_read_I_UWORD(modreader);
if(len) {
s=_mm_malloc(len+1);
_mm_read_UBYTES(s,len,modreader);
s[len]=0;
}
return s;
}
BOOL UNI_Test(void)
{
char id[6];
if(!_mm_read_UBYTES(id,6,modreader)) return 0;
/* UNIMod created by MikCvt */
if(!(memcmp(id,"UN0",3))) {
if((id[3]>='4')&&(id[3]<='6')) return 1;
}
/* UNIMod created by APlayer */
if(!(memcmp(id,"APUN\01",5))) {
if((id[5]>=1)&&(id[5]<=6)) return 1;
}
return 0;
}
BOOL UNI_Init(void)
{
return 1;
}
void UNI_Cleanup(void)
{
_mm_free(wh);
s=NULL;
}
static UBYTE* readtrack(void)
{
UBYTE *t;
UWORD len;
int cur=0,chunk;
if(universion>=6)
len=_mm_read_M_UWORD(modreader);
else
len=_mm_read_I_UWORD(modreader);
if(!len) return NULL;
if(!(t=_mm_malloc(len))) return NULL;
_mm_read_UBYTES(t,len,modreader);
/* Check if the track is correct */
while(1) {
chunk=t[cur++];
if(!chunk) break;
chunk=(chunk&0x1f)-1;
while(chunk>0) {
int opcode,oplen;
if(cur>=len) {
free(t);
return NULL;
}
opcode=t[cur];
/* Remap opcodes */
if (universion <= 5) {
if (opcode > 29) {
free(t);
return NULL;
}
switch (opcode) {
/* UNI_NOTE .. UNI_S3MEFFECTQ are the same */
case 25:
opcode = UNI_S3MEFFECTT;
break;
case 26:
opcode = UNI_XMEFFECTA;
break;
case 27:
opcode = UNI_XMEFFECTG;
break;
case 28:
opcode = UNI_XMEFFECTH;
break;
case 29:
opcode = UNI_XMEFFECTP;
break;
}
} else {
/* APlayer < 1.05 does not have XMEFFECT6 */
if (opcode >= UNI_XMEFFECT6 && universion < 0x105)
opcode++;
/* APlayer < 1.03 does not have ITEFFECTT */
if (opcode >= UNI_ITEFFECTT && universion < 0x103)
opcode++;
/* APlayer < 1.02 does not have ITEFFECTZ */
if (opcode >= UNI_ITEFFECTZ && universion < 0x102)
opcode++;
}
if((!opcode)||(opcode>=UNI_LAST)) {
free(t);
return NULL;
}
t[cur]=opcode;
oplen=unioperands[opcode]+1;
cur+=oplen;
chunk-=oplen;
}
if((chunk<0)||(cur>=len)) {
free(t);
return NULL;
}
}
return t;
}
static BOOL loadsmp6(void)
{
int t;
SAMPLE *s;
s=of.samples;
for(t=0;t<of.numsmp;t++,s++) {
int flags;
flags = _mm_read_M_UWORD(modreader);
s->flags=0;
if(flags&0x0004) s->flags|=SF_STEREO;
if(flags&0x0002) s->flags|=SF_SIGNED;
if(flags&0x0001) s->flags|=SF_16BITS;
/* convert flags */
if(universion>=0x104) {
if(flags&0x2000) s->flags|=SF_UST_LOOP;
if(flags&0x1000) s->flags|=SF_OWNPAN;
if(flags&0x0800) s->flags|=SF_SUSTAIN;
if(flags&0x0400) s->flags|=SF_REVERSE;
if(flags&0x0200) s->flags|=SF_BIDI;
if(flags&0x0100) s->flags|=SF_LOOP;
if(flags&0x0020) s->flags|=SF_ITPACKED;
if(flags&0x0010) s->flags|=SF_DELTA;
if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;
} else if(universion>=0x102) {
if(flags&0x0800) s->flags|=SF_UST_LOOP;
if(flags&0x0400) s->flags|=SF_OWNPAN;
if(flags&0x0200) s->flags|=SF_SUSTAIN;
if(flags&0x0100) s->flags|=SF_REVERSE;
if(flags&0x0080) s->flags|=SF_BIDI;
if(flags&0x0040) s->flags|=SF_LOOP;
if(flags&0x0020) s->flags|=SF_ITPACKED;
if(flags&0x0010) s->flags|=SF_DELTA;
if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;
} else {
if(flags&0x400) s->flags|=SF_UST_LOOP;
if(flags&0x200) s->flags|=SF_OWNPAN;
if(flags&0x100) s->flags|=SF_REVERSE;
if(flags&0x080) s->flags|=SF_SUSTAIN;
if(flags&0x040) s->flags|=SF_BIDI;
if(flags&0x020) s->flags|=SF_LOOP;
if(flags&0x010) s->flags|=SF_BIG_ENDIAN;
if(flags&0x008) s->flags|=SF_DELTA;
}
s->speed = _mm_read_M_ULONG(modreader);
s->volume = _mm_read_UBYTE(modreader);
s->panning = _mm_read_M_UWORD(modreader);
s->length = _mm_read_M_ULONG(modreader);
s->loopstart = _mm_read_M_ULONG(modreader);
s->loopend = _mm_read_M_ULONG(modreader);
s->susbegin = _mm_read_M_ULONG(modreader);
s->susend = _mm_read_M_ULONG(modreader);
s->globvol = _mm_read_UBYTE(modreader);
s->vibflags = _mm_read_UBYTE(modreader);
s->vibtype = _mm_read_UBYTE(modreader);
s->vibsweep = _mm_read_UBYTE(modreader);
s->vibdepth = _mm_read_UBYTE(modreader);
s->vibrate = _mm_read_UBYTE(modreader);
s->samplename=readstring();
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
return 1;
}
static BOOL loadinstr6(void)
{
int t,w;
INSTRUMENT *i;
i=of.instruments;
for(t=0;t<of.numins;t++,i++) {
i->flags = _mm_read_UBYTE(modreader);
i->nnatype = _mm_read_UBYTE(modreader);
i->dca = _mm_read_UBYTE(modreader);
i->dct = _mm_read_UBYTE(modreader);
i->globvol = _mm_read_UBYTE(modreader);
i->panning = _mm_read_M_UWORD(modreader);
i->pitpansep = _mm_read_UBYTE(modreader);
i->pitpancenter = _mm_read_UBYTE(modreader);
i->rvolvar = _mm_read_UBYTE(modreader);
i->rpanvar = _mm_read_UBYTE(modreader);
i->volfade = _mm_read_M_UWORD(modreader);
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define UNI_LoadEnvelope6(name) \
i-> name##flg=_mm_read_UBYTE(modreader); \
i-> name##pts=_mm_read_UBYTE(modreader); \
i-> name##susbeg=_mm_read_UBYTE(modreader); \
i-> name##susend=_mm_read_UBYTE(modreader); \
i-> name##beg=_mm_read_UBYTE(modreader); \
i-> name##end=_mm_read_UBYTE(modreader); \
for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) { \
i-> name##env[w].pos=_mm_read_M_SWORD(modreader); \
i-> name##env[w].val=_mm_read_M_SWORD(modreader); \
}
#else
#define UNI_LoadEnvelope6(name) \
i-> name/**/flg=_mm_read_UBYTE(modreader); \
i-> name/**/pts=_mm_read_UBYTE(modreader); \
i-> name/**/susbeg=_mm_read_UBYTE(modreader); \
i-> name/**/susend=_mm_read_UBYTE(modreader); \
i-> name/**/beg=_mm_read_UBYTE(modreader); \
i-> name/**/end=_mm_read_UBYTE(modreader); \
for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) { \
i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader); \
i-> name/**/env[w].val=_mm_read_M_SWORD(modreader); \
}
#endif
UNI_LoadEnvelope6(vol);
UNI_LoadEnvelope6(pan);
UNI_LoadEnvelope6(pit);
#undef UNI_LoadEnvelope6
if(universion>=0x103)
_mm_read_M_UWORDS(i->samplenumber,120,modreader);
else
for(w=0;w<120;w++)
i->samplenumber[w]=_mm_read_UBYTE(modreader);
_mm_read_UBYTES(i->samplenote,120,modreader);
i->insname=readstring();
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
return 1;
}
static BOOL loadinstr5(void)
{
INSTRUMENT *i;
int t;
UWORD wavcnt=0;
UBYTE vibtype,vibsweep,vibdepth,vibrate;
i=of.instruments;
for(of.numsmp=t=0;t<of.numins;t++,i++) {
int u,numsmp;
numsmp=_mm_read_UBYTE(modreader);
memset(i->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
for(u=0;u<96;u++)
i->samplenumber[u]=of.numsmp+_mm_read_UBYTE(modreader);
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define UNI_LoadEnvelope5(name) \
i-> name##flg=_mm_read_UBYTE(modreader); \
i-> name##pts=_mm_read_UBYTE(modreader); \
i-> name##susbeg=_mm_read_UBYTE(modreader); \
i-> name##susend=i-> name##susbeg; \
i-> name##beg=_mm_read_UBYTE(modreader); \
i-> name##end=_mm_read_UBYTE(modreader); \
for(u=0;u<12;u++) { \
i-> name##env[u].pos=_mm_read_I_SWORD(modreader); \
i-> name##env[u].val=_mm_read_I_SWORD(modreader); \
}
#else
#define UNI_LoadEnvelope5(name) \
i-> name/**/flg=_mm_read_UBYTE(modreader); \
i-> name/**/pts=_mm_read_UBYTE(modreader); \
i-> name/**/susbeg=_mm_read_UBYTE(modreader); \
i-> name/**/susend=i-> name/**/susbeg; \
i-> name/**/beg=_mm_read_UBYTE(modreader); \
i-> name/**/end=_mm_read_UBYTE(modreader); \
for(u=0;u<12;u++) { \
i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader); \
i-> name/**/env[u].val=_mm_read_I_SWORD(modreader); \
}
#endif
UNI_LoadEnvelope5(vol);
UNI_LoadEnvelope5(pan);
#undef UNI_LoadEnvelope5
vibtype =_mm_read_UBYTE(modreader);
vibsweep =_mm_read_UBYTE(modreader);
vibdepth =_mm_read_UBYTE(modreader);
vibrate =_mm_read_UBYTE(modreader);
i->volfade=_mm_read_I_UWORD(modreader);
i->insname=readstring();
for(u=0;u<numsmp;u++,s++,of.numsmp++) {
/* Allocate more room for sample information if necessary */
if(of.numsmp+u==wavcnt) {
wavcnt+=UNI_SMPINCR;
if(!(wh=realloc(wh,wavcnt*sizeof(UNISMP05)))) {
_mm_errno=MMERR_OUT_OF_MEMORY;
return 0;
}
s=wh+(wavcnt-UNI_SMPINCR);
}
s->c2spd =_mm_read_I_UWORD(modreader);
s->transpose=_mm_read_SBYTE(modreader);
s->volume =_mm_read_UBYTE(modreader);
s->panning =_mm_read_UBYTE(modreader);
s->length =_mm_read_I_ULONG(modreader);
s->loopstart=_mm_read_I_ULONG(modreader);
s->loopend =_mm_read_I_ULONG(modreader);
s->flags =_mm_read_I_UWORD(modreader);
s->samplename=readstring();
s->vibtype =vibtype;
s->vibsweep=vibsweep;
s->vibdepth=vibdepth;
s->vibrate =vibrate;
if(_mm_eof(modreader)) {
free(wh);wh=NULL;
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
}
/* sanity check */
if(!of.numsmp) {
if(wh) { free(wh);wh=NULL; }
_mm_errno=MMERR_LOADING_SAMPLEINFO;
return 0;
}
return 1;
}
static BOOL loadsmp5(void)
{
int t,u;
SAMPLE *q;
INSTRUMENT *d;
q=of.samples;s=wh;
for(u=0;u<of.numsmp;u++,q++,s++) {
q->samplename=s->samplename;
q->length =s->length;
q->loopstart=s->loopstart;
q->loopend =s->loopend;
q->volume =s->volume;
q->speed =s->c2spd;
q->panning =s->panning;
q->vibtype =s->vibtype;
q->vibsweep =s->vibsweep;
q->vibdepth =s->vibdepth;
q->vibrate =s->vibrate;
/* convert flags */
q->flags=0;
if(s->flags&128) q->flags|=SF_REVERSE;
if(s->flags& 64) q->flags|=SF_SUSTAIN;
if(s->flags& 32) q->flags|=SF_BIDI;
if(s->flags& 16) q->flags|=SF_LOOP;
if(s->flags& 8) q->flags|=SF_BIG_ENDIAN;
if(s->flags& 4) q->flags|=SF_DELTA;
if(s->flags& 2) q->flags|=SF_SIGNED;
if(s->flags& 1) q->flags|=SF_16BITS;
}
d=of.instruments;s=wh;
for(u=0;u<of.numins;u++,d++)
for(t=0;t<INSTNOTES;t++)
d->samplenote[t]=(d->samplenumber[t]>=of.numsmp)?
255:(t+s[d->samplenumber[t]].transpose);
free(wh);wh=NULL;
return 1;
}
BOOL UNI_Load(BOOL curious)
{
int t;
char *modtype,*oldtype=NULL;
INSTRUMENT *d;
SAMPLE *q;
/* read module header */
_mm_read_UBYTES(mh.id,4,modreader);
if(mh.id[3]!='N')
universion=mh.id[3]-'0';
else
universion=0x100;
if(universion>=6) {
if (universion==6)
_mm_read_UBYTE(modreader);
else
universion=_mm_read_M_UWORD(modreader);
mh.flags =_mm_read_M_UWORD(modreader);
mh.numchn =_mm_read_UBYTE(modreader);
mh.numvoices =_mm_read_UBYTE(modreader);
mh.numpos =_mm_read_M_UWORD(modreader);
mh.numpat =_mm_read_M_UWORD(modreader);
mh.numtrk =_mm_read_M_UWORD(modreader);
mh.numins =_mm_read_M_UWORD(modreader);
mh.numsmp =_mm_read_M_UWORD(modreader);
mh.reppos =_mm_read_M_UWORD(modreader);
mh.initspeed =_mm_read_UBYTE(modreader);
mh.inittempo =_mm_read_UBYTE(modreader);
mh.initvolume=_mm_read_UBYTE(modreader);
/* I expect this to show up soon in APlayer 1.06 format */
if (universion >= 0x106)
mh.bpmlimit=_mm_read_M_UWORD(modreader);
else
mh.bpmlimit=32;
mh.flags &= UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA;
mh.flags |= UF_PANNING;
} else {
mh.numchn =_mm_read_UBYTE(modreader);
mh.numpos =_mm_read_I_UWORD(modreader);
mh.reppos =(universion==5)?_mm_read_I_UWORD(modreader):0;
mh.numpat =_mm_read_I_UWORD(modreader);
mh.numtrk =_mm_read_I_UWORD(modreader);
mh.numins =_mm_read_I_UWORD(modreader);
mh.initspeed =_mm_read_UBYTE(modreader);
mh.inittempo =_mm_read_UBYTE(modreader);
_mm_read_UBYTES(mh.positions,256,modreader);
_mm_read_UBYTES(mh.panning,32,modreader);
mh.flags =_mm_read_UBYTE(modreader);
mh.bpmlimit =32;
mh.flags &= UF_XMPERIODS | UF_LINEAR;
mh.flags |= UF_INST | UF_NOWRAP | UF_PANNING;
}
/* set module parameters */
of.flags =mh.flags;
of.numchn =mh.numchn;
of.numpos =mh.numpos;
of.numpat =mh.numpat;
of.numtrk =mh.numtrk;
of.numins =mh.numins;
of.reppos =mh.reppos;
of.initspeed =mh.initspeed;
of.inittempo =mh.inittempo;
if(mh.bpmlimit)
of.bpmlimit=mh.bpmlimit;
else
/* be bug-compatible with older releases */
of.bpmlimit=32;
of.songname=readstring();
if(universion<0x102)
oldtype=readstring();
if(oldtype) {
int len=strlen(oldtype)+20;
if(!(modtype=_mm_malloc(len))) return 0;
#ifdef HAVE_SNPRINTF
snprintf(modtype,len,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);
#else
sprintf(modtype,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);
#endif
} else {
if(!(modtype=_mm_malloc(10))) return 0;
#ifdef HAVE_SNPRINTF
snprintf(modtype,10,"%s",(universion>=0x100)?"APlayer":"MikCvt3");
#else
sprintf(modtype,"%s",(universion>=0x100)?"APlayer":"MikCvt3");
#endif
}
of.modtype=strdup(modtype);
free(modtype);free(oldtype);
of.comment=readstring();
if(universion>=6) {
of.numvoices=mh.numvoices;
of.initvolume=mh.initvolume;
}
if(_mm_eof(modreader)) {
_mm_errno=MMERR_LOADING_HEADER;
return 0;
}
/* positions */
if(!AllocPositions(of.numpos)) return 0;
if(universion>=6) {
if(universion>=0x100)
_mm_read_M_UWORDS(of.positions,of.numpos,modreader);
else
for(t=0;t<of.numpos;t++) of.positions[t]=_mm_read_UBYTE(modreader);
_mm_read_M_UWORDS(of.panning,of.numchn,modreader);
_mm_read_UBYTES(of.chanvol,of.numchn,modreader);
} else {
if((mh.numpos>256)||(mh.numchn>32)) {
_mm_errno=MMERR_LOADING_HEADER;
return 0;
}
for(t=0;t<of.numpos;t++) of.positions[t]=mh.positions[t];
for(t=0;t<of.numchn;t++) of.panning[t]=mh.panning[t];
}
/* convert the ``end of song'' pattern code if necessary */
if(universion<0x106)
for(t=0;t<of.numpos;t++)
if(of.positions[t]==255) of.positions[t]=LAST_PATTERN;
/* instruments and samples */
if(universion>=6) {
of.numsmp=mh.numsmp;
if(!AllocSamples()) return 0;
if(!loadsmp6()) return 0;
if(of.flags&UF_INST) {
if(!AllocInstruments()) return 0;
if(!loadinstr6()) return 0;
}
} else {
if(!AllocInstruments()) return 0;
if(!loadinstr5()) return 0;
if(!AllocSamples()) {
if(wh) { free(wh);wh=NULL; }
return 0;
}
if(!loadsmp5()) return 0;
/* check if the original file had no instruments */
if(of.numsmp==of.numins) {
for(t=0,d=of.instruments;t<of.numins;t++,d++) {
int u;
if((d->volpts)||(d->panpts)||(d->globvol!=64)) break;
for(u=0;u<96;u++)
if((d->samplenumber[u]!=t)||(d->samplenote[u]!=u)) break;
if(u!=96) break;
}
if(t==of.numins) {
of.flags&=~UF_INST;
of.flags&=~UF_NOWRAP;
for(t=0,d=of.instruments,q=of.samples;t<of.numins;t++,d++,q++) {
q->samplename=d->insname;
d->insname=NULL;
}
}
}
}
/* patterns */
if(!AllocPatterns()) return 0;
if(universion>=6) {
_mm_read_M_UWORDS(of.pattrows,of.numpat,modreader);
_mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modreader);
} else {
_mm_read_I_UWORDS(of.pattrows,of.numpat,modreader);
_mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modreader);
}
/* tracks */
if(!AllocTracks()) return 0;
for(t=0;t<of.numtrk;t++)
if(!(of.tracks[t]=readtrack())) {
_mm_errno=MMERR_LOADING_TRACK;
return 0;
}
return 1;
}
CHAR *UNI_LoadTitle(void)
{
UBYTE ver;
int posit[3]={304,306,26};
_mm_fseek(modreader,3,SEEK_SET);
ver=_mm_read_UBYTE(modreader);
if(ver=='N') ver='6';
_mm_fseek(modreader,posit[ver-'4'],SEEK_SET);
return readstring();
}
/*========== Loader information */
MIKMODAPI MLOADER load_uni={
NULL,
"UNI",
"APUN (APlayer) and UNI (MikMod)",
UNI_Init,
UNI_Test,
UNI_Load,
UNI_Cleanup,
UNI_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,815 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: load_xm.c,v 1.2 2004/02/06 19:29:03 raph Exp $
Fasttracker (XM) module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Module structure */
typedef struct XMHEADER {
CHAR id[17]; /* ID text: 'Extended module: ' */
CHAR songname[21]; /* Module name */
CHAR trackername[20]; /* Tracker name */
UWORD version; /* Version number */
ULONG headersize; /* Header size */
UWORD songlength; /* Song length (in patten order table) */
UWORD restart; /* Restart position */
UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */
UWORD numpat; /* Number of patterns (max 256) */
UWORD numins; /* Number of instruments (max 128) */
UWORD flags;
UWORD tempo; /* Default tempo */
UWORD bpm; /* Default BPM */
UBYTE orders[256]; /* Pattern order table */
} XMHEADER;
typedef struct XMINSTHEADER {
ULONG size; /* Instrument size */
CHAR name[22]; /* Instrument name */
UBYTE type; /* Instrument type (always 0) */
UWORD numsmp; /* Number of samples in instrument */
ULONG ssize;
} XMINSTHEADER;
#define XMENVCNT (12*2)
#define XMNOTECNT (8*OCTAVE)
typedef struct XMPATCHHEADER {
UBYTE what[XMNOTECNT]; /* Sample number for all notes */
UWORD volenv[XMENVCNT]; /* Points for volume envelope */
UWORD panenv[XMENVCNT]; /* Points for panning envelope */
UBYTE volpts; /* Number of volume points */
UBYTE panpts; /* Number of panning points */
UBYTE volsus; /* Volume sustain point */
UBYTE volbeg; /* Volume loop start point */
UBYTE volend; /* Volume loop end point */
UBYTE pansus; /* Panning sustain point */
UBYTE panbeg; /* Panning loop start point */
UBYTE panend; /* Panning loop end point */
UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */
UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */
UBYTE vibflg; /* Vibrato type */
UBYTE vibsweep; /* Vibrato sweep */
UBYTE vibdepth; /* Vibrato depth */
UBYTE vibrate; /* Vibrato rate */
UWORD volfade; /* Volume fadeout */
} XMPATCHHEADER;
typedef struct XMWAVHEADER {
ULONG length; /* Sample length */
ULONG loopstart; /* Sample loop start */
ULONG looplength; /* Sample loop length */
UBYTE volume; /* Volume */
SBYTE finetune; /* Finetune (signed byte -128..+127) */
UBYTE type; /* Loop type */
UBYTE panning; /* Panning (0-255) */
SBYTE relnote; /* Relative note number (signed byte) */
UBYTE reserved;
CHAR samplename[22]; /* Sample name */
UBYTE vibtype; /* Vibrato type */
UBYTE vibsweep; /* Vibrato sweep */
UBYTE vibdepth; /* Vibrato depth */
UBYTE vibrate; /* Vibrato rate */
} XMWAVHEADER;
typedef struct XMPATHEADER {
ULONG size; /* Pattern header length */
UBYTE packing; /* Packing type (always 0) */
UWORD numrows; /* Number of rows in pattern (1..256) */
SWORD packsize; /* Packed patterndata size */
} XMPATHEADER;
typedef struct XMNOTE {
UBYTE note,ins,vol,eff,dat;
} XMNOTE;
/*========== Loader variables */
static XMNOTE *xmpat=NULL;
static XMHEADER *mh=NULL;
/* increment unit for sample array reallocation */
#define XM_SMPINCR 64
static ULONG *nextwav=NULL;
static XMWAVHEADER *wh=NULL,*s=NULL;
/*========== Loader code */
BOOL XM_Test(void)
{
UBYTE id[38];
if(!_mm_read_UBYTES(id,38,modreader)) return 0;
if(memcmp(id,"Extended Module: ",17)) return 0;
if(id[37]==0x1a) return 1;
return 0;
}
BOOL XM_Init(void)
{
if(!(mh=(XMHEADER *)_mm_malloc(sizeof(XMHEADER)))) return 0;
return 1;
}
void XM_Cleanup(void)
{
_mm_free(mh);
}
static int XM_ReadNote(XMNOTE* n)
{
UBYTE cmp,result=1;
memset(n,0,sizeof(XMNOTE));
cmp=_mm_read_UBYTE(modreader);
if(cmp&0x80) {
if(cmp&1) { result++;n->note = _mm_read_UBYTE(modreader); }
if(cmp&2) { result++;n->ins = _mm_read_UBYTE(modreader); }
if(cmp&4) { result++;n->vol = _mm_read_UBYTE(modreader); }
if(cmp&8) { result++;n->eff = _mm_read_UBYTE(modreader); }
if(cmp&16) { result++;n->dat = _mm_read_UBYTE(modreader); }
} else {
n->note = cmp;
n->ins = _mm_read_UBYTE(modreader);
n->vol = _mm_read_UBYTE(modreader);
n->eff = _mm_read_UBYTE(modreader);
n->dat = _mm_read_UBYTE(modreader);
result += 4;
}
return result;
}
static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows)
{
int t;
UBYTE note,ins,vol,eff,dat;
UniReset();
for(t=0;t<rows;t++) {
note = xmtrack->note;
ins = xmtrack->ins;
vol = xmtrack->vol;
eff = xmtrack->eff;
dat = xmtrack->dat;
if(note) {
if(note>XMNOTECNT)
UniEffect(UNI_KEYFADE,0);
else
UniNote(note-1);
}
if(ins) UniInstrument(ins-1);
switch(vol>>4) {
case 0x6: /* volslide down */
if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf);
break;
case 0x7: /* volslide up */
if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4);
break;
/* volume-row fine volume slide is compatible with protracker
EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as
opposed to 'take the last sliding value'. */
case 0x8: /* finevol down */
UniPTEffect(0xe,0xb0|(vol&0xf));
break;
case 0x9: /* finevol up */
UniPTEffect(0xe,0xa0|(vol&0xf));
break;
case 0xa: /* set vibrato speed */
UniEffect(UNI_XMEFFECT4,vol<<4);
break;
case 0xb: /* vibrato */
UniEffect(UNI_XMEFFECT4,vol&0xf);
break;
case 0xc: /* set panning */
UniPTEffect(0x8,vol<<4);
break;
case 0xd: /* panning slide left (only slide when data not zero) */
if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf);
break;
case 0xe: /* panning slide right (only slide when data not zero) */
if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4);
break;
case 0xf: /* tone porta */
UniPTEffect(0x3,vol<<4);
break;
default:
if((vol>=0x10)&&(vol<=0x50))
UniPTEffect(0xc,vol-0x10);
}
switch(eff) {
case 0x4:
UniEffect(UNI_XMEFFECT4,dat);
break;
case 0x6:
UniEffect(UNI_XMEFFECT6,dat);
break;
case 0xa:
UniEffect(UNI_XMEFFECTA,dat);
break;
case 0xe: /* Extended effects */
switch(dat>>4) {
case 0x1: /* XM fine porta up */
UniEffect(UNI_XMEFFECTE1,dat&0xf);
break;
case 0x2: /* XM fine porta down */
UniEffect(UNI_XMEFFECTE2,dat&0xf);
break;
case 0xa: /* XM fine volume up */
UniEffect(UNI_XMEFFECTEA,dat&0xf);
break;
case 0xb: /* XM fine volume down */
UniEffect(UNI_XMEFFECTEB,dat&0xf);
break;
default:
UniPTEffect(eff,dat);
}
break;
case 'G'-55: /* G - set global volume */
UniEffect(UNI_XMEFFECTG,dat>64?128:dat<<1);
break;
case 'H'-55: /* H - global volume slide */
UniEffect(UNI_XMEFFECTH,dat);
break;
case 'K'-55: /* K - keyOff and KeyFade */
UniEffect(UNI_KEYFADE,dat);
break;
case 'L'-55: /* L - set envelope position */
UniEffect(UNI_XMEFFECTL,dat);
break;
case 'P'-55: /* P - panning slide */
UniEffect(UNI_XMEFFECTP,dat);
break;
case 'R'-55: /* R - multi retrig note */
UniEffect(UNI_S3MEFFECTQ,dat);
break;
case 'T'-55: /* T - Tremor */
UniEffect(UNI_S3MEFFECTI,dat);
break;
case 'X'-55:
switch(dat>>4) {
case 1: /* X1 - Extra Fine Porta up */
UniEffect(UNI_XMEFFECTX1,dat&0xf);
break;
case 2: /* X2 - Extra Fine Porta down */
UniEffect(UNI_XMEFFECTX2,dat&0xf);
break;
}
break;
default:
if(eff<=0xf) {
/* the pattern jump destination is written in decimal,
but it seems some poor tracker software writes them
in hexadecimal... (sigh) */
if (eff==0xd)
/* don't change anything if we're sure it's in hexa */
if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9))
/* otherwise, convert from dec to hex */
dat=(((dat&0xf0)>>4)*10)+(dat&0xf);
UniPTEffect(eff,dat);
}
break;
}
UniNewline();
xmtrack++;
}
return UniDup();
}
static BOOL LoadPatterns(BOOL dummypat)
{
int t,u,v,numtrk;
if(!AllocTracks()) return 0;
if(!AllocPatterns()) return 0;
numtrk=0;
for(t=0;t<mh->numpat;t++) {
XMPATHEADER ph;
ph.size =_mm_read_I_ULONG(modreader);
if (ph.size<(mh->version==0x0102?8:9)) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
ph.packing =_mm_read_UBYTE(modreader);
if(ph.packing) {
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
if(mh->version==0x0102)
ph.numrows =_mm_read_UBYTE(modreader)+1;
else
ph.numrows =_mm_read_I_UWORD(modreader);
ph.packsize =_mm_read_I_UWORD(modreader);
ph.size-=(mh->version==0x0102?8:9);
if(ph.size)
_mm_fseek(modreader,ph.size,SEEK_CUR);
of.pattrows[t]=ph.numrows;
if(ph.numrows) {
if(!(xmpat=(XMNOTE*)_mm_calloc(ph.numrows*of.numchn,sizeof(XMNOTE))))
return 0;
/* when packsize is 0, don't try to load a pattern.. it's empty. */
if(ph.packsize)
for(u=0;u<ph.numrows;u++)
for(v=0;v<of.numchn;v++) {
if(!ph.packsize) break;
ph.packsize-=XM_ReadNote(&xmpat[(v*ph.numrows)+u]);
if(ph.packsize<0) {
free(xmpat);xmpat=NULL;
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
}
if(ph.packsize) {
_mm_fseek(modreader,ph.packsize,SEEK_CUR);
}
if(_mm_eof(modreader)) {
free(xmpat);xmpat=NULL;
_mm_errno=MMERR_LOADING_PATTERN;
return 0;
}
for(v=0;v<of.numchn;v++)
of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);
free(xmpat);xmpat=NULL;
} else {
for(v=0;v<of.numchn;v++)
of.tracks[numtrk++]=XM_Convert(NULL,ph.numrows);
}
}
if(dummypat) {
of.pattrows[t]=64;
if(!(xmpat=(XMNOTE*)_mm_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0;
for(v=0;v<of.numchn;v++)
of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64);
free(xmpat);xmpat=NULL;
}
return 1;
}
static void FixEnvelope(ENVPT *cur, int pts)
{
int u, old, tmp;
ENVPT *prev;
/* Some broken XM editing program will only save the low byte
of the position value. Try to compensate by adding the
missing high byte. */
prev = cur++;
old = prev->pos;
for (u = 1; u < pts; u++, prev++, cur++) {
if (cur->pos < prev->pos) {
if (cur->pos < 0x100) {
if (cur->pos > old) /* same hex century */
tmp = cur->pos + (prev->pos - old);
else
tmp = cur->pos | ((prev->pos + 0x100) & 0xff00);
old = cur->pos;
cur->pos = tmp;
#ifdef MIKMOD_DEBUG
fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d -> %d\n",
u, pts, prev->pos, old, cur->pos);
#endif
} else {
#ifdef MIKMOD_DEBUG
/* different brokenness style... fix unknown */
fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d\n",
u, pts, old, cur->pos);
#endif
old = cur->pos;
}
} else
old = cur->pos;
}
}
static BOOL LoadInstruments(void)
{
int t,u;
INSTRUMENT *d;
ULONG next=0;
UWORD wavcnt=0;
if(!AllocInstruments()) return 0;
d=of.instruments;
for(t=0;t<of.numins;t++,d++) {
XMINSTHEADER ih;
long headend;
memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
/* read instrument header */
headend = _mm_ftell(modreader);
ih.size = _mm_read_I_ULONG(modreader);
headend += ih.size;
_mm_read_string(ih.name, 22, modreader);
ih.type = _mm_read_UBYTE(modreader);
ih.numsmp = _mm_read_I_UWORD(modreader);
d->insname = DupStr(ih.name,22,1);
if((SWORD)ih.size>29) {
ih.ssize = _mm_read_I_ULONG(modreader);
if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) {
XMPATCHHEADER pth;
int p;
_mm_read_UBYTES (pth.what,XMNOTECNT,modreader);
_mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader);
_mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader);
pth.volpts = _mm_read_UBYTE(modreader);
pth.panpts = _mm_read_UBYTE(modreader);
pth.volsus = _mm_read_UBYTE(modreader);
pth.volbeg = _mm_read_UBYTE(modreader);
pth.volend = _mm_read_UBYTE(modreader);
pth.pansus = _mm_read_UBYTE(modreader);
pth.panbeg = _mm_read_UBYTE(modreader);
pth.panend = _mm_read_UBYTE(modreader);
pth.volflg = _mm_read_UBYTE(modreader);
pth.panflg = _mm_read_UBYTE(modreader);
pth.vibflg = _mm_read_UBYTE(modreader);
pth.vibsweep = _mm_read_UBYTE(modreader);
pth.vibdepth = _mm_read_UBYTE(modreader);
pth.vibrate = _mm_read_UBYTE(modreader);
pth.volfade = _mm_read_I_UWORD(modreader);
/* read the remainder of the header
(2 bytes for 1.03, 22 for 1.04) */
for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);
/* we can't trust the envelope point count here, as some
modules have incorrect values (K_OSPACE.XM reports 32 volume
points, for example). */
if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2;
if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2;
if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) {
if(nextwav) { free(nextwav);nextwav=NULL; }
if(wh) { free(wh);wh=NULL; }
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
for(u=0;u<XMNOTECNT;u++)
d->samplenumber[u]=pth.what[u]+of.numsmp;
d->volfade = pth.volfade;
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define XM_ProcessEnvelope(name) \
for (u = 0; u < (XMENVCNT >> 1); u++) { \
d-> name##env[u].pos = pth. name##env[u << 1]; \
d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \
} \
if (pth. name##flg&1) d-> name##flg|=EF_ON; \
if (pth. name##flg&2) d-> name##flg|=EF_SUSTAIN; \
if (pth. name##flg&4) d-> name##flg|=EF_LOOP; \
d-> name##susbeg=d-> name##susend=pth. name##sus; \
d-> name##beg=pth. name##beg; \
d-> name##end=pth. name##end; \
d-> name##pts=pth. name##pts; \
\
/* scale envelope */ \
for (p=0;p<XMENVCNT/2;p++) \
d-> name##env[p].val<<=2; \
\
if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
d-> name##flg&=~EF_ON
#else
#define XM_ProcessEnvelope(name) \
for (u = 0; u < (XMENVCNT >> 1); u++) { \
d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \
d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \
} \
if (pth. name/**/flg&1) d-> name/**/flg|=EF_ON; \
if (pth. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \
if (pth. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \
d-> name/**/susbeg=d-> name/**/susend= \
pth. name/**/sus; \
d-> name/**/beg=pth. name/**/beg; \
d-> name/**/end=pth. name/**/end; \
d-> name/**/pts=pth. name/**/pts; \
\
/* scale envelope */ \
for (p=0;p<XMENVCNT/2;p++) \
d-> name/**/env[p].val<<=2; \
\
if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
d-> name/**/flg&=~EF_ON
#endif
XM_ProcessEnvelope(vol);
XM_ProcessEnvelope(pan);
#undef XM_ProcessEnvelope
if (d->volflg & EF_ON)
FixEnvelope(d->volenv, d->volpts);
if (d->panflg & EF_ON)
FixEnvelope(d->panenv, d->panpts);
/* Samples are stored outside the instrument struct now, so we
have to load them all into a temp area, count the of.numsmp
along the way and then do an AllocSamples() and move
everything over */
if(mh->version>0x0103) next = 0;
for(u=0;u<ih.numsmp;u++,s++) {
/* Allocate more room for sample information if necessary */
if(of.numsmp+u==wavcnt) {
wavcnt+=XM_SMPINCR;
if(!(nextwav=realloc(nextwav,wavcnt*sizeof(ULONG)))){
if(wh) { free(wh);wh=NULL; }
_mm_errno = MMERR_OUT_OF_MEMORY;
return 0;
}
if(!(wh=realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) {
free(nextwav);nextwav=NULL;
_mm_errno = MMERR_OUT_OF_MEMORY;
return 0;
}
s=wh+(wavcnt-XM_SMPINCR);
}
s->length =_mm_read_I_ULONG (modreader);
s->loopstart =_mm_read_I_ULONG (modreader);
s->looplength =_mm_read_I_ULONG (modreader);
s->volume =_mm_read_UBYTE (modreader);
s->finetune =_mm_read_SBYTE (modreader);
s->type =_mm_read_UBYTE (modreader);
s->panning =_mm_read_UBYTE (modreader);
s->relnote =_mm_read_SBYTE (modreader);
s->vibtype = pth.vibflg;
s->vibsweep = pth.vibsweep;
s->vibdepth = pth.vibdepth*4;
s->vibrate = pth.vibrate;
s->reserved =_mm_read_UBYTE (modreader);
_mm_read_string(s->samplename, 22, modreader);
nextwav[of.numsmp+u]=next;
next+=s->length;
if(_mm_eof(modreader)) {
free(nextwav);free(wh);
nextwav=NULL;wh=NULL;
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
if(mh->version>0x0103) {
for(u=0;u<ih.numsmp;u++)
nextwav[of.numsmp++]+=_mm_ftell(modreader);
_mm_fseek(modreader,next,SEEK_CUR);
} else
of.numsmp+=ih.numsmp;
} else {
/* read the remainder of the header */
for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);
if(_mm_eof(modreader)) {
free(nextwav);free(wh);
nextwav=NULL;wh=NULL;
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
}
}
}
/* sanity check */
if(!of.numsmp) {
if(nextwav) { free(nextwav);nextwav=NULL; }
if(wh) { free(wh);wh=NULL; }
_mm_errno = MMERR_LOADING_SAMPLEINFO;
return 0;
}
return 1;
}
BOOL XM_Load(BOOL curious)
{
INSTRUMENT *d;
SAMPLE *q;
int t,u;
BOOL dummypat=0;
char tracker[21],modtype[60];
/* try to read module header */
_mm_read_string(mh->id,17,modreader);
_mm_read_string(mh->songname,21,modreader);
_mm_read_string(mh->trackername,20,modreader);
mh->version =_mm_read_I_UWORD(modreader);
if((mh->version<0x102)||(mh->version>0x104)) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
mh->headersize =_mm_read_I_ULONG(modreader);
mh->songlength =_mm_read_I_UWORD(modreader);
mh->restart =_mm_read_I_UWORD(modreader);
mh->numchn =_mm_read_I_UWORD(modreader);
mh->numpat =_mm_read_I_UWORD(modreader);
mh->numins =_mm_read_I_UWORD(modreader);
mh->flags =_mm_read_I_UWORD(modreader);
mh->tempo =_mm_read_I_UWORD(modreader);
mh->bpm =_mm_read_I_UWORD(modreader);
if(!mh->bpm) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
_mm_read_UBYTES(mh->orders,256,modreader);
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
return 0;
}
/* set module variables */
of.initspeed = mh->tempo;
of.inittempo = mh->bpm;
strncpy(tracker,mh->trackername,20);tracker[20]=0;
for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0;
/* some modules have the tracker name empty */
if (!tracker[0])
strcpy(tracker,"Unknown tracker");
#ifdef HAVE_SNPRINTF
snprintf(modtype,60,"%s (XM format %d.%02d)",
tracker,mh->version>>8,mh->version&0xff);
#else
sprintf(modtype,"%s (XM format %d.%02d)",
tracker,mh->version>>8,mh->version&0xff);
#endif
of.modtype = strdup(modtype);
of.numchn = mh->numchn;
of.numpat = mh->numpat;
of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */
of.songname = DupStr(mh->songname,20,1);
of.numpos = mh->songlength; /* copy the songlength */
of.reppos = mh->restart<mh->songlength?mh->restart:0;
of.numins = mh->numins;
of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS |
UF_PANNING;
if(mh->flags&1) of.flags |= UF_LINEAR;
of.bpmlimit = 32;
memset(of.chanvol,64,of.numchn); /* store channel volumes */
if(!AllocPositions(of.numpos+1)) return 0;
for(t=0;t<of.numpos;t++)
of.positions[t]=mh->orders[t];
/* We have to check for any pattern numbers in the order list greater than
the number of patterns total. If one or more is found, we set it equal to
the pattern total and make a dummy pattern to workaround the problem */
for(t=0;t<of.numpos;t++) {
if(of.positions[t]>=of.numpat) {
of.positions[t]=of.numpat;
dummypat=1;
}
}
if(dummypat) {
of.numpat++;of.numtrk+=of.numchn;
}
if(mh->version<0x0104) {
if(!LoadInstruments()) return 0;
if(!LoadPatterns(dummypat)) return 0;
for(t=0;t<of.numsmp;t++)
nextwav[t]+=_mm_ftell(modreader);
} else {
if(!LoadPatterns(dummypat)) return 0;
if(!LoadInstruments()) return 0;
}
if(!AllocSamples()) {
free(nextwav);free(wh);
nextwav=NULL;wh=NULL;
return 0;
}
q = of.samples;
s = wh;
for(u=0;u<of.numsmp;u++,q++,s++) {
q->samplename = DupStr(s->samplename,22,1);
q->length = s->length;
q->loopstart = s->loopstart;
q->loopend = s->loopstart+s->looplength;
q->volume = s->volume;
q->speed = s->finetune+128;
q->panning = s->panning;
q->seekpos = nextwav[u];
q->vibtype = s->vibtype;
q->vibsweep = s->vibsweep;
q->vibdepth = s->vibdepth;
q->vibrate = s->vibrate;
if(s->type & 0x10) {
q->length >>= 1;
q->loopstart >>= 1;
q->loopend >>= 1;
}
q->flags|=SF_OWNPAN|SF_DELTA|SF_SIGNED;
if(s->type&0x3) q->flags|=SF_LOOP;
if(s->type&0x2) q->flags|=SF_BIDI;
if(s->type&0x10) q->flags|=SF_16BITS;
}
d=of.instruments;
s=wh;
for(u=0;u<of.numins;u++,d++)
for(t=0;t<XMNOTECNT;t++) {
if (d->samplenumber[t]>=of.numsmp)
d->samplenote[t]=255;
else {
int note=t+s[d->samplenumber[t]].relnote;
d->samplenote[t]=(note<0)?0:note;
}
}
free(wh);free(nextwav);
wh=NULL;nextwav=NULL;
return 1;
}
CHAR *XM_LoadTitle(void)
{
CHAR s[21];
_mm_fseek(modreader,17,SEEK_SET);
if(!_mm_read_UBYTES(s,21,modreader)) return NULL;
return(DupStr(s,21,1));
}
/*========== Loader information */
MIKMODAPI MLOADER load_xm={
NULL,
"XM",
"XM (FastTracker 2)",
XM_Init,
XM_Test,
XM_Load,
XM_Cleanup,
XM_LoadTitle
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,59 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mmalloc.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Dynamic memory routines
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
/* Same as malloc, but sets error variable _mm_error when fails */
void* _mm_malloc(size_t size)
{
void *d;
if(!(d=calloc(1,size))) {
_mm_errno = MMERR_OUT_OF_MEMORY;
if(_mm_errorhandler) _mm_errorhandler();
}
return d;
}
/* Same as calloc, but sets error variable _mm_error when fails */
void* _mm_calloc(size_t nitems,size_t size)
{
void *d;
if(!(d=calloc(nitems,size))) {
_mm_errno = MMERR_OUT_OF_MEMORY;
if(_mm_errorhandler) _mm_errorhandler();
}
return d;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,197 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mmerror.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Error handling functions.
Register an error handler with _mm_RegisterErrorHandler() and you're all set.
==============================================================================*/
/*
The global variables _mm_errno, and _mm_critical are set before the error
handler in called. See below for the values of these variables.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
CHAR *_mm_errmsg[MMERR_MAX+1] =
{
/* No error */
"No error",
/* Generic errors */
"Could not open requested file",
"Out of memory",
"Dynamic linking failed",
/* Sample errors */
"Out of memory to load sample",
"Out of sample handles to load sample",
"Sample format not recognized",
/* Module errors */
"Failure loading module pattern",
"Failure loading module track",
"Failure loading module header",
"Failure loading sampleinfo",
"Module format not recognized",
"Module sample format not recognized",
"Synthsounds not supported in MED files",
"Compressed sample is invalid",
/* Driver errors: */
"Sound device not detected",
"Device number out of range",
"Software mixer failure",
"Could not open sound device",
"This driver supports 8 bit linear output only",
"This driver supports 16 bit linear output only",
"This driver supports stereo output only",
"This driver supports uLaw output (8 bit mono, 8 kHz) only",
"Unable to set non-blocking mode for audio device",
/* AudioFile driver errors */
"Cannot find suitable AudioFile audio port",
/* AIX driver errors */
"Configuration (init step) of audio device failed",
"Configuration (control step) of audio device failed",
"Configuration (start step) of audio device failed",
/* ALSA driver errors */
/* EsounD driver errors */
/* Ultrasound driver errors */
"Ultrasound driver only works in 16 bit stereo 44 KHz",
"Ultrasound card could not be reset",
"Could not start Ultrasound timer",
/* HP driver errors */
"Unable to select 16bit-linear sample format",
"Could not select requested sample-rate",
"Could not select requested number of channels",
"Unable to select audio output",
"Unable to get audio description",
"Could not set transmission buffer size",
/* Open Sound System driver errors */
"Could not set fragment size",
"Could not set sample size",
"Could not set mono/stereo setting",
"Could not set sample rate",
/* SGI driver errors */
"Unsupported sample rate",
"Hardware does not support 16 bit sound",
"Hardware does not support 8 bit sound",
"Hardware does not support stereo sound",
"Hardware does not support mono sound",
/* Sun driver errors */
"Sound device initialization failed",
/* OS/2 drivers errors */
"Could not set mixing parameters",
"Could not create playback semaphores",
"Could not create playback timer",
"Could not create playback thread",
/* DirectSound driver errors */
"Could not set playback priority",
"Could not create playback buffers",
"Could not set playback format",
"Could not register callback",
"Could not register event",
"Could not create playback thread",
"Could not initialize playback thread",
/* Windows Multimedia API driver errors */
"Invalid device handle",
"The resource is already allocated",
"Invalid device identifier",
"Unsupported output format",
"Unknown error",
/* Macintosh driver errors */
"Unsupported sample rate",
"Could not start playback",
/* Invalid error */
"Invalid error code"
};
MIKMODAPI char *MikMod_strerror(int code)
{
if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX+1;
return _mm_errmsg[code];
}
/* User installed error callback */
MikMod_handler_t _mm_errorhandler = NULL;
MIKMODAPI int _mm_errno = 0;
MIKMODAPI BOOL _mm_critical = 0;
MikMod_handler_t _mm_registererrorhandler(MikMod_handler_t proc)
{
MikMod_handler_t oldproc=_mm_errorhandler;
_mm_errorhandler = proc;
return oldproc;
}
MIKMODAPI MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t proc)
{
MikMod_handler_t result;
MUTEX_LOCK(vars);
result=_mm_registererrorhandler(proc);
MUTEX_UNLOCK(vars);
return result;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,378 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mmio.c,v 1.2 2004/02/06 19:29:05 raph Exp $
Portable file I/O routines
==============================================================================*/
/*
The way this module works:
- _mm_fopen will call the errorhandler [see mmerror.c] in addition to
setting _mm_errno on exit.
- _mm_iobase is for internal use. It is used by Player_LoadFP to
ensure that it works properly with wad files.
- _mm_read_I_* and _mm_read_M_* differ : the first is for reading data
written by a little endian (intel) machine, and the second is for reading
big endian (Mac, RISC, Alpha) machine data.
- _mm_write functions work the same as the _mm_read functions.
- _mm_read_string is for reading binary strings. It is basically the same
as an fread of bytes.
*/
/* FIXME
the _mm_iobase variable ought to be MREADER-specific. It will eventually
become a private field of the MREADER structure, but this will require a
soname version bump.
In the meantime, the drawback is that if you use the xxx_LoadFP functions,
you can't have several MREADER objects with different iobase values.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdio.h>
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fclose(FILE *);
extern int fgetc(FILE *);
extern int fputc(int, FILE *);
extern size_t fread(void *, size_t, size_t, FILE *);
extern int fseek(FILE *, long, int);
extern size_t fwrite(const void *, size_t, size_t, FILE *);
#endif
#define COPY_BUFSIZE 1024
static long _mm_iobase=0,temp_iobase=0;
FILE* _mm_fopen(CHAR* fname,CHAR* attrib)
{
FILE *fp;
if(!(fp=fopen(fname,attrib))) {
_mm_errno = MMERR_OPENING_FILE;
if(_mm_errorhandler) _mm_errorhandler();
}
return fp;
}
BOOL _mm_FileExists(CHAR* fname)
{
FILE *fp;
if(!(fp=fopen(fname,"r"))) return 0;
fclose(fp);
return 1;
}
int _mm_fclose(FILE *fp)
{
return fclose(fp);
}
/* Sets the current file-position as the new _mm_iobase */
void _mm_iobase_setcur(MREADER* reader)
{
temp_iobase=_mm_iobase; /* store old value in case of revert */
_mm_iobase=reader->Tell(reader);
}
/* Reverts to the last known _mm_iobase value. */
void _mm_iobase_revert(void)
{
_mm_iobase=temp_iobase;
}
/*========== File Reader */
typedef struct MFILEREADER {
MREADER core;
FILE* file;
} MFILEREADER;
static BOOL _mm_FileReader_Eof(MREADER* reader)
{
return feof(((MFILEREADER*)reader)->file);
}
static BOOL _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size)
{
return fread(ptr,size,1,((MFILEREADER*)reader)->file);
}
static int _mm_FileReader_Get(MREADER* reader)
{
return fgetc(((MFILEREADER*)reader)->file);
}
static BOOL _mm_FileReader_Seek(MREADER* reader,long offset,int whence)
{
return fseek(((MFILEREADER*)reader)->file,
(whence==SEEK_SET)?offset+_mm_iobase:offset,whence);
}
static long _mm_FileReader_Tell(MREADER* reader)
{
return ftell(((MFILEREADER*)reader)->file)-_mm_iobase;
}
MREADER *_mm_new_file_reader(FILE* fp)
{
MFILEREADER* reader=(MFILEREADER*)_mm_malloc(sizeof(MFILEREADER));
if (reader) {
reader->core.Eof =&_mm_FileReader_Eof;
reader->core.Read=&_mm_FileReader_Read;
reader->core.Get =&_mm_FileReader_Get;
reader->core.Seek=&_mm_FileReader_Seek;
reader->core.Tell=&_mm_FileReader_Tell;
reader->file=fp;
}
return (MREADER*)reader;
}
void _mm_delete_file_reader (MREADER* reader)
{
if(reader) free(reader);
}
/*========== File Writer */
typedef struct MFILEWRITER {
MWRITER core;
FILE* file;
} MFILEWRITER;
static BOOL _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence)
{
return fseek(((MFILEWRITER*)writer)->file,offset,whence);
}
static long _mm_FileWriter_Tell(MWRITER* writer)
{
return ftell(((MFILEWRITER*)writer)->file);
}
static BOOL _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size)
{
return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size);
}
static BOOL _mm_FileWriter_Put(MWRITER* writer,int value)
{
return fputc(value,((MFILEWRITER*)writer)->file);
}
MWRITER *_mm_new_file_writer(FILE* fp)
{
MFILEWRITER* writer=(MFILEWRITER*)_mm_malloc(sizeof(MFILEWRITER));
if (writer) {
writer->core.Seek =&_mm_FileWriter_Seek;
writer->core.Tell =&_mm_FileWriter_Tell;
writer->core.Write=&_mm_FileWriter_Write;
writer->core.Put =&_mm_FileWriter_Put;
writer->file=fp;
}
return (MWRITER*) writer;
}
void _mm_delete_file_writer (MWRITER* writer)
{
if(writer) free (writer);
}
/*========== Write functions */
void _mm_write_string(CHAR* data,MWRITER* writer)
{
if(data)
_mm_write_UBYTES(data,strlen(data),writer);
}
void _mm_write_M_UWORD(UWORD data,MWRITER* writer)
{
_mm_write_UBYTE(data>>8,writer);
_mm_write_UBYTE(data&0xff,writer);
}
void _mm_write_I_UWORD(UWORD data,MWRITER* writer)
{
_mm_write_UBYTE(data&0xff,writer);
_mm_write_UBYTE(data>>8,writer);
}
void _mm_write_M_ULONG(ULONG data,MWRITER* writer)
{
_mm_write_M_UWORD(data>>16,writer);
_mm_write_M_UWORD(data&0xffff,writer);
}
void _mm_write_I_ULONG(ULONG data,MWRITER* writer)
{
_mm_write_I_UWORD(data&0xffff,writer);
_mm_write_I_UWORD(data>>16,writer);
}
void _mm_write_M_SWORD(SWORD data,MWRITER* writer)
{
_mm_write_M_UWORD((UWORD)data,writer);
}
void _mm_write_I_SWORD(SWORD data,MWRITER* writer)
{
_mm_write_I_UWORD((UWORD)data,writer);
}
void _mm_write_M_SLONG(SLONG data,MWRITER* writer)
{
_mm_write_M_ULONG((ULONG)data,writer);
}
void _mm_write_I_SLONG(SLONG data,MWRITER* writer)
{
_mm_write_I_ULONG((ULONG)data,writer);
}
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \
void _mm_write_##type_name##S (type *buffer,int number,MWRITER* writer) \
{ \
while(number-->0) \
_mm_write_##type_name(*(buffer++),writer); \
}
#else
#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \
void _mm_write_/**/type_name/**/S (type *buffer,int number,MWRITER* writer) \
{ \
while(number-->0) \
_mm_write_/**/type_name(*(buffer++),writer); \
}
#endif
DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD)
DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG)
DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG)
DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG)
/*========== Read functions */
int _mm_read_string(CHAR* buffer,int number,MREADER* reader)
{
return reader->Read(reader,buffer,number);
}
UWORD _mm_read_M_UWORD(MREADER* reader)
{
UWORD result=((UWORD)_mm_read_UBYTE(reader))<<8;
result|=_mm_read_UBYTE(reader);
return result;
}
UWORD _mm_read_I_UWORD(MREADER* reader)
{
UWORD result=_mm_read_UBYTE(reader);
result|=((UWORD)_mm_read_UBYTE(reader))<<8;
return result;
}
ULONG _mm_read_M_ULONG(MREADER* reader)
{
ULONG result=((ULONG)_mm_read_M_UWORD(reader))<<16;
result|=_mm_read_M_UWORD(reader);
return result;
}
ULONG _mm_read_I_ULONG(MREADER* reader)
{
ULONG result=_mm_read_I_UWORD(reader);
result|=((ULONG)_mm_read_I_UWORD(reader))<<16;
return result;
}
SWORD _mm_read_M_SWORD(MREADER* reader)
{
return((SWORD)_mm_read_M_UWORD(reader));
}
SWORD _mm_read_I_SWORD(MREADER* reader)
{
return((SWORD)_mm_read_I_UWORD(reader));
}
SLONG _mm_read_M_SLONG(MREADER* reader)
{
return((SLONG)_mm_read_M_ULONG(reader));
}
SLONG _mm_read_I_SLONG(MREADER* reader)
{
return((SLONG)_mm_read_I_ULONG(reader));
}
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \
int _mm_read_##type_name##S (type *buffer,int number,MREADER* reader) \
{ \
while(number-->0) \
*(buffer++)=_mm_read_##type_name(reader); \
return !reader->Eof(reader); \
}
#else
#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \
int _mm_read_/**/type_name/**/S (type *buffer,int number,MREADER* reader) \
{ \
while(number-->0) \
*(buffer++)=_mm_read_/**/type_name(reader); \
return !reader->Eof(reader); \
}
#endif
DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD)
DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD)
DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD)
DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD)
DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG)
DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG)
DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG)
DEFINE_MULTIPLE_READ_FUNCTION(I_ULONG,ULONG)
/* ex:set ts=4: */

View File

@@ -0,0 +1,122 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mdreg.c,v 1.5 2004/02/20 22:08:35 raph Exp $
Routine for registering all drivers in libmikmod for the current platform.
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
void _mm_registeralldrivers(void)
{
/* Register network drivers */
#ifdef DRV_AF
_mm_registerdriver(&drv_AF);
#endif
#ifdef DRV_ESD
_mm_registerdriver(&drv_esd);
#endif
/* Register hardware drivers - hardware mixing */
#ifdef DRV_ULTRA
_mm_registerdriver(&drv_ultra);
#endif
/* Register hardware drivers - software mixing */
#ifdef DRV_AIX
_mm_registerdriver(&drv_aix);
#endif
#ifdef DRV_ALSA
_mm_registerdriver(&drv_alsa);
#endif
#ifdef DRV_HP
_mm_registerdriver(&drv_hp);
#endif
#ifdef DRV_OSS
_mm_registerdriver(&drv_oss);
#endif
#ifdef DRV_SGI
_mm_registerdriver(&drv_sgi);
#endif
#ifdef DRV_SUN
_mm_registerdriver(&drv_sun);
#endif
#ifdef DRV_DART
_mm_registerdriver(&drv_dart);
#endif
#ifdef DRV_OS2
_mm_registerdriver(&drv_os2);
#endif
#ifdef DRV_DS
_mm_registerdriver(&drv_ds);
#endif
#ifdef DRV_WIN
_mm_registerdriver(&drv_win);
#endif
#ifdef DRV_MAC
_mm_registerdriver(&drv_mac);
#endif
#ifdef DRV_OSX
_mm_registerdriver(&drv_osx);
#endif
/* dos drivers */
#ifdef DRV_WSS
/* wss first, since some cards emulate sb */
_mm_registerdriver(&drv_wss);
#endif
#ifdef DRV_SB
_mm_registerdriver(&drv_sb);
#endif
/* Register disk writers */
_mm_registerdriver(&drv_raw);
_mm_registerdriver(&drv_wav);
#ifdef DRV_AIFF
_mm_registerdriver(&drv_aiff);
#endif
/* Register other drivers */
#ifdef DRV_PIPE
_mm_registerdriver(&drv_pipe);
#endif
#ifndef macintosh
_mm_registerdriver(&drv_stdout);
#endif
_mm_registerdriver(&drv_nos);
}
void MikMod_RegisterAllDrivers(void)
{
MUTEX_LOCK(lists);
_mm_registeralldrivers();
MUTEX_UNLOCK(lists);
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,948 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mdriver.c,v 1.3 2004/02/18 13:29:19 raph Exp $
These routines are used to access the available soundcard drivers.
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined unix || (defined __APPLE__ && defined __MACH__)
#include <pwd.h>
#include <sys/stat.h>
#endif
#include <string.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
static MDRIVER *firstdriver=NULL;
MIKMODAPI MDRIVER *md_driver=NULL;
extern MODULE *pf; /* modfile being played */
/* Initial global settings */
MIKMODAPI UWORD md_device = 0; /* autodetect */
MIKMODAPI UWORD md_mixfreq = 44100;
MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |
DMODE_SURROUND |DMODE_SOFT_MUSIC |
DMODE_SOFT_SNDFX;
MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
MIKMODAPI UBYTE md_reverb = 0; /* no reverb */
MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */
MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */
MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */
UWORD md_bpm = 125; /* tempo */
/* Do not modify the numchn variables yourself! use MD_SetVoices() */
UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;
UBYTE md_hardchn=0,md_softchn=0;
void (*md_player)(void) = Player_HandleTick;
static BOOL isplaying=0, initialized = 0;
static UBYTE *sfxinfo;
static int sfxpool;
static SAMPLE **md_sample = NULL;
/* Previous driver in use */
static SWORD olddevice = -1;
/* Limits the number of hardware voices to the specified amount.
This function should only be used by the low-level drivers. */
static void LimitHardVoices(int limit)
{
int t=0;
if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
if (!(md_mode & DMODE_SOFT_SNDFX))
md_hardchn=md_sfxchn;
else
md_hardchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
while (md_hardchn>limit) {
if (++t & 1) {
if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
} else {
if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
}
if (!(md_mode & DMODE_SOFT_SNDFX))
md_hardchn=md_sfxchn;
else
md_hardchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC))
md_hardchn+=md_sngchn;
}
md_numchn=md_hardchn+md_softchn;
}
/* Limits the number of hardware voices to the specified amount.
This function should only be used by the low-level drivers. */
static void LimitSoftVoices(int limit)
{
int t=0;
if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
if (md_mode & DMODE_SOFT_SNDFX)
md_softchn=md_sfxchn;
else
md_softchn=0;
if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;
while (md_softchn>limit) {
if (++t & 1) {
if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
} else {
if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
}
if (!(md_mode & DMODE_SOFT_SNDFX))
md_softchn=md_sfxchn;
else
md_softchn=0;
if (!(md_mode & DMODE_SOFT_MUSIC))
md_softchn+=md_sngchn;
}
md_numchn=md_hardchn+md_softchn;
}
/* Note: 'type' indicates whether the returned value should be for music or for
sound effects. */
ULONG MD_SampleSpace(int type)
{
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
return md_driver->FreeSampleSpace(type);
}
ULONG MD_SampleLength(int type,SAMPLE* s)
{
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else
if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
return md_driver->RealSampleLength(type,s);
}
MIKMODAPI CHAR* MikMod_InfoDriver(void)
{
int t,len=0;
MDRIVER *l;
CHAR *list=NULL;
MUTEX_LOCK(lists);
/* compute size of buffer */
for(l=firstdriver;l;l=l->next)
len+=4+(l->next?1:0)+strlen(l->Version);
if(len)
if((list=_mm_malloc(len*sizeof(CHAR)))) {
list[0]=0;
/* list all registered device drivers : */
for(t=1,l=firstdriver;l;l=l->next,t++)
sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",
list,t,l->Version);
}
MUTEX_UNLOCK(lists);
return list;
}
void _mm_registerdriver(struct MDRIVER* drv)
{
MDRIVER *cruise = firstdriver;
/* don't register a MISSING() driver */
if ((drv->Name) && (drv->Version)) {
if (cruise) {
while (cruise->next) cruise = cruise->next;
cruise->next = drv;
} else
firstdriver = drv;
}
}
MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)
{
/* if we try to register an invalid driver, or an already registered driver,
ignore this attempt */
if ((!drv)||(drv->next)||(!drv->Name))
return;
MUTEX_LOCK(lists);
_mm_registerdriver(drv);
MUTEX_UNLOCK(lists);
}
MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)
{
int rank=1;
MDRIVER *cruise;
MUTEX_LOCK(lists);
cruise=firstdriver;
while(cruise) {
if (cruise->Alias) {
if (!(strcasecmp(alias,cruise->Alias))) break;
rank++;
}
cruise=cruise->next;
}
if(!cruise) rank=0;
MUTEX_UNLOCK(lists);
return rank;
}
MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)
{
MDRIVER *cruise;
/* Allow only driver ordinals > 0 */
if (!ordinal)
return 0;
MUTEX_LOCK(lists);
cruise = firstdriver;
while (cruise && --ordinal)
cruise = cruise->next;
MUTEX_UNLOCK(lists);
return cruise;
}
SWORD MD_SampleLoad(SAMPLOAD* s, int type)
{
SWORD result;
if(type==MD_MUSIC)
type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
else if(type==MD_SNDFX)
type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
SL_Init(s);
result=md_driver->SampleLoad(s,type);
SL_Exit(s);
return result;
}
void MD_SampleUnload(SWORD handle)
{
md_driver->SampleUnload(handle);
}
MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
{
MikMod_player_t result;
MUTEX_LOCK(vars);
result=md_player;
md_player=player;
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI void MikMod_Update(void)
{
MUTEX_LOCK(vars);
if(isplaying) {
if((!pf)||(!pf->forbid))
md_driver->Update();
else {
if (md_driver->Pause)
md_driver->Pause();
}
}
MUTEX_UNLOCK(vars);
}
void Voice_SetVolume_internal(SBYTE voice,UWORD vol)
{
ULONG tmp;
if((voice<0)||(voice>=md_numchn)) return;
/* range checks */
if(md_musicvolume>128) md_musicvolume=128;
if(md_sndfxvolume>128) md_sndfxvolume=128;
if(md_volume>128) md_volume=128;
tmp=(ULONG)vol*(ULONG)md_volume*
((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
md_driver->VoiceSetVolume(voice,tmp/16384UL);
}
MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
{
MUTEX_LOCK(vars);
Voice_SetVolume_internal(voice,vol);
MUTEX_UNLOCK(vars);
}
MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)
{
UWORD result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetVolume(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)
{
if((voice<0)||(voice>=md_numchn)) return;
if((md_sample[voice])&&(md_sample[voice]->divfactor))
frq/=md_sample[voice]->divfactor;
md_driver->VoiceSetFrequency(voice,frq);
}
MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
{
MUTEX_LOCK(vars);
Voice_SetFrequency_internal(voice,frq);
MUTEX_UNLOCK(vars);
}
MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)
{
ULONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetFrequency(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_SetPanning_internal(SBYTE voice,ULONG pan)
{
if((voice<0)||(voice>=md_numchn)) return;
if(pan!=PAN_SURROUND) {
if(md_pansep>128) md_pansep=128;
if(md_mode & DMODE_REVERSE) pan=255-pan;
pan = (((SWORD)(pan-128)*md_pansep)/128)+128;
}
md_driver->VoiceSetPanning(voice, pan);
}
MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)
{
#ifdef MIKMOD_DEBUG
if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))
fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);
#endif
MUTEX_LOCK(vars);
Voice_SetPanning_internal(voice,pan);
MUTEX_UNLOCK(vars);
}
MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)
{
ULONG result=PAN_CENTER;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn))
result=md_driver->VoiceGetPanning(voice);
MUTEX_UNLOCK(vars);
return result;
}
void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)
{
ULONG repend;
if((voice<0)||(voice>=md_numchn)) return;
md_sample[voice]=s;
repend=s->loopend;
if(s->flags&SF_LOOP)
/* repend can't be bigger than size */
if(repend>s->length) repend=s->length;
md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
}
MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
{
if(start>s->length) return;
MUTEX_LOCK(vars);
Voice_Play_internal(voice,s,start);
MUTEX_UNLOCK(vars);
}
void Voice_Stop_internal(SBYTE voice)
{
if((voice<0)||(voice>=md_numchn)) return;
if(voice>=md_sngchn)
/* It is a sound effects channel, so flag the voice as non-critical! */
sfxinfo[voice-md_sngchn]=0;
md_driver->VoiceStop(voice);
}
MIKMODAPI void Voice_Stop(SBYTE voice)
{
MUTEX_LOCK(vars);
Voice_Stop_internal(voice);
MUTEX_UNLOCK(vars);
}
BOOL Voice_Stopped_internal(SBYTE voice)
{
if((voice<0)||(voice>=md_numchn)) return 0;
return(md_driver->VoiceStopped(voice));
}
MIKMODAPI BOOL Voice_Stopped(SBYTE voice)
{
BOOL result;
MUTEX_LOCK(vars);
result=Voice_Stopped_internal(voice);
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)
{
SLONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn)) {
if (md_driver->VoiceGetPosition)
result=(md_driver->VoiceGetPosition(voice));
else
result=-1;
}
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI ULONG Voice_RealVolume(SBYTE voice)
{
ULONG result=0;
MUTEX_LOCK(vars);
if((voice>=0)&&(voice<md_numchn)&& md_driver->VoiceRealVolume)
result=(md_driver->VoiceRealVolume(voice));
MUTEX_UNLOCK(vars);
return result;
}
static BOOL _mm_init(CHAR *cmdline)
{
UWORD t;
_mm_critical = 1;
/* if md_device==0, try to find a device number */
if(!md_device) {
cmdline=NULL;
for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)
if(md_driver->IsPresent()) break;
if(!md_driver) {
_mm_errno = MMERR_DETECTING_DEVICE;
if(_mm_errorhandler) _mm_errorhandler();
md_driver = &drv_nos;
return 1;
}
md_device = t;
} else {
/* if n>0, use that driver */
for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next)
t++;
if(!md_driver) {
_mm_errno = MMERR_INVALID_DEVICE;
if(_mm_errorhandler) _mm_errorhandler();
md_driver = &drv_nos;
return 1;
}
/* arguments here might be necessary for the presence check to succeed */
if(cmdline&&(md_driver->CommandLine))
md_driver->CommandLine(cmdline);
if(!md_driver->IsPresent()) {
_mm_errno = MMERR_DETECTING_DEVICE;
if(_mm_errorhandler) _mm_errorhandler();
md_driver = &drv_nos;
return 1;
}
}
olddevice = md_device;
if(md_driver->Init()) {
MikMod_Exit_internal();
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
initialized=1;
_mm_critical=0;
return 0;
}
MIKMODAPI BOOL MikMod_Init(CHAR *cmdline)
{
BOOL result;
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
result=_mm_init(cmdline);
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
return result;
}
void MikMod_Exit_internal(void)
{
MikMod_DisableOutput_internal();
md_driver->Exit();
md_numchn = md_sfxchn = md_sngchn = 0;
md_driver = &drv_nos;
if(sfxinfo) free(sfxinfo);
if(md_sample) free(md_sample);
md_sample = NULL;
sfxinfo = NULL;
initialized = 0;
}
MIKMODAPI void MikMod_Exit(void)
{
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
MikMod_Exit_internal();
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
}
/* Reset the driver using the new global variable settings.
If the driver has not been initialized, it will be now. */
static BOOL _mm_reset(CHAR *cmdline)
{
BOOL wasplaying = 0;
if(!initialized) return _mm_init(cmdline);
if (isplaying) {
wasplaying = 1;
md_driver->PlayStop();
}
if((!md_driver->Reset)||(md_device != olddevice)) {
/* md_driver->Reset was NULL, or md_device was changed, so do a full
reset of the driver. */
md_driver->Exit();
if(_mm_init(cmdline)) {
MikMod_Exit_internal();
if(_mm_errno)
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
} else {
if(md_driver->Reset()) {
MikMod_Exit_internal();
if(_mm_errno)
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
}
if (wasplaying) md_driver->PlayStart();
return 0;
}
MIKMODAPI BOOL MikMod_Reset(CHAR *cmdline)
{
BOOL result;
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
result=_mm_reset(cmdline);
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
return result;
}
/* If either parameter is -1, the current set value will be retained. */
BOOL MikMod_SetNumVoices_internal(int music, int sfx)
{
BOOL resume = 0;
int t, oldchn = 0;
if((!music)&&(!sfx)) return 1;
_mm_critical = 1;
if(isplaying) {
MikMod_DisableOutput_internal();
oldchn = md_numchn;
resume = 1;
}
if(sfxinfo) free(sfxinfo);
if(md_sample) free(md_sample);
md_sample = NULL;
sfxinfo = NULL;
if(music!=-1) md_sngchn = music;
if(sfx!=-1) md_sfxchn = sfx;
md_numchn = md_sngchn + md_sfxchn;
LimitHardVoices(md_driver->HardVoiceLimit);
LimitSoftVoices(md_driver->SoftVoiceLimit);
if(md_driver->SetNumVoices()) {
MikMod_Exit_internal();
if(_mm_errno)
if(_mm_errorhandler!=NULL) _mm_errorhandler();
md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
return 1;
}
if(md_sngchn+md_sfxchn)
md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));
if(md_sfxchn)
sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE));
/* make sure the player doesn't start with garbage */
for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t);
sfxpool = 0;
if(resume) MikMod_EnableOutput_internal();
_mm_critical = 0;
return 0;
}
MIKMODAPI BOOL MikMod_SetNumVoices(int music, int sfx)
{
BOOL result;
MUTEX_LOCK(vars);
result=MikMod_SetNumVoices_internal(music,sfx);
MUTEX_UNLOCK(vars);
return result;
}
BOOL MikMod_EnableOutput_internal(void)
{
_mm_critical = 1;
if(!isplaying) {
if(md_driver->PlayStart()) return 1;
isplaying = 1;
}
_mm_critical = 0;
return 0;
}
MIKMODAPI BOOL MikMod_EnableOutput(void)
{
BOOL result;
MUTEX_LOCK(vars);
result=MikMod_EnableOutput_internal();
MUTEX_UNLOCK(vars);
return result;
}
void MikMod_DisableOutput_internal(void)
{
if(isplaying && md_driver) {
isplaying = 0;
md_driver->PlayStop();
}
}
MIKMODAPI void MikMod_DisableOutput(void)
{
MUTEX_LOCK(vars);
MikMod_DisableOutput_internal();
MUTEX_UNLOCK(vars);
}
BOOL MikMod_Active_internal(void)
{
return isplaying;
}
MIKMODAPI BOOL MikMod_Active(void)
{
BOOL result;
MUTEX_LOCK(vars);
result=MikMod_Active_internal();
MUTEX_UNLOCK(vars);
return result;
}
/* Plays a sound effects sample. Picks a voice from the number of voices
allocated for use as sound effects (loops through voices, skipping all active
criticals).
Returns the voice that the sound is being played on. */
SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)
{
int orig=sfxpool;/* for cases where all channels are critical */
int c;
if(!md_sfxchn) return -1;
if(s->volume>64) s->volume = 64;
/* check the first location after sfxpool */
do {
if(sfxinfo[sfxpool]&SFX_CRITICAL) {
if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) {
sfxinfo[sfxpool]=flags;
Voice_Play_internal(c,s,start);
md_driver->VoiceSetVolume(c,s->volume<<2);
Voice_SetPanning_internal(c,s->panning);
md_driver->VoiceSetFrequency(c,s->speed);
sfxpool++;
if(sfxpool>=md_sfxchn) sfxpool=0;
return c;
}
} else {
sfxinfo[sfxpool]=flags;
Voice_Play_internal(c=sfxpool+md_sngchn,s,start);
md_driver->VoiceSetVolume(c,s->volume<<2);
Voice_SetPanning_internal(c,s->panning);
md_driver->VoiceSetFrequency(c,s->speed);
sfxpool++;
if(sfxpool>=md_sfxchn) sfxpool=0;
return c;
}
sfxpool++;
if(sfxpool>=md_sfxchn) sfxpool = 0;
} while(sfxpool!=orig);
return -1;
}
MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)
{
SBYTE result;
MUTEX_LOCK(vars);
result=Sample_Play_internal(s,start,flags);
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI long MikMod_GetVersion(void)
{
return LIBMIKMOD_VERSION;
}
/*========== MT-safe stuff */
#ifdef HAVE_PTHREAD
#define INIT_MUTEX(name) \
pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER
#elif defined(__OS2__)||defined(__EMX__)
#define INIT_MUTEX(name) \
HMTX _mm_mutex_##name
#elif defined(WIN32)
#define INIT_MUTEX(name) \
HANDLE _mm_mutex_##name
#else
#define INIT_MUTEX(name) \
void *_mm_mutex_##name = NULL
#endif
INIT_MUTEX(vars);
INIT_MUTEX(lists);
MIKMODAPI BOOL MikMod_InitThreads(void)
{
static int firstcall=1;
static int result=0;
if (firstcall) {
firstcall=0;
#ifdef HAVE_PTHREAD
result=1;
#elif defined(__OS2__)||defined(__EMX__)
if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) ||
DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) {
_mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL;
result=0;
} else
result=1;
#elif defined(WIN32)
if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))||
(!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)"))))
result=0;
else
result=1;
#endif
}
return result;
}
MIKMODAPI void MikMod_Unlock(void)
{
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
}
MIKMODAPI void MikMod_Lock(void)
{
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
}
/*========== Parameter extraction helper */
CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,BOOL implicit)
{
CHAR *ret=NULL;
if(cmdline) {
CHAR *buf=strstr(cmdline,atomname);
if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {
CHAR *ptr=buf+strlen(atomname);
if(*ptr=='=') {
for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);
ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));
if(ret)
strncpy(ret,buf,ptr-buf);
} else if((*ptr==',')||(!*ptr)) {
if(implicit) {
ret=_mm_malloc((1+ptr-buf)*sizeof(CHAR));
if(ret)
strncpy(ret,buf,ptr-buf);
}
}
}
}
return ret;
}
#if defined unix || (defined __APPLE__ && defined __MACH__)
/*========== Posix helper functions */
/* Check if the file is a regular or nonexistant file (or a link to a such a
file), and that, should the calling program be setuid, the access rights are
reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise.
The goal is to prevent a setuid root libmikmod application from overriding
files like /etc/passwd with digital sound... */
BOOL MD_Access(CHAR *filename)
{
struct stat buf;
if(!stat(filename,&buf)) {
/* not a regular file ? */
if(!S_ISREG(buf.st_mode)) return 0;
/* more than one hard link to the file ? */
if(buf.st_nlink>1) return 0;
/* check access rights with the real user and group id */
if(getuid()==buf.st_uid) {
if(!(buf.st_mode&S_IWUSR)) return 0;
} else if(getgid()==buf.st_gid) {
if(!(buf.st_mode&S_IWGRP)) return 0;
} else
if(!(buf.st_mode&S_IWOTH)) return 0;
}
return 1;
}
/* Drop all root privileges we might have */
BOOL MD_DropPrivileges(void)
{
if(!geteuid()) {
if(getuid()) {
/* we are setuid root -> drop setuid to become the real user */
if(setuid(getuid())) return 1;
} else {
/* we are run as root -> drop all and become user 'nobody' */
struct passwd *nobody;
int uid;
if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */
uid=nobody->pw_uid;
if (!uid) /* user 'nobody' has root privileges ? weird... */
return 1;
if (setuid(uid)) return 1;
}
}
return 0;
}
#endif
/* ex:set ts=4: */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,564 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
These routines are used to access the available module loaders
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
MREADER *modreader;
MODULE of;
static MLOADER *firstloader=NULL;
UWORD finetune[16]={
8363,8413,8463,8529,8581,8651,8723,8757,
7895,7941,7985,8046,8107,8169,8232,8280
};
MIKMODAPI CHAR* MikMod_InfoLoader(void)
{
int len=0;
MLOADER *l;
CHAR *list=NULL;
MUTEX_LOCK(lists);
/* compute size of buffer */
for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version);
if(len)
if((list=_mm_malloc(len*sizeof(CHAR)))) {
list[0]=0;
/* list all registered module loders */
for(l=firstloader;l;l=l->next)
sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version);
}
MUTEX_UNLOCK(lists);
return list;
}
void _mm_registerloader(MLOADER* ldr)
{
MLOADER *cruise=firstloader;
if(cruise) {
while(cruise->next) cruise = cruise->next;
cruise->next=ldr;
} else
firstloader=ldr;
}
MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
{
/* if we try to register an invalid loader, or an already registered loader,
ignore this attempt */
if ((!ldr)||(ldr->next))
return;
MUTEX_LOCK(lists);
_mm_registerloader(ldr);
MUTEX_UNLOCK(lists);
}
BOOL ReadComment(UWORD len)
{
if(len) {
int i;
if(!(of.comment=(CHAR*)_mm_malloc(len+1))) return 0;
_mm_read_UBYTES(of.comment,len,modreader);
/* translate IT linefeeds */
for(i=0;i<len;i++)
if(of.comment[i]=='\r') of.comment[i]='\n';
of.comment[len]=0; /* just in case */
}
if(!of.comment[0]) {
free(of.comment);
of.comment=NULL;
}
return 1;
}
BOOL ReadLinedComment(UWORD len,UWORD linelen)
{
CHAR *tempcomment,*line,*storage;
UWORD total=0,t,lines;
int i;
lines = (len + linelen - 1) / linelen;
if (len) {
if(!(tempcomment=(CHAR*)_mm_malloc(len+1))) return 0;
if(!(storage=(CHAR*)_mm_malloc(linelen+1))) {
free(tempcomment);
return 0;
}
memset(tempcomment, ' ', len);
_mm_read_UBYTES(tempcomment,len,modreader);
/* compute message length */
for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;
for(i=0;i<linelen;i++) if (!line[i]) break;
total+=1+i;
}
if(total>lines) {
if(!(of.comment=(CHAR*)_mm_malloc(total+1))) {
free(storage);
free(tempcomment);
return 0;
}
/* convert message */
for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
storage[i]=0; /* if (i==linelen) */
strcat(of.comment,storage);strcat(of.comment,"\r");
}
free(storage);
free(tempcomment);
}
}
return 1;
}
BOOL AllocPositions(int total)
{
if(!total) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.positions=_mm_calloc(total,sizeof(UWORD)))) return 0;
return 1;
}
BOOL AllocPatterns(void)
{
int s,t,tracks = 0;
if((!of.numpat)||(!of.numchn)) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
/* Allocate track sequencing array */
if(!(of.patterns=(UWORD*)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
if(!(of.pattrows=(UWORD*)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
for(t=0;t<=of.numpat;t++) {
of.pattrows[t]=64;
for(s=0;s<of.numchn;s++)
of.patterns[(t*of.numchn)+s]=tracks++;
}
return 1;
}
BOOL AllocTracks(void)
{
if(!of.numtrk) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.tracks=(UBYTE **)_mm_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
return 1;
}
BOOL AllocInstruments(void)
{
int t,n;
if(!of.numins) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.instruments=(INSTRUMENT*)_mm_calloc(of.numins,sizeof(INSTRUMENT))))
return 0;
for(t=0;t<of.numins;t++) {
for(n=0;n<INSTNOTES;n++) {
/* Init note / sample lookup table */
of.instruments[t].samplenote[n] = n;
of.instruments[t].samplenumber[n] = t;
}
of.instruments[t].globvol = 64;
}
return 1;
}
BOOL AllocSamples(void)
{
UWORD u;
if(!of.numsmp) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
}
if(!(of.samples=(SAMPLE*)_mm_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
for(u=0;u<of.numsmp;u++) {
of.samples[u].panning = 128; /* center */
of.samples[u].handle = -1;
of.samples[u].globvol = 64;
of.samples[u].volume = 64;
}
return 1;
}
static BOOL ML_LoadSamples(void)
{
SAMPLE *s;
int u;
for(u=of.numsmp,s=of.samples;u;u--,s++)
if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
return 1;
}
/* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
terminating non-printing characters like 0, spaces etc. */
CHAR *DupStr(CHAR* s,UWORD len,BOOL strict)
{
UWORD t;
CHAR *d=NULL;
/* Scan for last printing char in buffer [includes high ascii up to 254] */
while(len) {
if(s[len-1]>0x20) break;
len--;
}
/* Scan forward for possible NULL character */
if(strict) {
for(t=0;t<len;t++) if (!s[t]) break;
if (t<len) len=t;
}
/* When the buffer wasn't completely empty, allocate a cstring and copy the
buffer into that string, except for any control-chars */
if((d=(CHAR*)_mm_malloc(sizeof(CHAR)*(len+1)))) {
for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];
d[len]=0;
}
return d;
}
static void ML_XFreeSample(SAMPLE *s)
{
if(s->handle>=0)
MD_SampleUnload(s->handle);
if(s->samplename) free(s->samplename);
}
static void ML_XFreeInstrument(INSTRUMENT *i)
{
if(i->insname) free(i->insname);
}
static void ML_FreeEx(MODULE *mf)
{
UWORD t;
if(mf->songname) free(mf->songname);
if(mf->comment) free(mf->comment);
if(mf->modtype) free(mf->modtype);
if(mf->positions) free(mf->positions);
if(mf->patterns) free(mf->patterns);
if(mf->pattrows) free(mf->pattrows);
if(mf->tracks) {
for(t=0;t<mf->numtrk;t++)
if(mf->tracks[t]) free(mf->tracks[t]);
free(mf->tracks);
}
if(mf->instruments) {
for(t=0;t<mf->numins;t++)
ML_XFreeInstrument(&mf->instruments[t]);
free(mf->instruments);
}
if(mf->samples) {
for(t=0;t<mf->numsmp;t++)
if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
free(mf->samples);
}
memset(mf,0,sizeof(MODULE));
if(mf!=&of) free(mf);
}
static MODULE *ML_AllocUniMod(void)
{
MODULE *mf;
return (mf=_mm_malloc(sizeof(MODULE)));
}
void Player_Free_internal(MODULE *mf)
{
if(mf) {
Player_Exit_internal(mf);
ML_FreeEx(mf);
}
}
MIKMODAPI void Player_Free(MODULE *mf)
{
MUTEX_LOCK(vars);
Player_Free_internal(mf);
MUTEX_UNLOCK(vars);
}
static CHAR* Player_LoadTitle_internal(MREADER *reader)
{
MLOADER *l;
modreader=reader;
_mm_errno = 0;
_mm_critical = 0;
_mm_iobase_setcur(modreader);
/* Try to find a loader that recognizes the module */
for(l=firstloader;l;l=l->next) {
_mm_rewind(modreader);
if(l->Test()) break;
}
if(!l) {
_mm_errno = MMERR_NOT_A_MODULE;
if(_mm_errorhandler) _mm_errorhandler();
return NULL;
}
return l->LoadTitle();
}
MIKMODAPI CHAR* Player_LoadTitleFP(FILE *fp)
{
CHAR* result=NULL;
MREADER* reader;
if(fp && (reader=_mm_new_file_reader(fp))) {
MUTEX_LOCK(lists);
result=Player_LoadTitle_internal(reader);
MUTEX_UNLOCK(lists);
_mm_delete_file_reader(reader);
}
return result;
}
MIKMODAPI CHAR* Player_LoadTitle(CHAR* filename)
{
CHAR* result=NULL;
FILE* fp;
MREADER* reader;
if((fp=_mm_fopen(filename,"rb"))) {
if((reader=_mm_new_file_reader(fp))) {
MUTEX_LOCK(lists);
result=Player_LoadTitle_internal(reader);
MUTEX_UNLOCK(lists);
_mm_delete_file_reader(reader);
}
_mm_fclose(fp);
}
return result;
}
/* Loads a module given an reader */
MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)
{
int t;
MLOADER *l;
BOOL ok;
MODULE *mf;
modreader = reader;
_mm_errno = 0;
_mm_critical = 0;
_mm_iobase_setcur(modreader);
/* Try to find a loader that recognizes the module */
for(l=firstloader;l;l=l->next) {
_mm_rewind(modreader);
if(l->Test()) break;
}
if(!l) {
_mm_errno = MMERR_NOT_A_MODULE;
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
/* init unitrk routines */
if(!UniInit()) {
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
/* init the module structure with vanilla settings */
memset(&of,0,sizeof(MODULE));
of.bpmlimit = 33;
of.initvolume = 128;
for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64;
for (t = 0; t < UF_MAXCHAN; t++)
of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT;
/* init module loader and load the header / patterns */
if (!l->Init || l->Init()) {
_mm_rewind(modreader);
ok = l->Load(curious);
/* propagate inflags=flags for in-module samples */
for (t = 0; t < of.numsmp; t++)
if (of.samples[t].inflags == 0)
of.samples[t].inflags = of.samples[t].flags;
} else
ok = 0;
/* free loader and unitrk allocations */
if (l->Cleanup) l->Cleanup();
UniCleanup();
if(!ok) {
ML_FreeEx(&of);
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
if(!ML_LoadSamples()) {
ML_FreeEx(&of);
if(_mm_errorhandler) _mm_errorhandler();
_mm_rewind(modreader);_mm_iobase_revert();
return NULL;
}
if(!(mf=ML_AllocUniMod())) {
ML_FreeEx(&of);
_mm_rewind(modreader);_mm_iobase_revert();
if(_mm_errorhandler) _mm_errorhandler();
return NULL;
}
/* If the module doesn't have any specific panning, create a
MOD-like panning, with the channels half-separated. */
if (!(of.flags & UF_PANNING))
for (t = 0; t < of.numchn; t++)
of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT;
/* Copy the static MODULE contents into the dynamic MODULE struct. */
memcpy(mf,&of,sizeof(MODULE));
if(maxchan>0) {
if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
maxchan = mf->numchn;
else
if((mf->numvoices)&&(mf->numvoices<maxchan))
maxchan = mf->numvoices;
if(maxchan<mf->numchn) mf->flags |= UF_NNA;
if(MikMod_SetNumVoices_internal(maxchan,-1)) {
_mm_iobase_revert();
Player_Free(mf);
return NULL;
}
}
if(SL_LoadSamples()) {
_mm_iobase_revert();
Player_Free_internal(mf);
return NULL;
}
if(Player_Init(mf)) {
_mm_iobase_revert();
Player_Free_internal(mf);
mf=NULL;
}
_mm_iobase_revert();
return mf;
}
MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,BOOL curious)
{
MODULE* result;
MUTEX_LOCK(vars);
MUTEX_LOCK(lists);
result=Player_LoadGeneric_internal(reader,maxchan,curious);
MUTEX_UNLOCK(lists);
MUTEX_UNLOCK(vars);
return result;
}
/* Loads a module given a file pointer.
File is loaded from the current file seek position. */
MIKMODAPI MODULE* Player_LoadFP(FILE* fp,int maxchan,BOOL curious)
{
MODULE* result=NULL;
struct MREADER* reader=_mm_new_file_reader (fp);
if (reader) {
result=Player_LoadGeneric(reader,maxchan,curious);
_mm_delete_file_reader(reader);
}
return result;
}
/* Open a module via its filename. The loader will initialize the specified
song-player 'player'. */
MIKMODAPI MODULE* Player_Load(CHAR* filename,int maxchan,BOOL curious)
{
FILE *fp;
MODULE *mf=NULL;
if((fp=_mm_fopen(filename,"rb"))) {
mf=Player_LoadFP(fp,maxchan,curious);
_mm_fclose(fp);
}
return mf;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,65 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mlreg.c,v 1.2 2004/01/28 00:49:56 raph Exp $
Routine for registering all loaders in libmikmod for the current platform.
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
void MikMod_RegisterAllLoaders_internal(void)
{
_mm_registerloader(&load_669);
_mm_registerloader(&load_amf);
_mm_registerloader(&load_asy);
_mm_registerloader(&load_dsm);
_mm_registerloader(&load_far);
_mm_registerloader(&load_gdm);
_mm_registerloader(&load_it);
_mm_registerloader(&load_imf);
_mm_registerloader(&load_mod);
_mm_registerloader(&load_med);
_mm_registerloader(&load_mtm);
_mm_registerloader(&load_okt);
_mm_registerloader(&load_s3m);
_mm_registerloader(&load_stm);
_mm_registerloader(&load_stx);
_mm_registerloader(&load_ult);
_mm_registerloader(&load_uni);
_mm_registerloader(&load_xm);
_mm_registerloader(&load_m15);
}
void MikMod_RegisterAllLoaders(void)
{
MUTEX_LOCK(lists);
MikMod_RegisterAllLoaders_internal();
MUTEX_UNLOCK(lists);
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,336 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mlutil.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Utility functions for the module loader
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
/*========== Shared tracker identifiers */
CHAR *STM_Signatures[STM_NTRACKERS] = {
"!Scream!",
"BMOD2STM",
"WUZAMOD!"
};
CHAR *STM_Version[STM_NTRACKERS] = {
"Screamtracker 2",
"Converted by MOD2STM (STM format)",
"Wuzamod (STM format)"
};
/*========== Shared loader variables */
SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank
pattern removal */
UBYTE poslookupcnt;
UWORD* origpositions=NULL;
BOOL filters; /* resonant filters in use */
UBYTE activemacro; /* active midi macro number for Sxx,xx<80h */
UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */
FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */
/*========== Linear periods stuff */
int* noteindex=NULL; /* remap value for linear period modules */
static int noteindexcount=0;
int *AllocLinear(void)
{
if(of.numsmp>noteindexcount) {
noteindexcount=of.numsmp;
noteindex=realloc(noteindex,noteindexcount*sizeof(int));
}
return noteindex;
}
void FreeLinear(void)
{
if(noteindex) {
free(noteindex);
noteindex=NULL;
}
noteindexcount=0;
}
int speed_to_finetune(ULONG speed,int sample)
{
int ctmp=0,tmp,note=1,finetune=0;
speed>>=1;
while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {
ctmp=tmp;
note++;
}
if(tmp!=speed) {
if((tmp-speed)<(speed-ctmp))
while(tmp>speed)
tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));
else {
note--;
while(ctmp<speed)
ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));
}
}
noteindex[sample]=note-4*OCTAVE;
return finetune;
}
/*========== Order stuff */
/* handles S3M and IT orders */
void S3MIT_CreateOrders(BOOL curious)
{
int t;
of.numpos = 0;
memset(of.positions,0,poslookupcnt*sizeof(UWORD));
memset(poslookup,-1,256);
for(t=0;t<poslookupcnt;t++) {
int order=origpositions[t];
if(order==255) order=LAST_PATTERN;
of.positions[of.numpos]=order;
poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */
if(origpositions[t]<254) of.numpos++;
else
/* end of song special order */
if((order==LAST_PATTERN)&&(!(curious--))) break;
}
}
/*========== Effect stuff */
/* handles S3M and IT effects */
void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags)
{
UBYTE hi,lo;
lo=inf&0xf;
hi=inf>>4;
/* process S3M / IT specific command structure */
if(cmd!=255) {
switch(cmd) {
case 1: /* Axx set speed to xx */
UniEffect(UNI_S3MEFFECTA,inf);
break;
case 2: /* Bxx position jump */
if (inf<poslookupcnt) {
/* switch to curious mode if necessary, for example
sympex.it, deep joy.it */
if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255))
S3MIT_CreateOrders(1);
if(!((SBYTE)poslookup[inf]<0))
UniPTEffect(0xb,poslookup[inf]);
}
break;
case 3: /* Cxx patternbreak to row xx */
if ((flags & S3MIT_OLDSTYLE) && !(flags & S3MIT_IT))
UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));
else
UniPTEffect(0xd,inf);
break;
case 4: /* Dxy volumeslide */
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 5: /* Exy toneslide down */
UniEffect(UNI_S3MEFFECTE,inf);
break;
case 6: /* Fxy toneslide up */
UniEffect(UNI_S3MEFFECTF,inf);
break;
case 7: /* Gxx Tone portamento, speed xx */
if (flags & S3MIT_OLDSTYLE)
UniPTEffect(0x3,inf);
else
UniEffect(UNI_ITEFFECTG,inf);
break;
case 8: /* Hxy vibrato */
if (flags & S3MIT_OLDSTYLE)
UniPTEffect(0x4,inf);
else
UniEffect(UNI_ITEFFECTH,inf);
break;
case 9: /* Ixy tremor, ontime x, offtime y */
if (flags & S3MIT_OLDSTYLE)
UniEffect(UNI_S3MEFFECTI,inf);
else
UniEffect(UNI_ITEFFECTI,inf);
break;
case 0xa: /* Jxy arpeggio */
UniPTEffect(0x0,inf);
break;
case 0xb: /* Kxy Dual command H00 & Dxy */
if (flags & S3MIT_OLDSTYLE)
UniPTEffect(0x4,0);
else
UniEffect(UNI_ITEFFECTH,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xc: /* Lxy Dual command G00 & Dxy */
if (flags & S3MIT_OLDSTYLE)
UniPTEffect(0x3,0);
else
UniEffect(UNI_ITEFFECTG,0);
UniEffect(UNI_S3MEFFECTD,inf);
break;
case 0xd: /* Mxx Set Channel Volume */
UniEffect(UNI_ITEFFECTM,inf);
break;
case 0xe: /* Nxy Slide Channel Volume */
UniEffect(UNI_ITEFFECTN,inf);
break;
case 0xf: /* Oxx set sampleoffset xx00h */
UniPTEffect(0x9,inf);
break;
case 0x10: /* Pxy Slide Panning Commands */
UniEffect(UNI_ITEFFECTP,inf);
break;
case 0x11: /* Qxy Retrig (+volumeslide) */
UniWriteByte(UNI_S3MEFFECTQ);
if(inf && !lo && !(flags & S3MIT_OLDSTYLE))
UniWriteByte(1);
else
UniWriteByte(inf);
break;
case 0x12: /* Rxy tremolo speed x, depth y */
UniEffect(UNI_S3MEFFECTR,inf);
break;
case 0x13: /* Sxx special commands */
if (inf>=0xf0) {
/* change resonant filter settings if necessary */
if((filters)&&((inf&0xf)!=activemacro)) {
activemacro=inf&0xf;
for(inf=0;inf<0x80;inf++)
filtersettings[inf].filter=filtermacros[activemacro];
}
} else {
/* Scream Tracker does not have samples larger than
64 Kb, thus doesn't need the SAx effect */
if ((flags & S3MIT_SCREAM) && ((inf & 0xf0) == 0xa0))
break;
UniEffect(UNI_ITEFFECTS0,inf);
}
break;
case 0x14: /* Txx tempo */
if(inf>=0x20)
UniEffect(UNI_S3MEFFECTT,inf);
else {
if(!(flags & S3MIT_OLDSTYLE))
/* IT Tempo slide */
UniEffect(UNI_ITEFFECTT,inf);
}
break;
case 0x15: /* Uxy Fine Vibrato speed x, depth y */
if(flags & S3MIT_OLDSTYLE)
UniEffect(UNI_S3MEFFECTU,inf);
else
UniEffect(UNI_ITEFFECTU,inf);
break;
case 0x16: /* Vxx Set Global Volume */
UniEffect(UNI_XMEFFECTG,inf);
break;
case 0x17: /* Wxy Global Volume Slide */
UniEffect(UNI_ITEFFECTW,inf);
break;
case 0x18: /* Xxx amiga command 8xx */
if(flags & S3MIT_OLDSTYLE) {
if(inf>128)
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
else
UniPTEffect(0x8,(inf==128)?255:(inf<<1));
} else
UniPTEffect(0x8,inf);
break;
case 0x19: /* Yxy Panbrello speed x, depth y */
UniEffect(UNI_ITEFFECTY,inf);
break;
case 0x1a: /* Zxx midi/resonant filters */
if(filtersettings[inf].filter) {
UniWriteByte(UNI_ITEFFECTZ);
UniWriteByte(filtersettings[inf].filter);
UniWriteByte(filtersettings[inf].inf);
}
break;
}
}
}
/*========== Unitrk stuff */
/* Generic effect writing routine */
void UniEffect(UWORD eff,UWORD dat)
{
if((!eff)||(eff>=UNI_LAST)) return;
UniWriteByte(eff);
if(unioperands[eff]==2)
UniWriteWord(dat);
else
UniWriteByte(dat);
}
/* Appends UNI_PTEFFECTX opcode to the unitrk stream. */
void UniPTEffect(UBYTE eff, UBYTE dat)
{
#ifdef MIKMOD_DEBUG
if (eff>=0x10)
fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);
else
#endif
if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat);
}
/* Appends UNI_VOLEFFECT + effect/dat to unistream. */
void UniVolEffect(UWORD eff,UBYTE dat)
{
if((eff)||(dat)) { /* don't write empty effect */
UniWriteByte(UNI_VOLEFFECTS);
UniWriteByte(eff);UniWriteByte(dat);
}
}
/* ex:set ts=4: */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,303 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: munitrk.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
All routines dealing with the manipulation of UNITRK streams
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
#include <string.h>
/* Unibuffer chunk size */
#define BUFPAGE 128
UWORD unioperands[UNI_LAST]={
0, /* not used */
1, /* UNI_NOTE */
1, /* UNI_INSTRUMENT */
1, /* UNI_PTEFFECT0 */
1, /* UNI_PTEFFECT1 */
1, /* UNI_PTEFFECT2 */
1, /* UNI_PTEFFECT3 */
1, /* UNI_PTEFFECT4 */
1, /* UNI_PTEFFECT5 */
1, /* UNI_PTEFFECT6 */
1, /* UNI_PTEFFECT7 */
1, /* UNI_PTEFFECT8 */
1, /* UNI_PTEFFECT9 */
1, /* UNI_PTEFFECTA */
1, /* UNI_PTEFFECTB */
1, /* UNI_PTEFFECTC */
1, /* UNI_PTEFFECTD */
1, /* UNI_PTEFFECTE */
1, /* UNI_PTEFFECTF */
1, /* UNI_S3MEFFECTA */
1, /* UNI_S3MEFFECTD */
1, /* UNI_S3MEFFECTE */
1, /* UNI_S3MEFFECTF */
1, /* UNI_S3MEFFECTI */
1, /* UNI_S3MEFFECTQ */
1, /* UNI_S3MEFFECTR */
1, /* UNI_S3MEFFECTT */
1, /* UNI_S3MEFFECTU */
0, /* UNI_KEYOFF */
1, /* UNI_KEYFADE */
2, /* UNI_VOLEFFECTS */
1, /* UNI_XMEFFECT4 */
1, /* UNI_XMEFFECT6 */
1, /* UNI_XMEFFECTA */
1, /* UNI_XMEFFECTE1 */
1, /* UNI_XMEFFECTE2 */
1, /* UNI_XMEFFECTEA */
1, /* UNI_XMEFFECTEB */
1, /* UNI_XMEFFECTG */
1, /* UNI_XMEFFECTH */
1, /* UNI_XMEFFECTL */
1, /* UNI_XMEFFECTP */
1, /* UNI_XMEFFECTX1 */
1, /* UNI_XMEFFECTX2 */
1, /* UNI_ITEFFECTG */
1, /* UNI_ITEFFECTH */
1, /* UNI_ITEFFECTI */
1, /* UNI_ITEFFECTM */
1, /* UNI_ITEFFECTN */
1, /* UNI_ITEFFECTP */
1, /* UNI_ITEFFECTT */
1, /* UNI_ITEFFECTU */
1, /* UNI_ITEFFECTW */
1, /* UNI_ITEFFECTY */
2, /* UNI_ITEFFECTZ */
1, /* UNI_ITEFFECTS0 */
2, /* UNI_ULTEFFECT9 */
2, /* UNI_MEDSPEED */
0, /* UNI_MEDEFFECTF1 */
0, /* UNI_MEDEFFECTF2 */
0, /* UNI_MEDEFFECTF3 */
2, /* UNI_OKTARP */
};
/* Sparse description of the internal module format
------------------------------------------------
A UNITRK stream is an array of bytes representing a single track of a pattern.
It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly
language):
rrrlllll
[REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND]..
^ ^ ^
|-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track...
The rep/len byte contains the number of bytes in the current row, _including_
the length byte itself (So the LENGTH byte of row 0 in the previous example
would have a value of 5). This makes it easy to search through a stream for a
particular row. A track is concluded by a 0-value length byte.
The upper 3 bits of the rep/len byte contain the number of times -1 this row
is repeated for this track. (so a value of 7 means this row is repeated 8 times)
Opcodes can range from 1 to 255 but currently only opcodes 1 to 62 are being
used. Each opcode can have a different number of operands. You can find the
number of operands to a particular opcode by using the opcode as an index into
the 'unioperands' table.
*/
/*========== Reading routines */
static UBYTE *rowstart; /* startadress of a row */
static UBYTE *rowend; /* endaddress of a row (exclusive) */
static UBYTE *rowpc; /* current unimod(tm) programcounter */
static UBYTE lastbyte; /* for UniSkipOpcode() */
void UniSetRow(UBYTE* t)
{
rowstart = t;
rowpc = rowstart;
rowend = t?rowstart+(*(rowpc++)&0x1f):t;
}
UBYTE UniGetByte(void)
{
return lastbyte = (rowpc<rowend)?*(rowpc++):0;
}
UWORD UniGetWord(void)
{
return ((UWORD)UniGetByte()<<8)|UniGetByte();
}
void UniSkipOpcode(void)
{
if (lastbyte < UNI_LAST) {
UWORD t = unioperands[lastbyte];
while (t--)
UniGetByte();
}
}
/* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns
NULL if the row can't be found. */
UBYTE *UniFindRow(UBYTE* t,UWORD row)
{
UBYTE c,l;
if(t)
while(1) {
c = *t; /* get rep/len byte */
if(!c) return NULL; /* zero ? -> end of track.. */
l = (c>>5)+1; /* extract repeat value */
if(l>row) break; /* reached wanted row? -> return pointer */
row -= l; /* haven't reached row yet.. update row */
t += c&0x1f; /* point t to the next row */
}
return t;
}
/*========== Writing routines */
static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */
static UWORD unimax; /* buffer size */
static UWORD unipc; /* buffer cursor */
static UWORD unitt; /* current row index */
static UWORD lastp; /* previous row index */
/* Resets index-pointers to create a new track. */
void UniReset(void)
{
unitt = 0; /* reset index to rep/len byte */
unipc = 1; /* first opcode will be written to index 1 */
lastp = 0; /* no previous row yet */
unibuf[0] = 0; /* clear rep/len byte */
}
/* Expands the buffer */
static BOOL UniExpand(int wanted)
{
if ((unipc+wanted)>=unimax) {
UBYTE *newbuf;
/* Expand the buffer by BUFPAGE bytes */
newbuf=(UBYTE*)realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE));
/* Check if realloc succeeded */
if(newbuf) {
unibuf = newbuf;
unimax+=BUFPAGE;
return 1;
} else
return 0;
}
return 1;
}
/* Appends one byte of data to the current row of a track. */
void UniWriteByte(UBYTE data)
{
if (UniExpand(1))
/* write byte to current position and update */
unibuf[unipc++]=data;
}
void UniWriteWord(UWORD data)
{
if (UniExpand(2)) {
unibuf[unipc++]=data>>8;
unibuf[unipc++]=data&0xff;
}
}
static BOOL MyCmp(UBYTE* a,UBYTE* b,UWORD l)
{
UWORD t;
for(t=0;t<l;t++)
if(*(a++)!=*(b++)) return 0;
return 1;
}
/* Closes the current row of a unitrk stream (updates the rep/len byte) and sets
pointers to start a new row. */
void UniNewline(void)
{
UWORD n,l,len;
n = (unibuf[lastp]>>5)+1; /* repeat of previous row */
l = (unibuf[lastp]&0x1f); /* length of previous row */
len = unipc-unitt; /* length of current row */
/* Now, check if the previous and the current row are identical.. when they
are, just increase the repeat field of the previous row */
if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) {
unibuf[lastp]+=0x20;
unipc = unitt+1;
} else {
if (UniExpand(unitt-unipc)) {
/* current and previous row aren't equal... update the pointers */
unibuf[unitt] = len;
lastp = unitt;
unitt = unipc++;
}
}
}
/* Terminates the current unitrk stream and returns a pointer to a copy of the
stream. */
UBYTE* UniDup(void)
{
UBYTE *d;
if (!UniExpand(unitt-unipc)) return NULL;
unibuf[unitt] = 0;
if(!(d=(UBYTE *)_mm_malloc(unipc))) return NULL;
memcpy(d,unibuf,unipc);
return d;
}
BOOL UniInit(void)
{
unimax = BUFPAGE;
if(!(unibuf=(UBYTE*)_mm_malloc(unimax*sizeof(UBYTE)))) return 0;
return 1;
}
void UniCleanup(void)
{
if(unibuf) free(unibuf);
unibuf = NULL;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,198 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: mwav.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
WAV sample loader
==============================================================================*/
/*
FIXME: Stereo .WAV files are not yet supported as samples.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
#ifdef SUNOS
extern int fprintf(FILE *, const char *, ...);
#endif
typedef struct WAV {
CHAR rID[4];
ULONG rLen;
CHAR wID[4];
CHAR fID[4];
ULONG fLen;
UWORD wFormatTag;
UWORD nChannels;
ULONG nSamplesPerSec;
ULONG nAvgBytesPerSec;
UWORD nBlockAlign;
UWORD nFormatSpecific;
} WAV;
SAMPLE* Sample_LoadGeneric_internal(MREADER* reader)
{
SAMPLE *si=NULL;
WAV wh;
BOOL have_fmt=0;
/* read wav header */
_mm_read_string(wh.rID,4,reader);
wh.rLen = _mm_read_I_ULONG(reader);
_mm_read_string(wh.wID,4,reader);
/* check for correct header */
if(_mm_eof(reader)|| memcmp(wh.rID,"RIFF",4) || memcmp(wh.wID,"WAVE",4)) {
_mm_errno = MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
/* scan all RIFF blocks until we find the sample data */
for(;;) {
CHAR dID[4];
ULONG len,start;
_mm_read_string(dID,4,reader);
len = _mm_read_I_ULONG(reader);
/* truncated file ? */
if (_mm_eof(reader)) {
_mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
start = _mm_ftell(reader);
/* sample format block
should be present only once and before a data block */
if(!memcmp(dID,"fmt ",4)) {
wh.wFormatTag = _mm_read_I_UWORD(reader);
wh.nChannels = _mm_read_I_UWORD(reader);
wh.nSamplesPerSec = _mm_read_I_ULONG(reader);
wh.nAvgBytesPerSec = _mm_read_I_ULONG(reader);
wh.nBlockAlign = _mm_read_I_UWORD(reader);
wh.nFormatSpecific = _mm_read_I_UWORD(reader);
#ifdef MIKMOD_DEBUG
fprintf(stderr,"\rwavloader : wFormatTag=%04x blockalign=%04x nFormatSpc=%04x\n",
wh.wFormatTag,wh.nBlockAlign,wh.nFormatSpecific);
#endif
if((have_fmt)||(wh.nChannels>1)) {
_mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
have_fmt=1;
} else
/* sample data block
should be present only once and after a format block */
if(!memcmp(dID,"data",4)) {
if(!have_fmt) {
_mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
return NULL;
}
if(!(si=(SAMPLE*)_mm_malloc(sizeof(SAMPLE)))) return NULL;
si->speed = wh.nSamplesPerSec/wh.nChannels;
si->volume = 64;
si->length = len;
if(wh.nBlockAlign == 2) {
si->flags = SF_16BITS | SF_SIGNED;
si->length >>= 1;
}
si->inflags = si->flags;
SL_RegisterSample(si,MD_SNDFX,reader);
SL_LoadSamples();
/* skip any other remaining blocks - so in case of repeated sample
fragments, we'll return the first anyway instead of an error */
break;
}
/* onto next block */
_mm_fseek(reader,start+len,SEEK_SET);
if (_mm_eof(reader))
break;
}
return si;
}
MIKMODAPI SAMPLE* Sample_LoadGeneric(MREADER* reader)
{
SAMPLE* result;
MUTEX_LOCK(vars);
result=Sample_LoadGeneric_internal(reader);
MUTEX_UNLOCK(vars);
return result;
}
MIKMODAPI SAMPLE* Sample_LoadFP(FILE *fp)
{
SAMPLE* result=NULL;
MREADER* reader;
if((reader=_mm_new_file_reader(fp))) {
result=Sample_LoadGeneric(reader);
_mm_delete_file_reader(reader);
}
return result;
}
MIKMODAPI SAMPLE* Sample_Load(CHAR* filename)
{
FILE *fp;
SAMPLE *si=NULL;
if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;
if((fp=_mm_fopen(filename,"rb"))) {
si = Sample_LoadFP(fp);
_mm_fclose(fp);
}
return si;
}
MIKMODAPI void Sample_Free(SAMPLE* si)
{
if(si) {
MD_SampleUnload(si->handle);
free(si);
}
}
void Sample_Free_internal(SAMPLE *si)
{
MUTEX_LOCK(vars);
Sample_Free(si);
MUTEX_UNLOCK(vars);
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,48 @@
/* MikMod sound library
(c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: npertab.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
MOD format period table. Used by both the MOD and M15 (15-inst mod) Loaders.
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mikmod_internals.h"
UWORD npertab[7 * OCTAVE] = {
/* Octaves 6 -> 0 */
/* C C# D D# E F F# G G# A A# B */
0x6b0,0x650,0x5f4,0x5a0,0x54c,0x500,0x4b8,0x474,0x434,0x3f8,0x3c0,0x38a,
0x358,0x328,0x2fa,0x2d0,0x2a6,0x280,0x25c,0x23a,0x21a,0x1fc,0x1e0,0x1c5,
0x1ac,0x194,0x17d,0x168,0x153,0x140,0x12e,0x11d,0x10d,0x0fe,0x0f0,0x0e2,
0x0d6,0x0ca,0x0be,0x0b4,0x0aa,0x0a0,0x097,0x08f,0x087,0x07f,0x078,0x071,
0x06b,0x065,0x05f,0x05a,0x055,0x050,0x04b,0x047,0x043,0x03f,0x03c,0x038,
0x035,0x032,0x02f,0x02d,0x02a,0x028,0x025,0x023,0x021,0x01f,0x01e,0x01c,
0x01b,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010,0x00f,0x00e
};
/* ex:set ts=4: */

View File

@@ -0,0 +1,519 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: sloader.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
Routines for loading samples. The sample loader utilizes the routines
provided by the "registered" sample loader.
==============================================================================*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "mikmod_internals.h"
static int sl_rlength;
static SWORD sl_old;
static SWORD *sl_buffer=NULL;
static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;
/* size of the loader buffer in words */
#define SLBUFSIZE 2048
/* IT-Compressed status structure */
typedef struct ITPACK {
UWORD bits; /* current number of bits */
UWORD bufbits; /* bits in buffer */
SWORD last; /* last output */
UBYTE buf; /* bit buffer */
} ITPACK;
BOOL SL_Init(SAMPLOAD* s)
{
if(!sl_buffer)
if(!(sl_buffer=_mm_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;
sl_rlength = s->length;
if(s->infmt & SF_16BITS) sl_rlength>>=1;
sl_old = 0;
return 1;
}
void SL_Exit(SAMPLOAD *s)
{
if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR);
if(sl_buffer) {
free(sl_buffer);
sl_buffer=NULL;
}
}
/* unpack a 8bit IT packed sample */
static BOOL read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
{
SWORD *dest=sl_buffer,*end=sl_buffer+count;
UWORD x,y,needbits,havebits,new_count=0;
UWORD bits = status->bits;
UWORD bufbits = status->bufbits;
SBYTE last = status->last;
UBYTE buf = status->buf;
while (dest<end) {
needbits=new_count?3:bits;
x=havebits=0;
while (needbits) {
/* feed buffer */
if (!bufbits) {
if((*incnt)--)
buf=_mm_read_UBYTE(reader);
else
buf=0;
bufbits=8;
}
/* get as many bits as necessary */
y = needbits<bufbits?needbits:bufbits;
x|= (buf & ((1<<y)- 1))<<havebits;
buf>>=y;
bufbits-=y;
needbits-=y;
havebits+=y;
}
if (new_count) {
new_count = 0;
if (++x >= bits)
x++;
bits = x;
continue;
}
if (bits<7) {
if (x==(1<<(bits-1))) {
new_count = 1;
continue;
}
}
else if (bits<9) {
y = (0xff >> (9-bits)) - 4;
if ((x>y)&&(x<=y+8)) {
if ((x-=y)>=bits)
x++;
bits = x;
continue;
}
}
else if (bits<10) {
if (x>=0x100) {
bits=x-0x100+1;
continue;
}
} else {
/* error in compressed data... */
_mm_errno=MMERR_ITPACK_INVALID_DATA;
return 0;
}
if (bits<8) /* extend sign */
x = ((SBYTE)(x <<(8-bits))) >> (8-bits);
*(dest++)= (last+=x) << 8; /* convert to 16 bit */
}
status->bits = bits;
status->bufbits = bufbits;
status->last = last;
status->buf = buf;
return dest-sl_buffer;
}
/* unpack a 16bit IT packed sample */
static BOOL read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
{
SWORD *dest=sl_buffer,*end=sl_buffer+count;
SLONG x,y,needbits,havebits,new_count=0;
UWORD bits = status->bits;
UWORD bufbits = status->bufbits;
SWORD last = status->last;
UBYTE buf = status->buf;
while (dest<end) {
needbits=new_count?4:bits;
x=havebits=0;
while (needbits) {
/* feed buffer */
if (!bufbits) {
if((*incnt)--)
buf=_mm_read_UBYTE(reader);
else
buf=0;
bufbits=8;
}
/* get as many bits as necessary */
y=needbits<bufbits?needbits:bufbits;
x|=(buf &((1<<y)-1))<<havebits;
buf>>=y;
bufbits-=y;
needbits-=y;
havebits+=y;
}
if (new_count) {
new_count = 0;
if (++x >= bits)
x++;
bits = x;
continue;
}
if (bits<7) {
if (x==(1<<(bits-1))) {
new_count=1;
continue;
}
}
else if (bits<17) {
y=(0xffff>>(17-bits))-8;
if ((x>y)&&(x<=y+16)) {
if ((x-=y)>=bits)
x++;
bits = x;
continue;
}
}
else if (bits<18) {
if (x>=0x10000) {
bits=x-0x10000+1;
continue;
}
} else {
/* error in compressed data... */
_mm_errno=MMERR_ITPACK_INVALID_DATA;
return 0;
}
if (bits<16) /* extend sign */
x = ((SWORD)(x<<(16-bits)))>>(16-bits);
*(dest++)=(last+=x);
}
status->bits = bits;
status->bufbits = bufbits;
status->last = last;
status->buf = buf;
return dest-sl_buffer;
}
static BOOL SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,BOOL dither)
{
SBYTE *bptr = (SBYTE*)buffer;
SWORD *wptr = (SWORD*)buffer;
int stodo,t,u;
int result,c_block=0; /* compression bytes until next block */
ITPACK status;
UWORD incnt;
while(length) {
stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;
if(infmt&SF_ITPACKED) {
sl_rlength=0;
if (!c_block) {
status.bits = (infmt & SF_16BITS) ? 17 : 9;
status.last = status.bufbits = 0;
incnt=_mm_read_I_UWORD(reader);
c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;
if(infmt&SF_DELTA) sl_old=0;
}
if (infmt & SF_16BITS) {
if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))
return 1;
} else {
if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))
return 1;
}
if(result!=stodo) {
_mm_errno=MMERR_ITPACK_INVALID_DATA;
return 1;
}
c_block -= stodo;
} else {
if(infmt&SF_16BITS) {
if(infmt&SF_BIG_ENDIAN)
_mm_read_M_SWORDS(sl_buffer,stodo,reader);
else
_mm_read_I_SWORDS(sl_buffer,stodo,reader);
} else {
SBYTE *src;
SWORD *dest;
reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);
src = (SBYTE*)sl_buffer;
dest = sl_buffer;
src += stodo;dest += stodo;
for(t=0;t<stodo;t++) {
src--;dest--;
*dest = (*src)<<8;
}
}
sl_rlength-=stodo;
}
if(infmt & SF_DELTA)
for(t=0;t<stodo;t++) {
sl_buffer[t] += sl_old;
sl_old = sl_buffer[t];
}
if((infmt^outfmt) & SF_SIGNED)
for(t=0;t<stodo;t++)
sl_buffer[t]^= 0x8000;
if(scalefactor) {
int idx = 0;
SLONG scaleval;
/* Sample Scaling... average values for better results. */
t= 0;
while(t<stodo && length) {
scaleval = 0;
for(u=scalefactor;u && t<stodo;u--,t++)
scaleval+=sl_buffer[t];
sl_buffer[idx++]=scaleval/(scalefactor-u);
length--;
}
stodo = idx;
} else
length -= stodo;
if (dither) {
if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) {
/* dither stereo to mono, average together every two samples */
SLONG avgval;
int idx = 0;
t=0;
while(t<stodo && length) {
avgval=sl_buffer[t++];
avgval+=sl_buffer[t++];
sl_buffer[idx++]=avgval>>1;
length-=2;
}
stodo = idx;
}
}
if(outfmt & SF_16BITS) {
for(t=0;t<stodo;t++)
*(wptr++)=sl_buffer[t];
} else {
for(t=0;t<stodo;t++)
*(bptr++)=sl_buffer[t]>>8;
}
}
return 0;
}
BOOL SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)
{
return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,
length,smp->reader,0);
}
/* Registers a sample for loading when SL_LoadSamples() is called. */
SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)
{
SAMPLOAD *news,**samplist,*cruise;
if(type==MD_MUSIC) {
samplist = &musiclist;
cruise = musiclist;
} else
if (type==MD_SNDFX) {
samplist = &sndfxlist;
cruise = sndfxlist;
} else
return NULL;
/* Allocate and add structure to the END of the list */
if(!(news=(SAMPLOAD*)_mm_malloc(sizeof(SAMPLOAD)))) return NULL;
if(cruise) {
while(cruise->next) cruise=cruise->next;
cruise->next = news;
} else
*samplist = news;
news->infmt = s->flags & SF_FORMATMASK;
news->outfmt = news->infmt;
news->reader = reader;
news->sample = s;
news->length = s->length;
news->loopstart = s->loopstart;
news->loopend = s->loopend;
return news;
}
static void FreeSampleList(SAMPLOAD* s)
{
SAMPLOAD *old;
while(s) {
old = s;
s = s->next;
free(old);
}
}
/* Returns the total amount of memory required by the samplelist queue. */
static ULONG SampleTotal(SAMPLOAD* samplist,int type)
{
int total = 0;
while(samplist) {
samplist->sample->flags=
(samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;
total += MD_SampleLength(type,samplist->sample);
samplist=samplist->next;
}
return total;
}
static ULONG RealSpeed(SAMPLOAD *s)
{
return(s->sample->speed/(s->scalefactor?s->scalefactor:1));
}
static BOOL DitherSamples(SAMPLOAD* samplist,int type)
{
SAMPLOAD *c2smp=NULL;
ULONG maxsize, speed;
SAMPLOAD *s;
if(!samplist) return 0;
if((maxsize=MD_SampleSpace(type)*1024))
while(SampleTotal(samplist,type)>maxsize) {
/* First Pass - check for any 16 bit samples */
s = samplist;
while(s) {
if(s->outfmt & SF_16BITS) {
SL_Sample16to8(s);
break;
}
s=s->next;
}
/* Second pass (if no 16bits found above) is to take the sample with
the highest speed and dither it by half. */
if(!s) {
s = samplist;
speed = 0;
while(s) {
if((s->sample->length) && (RealSpeed(s)>speed)) {
speed=RealSpeed(s);
c2smp=s;
}
s=s->next;
}
if (c2smp)
SL_HalveSample(c2smp,2);
}
}
/* Samples dithered, now load them ! */
s = samplist;
while(s) {
/* sample has to be loaded ? -> increase number of samples, allocate
memory and load sample. */
if(s->sample->length) {
if(s->sample->seekpos)
_mm_fseek(s->reader, s->sample->seekpos, SEEK_SET);
/* Call the sample load routine of the driver module. It has to
return a 'handle' (>=0) that identifies the sample. */
s->sample->handle = MD_SampleLoad(s, type);
s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;
if(s->sample->handle<0) {
FreeSampleList(samplist);
if(_mm_errorhandler) _mm_errorhandler();
return 1;
}
}
s = s->next;
}
FreeSampleList(samplist);
return 0;
}
BOOL SL_LoadSamples(void)
{
BOOL ok;
_mm_critical = 0;
if((!musiclist)&&(!sndfxlist)) return 0;
ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);
musiclist=sndfxlist=NULL;
return ok;
}
void SL_Sample16to8(SAMPLOAD* s)
{
s->outfmt &= ~SF_16BITS;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_Sample8to16(SAMPLOAD* s)
{
s->outfmt |= SF_16BITS;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_SampleSigned(SAMPLOAD* s)
{
s->outfmt |= SF_SIGNED;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_SampleUnsigned(SAMPLOAD* s)
{
s->outfmt &= ~SF_SIGNED;
s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
}
void SL_HalveSample(SAMPLOAD* s,int factor)
{
s->scalefactor=factor>0?factor:2;
s->sample->divfactor = s->scalefactor;
s->sample->length = s->length / s->scalefactor;
s->sample->loopstart = s->loopstart / s->scalefactor;
s->sample->loopend = s->loopend / s->scalefactor;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,968 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
AUTHORS for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: virtch.c,v 1.2 2004/02/13 13:31:54 raph Exp $
Sample mixing routines, using a 32 bits mixing buffer.
==============================================================================*/
/*
Optional features include:
(a) 4-step reverb (for 16 bit output only)
(b) Interpolation of sample data during mixing
(c) Dolby Surround Sound
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stddef.h>
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
/*
Constant definitions
====================
BITSHIFT
Controls the maximum volume of the sound output. All data is shifted
right by BITSHIFT after being mixed. Higher values result in quieter
sound and less chance of distortion.
REVERBERATION
Controls the duration of the reverb. Larger values represent a shorter
reverb loop. Smaller values extend the reverb but can result in more of
an echo-ish sound.
*/
#define BITSHIFT 9
#define REVERBERATION 110000L
#define FRACBITS 11
#define FRACMASK ((1L<<FRACBITS)-1L)
#define TICKLSIZE 8192
#define TICKWSIZE (TICKLSIZE<<1)
#define TICKBSIZE (TICKWSIZE<<1)
#define CLICK_SHIFT 6
#define CLICK_BUFFER (1L<<CLICK_SHIFT)
#ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
typedef struct VINFO {
UBYTE kick; /* =1 -> sample has to be restarted */
UBYTE active; /* =1 -> sample is playing */
UWORD flags; /* 16/8 bits looping/one-shot */
SWORD handle; /* identifies the sample */
ULONG start; /* start index */
ULONG size; /* samplesize */
ULONG reppos; /* loop start */
ULONG repend; /* loop end */
ULONG frq; /* current frequency */
int vol; /* current volume */
int pan; /* current panning position */
int rampvol;
int lvolsel,rvolsel; /* Volume factor in range 0-255 */
int oldlvol,oldrvol;
SLONGLONG current; /* current index in the sample */
SLONGLONG increment; /* increment value */
} VINFO;
static SWORD **Samples;
static VINFO *vinf=NULL,*vnf;
static long tickleft,samplesthatfit,vc_memory=0;
static int vc_softchn;
static SLONGLONG idxsize,idxlpos,idxlend;
static SLONG *vc_tickbuf=NULL;
static UWORD vc_mode;
/* Reverb control variables */
static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
static ULONG RVRindex;
/* For Mono or Left Channel */
static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,
*RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;
/* For Stereo only (Right Channel) */
static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,
*RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;
#ifdef NATIVE_64BIT_INT
#define NATIVE SLONGLONG
#else
#define NATIVE SLONG
#endif
/*========== 32 bit sample mixers - only for 32 bit platforms */
#ifndef NATIVE_64BIT_INT
static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample;
SLONG lvolsel = vnf->lvolsel;
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ += lvolsel * sample;
}
return index;
}
static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
while(todo--) {
sample=srce[index >> FRACBITS];
index += increment;
*dest++ += lvolsel * sample;
*dest++ += rvolsel * sample;
}
return index;
}
static SLONG Mix32SurroundNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
if (lvolsel>=rvolsel) {
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ += lvolsel*sample;
*dest++ -= lvolsel*sample;
}
} else {
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ -= rvolsel*sample;
*dest++ += rvolsel*sample;
}
}
return index;
}
static SLONG Mix32MonoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SLONG sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rampvol = vnf->rampvol;
if (rampvol) {
SLONG oldlvol = vnf->oldlvol - lvolsel;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
* sample >> CLICK_SHIFT;
if (!--rampvol)
break;
}
vnf->rampvol = rampvol;
if (todo < 0)
return index;
}
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += lvolsel * sample;
}
return index;
}
static SLONG Mix32StereoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SLONG sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
SLONG rampvol = vnf->rampvol;
if (rampvol) {
SLONG oldlvol = vnf->oldlvol - lvolsel;
SLONG oldrvol = vnf->oldrvol - rvolsel;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
* sample >> CLICK_SHIFT;
*dest++ += ((rvolsel << CLICK_SHIFT) + oldrvol * rampvol)
* sample >> CLICK_SHIFT;
if (!--rampvol)
break;
}
vnf->rampvol = rampvol;
if (todo < 0)
return index;
}
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += lvolsel * sample;
*dest++ += rvolsel * sample;
}
return index;
}
static SLONG Mix32SurroundInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SLONG sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
SLONG rampvol = vnf->rampvol;
SLONG oldvol, vol;
if (lvolsel >= rvolsel) {
vol = lvolsel;
oldvol = vnf->oldlvol;
} else {
vol = rvolsel;
oldvol = vnf->oldrvol;
}
if (rampvol) {
oldvol -= vol;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
sample=((vol << CLICK_SHIFT) + oldvol * rampvol)
* sample >> CLICK_SHIFT;
*dest++ += sample;
*dest++ -= sample;
if (!--rampvol)
break;
}
vnf->rampvol = rampvol;
if (todo < 0)
return index;
}
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += vol*sample;
*dest++ -= vol*sample;
}
return index;
}
#endif
/*========== 64 bit sample mixers - all platforms */
static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample;
SLONG lvolsel = vnf->lvolsel;
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ += lvolsel * sample;
}
return index;
}
static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
while(todo--) {
sample=srce[index >> FRACBITS];
index += increment;
*dest++ += lvolsel * sample;
*dest++ += rvolsel * sample;
}
return index;
}
static SLONGLONG MixSurroundNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
if(vnf->lvolsel>=vnf->rvolsel) {
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ += lvolsel*sample;
*dest++ -= lvolsel*sample;
}
} else {
while(todo--) {
sample = srce[index >> FRACBITS];
index += increment;
*dest++ -= rvolsel*sample;
*dest++ += rvolsel*sample;
}
}
return index;
}
static SLONGLONG MixMonoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SLONG sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rampvol = vnf->rampvol;
if (rampvol) {
SLONG oldlvol = vnf->oldlvol - lvolsel;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
* sample >> CLICK_SHIFT;
if (!--rampvol)
break;
}
vnf->rampvol = rampvol;
if (todo < 0)
return index;
}
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += lvolsel * sample;
}
return index;
}
static SLONGLONG MixStereoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SLONG sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
SLONG rampvol = vnf->rampvol;
if (rampvol) {
SLONG oldlvol = vnf->oldlvol - lvolsel;
SLONG oldrvol = vnf->oldrvol - rvolsel;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ +=((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
* sample >> CLICK_SHIFT;
*dest++ +=((rvolsel << CLICK_SHIFT) + oldrvol * rampvol)
* sample >> CLICK_SHIFT;
if (!--rampvol)
break;
}
vnf->rampvol = rampvol;
if (todo < 0)
return index;
}
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += lvolsel * sample;
*dest++ += rvolsel * sample;
}
return index;
}
static SLONGLONG MixSurroundInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SLONG sample;
SLONG lvolsel = vnf->lvolsel;
SLONG rvolsel = vnf->rvolsel;
SLONG rampvol = vnf->rampvol;
SLONG oldvol, vol;
if (lvolsel >= rvolsel) {
vol = lvolsel;
oldvol = vnf->oldlvol;
} else {
vol = rvolsel;
oldvol = vnf->oldrvol;
}
if (rampvol) {
oldvol -= vol;
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
sample=((vol << CLICK_SHIFT) + oldvol * rampvol)
* sample >> CLICK_SHIFT;
*dest++ += sample;
*dest++ -= sample;
if (!--rampvol)
break;
}
vnf->rampvol = rampvol;
if (todo < 0)
return index;
}
while(todo--) {
sample=(SLONG)srce[index>>FRACBITS]+
((SLONG)(srce[(index>>FRACBITS)+1]-srce[index>>FRACBITS])
*(index&FRACMASK)>>FRACBITS);
index += increment;
*dest++ += vol*sample;
*dest++ -= vol*sample;
}
return index;
}
static void (*MixReverb)(SLONG* srce,NATIVE count);
/* Reverb macros */
#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n
#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)
#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)
static void MixReverb_Normal(SLONG* srce,NATIVE count)
{
unsigned int speedup;
int ReverbPct;
unsigned int loc1,loc2,loc3,loc4;
unsigned int loc5,loc6,loc7,loc8;
ReverbPct=58+(md_reverb<<2);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
}
}
static void MixReverb_Stereo(SLONG* srce,NATIVE count)
{
unsigned int speedup;
int ReverbPct;
unsigned int loc1, loc2, loc3, loc4;
unsigned int loc5, loc6, loc7, loc8;
ReverbPct = 92+(md_reverb<<1);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Compute the right channel echo buffers */
speedup = srce[1] >> 3;
COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);
COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel then right channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
*srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+
RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];
}
}
/* Mixing macros */
#define EXTRACT_SAMPLE_FP(var,size) var=(*srce++>>(BITSHIFT-size)) * ((1.0f / 32768.0f) / (1 << size))
#define CHECK_SAMPLE_FP(var,bound) var=(var>bound)?bound:(var<-bound)?-bound:var
#define PUT_SAMPLE_FP(var) *dste++=var
static void Mix32ToFP(float* dste,SLONG* srce,NATIVE count)
{
float x1,x2,x3,x4;
int remain;
#define FP_SHIFT 4
remain=count&3;
for(count>>=2;count;count--) {
EXTRACT_SAMPLE_FP(x1,FP_SHIFT); EXTRACT_SAMPLE_FP(x2,FP_SHIFT);
EXTRACT_SAMPLE_FP(x3,FP_SHIFT); EXTRACT_SAMPLE_FP(x4,FP_SHIFT);
CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);
CHECK_SAMPLE_FP(x3,1.0f); CHECK_SAMPLE_FP(x4,1.0f);
PUT_SAMPLE_FP(x1); PUT_SAMPLE_FP(x2);
PUT_SAMPLE_FP(x3); PUT_SAMPLE_FP(x4);
}
while(remain--) {
EXTRACT_SAMPLE_FP(x1,FP_SHIFT);
CHECK_SAMPLE_FP(x1,1.0f);
PUT_SAMPLE_FP(x1);
}
}
/* Mixing macros */
#define EXTRACT_SAMPLE(var,size) var=*srce++>>(BITSHIFT+16-size)
#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var
#define PUT_SAMPLE(var) *dste++=var
static void Mix32To16(SWORD* dste,SLONG* srce,NATIVE count)
{
SLONG x1,x2,x3,x4;
int remain;
remain=count&3;
for(count>>=2;count;count--) {
EXTRACT_SAMPLE(x1,16); EXTRACT_SAMPLE(x2,16);
EXTRACT_SAMPLE(x3,16); EXTRACT_SAMPLE(x4,16);
CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);
PUT_SAMPLE(x1); PUT_SAMPLE(x2); PUT_SAMPLE(x3); PUT_SAMPLE(x4);
}
while(remain--) {
EXTRACT_SAMPLE(x1,16);
CHECK_SAMPLE(x1,32768);
PUT_SAMPLE(x1);
}
}
static void Mix32To8(SBYTE* dste,SLONG* srce,NATIVE count)
{
SWORD x1,x2,x3,x4;
int remain;
remain=count&3;
for(count>>=2;count;count--) {
EXTRACT_SAMPLE(x1,8); EXTRACT_SAMPLE(x2,8);
EXTRACT_SAMPLE(x3,8); EXTRACT_SAMPLE(x4,8);
CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);
PUT_SAMPLE(x1+128); PUT_SAMPLE(x2+128);
PUT_SAMPLE(x3+128); PUT_SAMPLE(x4+128);
}
while(remain--) {
EXTRACT_SAMPLE(x1,8);
CHECK_SAMPLE(x1,128);
PUT_SAMPLE(x1+128);
}
}
static void AddChannel(SLONG* ptr,NATIVE todo)
{
SLONGLONG end,done;
SWORD *s;
if(!(s=Samples[vnf->handle])) {
vnf->current = vnf->active = 0;
return;
}
/* update the 'current' index so the sample loops, or stops playing if it
reached the end of the sample */
while(todo>0) {
SLONGLONG endpos;
if(vnf->flags & SF_REVERSE) {
/* The sample is playing in reverse */
if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {
/* the sample is looping and has reached the loopstart index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlpos */
vnf->current = idxlpos+(idxlpos-vnf->current);
vnf->flags &= ~SF_REVERSE;
vnf->increment = -vnf->increment;
} else
/* normal backwards looping, so set the current position to
loopend index */
vnf->current=idxlend-(idxlpos-vnf->current);
} else {
/* the sample is not looping, so check if it reached index 0 */
if(vnf->current < 0) {
/* playing index reached 0, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
} else {
/* The sample is playing forward */
if((vnf->flags & SF_LOOP) &&
(vnf->current >= idxlend)) {
/* the sample is looping, check the loopend index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlend */
vnf->flags |= SF_REVERSE;
vnf->increment = -vnf->increment;
vnf->current = idxlend-(vnf->current-idxlend);
} else
/* normal backwards looping, so set the current position
to loopend index */
vnf->current=idxlpos+(vnf->current-idxlend);
} else {
/* sample is not looping, so check if it reached the last
position */
if(vnf->current >= idxsize) {
/* yes, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
}
end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:
(vnf->flags&SF_LOOP)?idxlend:idxsize;
/* if the sample is not blocked... */
if((end==vnf->current)||(!vnf->increment))
done=0;
else {
done=MIN((end-vnf->current)/vnf->increment+1,todo);
if(done<0) done=0;
}
if(!done) {
vnf->active = 0;
break;
}
endpos=vnf->current+done*vnf->increment;
if(vnf->vol) {
#ifndef NATIVE_64BIT_INT
/* use the 32 bit mixers as often as we can (they're much faster) */
if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {
if((md_mode & DMODE_INTERP)) {
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))
vnf->current=Mix32SurroundInterp
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=Mix32StereoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=Mix32MonoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))
vnf->current=Mix32SurroundNormal
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=Mix32StereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=Mix32MonoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
#endif
{
if((md_mode & DMODE_INTERP)) {
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))
vnf->current=MixSurroundInterp
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=MixStereoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=MixMonoInterp
(s,ptr,vnf->current,vnf->increment,done);
} else if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(md_mode&DMODE_SURROUND))
vnf->current=MixSurroundNormal
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=MixStereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=MixMonoNormal
(s,ptr,vnf->current,vnf->increment,done);
}
} else
/* update sample position */
vnf->current=endpos;
todo-=done;
ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;
}
}
#define _IN_VIRTCH_
#include "virtch_common.c"
#undef _IN_VIRTCH_
void VC1_WriteSamples(SBYTE* buf,ULONG todo)
{
int left,portion=0,count;
SBYTE *buffer;
int t, pan, vol;
while(todo) {
if(!tickleft) {
if(vc_mode & DMODE_SOFT_MUSIC) md_player();
tickleft=(md_mixfreq*125L)/(md_bpm*50L);
}
left = MIN(tickleft, todo);
buffer = buf;
tickleft -= left;
todo -= left;
buf += samples2bytes(left);
while(left) {
portion = MIN(left, samplesthatfit);
count = (vc_mode & DMODE_STEREO)?(portion<<1):portion;
memset(vc_tickbuf, 0, count<<2);
for(t=0;t<vc_softchn;t++) {
vnf = &vinf[t];
if(vnf->kick) {
vnf->current=((SLONGLONG)vnf->start)<<FRACBITS;
vnf->kick =0;
vnf->active =1;
}
if(!vnf->frq) vnf->active = 0;
if(vnf->active) {
vnf->increment=((SLONGLONG)(vnf->frq<<FRACBITS))/md_mixfreq;
if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;
vol = vnf->vol; pan = vnf->pan;
vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;
if(vc_mode & DMODE_STEREO) {
if(pan != PAN_SURROUND) {
vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;
vnf->rvolsel=(vol*pan)>>8;
} else
vnf->lvolsel=vnf->rvolsel=vol/2;
} else
vnf->lvolsel=vol;
idxsize = (vnf->size)? ((SLONGLONG)vnf->size << FRACBITS)-1 : 0;
idxlend = (vnf->repend)? ((SLONGLONG)vnf->repend << FRACBITS)-1 : 0;
idxlpos = (SLONGLONG)vnf->reppos << FRACBITS;
AddChannel(vc_tickbuf, portion);
}
}
if(md_reverb) {
if(md_reverb>15) md_reverb=15;
MixReverb(vc_tickbuf, portion);
}
if(vc_mode & DMODE_FLOAT)
Mix32ToFP((float*) buffer, vc_tickbuf, count);
else if(vc_mode & DMODE_16BITS)
Mix32To16((SWORD*) buffer, vc_tickbuf, count);
else
Mix32To8((SBYTE*) buffer, vc_tickbuf, count);
buffer += samples2bytes(portion);
left -= portion;
}
}
}
BOOL VC1_Init(void)
{
VC_SetupPointers();
if (md_mode&DMODE_HQMIXER)
return VC2_Init();
if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
if(!vc_tickbuf)
if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal;
vc_mode = md_mode;
return 0;
}
BOOL VC1_PlayStart(void)
{
samplesthatfit=TICKLSIZE;
if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;
tickleft = 0;
RVc1 = (5000L * md_mixfreq) / REVERBERATION;
RVc2 = (5078L * md_mixfreq) / REVERBERATION;
RVc3 = (5313L * md_mixfreq) / REVERBERATION;
RVc4 = (5703L * md_mixfreq) / REVERBERATION;
RVc5 = (6250L * md_mixfreq) / REVERBERATION;
RVc6 = (6953L * md_mixfreq) / REVERBERATION;
RVc7 = (7813L * md_mixfreq) / REVERBERATION;
RVc8 = (8828L * md_mixfreq) / REVERBERATION;
if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
RVRindex = 0;
return 0;
}
void VC1_PlayStop(void)
{
if(RVbufL1) free(RVbufL1);
if(RVbufL2) free(RVbufL2);
if(RVbufL3) free(RVbufL3);
if(RVbufL4) free(RVbufL4);
if(RVbufL5) free(RVbufL5);
if(RVbufL6) free(RVbufL6);
if(RVbufL7) free(RVbufL7);
if(RVbufL8) free(RVbufL8);
RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
if(RVbufR1) free(RVbufR1);
if(RVbufR2) free(RVbufR2);
if(RVbufR3) free(RVbufR3);
if(RVbufR4) free(RVbufR4);
if(RVbufR5) free(RVbufR5);
if(RVbufR6) free(RVbufR6);
if(RVbufR7) free(RVbufR7);
if(RVbufR8) free(RVbufR8);
RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
}
BOOL VC1_SetNumVoices(void)
{
int t;
if(!(vc_softchn=md_softchn)) return 0;
if(vinf) free(vinf);
if(!(vinf= _mm_calloc(sizeof(VINFO),vc_softchn))) return 1;
for(t=0;t<vc_softchn;t++) {
vinf[t].frq=10000;
vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
}
return 0;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,938 @@
/* MikMod sound library
(c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: virtch2.c,v 1.2 2004/02/13 13:31:54 raph Exp $
High-quality sample mixing routines, using a 32 bits mixing buffer,
interpolation, and sample smoothing to improve sound quality and remove
clicks.
==============================================================================*/
/*
Future Additions:
Low-Pass filter to remove annoying staticy buzz.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#include <string.h>
#include "mikmod_internals.h"
/*
Constant Definitions
====================
MAXVOL_FACTOR (was BITSHIFT in virtch.c)
Controls the maximum volume of the output data. All mixed data is
divided by this number after mixing, so larger numbers result in
quieter mixing. Smaller numbers will increase the likeliness of
distortion on loud modules.
REVERBERATION
Larger numbers result in shorter reverb duration. Longer reverb
durations can cause unwanted static and make the reverb sound more
like a crappy echo.
SAMPLING_SHIFT
Specified the shift multiplier which controls by how much the mixing
rate is multiplied while mixing. Higher values can improve quality by
smoothing the sound and reducing pops and clicks. Note, this is a shift
value, so a value of 2 becomes a mixing-rate multiplier of 4, and a
value of 3 = 8, etc.
FRACBITS
The number of bits per integer devoted to the fractional part of the
number. Generally, this number should not be changed for any reason.
!!! IMPORTANT !!! All values below MUST ALWAYS be greater than 0
*/
#define MAXVOL_FACTOR (1<<9)
#define REVERBERATION 11000L
#define SAMPLING_SHIFT 2
#define SAMPLING_FACTOR (1UL<<SAMPLING_SHIFT)
#define FRACBITS 28
#define FRACMASK ((1UL<<FRACBITS)-1UL)
#define TICKLSIZE 8192
#define TICKWSIZE (TICKLSIZE * 2)
#define TICKBSIZE (TICKWSIZE * 2)
#define CLICK_SHIFT_BASE 6
#define CLICK_SHIFT (CLICK_SHIFT_BASE + SAMPLING_SHIFT)
#define CLICK_BUFFER (1L << CLICK_SHIFT)
#ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
typedef struct VINFO {
UBYTE kick; /* =1 -> sample has to be restarted */
UBYTE active; /* =1 -> sample is playing */
UWORD flags; /* 16/8 bits looping/one-shot */
SWORD handle; /* identifies the sample */
ULONG start; /* start index */
ULONG size; /* samplesize */
ULONG reppos; /* loop start */
ULONG repend; /* loop end */
ULONG frq; /* current frequency */
int vol; /* current volume */
int pan; /* current panning position */
int click;
int rampvol;
SLONG lastvalL,lastvalR;
int lvolsel,rvolsel; /* Volume factor in range 0-255 */
int oldlvol,oldrvol;
SLONGLONG current; /* current index in the sample */
SLONGLONG increment; /* increment value */
} VINFO;
static SWORD **Samples;
static VINFO *vinf=NULL,*vnf;
static long tickleft,samplesthatfit,vc_memory=0;
static int vc_softchn;
static SLONGLONG idxsize,idxlpos,idxlend;
static SLONG *vc_tickbuf=NULL;
static UWORD vc_mode;
/* Reverb control variables */
static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
static ULONG RVRindex;
/* For Mono or Left Channel */
static SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,
*RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;
/* For Stereo only (Right Channel) */
static SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,
*RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;
#ifdef NATIVE_64BIT_INT
#define NATIVE SLONGLONG
#else
#define NATIVE SLONG
#endif
/*========== 32 bit sample mixers - only for 32 bit platforms */
#ifndef NATIVE_64BIT_INT
static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
{
SWORD sample=0;
SLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=(((SLONG)(srce[i]*(FRACMASK+1L-f)) +
((SLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample ) +
(vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );
vnf->click--;
} else
*dest++ +=vnf->lvolsel*sample;
}
vnf->lastvalL=vnf->lvolsel * sample;
return index;
}
static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)
{
SWORD sample=0;
SLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONG)srce[i+1] * f)) >> FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( ((SLONG)vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONG)sample ) >> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONG)vnf->oldrvol*vnf->rampvol) +
(vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( (SLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample ) + (vnf->lastvalL * vnf->click) )
>> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample ) + (vnf->lastvalR * vnf->click) )
>> CLICK_SHIFT );
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ +=vnf->rvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->rvolsel*sample;
return index;
}
static SLONG Mix32StereoSurround(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)
{
SWORD sample=0;
long whoop;
SLONG i, f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
whoop=(long)(
( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONG)sample) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->rampvol--;
} else
if(vnf->click) {
whoop = (long)(
( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONG)sample) +
(vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ -=vnf->lvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->lvolsel*sample;
return index;
}
#endif
/*========== 64 bit mixers */
static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
{
SWORD sample=0;
SLONGLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=(((SLONGLONG)(srce[i]*(FRACMASK+1L-f)) +
((SLONGLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONGLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample ) +
(vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );
vnf->click--;
} else
*dest++ +=vnf->lvolsel*sample;
}
vnf->lastvalL=vnf->lvolsel * sample;
return index;
}
static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)
{
SWORD sample=0;
SLONGLONG i,f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONGLONG)srce[i+1] * f)) >> FRACBITS);
index += increment;
if(vnf->rampvol) {
*dest++ += (long)(
( ( ((SLONGLONG)vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONGLONG)sample ) >> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONGLONG)vnf->oldrvol*vnf->rampvol) +
(vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))
) * (SLONGLONG)sample ) >> CLICK_SHIFT );
vnf->rampvol--;
} else
if(vnf->click) {
*dest++ += (long)(
( ( (SLONGLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample ) + (vnf->lastvalL * vnf->click) )
>> CLICK_SHIFT );
*dest++ += (long)(
( ( ((SLONGLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample ) + (vnf->lastvalR * vnf->click) )
>> CLICK_SHIFT );
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ +=vnf->rvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->rvolsel*sample;
return index;
}
static SLONGLONG MixStereoSurround(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)
{
SWORD sample=0;
long whoop;
SLONGLONG i, f;
while(todo--) {
i=index>>FRACBITS,f=index&FRACMASK;
sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
((SLONGLONG)srce[i+1]*f)) >> FRACBITS);
index+=increment;
if(vnf->rampvol) {
whoop=(long)(
( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +
(vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
(SLONGLONG)sample) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->rampvol--;
} else
if(vnf->click) {
whoop = (long)(
( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
(SLONGLONG)sample) +
(vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );
*dest++ +=whoop;
*dest++ -=whoop;
vnf->click--;
} else {
*dest++ +=vnf->lvolsel*sample;
*dest++ -=vnf->lvolsel*sample;
}
}
vnf->lastvalL=vnf->lvolsel*sample;
vnf->lastvalR=vnf->lvolsel*sample;
return index;
}
static void(*Mix32toFP)(float* dste,SLONG* srce,NATIVE count);
static void(*Mix32to16)(SWORD* dste,SLONG* srce,NATIVE count);
static void(*Mix32to8)(SBYTE* dste,SLONG* srce,NATIVE count);
static void(*MixReverb)(SLONG* srce,NATIVE count);
/* Reverb macros */
#define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n
#define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)
#define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)
static void MixReverb_Normal(SLONG* srce,NATIVE count)
{
NATIVE speedup;
int ReverbPct;
unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;
ReverbPct=58+(md_reverb*4);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
}
}
static void MixReverb_Stereo(SLONG *srce,NATIVE count)
{
NATIVE speedup;
int ReverbPct;
unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;
ReverbPct=58+(md_reverb*4);
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
while(count--) {
/* Compute the left channel echo buffers */
speedup = *srce >> 3;
COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);
COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);
/* Compute the right channel echo buffers */
speedup = srce[1] >> 3;
COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);
COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);
/* Prepare to compute actual finalized data */
RVRindex++;
COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);
COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);
/* left channel */
*srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
/* right channel */
*srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+
RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];
}
}
/* Mixing macros */
#define EXTRACT_SAMPLE_FP(var,attenuation) var=*srce++*((1.0f / 32768.0f) / (MAXVOL_FACTOR*attenuation))
#define CHECK_SAMPLE_FP(var,bound) var=(var>bound)?bound:(var<-bound)?-bound:var
static void Mix32ToFP_Normal(float* dste,SLONG* srce,NATIVE count)
{
float x1,x2,tmpx;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=0.0f;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);
CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);
tmpx+=x1+x2;
}
*dste++ =tmpx*(1.0f/SAMPLING_FACTOR);
}
}
static void Mix32ToFP_Stereo(float* dste,SLONG* srce,NATIVE count)
{
float x1,x2,x3,x4,tmpx,tmpy;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=tmpy=0.0f;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);
EXTRACT_SAMPLE_FP(x3,1.0f); EXTRACT_SAMPLE_FP(x4,1.0f);
CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);
CHECK_SAMPLE_FP(x3,1.0f); CHECK_SAMPLE_FP(x4,1.0f);
tmpx+=x1+x3;
tmpy+=x2+x4;
}
*dste++ =tmpx*(1.0f/SAMPLING_FACTOR);
*dste++ =tmpy*(1.0f/SAMPLING_FACTOR);
}
}
/* Mixing macros */
#define EXTRACT_SAMPLE(var,attenuation) var=*srce++/(MAXVOL_FACTOR*attenuation)
#define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var
static void Mix32To16_Normal(SWORD* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,tmpx;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);
CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
tmpx+=x1+x2;
}
*dste++ =tmpx/SAMPLING_FACTOR;
}
}
static void Mix32To16_Stereo(SWORD* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,x3,x4,tmpx,tmpy;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=tmpy=0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);
EXTRACT_SAMPLE(x3,1); EXTRACT_SAMPLE(x4,1);
CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);
tmpx+=x1+x3;
tmpy+=x2+x4;
}
*dste++ =tmpx/SAMPLING_FACTOR;
*dste++ =tmpy/SAMPLING_FACTOR;
}
}
static void Mix32To8_Normal(SBYTE* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,tmpx;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx = 0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);
CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
tmpx+=x1+x2;
}
*dste++ =(tmpx/SAMPLING_FACTOR)+128;
}
}
static void Mix32To8_Stereo(SBYTE* dste,SLONG* srce,NATIVE count)
{
NATIVE x1,x2,x3,x4,tmpx,tmpy;
int i;
for(count/=SAMPLING_FACTOR;count;count--) {
tmpx=tmpy=0;
for(i=SAMPLING_FACTOR/2;i;i--) {
EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);
EXTRACT_SAMPLE(x3,256); EXTRACT_SAMPLE(x4,256);
CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);
tmpx+=x1+x3;
tmpy+=x2+x4;
}
*dste++ =(tmpx/SAMPLING_FACTOR)+128;
*dste++ =(tmpy/SAMPLING_FACTOR)+128;
}
}
static void AddChannel(SLONG* ptr,NATIVE todo)
{
SLONGLONG end,done;
SWORD *s;
if(!(s=Samples[vnf->handle])) {
vnf->current = vnf->active = 0;
vnf->lastvalL = vnf->lastvalR = 0;
return;
}
/* update the 'current' index so the sample loops, or stops playing if it
reached the end of the sample */
while(todo>0) {
SLONGLONG endpos;
if(vnf->flags & SF_REVERSE) {
/* The sample is playing in reverse */
if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {
/* the sample is looping and has reached the loopstart index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlpos */
vnf->current = idxlpos+(idxlpos-vnf->current);
vnf->flags &= ~SF_REVERSE;
vnf->increment = -vnf->increment;
} else
/* normal backwards looping, so set the current position to
loopend index */
vnf->current=idxlend-(idxlpos-vnf->current);
} else {
/* the sample is not looping, so check if it reached index 0 */
if(vnf->current < 0) {
/* playing index reached 0, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
} else {
/* The sample is playing forward */
if((vnf->flags & SF_LOOP) &&
(vnf->current >= idxlend)) {
/* the sample is looping, check the loopend index */
if(vnf->flags & SF_BIDI) {
/* sample is doing bidirectional loops, so 'bounce' the
current index against the idxlend */
vnf->flags |= SF_REVERSE;
vnf->increment = -vnf->increment;
vnf->current = idxlend-(vnf->current-idxlend);
} else
/* normal backwards looping, so set the current position
to loopend index */
vnf->current=idxlpos+(vnf->current-idxlend);
} else {
/* sample is not looping, so check if it reached the last
position */
if(vnf->current >= idxsize) {
/* yes, so stop playing this sample */
vnf->current = vnf->active = 0;
break;
}
}
}
end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:
(vnf->flags&SF_LOOP)?idxlend:idxsize;
/* if the sample is not blocked... */
if((end==vnf->current)||(!vnf->increment))
done=0;
else {
done=MIN((end-vnf->current)/vnf->increment+1,todo);
if(done<0) done=0;
}
if(!done) {
vnf->active = 0;
break;
}
endpos=vnf->current+done*vnf->increment;
if(vnf->vol || vnf->rampvol) {
#ifndef NATIVE_64BIT_INT
/* use the 32 bit mixers as often as we can (they're much faster) */
if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=Mix32StereoSurround
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=Mix32StereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=Mix32MonoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
#endif
{
if(vc_mode & DMODE_STEREO) {
if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))
vnf->current=MixStereoSurround
(s,ptr,vnf->current,vnf->increment,done);
else
vnf->current=MixStereoNormal
(s,ptr,vnf->current,vnf->increment,done);
} else
vnf->current=MixMonoNormal
(s,ptr,vnf->current,vnf->increment,done);
}
} else {
vnf->lastvalL = vnf->lastvalR = 0;
/* update sample position */
vnf->current=endpos;
}
todo -= done;
ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;
}
}
#define _IN_VIRTCH_
#define VC1_SilenceBytes VC2_SilenceBytes
#define VC1_WriteSamples VC2_WriteSamples
#define VC1_WriteBytes VC2_WriteBytes
#define VC1_Exit VC2_Exit
#define VC1_VoiceSetVolume VC2_VoiceSetVolume
#define VC1_VoiceGetVolume VC2_VoiceGetVolume
#define VC1_VoiceSetPanning VC2_VoiceSetPanning
#define VC1_VoiceGetPanning VC2_VoiceGetPanning
#define VC1_VoiceSetFrequency VC2_VoiceSetFrequency
#define VC1_VoiceGetFrequency VC2_VoiceGetFrequency
#define VC1_VoicePlay VC2_VoicePlay
#define VC1_VoiceStop VC2_VoiceStop
#define VC1_VoiceStopped VC2_VoiceStopped
#define VC1_VoiceGetPosition VC2_VoiceGetPosition
#define VC1_SampleUnload VC2_SampleUnload
#define VC1_SampleLoad VC2_SampleLoad
#define VC1_SampleSpace VC2_SampleSpace
#define VC1_SampleLength VC2_SampleLength
#define VC1_VoiceRealVolume VC2_VoiceRealVolume
#include "virtch_common.c"
#undef _IN_VIRTCH_
void VC2_WriteSamples(SBYTE* buf,ULONG todo)
{
int left,portion=0;
SBYTE *buffer;
int t,pan,vol;
todo*=SAMPLING_FACTOR;
while(todo) {
if(!tickleft) {
if(vc_mode & DMODE_SOFT_MUSIC) md_player();
tickleft=(md_mixfreq*125L*SAMPLING_FACTOR)/(md_bpm*50L);
tickleft&=~(SAMPLING_FACTOR-1);
}
left = MIN(tickleft, todo);
buffer = buf;
tickleft -= left;
todo -= left;
buf += samples2bytes(left)/SAMPLING_FACTOR;
while(left) {
portion = MIN(left, samplesthatfit);
memset(vc_tickbuf,0,portion<<((vc_mode&DMODE_STEREO)?3:2));
for(t=0;t<vc_softchn;t++) {
vnf = &vinf[t];
if(vnf->kick) {
vnf->current=((SLONGLONG)(vnf->start))<<FRACBITS;
vnf->kick = 0;
vnf->active = 1;
vnf->click = CLICK_BUFFER;
vnf->rampvol = 0;
}
if(!vnf->frq) vnf->active = 0;
if(vnf->active) {
vnf->increment=((SLONGLONG)(vnf->frq)<<(FRACBITS-SAMPLING_SHIFT))
/md_mixfreq;
if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;
vol = vnf->vol; pan = vnf->pan;
vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;
if(vc_mode & DMODE_STEREO) {
if(pan!=PAN_SURROUND) {
vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;
vnf->rvolsel=(vol*pan)>>8;
} else {
vnf->lvolsel=vnf->rvolsel=(vol * 256L) / 480;
}
} else
vnf->lvolsel=vol;
idxsize=(vnf->size)?((SLONGLONG)(vnf->size)<<FRACBITS)-1:0;
idxlend=(vnf->repend)?((SLONGLONG)(vnf->repend)<<FRACBITS)-1:0;
idxlpos=(SLONGLONG)(vnf->reppos)<<FRACBITS;
AddChannel(vc_tickbuf,portion);
}
}
if(md_reverb) {
if(md_reverb>15) md_reverb=15;
MixReverb(vc_tickbuf,portion);
}
if(vc_mode & DMODE_FLOAT)
Mix32toFP((float*)buffer,vc_tickbuf,portion);
else if(vc_mode & DMODE_16BITS)
Mix32to16((SWORD*)buffer,vc_tickbuf,portion);
else
Mix32to8((SBYTE*)buffer,vc_tickbuf,portion);
buffer += samples2bytes(portion) / SAMPLING_FACTOR;
left -= portion;
}
}
}
BOOL VC2_Init(void)
{
VC_SetupPointers();
if (!(md_mode&DMODE_HQMIXER))
return VC1_Init();
if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
if(!vc_tickbuf)
if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {
_mm_errno = MMERR_INITIALIZING_MIXER;
return 1;
}
if(md_mode & DMODE_STEREO) {
Mix32toFP = Mix32ToFP_Stereo;
Mix32to16 = Mix32To16_Stereo;
Mix32to8 = Mix32To8_Stereo;
MixReverb = MixReverb_Stereo;
} else {
Mix32toFP = Mix32ToFP_Normal;
Mix32to16 = Mix32To16_Normal;
Mix32to8 = Mix32To8_Normal;
MixReverb = MixReverb_Normal;
}
md_mode |= DMODE_INTERP;
vc_mode = md_mode;
return 0;
}
BOOL VC2_PlayStart(void)
{
md_mode|=DMODE_INTERP;
samplesthatfit = TICKLSIZE;
if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;
tickleft = 0;
RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 10);
RVc2 = (5078L * md_mixfreq) / (REVERBERATION * 10);
RVc3 = (5313L * md_mixfreq) / (REVERBERATION * 10);
RVc4 = (5703L * md_mixfreq) / (REVERBERATION * 10);
RVc5 = (6250L * md_mixfreq) / (REVERBERATION * 10);
RVc6 = (6953L * md_mixfreq) / (REVERBERATION * 10);
RVc7 = (7813L * md_mixfreq) / (REVERBERATION * 10);
RVc8 = (8828L * md_mixfreq) / (REVERBERATION * 10);
if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;
if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;
if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;
if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;
if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;
if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;
if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;
if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;
RVRindex = 0;
return 0;
}
void VC2_PlayStop(void)
{
if(RVbufL1) free(RVbufL1);
if(RVbufL2) free(RVbufL2);
if(RVbufL3) free(RVbufL3);
if(RVbufL4) free(RVbufL4);
if(RVbufL5) free(RVbufL5);
if(RVbufL6) free(RVbufL6);
if(RVbufL7) free(RVbufL7);
if(RVbufL8) free(RVbufL8);
if(RVbufR1) free(RVbufR1);
if(RVbufR2) free(RVbufR2);
if(RVbufR3) free(RVbufR3);
if(RVbufR4) free(RVbufR4);
if(RVbufR5) free(RVbufR5);
if(RVbufR6) free(RVbufR6);
if(RVbufR7) free(RVbufR7);
if(RVbufR8) free(RVbufR8);
RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
}
BOOL VC2_SetNumVoices(void)
{
int t;
md_mode|=DMODE_INTERP;
if(!(vc_softchn=md_softchn)) return 0;
if(vinf) free(vinf);
if(!(vinf=_mm_calloc(sizeof(VINFO),vc_softchn))) return 1;
for(t=0;t<vc_softchn;t++) {
vinf[t].frq=10000;
vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
}
return 0;
}
/* ex:set ts=4: */

View File

@@ -0,0 +1,459 @@
/* MikMod sound library
(c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
for complete list.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
/*==============================================================================
$Id: virtch_common.c,v 1.2 2004/02/13 13:31:54 raph Exp $
Common source parts between the two software mixers.
This file is probably the ugliest part of libmikmod...
==============================================================================*/
#ifndef _IN_VIRTCH_
#include "mikmod_internals.h"
extern BOOL VC1_Init(void);
extern BOOL VC2_Init(void);
static BOOL (*VC_Init_ptr)(void)=VC1_Init;
extern void VC1_Exit(void);
extern void VC2_Exit(void);
static void (*VC_Exit_ptr)(void)=VC1_Exit;
extern BOOL VC1_SetNumVoices(void);
extern BOOL VC2_SetNumVoices(void);
static BOOL (*VC_SetNumVoices_ptr)(void);
extern ULONG VC1_SampleSpace(int);
extern ULONG VC2_SampleSpace(int);
static ULONG (*VC_SampleSpace_ptr)(int);
extern ULONG VC1_SampleLength(int,SAMPLE*);
extern ULONG VC2_SampleLength(int,SAMPLE*);
static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);
extern BOOL VC1_PlayStart(void);
extern BOOL VC2_PlayStart(void);
static BOOL (*VC_PlayStart_ptr)(void);
extern void VC1_PlayStop(void);
extern void VC2_PlayStop(void);
static void (*VC_PlayStop_ptr)(void);
extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);
extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);
static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);
extern void VC1_SampleUnload(SWORD);
extern void VC2_SampleUnload(SWORD);
static void (*VC_SampleUnload_ptr)(SWORD);
extern ULONG VC1_WriteBytes(SBYTE*,ULONG);
extern ULONG VC2_WriteBytes(SBYTE*,ULONG);
static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);
extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);
extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);
static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);
extern void VC1_VoiceSetVolume(UBYTE,UWORD);
extern void VC2_VoiceSetVolume(UBYTE,UWORD);
static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);
extern UWORD VC1_VoiceGetVolume(UBYTE);
extern UWORD VC2_VoiceGetVolume(UBYTE);
static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);
extern void VC1_VoiceSetFrequency(UBYTE,ULONG);
extern void VC2_VoiceSetFrequency(UBYTE,ULONG);
static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);
extern ULONG VC1_VoiceGetFrequency(UBYTE);
extern ULONG VC2_VoiceGetFrequency(UBYTE);
static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);
extern void VC1_VoiceSetPanning(UBYTE,ULONG);
extern void VC2_VoiceSetPanning(UBYTE,ULONG);
static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);
extern ULONG VC1_VoiceGetPanning(UBYTE);
extern ULONG VC2_VoiceGetPanning(UBYTE);
static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);
extern void VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
extern void VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
extern void VC1_VoiceStop(UBYTE);
extern void VC2_VoiceStop(UBYTE);
static void (*VC_VoiceStop_ptr)(UBYTE);
extern BOOL VC1_VoiceStopped(UBYTE);
extern BOOL VC2_VoiceStopped(UBYTE);
static BOOL (*VC_VoiceStopped_ptr)(UBYTE);
extern SLONG VC1_VoiceGetPosition(UBYTE);
extern SLONG VC2_VoiceGetPosition(UBYTE);
static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);
extern ULONG VC1_VoiceRealVolume(UBYTE);
extern ULONG VC2_VoiceRealVolume(UBYTE);
static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);
#if defined __STDC__ || defined _MSC_VER
#define VC_PROC0(suffix) \
MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); }
#define VC_FUNC0(suffix,ret) \
MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); }
#define VC_PROC1(suffix,typ1) \
MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }
#define VC_FUNC1(suffix,ret,typ1) \
MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }
#define VC_PROC2(suffix,typ1,typ2) \
MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }
#define VC_FUNC2(suffix,ret,typ1,typ2) \
MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }
#else
#define VC_PROC0(suffix) \
MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); }
#define VC_FUNC0(suffix,ret) \
MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); }
#define VC_PROC1(suffix,typ1) \
MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); }
#define VC_FUNC1(suffix,ret,typ1) \
MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); }
#define VC_PROC2(suffix,typ1,typ2) \
MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }
#define VC_FUNC2(suffix,ret,typ1,typ2) \
MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }
#endif
VC_FUNC0(Init,BOOL)
VC_PROC0(Exit)
VC_FUNC0(SetNumVoices,BOOL)
VC_FUNC1(SampleSpace,ULONG,int)
VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)
VC_FUNC0(PlayStart,BOOL)
VC_PROC0(PlayStop)
VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)
VC_PROC1(SampleUnload,SWORD)
VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)
VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)
VC_PROC2(VoiceSetVolume,UBYTE,UWORD)
VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)
VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)
VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)
VC_PROC2(VoiceSetPanning,UBYTE,ULONG)
VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)
void VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g)
{ VC_VoicePlay_ptr(a,b,c,d,e,f,g); }
VC_PROC1(VoiceStop,UBYTE)
VC_FUNC1(VoiceStopped,BOOL,UBYTE)
VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)
VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)
void VC_SetupPointers(void)
{
if (md_mode&DMODE_HQMIXER) {
VC_Init_ptr=VC2_Init;
VC_Exit_ptr=VC2_Exit;
VC_SetNumVoices_ptr=VC2_SetNumVoices;
VC_SampleSpace_ptr=VC2_SampleSpace;
VC_SampleLength_ptr=VC2_SampleLength;
VC_PlayStart_ptr=VC2_PlayStart;
VC_PlayStop_ptr=VC2_PlayStop;
VC_SampleLoad_ptr=VC2_SampleLoad;
VC_SampleUnload_ptr=VC2_SampleUnload;
VC_WriteBytes_ptr=VC2_WriteBytes;
VC_SilenceBytes_ptr=VC2_SilenceBytes;
VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume;
VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume;
VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency;
VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency;
VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning;
VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning;
VC_VoicePlay_ptr=VC2_VoicePlay;
VC_VoiceStop_ptr=VC2_VoiceStop;
VC_VoiceStopped_ptr=VC2_VoiceStopped;
VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition;
VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume;
} else {
VC_Init_ptr=VC1_Init;
VC_Exit_ptr=VC1_Exit;
VC_SetNumVoices_ptr=VC1_SetNumVoices;
VC_SampleSpace_ptr=VC1_SampleSpace;
VC_SampleLength_ptr=VC1_SampleLength;
VC_PlayStart_ptr=VC1_PlayStart;
VC_PlayStop_ptr=VC1_PlayStop;
VC_SampleLoad_ptr=VC1_SampleLoad;
VC_SampleUnload_ptr=VC1_SampleUnload;
VC_WriteBytes_ptr=VC1_WriteBytes;
VC_SilenceBytes_ptr=VC1_SilenceBytes;
VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume;
VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume;
VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency;
VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency;
VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning;
VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning;
VC_VoicePlay_ptr=VC1_VoicePlay;
VC_VoiceStop_ptr=VC1_VoiceStop;
VC_VoiceStopped_ptr=VC1_VoiceStopped;
VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition;
VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume;
}
}
#else
#ifndef _VIRTCH_COMMON_
#define _VIRTCH_COMMON_
static ULONG samples2bytes(ULONG samples)
{
if(vc_mode & DMODE_FLOAT) samples <<= 2;
else if(vc_mode & DMODE_16BITS) samples <<= 1;
if(vc_mode & DMODE_STEREO) samples <<= 1;
return samples;
}
static ULONG bytes2samples(ULONG bytes)
{
if(vc_mode & DMODE_FLOAT) bytes >>= 2;
else if(vc_mode & DMODE_16BITS) bytes >>= 1;
if(vc_mode & DMODE_STEREO) bytes >>= 1;
return bytes;
}
/* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode
how the buffer is filled) */
ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo)
{
todo=samples2bytes(bytes2samples(todo));
/* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */
if(vc_mode & DMODE_FLOAT)
memset(buf,0,todo);
else if(vc_mode & DMODE_16BITS)
memset(buf,0,todo);
else
memset(buf,0x80,todo);
return todo;
}
void VC1_WriteSamples(SBYTE*,ULONG);
/* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES
actually written to 'buf' (which is rounded to number of samples that fit
into 'todo' bytes). */
ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo)
{
if(!vc_softchn)
return VC1_SilenceBytes(buf,todo);
todo = bytes2samples(todo);
VC1_WriteSamples(buf,todo);
return samples2bytes(todo);
}
void VC1_Exit(void)
{
if(vc_tickbuf) free(vc_tickbuf);
if(vinf) free(vinf);
if(Samples) free(Samples);
vc_tickbuf = NULL;
vinf = NULL;
Samples = NULL;
VC_SetupPointers();
}
UWORD VC1_VoiceGetVolume(UBYTE voice)
{
return vinf[voice].vol;
}
ULONG VC1_VoiceGetPanning(UBYTE voice)
{
return vinf[voice].pan;
}
void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)
{
vinf[voice].frq=frq;
}
ULONG VC1_VoiceGetFrequency(UBYTE voice)
{
return vinf[voice].frq;
}
void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
{
vinf[voice].flags = flags;
vinf[voice].handle = handle;
vinf[voice].start = start;
vinf[voice].size = size;
vinf[voice].reppos = reppos;
vinf[voice].repend = repend;
vinf[voice].kick = 1;
}
void VC1_VoiceStop(UBYTE voice)
{
vinf[voice].active = 0;
}
BOOL VC1_VoiceStopped(UBYTE voice)
{
return(vinf[voice].active==0);
}
SLONG VC1_VoiceGetPosition(UBYTE voice)
{
return(vinf[voice].current>>FRACBITS);
}
void VC1_VoiceSetVolume(UBYTE voice,UWORD vol)
{
/* protect against clicks if volume variation is too high */
if(abs((int)vinf[voice].vol-(int)vol)>32)
vinf[voice].rampvol=CLICK_BUFFER;
vinf[voice].vol=vol;
}
void VC1_VoiceSetPanning(UBYTE voice,ULONG pan)
{
/* protect against clicks if panning variation is too high */
if(abs((int)vinf[voice].pan-(int)pan)>48)
vinf[voice].rampvol=CLICK_BUFFER;
vinf[voice].pan=pan;
}
/*========== External mixer interface */
void VC1_SampleUnload(SWORD handle)
{
if (handle<MAXSAMPLEHANDLES) {
if (Samples[handle])
free(Samples[handle]);
Samples[handle]=NULL;
}
}
SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)
{
SAMPLE *s = sload->sample;
int handle;
ULONG t, length,loopstart,loopend;
if(type==MD_HARDWARE) return -1;
/* Find empty slot to put sample address in */
for(handle=0;handle<MAXSAMPLEHANDLES;handle++)
if(!Samples[handle]) break;
if(handle==MAXSAMPLEHANDLES) {
_mm_errno = MMERR_OUT_OF_HANDLES;
return -1;
}
/* Reality check for loop settings */
if (s->loopend > s->length)
s->loopend = s->length;
if (s->loopstart >= s->loopend)
s->flags &= ~SF_LOOP;
length = s->length;
loopstart = s->loopstart;
loopend = s->loopend;
SL_SampleSigned(sload);
SL_Sample8to16(sload);
if(!(Samples[handle]=(SWORD*)_mm_malloc((length+20)<<1))) {
_mm_errno = MMERR_SAMPLE_TOO_BIG;
return -1;
}
/* read sample into buffer */
if (SL_Load(Samples[handle],sload,length))
return -1;
/* Unclick sample */
if(s->flags & SF_LOOP) {
if(s->flags & SF_BIDI)
for(t=0;t<16;t++)
Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];
else
for(t=0;t<16;t++)
Samples[handle][loopend+t]=Samples[handle][t+loopstart];
} else
for(t=0;t<16;t++)
Samples[handle][t+length]=0;
return handle;
}
ULONG VC1_SampleSpace(int type)
{
return vc_memory;
}
ULONG VC1_SampleLength(int type,SAMPLE* s)
{
if (!s) return 0;
return (s->length*((s->flags&SF_16BITS)?2:1))+16;
}
ULONG VC1_VoiceRealVolume(UBYTE voice)
{
ULONG i,s,size;
int k,j;
SWORD *smp;
SLONG t;
t = vinf[voice].current>>FRACBITS;
if(!vinf[voice].active) return 0;
s = vinf[voice].handle;
size = vinf[voice].size;
i=64; t-=64; k=0; j=0;
if(i>size) i = size;
if(t<0) t = 0;
if(t+i > size) t = size-i;
i &= ~1; /* make sure it's EVEN. */
smp = &Samples[s][t];
for(;i;i--,smp++) {
if(k<*smp) k = *smp;
if(j>*smp) j = *smp;
}
return abs(k-j);
}
#endif
#endif
/* ex:set ts=4: */

View File

@@ -5,15 +5,16 @@ include $(CLEAR_VARS)
LOCAL_MODULE := sdl_mixer
LOCAL_CFLAGS := -O3 -I$(LOCAL_PATH) -I$(LOCAL_PATH)/../sdl-$(SDL_VERSION)/include -I$(LOCAL_PATH)/include \
-I$(LOCAL_PATH)/../mad/include -I$(LOCAL_PATH)/../flac/include -I$(LOCAL_PATH)/../ogg/include -I$(LOCAL_PATH)/../vorbis/include -I$(LOCAL_PATH)/../tremor/include \
-DWAV_MUSIC -DOGG_USE_TREMOR -DOGG_MUSIC -DFLAC_MUSIC
-I$(LOCAL_PATH)/../mad/include -I$(LOCAL_PATH)/../flac/include -I$(LOCAL_PATH)/../ogg/include \
-I$(LOCAL_PATH)/../vorbis/include -I$(LOCAL_PATH)/../tremor/include -I$(LOCAL_PATH)/../mikmod/include \
-DWAV_MUSIC -DOGG_USE_TREMOR -DOGG_MUSIC -DFLAC_MUSIC -DMOD_MUSIC
LOCAL_CPP_EXTENSION := .cpp
LOCAL_SRC_FILES := $(notdir $(wildcard $(LOCAL_PATH)/*.c))
LOCAL_SHARED_LIBRARIES := sdl-$(SDL_VERSION)
LOCAL_STATIC_LIBRARIES := flac
LOCAL_STATIC_LIBRARIES := flac mikmod
ifeq "$(TARGET_ARCH_ABI)" "armeabi"
LOCAL_CFLAGS += -DOGG_USE_TREMOR