add mikmod source
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 19 Sep 2016 02:58:51 +0000 (05:58 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 19 Sep 2016 02:58:51 +0000 (05:58 +0300)
53 files changed:
libs/mikmod/COPYING.LESSER [new file with mode: 0644]
libs/mikmod/COPYING.LIB [new file with mode: 0644]
libs/mikmod/GNUmakefile [new file with mode: 0644]
libs/mikmod/README [new file with mode: 0644]
libs/mikmod/README.dos [new file with mode: 0644]
libs/mikmod/config.h [new file with mode: 0644]
libs/mikmod/depackers/mmcmp.c [new file with mode: 0644]
libs/mikmod/depackers/pp20.c [new file with mode: 0644]
libs/mikmod/depackers/s404.c [new file with mode: 0644]
libs/mikmod/depackers/xpk.c [new file with mode: 0644]
libs/mikmod/drivers/dos/dosdma.c [new file with mode: 0644]
libs/mikmod/drivers/dos/dosdma.h [new file with mode: 0644]
libs/mikmod/drivers/dos/dosgus.c [new file with mode: 0644]
libs/mikmod/drivers/dos/dosgus.h [new file with mode: 0644]
libs/mikmod/drivers/dos/dosirq.c [new file with mode: 0644]
libs/mikmod/drivers/dos/dosirq.h [new file with mode: 0644]
libs/mikmod/drivers/dos/dossb.c [new file with mode: 0644]
libs/mikmod/drivers/dos/dossb.h [new file with mode: 0644]
libs/mikmod/drivers/dos/doswss.c [new file with mode: 0644]
libs/mikmod/drivers/dos/doswss.h [new file with mode: 0644]
libs/mikmod/drivers/dos/libgus.h [new file with mode: 0644]
libs/mikmod/drivers/drv_oss.c [new file with mode: 0644]
libs/mikmod/drivers/drv_sb.c [new file with mode: 0644]
libs/mikmod/drivers/drv_sdl.c [new file with mode: 0644]
libs/mikmod/drivers/drv_ultra.c [new file with mode: 0644]
libs/mikmod/drivers/drv_wss.c [new file with mode: 0644]
libs/mikmod/include/mikmod.h [new file with mode: 0644]
libs/mikmod/include/mikmod_ctype.h [new file with mode: 0644]
libs/mikmod/include/mikmod_internals.h [new file with mode: 0644]
libs/mikmod/loaders/load_it.c [new file with mode: 0644]
libs/mikmod/loaders/load_mod.c [new file with mode: 0644]
libs/mikmod/loaders/load_s3m.c [new file with mode: 0644]
libs/mikmod/loaders/load_xm.c [new file with mode: 0644]
libs/mikmod/mmio/mmalloc.c [new file with mode: 0644]
libs/mikmod/mmio/mmerror.c [new file with mode: 0644]
libs/mikmod/mmio/mmio.c [new file with mode: 0644]
libs/mikmod/playercode/mdreg.c [new file with mode: 0644]
libs/mikmod/playercode/mdriver.c [new file with mode: 0644]
libs/mikmod/playercode/mdulaw.c [new file with mode: 0644]
libs/mikmod/playercode/mloader.c [new file with mode: 0644]
libs/mikmod/playercode/mlreg.c [new file with mode: 0644]
libs/mikmod/playercode/mlutil.c [new file with mode: 0644]
libs/mikmod/playercode/mplayer.c [new file with mode: 0644]
libs/mikmod/playercode/munitrk.c [new file with mode: 0644]
libs/mikmod/playercode/mwav.c [new file with mode: 0644]
libs/mikmod/playercode/npertab.c [new file with mode: 0644]
libs/mikmod/playercode/sloader.c [new file with mode: 0644]
libs/mikmod/playercode/virtch.c [new file with mode: 0644]
libs/mikmod/playercode/virtch2.c [new file with mode: 0644]
libs/mikmod/playercode/virtch_common.c [new file with mode: 0644]
libs/mikmod/posix/memcmp.c [new file with mode: 0644]
libs/mikmod/posix/strcasecmp.c [new file with mode: 0644]
libs/mikmod/posix/strstr.c [new file with mode: 0644]

diff --git a/libs/mikmod/COPYING.LESSER b/libs/mikmod/COPYING.LESSER
new file mode 100644 (file)
index 0000000..4362b49
--- /dev/null
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+           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.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/libs/mikmod/COPYING.LIB b/libs/mikmod/COPYING.LIB
new file mode 100644 (file)
index 0000000..5bc8fb2
--- /dev/null
@@ -0,0 +1,481 @@
+                  GNU LIBRARY GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the 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.
+\f
+  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.
+\f
+                  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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
+\f
+           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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/libs/mikmod/GNUmakefile b/libs/mikmod/GNUmakefile
new file mode 100644 (file)
index 0000000..54ad1c3
--- /dev/null
@@ -0,0 +1,19 @@
+src = $(wildcard drivers/*.c) \
+         $(wildcard loaders/*.c) \
+         $(wildcard mmio/*.c) \
+         $(wildcard deackers/*.c) \
+         $(wildcard posix/*.c) \
+         $(wildcard playercode/*.c)
+obj = $(src:.c=.o)
+alib = libmikmod.a
+
+def = -DHAVE_CONFIG_H -DMIKMOD_BUILD
+inc = -I. -Iinclude
+CFLAGS = -pedantic -Wall -g $(def) $(inc) `pkg-config --cflags sdl`
+
+$(alib): $(obj)
+       $(AR) rcs $@ $(obj)
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(bin)
diff --git a/libs/mikmod/README b/libs/mikmod/README
new file mode 100644 (file)
index 0000000..4318cfb
--- /dev/null
@@ -0,0 +1,407 @@
+  Hello folks!
+
+
+This is libmikmod, version 3.3.10, a portable sound library for Unix
+and other systems. Check out the file 'NEWS' for more history information.
+
+
+>> BUILDING LIBMIKMOD
+---------------------
+
+- If you're building libmikmod for Windows, refer to the 'README' file
+  located in the 'win32' subdirectory.
+
+- If you're building libmikmod for Mac OS X, refer to the 'README' file
+  located in the 'macosx' subdirectory.
+
+- If you're building libmikmod for Android, refer to the 'README' file
+  located in the 'android' subdirectory.
+
+- If you're building libmikmod for DOS, refer to the 'README' file
+  located in the 'dos' subdirectory.
+
+- If you're building libmikmod for OS/2, refer to the 'README' file
+  located in the 'os2' subdirectory.
+
+- If you're building libmikmod for AmigaOS, or its variants like MorphOS
+  or AROS, refer to the 'README' located in the 'amiga' subdirectory.
+
+- If you're building libmikmod for MacOS, refer to the 'README' file
+  located in the 'macintosh' subdirectory.
+
+- If you're building libmikmod for dreamcast, gp32 or psp platforms,
+  refer to the corresponding 'README' files located under the 'dc',
+  'gp32' or 'psp' subdirectory.
+
+- If you're building libmikmod under any other system which is not a
+  Unix flavour, then be warned that your platform is probably not
+  supported and that libmikmod will probably not build out of the box.
+  Drop us a note and we'll see what we 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 try the GNU 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.
+
+- 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", "wav" and "aiff")
+  file=     Output file name. Default is music.raw for the raw driver
+            and music.wav for the wav driver.
+
+- OpenBSD sndio ("sndio") [OpenBSD only]
+  buffer=   logarithmic fragment size, in the range 7-17. Default is 12.
+
+- Sun/Solaris/NetBSD/OpenBSD audio ("audio")
+  [SunOS, Solaris, NetBSD, OpenBSD only]
+  buffer=   logarithmic fragment size, in the range 7-17. Default is 12.
+  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"), Windows XAudio2 ("xaudio2"),
+  Amiga AHI ("ahi"), Linux ALSA ("alsa")
+  These drivers 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. You can find
+more information on ALSA, including a HOWTO, on the web:
+  http://www.alsa-project.org
+
+This version of libmikmod ALSA driver works with ALSA versions 1.0.x.
+ALSA versions 0.9.x and earlier are not supported any more.
+
+
+>> ENLIGHTENED SOUND DAEMON SPECIFIC INFORMATION (Unix specific)
+------------------------------------------------
+
+The Enlightened Sound Daemon (EsounD) development has long been stopped,
+but libmikmod still supports it.  libmikmod should work with any esound
+version starting from 0.2.18, although the latest 0.2.41 is recommended:
+  http://ftp.gnome.org/pub/gnome/sources/esound/0.2/
+
+You can find more information on EsounD on the web:
+  http://www.tux.org/~ricdude/EsounD.html
+
+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 Miodrag Vallat.
+
+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
+----------------------------
+
+libmikmod home page is located at SourceForge:
+
+    http://mikmod.sourceforge.net/
+    http://sourceforge.net/projects/mikmod/
+
+There's a mailing list (mikmod-public) for discussing the development
+of MikMod (new features, bugs, ideas...) Look for more information on
+the web site.
+
diff --git a/libs/mikmod/README.dos b/libs/mikmod/README.dos
new file mode 100644 (file)
index 0000000..b6d104a
--- /dev/null
@@ -0,0 +1,110 @@
+  Hello folks !\r
+\r
+\r
+This is libmikmod, version 3.3.10, a portable sound library for DOS.\r
+Comments & feedback are welcome.\r
+\r
+\r
+>> BUILDING LIBMIKMOD\r
+---------------------\r
+\r
+- If you're not building libmikmod for DOS, then you're lost in the sources.\r
+  Go up one directory, and read the main README file.\r
+\r
+This port has been designed to work only with DJGPP compiler. However, it\r
+should not be too complex to make it compile with any other compiler. If you\r
+manage to make libmikmod compile and work with another compiler, we'd like to\r
+hear from you. You'll likely have to write an appropiate makefile, or build\r
+things manually ...\r
+\r
+If you have all proper tools installed, just type\r
+\r
+       make -f Makefile.dj\r
+\r
+To make your library ready to use, copy the files 'libmikmod.a' and\r
+'include/mikmod.h' to your '%DJGPP%/lib' and '%DJGPP%/include' directories\r
+respectively.\r
+\r
+HTML documentation of the library, for programmers, is located in the doc\r
+directory.\r
+\r
+\r
+>> SUPPORTED SOUNDCARDS\r
+-----------------------\r
+\r
+Currently three brands of sound cards are supported under DOS:\r
+\r
+- Gravis Ultrasound and compatibles. Not tested with Interwave cards. If\r
+  somebody has one and can debug the code under Interwave, please drop us a note\r
+  (see email at bottom).\r
+\r
+- SoundBlaster and compatibles. There is only one driver that supports all\r
+  flavours of SoundBlasters:\r
+\r
+       + SB original (8-bit mono, 22KHz)\r
+       + SB 2.0 (DMA autoinit mode -> less clicks, 44KHz 8-bit mono).\r
+       + SB Pro (8-bit 22KHz stereo, 8-bit 44KHz mono)\r
+       + SB 16+ (8- and 16-bit stereo, up to 44Khz both)\r
+\r
+  Note that SB16 should cover AWE32/64 as well...\r
+\r
+- Windows Sound System and compatibles. Most today SoundBlaster clones\r
+  (including the CS4236B card used for testing) emulates (in hardware) WSS.\r
+  That's because Creative Labs copyrighted the SB16 interface and thus\r
+  clonemakers cannot do similar hardware without violating their rights, so\r
+  most of them only emulate SB Pro (see above).\r
+\r
+  WSS supports up to 44KHz 16-bit stereo. The following playback rates (in both\r
+  8- and 16-bit) are supported: 5510, 6620, 8000, 9600, 11025, 16000, 18900,\r
+  22050, 27420, 32000, 33075, 37800, 44100 and 48000 Hz.\r
+\r
+\r
+>> THANKS\r
+---------\r
+\r
+We would like to thank everyone who contributed to libmikmod. Their names\r
+are in the AUTHORS file for the significative contributions, but some other\r
+names can be found in the NEWS file. Thanks a lot ! Keeping libmikmod alive\r
+wouldn't be much fun without you.\r
+\r
+\r
+>> LICENSE\r
+----------\r
+\r
+The libmikmod sound library is covered by the GNU Library General Public\r
+License as published by the Free Software Fundation (you'll find it in the\r
+file COPYING.LIB) ; either version 2 of the licence, or (at your option)\r
+any later version.\r
+\r
+The GNU Lesser General Public License, version 2.1, in file COPYING.LESSER, can\r
+be considered as a later version of the LGPL, and is strongly recommended for\r
+people who will embed libmikmod in their application as a shared library.\r
+\r
+\r
+>> CONTACT AND DOWNLOAD INFO\r
+----------------------------\r
+\r
+libmikmod home page is located at SourceForge:\r
+\r
+    http://mikmod.sourceforge.net/\r
+    http://sourceforge.net/projects/mikmod/\r
+\r
+There's a mailing list (mikmod-public) for discussing the development\r
+of MikMod (new features, bugs, ideas...) Look for more information on\r
+the web site.\r
+\r
+Things related to the DOS port should also be forwarded to the DOS\r
+``portmaster'', Andrew Zabolotny, at: bit@eltech.ru\r
+\r
+\r
+>> LAST NOTES\r
+-------------\r
+\r
+We hope you'll enjoy using this version of libmikmod as well as we enjoyed\r
+debugging and improving it.\r
+\r
+-- Miodrag ("Miod") Vallat, 10/19/1999\r
+   miodrag@mikmod.darkorb.net\r
+\r
+   Andrew Zabolotny\r
+   bit@eltech.ru\r
diff --git a/libs/mikmod/config.h b/libs/mikmod/config.h
new file mode 100644 (file)
index 0000000..92683f5
--- /dev/null
@@ -0,0 +1,85 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+#define HAVE_LIMITS_H 1
+#define HAVE_MEMCMP 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRSTR 1
+
+#ifdef DOS
+#define DRV_SB 1
+#define DRV_ULTRA 1
+#define DRV_WSS 1
+
+#define HAVE_UNISTD_H 1
+#define HAVE_FCNTL_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_IOCTL_H 1
+#endif
+
+#if defined(__unix__) || defined(__APPLE__)
+#define DRV_SDL 1
+
+#define HAVE_FCNTL_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SNPRINTF 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_POSIX_MEMALIGN 1
+#define HAVE_PTHREAD 1
+#define HAVE_SETENV 1
+#define HAVE_SRANDOM 1
+
+#define MIKMOD_UNIX 1
+#endif
+
+
+#if defined(WIN32)
+#define HAVE_WINDOWS_H 1
+#define HAVE_MALLOC_H 1
+#endif
+
+#undef MIKMOD_DEBUG
+
+/* disable the high quality mixer (build only with the standart mixer) */
+#undef NO_HQMIXER
+
+/* Name of package */
+#undef PACKAGE
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
diff --git a/libs/mikmod/depackers/mmcmp.c b/libs/mikmod/depackers/mmcmp.c
new file mode 100644 (file)
index 0000000..2a83540
--- /dev/null
@@ -0,0 +1,433 @@
+/* MikMod sound library (c) 2003-2015 Raphael Assenat and others -
+ * see AUTHORS file for a 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.
+ */
+
+/* MMCMP ("ziRCONia") decompression support
+ *
+ * Based on the public domain version from the libmodplug library by
+ * Olivier Lapicque <olivierl@jps.net> (sezero's fork of libmodplug
+ * at github: http://github.com/sezero/libmodplug/tree/sezero )
+ *
+ * Rewritten for libmikmod by O. Sezer <sezero@users.sourceforge.net>
+ * with some extra ideas from the libxmp version by Claudio Matsuoka.
+ */
+
+#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
+
+/*#define MMCMP_DEBUG*/
+
+typedef struct MMCMPFILEHDR
+{
+       UBYTE id[8]; /* string 'ziRCONia' */
+       UWORD hdrsize; /* sizeof MMCMPHEADER */
+} MMCMPFILEHDR; /* 10 bytes */
+
+typedef struct MMCMPHEADER
+{
+       UWORD version;
+       UWORD nblocks;
+       ULONG filesize;
+       ULONG blktable;
+       UBYTE glb_comp;
+       UBYTE fmt_comp;
+} MMCMPHEADER; /* 14 bytes */
+
+typedef struct MMCMPBLOCK
+{
+       ULONG unpk_size;
+       ULONG pk_size;
+       ULONG xor_chk;
+       UWORD sub_blk;
+       UWORD flags;
+       UWORD tt_entries;
+       UWORD num_bits;
+} MMCMPBLOCK; /* 20 bytes */
+
+typedef struct MMCMPSUBBLOCK
+{
+       ULONG unpk_pos;
+       ULONG unpk_size;
+} MMCMPSUBBLOCK; /* 8 bytes */
+
+#define MMCMP_COMP     0x0001
+#define MMCMP_DELTA    0x0002
+#define MMCMP_16BIT    0x0004
+#define MMCMP_STEREO   0x0100
+#define MMCMP_ABS16    0x0200
+#define MMCMP_ENDIAN   0x0400
+
+
+typedef struct MMCMPBITBUFFER
+{
+       ULONG bitcount;
+       ULONG bitbuffer;
+       const UBYTE *start;
+       const UBYTE *end;
+} MMCMPBITBUFFER;
+
+static ULONG MMCMP_GetBits(MMCMPBITBUFFER* b, ULONG nBits)
+{
+       ULONG d;
+       if (!nBits) return 0;
+       while (b->bitcount < 24)
+       {
+               b->bitbuffer |= ((b->start < b->end) ? *b->start++ : 0) << b->bitcount;
+               b->bitcount += 8;
+       }
+       d = b->bitbuffer & ((1 << nBits) - 1);
+       b->bitbuffer >>= nBits;
+       b->bitcount -= nBits;
+       return d;
+}
+
+static const ULONG MMCMP8BitCommands[8] =
+{
+       0x01, 0x03,     0x07, 0x0F,     0x1E, 0x3C,     0x78, 0xF8
+};
+
+static const ULONG MMCMP8BitFetch[8] =
+{
+       3, 3, 3, 3, 2, 1, 0, 0
+};
+
+static const ULONG MMCMP16BitCommands[16] =
+{
+       0x01, 0x03,     0x07, 0x0F,     0x1E, 0x3C,     0x78, 0xF0,
+       0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
+};
+
+static const ULONG MMCMP16BitFetch[16] =
+{
+       4, 4, 4, 4, 3, 2, 1, 0,
+       0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+BOOL MMCMP_Unpack(MREADER* reader, void** out, long* outlen)
+{
+       ULONG srclen, destlen;
+       UBYTE *destbuf, *destptr;
+       MMCMPHEADER mmh;
+       ULONG *pblk_table;
+       MMCMPSUBBLOCK *subblocks;
+       ULONG i, blockidx, numsubs;
+       UBYTE *buf;  ULONG bufsize;
+
+       _mm_fseek(reader,0,SEEK_END);
+       srclen = _mm_ftell(reader);
+       if (srclen < 256) return 0;
+
+       _mm_rewind(reader);
+       if (_mm_read_I_ULONG(reader) != 0x4352697A)     /* 'ziRC' */
+               return 0;
+       if (_mm_read_I_ULONG(reader) != 0x61694e4f)     /* 'ONia' */
+               return 0;
+       if (_mm_read_I_UWORD(reader) != 14)             /* header size */
+               return 0;
+
+       mmh.version = _mm_read_I_UWORD(reader);
+       mmh.nblocks = _mm_read_I_UWORD(reader);
+       mmh.filesize = _mm_read_I_ULONG(reader);
+       mmh.blktable = _mm_read_I_ULONG(reader);
+       mmh.glb_comp = _mm_read_UBYTE(reader);
+       mmh.fmt_comp = _mm_read_UBYTE(reader);
+
+       if ((!mmh.nblocks) || (mmh.filesize < 16) || (mmh.filesize > 0x8000000) ||
+           (mmh.blktable >= srclen) || (mmh.blktable + 4*mmh.nblocks > srclen)) {
+               return 0;
+       }
+       destlen = mmh.filesize;
+       numsubs = 32;
+       bufsize = 65536;
+
+       destbuf = (UBYTE*)MikMod_malloc(destlen);
+       buf = (UBYTE*)MikMod_malloc(bufsize);
+       pblk_table = (ULONG*)MikMod_malloc(mmh.nblocks*4);
+       subblocks = (MMCMPSUBBLOCK*)MikMod_malloc(numsubs*sizeof(MMCMPSUBBLOCK));
+       if (!destbuf || !buf || !pblk_table || !subblocks)
+               goto err;
+
+       _mm_fseek(reader,mmh.blktable,SEEK_SET);
+       for (blockidx = 0; blockidx < mmh.nblocks; blockidx++) {
+               pblk_table[blockidx] = _mm_read_I_ULONG(reader);
+       }
+
+       for (blockidx = 0; blockidx < mmh.nblocks; blockidx++)
+       {
+               ULONG srcpos = pblk_table[blockidx];
+               MMCMPBLOCK block;
+
+               if (srcpos + 20 >= srclen) goto err;
+
+               _mm_fseek(reader,srcpos,SEEK_SET);
+               block.unpk_size = _mm_read_I_ULONG(reader);
+               block.pk_size = _mm_read_I_ULONG(reader);
+               block.xor_chk = _mm_read_I_ULONG(reader);
+               block.sub_blk = _mm_read_I_UWORD(reader);
+               block.flags = _mm_read_I_UWORD(reader);
+               block.tt_entries = _mm_read_I_UWORD(reader);
+               block.num_bits = _mm_read_I_UWORD(reader);
+
+               if (!block.unpk_size || !block.pk_size || !block.sub_blk)
+                       goto err;
+               if (block.pk_size <= block.tt_entries)
+                       goto err;
+               if (block.flags & MMCMP_COMP) {
+                       if (block.flags & MMCMP_16BIT) {
+                               if (block.num_bits >= 16)
+                                       goto err;
+                       }
+                       else {
+                               if (block.num_bits >=  8)
+                                       goto err;
+                       }
+               }
+
+               srcpos += 20 + block.sub_blk*8;
+               if (srcpos >= srclen) goto err;
+
+               if (numsubs < block.sub_blk) {
+                       numsubs = (block.sub_blk + 31) & ~31;
+                       MikMod_free(subblocks);
+                       subblocks = (MMCMPSUBBLOCK*)MikMod_malloc(numsubs*sizeof(MMCMPSUBBLOCK));
+                       if (!subblocks) goto err;
+               }
+               for (i = 0; i < block.sub_blk; i++) {
+                       subblocks[i].unpk_pos = _mm_read_I_ULONG(reader);
+                       subblocks[i].unpk_size = _mm_read_I_ULONG(reader);
+                       if (subblocks[i].unpk_pos >= destlen) goto err;
+                       if (subblocks[i].unpk_size > destlen) goto err;
+                       if (subblocks[i].unpk_size > destlen - subblocks[i].unpk_pos) goto err;
+               }
+
+#ifdef MMCMP_DEBUG
+               fprintf(stderr, "block %u: flags=%04X sub_blocks=%u",
+                                 blockidx, (unsigned)block.flags, (unsigned)block.sub_blk);
+               fprintf(stderr, " pksize=%u unpksize=%u", block.pk_size, block.unpk_size);
+               fprintf(stderr, " tt_entries=%u num_bits=%u\n", block.tt_entries, block.num_bits);
+#endif
+               if (!(block.flags & MMCMP_COMP))
+               { /* Data is not packed */
+                       _mm_fseek(reader,srcpos,SEEK_SET);
+                       destptr = destbuf + subblocks[0].unpk_pos;
+                       i = 0;
+
+                       while (1) {
+#ifdef MMCMP_DEBUG
+                               fprintf(stderr, "  Unpacked sub-block %u: offset %u, size=%u\n",
+                                               i, subblocks[i].unpk_pos, subblocks[i].unpk_size);
+#endif
+                               _mm_read_UBYTES(destptr,subblocks[i].unpk_size,reader);
+                               destptr += subblocks[i].unpk_size;
+                               if (++i == block.sub_blk) break;
+                       }
+               }
+               else if (block.flags & MMCMP_16BIT)
+               { /* Data is 16-bit packed */
+                       MMCMPBITBUFFER bb;
+                       ULONG size;
+                       ULONG pos = 0;
+                       ULONG numbits = block.num_bits;
+                       ULONG oldval = 0;
+
+#ifdef MMCMP_DEBUG
+                       fprintf(stderr, "  16-bit block: pos=%u size=%u ",
+                                       subblocks[0].unpk_pos, subblocks[0].unpk_size);
+                       if (block.flags & MMCMP_DELTA) fprintf(stderr, "DELTA ");
+                       if (block.flags & MMCMP_ABS16) fprintf(stderr, "ABS16 ");
+                       fprintf(stderr, "\n");
+#endif
+                       size = block.pk_size - block.tt_entries;
+                       if (bufsize < size) {
+                               while (bufsize < size) bufsize += 65536;
+                               MikMod_free(buf);
+                               if (!(buf = (UBYTE*)MikMod_malloc(bufsize)))
+                                       goto err;
+                       }
+
+                       bb.bitcount = 0;
+                       bb.bitbuffer = 0;
+                       bb.start = buf;
+                       bb.end = buf + size;
+
+                       _mm_fseek(reader,srcpos+block.tt_entries,SEEK_SET);
+                       _mm_read_UBYTES(buf,size,reader);
+                       destptr = destbuf + subblocks[0].unpk_pos;
+                       size = subblocks[0].unpk_size;
+                       i = 0;
+
+                       while (1)
+                       {
+                               ULONG newval = 0x10000;
+                               ULONG d = MMCMP_GetBits(&bb, numbits+1);
+
+                               if (d >= MMCMP16BitCommands[numbits])
+                               {
+                                       ULONG nFetch = MMCMP16BitFetch[numbits];
+                                       ULONG newbits = MMCMP_GetBits(&bb, nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch);
+                                       if (newbits != numbits)
+                                       {
+                                               numbits = newbits & 0x0F;
+                                       } else
+                                       {
+                                               if ((d = MMCMP_GetBits(&bb, 4)) == 0x0F)
+                                               {
+                                                       if (MMCMP_GetBits(&bb, 1)) break;
+                                                       newval = 0xFFFF;
+                                               } else
+                                               {
+                                                       newval = 0xFFF0 + d;
+                                               }
+                                       }
+                               } else
+                               {
+                                       newval = d;
+                               }
+                               if (newval < 0x10000)
+                               {
+                                       newval = (newval & 1) ? (ULONG)(-(SLONG)((newval+1) >> 1)) : (ULONG)(newval >> 1);
+                                       if (block.flags & MMCMP_DELTA)
+                                       {
+                                               newval += oldval;
+                                               oldval = newval;
+                                       } else
+                                       if (!(block.flags & MMCMP_ABS16))
+                                       {
+                                               newval ^= 0x8000;
+                                       }
+                                       destptr[pos++] = (UBYTE) (((UWORD)newval) & 0xff);
+                                       destptr[pos++] = (UBYTE) (((UWORD)newval) >> 8);
+                               }
+                               if (pos >= size)
+                               {
+                                       if (++i == block.sub_blk) break;
+                                       size = subblocks[i].unpk_size;
+                                       destptr = destbuf + subblocks[i].unpk_pos;
+                                       pos = 0;
+                               }
+                       }
+               }
+               else
+               { /* Data is 8-bit packed */
+                       MMCMPBITBUFFER bb;
+                       ULONG size;
+                       ULONG pos = 0;
+                       ULONG numbits = block.num_bits;
+                       ULONG oldval = 0;
+                       UBYTE ptable[0x100];
+
+                       size = block.pk_size - block.tt_entries;
+                       if (bufsize < size) {
+                               while (bufsize < size) bufsize += 65536;
+                               MikMod_free(buf);
+                               if (!(buf = (UBYTE*)MikMod_malloc(bufsize)))
+                                       goto err;
+                       }
+
+                       bb.bitcount = 0;
+                       bb.bitbuffer = 0;
+                       bb.start = buf;
+                       bb.end = buf + size;
+
+                       _mm_read_UBYTES(ptable,0x100,reader);
+                       _mm_fseek(reader,srcpos+block.tt_entries,SEEK_SET);
+                       _mm_read_UBYTES(buf,size,reader);
+                       destptr = destbuf + subblocks[0].unpk_pos;
+                       size = subblocks[0].unpk_size;
+                       i = 0;
+
+                       while (1)
+                       {
+                               ULONG newval = 0x100;
+                               ULONG d = MMCMP_GetBits(&bb, numbits+1);
+
+                               if (d >= MMCMP8BitCommands[numbits])
+                               {
+                                       ULONG nFetch = MMCMP8BitFetch[numbits];
+                                       ULONG newbits = MMCMP_GetBits(&bb, nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch);
+                                       if (newbits != numbits)
+                                       {
+                                               numbits = newbits & 0x07;
+                                       } else
+                                       {
+                                               if ((d = MMCMP_GetBits(&bb, 3)) == 7)
+                                               {
+                                                       if (MMCMP_GetBits(&bb, 1)) break;
+                                                       newval = 0xFF;
+                                               } else
+                                               {
+                                                       newval = 0xF8 + d;
+                                               }
+                                       }
+                               } else
+                               {
+                                       newval = d;
+                               }
+                               if (newval < 0x100)
+                               {
+                                       int n = ptable[newval];
+                                       if (block.flags & MMCMP_DELTA)
+                                       {
+                                               n += oldval;
+                                               oldval = n;
+                                       }
+                                       destptr[pos++] = (UBYTE)n;
+                               }
+                               if (pos >= size)
+                               {
+                                       if (++i == block.sub_blk) break;
+                                       size = subblocks[i].unpk_size;
+                                       destptr = destbuf + subblocks[i].unpk_pos;
+                                       pos = 0;
+                               }
+                       }
+               }
+       }
+
+       MikMod_free(buf);
+       MikMod_free(pblk_table);
+       MikMod_free(subblocks);
+       *out = destbuf;
+       *outlen = destlen;
+       return 1;
+
+  err:
+       MikMod_free(buf);
+       MikMod_free(pblk_table);
+       MikMod_free(subblocks);
+       MikMod_free(destbuf);
+       return 0;
+}
diff --git a/libs/mikmod/depackers/pp20.c b/libs/mikmod/depackers/pp20.c
new file mode 100644 (file)
index 0000000..e5bd323
--- /dev/null
@@ -0,0 +1,208 @@
+/* MikMod sound library (c) 2003-2015 Raphael Assenat and others -
+ * see AUTHORS file for a 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.
+ */
+
+/* amiga Powerpack PP20 decompression support
+ *
+ * Code from Heikki Orsila's amigadepack 0.02
+ * based on code by Stuart Caie <kyzer@4u.net>
+ * This software is in the Public Domain
+ *
+ * Modified for xmp by Claudio Matsuoka, 08/2007
+ * - merged mld's checks from the old depack sources. Original credits:
+ *   - corrupt file and data detection
+ *     (thanks to Don Adan and Dirk Stoecker for help and infos)
+ *   - implemeted "efficiency" checks
+ *   - further detection based on code by Georg Hoermann
+ *
+ * Modified for xmp by Claudio Matsuoka, 05/2013
+ * - decryption code removed
+ *
+ * Modified for libmikmod by O. Sezer, Apr. 2015, with a few extra bits
+ * from the libmodplug library by Olivier Lapicque.
+ */
+
+#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
+
+#define PP_READ_BITS(nbits, var) do {                          \
+  bit_cnt = (nbits);                                           \
+  while (bits_left < bit_cnt) {                                \
+    if (buf_src < src) return 0; /* out of source bits */      \
+    bit_buffer |= (*--buf_src << bits_left);                   \
+    bits_left += 8;                                            \
+  }                                                            \
+  (var) = 0;                                                   \
+  bits_left -= bit_cnt;                                        \
+  while (bit_cnt--) {                                          \
+    (var) = ((var) << 1) | (bit_buffer & 1);                   \
+    bit_buffer >>= 1;                                          \
+  }                                                            \
+} while(0)
+
+#define PP_BYTE_OUT(byte) do {                                 \
+  if (out <= dest) return 0; /* output overflow */             \
+  *--out = (byte);                                             \
+  written++;                                                   \
+} while (0)
+
+static BOOL ppDecrunch(const UBYTE *src, UBYTE *dest,
+                       const UBYTE *offset_lens,
+                       ULONG src_len, ULONG dest_len,
+                       UBYTE skip_bits)
+{
+  ULONG bit_buffer, x, todo, offbits, offset, written;
+  const UBYTE *buf_src;
+  UBYTE *out, *dest_end, bits_left, bit_cnt;
+
+  /* set up input and output pointers */
+  buf_src = src + src_len;
+  out = dest_end = dest + dest_len;
+
+  written = 0;
+  bit_buffer = 0;
+  bits_left = 0;
+
+  /* skip the first few bits */
+  PP_READ_BITS(skip_bits, x);
+
+  /* while there are input bits left */
+  while (written < dest_len) {
+    PP_READ_BITS(1, x);
+    if (x == 0) {
+      /* 1bit==0: literal, then match. 1bit==1: just match */
+      todo = 1; do { PP_READ_BITS(2, x); todo += x; } while (x == 3);
+      while (todo--) { PP_READ_BITS(8, x); PP_BYTE_OUT(x); }
+
+      /* should we end decoding on a literal, break out of the main loop */
+      if (written == dest_len) break;
+    }
+
+    /* match: read 2 bits for initial offset bitlength / match length */
+    PP_READ_BITS(2, x);
+    offbits = offset_lens[x];
+    todo = x+2;
+    if (x == 3) {
+      PP_READ_BITS(1, x);
+      if (x==0) offbits = 7;
+      PP_READ_BITS(offbits, offset);
+      do { PP_READ_BITS(3, x); todo += x; } while (x == 7);
+    }
+    else {
+      PP_READ_BITS(offbits, offset);
+    }
+    if ((out + offset) >= dest_end) return 0; /* match overflow */
+    while (todo--) { x = out[offset]; PP_BYTE_OUT(x); }
+  }
+
+  /* all output bytes written without error */
+  return 1;
+  /* return (src == buf_src) ? 1 : 0; */
+}
+
+BOOL PP20_Unpack(MREADER* reader, void** out, long* outlen)
+{
+       ULONG srclen, destlen;
+       UBYTE *destbuf, *srcbuf;
+       UBYTE tmp[4], skip;
+       BOOL ret;
+
+       /* PP FORMAT:
+        *  1 longword identifier       'PP20' or 'PX20'
+        * [1 word checksum (if 'PX20') $ssss]
+        *  1 longword efficiency       $eeeeeeee
+        *  X longwords crunched file   $cccccccc,$cccccccc,...
+        *  1 longword decrunch info    'decrlen' << 8 | '8 bits other info'
+        */
+
+       _mm_fseek(reader,0,SEEK_END);
+       srclen = _mm_ftell(reader);
+       if (srclen < 256) return 0;
+       /* file length should be a multiple of 4 */
+       if (srclen & 3) return 0;
+
+       _mm_rewind(reader);
+       if (_mm_read_I_ULONG(reader) != 0x30325050)     /* 'PP20' */
+               return 0;
+
+       _mm_fseek(reader,srclen-4,SEEK_SET);
+       _mm_read_UBYTES(tmp,4,reader);
+       destlen = tmp[0] << 16;
+       destlen |= tmp[1] << 8;
+       destlen |= tmp[2];
+       skip = tmp[3];
+
+       _mm_fseek(reader,4,SEEK_SET);
+       _mm_read_UBYTES(tmp,4,reader);
+
+       /* original pp20 only support efficiency
+        * from 9 9 9 9 up to 9 10 12 13, afaik,
+        * but the xfd detection code says this...
+        *
+        * move.l 4(a0),d0
+        * cmp.b #9,d0
+        * blo.b .Exit
+        * and.l #$f0f0f0f0,d0
+        * bne.s .Exit
+        */
+       if ((tmp[0] < 9) || (tmp[0] & 0xf0)) return 0;
+       if ((tmp[1] < 9) || (tmp[1] & 0xf0)) return 0;
+       if ((tmp[2] < 9) || (tmp[2] & 0xf0)) return 0;
+       if ((tmp[3] < 9) || (tmp[3] & 0xf0)) return 0;
+
+       if ((destlen < 512) || (destlen > 0x400000) || (destlen > 16*srclen))
+               return 0;
+       if ((destbuf = (UBYTE*)MikMod_malloc(destlen)) == NULL)
+               return 0;
+
+       srclen -= 12;
+       if ((srcbuf = (UBYTE*)MikMod_malloc(srclen)) == NULL) {
+               MikMod_free(destbuf);
+               return 0;
+       }
+       _mm_read_UBYTES(srcbuf,srclen,reader);
+
+       ret = ppDecrunch(srcbuf, destbuf, tmp, srclen, destlen, skip);
+       MikMod_free(srcbuf);
+
+       if (!ret) {
+               MikMod_free(destbuf);
+       }
+       else {
+               *out = destbuf;
+               *outlen = destlen;
+       }
+       return ret;
+}
diff --git a/libs/mikmod/depackers/s404.c b/libs/mikmod/depackers/s404.c
new file mode 100644 (file)
index 0000000..7ca41cd
--- /dev/null
@@ -0,0 +1,393 @@
+/* MikMod sound library (c) 2003-2015 Raphael Assenat and others -
+ * see AUTHORS file for a 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.
+ */
+
+/*
+ * StoneCracker S404 algorithm data decompression routine
+ * (c) 2006 Jouni 'Mr.Spiv' Korhonen. The code is in public domain.
+ *
+ * modified for xmp by Claudio Matsuoka, Jan 2010
+ * modified for libmikmod by O. Sezer -- May 2015
+ */
+
+#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 <assert.h>*/
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+
+/*#define STC_DEBUG*/
+
+static UWORD readmem16b(UBYTE *m)
+{
+  ULONG a, b;
+  a = m[0];
+  b = m[1];
+  return (a << 8) | b;
+}
+
+struct bitstream {
+  /* bit buffer for rolling data bit by bit from the compressed file */
+  ULONG word;
+
+  /* bits left in the bit buffer */
+  int left;
+
+  /* compressed data source */
+  UWORD *src;
+  UBYTE *orgsrc;
+};
+
+static int initGetb(struct bitstream *bs, UBYTE *src, ULONG src_length)
+{
+  int eff;
+
+  bs->src = (UWORD *) (src + src_length);
+  bs->orgsrc = src;
+
+  bs->left = readmem16b((UBYTE *)bs->src); /* bit counter */
+#ifdef STC_DEBUG
+  if (bs->left & (~0xf))
+    fprintf(stderr, "Worked around an ancient stc bug\n");
+#endif
+  /* mask off any corrupt bits */
+  bs->left &= 0x000f;
+  bs->src--;
+
+  /* get the first 16-bits of the compressed stream */
+  bs->word = readmem16b((UBYTE *)bs->src);
+  bs->src--;
+
+  eff = readmem16b((UBYTE *)bs->src); /* efficiency */
+  bs->src--;
+
+  return eff;
+}
+
+/* get nbits from the compressed stream */
+static int getb(struct bitstream *bs, int nbits)
+{
+  bs->word &= 0x0000ffff;
+
+  /* If not enough bits in the bit buffer, get more */
+  if (bs->left < nbits) {
+    bs->word <<= bs->left;
+    /*assert((bs->word & 0x0000ffffU) == 0);*/
+
+    /* Check that we don't go out of bounds */
+    if (bs->orgsrc > (UBYTE *)bs->src) {
+       return -1;
+    }
+
+    bs->word |= readmem16b((UBYTE *)bs->src);
+    bs->src--;
+
+    nbits -= bs->left;
+    bs->left = 16; /* 16 unused (and some used) bits left in the word */
+  }
+
+  /* Shift nbits off the word and return them */
+  bs->left -= nbits;
+  bs->word <<= nbits;
+  return bs->word >> 16;
+}
+
+static int decompressS404(UBYTE *src, UBYTE *orgdst,
+                         SLONG dst_length, SLONG src_length)
+{
+  UWORD w;
+  SLONG eff;
+  SLONG n;
+  UBYTE *dst;
+  SLONG oLen = dst_length;
+  struct bitstream bs;
+  int x;
+
+  dst = orgdst + oLen;
+
+  eff = initGetb(&bs, src, src_length);
+
+  while (oLen > 0) {
+    x = getb(&bs, 9);
+    /* Sanity check */
+    if (x < 0) {
+      return -1;
+    }
+
+    w = x;
+
+    if (w < 0x100) {
+      if (orgdst >= dst) {
+        return -1;
+      }
+      *--dst = w;
+      oLen--;
+    } else if (w == 0x13e || w == 0x13f) {
+      w <<= 4;
+      x = getb(&bs, 4);
+      /* Sanity check */
+      if (x < 0) {
+        return -1;
+      }
+      w |= x;
+
+      n = (w & 0x1f) + 14;
+      oLen -= n;
+      while (n-- > 0) {
+        x = getb(&bs, 8);
+        /* Sanity check */
+        if (x < 0) {
+          return -1;
+        }
+        w = x;
+
+        if (orgdst >= dst) {
+          return -1;
+        }
+
+        *--dst = w;
+      }
+    } else {
+      if (w >= 0x180) {
+        /* copy 2-3 */
+        n = w & 0x40 ? 3 : 2;
+
+        if (w & 0x20) {
+          /* dist 545 -> */
+          w = (w & 0x1f) << (eff - 5);
+          x = getb(&bs, eff - 5);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+          w += 544;
+        } else if (w & 0x30) {
+          /* dist 1 -> 32 */
+          w = (w & 0x0f) << 1;
+          x = getb(&bs, 1);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+        } else {
+          /* dist 33 -> 544 */
+          w = (w & 0x0f) << 5;
+          x = getb(&bs, 5);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+          w += 32;
+        }
+      } else if (w >= 0x140) {
+        /* copy 4-7 */
+        n = ((w & 0x30) >> 4) + 4;
+
+        if (w & 0x08) {
+          /* dist 545 -> */
+          w = (w & 0x07) << (eff - 3);
+          x = getb(&bs, eff - 3);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+          w += 544;
+        } else if (w & 0x0c) {
+          /* dist 1 -> 32 */
+          w = (w & 0x03) << 3;
+          x = getb(&bs, 3);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+        } else {
+          /* dist 33 -> 544 */
+          w = (w & 0x03) << 7;
+          x = getb(&bs, 7);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+          w += 32;
+        }
+      } else if (w >= 0x120) {
+        /* copy 8-22 */
+        n = ((w & 0x1e) >> 1) + 8;
+
+        if (w & 0x01) {
+          /* dist 545 -> */
+          x = getb(&bs, eff);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w = x;
+          w += 544;
+        } else {
+          x = getb(&bs, 6);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w = x;
+
+          if (w & 0x20) {
+            /* dist 1 -> 32 */
+            w &= 0x1f;
+          } else {
+            /* dist 33 -> 544 */
+            w <<= 4;
+            x = getb(&bs, 4);
+            /* Sanity check */
+            if (x < 0) {
+              return -1;
+            }
+            w |= x;
+            w += 32;
+          }
+        }
+      } else {
+        w = (w & 0x1f) << 3;
+        x = getb(&bs, 3);
+        /* Sanity check */
+        if (x < 0) {
+          return -1;
+        }
+        w |= x;
+        n = 23;
+
+        while (w == 0xff) {
+          n += w;
+          x = getb(&bs, 8);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w = x;
+        }
+        n += w;
+
+        x = getb(&bs, 7);
+        w = x;
+
+        if (w & 0x40) {
+          /* dist 545 -> */
+          w = (w & 0x3f) << (eff - 6);
+          x = getb(&bs, eff - 6);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+          w += 544;
+        } else if (w & 0x20) {
+          /* dist 1 -> 32 */
+          w &= 0x1f;
+        } else {
+          /* dist 33 -> 544; */
+          w <<= 4;
+          x = getb(&bs, 4);
+          /* Sanity check */
+          if (x < 0) {
+            return -1;
+          }
+          w |= x;
+          w += 32;
+        }
+      }
+
+      oLen -= n;
+
+      while (n-- > 0) {
+        dst--;
+        if (dst < orgdst || (dst + w + 1) >= (orgdst + dst_length))
+            return -1;
+        *dst = dst[w + 1];
+      }
+    }
+  }
+
+  return 0;
+}
+
+BOOL S404_Unpack(MREADER *reader, void **out, long *outlen)
+{
+       SLONG iLen, sLen, oLen, pLen;
+       UBYTE *src, *dst = NULL;
+       int err;
+
+       _mm_fseek(reader,0,SEEK_END);
+       iLen = _mm_ftell(reader);
+       if (iLen <= 16) return 0;
+
+       _mm_rewind(reader);
+       if (_mm_read_M_ULONG(reader) != 0x53343034) /* S404 */
+               return 0;
+
+       sLen = _mm_read_M_SLONG(reader); /* Security length */
+       oLen = _mm_read_M_SLONG(reader); /* Depacked length */
+       pLen = _mm_read_M_SLONG(reader); /* Packed length */
+#ifdef STC_DEBUG
+       fprintf(stderr,"S404: iLen= %d, sLen= %d, pLen= %d, oLen= %d\n",
+               iLen, sLen, pLen, oLen);
+#endif
+       if (sLen < 0 || oLen <= 0 || pLen <= 0) return 0;
+       if (pLen + 16 >= iLen) return 0; /* sanity check */
+
+       if (!(src = (UBYTE*) MikMod_malloc(iLen - 16)))
+               return 0;
+       if (!(dst = (UBYTE*) MikMod_malloc(oLen))) {
+               MikMod_free(src);
+               return 0;
+       }
+
+       _mm_read_UBYTES(src, iLen - 16, reader);
+       err = decompressS404(src, dst, oLen, pLen);
+       MikMod_free(src);
+
+       if (!err) {
+               *out = dst;
+               *outlen = oLen;
+               return 1;
+       }
+
+       MikMod_free(dst);
+       return 0;
+}
diff --git a/libs/mikmod/depackers/xpk.c b/libs/mikmod/depackers/xpk.c
new file mode 100644 (file)
index 0000000..5bd7eea
--- /dev/null
@@ -0,0 +1,427 @@
+/* MikMod sound library (c) 2003-2015 Raphael Assenat and others -
+ * see AUTHORS file for a 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.
+ */
+
+/* XPK-SQSH depacker
+ * Algorithm from the portable decruncher by Bert Jahn (24.12.97)
+ * Checksum added by Sipos Attila <h430827@stud.u-szeged.hu>
+ * Rewritten for libxmp by Claudio Matsuoka
+ * Rewritten for libmikmod by O. Sezer
+ *
+ * Copyright (C) 2013 Claudio Matsuoka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#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
+
+struct io {
+       UBYTE *src;
+       UBYTE *dest;
+       int offs;
+};
+
+static const UBYTE ctable[]={
+       2, 3, 4, 5, 6, 7, 8, 0,
+       3, 2, 4, 5, 6, 7, 8, 0,
+       4, 3, 5, 2, 6, 7, 8, 0,
+       5, 4, 6, 2, 3, 7, 8, 0,
+       6, 5, 7, 2, 3, 4, 8, 0,
+       7, 6, 8, 2, 3, 4, 5, 0,
+       8, 7, 6, 2, 3, 4, 5, 0
+};
+
+static UWORD readmem16b(UBYTE *m)
+{
+       ULONG a, b;
+
+       a = m[0];
+       b = m[1];
+
+       return (a << 8) | b;
+}
+
+static ULONG readmem24b(UBYTE *m)
+{
+       ULONG a, b, c;
+
+       a = m[0];
+       b = m[1];
+       c = m[2];
+
+       return (a << 16) | (b << 8) | c;
+}
+
+static UWORD xchecksum(ULONG * ptr, ULONG count)
+{
+       register ULONG sum = 0;
+
+       while (count-- > 0) {
+               sum ^= *ptr++;
+       }
+
+       return (UWORD) (sum ^ (sum >> 16));
+}
+
+static int get_bits(struct io *io, int count)
+{
+       int r = readmem24b(io->src + (io->offs >> 3));
+
+       r <<= io->offs % 8;
+       r &= 0xffffff;
+       r >>= 24 - count;
+       io->offs += count;
+
+       return r;
+}
+
+static int get_bits_final(struct io *io, int count)
+{
+       int r = readmem24b(io->src + (io->offs >> 3));
+
+       r <<= (io->offs % 8) + 8;
+       r >>= 32 - count;
+       io->offs += count;
+
+       return r;
+}
+
+static int copy_data(struct io *io, int d1, int *data, UBYTE *dest_start, UBYTE *dest_end)
+{
+       UBYTE *copy_src;
+       int dest_offset, count, copy_len;
+
+       if (get_bits(io, 1) == 0) {
+               copy_len = get_bits(io, 1) + 2;
+       } else if (get_bits(io, 1) == 0) {
+               copy_len = get_bits(io, 1) + 4;
+       } else if (get_bits(io, 1) == 0) {
+               copy_len = get_bits(io, 1) + 6;
+       } else if (get_bits(io, 1) == 0) {
+               copy_len = get_bits(io, 3) + 8;
+       } else {
+               copy_len = get_bits(io, 5) + 16;
+       }
+
+       if (get_bits(io, 1) == 0) {
+               if (get_bits(io, 1) == 0) {
+                       count = 8;
+                       dest_offset = 0;
+               } else {
+                       count = 14;
+                       dest_offset = -0x1100;
+               }
+       } else {
+               count = 12;
+               dest_offset = -0x100;
+       }
+
+       copy_len -= 3;
+
+       if (copy_len >= 0) {
+               if (copy_len != 0) {
+                       d1--;
+               }
+               d1--;
+               if (d1 < 0) {
+                       d1 = 0;
+               }
+       }
+
+       copy_len += 2;
+
+       copy_src = io->dest + dest_offset - get_bits(io, count) - 1;
+
+       /* Sanity check */
+       if (copy_src < dest_start || copy_src + copy_len >= dest_end) {
+               return -1;
+       }
+
+       do {
+               //printf("dest=%p src=%p end=%p\n", io->dest, copy_src, dest_end);
+               *io->dest++ = *copy_src++;
+       } while (copy_len--);
+
+       *data = *(--copy_src);
+
+       return d1;
+}
+
+static int unsqsh_block(struct io *io, UBYTE *dest_start, UBYTE *dest_end)
+{
+       int d1, d2, data, unpack_len, count, old_count;
+
+       d1 = d2 = data = old_count = 0;
+       io->offs = 0;
+
+       data = *(io->src++);
+       *(io->dest++) = data;
+
+       do {
+               if (d1 < 8) {
+                       if (get_bits(io, 1)) {
+                               d1 = copy_data(io, d1, &data, dest_start, dest_end);
+                               if (d1 < 0)
+                                       return -1;
+                               d2 -= d2 >> 3;
+                               continue;
+                       } 
+                       unpack_len = 0;
+                       count = 8;
+               } else {
+                       if (get_bits(io, 1)) {
+                               count = 8;
+                               if (count == old_count) {
+                                       if (d2 >= 20) {
+                                               unpack_len = 1;
+                                               d2 += 8;
+                                       } else {
+                                               unpack_len = 0;
+                                       }
+                               } else {
+                                       count = old_count;
+                                       unpack_len = 4;
+                                       d2 += 8;
+                               }
+                       } else {
+                               if (get_bits(io, 1) == 0) {
+                                       d1 = copy_data(io, d1, &data, dest_start, dest_end);
+                                       if (d1 < 0)
+                                               return -1;
+                                       d2 -= d2 >> 3;
+                                       continue;
+                               }
+
+                               if (get_bits(io, 1) == 0) {
+                                       count = 2;
+                               } else {
+                                       if (get_bits(io, 1)) {
+                                               io->offs--;
+                                               count = get_bits(io, 3);
+                                       } else {
+                                               count = 3;
+                                       }
+                               }
+
+                               count = ctable[8 * old_count + count - 17];
+                               if (count != 8) {
+                                       unpack_len = 4;
+                                       d2 += 8;
+                               } else {
+                                       if (d2 >= 20) {
+                                               unpack_len = 1;
+                                               d2 += 8;
+                                       } else {
+                                               unpack_len = 0;
+                                       }
+                               }
+                       }
+               }
+
+               do {
+                       data -= get_bits_final(io, count);
+                       *io->dest++ = data;
+               } while (unpack_len--);
+
+               if (d1 != 31) {
+                       d1++;
+               }
+
+               old_count = count;
+
+               d2 -= d2 >> 3;
+
+       } while (io->dest < dest_end);
+
+       return 0;
+}
+
+static int unsqsh(UBYTE *src, SLONG srclen, UBYTE *dest, SLONG destlen)
+{
+       SLONG len = destlen;
+       SLONG decrunched = 0;
+       UBYTE type;
+       SLONG packed_size, unpacked_size;
+       ULONG sum, lchk;
+       UBYTE *c, *dest_start, *dest_end;
+       UBYTE bc[3];
+       struct io io;
+
+       io.src = src;
+       io.dest = dest;
+
+       dest_start = io.dest;
+
+       c = src + 20;
+
+       while (len) {
+               /* Sanity check */
+               if (c >= src + srclen) {
+                       return -1;
+               }
+
+               type = *c++;
+               c++;                    /* hchk */
+
+               sum = *(UWORD *)c;
+               c += 2;                 /* checksum */
+
+               packed_size = readmem16b(c);    /* packed */
+               c += 2;
+
+               unpacked_size = readmem16b(c);  /* unpacked */
+               c += 2;
+
+               /* Sanity check */
+               if (packed_size <= 0 || unpacked_size <= 0) {
+                       return -1;
+               }
+               if (c + packed_size + 3 > src + srclen) {
+                       return -1;
+               }
+
+               io.src = c + 2;
+               memcpy(bc, c + packed_size, 3);
+               memset(c + packed_size, 0, 3);
+               lchk = xchecksum((ULONG *) (c), (packed_size + 3) >> 2);
+               memcpy(c + packed_size, bc, 3);
+
+               if (lchk != sum) {
+                       return decrunched;
+               }
+
+               if (type == 0) {
+                       /* verbatim block */
+                       memcpy(io.dest, c, packed_size);
+                       io.dest += packed_size;
+                       c += packed_size;
+                       len -= packed_size;
+                       decrunched += packed_size;
+                       continue;
+               }
+
+               if (type != 1) {
+                       /* unknown type */
+                       return decrunched;
+               }
+
+               len -= unpacked_size;
+               decrunched += unpacked_size;
+
+               /* Sanity check */
+               if (decrunched > destlen) {
+                       return -1;
+               }
+
+               packed_size = (packed_size + 3) & 0xfffc;
+               c += packed_size;
+               dest_end = io.dest + unpacked_size;
+
+               if (unsqsh_block(&io, dest_start, dest_end) < 0) {
+                       return -1;
+               }
+               
+               io.dest = dest_end;
+       }
+
+       return decrunched;
+
+}
+
+BOOL XPK_Unpack(MREADER *reader, void **out, long *outlen)
+{
+       UBYTE *src, *dest;
+       SLONG inlen, srclen, destlen;
+
+       _mm_fseek(reader,0,SEEK_END);
+       inlen = _mm_ftell(reader);
+       if (inlen <= 8 || inlen > 0x100000)
+               return 0;
+
+       _mm_rewind(reader);
+       if (_mm_read_M_ULONG(reader) != 0x58504b46) /* XPKF */
+               return 0;
+       srclen = _mm_read_M_SLONG(reader);
+       if (srclen <= 8 || srclen > 0x100000 || srclen > inlen-8)
+               return 0;
+       if (_mm_read_M_ULONG(reader) != 0x53515348) /* SQSH */
+               return 0;
+       destlen = _mm_read_M_SLONG(reader);
+       if (destlen < 0 || destlen > 0x200000)
+               return 0;
+
+       if ((src = (UBYTE*) MikMod_malloc(srclen + 3)) == NULL)
+               return 0;
+       if ((dest = (UBYTE*) MikMod_malloc(destlen + 100)) == NULL) {
+               MikMod_free(src);
+               return 0;
+       }
+
+       if (!_mm_read_UBYTES(src, srclen - 8, reader))
+               goto err;
+
+       if (unsqsh(src, srclen, dest, destlen) != destlen)
+               goto err;
+
+       *out = dest;
+       *outlen = destlen;
+
+       MikMod_free(src);
+
+       return 1;
+
+    err:
+       MikMod_free(dest);
+       MikMod_free(src);
+       return 0;
+}
+
diff --git a/libs/mikmod/drivers/dos/dosdma.c b/libs/mikmod/drivers/dos/dosdma.c
new file mode 100644 (file)
index 0000000..e232c30
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+    Implementation of DMA routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "dosdma.h"
+
+#include <go32.h> /* includes sys/version.h (djgpp >= 2.02) */
+#include <dos.h>
+#include <dpmi.h>
+#include <sys/nearptr.h>
+#include <malloc.h>
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+/* BUG WARNING:  there is an error in DJGPP libraries <= 2.01:
+ * src/libc/dpmi/api/d0102.s loads the selector and allocsize
+ * arguments in the wrong order.  DJGPP >= 2.02 have it fixed. */
+#if (!defined(__DJGPP_MINOR__) || (__DJGPP_MINOR__+0) < 2)
+#warning __dpmi_resize_dos_memory() from DJGPP <= 2.01 is broken!
+#endif
+
+__dma_regs dma[8] = {
+/* *INDENT-OFF* */
+       {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+       {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+
+       {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+       {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
+        DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+
+       {DMA_ADDR_4,          0, DMA_SIZE_4,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+       {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+
+       {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+       {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
+        DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
+/* *INDENT-ON* */
+};
+
+static int __initialized = 0;
+static int __buffer_count = 0;
+static __dpmi_meminfo __locked_data;
+
+int dma_initialize()
+{
+       if (!__djgpp_nearptr_enable())
+               return 0;
+
+       /* Trick: Avoid re-setting DS selector limit on each memory allocation
+          call */
+       __djgpp_selector_limit = 0xffffffff;
+
+       __locked_data.address = __djgpp_base_address + (unsigned long)&dma;
+       __locked_data.size = sizeof(dma);
+       if (__dpmi_lock_linear_region(&__locked_data))
+               return 0;
+
+       return (__initialized = 1);
+}
+
+void dma_finalize()
+{
+       if (!__initialized)
+               return;
+       __dpmi_unlock_linear_region(&__locked_data);
+       __djgpp_nearptr_disable();
+}
+
+dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
+{
+       int parsize = (size + 15) >> 4; /* size in paragraphs */
+       int par = 0;                            /* Real-mode paragraph */
+       int selector = 0;                       /* Protected-mode selector */
+       int mask = channel <= 3 ? 0xfff : 0x1fff;       /* Alignment mask in para. */
+       int allocsize = parsize;        /* Allocated size in paragraphs */
+       int count;                                      /* Try count */
+       int bound = 0;                          /* Nearest bound address */
+       int maxsize;                            /* Maximal possible block size */
+       dma_buffer *buffer = NULL;
+       __dpmi_meminfo buff_info, struct_info;
+
+       if (!dma_initialize())
+               return NULL;
+
+       /* Loop until we'll get a properly aligned memory block */
+       for (count = 8; count; count--) {
+               int resize = (selector != 0);
+
+               /* Try first to resize (possibly previously) allocated block */
+               if (resize) {
+                       maxsize = (bound + parsize) - par;
+                       if (maxsize > parsize * 2)
+                               maxsize = parsize * 2;
+                       if (maxsize == allocsize)
+                               resize = 0;
+                       else {
+                               allocsize = maxsize;
+                               if (__dpmi_resize_dos_memory(selector, allocsize, &maxsize) !=
+                                       0) resize = 0;
+                       }
+               }
+
+               if (!resize) {
+                       if (selector)
+                               __dpmi_free_dos_memory(selector), selector = 0;
+                       par = __dpmi_allocate_dos_memory(allocsize, &selector);
+               }
+
+               if ((par == 0) || (par == -1))
+                       goto exit;
+
+               /* If memory block contains a properly aligned portion, quit loop */
+               bound = (par + mask + 1) & ~mask;
+               if (par + parsize <= bound)
+                       break;
+               if (bound + parsize <= par + allocsize) {
+                       par = bound;
+                       break;
+               }
+       }
+       if (!count) {
+               __dpmi_free_dos_memory(selector);
+               goto exit;
+       }
+
+       buffer = (dma_buffer *) MikMod_malloc(sizeof(dma_buffer));
+       buffer->linear = (unsigned char *)(__djgpp_conventional_base + bound * 16);
+       buffer->physical = bound * 16;
+       buffer->size = parsize * 16;
+       buffer->selector = selector;
+       buffer->channel = channel;
+
+       buff_info.address = buffer->physical;
+       buff_info.size = buffer->size;
+       /*
+          Don't pay attention to return code since under plain DOS it often
+          returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
+        */
+       __dpmi_lock_linear_region(&buff_info);
+
+       /* Lock the DMA buffer control structure as well */
+       struct_info.address = __djgpp_base_address + (unsigned long)buffer;
+       struct_info.size = sizeof(dma_buffer);
+       if (__dpmi_lock_linear_region(&struct_info)) {
+               __dpmi_unlock_linear_region(&buff_info);
+               __dpmi_free_dos_memory(selector);
+               MikMod_free(buffer);
+               buffer = NULL;
+               goto exit;
+       }
+
+  exit:
+       if (buffer)
+               __buffer_count++;
+       else if (--__buffer_count == 0)
+               dma_finalize();
+       return buffer;
+}
+
+void dma_free(dma_buffer * buffer)
+{
+       __dpmi_meminfo buff_info;
+
+       if (!buffer)
+               return;
+
+       buff_info.address = buffer->physical;
+       buff_info.size = buffer->size;
+       __dpmi_unlock_linear_region(&buff_info);
+
+       __dpmi_free_dos_memory(buffer->selector);
+       MikMod_free(buffer);
+
+       if (--__buffer_count == 0)
+               dma_finalize();
+}
+
+void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
+{
+       /* Disable interrupts */
+       int old_ints = disable();
+       dma_disable(buffer->channel);
+       dma_set_mode(buffer->channel, mode);
+       dma_clear_ff(buffer->channel);
+       dma_set_addr(buffer->channel, buffer->physical);
+       dma_clear_ff(buffer->channel);
+       dma_set_count(buffer->channel, count);
+       dma_enable(buffer->channel);
+       /* Re-enable interrupts */
+       if (old_ints)
+               enable();
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosdma.h b/libs/mikmod/drivers/dos/dosdma.h
new file mode 100644 (file)
index 0000000..882c9ac
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+    Interface for DMA routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __DOSDMA_H__
+#define __DOSDMA_H__
+
+#include <pc.h>
+
+#define DMA1_BASE              0x00    /* 8 bit slave DMA, channels 0..3 */
+#define DMA2_BASE              0xC0    /* 16 bit master DMA, ch 4(=slave input)..7 */
+
+#define DMA1_CMD_REG           0x08    /* command register (w) */
+#define DMA1_STAT_REG          0x08    /* status register (r) */
+#define DMA1_REQ_REG           0x09    /* request register (w) */
+#define DMA1_MASK_REG          0x0A    /* single-channel mask (w) */
+#define DMA1_MODE_REG          0x0B    /* mode register (w) */
+#define DMA1_CLEAR_FF_REG      0x0C    /* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG          0x0D    /* Temporary Register (r) */
+#define DMA1_RESET_REG         0x0D    /* Master Clear (w) */
+#define DMA1_CLR_MASK_REG      0x0E    /* Clear Mask */
+#define DMA1_MASK_ALL_REG      0x0F    /* all-channels mask (w) */
+
+#define DMA2_CMD_REG           0xD0    /* command register (w) */
+#define DMA2_STAT_REG          0xD0    /* status register (r) */
+#define DMA2_REQ_REG           0xD2    /* request register (w) */
+#define DMA2_MASK_REG          0xD4    /* single-channel mask (w) */
+#define DMA2_MODE_REG          0xD6    /* mode register (w) */
+#define DMA2_CLEAR_FF_REG      0xD8    /* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG          0xDA    /* Temporary Register (r) */
+#define DMA2_RESET_REG         0xDA    /* Master Clear (w) */
+#define DMA2_CLR_MASK_REG      0xDC    /* Clear Mask */
+#define DMA2_MASK_ALL_REG      0xDE    /* all-channels mask (w) */
+
+#define DMA_ADDR_0      0x00   /* DMA address registers */
+#define DMA_ADDR_1      0x02
+#define DMA_ADDR_2      0x04
+#define DMA_ADDR_3      0x06
+#define DMA_ADDR_4      0xC0
+#define DMA_ADDR_5      0xC4
+#define DMA_ADDR_6      0xC8
+#define DMA_ADDR_7      0xCC
+
+#define DMA_SIZE_0             0x01    /* DMA transfer size registers */
+#define DMA_SIZE_1             0x03
+#define DMA_SIZE_2             0x05
+#define DMA_SIZE_3             0x07
+#define DMA_SIZE_4             0xC2
+#define DMA_SIZE_5             0xC6
+#define DMA_SIZE_6             0xCA
+#define DMA_SIZE_7             0xCE
+
+#define DMA_PAGE_0      0x87   /* DMA page registers */
+#define DMA_PAGE_1      0x83
+#define DMA_PAGE_2      0x81
+#define DMA_PAGE_3      0x82
+#define DMA_PAGE_5      0x8B
+#define DMA_PAGE_6      0x89
+#define DMA_PAGE_7      0x8A
+
+#define DMA_MODE_AUTOINIT      0x10    /* Auto-init mode bit */
+#define DMA_MODE_READ          0x44    /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE         0x48    /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE       0xC0    /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+/* Indexable specific DMA registers */
+typedef struct __dma_regs_s {
+       unsigned char addr;                     /* DMA transfer address register */
+       unsigned char page;                     /* DMA page register */
+       unsigned char size;                     /* DMA transfer size register */
+       unsigned char mask;                     /* DMA mask/unmask register */
+       unsigned char flip;                     /* DMA flip-flop reset register */
+       unsigned char mode;                     /* DMA mode register */
+} __dma_regs;
+
+extern __dma_regs dma[8];
+
+/* Enable a specific DMA channel */
+static inline void dma_enable(unsigned int channel)
+{
+       outportb(dma[channel].mask, channel & 3);
+}
+
+/* Disable a specific DMA channel */
+static inline void dma_disable(unsigned int channel)
+{
+       outportb(dma[channel].mask, (channel & 3) | 0x04);
+}
+
+/* Clear the 'DMA Flip Flop' flag */
+static inline void dma_clear_ff(unsigned int channel)
+{
+       outportb(dma[channel].flip, 0);
+}
+
+/* Set mode for a specific DMA channel */
+static inline void dma_set_mode(unsigned int channel, char mode)
+{
+       outportb(dma[channel].mode, mode | (channel & 3));
+}
+
+/* Set DMA page register */
+static inline void dma_set_page(unsigned int channel, char page)
+{
+       if (channel > 3)
+               page &= 0xfe;
+       outportb(dma[channel].page, page);
+}
+
+/*
+  Set transfer address & page bits for specific DMA channel.
+  Assumes dma flipflop is clear.
+*/
+static inline void dma_set_addr(unsigned int channel, unsigned int address)
+{
+       unsigned char dma_reg = dma[channel].addr;
+       dma_set_page(channel, address >> 16);
+       if (channel <= 3) {
+               outportb(dma_reg, (address) & 0xff);
+               outportb(dma_reg, (address >> 8) & 0xff);
+       } else {
+               outportb(dma_reg, (address >> 1) & 0xff);
+               outportb(dma_reg, (address >> 9) & 0xff);
+       }
+}
+
+/*
+  Set transfer size for a specific DMA channel.
+  Assumes dma flip-flop is clear.
+*/
+static inline void dma_set_count(unsigned int channel, unsigned int count)
+{
+       unsigned char dma_reg = dma[channel].size;
+       count--;                                        /* number of DMA transfers is bigger by one */
+       if (channel > 3)
+               count >>= 1;
+       outportb(dma_reg, (count) & 0xff);
+       outportb(dma_reg, (count >> 8) & 0xff);
+}
+
+/*
+  Query the number of bytes left to transfer.
+  Assumes DMA flip-flop is clear.
+*/
+static inline int dma_get_count(unsigned int channel)
+{
+       unsigned char dma_reg = dma[channel].size;
+
+       /* using short to get 16-bit wrap around */
+       unsigned short count;
+       count = inportb(dma_reg);
+       count |= inportb(dma_reg) << 8;
+       count++;
+       return (channel <= 3) ? count : (count << 1);
+}
+
+typedef struct dma_buffer_s {
+       unsigned char *linear;          /* Linear address */
+       unsigned long physical;         /* Physical address */
+       unsigned long size;                     /* Buffer size */
+       unsigned short selector;        /* The selector assigned to this memory */
+       unsigned char channel;          /* The DMA channel */
+} dma_buffer;
+
+/* Allocate a block of memory suitable for using as a DMA buffer */
+extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size);
+/* Deallocate a DMA buffer */
+extern void dma_free(dma_buffer * buffer);
+/* Start DMA transfer to or from given buffer */
+extern void dma_start(dma_buffer * buffer, unsigned long count,
+                                         unsigned char mode);
+
+#endif /* __DOSDMA_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosgus.c b/libs/mikmod/drivers/dos/dosgus.c
new file mode 100644 (file)
index 0000000..637b526
--- /dev/null
@@ -0,0 +1,1907 @@
+/*     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.
+*/
+
+/*==============================================================================
+
+  Driver for GUS cards under DOS
+  Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_ULTRA
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <dpmi.h>
+#include <sys/farptr.h>
+#include <sys/nearptr.h>
+#include <go32.h>
+#include <string.h>
+
+#include "dosgus.h"
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+/********************************************* Private variables/routines *****/
+
+/* The Gravis Ultrasound state/info */
+__gus_state gus;
+
+/* Try to avoid holes in DRAM less than this size */
+#define DRAM_HOLE_THRESHOLD    8192
+/* If hole is larger than that, create a free block describing it */
+#define DRAM_SPLIT_THRESHOLD   64
+/* The size of DMA buffer used for RAM->DRAM transfers */
+#define GF1_DMA_BUFFER_SIZE    8192
+
+/* Debug macro: useful to change screen locations when some event occurs */
+#ifdef MIKMOD_DEBUG
+#  define DEBUG_PRINT(x) printf x;
+#  define DEBUG_OFS(addr, attr)                        \
+   {                                           \
+     unsigned short x;                         \
+     _dosmemgetw (0xb8780 + addr*2, 1, &x);    \
+     if ((x >> 8) != attr) x = '0';            \
+     x = ((x + 1) & 0xff) | (attr << 8);       \
+     _dosmemputw (&x, 1, 0xb8780 + addr*2);    \
+   }
+#else
+#  define DEBUG_PRINT(x)
+#  define DEBUG_OFS(addr, attr)
+#endif
+
+static unsigned short __gus_volume_table[512] = {
+       0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00,
+       0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00, 0xac00, 0xae00,
+       0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700,
+       0xb800, 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00,
+       0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380,
+       0xc400, 0xc480, 0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780,
+       0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80,
+       0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80,
+       0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140, 0xd180, 0xd1c0,
+       0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0,
+       0xd400, 0xd440, 0xd480, 0xd4c0, 0xd500, 0xd540, 0xd580, 0xd5c0,
+       0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0,
+       0xd800, 0xd840, 0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0,
+       0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0,
+       0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0,
+       0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40, 0xdf80, 0xdfc0,
+       0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0,
+       0xe100, 0xe120, 0xe140, 0xe160, 0xe180, 0xe1a0, 0xe1c0, 0xe1e0,
+       0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0,
+       0xe300, 0xe320, 0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0,
+       0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0,
+       0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0,
+       0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0, 0xe6c0, 0xe6e0,
+       0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0,
+       0xe800, 0xe820, 0xe840, 0xe860, 0xe880, 0xe8a0, 0xe8c0, 0xe8e0,
+       0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0,
+       0xea00, 0xea20, 0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0,
+       0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0,
+       0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0,
+       0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0, 0xedc0, 0xede0,
+       0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0,
+       0xef00, 0xef20, 0xef40, 0xef60, 0xef80, 0xefa0, 0xefc0, 0xefe0,
+       0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070,
+       0xf080, 0xf090, 0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0,
+       0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170,
+       0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0,
+       0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250, 0xf260, 0xf270,
+       0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0,
+       0xf300, 0xf310, 0xf320, 0xf330, 0xf340, 0xf350, 0xf360, 0xf370,
+       0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0,
+       0xf400, 0xf410, 0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470,
+       0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0,
+       0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570,
+       0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0, 0xf5e0, 0xf5f0,
+       0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670,
+       0xf680, 0xf690, 0xf6a0, 0xf6b0, 0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0,
+       0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770,
+       0xf780, 0xf790, 0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0,
+       0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870,
+       0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0,
+       0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950, 0xf960, 0xf970,
+       0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0,
+       0xfa00, 0xfa10, 0xfa20, 0xfa30, 0xfa40, 0xfa50, 0xfa60, 0xfa70,
+       0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0,
+       0xfb00, 0xfb10, 0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70,
+       0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0,
+       0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70,
+       0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0, 0xfce0, 0xfcf0,
+       0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70,
+       0xfd80, 0xfd90, 0xfda0, 0xfdb0, 0xfdc0, 0xfdd0, 0xfde0, 0xfdf0,
+       0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70,
+       0xfe80, 0xfe90, 0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0,
+       0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70,
+       0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0
+};
+
+/* Wait a bit for GUS before doing something
+ * Mark function as volatile: don't allow it to be inlined.
+ * It *should* be slow, no need to make it work faster :-)
+ */
+#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
+# define _func_noinline volatile /* match original code */
+# define _func_noclone
+#else
+/* avoid warnings from newer gcc:
+ * "function definition has qualified void return type" and
+ * function return types not compatible due to 'volatile' */
+# define _func_noinline __attribute__((__noinline__))
+# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+#  define _func_noclone
+# else
+#  define _func_noclone __attribute__((__noclone__))
+# endif
+#endif
+_func_noinline
+_func_noclone
+ void __gus_delay()
+{
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+       inportb(GF1_MIX_CTRL);
+}
+
+static void __gus_stop_controller(unsigned char gf1reg)
+{
+       register unsigned char value = __gus_inregb(gf1reg);
+       __gus_outregb(gf1reg, (value | GF1VC_STOPPED | GF1VC_STOP) &
+                      ~(GF1VC_IRQ_PENDING | GF1VC_IRQ));
+}
+
+/* Returns 1 if volume is already at given position */
+static boolean __gus_volume_ramp_to(unsigned short volume,
+                                    unsigned char rate,
+                                    unsigned char vol_ctrl)
+{
+       int svol = __gus_inregw(GF1R_VOLUME) & 0xfff0;
+       int evol = volume;
+
+       /* First of all, disable volume ramp */
+       __gus_stop_controller(GF1R_VOLUME_CONTROL);
+
+       /* If voice is stopped, set the volume to zero and return */
+       if (__gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED) {
+               __gus_outregw(GF1R_VOLUME, 0);
+               return 1;
+       }
+
+       /* Avoid clicks when volume ramp goes too high or too low */
+       if (svol < 0x0400)
+               svol = 0x0400;
+       if (svol > 0xfc00)
+               svol = 0xfc00;
+       if (evol < 0x0400)
+               evol = 0x0400;
+       if (evol > 0xfc00)
+               evol = 0xfc00;
+
+       /* Adjust start/end positions */
+       if (svol > evol) {
+               unsigned short tmp = evol;
+               evol = svol;
+               svol = tmp;
+               vol_ctrl |= GF1VL_BACKWARD;
+       }
+
+       /* If we already are (near) the target volume, quit */
+       if (evol - svol < 0x1000) {
+               __gus_outregw(GF1R_VOLUME, volume);
+               return 1;
+       }
+
+       __gus_outregb(GF1R_VOLUME_START, svol >> 8);
+       __gus_outregb(GF1R_VOLUME_END, evol >> 8);
+       __gus_outregb(GF1R_VOLUME_RATE, rate);
+       __gus_outregb_slow(GF1R_VOLUME_CONTROL, vol_ctrl);
+       return 0;
+}
+
+static inline void __gus_stop_voice()
+{
+       __gus_stop_controller(GF1R_VOICE_CONTROL);
+       __gus_outregb_slow(GF1R_VOICE_CONTROL, GF1VC_STOPPED | GF1VC_STOP);
+}
+
+/* The GUS IRQ handler */
+static void gf1_irq()
+{
+       unsigned char irq_source;       /* The contents of GF1_IRQ_STATUS register */
+       boolean timer_cb = 0;           /* Call timer callback function */
+
+       DEBUG_OFS(0, 0xCE)
+       gus.eow_ignore = 0;
+       while ((irq_source = inportb(GF1_IRQ_STATUS))) {
+               DEBUG_OFS(1, 0xCE)
+
+                 if (irq_source & GF1M_IRQ_DMA_COMPLETE) {
+                       DEBUG_OFS(4, 0x9F)
+                         /* reset the IRQ pending bit */
+                         __gus_inregb(GF1R_DMA_CONTROL);
+                       gus.dma_active = 0;
+
+                       if (gus.dma_callback)
+                               gus.dma_callback();
+               }
+
+               if (irq_source & (GF1M_IRQ_WAVETABLE | GF1M_IRQ_ENVELOPE)) {
+                       unsigned char vcirq;
+                       unsigned int done_mask = 0;
+
+                       /* IRQ bits are inverse (i.e. 0 = IRQ pending) */
+                       while ((vcirq = __gus_inregb(GF1R_IRQ_SOURCE) ^
+                               (GF1IRQ_WAVE | GF1IRQ_VOLUME)) &
+                               (GF1IRQ_WAVE | GF1IRQ_VOLUME)) {
+                               unsigned long voice = (vcirq & 0x1f);
+                               unsigned char voice_ctl, volume_ctl;
+                               unsigned int voice_mask = (1 << voice);
+
+                               /* Don't handle more than one IRQ from same voice */
+                               if (done_mask & voice_mask)
+                                       continue;
+
+                               done_mask |= voice_mask;
+
+                               /* Read voice/volume selection registers */
+                               __gus_select_voice(voice);
+                               voice_ctl = __gus_inregb(GF1R_VOICE_CONTROL);
+                               volume_ctl = __gus_inregb(GF1R_VOLUME_CONTROL);
+
+                               if ((vcirq & GF1IRQ_WAVE) && (gus.wt_callback)
+                                       && !(gus.eow_ignore & voice_mask)) {
+                                       DEBUG_OFS(5, 0xAF)
+                                       gus.wt_callback(voice, voice_ctl, volume_ctl);
+                               }
+
+                               if ((vcirq & GF1IRQ_VOLUME) && (gus.vl_callback)) {
+                                       DEBUG_OFS(6, 0xAF)
+                                       gus.vl_callback(voice, voice_ctl, volume_ctl);
+                               }
+                       }
+               }
+
+               /* Reset timers that sent this IRQ */
+               if (irq_source & (GF1M_IRQ_TIMER1 | GF1M_IRQ_TIMER2)) {
+                       unsigned char timer_ctl = gus.timer_ctl_reg;
+
+                       if (irq_source & GF1M_IRQ_TIMER1)
+                               timer_ctl &= ~GF1M_TIMER1;
+
+                       if (irq_source & GF1M_IRQ_TIMER2)
+                               timer_ctl &= ~GF1M_TIMER2;
+
+                       __gus_outregb_slow(GF1R_TIMER_CONTROL, timer_ctl);
+                       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+               }
+
+               if (irq_source & GF1M_IRQ_TIMER1)
+                       if (--gus.t1_countdown == 0) {
+                               gus.t1_countdown = gus.t1_multiple;
+                               gus.t1_ticks++;
+
+                               DEBUG_OFS(2, 0xCF)
+
+                               if (gus.t1_callback) {
+                                       timer_cb = 1;
+                                       gus.t1_callback();
+                               }
+                       }
+
+               if (irq_source & GF1M_IRQ_TIMER2)
+                       if (--gus.t2_countdown == 0) {
+                               gus.t2_countdown = gus.t2_multiple;
+                               gus.t2_ticks++;
+
+                               DEBUG_OFS(3, 0xCF)
+
+                               if (gus.t2_callback)
+                                       gus.t2_callback();
+                       }
+#if 0
+               /* The following are not used and implemented yet */
+               if (irq_source & (GF1M_IRQ_MIDI_TX | GF1M_IRQ_MIDI_RX)) {
+               }
+#endif
+       }
+
+       irq_ack(gus.gf1_irq);
+
+       if (timer_cb && gus.timer_callback)
+               gus.timer_callback();
+}
+
+static void gf1_irq_end()
+{
+}
+
+static boolean __gus_detect()
+{
+       /* A relatively relaxed autodetection;
+          We don't count on DRAM: GUS PnP could not have it
+          (although its anyway bad for us)
+        */
+       __gus_select_voice(0);
+       __gus_stop_voice();
+       __gus_outregw(GF1R_FREQUENCY, 0x1234);
+       __gus_outregw(GF1R_VOLUME, 0x5670);
+       return ((__gus_inregw(GF1R_FREQUENCY) & 0xfffe) == 0x1234)
+         && ((__gus_inregw(GF1R_VOLUME) & 0xfff0) == 0x5670);
+}
+
+static void __gus_reset(boolean reset_io_dma)
+{
+       static unsigned char irqctl[16] = { 0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7 };
+       static unsigned char dmactl[8] = { 0, 1, 0, 2, 0, 3, 4, 5 };
+       unsigned char irqtmp, dmatmp;
+
+       /* Disable interrupts while resetting to avoid spurious IRQs */
+       int i, timer, old_ints = disable();
+
+       /* Stop the timer so that GUS IRQ won't clobber registers */
+       timer = (gus.timer_ctl_reg & GF1M_TIMER1);
+       if (timer)
+               gus_timer_stop();
+
+       gus.dma_active = 0;
+
+       __gus_outregb(GF1R_RESET, 0);
+       for (i = 0; i < 10; i++)
+               __gus_delay();
+       __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET);
+       for (i = 0; i < 10; i++)
+               __gus_delay();
+
+       outportb(GF1_MIDI_CTRL, GF1M_MIDI_RESET);
+       for (i = 0; i < 10; i++)
+               __gus_delay();
+       outportb(GF1_MIDI_CTRL, 0);
+
+       /* Reset all IRQ sources */
+       __gus_outregb(GF1R_DMA_CONTROL, 0);
+       __gus_outregb(GF1R_TIMER_CONTROL, 0);
+       __gus_outregb(GF1R_SAMPLE_CONTROL, 0);
+
+       /* Reset all voices */
+       gus_reset(gus.voices, gus.dynmask);
+
+       /* Flush any pending IRQs */
+       inportb(GF1_IRQ_STATUS);
+       __gus_inregb(GF1R_DMA_CONTROL);
+       __gus_inregb(GF1R_SAMPLE_CONTROL);
+       __gus_inregb(GF1R_IRQ_SOURCE);
+
+       if (reset_io_dma) {
+               /* Now set up the GUS card to required IRQs and DMAs */
+               if (gus.irq[0] == gus.irq[1])
+                       irqtmp = irqctl[gus.irq[0]] | GF1M_IRQ_EQUAL;
+               else
+                       irqtmp = irqctl[gus.irq[0]] | (irqctl[gus.irq[1]] << 3);
+
+               if (gus.dma[0] == gus.dma[1])
+                       dmatmp = dmactl[gus.dma[0]] | GF1M_DMA_EQUAL;
+               else
+                       dmatmp = dmactl[gus.dma[0]] | (dmactl[gus.dma[1]] << 3);
+
+               /* Reset IRQs if possible */
+               gus.mixer =
+                 GF1M_MIXER_NO_LINE_IN | GF1M_MIXER_NO_OUTPUT | GF1M_MIXER_GF1_IRQ;
+               if (gus.version >= GUS_CARD_VERSION_CLASSIC1) {
+                       outportb(GF1_REG_CTRL, 0x05);
+                       outportb(GF1_MIX_CTRL, gus.mixer);
+                       outportb(GF1_IRQ_CTRL, 0x00);   /* Reset IRQs */
+                       outportb(GF1_REG_CTRL, 0x00);
+               }
+
+               /* Set up DMA channels: NEVER disable MIXER_GF1_IRQ in the future */
+               outportb(GF1_MIX_CTRL, gus.mixer);
+               outportb(GF1_IRQ_CTRL, dmatmp);
+
+               /* Set up IRQ channels */
+               outportb(GF1_MIX_CTRL, gus.mixer | GF1M_CONTROL_SELECT);
+               outportb(GF1_IRQ_CTRL, irqtmp);
+       }
+
+       __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET | GF1M_OUTPUT_ENABLE | GF1M_MASTER_IRQ);
+       __gus_delay();
+
+       /* Flush IRQs again */
+       inportb(GF1_IRQ_STATUS);
+       __gus_inregb(GF1R_DMA_CONTROL);
+       __gus_inregb(GF1R_SAMPLE_CONTROL);
+       __gus_inregb(GF1R_IRQ_SOURCE);
+
+       _irq_ack(gus.irq[0]);
+       _irq_ack(gus.irq[1]);
+
+       if (timer)
+               gus_timer_continue();
+
+       if (old_ints)
+               enable();
+
+       /* Enable output */
+       __gus_mixer_output(1);
+}
+
+/* Transfer a block of data from GUS DRAM to main RAM through port I/O */
+static void __gus_transfer_io_in(unsigned long address, unsigned char *source,
+                                 unsigned long size)
+{
+       while (size) {
+               register unsigned int size64k;
+
+               size64k = 0x10000 - (address & 0xffff);
+               if (size64k > size)
+                       size64k = size;
+               size -= size64k;
+
+               __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+               while (size64k--) {
+                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                       *source++ = inportb(GF1_DRAM);
+               }
+       }
+}
+
+/* Transfer a block of data into GUS DRAM through port I/O */
+static void __gus_transfer_io(unsigned long address, unsigned char *source,
+                              unsigned long size, int flags)
+{
+       while (size) {
+               register unsigned int size64k;
+
+               size64k = 0x10000 - (address & 0xffff);
+               if (size64k > size)
+                       size64k = size;
+               size -= size64k;
+
+               __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+               if (flags & GUS_WAVE_INVERT)
+                       if (flags & GUS_WAVE_16BIT)
+                               while (size64k-- && size64k--) {
+                                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                                       outportb(GF1_DRAM, *source++);
+                                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                                       outportb(GF1_DRAM, (*source++) ^ 0x80);
+                       } else
+                               while (size64k--) {
+                                       __gus_outregw(GF1R_DRAM_LOW, address++);
+                                       outportb(GF1_DRAM, (*source++) ^ 0x80);
+               } else
+                       while (size64k--) {
+                               __gus_outregw(GF1R_DRAM_LOW, address++);
+                               outportb(GF1_DRAM, *source++);
+                       }
+       }
+}
+
+/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */
+static int __gus_wait_dma()
+{
+       unsigned long timer;
+       _farsetsel(_dos_ds);
+       timer = _farnspeekl(0x46c);
+       while (gus.dma_active)
+               if (_farnspeekl(0x46c) - timer > 8) {
+                       /* Force DMA abort since something went wrong */
+                       __gus_reset(0);
+                       return -1;
+               }
+
+       return 0;
+}
+
+/* Transfer a block of data into GUS DRAM through DMA controller */
+static void __gus_transfer_dma(unsigned long address, unsigned char *source,
+                               unsigned long size, int flags)
+{
+       unsigned char dma_control;
+       unsigned long bytes_left;
+       unsigned long cur_size;
+       unsigned long dest_addr;
+
+       if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT))
+               size = (size + 1) & ~1;
+
+       bytes_left = size;
+       while (bytes_left) {
+               __gus_wait_dma();
+
+               cur_size = gus.dma_buff->size;
+               if (cur_size > bytes_left)
+                       cur_size = bytes_left;
+               bytes_left -= cur_size;
+               dest_addr = address;
+
+               if (gus.dma_buff->linear != source)
+                       memmove(gus.dma_buff->linear, source, cur_size);
+               source += cur_size;
+               address += cur_size;
+
+               /* Disable GUS -> DMA tie */
+               __gus_outregb(GF1R_DMA_CONTROL, 0);
+               __gus_delay();
+
+               /* Set up the DMA */
+               dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE);
+               gus.dma_active = 1;
+
+               /* Reset the DMA IRQ pending bit if set */
+               __gus_inregb(GF1R_DMA_CONTROL);
+
+               /* The 16-bit DMA channels needs a slightly different approach */
+               dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate;
+               if (gus.dma[0] > 3) {
+                       dest_addr = __gus_convert_addr16(dest_addr);
+                       dma_control |= GF1M_DMAR_CHAN16;
+               }
+
+               __gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4);
+
+               if (flags & GUS_WAVE_16BIT)
+                       dma_control |= GF1M_DMAR_DATA16;
+               if (flags & GUS_WAVE_INVERT)
+                       dma_control |= GF1M_DMAR_TOGGLE_SIGN;
+
+               /* Tell GUS to start transfer */
+               __gus_outregb(GF1R_DMA_CONTROL, dma_control);
+       }
+}
+
+static void __gus_detect_version()
+{
+       unsigned char tmp;
+
+       switch (gus.version = inportb(GF1_REVISION)) {
+         case 5:
+               gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
+               gus.ics = 1;
+               gus.ics_flipped = 1;
+               break;
+         case 6:
+         case 7:
+         case 8:
+         case 9:
+               gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
+               gus.ics = 1;
+               break;
+         case 10:
+               gus.version = GUS_CARD_VERSION_MAX;
+               gus.codec = 1;
+               break;
+         case 11:
+               gus.version = GUS_CARD_VERSION_MAX1;
+               gus.codec = 1;
+               break;
+         case 0x30:
+               gus.version = GUS_CARD_VERSION_ACE;
+               break;
+         case 0x50:
+               gus.version = GUS_CARD_VERSION_EXTREME;
+               break;
+         case 0xff:
+               /* Pre-3.7 board */
+               outportb(GF1_REG_CTRL, 0x20);
+               tmp = inportb(GF1_REG_CTRL);
+               if ((tmp != 0xff) && (tmp & 0x06))
+                       gus.version = GUS_CARD_VERSION_CLASSIC1;
+               else
+                       gus.version = GUS_CARD_VERSION_CLASSIC;
+               break;
+         default:
+               /* Hmm... unknown revision. Assume a safe Classic model */
+#ifdef MIKMOD_DEBUG
+               fprintf(stderr, "libgus: Unknown board revision (%02x)\n",
+                               gus.version);
+#endif
+               gus.version = GUS_CARD_VERSION_CLASSIC;
+               break;
+       }
+}
+
+static void __gus_detect_transfer()
+{
+       unsigned char *outbuff, *inbuff;
+       unsigned int i, j, seed = 0x13243546;
+       __gus_transfer_func func;
+
+#define TRANSFER_SIZE  0x4000
+
+       outbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
+       inbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
+
+       /* Suppose we have an malfunctioning GUS */
+       gus.transfer = NULL;
+
+       for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) {
+               switch (i) {
+                 case 0:
+                       gus.dma_rate = GF1M_DMAR_RATE0;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 1:
+                       gus.dma_rate = GF1M_DMAR_RATE1;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 2:
+                       gus.dma_rate = GF1M_DMAR_RATE2;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 3:
+                       gus.dma_rate = GF1M_DMAR_RATE3;
+                       func = __gus_transfer_dma;
+                       break;
+                 case 4:
+                       func = __gus_transfer_io;
+                       break;
+               }
+
+               /* Fill data array each time with pseudo-random values */
+               for (j = 0; j < TRANSFER_SIZE; j++)
+                       outbuff[j] = seed, seed =
+                         ((seed + 358979323) ^ (seed >> 16)) * 314159265;
+
+               /* Transfer the random array to GUS */
+               /* Poke a security fence around dest block */
+               __gus_poke(0x100 - 1, 0xAA);
+               __gus_poke(0x100 - 2, 0x55);
+               __gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA);
+               __gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55);
+
+               func(0x100, outbuff, TRANSFER_SIZE, 0);
+
+               if (__gus_wait_dma() == 0) {
+                       /* Check if the security fence was not damaged */
+                       if ((__gus_peek(0x100 - 1) != 0xAA)
+                               || (__gus_peek(0x100 - 2) != 0x55)
+                               || (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA)
+                               || (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55))
+                               continue;
+
+                       /* Now check if GUS DRAM really data that we expects to be transferred */
+                       __gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE);
+                       if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) {
+                               gus.transfer = func;
+                               break;
+                       }
+               }
+       }
+
+#undef TRANSFER_SIZE
+
+       MikMod_free(inbuff);
+       MikMod_free(outbuff);
+}
+
+static void __gus_detect_memory()
+{
+       unsigned int size;
+       for (size = 0; size < 1024; size += 256) {
+               __gus_poke(size * 1024, 0xaa);
+               if (__gus_peek(size * 1024) != 0xaa)
+                       break;
+               __gus_poke(size * 1024, 0x55);
+               if (__gus_peek(size * 1024) != 0x55)
+                       break;
+       }
+       gus.ram = size;
+}
+
+static void __gus_init()
+{
+       char *gusenv = getenv("ULTRASND");
+
+       memset((void *)&gus, 0, sizeof(gus));
+       gus.cmd_voice = -1;
+
+       if (!gusenv)
+               return;
+
+       sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1],
+                  &gus.irq[0], &gus.irq[1]);
+
+       /* A relaxed sanity check */
+       if ((gus.port < 0x100) || (gus.port > 0x1000)
+               || (gus.irq[0] < 2) || (gus.irq[0] > 15)
+               || (gus.irq[1] < 2) || (gus.irq[1] > 15)
+               || (gus.dma[0] < 0) || (gus.dma[0] > 7)
+               || (gus.dma[1] < 0) || (gus.dma[1] > 7))
+               return;
+
+       gus.voices = 32;
+       gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2;
+
+       /* Detect if the card is really there */
+       if (__gus_detect() == 0)
+               return;
+
+       /* Detect the version of Gravis Ultrasound */
+       __gus_detect_version();
+
+       /* Reset the card */
+       __gus_reset(1);
+
+       /* Detect the amount of on-board memory */
+       __gus_detect_memory();
+
+       gus.ok = 1;
+}
+
+static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset)
+{
+       unsigned char vc;
+
+       vc = GF1VC_IRQ;
+       if (wave->format & GUS_WAVE_16BIT)
+               vc |= GF1VC_DATA16;
+       if (wave->format & GUS_WAVE_BACKWARD)
+               vc |= GF1VC_BACKWARD;
+       if (wave->format & GUS_WAVE_LOOP) {
+               vc |= GF1VC_LOOP_ENABLE;
+               if (wave->format & GUS_WAVE_BIDIR)
+                       vc |= GF1VC_BI_LOOP;
+       }
+       __gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start);
+       if (wave->format & GUS_WAVE_LOOP)
+               __gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end);
+       else
+               __gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4);
+       __gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100);
+       __gus_outregb_slow(GF1R_VOICE_CONTROL, vc);
+}
+
+/* Timer 1 callback function (updates voices) */
+static void __gus_timer_update()
+{
+       gus_wave_t *wave;
+       unsigned long wave_offset;
+       unsigned char *src, *top;
+       unsigned int vmask = (1 << gus.cur_voice);
+
+       if (!gus.cmd_pool_ready)
+               return;
+
+       __gus_select_voice(gus.cur_voice);
+       wave_offset = 0;
+       src = gus.cmd_pool;
+       top = gus.cmd_pool + gus.cmd_pool_top;
+
+#define GET_B  *src
+#define GET_W  *((unsigned short *)src)
+#define GET_L  *((unsigned long *)src)
+
+       while (src < top) {
+               __gus_delay();
+               switch (GET_B++) {
+                 case PCMD_VOICE:
+                       __gus_select_voice(gus.cur_voice = GET_B++);
+                       vmask = (1 << gus.cur_voice);
+                       break;
+                 case PCMD_FREQ:
+               /*      __gus_outregw(GF1R_FREQUENCY, GET_W++);*/
+                       __gus_outregw(GF1R_FREQUENCY, *(unsigned short *)src);
+                       src += 2;
+                       break;
+                 case PCMD_PAN:
+                       __gus_outregb(GF1R_BALANCE, GET_B++);
+                       break;
+                 case PCMD_VOLUME:
+                       __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] =
+                                                       /*       GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);*/
+                                                 *(unsigned short *)src, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+                                                               src += 2;
+                       break;
+                 case PCMD_VOLUME_PREPARE:
+               /*      gus.cur_vol[gus.cur_voice] = GET_W++;*/
+                       gus.cur_vol[gus.cur_voice] = *(unsigned short *)src;
+                       src += 2;
+                       break;
+                 case PCMD_OFFSET:
+               /*      wave_offset = GET_L++;*/
+                       wave_offset = *(unsigned long *)src;
+                       src += 4;
+                       break;
+                 case PCMD_START:
+               /*      wave = (gus_wave_t *) GET_L++;*/
+                       wave = (gus_wave_t *) *(unsigned long *)src;
+                       src += 4;
+                       gus.cur_wave[gus.cur_voice] = wave;
+                       gus.kick_offs[gus.cur_voice] = wave_offset;
+                       if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) {
+                               __gus_kick(wave, wave_offset);
+                               __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice],
+                                                                        GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+                       } else
+                               gus.voice_kick[gus.cur_voice] = 1;
+                       wave_offset = 0;
+                       gus.eow_ignore |= vmask;
+                       break;
+                 case PCMD_STOP:
+                       /* If volume is close to nothing, abort immediately instead of
+                          ramping */
+                       gus.cur_vol[gus.cur_voice] = 0;
+                       gus.cur_wave[gus.cur_voice] = NULL;
+                       if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
+                               __gus_stop_voice();
+                       break;
+                 case PCMD_STOP_LOOP:
+                       __gus_outregb_slow(GF1R_VOICE_CONTROL,
+                                                          (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ)
+                                                          & ~GF1VC_LOOP_ENABLE);
+                       __gus_outregb_slow(GF1R_VOLUME_CONTROL,
+                                                          __gus_inregb(GF1R_VOLUME_CONTROL) &
+                                                          ~GF1VL_ROLLOVER);
+                       break;
+                 default:
+                       /* Alarm! Break out immediately */
+                       src = top;
+                       break;
+               }
+       }
+
+#undef GET_B
+#undef GET_W
+#undef GET_L
+
+       gus.cmd_pool_ready = 0;
+       gus.cmd_pool_top = 0;
+}
+
+static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl,
+                                                                  unsigned int volume_ctl)
+{
+       gus_wave_t *wave = gus.cur_wave[voice];
+
+       if (!wave || !(wave->format & GUS_WAVE_LOOP)) {
+               __gus_stop_voice();
+               gus.cur_wave[voice] = NULL;
+               gus.cur_vol[voice] = 0;
+               if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
+                       __gus_stop_voice();
+       }
+}
+
+static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl,
+                                                               unsigned int volume_ctl)
+{
+       __gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+       if (!gus.cur_wave[voice])
+               __gus_stop_voice();
+       else if (gus.voice_kick[voice])
+               __gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]);
+       gus.voice_kick[voice] = 0;
+}
+
+/***************************************************** GUS memory manager *****/
+
+/* Mark all GUS memory as available */
+static void __gus_mem_clear()
+{
+       __gus_mcb *cur = gus.mcb;
+
+       while (cur) {
+               __gus_mcb *next = cur->next;
+               if (cur != gus.mcb)
+                       MikMod_free(cur);
+               cur = next;
+       }
+
+       if (!gus.mcb)
+               gus.mcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+
+       gus.mcb->next = gus.mcb->prev = NULL;
+       gus.mcb->addr = 0;
+       gus.mcb->size = gus.ram * 1024;
+       gus.mcb->free = 1;
+}
+
+/* Return amount of free memory */
+static unsigned int __gus_mem_get_free()
+{
+       __gus_mcb *cur = gus.mcb;
+       unsigned int size = 0;
+
+       if (!gus.open)
+               return gus.ram * 1024;
+
+       while (cur) {
+               if (cur->free)
+                       size += cur->size;
+               cur = cur->next;
+       }
+
+       return size;
+}
+
+/* Return largest size for a 8-bit sample */
+static unsigned int __gus_mem_get_free_8()
+{
+       __gus_mcb *cur = gus.mcb;
+       unsigned int size = 0;
+
+       if (!gus.open)
+               return 0;
+
+       while (cur) {
+               if (cur->free && (cur->size > size))
+                       size = cur->size;
+               cur = cur->next;
+       }
+
+       return size;
+}
+
+/* Return largest size for a 16-bit sample */
+static unsigned int __gus_mem_get_free_16()
+{
+       __gus_mcb *cur = gus.mcb;
+       unsigned int size = 0;
+
+       if (!gus.open)
+               return 0;
+
+       while (cur) {
+               if (cur->free) {
+                       unsigned int size16 = cur->size;
+                       unsigned int tmp;
+                       /* 16-bit samples cannot cross 256K boundaries */
+                       tmp = 0x40000 - (cur->addr & 0x3ffff);
+                       if (size16 > tmp)
+                               size16 = tmp;
+                       /* 16-bit samples should be aligned on a 32-byte boundary */
+                       size16 -= (32 - cur->addr) & 0x1f;
+
+                       if (size16 > size)
+                               size = size16;
+
+                       /* Now try vice versa: skip a portion of aligned memory */
+                       size16 =
+                         (cur->addr + cur->size) - ((cur->addr + 0x3ffff) & ~0x3ffff);
+                       if ((size16 < 0x7fffffff) && (size16 > size))
+                               size = size16;
+               }
+               cur = cur->next;
+       }
+
+       return size;
+}
+
+/* Allocate a segment of GUS DRAM for a sample with given bits per sample.
+ * The algorithm tries to find the smallest free block that fits requested
+ * size; but if found free block is larger by some (large) delta than
+ * requested block size, the largest possible block is preffered.
+ */
+static unsigned int __gus_mem_alloc(unsigned int size, int bits16)
+{
+       __gus_mcb *cur = gus.mcb;
+       __gus_mcb *best_max = NULL, *best_min = NULL;
+       unsigned int best_max_delta = 0, best_min_delta = 0xffffffff;
+       unsigned int best_max_prefix = 0, best_min_prefix = 0;
+       unsigned int memaddr, memsize;
+
+       if (!gus.open || !size || (bits16 && size > 0x40000))
+               return -1;
+
+       /* Round block size up to nearest acceptable DMA bound */
+       if (bits16)
+               size = (size + 0x1f) & ~0x1f;
+       else
+               size = (size + 0x0f) & ~0x0f;
+
+       while (cur) {
+               if (cur->free) {
+                       unsigned char fits = 0;
+
+                       memsize = cur->size;
+                       memaddr = cur->addr;
+
+                       if (bits16) {
+                               /* 16-bit samples cannot cross 256K boundaries */
+                               unsigned int tmp = 256 * 1024 - (memaddr & 0x3ffff);
+                               if (memsize > tmp)
+                                       memsize = tmp;
+                               /* 16-bit samples should be aligned on a 32-byte boundary */
+                               memsize -= (32 - memaddr) & 0x1f;
+                               memaddr = (memaddr + 0x1f) & ~0x1f;
+                       }
+
+                       /* If block fits, analyze it */
+                       if (size <= memsize)
+                               fits = 1;
+                       /* Look if we still can complete the request by creating a free
+                          block */
+                       else if (size <= cur->size) {
+                               /* Align start address to next 256k boundary */
+                               unsigned int endaddr = cur->addr + cur->size;
+                               memaddr = (cur->addr + 0x3ffff) & ~0x3ffff;
+                               /* Can we split current block by inserting a free block at the
+                                  beginning? */
+                               if ((memaddr < endaddr) && (memaddr + size <= endaddr))
+                                       fits = 1;
+                       }
+
+                       if (fits) {
+                               unsigned int size_delta = cur->size - size;
+                               unsigned int size_prefix = memaddr - cur->addr;
+                               if (size_delta < best_min_delta)
+                                       best_min = cur, best_min_delta =
+                                         size_delta, best_min_prefix = size_prefix;
+                               if (size_delta > best_max_delta)
+                                       best_max = cur, best_max_delta =
+                                         size_delta, best_max_prefix = size_prefix;
+                       }
+               }
+
+               cur = cur->next;
+       }
+
+       if (!best_min)
+               return -1;
+
+       /* If minimal block that fits is too large, use largest block that fits */
+       /* But if using the maximal block is going to create a small hole, forget
+          it */
+       if ((best_max_prefix == 0)
+               || (best_max_prefix >= DRAM_HOLE_THRESHOLD)
+               || (best_min_prefix != 0))
+               if (
+                       ((best_min_delta < DRAM_HOLE_THRESHOLD) &&
+                        (best_max_delta >= DRAM_HOLE_THRESHOLD)) ||
+                       ((best_min_prefix > 0) && (best_min_prefix < DRAM_HOLE_THRESHOLD)
+                        && ((best_max_prefix == 0) ||
+                                (best_max_prefix > best_min_prefix))) ||
+                       ((best_min_prefix != 0) && (best_max_prefix == 0))) {
+                       best_min = best_max;
+                       best_min_delta = best_max_delta;
+                       best_min_prefix = best_max_prefix;
+               }
+
+       /* Compute the DRAM address to return */
+       memaddr = best_min->addr + best_min_prefix;
+       if (bits16)
+               memaddr = (memaddr + 0x1f) & ~0x1f;
+       else
+               memaddr = (memaddr + 0x0f) & ~0x0f;
+
+       /* If we have a considerable hole at the beginning of sample,
+          create a free node describing the hole */
+       if (memaddr - best_min->addr >= DRAM_SPLIT_THRESHOLD) {
+               __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+               newmcb->prev = best_min->prev;
+               newmcb->next = best_min;
+               newmcb->addr = best_min->addr;
+               newmcb->size = memaddr - best_min->addr;
+               newmcb->free = 1;
+               best_min->addr = memaddr;
+               best_min->size -= newmcb->size;
+               best_min->prev = newmcb;
+               if (newmcb->prev)
+                       newmcb->prev->next = newmcb;
+       }
+
+       /* Compute the size of hole at the end of block */
+       memsize = (best_min->addr + best_min->size) - (memaddr + size);
+
+       /* Split the block if the block is larger than requested amount */
+       if (memsize > DRAM_SPLIT_THRESHOLD) {
+               /* The next node cannot be free since free blocks are always glued
+                  together */
+               __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+               best_min->size -= memsize;
+               newmcb->prev = best_min;
+               newmcb->next = best_min->next;
+               newmcb->addr = best_min->addr + best_min->size;
+               newmcb->size = memsize;
+               newmcb->free = 1;
+               if (best_min->next)
+                       best_min->next->prev = newmcb;
+               best_min->next = newmcb;
+       }
+       best_min->free = 0;
+
+       return memaddr;
+}
+
+static void __gus_mem_free(unsigned int addr)
+{
+       __gus_mcb *cur = gus.mcb;
+       while (cur) {
+               if (!cur->free && (cur->addr <= addr) &&
+                       (cur->addr + cur->size > addr)) {
+                       cur->free = 1;
+
+                       /* If next block is free as well, link them together */
+                       if (cur->next && cur->next->free) {
+                               __gus_mcb *next = cur->next;
+                               cur->size += next->size;
+                               cur->next = next->next;
+                               if (next->next)
+                                       next->next->prev = cur;
+                               MikMod_free(next);
+                       }
+
+                       /* If previous block is free, link current block with it */
+                       if (cur->prev && cur->prev->free) {
+                               cur->prev->size += cur->size;
+                               cur->prev->next = cur->next;
+                               if (cur->next)
+                                       cur->next->prev = cur->prev;
+                               MikMod_free(cur);
+                       }
+                       return;
+               }
+               cur = cur->next;
+       }
+}
+
+static void __gus_mem_pack()
+{
+}
+
+#ifdef MIKMOD_DEBUG
+
+/* Debug dump of GUS DRAM heap */
+void __gus_mem_dump()
+{
+       __gus_mcb *cur = gus.mcb;
+       fprintf(stderr, "/-- Offset --+-- Prev --+-- Size --+-- Free --\\\n");
+       while (cur) {
+               fprintf(stderr, "|  %08X  | %08X |  %6d  |   %s    |\n",
+                               cur->addr, cur->prev ? cur->prev->addr : -1, cur->size,
+                               cur->free ? "yes" : " no");
+               cur = cur->next;
+       }
+       fprintf(stderr, "\\------------+----------+----------+----------/\n");
+}
+
+#endif
+
+/************************************************** Middle-level routines *****/
+
+static int __gus_instrument_free(gus_instrument_t * instrument)
+{
+       gus_instrument_t **cur_instr;
+       gus_layer_t *cur_layer;
+       gus_wave_t *cur_wave, *wave_head;
+
+       /* Remove the instrument from the list of registered instruments */
+       cur_instr = (gus_instrument_t **) & gus.instr;
+       while (*cur_instr) {
+               if (*cur_instr == instrument) {
+                       *cur_instr = instrument->next;
+                       goto instr_loaded;
+               }
+               cur_instr = &(*cur_instr)->next;
+       }
+       return -1;
+
+instr_loaded:
+       wave_head = NULL;
+       for (cur_layer = instrument->info.layer; cur_layer;
+                cur_layer = cur_layer->next)
+               /* Free all waves */
+               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
+                       if (!wave_head)
+                               wave_head = cur_wave;
+                       if (cur_wave->begin.memory != (unsigned int)-1)
+                               __gus_mem_free(cur_wave->begin.memory);
+               }
+       if (wave_head)
+               MikMod_free(wave_head);
+
+       MikMod_free(instrument->info.layer);
+       if (instrument->name)
+               MikMod_free(instrument->name);
+       MikMod_free(instrument);
+       return 0;
+}
+
+static gus_instrument_t *__gus_instrument_get(int program)
+{
+       gus_instrument_t *cur_instr = (gus_instrument_t *) gus.instr;
+       while (cur_instr) {
+               if (cur_instr->number.instrument == program)
+                       return cur_instr;
+               cur_instr = cur_instr->next;
+       }
+       return NULL;
+}
+
+static gus_instrument_t *__gus_instrument_copy(gus_instrument_t * instrument)
+{
+       gus_instrument_t **cur_instr, *instr;
+       gus_layer_t *cur_layer, *dest_layer;
+       gus_wave_t *cur_wave, *dest_wave;
+       unsigned int waves, layers;
+
+       if (!instrument || !instrument->info.layer || !gus.open)
+               return NULL;
+
+       if (__gus_instrument_get(instrument->number.instrument))
+               return NULL;
+
+       instr = (gus_instrument_t *) MikMod_malloc(sizeof(gus_instrument_t));
+       *instr = *instrument;
+
+       if (instrument->name)
+               instr->name = MikMod_strdup(instrument->name);
+
+       /* Make a copy of all layers at once */
+       for (layers = 0, cur_layer = instrument->info.layer; cur_layer; layers++)
+               cur_layer = cur_layer->next;
+
+       if (!(dest_layer = instr->info.layer = (gus_layer_t *) MikMod_malloc(sizeof(gus_layer_t) * layers))) {
+               if (instr->name)
+                       MikMod_free(instr->name);
+               MikMod_free(instr);
+               return NULL;
+       }
+       for (waves = 0, cur_layer = instrument->info.layer; cur_layer;
+                cur_layer = cur_layer->next) {
+               *dest_layer = *cur_layer;
+               dest_layer->wave = NULL;
+               /* Count the total number of waves */
+               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next)
+                       waves++;
+               if (cur_layer->next)
+                       dest_layer->next = dest_layer + 1;
+               else
+                       dest_layer->next = NULL;
+               dest_layer++;
+       }
+
+       /* Allocate memory for waves */
+       if (!(dest_wave = (gus_wave_t *) MikMod_malloc(sizeof(gus_wave_t) * waves))) {
+               MikMod_free(instr->info.layer);
+               if (instr->name)
+                       MikMod_free(instr->name);
+               MikMod_free(instr);
+               return NULL;
+       }
+       for (cur_layer = instrument->info.layer, dest_layer = instr->info.layer;
+            cur_layer; cur_layer = cur_layer->next, dest_layer = dest_layer->next)
+               /* Copy all waves */
+               for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
+                       if (!dest_layer->wave)
+                               dest_layer->wave = dest_wave;
+
+                       *dest_wave = *cur_wave;
+                       /* Mark DRAM address as unallocated */
+                       dest_wave->begin.memory = -1;
+
+                       if (cur_wave->next)
+                               dest_wave->next = (dest_wave + 1);
+                       else
+                               dest_wave->next = NULL;
+                       dest_wave++;
+               }
+
+       /* Insert the instrument into list of registered instruments */
+       cur_instr = (gus_instrument_t **) & gus.instr;
+       while (*cur_instr)
+               cur_instr = &(*cur_instr)->next;
+       *cur_instr = instr;
+
+       return instr;
+}
+
+static void __gus_instruments_clear()
+{
+       gus_instrument_t *next_instr, *cur_instr = (gus_instrument_t *) gus.instr;
+       while (cur_instr) {
+               next_instr = cur_instr->next;
+               __gus_instrument_free(cur_instr);
+               cur_instr = next_instr;
+       }
+}
+
+/******************************************************* libGUS interface *****/
+
+/* return value: number of GUS cards installed in system */
+int gus_cards()
+{
+       if (!gus.ok)
+               __gus_init();
+       return gus.ok ? 1 : 0;
+}
+
+int gus_info(gus_info_t * info, int reread)
+{
+       if (!gus.ok)
+               __gus_init();
+       if (!gus.ok)
+               return -1;
+
+       strcpy((char *)info->id, "gus0");
+       info->flags = (gus.ram ? GUS_STRU_INFO_F_PCM : 0);
+       info->version = gus.version;
+       info->port = gus.port;
+       info->irq = gus.irq[0];
+       info->dma1 = gus.dma[0];
+       info->dma2 = gus.dma[1];
+
+       info->mixing_freq = gus.freq;
+
+       info->memory_size = gus.ram * 1024;
+       info->memory_free = __gus_mem_get_free();
+       info->memory_block_8 = __gus_mem_get_free_8();
+       info->memory_block_16 = __gus_mem_get_free_16();
+       return 0;
+}
+
+int gus_open(int card, size_t queue_buffer_size, int non_block)
+{
+       __dpmi_meminfo struct_info, pool_info;
+
+       if (!gus.ok)
+               __gus_init();
+
+       if (!gus.ok || gus.open || card != 0)
+               return -1;
+
+       /* Now lock the gus structure in memory */
+       struct_info.address = __djgpp_base_address + (unsigned long)&gus;
+       struct_info.size = sizeof(gus);
+       if (__dpmi_lock_linear_region(&struct_info))
+               return -1;
+
+       /* And hook the GF1 interrupt */
+       __irq_stack_count = 4;
+       gus.gf1_irq =
+         irq_hook(gus.irq[0], gf1_irq, (long)gf1_irq_end - (long)gf1_irq);
+       __irq_stack_count = 1;
+       if (!gus.gf1_irq) {
+               __dpmi_unlock_linear_region(&struct_info);
+               return -1;
+       }
+
+       /* Enable the interrupt */
+       irq_enable(gus.gf1_irq);
+       if (gus.irq[0] > 7)
+               _irq_enable(2);
+
+       /* Allocate a DMA buffer: if we fail, we just use I/O so don't fail */
+       if ((gus.transfer == NULL) || (gus.transfer == __gus_transfer_dma))
+               gus.dma_buff = dma_allocate(gus.dma[0], GF1_DMA_BUFFER_SIZE);
+       else
+               gus.dma_buff = NULL;
+
+       /* Detect the best available RAM -> DRAM transfer function */
+       if (!gus.transfer) {
+               __gus_detect_transfer();
+               if (gus.transfer != __gus_transfer_dma || !gus.transfer)
+                       dma_free(gus.dma_buff), gus.dma_buff = NULL;
+
+               /* If no transfer function worked, fail */
+               if (!gus.transfer) {
+                       if (gus.dma_buff) {
+                               dma_free(gus.dma_buff);
+                               gus.dma_buff = NULL;
+                       }
+                       __dpmi_unlock_linear_region(&struct_info);
+                       irq_unhook(gus.gf1_irq);
+                       gus.gf1_irq = NULL;
+                       return -1;
+               }
+       }
+
+       /* Allocate and lock command pool buffer */
+       if (queue_buffer_size < 64)
+               queue_buffer_size = 64;
+       if (queue_buffer_size > 16384)
+               queue_buffer_size = 16384;
+       gus.cmd_pool = (unsigned char *) MikMod_malloc(queue_buffer_size);
+       pool_info.address = __djgpp_base_address + (unsigned long)&gus.cmd_pool;
+       pool_info.size = sizeof(queue_buffer_size);
+       if (__dpmi_lock_linear_region(&pool_info)) {
+               if (gus.dma_buff) {
+                       dma_free(gus.dma_buff);
+                       gus.dma_buff = NULL;
+               }
+               __dpmi_unlock_linear_region(&struct_info);
+               irq_unhook(gus.gf1_irq);
+               gus.gf1_irq = NULL;
+               return -1;
+       }
+
+       gus.open++;
+
+       __gus_mem_clear();
+       gus.t1_callback = __gus_timer_update;
+       gus.wt_callback = __gus_wavetable_update;
+       gus.vl_callback = __gus_volume_update;
+       gus_do_tempo(60);                       /* Default is 60 Hz */
+
+       return 0;
+}
+
+int gus_close(int card)
+{
+       __dpmi_meminfo struct_info;
+
+       if (!gus.open || card != 0)
+               return -1;
+
+       /* First reset the card: disable any operation it can currently perform */
+       __gus_reset(0);
+
+       gus.open--;
+
+       /* Stop the timer */
+       gus_timer_stop();
+
+       /* Free DMA buffer if used */
+       if (gus.dma_buff) {
+               dma_free(gus.dma_buff);
+               gus.dma_buff = NULL;
+       }
+
+       /* And unhook the GF1 interrupt */
+       irq_unhook(gus.gf1_irq);
+       gus.gf1_irq = NULL;
+
+       /* Unlock the gus structure */
+       struct_info.address = __djgpp_base_address + (unsigned long)&gus;
+       struct_info.size = sizeof(gus);
+       __dpmi_unlock_linear_region(&struct_info);
+
+       __gus_mem_clear();
+       __gus_instruments_clear();
+
+       return 0;
+}
+
+int gus_select(int card)
+{
+       if (!gus.open || (card != 0))
+               return -1;
+
+       return 0;
+}
+
+/* return value: same as gus_reset function
+   note: this command doesn't change number of active voices and doesn't do
+   hardware reset */
+int gus_reset_engine_only()
+{
+       gus.timer_base = 100;
+       return 0;
+}
+
+int gus_reset(int voices, unsigned int channel_voices)
+{
+       static unsigned short freq_table[32 - 14 + 1] = {
+               44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
+               25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
+       };
+       int voice;
+       int timer;
+
+       /* No support for dynamically allocated voices for now */
+       gus.dynmask = channel_voices;
+
+       if (voices < 14)
+               voices = 14;
+       if (voices > 32)
+               voices = 32;
+
+       /* Stop the timer so that GUS IRQ won't clobber registers */
+       timer = (gus.timer_ctl_reg & GF1M_TIMER1);
+       if (timer)
+               gus_timer_stop();
+
+       /* Stop all voices */
+       for (voice = 0; voice < 32; voice++) {
+               __gus_select_voice(voice);
+               __gus_stop_voice();
+               gus.cur_wave[voice] = NULL;
+               gus.cur_vol[voice] = 0;
+
+               __gus_delay();
+
+               /* Reset voice parameters to reasonable values */
+               __gus_set_current(0, 0);
+               __gus_set_loop_start(0, 0);
+               __gus_set_loop_end(0, 0);
+               __gus_outregw(GF1R_VOLUME, 0);
+               __gus_outregb(GF1R_VOLUME_RATE, 0);
+               __gus_outregb(GF1R_VOLUME_START, 0);
+               __gus_outregb(GF1R_VOLUME_END, 0);
+               __gus_outregb(GF1R_BALANCE, 0x7);
+       }
+
+       voice = (__gus_inregb(GF1R_VOICES) & 0x1f) + 1;
+
+       if (voice != voices) {
+               int reset = __gus_inregb(GF1R_RESET);
+               __gus_outregb(GF1R_RESET, reset & ~GF1M_OUTPUT_ENABLE);
+               __gus_delay();
+               __gus_outregb(GF1R_VOICES, 0xc0 | (voices - 1));
+               __gus_delay();
+               __gus_outregb(GF1R_RESET, reset);
+       }
+
+       /* Compute the discretization frequence */
+       gus.voices = voices;
+       if (gus.interwave)
+               gus.freq = 44100;
+       else
+               gus.freq = freq_table[voices - 14];
+
+       gus_reset_engine_only();
+
+       if (timer)
+               gus_timer_continue();
+
+       return gus.voices;
+}
+
+int gus_do_flush()
+{
+       DEBUG_PRINT(("gus_do_flush: top = %d\n", gus.cmd_pool_top))
+         gus.cmd_pool_ready = 1;
+       return 0;
+}
+
+/* set new tempo */
+void gus_do_tempo(unsigned int tempo)
+{
+       DEBUG_PRINT(("gus_do_tempo (%d)\n", tempo))
+         gus_timer_tempo(tempo);
+       gus_timer_start();
+}
+
+/* set voice frequency in Hz */
+void gus_do_voice_frequency(unsigned char voice, unsigned int freq)
+{
+       DEBUG_PRINT(("gus_do_voice_frequency (%d, %d)\n", voice, freq))
+         __pool_select_voice(voice);
+       __pool_command_w(PCMD_FREQ,
+                                        (((freq << 9) + (gus.freq >> 1)) / gus.freq) << 1);
+}
+
+/* set voice pan (0-16384) (full left - full right) */
+void gus_do_voice_pan(unsigned char voice, unsigned short pan)
+{
+       DEBUG_PRINT(("gus_do_voice_pan (%d, %d)\n", voice, pan))
+         pan >>= 10;
+       if (pan > 15)
+               pan = 15;
+       __pool_select_voice(voice);
+       __pool_command_b(PCMD_PAN, pan);
+}
+
+/* set voice volume level 0-16384 (linear) */
+void gus_do_voice_volume(unsigned char voice, unsigned short vol)
+{
+       DEBUG_PRINT(("gus_do_voice_volume (%d, %d)\n", voice, vol))
+         if (vol > 0x3fff)
+               vol = 0x3fff;
+       __pool_select_voice(voice);
+       __pool_command_w(PCMD_VOLUME, __gus_volume_table[vol >> 5]);
+}
+
+/* start voice
+ *   voice    : voice #
+ *   program  : program # or ~0 = current
+ *   freq     : frequency in Hz
+ *   volume   : volume level (0-16384) or ~0 = current
+ *   pan      : pan level (0-16384) or ~0 = current
+ */
+void gus_do_voice_start(unsigned char voice, unsigned int program,
+                                               unsigned int freq, unsigned short volume,
+                                               unsigned short pan)
+{
+       gus_do_voice_start_position(voice, program, freq, volume, pan, 0);
+}
+
+/* start voice
+ *   voice    : voice #
+ *   program  : program # or ~0 = current
+ *   freq     : frequency in Hz
+ *   volume   : volume level (0-16384) or ~0 = current
+ *   pan      : pan level (0-16384) or ~0 = current
+ *   position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
+ */
+void gus_do_voice_start_position(unsigned char voice, unsigned int program,
+                                                                unsigned int freq, unsigned short volume,
+                                                                unsigned short pan, unsigned int position)
+{
+       gus_instrument_t *instrument;
+       gus_wave_t *wave;
+
+       DEBUG_PRINT(
+                               ("gus_do_voice_start_position (%d, %d, pos: %d)\n", voice,
+                                program, position))
+
+         instrument = __gus_instrument_get(program);
+
+       if (!instrument
+               || !instrument->info.layer
+               || !instrument->info.layer->wave
+               || instrument->flags == GUS_INSTR_F_NOT_FOUND
+               || instrument->flags == GUS_INSTR_F_NOT_LOADED) return;
+
+       gus_do_voice_frequency(voice, freq);
+       gus_do_voice_pan(voice, pan);
+
+       /* We have to set volume different way, to avoid unneeded work in handler */
+       if (volume > 0x3fff)
+               volume = 0x3fff;
+       __pool_command_w(PCMD_VOLUME_PREPARE, __gus_volume_table[volume >> 5]);
+
+       switch (instrument->mode) {
+         case GUS_INSTR_SIMPLE:
+               wave = instrument->info.layer->wave;
+               if (position)
+                       __pool_command_l(PCMD_OFFSET, position);
+               __pool_command_l(PCMD_START, (unsigned long)wave);
+               break;
+       }
+}
+
+/* stop voice
+ *   mode = 0 : stop voice now
+ *   mode = 1 : disable wave loop and finish it
+ */
+void gus_do_voice_stop(unsigned char voice, unsigned char mode)
+{
+       __pool_select_voice(voice);
+       if (mode)
+               __pool_command(PCMD_STOP_LOOP);
+       else
+               __pool_command(PCMD_STOP);
+}
+
+/* wait x ticks - this command is block separator
+   all commands between blocks are interpreted in the begining of one tick */
+void gus_do_wait(unsigned int ticks)
+{
+       DEBUG_PRINT(("gus_do_wait (%d)\n", ticks))
+
+         ticks += gus.t1_ticks;
+       while ((int)(ticks - gus.t1_ticks) > 0);
+}
+
+int gus_get_voice_status(int voice)
+{
+       __gus_select_voice(voice);
+       return __gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED ? 0 : 1;
+}
+
+/* return value: file handle (descriptor) for /dev/gus */
+int gus_get_handle()
+{
+       /* Return stdout handle so that select() will "work" with it */
+       return 0;
+}
+
+/* return value: zero if instrument was successfully allocated */
+int gus_memory_alloc(gus_instrument_t * instrument)
+{
+       gus_instrument_t *instr = __gus_instrument_copy(instrument);
+       gus_layer_t *cur_layer;
+       gus_wave_t *cur_wave;
+
+       DEBUG_PRINT(("gus_memory_alloc (%d)\n", instrument->number.instrument))
+
+         if (!instr)
+               return -1;
+
+       for (cur_layer = instr->info.layer; cur_layer;
+                cur_layer = cur_layer->next) for (cur_wave = cur_layer->wave;
+                                                                                  cur_wave;
+                                                                                  cur_wave = cur_wave->next) {
+                       if (cur_layer->mode == GUS_INSTR_SIMPLE) {
+                               cur_wave->begin.memory = __gus_mem_alloc(cur_wave->size,
+                                                                                                                cur_wave->format &
+                                                                                                                GUS_WAVE_16BIT);
+                               if (cur_wave->begin.memory == (unsigned int)-1) {
+                                       __gus_instrument_free(instr);
+                                       return -1;
+                               }
+                               gus.transfer(cur_wave->begin.memory, cur_wave->begin.ptr,
+                                                        cur_wave->size, cur_wave->format);
+                       } else if (cur_layer->mode == GUS_INSTR_PATCH)
+                               /* not supported yet */ ;
+               }
+
+       return 0;
+}
+
+/* return value: zero if instrument was successfully removed */
+int gus_memory_free(gus_instrument_t * instrument)
+{
+       gus_instrument_t *cur_instr = gus.instr;
+
+       DEBUG_PRINT(("gus_memory_free (%d)\n", instrument->number.instrument))
+
+         for (; cur_instr; cur_instr = cur_instr->next)
+               if (cur_instr->number.instrument == instrument->number.instrument)
+                       return __gus_instrument_free(cur_instr);
+
+       return -1;
+}
+
+/* return value: unused gus memory in bytes */
+int gus_memory_free_size()
+{
+       return __gus_mem_get_free();
+}
+
+/* return value: zero if success */
+int gus_memory_pack()
+{
+       __gus_mem_pack();
+       return 0;
+}
+
+/* return value: gus memory size in bytes */
+int gus_memory_size()
+{
+       return gus.ram * 1024;
+}
+
+/* return value: current largest free block for 8-bit or 16-bit wave */
+int gus_memory_free_block(int w_16bit)
+{
+       return w_16bit ? __gus_mem_get_free_16() : __gus_mem_get_free_8();
+}
+
+/* input value:        see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
+   return value: zero if samples & instruments was successfully removed        from
+   GF1 memory manager */
+int gus_memory_reset(int mode)
+{
+       __gus_mem_clear();
+       __gus_instruments_clear();
+       return 0;
+}
+
+/* return value: zero if command queue was successfully flushed */
+int gus_queue_flush()
+{
+       return 0;
+}
+
+/* input value: echo buffer size in items (if 0 - erase echo buffer) */
+int gus_queue_read_set_size(int items)
+{
+       return 0;
+}
+
+/* input value: write queue size in items (each item have 8 bytes) */
+int gus_queue_write_set_size(int items)
+{
+       return 0;
+}
+
+/* return value: zero if successfull */
+int gus_timer_start()
+{
+       gus.timer_ctl_reg |= GF1M_TIMER1;
+       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+
+       gus.timer_ctl = gus.timer_ctl & ~GF1M_MASK_TIMER1;
+       outportb(GF1_TIMER_CTRL, 0x04);
+       outportb(GF1_TIMER_DATA, gus.timer_ctl | GF1M_START_TIMER1);
+       return 0;
+}
+
+/* return value: zero if timer was stoped */
+int gus_timer_stop()
+{
+       gus.timer_ctl_reg &= ~GF1M_TIMER1;
+       __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+
+       gus.timer_ctl = gus.timer_ctl | GF1M_MASK_TIMER1;
+       outportb(GF1_TIMER_CTRL, 0x04);
+       outportb(GF1_TIMER_DATA, gus.timer_ctl);
+       return 0;
+}
+
+/* return value: zero if setup was success */
+int gus_timer_tempo(int ticks)
+{
+       unsigned int counter;
+
+       /* Limit ticks per second to 1..1000 range */
+       if (ticks < 1)
+               ticks = 1;
+       if (ticks > 1000)
+               ticks = 1000;
+
+       /* GF1 timer1 period is 80 usecs, 12500 times per second */
+       counter = 1250000 / (ticks * gus.timer_base);
+       gus.t1_multiple = 1;
+       while (counter > 255) {
+               counter >>= 1;
+               gus.t1_multiple <<= 1;
+       }
+       gus.t1_countdown = gus.t1_multiple;
+       __gus_outregb(GF1R_TIMER1, 256 - counter);
+       return 0;
+}
+
+/* return value: zero if timer will be continue */
+int gus_timer_continue()
+{
+       return gus_timer_start();
+}
+
+/* return value: zero if setup was success (default timebase = 100) */
+int gus_timer_base(int base)
+{
+       gus.timer_base = base;
+       return 0;
+}
+
+void gus_timer_callback(void (*timer_callback) ())
+{
+       gus.timer_callback = timer_callback;
+}
+
+void gus_convert_delta(unsigned int type, unsigned char *dest,
+                                          unsigned char *src, size_t size)
+{
+       if (!(type & GUS_WAVE_DELTA))
+               return;
+
+       /* This doesn't depend much on wave signedness, since addition/subtraction
+          do not depend on operand signedness */
+       if (type & GUS_WAVE_16BIT) {
+               unsigned short delta = type & GUS_WAVE_UNSIGNED ? 0x8000 : 0;
+               while (size--) {
+                       delta = *(unsigned short *)dest = *(unsigned short *)src + delta;
+                       src += sizeof(unsigned short);
+                       dest += sizeof(unsigned short);
+               }
+       } else {
+               unsigned char delta = type & GUS_WAVE_UNSIGNED ? 0x80 : 0;
+               while (size--) {
+                       delta = *(unsigned char *)dest = *(unsigned char *)src + delta;
+                       src++;
+                       dest++;
+               }
+       }
+}
+
+int gus_dma_usage (int use)
+{
+       if (gus.dma_buff)
+               return -1;
+       gus.transfer = __gus_transfer_io;
+       return 0;
+}
+
+#endif /* DRV_ULTRA */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosgus.h b/libs/mikmod/drivers/dos/dosgus.h
new file mode 100644 (file)
index 0000000..ae3488a
--- /dev/null
@@ -0,0 +1,514 @@
+/*     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$
+
+  libGUS-alike definitions for DOS
+
+==============================================================================*/
+
+#ifndef __DOSGUS_H__
+#define __DOSGUS_H__
+
+#include <pc.h>
+#include "dosdma.h"
+#include "dosirq.h"
+#include "libgus.h"
+
+/* Private header file for a libGUS-alike library for DOS */
+
+#define JOYSTICK_TIMER                 (gus.port+0x201)        /* 201 */
+#define JOYSTICK_DATA                  (gus.port+0x201)        /* 201 */
+
+#define GF1_MIDI_CTRL                  (gus.port+0x100)        /* 3X0 */
+#define GF1_MIDI_DATA                  (gus.port+0x101)        /* 3X1 */
+
+#define GF1_VOICESEL                   (gus.port+0x102)        /* 3X2 */
+#define GF1_REGSEL                     (gus.port+0x103)        /* 3X3 */
+#define GF1_DATA                       (gus.port+0x104)        /* 3X4 */
+#define GF1_DATA_LOW                   (gus.port+0x104)        /* 3X4 */
+#define GF1_DATA_HIGH                  (gus.port+0x105)        /* 3X5 */
+#define GF1_IRQ_STATUS                 (gus.port+0x006)        /* 2X6 */
+#define GF1_DRAM                       (gus.port+0x107)        /* 3X7 */
+
+#define GF1_MIX_CTRL                   (gus.port+0x000)        /* 2X0 */
+#define GF1_TIMER_CTRL                 (gus.port+0x008)        /* 2X8 */
+#define GF1_TIMER_DATA                 (gus.port+0x009)        /* 2X9 */
+#define GF1_IRQ_CTRL                   (gus.port+0x00B)        /* 2XB */
+#define GF1_REG_CTRL                   (gus.port+0x00F)        /* 2XF */
+
+#define GF1_REVISION                   (gus.port+0x506)        /* 7X6 */
+
+/* The GF1 hardware clock rate */
+#define CLOCK_RATE                     9878400L
+
+/* GF1 voice-independent registers */
+#define        GF1R_DMA_CONTROL                0x41
+#define        GF1R_DMA_ADDRESS                0x42
+#define        GF1R_DRAM_LOW                   0x43
+#define        GF1R_DRAM_HIGH                  0x44
+
+#define        GF1R_TIMER_CONTROL              0x45
+#define        GF1R_TIMER1                     0x46
+#define        GF1R_TIMER2                     0x47
+
+#define        GF1R_SAMPLE_RATE                0x48
+#define        GF1R_SAMPLE_CONTROL             0x49
+
+#define        GF1R_JOYSTICK                   0x4B
+#define        GF1R_RESET                      0x4C
+
+/* GF1 voice-specific registers */
+#define        GF1R_VOICE_CONTROL              0x00
+#define        GF1R_FREQUENCY                  0x01
+#define        GF1R_START_HIGH                 0x02
+#define        GF1R_START_LOW                  0x03
+#define        GF1R_END_HIGH                   0x04
+#define        GF1R_END_LOW                    0x05
+#define        GF1R_VOLUME_RATE                0x06
+#define        GF1R_VOLUME_START               0x07
+#define        GF1R_VOLUME_END                 0x08
+#define        GF1R_VOLUME                     0x09
+#define        GF1R_ACC_HIGH                   0x0a
+#define        GF1R_ACC_LOW                    0x0b
+#define        GF1R_BALANCE                    0x0c
+#define        GF1R_VOLUME_CONTROL             0x0d
+#define        GF1R_VOICES                     0x0e
+#define        GF1R_IRQ_SOURCE                 0x0f
+
+/* Add this to above registers for reading */
+#define GF1R_READ_MASK                 0x80
+
+/* MIDI */
+#define        GF1M_MIDI_RESET                 0x03
+#define        GF1M_MIDI_ENABLE_XMIT           0x20
+#define        GF1M_MIDI_ENABLE_RCV            0x80
+
+#define        GF1M_MIDI_RCV_FULL              0x01
+#define        GF1M_MIDI_XMIT_EMPTY            0x02
+#define        GF1M_MIDI_FRAME_ERR             0x10
+#define        GF1M_MIDI_OVERRUN               0x20
+#define        GF1M_MIDI_IRQ_PEND              0x80
+
+/* Joystick */
+#define        GF1M_JOY_POSITION               0x0f
+#define        GF1M_JOY_BUTTONS                0xf0
+
+/* GF1_IRQ_STATUS (port 2X6) */
+#define        GF1M_IRQ_MIDI_TX                0x01    /* pending MIDI xmit IRQ */
+#define        GF1M_IRQ_MIDI_RX                0x02    /* pending MIDI recv IRQ */
+#define        GF1M_IRQ_TIMER1                 0x04    /* general purpose timer */
+#define        GF1M_IRQ_TIMER2                 0x08    /* general purpose timer */
+#define        GF1M_IRQ_WAVETABLE              0x20    /* pending wavetable IRQ */
+#define        GF1M_IRQ_ENVELOPE               0x40    /* pending volume envelope IRQ */
+#define        GF1M_IRQ_DMA_COMPLETE           0x80    /* pending dma transfer complete IRQ */
+
+/* GF1_MIX_CTRL (port 2X0) */
+#define        GF1M_MIXER_NO_LINE_IN           0x01    /* 0: enable */
+#define        GF1M_MIXER_NO_OUTPUT            0x02    /* 0: enable */
+#define        GF1M_MIXER_MIC_IN               0x04    /* 1: enable */
+#define        GF1M_MIXER_GF1_IRQ              0x08    /* 1: enable */
+#define GF1M_GF1_COMBINED_IRQ          0x10    /* 1: IRQ1 == IRQ2 */
+#define        GF1M_MIDI_LOOPBACK              0x20    /* 1: enable loop back */
+#define        GF1M_CONTROL_SELECT             0x40    /* 0: DMA latches; 1: IRQ latches */
+
+/* Timer data register (2X9) */
+#define GF1M_START_TIMER1              0x01
+#define GF1M_START_TIMER2              0x02
+#define GF1M_MASK_TIMER1               0x20
+#define GF1M_MASK_TIMER2               0x40
+#define GF1M_TIMER_CLRIRQ              0x80
+
+/* IRQ/DMA control register (2XB) */
+#define GF1M_IRQ_EQUAL                 0x40
+#define GF1M_DMA_EQUAL                 0x40
+
+/* (0x41) DMA control register bits */
+#define        GF1M_DMAR_ENABLE                0x01    /* 1: go */
+#define        GF1M_DMAR_READ                  0x02    /* 1: read (->RAM), 0: write (->DRAM) */
+#define        GF1M_DMAR_CHAN16                0x04    /* 1: 16 bit, 0: 8 bit DMA channel */
+#define        GF1M_DMAR_RATE                  0x18    /* 00: fast, 11: slow */
+#define        GF1M_DMAR_IRQ_ENABLE            0x20    /* 1: enable */
+#define        GF1M_DMAR_IRQ_PENDING           0x40    /* R: DMA irq pending */
+#define        GF1M_DMAR_DATA16                0x40    /* W: 0: 8 bits; 1: 16 bits per sample */
+#define        GF1M_DMAR_TOGGLE_SIGN           0x80    /* W: 1: invert high bit */
+
+/* DMA transfer rate divisors */
+#define        GF1M_DMAR_RATE0                 0x00    /* Fastest DMA xfer (~650khz) */
+#define        GF1M_DMAR_RATE1                 0x08    /* fastest / 2 */
+#define        GF1M_DMAR_RATE2                 0x10    /* fastest / 4 */
+#define        GF1M_DMAR_RATE3                 0x18    /* Slowest DMA xfer (fastest / 8) */
+
+/* (0x45) Timer Control */
+#define GF1M_TIMER1                    0x04    /* Enable timer 1 IRQ */
+#define GF1M_TIMER2                    0x08    /* Enable timer 2 IRQ */
+
+/* (0x49) Sampling (ADC) control register */
+#define        GF1M_DMAW_ENABLE                0x01    /* 1: Start sampling */
+#define        GF1M_DMAW_MODE                  0x02    /* 0: mono, 1: stereo */
+#define        GF1M_DMAW_CHAN16                0x04    /* 0: 8 bit, 1: 16 bit */
+#define        GF1M_DMAW_IRQ_ENABLE            0x20    /* 1: enable IRQ */
+#define        GF1M_DMAW_IRQ_PENDING           0x40    /* 1: irq pending */
+#define        GF1M_DMAW_TOGGLE_SIGN           0x80    /* 1: invert sign bit */
+
+/* (0x4C) GF1 reset register */
+#define        GF1M_MASTER_RESET               0x01    /* 0: hold in reset */
+#define        GF1M_OUTPUT_ENABLE              0x02    /* 1: enable output */
+#define        GF1M_MASTER_IRQ                 0x04    /* 1: master IRQ enable */
+
+/* (0x0,0x80) Voice control register - GF1R_VOICE_CONTROL */
+#define        GF1VC_STOPPED                   0x01    /* 1: voice has stopped */
+#define        GF1VC_STOP                      0x02    /* 1: stop voice */
+#define        GF1VC_DATA16                    0x04    /* 0: 8 bit, 1: 16 bit */
+#define        GF1VC_LOOP_ENABLE               0x08    /* 1: enable */
+#define        GF1VC_BI_LOOP                   0x10    /* 1: bi directional looping */
+#define        GF1VC_IRQ                       0x20    /* 1: enable voice's wave irq */
+#define        GF1VC_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
+#define        GF1VC_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
+
+/* (0x01,0x81) Frequency control */
+/* Bit 0       - Unused */
+/* Bits        1-9     - Fractional portion */
+/* Bits        10-15   - Integer portion */
+
+/* (0x02,0x82) Accumulator start address - GF1R_START_HIGH */
+/* Bits        0-11    - HIGH 12 bits of address */
+/* Bits        12-15   - Unused */
+
+/* (0x03,0x83) Accumulator start address - GF1R_START_LOW */
+/* Bits        0-4     - Unused */
+/* Bits        5-8     - Fractional portion */
+/* Bits        9-15    - Low 7 bits of integer portion */
+
+/* (0x04,0x84) Accumulator end address - GF1R_END_HIGH */
+/* Bits        0-11    - HIGH 12 bits of address */
+/* Bits        12-15   - Unused */
+
+/* (0x05,0x85) Accumulator end address - GF1R_END_LOW */
+/* Bits        0-4     - Unused */
+/* Bits        5-8     - Fractional portion */
+/* Bits        9-15    - Low 7 bits of integer portion */
+
+/* (0x06,0x86) Volume Envelope control register - GF1R_VOLUME_RATE */
+#define        GF1VL_RATE_MANTISSA             0x3f
+#define        GF1VL_RATE_RANGE                0xC0
+
+/* (0x07,0x87) Volume envelope start - GF1R_VOLUME_START */
+#define        GF1VL_START_MANT                0x0F
+#define        GF1VL_START_EXP                 0xF0
+
+/* (0x08,0x88) Volume envelope end - GF1R_VOLUME_END */
+#define        GF1VL_END_MANT                  0x0F
+#define        GF1VL_END_EXP                   0xF0
+
+/* (0x09,0x89) Current volume register - GF1R_VOLUME */
+/* Bits        0-3     - Unused */
+/* Bits        4-11    - Mantissa of current volume */
+/* Bits        10-15   - Exponent of current volume */
+
+/* (0x0A,0x8A) Accumulator value (high) */
+/* Bits        0-12    - HIGH 12 bits of current position (a19-a7) */
+
+/* (0x0B,0x8B) Accumulator value (low) */
+/* Bits        0-8     - Fractional portion */
+/* Bits        9-15    - Integer portion of low adress (a6-a0) */
+
+/* (0x0C,0x8C) Pan (balance) position */
+/* Bits        0-3     - Balance position 0=full left, 0x0f=full right */
+
+/* (0x0D,0x8D) Volume control register - GF1R_VOLUME_CONTROL */
+#define        GF1VL_STOPPED                   0x01    /* volume has stopped */
+#define        GF1VL_STOP                      0x02    /* stop volume */
+#define        GF1VL_ROLLOVER                  0x04    /* Roll PAST end & gen IRQ */
+#define        GF1VL_LOOP_ENABLE               0x08    /* 1: enable */
+#define        GF1VL_BI_LOOP                   0x10    /* 1: bi directional looping */
+#define        GF1VL_IRQ                       0x20    /* 1: enable voice's volume irq */
+#define        GF1VL_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
+#define        GF1VL_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
+
+/* (0x0E,0x8E) Number of active voices */
+/* Bits        0-5     - Number of active voices - 1 */
+
+/* (0x0F,0x8F) Sources of IRQs */
+/* Bits        0-4     - interrupting voice number */
+/* Bit 5       - Always a 1 */
+#define        GF1IRQ_VOLUME                   0x40    /* individual voice irq bit */
+#define        GF1IRQ_WAVE                     0x80    /* individual waveform irq bit */
+
+/* Commands are pooled and executed ON TIMER (1st timer) interrupt.
+ * Currently there is a limit on the number of commands that you can
+ * issue between gus_do_flush (...); this should not be an issue however
+ * because each voice has a limited (little) set of parameters that
+ * you can change (freq, vol, pan... what else?)
+ *
+ * The pool is a pseudo-CPU code that gets executed once per timer interrupt.
+ */
+
+/* Below are definitions for commands placed in GUS command pool */
+#define PCMD_NOP                       0x00    /* Traditionally ... */
+#define PCMD_VOICE                     0x01    /* +B: select voice */
+#define PCMD_START                     0x02    /* +L: start voice */
+#define PCMD_STOP                      0x03    /*     stop voice */
+#define PCMD_FREQ                      0x04    /* +W: set frequence */
+#define PCMD_VOLUME                    0x05    /* +W: set volume */
+#define PCMD_VOLUME_PREPARE            0x06    /* +W: prepare to set volume on (soon to follow) kick */
+#define PCMD_PAN                       0x07    /* +B: set panning */
+#define PCMD_OFFSET                    0x08    /* +L: set DRAM offset */
+#define PCMD_STOP_LOOP                 0x09    /*     stop looping */
+
+#define GUS_VOLCHANGE_RAMP             0x20    /* Volume change ramp speed */
+
+/* Definition for the boolean type */
+typedef unsigned char boolean;
+/* Prototype for functions that do block transfers to GUS DRAM:
+   flags can contain any of the following bits:
+   GUS_WAVE_16BIT    - sample is 16-bit
+   GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
+ */
+typedef void (*__gus_transfer_func) (unsigned long address,
+                                     unsigned char *source,
+                                     unsigned long size, int flags);
+typedef void (*__gus_callback) ();
+typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
+
+/* Structure used to keep track of all on-board GUS memory */
+typedef struct __struct_gus_mcb {
+       struct __struct_gus_mcb *next;          /* Next MCB in chain */
+       struct __struct_gus_mcb *prev;          /* Previous MCB in chain */
+       unsigned int addr;                      /* GUS DRAM address */
+       unsigned int size;                      /* Memory block size */
+       int free;                               /* 1: block is free */
+} __gus_mcb;
+
+/* Structure defining overall GUS state/information */
+typedef struct __gus_state_s {
+       unsigned int port;                      /* Base I/O port (0x220, 0x240, ...) */
+       unsigned int irq[2];                    /* GF1 IRQ and MIDI IRQ */
+       unsigned int dma[2];                    /* Play / record DMA */
+       unsigned int ram;                       /* Memory size (K), i.e. 256, 1024 etc */
+       unsigned int version;                   /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
+       unsigned int freq;                      /* Current mixing frequency */
+       unsigned int voices;                    /* Active voices (14-32) */
+       unsigned int dynmask;                   /* Dynamically allocated voices mask */
+       unsigned int timer_base;                /* The relative timer speed in percents (def: 100) */
+       volatile unsigned int t1_ticks;         /* Incremented per each timer1 tick */
+       volatile unsigned int t2_ticks;         /* Incremented per each timer2 tick */
+       volatile unsigned int t1_countdown;     /* t1_callback is called when this reaches zero */
+       volatile unsigned int t2_countdown;     /* t2_callback is called when this reaches zero */
+       unsigned int t1_multiple;               /* Timer1 handler is called once per such many ticks */
+       unsigned int t2_multiple;               /* Timer2 handler is called once per such many ticks */
+       struct irq_handle *gf1_irq;             /* The interrupt handler for GF1 events */
+       dma_buffer *dma_buff;                   /* Pre-allocated DMA buffer */
+       __gus_callback dma_callback;            /* Routine called at end of DMA transfers */
+       __gus_callback t1_callback;             /* Routine called on Timer1 events */
+       __gus_callback t2_callback;             /* Routine called on Timer1 events */
+       __gus_callback timer_callback;          /* Called once per TEMPO ticks */
+       __gus_callback_3 wt_callback;           /* Routine called on WaveTable events */
+       __gus_callback_3 vl_callback;           /* Routine called on Volume ramp events */
+       __gus_mcb *mcb;                         /* Chained list of memory control blocks */
+       __gus_transfer_func transfer;           /* Best working function for DRAM transfer */
+       gus_instrument_t *instr;                /* The list of registered instruments */
+       unsigned short mixer;                   /* Current mixer register state */
+       unsigned char dma_rate;                 /* One of GF1M_DMAR_RATEX constants defined above */
+       unsigned char timer_ctl;                /* Timer control register value (2x8/2x9) */
+       unsigned char timer_ctl_reg;            /* Timer control register value (GF1/0x45) */
+       boolean ok;                             /* Is the information below okay? */
+       boolean open;                           /* 1 if between gus_open() and gus_close() */
+       boolean ics;                            /* Is it equipped with an ICS mixer? */
+       boolean ics_flipped;                    /* rev 5 (3.7) has flipped R/L mixer */
+       boolean codec;                          /* Is it equipped with a GUS MAX codec? */
+       boolean interwave;                      /* GUS InterWave card */
+       volatile boolean dma_active;            /* DMA is transferring data */
+       volatile boolean cmd_pool_ready;        /* Flush cmd_pool during timer interrupt */
+       unsigned char cmd_voice;                /* Pool selection index cache */
+       unsigned int cmd_pool_top;              /* Command pool top */
+       unsigned char *cmd_pool;                /* Async commands pool */
+       /* The following data is for private use only by interrupt routines! */
+       gus_wave_t *cur_wave[32];               /* Currently played waves */
+       boolean voice_kick[32];                 /* Kick wave on next volume ramp IRQ */
+       unsigned int kick_offs[32];             /* Sample start position on kick */
+       unsigned short cur_vol[32];             /* Current voice volumes */
+       unsigned int cur_voice;                 /* Current voice */
+       unsigned int eow_ignore;                /* Temp ignore end-of-wave IRQ for these voices */
+} __gus_state;
+
+extern __gus_state gus;
+extern void __gus_delay();
+
+static unsigned long __gus_convert_addr16(unsigned long address)
+{
+       return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
+}
+
+/* The XXX_slow routines cannot be used outside IRQ handler! */
+static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportb(GF1_DATA_HIGH, value);
+       __gus_delay();
+       outportb(GF1_DATA_HIGH, value);
+}
+
+static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportw(GF1_DATA, value);
+       __gus_delay();
+       outportw(GF1_DATA, value);
+}
+
+static inline void __gus_outregb(unsigned char reg, unsigned char value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportb(GF1_DATA_HIGH, value);
+}
+
+static inline void __gus_outregw(unsigned char reg, unsigned short value)
+{
+       outportb(GF1_REGSEL, reg);
+       outportw(GF1_DATA, value);
+}
+
+static inline unsigned char __gus_inregb(unsigned char reg)
+{
+       if (reg < 0x10)
+               reg |= GF1R_READ_MASK;
+       outportb(GF1_REGSEL, reg);
+       return inportb(GF1_DATA_HIGH);
+}
+
+static inline unsigned short __gus_inregw(unsigned char reg)
+{
+       if (reg < 0x10)
+               reg |= GF1R_READ_MASK;
+       outportb(GF1_REGSEL, reg);
+       return inportw(GF1_DATA);
+}
+
+static inline void __gus_set_dram_address(unsigned int address)
+{
+       __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+       __gus_outregw(GF1R_DRAM_LOW, address);
+}
+
+static inline unsigned char __gus_peek(unsigned int address)
+{
+       __gus_set_dram_address(address);
+       return inportb(GF1_DRAM);
+}
+
+static inline void __gus_poke(unsigned int address, unsigned char value)
+{
+       __gus_set_dram_address(address);
+       outportb(GF1_DRAM, value);
+}
+
+static inline void __gus_select_voice(unsigned char voice)
+{
+       outportb(GF1_VOICESEL, voice);
+}
+
+static inline void __gus_set_current(unsigned char mode,
+                                     unsigned long address)
+{
+       if (mode & GF1VC_DATA16)
+               address = __gus_convert_addr16(address);
+       __gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
+       __gus_outregw_slow(GF1R_ACC_LOW, address << 5);
+}
+
+static inline void __gus_set_loop_start(unsigned char mode,
+                                                                               unsigned long address)
+{
+       if (mode & GF1VC_DATA16)
+               address = __gus_convert_addr16(address);
+       __gus_outregw_slow(GF1R_START_HIGH, address >> 11);
+       __gus_outregw_slow(GF1R_START_LOW, address << 5);
+}
+
+static inline void __gus_set_loop_end(unsigned char mode,
+                                      unsigned long address)
+{
+       address--;
+       if (mode & GF1VC_DATA16)
+               address = __gus_convert_addr16(address);
+       __gus_outregw_slow(GF1R_END_HIGH, address >> 11);
+       __gus_outregw_slow(GF1R_END_LOW, address << 5);
+}
+
+static inline void __gus_mixer_output(boolean state)
+{
+       if (state)
+               gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
+       else
+               gus.mixer |= GF1M_MIXER_NO_OUTPUT;
+       outportb(GF1_MIX_CTRL, gus.mixer);
+       /* Dummy read to avoid touching DMA latches */
+       __gus_inregb(GF1R_BALANCE);
+}
+
+/* Inline routines for working with command pools */
+
+/* WARNING: no bounds checking due to performance reasons */
+#define __POOL_VALUE(type,value)                                                               \
+  *((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value;        \
+  gus.cmd_pool_top += sizeof (type);
+
+static inline void __pool_command(unsigned char command)
+{
+       __POOL_VALUE(char, command);
+}
+
+static inline void __pool_command_b(unsigned char command, unsigned char arg)
+{
+       __POOL_VALUE(char, command);
+       __POOL_VALUE(char, arg);
+}
+
+static inline void __pool_command_w(unsigned char command, unsigned short arg)
+{
+       __POOL_VALUE(char, command);
+       __POOL_VALUE(short, arg);
+}
+
+static inline void __pool_command_l(unsigned char command, unsigned long arg)
+{
+       __POOL_VALUE(char, command);
+       __POOL_VALUE(long, arg);
+}
+
+static inline void __pool_select_voice(unsigned char voice)
+{
+       if (gus.cmd_voice != voice)
+               __pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
+}
+
+#undef __POOL_VALUE
+
+#ifdef DEBUG
+/* Debug dump of GUS DRAM heap */
+extern void __gus_mem_dump();
+#endif
+
+#endif /* __DOSGUS_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosirq.c b/libs/mikmod/drivers/dos/dosirq.c
new file mode 100644 (file)
index 0000000..9b0e21f
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+    Implementation of IRQ routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "dosirq.h"
+
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <malloc.h>
+#include <string.h>
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+unsigned int __irq_stack_size = 0x4000;
+unsigned int __irq_stack_count = 1;
+
+static void __int_stub_template (void)
+{
+/* *INDENT-OFF* */
+       asm("   pushal\n"
+               "       pushl   %ds\n"
+               "       pushl   %es\n"
+               "       pushl   %fs\n"
+               "       pushl   %gs\n"
+               "       movw    $0x1234,%ax\n"          /* Get DPMI data selector */
+               "       movw    %ax,%ds\n"                      /* Set DS and ES to data selector */
+               "       movw    %ax,%es\n"
+               "       movl    $0x12345678,%ebx\n"     /* Interrupt stack top */
+               "       movl    (%ebx),%ecx\n"
+               "       movl    %ecx,%edx\n"
+               "       subl    $0x12345678,%ecx\n"     /* Subtract irq_stack_count */
+               "       movl    %ecx,(%ebx)\n"
+               "       movw    %ss,%si\n"                      /* Save old SS:ESP */
+               "       movl    %esp,%edi\n"
+               "       movl    %edx,%esp\n"            /* Set SS:ESP to interrupt stack */
+               "       movw    %ax,%ss\n"
+               "       pushl   %esi\n"
+               "       pushl   %edi\n"
+               "       pushl   %ebx\n"
+               "       pushl   %edx\n"
+               "       call    1f\n"                           /* Call user interrupt handler */
+               "1:     popl    %edx\n"
+               "       popl    %ebx\n"
+               "       movl    %edx,(%ebx)\n"
+               "       popl    %edi\n"
+               "       popl    %esi\n"
+               "       movl    %edi,%esp\n"            /* Restore old SS:ESP */
+               "       movw    %si,%ss\n"
+               "       popl    %gs\n"
+               "       popl    %fs\n"
+               "       popl    %es\n"
+               "       popl    %ds\n"
+               "       popal\n"
+               "       iret\n");
+/* *INDENT-ON* */
+}
+
+#include <stdio.h>
+
+static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
+{
+       unsigned char *irqtpl = (unsigned char *)__int_stub_template;
+       unsigned char *irqend, *irqwrapper, *tmp;
+       __dpmi_meminfo handler_info;
+       unsigned int wrappersize;
+
+       /* First, skip until pushal */
+       while (*irqtpl != 0x60)
+               irqtpl++;
+       /* Now find the iret */
+       irqend = irqtpl;
+       while (*irqend++ != 0xcf);
+
+       wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
+         ((long)irqend - (long)irqtpl);
+       irqwrapper = (unsigned char *) MikMod_malloc(wrappersize);
+       /* Lock the wrapper */
+       handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
+       handler_info.size = wrappersize;
+       if (__dpmi_lock_linear_region(&handler_info)) {
+               MikMod_free(irqwrapper);
+               return -1;
+       }
+
+       /* First comes the interrupt wrapper size */
+       *(unsigned long *)irqwrapper = wrappersize;
+
+       /* Next comes the interrupt stack */
+       tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;
+
+       /* The following dword is interrupt stack pointer */
+       *((void **)tmp) = tmp;
+       tmp += 4;
+
+       /* Now comes the interrupt wrapper itself */
+       memcpy(tmp, irqtpl, irqend - irqtpl);
+       *(unsigned short *)(tmp + 9) = _my_ds();
+       *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
+       *(unsigned long *)(tmp + 26) = __irq_stack_size;
+       *(unsigned long *)(tmp + 46) =
+         info->pm_offset - (unsigned long)(tmp + 50);
+
+       info->pm_offset = (unsigned long)tmp;
+       info->pm_selector = _my_cs();
+
+       return 0;
+}
+
+static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
+{
+       __dpmi_meminfo handler_info;
+
+       info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;
+
+       handler_info.address = __djgpp_base_address + info->pm_offset;
+       handler_info.size = *(unsigned long *)info->pm_offset;
+       __dpmi_unlock_linear_region(&handler_info);
+
+       MikMod_free((void *)info->pm_offset);
+}
+
+struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size)
+{
+       int interrupt;
+       struct irq_handle *irq;
+       __dpmi_version_ret version;
+       __dpmi_meminfo handler_info, struct_info;
+       _go32_dpmi_seginfo info;
+       unsigned long old_sel, old_ofs;
+
+       __dpmi_get_version(&version);
+       if (irqno < 8)
+               interrupt = version.master_pic + irqno;
+       else
+               interrupt = version.slave_pic + (irqno - 8);
+
+       if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
+               return NULL;
+
+       old_sel = info.pm_selector;
+       old_ofs = info.pm_offset;
+
+       info.pm_offset = (unsigned long)handler;
+       if (_allocate_iret_wrapper(&info))
+               return NULL;
+
+       /* Lock the interrupt handler in memory */
+       handler_info.address = __djgpp_base_address + (unsigned long)handler;
+       handler_info.size = size;
+       if (__dpmi_lock_linear_region(&handler_info)) {
+               _free_iret_wrapper(&info);
+               return NULL;
+       }
+
+       irq = (struct irq_handle *) MikMod_malloc(sizeof(struct irq_handle));
+       irq->c_handler = handler;
+       irq->handler_size = size;
+       irq->handler = info.pm_offset;
+       irq->prev_selector = old_sel;
+       irq->prev_offset = old_ofs;
+       irq->int_num = interrupt;
+       irq->irq_num = irqno;
+       irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;
+
+       struct_info.address = __djgpp_base_address + (unsigned long)irq;
+       struct_info.size = sizeof(struct irq_handle);
+       if (__dpmi_lock_linear_region(&struct_info)) {
+               MikMod_free(irq);
+               __dpmi_unlock_linear_region(&handler_info);
+               _free_iret_wrapper(&info);
+               return NULL;
+       }
+
+       _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);
+
+       irq->pic_mask = irq_state(irq);
+       return irq;
+}
+
+void irq_unhook(struct irq_handle *irq)
+{
+       _go32_dpmi_seginfo info;
+       __dpmi_meminfo mem_info;
+
+       if (!irq)
+               return;
+
+       /* Restore the interrupt vector */
+       irq_disable(irq);
+       info.pm_offset = irq->prev_offset;
+       info.pm_selector = irq->prev_selector;
+       _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);
+
+       /* Unlock the interrupt handler */
+       mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
+       mem_info.size = irq->handler_size;
+       __dpmi_unlock_linear_region(&mem_info);
+
+       /* Unlock the irq_handle structure */
+       mem_info.address = __djgpp_base_address + (unsigned long)irq;
+       mem_info.size = sizeof(struct irq_handle);
+       __dpmi_unlock_linear_region(&mem_info);
+
+       info.pm_offset = irq->handler;
+       _free_iret_wrapper(&info);
+
+       /* If IRQ was enabled before we hooked, restore enabled state */
+       if (irq->pic_mask)
+               irq_enable(irq);
+       else
+               irq_disable(irq);
+
+       MikMod_free(irq);
+}
+
+/*---------------------------------------------- IRQ detection mechanism -----*/
+static struct irq_handle *__irqs[16];
+static int (*__irq_confirm) (int irqno);
+static volatile unsigned int __irq_mask;
+static volatile unsigned int __irq_count[16];
+
+#define DECLARE_IRQ_HANDLER(irqno)                                                     \
+static void __irq##irqno##_handler ()                                          \
+{                                                                                                                      \
+  if (irq_check (__irqs [irqno]) && __irq_confirm (irqno))     \
+  {                                                                                                                    \
+    __irq_count [irqno]++;                                                                     \
+    __irq_mask |= (1 << irqno);                                                                \
+  }                                                                                                                    \
+  irq_ack (__irqs [irqno]);                                                                    \
+}
+
+/* *INDENT-OFF* */
+DECLARE_IRQ_HANDLER(0)
+DECLARE_IRQ_HANDLER(1)
+DECLARE_IRQ_HANDLER(2)
+DECLARE_IRQ_HANDLER(3)
+DECLARE_IRQ_HANDLER(4)
+DECLARE_IRQ_HANDLER(5)
+DECLARE_IRQ_HANDLER(6)
+DECLARE_IRQ_HANDLER(7)
+DECLARE_IRQ_HANDLER(8)
+DECLARE_IRQ_HANDLER(9)
+DECLARE_IRQ_HANDLER(10)
+DECLARE_IRQ_HANDLER(11)
+DECLARE_IRQ_HANDLER(12)
+DECLARE_IRQ_HANDLER(13)
+DECLARE_IRQ_HANDLER(14)
+DECLARE_IRQ_HANDLER(15)
+/* *INDENT-ON* */
+
+static void (*__irq_handlers[16]) () = {
+       __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
+         __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
+         __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
+         __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};
+
+void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
+{
+       int i;
+
+       __irq_mask = 0;
+       __irq_confirm = irq_confirm;
+       memset(&__irqs, 0, sizeof(__irqs));
+       memset((void *) &__irq_count, 0, sizeof(__irq_count));
+
+       /* Hook all specified IRQs */
+       for (i = 1; i <= 15; i++)
+               if (irqs & (1 << i)) {
+                       __irqs[i] = irq_hook(i, __irq_handlers[i], 200);
+                       /* Enable the interrupt */
+                       irq_enable(__irqs[i]);
+               }
+       /* Enable IRQ2 if we need at least one IRQ above 7 */
+       if (irqs & 0xff00)
+               _irq_enable(2);
+}
+
+void irq_detect_end()
+{
+       int i;
+       for (i = 15; i >= 1; i--)
+               if (__irqs[i])
+                       irq_unhook(__irqs[i]);
+}
+
+int irq_detect_get(int irqno, unsigned int *irqmask)
+{
+       int oldirq = disable();
+       int count = __irq_count[irqno];
+       *irqmask = __irq_mask;
+       __irq_mask = 0;
+       if (oldirq)
+               enable();
+       return count;
+}
+
+void irq_detect_clear()
+{
+       int oldirq = disable();
+       memset((void *) &__irq_count, 0, sizeof(__irq_count));
+       __irq_mask = 0;
+       if (oldirq)
+               enable();
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dosirq.h b/libs/mikmod/drivers/dos/dosirq.h
new file mode 100644 (file)
index 0000000..eaf60a1
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+    Interface for IRQ routines on DOS
+    Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __DOSIRQ_H__
+#define __DOSIRQ_H__
+
+#include <pc.h>
+
+#define PIC1_BASE      0x20            /* PIC1 base */
+#define PIC2_BASE      0xA0            /* PIC2 base */
+
+struct irq_handle {
+       void (*c_handler) ();           /* The real interrupt handler */
+       unsigned long handler_size;     /* The size of interrupt handler */
+       unsigned long handler;          /* Interrupt wrapper address */
+       unsigned long prev_selector;    /* Selector of previous handler */
+       unsigned long prev_offset;      /* Offset of previous handler */
+       unsigned char irq_num;          /* IRQ number */
+       unsigned char int_num;          /* Interrupt number */
+       unsigned char pic_base;         /* PIC base (0x20 or 0xA0) */
+       unsigned char pic_mask;         /* Old PIC mask state */
+};
+
+/* Return the enabled state for specific IRQ */
+static inline unsigned char irq_state(struct irq_handle * irq)
+{
+       return ((~inportb(irq->pic_base + 1)) & (0x01 << (irq->irq_num & 7)));
+}
+
+/* Acknowledge the end of interrupt */
+static inline void _irq_ack(int irqno)
+{
+       outportb(irqno > 7 ? PIC2_BASE : PIC1_BASE, 0x60 | (irqno & 7));
+       /* For second controller we also should acknowledge first controller */
+       if (irqno > 7)
+               outportb(PIC1_BASE, 0x20);      /* 0x20, 0x62? */
+}
+
+/* Acknowledge the end of interrupt */
+static inline void irq_ack(struct irq_handle * irq)
+{
+       outportb(irq->pic_base, 0x60 | (irq->irq_num & 7));
+       /* For second controller we also should acknowledge first controller */
+       if (irq->pic_base != PIC1_BASE)
+               outportb(PIC1_BASE, 0x20);      /* 0x20, 0x62? */
+}
+
+/* Mask (disable) the particular IRQ given his ordinal */
+static inline void _irq_disable(int irqno)
+{
+       unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
+       outportb(port_no, inportb(port_no) | (1 << (irqno & 7)));
+}
+
+/* Unmask (enable) the particular IRQ given its ordinal */
+static inline void _irq_enable(int irqno)
+{
+       unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
+       outportb(port_no, inportb(port_no) & ~(1 << (irqno & 7)));
+}
+
+/* Mask (disable) the particular IRQ given its irq_handle structure */
+static inline void irq_disable(struct irq_handle * irq)
+{
+       outportb(irq->pic_base + 1,
+                 inportb(irq->pic_base + 1) | (1 << (irq->irq_num & 7)));
+}
+
+/* Unmask (enable) the particular IRQ given its irq_handle structure */
+static inline void irq_enable(struct irq_handle * irq)
+{
+       outportb(irq->pic_base + 1,
+                 inportb(irq->pic_base + 1) & ~(1 << (irq->irq_num & 7)));
+}
+
+/* Check if a specific IRQ is pending: return 0 is no */
+static inline int irq_check(struct irq_handle * irq)
+{
+       outportb(irq->pic_base, 0x0B);  /* Read IRR vector */
+       return (inportb(irq->pic_base) & (1 << (irq->irq_num & 7)));
+}
+
+/* Hook a specific IRQ; NOTE: IRQ is disabled upon return, irq_enable() it */
+extern struct irq_handle *irq_hook(int irqno, void (*handler)(),
+                                   unsigned long size);
+/* Unhook a previously hooked IRQ */
+extern void irq_unhook(struct irq_handle * irq);
+/* Start IRQ detection process (IRQ list is given with irq mask) */
+/* irq_confirm should return "1" if the IRQ really comes from the device */
+extern void irq_detect_start(unsigned int irqs,
+                             int (*irq_confirm) (int irqno));
+/* Finish IRQ detection process */
+extern void irq_detect_end();
+/* Get the count of specific irqno that happened */
+extern int irq_detect_get(int irqno, unsigned int *irqmask);
+/* Clear IRQ counters */
+extern void irq_detect_clear();
+
+/* The size of interrupt stack */
+extern unsigned int __irq_stack_size;
+/* The number of nested interrupts that can be handled */
+extern unsigned int __irq_stack_count;
+
+#endif /* __DOSIRQ_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dossb.c b/libs/mikmod/drivers/dos/dossb.c
new file mode 100644 (file)
index 0000000..344ac85
--- /dev/null
@@ -0,0 +1,575 @@
+/*     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.
+*/
+
+/*==============================================================================
+
+  Sound Blaster I/O routines, common for SB8, SBPro and SB16
+  Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_SB
+
+#include <stdlib.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <sys/farptr.h>
+#include <string.h>
+
+#include "dossb.h"
+
+/********************************************* Private variables/routines *****/
+
+__sb_state sb;
+
+/* Wait for SoundBlaster for some time */
+#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
+# define _func_noinline volatile /* match original code */
+# define _func_noclone
+#else
+/* avoid warnings from newer gcc:
+ * "function definition has qualified void return type" and
+ * function return types not compatible due to 'volatile' */
+# define _func_noinline __attribute__((__noinline__))
+# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+#  define _func_noclone
+# else
+#  define _func_noclone __attribute__((__noclone__))
+# endif
+#endif
+_func_noinline
+_func_noclone
+ void __sb_wait()
+{
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+       inportb(SB_DSP_RESET);
+}
+
+static void sb_irq()
+{
+       /* Make sure its not a spurious IRQ */
+       if (!irq_check(sb.irq_handle))
+               return;
+
+       sb.irqcount++;
+
+       /* Acknowledge DMA transfer is complete */
+       if (sb.mode & SBMODE_16BITS)
+               __sb_dsp_ack_dma16();
+       else
+               __sb_dsp_ack_dma8();
+
+       /* SoundBlaster 1.x cannot do autoinit ... */
+       if (sb.dspver < SBVER_20)
+               __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
+
+       /* Send EOI */
+       irq_ack(sb.irq_handle);
+
+       enable();
+       if (sb.timer_callback)
+               sb.timer_callback();
+}
+
+static void sb_irq_end()
+{
+}
+
+static boolean __sb_reset()
+{
+       /* Disable the output */
+       sb_output(FALSE);
+
+       /* Clear pending ints if any */
+       __sb_dsp_ack_dma8();
+       __sb_dsp_ack_dma16();
+
+       /* Reset the DSP */
+       outportb(SB_DSP_RESET, SBM_DSP_RESET);
+       __sb_wait();
+       __sb_wait();
+       outportb(SB_DSP_RESET, 0);
+
+       /* Now wait for AA coming from datain port */
+       if (__sb_dsp_in() != 0xaa)
+               return FALSE;
+
+       /* Finally, get the DSP version */
+       if ((sb.dspver = __sb_dsp_version()) == 0xffff)
+               return FALSE;
+       /* Check again */
+       if (sb.dspver != __sb_dsp_version())
+               return FALSE;
+
+       return TRUE;
+}
+
+/***************************************************** SB detection stuff *****/
+
+static int __sb_irq_irqdetect(int irqno)
+{
+       __sb_dsp_ack_dma8();
+       return 1;
+}
+
+static void __sb_irq_dmadetect()
+{
+       /* Make sure its not a spurious IRQ */
+       if (!irq_check(sb.irq_handle))
+               return;
+
+       sb.irqcount++;
+
+       /* Acknowledge DMA transfer is complete */
+       if (sb.mode & SBMODE_16BITS)
+               __sb_dsp_ack_dma16();
+       else
+               __sb_dsp_ack_dma8();
+
+       /* Send EOI */
+       irq_ack(sb.irq_handle);
+}
+
+static boolean __sb_detect()
+{
+       /* First find the port number */
+       if (!sb.port) {
+               int i;
+               for (i = 5; i >= 0; i--) {
+                       sb.port = 0x210 + i * 0x10;
+                       if (__sb_reset())
+                               break;
+               }
+               if (i < 0) {
+                       sb.port = 0;
+                       return FALSE;
+               }
+       }
+
+       /* Now detect the IRQ and DMA numbers */
+       if (!sb.irq) {
+               unsigned int irqmask, sbirqmask, sbirqcount;
+               unsigned long timer;
+
+               /* IRQ can be one of 2,3,5,7,10 */
+               irq_detect_start(0x04ac, __sb_irq_irqdetect);
+
+               /* Prepare timeout counter */
+               _farsetsel(_dos_ds);
+               timer = _farnspeekl(0x46c);
+
+               sbirqmask = 0;
+               sbirqcount = 10;                /* Emit 10 SB irqs */
+
+               /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
+               __sb_dsp_out(SBDSP_GEN_IRQ8);
+               __sb_wait();
+               for (;;) {
+                       irq_detect_get(0, &irqmask);
+                       if (irqmask) {
+                               sbirqmask |= irqmask;
+                               if (!--sbirqcount)
+                                       break;
+                               __sb_dsp_out(SBDSP_GEN_IRQ8);
+                       }
+                       if (_farnspeekl(0x46c) - timer >= 9)    /* Wait ~1/2 secs */
+                               break;
+               }
+               if (sbirqmask)
+                       for (sb.irq = 15; sb.irq > 0; sb.irq--)
+                               if (irq_detect_get(sb.irq, &irqmask) == 10)
+                                       break;
+
+               irq_detect_end();
+               if (!sb.irq)
+                       return FALSE;
+       }
+
+       /* Detect the 8-bit and 16-bit DMAs */
+       if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
+               static int __dma8[] = { 0, 1, 3 };
+               static int __dma16[] = { 5, 6, 7 };
+               int *dma;
+
+               sb_output(FALSE);
+               /* Temporary hook SB IRQ */
+               sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
+               irq_enable(sb.irq_handle);
+               if (sb.irq > 7)
+                       _irq_enable(2);
+
+               /* Start a short DMA transfer and check if IRQ happened */
+               for (;;) {
+                       int i;
+                       unsigned int timer, oldcount;
+
+                       if (!sb.dma8)
+                               dma = &sb.dma8;
+                       else if ((sb.dspver >= SBVER_16) && !sb.dma16)
+                               dma = &sb.dma16;
+                       else
+                               break;
+
+                       for (i = 0; i < 3; i++) {
+                               boolean success = 1;
+
+                               *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
+                               oldcount = sb.irqcount;
+
+                               dma_disable(*dma);
+                               dma_set_mode(*dma, DMA_MODE_WRITE);
+                               dma_clear_ff(*dma);
+                               dma_set_count(*dma, 2);
+                               dma_enable(*dma);
+
+                               __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
+                               if (dma == &sb.dma8) {
+                                       sb.mode = 0;
+                                       __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
+                               } else {
+                                       sb.mode = SBMODE_16BITS;
+                                       __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
+                                       __sb_dsp_out(0);
+                                       __sb_dsp_out(1);
+                               }
+
+                               _farsetsel(_dos_ds);
+                               timer = _farnspeekl(0x46c);
+
+                               while (oldcount == sb.irqcount)
+                                       if (_farnspeekl(0x46c) - timer >= 2) {
+                                               success = 0;
+                                               break;
+                                       }
+                               dma_disable(*dma);
+                               if (success)
+                                       break;
+                               *dma = 0;
+                       }
+                       if (!*dma)
+                               break;
+               }
+
+               irq_unhook(sb.irq_handle);
+               sb.irq_handle = NULL;
+               if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/*************************************************** High-level interface *****/
+
+/* Detect whenever SoundBlaster is present and fill "sb" structure */
+boolean sb_detect()
+{
+       char *env;
+
+       /* Try to find the port and DMA from environment */
+       env = getenv("BLASTER");
+
+       while (env && *env) {
+               /* Skip whitespace */
+               while ((*env == ' ') || (*env == '\t'))
+                       env++;
+               if (!*env)
+                       break;
+
+               switch (*env++) {
+                 case 'A':
+                 case 'a':
+                       if (!sb.port)
+                               sb.port = strtol(env, &env, 16);
+                       break;
+                 case 'E':
+                 case 'e':
+                       if (!sb.aweport)
+                               sb.aweport = strtol(env, &env, 16);
+                       break;
+                 case 'I':
+                 case 'i':
+                       if (!sb.irq)
+                               sb.irq = strtol(env, &env, 10);
+                       break;
+                 case 'D':
+                 case 'd':
+                       if (!sb.dma8)
+                               sb.dma8 = strtol(env, &env, 10);
+                       break;
+                 case 'H':
+                 case 'h':
+                       if (!sb.dma16)
+                               sb.dma16 = strtol(env, &env, 10);
+                       break;
+                 default:
+                       /* Skip other values (H == MIDI, T == model, any other?) */
+                       while (*env && (*env != ' ') && (*env != '\t'))
+                               env++;
+                       break;
+               }
+       }
+
+       /* Try to detect missing sound card parameters */
+       __sb_detect();
+
+       if (!sb.port || !sb.irq || !sb.dma8)
+               return FALSE;
+
+       if (!__sb_reset())
+               return FALSE;
+
+       if ((sb.dspver >= SBVER_16) && !sb.dma16)
+               return FALSE;
+
+       if (sb.dspver >= SBVER_PRO)
+               sb.caps |= SBMODE_STEREO;
+       if (sb.dspver >= SBVER_16 && sb.dma16)
+               sb.caps |= SBMODE_16BITS;
+       if (sb.dspver < SBVER_20)
+               sb.maxfreq_mono = 22222;
+       else
+               sb.maxfreq_mono = 45454;
+       if (sb.dspver <= SBVER_16)
+               sb.maxfreq_stereo = 22727;
+       else
+               sb.maxfreq_stereo = 45454;
+
+       sb.ok = 1;
+       return TRUE;
+}
+
+/* Reset SoundBlaster */
+void sb_reset()
+{
+       sb_stop_dma();
+       __sb_reset();
+}
+
+/* Start working with SoundBlaster */
+boolean sb_open()
+{
+       __dpmi_meminfo struct_info;
+
+       if (!sb.ok)
+               if (!sb_detect())
+                       return FALSE;
+
+       if (sb.open)
+               return FALSE;
+
+       /* Now lock the sb structure in memory */
+       struct_info.address = __djgpp_base_address + (unsigned long)&sb;
+       struct_info.size = sizeof(sb);
+       if (__dpmi_lock_linear_region(&struct_info))
+               return FALSE;
+
+       /* Hook the SB IRQ */
+       sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
+       if (!sb.irq_handle) {
+               __dpmi_unlock_linear_region(&struct_info);
+               return FALSE;
+       }
+
+       /* Enable the interrupt */
+       irq_enable(sb.irq_handle);
+       if (sb.irq > 7)
+               _irq_enable(2);
+
+       sb.open++;
+
+       return TRUE;
+}
+
+/* Finish working with SoundBlaster */
+boolean sb_close()
+{
+       __dpmi_meminfo struct_info;
+       if (!sb.open)
+               return FALSE;
+
+       sb.open--;
+
+       /* Stop/free DMA buffer */
+       sb_stop_dma();
+
+       /* Unhook IRQ */
+       irq_unhook(sb.irq_handle);
+       sb.irq_handle = NULL;
+
+       /* Unlock the sb structure */
+       struct_info.address = __djgpp_base_address + (unsigned long)&sb;
+       struct_info.size = sizeof(sb);
+       __dpmi_unlock_linear_region(&struct_info);
+
+       return TRUE;
+}
+
+/* Enable/disable stereo DSP mode */
+/* Enable/disable speaker output */
+void sb_output(boolean enable)
+{
+       __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
+}
+
+/* Start playing from DMA buffer */
+boolean sb_start_dma(unsigned char mode, unsigned int freq)
+{
+       int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
+       int dmabuffsize;
+       unsigned int tc = 0;            /* timing constant (<=sbpro only) */
+
+       /* Stop DMA transfer if it is enabled */
+       sb_stop_dma();
+
+       /* Sanity check */
+       if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
+               return FALSE;
+
+       /* Check this SB can perform at requested frequency */
+       if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
+               || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
+               return FALSE;
+
+       /* Check the timing constant here to avoid failing later */
+       if (sb.dspver < SBVER_16) {
+               /* SBpro cannot do signed transfer */
+               if (mode & SBMODE_SIGNED)
+                       return FALSE;
+
+               /* Old SBs have a different way on setting DMA timing constant */
+               tc = freq;
+               if (mode & SBMODE_STEREO)
+                       tc *= 2;
+               tc = 1000000 / tc;
+               if (tc > 255)
+                       return FALSE;
+       }
+
+       sb.mode = mode;
+
+       /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
+       dmabuffsize = freq;
+       if (mode & SBMODE_STEREO)
+               dmabuffsize *= 2;
+       if (mode & SBMODE_16BITS)
+               dmabuffsize *= 2;
+       dmabuffsize >>= 2;
+       if (dmabuffsize < 4096)
+               dmabuffsize = 4096;
+       if (dmabuffsize > 32768)
+               dmabuffsize = 32768;
+       dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
+
+       sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
+       if (!sb.dma_buff)
+               return FALSE;
+
+       /* Fill DMA buffer with silence */
+       dmabuffsize = sb.dma_buff->size;
+       if (mode & SBMODE_SIGNED)
+               memset(sb.dma_buff->linear, 0, dmabuffsize);
+       else
+               memset(sb.dma_buff->linear, 0x80, dmabuffsize);
+
+       /* Prime DMA for transfer */
+       dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+
+       /* Tell SoundBlaster to start transfer */
+       if (sb.dspver >= SBVER_16) {    /* SB16 */
+               __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
+
+               /* Start DMA->DAC transfer */
+               __sb_dspreg_out(SBM_GENDAC_AUTOINIT | SBM_GENDAC_FIFO |
+                                               ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
+                                                SBDSP_DMA_GENERIC8),
+                                               ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
+                                               ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
+
+               /* Write the length of transfer */
+               dmabuffsize = (dmabuffsize >> 2) - 1;
+               __sb_dsp_out(dmabuffsize);
+               __sb_dsp_out(dmabuffsize >> 8);
+       } else {
+               __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
+               dmabuffsize = (dmabuffsize >> 1) - 1;
+               if (sb.dspver >= SBVER_20) {    /* SB 2.0/Pro */
+                       /* Set stereo mode */
+                       __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
+                       __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
+                       if (sb.dspver >= SBVER_PRO)
+                               __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
+                       else
+                               __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
+               } else {                                /* Original SB */
+                       /* Start DMA->DAC transfer */
+                       __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
+               }
+       }
+
+       return TRUE;
+}
+
+/* Stop playing from DMA buffer */
+void sb_stop_dma()
+{
+       if (!sb.dma_buff)
+               return;
+
+       if (sb.mode & SBMODE_16BITS)
+               __sb_dsp_out(SBDSP_DMA_HALT16);
+       else
+               __sb_dsp_out(SBDSP_DMA_HALT8);
+
+       dma_disable(sb.dma_buff->channel);
+       dma_free(sb.dma_buff);
+       sb.dma_buff = NULL;
+}
+
+/* Query current position/total size of the DMA buffer */
+void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
+{
+       unsigned int dma_left;
+       *dma_size = sb.dma_buff->size;
+       /* It can happen we try to read DMA count when HI/LO bytes will be
+          inconsistent */
+       for (;;) {
+               unsigned int dma_left_test;
+               dma_clear_ff(sb.dma_buff->channel);
+               dma_left_test = dma_get_count(sb.dma_buff->channel);
+               dma_left = dma_get_count(sb.dma_buff->channel);
+               if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
+                       break;
+       }
+       *dma_pos = *dma_size - dma_left;
+}
+
+#endif /* DRV_SB */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/dossb.h b/libs/mikmod/drivers/dos/dossb.h
new file mode 100644 (file)
index 0000000..cb8dc70
--- /dev/null
@@ -0,0 +1,341 @@
+/*     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$
+
+  SoundBlaster and compatible soundcards definitions
+
+==============================================================================*/
+
+#ifndef __DOSSB_H__
+#define __DOSSB_H__
+
+#include "dosdma.h"
+#include "dosirq.h"
+
+#define SB_FM_LEFT_STATUS              (sb.port + 0x00)        /* (r) Left FM status */
+#define SB_FM_LEFT_REGSEL              (sb.port + 0x00)        /* (w) Left FM register select */
+#define SB_FM_LEFT_DATA                        (sb.port + 0x01)        /* (w) Left FM data */
+#define SB_FM_RIGHT_STATUS             (sb.port + 0x02)        /* (r) Right FM status */
+#define SB_FM_RIGHT_REGSEL             (sb.port + 0x02)        /* (w) Right FM register select */
+#define SB_FM_RIGHT_DATA               (sb.port + 0x03)        /* (w) Right FM data */
+#define SB_MIXER_REGSEL                        (sb.port + 0x04)        /* (w) Mixer register select */
+#define SB_MIXER_DATA                  (sb.port + 0x05)        /* (rw)Mixer data */
+#define SB_DSP_RESET                   (sb.port + 0x06)        /* (w) DSP reset */
+#define SB_FM_STATUS                   (sb.port + 0x08)        /* (r) FM status */
+#define SB_FM_REGSEL                   (sb.port + 0x08)        /* (w) FM register select */
+#define SB_FM_DATA                     (sb.port + 0x09)        /* (w) FM data */
+#define SB_DSP_DATA_IN                 (sb.port + 0x0a)        /* (r) DSP data input */
+#define SB_DSP_DATA_OUT                        (sb.port + 0x0c)        /* (w) DSP data output */
+#define SB_DSP_DATA_OUT_STATUS         (sb.port + 0x0c)        /* (r) DSP data output status */
+#define SB_DSP_TIMER_IRQ               (sb.port + 0x0d)        /* (r) clear timer IRQ? */
+#define SB_DSP_DATA_IN_STATUS          (sb.port + 0x0e)        /* (r) DSP data input status */
+#define SB_DSP_DMA8_IRQ                        (sb.port + 0x0e)        /* (r) Acknowledge 8-bit DMA transfer */
+#define SB_DSP_DMA16_IRQ               (sb.port + 0x0f)        /* (r) Acknowledge 16-bit DMA transfer */
+
+/* DSP commands */
+#define SBDSP_ASP_STATUS               0x03    /* ASP Status (SB16ASP) */
+#define SBDSP_STATUS_OLD               0x04    /* DSP Status (Obsolete) (SB2.0-Pro2) */
+#define SBDSP_DIRECT_DAC               0x10    /* Direct DAC, 8-bit (SB) */
+#define SBDSP_DMA_PCM8                 0x14    /* DMA DAC, 8-bit (SB) */
+#define SBDSP_DMA_ADPCM2               0x16    /* DMA DAC, 2-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM2R              0x17    /* DMA DAC, 2-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_PCM8_AUTO            0x1C    /* Auto-Initialize DMA DAC, 8-bit (SB2.0) */
+#define SBDSP_DMA_ADPCM2R_AUTO         0x1F    /* Auto-Initialize DMA DAC, 2-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DIRECT_ADC               0x20    /* Direct ADC, 8-bit (SB) */
+#define SBDSP_DMA_ADC8                 0x24    /* DMA ADC, 8-bit (SB) */
+#define SBDSP_DIRECT_ADC8_BURST                0x28    /* Direct ADC, 8-bit (Burst) (SB-Pro2) */
+#define SBDSP_DMA_ADC8_AUTO            0x2C    /* Auto-Initialize DMA ADC, 8-bit (SB2.0) */
+#define SBDSP_MIDI_READ_POLL           0x30    /* MIDI Read Poll (SB) */
+#define SBDSP_MIDI_READ_IRQ            0x31    /* MIDI Read Interrupt (SB) */
+#define SBDSP_MIDI_READ_TIME           0x32    /* MIDI Read Timestamp Poll (SB???) */
+#define SBDSP_MIDI_READ_TIME_IRQ       0x33    /* MIDI Read Timestamp Interrupt (SB???) */
+#define SBDSP_MIDI_RW_POLL             0x34    /* MIDI Read Poll + Write Poll (UART) (SB2.0) */
+#define SBDSP_MIDI_RW_IRQ              0x35    /* MIDI Read Interrupt + Write Poll (UART) (SB2.0???) */
+#define SBDSP_MIDI_RW_TIME_IRQ         0x37    /* MIDI Read Timestamp Interrupt + Write Poll (UART) (SB2.0???) */
+#define SBDSP_MIDI_WRITE_POLL          0x38    /* MIDI Write Poll (SB) */
+#define SBDSP_SET_TIMING               0x40    /* Set Time Constant (SB) */
+#define SBDSP_SET_RATE                 0x41    /* Set Sample Rate, Hz (SB16) */
+#define SBDSP_DMA_CONT8_AUTO           0x45    /* Continue Auto-Initialize DMA, 8-bit (SB16) */
+#define SBDSP_DMA_CONT16_AUTO          0x47    /* Continue Auto-Initialize DMA, 16-bit (SB16) */
+#define SBDSP_SET_DMA_BLOCK            0x48    /* Set DMA Block Size (SB2.0) */
+#define SBDSP_DMA_ADPCM4               0x74    /* DMA DAC, 4-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM4_REF           0x75    /* DMA DAC, 4-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_ADPCM26              0x76    /* DMA DAC, 2.6-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM26_REF          0x77    /* DMA DAC, 2.6-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_ADPCM4R_AUTO         0x7D    /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DMA_ADPCM26R_AUTO                0x7F    /* Auto-Initialize DMA DAC, 2.6-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DISABLE_DAC              0x80    /* Silence DAC (SB) */
+#define SBDSP_HS_DMA_DAC8_AUTO         0x90    /* Auto-Initialize DMA DAC, 8-bit (High Speed) (SB2.0-Pro2) */
+#define SBDSP_HS_DMA_ADC8_AUTO         0x98    /* Auto-Initialize DMA ADC, 8-bit (High Speed) (SB2.0-Pro2) */
+#define SBDSP_STEREO_ADC_DIS           0xA0    /* Disable Stereo Input Mode (SBPro Only) */
+#define SBDSP_STEREO_ADC_ENA           0xA8    /* Enable Stereo Input Mode (SBPro Only) */
+#define SBDSP_DMA_GENERIC16            0xB0    /* Generic DAC/ADC DMA (16-bit) (SB16) */
+#define SBDSP_DMA_GENERIC8             0xC0    /* Generic DAC/ADC DMA (8-bit) (SB16) */
+#define SBDSP_DMA_HALT8                        0xD0    /* Halt DMA Operation, 8-bit (SB) */
+#define SBDSP_SPEAKER_ENA              0xD1    /* Enable Speaker (SB) */
+#define SBDSP_SPEAKER_DIS              0xD3    /* Disable Speaker (SB) */
+#define SBDSP_DMA_CONT8                        0xD4    /* Continue DMA Operation, 8-bit (SB) */
+#define SBDSP_DMA_HALT16               0xD5    /* Halt DMA Operation, 16-bit (SB16) */
+#define SBDSP_DMA_CONT16               0xD6    /* Continue DMA Operation, 16-bit (SB16) */
+#define SBDSP_SPEAKER_STATUS           0xD8    /* Speaker Status (SB) */
+#define SBDSP_DMA_EXIT16_AUTO          0xD9    /* Exit Auto-Initialize DMA Operation, 16-bit (SB16) */
+#define SBDSP_DMA_EXIT8_AUTO           0xDA    /* Exit Auto-Initialize DMA Operation, 8-bit (SB2.0) */
+#define SBDSP_IDENTIFY                 0xE0    /* DSP Identification (SB2.0) */
+#define SBDSP_VERSION                  0xE1    /* DSP Version (SB) */
+#define SBDSP_COPYRIGHT                        0xE3    /* DSP Copyright (SBPro2???) */
+#define SBDSP_WRITE_TEST               0xE4    /* Write Test Register (SB2.0) */
+#define SBDSP_READ_TEST                        0xE8    /* Read Test Register (SB2.0) */
+#define SBDSP_SINE_GEN                 0xF0    /* Sine Generator (SB) */
+#define SBDSP_AUX_STATUS_PRO           0xF1    /* DSP Auxiliary Status (Obsolete) (SB-Pro2) */
+#define SBDSP_GEN_IRQ8                 0xF2    /* IRQ Request, 8-bit (SB) */
+#define SBDSP_GEN_IRQ16                        0xF3    /* IRQ Request, 16-bit (SB16) */
+#define SBDSP_STATUS                   0xFB    /* DSP Status (SB16) */
+#define SBDSP_AUX_STATUS_16            0xFC    /* DSP Auxiliary Status (SB16) */
+#define SBDSP_CMD_STATUS               0xFD    /* DSP Command Status (SB16) */
+
+/* Mixer commands */
+#define SBMIX_RESET                    0x00    /* Reset                        Write       SBPro */
+#define SBMIX_STATUS                   0x01    /* Status                       Read        SBPro */
+#define SBMIX_MASTER_LEVEL1            0x02    /* Master Volume                Read/Write  SBPro Only */
+#define SBMIX_DAC_LEVEL                        0x04    /* DAC Level                    Read/Write  SBPro */
+#define SBMIX_FM_OUTPUT                        0x06    /* FM Output Control            Read/Write  SBPro Only */
+#define SBMIX_MIC_LEVEL                        0x0A    /* Microphone Level             Read/Write  SBPro */
+#define SBMIX_INPUT_SELECT             0x0C    /* Input/Filter Select          Read/Write  SBPro Only */
+#define SBMIX_OUTPUT_SELECT            0x0E    /* Output/Stereo Select         Read/Write  SBPro Only */
+#define SBMIX_FM_LEVEL                 0x22    /* Master Volume                Read/Write  SBPro */
+#define SBMIX_MASTER_LEVEL             0x26    /* FM Level                     Read/Write  SBPro */
+#define SBMIX_CD_LEVEL                 0x28    /* CD Audio Level               Read/Write  SBPro */
+#define SBMIX_LINEIN_LEVEL             0x2E    /* Line In Level                Read/Write  SBPro */
+#define SBMIX_MASTER_LEVEL_L           0x30    /* Master Volume Left           Read/Write  SB16 */
+#define SBMIX_MASTER_LEVEL_R           0x31    /* Master Volume Right          Read/Write  SB16 */
+#define SBMIX_DAC_LEVEL_L              0x32    /* DAC Level Left               Read/Write  SB16 */
+#define SBMIX_DAC_LEVEL_R              0x33    /* DAC Level Right              Read/Write  SB16 */
+#define SBMIX_FM_LEVEL_L               0x34    /* FM Level Left                Read/Write  SB16 */
+#define SBMIX_FM_LEVEL_R               0x35    /* FM Level Right               Read/Write  SB16 */
+#define SBMIX_CD_LEVEL_L               0x36    /* CD Audio Level Left          Read/Write  SB16 */
+#define SBMIX_CD_LEVEL_R               0x37    /* CD Audio Level Right         Read/Write  SB16 */
+#define SBMIX_LINEIN_LEVEL_L           0x38    /* Line In Level Left           Read/Write  SB16 */
+#define SBMIX_LINEIN_LEVEL_R           0x39    /* Line In Level Right          Read/Write  SB16 */
+#define SBMIX_MIC_LEVEL_16             0x3A    /* Microphone Level             Read/Write  SB16 */
+#define SBMIX_PCSPK_LEVEL              0x3B    /* PC Speaker Level             Read/Write  SB16 */
+#define SBMIX_OUTPUT_CONTROL           0x3C    /* Output Control               Read/Write  SB16 */
+#define SBMIX_INPUT_CONTROL_L          0x3D    /* Input Control Left           Read/Write  SB16 */
+#define SBMIX_INPUT_CONTROL_R          0x3E    /* Input Control Right          Read/Write  SB16 */
+#define SBMIX_INPUT_GAIN_L             0x3F    /* Input Gain Control Left      Read/Write  SB16 */
+#define SBMIX_INPUT_GAIN_R             0x40    /* Input Gain Control Right     Read/Write  SB16 */
+#define SBMIX_OUTPUT_GAIN_L            0x41    /* Output Gain Control Left     Read/Write  SB16 */
+#define SBMIX_OUTPUT_GAIN_R            0x42    /* Output Gain Control Right    Read/Write  SB16 */
+#define SBMIX_AGC_CONTROL              0x43    /* Automatic Gain Control (AGC) Read/Write  SB16 */
+#define SBMIX_TREBLE_L                 0x44    /* Treble Left                  Read/Write  SB16 */
+#define SBMIX_TREBLE_R                 0x45    /* Treble Right                 Read/Write  SB16 */
+#define SBMIX_BASS_L                   0x46    /* Bass Left                    Read/Write  SB16 */
+#define SBMIX_BASS_R                   0x47    /* Bass Right                   Read/Write  SB16 */
+#define SBMIX_IRQ_SELECT               0x80    /* IRQ Select                   Read/Write  SB16 */
+#define SBMIX_DMA_SELECT               0x81    /* DMA Select                   Read/Write  SB16 */
+#define SBMIX_IRQ_STATUS               0x82    /* IRQ Status                   Read        SB16 */
+
+/* SB_DSP_DATA_OUT_STATUS and SB_DSP_DATA_IN_STATUS bits */
+#define SBM_DSP_READY                  0x80
+
+/* SB_DSP_RESET / SBMIX_RESET */
+#define SBM_DSP_RESET                  0x01
+
+/* SBMIX_OUTPUT_SELECT */
+#define SBM_MIX_STEREO                 0x02
+#define SBM_MIX_FILTER                 0x20
+
+/* SBDSP_DMA_GENERIC16/SBDSP_DMA_GENERIC8 */
+#define SBM_GENDAC_FIFO                        0x02
+#define SBM_GENDAC_AUTOINIT            0x04
+#define SBM_GENDAC_ADC                 0x08
+/* Second (mode) byte */
+#define SBM_GENDAC_SIGNED              0x10
+#define SBM_GENDAC_STEREO              0x20
+
+/* DSP version masks */
+#define SBVER_10                       0x0100  /* Original SoundBlaster */
+#define SBVER_15                       0x0105  /* SoundBlaster 1.5 */
+#define SBVER_20                       0x0200  /* SoundBlaster 2.0 */
+#define SBVER_PRO                      0x0300  /* SoundBlaster Pro */
+#define SBVER_PRO2                     0x0301  /* SoundBlaster Pro 2 */
+#define SBVER_16                       0x0400  /* SoundBlaster 16 */
+#define SBVER_AWE32                    0x040c  /* SoundBlaster AWE32 */
+
+typedef unsigned char boolean;
+
+#ifndef FALSE
+#define FALSE                          0
+#define TRUE                           1
+#endif
+
+/* Play mode bits */
+#define SBMODE_16BITS                  0x0001
+#define SBMODE_STEREO                  0x0002
+#define SBMODE_SIGNED                  0x0004
+
+/* Mask for capabilities that never change */
+#define SBMODE_MASK                    (SBMODE_16BITS | SBMODE_STEREO)
+
+/* You can fill some members of this struct (i.e. port,irq,dma) before
+ * calling sb_detect() or sb_open()... this will ignore environment settings.
+ */
+typedef struct __sb_state_s {
+       boolean ok;                     /* Are structure contents valid? */
+       int port, aweport;              /* sb/awe32 base port */
+       int irq;                        /* SoundBlaster IRQ */
+       int dma8, dma16;                /* 8-bit and 16-bit DMAs */
+       int maxfreq_mono;               /* Maximum discretization frequency / mono mode */
+       int maxfreq_stereo;             /* Maximum discretization frequency / stereo mode */
+       unsigned short dspver;          /* DSP version number */
+       struct irq_handle *irq_handle;  /* The interrupt handler */
+       dma_buffer *dma_buff;           /* Pre-allocated DMA buffer */
+       unsigned char caps;             /* SoundBlaster capabilities (SBMODE_XXX) */
+       unsigned char mode;             /* Current SB mode (SBMODE_XXX) */
+       boolean open;                   /* Whenever the card has been opened */
+       volatile int irqcount;          /* Incremented on each IRQ... for diagnostics */
+       void (*timer_callback) ();      /* Called TWICE per buffer play */
+} __sb_state;
+
+extern __sb_state sb;
+
+extern void __sb_wait();
+
+static inline boolean __sb_dsp_ready_in()
+{
+       int count;
+       for (count = 10000; count >= 0; count--)
+               if (inportb(SB_DSP_DATA_IN_STATUS) & SBM_DSP_READY)
+                       return TRUE;
+       return FALSE;
+}
+
+static inline boolean __sb_dsp_ready_out()
+{
+       int count;
+       for (count = 10000; count >= 0; count--)
+               if ((inportb(SB_DSP_DATA_OUT_STATUS) & SBM_DSP_READY) == 0)
+                       return TRUE;
+       return FALSE;
+}
+
+static inline void __sb_dsp_out(unsigned char reg)
+{
+       __sb_dsp_ready_out();
+       outportb(SB_DSP_DATA_OUT, reg);
+}
+
+static inline unsigned char __sb_dsp_in()
+{
+       __sb_dsp_ready_in();
+       return inportb(SB_DSP_DATA_IN);
+}
+
+static inline void __sb_dspreg_out(unsigned char reg, unsigned char val)
+{
+       __sb_dsp_out(reg);
+       __sb_dsp_out(val);
+}
+
+static inline void __sb_dspreg_outwlh(unsigned char reg, unsigned short val)
+{
+       __sb_dsp_out(reg);
+       __sb_dsp_out(val);
+       __sb_dsp_out(val >> 8);
+}
+
+static inline void __sb_dspreg_outwhl(unsigned char reg, unsigned short val)
+{
+       __sb_dsp_out(reg);
+       __sb_dsp_out(val >> 8);
+       __sb_dsp_out(val);
+}
+
+static inline unsigned char __sb_dspreg_in(unsigned char reg)
+{
+       __sb_dsp_out(reg);
+       return __sb_dsp_in();
+}
+
+static inline void __sb_dsp_ack_dma8()
+{
+       inportb(SB_DSP_DMA8_IRQ);
+}
+
+static inline void __sb_dsp_ack_dma16()
+{
+       inportb(SB_DSP_DMA16_IRQ);
+}
+
+static inline unsigned short __sb_dsp_version()
+{
+       unsigned short ver;
+       __sb_dsp_out(SBDSP_VERSION);
+       __sb_dsp_ready_in();
+       ver = ((unsigned short)__sb_dsp_in()) << 8;
+       ver |= __sb_dsp_in();
+       return ver;
+}
+
+static inline void __sb_mixer_out(unsigned char reg, unsigned char val)
+{
+       outportb(SB_MIXER_REGSEL, reg);
+       outportb(SB_MIXER_DATA, val);
+}
+
+static inline unsigned char __sb_mixer_in(unsigned char reg)
+{
+       outportb(SB_MIXER_REGSEL, reg);
+       return inportb(SB_MIXER_DATA);
+}
+
+/* Enable stereo transfers: sbpro mode only */
+static inline void __sb_stereo(boolean stereo)
+{
+       unsigned char val = __sb_mixer_in(SBMIX_OUTPUT_SELECT);
+       if (stereo)
+               val |= SBM_MIX_STEREO;
+       else
+               val &= ~SBM_MIX_STEREO;
+       __sb_mixer_out(SBMIX_OUTPUT_SELECT, val);
+}
+
+/* Detect whenever SoundBlaster is present and fill "sb" structure */
+extern boolean sb_detect();
+/* Reset SoundBlaster */
+extern void sb_reset();
+/* Start working with SoundBlaster */
+extern boolean sb_open();
+/* Finish working with SoundBlaster */
+extern boolean sb_close();
+/* Enable/disable speaker output */
+extern void sb_output(boolean enable);
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+extern boolean sb_start_dma(unsigned char mode, unsigned int freq);
+/* Stop playing from DMA buffer */
+extern void sb_stop_dma();
+/* Query current position/total size of the DMA buffer */
+extern void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
+
+#endif /* __DOSSB_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/doswss.c b/libs/mikmod/drivers/dos/doswss.c
new file mode 100644 (file)
index 0000000..41cdf38
--- /dev/null
@@ -0,0 +1,577 @@
+/*     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.
+*/
+
+/*==============================================================================
+
+  Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc)
+  Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_WSS
+
+#include <stdlib.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <sys/farptr.h>
+#include <string.h>
+
+#include "doswss.h"
+
+/********************************************* Private variables/routines *****/
+
+__wss_state wss;
+
+/* WSS frequency rates... lower bit selects one of two frequency generators */
+static unsigned int wss_rates[14][2] = {
+       {5510, 0x00 | WSSM_XTAL2},
+       {6620, 0x0E | WSSM_XTAL2},
+       {8000, 0x00 | WSSM_XTAL1},
+       {9600, 0x0E | WSSM_XTAL1},
+       {11025, 0x02 | WSSM_XTAL2},
+       {16000, 0x02 | WSSM_XTAL1},
+       {18900, 0x04 | WSSM_XTAL2},
+       {22050, 0x06 | WSSM_XTAL2},
+       {27420, 0x04 | WSSM_XTAL1},
+       {32000, 0x06 | WSSM_XTAL1},
+       {33075, 0x0C | WSSM_XTAL2},
+       {37800, 0x08 | WSSM_XTAL2},
+       {44100, 0x0A | WSSM_XTAL2},
+       {48000, 0x0C | WSSM_XTAL1}
+};
+
+static void wss_irq()
+{
+       /* Make sure its not a spurious IRQ */
+       if (!irq_check(wss.irq_handle))
+               return;
+
+       wss.irqcount++;
+
+       /* Clear IRQ status */
+       outportb(WSS_STATUS, 0);
+
+       /* Write transfer count again */
+       __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
+       __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
+       irq_ack(wss.irq_handle);
+
+       enable();
+       if (wss.timer_callback)
+               wss.timer_callback();
+}
+
+static void wss_irq_end()
+{
+}
+
+/* WSS accepts some conventional values instead of frequency in Hz... */
+static unsigned char __wss_getrate(unsigned int *freq)
+{
+       int i, best = -1, delta = 0xffff;
+
+       for (i = 0; i < 14; i++) {
+               int newdelta = abs(wss_rates[i][0] - *freq);
+               if (newdelta < delta)
+                       best = i, delta = newdelta;
+       }
+
+       *freq = wss_rates[best][0];
+       return wss_rates[best][1];
+}
+
+/* Check if we really have a WSS compatible card on given address */
+static boolean __wss_ping()
+{
+       /* Disable CODEC operations first */
+       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+       /* Now put some harmless values in registers and check them */
+       __wss_outreg(WSSR_COUNT_LOW, 0xaa);
+       __wss_outreg(WSSR_COUNT_HIGH, 0x55);
+       return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa)
+         && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55);
+}
+
+static boolean __wss_reset()
+{
+       int count;
+
+       /* Disable output */
+       wss_output(FALSE);
+
+       /* Now select the test/initialization register */
+       count = 10000;
+       while (inportb(WSS_ADDR) != WSSR_TEST_INIT) {
+               outportb(WSS_ADDR, WSSR_TEST_INIT);
+               if (!--count)
+                       return FALSE;
+       }
+
+       count = 10000;
+       while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) {
+               outportb(WSS_ADDR, WSSR_TEST_INIT);
+               if (!--count)
+                       return FALSE;
+       }
+
+       /* Enable playback IRQ */
+       __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
+       __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
+
+       /* Clear IRQ status */
+       outportb(WSS_STATUS, 0);
+
+       return TRUE;
+}
+
+static boolean __wss_setformat(unsigned char format)
+{
+       int count;
+
+       outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT);
+       outportb(WSS_DATA, format);
+       inportb(WSS_DATA);                      /* ERRATA SHEETS ... */
+       inportb(WSS_DATA);                      /* ERRATA SHEETS ... */
+
+       /* Wait end of syncronization ... */
+       if (!__wss_wait())
+               return FALSE;
+
+       /* Turn off the ModeChangeEnable bit: do it until it works */
+       count = 10000;
+       while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) {
+               outportb(WSS_ADDR, WSSR_PLAY_FORMAT);
+               if (!--count)
+                       return FALSE;
+       }
+
+       return __wss_reset();
+}
+
+/**************************************************** WSS detection stuff *****/
+
+static int __wss_irq_irqdetect(int irqno)
+{
+       unsigned char status = inportb(WSS_STATUS);
+       /* Clear IRQ status */
+       outportb(WSS_STATUS, 0);
+       /* Reset transfer counter */
+       __wss_outreg(WSSR_COUNT_LOW, 0);
+       __wss_outreg(WSSR_COUNT_HIGH, 0);
+       return (status & WSSM_INT);
+}
+
+static boolean __wss_detect()
+{
+       /* First find the port number */
+       if (!wss.port) {
+               static unsigned int wss_ports[] =
+                 { 0x32c, 0x530, 0x604, 0xE80, 0xF40 };
+               int i;
+               for (i = 0; i < 5; i++) {
+                       wss.port = wss_ports[i];
+                       if (__wss_ping())
+                               break;
+               }
+               if (i < 0) {
+                       wss.port = 0;
+                       return FALSE;
+               }
+       }
+
+       /* Now disable output */
+       wss_output(FALSE);
+
+       /* Detect the DMA channel */
+       if (!wss.dma) {
+               static int __dma[] = { 0, 1, 3 };
+               int i;
+
+               /* Enable playback IRQ */
+               __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
+               __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
+
+               /* Start a short DMA transfer and check if DMA count is zero */
+               for (i = 0; i < 3; i++) {
+                       unsigned int timer, status, freq = 44100;
+
+                       wss.dma = __dma[i];
+
+                       dma_disable(wss.dma);
+                       dma_set_mode(wss.dma, DMA_MODE_WRITE);
+                       dma_clear_ff(wss.dma);
+                       dma_set_count(wss.dma, 10);
+                       dma_enable(wss.dma);
+
+                       /* Clear IRQ status */
+                       outportb(WSS_STATUS, 0);
+
+                       __wss_setformat(__wss_getrate(&freq));
+                       __wss_outreg(WSSR_COUNT_LOW, 1);
+                       __wss_outreg(WSSR_COUNT_HIGH, 0);
+                       /* Tell codec to start transfer */
+                       __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+                       _farsetsel(_dos_ds);
+                       timer = _farnspeekl(0x46c);
+
+                       while (_farnspeekl(0x46c) - timer <= 2)
+                               if (dma_get_count(wss.dma) == 0)
+                                       break;
+                       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+                       dma_disable(wss.dma);
+
+                       /* Now check if DMA transfer count is zero and an IRQ is pending */
+                       status = inportb(WSS_STATUS);
+                       outportb(WSS_STATUS, 0);
+                       if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT))
+                               break;
+
+                       wss.dma = 0;
+               }
+
+               if (!wss.dma)
+                       return FALSE;
+       }
+
+       /* Now detect the IRQ number */
+       if (!wss.irq) {
+               unsigned int i, irqmask, freq = 5510;
+               unsigned long timer, delta = 0x7fffffff;
+
+               /* IRQ can be one of 2,3,5,7,10 */
+               irq_detect_start(0x04ac, __wss_irq_irqdetect);
+
+               dma_disable(wss.dma);
+               dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+               dma_clear_ff(wss.dma);
+               dma_set_count(wss.dma, 1);
+               dma_enable(wss.dma);
+
+               __wss_setformat(__wss_getrate(&freq));
+
+               /* Clear IRQ status */
+               outportb(WSS_STATUS, 0);
+
+               __wss_outreg(WSSR_COUNT_LOW, 0);
+               __wss_outreg(WSSR_COUNT_HIGH, 0);
+
+               /* Prepare timeout counter */
+               _farsetsel(_dos_ds);
+               timer = _farnspeekl(0x46c);
+               while (timer == _farnspeekl(0x46c));
+               timer = _farnspeekl(0x46c);
+
+               /* Reset all IRQ counters */
+               irq_detect_clear();
+
+               /* Tell codec to start transfer */
+               __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+               /* Now wait 1/18 seconds */
+               while (timer == _farnspeekl(0x46c));
+               __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+               dma_disable(wss.dma);
+
+               /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval
+                  of 1/18.2 second, we should have received about 302 interrupts */
+               for (i = 2; i <= 10; i++) {
+                       int count = abs(302 - irq_detect_get(i, &irqmask));
+                       if (count < delta)
+                               wss.irq = i, delta = count;
+               }
+               if (delta > 150)
+                       wss.irq = 0;
+
+               irq_detect_end();
+               if (!wss.irq)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+/*************************************************** High-level interface *****/
+
+/* Detect whenever WSS is present and fill "wss" structure */
+boolean wss_detect()
+{
+       char *env;
+
+       /* Try to find the port and DMA from environment */
+       env = getenv("WSS");
+
+       while (env && *env) {
+               /* Skip whitespace */
+               while ((*env == ' ') || (*env == '\t'))
+                       env++;
+               if (!*env)
+                       break;
+
+               switch (*env++) {
+                 case 'A':
+                 case 'a':
+                       if (!wss.port)
+                               wss.port = strtol(env, &env, 16);
+                       break;
+                 case 'I':
+                 case 'i':
+                       if (!wss.irq)
+                               wss.irq = strtol(env, &env, 10);
+                       break;
+                 case 'D':
+                 case 'd':
+                       if (!wss.dma)
+                               wss.dma = strtol(env, &env, 10);
+                       break;
+                 default:
+                       /* Skip other values */
+                       while (*env && (*env != ' ') && (*env != '\t'))
+                               env++;
+                       break;
+               }
+       }
+
+       /* Try to fill the gaps in wss hardware parameters */
+       __wss_detect();
+
+       if (!wss.port || !wss.irq || !wss.dma)
+               return FALSE;
+
+       if (!__wss_ping())
+               return FALSE;
+
+       if (!__wss_reset())
+               return FALSE;
+
+       wss.ok = 1;
+       return TRUE;
+}
+
+/* Reset WSS */
+void wss_reset()
+{
+       wss_stop_dma();
+       __wss_reset();
+}
+
+/* Open WSS for usage */
+boolean wss_open()
+{
+       __dpmi_meminfo struct_info;
+
+       if (!wss.ok)
+               if (!wss_detect())
+                       return FALSE;
+
+       if (wss.open)
+               return FALSE;
+
+       /* Now lock the wss structure in memory */
+       struct_info.address = __djgpp_base_address + (unsigned long)&wss;
+       struct_info.size = sizeof(wss);
+       if (__dpmi_lock_linear_region(&struct_info))
+               return FALSE;
+
+       /* Hook the WSS IRQ */
+       wss.irq_handle =
+         irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq);
+       if (!wss.irq_handle) {
+               __dpmi_unlock_linear_region(&struct_info);
+               return FALSE;
+       }
+
+       /* Enable the interrupt */
+       irq_enable(wss.irq_handle);
+       if (wss.irq > 7)
+               _irq_enable(2);
+
+       wss.open++;
+
+       return TRUE;
+}
+
+/* Finish working with WSS */
+boolean wss_close()
+{
+       __dpmi_meminfo struct_info;
+       if (!wss.open)
+               return FALSE;
+
+       wss.open--;
+
+       /* Stop/free DMA buffer */
+       wss_stop_dma();
+
+       /* Unhook IRQ */
+       irq_unhook(wss.irq_handle);
+       wss.irq_handle = NULL;
+
+       /* Unlock the wss structure */
+       struct_info.address = __djgpp_base_address + (unsigned long)&wss;
+       struct_info.size = sizeof(wss);
+       __dpmi_unlock_linear_region(&struct_info);
+
+       return TRUE;
+}
+
+/* Adjust frequency rate to nearest WSS available */
+unsigned int wss_adjust_freq(unsigned int freq)
+{
+       __wss_getrate(&freq);
+       return freq;
+}
+
+/* Enable/disable speaker output */
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+boolean wss_start_dma(unsigned char mode, unsigned int freq)
+{
+       int dmabuffsize;
+       unsigned char format;
+
+       /* Stop DMA transfer if it is enabled */
+       wss_stop_dma();
+
+       /* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */
+       if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED))
+               || (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED)))
+               return FALSE;
+
+       /* Find the nearest frequency divisor (rate) */
+       format = __wss_getrate(&freq);
+       wss.mode = mode;
+
+       /* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */
+       dmabuffsize = freq;
+       if (mode & WSSMODE_STEREO)
+               dmabuffsize *= 2;
+       if (mode & WSSMODE_16BITS)
+               dmabuffsize *= 2;
+       dmabuffsize >>= 2;
+       if (dmabuffsize < 4096)
+               dmabuffsize = 4096;
+       if (dmabuffsize > 32768)
+               dmabuffsize = 32768;
+       dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
+
+       wss.dma_buff = dma_allocate(wss.dma, dmabuffsize);
+       if (!wss.dma_buff)
+               return FALSE;
+
+       /* Fill DMA buffer with silence */
+       dmabuffsize = wss.dma_buff->size;
+       if (mode & WSSMODE_SIGNED)
+               memset(wss.dma_buff->linear, 0, dmabuffsize);
+       else
+               memset(wss.dma_buff->linear, 0x80, dmabuffsize);
+
+       /* Check data size and build a WSSR_PLAY_FORMAT value accordingly */
+       wss.samples = dmabuffsize;
+       if (mode & WSSMODE_16BITS) {
+               wss.samples >>= 1;
+               format |= WSSM_16BITS;
+       }
+
+       if (mode & WSSMODE_STEREO) {
+               wss.samples >>= 1;
+               format |= WSSM_STEREO;
+       }
+
+       if (!__wss_setformat(format)) {
+               wss_stop_dma();
+               return FALSE;
+       }
+
+       /* Prime DMA for transfer */
+       dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+
+       /* Tell codec how many samples to transfer */
+       wss.samples = (wss.samples >> 1) - 1;
+       __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
+       __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
+
+       /* Tell codec to start transfer */
+       __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+       return TRUE;
+}
+
+/* Stop playing from DMA buffer */
+void wss_stop_dma()
+{
+       if (!wss.dma_buff)
+               return;
+
+       __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+       dma_disable(wss.dma);
+       dma_free(wss.dma_buff);
+       wss.dma_buff = NULL;
+}
+
+/* Query current position/total size of the DMA buffer */
+void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
+{
+       unsigned int dma_left;
+       *dma_size = wss.dma_buff->size;
+       /* It can happen we try to read DMA count when HI/LO bytes will be
+          inconsistent */
+       for (;;) {
+               unsigned int dma_left_test;
+               dma_clear_ff(wss.dma);
+               dma_left_test = dma_get_count(wss.dma);
+               dma_left = dma_get_count(wss.dma);
+               if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
+                       break;
+       }
+       *dma_pos = *dma_size - dma_left;
+}
+
+void wss_output(boolean enable)
+{
+       if (enable)
+               wss.curlevel = wss.level;
+       else
+               wss.curlevel = 0x3f;
+
+       __wss_outreg(WSSR_MASTER_L, wss.curlevel);
+       __wss_outreg(WSSR_MASTER_R, wss.curlevel);
+}
+
+void wss_level(int level)
+{
+       if (level < 0)
+               level = 0;
+       if (level > 63)
+               level = 63;
+       wss.curlevel = wss.level = level ^ 63;
+
+       __wss_outreg(WSSR_MASTER_L, wss.curlevel);
+       __wss_outreg(WSSR_MASTER_R, wss.curlevel);
+}
+
+#endif /* DRV_WSS */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/doswss.h b/libs/mikmod/drivers/dos/doswss.h
new file mode 100644 (file)
index 0000000..ae77bb5
--- /dev/null
@@ -0,0 +1,217 @@
+/*     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$
+
+  Windows Sound System and compatible soundcards definitions
+
+==============================================================================*/
+
+#ifndef __DOSWSS_H__
+#define __DOSWSS_H__
+
+#include "dosdma.h"
+#include "dosirq.h"
+
+#define WSS_ADDR                       (wss.port + 0x04)
+#define WSS_DATA                       (wss.port + 0x05)
+#define WSS_STATUS                     (wss.port + 0x06)
+#define WSS_PIO                                (wss.port + 0x07)
+
+/* WSS_ADDR: Bits 0-4 select an internal register to read/write */
+#define WSSR_INPUT_L                   0x00    /* Left input control register */
+#define WSSR_INPUT_R                   0x01    /* RIght input control register */
+#define WSSR_AUX1_L                    0x02    /* Left Aux #1 input control */
+#define WSSR_AUX1_R                    0x03    /* Right Aux #1 input control */
+#define WSSR_CD_L                      0x04    /* Left Aux #2 input control */
+#define WSSR_CD_R                      0x05    /* Right Aux #2 input control */
+#define WSSR_MASTER_L                  0x06    /* Left output control */
+#define WSSR_MASTER_R                  0x07    /* Right output control */
+#define WSSR_PLAY_FORMAT               0x08    /* Clock and data format */
+#define WSSR_IFACE_CTRL                        0x09    /* Interface control */
+#define WSSR_PIN_CTRL                  0x0a    /* Pin control */
+#define WSSR_TEST_INIT                 0x0b    /* Test and initialization */
+#define WSSR_MISC_INFO                 0x0c    /* Miscellaneaous information */
+#define WSSR_LOOPBACK                  0x0d    /* Digital Mix */
+#define WSSR_COUNT_HIGH                        0x0e    /* Playback Upper Base Count */
+#define WSSR_COUNT_LOW                 0x0f    /* Playback Lower Base Count */
+#define WSSR_ALT_FEATURE_1             0x10    /* alternate #1 feature enable */
+#define WSSR_ALT_FEATURE_2             0x11    /* alternate #2 feature enable */
+#define WSSR_LINE_IN_L                 0x12    /* left line input control */
+#define WSSR_LINE_IN_R                 0x13    /* right line input control */
+#define WSSR_TIMER_LOW                 0x14    /* timer low byte */
+#define WSSR_TIMER_HIGH                        0x15    /* timer high byte */
+#define WSSR_IRQ_STATUS                        0x18    /* irq status register */
+#define WSSR_MONO_IO_CTRL              0x1a    /* mono input/output control */
+#define WSSR_REC_FORMAT                        0x1c    /* record format */
+#define WSSR_REC_COUNT_HIGH            0x1e    /* record upper count */
+#define WSSR_REC_COUNT_LOW             0x1f    /* record lower count */
+
+/* WSS_ADDR bits 7-5 definition */
+#define WSSM_INIT                      0x80    /* Codec is initializing */
+#define WSSM_MCE                       0x40    /* Mode change enable */
+#define WSSM_TRD                       0x20    /* Transfer Request Disable */
+/* bits 4-0 are indirect register address (0-15) */
+
+/* WSS_STATUS bit masks */
+#define WSSM_CUL                       0x80    /* Capture data upper/lower byte */
+#define WSSM_CLR                       0x40    /* Capture left/right sample */
+#define WSSM_CRDY                      0x20    /* Capture data read */
+#define WSSM_SOUR                      0x10    /* Playback over/under run error */
+#define WSSM_PUL                       0x08    /* Playback upper/lower byte */
+#define WSSM_PLR                       0x04    /* Playback left/right sample */
+#define WSSM_PRDY                      0x02    /* Playback data register read */
+#define WSSM_INT                       0x01    /* interrupt status */
+
+/* Definitions for output level registers */
+#define WSSM_MUTE                      0x80    /* Mute this output source */
+/* bits 5-0 are left output attenuation select (0-63) */
+/* bits 5-0 are right output attenuation select (0-63) */
+
+/* Definitions for clock and data format register (WSSR_PLAY_FORMAT) */
+#define WSSM_STEREO                    0x10    /* stero mode */
+#define WSSM_ULAW_8                    0x20    /* 8-bit U-law companded */
+#define WSSM_16BITS                    0x40    /* 16 bit twos complement data - little endian */
+#define WSSM_ALAW_8                    0x60    /* 8-bit A-law companded */
+#define WSSM_16BITS_BE                 0xc0    /* 16-bit twos complement data - big endian */
+#define WSSM_ADPCM_16                  0xa0    /* 16-bit ADPCM */
+/* Bits 3-1 define frequency divisor */
+#define WSSM_XTAL1                     0x00    /* 24.576 crystal */
+#define WSSM_XTAL2                     0x01    /* 16.9344 crystal */
+
+/* Definitions for interface control register (WSSR_IFACE_CTRL) */
+#define WSSM_CAPTURE_PIO               0x80    /* Capture PIO enable */
+#define WSSM_PLAYBACK_PIO              0x40    /* Playback PIO enable */
+#define WSSM_AUTOCALIB                 0x08    /* auto calibrate */
+#define WSSM_SINGLE_DMA                        0x04    /* Use single DMA channel */
+#define WSSM_PLAYBACK_ENABLE           0x01    /* playback enable */
+
+/* Definitions for Pin control register (WSSR_PIN_CTRL) */
+#define WSSM_IRQ_ENABLE                        0x02    /* interrupt enable */
+#define WSSM_XCTL1                     0x40    /* external control #1 */
+#define WSSM_XCTL0                     0x80    /* external control #0 */
+
+/* Definitions for WSSR_TEST_INIT register */
+#define WSSM_CALIB_IN_PROGRESS 0x20    /* auto calibrate in progress */
+
+/* Definitions for misc control register (WSR_MISC_INFO) */
+#define WSSM_MODE2                     0x40    /* MODE 2 */
+#define WSSM_MODE3                     0x6c    /* MODE 3 - enhanced mode */
+
+/* Definitions for codec irq status (WSSR_IRQ_STATUS) */
+#define WSSM_PLAYBACK_IRQ              0x10
+#define WSSM_RECORD_IRQ                        0x20
+#define WSSM_TIMER_IRQ                 0x40
+
+typedef unsigned char boolean;
+
+#ifndef FALSE
+#define FALSE                          0
+#define TRUE                           1
+#endif
+
+/* Play mode bits */
+#define WSSMODE_16BITS                 0x0001
+#define WSSMODE_STEREO                 0x0002
+#define WSSMODE_SIGNED                 0x0004
+
+/* You can fill some members of this struct (i.e. port,irq,dma) before
+ * calling wss_detect() or wss_open()... this will ignore environment settings.
+ */
+typedef struct __wss_state_s {
+       boolean ok;                     /* Set if this structure is properly filled */
+       int port;                       /* Base codec port */
+       int irq;                        /* codec IRQ */
+       int dma;                        /* codec DMA */
+       struct irq_handle *irq_handle;  /* The interrupt handler */
+       dma_buffer *dma_buff;           /* Pre-allocated DMA buffer */
+       unsigned char mode;             /* Current WSS mode (WSSMODE_XXX) */
+       boolean open;                   /* Whenever the card has been opened */
+       int samples;                    /* Number of samples in DMA buffer */
+       unsigned char level;            /* Output level (63..0): doesn't change when mute */
+       unsigned char curlevel;         /* Current output level (63(min)..0(max)) */
+       volatile int irqcount;          /* Incremented on each IRQ... for diagnostics */
+       void (*timer_callback) ();      /* Called TWICE per buffer play */
+} __wss_state;
+
+extern __wss_state wss;
+
+/* Wait until codec finishes initialization */
+static inline boolean __wss_wait()
+{
+       int count;
+       for (count = 10000; count >= 0; count--)
+               if (!(inportb(WSS_ADDR) & WSSM_INIT))
+                       return TRUE;
+       return FALSE;
+}
+
+static inline void __wss_outreg(unsigned char reg, unsigned char val)
+{
+       outportb(WSS_ADDR, reg);
+       outportb(WSS_DATA, val);
+}
+
+static inline unsigned char __wss_inreg(unsigned char reg)
+{
+       outportb(WSS_ADDR, reg);
+       return inportb(WSS_DATA);
+}
+
+/* Set some bits in a specific register */
+static inline void __wss_regbit_set(unsigned char reg, unsigned char mask)
+{
+       outportb(WSS_ADDR, reg);
+       outportb(WSS_DATA, inportb(WSS_DATA) | mask);
+}
+
+/* Reset some bits in a specific register */
+static inline void __wss_regbit_reset(unsigned char reg, unsigned char mask)
+{
+       outportb(WSS_ADDR, reg);
+       outportb(WSS_DATA, inportb(WSS_DATA) & ~mask);
+}
+
+/* Detect whenever WSS is present and fill "wss" structure */
+extern boolean wss_detect();
+/* Reset WSS */
+extern void wss_reset();
+/* Open WSS for usage */
+extern boolean wss_open();
+/* Finish working with WSS */
+extern boolean wss_close();
+/* Enable/disable speaker output */
+extern void wss_output(boolean enable);
+/* Adjust frequency rate to nearest WSS available */
+extern unsigned int wss_adjust_freq(unsigned int freq);
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+extern boolean wss_start_dma(unsigned char mode, unsigned int freq);
+/* Stop playing from DMA buffer */
+extern void wss_stop_dma();
+/* Query current position/total size of the DMA buffer */
+extern void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
+/* Set output level (0(min)-63(max)) */
+extern void wss_level(int level);
+
+#endif /* __DOSWSS_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/dos/libgus.h b/libs/mikmod/drivers/dos/libgus.h
new file mode 100644 (file)
index 0000000..0d66ee9
--- /dev/null
@@ -0,0 +1,402 @@
+/*     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$
+
+  Linux libGUS-alike library for DOS, used by drv_ultra.c under DOS.
+
+==============================================================================*/
+
+/*
+       Current limitations:
+       - Only a subset of libgus is supported
+       - Only one GUS card is supported (due to the fact that ULTRASND environment
+         variable is used)
+       - No Interwawe support (if IW works the old way, it's ok).
+*/
+
+#ifndef __LIBGUS_H__
+#define __LIBGUS_H__
+
+#include <stddef.h>
+
+#define __LITTLE_ENDIAN
+
+typedef struct _gus_info_t gus_info_t;
+typedef struct _gus_instrument_t gus_instrument_t;
+typedef struct _gus_wave_t gus_wave_t;
+typedef struct _gus_layer_t gus_layer_t;
+
+#define GUS_CARD_VERSION_CLASSIC       0x0024  /* revision 2.4 */
+#define GUS_CARD_VERSION_CLASSIC1      0x0034  /* revision 3.4? */
+#define GUS_CARD_VERSION_CLASSIC_ICS   0x0037  /* revision 3.7 (ICS mixer) */
+#define GUS_CARD_VERSION_EXTREME       0x0050  /* GUS Extreme */
+#define GUS_CARD_VERSION_ACE           0x0090  /* GUS ACE */
+#define GUS_CARD_VERSION_MAX           0x00a0  /* GUS MAX - revision 10 */
+#define GUS_CARD_VERSION_MAX1          0x00a1  /* GUS MAX - revision 11 */
+#define GUS_CARD_VERSION_PNP           0x0100  /* GUS Plug & Play */
+
+#define GUS_STRU_INFO_F_DB16           0x00000001      /* 16-bit daughter board present */
+#define GUS_STRU_INFO_F_PCM            0x00000004      /* GF1 PCM during SYNTH enabled */
+#define GUS_STRU_INFO_F_ENHANCED       0x00000008      /* InterWave - enhanced mode */
+#define GUS_STRU_INFO_F_DAEMON         0x00000010      /* instrument daemon is present */
+
+struct _gus_info_t {
+       unsigned char id[8];            /* id of this card (warning! maybe unterminated!!!) */
+
+       unsigned int flags;             /* some info flags - see to GUS_STRU_INFO_F_XXXX */
+       unsigned int version;           /* see to GUS_CARD_VERSION_XXXX constants */
+
+       unsigned short port;
+       unsigned short irq;
+       unsigned short dma1;            /* DMA1 - GF1 download & codec record */
+       unsigned short dma2;            /* DMA2 - GF1 record & codec playback */
+
+       unsigned int mixing_freq;       /* mixing frequency in Hz */
+
+       unsigned int memory_size;       /* in bytes */
+       unsigned int memory_free;       /* in bytes */
+       unsigned int memory_block_8;    /* largest free 8-bit block in memory */
+       unsigned int memory_block_16;   /* largest free 16-bit block in memory */
+};
+
+/* struct gus_instrument_t - mode */
+
+#define GUS_INSTR_SIMPLE       0x00    /* simple format - for MOD players */
+#define GUS_INSTR_PATCH                0x01    /* old GF1 patch format */
+#define GUS_INSTR_COUNT                2
+
+#define GUS_INSTR_F_NORMAL     0x0000  /* normal mode */
+#define GUS_INSTR_F_NOT_FOUND  0x0001  /* instrument can't be loaded */
+#define GUS_INSTR_F_ALIAS      0x0002  /* alias */
+#define GUS_INSTR_F_NOT_LOADED 0x00ff  /* instrument not loaded (not found) */
+
+#define GUS_INSTR_E_NONE       0x0000  /* exclusion mode - none */
+#define GUS_INSTR_E_SINGLE     0x0001  /* exclude single - single note from this instrument */
+#define GUS_INSTR_E_MULTIPLE   0x0002  /* exclude multiple - stop only same note from this instrument */
+
+#define GUS_INSTR_L_NONE       0x0000  /* not layered */
+#define GUS_INSTR_L_ON         0x0001  /* layered */
+#define GUS_INSTR_L_VELOCITY   0x0002  /* layered by velocity */
+#define GUS_INSTR_L_FREQUENCY  0x0003  /* layered by frequency */
+
+struct _gus_instrument_t {
+       union {
+               unsigned int instrument;/* instrument number */
+       } number;
+
+       char *name;                     /* name of this instrument or NULL */
+
+       unsigned int mode:8,            /* see to GUS_INSTR_XXXX */
+           flags:8,                    /* see to GUS_INSTR_F_XXXX */
+           exclusion:4,                /* see to GUS_INSTR_E_XXXX */
+           layer:4;                    /* see to GUS_INSTR_L_XXXX */
+       unsigned short exclusion_group; /* 0 - none, 1-65535 */
+
+       struct {
+               unsigned char effect1:4,/* use global effect if available */
+                   effect2:4;          /* use global effect if available */
+               unsigned char effect1_depth;/* 0-127 */
+               unsigned char effect2_depth;/* 0-127 */
+       } patch;
+
+       union {
+               gus_layer_t *layer;     /* first layer */
+               unsigned int alias;     /* pointer to instrument */
+       } info;
+       gus_instrument_t *next;         /* next instrument */
+};
+
+struct _gus_layer_t {
+       unsigned char mode;             /* see to GUS_INSTR_XXXX constants */
+
+       gus_wave_t *wave;
+       gus_layer_t *next;
+};
+
+/* bits for format variable in gus_wave_t */
+
+#define GUS_WAVE_16BIT          0x0001 /* 16-bit wave */
+#define GUS_WAVE_UNSIGNED       0x0002 /* unsigned wave */
+#define GUS_WAVE_INVERT         0x0002 /* same as unsigned wave */
+#define GUS_WAVE_BACKWARD       0x0004 /* forward mode */
+#define GUS_WAVE_LOOP           0x0008 /* loop mode */
+#define GUS_WAVE_BIDIR          0x0010 /* bidirectional mode */
+#define GUS_WAVE_ULAW           0x0020 /* uLaw compressed wave */
+#define GUS_WAVE_RAM            0x0040 /* wave is _preloaded_ in RAM (it is used for ROM simulation) */
+#define GUS_WAVE_ROM            0x0080 /* wave is in ROM */
+#define GUS_WAVE_DELTA          0x0100
+
+#define GUS_WAVE_PATCH_ENVELOPE 0x01   /* envelopes on */
+#define GUS_WAVE_PATCH_SUSTAIN  0x02   /* sustain mode */
+
+struct _gus_wave_t {
+       unsigned char mode;             /* see to GUS_INSTR_XXXX constants */
+       unsigned char format;           /* see to GUS_WAVE_XXXX constants */
+       unsigned int size;              /* size of waveform in bytes */
+       unsigned int start;             /* start offset in bytes * 16 (lowest 4 bits - fraction) */
+       unsigned int loop_start;        /* bits loop start offset in bytes * 16 (lowest 4 bits - fraction) */
+       unsigned int loop_end;          /* loop start offset in bytes * 16 (lowest 4 bits - fraction) */
+       unsigned short loop_repeat;     /* loop repeat - 0 = forever */
+       struct {
+               unsigned int memory;    /* begin of waveform in GUS's memory */
+               unsigned char *ptr;     /* pointer to waveform in system memory */
+       } begin;
+
+       struct {
+               unsigned char flags;
+               unsigned int sample_rate;
+               unsigned int low_frequency;/* low frequency range for this waveform */
+               unsigned int high_frequency;/* high frequency range for this waveform */
+               unsigned int root_frequency;/* root frequency for this waveform */
+               signed short tune;
+               unsigned char balance;
+               unsigned char envelope_rate[6];
+               unsigned char envelope_offset[6];
+               unsigned char tremolo_sweep;
+               unsigned char tremolo_rate;
+               unsigned char tremolo_depth;
+               unsigned char vibrato_sweep;
+               unsigned char vibrato_rate;
+               unsigned char vibrato_depth;
+               unsigned short scale_frequency;
+               unsigned short scale_factor;/* 0-2048 or 0-2 */
+       } patch;
+
+       gus_wave_t *next;
+};
+
+/* defines for gus_memory_reset () */
+#define GUS_DOWNLOAD_MODE_NORMAL 0x0000
+#define GUS_DOWNLOAD_MODE_TEST  0x0001
+
+/*
+    A subset of libgus functions (used by MikMod Ultrasound driver)
+*/
+int gus_cards(void);
+  /*
+   * return value:      number of GUS cards installed in system or
+   *                    zero if driver isn't installed
+   */
+int gus_close(int card);
+  /*
+   * close file (gus synthesizer) previously opened with gusOpen function
+   * return value:      zero if success
+   */
+int gus_do_flush(void);
+  /*
+   * return value:      zero if command queue was successfully flushed
+   *                    in non block mode - number of written bytes
+   */
+void gus_do_tempo(unsigned int tempo);
+  /*
+   * set new tempo
+   */
+void gus_do_voice_frequency(unsigned char voice, unsigned int freq);
+  /*
+   * set voice frequency in Hz
+   */
+void gus_do_voice_pan(unsigned char voice, unsigned short pan);
+  /*
+   * set voice pan (0-16384) (full left - full right)
+   */
+void gus_do_voice_start(unsigned char voice, unsigned int program,
+                        unsigned int freq, unsigned short volume,
+                        unsigned short pan);
+  /*
+   * start voice
+   *            voice    : voice #
+   *            program  : program # or ~0 = current
+   *            freq     : frequency in Hz
+   *            volume   : volume level (0-16384) or ~0 = current
+   *            pan      : pan level (0-16384) or ~0 = current
+   */
+void gus_do_voice_start_position(unsigned char voice, unsigned int program,
+                                 unsigned int freq, unsigned short volume,
+                                 unsigned short pan, unsigned int position);
+  /*
+   * start voice
+   *            voice    : voice #
+   *            program  : program # or ~0 = current
+   *            freq     : frequency in Hz
+   *            volume   : volume level (0-16384) or ~0 = current
+   *            pan      : pan level (0-16384) or ~0 = current
+   *            position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
+   */
+void gus_do_voice_stop(unsigned char voice, unsigned char mode);
+  /*
+   * stop voice
+   *            mode = 0 : stop voice now
+   *            mode = 1 : disable wave loop and finish it
+   */
+void gus_do_voice_volume(unsigned char voice, unsigned short vol);
+  /*
+   * set voice volume level 0-16384 (linear)
+   */
+void gus_do_wait(unsigned int ticks);
+  /*
+   * wait x ticks - this command is block separator
+   * all commands between blocks are interpreted in the begining of one tick
+   */
+int gus_get_voice_status(int voice);
+  /*
+   * THIS IS NOT A FUNCTION OF ORIGINAL libGUS!
+   * Return voice status: -1 on error, 0 if voice stopped, 1 if playing
+   */
+int gus_get_handle(void);
+  /*
+   * return value:      file handle (descriptor) for /dev/gus
+   */
+int gus_info(gus_info_t * info, int reread);
+  /*
+   * return value:      filled info variable with actual values
+   *                    (look at gus.h header file for more informations)
+   * version field:     0x0024  - GUS revision 2.4
+   *                    0x0035  - GUS revision 3.7 with flipped mixer channels
+   *                    0x0037  - GUS revision 3.7
+   *                    0x0090  - GUS ACE
+   *                    0x00a0  - GUS MAX revision 10
+   *                    0x00a1  - GUS MAX revision 11
+   *                    0x0100  - InterWave (full version)
+   * flags field:       see to GUS_STRU_INFO_F_???? constants (gus.h header file)
+   * port field:        port number (for example 0x220)
+   * irq field:         irq number (for example 11)
+   * dma1 field:        dma1 number (for example 5)
+   * dma2 field:        dma2 number (for example 6)
+   * note:              dma1 and dma2 could be same in case of only one dma channel used
+   */
+int gus_memory_alloc(gus_instrument_t * instrument);
+  /*
+   * input value:       look at gus.h for more details about gus_instrument_t structure
+   * return value:      zero if instrument was successfully allocated
+   */
+int gus_memory_free(gus_instrument_t * instrument);
+  /*
+   * input value:       look at gus.h for more details about gus_instrument_t structure
+   * return value:      zero if instrument was successfully removed
+   */
+int gus_memory_size(void);
+  /*
+   * return value:  gus memory size in bytes
+   */
+int gus_memory_free_size(void);
+  /*
+   * return value:      unused gus memory in bytes
+   * warning:           reset function must be called before
+   */
+int gus_memory_free_block(int w_16bit);
+  /*
+   * return value:  current largest free block for 8-bit or 16-bit wave
+   */
+int gus_memory_pack(void);
+  /*
+   * return value:      zero if success
+   */
+int gus_memory_reset(int mode);
+  /*
+   * input value:   see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
+   * return value:  zero if samples & instruments was successfully removed
+   *            from GF1 memory manager
+   */
+
+int gus_open(int card, size_t queue_buffer_size, int non_block);
+  /*
+   * input values:      card number,
+   *                    size of command queue buffer (512-1MB)
+   *                    buffer is allocated dynamically,
+   *                    non block mode
+   * return value:      zero if success
+   * note 1:            this function must be called as first
+   *                    open file /dev/gus
+   * note 2:            you can open more cards with one process
+   */
+int gus_queue_flush(void);
+  /*
+   * return value:      zero if command queue was successfully flushed
+   */
+int gus_queue_read_set_size(int items);
+  /*
+   * input value:       echo buffer size in items (if 0 - erase echo buffer)
+   */
+int gus_queue_write_set_size(int items);
+  /*
+   * input value:       write queue size in items (each item have 8 bytes)
+   */
+int gus_reset(int voices, unsigned int channel_voices);
+  /*
+   * input values:      active voices and channel voices (for dynamic allocation)
+   * return value:      number of active voices if reset was successfull (GF1 chip active)
+   */
+int gus_reset_engine_only(void);
+  /*
+   * return value:  same as gus_reset function
+   * note:      this command doesn't change number of active
+   *            voices and doesn't do hardware reset
+   */
+int gus_select(int card);
+  /*
+   * select specified card
+   * return value:      zero if success
+   */
+int gus_timer_start(void);
+  /*
+   * return value:      zero if successfull
+   */
+int gus_timer_stop(void);
+  /*
+   * return value:      zero if timer was stoped
+   */
+int gus_timer_continue(void);
+  /*
+   * return value:  zero if timer will be continue
+   */
+int gus_timer_tempo(int ticks);
+  /*
+   * return value:      zero if setup was success
+   */
+int gus_timer_base(int base);
+  /*
+   * return value:  zero if setup was success (default timebase = 100)
+   */
+
+void gus_convert_delta(unsigned int type, unsigned char *dest,
+                       unsigned char *src, size_t size);
+  /*
+   * note: dest and src pointers can be equal
+   */
+
+void gus_timer_callback(void (*timer_callback) ());
+  /*
+   * Set a callback to be called once per tempo tick
+   */
+
+int gus_dma_usage (int use);
+  /*
+   * Tell GUS library to use/to not use DMA for sample transfer.
+   * In some environments/on some hardware platforms you will need
+   * to disable DMA in order to function properly. You should call
+   * this function before opening the card.
+   */
+
+#endif /* __LIBGUS_H__ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/drv_oss.c b/libs/mikmod/drivers/drv_oss.c
new file mode 100644 (file)
index 0000000..64957f7
--- /dev/null
@@ -0,0 +1,417 @@
+/*     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$
+
+  Driver for output on Linux and FreeBSD Open Sound System (OSS) (/dev/dsp)
+
+==============================================================================*/
+
+/*
+
+       Written by Chris Conn <cconn@tohs.abacom.com>
+
+       Extended by Miodrag Vallat:
+       - compatible with all OSS/Voxware versions on Linux/i386, at least
+       - support for uLaw output (for sparc systems)
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+#ifdef DRV_OSS
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOUNDCARD_H
+#include <sys/soundcard.h> /* Linux and newer BSD versions - OSS standart */
+#elif defined(HAVE_MACHINE_SOUNDCARD_H)
+#include <machine/soundcard.h> /*  Some old BSD versions */
+#elif defined(HAVE_SOUNDCARD_H)
+#include <soundcard.h> /* Some old BSD versions and also newer OpenBSD versions */
+#endif
+
+/* Compatibility with old versions of OSS
+   (Voxware <= 2.03, Linux kernel < 1.1.31) */
+#ifndef AFMT_S16_LE
+#define AFMT_S16_LE 16
+#endif
+#ifndef AFMT_S16_BE
+#define AFMT_S16_BE 0x20
+#endif
+#ifndef AFMT_U8
+#define AFMT_U8 8
+#endif
+#ifndef SNDCTL_DSP_SETFMT
+#define SNDCTL_DSP_SETFMT SNDCTL_DSP_SAMPLESIZE
+#endif
+
+/* Compatibility with not-so-old versions of OSS
+   (OSS < 3.7, Linux kernel < 2.1.16) */
+#ifndef AFMT_S16_NE
+#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(HPPA) || defined(PPC)
+#define AFMT_S16_NE AFMT_S16_BE
+#else
+#define AFMT_S16_NE AFMT_S16_LE
+#endif
+#endif
+
+/* Compatibility with OSS 4.x: AFMT_FLOAT is documented
+   as "not recommended" on the OSS website.  This post
+   on the OSS mailing lists says: "In general AFMT_FLOAT
+   is not supported by OSS except in some special cases."
+   (http://sf.net/p/opensound/mailman/message/28840674/) */
+#ifndef AFMT_FLOAT
+#define AFMT_FLOAT 0x00004000
+#endif
+
+static int sndfd=-1;
+static SBYTE *audiobuffer=NULL;
+static int buffersize;
+static int play_precision;
+
+#define DEFAULT_CARD 0
+static int card=DEFAULT_CARD;
+
+#ifdef SNDCTL_DSP_SETFRAGMENT
+
+#define DEFAULT_FRAGSIZE 14
+#define DEFAULT_NUMFRAGS 16
+
+static int fragsize=DEFAULT_FRAGSIZE;
+static int numfrags=DEFAULT_NUMFRAGS;
+
+#endif
+
+static void OSS_CommandLine(const CHAR *cmdline)
+{
+       CHAR *ptr;
+
+#ifdef SNDCTL_DSP_SETFRAGMENT
+       if((ptr=MD_GetAtom("buffer",cmdline,0)) != NULL) {
+               fragsize=atoi(ptr);
+               if((fragsize<7)||(fragsize>17)) fragsize=DEFAULT_FRAGSIZE;
+               MikMod_free(ptr);
+       }
+       if((ptr=MD_GetAtom("count",cmdline,0)) != NULL) {
+               numfrags=atoi(ptr);
+               if((numfrags<2)||(numfrags>255)) numfrags=DEFAULT_NUMFRAGS;
+               MikMod_free(ptr);
+       }
+#endif
+       if((ptr=MD_GetAtom("card",cmdline,0)) != NULL) {
+               card = atoi(ptr);
+               if((card<0)||(card>99)) card=DEFAULT_CARD;
+               MikMod_free(ptr);
+       }
+}
+
+static char *OSS_GetDeviceName(void)
+{
+       static char sounddevice[20];
+
+       /* First test for devfs enabled Linux sound devices */
+       if (card)
+               sprintf(sounddevice,"/dev/sound/dsp%d",card);
+       else
+               strcpy(sounddevice,"/dev/sound/dsp");
+       if(!access(sounddevice,F_OK))
+               return sounddevice;
+
+       sprintf(sounddevice,"/dev/dsp%d",card);
+       if (!card) {
+               /* prefer /dev/dsp0 over /dev/dsp, as /dev/dsp might be a symbolic link
+                  to something else than /dev/dsp0. Revert to /dev/dsp if /dev/dsp0
+                  does not exist. */
+               if(access("/dev/dsp0",F_OK))
+                       strcpy(sounddevice,"/dev/dsp");
+       }
+
+       return sounddevice;
+}
+
+static BOOL OSS_IsThere(void)
+{
+       /* under Linux, and perhaps other Unixes, access()ing the device is not
+          enough since it won't fail if the machine doesn't have sound support
+          in the kernel or sound hardware                                      */
+       int fd;
+
+       if((fd=open(OSS_GetDeviceName(),O_WRONLY|O_NONBLOCK))>=0) {
+               close(fd);
+               return 1;
+       }
+       return (errno==EACCES?1:0);
+}
+
+static int OSS_Init_internal(void)
+{
+       int play_stereo,play_rate;
+       int orig_precision,orig_stereo;
+       int formats;
+#if SOUND_VERSION >= 301
+       audio_buf_info buffinf;
+#endif
+
+#ifdef SNDCTL_DSP_GETFMTS
+       /* Ask device for supported formats */
+       if(ioctl(sndfd,SNDCTL_DSP_GETFMTS,&formats)<0) {
+               _mm_errno=MMERR_OPENING_AUDIO;
+               return 1;
+       }
+#else
+       formats=AFMT_S16_NE|AFMT_U8;
+#endif
+
+       orig_precision=play_precision=(md_mode&DMODE_FLOAT)? AFMT_FLOAT :
+                                       (md_mode&DMODE_16BITS)? AFMT_S16_NE : AFMT_U8;
+
+    /* Device does not support the format we would prefer... */
+    if(!(formats & play_precision)) {
+        if(play_precision==AFMT_FLOAT) {
+            _mm_errno=MMERR_NO_FLOAT32;
+            return 1;
+        }
+        /* We could try 8 bit sound if available */
+        if(play_precision==AFMT_S16_NE &&(formats&AFMT_U8)) {
+            _mm_errno=MMERR_8BIT_ONLY;
+            return 1;
+        }
+#ifdef AFMT_MU_LAW
+        /* We could try uLaw if available */
+        if(formats&AFMT_MU_LAW) {
+            if((md_mode&DMODE_STEREO)||(md_mode&DMODE_16BITS)||
+                md_mixfreq!=8000) {
+                _mm_errno=MMERR_ULAW;
+                return 1;
+            } else
+                orig_precision=play_precision=AFMT_MU_LAW;
+        } else
+#endif
+            /* Otherwise, just abort */
+        {
+            _mm_errno=MMERR_OSS_SETSAMPLESIZE;
+            return 1;
+        }
+    }
+
+       if((ioctl(sndfd,SNDCTL_DSP_SETFMT,&play_precision)<0)||
+          (orig_precision!=play_precision)) {
+               _mm_errno=MMERR_OSS_SETSAMPLESIZE;
+               return 1;
+       }
+#ifdef SNDCTL_DSP_CHANNELS
+       orig_stereo=play_stereo=(md_mode&DMODE_STEREO)?2:1;
+       if((ioctl(sndfd,SNDCTL_DSP_CHANNELS,&play_stereo)<0)||
+          (orig_stereo!=play_stereo)) {
+               _mm_errno=MMERR_OSS_SETSTEREO;
+               return 1;
+       }
+#else
+       orig_stereo=play_stereo=(md_mode&DMODE_STEREO)?1:0;
+       if((ioctl(sndfd,SNDCTL_DSP_STEREO,&play_stereo)<0)||
+          (orig_stereo!=play_stereo)) {
+               _mm_errno=MMERR_OSS_SETSTEREO;
+               return 1;
+       }
+#endif
+
+       play_rate=md_mixfreq;
+       if((ioctl(sndfd,SNDCTL_DSP_SPEED,&play_rate)<0)) {
+               _mm_errno=MMERR_OSS_SETSPEED;
+               return 1;
+       }
+       md_mixfreq=play_rate;
+
+#if SOUND_VERSION >= 301
+       /* This call fails on Linux/PPC */
+       if((ioctl(sndfd,SNDCTL_DSP_GETOSPACE,&buffinf)<0))
+               ioctl(sndfd,SNDCTL_DSP_GETBLKSIZE,&buffinf.fragsize);
+       if(!(audiobuffer=(SBYTE*)MikMod_malloc(buffinf.fragsize)))
+               return 1;
+
+       buffersize = buffinf.fragsize;
+#else
+       ioctl(sndfd,SNDCTL_DSP_GETBLKSIZE,&buffersize);
+       if(!(audiobuffer=(SBYTE*)MikMod_malloc(buffersize)))
+               return 1;
+#endif
+
+       return VC_Init();
+}
+
+static int OSS_Init(void)
+{
+#ifdef SNDCTL_DSP_SETFRAGMENT
+       int fragmentsize;
+#endif
+
+       if((sndfd=open(OSS_GetDeviceName(),O_WRONLY))<0) {
+               _mm_errno=MMERR_OPENING_AUDIO;
+               return 1;
+       }
+
+#ifdef SNDCTL_DSP_SETFRAGMENT
+       if((fragsize==DEFAULT_FRAGSIZE)&&(getenv("MM_FRAGSIZE"))) {
+               fragsize=atoi(getenv("MM_FRAGSIZE"));
+               if((fragsize<7)||(fragsize>17)) fragsize=DEFAULT_FRAGSIZE;
+       }
+       if((numfrags==DEFAULT_NUMFRAGS)&&(getenv("MM_NUMFRAGS"))) {
+               numfrags=atoi(getenv("MM_NUMFRAGS"));
+               if((numfrags<2)||(numfrags>255)) numfrags=DEFAULT_NUMFRAGS;
+       }
+
+       fragmentsize=(numfrags<<16)|fragsize;
+
+       if(ioctl(sndfd,SNDCTL_DSP_SETFRAGMENT,&fragmentsize)<0) {
+               _mm_errno=MMERR_OSS_SETFRAGMENT;
+               return 1;
+       }
+#endif
+
+       return OSS_Init_internal();
+}
+
+static void OSS_Exit_internal(void)
+{
+       VC_Exit();
+       MikMod_free(audiobuffer);
+       audiobuffer = NULL;
+}
+
+static void OSS_Exit(void)
+{
+       OSS_Exit_internal();
+
+       if (sndfd>=0) {
+               close(sndfd);
+               sndfd=-1;
+       }
+}
+
+static void OSS_PlayStop(void)
+{
+       VC_PlayStop();
+
+       ioctl(sndfd,SNDCTL_DSP_POST,0);
+}
+
+static void OSS_Update(void)
+{
+       int done;
+
+#if SOUND_VERSION >= 301
+       audio_buf_info buffinf;
+
+       buffinf.fragments = 2;
+       for(;;) {
+               /* This call fails on Linux/PPC */
+               if ((ioctl(sndfd,SNDCTL_DSP_GETOSPACE,&buffinf)<0)) {
+                       buffinf.fragments--;
+                       buffinf.fragsize = buffinf.bytes = buffersize;
+               }
+               if(!buffinf.fragments)
+                       break;
+               done=VC_WriteBytes(audiobuffer,buffinf.fragsize>buffinf.bytes?
+                                                  buffinf.bytes:buffinf.fragsize);
+#ifdef AFMT_MU_LAW
+               if (play_precision==AFMT_MU_LAW)
+                       unsignedtoulaw((char *)audiobuffer,done);
+#endif
+               write(sndfd,audiobuffer,done);
+       }
+#else
+       done=VC_WriteBytes(audiobuffer,buffersize);
+#ifdef AFMT_MU_LAW
+       if (play_precision==AFMT_MU_LAW)
+               unsignedtoulaw(audiobuffer,done);
+#endif
+       write(sndfd,audiobuffer,done);
+#endif
+}
+
+static int OSS_Reset(void)
+{
+       OSS_Exit_internal();
+       ioctl(sndfd,SNDCTL_DSP_RESET,0);
+       return OSS_Init_internal();
+}
+
+MIKMODAPI MDRIVER drv_oss={
+       NULL,
+       "Open Sound System",
+       "Open Sound System driver v1.7",
+       0,255,
+       "oss",
+#ifdef SNDCTL_DSP_SETFRAGMENT
+       "buffer:r:7,17,14:Audio buffer log2 size\n"
+       "count:r:2,255,16:Audio buffer count\n"
+#endif
+       "card:r:0,99,0:Sound card id\n",
+       OSS_CommandLine,
+       OSS_IsThere,
+       VC_SampleLoad,
+       VC_SampleUnload,
+       VC_SampleSpace,
+       VC_SampleLength,
+       OSS_Init,
+       OSS_Exit,
+       OSS_Reset,
+       VC_SetNumVoices,
+       VC_PlayStart,
+       OSS_PlayStop,
+       OSS_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_oss);
+
+#endif
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/drv_sb.c b/libs/mikmod/drivers/drv_sb.c
new file mode 100644 (file)
index 0000000..a0c65c6
--- /dev/null
@@ -0,0 +1,235 @@
+/*     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$
+
+  Driver for SoundBlaster/Pro/16/AWE32 under DOS
+
+==============================================================================*/
+
+/*
+
+       Written by Andrew Zabolotny <bit@eltech.ru>
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_SB
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "mikmod_internals.h"
+
+#include "dossb.h"
+
+static void SB_CommandLine(const CHAR *cmdline)
+{
+       char *ptr, *end;
+
+       if ((ptr=MD_GetAtom("port",cmdline,0)) != NULL) {
+               sb.port = strtol(ptr, &end, 16);
+               MikMod_free(ptr);
+       }
+       if ((ptr=MD_GetAtom("irq",cmdline,0)) != NULL) {
+               sb.irq = strtol(ptr, &end, 10);
+               MikMod_free(ptr);
+       }
+       if ((ptr=MD_GetAtom("dma",cmdline,0)) != NULL) {
+               sb.dma8 = strtol(ptr, &end, 10);
+               MikMod_free(ptr);
+       }
+       if ((ptr=MD_GetAtom("hidma",cmdline,0)) != NULL) {
+               sb.dma16 = strtol(ptr, &end, 10);
+               MikMod_free(ptr);
+       }
+}
+
+static BOOL SB_IsThere(void)
+{
+       return sb_detect();
+}
+
+static int SB_Init(void)
+{
+       if (!sb_open()) {
+               _mm_errno = MMERR_INVALID_DEVICE;
+               return 1;
+       }
+
+       /* Adjust md_mode according to sound card capabilities */
+       if (!(sb.caps & SBMODE_STEREO))
+               md_mode &= ~DMODE_STEREO;
+       if (!(sb.caps & SBMODE_16BITS))
+               md_mode &= ~DMODE_16BITS;
+
+       if (md_mixfreq < 4000)
+               md_mixfreq = 4000;
+       if (md_mode & DMODE_STEREO) {
+               if (md_mixfreq > sb.maxfreq_stereo)
+                       md_mixfreq = sb.maxfreq_stereo;
+       } else {
+               if (md_mixfreq > sb.maxfreq_mono)
+                       md_mixfreq = sb.maxfreq_mono;
+       }
+
+       return VC_Init();
+}
+
+static void SB_Exit(void)
+{
+       VC_Exit();
+       sb_close();
+}
+
+/* The last buffer byte filled with sound */
+static unsigned int buff_tail = 0;
+
+static void SB_Callback(void)
+{
+       unsigned int dma_size, dma_pos;
+       ULONG (*mixer)(SBYTE *buf, ULONG todo);
+
+       sb_query_dma(&dma_size, &dma_pos);
+       /* There isn't much sense in filling less than 256 bytes */
+       dma_pos &= ~255;
+
+       /* If nothing to mix, quit */
+       if (buff_tail == dma_pos)
+               return;
+
+       if (Player_Paused_internal())
+               mixer = VC_SilenceBytes;
+       else
+               mixer = VC_WriteBytes;
+
+       /* If DMA pointer still didn't wrapped around ... */
+       if (dma_pos > buff_tail) {
+               buff_tail += mixer ((SBYTE *)(sb.dma_buff->linear + buff_tail), dma_pos - buff_tail);
+               /* If we arrived right to the DMA buffer end, jump to the beginning */
+               if (buff_tail >= dma_size)
+                       buff_tail = 0;
+       } else {
+               /* If wrapped around, fill first to the end of buffer */
+               mixer ((SBYTE *)(sb.dma_buff->linear + buff_tail), dma_size - buff_tail);
+               /* Now fill from buffer beginning to current DMA pointer */
+               buff_tail = mixer ((SBYTE *)sb.dma_buff->linear, dma_pos);
+       }
+}
+
+static void SB_Update(void)
+{
+       /* Do nothing: the real update is done during SB interrupts */
+}
+
+static int SB_PlayStart (void)
+{
+       if (VC_PlayStart())
+               return 1;
+
+       /* Enable speaker output */
+       sb_output(TRUE);
+
+       /* Set our routine to be called during SB IRQs */
+       buff_tail = 0;
+       sb.timer_callback = SB_Callback;
+
+       /* Start cyclic DMA transfer */
+       if (!sb_start_dma(((md_mode & DMODE_16BITS) ? SBMODE_16BITS | SBMODE_SIGNED : 0) |
+               ((md_mode & DMODE_STEREO) ? SBMODE_STEREO : 0), md_mixfreq))
+       {
+               _mm_errno = MMERR_DOSSB_STARTDMA;
+               return 1;
+       }
+
+       return 0;
+}
+
+static int SB_Reset(void)
+{
+       sb_reset();
+       VC_Exit();
+       return VC_Init();
+}
+
+static void SB_PlayStop(void)
+{
+       sb.timer_callback = NULL;
+       sb_output(FALSE);
+       sb_stop_dma();
+       VC_PlayStop();
+}
+
+MDRIVER drv_sb =
+{
+       NULL,
+       "Sound Blaster",
+       "Sound Blaster Orig/2.0/Pro/16 v1.0",
+       0, 255,
+       "sb",
+       "port:c:220,230,240,250,260,270,280,32C,530,604,E80,F40,220:Sound Blaster base I/O port\n"
+       "irq:c:2,3,5,7,10,5:Sound Blaster IRQ\n"
+       "dma:c:0,1,3,1:Sound Blaster 8 bit DMA channel\n"
+       "hidma:c:5,6,7,5:Sound Blaster 16 bit DMA channel (SB16/AWE32 only)\n",
+
+       SB_CommandLine,
+       SB_IsThere,
+       VC_SampleLoad,
+       VC_SampleUnload,
+       VC_SampleSpace,
+       VC_SampleLength,
+       SB_Init,
+       SB_Exit,
+       SB_Reset,
+       VC_SetNumVoices,
+       SB_PlayStart,
+       SB_PlayStop,
+       SB_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 /* DRV_SB */
+
+#include "mikmod_internals.h"
+MISSING(drv_sb);
+
+#endif
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/drivers/drv_sdl.c b/libs/mikmod/drivers/drv_sdl.c
new file mode 100644 (file)
index 0000000..e5a1ba2
--- /dev/null
@@ -0,0 +1,205 @@
+/*  MikMod sound library
+    (c) 1998-2005 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.
+    */
+
+/*==============================================================================
+
+  libmikmod driver for audio output on SDL-supported platforms.
+  Initially written by Paul Spark <sparkynz74@gmail.com>
+  Rewrite/major fixes by O. Sezer <sezero@users.sourceforge.net>
+
+  ==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+#ifdef DRV_SDL
+
+#include <string.h>
+#if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG)
+#include <SDL/SDL.h>
+#else
+#include "SDL.h"
+#endif
+
+#define NUMSAMPLES 256 /* a fair default for md_mixfreq <= 11025 Hz */
+static SDL_AudioSpec spec;
+static int enabled = 0;
+
+static void SDLSoundCallback(void *userdata, Uint8 *stream, int len)
+{
+    if (!enabled) return;
+    if (enabled < 0) {
+        if (++enabled == 0)
+            enabled = 1;
+        return;
+    }
+
+    MUTEX_LOCK(vars);
+    if (Player_Paused_internal()) {
+        VC_SilenceBytes((SBYTE *) stream, (ULONG)len);
+    }
+    else
+    {
+        int got = (int) VC_WriteBytes((SBYTE *) stream, (ULONG)len);
+        if (got < len) {       /* fill the rest with silence, then */
+            VC_SilenceBytes((SBYTE *) &stream[got], (ULONG)(len-got));
+        }
+    }
+    MUTEX_UNLOCK(vars);
+}
+
+static BOOL SetupSDLAudio(void)
+{
+    SDL_AudioSpec wanted;
+
+    wanted.freq     = md_mixfreq;
+    wanted.format   =
+#if (SDL_MAJOR_VERSION >= 2)
+                      (md_mode & DMODE_FLOAT) ? AUDIO_F32SYS :
+#endif
+                      (md_mode & DMODE_16BITS)? AUDIO_S16SYS : AUDIO_U8;
+    wanted.channels = (md_mode & DMODE_STEREO)? 2 : 1;
+    wanted.samples  = (md_mixfreq <= 11025)? (NUMSAMPLES    ) :
+                      (md_mixfreq <= 22050)? (NUMSAMPLES * 2) :
+                      (md_mixfreq <= 44100)? (NUMSAMPLES * 4) :
+                                             (NUMSAMPLES * 8);
+    wanted.userdata = NULL;
+    wanted.callback = SDLSoundCallback;
+
+    if (SDL_OpenAudio(&wanted, &spec) < 0) {
+        _mm_errno=MMERR_OPENING_AUDIO;
+        return 0;
+    }
+
+    return 1;
+}
+
+static BOOL SDLDrv_IsPresent(void)
+{
+    if ((SDL_WasInit(SDL_INIT_AUDIO)) == 0) {
+        if (SDL_Init(SDL_INIT_AUDIO) < 0)
+            return 0;
+        SDL_QuitSubSystem(SDL_INIT_AUDIO);
+    }
+    return 1;
+}
+
+static int SDLDrv_Init(void)
+{
+#if (SDL_MAJOR_VERSION < 2)
+    if (md_mode & DMODE_FLOAT) {
+        _mm_errno=MMERR_NO_FLOAT32;
+        return 1;
+    }
+#endif
+    if (SDL_Init(SDL_INIT_AUDIO) < 0) {
+        _mm_errno=MMERR_OPENING_AUDIO;
+        return 1;
+    }
+    if (!SetupSDLAudio()) {
+        return 1;
+    }
+
+    md_mode |= DMODE_SOFT_MUSIC;
+    if (VC_Init())
+        return 1;
+
+    enabled = -2; /* delay the callback 2 frames */
+    return 0;
+}
+
+static void SDLDrv_Exit(void)
+{
+    SDL_LockAudio();
+    enabled = 0;
+    SDL_UnlockAudio();
+    SDL_CloseAudio();
+    VC_Exit();
+}
+
+static int SDLDrv_Reset(void)
+{
+    SDLDrv_Exit();
+    return SDLDrv_Init();
+}
+
+static void SDLDrv_Update( void )
+{
+/* do nothing */
+}
+
+static void SDLDrv_PlayStop(void)
+{
+    SDL_PauseAudio(1);
+    VC_PlayStop();
+}
+
+static int SDLDrv_PlayStart(void)
+{
+    if (VC_PlayStart())
+        return 1;
+    SDL_PauseAudio(0);
+    return 0;
+}
+
+MIKMODAPI struct MDRIVER drv_sdl =
+{
+    NULL,
+    "SDL",
+    "SDL Driver v1.3",
+    0,255,
+    "sdl",
+    NULL,
+    NULL,
+    SDLDrv_IsPresent,
+    VC_SampleLoad,
+    VC_SampleUnload,
+    VC_SampleSpace,
+    VC_SampleLength,
+    SDLDrv_Init,
+    SDLDrv_Exit,
+    SDLDrv_Reset,
+    VC_SetNumVoices,
+    SDLDrv_PlayStart,
+    SDLDrv_PlayStop,
+    SDLDrv_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_sdl);
+
+#endif
+
diff --git a/libs/mikmod/drivers/drv_ultra.c b/libs/mikmod/drivers/drv_ultra.c
new file mode 100644 (file)
index 0000000..dbd0b7c
--- /dev/null
@@ -0,0 +1,1020 @@
+/*     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$
+
+  Driver for Gravis Ultrasound cards using libGUS.
+  A subset of libGUS is provided for DOS/DJGPP and OS/2
+
+==============================================================================*/
+
+/*
+
+       Written by Andy Lo A Foe <andy@alsa-project.org>
+
+       Updated to work with later versions of both the ultrasound driver and
+       libmikmod by C. Ray C. <crayc@pyro.net>
+
+       Major fixes by Andrew Zabolotny <bit@eltech.ru>
+       + Ported to OS/2 and DOS.
+       + Eight-bit samples are not converted to 16-bit anymore.
+       + Samples are no longer kept in normal memory.
+       + Removed sample 'unclick' logic... libGUS does unclick internally.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+#ifdef DRV_ULTRA
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef MIKMOD_DYNAMIC
+#include <dlfcn.h>
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libgus.h>
+
+#if !defined(GUS_INSTR_SIMPLE) || !defined(GUS_WAVE_BIDIR)
+#error libgus version is too old
+#endif
+/* just in case */
+#ifndef LIBGUS_VERSION_MAJOR
+#define LIBGUS_VERSION_MAJOR 0x0003
+#endif
+
+/* DOS/DJGPP and OS/2 libGUS'es have gus_get_voice_status() */
+#if defined(__EMX__) || defined(__DJGPP__)
+#define HAVE_VOICE_STATUS
+#else
+#include <time.h>
+#endif
+
+
+#ifdef MIKMOD_DYNAMIC
+/* runtime link with libgus */
+static int (*_libgus_cards) (void);
+
+#if LIBGUS_VERSION_MAJOR < 0x0004
+static int (*_libgus_close) (int);
+static int (*_libgus_do_flush) (void);
+static void (*_libgus_do_tempo) (unsigned int);
+static void (*_libgus_do_voice_frequency) (unsigned char, unsigned int);
+static void (*_libgus_do_voice_pan) (unsigned char, unsigned short);
+static void (*_libgus_do_voice_start) (unsigned char, unsigned int,
+                                       unsigned int, unsigned short,
+                                       unsigned short);
+static void (*_libgus_do_voice_start_position) (unsigned char, unsigned int,
+                                               unsigned int, unsigned short,
+                                               unsigned short, unsigned int);
+static void (*_libgus_do_voice_stop) (unsigned char, unsigned char);
+static void (*_libgus_do_voice_volume) (unsigned char, unsigned short);
+static void (*_libgus_do_wait) (unsigned int);
+static int (*_libgus_get_handle) (void);
+static int (*_libgus_info) (gus_info_t *, int);
+static int (*_libgus_memory_alloc) (gus_instrument_t *);
+static int (*_libgus_memory_free) (gus_instrument_t *);
+static int (*_libgus_memory_free_size) (void);
+static int (*_libgus_memory_pack) (void);
+static int (*_libgus_open) (int, size_t, int);
+static int (*_libgus_queue_flush) (void);
+static int (*_libgus_queue_read_set_size) (int);
+static int (*_libgus_queue_write_set_size) (int);
+static int (*_libgus_reset) (int, unsigned int);
+static int (*_libgus_select) (int);
+static int (*_libgus_timer_start) (void);
+static int (*_libgus_timer_stop) (void);
+static int (*_libgus_timer_tempo) (int);
+#else
+static int (*_libgus_close) (void*);
+static int (*_libgus_do_flush) (void*);
+static void (*_libgus_do_tempo) (void*, unsigned int);
+static void (*_libgus_do_voice_frequency) (void*, unsigned char, unsigned int);
+static void (*_libgus_do_voice_pan) (void*, unsigned char,unsigned short);
+static void (*_libgus_do_voice_start) (void*, unsigned char, unsigned int,
+                                       unsigned int, unsigned short,
+                                       unsigned short);
+static void (*_libgus_do_voice_start_position) (void*, unsigned char, unsigned int,
+                                               unsigned int,unsigned short,
+                                               unsigned short, unsigned int);
+static void (*_libgus_do_voice_stop) (void*, unsigned char, unsigned char);
+static void (*_libgus_do_voice_volume) (void*, unsigned char, unsigned short);
+static void (*_libgus_do_wait) (void*, unsigned int);
+static int (*_libgus_get_file_descriptor) (void*);
+static int (*_libgus_info) (void*, gus_info_t*, int);
+static int (*_libgus_memory_alloc) (void*, gus_instrument_t*);
+static int (*_libgus_memory_free) (void*, gus_instrument_t*);
+static int (*_libgus_memory_free_size) (void*);
+static int (*_libgus_memory_pack) (void*);
+static int (*_libgus_open) (void**, int, int, size_t, int);
+static int (*_libgus_queue_flush) (void*);
+static int (*_libgus_queue_read_set_size) (void*, int);
+static int (*_libgus_queue_write_set_size) (void*, int);
+static int (*_libgus_reset) (void*, int, unsigned int);
+static int (*_libgus_timer_start)(void*);
+static int (*_libgus_timer_stop) (void*);
+static int (*_libgus_timer_tempo) (void*, int);
+#endif
+#ifndef HAVE_RTLD_GLOBAL
+#define RTLD_GLOBAL (0)
+#endif
+static void *libgus = NULL;
+
+#else
+/* compile-time link with libgus */
+#define _libgus_cards                          gus_cards
+#define _libgus_close                          gus_close
+#define _libgus_do_flush                       gus_do_flush
+#define _libgus_do_tempo                       gus_do_tempo
+#define _libgus_do_voice_frequency             gus_do_voice_frequency
+#define _libgus_do_voice_pan                   gus_do_voice_pan
+#define _libgus_do_voice_start                 gus_do_voice_start
+#define _libgus_do_voice_start_position                gus_do_voice_start_position
+#define _libgus_do_voice_stop                  gus_do_voice_stop
+#define _libgus_do_voice_volume                        gus_do_voice_volume
+#define _libgus_do_wait                                gus_do_wait
+#if LIBGUS_VERSION_MAJOR < 0x0004
+#define _libgus_get_handle                     gus_get_handle
+#else
+#define _libgus_get_file_descriptor            gus_get_file_descriptor
+#endif
+#define _libgus_info                           gus_info
+#define _libgus_memory_alloc                   gus_memory_alloc
+#define _libgus_memory_free                    gus_memory_free
+#define _libgus_memory_free_size               gus_memory_free_size
+#define _libgus_memory_pack                    gus_memory_pack
+#define _libgus_open                           gus_open
+#define _libgus_queue_flush                    gus_queue_flush
+#define _libgus_queue_read_set_size            gus_queue_read_set_size
+#define _libgus_queue_write_set_size           gus_queue_write_set_size
+#define _libgus_reset                          gus_reset
+#if LIBGUS_VERSION_MAJOR < 0x0004
+#define _libgus_select                         gus_select
+#endif
+#define _libgus_timer_start                    gus_timer_start
+#define _libgus_timer_stop                     gus_timer_stop
+#define _libgus_timer_tempo                    gus_timer_tempo
+#endif
+
+#define libgus_cards                           _libgus_cards   /* same between v3 and v4 */
+#define libgus_open                            _libgus_open    /* different between v3 and v4: must use #ifdef */
+#define libgus_close                           _libgus_close   /* different between v3 and v4: must use #ifdef */
+/* the following can be handled easily by macros: v4 only adds them the handle as the first param */
+#if LIBGUS_VERSION_MAJOR < 0x0004
+#define libgus_get_handle                      _libgus_get_handle /* only in v3 */
+#define libgus_do_flush                                _libgus_do_flush
+#define libgus_do_tempo                                _libgus_do_tempo
+#define libgus_do_voice_frequency              _libgus_do_voice_frequency
+#define libgus_do_voice_pan                    _libgus_do_voice_pan
+#define libgus_do_voice_start                  _libgus_do_voice_start
+#define libgus_do_voice_start_position         _libgus_do_voice_start_position
+#define libgus_do_voice_stop                   _libgus_do_voice_stop
+#define libgus_do_voice_volume                 _libgus_do_voice_volume
+#define libgus_do_wait                         _libgus_do_wait
+#define libgus_info                            _libgus_info
+#define libgus_memory_alloc                    _libgus_memory_alloc
+#define libgus_memory_free                     _libgus_memory_free
+#define libgus_memory_free_size                        _libgus_memory_free_size
+#define libgus_memory_pack                     _libgus_memory_pack
+#define libgus_queue_flush                     _libgus_queue_flush
+#define libgus_queue_read_set_size             _libgus_queue_read_set_size
+#define libgus_queue_write_set_size            _libgus_queue_write_set_size
+#define libgus_reset                           _libgus_reset
+#define libgus_select                          _libgus_select
+#define libgus_timer_start                     _libgus_timer_start
+#define libgus_timer_stop                      _libgus_timer_stop
+#define libgus_timer_tempo                     _libgus_timer_tempo
+#else
+#define libgus_get_file_descriptor             _libgus_get_file_descriptor /* only in v4 */
+#define libgus_do_flush()                      _libgus_do_flush(ultra_h)
+#define libgus_do_tempo(t)                     _libgus_do_tempo(ultra_h,t)
+#define libgus_do_voice_frequency(a,b)         _libgus_do_voice_frequency(ultra_h,a,b)
+#define libgus_do_voice_pan(a,b)               _libgus_do_voice_pan(ultra_h,a,b)
+#define libgus_do_voice_start(a,b,c,d,e)       _libgus_do_voice_start(ultra_h,a,b,c,d,e)
+#define libgus_do_voice_start_position(a,b,c,d,e,f) _libgus_do_voice_start_position(ultra_h,a,b,c,d,e,f)
+#define libgus_do_voice_stop(a,b)              _libgus_do_voice_stop(ultra_h,a,b)
+#define libgus_do_voice_volume(a,b)            _libgus_do_voice_volume(ultra_h,a,b)
+#define libgus_do_wait(a)                      _libgus_do_wait(ultra_h,a)
+#define libgus_info(a,b)                       _libgus_info(ultra_h,a,b)
+#define libgus_memory_alloc(a)                 _libgus_memory_alloc(ultra_h,a)
+#define libgus_memory_free(a)                  _libgus_memory_free(ultra_h,a)
+#define libgus_memory_free_size()              _libgus_memory_free_size(ultra_h)
+#define libgus_memory_pack()                   _libgus_memory_pack(ultra_h)
+#define libgus_queue_flush()                   _libgus_queue_flush(ultra_h)
+#define libgus_queue_read_set_size(a)          _libgus_queue_read_set_size(ultra_h,a)
+#define libgus_queue_write_set_size(a)         _libgus_queue_write_set_size(ultra_h,a)
+#define libgus_reset(a,b)                      _libgus_reset(ultra_h,a,b)
+#define libgus_timer_start()                   _libgus_timer_start(ultra_h)
+#define libgus_timer_stop()                    _libgus_timer_stop(ultra_h)
+#define libgus_timer_tempo(a)                  _libgus_timer_tempo(ultra_h,a)
+#endif
+
+#define GUS_SAMPLES                    256     /* Max. GUS samples loadable */
+#define GUS_CHANNELS                   32      /* Max. GUS channels available */
+#define SIZE_OF_SEQBUF         (8 * 1024)      /* Size of the sequence buffer */
+#define ULTRA_PAN_MIDDLE       (16383 >> 1)    /* Middle balance position */
+
+#define CH_FREQ        1
+#define CH_VOL 2
+#define CH_PAN 4
+
+/*     This structure holds the current state of a GUS voice channel. */
+typedef struct GUS_VOICE {
+       UBYTE kick;
+       UBYTE active;
+       UWORD flags;
+       SWORD handle;
+       ULONG start;
+       ULONG size;
+       ULONG reppos;
+       ULONG repend;
+       ULONG frq;
+       int vol;
+       int decvol;
+       int pan;
+
+       int changes;
+#ifndef HAVE_VOICE_STATUS
+       time_t started;
+#endif
+} GUS_VOICE;
+
+/* Global declarations follow */
+
+static SAMPLE *samples[GUS_SAMPLES];   /* sample handles */
+static GUS_VOICE voices[GUS_CHANNELS]; /* channel status */
+
+static int ultra_dev = 0;      /* GUS index, if more than one card */
+#if LIBGUS_VERSION_MAJOR < 0x0004
+static int ultra_card = -1;    /* returned by gus_open(ultra_dev,,) - must be same as ultra_dev */
+#else
+static void* ultra_h = NULL;   /* GUS handle */
+#endif
+static int ultra_fd = -1;      /* GUS file descriptor */
+
+
+#ifdef MIKMOD_DYNAMIC
+static int Ultra_Link(void)
+{
+       if (libgus)
+               return 0;
+
+       /* load libgus.so */
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       libgus = dlopen("libgus.so.3", RTLD_LAZY | RTLD_GLOBAL);
+#else
+       libgus = dlopen("libgus.so.4", RTLD_LAZY | RTLD_GLOBAL);
+#endif
+       if (!libgus) /* then this won't succeed either, but whatever.. */
+               libgus = dlopen("libgus.so", RTLD_LAZY | RTLD_GLOBAL);
+       if (!libgus)
+               return 1;
+
+       /* resolve function references */
+#define IMPORT_SYMBOL(x,ret,params) \
+       if (!(_lib##x = (ret (*)params) dlsym(libgus, #x))) return 1
+
+       IMPORT_SYMBOL(gus_cards, int, (void));
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       IMPORT_SYMBOL(gus_close, int, (int));
+       IMPORT_SYMBOL(gus_do_flush, int, (void));
+       IMPORT_SYMBOL(gus_do_tempo, void, (unsigned int));
+       IMPORT_SYMBOL(gus_do_voice_frequency, void, (unsigned char, unsigned int));
+       IMPORT_SYMBOL(gus_do_voice_pan, void, (unsigned char, unsigned short));
+       IMPORT_SYMBOL(gus_do_voice_start, void, (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short));
+       IMPORT_SYMBOL(gus_do_voice_start_position, void, (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int));
+       IMPORT_SYMBOL(gus_do_voice_stop, void, (unsigned char, unsigned char));
+       IMPORT_SYMBOL(gus_do_voice_volume, void, (unsigned char, unsigned short));
+       IMPORT_SYMBOL(gus_do_wait, void, (unsigned int));
+       IMPORT_SYMBOL(gus_get_handle, int, (void));
+       IMPORT_SYMBOL(gus_info, int, (gus_info_t *, int));
+       IMPORT_SYMBOL(gus_memory_alloc, int, (gus_instrument_t *));
+       IMPORT_SYMBOL(gus_memory_free, int, (gus_instrument_t *));
+       IMPORT_SYMBOL(gus_memory_free_size, int, (void));
+       IMPORT_SYMBOL(gus_memory_pack, int, (void));
+       IMPORT_SYMBOL(gus_open, int, (int, size_t, int));
+       IMPORT_SYMBOL(gus_queue_flush, int, (void));
+       IMPORT_SYMBOL(gus_queue_read_set_size, int, (int));
+       IMPORT_SYMBOL(gus_queue_write_set_size, int, (int));
+       IMPORT_SYMBOL(gus_reset, int, (int, unsigned int));
+       IMPORT_SYMBOL(gus_select, int, (int));
+       IMPORT_SYMBOL(gus_timer_start, int, (void));
+       IMPORT_SYMBOL(gus_timer_stop, int, (void));
+       IMPORT_SYMBOL(gus_timer_tempo, int, (int));
+#else
+       IMPORT_SYMBOL(gus_close, int, (void*));
+       IMPORT_SYMBOL(gus_do_flush, int, (void*));
+       IMPORT_SYMBOL(gus_do_tempo, void, (void*, unsigned int));
+       IMPORT_SYMBOL(gus_do_voice_frequency, void, (void*, unsigned char, unsigned int));
+       IMPORT_SYMBOL(gus_do_voice_pan, void, (void*, unsigned char, unsigned short));
+       IMPORT_SYMBOL(gus_do_voice_start, void, (void*, unsigned char, unsigned int, unsigned int, unsigned short, unsigned short));
+       IMPORT_SYMBOL(gus_do_voice_start_position, void, (void*, unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int));
+       IMPORT_SYMBOL(gus_do_voice_stop, void, (void*, unsigned char, unsigned char));
+       IMPORT_SYMBOL(gus_do_voice_volume, void, (void*, unsigned char, unsigned short));
+       IMPORT_SYMBOL(gus_do_wait, void, (void*, unsigned int));
+       IMPORT_SYMBOL(gus_get_file_descriptor, int, (void*));
+       IMPORT_SYMBOL(gus_info, int, (void*, gus_info_t *, int));
+       IMPORT_SYMBOL(gus_memory_alloc, int, (void*, gus_instrument_t *));
+       IMPORT_SYMBOL(gus_memory_free, int, (void*, gus_instrument_t *));
+       IMPORT_SYMBOL(gus_memory_free_size, int, (void*));
+       IMPORT_SYMBOL(gus_memory_pack, int, (void*));
+       IMPORT_SYMBOL(gus_open, int, (void**, int, int, size_t, int));
+       IMPORT_SYMBOL(gus_queue_flush, int, (void*));
+       IMPORT_SYMBOL(gus_queue_read_set_size, int, (void*, int));
+       IMPORT_SYMBOL(gus_queue_write_set_size, int, (void*, int));
+       IMPORT_SYMBOL(gus_reset, int, (void*, int, unsigned int));
+       IMPORT_SYMBOL(gus_timer_start, int, (void*));
+       IMPORT_SYMBOL(gus_timer_stop, int, (void*));
+       IMPORT_SYMBOL(gus_timer_tempo, int, (void*, int));
+#endif
+#undef IMPORT_SYMBOL
+
+       return 0;
+}
+
+static void Ultra_Unlink(void)
+{
+       _libgus_cards = NULL;
+       _libgus_close = NULL;
+       _libgus_do_flush = NULL;
+       _libgus_do_tempo = NULL;
+       _libgus_do_voice_frequency = NULL;
+       _libgus_do_voice_pan = NULL;
+       _libgus_do_voice_start = NULL;
+       _libgus_do_voice_start_position = NULL;
+       _libgus_do_voice_stop = NULL;
+       _libgus_do_voice_volume = NULL;
+       _libgus_do_wait = NULL;
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       _libgus_get_handle = NULL;
+#else
+       _libgus_get_file_descriptor = NULL;
+#endif
+       _libgus_info = NULL;
+       _libgus_memory_alloc = NULL;
+       _libgus_memory_free = NULL;
+       _libgus_memory_free_size = NULL;
+       _libgus_memory_pack = NULL;
+       _libgus_open = NULL;
+       _libgus_queue_flush = NULL;
+       _libgus_queue_read_set_size = NULL;
+       _libgus_queue_write_set_size = NULL;
+       _libgus_reset = NULL;
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       _libgus_select = NULL;
+#endif
+       _libgus_timer_start = NULL;
+       _libgus_timer_stop = NULL;
+       _libgus_timer_tempo = NULL;
+
+       if (libgus) {
+               dlclose(libgus);
+               libgus = NULL;
+       }
+}
+#endif
+
+static void Ultra_CommandLine(const CHAR *cmdline)
+{
+       CHAR *ptr = MD_GetAtom("card", cmdline, 0);
+
+       if (ptr) {
+               int buf = atoi(ptr);
+
+               if (buf >= 0 && buf <= 8)
+                       ultra_dev = buf;
+               MikMod_free(ptr);
+       }
+#ifdef __DJGPP__
+       ptr = MD_GetAtom("dma", cmdline, 0);
+       if (ptr) {
+               gus_dma_usage (atoi(ptr));
+               MikMod_free(ptr);
+       }
+#endif
+}
+
+/* Checks for the presence of GUS cards */
+static BOOL Ultra_IsThere(void)
+{
+       BOOL retval;
+
+#ifdef MIKMOD_DYNAMIC
+       if (Ultra_Link())
+               return 0;
+#endif
+       retval = libgus_cards()? 1 : 0;
+#ifdef MIKMOD_DYNAMIC
+       Ultra_Unlink();
+#endif
+       return retval;
+}
+
+/* Load a new sample directly into GUS DRAM and return a handle */
+static SWORD Ultra_SampleLoad(struct SAMPLOAD *sload, int type)
+{
+       int handle;
+       SAMPLE *s = sload->sample;
+       gus_instrument_t instrument;
+       gus_layer_t layer;
+       gus_wave_t wave;
+       unsigned char *buffer;
+       unsigned int length, loopstart, loopend;
+
+       /* Find empty slot to put sample in */
+       for (handle = 0; handle < GUS_SAMPLES; handle++)
+               if (!samples[handle])
+                       break;
+
+       if (handle == GUS_SAMPLES) {
+               _mm_errno = MMERR_OUT_OF_HANDLES;
+               return -1;
+       }
+
+       /* Fill an gus_instrument_t structure and feed it to libgus. We can
+          download 8 and 16 bit, both signed and unsigned samples into GUS, so
+          don't bother much about formats here. */
+
+       /* convert position/length data from samples to bytes */
+       length = s->length;
+       loopstart = s->loopstart;
+       loopend = s->loopend ? s->loopend : length;
+       /* sanity checks */
+       if (loopend > length)
+               loopend = length;
+       if (loopstart > loopend)
+               loopstart = loopend;
+       if (s->flags & SF_16BITS) {
+               length <<= 1;
+               loopstart <<= 1;
+               loopend <<= 1;
+       }
+
+       /* Load sample into normal memory */
+       if (!(buffer = (unsigned char *) MikMod_malloc(length))) {
+               _mm_errno = MMERR_SAMPLE_TOO_BIG;
+               return -1;
+       }
+
+       if (SL_Load(buffer, sload, s->length)) {
+               MikMod_free(buffer);
+               return -1;
+       }
+
+       samples[handle] = s;
+
+       memset(&wave, 0, sizeof(wave));
+       memset(&layer, 0, sizeof(layer));
+       memset(&instrument, 0, sizeof(instrument));
+
+       wave.format =
+               ((s->flags & SF_SIGNED) ? 0 : GUS_WAVE_INVERT) |
+               ((s->flags & SF_16BITS) ? GUS_WAVE_16BIT : 0) |
+               ((s->flags & SF_DELTA ) ? GUS_WAVE_DELTA : 0) |
+               ((s->flags & SF_LOOP  ) ? GUS_WAVE_LOOP  : 0) |
+               ((s->flags & SF_BIDI  ) ? GUS_WAVE_BIDIR : 0);
+       wave.begin.ptr = buffer;
+       wave.loop_start = loopstart << 4;
+       wave.loop_end = loopend << 4;
+       wave.size = length;
+
+       layer.wave = &wave;
+
+       instrument.mode = layer.mode = wave.mode = GUS_INSTR_SIMPLE;
+       instrument.number.instrument = handle;
+       instrument.info.layer = &layer;
+
+       /* Download the sample to GUS RAM */
+       if (libgus_memory_alloc(&instrument)) {
+               MikMod_free(buffer);
+               _mm_errno = MMERR_SAMPLE_TOO_BIG;
+               return -1;
+       }
+
+       MikMod_free(buffer);
+       return handle;
+}
+
+/* Discards a sample from the GUS memory and mark handle as free */
+static void Ultra_SampleUnload(SWORD handle)
+{
+       gus_instrument_t instrument;
+
+       if (handle >= GUS_SAMPLES || handle < 0 || !samples[handle])
+               return;
+
+       memset(&instrument, 0, sizeof(instrument));
+       instrument.mode = GUS_INSTR_SIMPLE;
+       instrument.number.instrument = handle;
+       libgus_memory_free(&instrument);
+       samples[handle] = NULL;
+}
+
+/* Reports available sample space */
+static ULONG Ultra_SampleSpace(int type)
+{
+       libgus_memory_pack();
+       return (libgus_memory_free_size());
+}
+
+/* Reports the size of a sample */
+static ULONG Ultra_SampleLength(int type, SAMPLE *s)
+{
+       if (!s)
+               return 0;
+
+       if (s->flags & SF_16BITS)
+               return ((s->length << 1) + 31) & ~31;
+       else
+               return ( s->length       + 15) & ~15;
+}
+
+/* Initializes the driver */
+static int Ultra_Init_internal(void)
+{
+       gus_info_t info;
+
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       if ((ultra_card = libgus_open(ultra_dev, SIZE_OF_SEQBUF, 0)) < 0) {
+               _mm_errno = (errno == ENOMEM)? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE;
+               return 1;
+       }
+       libgus_select(ultra_card);
+       ultra_fd = libgus_get_handle();
+#else
+       if (libgus_open(&ultra_h, ultra_dev, 0, SIZE_OF_SEQBUF, GUS_OPEN_FLAG_NONE) < 0) {
+               _mm_errno = (errno == ENOMEM)? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE;
+               return 1;
+       }
+       ultra_fd = libgus_get_file_descriptor(ultra_h);
+#endif
+
+       /* We support only 16-bit stereo with 44K mixing frequency. On UltraSound
+          Classic mixing frequency depends on number of channels, on Interwave it
+          is always 44KHz. */
+       md_mode |= DMODE_16BITS | DMODE_STEREO;
+       md_mixfreq = info.mixing_freq;
+
+       libgus_info(&info, 0);
+#ifdef MIKMOD_DEBUG
+       switch (info.version) {
+         case 0x24:
+               fputs("GUS 2.4", stderr);
+               break;
+         case 0x35:
+               fputs("GUS 3.7 (flipped)", stderr);
+               break;
+         case 0x37:
+               fputs("GUS 3.7", stderr);
+               break;
+         case 0x90:
+               fputs("GUS ACE", stderr);
+               break;
+         case 0xa0:
+               fputs("GUS MAX 10", stderr);
+               break;
+         case 0xa1:
+               fputs("GUS MAX 11", stderr);
+               break;
+         case 0x100:
+               fputs("Interwave/GUS PnP", stderr);
+               break;
+         default:
+               fprintf(stderr, "Unknown GUS type %x", info.version);
+               break;
+       }
+       fprintf(stderr, " with %dKb RAM on board\n", info.memory_size >> 10);
+#endif
+
+       /* Zero the voice states and sample handles */
+       memset (&voices, 0, sizeof (voices));
+       memset (&samples, 0, sizeof (samples));
+
+       return 0;
+}
+
+static int Ultra_Init(void)
+{
+#ifdef MIKMOD_DYNAMIC
+       if (Ultra_Link()) {
+               _mm_errno = MMERR_DYNAMIC_LINKING;
+               return 1;
+       }
+#endif
+       return Ultra_Init_internal();
+}
+
+/* Closes the driver */
+static void Ultra_Exit_internal(void)
+{
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       if (ultra_card >= 0) {
+               ultra_card = -1;
+               libgus_close(ultra_dev);
+       }
+#else
+       if (ultra_h) {
+               libgus_close(ultra_h);
+               ultra_h = NULL;
+       }
+#endif
+       ultra_fd = -1;
+}
+
+static void Ultra_Exit(void)
+{
+       Ultra_Exit_internal();
+#ifdef MIKMOD_DYNAMIC
+       Ultra_Unlink();
+#endif
+}
+
+/* Poor man's reset function */
+static int Ultra_Reset(void)
+{
+       Ultra_Exit_internal();
+       return Ultra_Init_internal();
+}
+
+static int Ultra_SetNumVoices(void)
+{
+       return 0;
+}
+
+/* Module player tick function */
+static void UltraPlayer(void)
+{
+       int channel, panning;
+       struct GUS_VOICE *voice;
+       static BOOL ultra_pause = 1;    /* paused status */
+
+       md_player();
+
+       if (ultra_pause != Player_Paused())
+               if ((ultra_pause = Player_Paused()))
+                       for (channel = 0, voice = voices; channel < md_numchn;
+                            channel++, voice++) {
+                               libgus_do_voice_volume (channel, 0);
+                               voices->changes |= (CH_VOL | CH_FREQ | CH_PAN);
+                       }
+
+       if (ultra_pause)
+               return;
+
+       for (channel = 0, voice = voices; channel < md_numchn; channel++, voice++) {
+               panning = (voice->pan == PAN_SURROUND) ?
+                              ULTRA_PAN_MIDDLE : (voice->pan << 6);
+
+               if (voice->kick) {
+                       voice->kick = 0;
+                       voice->decvol = voice->vol;
+                       if (voice->start > 0)
+                               libgus_do_voice_start_position(channel, voice->handle,
+                                     voice->frq, voice->vol << 6, panning, voice->start << 4);
+                       else
+                               libgus_do_voice_start(channel, voice->handle, voice->frq,
+                                                        voice->vol << 6, voice->pan << 6);
+               } else {
+                       if (voice->changes & CH_FREQ)
+                               libgus_do_voice_frequency(channel, voice->frq);
+                       if (voice->changes & CH_VOL)
+                               libgus_do_voice_volume(channel, voice->vol << 6);
+                       if (voice->changes & CH_PAN)
+                               libgus_do_voice_pan(channel, panning);
+                       if (voice->decvol)
+                               voice->decvol -= 4;
+               }
+               voice->changes = 0;
+       }
+}
+
+/* Play sound */
+#if defined(__DJGPP__) || defined(__EMX__)
+static void Ultra_Callback(void)
+{
+       UltraPlayer();
+       libgus_do_flush();
+}
+
+static void Ultra_Update(void)
+{
+       static UWORD ultra_bpm = 0;             /* current GUS tempo */
+
+       /* All real work is done during GF1 timer 1 interrupt */
+       if (ultra_bpm != md_bpm) {
+               libgus_do_tempo((md_bpm * 50) / 125);
+               ultra_bpm = md_bpm;
+       }
+}
+
+#else
+static void Ultra_Update(void)
+{
+       fd_set write_fds;
+       int need_write;
+       static UWORD ultra_bpm = 0;     /* current GUS tempo */
+
+       if (ultra_bpm != md_bpm) {
+               libgus_do_tempo((md_bpm * 50) / 125);
+               ultra_bpm = md_bpm;
+       }
+
+       UltraPlayer();
+
+       do {
+               need_write = libgus_do_flush();
+
+               FD_ZERO(&write_fds);
+               do {
+                       FD_SET(ultra_fd, &write_fds);
+
+                       select(ultra_fd + 1, NULL, &write_fds, NULL, NULL);
+               } while (!FD_ISSET(ultra_fd, &write_fds));
+       } while(need_write > 0);
+
+       /* Wait so that all voice commands gets executed */
+       libgus_do_wait (1);
+}
+
+#endif
+
+/* Start playback */
+static int Ultra_PlayStart(void)
+{
+       int t;
+       gus_info_t info;
+
+       for (t = 0; t < md_numchn; t++) {
+               voices[t].flags = 0;
+               voices[t].handle = 0;
+               voices[t].size = 0;
+               voices[t].start = 0;
+               voices[t].reppos = 0;
+               voices[t].repend = 0;
+               voices[t].changes = 0;
+               voices[t].kick = 0;
+               voices[t].frq = 10000;
+               voices[t].vol = 0;
+               voices[t].pan = ULTRA_PAN_MIDDLE;
+               voices[t].active = 0;
+       }
+
+#if LIBGUS_VERSION_MAJOR < 0x0004
+       libgus_select(ultra_card);
+#endif
+       if (libgus_reset(md_numchn, 0) < 0) {
+               _mm_errno = MMERR_GUS_RESET;
+               return 1;
+       }
+
+       /* Query mixing frequency */
+       libgus_info(&info, 0);
+       md_mixfreq = info.mixing_freq;
+
+       libgus_queue_write_set_size(1024);
+       libgus_queue_read_set_size(128);
+
+       if (libgus_timer_start() < 0) {
+               _mm_errno = MMERR_GUS_TIMER;
+               return 1;
+       }
+
+#if defined(__DJGPP__) || defined(__EMX__)
+       gus_timer_callback(Ultra_Callback);
+#endif
+
+       libgus_timer_tempo(50);
+
+       for (t = 0; t < md_numchn; t++) {
+               libgus_do_voice_pan(t, ULTRA_PAN_MIDDLE);
+               libgus_do_voice_volume(t, 0 << 8);
+       }
+
+       libgus_do_flush();
+
+       return 0;
+}
+
+/* Stop playback */
+static void Ultra_PlayStop(void)
+{
+       int voice;
+
+       libgus_queue_flush();
+       libgus_timer_stop();
+       libgus_queue_write_set_size(0);
+       libgus_queue_read_set_size(0);
+       for(voice = 0; voice < md_numchn; voice++)
+               libgus_do_voice_stop(voice, 0);
+
+#if defined(__DJGPP__) || defined(__EMX__)
+       gus_timer_callback(NULL);
+#endif
+
+       libgus_do_flush();
+}
+
+/* Set the volume for the given voice */
+static void Ultra_VoiceSetVolume(UBYTE voice, UWORD vol)
+{
+       if (voice < md_numchn)
+               if (vol != voices[voice].vol) {
+                       voices[voice].decvol =
+                       voices[voice].vol = vol;
+                       voices[voice].changes |= CH_VOL;
+               }
+}
+
+/* Returns the volume of the given voice */
+static UWORD Ultra_VoiceGetVolume(UBYTE voice)
+{
+       return (voice < md_numchn) ? voices[voice].vol : 0;
+}
+
+/* Set the pitch for the given voice */
+static void Ultra_VoiceSetFrequency(UBYTE voice, ULONG frq)
+{
+       if (voice < md_numchn)
+               if (frq != voices[voice].frq) {
+                       voices[voice].frq = frq;
+                       voices[voice].changes |= CH_FREQ;
+               }
+}
+
+/* Returns the frequency of the given voice */
+static ULONG Ultra_VoiceGetFrequency(UBYTE voice)
+{
+       return (voice < md_numchn) ? voices[voice].frq : 0;
+}
+
+/* Set the panning position for the given voice */
+static void Ultra_VoiceSetPanning(UBYTE voice, ULONG pan)
+{
+       if (voice < md_numchn)
+               if (pan != voices[voice].pan) {
+                       voices[voice].pan = pan;
+                       voices[voice].changes |= CH_PAN;
+               }
+}
+
+/* Returns the panning of the given voice */
+static ULONG Ultra_VoiceGetPanning(UBYTE voice)
+{
+       return (voice < md_numchn) ? voices[voice].pan : 0;
+}
+
+/* Start a new sample on a voice */
+static void Ultra_VoicePlay(UBYTE voice, SWORD handle, ULONG start,
+                                                       ULONG size, ULONG reppos, ULONG repend,
+                                                       UWORD flags)
+{
+       if ((voice >= md_numchn) || (start >= size))
+               return;
+
+       if (flags & SF_LOOP)
+               if (repend > size)
+                       repend = size;
+
+       voices[voice].flags = flags;
+       voices[voice].handle = handle;
+       voices[voice].start = start;
+       voices[voice].size = size;
+       voices[voice].reppos = reppos;
+       voices[voice].repend = repend;
+       voices[voice].kick = 1;
+       voices[voice].active = 1;
+#ifndef HAVE_VOICE_STATUS
+       voices[voice].started = time(NULL);
+#endif
+}
+
+/* Stops a voice */
+static void Ultra_VoiceStop(UBYTE voice)
+{
+       if (voice < md_numchn)
+               voices[voice].active = 0;
+}
+
+/* Returns whether a voice is stopped */
+static BOOL Ultra_VoiceStopped(UBYTE voice)
+{
+       if (voice >= md_numchn)
+               return 1;
+
+#ifdef HAVE_VOICE_STATUS
+       if (voices[voice].active)
+               return gus_get_voice_status(voice) ? 0 : 1;
+       else
+               return 1;
+#else
+       if (voices[voice].active) {
+               /* is sample looping ? */
+               if (voices[voice].flags & (SF_LOOP | SF_BIDI))
+                       return 0;
+               else
+                 if (time(NULL) - voices[voice].started >=
+                         ((voices[voice].size - voices[voice].start + md_mixfreq -1)
+                         / md_mixfreq)) {
+                       voices[voice].active = 0;
+                       return 1;
+               }
+               return 0;
+       } else
+               return 1;
+#endif
+}
+
+/* Returns current voice position */
+static SLONG Ultra_VoiceGetPosition(UBYTE voice)
+{
+       /* NOTE This information can not be determined. */
+       return -1;
+}
+
+/* Returns voice real volume */
+static ULONG Ultra_VoiceRealVolume(UBYTE voice)
+{
+       int retval = 0;
+       if (!Ultra_VoiceStopped (voice)) {
+               /* NOTE This information can not be accurately determined. */
+               retval = (voices [voice].decvol) << 8;
+               if (retval > 0xffff) retval = 0xffff;
+       }
+       return retval;
+}
+
+MDRIVER drv_ultra = {
+       NULL,
+       "Gravis Ultrasound native mode",
+       "Gravis Ultrasound native mode driver v1.2",
+       0, (GUS_CHANNELS)-1,
+       "ultra",
+#ifdef __DJGPP__
+        "dma:b:1:Use DMA for transferring samples into GUS DRAM\n"
+#endif
+       "card:r:0,8,0:Soundcard number\n",
+
+       Ultra_CommandLine,
+       Ultra_IsThere,
+       Ultra_SampleLoad,
+       Ultra_SampleUnload,
+       Ultra_SampleSpace,
+       Ultra_SampleLength,
+       Ultra_Init,
+       Ultra_Exit,
+       Ultra_Reset,
+       Ultra_SetNumVoices,
+       Ultra_PlayStart,
+       Ultra_PlayStop,
+       Ultra_Update,
+       NULL,
+       Ultra_VoiceSetVolume,
+       Ultra_VoiceGetVolume,
+       Ultra_VoiceSetFrequency,
+       Ultra_VoiceGetFrequency,
+       Ultra_VoiceSetPanning,
+       Ultra_VoiceGetPanning,
+       Ultra_VoicePlay,
+       Ultra_VoiceStop,
+       Ultra_VoiceStopped,
+       Ultra_VoiceGetPosition,
+       Ultra_VoiceRealVolume
+};
+#else
+
+MISSING(drv_ultra);
+
+#endif /* DRV_ULTRA */
+
+/* ex:set ts=8: */
diff --git a/libs/mikmod/drivers/drv_wss.c b/libs/mikmod/drivers/drv_wss.c
new file mode 100644 (file)
index 0000000..a89d5ec
--- /dev/null
@@ -0,0 +1,217 @@
+/*     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$
+
+  Driver for Windows Sound System under DOS
+
+==============================================================================*/
+
+/*
+
+       Written by Andrew Zabolotny <bit@eltech.ru>
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_WSS
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "mikmod_internals.h"
+
+#include "doswss.h"
+
+static void WSS_CommandLine(const CHAR *cmdline)
+{
+       char *ptr, *end;
+
+       if ((ptr=MD_GetAtom("port",cmdline,0)) != NULL) {
+               wss.port = strtol(ptr, &end, 16);
+               MikMod_free(ptr);
+       }
+       if ((ptr=MD_GetAtom("irq",cmdline,0)) != NULL) {
+               wss.irq = strtol(ptr, &end, 10);
+               MikMod_free(ptr);
+       }
+       if ((ptr=MD_GetAtom("dma",cmdline,0)) != NULL) {
+               wss.dma = strtol(ptr, &end, 10);
+               MikMod_free(ptr);
+       }
+}
+
+static BOOL WSS_IsThere(void)
+{
+       return wss_detect();
+}
+
+static int WSS_Init(void)
+{
+       if (!wss_open()) {
+               _mm_errno = MMERR_INVALID_DEVICE;
+               return 1;
+       }
+
+       /* Adjust mixing frequency according to card capabilities */
+       md_mixfreq = wss_adjust_freq(md_mixfreq);
+
+       return VC_Init();
+}
+
+static void WSS_Exit(void)
+{
+       VC_Exit();
+       wss_close();
+}
+
+/* The last buffer byte filled with sound */
+static unsigned int buff_tail = 0;
+
+static void WSS_Callback(void)
+{
+       unsigned int dma_size, dma_pos;
+       ULONG (*mixer)(SBYTE *buf, ULONG todo);
+
+       wss_query_dma(&dma_size, &dma_pos);
+       /* There isn't much sense in filling less than 256 bytes */
+       dma_pos &= ~255;
+
+       /* If nothing to mix, quit */
+       if (buff_tail == dma_pos)
+               return;
+
+       if (Player_Paused_internal())
+               mixer = VC_SilenceBytes;
+       else
+               mixer = VC_WriteBytes;
+
+       /* If DMA pointer still didn't wrapped around ... */
+       if (dma_pos > buff_tail) {
+               buff_tail += mixer ((SBYTE *)(wss.dma_buff->linear + buff_tail), dma_pos - buff_tail);
+               /* If we arrived right to the DMA buffer end, jump to the beginning */
+               if (buff_tail >= dma_size)
+                       buff_tail = 0;
+       } else {
+               /* If wrapped around, fill first to the end of buffer */
+               mixer ((SBYTE *)(wss.dma_buff->linear + buff_tail), dma_size - buff_tail);
+               /* Now fill from buffer beginning to current DMA pointer */
+               buff_tail = mixer ((SBYTE *)wss.dma_buff->linear, dma_pos);
+       }
+}
+
+static void WSS_Update(void)
+{
+       /* Do nothing: the real update is done during SB interrupts */
+}
+
+static int WSS_PlayStart(void)
+{
+       if (VC_PlayStart())
+               return 1;
+
+       /* Set our routine to be called during WSS IRQs */
+       buff_tail = 0;
+       wss.timer_callback = WSS_Callback;
+
+       /* Start cyclic DMA transfer */
+       if (!wss_start_dma(((md_mode & DMODE_16BITS) ? WSSMODE_16BITS | WSSMODE_SIGNED : 0) |
+               ((md_mode & DMODE_STEREO) ? WSSMODE_STEREO : 0), md_mixfreq))
+       {
+               _mm_errno = MMERR_DOSWSS_STARTDMA;
+               return 1;
+       }
+
+       /* Enable speaker output */
+       wss_output(TRUE);
+
+       return 0;
+}
+
+static int WSS_Reset(void)
+{
+       wss_reset();
+       VC_Exit();
+       return VC_Init();
+}
+
+static void WSS_PlayStop(void)
+{
+       wss.timer_callback = NULL;
+       wss_output(FALSE);
+       wss_stop_dma();
+       VC_PlayStop();
+}
+
+MDRIVER drv_wss =
+{
+       NULL,
+       "Windows Sound System",
+       "Windows Sound System (CS423*,ESS*) v1.0",
+       0, 255,
+       "wss",
+       "port:c:32C,530,604,E80,F40,530:Windows Sound System base I/O port\n"
+       "irq:c:2,3,5,7,10,5:Windows Sound System IRQ\n"
+       "dma:c:0,1,3,0:Windows Sound System DMA channel\n",
+
+       WSS_CommandLine,
+       WSS_IsThere,
+       VC_SampleLoad,
+       VC_SampleUnload,
+       VC_SampleSpace,
+       VC_SampleLength,
+       WSS_Init,
+       WSS_Exit,
+       WSS_Reset,
+       VC_SetNumVoices,
+       WSS_PlayStart,
+       WSS_PlayStop,
+       WSS_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 /* ifdef DRV_WSS */
+
+#include "mikmod_internals.h"
+MISSING(drv_wss);
+
+#endif
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/include/mikmod.h b/libs/mikmod/include/mikmod.h
new file mode 100644 (file)
index 0000000..6bfe938
--- /dev/null
@@ -0,0 +1,879 @@
+/*  MikMod sound library
+    (c) 1998-2014 Miodrag Vallat and others - see the AUTHORS file
+    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.
+*/
+
+/*==============================================================================
+
+  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
+ *
+ * ========== NOTE TO WINDOWS DEVELOPERS:
+ * If you are compiling for Windows and will link to the static library
+ * (libmikmod.a with MinGW, or mikmod_static.lib with MSVC or LCC, etc),
+ * you must define MIKMOD_STATIC in your project.  Otherwise, dllimport
+ * will be assumed.
+ */
+#if defined(_WIN32) || defined(__CYGWIN__)
+# if defined(MIKMOD_BUILD) && defined(DLL_EXPORT)       /* building libmikmod as a dll for windows */
+#   define MIKMODAPI __declspec(dllexport)
+# elif defined(MIKMOD_BUILD) || defined(MIKMOD_STATIC)  /* building or using static libmikmod for windows */
+#   define MIKMODAPI
+# else
+#   define MIKMODAPI __declspec(dllimport)                      /* using libmikmod dll for windows */
+# endif
+#elif defined(__OS2__) && defined(__WATCOMC__)
+# if defined(MIKMOD_BUILD) && defined(__SW_BD)          /* building libmikmod as a dll for os/2 */
+#   define MIKMODAPI __declspec(dllexport)
+# else
+#   define MIKMODAPI                                    /* using dll or static libmikmod for os/2 */
+# endif
+/* SYM_VISIBILITY should be defined if both the compiler
+ * and the target support the visibility attributes. the
+ * configury does that automatically. for the standalone
+ * makefiles, etc, the developer should add the required
+ * flags, i.e.:  -DSYM_VISIBILITY -fvisibility=hidden  */
+#elif defined(MIKMOD_BUILD) && defined(SYM_VISIBILITY)
+#   define MIKMODAPI __attribute__((visibility("default")))
+#else
+#   define MIKMODAPI
+#endif
+
+/*
+ *  ========== Library version
+ */
+
+#define LIBMIKMOD_VERSION_MAJOR 3L
+#define LIBMIKMOD_VERSION_MINOR 3L
+#define LIBMIKMOD_REVISION     10L
+
+#define LIBMIKMOD_VERSION \
+    ((LIBMIKMOD_VERSION_MAJOR<<16)| \
+     (LIBMIKMOD_VERSION_MINOR<< 8)| \
+     (LIBMIKMOD_REVISION))
+
+MIKMODAPI extern long MikMod_GetVersion(void);
+
+/*
+ *  ========== Dependency platform headers
+ */
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <io.h>
+#include <mmsystem.h>
+#define _MIKMOD_WIN32
+#endif
+
+#if defined(__DJGPP__) || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__)
+#define _MIKMOD_DOS
+#endif
+
+#if defined(__OS2__) || defined(__EMX__)
+#define INCL_DOSSEMAPHORES
+#include <os2.h>
+#include <io.h>
+#define _MIKMOD_OS2
+#endif
+
+#if defined(__MORPHOS__) || defined(__AROS__) || defined(_AMIGA) || defined(__AMIGA__) || defined(__amigaos__) || defined(AMIGAOS)
+#include <exec/types.h>
+#define _MIKMOD_AMIGA
+#endif
+
+/*
+ *  ========== Platform independent-type definitions
+ * (pain when it comes to cross-platform maintenance..)
+ */
+
+#if !(defined(_MIKMOD_OS2) || defined(_MIKMOD_WIN32))
+typedef char               CHAR;
+#endif
+
+/* BOOL:  0=false, <>0 true -- 16 bits on Amiga, int-wide on others. */
+#if !(defined(_MIKMOD_OS2) || defined(_MIKMOD_WIN32) || defined(_MIKMOD_AMIGA))
+typedef int                BOOL;
+#endif
+
+/* 1 byte, signed and unsigned: */
+typedef signed char        SBYTE;
+#ifndef _MIKMOD_AMIGA
+typedef unsigned char      UBYTE;
+#endif
+
+/* 2 bytes, signed and unsigned: */
+#ifndef __LCC__
+typedef signed short int   SWORD;
+#endif
+#if !(defined(__LCC__) || defined(_MIKMOD_AMIGA))
+typedef unsigned short int UWORD;
+#endif
+
+/* 4 bytes, signed and unsigned: */
+#if defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__)
+        /* 64 bit architectures: */
+typedef signed int         SLONG;
+#if !(defined(_WIN32) || defined(_MIKMOD_AMIGA))
+typedef unsigned int       ULONG;
+#endif
+
+#else  /* 32 bit architectures: */
+typedef signed long int    SLONG;
+#if !(defined(_MIKMOD_OS2) || defined(_MIKMOD_WIN32) || defined(_MIKMOD_AMIGA))
+typedef unsigned long int  ULONG;
+#endif
+#endif
+
+/* make sure types are of correct sizes: */
+typedef int __mikmod_typetest [
+   (
+        (sizeof(SBYTE)==1) && (sizeof(UBYTE)==1)
+     && (sizeof(SWORD)==2) && (sizeof(UWORD)==2)
+     && (sizeof(SLONG)==4) && (sizeof(ULONG)==4)
+#ifndef _MIKMOD_AMIGA
+     && (sizeof(BOOL) == sizeof(int))
+#endif
+     && (sizeof(CHAR) == sizeof(char))
+   ) * 2 - 1 ];
+
+/*
+ *  ========== 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_NO_FLOAT32,/* should actually be after MMERR_ULAW or something */
+
+    MMERR_OPENAL_CREATECTX,
+    MMERR_OPENAL_CTXCURRENT,
+    MMERR_OPENAL_GENBUFFERS,
+    MMERR_OPENAL_GENSOURCES,
+    MMERR_OPENAL_SOURCE,
+    MMERR_OPENAL_QUEUEBUFFERS,
+    MMERR_OPENAL_UNQUEUEBUFFERS,
+    MMERR_OPENAL_BUFFERDATA,
+    MMERR_OPENAL_GETSOURCE,
+    MMERR_OPENAL_SOURCEPLAY,
+    MMERR_OPENAL_SOURCESTOP,
+
+    MMERR_ALSA_NOCONFIG,
+    MMERR_ALSA_SETPARAMS,
+    MMERR_ALSA_SETFORMAT,
+    MMERR_ALSA_SETRATE,
+    MMERR_ALSA_SETCHANNELS,
+    MMERR_ALSA_BUFFERSIZE,
+    MMERR_ALSA_PCM_START,
+    MMERR_ALSA_PCM_WRITE,
+    MMERR_ALSA_PCM_RECOVER,
+
+    MMERR_SNDIO_SETPARAMS,
+    MMERR_SNDIO_BADPARAMS,
+
+    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 const 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(const CHAR*);
+MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int);
+
+MIKMODAPI extern int    MikMod_Init(const CHAR*);
+MIKMODAPI extern void   MikMod_Exit(void);
+MIKMODAPI extern int    MikMod_Reset(const CHAR*);
+MIKMODAPI extern int    MikMod_SetNumVoices(int,int);
+MIKMODAPI extern BOOL   MikMod_Active(void);
+MIKMODAPI extern int    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);
+
+MIKMODAPI extern void*  MikMod_malloc(size_t);
+MIKMODAPI extern void*  MikMod_calloc(size_t,size_t);
+MIKMODAPI extern void*  MikMod_realloc(void*,size_t);
+MIKMODAPI extern CHAR*  MikMod_strdup(const CHAR*);
+MIKMODAPI extern void   MikMod_free(void*);  /* frees if ptr != NULL */
+
+/*
+ *  ========== Reader, Writer
+ */
+
+typedef struct MREADER {
+    int  (*Seek)(struct MREADER*,long,int);
+    long (*Tell)(struct MREADER*);
+    BOOL (*Read)(struct MREADER*,void*,size_t);
+    int  (*Get)(struct MREADER*);
+    BOOL (*Eof)(struct MREADER*);
+    long iobase;
+    long prev_iobase;
+} MREADER;
+
+typedef struct MWRITER {
+    int  (*Seek)(struct MWRITER*, long, int);
+    long (*Tell)(struct MWRITER*);
+    BOOL (*Write)(struct MWRITER*, const void*, size_t);
+    int  (*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 */
+    void (*onfree)(void *ctx); /* called from Sample_Free if not NULL */
+    void *ctx;          /* context passed to previous function*/
+} SAMPLE;
+
+/* Sample functions */
+
+MIKMODAPI extern SAMPLE *Sample_LoadRaw(const CHAR *,ULONG rate, ULONG channel, ULONG flags);
+MIKMODAPI extern SAMPLE *Sample_LoadRawFP(FILE *fp,ULONG rate,ULONG channel, ULONG flags);
+MIKMODAPI extern SAMPLE *Sample_LoadRawMem(const char *buf, int len, ULONG rate, ULONG channel, ULONG flags);
+MIKMODAPI extern SAMPLE *Sample_LoadRawGeneric(MREADER*reader,ULONG rate, ULONG channel, ULONG flags);
+
+MIKMODAPI extern SAMPLE *Sample_Load(const CHAR*);
+MIKMODAPI extern SAMPLE *Sample_LoadFP(FILE*);
+MIKMODAPI extern SAMPLE *Sample_LoadMem(const char *buf, int len);
+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_gt2; /* Graoumf tracker */
+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_umx; /* Unreal UMX container of Epic Games */
+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(const CHAR*,int,BOOL);
+MIKMODAPI extern MODULE* Player_LoadFP(FILE*,int,BOOL);
+MIKMODAPI extern MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,BOOL curious);
+MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,BOOL);
+MIKMODAPI extern CHAR*   Player_LoadTitle(const CHAR*);
+MIKMODAPI extern CHAR*   Player_LoadTitleFP(FILE*);
+MIKMODAPI extern CHAR*   Player_LoadTitleMem(const char *buffer,int len);
+MIKMODAPI extern CHAR*   Player_LoadTitleGeneric(MREADER*);
+
+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);
+MIKMODAPI extern int     Player_GetRow(void);
+MIKMODAPI extern int     Player_GetOrder(void);
+
+typedef void (*MikMod_player_t)(void);
+typedef void (*MikMod_callback_t)(unsigned char *data, size_t len);
+
+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 */
+#define DMODE_SIMDMIXER  0x0800 /* enable SIMD mixing */
+#define DMODE_NOISEREDUCTION 0x1000 /* Low pass filtering */
+
+
+struct SAMPLOAD;
+
+typedef struct MDRIVER {
+    struct MDRIVER* next;
+    const CHAR* Name;
+    const CHAR* Version;
+
+    UBYTE       HardVoiceLimit; /* Limit of hardware mixer voices */
+    UBYTE       SoftVoiceLimit; /* Limit of software mixer voices */
+
+    const CHAR* Alias;
+    const CHAR* CmdLineHelp;
+
+    void        (*CommandLine)      (const CHAR*);
+    BOOL        (*IsPresent)        (void);
+    SWORD       (*SampleLoad)       (struct SAMPLOAD*,int);
+    void        (*SampleUnload)     (SWORD);
+    ULONG       (*FreeSampleSpace)  (int);
+    ULONG       (*RealSampleLength) (int,struct SAMPLE*);
+    int         (*Init)             (void);
+    void        (*Exit)             (void);
+    int         (*Reset)            (void);
+    int         (*SetNumVoices)     (void);
+    int         (*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_ahi;    /* Amiga AHI */
+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_pulseaudio; /* PulseAudio  */
+MIKMODAPI extern struct MDRIVER drv_hp;     /* HP-UX audio device */
+MIKMODAPI extern struct MDRIVER drv_nas;    /* Network Audio System (NAS) */
+MIKMODAPI extern struct MDRIVER drv_oss;    /* OpenSound System (Linux,FreeBSD...) */
+MIKMODAPI extern struct MDRIVER drv_openal; /* OpenAL driver */
+MIKMODAPI extern struct MDRIVER drv_sdl;    /* SDL audio driver */
+MIKMODAPI extern struct MDRIVER drv_sgi;    /* SGI audio library */
+MIKMODAPI extern struct MDRIVER drv_sndio;  /* OpenBSD sndio */
+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_xaudio2;/* Win32 XAudio2 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 */
+
+MIKMODAPI extern struct MDRIVER drv_dc;     /* Dreamcast driver */
+MIKMODAPI extern struct MDRIVER drv_gp32;   /* GP32 Sound driver */
+MIKMODAPI extern struct MDRIVER drv_psp;    /* PlayStation Portable driver */
+
+MIKMODAPI extern struct MDRIVER drv_wss;    /* DOS WSS driver */
+MIKMODAPI extern struct MDRIVER drv_sb;     /* DOS S/B driver */
+
+MIKMODAPI extern struct MDRIVER drv_osles;  /* OpenSL ES driver for android */
+
+/*========== Virtual channel mixer interface (for user-supplied drivers only) */
+
+MIKMODAPI extern int   VC_Init(void);
+MIKMODAPI extern void  VC_Exit(void);
+MIKMODAPI extern void  VC_SetCallback(MikMod_callback_t callback);
+MIKMODAPI extern int   VC_SetNumVoices(void);
+MIKMODAPI extern ULONG VC_SampleSpace(int);
+MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);
+
+MIKMODAPI extern int   VC_PlayStart(void);
+MIKMODAPI extern void  VC_PlayStop(void);
+
+MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);
+MIKMODAPI extern void  VC_SampleUnload(SWORD);
+
+MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);
+MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);
+
+MIKMODAPI extern void  VC_VoiceSetVolume(UBYTE,UWORD);
+MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);
+MIKMODAPI extern void  VC_VoiceSetFrequency(UBYTE,ULONG);
+MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);
+MIKMODAPI extern void  VC_VoiceSetPanning(UBYTE,ULONG);
+MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);
+MIKMODAPI extern void  VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
+
+MIKMODAPI extern void  VC_VoiceStop(UBYTE);
+MIKMODAPI extern BOOL  VC_VoiceStopped(UBYTE);
+MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);
+MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/include/mikmod_ctype.h b/libs/mikmod/include/mikmod_ctype.h
new file mode 100644 (file)
index 0000000..ea32e9e
--- /dev/null
@@ -0,0 +1,84 @@
+/* Locale insensitive ctype.h functions taken from the RPM library.
+ * RPM is Copyright (c) 1998 by Red Hat Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef MIKMOD_CTYPE_H
+#define MIKMOD_CTYPE_H
+
+static inline int mik_isascii(int c) {
+    return ((c & ~0x7f) == 0);
+}
+
+static inline int mik_islower(int c) {
+    return (c >= 'a' && c <= 'z');
+}
+
+static inline int mik_isupper(int c) {
+    return (c >= 'A' && c <= 'Z');
+}
+
+static inline int mik_isalpha(int c) {
+    return (mik_islower(c) || mik_isupper(c));
+}
+
+static inline int mik_isdigit(int c) {
+    return (c >= '0' && c <= '9');
+}
+
+static inline int mik_isxdigit(int c) {
+    return (mik_isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
+static inline int mik_isalnum(int c) {
+    return (mik_isalpha(c) || mik_isdigit(c));
+}
+
+static inline int mik_isblank(int c) {
+    return (c == ' ' || c == '\t');
+}
+
+static inline int mik_isspace(int c) {
+    switch (c) {
+    case ' ':  case '\t':
+    case '\n': case '\r':
+    case '\f': case '\v': return 1;
+    }
+    return 0;
+}
+
+static inline int mik_isgraph(int c) {
+    return (c > 0x20 && c <= 0x7e);
+}
+
+static inline int mik_isprint(int c) {
+    return (c >= 0x20 && c <= 0x7e);
+}
+
+static inline int mik_toascii(int c) {
+    return (c & 0x7f);
+}
+
+static inline int mik_tolower(int c) {
+    return ((mik_isupper(c)) ? (c | ('a' - 'A')) : c);
+}
+
+static inline int mik_toupper(int c) {
+    return ((mik_islower(c)) ? (c & ~('a' - 'A')) : c);
+}
+
+#endif /* MIKMOD_CTYPE_H */
diff --git a/libs/mikmod/include/mikmod_internals.h b/libs/mikmod/include/mikmod_internals.h
new file mode 100644 (file)
index 0000000..e90e6cd
--- /dev/null
@@ -0,0 +1,866 @@
+/*     MikMod sound library
+       (c) 1998, 1999, 2005 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.
+*/
+
+/*==============================================================================
+
+  MikMod sound library internal definitions
+
+  ==============================================================================*/
+
+#ifndef _MIKMOD_INTERNALS_H
+#define _MIKMOD_INTERNALS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#if defined(_MSC_VER) && !defined(__cplusplus) && !defined(HAVE_CONFIG_H)
+#define inline __inline
+#endif
+
+#ifndef MIKMOD_UNIX
+#if (defined(unix) || defined(__unix__) || defined(__unix) || \
+        (defined(__APPLE__) && defined(__MACH__))) && \
+   !(defined(__DJGPP__) || defined(_WIN32) || defined(__OS2__) || defined(__EMX__))
+#define MIKMOD_UNIX 1
+#endif
+#endif /* MIKMOD_UNIX */
+
+#include "mikmod.h"
+
+/*========== More type definitions */
+
+/* SLONGLONG: 64bit, signed */
+#if !defined(_WIN32) && \
+   (defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(__alpha) || defined(__x64_64) || defined(__powerpc64__))
+typedef long            SLONGLONG;
+#define NATIVE_64BIT_INT
+#elif defined(_WIN64) /* win64 is LLP64, not LP64  */
+#define NATIVE_64BIT_INT
+typedef long long       SLONGLONG;
+#elif defined(__WATCOMC__)
+typedef __int64         SLONGLONG;
+#elif defined(_WIN32) && !defined(__MWERKS__)
+typedef LONGLONG        SLONGLONG;
+#elif defined(macintosh) && !TYPE_LONGLONG
+#include <Types.h>
+typedef SInt64          SLONGLONG;
+#else
+typedef long long       SLONGLONG;
+#endif
+typedef int __s64_typetest [(sizeof(SLONGLONG)==8) * 2 - 1];
+
+/* pointer-sized signed int (ssize_t/intptr_t) : */
+#if defined(_WIN64) /* win64 is LLP64, not LP64  */
+typedef long long       SINTPTR_T;
+#else
+/* long should be pointer-sized for all others : */
+typedef long            SINTPTR_T;
+#endif
+typedef int __iptr_typetest [(sizeof(SINTPTR_T)==sizeof(void*)) * 2 - 1];
+
+/*========== Error handling */
+
+#define _mm_errno MikMod_errno
+#define _mm_critical MikMod_critical
+extern MikMod_handler_t _mm_errorhandler;
+
+/*========== 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);
+
+/*========== Replacement funcs */
+
+extern int _mm_strcasecmp (const char *__s1, const char *__s2);
+
+/*========== Portable file I/O */
+
+extern MREADER* _mm_new_mem_reader(const void *buffer, long len);
+extern void _mm_delete_mem_reader(MREADER *reader);
+
+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(const 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_skip_BYTE(x)        (void)x->Get(x)
+
+#define _mm_write_SBYTES(x,y,z) z->Write(z,(const void *)x,y)
+#define _mm_write_UBYTES(x,y,z) z->Write(z,(const 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(MREADER*);
+extern FILE* _mm_fopen(const CHAR *, const CHAR *);
+extern int  _mm_fclose(FILE *);
+extern void _mm_write_string(const CHAR*,MWRITER*);
+extern BOOL _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 BOOL _mm_read_M_SWORDS(SWORD*,int,MREADER*);
+extern BOOL _mm_read_I_SWORDS(SWORD*,int,MREADER*);
+extern BOOL _mm_read_M_UWORDS(UWORD*,int,MREADER*);
+extern BOOL _mm_read_I_UWORDS(UWORD*,int,MREADER*);
+
+extern BOOL _mm_read_M_SLONGS(SLONG*,int,MREADER*);
+extern BOOL _mm_read_I_SLONGS(SLONG*,int,MREADER*);
+extern BOOL _mm_read_M_ULONGS(ULONG*,int,MREADER*);
+extern BOOL _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 int       SL_LoadSamples(void);
+extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);
+extern int       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 const 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;
+    const CHAR* type;
+    const 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 MODULE  of;                  /* static unimod loading space */
+extern const UWORD finetune[16];
+extern const 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 UWORD   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(const 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 const CHAR *STM_Signatures[STM_NTRACKERS];
+
+/*========== Player interface */
+
+extern int    Player_Init(MODULE*);
+extern void   Player_Exit(MODULE*);
+extern void   Player_HandleTick(void);
+
+/*========== UnPackers */
+
+typedef BOOL (*MUNPACKER) (struct MREADER*,
+                           void** /* unpacked data out */ ,
+                           long* /* unpacked data size */ );
+extern BOOL PP20_Unpack(MREADER*, void**, long*);
+extern BOOL MMCMP_Unpack(MREADER*, void**, long*);
+extern BOOL XPK_Unpack(MREADER*, void**, long*);
+extern BOOL S404_Unpack(MREADER*, void**, long*);
+
+/*========== 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(const CHAR*, const CHAR*, BOOL);
+
+/* Internal software mixer stuff */
+extern void VC_SetupPointers(void);
+extern int  VC1_Init(void);
+extern int  VC2_Init(void);
+
+#if (MIKMOD_UNIX)
+/* POSIX helper functions */
+extern BOOL MD_Access(const CHAR *);
+extern int  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 int  MikMod_EnableOutput_internal(void);
+extern void MikMod_Exit_internal(void);
+extern int  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);
+
+extern int   VC1_PlayStart(void);
+extern int   VC2_PlayStart(void);
+extern void  VC1_PlayStop(void);
+extern void  VC2_PlayStop(void);
+extern int  VC1_SetNumVoices(void);
+extern int  VC2_SetNumVoices(void);
+
+extern MikMod_callback_t vc_callback;
+
+#ifdef __cplusplus
+}
+#endif
+
+/*========== SIMD mixing routines */
+#undef HAVE_ALTIVEC
+#undef HAVE_SSE2
+#if defined(MIKMOD_SIMD)
+
+#if (defined(__ppc__) || defined(__ppc64__)) && defined(__VEC__) && !(defined(__GNUC__) && (__GNUC__ < 3))
+#define HAVE_ALTIVEC
+
+#elif defined(__GNUC__) && defined(__SSE2__) /* x86 / x86_64 */
+#define HAVE_SSE2
+
+#elif defined(_MSC_VER) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64))
+/* FIXME: emmintrin.h requires VC6 processor pack or VC2003+ */
+#define HAVE_SSE2
+/* avoid some warnings */
+#pragma warning(disable:4761)
+#pragma warning(disable:4391)
+#pragma warning(disable:4244)
+
+#endif /* AltiVec/SSE2 */
+#endif /* MIKMOD_SIMD */
+
+/*========== SIMD mixing helper functions =============*/
+
+#if defined(_WIN64)
+# if defined(_MSC_VER)
+#  define IS_ALIGNED_16(ptr) (!((__int64)(ptr) & 15i64))
+# else /* GCC, LCC, .. */
+#  define IS_ALIGNED_16(ptr) (!((long long)(ptr) & 15LL))
+# endif
+#else /* long cast should be OK for all else */
+#define IS_ALIGNED_16(ptr) (!((long)(ptr) & 15L))
+#endif
+
+/* Altivec helper function */
+#if defined HAVE_ALTIVEC
+
+#define simd_m128i vector signed int
+#define simd_m128 vector float
+
+#ifdef __GNUC__
+#include <ppc_intrinsics.h>
+#endif
+
+/* Helper functions */
+
+/* Set single float across the four values */
+static inline vector float vec_mul(const vector float a, const vector float b) {
+    return vec_madd(a, b, (const vector float)(0.f));
+}
+
+/* Set single float across the four values */
+static inline vector float vec_load_ps1(const float *pF) {
+    vector float data = vec_lde(0, pF);
+    return vec_splat(vec_perm(data, data, vec_lvsl(0, pF)), 0);
+}
+
+/* Set vector to 0 */
+static inline vector float vec_setzero() {
+    return (vector float) (0.);
+}
+
+static inline vector signed char vec_set1_8(unsigned char splatchar) {
+    vector unsigned char splatmap = vec_lvsl(0, &splatchar);
+    vector unsigned char result = vec_lde(0, &splatchar);
+    splatmap = vec_splat(splatmap, 0);
+    return (vector signed char)vec_perm(result, result, splatmap);
+}
+
+#define PERM_A0 0x00,0x01,0x02,0x03
+#define PERM_A1 0x04,0x05,0x06,0x07
+#define PERM_A2 0x08,0x09,0x0A,0x0B
+#define PERM_A3 0x0C,0x0D,0x0E,0x0F
+#define PERM_B0 0x10,0x11,0x12,0x13
+#define PERM_B1 0x14,0x15,0x16,0x17
+#define PERM_B2 0x18,0x19,0x1A,0x1B
+#define PERM_B3 0x1C,0x1D,0x1E,0x1F
+
+/* Equivalent to _mm_unpacklo_epi32 */
+static inline vector signed int vec_unpacklo(vector signed int a, vector signed int b) {
+   return vec_perm(a, b, (vector unsigned char)(PERM_A0,PERM_A1,PERM_B0,PERM_B1));
+}
+
+/* Equivalent to _mm_srli_si128(a, 8) (without the zeroing in high part). */
+static inline vector signed int vec_hiqq(vector signed int a) {
+   vector signed int b = vec_splat_s32(0);
+   return vec_perm(a, b, (vector unsigned char)(PERM_A2,PERM_A3,PERM_B2,PERM_B3));
+}
+
+/* vec_sra is max +15. We have to do in two times ... */
+#define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = vec_mul(vec_ctf(vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(BITSHIFT-size)),0), mul);
+#define EXTRACT_SAMPLE_SIMD_0(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-0));
+#define EXTRACT_SAMPLE_SIMD_8(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-8));
+#define EXTRACT_SAMPLE_SIMD_16(srce, var) var = vec_sra(vec_ld(0, (vector signed int const *)(srce)), vec_splat_u32(BITSHIFT+16-16));
+#define PUT_SAMPLE_SIMD_W(dste, v1, v2)  vec_st(vec_packs(v1, v2), 0, dste);
+#define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4)  vec_st(vec_add(vec_packs((vector signed short)vec_packs(v1, v2), (vector signed short)vec_packs(v3, v4)), vec_set1_8(128)), 0, dste);
+#define PUT_SAMPLE_SIMD_F(dste, v1)  vec_st(v1, 0, dste);
+#define LOAD_PS1_SIMD(ptr) vec_load_ps1(ptr)
+
+#elif defined HAVE_SSE2
+
+#include <emmintrin.h>
+
+/* SSE2 helper function */
+
+static __inline __m128i mm_hiqq(const __m128i a) {
+   return _mm_srli_si128(a, 8); /* get the 64bit upper part. new 64bit upper is undefined (zeroed is fine). */
+}
+
+/* 128-bit mixing macros */
+#define EXTRACT_SAMPLE_SIMD(srce, var, size) var = _mm_srai_epi32(_mm_load_si128((__m128i const *)(srce)), BITSHIFT+16-size);
+#define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_load_si128((__m128i const *)(srce)), BITSHIFT-size)), mul);
+#define EXTRACT_SAMPLE_SIMD_0(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 0)
+#define EXTRACT_SAMPLE_SIMD_8(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 8)
+#define EXTRACT_SAMPLE_SIMD_16(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 16)
+#define PUT_SAMPLE_SIMD_W(dste, v1, v2)  _mm_store_si128((__m128i*)(dste), _mm_packs_epi32(v1, v2));
+#define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4)  _mm_store_si128((__m128i*)(dste), _mm_add_epi8(_mm_packs_epi16(_mm_packs_epi32(v1, v2), _mm_packs_epi32(v3, v4)), _mm_set1_epi8(128)));
+#define PUT_SAMPLE_SIMD_F(dste, v1)  _mm_store_ps((float*)(dste), v1);
+#define LOAD_PS1_SIMD(ptr) _mm_load_ps1(ptr)
+#define simd_m128i __m128i
+#define simd_m128 __m128
+
+#endif
+
+#if defined(HAVE_SSE2) || defined(HAVE_ALTIVEC)
+/* MikMod_amalloc() returns a 16 byte aligned zero-filled
+   memory in SIMD-enabled builds.
+ - the returned memory can be freed with MikMod_afree()
+ - the returned memory CAN NOT be realloc()'ed safely.  */
+#ifdef __cplusplus
+extern "C" {
+#endif
+void* MikMod_amalloc(size_t);
+void MikMod_afree(void *);  /* frees if ptr != NULL */
+#ifdef __cplusplus
+}
+#endif
+
+#else /* NO SIMD */
+#define MikMod_amalloc MikMod_malloc
+#define MikMod_afree MikMod_free
+#endif
+
+#endif /* _MIKMOD_INTERNALS_H */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/loaders/load_it.c b/libs/mikmod/loaders/load_it.c
new file mode 100644 (file)
index 0000000..efe63a9
--- /dev/null
@@ -0,0 +1,1020 @@
+/*     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$
+
+  Impulse tracker (IT) 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"
+#include "mikmod_ctype.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+/*========== Module structure */
+
+/* header */
+typedef struct ITHEADER {
+       CHAR    songname[26];
+       UBYTE   blank01[2];
+       UWORD   ordnum;
+       UWORD   insnum;
+       UWORD   smpnum;
+       UWORD   patnum;
+       UWORD   cwt;            /* Created with tracker (y.xx = 0x0yxx) */
+       UWORD   cmwt;           /* Compatible with tracker ver > than val. */
+       UWORD   flags;
+       UWORD   special;        /* bit 0 set = song message attached */
+       UBYTE   globvol;
+       UBYTE   mixvol;         /* mixing volume [ignored] */
+       UBYTE   initspeed;
+       UBYTE   inittempo;
+       UBYTE   pansep;         /* panning separation between channels */
+       UBYTE   zerobyte;
+       UWORD   msglength;
+       ULONG   msgoffset;
+       UBYTE   blank02[4];
+       UBYTE   pantable[64];
+       UBYTE   voltable[64];
+} ITHEADER;
+
+/* sample information */
+typedef struct ITSAMPLE {
+       CHAR    filename[12];
+       UBYTE   zerobyte;
+       UBYTE   globvol;
+       UBYTE   flag;
+       UBYTE   volume;
+       UBYTE   panning;
+       CHAR    sampname[28];
+       UWORD   convert;        /* sample conversion flag */
+       ULONG   length;
+       ULONG   loopbeg;
+       ULONG   loopend;
+       ULONG   c5spd;
+       ULONG   susbegin;
+       ULONG   susend;
+       ULONG   sampoffset;
+       UBYTE   vibspeed;
+       UBYTE   vibdepth;
+       UBYTE   vibrate;
+       UBYTE   vibwave;        /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */
+} ITSAMPLE;
+
+/* instrument information */
+
+#define ITENVCNT 25
+#define ITNOTECNT 120
+typedef struct ITINSTHEADER {
+       ULONG   size;                   /* (dword) Instrument size */
+       CHAR    filename[12];   /* (char) Instrument filename */
+       UBYTE   zerobyte;               /* (byte) Instrument type (always 0) */
+       UBYTE   volflg;
+       UBYTE   volpts;
+       UBYTE   volbeg;                 /* (byte) Volume loop start (node) */
+       UBYTE   volend;                 /* (byte) Volume loop end (node) */
+       UBYTE   volsusbeg;              /* (byte) Volume sustain begin (node) */
+       UBYTE   volsusend;              /* (byte) Volume Sustain end (node) */
+       UBYTE   panflg;
+       UBYTE   panpts;
+       UBYTE   panbeg;                 /* (byte) channel loop start (node) */
+       UBYTE   panend;                 /* (byte) channel loop end (node) */
+       UBYTE   pansusbeg;              /* (byte) channel sustain begin (node) */
+       UBYTE   pansusend;              /* (byte) channel Sustain end (node) */
+       UBYTE   pitflg;
+       UBYTE   pitpts;
+       UBYTE   pitbeg;                 /* (byte) pitch loop start (node) */
+       UBYTE   pitend;                 /* (byte) pitch loop end (node) */
+       UBYTE   pitsusbeg;              /* (byte) pitch sustain begin (node) */
+       UBYTE   pitsusend;              /* (byte) pitch Sustain end (node) */
+       UWORD   blank;
+       UBYTE   globvol;
+       UBYTE   chanpan;
+       UWORD   fadeout;                /* Envelope end / NNA volume fadeout */
+       UBYTE   dnc;                    /* Duplicate note check */
+       UBYTE   dca;                    /* Duplicate check action */
+       UBYTE   dct;                    /* Duplicate check type */
+       UBYTE   nna;                    /* New Note Action [0,1,2,3] */
+       UWORD   trkvers;                /* tracker version used to save [files only] */
+       UBYTE   ppsep;                  /* Pitch-pan Separation */
+       UBYTE   ppcenter;               /* Pitch-pan Center */
+       UBYTE   rvolvar;                /* random volume varations */
+       UBYTE   rpanvar;                /* random panning varations */
+       UWORD   numsmp;                 /* Number of samples in instrument [files only] */
+       CHAR    name[26];               /* Instrument name */
+       UBYTE   blank01[6];
+       UWORD   samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */
+       UBYTE   volenv[200];         /* volume envelope (IT 1.x stuff) */
+       UBYTE   oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */
+       UBYTE   volnode[ITENVCNT];   /* amplitude of volume nodes */
+       UWORD   voltick[ITENVCNT];   /* tick value of volume nodes */
+       SBYTE   pannode[ITENVCNT];   /* panenv - node points */
+       UWORD   pantick[ITENVCNT];   /* tick value of panning nodes */
+       SBYTE   pitnode[ITENVCNT];   /* pitchenv - node points */
+       UWORD   pittick[ITENVCNT];   /* tick value of pitch nodes */
+} ITINSTHEADER;
+
+/* unpacked note */
+
+typedef struct ITNOTE {
+       UBYTE note,ins,volpan,cmd,inf;
+} ITNOTE;
+
+/*========== Loader data */
+
+static ULONG *paraptr=NULL;    /* parapointer array (see IT docs) */
+static ITHEADER *mh=NULL;
+static ITNOTE *itpat=NULL;     /* allocate to space for one full pattern */
+static UBYTE *mask=NULL;       /* arrays allocated to 64 elements and used for */
+static ITNOTE *last=NULL;      /* uncompressing IT's pattern information */
+static int numtrk=0;
+static unsigned int old_effect;                /* if set, use S3M old-effects stuffs */
+
+static const CHAR* IT_Version[]={
+       "ImpulseTracker  .  ",
+       "Compressed ImpulseTracker  .  ",
+       "ImpulseTracker 2.14p3",
+       "Compressed ImpulseTracker 2.14p3",
+       "ImpulseTracker 2.14p4",
+       "Compressed ImpulseTracker 2.14p4",
+};
+
+/* table for porta-to-note command within volume/panning column */
+static const UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255};
+
+/*========== Loader code */
+
+static BOOL IT_Test(void)
+{
+       UBYTE id[4];
+
+       if(!_mm_read_UBYTES(id,4,modreader)) return 0;
+       if(!memcmp(id,"IMPM",4)) return 1;
+       return 0;
+}
+
+static BOOL IT_Init(void)
+{
+       if(!(mh=(ITHEADER*)MikMod_malloc(sizeof(ITHEADER)))) return 0;
+       if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0;
+       if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0;
+       if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0;
+       if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0;
+
+       return 1;
+}
+
+static void IT_Cleanup(void)
+{
+       FreeLinear();
+
+       MikMod_free(mh);
+       MikMod_free(poslookup);
+       MikMod_free(itpat);
+       MikMod_free(mask);
+       MikMod_free(last);
+       MikMod_free(paraptr);
+       MikMod_free(origpositions);
+       mh=NULL;
+       poslookup=NULL;
+       itpat=NULL;
+       mask=NULL;
+       last=NULL;
+       paraptr=NULL;
+       origpositions=NULL;
+}
+
+/* Because so many IT files have 64 channels as the set number used, but really
+   only use far less (usually from 8 to 24 still), I had to make this function,
+   which determines the number of channels that are actually USED by a pattern.
+
+   NOTE: You must first seek to the file location of the pattern before calling
+   this procedure.
+
+   Returns 0 on error
+*/
+static BOOL IT_GetNumChannels(UWORD patrows)
+{
+       int row=0,flag,ch;
+
+       do {
+               if((flag=_mm_read_UBYTE(modreader))==EOF) {
+                       _mm_errno=MMERR_LOADING_PATTERN;
+                       return 0;
+               }
+               if(!flag)
+                       row++;
+               else {
+                       ch=(flag-1)&63;
+                       remap[ch]=0;
+                       if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader);
+                       if(mask[ch]&1)   _mm_skip_BYTE(modreader);
+                       if(mask[ch]&2)   _mm_skip_BYTE(modreader);
+                       if(mask[ch]&4)   _mm_skip_BYTE(modreader);
+                       if(mask[ch]&8) { _mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader); }
+               }
+       } while(row<patrows);
+
+       return 1;
+}
+
+static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows)
+{
+       int t;
+       UBYTE note,ins,volpan;
+
+       UniReset();
+
+       for(t=0;t<numrows;t++) {
+               note=tr[t*of.numchn].note;
+               ins=tr[t*of.numchn].ins;
+               volpan=tr[t*of.numchn].volpan;
+
+               if(note!=255) {
+                       if(note==253)
+                               UniWriteByte(UNI_KEYOFF);
+                       else if(note==254) {
+                               UniPTEffect(0xc,-1);    /* note cut command */
+                               volpan=255;
+                       } else
+                               UniNote(note);
+               }
+
+               if((ins)&&(ins<100))
+                       UniInstrument(ins-1);
+               else if(ins==253)
+                       UniWriteByte(UNI_KEYOFF);
+               else if(ins!=255) { /* crap */
+                       _mm_errno=MMERR_LOADING_PATTERN;
+                       return NULL;
+               }
+
+               /* process volume / panning column
+                  volume / panning effects do NOT all share the same memory address
+                  yet. */
+               if(volpan<=64)
+                       UniVolEffect(VOL_VOLUME,volpan);
+               else if(volpan==65) /* fine volume slide up (65-74) - A0 case */
+                       UniVolEffect(VOL_VOLSLIDE,0);
+               else if(volpan<=74)     { /* fine volume slide up (65-74) - general case */
+                       UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4));
+               } else if(volpan==75)   /* fine volume slide down (75-84) - B0 case */
+                       UniVolEffect(VOL_VOLSLIDE,0);
+               else if(volpan<=84) {   /* fine volume slide down (75-84) - general case*/
+                       UniVolEffect(VOL_VOLSLIDE,0xf0+(volpan-75));
+               } else if(volpan<=94)   /* volume slide up (85-94) */
+                       UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4));
+               else if(volpan<=104)/* volume slide down (95-104) */
+                       UniVolEffect(VOL_VOLSLIDE,(volpan-95));
+               else if(volpan<=114)/* pitch slide down (105-114) */
+                       UniVolEffect(VOL_PITCHSLIDEDN,(volpan-105));
+               else if(volpan<=124)/* pitch slide up (115-124) */
+                       UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115));
+               else if(volpan<=127) { /* crap */
+                       _mm_errno=MMERR_LOADING_PATTERN;
+                       return NULL;
+               } else if(volpan<=192)
+                       UniVolEffect(VOL_PANNING,((volpan-128)==64)?255:((volpan-128)<<2));
+               else if(volpan<=202)/* portamento to note */
+                       UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]);
+               else if(volpan<=212)/* vibrato */
+                       UniVolEffect(VOL_VIBRATO,(volpan-203));
+               else if((volpan!=239)&&(volpan!=255)) { /* crap */
+                       _mm_errno=MMERR_LOADING_PATTERN;
+                       return NULL;
+               }
+
+               S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,
+                   old_effect|S3MIT_IT);
+
+               UniNewline();
+       }
+       return UniDup();
+}
+
+static BOOL IT_ReadPattern(UWORD patrows)
+{
+       int row=0,flag,ch,blah;
+       ITNOTE *itt=itpat,dummy,*n,*l;
+
+       memset(itt,255,200*64*sizeof(ITNOTE));
+
+       do {
+               if((flag=_mm_read_UBYTE(modreader))==EOF) {
+                       _mm_errno = MMERR_LOADING_PATTERN;
+                       return 0;
+               }
+               if(!flag) {
+                       itt=&itt[of.numchn];
+                       row++;
+               } else {
+                       ch=remap[(flag-1)&63];
+                       if(ch!=-1) {
+                               n=&itt[ch];
+                               l=&last[ch];
+                       } else
+                               n=l=&dummy;
+
+                       if(flag&128) mask[ch]=_mm_read_UBYTE(modreader);
+                       if(mask[ch]&1)
+                               /* convert IT note off to internal note off */
+                               if((l->note=n->note=_mm_read_UBYTE(modreader))==255)
+                                       l->note=n->note=253;
+                       if(mask[ch]&2)
+                               l->ins=n->ins=_mm_read_UBYTE(modreader);
+                       if(mask[ch]&4)
+                               l->volpan=n->volpan=_mm_read_UBYTE(modreader);
+                       if(mask[ch]&8) {
+                               l->cmd=n->cmd=_mm_read_UBYTE(modreader);
+                               l->inf=n->inf=_mm_read_UBYTE(modreader);
+                       }
+                       if(mask[ch]&16)
+                               n->note=l->note;
+                       if(mask[ch]&32)
+                               n->ins=l->ins;
+                       if(mask[ch]&64)
+                               n->volpan=l->volpan;
+                       if(mask[ch]&128) {
+                               n->cmd=l->cmd;
+                               n->inf=l->inf;
+                       }
+               }
+       } while(row<patrows);
+
+       for(blah=0;blah<of.numchn;blah++) {
+               if(!(of.tracks[numtrk++]=IT_ConvertTrack(&itpat[blah],patrows)))
+                       return 0;
+       }
+
+       return 1;
+}
+
+static void LoadMidiString(MREADER* r,CHAR* dest)
+{
+       CHAR *curp,*lastp;
+
+       _mm_read_UBYTES(dest,32,r);
+       curp=lastp=dest;
+       /* remove blanks and uppercase all */
+       while(*lastp) {
+               if(mik_isalnum((int)*lastp)) *(curp++)=mik_toupper((int)*lastp);
+               lastp++;
+       }
+       *curp=0;
+}
+
+/* Load embedded midi information for resonant filters */
+static void IT_LoadMidiConfiguration(MREADER* r)
+{
+       int i;
+
+       memset(filtermacros,0,sizeof(filtermacros));
+       memset(filtersettings,0,sizeof(filtersettings));
+
+       if (r) { /* information is embedded in file */
+               UWORD dat;
+               CHAR midiline[33];
+
+               dat=_mm_read_I_UWORD(r);
+               _mm_fseek(r,8*dat+0x120,SEEK_CUR);
+
+               /* read midi macros */
+               for(i=0;i<UF_MAXMACRO;i++) {
+                       LoadMidiString(r,midiline);
+                       if((!strncmp(midiline,"F0F00",5))&&
+                          ((midiline[5]=='0')||(midiline[5]=='1')))
+                                       filtermacros[i]=(midiline[5]-'0')|0x80;
+               }
+
+               /* read standalone filters */
+               for(i=0x80;i<0x100;i++) {
+                       LoadMidiString(r,midiline);
+                       if((!strncmp(midiline,"F0F00",5))&&
+                          ((midiline[5]=='0')||(midiline[5]=='1'))) {
+                               filtersettings[i].filter=(midiline[5]-'0')|0x80;
+                               dat=(midiline[6])?(midiline[6]-'0'):0;
+                               if(midiline[7])dat=(dat<<4)|(midiline[7]-'0');
+                               filtersettings[i].inf=dat;
+                       }
+               }
+       } else { /* use default information */
+               filtermacros[0]=FILT_CUT;
+               for(i=0x80;i<0x90;i++) {
+                       filtersettings[i].filter=FILT_RESONANT;
+                       filtersettings[i].inf=(i&0x7f)<<3;
+               }
+       }
+       activemacro=0;
+       for(i=0;i<0x80;i++) {
+               filtersettings[i].filter=filtermacros[0];
+               filtersettings[i].inf=i;
+       }
+}
+
+static BOOL IT_Load(BOOL curious)
+{
+       int t,u,lp;
+       INSTRUMENT *d;
+       SAMPLE *q;
+       /*BOOL compressed=0;*/
+
+       numtrk=0;
+       filters=0;
+
+       /* try to read module header */
+       _mm_read_I_ULONG(modreader);    /* kill the 4 byte header */
+       _mm_read_string(mh->songname,26,modreader);
+       _mm_read_UBYTES(mh->blank01,2,modreader);
+       mh->ordnum      =_mm_read_I_UWORD(modreader);
+       mh->insnum      =_mm_read_I_UWORD(modreader);
+       mh->smpnum      =_mm_read_I_UWORD(modreader);
+       mh->patnum      =_mm_read_I_UWORD(modreader);
+       mh->cwt         =_mm_read_I_UWORD(modreader);
+       mh->cmwt        =_mm_read_I_UWORD(modreader);
+       mh->flags       =_mm_read_I_UWORD(modreader);
+       mh->special     =_mm_read_I_UWORD(modreader);
+       mh->globvol     =_mm_read_UBYTE(modreader);
+       mh->mixvol      =_mm_read_UBYTE(modreader);
+       mh->initspeed   =_mm_read_UBYTE(modreader);
+       mh->inittempo   =_mm_read_UBYTE(modreader);
+       mh->pansep      =_mm_read_UBYTE(modreader);
+       mh->zerobyte    =_mm_read_UBYTE(modreader);
+       mh->msglength   =_mm_read_I_UWORD(modreader);
+       mh->msgoffset   =_mm_read_I_ULONG(modreader);
+       _mm_read_UBYTES(mh->blank02,4,modreader);
+       _mm_read_UBYTES(mh->pantable,64,modreader);
+       _mm_read_UBYTES(mh->voltable,64,modreader);
+
+       if(_mm_eof(modreader)) {
+               _mm_errno=MMERR_LOADING_HEADER;
+               return 0;
+       }
+
+       /* set module variables */
+       of.songname    = DupStr(mh->songname,26,0); /* make a cstr of songname  */
+       of.reppos      = 0;
+       of.numpat      = mh->patnum;
+       of.numins      = mh->insnum;
+       of.numsmp      = mh->smpnum;
+       of.initspeed   = mh->initspeed;
+       of.inittempo   = mh->inittempo;
+       of.initvolume  = mh->globvol;
+       of.flags      |= UF_BGSLIDES | UF_ARPMEM;
+       if (!(mh->flags & 1))
+                       of.flags |= UF_PANNING;
+       of.bpmlimit=32;
+
+       if(mh->songname[25]) {
+               of.numvoices=1+mh->songname[25];
+#ifdef MIKMOD_DEBUG
+               fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices);
+#endif
+       }
+
+       /* set the module type */
+       /* 2.17 : IT 2.14p4 */
+       /* 2.16 : IT 2.14p3 with resonant filters */
+       /* 2.15 : IT 2.14p3 (improved compression) */
+       if((mh->cwt<=0x219)&&(mh->cwt>=0x217))
+               of.modtype=MikMod_strdup(IT_Version[mh->cmwt<0x214?4:5]);
+       else if (mh->cwt>=0x215)
+               of.modtype=MikMod_strdup(IT_Version[mh->cmwt<0x214?2:3]);
+       else {
+               of.modtype = MikMod_strdup(IT_Version[mh->cmwt<0x214?0:1]);
+               of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0';
+               of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0';
+               of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0';
+       }
+
+       if(mh->flags&8)
+               of.flags |= UF_XMPERIODS | UF_LINEAR;
+
+       if((mh->cwt>=0x106)&&(mh->flags&16))
+               old_effect=S3MIT_OLDSTYLE;
+       else
+               old_effect=0;
+
+       /* set panning positions */
+       if (mh->flags & 1)
+               for(t=0;t<64;t++) {
+                       mh->pantable[t]&=0x7f;
+                       if(mh->pantable[t]<64)
+                               of.panning[t]=mh->pantable[t]<<2;
+                       else if(mh->pantable[t]==64)
+                               of.panning[t]=255;
+                       else if(mh->pantable[t]==100)
+                               of.panning[t]=PAN_SURROUND;
+                       else if(mh->pantable[t]==127)
+                               of.panning[t]=PAN_CENTER;
+                       else {
+                               _mm_errno=MMERR_LOADING_HEADER;
+                               return 0;
+                       }
+               }
+       else
+               for(t=0;t<64;t++)
+                       of.panning[t]=PAN_CENTER;
+
+       /* set channel volumes */
+       memcpy(of.chanvol,mh->voltable,64);
+
+       /* read the order data */
+       if(!AllocPositions(mh->ordnum)) return 0;
+       if(!(origpositions=(UWORD*)MikMod_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;
+       }
+
+       if(_mm_eof(modreader)) {
+               _mm_errno = MMERR_LOADING_HEADER;
+               return 0;
+       }
+
+       poslookupcnt=mh->ordnum;
+       S3MIT_CreateOrders(curious);
+
+       if(!(paraptr=(ULONG*)MikMod_malloc((mh->insnum+mh->smpnum+of.numpat)*
+                                      sizeof(ULONG)))) return 0;
+
+       /* read the instrument, sample, and pattern parapointers */
+       _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader);
+
+       if(_mm_eof(modreader)) {
+               _mm_errno = MMERR_LOADING_HEADER;
+               return 0;
+       }
+
+       /* Check for and load midi information for resonant filters */
+       if(mh->cmwt>=0x216) {
+               if(mh->special&8) {
+                       IT_LoadMidiConfiguration(modreader);
+                       if(_mm_eof(modreader)) {
+                               _mm_errno = MMERR_LOADING_HEADER;
+                               return 0;
+                       }
+               } else
+                       IT_LoadMidiConfiguration(NULL);
+               filters=1;
+       }
+
+       /* Check for and load song comment */
+       if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) {
+               _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET);
+               if(!ReadComment(mh->msglength)) return 0;
+       }
+
+       if(!(mh->flags&4)) of.numins=of.numsmp;
+       if(!AllocSamples()) return 0;
+
+       if(!AllocLinear()) return 0;
+
+       /* Load all samples */
+       q = of.samples;
+       for(t=0;t<mh->smpnum;t++) {
+               ITSAMPLE s;
+
+               /* seek to sample position */
+               _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET);
+
+               /* load sample info */
+               _mm_read_string(s.filename,12,modreader);
+               s.zerobyte    = _mm_read_UBYTE(modreader);
+               s.globvol     = _mm_read_UBYTE(modreader);
+               s.flag        = _mm_read_UBYTE(modreader);
+               s.volume      = _mm_read_UBYTE(modreader);
+               _mm_read_string(s.sampname,26,modreader);
+               s.convert     = _mm_read_UBYTE(modreader);
+               s.panning     = _mm_read_UBYTE(modreader);
+               s.length      = _mm_read_I_ULONG(modreader);
+               s.loopbeg     = _mm_read_I_ULONG(modreader);
+               s.loopend     = _mm_read_I_ULONG(modreader);
+               s.c5spd       = _mm_read_I_ULONG(modreader);
+               s.susbegin    = _mm_read_I_ULONG(modreader);
+               s.susend      = _mm_read_I_ULONG(modreader);
+               s.sampoffset  = _mm_read_I_ULONG(modreader);
+               s.vibspeed    = _mm_read_UBYTE(modreader);
+               s.vibdepth    = _mm_read_UBYTE(modreader);
+               s.vibrate     = _mm_read_UBYTE(modreader);
+               s.vibwave     = _mm_read_UBYTE(modreader);
+
+               /* Generate an error if c5spd is > 512k, or samplelength > 256 megs
+                  (nothing would EVER be that high) */
+
+               if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)) {
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;
+                       return 0;
+               }
+
+               /* Reality check for sample loop information */
+               if((s.flag&16)&&
+                  ((s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL))) {
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;
+                       return 0;
+               }
+
+               q->samplename = DupStr(s.sampname,26,0);
+               q->speed      = s.c5spd / 2;
+               q->panning    = ((s.panning&127)==64)?255:(s.panning&127)<<2;
+               q->length     = s.length;
+               q->loopstart  = s.loopbeg;
+               q->loopend    = s.loopend;
+               q->volume     = s.volume;
+               q->globvol    = s.globvol;
+               q->seekpos    = s.sampoffset;
+
+               /* Convert speed to XM linear finetune */
+               if(of.flags&UF_LINEAR)
+                       q->speed=speed_to_finetune(s.c5spd,t);
+
+               if(s.panning&128) q->flags|=SF_OWNPAN;
+
+               if(s.vibrate) {
+                       q->vibflags |= AV_IT;
+                       q->vibtype   = s.vibwave;
+                       q->vibsweep  = s.vibrate * 2;
+                       q->vibdepth  = s.vibdepth;
+                       q->vibrate   = s.vibspeed;
+               }
+
+               if(s.flag&2) q->flags|=SF_16BITS;
+               if((s.flag&8)&&(mh->cwt>=0x214)) {
+                       q->flags|=SF_ITPACKED;
+                       /*compressed=1;*/
+               }
+               if(s.flag&16) q->flags|=SF_LOOP;
+               if(s.flag&64) q->flags|=SF_BIDI;
+
+               if(mh->cwt>=0x200) {
+                       if(s.convert&1) q->flags|=SF_SIGNED;
+                       if(s.convert&4) q->flags|=SF_DELTA;
+               }
+               q++;
+       }
+
+       /* Load instruments if instrument mode flag enabled */
+       if(mh->flags&4) {
+               if(!AllocInstruments()) return 0;
+               d=of.instruments;
+               of.flags|=UF_NNA|UF_INST;
+
+               for(t=0;t<mh->insnum;t++) {
+                       ITINSTHEADER ih;
+
+                       /* seek to instrument position */
+                       _mm_fseek(modreader,paraptr[t]+4,SEEK_SET);
+
+                       /* load instrument info */
+                       _mm_read_string(ih.filename,12,modreader);
+                       ih.zerobyte  = _mm_read_UBYTE(modreader);
+                       if(mh->cwt<0x200) {
+                               /* load IT 1.xx inst header */
+                               ih.volflg    = _mm_read_UBYTE(modreader);
+                               ih.volbeg    = _mm_read_UBYTE(modreader);
+                               ih.volend    = _mm_read_UBYTE(modreader);
+                               ih.volsusbeg = _mm_read_UBYTE(modreader);
+                               ih.volsusend = _mm_read_UBYTE(modreader);
+                               _mm_read_I_UWORD(modreader);
+                               ih.fadeout   = _mm_read_I_UWORD(modreader);
+                               ih.nna       = _mm_read_UBYTE(modreader);
+                               ih.dnc       = _mm_read_UBYTE(modreader);
+                       } else {
+                               /* Read IT200+ header */
+                               ih.nna       = _mm_read_UBYTE(modreader);
+                               ih.dct       = _mm_read_UBYTE(modreader);
+                               ih.dca       = _mm_read_UBYTE(modreader);
+                               ih.fadeout   = _mm_read_I_UWORD(modreader);
+                               ih.ppsep     = _mm_read_UBYTE(modreader);
+                               ih.ppcenter  = _mm_read_UBYTE(modreader);
+                               ih.globvol   = _mm_read_UBYTE(modreader);
+                               ih.chanpan   = _mm_read_UBYTE(modreader);
+                               ih.rvolvar   = _mm_read_UBYTE(modreader);
+                               ih.rpanvar   = _mm_read_UBYTE(modreader);
+                       }
+
+                       ih.trkvers   = _mm_read_I_UWORD(modreader);
+                       ih.numsmp    = _mm_read_UBYTE(modreader);
+                       _mm_skip_BYTE(modreader);
+                       _mm_read_string(ih.name,26,modreader);
+                       _mm_read_UBYTES(ih.blank01,6,modreader);
+                       _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader);
+                       if(mh->cwt<0x200) {
+                               /* load IT 1xx volume envelope */
+                               _mm_read_UBYTES(ih.volenv,200,modreader);
+                               for(lp=0;lp<ITENVCNT;lp++) {
+                                       ih.oldvoltick[lp] = _mm_read_UBYTE(modreader);
+                                       ih.volnode[lp]    = _mm_read_UBYTE(modreader);
+                               }
+                       } else {
+                               /* load IT 2xx volume, pan and pitch envelopes */
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define IT_LoadEnvelope(name,type)                                                                             \
+                               ih. name##flg   =_mm_read_UBYTE(modreader);                             \
+                               ih. name##pts   =_mm_read_UBYTE(modreader);                             \
+                               if (ih. name##pts > ITENVCNT)                                                   \
+                                       ih. name##pts = ITENVCNT;                                                       \
+                               ih. name##beg   =_mm_read_UBYTE(modreader);                             \
+                               ih. name##end   =_mm_read_UBYTE(modreader);                             \
+                               ih. name##susbeg=_mm_read_UBYTE(modreader);                             \
+                               ih. name##susend=_mm_read_UBYTE(modreader);                             \
+                               for(lp=0;lp<ITENVCNT;lp++) {                                                    \
+                                       ih. name##node[lp]=_mm_read_##type (modreader);         \
+                                       ih. name##tick[lp]=_mm_read_I_UWORD(modreader);         \
+                               }                                                                                                               \
+                               _mm_skip_BYTE(modreader)
+#else
+#define IT_LoadEnvelope(name,type)                                                                             \
+                               ih. name/**/flg   =_mm_read_UBYTE(modreader);                   \
+                               ih. name/**/pts   =_mm_read_UBYTE(modreader);                   \
+                               if (ih. name/**/pts > ITENVCNT)                                                 \
+                                       ih. name/**/pts = ITENVCNT;                                                     \
+                               ih. name/**/beg   =_mm_read_UBYTE(modreader);                   \
+                               ih. name/**/end   =_mm_read_UBYTE(modreader);                   \
+                               ih. name/**/susbeg=_mm_read_UBYTE(modreader);                   \
+                               ih. name/**/susend=_mm_read_UBYTE(modreader);                   \
+                               for(lp=0;lp<ITENVCNT;lp++) {                                                    \
+                                       ih. name/**/node[lp]=_mm_read_/**/type (modreader);     \
+                                       ih. name/**/tick[lp]=_mm_read_I_UWORD(modreader);       \
+                               }                                                                                                               \
+                               _mm_skip_BYTE(modreader)
+#endif
+
+                               IT_LoadEnvelope(vol,UBYTE);
+                               IT_LoadEnvelope(pan,SBYTE);
+                               IT_LoadEnvelope(pit,SBYTE);
+#undef IT_LoadEnvelope
+                       }
+
+                       if(_mm_eof(modreader)) {
+                               _mm_errno = MMERR_LOADING_SAMPLEINFO;
+                               return 0;
+                       }
+
+                       d->volflg|=EF_VOLENV;
+                       d->insname = DupStr(ih.name,26,0);
+                       d->nnatype = ih.nna & NNA_MASK;
+
+                       if(mh->cwt<0x200) {
+                               d->volfade=ih.fadeout<< 6;
+                               if(ih.dnc) {
+                                       d->dct=DCT_NOTE;
+                                       d->dca=DCA_CUT;
+                               }
+
+                               if(ih.volflg&1) d->volflg|=EF_ON;
+                               if(ih.volflg&2) d->volflg|=EF_LOOP;
+                               if(ih.volflg&4) d->volflg|=EF_SUSTAIN;
+
+                               /* XM conversion of IT envelope Array */
+                               d->volbeg    = ih.volbeg;
+                               d->volend    = ih.volend;
+                               d->volsusbeg = ih.volsusbeg;
+                               d->volsusend = ih.volsusend;
+
+                               if(ih.volflg&1) {
+                                       for(u=0;u<ITENVCNT;u++)
+                                               if(ih.oldvoltick[d->volpts]!=0xff) {
+                                                       d->volenv[d->volpts].val=(ih.volnode[d->volpts]<<2);
+                                                       d->volenv[d->volpts].pos=ih.oldvoltick[d->volpts];
+                                                       d->volpts++;
+                                               } else
+                                                       break;
+                               }
+                       } else {
+                               d->panning=((ih.chanpan&127)==64)?255:(ih.chanpan&127)<<2;
+                               if(!(ih.chanpan&128)) d->flags|=IF_OWNPAN;
+
+                               if(!(ih.ppsep & 128)) {
+                                       d->pitpansep=ih.ppsep<<2;
+                                       d->pitpancenter=ih.ppcenter;
+                                       d->flags|=IF_PITCHPAN;
+                               }
+                               d->globvol=ih.globvol>>1;
+                               d->volfade=ih.fadeout<<5;
+                               d->dct    =ih.dct;
+                               d->dca    =ih.dca;
+
+                               if(mh->cwt>=0x204) {
+                                       d->rvolvar = ih.rvolvar;
+                                       d->rpanvar = ih.rpanvar;
+                               }
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define IT_ProcessEnvelope(name)                                                                               \
+                               if(ih. name##flg&1) d-> name##flg|=EF_ON;                               \
+                               if(ih. name##flg&2) d-> name##flg|=EF_LOOP;                             \
+                               if(ih. name##flg&4) d-> name##flg|=EF_SUSTAIN;                  \
+                               d-> name##pts=ih. name##pts;                                                    \
+                               d-> name##beg=ih. name##beg;                                                    \
+                               d-> name##end=ih. name##end;                                                    \
+                               d-> name##susbeg=ih. name##susbeg;                                              \
+                               d-> name##susend=ih. name##susend;                                              \
+                                                                                                                                               \
+                               for(u=0;u<ih. name##pts;u++)                                                    \
+                                       d-> name##env[u].pos=ih. name##tick[u];                         \
+                                                                                                                                               \
+                               if((d-> name##flg&EF_ON)&&(d-> name##pts<2))                    \
+                                       d-> name##flg&=~EF_ON
+#else
+#define IT_ProcessEnvelope(name)                                                                       \
+                               if(ih. name/**/flg&1) d-> name/**/flg|=EF_ON;           \
+                               if(ih. name/**/flg&2) d-> name/**/flg|=EF_LOOP;         \
+                               if(ih. name/**/flg&4) d-> name/**/flg|=EF_SUSTAIN;      \
+                               d-> name/**/pts=ih. name/**/pts;                                        \
+                               d-> name/**/beg=ih. name/**/beg;                                        \
+                               d-> name/**/end=ih. name/**/end;                                        \
+                               d-> name/**/susbeg=ih. name/**/susbeg;                          \
+                               d-> name/**/susend=ih. name/**/susend;                          \
+                                                                                                                                       \
+                               for(u=0;u<ih. name/**/pts;u++)                                          \
+                                       d-> name/**/env[u].pos=ih. name/**/tick[u];             \
+                                                                                                                                       \
+                               if((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2))        \
+                                       d-> name/**/flg&=~EF_ON
+#endif
+
+                               IT_ProcessEnvelope(vol);
+
+                               for(u=0;u<ih.volpts;u++)
+                                       d->volenv[u].val=(ih.volnode[u]<<2);
+
+                               IT_ProcessEnvelope(pan);
+                               for(u=0;u<ih.panpts;u++)
+                                       d->panenv[u].val=
+                                         ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2;
+
+                               IT_ProcessEnvelope(pit);
+                               for(u=0;u<ih.pitpts;u++)
+                                       d->pitenv[u].val=ih.pitnode[u]+32;
+#undef IT_ProcessEnvelope
+
+                               if(ih.pitflg&0x80) {
+                                       /* filter envelopes not supported yet */
+                                       d->pitflg&=~EF_ON;
+                                       ih.pitpts=ih.pitbeg=ih.pitend=0;
+#ifdef MIKMOD_DEBUG
+                                       {
+                                               static int warn=0;
+
+                                               if(!warn)
+                                                       fprintf(stderr, "\rFilter envelopes not supported yet\n");
+                                               warn=1;
+                                       }
+#endif
+                               }
+                       }
+
+                       for(u=0;u<ITNOTECNT;u++) {
+                               d->samplenote[u]=(ih.samptable[u]&255);
+                               d->samplenumber[u]=
+                                 (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff;
+                               if(d->samplenumber[u]>=of.numsmp)
+                                       d->samplenote[u]=255;
+                               else if (of.flags&UF_LINEAR) {
+                                       int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];
+                                       d->samplenote[u]=(note<0)?0:(note>255?255:note);
+                               }
+                       }
+
+                       d++;
+               }
+       } else if(of.flags & UF_LINEAR) {
+               if(!AllocInstruments()) return 0;
+               d=of.instruments;
+               of.flags|=UF_INST;
+
+               for(t=0;t<mh->smpnum;t++,d++)
+                       for(u=0;u<ITNOTECNT;u++) {
+                               if(d->samplenumber[u]>=of.numsmp)
+                                       d->samplenote[u]=255;
+                               else {
+                                       int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];
+                                       d->samplenote[u]=(note<0)?0:(note>255?255:note);
+                               }
+                       }
+       }
+
+       /* Figure out how many channels this song actually uses */
+       of.numchn=0;
+       memset(remap,-1,UF_MAXCHAN*sizeof(UBYTE));
+       for(t=0;t<of.numpat;t++) {
+               UWORD packlen;
+
+               /* seek to pattern position */
+               if(paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
+                       _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
+                       _mm_read_I_UWORD(modreader);
+                       /* read pattern length (# of rows)
+                          Impulse Tracker never creates patterns with less than 32 rows,
+                          but some other trackers do, so we only check for more than 256
+                          rows */
+                       packlen=_mm_read_I_UWORD(modreader);
+                       if(packlen>256) {
+                               _mm_errno=MMERR_LOADING_PATTERN;
+                               return 0;
+                       }
+                       _mm_read_I_ULONG(modreader);
+                       if(!IT_GetNumChannels(packlen)) return 0;
+               }
+       }
+
+       /* give each of them a different number */
+       for(t=0;t<UF_MAXCHAN;t++)
+               if(!remap[t])
+                       remap[t]=of.numchn++;
+
+       of.numtrk = of.numpat*of.numchn;
+       if(of.numvoices)
+               if (of.numvoices<of.numchn) of.numvoices=of.numchn;
+
+       if(!AllocPatterns()) return 0;
+       if(!AllocTracks()) return 0;
+
+       for(t=0;t<of.numpat;t++) {
+               UWORD packlen;
+
+               /* seek to pattern position */
+               if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
+                       of.pattrows[t]=64;
+                       for(u=0;u<of.numchn;u++) {
+                               int k;
+
+                               UniReset();
+                               for(k=0;k<64;k++) UniNewline();
+                               of.tracks[numtrk++]=UniDup();
+                       }
+               } else {
+                       _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
+                       packlen=_mm_read_I_UWORD(modreader);
+                       (void)packlen; /* unused */
+                       of.pattrows[t]=_mm_read_I_UWORD(modreader);
+                       _mm_read_I_ULONG(modreader);
+                       if(!IT_ReadPattern(of.pattrows[t])) return 0;
+               }
+       }
+
+       return 1;
+}
+
+static CHAR *IT_LoadTitle(void)
+{
+       CHAR s[26];
+
+       _mm_fseek(modreader,4,SEEK_SET);
+       if(!_mm_read_UBYTES(s,26,modreader)) return NULL;
+
+       return(DupStr(s,26,0));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_it={
+       NULL,
+       "IT",
+       "IT (Impulse Tracker)",
+       IT_Init,
+       IT_Test,
+       IT_Load,
+       IT_Cleanup,
+       IT_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/loaders/load_mod.c b/libs/mikmod/loaders/load_mod.c
new file mode 100644 (file)
index 0000000..6fffac0
--- /dev/null
@@ -0,0 +1,514 @@
+/*     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$
+
+  Generic MOD loader (Protracker, StarTracker, FastTracker, etc)
+
+==============================================================================*/
+
+#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"
+#include "mikmod_ctype.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))) &&
+               (mik_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)) && (mik_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)))
+               && (mik_isdigit(id[0])) && (mik_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 *)MikMod_malloc(sizeof(MODULEHEADER))))
+               return 0;
+       return 1;
+}
+
+static void MOD_Cleanup(void)
+{
+       MikMod_free(mh);
+       MikMod_free(patbuf);
+       mh=NULL;
+       patbuf=NULL;
+}
+
+/*
+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 *)MikMod_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 = MikMod_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: */
diff --git a/libs/mikmod/loaders/load_s3m.c b/libs/mikmod/loaders/load_s3m.c
new file mode 100644 (file)
index 0000000..039650e
--- /dev/null
@@ -0,0 +1,476 @@
+/*     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$
+
+  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 const 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 const int numeric[NUMTRACKERS]={14,14,16,16};
+
+/*========== Loader code */
+
+static 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;
+}
+
+static BOOL S3M_Init(void)
+{
+       if(!(s3mbuf=(S3MNOTE*)MikMod_malloc(32*64*sizeof(S3MNOTE)))) return 0;
+       if(!(mh=(S3MHEADER*)MikMod_malloc(sizeof(S3MHEADER)))) return 0;
+       if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0;
+       memset(poslookup,-1,256);
+
+       return 1;
+}
+
+static void S3M_Cleanup(void)
+{
+       MikMod_free(s3mbuf);
+       MikMod_free(paraptr);
+       MikMod_free(poslookup);
+       MikMod_free(mh);
+       MikMod_free(origpositions);
+       s3mbuf=NULL;
+       paraptr=NULL;
+       poslookup=NULL;
+       mh=NULL;
+       origpositions=NULL;
+}
+
+/* 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 0 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 0;
+               }
+
+               if(flag) {
+                       ch=flag&31;
+                       if(mh->channels[ch]<32) remap[ch] = 0;
+                       if(flag&32) {_mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader);}
+                       if(flag&64) _mm_skip_BYTE(modreader);
+                       if(flag&128){_mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader);}
+               } else row++;
+       }
+       return 1;
+}
+
+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();
+}
+
+static 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 = MikMod_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=(UWORD*)MikMod_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*)MikMod_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 */
+               /* enforce it, if we'll use S3MIT_SCREAM in S3M_ConvertTrack() */
+               if (s.length > 64000 && tracker == 1)
+                       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    = (((ULONG)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;
+}
+
+static 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: */
diff --git a/libs/mikmod/loaders/load_xm.c b/libs/mikmod/loaders/load_xm.c
new file mode 100644 (file)
index 0000000..f40f27c
--- /dev/null
@@ -0,0 +1,840 @@
+/*     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$
+
+  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 */
+
+static 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;
+}
+
+static BOOL XM_Init(void)
+{
+       if(!(mh=(XMHEADER *)MikMod_malloc(sizeof(XMHEADER)))) return 0;
+       return 1;
+}
+
+static void XM_Cleanup(void)
+{
+       MikMod_free(mh);
+       mh=NULL;
+}
+
+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*)MikMod_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) {
+                                                       MikMod_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)) {
+                               MikMod_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);
+
+                       MikMod_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*)MikMod_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0;
+               for(v=0;v<of.numchn;v++)
+                       of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64);
+               MikMod_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, ck;
+       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;
+               ck = _mm_ftell(modreader);
+               _mm_fseek(modreader,0,SEEK_END);
+               if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) {
+                       _mm_fseek(modreader,ck,SEEK_SET);
+                       break;
+               }
+               _mm_fseek(modreader,ck,SEEK_SET);
+               _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) */
+                               if (headend>=_mm_ftell(modreader)) {
+                                       for(u=headend-_mm_ftell(modreader);u;u--) {
+                                               _mm_skip_BYTE(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)) {
+                                       MikMod_free(nextwav);nextwav=NULL;
+                                       MikMod_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=(ULONG*)MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))){
+                                                       MikMod_free(wh);wh=NULL;
+                                                       _mm_errno = MMERR_OUT_OF_MEMORY;
+                                                       return 0;
+                                               }
+                                               if(!(wh=(XMWAVHEADER*)MikMod_realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) {
+                                                       MikMod_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;
+
+                                       /* last instrument is at the end of file in version 0x0104 */
+                                       if(_mm_eof(modreader) && (mh->version<0x0104 || t<of.numins-1)) {
+                                               MikMod_free(nextwav);MikMod_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 */
+                               ck = _mm_ftell(modreader);
+                               _mm_fseek(modreader,0,SEEK_END);
+                               if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) {
+                                       _mm_fseek(modreader,ck,SEEK_SET);
+                                       break;
+                               }
+                               _mm_fseek(modreader,ck,SEEK_SET);
+                               for(u=headend-_mm_ftell(modreader);u;u--) {
+                                       _mm_skip_BYTE(modreader);
+                               }
+
+                               /* last instrument is at the end of file in version 0x0104 */
+                               if(_mm_eof(modreader) && (mh->version<0x0104 || t<of.numins-1)) {
+                                       MikMod_free(nextwav);MikMod_free(wh);
+                                       nextwav=NULL;wh=NULL;
+                                       _mm_errno = MMERR_LOADING_SAMPLEINFO;
+                                       return 0;
+                               }
+                       }
+               }
+       }
+
+       /* sanity check */
+       if(!of.numsmp) {
+               MikMod_free(nextwav);nextwav=NULL;
+               MikMod_free(wh);wh=NULL;
+               _mm_errno = MMERR_LOADING_SAMPLEINFO;
+               return 0;
+       }
+
+       return 1;
+}
+
+static 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 || mh->songlength > 256) {
+               _mm_errno=MMERR_NOT_A_MODULE;
+               return 0;
+       }
+/*     _mm_read_UBYTES(mh->orders,256,modreader);*/
+/*     _mm_read_UBYTES(mh->orders,mh->headersize-20,modreader);*/
+       _mm_read_UBYTES(mh->orders,mh->songlength,modreader);
+       if(_mm_fseek(modreader, mh->headersize+60, SEEK_SET) ||
+          _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;(t>=0)&&(tracker[t]<=' ');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   = MikMod_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()) {
+               MikMod_free(nextwav);MikMod_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;
+                       }
+               }
+
+       MikMod_free(wh);MikMod_free(nextwav);
+       wh=NULL;nextwav=NULL;
+       return 1;
+}
+
+static CHAR *XM_LoadTitle(void)
+{
+       CHAR str[21];
+
+       _mm_fseek(modreader,17,SEEK_SET);
+       if(!_mm_read_UBYTES(str, 21, modreader)) return NULL;
+
+       return(DupStr(str,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: */
diff --git a/libs/mikmod/mmio/mmalloc.c b/libs/mikmod/mmio/mmalloc.c
new file mode 100644 (file)
index 0000000..ed5fd46
--- /dev/null
@@ -0,0 +1,142 @@
+/*     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$
+
+  Dynamic memory routines
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_POSIX_MEMALIGN
+#define _XOPEN_SOURCE 600 /* for posix_memalign */
+#endif
+
+#include "string.h"
+#include "mikmod_internals.h"
+
+#if defined(HAVE_SSE2) || defined(HAVE_ALTIVEC)
+#undef WIN32_ALIGNED_MALLOC
+#if defined(_WIN32) && !defined(_WIN32_WCE)
+# if defined(_WIN64) /* OK with MSVC and MinGW */
+#  define WIN32_ALIGNED_MALLOC
+# elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+#  define WIN32_ALIGNED_MALLOC
+# elif defined(__MINGW32__)
+  /* no guarantees that msvcrt.dll will have it */
+# endif
+#endif
+
+#define PTRSIZE (sizeof(void*))
+
+/* return a 16 byte aligned address */
+void* MikMod_amalloc(size_t size)
+{
+       void *d;
+#if defined(HAVE_POSIX_MEMALIGN)
+       if (!posix_memalign(&d, 16, size)) {
+               memset(d, 0, size);
+               return d;
+       }
+#elif defined(WIN32_ALIGNED_MALLOC)
+       d = _aligned_malloc(size, 16);
+       if (d) {
+               ZeroMemory(d, size);
+               return d;
+       }
+#else
+       size_t s = (size)? ((size + (PTRSIZE-1)) & ~(PTRSIZE-1)) : PTRSIZE;
+       s += PTRSIZE + 16;
+       d = calloc(1, s);
+       if (d) {
+               char *pptr = (char *)d + PTRSIZE;
+               size_t err = ((size_t)pptr) & 15;
+               char *fptr = pptr + (16 - err);
+               *(size_t*)(fptr - PTRSIZE) = (size_t)d;
+               return fptr;
+       }
+#endif
+
+       _mm_errno = MMERR_OUT_OF_MEMORY;
+       if(_mm_errorhandler) _mm_errorhandler();
+       return NULL;
+}
+
+void MikMod_afree(void *data)
+{
+       if (!data) return;
+#if defined(HAVE_POSIX_MEMALIGN)
+       free(data);
+#elif defined(WIN32_ALIGNED_MALLOC)
+       _aligned_free(data);
+#else
+       free((void *) *(size_t*)((unsigned char *)data - PTRSIZE));
+#endif
+}
+#endif /* (HAVE_SSE2) || (HAVE_ALTIVEC) */
+
+void* MikMod_realloc(void *data, size_t size)
+{
+       if (data) return realloc(data, size);
+       return calloc(1, size);
+}
+
+/* Same as malloc, but sets error variable _mm_error when fails */
+void* MikMod_malloc(size_t size)
+{
+       return MikMod_calloc(1, size);
+}
+
+/* Same as calloc, but sets error variable _mm_error when fails */
+void* MikMod_calloc(size_t nitems, size_t size)
+{
+       void *d = calloc(nitems, size);
+       if (d) return d;
+
+       _mm_errno = MMERR_OUT_OF_MEMORY;
+       if(_mm_errorhandler) _mm_errorhandler();
+       return NULL;
+}
+
+void MikMod_free(void *data)
+{
+       if (data) free(data);
+}
+
+/* like strdup(), but the result must be freed using MikMod_free() */
+CHAR *MikMod_strdup(const CHAR *s)
+{
+       size_t l;
+       CHAR *d;
+
+       if (!s) return NULL;
+
+       l = strlen(s) + 1;
+       d = (CHAR *) MikMod_calloc(1, l * sizeof(CHAR));
+       if (d) strcpy(d, s);
+       return d;
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/mmio/mmerror.c b/libs/mikmod/mmio/mmerror.c
new file mode 100644 (file)
index 0000000..cf4c99e
--- /dev/null
@@ -0,0 +1,315 @@
+/*     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$
+
+  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"
+
+#define _mmerr_invalid "Invalid error code"
+
+static const 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  */
+#ifdef DRV_AF
+       "Cannot find suitable AudioFile audio port",
+#else
+       _mmerr_invalid,
+#endif
+
+/* AIX driver errors */
+#ifdef DRV_AIX
+       "Configuration (init step) of audio device failed",
+       "Configuration (control step) of audio device failed",
+       "Configuration (start step) of audio device failed",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* Ultrasound driver errors */
+#ifdef DRV_ULTRA
+       "Ultrasound driver only works in 16 bit stereo 44 KHz",
+       "Ultrasound card could not be reset",
+       "Could not start Ultrasound timer",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* HP driver errors  */
+#ifdef DRV_HP
+       "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",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* Open Sound System driver errors */
+#ifdef DRV_OSS
+       "Could not set fragment size",
+       "Could not set sample size",
+       "Could not set mono/stereo setting",
+       "Could not set sample rate",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid,
+#endif
+
+/* SGI driver errors */
+#ifdef DRV_SGI
+       "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",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* Sun driver errors */
+#ifdef DRV_SUN
+       "Sound device initialization failed",
+#else
+       _mmerr_invalid,
+#endif
+
+/* OS/2 drivers errors */
+#if defined(DRV_OS2) || defined(DRV_DART)
+       "Could not set mixing parameters",
+#else
+       _mmerr_invalid,
+#endif
+#ifdef DRV_OS2
+       "Could not create playback semaphores",
+       "Could not create playback timer",
+       "Could not create playback thread",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* DirectSound driver errors */
+#ifdef DRV_DS
+       "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",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid,
+#endif
+
+/* Windows Multimedia API driver errors */
+#ifdef DRV_WIN
+       "Invalid device handle",
+       "The resource is already allocated",
+       "Invalid device identifier",
+       "Unsupported output format",
+       "Unknown error",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* Macintosh driver errors */
+#ifdef DRV_MAC
+       "Unsupported sample rate",
+       "Could not start playback",
+#else
+       _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* MacOS X/Darwin driver errors */
+#ifdef DRV_OSX
+       "Unknown device",
+       "Bad property",
+       "Could not set playback format",
+       "Could not set mono/stereo setting",
+       "Could not create playback buffers",
+       "Could not create playback thread",
+       "Could not start audio device",
+       "Could not create buffer thread",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* DOS driver errors */
+#ifdef DRV_WSS
+       "WSS_STARTDMA",
+#else
+       _mmerr_invalid,
+#endif
+#ifdef DRV_SB
+       "SB_STARTDMA",
+#else
+       _mmerr_invalid,
+#endif
+
+/* float32 output */
+
+       "This driver doesn't support 32 bit float output",
+
+/* OpenAL driver errors */
+#ifdef DRV_OPENAL
+       "Could not create context",
+       "Could not make context current",
+       "Could not create buffers",
+       "Could not create sources",
+       "Could not change source parameters",
+       "Could not queue buffers",
+       "Could not unqueue buffers",
+       "Could not copy buffer data",
+       "Could not get source parameters",
+       "Could not play source",
+       "Could not stop source",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* ALSA driver errors */
+#ifdef DRV_ALSA
+       "No ALSA configurations available",
+       "Could not set ALSA output params",
+       "Could not set playback format",
+       "Could not set sample rate",
+       "Could not set mono/stereo setting",
+       "Could not get buffer size from ALSA",
+       "ALSA PCM start error",
+       "ALSA PCM write error",
+       "ALSA PCM recovery failure",
+#else
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+       _mmerr_invalid, _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* Sndio errors */
+#ifdef DRV_SNDIO
+       "Could not set SNDIO output params",
+       "Unsupported SNDIO output params",
+#else
+       _mmerr_invalid, _mmerr_invalid,
+#endif
+
+/* Invalid error */
+
+       _mmerr_invalid
+};
+
+MIKMODAPI const char *MikMod_strerror(int code)
+{
+       if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX;
+       return _mm_errmsg[code];
+}
+
+/* User installed error callback */
+MikMod_handler_t _mm_errorhandler = NULL;
+MIKMODAPI int  _mm_errno = 0;
+MIKMODAPI BOOL _mm_critical = 0;
+
+static 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: */
diff --git a/libs/mikmod/mmio/mmio.c b/libs/mikmod/mmio/mmio.c
new file mode 100644 (file)
index 0000000..2ab6aff
--- /dev/null
@@ -0,0 +1,537 @@
+/*     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$
+
+  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.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.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
+
+/* some prototypes */
+static BOOL _mm_MemReader_Eof(MREADER* reader);
+static BOOL _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size);
+static int _mm_MemReader_Get(MREADER* reader);
+static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence);
+static long _mm_MemReader_Tell(MREADER* reader);
+
+/*static long _mm_iobase = 0, temp_iobase = 0;*/
+
+FILE* _mm_fopen(const CHAR* fname, const CHAR* attrib)
+{
+       FILE *fp;
+
+       if(!(fp=fopen(fname,attrib))) {
+               _mm_errno = MMERR_OPENING_FILE;
+               if(_mm_errorhandler) _mm_errorhandler();
+       }
+       return fp;
+}
+
+BOOL _mm_FileExists(const 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 iobase */
+void _mm_iobase_setcur(MREADER* reader)
+{
+       reader->prev_iobase=reader->iobase;  /* store old value in case of revert */
+       reader->iobase=reader->Tell(reader);
+}
+
+/* Reverts to the last known iobase value. */
+void _mm_iobase_revert(MREADER* reader)
+{
+       reader->iobase=reader->prev_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 int _mm_FileReader_Seek(MREADER* reader,long offset,int whence)
+{
+       return fseek(((MFILEREADER*)reader)->file,
+                                (whence==SEEK_SET)?offset+reader->iobase:offset,whence);
+}
+
+static long _mm_FileReader_Tell(MREADER* reader)
+{
+       return ftell(((MFILEREADER*)reader)->file)-reader->iobase;
+}
+
+MREADER *_mm_new_file_reader(FILE* fp)
+{
+       MFILEREADER* reader=(MFILEREADER*)MikMod_calloc(1,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)
+{
+       MikMod_free(reader);
+}
+
+/*========== File Writer */
+
+typedef struct MFILEWRITER {
+       MWRITER core;
+       FILE*   file;
+} MFILEWRITER;
+
+static int _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, const void* ptr, size_t size)
+{
+       return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size);
+}
+
+static int _mm_FileWriter_Put(MWRITER* writer,int value)
+{
+       return fputc(value,((MFILEWRITER*)writer)->file);
+}
+
+MWRITER *_mm_new_file_writer(FILE* fp)
+{
+       MFILEWRITER* writer=(MFILEWRITER*)MikMod_calloc(1,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)
+{
+       MikMod_free (writer);
+}
+
+/*========== Memory Reader */
+
+typedef struct MMEMREADER {
+       MREADER core;
+       const void *buffer;
+       long len;
+       long pos;
+} MMEMREADER;
+
+void _mm_delete_mem_reader(MREADER* reader)
+{
+       MikMod_free(reader);
+}
+
+MREADER *_mm_new_mem_reader(const void *buffer, long len)
+{
+       MMEMREADER* reader=(MMEMREADER*)MikMod_calloc(1,sizeof(MMEMREADER));
+       if (reader)
+       {
+               reader->core.Eof =&_mm_MemReader_Eof;
+               reader->core.Read=&_mm_MemReader_Read;
+               reader->core.Get =&_mm_MemReader_Get;
+               reader->core.Seek=&_mm_MemReader_Seek;
+               reader->core.Tell=&_mm_MemReader_Tell;
+               reader->buffer = buffer;
+               reader->len = len;
+               reader->pos = 0;
+       }
+       return (MREADER*)reader;
+}
+
+static BOOL _mm_MemReader_Eof(MREADER* reader)
+{
+       MMEMREADER* mr = (MMEMREADER*) reader;
+       if (!mr) return 1;
+       if (mr->pos >= mr->len) return 1;
+       return 0;
+}
+
+static BOOL _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size)
+{
+       unsigned char *d;
+       const unsigned char *s;
+       MMEMREADER* mr;
+       long siz;
+       BOOL ret;
+
+       if (!reader || !size || (size > (size_t) LONG_MAX))
+               return 0;
+
+       mr = (MMEMREADER*) reader;
+       siz = (long) size;
+       if (mr->pos >= mr->len) return 0;       /* @ eof */
+       if (mr->pos + siz > mr->len) {
+               siz = mr->len - mr->pos;
+               ret = 0; /* not enough remaining bytes */
+       }
+       else {
+               ret = 1;
+       }
+
+       s = (const unsigned char *) mr->buffer;
+       s += mr->pos;
+       mr->pos += siz;
+       d = (unsigned char *) ptr;
+
+       while (siz) {
+               *d++ = *s++;
+               siz--;
+       }
+
+       return ret;
+}
+
+static int _mm_MemReader_Get(MREADER* reader)
+{
+       MMEMREADER* mr;
+       int c;
+
+       mr = (MMEMREADER*) reader;
+       if (mr->pos >= mr->len) return EOF;
+       c = ((const unsigned char*) mr->buffer)[mr->pos];
+       mr->pos++;
+
+       return c;
+}
+
+static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence)
+{
+       MMEMREADER* mr;
+
+       if (!reader) return -1;
+       mr = (MMEMREADER*) reader;
+       switch(whence)
+       {
+       case SEEK_CUR:
+               mr->pos += offset;
+               break;
+       case SEEK_SET:
+               mr->pos = reader->iobase + offset;
+               break;
+       case SEEK_END:
+               mr->pos = mr->len + offset;
+               break;
+       }
+       if (mr->pos < reader->iobase) {
+               mr->pos = mr->core.iobase;
+               return -1;
+       }
+       if (mr->pos > mr->len) {
+               mr->pos = mr->len;
+       }
+       return 0;
+}
+
+static long _mm_MemReader_Tell(MREADER* reader)
+{
+       if (reader) {
+               return ((MMEMREADER*)reader)->pos - reader->iobase;
+       }
+       return 0;
+}
+
+/*========== Write functions */
+
+void _mm_write_string(const 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);
+}
+
+void _mm_write_M_SWORDS(SWORD *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_M_SWORD(*(buffer++),writer);
+}
+
+void _mm_write_M_UWORDS(UWORD *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_M_UWORD(*(buffer++),writer);
+}
+
+void _mm_write_I_SWORDS(SWORD *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_I_SWORD(*(buffer++),writer);
+}
+
+void _mm_write_I_UWORDS(UWORD *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_I_UWORD(*(buffer++),writer);
+}
+
+void _mm_write_M_SLONGS(SLONG *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_M_SLONG(*(buffer++),writer);
+}
+
+void _mm_write_M_ULONGS(ULONG *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_M_ULONG(*(buffer++),writer);
+}
+
+void _mm_write_I_SLONGS(SLONG *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_I_SLONG(*(buffer++),writer);
+}
+
+void _mm_write_I_ULONGS(ULONG *buffer,int cnt,MWRITER* writer)
+{
+       while(cnt-- > 0) _mm_write_I_ULONG(*(buffer++),writer);
+}
+
+/*========== Read functions */
+
+BOOL _mm_read_string(CHAR* buffer,int cnt,MREADER* reader)
+{
+       return reader->Read(reader,buffer,cnt);
+}
+
+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));
+}
+
+BOOL _mm_read_M_SWORDS(SWORD *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_M_SWORD(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_M_UWORDS(UWORD *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_M_UWORD(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_I_SWORDS(SWORD *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_I_SWORD(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_I_UWORDS(UWORD *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_I_UWORD(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_M_SLONGS(SLONG *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_M_SLONG(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_M_ULONGS(ULONG *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_M_ULONG(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_I_SLONGS(SLONG *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_I_SLONG(reader);
+       return !reader->Eof(reader);
+}
+
+BOOL _mm_read_I_ULONGS(ULONG *buffer,int cnt,MREADER* reader)
+{
+       while(cnt-- > 0) *(buffer++)=_mm_read_I_ULONG(reader);
+       return !reader->Eof(reader);
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/mdreg.c b/libs/mikmod/playercode/mdreg.c
new file mode 100644 (file)
index 0000000..88bb673
--- /dev/null
@@ -0,0 +1,162 @@
+/*     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.
+*/
+
+/*==============================================================================
+
+  Routine for registering all drivers in libmikmod for the current platform.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+static void _mm_registeralldrivers(void)
+{
+       /* Register network drivers */
+#ifdef DRV_AF
+       _mm_registerdriver(&drv_AF);
+#endif
+#ifdef DRV_PULSEAUDIO
+       _mm_registerdriver(&drv_pulseaudio);
+#endif
+#ifdef DRV_ESD
+       _mm_registerdriver(&drv_esd);
+#endif
+#ifdef DRV_NAS
+       _mm_registerdriver(&drv_nas);
+#endif
+
+       /* Register hardware drivers - hardware mixing */
+#ifdef DRV_ULTRA
+       _mm_registerdriver(&drv_ultra);
+#endif
+#ifdef DRV_SAM9407
+       _mm_registerdriver(&drv_sam9407);
+#endif
+
+       /* Register multi-platform drivers -- software mixing */
+#ifdef DRV_SDL
+       _mm_registerdriver(&drv_sdl);
+#endif
+#ifdef DRV_OPENAL
+       _mm_registerdriver(&drv_openal);
+#endif
+
+       /* Register OS-specific hardware drivers - software mixing */
+#ifdef DRV_AHI
+       _mm_registerdriver(&drv_ahi);
+#endif
+#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_SNDIO
+       _mm_registerdriver(&drv_sndio);
+#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_XAUDIO2
+       _mm_registerdriver(&drv_xaudio2);
+#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
+#ifdef DRV_DC
+       _mm_registerdriver(&drv_dc);
+#endif
+#ifdef DRV_GP32
+       _mm_registerdriver(&drv_gp32);
+#endif
+#ifdef DRV_PSP
+       _mm_registerdriver(&drv_psp);
+#endif
+#ifdef DRV_OSLES
+       _mm_registerdriver(&drv_osles);
+#endif
+
+       /* dos drivers - wss first, since some cards emulate sb */
+#ifdef DRV_WSS
+       _mm_registerdriver(&drv_wss);
+#endif
+#ifdef DRV_SB
+       _mm_registerdriver(&drv_sb);
+#endif
+
+       /* Register disk writers */
+#ifdef DRV_WAV
+       _mm_registerdriver(&drv_wav);
+#endif
+#ifdef DRV_AIFF
+       _mm_registerdriver(&drv_aiff);
+#endif
+#ifdef DRV_RAW
+       _mm_registerdriver(&drv_raw);
+#endif
+
+       /* Register other drivers */
+#ifdef DRV_PIPE
+       _mm_registerdriver(&drv_pipe);
+#endif
+#if defined(DRV_STDOUT) && !defined(macintosh)
+       _mm_registerdriver(&drv_stdout);
+#endif
+
+       /* Register 'nosound' driver */
+       _mm_registerdriver(&drv_nos);
+}
+
+MIKMODAPI void MikMod_RegisterAllDrivers(void)
+{
+       MUTEX_LOCK(lists);
+       _mm_registeralldrivers();
+       MUTEX_UNLOCK(lists);
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/mdriver.c b/libs/mikmod/playercode/mdriver.c
new file mode 100644 (file)
index 0000000..b3d3d4a
--- /dev/null
@@ -0,0 +1,968 @@
+/*     MikMod sound library
+       (c) 1998-2014 Miodrag Vallat and others - see file AUTHORS
+       for a 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.
+*/
+
+/*==============================================================================
+
+  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
+
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+#if (MIKMOD_UNIX)
+#include <pwd.h>
+#include <sys/stat.h>
+#endif
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+extern MODULE *pf; /* modfile being played */
+
+/* EXPORTED GLOBALS */
+MIKMODAPI MDRIVER *md_driver   = NULL;
+
+/* 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 */
+
+/* INTERNAL GLOBALS */
+UWORD md_bpm = 125;    /* tempo */
+
+/* Do not modify the numchn variables yourself!  use MikMod_SetNumVoices() */
+UBYTE md_numchn  = 0, md_sngchn = 0, md_sfxchn = 0;
+UBYTE md_hardchn = 0, md_softchn= 0;
+
+void (*md_player)(void) = Player_HandleTick;
+
+MikMod_callback_t vc_callback = NULL;
+
+/* PRIVATE VARS */
+static MDRIVER *firstdriver = NULL;
+
+static volatile 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;
+       size_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=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
+               CHAR *list_end = list;
+               list[0] = 0;
+               /* list all registered device drivers : */
+               for(t = 1, l = firstdriver; l; l = l->next, t++) {
+                   list_end += sprintf(list_end, "%2d %s%s", t, l->Version, (l->next)? "\n" : "");
+               }
+       }
+       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) {
+                       if ( cruise == drv )
+                               return;
+                       while(cruise->next) {
+                               cruise = cruise->next;
+                               if ( cruise == drv )
+                                       return;
+                       }
+                       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(const CHAR *alias)
+{
+       int rank=1;
+       MDRIVER *cruise;
+
+       MUTEX_LOCK(lists);
+       cruise=firstdriver;
+       while(cruise) {
+               if (cruise->Alias) {
+                       if (!(_mm_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 NULL;
+
+       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;
+}
+
+MIKMODAPI void VC_SetCallback(MikMod_callback_t callback)
+{
+       vc_callback = callback;
+}
+
+static int _mm_init(const 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 int MikMod_Init(const CHAR *cmdline)
+{
+       int 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;
+
+       MikMod_free(sfxinfo);
+       MikMod_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 int _mm_reset(const 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) return md_driver->PlayStart();
+       return 0;
+}
+
+MIKMODAPI int MikMod_Reset(const CHAR *cmdline)
+{
+       int 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. */
+int 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;
+       }
+
+       MikMod_free(sfxinfo);
+       MikMod_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**)MikMod_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));
+       if(md_sfxchn)
+               sfxinfo = (UBYTE *)MikMod_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 int MikMod_SetNumVoices(int music, int sfx)
+{
+       int result;
+
+       MUTEX_LOCK(vars);
+       result=MikMod_SetNumVoices_internal(music,sfx);
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+int MikMod_EnableOutput_internal(void)
+{
+       _mm_critical = 1;
+       if(!isplaying) {
+               if(md_driver->PlayStart()) return 1;
+               isplaying = 1;
+       }
+       _mm_critical = 0;
+       return 0;
+}
+
+MIKMODAPI int MikMod_EnableOutput(void)
+{
+       int 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. */
+static 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 BOOL 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,TEXT("libmikmod(lists)"))))||
+                  (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,TEXT("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(const CHAR *atomname, const CHAR *cmdline, BOOL implicit)
+{
+       CHAR *ret=NULL;
+
+       if(cmdline) {
+               const CHAR *buf=strstr(cmdline,atomname);
+
+               if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {
+                       const CHAR *ptr=buf+strlen(atomname);
+
+                       if(*ptr=='=') {
+                               for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);
+                               ret=(CHAR *)MikMod_malloc((1+ptr-buf)*sizeof(CHAR));
+                               if(ret)
+                                       strncpy(ret,buf,ptr-buf);
+                       } else if((*ptr==',')||(!*ptr)) {
+                               if(implicit) {
+                                       ret=(CHAR *)MikMod_malloc((1+ptr-buf)*sizeof(CHAR));
+                                       if(ret)
+                                               strncpy(ret,buf,ptr-buf);
+                               }
+                       }
+               }
+       }
+       return ret;
+}
+
+#if (MIKMOD_UNIX)
+
+/*========== 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(const 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 */
+int 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=8: */
diff --git a/libs/mikmod/playercode/mdulaw.c b/libs/mikmod/playercode/mdulaw.c
new file mode 100644 (file)
index 0000000..7cee49b
--- /dev/null
@@ -0,0 +1,2119 @@
+/*     MikMod sound library
+       (c) 1998, 1999, 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$
+
+  Mu-law routines
+
+==============================================================================*/
+
+/*
+       The contents of this file 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:
+
+       ** 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "mikmod_internals.h"
+
+static const unsigned char ulaw_comp_table[16384] = {
+       0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb,
+       0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7,
+       0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3,
+       0xf3, 0xf2, 0xf2, 0xf1, 0xf1, 0xf0, 0xf0, 0xef,
+       0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed,
+       0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb,
+       0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xe9,
+       0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7,
+       0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5,
+       0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe3,
+       0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1,
+       0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf,
+       0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xde,
+       0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd,
+       0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc,
+       0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb,
+       0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda,
+       0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9,
+       0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8,
+       0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7,
+       0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6,
+       0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd5,
+       0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4,
+       0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3,
+       0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2,
+       0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1,
+       0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0,
+       0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf,
+       0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf,
+       0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce,
+       0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce,
+       0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd,
+       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+       0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcc,
+       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb,
+       0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb,
+       0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca,
+       0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca,
+       0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xc9,
+       0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9,
+       0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8,
+       0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8,
+       0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7,
+       0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7,
+       0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+       0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5,
+       0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5,
+       0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4,
+       0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4,
+       0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3,
+       0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3,
+       0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2,
+       0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+       0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1,
+       0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1,
+       0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0,
+       0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+       0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf,
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf,
+       0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe,
+       0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+       0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+       0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+       0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd,
+       0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+       0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+       0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd,
+       0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc,
+       0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+       0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+       0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc,
+       0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbb,
+       0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+       0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+       0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+       0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba,
+       0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+       0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+       0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+       0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9,
+       0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+       0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+       0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9,
+       0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8,
+       0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+       0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+       0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8,
+       0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7,
+       0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+       0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+       0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7,
+       0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6,
+       0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+       0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+       0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6,
+       0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb5,
+       0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+       0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+       0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5,
+       0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4,
+       0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+       0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+       0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
+       0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3,
+       0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+       0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+       0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3,
+       0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2,
+       0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+       0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+       0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2,
+       0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1,
+       0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+       0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+       0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1,
+       0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0,
+       0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+       0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+       0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0,
+       0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf,
+       0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae,
+       0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad,
+       0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+       0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
+       0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+       0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9,
+       0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8,
+       0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7,
+       0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
+       0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+       0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4,
+       0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+       0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2,
+       0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1,
+       0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0,
+       0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f,
+       0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+       0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d,
+       0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c,
+       0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
+       0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a,
+       0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+       0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+       0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+       0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+       0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+       0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+       0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+       0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+       0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e,
+       0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d,
+       0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c,
+       0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,
+       0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a,
+       0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+       0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+       0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+       0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+       0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+       0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+       0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+       0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+       0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+       0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+       0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+       0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+       0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+       0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+       0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+       0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+       0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
+       0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+       0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+       0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+       0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d,
+       0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e,
+       0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+       0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+       0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+       0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+       0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+       0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
+       0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
+       0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+       0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+       0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+       0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+       0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b,
+       0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+       0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
+       0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+       0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+       0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+       0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
+       0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+       0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,
+       0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
+       0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
+       0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,
+       0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27,
+       0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+       0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
+       0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+       0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+       0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
+       0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
+       0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
+       0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f,
+       0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+       0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+       0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+       0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+       0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+       0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+       0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+       0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
+       0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+       0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+       0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+       0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+       0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+       0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+       0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+       0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
+       0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+       0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+       0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+       0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,
+       0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
+       0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
+       0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
+       0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35,
+       0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+       0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
+       0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
+       0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
+       0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
+       0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+       0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+       0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+       0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
+       0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+       0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+       0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+       0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
+       0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
+       0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
+       0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
+       0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a,
+       0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+       0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+       0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+       0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
+       0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+       0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+       0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+       0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+       0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+       0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+       0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+       0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+       0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e,
+       0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
+       0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
+       0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
+       0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
+       0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+       0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+       0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+       0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+       0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+       0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+       0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
+       0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
+       0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+       0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+       0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
+       0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
+       0x45, 0x45, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
+       0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46,
+       0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47,
+       0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47,
+       0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+       0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+       0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+       0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,
+       0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+       0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a,
+       0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
+       0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
+       0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
+       0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
+       0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d,
+       0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d,
+       0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
+       0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
+       0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
+       0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
+       0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
+       0x50, 0x50, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
+       0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,
+       0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53,
+       0x53, 0x53, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
+       0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+       0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56,
+       0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+       0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
+       0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59,
+       0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
+       0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b,
+       0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+       0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d,
+       0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+       0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
+       0x5f, 0x5f, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61,
+       0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63,
+       0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65,
+       0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67,
+       0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69,
+       0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b,
+       0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d,
+       0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f,
+       0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72,
+       0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x76, 0x76,
+       0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a,
+       0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e
+};
+
+#define st_linear_to_ulaw(x) ulaw_comp_table[(x / 4) & 0x3fff]
+
+/* convert unsigned linear data from Mixer_WriteBytes() to ulaw */
+void unsignedtoulaw(char *buf, int nsamp)
+{
+       while (nsamp--) {
+               register long datum = (long)*((unsigned char *)buf);
+
+               datum ^= 128;                   /* convert to signed */
+               datum <<= 8;
+               /* round up to 12 bits of data */
+               datum += 0x8;                   /* + 0b1000 */
+               datum = st_linear_to_ulaw(datum);
+               *buf++ = (char)datum;
+       }
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/mloader.c b/libs/mikmod/playercode/mloader.c
new file mode 100644 (file)
index 0000000..684b8f2
--- /dev/null
@@ -0,0 +1,670 @@
+/*     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$
+
+  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;
+
+static MUNPACKER unpackers[] = {
+       PP20_Unpack,
+       MMCMP_Unpack,
+       XPK_Unpack,
+       S404_Unpack,
+       NULL
+};
+
+const 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=(CHAR*)MikMod_malloc(len*sizeof(CHAR))) != NULL) {
+               CHAR *list_end = list;
+               list[0] = 0;
+               /* list all registered module loders */
+               for(l = firstloader; l; l = l->next) {
+                   list_end += sprintf(list_end, "%s%s", l->version, (l->next) ? "\n" : "");
+               }
+       }
+       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*)MikMod_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]) {
+               MikMod_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*)MikMod_malloc(len+1))) return 0;
+               if(!(storage=(CHAR*)MikMod_malloc(linelen+1))) {
+                       MikMod_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*)MikMod_malloc(total+1))) {
+                               MikMod_free(storage);
+                               MikMod_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");
+                       }
+                       MikMod_free(storage);
+                       MikMod_free(tempcomment);
+               }
+       }
+       return 1;
+}
+
+BOOL AllocPositions(int total)
+{
+       if(!total) {
+               _mm_errno=MMERR_NOT_A_MODULE;
+               return 0;
+       }
+       if(!(of.positions=(UWORD*)MikMod_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*)MikMod_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
+       if(!(of.pattrows=(UWORD*)MikMod_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 **)MikMod_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*)MikMod_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*)MikMod_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(const 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*)MikMod_malloc(sizeof(CHAR)*(len+1))) != NULL) {
+               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);
+
+/* moved samplename freeing to our caller ML_FreeEx(),
+ * because we are called conditionally. */
+}
+
+static void ML_XFreeInstrument(INSTRUMENT *i)
+{
+       MikMod_free(i->insname);
+}
+
+static void ML_FreeEx(MODULE *mf)
+{
+       UWORD t;
+
+       MikMod_free(mf->songname);
+       MikMod_free(mf->comment);
+
+       MikMod_free(mf->modtype);
+       MikMod_free(mf->positions);
+       MikMod_free(mf->patterns);
+       MikMod_free(mf->pattrows);
+
+       if(mf->tracks) {
+               for(t=0;t<mf->numtrk;t++)
+                       MikMod_free(mf->tracks[t]);
+               MikMod_free(mf->tracks);
+       }
+       if(mf->instruments) {
+               for(t=0;t<mf->numins;t++)
+                       ML_XFreeInstrument(&mf->instruments[t]);
+               MikMod_free(mf->instruments);
+       }
+       if(mf->samples) {
+               for(t=0;t<mf->numsmp;t++) {
+                       MikMod_free(mf->samples[t].samplename);
+                       if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
+               }
+               MikMod_free(mf->samples);
+       }
+       memset(mf,0,sizeof(MODULE));
+       if(mf!=&of) MikMod_free(mf);
+}
+
+static MODULE *ML_AllocUniMod(void)
+{
+       return (MODULE *) MikMod_malloc(sizeof(MODULE));
+}
+
+static BOOL ML_TryUnpack(MREADER *reader,void **out,long *outlen)
+{
+       int i;
+
+       *out = NULL;
+       *outlen = 0;
+
+       for(i=0;unpackers[i]!=NULL;++i) {
+               _mm_rewind(reader);
+               if(unpackers[i](reader,out,outlen)) return 1;
+       }
+       return 0;
+}
+
+static 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;
+       CHAR *title;
+       void *unpk;
+       long newlen;
+
+       modreader=reader;
+       _mm_errno = 0;
+       _mm_critical = 0;
+       _mm_iobase_setcur(modreader);
+
+       if(ML_TryUnpack(modreader,&unpk,&newlen)) {
+               if(!(modreader=_mm_new_mem_reader(unpk,newlen))) {
+                       modreader=reader;
+                       MikMod_free(unpk);
+                       return NULL;
+               }
+       }
+
+       /* 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) {
+               title = l->LoadTitle();
+       }
+       else {
+               _mm_errno = MMERR_NOT_A_MODULE;
+               if(_mm_errorhandler) _mm_errorhandler();
+               title = NULL;
+       }
+
+       if (modreader!=reader) {
+               _mm_delete_mem_reader(modreader);
+               modreader=reader;
+               MikMod_free(unpk);
+       }
+       return title;
+}
+
+MIKMODAPI CHAR* Player_LoadTitleFP(FILE *fp)
+{
+       CHAR* result=NULL;
+       MREADER* reader;
+
+       if(fp && (reader=_mm_new_file_reader(fp)) != NULL) {
+               MUTEX_LOCK(lists);
+               result=Player_LoadTitle_internal(reader);
+               MUTEX_UNLOCK(lists);
+               _mm_delete_file_reader(reader);
+       }
+       return result;
+}
+
+MIKMODAPI CHAR* Player_LoadTitleMem(const char *buffer,int len)
+{
+       CHAR *result=NULL;
+       MREADER* reader;
+
+       if (!buffer || len <= 0) return NULL;
+       if ((reader=_mm_new_mem_reader(buffer,len)) != NULL)
+       {
+               MUTEX_LOCK(lists);
+               result=Player_LoadTitle_internal(reader);
+               MUTEX_UNLOCK(lists);
+               _mm_delete_mem_reader(reader);
+       }
+
+       return result;
+}
+
+MIKMODAPI CHAR* Player_LoadTitleGeneric(MREADER *reader)
+{
+       CHAR *result=NULL;
+
+       if (reader) {
+               MUTEX_LOCK(lists);
+               result=Player_LoadTitle_internal(reader);
+               MUTEX_UNLOCK(lists);
+       }
+       return result;
+}
+
+MIKMODAPI CHAR* Player_LoadTitle(const CHAR* filename)
+{
+       CHAR* result=NULL;
+       FILE* fp;
+       MREADER* reader;
+
+       if((fp=_mm_fopen(filename,"rb")) != NULL) {
+               if((reader=_mm_new_file_reader(fp)) != NULL) {
+                       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 */
+static MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,BOOL curious)
+{
+       int t;
+       MLOADER *l;
+       BOOL ok;
+       MODULE *mf;
+       void *unpk;
+       long newlen;
+
+       modreader = reader;
+       _mm_errno = 0;
+       _mm_critical = 0;
+       _mm_iobase_setcur(modreader);
+
+       if(ML_TryUnpack(modreader,&unpk,&newlen)) {
+               if(!(modreader=_mm_new_mem_reader(unpk,newlen))) {
+                       modreader=reader;
+                       MikMod_free(unpk);
+                       return NULL;
+               }
+       }
+
+       /* 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(modreader!=reader) {
+                       _mm_delete_mem_reader(modreader);
+                       modreader=reader;
+                       MikMod_free(unpk);
+               }
+               if(_mm_errorhandler) _mm_errorhandler();
+               _mm_rewind(modreader);
+               _mm_iobase_revert(modreader);
+               return NULL;
+       }
+
+       /* init unitrk routines */
+       if(!UniInit()) {
+               if(modreader!=reader) {
+                       _mm_delete_mem_reader(modreader);
+                       modreader=reader;
+                       MikMod_free(unpk);
+               }
+               if(_mm_errorhandler) _mm_errorhandler();
+               _mm_rewind(modreader);
+               _mm_iobase_revert(modreader);
+               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);
+               if (ok) {
+                       /* 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) ok = ML_LoadSamples();
+       if(ok) ok = ((mf=ML_AllocUniMod()) != NULL);
+       if(!ok) {
+               ML_FreeEx(&of);
+               if(modreader!=reader) {
+                       _mm_delete_mem_reader(modreader);
+                       modreader=reader;
+                       MikMod_free(unpk);
+               }
+               if(_mm_errorhandler) _mm_errorhandler();
+               _mm_rewind(modreader);
+               _mm_iobase_revert(modreader);
+               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;
+
+               ok = !MikMod_SetNumVoices_internal(maxchan,-1);
+       }
+
+       if(ok) ok = !SL_LoadSamples();
+       if(ok) ok = !Player_Init(mf);
+
+       if(modreader!=reader) {
+               _mm_delete_mem_reader(modreader);
+               modreader=reader;
+               MikMod_free(unpk);
+       }
+       _mm_iobase_revert(modreader);
+
+       if(!ok) {
+               Player_Free_internal(mf);
+               return NULL;
+       }
+       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;
+}
+
+MIKMODAPI MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,BOOL curious)
+{
+       MODULE* result=NULL;
+       MREADER* reader;
+
+       if (!buffer || len <= 0) return NULL;
+       if ((reader=_mm_new_mem_reader(buffer, len)) != NULL) {
+               result=Player_LoadGeneric(reader,maxchan,curious);
+               _mm_delete_mem_reader(reader);
+       }
+       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;
+
+       if (fp && (reader=_mm_new_file_reader(fp)) != NULL) {
+               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(const CHAR* filename,int maxchan,BOOL curious)
+{
+       FILE *fp;
+       MODULE *mf=NULL;
+
+       if((fp=_mm_fopen(filename,"rb")) != NULL) {
+               mf=Player_LoadFP(fp,maxchan,curious);
+               _mm_fclose(fp);
+       }
+       return mf;
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/mlreg.c b/libs/mikmod/playercode/mlreg.c
new file mode 100644 (file)
index 0000000..fd41e86
--- /dev/null
@@ -0,0 +1,67 @@
+/*     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$
+
+  Routine for registering all loaders in libmikmod for the current platform.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+static 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_gt2);*/ /* load_gt2 isn't complete */
+       _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_umx);
+       _mm_registerloader(&load_uni);
+       _mm_registerloader(&load_xm);
+
+       _mm_registerloader(&load_m15);
+}
+
+MIKMODAPI void MikMod_RegisterAllLoaders(void)
+{
+       MUTEX_LOCK(lists);
+       MikMod_RegisterAllLoaders_internal();
+       MUTEX_UNLOCK(lists);
+}
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/mlutil.c b/libs/mikmod/playercode/mlutil.c
new file mode 100644 (file)
index 0000000..21dcb20
--- /dev/null
@@ -0,0 +1,330 @@
+/*     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$
+
+  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 */
+
+const CHAR *STM_Signatures[STM_NTRACKERS] = {
+       "!Scream!",
+       "BMOD2STM",
+       "WUZAMOD!"
+};
+
+const 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 */
+UWORD  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 unsigned noteindexcount=0;
+
+int *AllocLinear(void)
+{
+       if(of.numsmp>noteindexcount) {
+               noteindexcount=of.numsmp;
+               noteindex=(int*)MikMod_realloc(noteindex,noteindexcount*sizeof(int));
+       }
+       return noteindex;
+}
+
+void FreeLinear(void)
+{
+       MikMod_free(noteindex);
+       noteindex=NULL;
+       noteindexcount=0;
+}
+
+int speed_to_finetune(ULONG speed,int sample)
+{
+    int ctmp=0,tmp,note=1,ft=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,--ft));
+        else {
+            note--;
+            while(ctmp<speed)
+                ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++ft));
+        }
+    }
+
+    noteindex[sample]=note-4*OCTAVE;
+    return ft;
+}
+
+/*========== 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 lo = inf&0xF;
+       /* 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: */
diff --git a/libs/mikmod/playercode/mplayer.c b/libs/mikmod/playercode/mplayer.c
new file mode 100644 (file)
index 0000000..e8c46ea
--- /dev/null
@@ -0,0 +1,3429 @@
+/*     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$
+
+  The Protracker Player Driver
+
+  The protracker driver supports all base Protracker 3.x commands and features.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#ifdef SRANDOM_IN_MATH_H
+#include <math.h>
+#else
+#include <stdlib.h>
+#endif
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+extern long int random(void);
+#endif
+
+/* The currently playing module */
+MODULE *pf = NULL;
+
+#define NUMVOICES(mod) (md_sngchn < (mod)->numvoices ? md_sngchn : (mod)->numvoices)
+
+#define        HIGH_OCTAVE             2       /* number of above-range octaves */
+
+static const UWORD oldperiods[OCTAVE*2]={
+       0x6b00, 0x6800, 0x6500, 0x6220, 0x5f50, 0x5c80,
+       0x5a00, 0x5740, 0x54d0, 0x5260, 0x5010, 0x4dc0,
+       0x4b90, 0x4960, 0x4750, 0x4540, 0x4350, 0x4160,
+       0x3f90, 0x3dc0, 0x3c10, 0x3a40, 0x38b0, 0x3700
+};
+
+static const UBYTE VibratoTable[32]={
+         0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253,
+       255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24
+};
+
+static const UBYTE avibtab[128]={
+        0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,
+       24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44,
+       45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58,
+       59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63,
+       64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59,
+       59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46,
+       45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25,
+       24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1
+};
+
+/* Triton's linear periods to frequency translation table (for XM modules) */
+static const ULONG lintab[768]={
+       535232,534749,534266,533784,533303,532822,532341,531861,
+       531381,530902,530423,529944,529466,528988,528511,528034,
+       527558,527082,526607,526131,525657,525183,524709,524236,
+       523763,523290,522818,522346,521875,521404,520934,520464,
+       519994,519525,519057,518588,518121,517653,517186,516720,
+       516253,515788,515322,514858,514393,513929,513465,513002,
+       512539,512077,511615,511154,510692,510232,509771,509312,
+       508852,508393,507934,507476,507018,506561,506104,505647,
+       505191,504735,504280,503825,503371,502917,502463,502010,
+       501557,501104,500652,500201,499749,499298,498848,498398,
+       497948,497499,497050,496602,496154,495706,495259,494812,
+       494366,493920,493474,493029,492585,492140,491696,491253,
+       490809,490367,489924,489482,489041,488600,488159,487718,
+       487278,486839,486400,485961,485522,485084,484647,484210,
+       483773,483336,482900,482465,482029,481595,481160,480726,
+       480292,479859,479426,478994,478562,478130,477699,477268,
+       476837,476407,475977,475548,475119,474690,474262,473834,
+       473407,472979,472553,472126,471701,471275,470850,470425,
+       470001,469577,469153,468730,468307,467884,467462,467041,
+       466619,466198,465778,465358,464938,464518,464099,463681,
+       463262,462844,462427,462010,461593,461177,460760,460345,
+       459930,459515,459100,458686,458272,457859,457446,457033,
+       456621,456209,455797,455386,454975,454565,454155,453745,
+       453336,452927,452518,452110,451702,451294,450887,450481,
+       450074,449668,449262,448857,448452,448048,447644,447240,
+       446836,446433,446030,445628,445226,444824,444423,444022,
+       443622,443221,442821,442422,442023,441624,441226,440828,
+       440430,440033,439636,439239,438843,438447,438051,437656,
+       437261,436867,436473,436079,435686,435293,434900,434508,
+       434116,433724,433333,432942,432551,432161,431771,431382,
+       430992,430604,430215,429827,429439,429052,428665,428278,
+       427892,427506,427120,426735,426350,425965,425581,425197,
+       424813,424430,424047,423665,423283,422901,422519,422138,
+       421757,421377,420997,420617,420237,419858,419479,419101,
+       418723,418345,417968,417591,417214,416838,416462,416086,
+       415711,415336,414961,414586,414212,413839,413465,413092,
+       412720,412347,411975,411604,411232,410862,410491,410121,
+       409751,409381,409012,408643,408274,407906,407538,407170,
+       406803,406436,406069,405703,405337,404971,404606,404241,
+       403876,403512,403148,402784,402421,402058,401695,401333,
+       400970,400609,400247,399886,399525,399165,398805,398445,
+       398086,397727,397368,397009,396651,396293,395936,395579,
+       395222,394865,394509,394153,393798,393442,393087,392733,
+       392378,392024,391671,391317,390964,390612,390259,389907,
+       389556,389204,388853,388502,388152,387802,387452,387102,
+       386753,386404,386056,385707,385359,385012,384664,384317,
+       383971,383624,383278,382932,382587,382242,381897,381552,
+       381208,380864,380521,380177,379834,379492,379149,378807,
+       378466,378124,377783,377442,377102,376762,376422,376082,
+       375743,375404,375065,374727,374389,374051,373714,373377,
+       373040,372703,372367,372031,371695,371360,371025,370690,
+       370356,370022,369688,369355,369021,368688,368356,368023,
+       367691,367360,367028,366697,366366,366036,365706,365376,
+       365046,364717,364388,364059,363731,363403,363075,362747,
+       362420,362093,361766,361440,361114,360788,360463,360137,
+       359813,359488,359164,358840,358516,358193,357869,357547,
+       357224,356902,356580,356258,355937,355616,355295,354974,
+       354654,354334,354014,353695,353376,353057,352739,352420,
+       352103,351785,351468,351150,350834,350517,350201,349885,
+       349569,349254,348939,348624,348310,347995,347682,347368,
+       347055,346741,346429,346116,345804,345492,345180,344869,
+       344558,344247,343936,343626,343316,343006,342697,342388,
+       342079,341770,341462,341154,340846,340539,340231,339924,
+       339618,339311,339005,338700,338394,338089,337784,337479,
+       337175,336870,336566,336263,335959,335656,335354,335051,
+       334749,334447,334145,333844,333542,333242,332941,332641,
+       332341,332041,331741,331442,331143,330844,330546,330247,
+       329950,329652,329355,329057,328761,328464,328168,327872,
+       327576,327280,326985,326690,326395,326101,325807,325513,
+       325219,324926,324633,324340,324047,323755,323463,323171,
+       322879,322588,322297,322006,321716,321426,321136,320846,
+       320557,320267,319978,319690,319401,319113,318825,318538,
+       318250,317963,317676,317390,317103,316817,316532,316246,
+       315961,315676,315391,315106,314822,314538,314254,313971,
+       313688,313405,313122,312839,312557,312275,311994,311712,
+       311431,311150,310869,310589,310309,310029,309749,309470,
+       309190,308911,308633,308354,308076,307798,307521,307243,
+       306966,306689,306412,306136,305860,305584,305308,305033,
+       304758,304483,304208,303934,303659,303385,303112,302838,
+       302565,302292,302019,301747,301475,301203,300931,300660,
+       300388,300117,299847,299576,299306,299036,298766,298497,
+       298227,297958,297689,297421,297153,296884,296617,296349,
+       296082,295815,295548,295281,295015,294749,294483,294217,
+       293952,293686,293421,293157,292892,292628,292364,292100,
+       291837,291574,291311,291048,290785,290523,290261,289999,
+       289737,289476,289215,288954,288693,288433,288173,287913,
+       287653,287393,287134,286875,286616,286358,286099,285841,
+       285583,285326,285068,284811,284554,284298,284041,283785,
+       283529,283273,283017,282762,282507,282252,281998,281743,
+       281489,281235,280981,280728,280475,280222,279969,279716,
+       279464,279212,278960,278708,278457,278206,277955,277704,
+       277453,277203,276953,276703,276453,276204,275955,275706,
+       275457,275209,274960,274712,274465,274217,273970,273722,
+       273476,273229,272982,272736,272490,272244,271999,271753,
+       271508,271263,271018,270774,270530,270286,270042,269798,
+       269555,269312,269069,268826,268583,268341,268099,267857
+};
+
+#define LOGFAC 2*16
+static const UWORD logtab[104]={
+       LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,
+       LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,
+       LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,
+       LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,
+       LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,
+       LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,
+       LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,
+       LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,
+       LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,
+       LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,
+       LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,
+       LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,
+       LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,
+       LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,
+       LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,
+       LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,
+       LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,
+       LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,
+       LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,
+       LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,
+       LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,
+       LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,
+       LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,
+       LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,
+       LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,
+       LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431
+};
+
+static const SBYTE PanbrelloTable[256]={
+         0,  2,  3,  5,  6,  8,  9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
+        24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
+        45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+        59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
+        64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
+        59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
+        45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
+        24, 23, 22, 20, 19, 17, 16, 14, 12, 11,  9,  8,  6,  5,  3,  2,
+         0,- 2,- 3,- 5,- 6,- 8,- 9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
+       -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44,
+       -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59,
+       -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64,
+       -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60,
+       -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,
+       -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,
+       -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,- 9,- 8,- 6,- 5,- 3,- 2
+};
+
+/* returns a random value between 0 and ceil-1, ceil must be a power of two */
+static int getrandom(int ceilval)
+{
+#if defined(HAVE_SRANDOM) && !defined(_MIKMOD_AMIGA)
+       return random()&(ceilval-1);
+#else
+       return (rand()*ceilval)/(RAND_MAX+1.0);
+#endif
+}
+
+/*     New Note Action Scoring System :
+       --------------------------------
+       1)      total-volume (fadevol, chanvol, volume) is the main scorer.
+       2)      a looping sample is a bonus x2
+       3)      a foreground channel is a bonus x4
+       4)      an active envelope with keyoff is a handicap -x2
+*/
+static int MP_FindEmptyChannel(MODULE *mod)
+{
+       MP_VOICE *a;
+       ULONG t,k,tvol,pp;
+
+       for (t=0;t<NUMVOICES(mod);t++)
+               if (((mod->voice[t].main.kick==KICK_ABSENT)||
+                        (mod->voice[t].main.kick==KICK_ENV))&&
+                  Voice_Stopped_internal(t))
+                       return t;
+
+       tvol=0xffffffUL;t=-1;a=mod->voice;
+       for (k=0;k<NUMVOICES(mod);k++,a++) {
+               /* allow us to take over a nonexisting sample */
+               if (!a->main.s)
+                       return k;
+
+               if ((a->main.kick==KICK_ABSENT)||(a->main.kick==KICK_ENV)) {
+                       pp=a->totalvol<<((a->main.s->flags&SF_LOOP)?1:0);
+                       if ((a->master)&&(a==a->master->slave))
+                               pp<<=2;
+
+                       if (pp<tvol) {
+                               tvol=pp;
+                               t=k;
+                       }
+               }
+       }
+
+       if (tvol>8000*7) return -1;
+       return t;
+}
+
+static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)
+{
+       if ((p1==p2)||(p==p1)) return v1;
+       return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1));
+}
+
+UWORD getlinearperiod(UWORD note,ULONG fine)
+{
+       UWORD t;
+
+       t=((20L+2*HIGH_OCTAVE)*OCTAVE+2-note)*32L-(fine>>1);
+       return t;
+}
+
+static UWORD getlogperiod(UWORD note,ULONG fine)
+{
+       UWORD n,o;
+       UWORD p1,p2;
+       ULONG i;
+
+       n=note%(2*OCTAVE);
+       o=note/(2*OCTAVE);
+       i=(n<<2)+(fine>>4); /* n*8 + fine/16 */
+
+       p1=logtab[i];
+       p2=logtab[i+1];
+
+       return (Interpolate(fine>>4,0,15,p1,p2)>>o);
+}
+
+static UWORD getoldperiod(UWORD note,ULONG speed)
+{
+       UWORD n,o;
+
+       /* This happens sometimes on badly converted AMF, and old MOD */
+       if (!speed) {
+#ifdef MIKMOD_DEBUG
+               fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note);
+#endif
+               return 4242; /* <- prevent divide overflow.. (42 hehe) */
+       }
+
+       n=note%(2*OCTAVE);
+       o=note/(2*OCTAVE);
+       return ((8363L*(ULONG)oldperiods[n])>>o)/speed;
+}
+
+static UWORD GetPeriod(UWORD flags, UWORD note, ULONG speed)
+{
+       if (flags & UF_XMPERIODS) {
+               if (flags & UF_LINEAR)
+                       return getlinearperiod(note, speed);
+               else
+                       return getlogperiod(note, speed);
+       } else
+               return getoldperiod(note, speed);
+}
+
+static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)
+{
+       return (Interpolate(p,a->pos,b->pos,a->val,b->val));
+}
+
+static SWORD DoPan(SWORD envpan,SWORD pan)
+{
+       int newpan;
+
+       newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128);
+
+       return (newpan<PAN_LEFT)?PAN_LEFT:(newpan>PAN_RIGHT?PAN_RIGHT:newpan);
+}
+
+static SWORD StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff)
+{
+       t->flg=flg;
+       t->pts=pts;
+       t->susbeg=susbeg;
+       t->susend=susend;
+       t->beg=beg;
+       t->end=end;
+       t->env=p;
+       t->p=0;
+       t->a=0;
+       t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1;
+
+       /* Imago Orpheus sometimes stores an extra initial point in the envelope */
+       if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) {
+               t->a++;
+               t->b++;
+       }
+
+       /* Fit in the envelope, still */
+       if (t->a >= t->pts)
+               t->a = t->pts - 1;
+       if (t->b >= t->pts)
+               t->b = t->pts-1;
+
+       return t->env[t->a].val;
+}
+
+/* This procedure processes all envelope types, include volume, pitch, and
+   panning.  Envelopes are defined by a set of points, each with a magnitude
+   [relating either to volume, panning position, or pitch modifier] and a tick
+   position.
+
+   Envelopes work in the following manner:
+
+   (a) Each tick the envelope is moved a point further in its progression. For
+       an accurate progression, magnitudes between two envelope points are
+       interpolated.
+
+   (b) When progression reaches a defined point on the envelope, values are
+       shifted to interpolate between this point and the next, and checks for
+       loops or envelope end are done.
+
+   Misc:
+     Sustain loops are loops that are only active as long as the keyoff flag is
+     clear.  When a volume envelope terminates, so does the current fadeout.
+*/
+static SWORD ProcessEnvelope(MP_VOICE *aout, ENVPR *t, SWORD v)
+{
+       if (t->flg & EF_ON) {
+               UBYTE a, b;             /* actual points in the envelope */
+               UWORD p;                /* the 'tick counter' - real point being played */
+
+               a = t->a;
+               b = t->b;
+               p = t->p;
+
+               /*
+                * Sustain loop on one point (XM type).
+                * Not processed if KEYOFF.
+                * Don't move and don't interpolate when the point is reached
+                */
+               if ((t->flg & EF_SUSTAIN) && t->susbeg == t->susend &&
+                  (!(aout->main.keyoff & KEY_OFF) && p == t->env[t->susbeg].pos)) {
+                       v = t->env[t->susbeg].val;
+               } else {
+                       /*
+                        * All following situations will require interpolation between
+                        * two envelope points.
+                        */
+
+                       /*
+                        * Sustain loop between two points (IT type).
+                        * Not processed if KEYOFF.
+                        */
+                       /* if we were on a loop point, loop now */
+                       if ((t->flg & EF_SUSTAIN) && !(aout->main.keyoff & KEY_OFF) &&
+                          a >= t->susend) {
+                               a = t->susbeg;
+                               b = (t->susbeg==t->susend)?a:a+1;
+                               p = t->env[a].pos;
+                               v = t->env[a].val;
+                       } else
+                       /*
+                        * Regular loop.
+                        * Be sure to correctly handle single point loops.
+                        */
+                       if ((t->flg & EF_LOOP) && a >= t->end) {
+                               a = t->beg;
+                               b = t->beg == t->end ? a : a + 1;
+                               p = t->env[a].pos;
+                               v = t->env[a].val;
+                       } else
+                       /*
+                        * Non looping situations.
+                        */
+                       if (a != b)
+                               v = InterpolateEnv(p, &t->env[a], &t->env[b]);
+                       else
+                               v = t->env[a].val;
+
+                       /*
+                        * Start to fade if the volume envelope is finished.
+                        */
+                       if (p >= t->env[t->pts - 1].pos) {
+                               if (t->flg & EF_VOLENV) {
+                                       aout->main.keyoff |= KEY_FADE;
+                                       if (!v)
+                                               aout->main.fadevol = 0;
+                               }
+                       } else {
+                               p++;
+                               /* did pointer reach point b? */
+                               if (p >= t->env[b].pos)
+                                       a = b++; /* shift points a and b */
+                       }
+                       t->a = a;
+                       t->b = b;
+                       t->p = p;
+               }
+       }
+       return v;
+}
+
+/* XM linear period to frequency conversion */
+ULONG getfrequency(UWORD flags,ULONG period)
+{
+       if (flags & UF_LINEAR) {
+               SLONG shift = ((SLONG)period / 768) - HIGH_OCTAVE;
+
+               if (shift >= 0)
+                       return lintab[period % 768] >> shift;
+               else
+                       return lintab[period % 768] << (-shift);
+       } else
+               return (8363L*1712L)/(period?period:1);
+}
+
+/*========== Protracker effects */
+
+static void DoArpeggio(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE style)
+{
+       UBYTE note=a->main.note;
+
+       if (a->arpmem) {
+               switch (style) {
+               case 0:         /* mod style: N, N+x, N+y */
+                       switch (tick % 3) {
+                       /* case 0: unchanged */
+                       case 1:
+                               note += (a->arpmem >> 4);
+                               break;
+                       case 2:
+                               note += (a->arpmem & 0xf);
+                               break;
+                       }
+                       break;
+               case 3:         /* okt arpeggio 3: N-x, N, N+y */
+                       switch (tick % 3) {
+                       case 0:
+                               note -= (a->arpmem >> 4);
+                               break;
+                       /* case 1: unchanged */
+                       case 2:
+                               note += (a->arpmem & 0xf);
+                               break;
+                       }
+                       break;
+               case 4:         /* okt arpeggio 4: N, N+y, N, N-x */
+                       switch (tick % 4) {
+                       /* case 0, case 2: unchanged */
+                       case 1:
+                               note += (a->arpmem & 0xf);
+                               break;
+                       case 3:
+                               note -= (a->arpmem >> 4);
+                               break;
+                       }
+                       break;
+               case 5:         /* okt arpeggio 5: N-x, N+y, N, and nothing at tick 0 */
+                       if (!tick)
+                               break;
+                       switch (tick % 3) {
+                       /* case 0: unchanged */
+                       case 1:
+                               note -= (a->arpmem >> 4);
+                               break;
+                       case 2:
+                               note += (a->arpmem & 0xf);
+                               break;
+                       }
+                       break;
+               }
+               a->main.period = GetPeriod(flags, (UWORD)note << 1, a->speed);
+               a->ownper = 1;
+       }
+}
+
+static int DoPTEffect0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat = UniGetByte();
+       if (!tick) {
+               if (!dat && (flags & UF_ARPMEM))
+                       dat=a->arpmem;
+               else
+                       a->arpmem=dat;
+       }
+       if (a->main.period)
+               DoArpeggio(tick, flags, a, 0);
+
+       return 0;
+}
+
+static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat = UniGetByte();
+       if (!tick && dat)
+               a->slidespeed = (UWORD)dat << 2;
+       if (a->main.period)
+               if (tick)
+                       a->tmpperiod -= a->slidespeed;
+
+       return 0;
+}
+
+static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat = UniGetByte();
+       if (!tick && dat)
+               a->slidespeed = (UWORD)dat << 2;
+       if (a->main.period)
+               if (tick)
+                       a->tmpperiod += a->slidespeed;
+
+       return 0;
+}
+
+static void DoToneSlide(UWORD tick, MP_CONTROL *a)
+{
+       if (!a->main.fadevol)
+               a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF;
+       else
+               a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT;
+
+       if (tick != 0) {
+               int dist;
+
+               /* We have to slide a->main.period towards a->wantedperiod, so compute
+                  the difference between those two values */
+               dist=a->main.period-a->wantedperiod;
+
+               /* if they are equal or if portamentospeed is too big ...*/
+               if (dist == 0 || a->portspeed > abs(dist))
+                       /* ...make tmpperiod equal tperiod */
+                       a->tmpperiod=a->main.period=a->wantedperiod;
+               else if (dist>0) {
+                       a->tmpperiod-=a->portspeed;
+                       a->main.period-=a->portspeed; /* dist>0, slide up */
+               } else {
+                       a->tmpperiod+=a->portspeed;
+                       a->main.period+=a->portspeed; /* dist<0, slide down */
+               }
+       } else
+               a->tmpperiod=a->main.period;
+       a->ownper = 1;
+}
+
+static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2;
+       if (a->main.period)
+               DoToneSlide(tick, a);
+
+       return 0;
+}
+
+static void DoVibrato(UWORD tick, MP_CONTROL *a)
+{
+       UBYTE q;
+       UWORD temp = 0; /* silence warning */
+
+       if (!tick)
+               return;
+
+       q=(a->vibpos>>2)&0x1f;
+
+       switch (a->wavecontrol&3) {
+       case 0: /* sine */
+               temp=VibratoTable[q];
+               break;
+       case 1: /* ramp down */
+               q<<=3;
+               if (a->vibpos<0) q=255-q;
+               temp=q;
+               break;
+       case 2: /* square wave */
+               temp=255;
+               break;
+       case 3: /* random wave */
+               temp=getrandom(256);
+               break;
+       }
+
+       temp*=a->vibdepth;
+       temp>>=7;temp<<=2;
+
+       if (a->vibpos>=0)
+               a->main.period=a->tmpperiod+temp;
+       else
+               a->main.period=a->tmpperiod-temp;
+       a->ownper = 1;
+
+       if (tick != 0)
+               a->vibpos+=a->vibspd;
+}
+
+static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (!tick) {
+               if (dat&0x0f) a->vibdepth=dat&0xf;
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+       }
+       if (a->main.period)
+               DoVibrato(tick, a);
+
+       return 0;
+}
+
+static void DoVolSlide(MP_CONTROL *a, UBYTE dat)
+{
+       if (dat&0xf) {
+               a->tmpvolume-=(dat&0x0f);
+               if (a->tmpvolume<0)
+                       a->tmpvolume=0;
+       } else {
+               a->tmpvolume+=(dat>>4);
+               if (a->tmpvolume>64)
+                       a->tmpvolume=64;
+       }
+}
+
+static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (a->main.period)
+               DoToneSlide(tick, a);
+
+       if (tick)
+               DoVolSlide(a, dat);
+
+       return 0;
+}
+
+/* DoPTEffect6 after DoPTEffectA */
+
+static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+       UBYTE q;
+       UWORD temp = 0; /* silence warning */
+
+       dat=UniGetByte();
+       if (!tick) {
+               if (dat&0x0f) a->trmdepth=dat&0xf;
+               if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
+       }
+       if (a->main.period) {
+               q=(a->trmpos>>2)&0x1f;
+
+               switch ((a->wavecontrol>>4)&3) {
+               case 0: /* sine */
+                       temp=VibratoTable[q];
+                       break;
+               case 1: /* ramp down */
+                       q<<=3;
+                       if (a->trmpos<0) q=255-q;
+                       temp=q;
+                       break;
+               case 2: /* square wave */
+                       temp=255;
+                       break;
+               case 3: /* random wave */
+                       temp=getrandom(256);
+                       break;
+               }
+               temp*=a->trmdepth;
+               temp>>=6;
+
+               if (a->trmpos>=0) {
+                       a->volume=a->tmpvolume+temp;
+                       if (a->volume>64) a->volume=64;
+               } else {
+                       a->volume=a->tmpvolume-temp;
+                       if (a->volume<0) a->volume=0;
+               }
+               a->ownvol = 1;
+
+               if (tick)
+                       a->trmpos+=a->trmspd;
+       }
+
+       return 0;
+}
+
+static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat = UniGetByte();
+       if (mod->panflag)
+               a->main.panning = mod->panning[channel] = dat;
+
+       return 0;
+}
+
+static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (!tick) {
+               if (dat) a->soffset=(UWORD)dat<<8;
+               a->main.start=a->hioffset|a->soffset;
+
+               if ((a->main.s)&&(a->main.start>a->main.s->length))
+                       a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
+                           a->main.s->loopstart:a->main.s->length;
+       }
+
+       return 0;
+}
+
+static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (tick)
+               DoVolSlide(a, dat);
+
+       return 0;
+}
+
+static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       if (a->main.period)
+               DoVibrato(tick, a);
+       DoPTEffectA(tick, flags, a, mod, channel);
+
+       return 0;
+}
+
+static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+
+       if (tick || mod->patdly2)
+               return 0;
+
+       /* Vincent Voois uses a nasty trick in "Universal Bolero" */
+       if (dat == mod->sngpos && mod->patbrk == mod->patpos)
+               return 0;
+
+       if (!mod->loop && !mod->patbrk &&
+           (dat < mod->sngpos ||
+                (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) ||
+            (dat == mod->sngpos && (flags & UF_NOWRAP)) ) )
+       {
+               /* if we don't loop, better not to skip the end of the
+                  pattern, after all... so:
+               mod->patbrk=0; */
+               mod->posjmp=3;
+       } else {
+               /* if we were fading, adjust... */
+               if (mod->sngpos == (mod->numpos-1))
+                       mod->volume=mod->initvolume>128?128:mod->initvolume;
+               mod->sngpos=dat;
+               mod->posjmp=2;
+               mod->patpos=0;
+               /* cancel the FT2 pattern loop (E60) bug.
+                * also see DoEEffects() below for it. */
+               if (flags & UF_FT2QUIRKS) mod->patbrk=0;
+       }
+
+       return 0;
+}
+
+static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (tick) return 0;
+       if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */
+       else if (dat>64) dat=64;
+       a->tmpvolume=dat;
+
+       return 0;
+}
+
+static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if ((tick)||(mod->patdly2)) return 0;
+       if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&&
+           (dat>mod->pattrows[mod->positions[mod->sngpos]])) {
+               dat=mod->pattrows[mod->positions[mod->sngpos]];
+       }
+       mod->patbrk=dat;
+       if (!mod->posjmp) {
+               /* don't ask me to explain this code - it makes
+                  backwards.s3m and children.xm (heretic's version) play
+                  correctly, among others. Take that for granted, or write
+                  the page of comments yourself... you might need some
+                  aspirin - Miod */
+               if ((mod->sngpos==mod->numpos-1)&&(dat)&&
+                   ((mod->loop) || (mod->positions[mod->sngpos]==(mod->numpat-1) && !(flags&UF_NOWRAP)))) {
+                       mod->sngpos=0;
+                       mod->posjmp=2;
+               } else
+                       mod->posjmp=3;
+       }
+
+       return 0;
+}
+
+static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod,
+       SWORD channel, UBYTE dat)
+{
+       UBYTE nib = dat & 0xf;
+
+       switch (dat>>4) {
+       case 0x0: /* hardware filter toggle, not supported */
+               break;
+       case 0x1: /* fineslide up */
+               if (a->main.period)
+                       if (!tick)
+                               a->tmpperiod-=(nib<<2);
+               break;
+       case 0x2: /* fineslide dn */
+               if (a->main.period)
+                       if (!tick)
+                               a->tmpperiod+=(nib<<2);
+               break;
+       case 0x3: /* glissando ctrl */
+               a->glissando=nib;
+               break;
+       case 0x4: /* set vibrato waveform */
+               a->wavecontrol&=0xf0;
+               a->wavecontrol|=nib;
+               break;
+       case 0x5: /* set finetune */
+               if (a->main.period) {
+                       if (flags&UF_XMPERIODS)
+                               a->speed=nib+128;
+                       else
+                               a->speed=finetune[nib];
+                       a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed);
+               }
+               break;
+       case 0x6: /* set patternloop */
+               if (tick)
+                       break;
+               if (nib) { /* set reppos or repcnt ? */
+                       /* set repcnt, so check if repcnt already is set, which means we
+                          are already looping */
+                       if (a->pat_repcnt)
+                               a->pat_repcnt--; /* already looping, decrease counter */
+                       else {
+#if 0
+                               /* this would make walker.xm, shipped with Xsoundtracker,
+                                  play correctly, but it's better to remain compatible
+                                  with FT2 */
+                               if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE))
+#endif
+                                       a->pat_repcnt=nib; /* not yet looping, so set repcnt */
+                       }
+
+                       if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */
+                               if (a->pat_reppos==POS_NONE)
+                                       a->pat_reppos=mod->patpos-1;
+                               if (a->pat_reppos==-1) {
+                                       mod->pat_repcrazy=1;
+                                       mod->patpos=0;
+                               } else
+                                       mod->patpos=a->pat_reppos;
+                       } else a->pat_reppos=POS_NONE;
+               } else {
+                       a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */
+                       /* emulate the FT2 pattern loop (E60) bug:
+                        * http://milkytracker.org/docs/MilkyTracker.html#fxE6x
+                        * roadblas.xm plays correctly with this. */
+                       if (flags & UF_FT2QUIRKS) mod->patbrk=mod->patpos;
+               }
+               break;
+       case 0x7: /* set tremolo waveform */
+               a->wavecontrol&=0x0f;
+               a->wavecontrol|=nib<<4;
+               break;
+       case 0x8: /* set panning */
+               if (mod->panflag) {
+                       if (nib<=8) nib<<=4;
+                       else nib*=17;
+                       a->main.panning=mod->panning[channel]=nib;
+               }
+               break;
+       case 0x9: /* retrig note */
+               /* do not retrigger on tick 0, until we are emulating FT2 and effect
+                  data is zero */
+               if (!tick && !((flags & UF_FT2QUIRKS) && (!nib)))
+                       break;
+               /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */
+               if (nib || !tick) {
+                       if (!a->retrig) {
+                               /* when retrig counter reaches 0, reset counter and restart
+                                  the sample */
+                               if (a->main.period) a->main.kick=KICK_NOTE;
+                               a->retrig=nib;
+                       }
+                       a->retrig--; /* countdown */
+               }
+               break;
+       case 0xa: /* fine volume slide up */
+               if (tick)
+                       break;
+               a->tmpvolume+=nib;
+               if (a->tmpvolume>64) a->tmpvolume=64;
+               break;
+       case 0xb: /* fine volume slide dn  */
+               if (tick)
+                       break;
+               a->tmpvolume-=nib;
+               if (a->tmpvolume<0)a->tmpvolume=0;
+               break;
+       case 0xc: /* cut note */
+               /* When tick reaches the cut-note value, turn the volume to
+                  zero (just like on the amiga) */
+               if (tick>=nib)
+                       a->tmpvolume=0; /* just turn the volume down */
+               break;
+       case 0xd: /* note delay */
+               /* delay the start of the sample until tick==nib */
+               if (!tick)
+                       a->main.notedelay=nib;
+               else if (a->main.notedelay)
+                       a->main.notedelay--;
+               break;
+       case 0xe: /* pattern delay */
+               if (!tick)
+                       if (!mod->patdly2)
+                               mod->patdly=nib+1; /* only once, when tick=0 */
+               break;
+       case 0xf: /* invert loop, not supported  */
+               break;
+       }
+}
+
+static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoEEffects(tick, flags, a, mod, channel, UniGetByte());
+
+       return 0;
+}
+
+static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (tick||mod->patdly2) return 0;
+       if (mod->extspd&&(dat>=mod->bpmlimit))
+               mod->bpm=dat;
+       else
+         if (dat) {
+               mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat;
+               mod->vbtick=0;
+       }
+
+       return 0;
+}
+
+/*========== Scream Tracker effects */
+
+static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE speed;
+
+       speed = UniGetByte();
+
+       if (tick || mod->patdly2)
+               return 0;
+
+       if (speed > 128)
+               speed -= 128;
+       if (speed) {
+               mod->sngspd = speed;
+               mod->vbtick = 0;
+       }
+
+       return 0;
+}
+
+static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf)
+{
+       UBYTE lo, hi;
+
+       if (inf)
+               a->s3mvolslide=inf;
+       else
+               inf=a->s3mvolslide;
+
+       lo=inf&0xf;
+       hi=inf>>4;
+
+       if (!lo) {
+               if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi;
+       } else
+         if (!hi) {
+               if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo;
+       } else
+         if (lo==0xf) {
+               if (!tick) a->tmpvolume+=(hi?hi:0xf);
+       } else
+         if (hi==0xf) {
+               if (!tick) a->tmpvolume-=(lo?lo:0xf);
+       } else
+         return;
+
+       if (a->tmpvolume<0)
+               a->tmpvolume=0;
+       else if (a->tmpvolume>64)
+               a->tmpvolume=64;
+}
+
+static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoS3MVolSlide(tick, flags, a, UniGetByte());
+
+       return 1;
+}
+
+static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf)
+{
+       UBYTE hi,lo;
+
+       if (inf)
+               a->slidespeed=inf;
+       else
+               inf=a->slidespeed;
+
+       hi=inf>>4;
+       lo=inf&0xf;
+
+       if (hi==0xf) {
+               if (!tick) a->tmpperiod+=(UWORD)lo<<2;
+       } else
+         if (hi==0xe) {
+               if (!tick) a->tmpperiod+=lo;
+       } else {
+               if (tick) a->tmpperiod+=(UWORD)inf<<2;
+       }
+}
+
+static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (a->main.period)
+               DoS3MSlideDn(tick, a,dat);
+
+       return 0;
+}
+
+static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf)
+{
+       UBYTE hi,lo;
+
+       if (inf) a->slidespeed=inf;
+       else inf=a->slidespeed;
+
+       hi=inf>>4;
+       lo=inf&0xf;
+
+       if (hi==0xf) {
+               if (!tick) a->tmpperiod-=(UWORD)lo<<2;
+       } else
+         if (hi==0xe) {
+               if (!tick) a->tmpperiod-=lo;
+       } else {
+               if (tick) a->tmpperiod-=(UWORD)inf<<2;
+       }
+}
+
+static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (a->main.period)
+               DoS3MSlideUp(tick, a,dat);
+
+       return 0;
+}
+
+static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, on, off;
+
+       inf = UniGetByte();
+       if (inf)
+               a->s3mtronof = inf;
+       else {
+               inf = a->s3mtronof;
+               if (!inf)
+                       return 0;
+       }
+
+       if (!tick)
+               return 0;
+
+       on=(inf>>4)+1;
+       off=(inf&0xf)+1;
+       a->s3mtremor%=(on+off);
+       a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
+       a->ownvol=1;
+       a->s3mtremor++;
+
+       return 0;
+}
+
+static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf;
+
+       inf = UniGetByte();
+       if (a->main.period) {
+               if (inf) {
+                       a->s3mrtgslide=inf>>4;
+                       a->s3mrtgspeed=inf&0xf;
+               }
+
+               /* only retrigger if low nibble > 0 */
+               if (a->s3mrtgspeed>0) {
+                       if (!a->retrig) {
+                               /* when retrig counter reaches 0, reset counter and restart the
+                                  sample */
+                               if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF;
+                               a->retrig=a->s3mrtgspeed;
+
+                               if ((tick)||(flags&UF_S3MSLIDES)) {
+                                       switch (a->s3mrtgslide) {
+                                       case 1:
+                                       case 2:
+                                       case 3:
+                                       case 4:
+                                       case 5:
+                                               a->tmpvolume-=(1<<(a->s3mrtgslide-1));
+                                               break;
+                                       case 6:
+                                               a->tmpvolume=(2*a->tmpvolume)/3;
+                                               break;
+                                       case 7:
+                                               a->tmpvolume>>=1;
+                                               break;
+                                       case 9:
+                                       case 0xa:
+                                       case 0xb:
+                                       case 0xc:
+                                       case 0xd:
+                                               a->tmpvolume+=(1<<(a->s3mrtgslide-9));
+                                               break;
+                                       case 0xe:
+                                               a->tmpvolume=(3*a->tmpvolume)>>1;
+                                               break;
+                                       case 0xf:
+                                               a->tmpvolume=a->tmpvolume<<1;
+                                               break;
+                                       }
+                                       if (a->tmpvolume<0)
+                                               a->tmpvolume=0;
+                                       else if (a->tmpvolume>64)
+                                               a->tmpvolume=64;
+                               }
+                       }
+                       a->retrig--; /* countdown  */
+               }
+       }
+
+       return 0;
+}
+
+static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat, q;
+       UWORD temp=0;   /* silence warning */
+
+       dat = UniGetByte();
+       if (!tick) {
+               if (dat&0x0f) a->trmdepth=dat&0xf;
+               if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
+       }
+
+       q=(a->trmpos>>2)&0x1f;
+
+       switch ((a->wavecontrol>>4)&3) {
+       case 0: /* sine */
+               temp=VibratoTable[q];
+               break;
+       case 1: /* ramp down */
+               q<<=3;
+               if (a->trmpos<0) q=255-q;
+               temp=q;
+               break;
+       case 2: /* square wave */
+               temp=255;
+               break;
+       case 3: /* random */
+               temp=getrandom(256);
+               break;
+       }
+
+       temp*=a->trmdepth;
+       temp>>=7;
+
+       if (a->trmpos>=0) {
+               a->volume=a->tmpvolume+temp;
+               if (a->volume>64) a->volume=64;
+       } else {
+               a->volume=a->tmpvolume-temp;
+               if (a->volume<0) a->volume=0;
+       }
+       a->ownvol = 1;
+
+       if (tick)
+               a->trmpos+=a->trmspd;
+
+       return 0;
+}
+
+static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE tempo;
+
+       tempo = UniGetByte();
+
+       if (tick || mod->patdly2)
+               return 0;
+
+       mod->bpm = (tempo < 32) ? 32 : tempo;
+
+       return 0;
+}
+
+static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat, q;
+       UWORD temp = 0; /* silence warning */
+
+       dat = UniGetByte();
+       if (!tick) {
+               if (dat&0x0f) a->vibdepth=dat&0xf;
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+       } else
+               if (a->main.period) {
+                       q=(a->vibpos>>2)&0x1f;
+
+                       switch (a->wavecontrol&3) {
+                       case 0: /* sine */
+                               temp=VibratoTable[q];
+                               break;
+                       case 1: /* ramp down */
+                               q<<=3;
+                               if (a->vibpos<0) q=255-q;
+                               temp=q;
+                               break;
+                       case 2: /* square wave */
+                               temp=255;
+                               break;
+                       case 3: /* random */
+                               temp=getrandom(256);
+                               break;
+                       }
+
+                       temp*=a->vibdepth;
+                       temp>>=8;
+
+                       if (a->vibpos>=0)
+                               a->main.period=a->tmpperiod+temp;
+                       else
+                               a->main.period=a->tmpperiod-temp;
+                       a->ownper = 1;
+
+                       a->vibpos+=a->vibspd;
+       }
+
+       return 0;
+}
+
+/*========== Envelope helpers */
+
+static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       a->main.keyoff|=KEY_OFF;
+       if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP))
+               a->main.keyoff=KEY_KILL;
+
+       return 0;
+}
+
+static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if ((tick>=dat)||(tick==mod->sngspd-1)) {
+               a->main.keyoff=KEY_KILL;
+               if (!(a->main.volflg&EF_ON))
+                       a->main.fadevol=0;
+       }
+
+       return 0;
+}
+
+/*========== Fast Tracker effects */
+
+/* DoXMEffect6 after DoXMEffectA */
+
+static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, lo, hi;
+
+       inf = UniGetByte();
+       if (inf)
+               a->s3mvolslide = inf;
+       else
+               inf = a->s3mvolslide;
+
+       if (tick) {
+               lo=inf&0xf;
+               hi=inf>>4;
+
+               if (!hi) {
+                       a->tmpvolume-=lo;
+                       if (a->tmpvolume<0) a->tmpvolume=0;
+               } else {
+                       a->tmpvolume+=hi;
+                       if (a->tmpvolume>64) a->tmpvolume=64;
+               }
+       }
+
+       return 0;
+}
+
+static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       if (a->main.period)
+               DoVibrato(tick, a);
+
+       return DoXMEffectA(tick, flags, a, mod, channel);
+}
+
+static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (!tick) {
+               if (dat) a->fportupspd=dat;
+               if (a->main.period)
+                       a->tmpperiod-=(a->fportupspd<<2);
+       }
+
+       return 0;
+}
+
+static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (!tick) {
+               if (dat) a->fportdnspd=dat;
+               if (a->main.period)
+                       a->tmpperiod+=(a->fportdnspd<<2);
+       }
+
+       return 0;
+}
+
+static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (!tick)
+               if (dat) a->fslideupspd=dat;
+       a->tmpvolume+=a->fslideupspd;
+       if (a->tmpvolume>64) a->tmpvolume=64;
+
+       return 0;
+}
+
+static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if (!tick)
+               if (dat) a->fslidednspd=dat;
+       a->tmpvolume-=a->fslidednspd;
+       if (a->tmpvolume<0) a->tmpvolume=0;
+
+       return 0;
+}
+
+static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       mod->volume=UniGetByte()<<1;
+       if (mod->volume>128) mod->volume=128;
+
+       return 0;
+}
+
+static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf;
+
+       inf = UniGetByte();
+
+       if (tick) {
+               if (inf) mod->globalslide=inf;
+               else inf=mod->globalslide;
+               if (inf & 0xf0) inf&=0xf0;
+               mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2;
+
+               if (mod->volume<0)
+                       mod->volume=0;
+               else if (mod->volume>128)
+                       mod->volume=128;
+       }
+
+       return 0;
+}
+
+static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat=UniGetByte();
+       if ((!tick)&&(a->main.i)) {
+               UWORD points;
+               INSTRUMENT *i=a->main.i;
+               MP_VOICE *aout;
+
+               if ((aout=a->slave) != NULL) {
+                       if (aout->venv.env) {
+                               points=i->volenv[i->volpts-1].pos;
+                               aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos;
+                       }
+                       if (aout->penv.env) {
+                               points=i->panenv[i->panpts-1].pos;
+                               aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, lo, hi;
+       SWORD pan;
+
+       inf = UniGetByte();
+       if (!mod->panflag)
+               return 0;
+
+       if (inf)
+               a->pansspd = inf;
+       else
+               inf =a->pansspd;
+
+       if (tick) {
+               lo=inf&0xf;
+               hi=inf>>4;
+
+               /* slide right has absolute priority */
+               if (hi)
+                       lo = 0;
+
+               pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo;
+               a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
+       }
+
+       return 0;
+}
+
+static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat = UniGetByte();
+       if (dat)
+               a->ffportupspd = dat;
+       else
+               dat = a->ffportupspd;
+
+       if (a->main.period)
+               if (!tick) {
+                       a->main.period-=dat;
+                       a->tmpperiod-=dat;
+                       a->ownper = 1;
+               }
+
+       return 0;
+}
+
+static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat;
+
+       dat = UniGetByte();
+       if (dat)
+               a->ffportdnspd=dat;
+       else
+               dat = a->ffportdnspd;
+
+       if (a->main.period)
+               if (!tick) {
+                       a->main.period+=dat;
+                       a->tmpperiod+=dat;
+                       a->ownper = 1;
+               }
+
+       return 0;
+}
+
+/*========== Impulse Tracker effects */
+
+static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat)
+{
+       if (dat)
+               a->portspeed = dat;
+
+       /* if we don't come from another note, ignore the slide and play the note
+          as is */
+       if (!a->oldnote || !a->main.period)
+               return;
+
+       if ((!tick)&&(a->newsamp)){
+               a->main.kick=KICK_NOTE;
+               a->main.start=-1;
+       } else
+               a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT;
+
+       if (tick) {
+               int dist;
+
+               /* We have to slide a->main.period towards a->wantedperiod, compute the
+                  difference between those two values */
+               dist=a->main.period-a->wantedperiod;
+
+               /* if they are equal or if portamentospeed is too big... */
+               if ((!dist)||((a->portspeed<<2)>abs(dist)))
+                       /* ... make tmpperiod equal tperiod */
+                       a->tmpperiod=a->main.period=a->wantedperiod;
+               else
+                 if (dist>0) {
+                       a->tmpperiod-=a->portspeed<<2;
+                       a->main.period-=a->portspeed<<2; /* dist>0 slide up */
+               } else {
+                       a->tmpperiod+=a->portspeed<<2;
+                       a->main.period+=a->portspeed<<2; /* dist<0 slide down */
+               }
+       } else
+               a->tmpperiod=a->main.period;
+       a->ownper=1;
+}
+
+static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoITToneSlide(tick, a, UniGetByte());
+
+       return 0;
+}
+
+static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat)
+{
+       UBYTE q;
+       UWORD temp=0;
+
+       if (!tick) {
+               if (dat&0x0f) a->vibdepth=dat&0xf;
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+       }
+       if (!a->main.period)
+               return;
+
+       q=(a->vibpos>>2)&0x1f;
+
+       switch (a->wavecontrol&3) {
+       case 0: /* sine */
+               temp=VibratoTable[q];
+               break;
+       case 1: /* square wave */
+               temp=255;
+               break;
+       case 2: /* ramp down */
+               q<<=3;
+               if (a->vibpos<0) q=255-q;
+               temp=q;
+               break;
+       case 3: /* random */
+               temp=getrandom(256);
+               break;
+       }
+
+       temp*=a->vibdepth;
+       temp>>=8;
+       temp<<=2;
+
+       if (a->vibpos>=0)
+               a->main.period=a->tmpperiod+temp;
+       else
+               a->main.period=a->tmpperiod-temp;
+       a->ownper=1;
+
+       a->vibpos+=a->vibspd;
+}
+
+static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoITVibrato(tick, a, UniGetByte());
+
+       return 0;
+}
+
+static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, on, off;
+
+       inf = UniGetByte();
+       if (inf)
+               a->s3mtronof = inf;
+       else {
+               inf = a->s3mtronof;
+               if (!inf)
+                       return 0;
+       }
+
+       on=(inf>>4);
+       off=(inf&0xf);
+
+       a->s3mtremor%=(on+off);
+       a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
+       a->ownvol = 1;
+       a->s3mtremor++;
+
+       return 0;
+}
+
+static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       a->main.chanvol=UniGetByte();
+       if (a->main.chanvol>64)
+               a->main.chanvol=64;
+       else if (a->main.chanvol<0)
+               a->main.chanvol=0;
+
+       return 0;
+}
+
+static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, lo, hi;
+
+       inf = UniGetByte();
+
+       if (inf)
+               a->chanvolslide = inf;
+       else
+               inf = a->chanvolslide;
+
+       lo=inf&0xf;
+       hi=inf>>4;
+
+       if (!hi)
+               a->main.chanvol-=lo;
+       else
+         if (!lo) {
+               a->main.chanvol+=hi;
+       } else
+         if (hi==0xf) {
+               if (!tick) a->main.chanvol-=lo;
+       } else
+         if (lo==0xf) {
+               if (!tick) a->main.chanvol+=hi;
+       }
+
+       if (a->main.chanvol<0)
+               a->main.chanvol=0;
+       else if (a->main.chanvol>64)
+               a->main.chanvol=64;
+
+       return 0;
+}
+
+static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, lo, hi;
+       SWORD pan;
+
+       inf = UniGetByte();
+       if (inf)
+               a->pansspd = inf;
+       else
+               inf = a->pansspd;
+
+       if (!mod->panflag)
+               return 0;
+
+       lo=inf&0xf;
+       hi=inf>>4;
+
+       pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning;
+
+       if (!hi)
+               pan+=lo<<2;
+       else
+         if (!lo) {
+               pan-=hi<<2;
+       } else
+         if (hi==0xf) {
+               if (!tick) pan+=lo<<2;
+       } else
+         if (lo==0xf) {
+               if (!tick) pan-=hi<<2;
+       }
+       a->main.panning=
+         (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
+
+       return 0;
+}
+
+static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE tempo;
+       SWORD temp;
+
+       tempo = UniGetByte();
+
+       if (mod->patdly2)
+               return 0;
+
+       temp = mod->bpm;
+       if (tempo & 0x10)
+               temp += (tempo & 0x0f);
+       else
+               temp -= tempo;
+
+       mod->bpm=(temp>255)?255:(temp<1?1:temp);
+
+       return 0;
+}
+
+static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat, q;
+       UWORD temp = 0; /* silence warning */
+
+       dat = UniGetByte();
+       if (!tick) {
+               if (dat&0x0f) a->vibdepth=dat&0xf;
+               if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+       }
+       if (a->main.period) {
+               q=(a->vibpos>>2)&0x1f;
+
+               switch (a->wavecontrol&3) {
+               case 0: /* sine */
+                       temp=VibratoTable[q];
+                       break;
+               case 1: /* square wave */
+                       temp=255;
+                       break;
+               case 2: /* ramp down */
+                       q<<=3;
+                       if (a->vibpos<0) q=255-q;
+                       temp=q;
+                       break;
+               case 3: /* random */
+                       temp=getrandom(256);
+                       break;
+               }
+
+               temp*=a->vibdepth;
+               temp>>=8;
+
+               if (a->vibpos>=0)
+                       a->main.period=a->tmpperiod+temp;
+               else
+                       a->main.period=a->tmpperiod-temp;
+               a->ownper = 1;
+
+               a->vibpos+=a->vibspd;
+       }
+
+       return 0;
+}
+
+static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE inf, lo, hi;
+
+       inf = UniGetByte();
+
+       if (inf)
+               mod->globalslide = inf;
+       else
+               inf = mod->globalslide;
+
+       lo=inf&0xf;
+       hi=inf>>4;
+
+       if (!lo) {
+               if (tick) mod->volume+=hi;
+       } else
+         if (!hi) {
+               if (tick) mod->volume-=lo;
+       } else
+         if (lo==0xf) {
+               if (!tick) mod->volume+=hi;
+       } else
+         if (hi==0xf) {
+               if (!tick) mod->volume-=lo;
+       }
+
+       if (mod->volume<0)
+               mod->volume=0;
+       else if (mod->volume>128)
+               mod->volume=128;
+
+       return 0;
+}
+
+static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat, q;
+       SLONG temp = 0; /* silence warning */
+
+
+       dat=UniGetByte();
+       if (!tick) {
+               if (dat&0x0f) a->panbdepth=(dat&0xf);
+               if (dat&0xf0) a->panbspd=(dat&0xf0)>>4;
+       }
+       if (mod->panflag) {
+               q=a->panbpos;
+
+               switch (a->panbwave) {
+               case 0: /* sine */
+                       temp=PanbrelloTable[q];
+                       break;
+               case 1: /* square wave */
+                       temp=(q<0x80)?64:0;
+                       break;
+               case 2: /* ramp down */
+                       q<<=3;
+                       temp=q;
+                       break;
+               case 3: /* random */
+                       temp=getrandom(256);
+                       break;
+               }
+
+               temp*=a->panbdepth;
+               temp=(temp/8)+mod->panning[channel];
+
+               a->main.panning=
+                       (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp);
+               a->panbpos+=a->panbspd;
+
+       }
+
+       return 0;
+}
+
+static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);
+
+/* Impulse/Scream Tracker Sxx effects.
+   All Sxx effects share the same memory space. */
+static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat, inf, c;
+
+       dat = UniGetByte();
+       inf=dat&0xf;
+       c=dat>>4;
+
+       if (!dat) {
+               c=a->sseffect;
+               inf=a->ssdata;
+       } else {
+               a->sseffect=c;
+               a->ssdata=inf;
+       }
+
+       switch (c) {
+       case SS_GLISSANDO: /* S1x set glissando voice */
+               DoEEffects(tick, flags, a, mod, channel, 0x30|inf);
+               break;
+       case SS_FINETUNE: /* S2x set finetune */
+               DoEEffects(tick, flags, a, mod, channel, 0x50|inf);
+               break;
+       case SS_VIBWAVE: /* S3x set vibrato waveform */
+               DoEEffects(tick, flags, a, mod, channel, 0x40|inf);
+               break;
+       case SS_TREMWAVE: /* S4x set tremolo waveform */
+               DoEEffects(tick, flags, a, mod, channel, 0x70|inf);
+               break;
+       case SS_PANWAVE: /* S5x panbrello */
+               a->panbwave=inf;
+               break;
+       case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */
+               DoEEffects(tick, flags, a, mod, channel, 0xe0|inf);
+               break;
+       case SS_S7EFFECTS: /* S7x instrument / NNA commands */
+               DoNNAEffects(mod, a, inf);
+               break;
+       case SS_PANNING: /* S8x set panning position */
+               DoEEffects(tick, flags, a, mod, channel, 0x80 | inf);
+               break;
+       case SS_SURROUND: /* S9x set surround sound */
+               if (mod->panflag)
+                       a->main.panning = mod->panning[channel] = PAN_SURROUND;
+               break;
+       case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */
+               if (!tick) {
+                       a->hioffset=inf<<16;
+                       a->main.start=a->hioffset|a->soffset;
+
+                       if ((a->main.s)&&(a->main.start>a->main.s->length))
+                               a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
+                                   a->main.s->loopstart:a->main.s->length;
+               }
+               break;
+       case SS_PATLOOP: /* SBx pattern loop */
+               DoEEffects(tick, flags, a, mod, channel, 0x60|inf);
+               break;
+       case SS_NOTECUT: /* SCx notecut */
+               if (!inf) inf = 1;
+               DoEEffects(tick, flags, a, mod, channel, 0xC0|inf);
+               break;
+       case SS_NOTEDELAY: /* SDx notedelay */
+               DoEEffects(tick, flags, a, mod, channel, 0xD0|inf);
+               break;
+       case SS_PATDELAY: /* SEx patterndelay */
+               DoEEffects(tick, flags, a, mod, channel, 0xE0|inf);
+               break;
+       }
+
+       return 0;
+}
+
+/*========== Impulse Tracker Volume/Pan Column effects */
+
+/*
+ * All volume/pan column effects share the same memory space.
+ */
+
+static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE c, inf;
+
+       c = UniGetByte();
+       inf = UniGetByte();
+
+       if ((!c)&&(!inf)) {
+               c=a->voleffect;
+               inf=a->voldata;
+       } else {
+               a->voleffect=c;
+               a->voldata=inf;
+       }
+
+       if (c)
+               switch (c) {
+               case VOL_VOLUME:
+                       if (tick) break;
+                       if (inf>64) inf=64;
+                       a->tmpvolume=inf;
+                       break;
+               case VOL_PANNING:
+                       if (mod->panflag)
+                               a->main.panning=inf;
+                       break;
+               case VOL_VOLSLIDE:
+                       DoS3MVolSlide(tick, flags, a, inf);
+                       return 1;
+               case VOL_PITCHSLIDEDN:
+                       if (a->main.period)
+                               DoS3MSlideDn(tick, a, inf);
+                       break;
+               case VOL_PITCHSLIDEUP:
+                       if (a->main.period)
+                               DoS3MSlideUp(tick, a, inf);
+                       break;
+               case VOL_PORTAMENTO:
+                       DoITToneSlide(tick, a, inf);
+                       break;
+               case VOL_VIBRATO:
+                       DoITVibrato(tick, a, inf);
+                       break;
+       }
+
+       return 0;
+}
+
+/*========== UltraTracker effects */
+
+static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UWORD offset=UniGetWord();
+
+       if (offset)
+               a->ultoffset=offset;
+
+       a->main.start=a->ultoffset<<2;
+       if ((a->main.s)&&(a->main.start>a->main.s->length))
+               a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
+                   a->main.s->loopstart:a->main.s->length;
+
+       return 0;
+}
+
+/*========== OctaMED effects */
+
+static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UWORD speed=UniGetWord();
+
+       mod->bpm=speed;
+
+       return 0;
+}
+
+static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2));
+
+       return 0;
+}
+
+static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2));
+
+       return 0;
+}
+
+static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3));
+
+       return 0;
+}
+
+/*========== Oktalyzer effects */
+
+static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UBYTE dat, dat2;
+
+       dat2 = UniGetByte();    /* arpeggio style */
+       dat = UniGetByte();
+       if (!tick) {
+               if (!dat && (flags & UF_ARPMEM))
+                       dat=a->arpmem;
+               else
+                       a->arpmem=dat;
+       }
+       if (a->main.period)
+               DoArpeggio(tick, flags, a, dat2);
+
+       return 0;
+}
+
+/*========== General player functions */
+
+static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+       UniSkipOpcode();
+
+       return 0;
+}
+
+typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);
+
+static effect_func effects[UNI_LAST] = {
+       DoNothing,              /* 0 */
+       DoNothing,              /* UNI_NOTE */
+       DoNothing,              /* UNI_INSTRUMENT */
+       DoPTEffect0,    /* UNI_PTEFFECT0 */
+       DoPTEffect1,    /* UNI_PTEFFECT1 */
+       DoPTEffect2,    /* UNI_PTEFFECT2 */
+       DoPTEffect3,    /* UNI_PTEFFECT3 */
+       DoPTEffect4,    /* UNI_PTEFFECT4 */
+       DoPTEffect5,    /* UNI_PTEFFECT5 */
+       DoPTEffect6,    /* UNI_PTEFFECT6 */
+       DoPTEffect7,    /* UNI_PTEFFECT7 */
+       DoPTEffect8,    /* UNI_PTEFFECT8 */
+       DoPTEffect9,    /* UNI_PTEFFECT9 */
+       DoPTEffectA,    /* UNI_PTEFFECTA */
+       DoPTEffectB,    /* UNI_PTEFFECTB */
+       DoPTEffectC,    /* UNI_PTEFFECTC */
+       DoPTEffectD,    /* UNI_PTEFFECTD */
+       DoPTEffectE,    /* UNI_PTEFFECTE */
+       DoPTEffectF,    /* UNI_PTEFFECTF */
+       DoS3MEffectA,   /* UNI_S3MEFFECTA */
+       DoS3MEffectD,   /* UNI_S3MEFFECTD */
+       DoS3MEffectE,   /* UNI_S3MEFFECTE */
+       DoS3MEffectF,   /* UNI_S3MEFFECTF */
+       DoS3MEffectI,   /* UNI_S3MEFFECTI */
+       DoS3MEffectQ,   /* UNI_S3MEFFECTQ */
+       DoS3MEffectR,   /* UNI_S3MEFFECTR */
+       DoS3MEffectT,   /* UNI_S3MEFFECTT */
+       DoS3MEffectU,   /* UNI_S3MEFFECTU */
+       DoKeyOff,       /* UNI_KEYOFF */
+       DoKeyFade,      /* UNI_KEYFADE */
+       DoVolEffects,   /* UNI_VOLEFFECTS */
+       DoPTEffect4,    /* UNI_XMEFFECT4 */
+       DoXMEffect6,    /* UNI_XMEFFECT6 */
+       DoXMEffectA,    /* UNI_XMEFFECTA */
+       DoXMEffectE1,   /* UNI_XMEFFECTE1 */
+       DoXMEffectE2,   /* UNI_XMEFFECTE2 */
+       DoXMEffectEA,   /* UNI_XMEFFECTEA */
+       DoXMEffectEB,   /* UNI_XMEFFECTEB */
+       DoXMEffectG,    /* UNI_XMEFFECTG */
+       DoXMEffectH,    /* UNI_XMEFFECTH */
+       DoXMEffectL,    /* UNI_XMEFFECTL */
+       DoXMEffectP,    /* UNI_XMEFFECTP */
+       DoXMEffectX1,   /* UNI_XMEFFECTX1 */
+       DoXMEffectX2,   /* UNI_XMEFFECTX2 */
+       DoITEffectG,    /* UNI_ITEFFECTG */
+       DoITEffectH,    /* UNI_ITEFFECTH */
+       DoITEffectI,    /* UNI_ITEFFECTI */
+       DoITEffectM,    /* UNI_ITEFFECTM */
+       DoITEffectN,    /* UNI_ITEFFECTN */
+       DoITEffectP,    /* UNI_ITEFFECTP */
+       DoITEffectT,    /* UNI_ITEFFECTT */
+       DoITEffectU,    /* UNI_ITEFFECTU */
+       DoITEffectW,    /* UNI_ITEFFECTW */
+       DoITEffectY,    /* UNI_ITEFFECTY */
+       DoNothing,      /* UNI_ITEFFECTZ */
+       DoITEffectS0,   /* UNI_ITEFFECTS0 */
+       DoULTEffect9,   /* UNI_ULTEFFECT9 */
+       DoMEDSpeed,     /* UNI_MEDSPEED */
+       DoMEDEffectF1,  /* UNI_MEDEFFECTF1 */
+       DoMEDEffectF2,  /* UNI_MEDEFFECTF2 */
+       DoMEDEffectF3,  /* UNI_MEDEFFECTF3 */
+       DoOktArp,       /* UNI_OKTARP */
+};
+
+static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a)
+{
+       UWORD tick = mod->vbtick;
+       UWORD flags = mod->flags;
+       UBYTE c;
+       int explicitslides = 0;
+       effect_func f;
+
+       while((c=UniGetByte()) != 0) {
+#if 0 /* this doesn't normally happen unless things go fubar elsewhere */
+               if (c >= UNI_LAST)
+                   fprintf(stderr,"fubar'ed opcode %u\n",c);
+#endif
+               f = effects[c];
+               if (f != DoNothing)
+                   a->sliding = 0;
+               explicitslides |= f(tick, flags, a, mod, channel);
+       }
+       return explicitslides;
+}
+
+static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat)
+{
+       int t;
+       MP_VOICE *aout;
+
+       dat&=0xf;
+       aout=(a->slave)?a->slave:NULL;
+
+       switch (dat) {
+       case 0x0: /* past note cut */
+               for (t=0;t<NUMVOICES(mod);t++)
+                       if (mod->voice[t].master==a)
+                               mod->voice[t].main.fadevol=0;
+               break;
+       case 0x1: /* past note off */
+               for (t=0;t<NUMVOICES(mod);t++)
+                       if (mod->voice[t].master==a) {
+                               mod->voice[t].main.keyoff|=KEY_OFF;
+                               if ((!(mod->voice[t].venv.flg & EF_ON))||
+                                  (mod->voice[t].venv.flg & EF_LOOP))
+                                       mod->voice[t].main.keyoff=KEY_KILL;
+                       }
+               break;
+       case 0x2: /* past note fade */
+               for (t=0;t<NUMVOICES(mod);t++)
+                       if (mod->voice[t].master==a)
+                               mod->voice[t].main.keyoff|=KEY_FADE;
+               break;
+       case 0x3: /* set NNA note cut */
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT;
+               break;
+       case 0x4: /* set NNA note continue */
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE;
+               break;
+       case 0x5: /* set NNA note off */
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF;
+               break;
+       case 0x6: /* set NNA note fade */
+               a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE;
+               break;
+       case 0x7: /* disable volume envelope */
+               if (aout)
+                       aout->main.volflg&=~EF_ON;
+               break;
+       case 0x8: /* enable volume envelope  */
+               if (aout)
+                       aout->main.volflg|=EF_ON;
+               break;
+       case 0x9: /* disable panning envelope */
+               if (aout)
+                       aout->main.panflg&=~EF_ON;
+               break;
+       case 0xa: /* enable panning envelope */
+               if (aout)
+                       aout->main.panflg|=EF_ON;
+               break;
+       case 0xb: /* disable pitch envelope */
+               if (aout)
+                       aout->main.pitflg&=~EF_ON;
+               break;
+       case 0xc: /* enable pitch envelope */
+               if (aout)
+                       aout->main.pitflg|=EF_ON;
+               break;
+       }
+}
+
+static void pt_UpdateVoices(MODULE *mod, int max_volume)
+{
+       SWORD envpan,envvol,envpit,channel;
+       UWORD playperiod;
+       SLONG vibval,vibdpt;
+       ULONG tmpvol;
+
+       MP_VOICE *aout;
+       INSTRUMENT *i;
+       SAMPLE *s;
+
+       mod->totalchn=mod->realchn=0;
+       for (channel=0;channel<NUMVOICES(mod);channel++) {
+               aout=&mod->voice[channel];
+               i=aout->main.i;
+               s=aout->main.s;
+
+               if (!s || !s->length) continue;
+
+               if (aout->main.period<40)
+                       aout->main.period=40;
+               else if (aout->main.period>50000)
+                       aout->main.period=50000;
+
+               if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) {
+                       Voice_Play_internal(channel,s,(aout->main.start==-1)?
+                           ((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->main.start);
+                       aout->main.fadevol=32768;
+                       aout->aswppos=0;
+               }
+
+               envvol = 256;
+               envpan = PAN_CENTER;
+               envpit = 32;
+               if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) {
+                       if (aout->main.volflg & EF_ON)
+                               envvol = StartEnvelope(&aout->venv,aout->main.volflg,
+                                 i->volpts,i->volsusbeg,i->volsusend,
+                                 i->volbeg,i->volend,i->volenv,aout->main.keyoff);
+                       if (aout->main.panflg & EF_ON)
+                               envpan = StartEnvelope(&aout->penv,aout->main.panflg,
+                                 i->panpts,i->pansusbeg,i->pansusend,
+                                 i->panbeg,i->panend,i->panenv,aout->main.keyoff);
+                       if (aout->main.pitflg & EF_ON)
+                               envpit = StartEnvelope(&aout->cenv,aout->main.pitflg,
+                                 i->pitpts,i->pitsusbeg,i->pitsusend,
+                                 i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff);
+
+                       if (aout->cenv.flg & EF_ON)
+                               aout->masterperiod=GetPeriod(mod->flags,
+                                 (UWORD)aout->main.note<<1, aout->master->speed);
+               } else {
+                       if (aout->main.volflg & EF_ON)
+                               envvol = ProcessEnvelope(aout,&aout->venv,256);
+                       if (aout->main.panflg & EF_ON)
+                               envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER);
+                       if (aout->main.pitflg & EF_ON)
+                               envpit = ProcessEnvelope(aout,&aout->cenv,32);
+               }
+               if (aout->main.kick == KICK_NOTE) {
+                       aout->main.kick_flag = 1;
+               }
+               aout->main.kick=KICK_ABSENT;
+
+               tmpvol = aout->main.fadevol;    /* max 32768 */
+               tmpvol *= aout->main.chanvol;   /* * max 64 */
+               tmpvol *= aout->main.outvolume; /* * max 256 */
+               tmpvol /= (256 * 64);                   /* tmpvol is max 32768 again */
+               aout->totalvol = tmpvol >> 2;   /* used to determine samplevolume */
+               tmpvol *= envvol;                               /* * max 256 */
+               tmpvol *= mod->volume;                  /* * max 128 */
+               tmpvol /= (128 * 256 * 128);
+
+               /* fade out */
+               if (mod->sngpos>=mod->numpos)
+                       tmpvol=0;
+               else
+                       tmpvol=(tmpvol*max_volume)/128;
+
+               if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted)
+                       Voice_SetVolume_internal(channel,0);
+               else {
+                       Voice_SetVolume_internal(channel,tmpvol);
+                       if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
+                               mod->realchn++;
+                       mod->totalchn++;
+               }
+
+               if (aout->main.panning==PAN_SURROUND)
+                       Voice_SetPanning_internal(channel,PAN_SURROUND);
+               else
+                       if ((mod->panflag)&&(aout->penv.flg & EF_ON))
+                               Voice_SetPanning_internal(channel,
+                                   DoPan(envpan,aout->main.panning));
+                       else
+                               Voice_SetPanning_internal(channel,aout->main.panning);
+
+               if (aout->main.period && s->vibdepth)
+                       switch (s->vibtype) {
+                       case 0:
+                               vibval=avibtab[s->avibpos&127];
+                               if (aout->avibpos & 0x80) vibval=-vibval;
+                               break;
+                       case 1:
+                               vibval=64;
+                               if (aout->avibpos & 0x80) vibval=-vibval;
+                               break;
+                       case 2:
+                               vibval=63-(((aout->avibpos+128)&255)>>1);
+                               break;
+                       default:
+                               vibval=(((aout->avibpos+128)&255)>>1)-64;
+                               break;
+                       }
+               else
+                       vibval=0;
+
+               if (s->vibflags & AV_IT) {
+                       if ((aout->aswppos>>8)<s->vibdepth) {
+                               aout->aswppos += s->vibsweep;
+                               vibdpt=aout->aswppos;
+                       } else
+                               vibdpt=s->vibdepth<<8;
+                       vibval=(vibval*vibdpt)>>16;
+                       if (aout->mflag) {
+                               if (!(mod->flags&UF_LINEAR)) vibval>>=1;
+                               aout->main.period-=vibval;
+                       }
+               } else {
+                       /* do XM style auto-vibrato */
+                       if (!(aout->main.keyoff & KEY_OFF)) {
+                               if (aout->aswppos<s->vibsweep) {
+                                       vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep;
+                                       aout->aswppos++;
+                               } else
+                                       vibdpt=s->vibdepth;
+                       } else {
+                               /* keyoff -> depth becomes 0 if final depth wasn't reached or
+                                  stays at final level if depth WAS reached */
+                               if (aout->aswppos>=s->vibsweep)
+                                       vibdpt=s->vibdepth;
+                               else
+                                       vibdpt=0;
+                       }
+                       vibval=(vibval*vibdpt)>>8;
+                       aout->main.period-=vibval;
+               }
+
+               /* update vibrato position */
+               aout->avibpos=(aout->avibpos+s->vibrate)&0xff;
+
+               /* process pitch envelope */
+               playperiod=aout->main.period;
+
+               if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) {
+                       long p1;
+
+                       envpit-=32;
+                       if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1);
+
+                       p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit,
+                           aout->master->speed)-aout->masterperiod;
+                       if (p1>0) {
+                               if ((UWORD)(playperiod+p1)<=playperiod) {
+                                       p1=0;
+                                       aout->main.keyoff|=KEY_OFF;
+                               }
+                       } else if (p1<0) {
+                               if ((UWORD)(playperiod+p1)>=playperiod) {
+                                       p1=0;
+                                       aout->main.keyoff|=KEY_OFF;
+                               }
+                       }
+                       playperiod+=p1;
+               }
+
+               if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */
+                       Voice_Stop_internal(channel);
+                       mod->totalchn--;
+                       if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
+                               mod->realchn--;
+               } else {
+                       Voice_SetFrequency_internal(channel,
+                                                   getfrequency(mod->flags,playperiod));
+
+                       /* if keyfade, start substracting fadeoutspeed from fadevol: */
+                       if ((i)&&(aout->main.keyoff&KEY_FADE)) {
+                               if (aout->main.fadevol>=i->volfade)
+                                       aout->main.fadevol-=i->volfade;
+                               else
+                                       aout->main.fadevol=0;
+                       }
+               }
+
+               md_bpm=mod->bpm+mod->relspd;
+               if (md_bpm<32)
+                       md_bpm=32;
+               else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255)
+                       md_bpm=255;
+       }
+}
+
+/* Handles new notes or instruments */
+static void pt_Notes(MODULE *mod)
+{
+       SWORD channel;
+       MP_CONTROL *a;
+       UBYTE c,inst;
+       int tr,funky; /* funky is set to indicate note or instrument change */
+
+       for (channel=0;channel<mod->numchn;channel++) {
+               a=&mod->control[channel];
+
+               if (mod->sngpos>=mod->numpos) {
+                       tr=mod->numtrk;
+                       mod->numrow=0;
+               } else {
+                       tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel];
+                       mod->numrow=mod->pattrows[mod->positions[mod->sngpos]];
+               }
+
+               a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL;
+               a->newsamp=0;
+               if (!mod->vbtick) a->main.notedelay=0;
+
+               if (!a->row) continue;
+               UniSetRow(a->row);
+               funky=0;
+
+               while((c=UniGetByte()) != 0)
+                       switch (c) {
+                       case UNI_NOTE:
+                               funky|=1;
+                               a->oldnote=a->anote,a->anote=UniGetByte();
+                               a->main.kick =KICK_NOTE;
+                               a->main.start=-1;
+                               a->sliding=0;
+
+                               /* retrig tremolo and vibrato waves ? */
+                               if (!(a->wavecontrol & 0x80)) a->trmpos=0;
+                               if (!(a->wavecontrol & 0x08)) a->vibpos=0;
+                               if (!a->panbwave) a->panbpos=0;
+                               break;
+                       case UNI_INSTRUMENT:
+                               inst=UniGetByte();
+                               if (inst>=mod->numins) break; /* safety valve */
+                               funky|=2;
+                               a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL;
+                               a->retrig=0;
+                               a->s3mtremor=0;
+                               a->ultoffset=0;
+                               a->main.sample=inst;
+                               break;
+                       default:
+                               UniSkipOpcode();
+                               break;
+                       }
+
+               if (funky) {
+                       INSTRUMENT *i;
+                       SAMPLE *s;
+
+                       if ((i=a->main.i) != NULL) {
+                               if (i->samplenumber[a->anote] >= mod->numsmp) continue;
+                               s=&mod->samples[i->samplenumber[a->anote]];
+                               a->main.note=i->samplenote[a->anote];
+                       } else {
+                               a->main.note=a->anote;
+                               s=&mod->samples[a->main.sample];
+                       }
+
+                       if (a->main.s!=s) {
+                               a->main.s=s;
+                               a->newsamp=a->main.period;
+                       }
+
+                       /* channel or instrument determined panning ? */
+                       a->main.panning=mod->panning[channel];
+                       if (s->flags & SF_OWNPAN)
+                               a->main.panning=s->panning;
+                       else if ((i)&&(i->flags & IF_OWNPAN))
+                               a->main.panning=i->panning;
+
+                       a->main.handle=s->handle;
+                       a->speed=s->speed;
+
+                       if (i) {
+                               if ((mod->panflag)&&(i->flags & IF_PITCHPAN)
+                                  &&(a->main.panning!=PAN_SURROUND)){
+                                       a->main.panning+=
+                                           ((a->anote-i->pitpancenter)*i->pitpansep)/8;
+                                       if (a->main.panning<PAN_LEFT)
+                                               a->main.panning=PAN_LEFT;
+                                       else if (a->main.panning>PAN_RIGHT)
+                                               a->main.panning=PAN_RIGHT;
+                               }
+                               a->main.pitflg=i->pitflg;
+                               a->main.volflg=i->volflg;
+                               a->main.panflg=i->panflg;
+                               a->main.nna=i->nnatype;
+                               a->dca=i->dca;
+                               a->dct=i->dct;
+                       } else {
+                               a->main.pitflg=a->main.volflg=a->main.panflg=0;
+                               a->main.nna=a->dca=0;
+                               a->dct=DCT_OFF;
+                       }
+
+                       if (funky&2) /* instrument change */ {
+                               /* IT random volume variations: 0:8 bit fixed, and one bit for
+                                  sign. */
+                               a->volume=a->tmpvolume=s->volume;
+                               if ((s)&&(i)) {
+                                       if (i->rvolvar) {
+                                               a->volume=a->tmpvolume=s->volume+
+                                                 ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512)
+                                                 ))/25600);
+                                               if (a->volume<0)
+                                                       a->volume=a->tmpvolume=0;
+                                               else if (a->volume>64)
+                                                       a->volume=a->tmpvolume=64;
+                                       }
+                                       if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) {
+                                               a->main.panning+=((a->main.panning*((SLONG)i->rpanvar*
+                                                 (SLONG)getrandom(512)))/25600);
+                                               if (a->main.panning<PAN_LEFT)
+                                                       a->main.panning=PAN_LEFT;
+                                               else if (a->main.panning>PAN_RIGHT)
+                                                       a->main.panning=PAN_RIGHT;
+                                       }
+                               }
+                       }
+
+                       a->wantedperiod=a->tmpperiod=
+                           GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed);
+                       a->main.keyoff=KEY_KICK;
+               }
+       }
+}
+
+/* Handles effects */
+static void pt_EffectsPass1(MODULE *mod)
+{
+       SWORD channel;
+       MP_CONTROL *a;
+       MP_VOICE *aout;
+       int explicitslides;
+
+       for (channel=0;channel<mod->numchn;channel++) {
+               a=&mod->control[channel];
+
+               if ((aout=a->slave) != NULL) {
+                       a->main.fadevol=aout->main.fadevol;
+                       a->main.period=aout->main.period;
+                       if (a->main.kick==KICK_KEYOFF)
+                               a->main.keyoff=aout->main.keyoff;
+               }
+
+               if (!a->row) continue;
+               UniSetRow(a->row);
+
+               a->ownper=a->ownvol=0;
+               explicitslides = pt_playeffects(mod, channel, a);
+
+               /* continue volume slide if necessary for XM and IT */
+               if (mod->flags&UF_BGSLIDES) {
+                       if (!explicitslides && a->sliding)
+                               DoS3MVolSlide(mod->vbtick, mod->flags, a, 0);
+                       else if (a->tmpvolume)
+                               a->sliding = explicitslides;
+               }
+
+               if (!a->ownper)
+                       a->main.period=a->tmpperiod;
+               if (!a->ownvol)
+                       a->volume=a->tmpvolume;
+
+               if (a->main.s) {
+                       if (a->main.i)
+                               a->main.outvolume=
+                                   (a->volume*a->main.s->globvol*a->main.i->globvol)>>10;
+                       else
+                               a->main.outvolume=(a->volume*a->main.s->globvol)>>4;
+                       if (a->main.outvolume>256)
+                               a->main.outvolume=256;
+                       else if (a->main.outvolume<0)
+                               a->main.outvolume=0;
+               }
+       }
+}
+
+/* NNA management */
+static void pt_NNA(MODULE *mod)
+{
+       SWORD channel;
+       MP_CONTROL *a;
+
+       for (channel=0;channel<mod->numchn;channel++) {
+               a=&mod->control[channel];
+
+               if (a->main.kick==KICK_NOTE) {
+                       BOOL kill=0;
+
+                       if (a->slave) {
+                               MP_VOICE *aout;
+
+                               aout=a->slave;
+                               if (aout->main.nna & NNA_MASK) {
+                                       /* Make sure the old MP_VOICE channel knows it has no
+                                          master now ! */
+                                       a->slave=NULL;
+                                       /* assume the channel is taken by NNA */
+                                       aout->mflag=0;
+
+                                       switch (aout->main.nna) {
+                                       case NNA_CONTINUE: /* continue note, do nothing */
+                                               break;
+                                       case NNA_OFF: /* note off */
+                                               aout->main.keyoff|=KEY_OFF;
+                                               if ((!(aout->main.volflg & EF_ON))||
+                                                         (aout->main.volflg & EF_LOOP))
+                                                       aout->main.keyoff=KEY_KILL;
+                                               break;
+                                       case NNA_FADE:
+                                               aout->main.keyoff |= KEY_FADE;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (a->dct!=DCT_OFF) {
+                               int t;
+
+                               for (t=0;t<NUMVOICES(mod);t++)
+                                       if ((!Voice_Stopped_internal(t))&&
+                                          (mod->voice[t].masterchn==channel)&&
+                                          (a->main.sample==mod->voice[t].main.sample)) {
+                                               kill=0;
+                                               switch (a->dct) {
+                                               case DCT_NOTE:
+                                                       if (a->main.note==mod->voice[t].main.note)
+                                                               kill=1;
+                                                       break;
+                                               case DCT_SAMPLE:
+                                                       if (a->main.handle==mod->voice[t].main.handle)
+                                                               kill=1;
+                                                       break;
+                                               case DCT_INST:
+                                                       kill=1;
+                                                       break;
+                                               }
+                                               if (kill)
+                                                       switch (a->dca) {
+                                                       case DCA_CUT:
+                                                               mod->voice[t].main.fadevol=0;
+                                                               break;
+                                                       case DCA_OFF:
+                                                               mod->voice[t].main.keyoff|=KEY_OFF;
+                                                               if ((!(mod->voice[t].main.volflg&EF_ON))||
+                                                                   (mod->voice[t].main.volflg&EF_LOOP))
+                                                                       mod->voice[t].main.keyoff=KEY_KILL;
+                                                               break;
+                                                       case DCA_FADE:
+                                                               mod->voice[t].main.keyoff|=KEY_FADE;
+                                                               break;
+                                                       }
+                                       }
+                       }
+               } /* if (a->main.kick==KICK_NOTE) */
+       }
+}
+
+/* Setup module and NNA voices */
+static void pt_SetupVoices(MODULE *mod)
+{
+       SWORD channel;
+       MP_CONTROL *a;
+       MP_VOICE *aout;
+
+       for (channel=0;channel<mod->numchn;channel++) {
+               a=&mod->control[channel];
+
+               if (a->main.notedelay) continue;
+               if (a->main.kick==KICK_NOTE) {
+                       /* if no channel was cut above, find an empty or quiet channel
+                          here */
+                       if (mod->flags&UF_NNA) {
+                               if (!a->slave) {
+                                       int newchn;
+
+                                       if ((newchn=MP_FindEmptyChannel(mod))!=-1)
+                                               a->slave=&mod->voice[a->slavechn=newchn];
+                               }
+                       } else
+                               a->slave=&mod->voice[a->slavechn=channel];
+
+                       /* assign parts of MP_VOICE only done for a KICK_NOTE */
+                       if ((aout=a->slave) != NULL) {
+                               if (aout->mflag && aout->master) aout->master->slave=NULL;
+                               aout->master=a;
+                               a->slave=aout;
+                               aout->masterchn=channel;
+                               aout->mflag=1;
+                       }
+               } else
+                       aout=a->slave;
+
+               if (aout)
+                       aout->main=a->main;
+               a->main.kick=KICK_ABSENT;
+       }
+}
+
+/* second effect pass */
+static void pt_EffectsPass2(MODULE *mod)
+{
+       SWORD channel;
+       MP_CONTROL *a;
+       UBYTE c;
+
+       for (channel=0;channel<mod->numchn;channel++) {
+               a=&mod->control[channel];
+
+               if (!a->row) continue;
+               UniSetRow(a->row);
+
+               while((c=UniGetByte()) != 0)
+                       if (c==UNI_ITEFFECTS0) {
+                               c=UniGetByte();
+                               if ((c>>4)==SS_S7EFFECTS)
+                                       DoNNAEffects(mod, a, c&0xf);
+                       } else
+                               UniSkipOpcode();
+       }
+}
+
+void Player_HandleTick(void)
+{
+       SWORD channel;
+       int max_volume;
+
+#if 0
+       /* don't handle the very first ticks, this allows the other hardware to
+          settle down so we don't loose any starting notes */
+       if (isfirst) {
+               isfirst--;
+               return;
+       }
+#endif
+
+       if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return;
+
+       /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */
+       pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */
+       pf->sngtime+=pf->sngremainder/pf->bpm;
+       pf->sngremainder%=pf->bpm;
+
+       if (++pf->vbtick>=pf->sngspd) {
+               if (pf->pat_repcrazy)
+                       pf->pat_repcrazy=0; /* play 2 times row 0 */
+               else
+                       pf->patpos++;
+               pf->vbtick=0;
+
+               /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is
+                  the command memory. */
+               if (pf->patdly)
+                       pf->patdly2=pf->patdly,pf->patdly=0;
+               if (pf->patdly2) {
+                       /* patterndelay active */
+                       if (--pf->patdly2)
+                               /* so turn back pf->patpos by 1 */
+                               if (pf->patpos) pf->patpos--;
+               }
+
+               /* do we have to get a new patternpointer ? (when pf->patpos reaches the
+                  pattern size, or when a patternbreak is active) */
+               if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp))
+                       pf->posjmp=3;
+
+               if (pf->posjmp) {
+                       pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0;
+                       pf->pat_repcrazy=0;
+                       pf->sngpos+=(pf->posjmp-2);
+                       for (channel=0;channel<pf->numchn;channel++)
+                               pf->control[channel].pat_reppos=-1;
+
+                       pf->patbrk=pf->posjmp=0;
+
+                       if (pf->sngpos<0) pf->sngpos=(SWORD)(pf->numpos-1);
+
+                       /* handle the "---" (end of song) pattern since it can occur
+                          *inside* the module in some formats */
+                       if ((pf->sngpos>=pf->numpos)||
+                               (pf->positions[pf->sngpos]==LAST_PATTERN)) {
+                               if (!pf->wrap) return;
+                               if (!(pf->sngpos=pf->reppos)) {
+                                   pf->volume=pf->initvolume>128?128:pf->initvolume;
+                                       if(pf->initspeed!=0)
+                                               pf->sngspd=pf->initspeed<32?pf->initspeed:32;
+                                       else
+                                               pf->sngspd=6;
+                                       pf->bpm=pf->inittempo<32?32:pf->inittempo;
+                               }
+                       }
+               }
+
+               if (!pf->patdly2)
+                       pt_Notes(pf);
+       }
+
+       /* Fade global volume if enabled and we're playing the last pattern */
+       if (((pf->sngpos==pf->numpos-1)||
+                (pf->positions[pf->sngpos+1]==LAST_PATTERN))&&
+           (pf->fadeout))
+               max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0;
+       else
+               max_volume=128;
+
+       pt_EffectsPass1(pf);
+       if (pf->flags&UF_NNA)
+               pt_NNA(pf);
+       pt_SetupVoices(pf);
+       pt_EffectsPass2(pf);
+
+       /* now set up the actual hardware channel playback information */
+       pt_UpdateVoices(pf, max_volume);
+}
+
+static void Player_Init_internal(MODULE* mod)
+{
+       int t;
+
+       for (t=0;t<mod->numchn;t++) {
+               mod->control[t].main.chanvol=mod->chanvol[t];
+               mod->control[t].main.panning=mod->panning[t];
+       }
+
+       mod->sngtime=0;
+       mod->sngremainder=0;
+
+       mod->pat_repcrazy=0;
+       mod->sngpos=0;
+       if(mod->initspeed!=0)
+               mod->sngspd=mod->initspeed<32?mod->initspeed:32;
+       else
+               mod->sngspd=6;
+       mod->volume=mod->initvolume>128?128:mod->initvolume;
+
+       mod->vbtick=mod->sngspd;
+       mod->patdly=0;
+       mod->patdly2=0;
+       mod->bpm=mod->inittempo<32?32:mod->inittempo;
+       mod->realchn=0;
+
+       mod->patpos=0;
+       mod->posjmp=2; /* make sure the player fetches the first note */
+       mod->numrow=-1;
+       mod->patbrk=0;
+}
+
+int Player_Init(MODULE* mod)
+{
+       mod->extspd=1;
+       mod->panflag=1;
+       mod->wrap=0;
+       mod->loop=1;
+       mod->fadeout=0;
+
+       mod->relspd=0;
+
+       /* make sure the player doesn't start with garbage */
+       if (!(mod->control=(MP_CONTROL*)MikMod_calloc(mod->numchn,sizeof(MP_CONTROL))))
+               return 1;
+       if (!(mod->voice=(MP_VOICE*)MikMod_calloc(md_sngchn,sizeof(MP_VOICE))))
+               return 1;
+
+       /* mod->numvoices was used during loading to clamp md_sngchn.
+          After loading it's used to remember how big mod->voice is.
+       */
+       mod->numvoices = md_sngchn;
+
+       Player_Init_internal(mod);
+       return 0;
+}
+
+void Player_Exit_internal(MODULE* mod)
+{
+       if (!mod)
+               return;
+
+       /* Stop playback if necessary */
+       if (mod==pf) {
+               Player_Stop_internal();
+               pf=NULL;
+       }
+
+       MikMod_free(mod->control);
+       MikMod_free(mod->voice);
+       mod->control=NULL;
+       mod->voice=NULL;
+}
+
+void Player_Exit(MODULE* mod)
+{
+       MUTEX_LOCK(vars);
+       Player_Exit_internal(mod);
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetVolume(SWORD volume)
+{
+       MUTEX_LOCK(vars);
+       if (pf) {
+               pf->volume=(volume<0)?0:(volume>128)?128:volume;
+               pf->initvolume=pf->volume;
+       }
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI MODULE* Player_GetModule(void)
+{
+       MODULE* result;
+
+       MUTEX_LOCK(vars);
+       result=pf;
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI void Player_Start(MODULE *mod)
+{
+       int t;
+
+       if (!mod)
+               return;
+
+       if (!MikMod_Active())
+               MikMod_EnableOutput();
+
+       mod->forbid=0;
+
+       MUTEX_LOCK(vars);
+       if (pf!=mod) {
+               /* new song is being started, so completely stop out the old one. */
+               if (pf) pf->forbid=1;
+               for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t);
+       }
+       pf=mod;
+       MUTEX_UNLOCK(vars);
+}
+
+void Player_Stop_internal(void)
+{
+       if (!md_sfxchn) MikMod_DisableOutput_internal();
+       if (pf) pf->forbid=1;
+       pf=NULL;
+}
+
+MIKMODAPI void Player_Stop(void)
+{
+       MUTEX_LOCK(vars);
+               Player_Stop_internal();
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI BOOL Player_Active(void)
+{
+       BOOL result=0;
+
+       MUTEX_LOCK(vars);
+       if (pf)
+               result=(!(pf->sngpos>=pf->numpos));
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI void Player_NextPosition(void)
+{
+       MUTEX_LOCK(vars);
+       if (pf) {
+               int t;
+
+               pf->forbid=1;
+               pf->posjmp=3;
+               pf->patbrk=0;
+               pf->vbtick=pf->sngspd;
+
+               for (t=0;t<NUMVOICES(pf);t++) {
+                       Voice_Stop_internal(t);
+                       pf->voice[t].main.i=NULL;
+                       pf->voice[t].main.s=NULL;
+               }
+               for (t=0;t<pf->numchn;t++) {
+                       pf->control[t].main.i=NULL;
+                       pf->control[t].main.s=NULL;
+               }
+               pf->forbid=0;
+       }
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_PrevPosition(void)
+{
+       MUTEX_LOCK(vars);
+       if (pf) {
+               int t;
+
+               pf->forbid=1;
+               pf->posjmp=1;
+               pf->patbrk=0;
+               pf->vbtick=pf->sngspd;
+
+               for (t=0;t<NUMVOICES(pf);t++) {
+                       Voice_Stop_internal(t);
+                       pf->voice[t].main.i=NULL;
+                       pf->voice[t].main.s=NULL;
+               }
+               for (t=0;t<pf->numchn;t++) {
+                       pf->control[t].main.i=NULL;
+                       pf->control[t].main.s=NULL;
+               }
+               pf->forbid=0;
+       }
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetPosition(UWORD pos)
+{
+       MUTEX_LOCK(vars);
+       if (pf) {
+               int t;
+
+               pf->forbid=1;
+               if (pos>=pf->numpos) pos=pf->numpos;
+               pf->posjmp=2;
+               pf->patbrk=0;
+               pf->sngpos=pos;
+               pf->vbtick=pf->sngspd;
+
+               for (t=0;t<NUMVOICES(pf);t++) {
+                       Voice_Stop_internal(t);
+                       pf->voice[t].main.i=NULL;
+                       pf->voice[t].main.s=NULL;
+               }
+               for (t=0;t<pf->numchn;t++) {
+                       pf->control[t].main.i=NULL;
+                       pf->control[t].main.s=NULL;
+               }
+               pf->forbid=0;
+
+               if (!pos)
+                       Player_Init_internal(pf);
+       }
+       MUTEX_UNLOCK(vars);
+}
+
+static void Player_Unmute_internal(SLONG arg1,va_list ap)
+{
+       SLONG t,arg2,arg3=0;
+
+       if (pf) {
+               switch (arg1) {
+               case MUTE_INCLUSIVE:
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+                          (arg2>arg3)||(arg3>=pf->numchn))
+                               return;
+                       for (;arg2<pf->numchn && arg2<=arg3;arg2++)
+                               pf->control[arg2].muted=0;
+                       break;
+               case MUTE_EXCLUSIVE:
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+                          (arg2>arg3)||(arg3>=pf->numchn))
+                               return;
+                       for (t=0;t<pf->numchn;t++) {
+                               if ((t>=arg2) && (t<=arg3))
+                                       continue;
+                               pf->control[t].muted=0;
+                       }
+                       break;
+               default:
+                       if (arg1<pf->numchn) pf->control[arg1].muted=0;
+                       break;
+               }
+       }
+}
+
+MIKMODAPI void Player_Unmute(SLONG arg1, ...)
+{
+       va_list args;
+
+       va_start(args,arg1);
+       MUTEX_LOCK(vars);
+       Player_Unmute_internal(arg1,args);
+       MUTEX_UNLOCK(vars);
+       va_end(args);
+}
+
+static void Player_Mute_internal(SLONG arg1,va_list ap)
+{
+       SLONG t,arg2,arg3=0;
+
+       if (pf) {
+               switch (arg1) {
+               case MUTE_INCLUSIVE:
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+                           (arg2>arg3)||(arg3>=pf->numchn))
+                               return;
+                       for (;arg2<pf->numchn && arg2<=arg3;arg2++)
+                               pf->control[arg2].muted=1;
+                       break;
+               case MUTE_EXCLUSIVE:
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+                           (arg2>arg3)||(arg3>=pf->numchn))
+                               return;
+                       for (t=0;t<pf->numchn;t++) {
+                               if ((t>=arg2) && (t<=arg3))
+                                       continue;
+                               pf->control[t].muted=1;
+                       }
+                       break;
+               default:
+                       if (arg1<pf->numchn)
+                               pf->control[arg1].muted=1;
+                       break;
+               }
+       }
+}
+
+MIKMODAPI void Player_Mute(SLONG arg1,...)
+{
+       va_list args;
+
+       va_start(args,arg1);
+       MUTEX_LOCK(vars);
+       Player_Mute_internal(arg1,args);
+       MUTEX_UNLOCK(vars);
+       va_end(args);
+}
+
+static void Player_ToggleMute_internal(SLONG arg1,va_list ap)
+{
+       SLONG arg2,arg3=0;
+       ULONG t;
+
+       if (pf) {
+               switch (arg1) {
+               case MUTE_INCLUSIVE:
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+                           (arg2>arg3)||(arg3>=pf->numchn))
+                               return;
+                       for (;arg2<pf->numchn && arg2<=arg3;arg2++)
+                               pf->control[arg2].muted=1-pf->control[arg2].muted;
+                       break;
+               case MUTE_EXCLUSIVE:
+                       if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+                           (arg2>arg3)||(arg3>=pf->numchn))
+                               return;
+                       for (t=0;t<pf->numchn;t++) {
+                               if ((t>=arg2) && (t<=arg3))
+                                       continue;
+                               pf->control[t].muted=1-pf->control[t].muted;
+                       }
+                       break;
+               default:
+                       if (arg1<pf->numchn)
+                               pf->control[arg1].muted=1-pf->control[arg1].muted;
+                       break;
+               }
+       }
+}
+
+MIKMODAPI void Player_ToggleMute(SLONG arg1,...)
+{
+       va_list args;
+
+       va_start(args,arg1);
+       MUTEX_LOCK(vars);
+       Player_ToggleMute_internal(arg1,args);
+       MUTEX_UNLOCK(vars);
+       va_end(args);
+}
+
+MIKMODAPI BOOL Player_Muted(UBYTE chan)
+{
+       BOOL result=1;
+
+       MUTEX_LOCK(vars);
+       if (pf)
+               result=(chan<pf->numchn)?pf->control[chan].muted:1;
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI int Player_GetChannelVoice(UBYTE chan)
+{
+       int result=0;
+
+       MUTEX_LOCK(vars);
+       if (pf)
+               result=(chan<pf->numchn)?pf->control[chan].slavechn:-1;
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan)
+{
+       UWORD result=0;
+
+       MUTEX_LOCK(vars);
+       if (pf)
+           result=(chan<pf->numchn)?pf->control[chan].main.period:0;
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+BOOL Player_Paused_internal(void)
+{
+       return pf?pf->forbid:1;
+}
+
+MIKMODAPI BOOL Player_Paused(void)
+{
+       BOOL result;
+
+       MUTEX_LOCK(vars);
+       result=Player_Paused_internal();
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI void Player_TogglePause(void)
+{
+       MUTEX_LOCK(vars);
+       if (pf)
+               pf->forbid=1-pf->forbid;
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetSpeed(UWORD speed)
+{
+       MUTEX_LOCK(vars);
+       if (pf)
+               pf->sngspd=speed?(speed<32?speed:32):1;
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetTempo(UWORD tempo)
+{
+       if (tempo<32) tempo=32;
+       MUTEX_LOCK(vars);
+       if (pf) {
+               if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255;
+               pf->bpm=tempo;
+       }
+       MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo)
+{
+       int i;
+
+       if (numvoices > md_sngchn)
+               numvoices = md_sngchn;
+
+       MUTEX_LOCK(vars);
+       if (pf)
+               for (i = 0; i < md_sngchn; i++) {
+                       vinfo [i].i = pf->voice[i].main.i;
+                       vinfo [i].s = pf->voice[i].main.s;
+                       vinfo [i].panning = pf->voice [i].main.panning;
+                       vinfo [i].volume = pf->voice [i].main.chanvol;
+                       vinfo [i].period = pf->voice [i].main.period;
+                       vinfo [i].kick = pf->voice [i].main.kick_flag;
+                       pf->voice [i].main.kick_flag = 0;
+               }
+       MUTEX_UNLOCK(vars);
+
+       return numvoices;
+}
+
+/* Get current module order */
+MIKMODAPI int Player_GetOrder(void)
+{
+       int ret;
+       MUTEX_LOCK(vars);
+       ret = pf ? pf->sngpos :0; /* pf->positions[pf->sngpos ? pf->sngpos-1 : 0]: 0; */
+       MUTEX_UNLOCK(vars);
+       return ret;
+}
+
+/* Get current module row */
+MIKMODAPI int Player_GetRow(void)
+{
+       int ret;
+       MUTEX_LOCK(vars);
+       ret = pf ? pf->patpos : 0;
+       MUTEX_UNLOCK(vars);
+       return ret;
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/munitrk.c b/libs/mikmod/playercode/munitrk.c
new file mode 100644 (file)
index 0000000..349038c
--- /dev/null
@@ -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$
+
+  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
+
+const 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*)MikMod_realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE));
+
+               /* Check if MikMod_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(const UBYTE* a,const 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)
+{
+       void *d;
+
+       if (!UniExpand(unipc-unitt)) return NULL;
+       unibuf[unitt] = 0;
+
+       if(!(d=MikMod_malloc(unipc))) return NULL;
+       memcpy(d,unibuf,unipc);
+
+       return (UBYTE *)d;
+}
+
+BOOL UniInit(void)
+{
+       unimax = BUFPAGE;
+
+       if(!(unibuf=(UBYTE*)MikMod_malloc(unimax*sizeof(UBYTE)))) return 0;
+       return 1;
+}
+
+void UniCleanup(void)
+{
+       MikMod_free(unibuf);
+       unibuf = NULL;
+}
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/mwav.c b/libs/mikmod/playercode/mwav.c
new file mode 100644 (file)
index 0000000..6f2394f
--- /dev/null
@@ -0,0 +1,388 @@
+/*     MikMod sound library
+       (c) 2004, Raphael Assenat
+       (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.
+*/
+
+/*==============================================================================
+
+  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
+
+static void extract_channel(const char *src, char *dst, int num_chan, int num_samples, int samp_size, int channel);
+
+
+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;
+
+static BOOL isWaveFile(MREADER* reader)
+{
+       WAV wh;
+
+       _mm_fseek(reader, SEEK_SET, 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)) {
+               return 0;
+       }
+       return 1;
+}
+
+static SAMPLE* Sample_LoadGeneric_internal_wav(MREADER* reader)
+{
+       SAMPLE *si=NULL;
+       WAV wh;
+       BOOL have_fmt=0;
+
+       _mm_fseek(reader, SEEK_SET, 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*)MikMod_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;
+}
+
+static SAMPLE* Sample_LoadRawGeneric_internal(MREADER* reader, ULONG rate, ULONG channel, ULONG flags)
+{
+       SAMPLE *si;
+       long len;
+       int samp_size=1;
+
+       if(!(si=(SAMPLE*)MikMod_malloc(sizeof(SAMPLE)))) return NULL;
+
+       /* length */
+       _mm_fseek(reader, 0, SEEK_END);
+       len = _mm_ftell(reader);
+
+       si->panning = PAN_CENTER;
+       si->speed = rate/1;
+       si->volume = 64;
+       si->length = len;
+       si->loopstart=0;
+       si->loopend = len;
+       si->susbegin = 0;
+       si->susend = 0;
+       si->inflags = si->flags = flags;
+       if (si->flags & SF_16BITS) {
+               si->length >>= 1;
+               si->loopstart >>= 1;
+               si->loopend >>= 1;
+               samp_size = 2;
+       }
+
+       if (si->flags & SF_STEREO)
+       {
+               char *data, *channel_data;
+               int num_samp = si->length/samp_size/2;
+               MREADER *chn_reader;
+
+               data = (char*)MikMod_malloc(si->length);
+               if (!data) { MikMod_free(si); return NULL; }
+
+               channel_data = (char*)MikMod_malloc(si->length/2);
+               if (!channel_data) { MikMod_free(data); MikMod_free(si); return NULL; }
+
+               /* load the raw samples completely, and fully extract the
+                * requested channel. Create a memory reader pointing to
+                * the channel data. */
+               _mm_fseek(reader, 0, SEEK_SET);
+               reader->Read(reader, data, si->length);
+
+               extract_channel(data, channel_data, 2, num_samp, samp_size, channel);
+               chn_reader = _mm_new_mem_reader(channel_data, num_samp * samp_size);
+               if (!chn_reader) {
+                       MikMod_free(channel_data);
+                       MikMod_free(data);
+                       MikMod_free(si);
+                       return NULL;
+               }
+
+               /* half of the samples were in the other channel */
+               si->loopstart=0;
+               si->length=num_samp;
+               si->loopend=num_samp;
+
+               SL_RegisterSample(si, MD_SNDFX, chn_reader);
+               SL_LoadSamples();
+
+               _mm_delete_mem_reader(chn_reader);
+               MikMod_free(channel_data);
+               MikMod_free(data);
+
+               return si;
+       }
+
+       _mm_fseek(reader, 0, SEEK_SET);
+       SL_RegisterSample(si, MD_SNDFX, reader);
+       SL_LoadSamples();
+
+       return si;
+}
+
+static SAMPLE* Sample_LoadGeneric_internal(MREADER* reader, const char *options)
+{
+       if (isWaveFile(reader)) {
+               return Sample_LoadGeneric_internal_wav(reader);
+       }
+
+       return NULL;
+}
+
+MIKMODAPI SAMPLE* Sample_LoadRawGeneric(MREADER* reader, ULONG rate, ULONG channel, ULONG flags)
+{
+       SAMPLE* result;
+
+       MUTEX_LOCK(vars);
+       result = Sample_LoadRawGeneric_internal(reader, rate, channel, flags);
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI SAMPLE *Sample_LoadRawMem(const char *buf, int len, ULONG rate, ULONG channel, ULONG flags)
+{
+       SAMPLE *result=NULL;
+       MREADER *reader;
+
+       if (!buf || len <= 0) return NULL;
+       if ((reader=_mm_new_mem_reader(buf, len)) != NULL) {
+               result=Sample_LoadRawGeneric(reader, rate, channel, flags);
+               _mm_delete_mem_reader(reader);
+       }
+       return result;
+}
+
+MIKMODAPI SAMPLE* Sample_LoadRawFP(FILE *fp, ULONG rate, ULONG channel, ULONG flags)
+{
+       SAMPLE* result=NULL;
+       MREADER* reader;
+
+       if(fp && (reader=_mm_new_file_reader(fp)) != NULL) {
+               result=Sample_LoadRawGeneric(reader, rate, channel, flags);
+               _mm_delete_file_reader(reader);
+       }
+       return result;
+}
+
+MIKMODAPI SAMPLE* Sample_LoadRaw(const CHAR* filename, ULONG rate, ULONG channel, ULONG flags)
+{
+       FILE *fp;
+       SAMPLE *si=NULL;
+
+       if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;
+       if((fp=_mm_fopen(filename,"rb")) != NULL) {
+               si = Sample_LoadRawFP(fp, rate, channel, flags);
+               _mm_fclose(fp);
+       }
+       return si;
+}
+
+MIKMODAPI SAMPLE* Sample_LoadGeneric(MREADER* reader)
+{
+       SAMPLE* result;
+
+       MUTEX_LOCK(vars);
+       result=Sample_LoadGeneric_internal(reader, NULL);
+       MUTEX_UNLOCK(vars);
+
+       return result;
+}
+
+MIKMODAPI SAMPLE *Sample_LoadMem(const char *buf, int len)
+{
+       SAMPLE* result=NULL;
+       MREADER* reader;
+
+       if (!buf || len <= 0) return NULL;
+       if ((reader=_mm_new_mem_reader(buf, len)) != NULL) {
+               result=Sample_LoadGeneric(reader);
+               _mm_delete_mem_reader(reader);
+       }
+       return result;
+}
+
+MIKMODAPI SAMPLE* Sample_LoadFP(FILE *fp)
+{
+       SAMPLE* result=NULL;
+       MREADER* reader;
+
+       if(fp && (reader=_mm_new_file_reader(fp)) != NULL) {
+               result=Sample_LoadGeneric(reader);
+               _mm_delete_file_reader(reader);
+       }
+       return result;
+}
+
+MIKMODAPI SAMPLE* Sample_Load(const CHAR* filename)
+{
+       FILE *fp;
+       SAMPLE *si=NULL;
+
+       if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL;
+       if((fp=_mm_fopen(filename,"rb")) != NULL) {
+               si = Sample_LoadFP(fp);
+               _mm_fclose(fp);
+       }
+       return si;
+}
+
+MIKMODAPI void Sample_Free(SAMPLE* si)
+{
+       if(si) {
+               if (si->onfree) si->onfree(si->ctx);
+               MD_SampleUnload(si->handle);
+               MikMod_free(si);
+       }
+}
+
+void Sample_Free_internal(SAMPLE *si)
+{
+       MUTEX_LOCK(vars);
+       Sample_Free(si);
+       MUTEX_UNLOCK(vars);
+}
+
+static void extract_channel(const char *src, char *dst, int num_chan, int num_samples, int samp_size, int channel)
+{
+       int i;
+#ifdef MIKMOD_DEBUG
+       fprintf(stderr,"Extract channel: %p %p, num_chan=%d, num_samples=%d, samp_size=%d, channel=%d\n",
+               src,dst,num_chan,num_samples,samp_size,channel);
+#endif
+       src += channel * samp_size;
+
+       while (num_samples--)
+       {
+               for (i=0; i<samp_size; i++) {
+                       dst[i] = src[i];
+               }
+               src += samp_size * num_chan;
+               dst += samp_size;
+       }
+}
+
+/* ex:set ts=8: */
diff --git a/libs/mikmod/playercode/npertab.c b/libs/mikmod/playercode/npertab.c
new file mode 100644 (file)
index 0000000..b106b2a
--- /dev/null
@@ -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$
+
+  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"
+
+const 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: */
+
diff --git a/libs/mikmod/playercode/sloader.c b/libs/mikmod/playercode/sloader.c
new file mode 100644 (file)
index 0000000..30e9675
--- /dev/null
@@ -0,0 +1,522 @@
+/*     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$
+
+  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=(SWORD*)MikMod_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);
+
+       MikMod_free(sl_buffer);
+       sl_buffer=NULL;
+}
+
+/* unpack a 8bit IT packed sample */
+static int read_itcompr8(ITPACK* status,MREADER *reader,SWORD *out,UWORD count,UWORD* incnt)
+{
+       SWORD *dest=out,*end=out+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-out);
+}
+
+/* unpack a 16bit IT packed sample */
+static int read_itcompr16(ITPACK *status,MREADER *reader,SWORD *out,UWORD count,UWORD* incnt)
+{
+       SWORD *dest=out,*end=out+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-=(UWORD)y;
+                       needbits-=(UWORD)y;
+                       havebits+=(UWORD)y;
+               }
+               if (new_count) {
+                       new_count = 0;
+                       if (++x >= bits)
+                               x++;
+                       bits = (UWORD)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 = (UWORD)x;
+                               continue;
+                       }
+               }
+               else if (bits<18) {
+                       if (x>=0x10000) {
+                               bits=(UWORD)(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-out);
+}
+
+static int 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 = 0;
+
+       status.buf = 0;
+       status.last = 0;
+       status.bufbits = 0;
+       status.bits = 0;
+
+       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++]=(UWORD)(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++]=(SWORD)(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;
+}
+
+int 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*)MikMod_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;
+               MikMod_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 int DitherSamples(SAMPLOAD* samplist,int type)
+{
+       SAMPLOAD *c2smp=NULL;
+       ULONG maxsize, speed;
+       SAMPLOAD *s;
+
+       if(!samplist) return 0;
+
+       if((maxsize=MD_SampleSpace(type)*1024) != 0)
+               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;
+}
+
+int SL_LoadSamples(void)
+{
+       int rc;
+
+       _mm_critical = 0;
+
+       if((!musiclist)&&(!sndfxlist)) return 0;
+       rc=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);
+       musiclist=sndfxlist=NULL;
+
+       return rc;
+}
+
+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: */
diff --git a/libs/mikmod/playercode/virtch.c b/libs/mikmod/playercode/virtch.c
new file mode 100644 (file)
index 0000000..9342978
--- /dev/null
@@ -0,0 +1,1351 @@
+/*     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$
+
+  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
+
+#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
+
+#if defined HAVE_SSE2 || defined HAVE_ALTIVEC
+
+# if !defined(NATIVE_64BIT_INT)
+static SINTPTR_T MixSIMDMonoNormal(const SWORD* srce,SLONG* dest,SINTPTR_T idx,SINTPTR_T increment,SINTPTR_T todo)
+{
+       /* TODO: */
+       SWORD sample;
+       SLONG lvolsel = vnf->lvolsel;
+
+       while(todo--) {
+               sample = srce[idx >> FRACBITS];
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+       }
+       return idx;
+}
+# endif /* !NATIVE_64BIT_INT */
+
+static SINTPTR_T MixSIMDStereoNormal(const SWORD* srce,SLONG* dest,SINTPTR_T idx,SINTPTR_T increment,SINTPTR_T todo)
+{
+       SWORD vol[8] = {vnf->lvolsel, vnf->rvolsel};
+       SWORD sample;
+       SLONG remain = todo;
+
+       /* Dest can be misaligned */
+       while(!IS_ALIGNED_16(dest)) {
+               sample=srce[idx >> FRACBITS];
+               idx += increment;
+               *dest++ += vol[0] * sample;
+               *dest++ += vol[1] * sample;
+               todo--;
+               if(!todo) return idx;
+       }
+
+       /* Srce is always aligned */
+
+#if defined HAVE_SSE2
+       remain = todo&3;
+       {
+               __m128i v0 = _mm_set_epi16(0, vol[1],
+                                          0, vol[0],
+                                          0, vol[1],
+                                          0, vol[0]);
+               for(todo>>=2;todo; todo--)
+               {
+                       SWORD s0 = srce[idx >> FRACBITS];
+                       SWORD s1 = srce[(idx += increment) >> FRACBITS];
+                       SWORD s2 = srce[(idx += increment) >> FRACBITS];
+                       SWORD s3 = srce[(idx += increment) >> FRACBITS];
+                       __m128i v1 = _mm_set_epi16(0, s1, 0, s1, 0, s0, 0, s0);
+                       __m128i v2 = _mm_set_epi16(0, s3, 0, s3, 0, s2, 0, s2);
+                       __m128i v3 = _mm_load_si128((__m128i*)(dest+0));
+                       __m128i v4 = _mm_load_si128((__m128i*)(dest+4));
+                       _mm_store_si128((__m128i*)(dest+0), _mm_add_epi32(v3, _mm_madd_epi16(v0, v1)));
+                       _mm_store_si128((__m128i*)(dest+4), _mm_add_epi32(v4, _mm_madd_epi16(v0, v2)));
+                       dest+=8;
+                       idx += increment;
+               }
+       }
+
+#elif defined HAVE_ALTIVEC
+       remain = todo&3;
+       {
+               SWORD s[8];
+               vector signed short r0 = vec_ld(0, vol);
+               vector signed short v0 = vec_perm(r0, r0, (vector unsigned char)(0, 1, /* l */
+                                                                                0, 1, /* l */
+                                                                                2, 3, /* r */
+                                                                                2, 1, /* r */
+                                                                                0, 1, /* l */
+                                                                                0, 1, /* l */
+                                                                                2, 3, /* r */
+                                                                                2, 3  /* r */
+                                                                                ));
+
+               for(todo>>=2;todo; todo--)
+               {
+                       vector short int r1;
+                       vector signed short v1, v2;
+                       vector signed int v3, v4, v5, v6;
+
+                       /* Load constants */
+                       s[0] = srce[idx >> FRACBITS];
+                       s[1] = srce[(idx += increment) >> FRACBITS];
+                       s[2] = srce[(idx += increment) >> FRACBITS];
+                       s[3] = srce[(idx += increment) >> FRACBITS];
+                       s[4] = 0;
+
+                       r1 = vec_ld(0, s);
+                       v1 = vec_perm(r1, r1, (vector unsigned char)
+                                                               (0*2, 0*2+1, /* s0 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                0*2, 0*2+1, /* s0 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                1*2, 1*2+1, /* s1 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                1*2, 1*2+1, /* s1 */
+                                                                4*2, 4*2+1  /* 0  */
+                                                               ) );
+                       v2 = vec_perm(r1, r1, (vector unsigned char)
+                                                               (2*2, 2*2+1, /* s2 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                2*2, 2*2+1, /* s2 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                3*2, 3*2+1, /* s3 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                3*2, 3*2+1, /* s3 */
+                                                                4*2, 4*2+1  /* 0  */
+                                                               ) );
+
+                       v3 = vec_ld(0, dest);
+                       v4 = vec_ld(0, dest + 4);
+                       v5 = vec_mule(v0, v1);
+                       v6 = vec_mule(v0, v2);
+
+                       vec_st(vec_add(v3, v5), 0, dest);
+                       vec_st(vec_add(v4, v6), 0x10, dest);
+
+                       dest+=8;
+                       idx += increment;
+               }
+       }
+#endif /* HAVE_ALTIVEC */
+
+       /* Remaining bits */
+       while(remain--) {
+               sample=srce[idx >> FRACBITS];
+               idx += increment;
+
+               *dest++ += vol[0] * sample;
+               *dest++ += vol[1] * sample;
+       }
+       return idx;
+}
+#endif
+
+/*========== 32 bit sample mixers - only for 32 bit platforms */
+#ifndef NATIVE_64BIT_INT
+
+static SLONG Mix32MonoNormal(const SWORD* srce,SLONG* dest,SLONG idx,SLONG increment,SLONG todo)
+{
+#if defined HAVE_ALTIVEC || defined HAVE_SSE2
+       if (md_mode & DMODE_SIMDMIXER) {
+               return MixSIMDMonoNormal(srce, dest, idx, increment, todo);
+       }
+       else
+#endif
+       {
+               SWORD sample;
+               SLONG lvolsel = vnf->lvolsel;
+
+               while(todo--) {
+                       sample = srce[idx >> FRACBITS];
+                       idx += increment;
+
+                       *dest++ += lvolsel * sample;
+               }
+       }
+       return idx;
+}
+
+/* FIXME: This mixer should works also on 64-bit platform */
+/* Hint : changes SLONG / SLONGLONG mess with intptr */
+static SLONG Mix32StereoNormal(const SWORD* srce,SLONG* dest,SLONG idx,SLONG increment,SLONG todo)
+{
+#if defined HAVE_ALTIVEC || defined HAVE_SSE2
+       if (md_mode & DMODE_SIMDMIXER) {
+               return MixSIMDStereoNormal(srce, dest, idx, increment, todo);
+       }
+       else
+#endif
+       {
+               SWORD sample;
+               SLONG lvolsel = vnf->lvolsel;
+               SLONG rvolsel = vnf->rvolsel;
+
+               while(todo--) {
+                       sample=srce[idx >> FRACBITS];
+                       idx += increment;
+
+                       *dest++ += lvolsel * sample;
+                       *dest++ += rvolsel * sample;
+               }
+       }
+       return idx;
+}
+
+static SLONG Mix32SurroundNormal(const SWORD* srce,SLONG* dest,SLONG idx,SLONG increment,SLONG todo)
+{
+       SWORD sample;
+       SLONG lvolsel = vnf->lvolsel;
+       SLONG rvolsel = vnf->rvolsel;
+
+       if (lvolsel>=rvolsel) {
+               while(todo--) {
+                       sample = srce[idx >> FRACBITS];
+                       idx += increment;
+
+                       *dest++ += lvolsel*sample;
+                       *dest++ -= lvolsel*sample;
+               }
+       }
+       else {
+               while(todo--) {
+                       sample = srce[idx >> FRACBITS];
+                       idx += increment;
+
+                       *dest++ -= rvolsel*sample;
+                       *dest++ += rvolsel*sample;
+               }
+       }
+       return idx;
+}
+
+static SLONG Mix32MonoInterp(const SWORD* srce,SLONG* dest,SLONG idx,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[idx>>FRACBITS]+
+                               ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                                *(idx&FRACMASK)>>FRACBITS);
+                       idx += increment;
+
+                       *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
+                                          * sample >> CLICK_SHIFT;
+                       if (!--rampvol)
+                               break;
+               }
+               vnf->rampvol = rampvol;
+               if (todo < 0)
+                       return idx;
+       }
+
+       while(todo--) {
+               sample=(SLONG)srce[idx>>FRACBITS]+
+                       ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                        *(idx&FRACMASK)>>FRACBITS);
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+       }
+       return idx;
+}
+
+static SLONG Mix32StereoInterp(const SWORD* srce,SLONG* dest,SLONG idx,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[idx>>FRACBITS]+
+                               ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                                *(idx&FRACMASK)>>FRACBITS);
+                       idx += 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 idx;
+       }
+
+       while(todo--) {
+               sample=(SLONG)srce[idx>>FRACBITS]+
+                       ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                        *(idx&FRACMASK)>>FRACBITS);
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+               *dest++ += rvolsel * sample;
+       }
+       return idx;
+}
+
+static SLONG Mix32SurroundInterp(const SWORD* srce,SLONG* dest,SLONG idx,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[idx>>FRACBITS]+
+                               ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                                *(idx&FRACMASK)>>FRACBITS);
+                       idx += increment;
+
+                       sample=((vol << CLICK_SHIFT) + oldvol * rampvol)
+                                          * sample >> CLICK_SHIFT;
+                       *dest++ += sample;
+                       *dest++ -= sample;
+
+                       if (!--rampvol)
+                               break;
+               }
+               vnf->rampvol = rampvol;
+               if (todo < 0)
+                       return idx;
+       }
+
+       while(todo--) {
+               sample=(SLONG)srce[idx>>FRACBITS]+
+                       ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                        *(idx&FRACMASK)>>FRACBITS);
+               idx += increment;
+
+               *dest++ += vol*sample;
+               *dest++ -= vol*sample;
+       }
+       return idx;
+}
+#endif
+
+/*========== 64 bit sample mixers - all platforms */
+
+static SLONGLONG MixMonoNormal(const SWORD* srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,SLONG todo)
+{
+       SWORD sample;
+       SLONG lvolsel = vnf->lvolsel;
+
+       while(todo--) {
+               sample = srce[idx >> FRACBITS];
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+       }
+       return idx;
+}
+
+static SLONGLONG MixStereoNormal(const SWORD* srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,SLONG todo)
+{
+       SWORD sample;
+       SLONG lvolsel = vnf->lvolsel;
+       SLONG rvolsel = vnf->rvolsel;
+
+       while(todo--) {
+               sample=srce[idx >> FRACBITS];
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+               *dest++ += rvolsel * sample;
+       }
+       return idx;
+}
+
+static SLONGLONG MixSurroundNormal(const SWORD* srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,SLONG todo)
+{
+       SWORD sample;
+       SLONG lvolsel = vnf->lvolsel;
+       SLONG rvolsel = vnf->rvolsel;
+
+       if(vnf->lvolsel>=vnf->rvolsel) {
+               while(todo--) {
+                       sample = srce[idx >> FRACBITS];
+                       idx += increment;
+
+                       *dest++ += lvolsel*sample;
+                       *dest++ -= lvolsel*sample;
+               }
+       }
+       else {
+               while(todo--) {
+                       sample = srce[idx >> FRACBITS];
+                       idx += increment;
+
+                       *dest++ -= rvolsel*sample;
+                       *dest++ += rvolsel*sample;
+               }
+       }
+       return idx;
+}
+
+static SLONGLONG MixMonoInterp(const SWORD* srce,SLONG* dest,SLONGLONG idx,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[idx>>FRACBITS]+
+                               ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                                *(idx&FRACMASK)>>FRACBITS);
+                       idx += increment;
+
+                       *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
+                                          * sample >> CLICK_SHIFT;
+                       if (!--rampvol)
+                               break;
+               }
+               vnf->rampvol = rampvol;
+               if (todo < 0)
+                       return idx;
+       }
+
+       while(todo--) {
+               sample=(SLONG)srce[idx>>FRACBITS]+
+                       ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                        *(idx&FRACMASK)>>FRACBITS);
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+       }
+       return idx;
+}
+
+static SLONGLONG MixStereoInterp(const SWORD* srce,SLONG* dest,SLONGLONG idx,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[idx>>FRACBITS]+
+                               ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                                *(idx&FRACMASK)>>FRACBITS);
+                       idx += 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 idx;
+       }
+
+       while(todo--) {
+               sample=(SLONG)srce[idx>>FRACBITS]+
+                       ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                        *(idx&FRACMASK)>>FRACBITS);
+               idx += increment;
+
+               *dest++ += lvolsel * sample;
+               *dest++ += rvolsel * sample;
+       }
+       return idx;
+}
+
+static SLONGLONG MixSurroundInterp(const SWORD* srce,SLONG* dest,SLONGLONG idx,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[idx>>FRACBITS]+
+                               ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                                *(idx&FRACMASK)>>FRACBITS);
+                       idx += increment;
+
+                       sample=((vol << CLICK_SHIFT) + oldvol * rampvol)
+                                          * sample >> CLICK_SHIFT;
+                       *dest++ += sample;
+                       *dest++ -= sample;
+                       if (!--rampvol)
+                               break;
+               }
+               vnf->rampvol = rampvol;
+               if (todo < 0)
+                       return idx;
+       }
+
+       while(todo--) {
+               sample=(SLONG)srce[idx>>FRACBITS]+
+                       ((SLONG)(srce[(idx>>FRACBITS)+1]-srce[idx>>FRACBITS])
+                        *(idx&FRACMASK)>>FRACBITS);
+               idx += increment;
+
+               *dest++ += vol*sample;
+               *dest++ -= vol*sample;
+       }
+       return idx;
+}
+
+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];
+       }
+}
+
+static void (*MixLowPass)(SLONG* srce,NATIVE count);
+
+static int nLeftNR, nRightNR;
+
+static void MixLowPass_Stereo(SLONG* srce,NATIVE count)
+{
+       int n1 = nLeftNR, n2 = nRightNR;
+       SLONG *pnr = srce;
+       int nr=count;
+       for (; nr; nr--)
+       {
+               int vnr = pnr[0] >> 1;
+               pnr[0] = vnr + n1;
+               n1 = vnr;
+               vnr = pnr[1] >> 1;
+               pnr[1] = vnr + n2;
+               n2 = vnr;
+               pnr += 2;
+       }
+       nLeftNR = n1;
+       nRightNR = n2;
+}
+
+static void MixLowPass_Normal(SLONG* srce,NATIVE count)
+{
+       int n1 = nLeftNR;
+       SLONG *pnr = srce;
+       int nr=count;
+       for (; nr; nr--)
+       {
+               int vnr = pnr[0] >> 1;
+               pnr[0] = vnr + n1;
+               n1 = vnr;
+               pnr ++;
+       }
+       nLeftNR = n1;
+}
+
+/* shifting fudge factor for FP scaling, should be 0 < FP_SHIFT < BITSHIFT */
+#define FP_SHIFT 4
+
+/* 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,const SLONG *srce,NATIVE count)
+{
+       float x1,x2,x3,x4;
+       int     remain;
+
+       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,const 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,const 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);
+       }
+}
+
+#if defined HAVE_ALTIVEC || defined HAVE_SSE2
+
+/* Mix 32bit input to floating point. 32 samples per iteration */
+/* PC: ?, Mac OK */
+static void Mix32ToFP_SIMD(float* dste,const SLONG* srce,NATIVE count)
+{
+       const float k = ((1.0f / 32768.0f) / (1 << FP_SHIFT));
+       int     remain=count;
+       simd_m128 x1, x2, xk;
+
+       while(!IS_ALIGNED_16(dste) || !IS_ALIGNED_16(srce))
+       {
+               float xf;
+               EXTRACT_SAMPLE_FP(xf,FP_SHIFT);
+               CHECK_SAMPLE_FP(xf,1.0f);
+               PUT_SAMPLE_FP(xf);
+               count--;
+               if (!count) return;
+       }
+
+       remain = count&7;
+
+       xk = LOAD_PS1_SIMD(&k); /* Scale factor */
+
+       for(count>>=3;count;count--) {
+               EXTRACT_SAMPLE_SIMD_F(srce, x1, FP_SHIFT, xk);  /* Load 4 samples */
+               EXTRACT_SAMPLE_SIMD_F(srce+4, x2, FP_SHIFT, xk);  /* Load 4 samples */
+               PUT_SAMPLE_SIMD_F(dste, x1); /* Store 4 samples */
+               PUT_SAMPLE_SIMD_F(dste+4, x2); /* Store 4 samples */
+               srce+=8;
+               dste+=8;
+       }
+
+       if (remain&4) {
+               EXTRACT_SAMPLE_SIMD_F(srce, x1, FP_SHIFT, xk);  /* Load 4 samples */
+               PUT_SAMPLE_SIMD_F(dste, x1); /* Store 4 samples */
+               srce+=4;
+               dste+=4;
+               remain &= 3;
+       }
+
+       while(remain--) {
+               float xf;
+               EXTRACT_SAMPLE_FP(xf,FP_SHIFT);
+               CHECK_SAMPLE_FP(xf,1.0f);
+               PUT_SAMPLE_FP(xf);
+       }
+}
+
+/* PC: Ok, Mac Ok */
+static void Mix32To16_SIMD(SWORD* dste,const SLONG* srce,NATIVE count)
+{
+       int     remain = count;
+
+       while(!IS_ALIGNED_16(dste) || !IS_ALIGNED_16(srce))
+       {
+               SLONG x1;
+               EXTRACT_SAMPLE(x1,16);
+               CHECK_SAMPLE(x1,32768);
+               PUT_SAMPLE(x1);
+               count--;
+               if (!count) return;
+       }
+
+       remain = count&7;
+
+       for(count>>=3;count;count--)
+       {
+               simd_m128i x1,x2;
+               EXTRACT_SAMPLE_SIMD_16(srce, x1);  /* Load 4 samples */
+               EXTRACT_SAMPLE_SIMD_16(srce+4, x2);  /* Load 4 samples */
+               PUT_SAMPLE_SIMD_W(dste, x1, x2);  /* Store 8 samples */
+               srce+=8;
+               dste+=8;
+       }
+
+       if (remain)
+               Mix32To16(dste, srce, remain);
+}
+
+/* Mix 32bit input to 8bit. 128 samples per iteration */
+/* PC:OK, Mac: Ok */
+static void Mix32To8_SIMD(SBYTE* dste,const SLONG* srce,NATIVE count)
+{
+       int     remain=count;
+
+       while(!IS_ALIGNED_16(dste) || !IS_ALIGNED_16(srce))
+       {
+               SWORD x1;
+               EXTRACT_SAMPLE(x1,8);
+               CHECK_SAMPLE(x1,128);
+               PUT_SAMPLE(x1+128);
+               count--;
+               if (!count) return;
+       }
+
+       remain = count&15;
+
+       for(count>>=4;count;count--) {
+               simd_m128i x1,x2,x3,x4;
+               EXTRACT_SAMPLE_SIMD_8(srce, x1);  /* Load 4 samples */
+               EXTRACT_SAMPLE_SIMD_8(srce+4, x2);  /* Load 4 samples */
+               EXTRACT_SAMPLE_SIMD_8(srce+8, x3);  /* Load 4 samples */
+               EXTRACT_SAMPLE_SIMD_8(srce+12, x4);  /* Load 4 samples */
+               PUT_SAMPLE_SIMD_B(dste, x1, x2, x3, x4); /* Store 16 samples */
+               srce+=16;
+               dste+=16;
+       }
+
+       if (remain)
+               Mix32To8(dste, srce, remain);
+}
+
+#endif
+
+
+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
+                                       {
+#if defined HAVE_ALTIVEC || defined HAVE_SSE2
+                                           if (md_mode & DMODE_SIMDMIXER)
+                                               vnf->current=MixSIMDStereoNormal
+                                                                  (s,ptr,vnf->current,vnf->increment,done);
+                                           else
+#endif
+                                               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
+                                       {
+#if defined HAVE_ALTIVEC || defined HAVE_SSE2
+                                           if (md_mode & DMODE_SIMDMIXER)
+                                               vnf->current=MixSIMDStereoNormal
+                                                                  (s,ptr,vnf->current,vnf->increment,done);
+                                           else
+#endif
+                                               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;
+       }
+}
+
+#ifdef NO_HQMIXER
+#define VC_SetupPointers() do{}while(0)
+#define VC1_Init VC_Init
+#define VC1_Exit VC_Exit
+#define VC1_PlayStart VC_PlayStart
+#define VC1_PlayStop VC_PlayStop
+#define VC1_SampleLength VC_SampleLength
+#define VC1_SampleSpace VC_SampleSpace
+#define VC1_SampleLoad VC_SampleLoad
+#define VC1_SampleUnload VC_SampleUnload
+#define VC1_SetNumVoices VC_SetNumVoices
+#define VC1_SilenceBytes VC_SilenceBytes
+#define VC1_VoicePlay VC_VoicePlay
+#define VC1_VoiceStop VC_VoiceStop
+#define VC1_VoiceGetFrequency VC_VoiceGetFrequency
+#define VC1_VoiceGetPanning VC_VoiceGetPanning
+#define VC1_VoiceGetPosition VC_VoiceGetPosition
+#define VC1_VoiceGetVolume VC_VoiceGetVolume
+#define VC1_VoiceRealVolume VC_VoiceRealVolume
+#define VC1_VoiceSetFrequency VC_VoiceSetFrequency
+#define VC1_VoiceSetPanning VC_VoiceSetPanning
+#define VC1_VoiceSetVolume VC_VoiceSetVolume
+#define VC1_VoiceStopped VC_VoiceStopped
+#define VC1_WriteBytes VC_WriteBytes
+#define VC1_WriteSamples VC_WriteSamples
+#endif
+
+#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_mode & DMODE_NOISEREDUCTION) {
+                               MixLowPass(vc_tickbuf, portion);
+                       }
+
+                       if(md_reverb) {
+                               if(md_reverb>15) md_reverb=15;
+                               MixReverb(vc_tickbuf, portion);
+                       }
+
+                       if (vc_callback) {
+                               vc_callback((unsigned char*)vc_tickbuf, portion);
+                       }
+
+#if defined HAVE_ALTIVEC || defined HAVE_SSE2
+                       if (md_mode & DMODE_SIMDMIXER)
+                       {
+                               if(vc_mode & DMODE_FLOAT)
+                                       Mix32ToFP_SIMD((float*) buffer, vc_tickbuf, count);
+                               else if(vc_mode & DMODE_16BITS)
+                                       Mix32To16_SIMD((SWORD*) buffer, vc_tickbuf, count);
+                               else
+                                       Mix32To8_SIMD((SBYTE*) buffer, vc_tickbuf, count);
+                       }
+                       else
+#endif
+                       {
+                               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;
+               }
+       }
+}
+
+int VC1_Init(void)
+{
+#ifndef NO_HQMIXER
+       VC_SetupPointers();
+
+       if (md_mode&DMODE_HQMIXER)
+               return VC2_Init();
+#endif
+
+       if(!(Samples=(SWORD**)MikMod_amalloc(MAXSAMPLEHANDLES*sizeof(SWORD*)))) {
+               _mm_errno = MMERR_INITIALIZING_MIXER;
+               return 1;
+       }
+       if(!vc_tickbuf) {
+               if(!(vc_tickbuf=(SLONG*)MikMod_amalloc((TICKLSIZE+32)*sizeof(SLONG)))) {
+                       _mm_errno = MMERR_INITIALIZING_MIXER;
+                       return 1;
+               }
+       }
+
+       MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal;
+       MixLowPass=(md_mode&DMODE_STEREO)?MixLowPass_Stereo:MixLowPass_Normal;
+       vc_mode = md_mode;
+       return 0;
+}
+
+int 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*)MikMod_calloc((RVc1+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL2=(SLONG*)MikMod_calloc((RVc2+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL3=(SLONG*)MikMod_calloc((RVc3+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL4=(SLONG*)MikMod_calloc((RVc4+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL5=(SLONG*)MikMod_calloc((RVc5+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL6=(SLONG*)MikMod_calloc((RVc6+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL7=(SLONG*)MikMod_calloc((RVc7+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL8=(SLONG*)MikMod_calloc((RVc8+1),sizeof(SLONG)))) return 1;
+
+       /* allocate reverb buffers for the right channel if in stereo mode only. */
+       if (vc_mode & DMODE_STEREO) {
+               if(!(RVbufR1=(SLONG*)MikMod_calloc((RVc1+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR2=(SLONG*)MikMod_calloc((RVc2+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR3=(SLONG*)MikMod_calloc((RVc3+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR4=(SLONG*)MikMod_calloc((RVc4+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR5=(SLONG*)MikMod_calloc((RVc5+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR6=(SLONG*)MikMod_calloc((RVc6+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR7=(SLONG*)MikMod_calloc((RVc7+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR8=(SLONG*)MikMod_calloc((RVc8+1),sizeof(SLONG)))) return 1;
+       }
+
+       RVRindex = 0;
+       return 0;
+}
+
+void VC1_PlayStop(void)
+{
+       MikMod_free(RVbufL1);
+       MikMod_free(RVbufL2);
+       MikMod_free(RVbufL3);
+       MikMod_free(RVbufL4);
+       MikMod_free(RVbufL5);
+       MikMod_free(RVbufL6);
+       MikMod_free(RVbufL7);
+       MikMod_free(RVbufL8);
+       RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
+       MikMod_free(RVbufR1);
+       MikMod_free(RVbufR2);
+       MikMod_free(RVbufR3);
+       MikMod_free(RVbufR4);
+       MikMod_free(RVbufR5);
+       MikMod_free(RVbufR6);
+       MikMod_free(RVbufR7);
+       MikMod_free(RVbufR8);
+       RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
+}
+
+int VC1_SetNumVoices(void)
+{
+       int t;
+
+       if(!(vc_softchn=md_softchn)) return 0;
+
+       MikMod_free(vinf);
+       if(!(vinf=(VINFO*)MikMod_calloc(vc_softchn,sizeof(VINFO)))) 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: */
diff --git a/libs/mikmod/playercode/virtch2.c b/libs/mikmod/playercode/virtch2.c
new file mode 100644 (file)
index 0000000..6b9807d
--- /dev/null
@@ -0,0 +1,1368 @@
+/*     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$
+
+  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
+
+#ifndef NO_HQMIXER
+
+#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 BITSHIFT 9
+#define MAXVOL_FACTOR (1<<BITSHIFT)
+#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;
+
+#ifdef _MSC_VER
+/* Weird bug in compiler */ /* FIXME is this still needed? */
+typedef void (*MikMod_callback_t)(unsigned char *data, size_t len);
+#endif
+
+/* 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(const SWORD* const srce,SLONG* dest,SLONG idx,SLONG increment,SLONG todo)
+{
+       SWORD sample=0;
+       SLONG i,f;
+
+       while(todo--) {
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)( (((SLONG)(srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONG)srce[i+1]*f)) >> FRACBITS));
+               idx+=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 idx;
+}
+
+static SLONG Mix32StereoNormal(const SWORD* const srce,SLONG* dest,SLONG idx,SLONG increment,ULONG todo)
+{
+       SWORD sample=0;
+       SLONG i,f;
+
+       while(todo--) {
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)(((((SLONG)srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONG)srce[i+1] * f)) >> FRACBITS));
+               idx += 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 idx;
+}
+
+static SLONG Mix32StereoSurround(const SWORD* const srce,SLONG* dest,SLONG idx,SLONG increment,ULONG todo)
+{
+       SWORD sample=0;
+       long whoop;
+       SLONG i, f;
+
+       while(todo--) {
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)(((((SLONG)srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONG)srce[i+1]*f)) >> FRACBITS));
+               idx+=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 idx;
+}
+#endif
+
+/*========== 64 bit mixers */
+
+static SLONGLONG MixMonoNormal(const SWORD* const srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,SLONG todo)
+{
+       SWORD sample=0;
+       SLONGLONG i,f;
+
+       while(todo--) {
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)((((SLONGLONG)(srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONGLONG)srce[i+1]*f)) >> FRACBITS));
+               idx+=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 idx;
+}
+
+/* Slowest part... */
+
+#if defined HAVE_SSE2 || defined HAVE_ALTIVEC
+
+static __inline SWORD GetSample(const SWORD* const srce, SLONGLONG idx)
+{
+       SLONGLONG i=idx>>FRACBITS;
+       SLONGLONG f=idx&FRACMASK;
+       return (SWORD)(((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
+                               ((SLONGLONG)srce[i+1] * f)) >> FRACBITS));
+}
+
+static SLONGLONG MixSIMDStereoNormal(const SWORD* const srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,ULONG todo)
+{
+       SWORD vol[8] = {vnf->lvolsel, vnf->rvolsel};
+       SWORD sample=0;
+       SLONG remain = todo;
+
+       /* Dest can be misaligned */
+       while(!IS_ALIGNED_16(dest)) {
+               sample=srce[idx >> FRACBITS];
+               idx += increment;
+               *dest++ += vol[0] * sample;
+               *dest++ += vol[1] * sample;
+               todo--;
+               if(!todo) goto end;
+       }
+
+       /* Srce is always aligned */
+
+#if defined HAVE_SSE2
+       remain = todo&3;
+       {
+               __m128i v0 = _mm_set_epi16(0, vol[1],
+                                          0, vol[0],
+                                          0, vol[1],
+                                          0, vol[0]);
+               for(todo>>=2;todo; todo--)
+               {
+                       SWORD s0 = GetSample(srce, idx);
+                       SWORD s1 = GetSample(srce, idx += increment);
+                       SWORD s2 = GetSample(srce, idx += increment);
+                       SWORD s3 = GetSample(srce, idx += increment);
+                       __m128i v1 = _mm_set_epi16(0, s1, 0, s1, 0, s0, 0, s0);
+                       __m128i v2 = _mm_set_epi16(0, s3, 0, s3, 0, s2, 0, s2);
+                       __m128i v3 = _mm_load_si128((__m128i*)(dest+0));
+                       __m128i v4 = _mm_load_si128((__m128i*)(dest+4));
+                       _mm_store_si128((__m128i*)(dest+0), _mm_add_epi32(v3, _mm_madd_epi16(v0, v1)));
+                       _mm_store_si128((__m128i*)(dest+4), _mm_add_epi32(v4, _mm_madd_epi16(v0, v2)));
+                       dest+=8;
+                       idx += increment;
+               }
+       }
+
+#elif defined HAVE_ALTIVEC
+       remain = todo&3;
+       {
+               SWORD s[8];
+               vector signed short r0 = vec_ld(0, vol);
+               vector signed short v0 = vec_perm(r0, r0, (vector unsigned char)(0, 1, /* l */
+                                                                                0, 1, /* l */
+                                                                                2, 3, /* r */
+                                                                                2, 1, /* r */
+                                                                                0, 1, /* l */
+                                                                                0, 1, /* l */
+                                                                                2, 3, /* r */
+                                                                                2, 3  /* r */
+                                                                                ));
+
+               for(todo>>=2;todo; todo--)
+               {
+                       vector short int r1;
+                       vector signed short v1, v2;
+                       vector signed int v3, v4, v5, v6;
+
+                       /* Load constants */
+                       s[0] = GetSample(srce, idx);
+                       s[1] = GetSample(srce, idx += increment);
+                       s[2] = GetSample(srce, idx += increment);
+                       s[3] = GetSample(srce, idx += increment);
+                       s[4] = 0;
+
+                       r1 = vec_ld(0, s);
+                       v1 = vec_perm(r1, r1, (vector unsigned char)
+                                                               (0*2, 0*2+1, /* s0 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                0*2, 0*2+1, /* s0 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                1*2, 1*2+1, /* s1 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                1*2, 1*2+1, /* s1 */
+                                                                4*2, 4*2+1  /* 0  */
+                                                               ) );
+                       v2 = vec_perm(r1, r1, (vector unsigned char)
+                                                               (2*2, 2*2+1, /* s2 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                2*2, 2*2+1, /* s2 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                3*2, 3*2+1, /* s3 */
+                                                                4*2, 4*2+1, /* 0  */
+                                                                3*2, 3*2+1, /* s3 */
+                                                                4*2, 4*2+1  /* 0  */
+                                                               ) );
+
+                       v3 = vec_ld(0, dest);
+                       v4 = vec_ld(0x10, dest);
+                       v5 = vec_mule(v0, v1);
+                       v6 = vec_mule(v0, v2);
+
+                       vec_st(vec_add(v3, v5), 0, dest);
+                       vec_st(vec_add(v4, v6), 0x10, dest);
+
+                       dest+=8;
+                       idx += increment;
+               }
+       }
+#endif /* HAVE_ALTIVEC */
+
+       /* Remaining bits */
+       while(remain--) {
+               sample=GetSample(srce, idx);
+               idx+= increment;
+               *dest++ += vol[0] * sample;
+               *dest++ += vol[1] * sample;
+       }
+end:
+       vnf->lastvalL=vnf->lvolsel*sample;
+       vnf->lastvalR=vnf->rvolsel*sample;
+       return idx;
+}
+
+static SLONGLONG MixStereoNormal(const SWORD* const srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,ULONG todo)
+{
+       SWORD sample=0;
+       SLONGLONG i,f;
+
+       if (vnf->rampvol)
+       while(todo) {
+               todo--;
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)(((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONGLONG)srce[i+1] * f)) >> FRACBITS));
+               idx += increment;
+
+               *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--;
+
+               if (!vnf->rampvol)
+                       break;
+       }
+
+       if (vnf->click)
+       while(todo) {
+               todo--;
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)(((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONGLONG)srce[i+1] * f)) >> FRACBITS));
+               idx += increment;
+
+               *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--;
+
+               if (!vnf->click)
+                       break;
+       }
+
+       if (todo)
+       {
+               if (md_mode & DMODE_SIMDMIXER) {
+                       return MixSIMDStereoNormal(srce, dest, idx, increment, todo);
+               }
+               while(todo)
+               {
+                       i=idx>>FRACBITS,
+                       f=idx&FRACMASK;
+                       sample=(SWORD)(((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
+                                                       ((SLONGLONG)srce[i+1] * f)) >> FRACBITS));
+                       idx += increment;
+
+                       *dest++ +=vnf->lvolsel*sample;
+                       *dest++ +=vnf->rvolsel*sample;
+                       todo--;
+               }
+       }
+       vnf->lastvalL=vnf->lvolsel*sample;
+       vnf->lastvalR=vnf->rvolsel*sample;
+
+       return idx;
+}
+
+#else /* HAVE_SSE2 || HAVE_ALTIVEC */
+static SLONGLONG MixStereoNormal(const SWORD* const srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,ULONG todo)
+{
+       SWORD sample=0;
+       SLONGLONG i,f;
+
+       while(todo--) {
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)(((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONGLONG)srce[i+1] * f)) >> FRACBITS));
+               idx += 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 idx;
+}
+#endif /* HAVE_SSE2 || HAVE_ALTIVEC */
+
+
+static SLONGLONG MixStereoSurround(const SWORD* srce,SLONG* dest,SLONGLONG idx,SLONGLONG increment,ULONG todo)
+{
+       SWORD sample=0;
+       long whoop;
+       SLONGLONG i, f;
+
+       while(todo--) {
+               i=idx>>FRACBITS,f=idx&FRACMASK;
+               sample=(SWORD)(((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +
+                       ((SLONGLONG)srce[i+1]*f)) >> FRACBITS));
+               idx+=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 idx;
+}
+
+static void(*Mix32toFP)(float* dste,const SLONG *srce,NATIVE count);
+static void(*Mix32to16)(SWORD* dste,const SLONG *srce,NATIVE count);
+static void(*Mix32to8)(SBYTE* dste,const 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];
+       }
+}
+
+static void (*MixLowPass)(SLONG* srce,NATIVE count);
+
+static int nLeftNR, nRightNR;
+
+static void MixLowPass_Stereo(SLONG* srce,NATIVE count)
+{
+       int n1 = nLeftNR, n2 = nRightNR;
+       SLONG *pnr = srce;
+       int nr=count;
+       for (; nr; nr--)
+       {
+               int vnr = pnr[0] >> 1;
+               pnr[0] = vnr + n1;
+               n1 = vnr;
+               vnr = pnr[1] >> 1;
+               pnr[1] = vnr + n2;
+               n2 = vnr;
+               pnr += 2;
+       }
+       nLeftNR = n1;
+       nRightNR = n2;
+}
+
+static void MixLowPass_Normal(SLONG* srce,NATIVE count)
+{
+       int n1 = nLeftNR;
+       SLONG *pnr = srce;
+       int nr=count;
+       for (; nr; nr--)
+       {
+               int vnr = pnr[0] >> 1;
+               pnr[0] = vnr + n1;
+               n1 = vnr;
+               pnr ++;
+       }
+       nLeftNR = n1;
+}
+
+/* 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,const 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,const 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,const 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++ =(SWORD)(tmpx/SAMPLING_FACTOR);
+       }
+}
+
+
+static void Mix32To16_Stereo(SWORD* dste,const 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++ =(SWORD)(tmpx/SAMPLING_FACTOR);
+               *dste++ =(SWORD)(tmpy/SAMPLING_FACTOR);
+       }
+}
+
+static void Mix32To8_Normal(SBYTE* dste,const 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++ = (SBYTE)((tmpx/SAMPLING_FACTOR)+128);
+       }
+}
+
+static void Mix32To8_Stereo(SBYTE* dste,const 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++ =(SBYTE)((tmpx/SAMPLING_FACTOR)+128);
+               *dste++ =(SBYTE)((tmpy/SAMPLING_FACTOR)+128);
+       }
+}
+
+#if defined HAVE_SSE2
+#define SHIFT_MIX_TO_16 (BITSHIFT + 16 - 16)
+/* TEST: Ok */
+static void Mix32To16_Stereo_SIMD_4Tap(SWORD* dste, const SLONG* srce, NATIVE count)
+{
+       int remain = count;
+
+       /* Check unaligned dste buffer. srce is always aligned. */
+       while(!IS_ALIGNED_16(dste))
+       {
+               Mix32To16_Stereo(dste, srce, SAMPLING_FACTOR);
+               dste+=2;
+               srce+=8;
+               count--;
+               if(!count) return;
+       }
+
+       /* dste and srce aligned. srce is always aligned. */
+       remain = count & 15;
+       /* count / 2 for 1 sample */
+
+       for(count>>=4;count;count--)
+       {
+               /* Load 32bit sample. 1st average */
+               __m128i v0 = _mm_add_epi32(
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+0)), SHIFT_MIX_TO_16),
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+4)), SHIFT_MIX_TO_16)
+               );  /* v0: s0.l+s2.l | s0.r+s2.r | s1.l+s3.l | s1.r+s3.r */
+
+               /* 2nd average (s0.l+s2.l+s1.l+s3.l / 4, s0.r+s2.r+s1.r+s3.r / 4). Upper 64bit is unused  (1 stereo sample) */
+               __m128i v1 = _mm_srai_epi32(_mm_add_epi32(v0, mm_hiqq(v0)), 2);
+               /* v1: s0.l+s2.l / 4 | s0.r+s2.r / 4 | s1.l+s3.l+s0.l+s2.l / 4 | s1.r+s3.r+s0.r+s2.r / 4 */
+
+               __m128i v2 = _mm_add_epi32(
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+8)), SHIFT_MIX_TO_16),
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+12)), SHIFT_MIX_TO_16)
+               );  /* v2: s4.l+s6.l | s4.r+s6.r | s5.l+s7.l | s5.r+s7.r */
+
+               __m128i v3 = _mm_srai_epi32(_mm_add_epi32(v2, mm_hiqq(v2)), 2);  /* Upper 64bit is unused */
+               /* v3: s4.l+s6.l /4 | s4.r+s6.r / 4| s5.l+s7.l+s4.l+s6.l / 4 | s5.r+s7.r+s4.r+s6.l / 4 */
+
+               /* pack two stereo samples in one */
+               __m128i v4 = _mm_unpacklo_epi64(v1, v3);  /* v4 = avg(s0,s1,s2,s3) | avg(s4,s5,s6,s7) */
+
+               __m128i v6;
+
+               /* Load 32bit sample. 1st average (s0.l+s2.l, s0.r+s2.r, s1.l+s3.l, s1.r+s3.r) */
+               v0 = _mm_add_epi32(
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+16)), SHIFT_MIX_TO_16),
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+20)), SHIFT_MIX_TO_16)
+               );  /* 128bit = 2 stereo samples */
+
+               /* 2nd average (s0.l+s2.l+s1.l+s3.l / 4, s0.r+s2.r+s1.r+s3.r / 4). Upper 64bit is unused  (1 stereo sample) */
+               v1 = _mm_srai_epi32(_mm_add_epi32(v0, mm_hiqq(v0)), 2);
+
+               v2 = _mm_add_epi32(
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+24)), SHIFT_MIX_TO_16),
+                       _mm_srai_epi32(_mm_loadu_si128((__m128i const *)(srce+28)), SHIFT_MIX_TO_16)
+               );
+
+               v3 = _mm_srai_epi32(_mm_add_epi32(v2, mm_hiqq(v2)), 2);  /* Upper 64bit is unused */
+
+               /* pack two stereo samples in one */
+               v6 = _mm_unpacklo_epi64(v1, v3);  /* v6 = avg(s8,s9,s10,s11) | avg(s12,s13,s14,s15) */
+
+               _mm_store_si128((__m128i*)dste, _mm_packs_epi32(v4, v6));  /* 4 interpolated stereo sample 32bit to 4 */
+
+               dste+=8;
+               srce+=32; /* 32 = 4 * 8  */
+       }
+
+       /* FIXME: THIS PART WRITES PAST DST !! */
+       if (remain)
+       {
+               Mix32To16_Stereo(dste, srce, remain);
+       }
+}
+
+#elif defined HAVE_ALTIVEC
+#define SHIFT_MIX_TO_16 vec_splat_u32(BITSHIFT + 16 - 16)
+/* TEST: Ok */
+static void Mix32To16_Stereo_SIMD_4Tap(SWORD* dste, const SLONG* srce, NATIVE count)
+{
+       int remain = count;
+
+       /* Check unaligned dste buffer. srce is always aligned. */
+       while(!IS_ALIGNED_16(dste))
+       {
+               Mix32To16_Stereo(dste, srce, SAMPLING_FACTOR);
+               dste+=2;
+               srce+=8;
+               count--;
+               if(!count) return;
+       }
+
+       /* dste and srce aligned. srce is always aligned. */
+       remain = count & 15;
+       for(count>>=4;count;count--)
+       {
+               /* Load 32bit sample. 1st average (s0.l+s2.l, s0.r+s2.r, s1.l+s3.l, s1.r+s3.r) */
+               vector signed int v0 = vec_add(
+                       vec_sra(vec_ld(0, srce), SHIFT_MIX_TO_16),  /* 128bit = 2 stereo samples */
+                       vec_sra(vec_ld(0x10, srce), SHIFT_MIX_TO_16)
+               );  /* 128bit = 2 stereo samples */
+
+               /* 2nd average (s0.l+s2.l+s1.l+s3.l / 4, s0.r+s2.r+s1.r+s3.r / 4). Upper 64bit is unused  (1 stereo sample) */
+               vector signed int v1 = vec_sra(vec_add(v0, vec_hiqq(v0)), vec_splat_u32(2));
+
+               vector signed int v2 = vec_add(
+                       vec_sra(vec_ld(0x20, srce), SHIFT_MIX_TO_16),
+                       vec_sra(vec_ld(0x30, srce), SHIFT_MIX_TO_16)
+               );
+
+               vector signed int v3 = vec_sra(vec_add(v2, vec_hiqq(v2)), vec_splat_u32(2));  /* Upper 64bit is unused */
+
+               /* pack two stereo samples in one */
+               vector signed int v6, v4 = vec_unpacklo(v1, v3); /* v4 = lo64(v1) | lo64(v3) */
+
+               /* Load 32bit sample. 1st average (s0.l+s2.l, s0.r+s2.r, s1.l+s3.l, s1.r+s3.r) */
+               v0 = vec_add(
+                       vec_sra(vec_ld(0x40, srce), SHIFT_MIX_TO_16),   /* 128bit = 2 stereo samples */
+                       vec_sra(vec_ld(0x50, srce), SHIFT_MIX_TO_16)
+               );  /* 128bit = 2 stereo samples */
+
+               /* 2nd average (s0.l+s2.l+s1.l+s3.l / 4, s0.r+s2.r+s1.r+s3.r / 4). Upper 64bit is unused  (1 stereo sample) */
+               v1 = vec_sra(vec_add(v0, vec_hiqq(v0)), vec_splat_u32(2));
+
+               v2 = vec_add(
+                       vec_sra(vec_ld(0x60, srce), SHIFT_MIX_TO_16),
+                       vec_sra(vec_ld(0x70, srce), SHIFT_MIX_TO_16)
+               );
+
+               v3 = vec_sra(vec_add(v2, vec_hiqq(v2)), vec_splat_u32(2));  /* Upper 64bit is unused */
+
+               /* pack two stereo samples in one */
+               v6 = vec_unpacklo(v1, v3);
+
+               vec_st(vec_packs(v4, v6), 0, dste);  /* 4 interpolated stereo sample 32bit to 4 interpolated stereo sample 16bit + saturation */
+
+               dste+=8;
+               srce+=32; /* 32 = 4 * 8  */
+       }
+
+       if (remain)
+       {
+               Mix32To16_Stereo(dste, srce, remain);
+       }
+}
+
+#endif
+
+
+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=(SLONGLONG)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_mode & DMODE_NOISEREDUCTION) {
+                               MixLowPass(vc_tickbuf, portion);
+                       }
+
+                       if(md_reverb) {
+                               if(md_reverb>15) md_reverb=15;
+                               MixReverb(vc_tickbuf,portion);
+                       }
+
+                       if (vc_callback) {
+                               vc_callback((unsigned char*)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;
+               }
+       }
+}
+
+int VC2_Init(void)
+{
+       VC_SetupPointers();
+
+       if (!(md_mode&DMODE_HQMIXER))
+               return VC1_Init();
+
+       if(!(Samples=(SWORD**)MikMod_amalloc(MAXSAMPLEHANDLES*sizeof(SWORD*)))) {
+               _mm_errno = MMERR_INITIALIZING_MIXER;
+               return 1;
+       }
+       if(!vc_tickbuf) {
+               if(!(vc_tickbuf=(SLONG*)MikMod_amalloc((TICKLSIZE+32)*sizeof(SLONG)))) {
+                       _mm_errno = MMERR_INITIALIZING_MIXER;
+                       return 1;
+               }
+       }
+
+       if(md_mode & DMODE_STEREO) {
+               Mix32toFP  = Mix32ToFP_Stereo;
+#if ((defined HAVE_ALTIVEC || defined HAVE_SSE2) && (SAMPLING_FACTOR == 4))
+               if (md_mode & DMODE_SIMDMIXER)
+                       Mix32to16  = Mix32To16_Stereo_SIMD_4Tap;
+               else
+#endif
+                       Mix32to16  = Mix32To16_Stereo;
+               Mix32to8   = Mix32To8_Stereo;
+               MixReverb  = MixReverb_Stereo;
+               MixLowPass = MixLowPass_Stereo;
+       } else {
+               Mix32toFP  = Mix32ToFP_Normal;
+               Mix32to16  = Mix32To16_Normal;
+               Mix32to8   = Mix32To8_Normal;
+               MixReverb  = MixReverb_Normal;
+               MixLowPass = MixLowPass_Normal;
+       }
+
+       md_mode |= DMODE_INTERP;
+       vc_mode = md_mode;
+       return 0;
+}
+
+int 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*)MikMod_calloc((RVc1+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL2=(SLONG*)MikMod_calloc((RVc2+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL3=(SLONG*)MikMod_calloc((RVc3+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL4=(SLONG*)MikMod_calloc((RVc4+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL5=(SLONG*)MikMod_calloc((RVc5+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL6=(SLONG*)MikMod_calloc((RVc6+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL7=(SLONG*)MikMod_calloc((RVc7+1),sizeof(SLONG)))) return 1;
+       if(!(RVbufL8=(SLONG*)MikMod_calloc((RVc8+1),sizeof(SLONG)))) return 1;
+
+       /* allocate reverb buffers for the right channel if in stereo mode only. */
+       if (vc_mode & DMODE_STEREO) {
+               if(!(RVbufR1=(SLONG*)MikMod_calloc((RVc1+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR2=(SLONG*)MikMod_calloc((RVc2+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR3=(SLONG*)MikMod_calloc((RVc3+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR4=(SLONG*)MikMod_calloc((RVc4+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR5=(SLONG*)MikMod_calloc((RVc5+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR6=(SLONG*)MikMod_calloc((RVc6+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR7=(SLONG*)MikMod_calloc((RVc7+1),sizeof(SLONG)))) return 1;
+               if(!(RVbufR8=(SLONG*)MikMod_calloc((RVc8+1),sizeof(SLONG)))) return 1;
+       }
+
+       RVRindex = 0;
+       return 0;
+}
+
+void VC2_PlayStop(void)
+{
+       MikMod_free(RVbufL1);
+       MikMod_free(RVbufL2);
+       MikMod_free(RVbufL3);
+       MikMod_free(RVbufL4);
+       MikMod_free(RVbufL5);
+       MikMod_free(RVbufL6);
+       MikMod_free(RVbufL7);
+       MikMod_free(RVbufL8);
+       MikMod_free(RVbufR1);
+       MikMod_free(RVbufR2);
+       MikMod_free(RVbufR3);
+       MikMod_free(RVbufR4);
+       MikMod_free(RVbufR5);
+       MikMod_free(RVbufR6);
+       MikMod_free(RVbufR7);
+       MikMod_free(RVbufR8);
+
+       RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
+       RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
+}
+
+int VC2_SetNumVoices(void)
+{
+       int t;
+
+       md_mode|=DMODE_INTERP;
+
+       if(!(vc_softchn=md_softchn)) return 0;
+
+       MikMod_free(vinf);
+       if(!(vinf=(VINFO*)MikMod_calloc(vc_softchn,sizeof(VINFO)))) return 1;
+
+       for(t=0;t<vc_softchn;t++) {
+               vinf[t].frq=10000;
+               vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
+       }
+
+       return 0;
+}
+
+#endif /* ! NO_HQMIXER */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/playercode/virtch_common.c b/libs/mikmod/playercode/virtch_common.c
new file mode 100644 (file)
index 0000000..5d92df8
--- /dev/null
@@ -0,0 +1,467 @@
+/*     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$
+
+  Common source parts between the two software mixers.
+  This file is probably the ugliest part of libmikmod...
+
+==============================================================================*/
+
+#if defined(HAVE_CONFIG_H) && !defined(_IN_VIRTCH_) /* config.h isn't guarded */
+#include "config.h"
+#endif
+#include "mikmod_internals.h"
+
+#ifndef NO_HQMIXER
+extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);
+extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);
+extern ULONG VC1_WriteBytes(SBYTE*,ULONG);
+extern ULONG VC2_WriteBytes(SBYTE*,ULONG);
+extern void  VC1_Exit(void);
+extern void  VC2_Exit(void);
+extern UWORD VC1_VoiceGetVolume(UBYTE);
+extern UWORD VC2_VoiceGetVolume(UBYTE);
+extern ULONG VC1_VoiceGetPanning(UBYTE);
+extern ULONG VC2_VoiceGetPanning(UBYTE);
+extern void  VC1_VoiceSetFrequency(UBYTE,ULONG);
+extern void  VC2_VoiceSetFrequency(UBYTE,ULONG);
+extern ULONG VC1_VoiceGetFrequency(UBYTE);
+extern ULONG VC2_VoiceGetFrequency(UBYTE);
+extern void  VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
+extern void  VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
+extern void  VC1_VoiceStop(UBYTE);
+extern void  VC2_VoiceStop(UBYTE);
+extern BOOL  VC1_VoiceStopped(UBYTE);
+extern BOOL  VC2_VoiceStopped(UBYTE);
+extern SLONG VC1_VoiceGetPosition(UBYTE);
+extern SLONG VC2_VoiceGetPosition(UBYTE);
+extern void  VC1_VoiceSetVolume(UBYTE,UWORD);
+extern void  VC2_VoiceSetVolume(UBYTE,UWORD);
+extern void  VC1_VoiceSetPanning(UBYTE,ULONG);
+extern void  VC2_VoiceSetPanning(UBYTE,ULONG);
+extern void  VC1_SampleUnload(SWORD);
+extern void  VC2_SampleUnload(SWORD);
+extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);
+extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);
+extern ULONG VC1_SampleSpace(int);
+extern ULONG VC2_SampleSpace(int);
+extern ULONG VC1_SampleLength(int,SAMPLE*);
+extern ULONG VC2_SampleLength(int,SAMPLE*);
+extern ULONG VC1_VoiceRealVolume(UBYTE);
+extern ULONG VC2_VoiceRealVolume(UBYTE);
+#endif
+
+
+#ifndef _IN_VIRTCH_
+
+#ifndef NO_HQMIXER
+extern int   VC1_Init(void);
+extern int   VC2_Init(void);
+static int  (*VC_Init_ptr)(void)=VC1_Init;
+static void (*VC_Exit_ptr)(void)=VC1_Exit;
+extern int   VC1_SetNumVoices(void);
+extern int   VC2_SetNumVoices(void);
+static int  (*VC_SetNumVoices_ptr)(void);
+static ULONG (*VC_SampleSpace_ptr)(int);
+static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);
+
+extern int   VC2_PlayStart(void);
+static int  (*VC_PlayStart_ptr)(void);
+extern void  VC2_PlayStop(void);
+static void (*VC_PlayStop_ptr)(void);
+
+static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);
+static void (*VC_SampleUnload_ptr)(SWORD);
+
+static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);
+static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);
+
+static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);
+static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);
+static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);
+static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);
+static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);
+static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);
+static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
+
+static void (*VC_VoiceStop_ptr)(UBYTE);
+static BOOL (*VC_VoiceStopped_ptr)(UBYTE);
+static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);
+static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#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,int)
+VC_PROC0(Exit)
+VC_FUNC0(SetNumVoices,int)
+VC_FUNC1(SampleSpace,ULONG,int)
+VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)
+VC_FUNC0(PlayStart,int)
+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;
+       }
+}
+#endif/* !NO_HQMIXER */
+
+#else /* _IN_VIRTCH_ */
+
+#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_16BITS|DMODE_FLOAT))
+               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)
+{
+       MikMod_free(vinf);
+       MikMod_afree(vc_tickbuf);
+       MikMod_afree(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 (SLONG)(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 (Samples && (handle < MAXSAMPLEHANDLES)) {
+               MikMod_afree(Samples[handle]);
+               Samples[handle]=NULL;
+       }
+}
+
+SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)
+{
+       SAMPLE *s = sload->sample;
+       int handle;
+       ULONG t, length,loopstart,loopend,looplen;
+
+       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*)MikMod_amalloc((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) {
+               looplen = loopend - loopstart;/* handle short samples */
+               if(s->flags & SF_BIDI)
+                       for(t=0;t<16 && t<looplen;t++)
+                               Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];
+               else
+                       for(t=0;t<16 && t<looplen;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 = (SLONG)(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 /* _VIRTCH_COMMON_ */
+
+#endif /* _IN_VIRTCH_ */
+
+/* ex:set ts=4: */
diff --git a/libs/mikmod/posix/memcmp.c b/libs/mikmod/posix/memcmp.c
new file mode 100644 (file)
index 0000000..7f41705
--- /dev/null
@@ -0,0 +1,22 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+int memcmp(const void *__s1, const void *__s2, size_t __n)
+{
+       const char *scan1, *scan2;
+       size_t n;
+
+       scan1 = __s1;
+       scan2 = __s2;
+       for (n = __n; n > 0; n--)
+               if (*scan1 == *scan2) {
+                       scan1++;
+                       scan2++;
+               } else
+                       return *scan1 - *scan2;
+
+       return 0;
+}
diff --git a/libs/mikmod/posix/strcasecmp.c b/libs/mikmod/posix/strcasecmp.c
new file mode 100644 (file)
index 0000000..5b9935f
--- /dev/null
@@ -0,0 +1,23 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+#include "mikmod_ctype.h"
+
+int _mm_strcasecmp(const char *__s1, const char *__s2)
+{
+       const char *p1 = __s1;
+       const char *p2 = __s2;
+       char c1, c2;
+
+       if (p1 == p2) return 0;
+
+       do {
+               c1 = mik_tolower(*p1++);
+               c2 = mik_tolower(*p2++);
+               if (c1 == '\0') break;
+       } while (c1 == c2);
+
+       return (int)(c1 - c2);
+}
diff --git a/libs/mikmod/posix/strstr.c b/libs/mikmod/posix/strstr.c
new file mode 100644 (file)
index 0000000..82e1fd4
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+char *strstr(const char *haystack, const char *needle)
+{
+       const char *scan;
+       size_t len;
+       char firstc;
+
+       firstc = *needle;
+       len = strlen(needle);
+       for (scan = haystack; *scan != firstc || strncmp(scan, needle, len); )
+               if (!*scan++)
+                       return NULL;
+       return (char *)scan;
+}