]> 4ch.mooo.com Git - 16.git/blobdiff - 16/adplug/adplug-2.2.1/doc/libadplug.texi
Please enter the commit message for your changes. Lines starting
[16.git] / 16 / adplug / adplug-2.2.1 / doc / libadplug.texi
diff --git a/16/adplug/adplug-2.2.1/doc/libadplug.texi b/16/adplug/adplug-2.2.1/doc/libadplug.texi
new file mode 100644 (file)
index 0000000..12fe8b2
--- /dev/null
@@ -0,0 +1,1687 @@
+\input texinfo   @c -*-texinfo-*-
+@c %**start of header
+@setfilename libadplug.info
+@include version.texi
+@settitle AdPlug Core Library @value{VERSION} Manual
+@c %**end of header
+
+@macro class{name}
+@tindex \name\
+@code{\name\}
+@end macro
+
+@copying
+This manual documents the AdPlug core library, version
+@value{VERSION}.
+
+Copyright @copyright{} 2002 - 2010 Simon Peter <dn.tlp@@gmx.net>
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover texts being ``A GNU Manual,''
+and with the Back-Cover Texts as in (a) below.  A copy of the license is
+included in the section entitled ``GNU Free Documentation License.''
+
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
+this GNU Manual, like GNU software.  Copies published by the Free
+Software Foundation raise funds for GNU development.''
+@end quotation
+@end copying
+
+@dircategory Software Libraries
+@direntry
+* AdPlug Core Library: (libadplug).     AdPlug Core Library @value{VERSION}
+@end direntry
+
+@titlepage
+@title AdPlug Core Library Manual
+@subtitle Version @value{VERSION}
+@subtitle Last updated on @value{UPDATED}
+@author Simon Peter
+
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top AdPlug core library
+
+@insertcopying
+@end ifnottex
+
+@menu
+* Introduction::                What is AdPlug?
+* Basic Usage::                 Using AdPlug in your programs the easy way.
+* Advanced Usage::              Using AdPlug in your programs the hard way.
+* Hacking::                     How to hack around in AdPlug.
+* Player development::          How to write new replayers for AdPlug.
+* Protracker based players::    How to write Protracker based players.
+* Copying This Manual::         Your rights and freedoms.
+* Method Index::
+* Variable Index::
+* Class Index::
+@end menu
+
+@node Introduction
+@chapter Introduction
+
+AdPlug is a free, multi-platform, hardware independent AdLib sound
+player library, mainly written in C++. AdPlug plays sound data,
+originally created for the AdLib and Sound Blaster (OPL2/OPL3) audio
+boards, on top of an OPL emulator or by using the real hardware. No
+OPL chip is required for playback.
+
+@menu
+* Supported Formats::
+* Concepts::
+@end menu
+
+@node Supported Formats
+@section Supported Formats
+
+AdPlug implements unique file replayers for each supported format in
+order to achieve the best possible replay quality. Below is a list of
+all currently supported file formats along with information about
+possible replay issues. Players marked as "preliminary" aren't
+considered final by the author(s) and may contain many replay issues,
+but are included for testing purposes anyway.
+
+@itemize @bullet
+@item @file{A2M}: AdLib Tracker 2 by subz3ro
+@itemize @bullet
+@item File format versions 1, 4, 5 and 8 are supported
+@item Unimplemented commands (versions 1-4): @code{FF1 - FF9, FAx - FEx}
+@item Unimplemented commands (versions 5-8): @code{Gxy, Hxy, Kxy - &xy}
+@item In version 5-8 files, some parts of the flags byte are ignored
+@item Only SixPack compressed and uncompressed files are supported
+@end itemize
+@item @file{ADL}: Westwood ADL File Format
+@item @file{AMD}: AMUSIC Adlib Tracker by Elyssis
+@item @file{BAM}: Bob's Adlib Music Format by Bob
+@item @file{CFF}: BoomTracker 4.0 by CUD
+@item @file{CMF}: Creative Music File Format by Creative Technology
+@item @file{D00}: EdLib by Vibrants
+@itemize @bullet
+@item Bugs: Hard restart SR sometimes sounds wrong
+@end itemize
+@item @file{DFM}: Digital-FM by R.Verhaag
+@item @file{DMO}: Twin TrackPlayer by TwinTeam
+@item @file{DRO}: DOSBox Raw OPL Format
+@item @file{DTM}: DeFy Adlib Tracker by DeFy
+@item @file{HSC}: HSC Adlib Composer by Hannes Seifert, HSC-Tracker by Electronic Rats
+@item @file{HSP}: HSC Packed by Number Six / Aegis Corp.
+@item @file{IMF}: Apogee IMF File Format by Apogee
+@item @file{KSM}: Ken Silverman's Adlib Music Format by Ken Silverman
+@itemize @bullet
+@item Needs file @file{insts.dat} in the same directory as loaded file
+@end itemize
+@item @file{LAA}: LucasArts AdLib Audio File Format by LucasArts
+@itemize @bullet
+@item Bugs: Some volumes are a bit off
+@end itemize
+@item @file{LDS}: LOUDNESS Music Format by Andras Molnar
+@item @file{M}: Ultima 6 Music Format by Origin
+@item @file{MAD}: Mlat Adlib Tracker
+@item @file{MID}: MIDI Audio File Format
+@item @file{MKJ}: MKJamz by M \ K Productions @strong{(preliminary)}
+@item @file{MSC}: AdLib MSCplay
+@item @file{MTK}: MPU-401 Trakker by SuBZeR0
+@item @file{RAD}: Reality ADlib Tracker by Reality
+@item @file{RAW}: RdosPlay RAW file format by RDOS
+@item @file{RIX}: Softstar RIX OPL Music Format
+@item @file{ROL}: AdLib Visual Composer by AdLib Inc.
+@itemize @bullet
+@item Needs file @file{standard.bnk} in the same directory as loaded file
+@end itemize
+@item @file{S3M}: Scream Tracker 3 by Future Crew
+@itemize @bullet
+@item Bugs: Extra Fine Slides (@code{EEx, FEx}) & Fine Vibrato
+(@code{Uxy}) are inaccurate
+@end itemize
+@item @file{SA2}: Surprise! Adlib Tracker 2 by Surprise! Productions
+@item @file{SAT}: Surprise! Adlib Tracker by Surprise! Productions
+@item @file{SCI}: Sierra's AdLib Audio File Format by Sierra On-Line Inc.
+@itemize @bullet
+@item Needs file @file{@var{???}patch.003} in the same directory as
+loaded file, where @var{???} are the first 3 characters of the loaded
+file's filename
+@item Bugs: Some instruments are messed up
+@end itemize
+@item @file{SNG}: SNGPlay by BUGSY of OBSESSION
+@item @file{SNG}: Faust Music Creator by FAUST
+@item @file{SNG}: Adlib Tracker 1.0 by TJ
+@itemize @bullet
+@item Needs file @file{@var{songname}.ins} in the same directory as
+loaded file, where @var{songname} is the song's filename without
+@file{.sng} extension.
+@end itemize
+@item @file{XAD}: eXotic ADlib Format by Riven the Mage
+@item @file{XMS}: XMS-Tracker by MaDoKaN/E.S.G
+@item @file{XSM}: eXtra Simple Music by Davey W Taylor
+@end itemize
+
+Whenever a player requires more files to be present in a given
+directory, be especially careful under UNIX systems, because all file
+names are case-sensitive.
+
+@node Concepts
+@section Concepts
+
+All of AdPlug's header files are installed under the directory
+@file{adplug} inside your specified include path. Whenever a specific
+header file in this manual is referred to, the filename with the path
+@file{adplug/} prepended is meant.
+
+AdPlug can be divided into 2 sections and 3 layers of
+functionality. These are the @dfn{Playback} and @dfn{Sound
+generation} sections and the @dfn{Frontend}, @dfn{Mid-End} and
+@dfn{Backend} layers.
+
+The Frontend layer is simply your application itself, using AdPlug. It
+is above of it all and does not belong to any particular
+section. Anything that provides the user-interface to AdPlug or an
+interface to another application is in the Frontend layer.
+
+@menu
+* Playback section::
+* Sound generation section::
+@end menu
+
+@node Playback section
+@subsection Playback section
+
+The Playback section is divided into the Mid-End and the Backend
+layers. As a whole, it is responsible for making the sound files play
+back.
+
+The Mid-End layer provides the glue between the Frontend and the
+Backend layers. It provides methods and classes for these layers to
+communicate. The headers @file{adplug.h}, @file{fprovide.h},
+@file{players.h} and @file{database.h} belong to the Mid-End
+layer. From your application's point of view, you only have to include
+the file @file{adplug.h} in your source files, which automatically
+includes all the other Mid-End headers.
+
+The Backend layer is responsible for reading and decoding the sound
+files into OPL command data. It then passes this data to the sound
+generation section, which generates the final audio data. The header
+@file{player.h} and all player header files belong to the Backend
+layer.
+
+@node Sound generation section
+@subsection Sound generation section
+
+The Sound generation section is responsible for generating the OPL's
+sound, according to the input of the Playback section. This sound is
+either routed back to the application for it to do something with it
+or routed directly to a specific audio hardware.
+
+The following headers provide the interface to the sound generation
+section: @file{emuopl.h}, @file{temuopl.h}, @file{kemuopl.h},
+@file{realopl.h}, @file{silentopl.h}, @file{analopl.h} and
+@file{diskopl.h}. All classes inside these headers are derived from
+the abstract base class @class{Copl}, declared inside the file
+@file{opl.h}, which provides the common interface for the Backend
+layer of the Playback section. This interface is not meant for the
+Frontend layer (i.e. your application). Your application, however, has
+to call special methods of these classes in order to route the data
+back, if there is any.
+
+@file{emuopl.h} provides the class @class{CEmuopl}, which implements a
+virtual OPL emulator, which automatically selects the best available
+OPL chip emulation and type for each replayer.
+
+@file{temuopl.h} provides the class @class{CTEmuopl}, which is a
+wrapper class around Tatsuyuki Satoh's fmopl OPL2 emulator, which
+generates wave audio data to be routed back to the application.
+
+@file{kemuopl.h} provides the class @class{CKemuopl}, which is a
+wrapper class around Ken Silverman's adlibemu OPL2 emulator, which
+generates wave audio data to be routed back to the application.
+
+@file{realopl.h} provides the class @class{CRealopl}, which outputs to
+a real hardware OPL2 or OPL3 chip. No data is routed back to the
+application. This class is currently only working on x86 hardware.
+
+@file{silentopl.h} provides the class @class{CSilentopl}, which is a
+dummy OPL2/3, which generates nothing. All data sent to it is
+forgotten immediately. No data is routed back to the application.
+
+@file{analopl.h} provides the class @class{CAnalopl}, which is the same
+as @class{CRealopl}, but also provides a 9-channel loudness
+pseudo-analyzer interface for the application. The loudness data is
+the only data routed back to the application.
+
+@file{diskopl.h} provides the class @class{CDiskopl}, which is an OPL3
+emulator that does not output any sound to the soundcard, but instead
+writes all received OPL commands to a file in the RdosPlay RAW
+format.
+
+@node Basic Usage
+@chapter Basic Usage
+
+AdPlug provides convenience methods and classes inside its Mid-End
+layer that make generic usage in your applications pretty easy. This
+is most probably all that you need. For very advanced usage of
+particular features of AdPlug, please refer to @ref{Advanced Usage}.
+
+For basic usage, you need to include the header @file{adplug.h} inside
+your application's source code. In addition, you need one of the
+headers from the sound generation section, if you want sound output.
+
+@file{adplug.h} provides the class @class{CAdPlug}, which in turn
+provides the load and playback facilities for the song
+files. @code{CAdPlug} is a static class, you do not need to
+instantiate an object of it.
+
+@menu
+* Loading::
+* Playback::
+* Audio output::
+* Chip support selection::
+* Getting Playback Information::
+* Example::
+@end menu
+
+@node Loading
+@section Loading
+
+To load a supported file for playback, you use the method
+@code{CAdPlug::factory(const std::string &@var{filename}, Copl *@var{opl},
+...)}. The method takes more arguments, but we don't need them for
+basic usage. They are explained in @ref{Advanced Usage}.
+
+The first argument, @var{filename}, is a string object, containing the
+filename of the sound file to be loaded with AdPlug. The second
+argument, @var{opl}, is a pointer to an already initialized object
+from the sound generation section of the library.
+
+The method returns a pointer to an initialized player object from the
+Backend layer, or the NULL pointer if the file couldn't be loaded for
+any reason.
+
+I guess @var{filename} does not need any more explanation, so i will
+just explain how to get an instance of a @code{Copl} derived class:
+
+If you want to use the OPL emulator class @code{CEmuopl}, you have to
+include the header @file{emuopl.h} inside your application's source
+code. @code{CEmuopl}'s constructor looks like this:
+@code{CEmuopl::CEmuopl(int @var{rate}, bool @var{bit16}, bool
+@var{usestereo})}. The @var{rate} argument specifies the playback
+frequency rate in Hz. The @var{bit16} argument specifies whether to
+create 8 bit or 16 bit wave audio data. If it is set, 16 bit data is
+created. The @var{usestereo} argument specifies whether to create
+stereo or mono audio data. If it is set, stereo data is created.
+
+If you want to use real hardware OPL2 output, you have to include the
+header @file{realopl.h} inside your application and use the class
+@code{CRealopl}. Its constructor just takes one optional argument,
+specifying the hardware OPL2's base port, which is @samp{0x388} by
+default. As an option, you can include @file{analopl.h} instead, using
+the class @code{CAnalopl}, and also use the analyzer interface
+instead. This is explained in @ref{Audio output}.
+
+For no audio generation at all, include the header @file{silentopl.h}
+inside your application and use the class @code{CSilentopl}. Its
+constructor does not take any arguments.
+
+@node Playback
+@section Playback
+
+On successful operation, @code{CAdPlug}'s @code{factory()} method
+returns a pointer to an initialized player object from the Backend
+layer. You use this object to do the main song playback. The important
+methods for song playback are:
+
+@ftable @code
+@item void seek(unsigned long ms)
+Use this to seek inside the song. The only argument specifies the
+number of milliseconds to seek from the beginning of the song.
+
+@item bool update()
+The most important method of them all. You have to call this method in
+a loop. As long as it returns @samp{true}, the song has not ended
+yet. At some point, it will start to always return @samp{false}. When
+it does this, the song has ended. The song will play on (and is maybe
+already automatically rewound by the player itself), but you should
+use the @code{rewind()} method to rewind it or stop playing.
+
+@item void rewind(int subsong = -1)
+This method rewinds the song to the beginning of the subsong,
+specified by the only argument. If no argument or @samp{-1} is given,
+the currently selected subsong will be rewound. If the player does not
+support subsongs, just don't provide an argument.
+
+@item float getrefresh()
+Returns a float containing the player object's idea of with what
+frequency its @code{update()} method should be called, in Hz. This can
+change at any time, so you have to poll it before every call to
+@code{update()}.
+
+@item unsigned int getsubsongs()
+Returns the number of subsongs of the currently loaded song. If the
+player doesn't support subsongs, @samp{1} is returned, representing
+the only ``subsong''.
+@end ftable
+
+@node Audio output
+@section Audio output
+
+To actually generate some sound, you probably additionally have to
+make some calls to the OPL object. While the two hardware OPL2 output
+and the silent OPL2 classes do not need any additional calls, the
+@code{CEmuopl} class provides methods for your application's readback
+of the generated wave audio data.
+
+To get a buffer of wave audio data from the emulator, you have to call
+the @code{void CEmuopl::update(short *@var{buf}, int @var{samples})}
+method. The @var{buf} argument is a pointer to a previously allocated
+memory block of the size specified by the @var{samples} argument, in
+samples. The method will fill the specified amount of samples into the
+buffer. Multibyte samples have the machine's byte ordering.
+
+For easier and more uniform handling of the different OPL classes, the
+@code{Copl} base class also provides the @code{update()} method. For
+subclasses that do not support read back of the audio data (and for
+which this is not necessary), the method is empty and does nothing.
+
+The volume analyzing hardware OPL class @code{CAnalopl} also has some
+data readback methods:
+
+@ftable @code
+@item int getcarriervol(unsigned int v)
+Returns the carrier's current volume of the OPL2 channel given as the
+only argument.
+@item int getmodulatorvol(unsigned int v)
+Returns the modulator's current volume of the OPL2 channel given as
+the only argument.
+@item bool getkeyon(unsigned int v)
+Returns whether a key-on event just happened on the OPL2 channel given
+as the only argument.
+@end ftable
+
+@node Chip support selection
+@section Chip support selection
+
+With some OPL classes, like @code{CEmuopl} and @code{CRealopl}, it is
+also possible to select the chip type to support. The hardware OPL
+class will of course only be able to support those chip types that are
+available in the system. The emulated OPL class will be able to
+support all chip types that it can emulate, provided the corresponding
+emulators are compiled in.
+
+Three different OPL chip configurations can be identified, which can
+all be support by AdPlug.
+
+@itemize
+@item Single OPL2: This is the classic configuration found on the
+standard AdLib boards. One OPL2 chip is supported.
+@item Dual OPL2: This configuration was first implemented on the Sound
+Blaster Pro II boards. Two independant OPL2 chips are on this card.
+@item OPL3: This is the configuration found on all newer sound
+cards. An OPL3 chip is supported, which is capable of emulating the
+other two configurations.
+@end itemize
+
+In accordance to this, AdPlug's @code{Copl} base class defines the
+enumeration type @code{ChipType}, containing the items
+@code{TYPE_OPL2}, @code{TYPE_OPL3} and @code{TYPE_DUAL_OPL2}.
+
+OPL classes supporting multiple OPL interfaces have the
+@code{settype(@var{type})} method, which can be used to set the chip
+interface to support, using the @code{ChipType} enumeration type.
+
+The chip type needs not to be set, as all supporting classes
+automatically set the best available chip type, they can support, but
+you may like to provide your user with this selection to suite his
+listenting preferences.
+
+You may retrieve the currently supported chip type of a class by using
+the method @code{Copl::gettype()}, which returns a variable of type
+@code{ChipType}. This method is defined in the @code{Copl} base class
+and thus supported by all of the OPL classes.
+
+@node Getting Playback Information
+@section Getting Playback Information
+
+During playback, it is possible to gain some replay statistics with
+some players. The following methods are for getting playback
+informations:
+
+@ftable @code
+@item std::string gettype()
+Returns a descriptive string containing the current file's format
+type. This is for user information only and cannot be interpreted by
+software.
+
+@item std::string gettitle()
+Returns a string holding the current song's title. An empty string is
+returned if the song's format does not support title information.
+
+@item std::string getauthor()
+Returns a string containing the current song's author name. An empty
+string is returned if the song's format doesn't support author
+information.
+
+@item std::string getdesc()
+Returns a string with the current song's description. An empty string
+is returned if the song's format doesn't support a description.
+
+@item unsigned int getpatterns()
+Returns the number of patterns in the current song. @samp{0} is
+returned if the format isn't pattern-based.
+
+@item unsigned int getpattern()
+Returns the number of the currently playing pattern. @samp{0} is
+returned if the format isn't pattern-based.
+
+@item unsigned int getorders()
+Returns the length of the order list of the current song. @samp{0} is
+returned if the format doesn't have an order list.
+
+@item unsigned int getorder()
+Returns the number of the currently playing order list entry. @samp{0}
+is returned if the format doesn't have an order list.
+
+@item unsigned int getrow()
+Returns the number of the currently playing row inside the current
+pattern. @samp{0} is returned if the format isn't pattern-based.
+
+@item unsigned int getspeed()
+Returns the current speed setting of the song. @samp{0} is returned if
+the format doesn't support Protracker-based speed settings.
+
+@item unsinged int getinstruments()
+Returns the number of defined instruments in the song. This does not
+necessarily mean that any of the defined instruments has an instrument
+name attached to it. @samp{0} is returned if the format doesn't define
+any instruments.
+
+@item std::string getinstrument(unsigned int n)
+Returns a string with the name of the instrument, specified by the
+only argument. If the specified instrument doesn't have a name, an
+empty string is returned instead.
+@end ftable
+
+These methods may be called at any time on an initialized player
+object (i.e. a file has already been loaded). If a player or song does
+not support any of the above methods, or their values are not
+meaningful for a format, reasonable bogus values are returned
+instead.
+
+Some informational methods may not be called while the song itself is
+playing because they change the internal replay state and will
+destroy the running playback. These are:
+
+@ftable @code
+@item unsigned long songlength(int subsong = -1)
+This method returns the total length in milliseconds of the subsong
+given as the only argument. If it is omitted or @samp{-1}, the
+currently selected subsong's length will be returned.
+@end ftable
+
+@node Example
+@section Example
+
+This is an example of a minimal playback utility that reads the
+filename to be played from the commandline, uses the emulator to
+generate the sound and writes the raw wave audio data back to disk:
+
+@verbatim
+#include <stdlib.h>
+#include <stdio.h>
+#include <adplug/adplug.h>
+#include <adplug/emuopl.h>
+
+#define RATE   44100   // Output frequency in Hz
+#define BIT16  true    // true when 16bit samples should be used
+#define STEREO false   // true when stereo samples should be used
+#define BUFSIZE        512     // Sound buffer size in samples
+
+bool play(const char *filename, const char *output)
+/*
+ * Main playback function. Returns true on successful playback.
+ * false is returned otherwise.
+ */
+{
+  CEmuopl      opl(RATE, BIT16, STEREO);
+  CPlayer      *p = CAdPlug::factory(filename, &opl);
+  FILE         *f;
+  short                buf[BUFSIZE];
+  unsigned long        towrite, write;
+
+  if(!p) return false;         // File couldn't be loaded
+
+  f = fopen(output, "wb");
+  while(p->update())
+    for(towrite = RATE / p->getrefresh(); towrite; towrite -= write) {
+      write = (towrite > BUFSIZE ? BUFSIZE : towrite);
+      opl.update(buf, write);
+      fwrite(buf, write, 2, f);
+    }
+
+  fclose(f);
+  return true;
+}
+
+int main(int argc, char **argv)
+{
+  if(argc < 3) {
+    cout << "usage: " << argv[0] << " <filename> <output>" << endl;
+    exit(EXIT_FAILURE);
+  }
+
+  if(play(argv[1], argv[2]))
+    exit(EXIT_SUCCESS);
+  else
+    exit(EXIT_FAILURE);
+}
+@end verbatim
+
+@node Advanced Usage
+@chapter Advanced Usage
+
+This chapter explains very advanced usage of AdPlug. You do not
+normally need to read this if you just want to write a usual frontend
+application for AdPlug.
+
+@menu
+* Player Lists::
+* File Providers::
+* Using the Database::
+* Without CAdPlug::
+@end menu
+
+@node Player Lists
+@section Player Lists
+
+There is another argument to the @code{CAdPlug::factory(const
+std::string &fn, Copl *opl, const CPlayers &@var{pl} = players, ...)}
+method. The argument @var{pl} is a reference to an object holding a
+@dfn{Player List}.
+
+A player list object is an instance of the @class{CPlayers} class (not
+to be confused with the @class{CPlayer} class). The object can be
+constant and even static (so it is possible to pass a temporary
+object, created on the fly).
+
+The @code{CPlayers} class itself is not much more than a specialized
+@code{std::list} from the @acronym{STL}, holding pointers to objects
+of type @class{CPlayerDesc}, which are explained below. Look into the
+@acronym{STL} documentation for more information on @code{std::list}
+functionality.
+
+The @class{CPlayerDesc} class is essentially an information-holder,
+describing all needed characteristics of a player class, to create an
+instance and load a supported file with it. It has two public
+attributes:
+
+@vtable @code
+@item Factory factory
+The @code{Factory} type defines a pointer to a static method inside a
+class, inherited from @code{CPlayer}, taking a pointer to a
+@code{Copl}-derived object as the sole argument. The meaning of this
+attribute is to provide a pointer to the factory method of the player
+class, which takes a pointer to an initialized @code{Copl}-derived
+object and returns a pointer to an initialized instance of the same
+player class, this @code{CPlayerDesc} object describes.
+
+@item std::string filetype
+This is a string containing the unique file type identifier of the
+player class, this @code{CPlayerDesc} object describes. The string
+normally contains the name of the file format, which the belonging
+player class handles. This string should be unique.
+@end vtable
+
+In addition, @code{CPlayerDesc} has the following methods:
+
+@ftable @code
+@item CPlayerDesc(Factory f, const std::string &type, const char *ext)
+A specialized constructor, which initializes the whole object at
+once. The first argument is the pointer to the factory method of the
+accompanying player class. The second argument is a string with the
+unique file type description, this player class handles. The last
+argument is a pseudo @acronym{ASCIIZ} string, holding many
+@acronym{ASCIIZ} strings with all file extensions to be associated
+with the accompanying player class. To create such a string, include
+the leading @samp{.} with all file extensions and terminate any file
+extension entry with a @samp{\0} character. Concatenate all entries
+one after the other, forming a string of strings. Terminate the last
+entry with another @samp{\0} character, so the final string is doubly
+terminated.
+
+@item void add_extension(const std::string &ext)
+Adds the single file extension, passed as the only argument, to the
+list of file extensions, the accompanying player class handles.
+
+@item const char *get_extension(unsigned int n)
+Returns a pointer to the @var{n}-th file extension string in the file
+extension list. If @var{n} is out of range, a @samp{NULL}-pointer is
+returned instead.
+@end ftable
+
+The @code{CPlayers} class itself adds two more methods to the
+inherited @code{std::list} interface:
+
+@ftable @code
+@item const CPlayerDesc *lookup_filetype(const std::string &ftype)
+Returns a pointer to the first occurence of a @code{CPlayerDesc}
+object with a file type of @var{ftype}, passed as the only
+argument. This should also be the only object with that file type in
+the list. If an object with the given file type is not found, a
+@samp{NULL}-pointer if returned instead.
+
+@item const CPlayerDesc *lookup_extension(const std::string &extension)
+Returns a pointer to the first occurence of a @code{CPlayerDesc}
+object, defining a file extension of @var{extension}, passed as the
+only argument. Since file extensions are not necessarily unique in a
+@code{CPlayers} list, it is often much more efficient to use the
+search facilities provided by the @acronym{STL}. If no object,
+specifying the given file extension, could be found, a
+@samp{NULL}-pointer is returned instead.
+@end ftable
+
+Thus, the @code{CPlayers} class holds a list of player
+descriptions. This list is used by the @code{CAdPlug::factory()}
+method for the list of players to try out on a given filename. If no
+list is passed to the method, it is @code{CAdPlug::players} by
+default. This list always holds all players compiled into the AdPlug
+library and is also your starting point for generating lists of your
+own.
+
+@node File Providers
+@section File Providers
+
+@dfn{File Providers} are special classes that provide abstracted
+access to files. AdPlug's player classes request files using a file
+provider, in their @code{load()} methods. This system is necessary
+because some players require multiple files in their load stage and
+these files cannot all be passed to their @code{load()} method
+because the application's programmer would have to be aware of each of
+the player's characteristics to know which files to pass.
+
+A file provider class is derived from the abstract base class
+@class{CFileProvider}, which is declared in the header
+@file{fprovide.h}. This class defines the following methods:
+
+@ftable @code
+@item binistream *open(std::string) const
+An abstract virtual method that takes a string containing a filename
+as the only argument and returns an initialized input-only binary
+stream to that file. The stream is always created with x86
+capabilities (i.e. Little-Endian, @acronym{IEEE-754} floating-point
+numbers). If the file could not be opened, the @samp{NULL}-pointer is
+returned instead.
+
+@item void close(binistream *) const
+An abstract virtual method that takes an input-only binary stream,
+which was formerly created with the @code{open()} method, and closes
+this stream.
+
+@item bool extension(const std::string &filename, const std::string &extension)
+This static method takes a string holding a filename as its first and
+another string holding a file extension as its last argument. It does
+a caseless compare of the given file extension to the extension of the
+given filename and returns @samp{true} if they match. @samp{false} is
+returned otherwise.
+
+@item unsigned long filesize(binistream *f)
+This static method takes an input-only binary stream, previously
+returned by the @code{open()} method, and returns the total size, in
+bytes, of the associated file. The stream's state is not altered.
+@end ftable
+
+If you like to create your own file provider, you have to inherit from
+this class and implement the methods @code{open()} and
+@code{close()}. Remember to open the stream with x86 capabilites! One
+situation in which you would have to create your own file provider is
+when your application doesn't load the files from the machine's local
+filesystem. For example, when it supports reading from archives, you
+would use your file provider to fetch and depack the file from the
+archive first, before passing it to AdPlug.
+
+One derived file provider class is already defined in
+@file{fprovide.h}: @class{CProvider_Filesystem}. This file provider
+supports loading from the machine's local filesystem. File names are
+normal paths in the operating system's common notation.
+
+A file provider object can also be passed to the
+@code{CAdPlug::factory()} method as last argument. If it is not
+provided, it is a temporary instance of @code{CProvider_Filesystem} by
+default. The method passes this object on to all player objects'
+@code{load()} methods, it tries to open the file with. The player
+objects' @code{load()} methods also take the file provider object as
+their last argument and default to @code{CProvider_Filesystem} if none
+is given.
+
+@node Using the Database
+@section Using the Database
+
+AdPlug recently features a full-blown database, specialized for
+storing information relevant to the replay of AdLib-specific music
+data.
+
+The database can be maintained by using the @command{adplugdb}
+command. Usage of this command is explained in its own manual page.
+
+The application's interface to the database is defined through the
+@class{CAdPlugDatabase} class, residing in the header file
+@file{database.h}.
+
+If you just want to pass a database for AdPlug to make use of it,
+reading @ref{Usage with CAdPlug} is sufficient. If you want to write a
+complete database manipulation application, you have to read the other
+subsections as well.
+
+@menu
+* Usage with CAdPlug::
+* Records::
+* Keys::
+* Players using the Database::
+* Direct Usage::
+@end menu
+
+@node Usage with CAdPlug
+@subsection Usage with CAdPlug
+
+You can pass AdPlug a database for it to get specific information
+about a file. Some file formats store insufficient information within
+themselves and AdPlug uses the database to get the missing data. You
+do not need to include any more header files other than
+@file{adplug.h} within your application to do this.
+
+To hand a database to AdPlug, you have to initialize an instance of
+@code{CAdPlugDatabase} first. To do this, you just have to declare an
+object of this class. This creates an empty database for
+you.
+
+Additionally, for the database to be of any use to AdPlug, you have to
+fill it with some records (see @ref{Records}). This is most preferably
+done by loading an already existing database from a file. To do this,
+you use the @code{load(std::string  @var{db_name})} method of the
+class. This will merge any records in the database file @var{db_name}
+into your database object. You can merge any more database files, if
+you wish. Only new records will be merged. Duplicate records will be
+ignored.
+
+To hand your database to AdPlug, you simply call
+@code{CAdPlug::set_database(CAdPlugDatabase *db)} and pass a pointer
+to your database object as the only argument. From now on, AdPlug will
+use your database to do lookups for special information about some
+file types. You have to keep your instance of the database until you
+close AdPlug and free it by yourself after that.
+
+@node Records
+@subsection Records
+
+@dfn{Records} are the primary data containers in the database. A
+record is a very flexible object. It can store virtually any number of
+different data types, you can think of.
+
+All record classes are derived from the common abstract base class
+@code{CAdPlugDatabase::CRecord}. All records have at least three
+common attributes:
+
+@vtable @code
+@item RecordType type
+Specifies what type of data this record holds. @code{RecordType} is an
+enumeration variable with the following values:
+
+@vtable @code
+@item Plain
+This record doesn't store any more information than the three standard
+attributes.
+@item SongInfo
+This record additionally stores song name and author information.
+@item ClockSpeed
+This record additionally stores timer clock speed information.
+@end vtable
+
+@item CKey key
+This is the unique key, allocated for any record in the
+database. @xref{Keys}.
+
+@item std::string filetype
+Holds the unique file type of the file associated with the
+record. This value is taken from the player list (see
+@ref{Player Lists}).
+@end vtable
+
+The common base class @code{CAdPlugDatabase::CRecord} defines a
+static method @code{factory(RecordType type)} for application usage
+that returns a pointer to a newly allocated @class{CRecord} object, or
+the @samp{NULL}-pointer if an error occured. You pass the type of the
+record to be created as the only argument.
+
+All other public methods are meant for internal use of the database
+only and should not be called from an application. They are explained
+here anyway, for informational purposes:
+
+@ftable @code
+@item CRecord *factory(binistream &in)
+Another factory method that takes a reference to an input-only binary
+stream as the only argument. It tries to extract a record from the
+stream's current position, initializes a new record object with the
+data and returns a pointer to that record object. The
+@samp{NULL}-pointer is returned if the record type couldn't be
+determined from the stream's data.
+
+@item void write(binostream &out)
+Writes the record's contents to the output-only binary stream,
+referenced by the only argument.
+
+@item bool user_read(std::istream &in, std::ostream &out)
+Attaches to the input and output streams, referenced by the first and
+second arguments and tries to prompt an apparent user for the relevant
+data input.
+
+@item bool user_write(std::ostream &out)
+Attaches to the output stream, referenced by the only argument and
+writes the record's contents in human-readable form to it.
+
+@item void read_own(binistream &in)
+@itemx void write_own(binostream &out)
+@itemx bool user_read_own(std::istream &in, std::ostream &out)
+@itemx bool user_write_own(std::ostream &out)
+Abstract virtual base methods to be inherited by the real record
+classes to read and write their own data, in both binary and
+human-readable ways.
+
+@item unsigned long get_size()
+Abstract virtual base method to be inherited by the real record
+classes to report the size of the extra data defined by them.
+@end ftable
+
+@node Keys
+@subsection Keys
+
+@dfn{Keys} are @acronym{CRC32}:@acronym{CRC16} pairs that uniquely
+identify a file's contents and are used to associate a record with a
+file. Only if the file's key match with the record key, that record is
+actually used for that file.
+
+Keys are stored in key objects, which are instances of the
+@code{CAdPlugDatabase::CKey} class. The class has two attributes,
+@code{crc16} and @code{crc32} which store the two @acronym{CRC}
+values, respectively. It also has the following methods:
+
+@ftable @code
+@item CKey()
+A constructor that creates an empty key object.
+@item CKey(binistream &in)
+A constructor that creates a key from the contents of the input-only
+binary stream, referenced by the only argument.
+
+@item bool operator==(const CKey &key)
+Operator that compares two key objects and returns @samp{true} when
+they are equal. @samp{false} is returned otherwise.
+@end ftable
+
+@node Players using the Database
+@subsection Players using the Database
+
+The following players make active use of the database:
+
+@table @asis
+@item Apogee IMF
+The IMF player uses the database to find out about the timer clock
+speed of a file, since this data is not stored in the file itself.
+@end table
+
+@node Direct Usage
+@subsection Direct Usage
+
+The following methods are for application usage of the database:
+
+@ftable @code
+@item bool load(std::string db_name)
+@itemx bool load(binistream &f)
+Two versions to load a database. The first method takes a string
+containing a file name of a file from which the database is
+loaded. The second method takes a reference to an input-only binary
+stream to load the database from.
+
+@item bool save(std::string db_name)
+@itemx bool save(binostream &f)
+Two versions to save the database. These work analogous to the
+@code{load()} methods, above.
+
+@item bool insert(CRecord *record)
+Inserts the record object, pointed to by the only argument, into the
+database and returns @samp{true} on successful operation. @samp{false}
+is returned otherwise. Duplicate record entries (i.e. records that
+have the same key) cannot be inserted into the database and old ones
+will not automatically be overwritten by the new ones with this
+method. @samp{false} is returned in this case.
+
+@item void wipe(CRecord *record)
+@itemx void wipe()
+Two versions of a method to remove (wipe) a record from the
+database. The first version takes a pointer to a record object as the
+only argument and removes exactly this record from the database. The
+record object itself is deallocated, too. Do not reference it again!
+If the record object is not in the database, nothing is done. The
+second version removes the record at the current position in the
+database.
+
+@item CRecord *search(CKey const &key)
+Takes a reference to a key object, searches for a record with the same
+key value in the database and returns a pointer to this record. The
+@samp{NULL}-pointer is returned if the record could not be found.
+
+@item bool lookup(CKey const &key)
+The same as @code{search()}, but instead of returning a pointer to the
+record, it just positions the internal database pointer to the
+corresponding record. Returns @samp{true} if the record could be found
+and @samp{false} otherwise.
+
+@item CRecord *get_record()
+Returns a pointer to the record at the current position in the
+database. The @samp{NULL}-pointer is returned if an error occured.
+
+@item bool go_forward()
+Advances the internal position in the database by one record. Returns
+@samp{true} on success, @samp{false} otherwise.
+@item bool go_backward()
+The same as @code{go_forward()}, but goes backward by one record.
+@item void goto_begin()
+Goes to the beginning (i.e. the first record) of the database.
+@item void goto_end()
+Goes to the end (i.e. the last record) of the database.
+@end ftable
+
+@node Without CAdPlug
+@section Without CAdPlug
+
+It is also possible to only use specific players from the AdPlug
+library, without using the @code{CAdPlug} class to cycle through them
+all.
+
+If you just want to use a single player class from the library, you
+only include that player's header file in your application's source
+code.
+
+You can construct an instance of that player by either using its
+constructor or by using the @code{factory()} method of that
+class. Both have the same syntax and take a pointer to an initialized
+@code{Copl}-derived object.
+
+Use the player's @code{load()} method to load a file. It takes a
+filename as the first argument and, optionally, a file provider class
+as its last argument.
+
+All other methods have already been explained in the text above.
+
+@node Hacking
+@chapter Hacking
+
+This chapter gives some coding guidelines for people wishing to hack
+around in AdPlug. Be sure to also read the overall and system-specific
+@file{INSTALL} files in the distribution's base directory to learn
+more about the build systems.
+
+@menu
+* Coding Style::
+* Debug Logging::
+@end menu
+
+@node Coding Style
+@section Coding Style
+I do not really enforce any coding style guidelines (i don't adhere to any
+style guidelines myself, so... ;) ), but it would be nice if you follow the
+overall coding style, used throughout most of AdPlug's source files. If you
+don't, that's perfectly okay, too.
+
+Most of today's "super-intelligent" editors, like MSVC's one or GNU Emacs'
+cc-mode, have their own idea of what the code has to look like, anyway. And
+since most people tend to use these, there's no point in torturing them to
+always having to change anything their editor thinks it knows better. ;)
+
+@node Debug Logging
+@section Debug Logging
+
+AdPlug recently offers centralized debug log management. If you like to
+implement debug logging inside your code, please follow these guidelines:
+
+To implement debug logging, @code{#include "debug.h"} in your code
+(this header is @emph{not} being installed with the rest of the
+AdPlug header files into your standard include directory! It is only
+available in AdPlug's @file{src/} subdirectory!).
+
+@file{debug.h} is C code, so it is useable from both C and C++
+sources. The only function you have to use is the
+@code{LogWrite(fmt, ...)} function. @code{LogFile()} is used by AdPlug
+internally. @code{LogWrite()} works exactly like @code{printf()},
+instead that it writes to a logfile, rather than on the console.
+
+Please format your log messages like this:
+
+@itemize @bullet
+@item
+If your method/function is going to output a lot of debug info
+(i.e. more than one line), please put a @code{LogWrite()} directly at
+the beginning of your function, which looks like this:
+
+@example
+LogWrite("*** yourclass::yourmethod(@var{param1}, @var{param2}, @var{...}) ***\n");
+@end example
+
+And put the following line before every return from your function:
+
+@example
+LogWrite("--- yourclass::yourmethod ---\n");
+@end example
+
+This way, one can easily inspect the logfile and know to which
+function every logfile-line belongs. The @code{***} lines mark the
+start of a function, and the @code{---} lines mark the end.
+
+Please substitute @var{param*} with the corresponding parameter values
+of your function, if that is reasonable. For example, it won't help
+much to log a pointer value --- just put something bogus or helpful
+there, or noting (i.e. just a comma, so the logfile reader knows, to
+which parameters the other values correspond). But logging the values
+of passed ints or strings could be very helpful.
+
+@item
+If your method/function is going to output just one line, format the
+line something like this:
+
+@example
+LogWrite("yourclass::yourmethod(@var{param1}, @var{param2}): your message\n");
+@end example
+
+You don't need the @code{***} and @code{---} beginning and end markers
+then.
+
+@item
+For threads, there is no way but to prefix any line with the function
+name, because these messages will be sprayed throughout the logfile.
+@end itemize
+
+@node Player development
+@chapter Player development
+
+Before you try to write a new player for AdPlug, be sure to also read
+through @ref{Hacking}.
+
+@menu
+* Before the work::
+* Main work::
+* Loading and File Providers::
+* Sound generation::
+@end menu
+
+@node Before the work
+@section Before the work
+
+Your player normally consists of two files (the @file{.h} &
+@file{.cpp} files) and you normally name them by the file extensions,
+your player handles. For example, the HSC player consists of the files
+@file{hsc.cpp} & @file{hsc.h}, because it handles @file{.hsc}
+files. This is the same with your player class name. Thus, the HSC
+player's class is called @class{ChscPlayer}. If any of these names
+happens to be already taken for other purposes, just name your player
+something else, appropriately.
+
+@file{player.h} contains the abstract player interface. You have to
+include it in your player to communicate with AdPlug. It also contains
+some very helpful structures for use in your player. You don't need to
+use the structs, but you have to use the methods provided by the
+@code{opl} object (declared in @file{opl.h}, but automatically
+included from @file{player.h}) inside the player class to do the OPL
+I/O and initialization work.
+
+@node Main work
+@section Main work
+
+All you have to do now is to inherit the @class{CPlayer} class into
+your own player class and fill the abstract methods with code. You at
+least have to fill in the following methods:
+
+@example
+bool load(const std::string &filename, const CFileProvider &fp);
+bool update();
+void rewind(int subsong);
+float getrefresh();
+std::string gettype();
+@end example
+
+The other methods from @code{CPlayer} just serve informational
+purposes (as does @code{gettype()}, but it's required anyway) for
+AdPlug's info box and needn't to be filled. It would be nice if you
+fill them anyway, if that's reasonable for your player.
+
+There's one more public method you have to define in your player
+class:
+
+@example
+static CPlayer *factory(Copl *newopl);
+@end example
+
+Since it is static, it isn't already virtually defined in the
+@code{CPlayer} class and you have to add it manually. This method
+should return a pointer to a freshly initialized object of your player
+class. If any errors occured (e.g. not enough memory), return @samp{0}
+instead.
+
+Return true from your @code{load()} method, if the file was loaded
+successfully, or false if it couldn't be loaded for any reason (e.g.
+because AdPlug passed a wrong file to your player). Your
+@code{update()} method will be called with the frequency, you return
+from your @code{getrefresh()} method, in Hz. Return true from
+@code{update()} if your module hasn't ended yet. If it looped or
+ended, return false from that point, but play further for any
+subsequent calls to @code{update()}. AdPlug will rewind or stop your
+player by itself, using the @code{rewind()} method, when necessary.
+
+AdPlug passes the number of the subsong, it wants to play next, to the
+@code{rewind()} method of your player. This can be any value from
+@samp{0} to the value returned by @code{getsubsongs()}. If you haven't
+provided your own @code{getsubsongs()}, AdPlug will presume your
+player doesn't have support for subsongs. In that case, AdPlug will
+always @code{rewind(0)}. Please ignore any value passed to
+@code{rewind()} that is out of spec for your player. This should
+virtually never happen, but who knows. If a value of @samp{-1} is
+given as an argument, you should rewind the currently playing
+subsong.
+
+After initializing your player (either by a call to @code{factory()}
+or by creating an instance by itself), AdPlug normally first calls
+@code{load()} and then @code{getrefresh()} and @code{update()} in a
+loop until something happens (i.e. the user stops playback or the song
+ends). @code{rewind()} and all the informational methods can be called
+anytime in between the other calls, but of course only after
+@code{load()} has been called.
+
+You can add your own constructors, destructors and methods to your
+player object, as you like. AdPlug won't care in any way.
+
+@node Loading and File Providers
+@section Loading and File Providers
+
+The @code{load(const std::string &filename, const CFileProvider &fp)}
+method needs some special explanation. This method takes two
+arguments. The first is a reference to a string containing the
+filename of the main file for your player to load. This is the
+filename the user selected in the frontend (maybe altered by the
+frontend, but not by AdPlug) and does not need to have any meaning to
+your player.
+
+To finally load your files to get to their data, you have to request
+them. This is done through a @dfn{File Provider}. A reference to a
+file provider is always passed as the second argument to your
+@code{load()} method. You will most likely want to load the file,
+using the filename passed as the first argument. To do this, you
+simply call @code{binistream *f = fp.open(filename)}. This method
+returns a pointer to an open, input-only binary stream of the
+requested file. You can now operate on this stream, using its standard
+interface (refer to the manual of the binary I/O stream class library
+for further information). When you're done loading your file, don't
+forget to call @code{fp.close(f)} to close it again. It is very
+important to do this anytime you leave your @code{load()} method! Any
+streams not closed will be left open for the whole lifetime of the
+controlling process!
+
+Don't worry about the passed filename. It normally doesn't need to
+have any meaning to your player. The file provider will know how and
+from where to open the file.
+
+@code{fp.open()} returns a null-pointer if something went wrong
+(e.g. file not found or access denied, etc.). If this happens, return
+@samp{false} from your @code{load()} method immediately. You do not
+have to call @code{fp.close()} in this case.
+
+The @class{CFileProvider} class offers two convenience methods. These
+are @code{unsigned long filesize(binistream *f)} and @code{bool
+extension(const std::string &filename, const std::string
+&extension)}.
+
+@code{filesize()} returns the size in bytes of the stream, pointed to
+by @code{f}, without altering it otherwise. @code{extension()} does a
+filename extension check as follows: The first argument is a reference
+to a string containing a filename. The second argument is a reference
+to a string containing a file extension to check for. If the passed
+filename has got exactly this extension (caselessly), the method
+returns @samp{true}. @code{false} is returned otherwise.
+
+@node Sound generation
+@section Sound generation
+
+You generate sound by using the @code{Copl::write(@var{reg},
+@var{val})} method of the @code{Copl} class, which has been passed to
+your constructor.
+
+@var{reg} is the number of the register of the OPL chip, you want to
+write data into. @var{val} is the value to write into it. There is no
+method to read back written data from an OPL chip, as this also was
+not possible with the original hardware. Log all data into an array if
+you have to remember written values.
+
+If your player supports the dual-OPL2 or OPL3 configurations, you can
+use the method @code{Copl::setchip(@var{n})} to set the output chip
+number, all subsequent @code{write()} methods will write to. As two
+chips can be supported at maximum, the value of @var{n} may only be 0
+or 1 for the first or the second chip, respectively.
+
+Before switching to another chip, your player always has to make sure
+that the configuration, you are going to address, is supported by the
+current OPL class. This can be done by calling the
+@code{Copl::gettype()} method, which will return the currently
+supported OPL chip type as an enumeration of type
+@code{Copl::ChipType}.
+
+If the desired configuration is not supported, your player should
+support playback on any of the other configurations. Your player
+should never switch to another OPL chip when this is not actually
+supported by the OPL class! The sound will be totally messed up.
+
+@node Protracker based players
+@chapter Protracker based players
+
+If you want to create a player for a Protracker-derivative format, the
+generic Protracker player @class{CmodPlayer} that comes with AdPlug can
+be of great help. It supports all standard Protracker features, plus a
+good set of extensions to cope with most derivative formats.
+
+When writing a player for a Protracker-derivative format, it is almost
+always better to use and extend the @code{CmodPlayer} class, instead
+of writing a whole new player.
+
+@menu
+* Features::
+* Defaults::
+* Protracker Loaders::
+* Designing your Loader::
+* Loading Patterns::
+* Loading Instruments::
+* Special Flags::
+* Special Arpeggio::
+@end menu
+
+@node Features
+@section Features
+
+In addition to handling your data just like the original Protracker
+would, AdPlug's generic Protracker player has the following extra
+features:
+
+@itemize @bullet
+@item Special Arpeggio lists, compatible with the SA2 format.
+@item Extendable set of up to 256 note commands.
+@item Simulates many different tracker flavors.
+@item Arbitrary numbers of rows, patterns, tracks, instruments and
+orderlist entries.
+@end itemize
+
+The only current limitation is that it has a maximum 9 voice
+polyphony, which isn't really a limitation, since the OPL2 is just 9
+voices, anyway.
+
+@node Defaults
+@section Defaults
+
+For historical reasons, @code{CmodPlayer} sets defaults to some
+values, so they need not be initialized. These are:
+
+@itemize @bullet
+@item The orderlist is preallocated to 128 entries.
+@item The patterndata is preinitialized to 64 patterns with 9 channels
+and 64 rows each.
+@item The instruments array is preallocated to 250 instruments.
+@item All flags are cleared (simulates Protracker flavor).
+@end itemize
+
+These are mostly standard Protracker limits. They stem from the
+original SA2 defaults, for which this was once the player. Look at the
+@code{CmodPlayer} constructor for info on which variables are
+involved.
+
+@node Protracker Loaders
+@section Protracker Loaders
+
+When you decided to extend the @code{CmodPlayer} class, instead of
+writing a whole new player, you do this by writing a loader for
+it. This is done very similarily to writing a unique player for
+AdPlug. Thus, reading the @ref{Player development} chapter is
+recommended for this task, too.
+
+Instead of naming your player class @code{CxxxPlayer}, you should name
+it @code{CxxxLoader} or something appropriate if the name is already
+taken. You then publicly inherit the @code{CmodPlayer} class and fill
+the missing methods with code. These are now:
+
+@example
+static CPlayer *factory(Copl *newopl);
+bool load(const std::string &filename, const CFileProvider &fp);
+float getrefresh();
+std::string gettype();
+@end example
+
+Plus maybe some (or all) of the other informational methods, listed in
+the @ref{Player development} chapter. Refer also to that chapter to
+see what the above methods are about.
+
+@node Designing your Loader
+@section Designing your Loader
+
+File validation and initial loading is the same as it would be with
+any other player. One speciality is that you have to call
+@code{rewind(0)} whenever you completely loaded a valid file. Don't
+call it when you just exit your loader because the file was invalid!
+
+The Protracker player needs at least an orderlist, the patterns and
+the instruments to function. Most of the time, you have to convert
+these between your file's ordering and @code{CmodPlayer}'s internal
+ordering. Look in the file @file{protrack.cpp}, @code{CmodPlayer}'s
+actual sources, for a list on how these constructs are ordered
+internally.
+
+Also, please look up the @ref{Defaults} section to see if you need to
+reallocate any of the defaults.
+
+There are some variables that you have automatically inherited with
+your new loader and that you have to set in order to tell the
+Protracker player something about your loaded module. These are the
+following:
+
+@vtable @code
+@item length
+The orderlist length. When @code{CmodPlayer}'s orderlist pointer
+equals or is bigger than this length, it is automatically wrapped
+around to @code{restartpos}. This variable has no default.
+
+@item trackord
+Refer to @ref{Loading Patterns} below on this one. This variable
+defaults to @samp{0}.
+
+@item restartpos
+The restarting position in the orderlist, when @code{length} is
+exceeded. This variable has no default.
+
+@item activechan
+A flag array, telling the player which channels in every pattern are
+actually active and to be played. The ordering of this variable is a
+bit awkward, so be careful! It is a 32-bit @code{unsigned long},
+holding the activeness of a channel in each of its bits,
+@emph{starting at the highest order bit}. It can hold values for up to
+32 channels. So, to set channel 0 active, you have to set bit 31
+(counting from bit 0) to @samp{1} and so on. Setting any bits for
+channels that are not defined has no effect. This variable defaults to
+all bits set to 1, meaning all channels are enabled.
+
+@item initspeed
+Initial protracker-compatible speed setting. This variable defaults to
+@samp{6}, the standard Protracker speed setting.
+
+@item bpm
+Initial protracker-compatible bpm (sometimes called tempo)
+setting. This variable has no default.
+
+@item flags
+Refer to @ref{Special Flags} below. This variable defaults to
+@samp{Standard}, which sets standard Protracker defaults and imposes
+no specialities.
+
+@item nop
+The number of patterns in your module. You don't need to set this
+value. If you leave it at @samp{0}, @code{CmodPlayer} will
+automatically determine the number of @emph{accessed} patterns (which
+need not be the same as the actual number of patterns in your module)
+from the orderlist, in the @code{rewind()} method. The value serves
+only informational purposes, anyway. It is not needed for the actual
+playback. If you think you know better than @code{CmodPlayer}, feel
+free to set it to something else and @code{CmodPlayer} won't touch it
+anymore and display your value instead. This variable defaults to
+@samp{0}.
+@end vtable
+
+@node Loading Patterns
+@section Loading Patterns
+
+AdPlug's Protracker player stores the tracks (or channels, as some may
+call them), that make up a pattern, in a way that makes it possible
+for you to reorder and reuse them in an easy way. This also makes
+storing patterns in the classic way a bit awkward.
+
+If you just want to store your tracks the classic Protracker way
+(usually the case), first use the @code{CmodPlayer::init_trackord()}
+method to do an initial setup. Then store your tracks in a sequential
+manner, counting from 0, in the @code{tracks} array. That is, for the
+first 9 channels of your first pattern, use @code{tracks[0..9]}. The
+second dimension of this array holds the rows of each channel. For the
+next 9 channels, you use @code{tracks[10..19]}, and so on.
+
+If you want to make use of the reorder/reuse feature of the
+@code{trackord} array, please refer to the @file{sa2.cpp} source
+file. This player utilizes this method.  Basically, the
+@code{trackord} array tells the player which track out of the
+@code{tracks} array it has to insert for each of the 9 tracks of a
+pattern. Thus, the first dimension of this array stands for the
+corresponding pattern and the next dimension holds the entries for all
+the 9 tracks.
+
+@code{CmodPlayer} orders its note data, in the @code{Tracks} struct,
+the following way:
+
+@code{note} holds the note value. A value of @samp{0} means @samp{no
+note}. A value of @samp{127} means @samp{key off}. Values from
+@samp{1} to @samp{96} are actual notes to be played. Everything else
+is ignored. The octaves are encoded with the actual note values. Thus,
+notes from @samp{1} to @samp{12} are the 12 halftone-steps of the
+first, lowest octave, @samp{13} to @samp{24} are those of the next
+lowest octave, and so on. Refer to the source code to see which
+frequencies are actually associated with the note values.
+
+@code{inst} holds the instrument to be played with this note. Again, a
+@samp{0} value means no instrument is associated with this note and
+the last active instrument is taken instead. Otherwise, the instrument
+with the number @code{inst} minus 1 is fetched from the @code{inst}
+array (it's 0 based).
+
+@code{command} holds the command to be issued with this note. All
+available commands are listed in the following table:
+
+@multitable {@code{255--}} {Command descriptionwifuehwuifhw} {Parametersewufwuhwjjhhui} {@code{[0-3,F]iufhu}}
+@headitem Value @tab Command description @tab Parameters @tab Range
+@item @code{@ @ 0xy} @tab Arpeggio @tab @code{xy}=1st note,2nd note @tab @code{[0-F]}
+@item @code{@ @ 1xx} @tab Frequency slide up @tab @code{xx}=sliding speed @tab @code{[0-FF]}
+@item @code{@ @ 2xx} @tab Frequency slide down @tab @code{xx}=sliding speed @tab @code{[0-FF]}
+@item @code{@ @ 3xx} @tab Tone portamento @tab @code{xx}=sliding speed @tab @code{[0-FF]}
+@item @code{@ @ 4xy} @tab Vibrato @tab @code{xx}=speed,depth @tab @code{[0-F]}
+@item @code{@ @ 5xy} @tab Tone portamento & volume slide @tab @code{xy}=vol up|vol down @tab @code{[0-FF]}
+@item @code{@ @ 6xy} @tab Vibrato & volume slide @tab @code{xy}=vol up|vol down @tab @code{[0-FF]}
+@item @code{@ @ 7xx} @tab Set tempo @tab @code{xx}=new tempo @tab @code{[0-FF]}
+@item @code{@ @ 8--} @tab Release sustaining note
+@item @code{@ @ 9xy} @tab Set carrier/modulator volume @tab @code{xy}=car vol|mod vol @tab @code{[0-F]}
+@item @code{@ 10xy} @tab SA2 volume slide @tab @code{xy}=vol up|vol down @tab @code{[0-F]}
+@item @code{@ 11xx} @tab Position jump @tab @code{xx}=new position @tab @code{[0-FF]}
+@item @code{@ 12xx} @tab Set carr. & mod. volume @tab @code{xx}=new volume @tab @code{[0-3F]}
+@item @code{@ 13xx} @tab Pattern break @tab @code{xx}=new row @tab @code{[0-FF]}
+@item @code{@ 14??} @tab Extended command:
+@item @code{@ @ @ 0y} @tab Set chip tremolo @tab @code{y}=new depth @tab @code{[0-1]}
+@item @code{@ @ @ 1y} @tab Set chip vibrato @tab @code{y}=new depth @tab @code{[0-1]}
+@item @code{@ @ @ 3y} @tab Retrig note @tab @code{y}=retrig speed @tab @code{[0-F]}
+@item @code{@ @ @ 4y} @tab Fine volume slide up @tab @code{y}=vol up @tab @code{[0-F]}
+@item @code{@ @ @ 5y} @tab Fine volume slide down @tab @code{y}=vol down @tab @code{[0-F]}
+@item @code{@ @ @ 6y} @tab Fine frequency slide up @tab @code{y}=freq up @tab @code{[0-F]}
+@item @code{@ @ @ 7y} @tab Fine frequency slide down @tab @code{y}=freq down @tab @code{[0-F]}
+@item @code{@ @ @ 8y} @tab Pattern delay (rows) @tab @code{y}=rows to delay @tab @code{[0-F]}
+@item @code{@ 15xx} @tab SA2 set speed @tab @code{xx}=new speed @tab @code{[0-FF]}
+@item @code{@ 16xy} @tab AMD volume slide @tab @code{xy}=vol up|vol down @tab @code{[0-F]}
+@item @code{@ 17xx} @tab Set instrument volume @tab @code{xx}=new volume @tab @code{[0-3F]}
+@item @code{@ 18xx} @tab AMD set speed @tab @code{xx}=new speed @tab @code{[0-FF]}
+@item @code{@ 19xx} @tab RAD set speed @tab @code{xx}=new speed @tab @code{[0-FF]}
+@item @code{@ 20xx} @tab RAD volume slide @tab @code{xx}=vol up/down @tab @code{[0-FF]}
+@item @code{@ 21xx} @tab Set modulator volume @tab @code{xx}=new volume @tab @code{[0-3F]}
+@item @code{@ 22xx} @tab Set carrier volume @tab @code{xx}=new volume @tab @code{[0-3F]}
+@item @code{@ 23xx} @tab Fine frequency slide up @tab @code{xx}=freq up @tab @code{[0-FF]}
+@item @code{@ 24xx} @tab Fine frequency slide down @tab @code{xx}=freq down @tab @code{[0-FF]}
+@item @code{@ 25xy} @tab Set carrier/modulator waveform @tab @code{xy}=carr wav|mod wav @tab @code{[0-3,F]}
+@item @code{@ 26xy} @tab Volume slide @tab @code{xy}=vol up|vol down @tab @code{[0-F]}
+@item @code{@ 27xy} @tab Set chip tremolo/vibrato @tab @code{xy}=tr depth|vb depth @tab @code{[0-1]}
+@item @code{@ 28xy} @tab DTM frequency slide @tab @code{xy}=frames up|down @tab @code{[0-F]}
+@item @code{@ 29xx} @tab Pattern delay (frames) @tab @code{xx}=frames to delay @tab @code{[0-FF]}
+@item @code{255--} @tab No operation (NOP)
+@end multitable
+
+The @code{param1} and @code{param2} variables hold the command's
+parameters. These are command-dependant. Refer to the table above to
+see what they do with each of the commands and their value ranges. An
+@samp{xx} in the @emph{Parameters} column means that @code{param1} and
+@code{param2} form one 2-digit parameter, with @code{param1} being the
+leftmost decimal. Otherwise, @samp{x} refers to @code{param1} and
+@samp{y} to @code{param2}.
+
+@node Loading Instruments
+@section Loading Instruments
+
+For the instrument data, @code{CmodPlayer} stores it in the
+@code{inst[].data[]} array, in the following way:
+
+@multitable {Index} {Modulator} {Amp Mod / Vib / EG type / Key Scaling / Multiple} {@samp{0x00}}
+@headitem Index @tab Operator @tab Description @tab Register
+@item 0 @tab Channel @tab (Panning) / Feedback strength / Connection type @tab @samp{0xc0}
+@item 1 @tab Modulator @tab Tremolo / Vibrato / Sustain / KSR / Multiple @tab @samp{0x20}
+@item 2        @tab Carrier @tab Tremolo / Vibrato / Sustain / KSR / Multiple @tab @samp{0x23}
+@item 3 @tab Modulator @tab Attack Rate / Decay Rate @tab @samp{0x60}
+@item 4 @tab Carrier @tab Attack Rate / Decay Rate @tab @samp{0x63}
+@item 5 @tab Modulator @tab Sustain Level / Release Rate @tab @samp{0x80}
+@item 6 @tab Carrier @tab Sustain Level / Release Rate @tab @samp{0x83}
+@item 7 @tab Modulator @tab Wave Select @tab @samp{0xe0}
+@item 8 @tab Carrier @tab Wave Select @tab @samp{0xe3}
+@item 9 @tab Modulator @tab Key scaling level / Operator output level @tab @samp{0x40}
+@item 10 @tab Carrier @tab Key scaling level / Operator output level @tab @samp{0x43}
+@end multitable
+
+There are three extensions to the standard instrument data. These are
+also stored within the @code{inst[]} array.
+
+@enumerate
+@item The @emph{Special Arpeggio}. This is explained in the
+@ref{Special Arpeggio} section, below.
+
+@item The @code{slide} variable. This is a pre-slide value that is
+always added to the frequency of the note, whenever this instrument is
+to be played.
+
+@item The @code{misc} variable. This is just the holder for the value
+of the 0xbd register (i.e. the "drums'n'misc" register) of the OPL.
+@end enumerate
+
+@node Special Flags
+@section Special Flags
+
+The @code{flags} variable holds special flags to change the behaviour
+of the player. These are:
+
+@table @samp
+@item Standard
+Act like standard Protracker would. This is the default.
+
+@item Decimal
+Command parameters are decimal values, not hexadecimal. For split
+parameter commands (i.e. commands with two parameters, like
+@samp{0xy}), this has no effect, since decimal values would be from
+@samp{0} to @samp{9}, anyway. But commands that take both parameters
+as one value (i.e. like @samp{1xx}) now take values from @samp{0} to
+@samp{99} and handle them properly (i.e. decimal wrap-around is now at
+@samp{9} to @samp{10} and not at @samp{F} to @samp{10}).
+
+@item Faust
+Treat the files like @emph{Faust Music Creator} does. This tracker
+uses a different volume handling scheme. In standard Protracker, the
+volume is computed as follows:
+
+@example
+final volume = channel volume = instrument volume
+@end example
+
+In @emph{Faust Music Creator}, it is done like this:
+
+@example
+final volume = (channel volume + instrument volume) / 2
+@end example
+
+@item NoKeyOn
+This prevents the OPL key off/on toggle on every newly played
+note. Some trackers require it that way...
+
+@item Opl3
+Sets the player into OPL3 mode. Extended register settings of the OPL3
+become effective and the player initializes the OPL chip to OPL3
+mode. This has no effect if the hardware does not support OPL3
+features. Be careful to set panning information in register
+@code{0xc0} or else no sound will appear.
+
+@item Tremolo
+Sets tremolo depth to 4.8dB upon each @code{rewind()}.
+
+@item Vibrato
+Sets Vibrato depth to 14 cents upon each @code{rewind()}.
+
+@item Percussion
+Enables the OPL percussion mode.
+@end table
+
+These flags can be set and unset at any time. To set a flag, just
+binary @emph{OR} it with the @code{flags} variable. Use the
+@code{enum Flags} data type, defined in the @code{CmodPlayer} class
+for this purpose.
+
+@node Special Arpeggio
+@section Special Arpeggio
+
+To use the @emph{Special Arpeggio} facility, you have to initalize it
+first. Use the @code{init_specialarp()} method for this
+purpose. @code{CmodPlayer}'s deconstructor automatically handles the
+deinit for you.
+
+The special arpeggio uses the 4 variables @code{arpstart},
+@code{arpspeed}, @code{arppos} and @code{arpspdcnt} of the
+@code{Instrument} struct.
+
+[TODO: actually explain. Refer to sa2.[cpp,h] and the original SA2 docs in
+the meantime. The following table summarizes the special commands.]
+
+@multitable {Value} {Set carr. & mod. volume}
+@headitem Value @tab Command description
+@item @samp{252} @tab Set carr. & mod. volume
+@item @samp{253} @tab Release sustaining note
+@item @samp{254} @tab Arpeggio loop
+@item @samp{255} @tab End of special arpeggio
+@end multitable
+
+@node Copying This Manual
+@appendix Copying This Manual
+
+@menu
+* GNU Free Documentation License::  License for copying this manual.
+@end menu
+
+@include fdl.texi
+
+@node Method Index
+@unnumbered Method Index
+
+@printindex fn
+
+@node Variable Index
+@unnumbered Variable Index
+
+@printindex vr
+
+@node Class Index
+@unnumbered Class Index
+
+@printindex tp
+
+@shortcontents
+
+@bye