     [file version.texi not included]

AdPlug core library
*******************

This manual documents the AdPlug core library, version VERSION.

Copyright © 2002, 2003 Simon Peter <dn.tlp@gmx.net>

     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.''

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 (OPL2) audio board, on top of an OPL2 emulator or by using the real hardware. No OPL2 chip is required for playback.

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.

  * A2M: AdLib Tracker 2 by subz3ro

       * Unimplemented commands (version 1-4): FF1 - FF9, FAx - FEx

       * Unimplemented commands (version 5-8): Gxy, Hxy, Kxy - &xy

       * In version 5-8 files, instrument panning & the flags byte is ignored

       * Only SixPack compressed and uncompressed files are supported

       * All OPL3 functionality is absent (not possible with AdLib)

  * AMD: AMUSIC Adlib Tracker by Elyssis

  * BAM: Bob's Adlib Music Format by Bob

  * CFF: BoomTracker 4.0 by CUD

  * CMF: Creative Music File Format by Creative Technology

       * Unimplemented: AdLib rhythm mode

  * D00: EdLib by Vibrants

       * Bugs: Hard restart SR sometimes sound wrong

  * DFM: Digital-FM by R.Verhaag

  * DMO: Twin TrackPlayer by TwinTeam

  * DTM: DeFy Adlib Tracker by DeFy

  * HSC: HSC Adlib Composer by Hannes Seifert, HSC-Tracker by Electronic Rats

  * HSP: HSC Packed by Number Six / Aegis Corp.

  * IMF: Apogee IMF File Format by Apogee

  * KSM: Ken Silverman's Adlib Music Format by Ken Silverman

       * Needs file insts.dat in the same directory as loaded file

  * LAA: LucasArts AdLib Audio File Format by LucasArts

       * Bugs: Some volumes are a bit off

  * LDS: LOUDNESS Music Format (preliminary)

       * Bugs: Undocumented format, more to come.

  * M: Ultima 6 Music Format by Origin

  * MAD: Mlat Adlib Tracker

  * MID: MIDI Audio File Format

  * MKJ: MKJamz by M \ K Productions (preliminary)

  * MTK: MPU-401 Trakker by SuBZeR0

  * RAD: Reality ADlib Tracker by Reality

  * RAW: RdosPlay RAW file format by RDOS

       * Unimplemented: OPL3 register writes (not possible with AdLib)

  * ROL: AdLib Visual Composer by AdLib Inc.

       * Needs file standard.bnk in the same directory as loaded file

  * S3M: Scream Tracker 3 by Future Crew

       * Bugs: Extra Fine Slides (EEx, FEx) & Fine Vibrato (Uxy) are inaccurate

  * SA2: Surprise! Adlib Tracker 2 by Surprise! Productions

  * SAT: Surprise! Adlib Tracker by Surprise! Productions

  * SCI: Sierra's AdLib Audio File Format by Sierra On-Line Inc.

       * Needs file ???patch.003 in the same directory as loaded file, while ??? are the first 3 characters of the loaded file's filename

       * Bugs: Some instruments are messed up

  * SNG: SNGPlay by BUGSY of OBSESSION

  * SNG: Faust Music Creator by FAUST

  * SNG: Adlib Tracker 1.0 by TJ

       * Needs file SONGNAME.ins in the same directory as loaded file, while SONGNAME is the song's filename without .sng extension.

  * XAD: eXotic ADlib Format by Riven the Mage

  * XMS: XMS-Tracker by MaDoKaN/E.S.G

  * XSM: eXtra Simple Music by Davey W Taylor

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.

Concepts
========

All of AdPlug's header files are installed under the directory adplug inside your specified include path. Whenever i refer to a specific header file in this manual, i mean the filename with the path adplug/ prepended.

AdPlug can be divided into 2 sections and 3 layers of functionality. These are the Playback and Sound generation sections and the Frontend, Mid-End and 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.

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 adplug.h, fprovide.h, players.h and database.h belong to the Mid-End layer. From your application's point of view, you only have to include the 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 OPL2 command data. It then passes this data to the sound generation section, which generates the final audio data. The header player.h and all player header files belong to the Backend layer.

Sound generation section
------------------------

The Sound generation section is responsible for generating the OPL2'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: emuopl.h, realopl.h, silentopl.h and analopl.h. All classes inside these headers are derived from the abstract base class Copl, declared inside the 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.

emuopl.h provides the class CEmuopl, which is a wrapper class around Tatsuyuki Satoh's fmopl OPL2 emulator, which generates wave audio data to be routed back to the application.

realopl.h provides the class CRealopl, which outputs to a real hardware OPL2 chip. No data is routed back to the application. This class is currently only working on x86 hardware.

silentopl.h provides the class CSilentopl, which is a dummy OPL2, which generates nothing. All data sent to it is forgotten immediately. No data is routed back to the application.

analopl.h provides the class CAnalopl, which is the same as 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.

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 Advanced Usage.

For basic usage, you need to include the header 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.

adplug.h provides the class CAdPlug, which in turn provides the load and playback facilities for the song files. CAdPlug is a static class, you do not need to instantiate an object of it.

Loading
=======

To load a supported file for playback, you use the method CAdPlug::factory(const std::string &FILENAME, Copl *OPL, ...). The method takes more arguments, but we don't need them for basic usage. They are explained in Advanced Usage.

The first argument, FILENAME, is a string object, containing the filename of the sound file to be loaded with AdPlug. The second argument, 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 FILENAME does not need any more explanation, so i will just explain how to get an instance of a Copl derived class:

If you want to use the OPL2 emulator class CEmuopl, you have to include the header emuopl.h inside your application's source code. CEmuopl's constructor looks like this: CEmuopl::CEmuopl(int RATE, bool BIT16, bool USESTEREO). The RATE argument specifies the playback frequency rate in Hz. The BIT16 argument specifies whether to create 8 bit or 16 bit wave audio data. If it is set, 16 bit data is created. The 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 realopl.h inside your application and use the class CRealopl. Its constructor just takes one optional argument, specifying the hardware OPL2's base port, which is 0x388 by default. As an option, you can include analopl.h instead, using the class CAnalopl, and also use the analyzer interface instead. This is explained in Audio output.

For no audio generation at all, include the header silentopl.h inside your application and use the class CSilentopl. Its constructor does not take any arguments.

Playback
========

On successful operation, CAdPlug's 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:

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.

bool update()
     The most important method of them all. You have to call this method in a loop. As long as it returns true, the song has not ended yet. At some point, it will start to always return 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 rewind() method to rewind it or stop playing.

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 -1 is given, the currently selected subsong will be rewound. If the player does not support subsongs, just don't provide an argument.

float getrefresh()
     Returns a float containing the player object's idea of with what frequency its update() method should be called, in Hz. This can change at any time, so you have to poll it before every call to update().

unsigned int getsubsongs()
     Returns the number of subsongs of the currently loaded song. If the player doesn't support subsongs, 1 is returned, representing the only ``subsong''.

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 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 void CEmuopl::update(short *BUF, int SAMPLES) method. The BUF argument is a pointer to a previously allocated memory block of the size specified by the SAMPLES argument, in samples. The method will fill the specified amount of samples into the buffer. Multibyte samples have the machine's byte ordering.

The volume analyzing hardware OPL2 class CAnalopl also has some data readback methods:

int getcarriervol(unsigned int v)
     Returns the carrier's current volume of the OPL2 channel given as the only argument.

int getmodulatorvol(unsigned int v)
     Returns the modulator's current volume of the OPL2 channel given as the only argument.

bool getkeyon(unsigned int v)
     Returns whether a key-on event just happened on the OPL2 channel given as the only argument.

Getting Playback Information
============================

During playback, it is possible to gain some replay statistics with some players. The following methods are for getting playback informations:

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.

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.

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.

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.

unsigned int getpatterns()
     Returns the number of patterns in the current song. 0 is returned if the format isn't pattern-based.

unsigned int getpattern()
     Returns the number of the currently playing pattern. 0 is returned if the format isn't pattern-based.

unsigned int getorders()
     Returns the length of the order list of the current song. 0 is returned if the format doesn't have an order list.

unsigned int getorder()
     Returns the number of the currently playing order list entry. 0 is returned if the format doesn't have an order list.

unsigned int getrow()
     Returns the number of the currently playing row inside the current pattern. 0 is returned if the format isn't pattern-based.

unsigned int getspeed()
     Returns the current speed setting of the song. 0 is returned if the format doesn't support Protracker-based speed settings.

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. 0 is returned if the format doesn't define any instruments.

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.

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:

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 -1, the currently selected subsong's length will be returned.

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:

#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);
}

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.

Player Lists
============

There is another argument to the CAdPlug::factory(const std::string &fn, Copl *opl, const CPlayers &PL = players, ...) method. The argument PL is a reference to an object holding a Player List.

A player list object is an instance of the CPlayers class (not to be confused with the CPlayer class). The object can be constant and even static (so it is possible to pass a temporary object, created on the fly).

The CPlayers class itself is not much more than a specialized std::list from the STL, holding pointers to objects of type CPlayerDesc, which are explained below. Look into the STL documentation for more information on std::list functionality.

The 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:

Factory factory
     The Factory type defines a pointer to a static method inside a class, inherited from CPlayer, taking a pointer to a 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 Copl-derived object and returns a pointer to an initialized instance of the same player class, this CPlayerDesc object describes.

std::string filetype
     This is a string containing the unique file type identifier of the player class, this CPlayerDesc object describes. The string normally contains the name of the file format, which the belonging player class handles. This string should be unique.

In addition, CPlayerDesc has the following methods:

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 ASCIIZ string, holding many ASCIIZ strings with all file extensions to be associated with the accompanying player class. To create such a string, include the leading . with all file extensions and terminate any file extension entry with a \0 character. Concatenate all entries one after the other, forming a string of strings. Terminate the last entry with another \0 character, so the final string is doubly terminated.

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.

const char *get_extension(unsigned int n)
     Returns a pointer to the N-th file extension string in the file extension list. If N is out of range, a NULL-pointer is returned instead.

The CPlayers class itself adds two more methods to the inherited std::list interface:

const CPlayerDesc *lookup_filetype(const std::string &ftype)
     Returns a pointer to the first occurence of a CPlayerDesc object with a file type of 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 NULL-pointer if returned instead.

const CPlayerDesc *lookup_extension(const std::string &extension)
     Returns a pointer to the first occurence of a CPlayerDesc object, defining a file extension of EXTENSION, passed as the only argument. Since file extensions are not necessarily unique in a CPlayers list, it is often much more efficient to use the search facilities provided by the STL. If no object, specifying the given file extension, could be found, a NULL-pointer is returned instead.

Thus, the CPlayers class holds a list of player descriptions. This list is used by the 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 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.

File Providers
==============

File Providers are special classes that provide abstracted access to files. AdPlug's player classes request files using a file provider, in their 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 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 CFileProvider, which is declared in the header fprovide.h. This class defines the following methods:

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, IEEE-754 floating-point numbers). If the file could not be opened, the NULL-pointer is returned instead.

void close(binistream *) const
     An abstract virtual method that takes an input-only binary stream, which was formerly created with the open() method, and closes this stream.

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 true if they match. false is returned otherwise.

unsigned long filesize(binistream *f)
     This static method takes an input-only binary stream, previously returned by the open() method, and returns the total size, in bytes, of the associated file. The stream's state is not altered.

If you like to create your own file provider, you have to inherit from this class and implement the methods open() and 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 fprovide.h: 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 CAdPlug::factory() method as last argument. If it is not provided, it is a temporary instance of CProvider_Filesystem by default. The method passes this object on to all player objects' load() methods, it tries to open the file with. The player objects' load() methods also take the file provider object as their last argument and default to CProvider_Filesystem if none is given.

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 adplugdb command. Usage of this command is explained in its own manual page.

The application's interface to the database is defined through the CAdPlugDatabase class, residing in the header file database.h.

If you just want to pass a database for AdPlug to make use of it, reading Usage with CAdPlug is sufficient. If you want to write a complete database manipulation application, you have to read the other subsections as well.

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 adplug.h within your application to do this.

To hand a database to AdPlug, you have to initialize an instance of 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 Records). This is most preferably done by loading an already existing database from a file. To do this, you use the load(std::string  DB_NAME) method of the class. This will merge any records in the database file 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 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.

Records
-------

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 CAdPlugDatabase::CRecord. All records have at least three common attributes:

RecordType type
     Specifies what type of data this record holds. RecordType is an enumeration variable with the following values:

     Plain
          This record doesn't store any more information than the three standard attributes.

     SongInfo
          This record additionally stores song name and author information.

     ClockSpeed
          This record additionally stores timer clock speed information.

CKey key
     This is the unique key, allocated for any record in the database. See Keys.

std::string filetype
     Holds the unique file type of the file associated with the record. This value is taken from the player list (see Player Lists).

The common base class CAdPlugDatabase::CRecord defines a static method factory(RecordType type) for application usage that returns a pointer to a newly allocated CRecord object, or the 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:

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 NULL-pointer is returned if the record type couldn't be determined from the stream's data.

void write(binostream &out)
     Writes the record's contents to the output-only binary stream, referenced by the only argument.

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.

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.

void read_own(binistream &in)
void write_own(binostream &out)
bool user_read_own(std::istream &in, std::ostream &out)
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.

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.

Keys
----

Keys are CRC32: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 CAdPlugDatabase::CKey class. The class has two attributes, crc16 and crc32 which store the two CRC values, respectively. It also has the following methods:

CKey()
     A constructor that creates an empty key object.

CKey(binistream &in)
     A constructor that creates a key from the contents of the input-only binary stream, referenced by the only argument.

bool operator==(const CKey &key)
     Operator that compares two key objects and returns true when they are equal. false is returned otherwise.

Players using the Database
--------------------------

The following players make active use of the database:

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.

Direct Usage
------------

The following methods are for application usage of the database:

bool load(std::string db_name)
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.

bool save(std::string db_name)
bool save(binostream &f)
     Two versions to save the database. These work analogous to the load() methods, above.

bool insert(CRecord *record)
     Inserts the record object, pointed to by the only argument, into the database and returns true on successful operation. 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. false is returned in this case.

void wipe(CRecord *record)
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.

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 NULL-pointer is returned if the record could not be found.

bool lookup(CKey const &key)
     The same as search(), but instead of returning a pointer to the record, it just positions the internal database pointer to the corresponding record. Returns true if the record could be found and false otherwise.

CRecord *get_record()
     Returns a pointer to the record at the current position in the database. The NULL-pointer is returned if an error occured.

bool go_forward()
     Advances the internal position in the database by one record. Returns true on success, false otherwise.

bool go_backward()
     The same as go_forward(), but goes backward by one record.

void goto_begin()
     Goes to the beginning (i.e. the first record) of the database.

void goto_end()
     Goes to the end (i.e. the last record) of the database.

Without CAdPlug
===============

It is also possible to only use specific players from the AdPlug library, without using the 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 factory() method of that class. Both have the same syntax and take a pointer to an initialized Copl-derived object.

Use the player's 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.

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 INSTALL files in the distribution's base directory to learn more about the build systems.

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. ;)

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, #include "debug.h" in your code (this header is NOT being installed with the rest of the AdPlug header files into your standard include directory! It is only available in AdPlug's src/ subdirectory!).

debug.h is C code, so it is useable from both C and C++ sources. The only function you have to use is the LogWrite(fmt, ...) function. LogFile() is used by AdPlug internally. LogWrite() works exactly like printf(), instead that it writes to a logfile, rather than on the console.

Please format your log messages like this:

  * If your method/function is going to output a lot of debug info (i.e. more than one line), please put a LogWrite() directly at the beginning of your function, which looks like this:

          LogWrite("*** yourclass::yourmethod(PARAM1, PARAM2, ...) ***\n");

     And put the following line before every return from your function:

          LogWrite("--- yourclass::yourmethod ---\n");

     This way, one can easily inspect the logfile and know to which function every logfile-line belongs. The *** lines mark the start of a function, and the --- lines mark the end.

     Please substitute 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.

  * If your method/function is going to output just one line, format the line something like this:

          LogWrite("yourclass::yourmethod(PARAM1, PARAM2): your message\n");

     You don't need the *** and --- beginning and end markers then.

  * For threads, there is no way but to prefix any line with the function name, because these messages will be sprayed throughout the logfile.

Player development
******************

Before you try to write a new player for AdPlug, be sure to also read through Hacking.

Before the work
===============

Your player normally consists of two files (the .h & .cpp files) and you normally name them by the file extensions, your player handles. For example, the HSC player consists of the files hsc.cpp & hsc.h, because it handles .hsc files. This is the same with your player class name. Thus, the HSC player's class is called ChscPlayer. If any of these names happens to be already taken for other purposes, just name your player something else, appropriately.

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 opl object (declared in opl.h, but automatically included from player.h) inside the player class to do the OPL I/O and initialization work.

Main work
=========

All you have to do now is to inherit the CPlayer class into your own player class and fill the abstract methods with code. You at least have to fill in the following methods:

     bool load(const std::string &filename, const CFileProvider &fp);
     bool update();
     void rewind(int subsong);
     float getrefresh();
     std::string gettype();

The other methods from CPlayer just serve informational purposes (as does 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:

     static CPlayer *factory(Copl *newopl);

Since it is static, it isn't already virtually defined in the 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 0 instead.

Return true from your 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 update() method will be called with the frequency, you return from your getrefresh() method, in Hz. Return true from 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 update(). AdPlug will rewind or stop your player by itself, using the rewind() method, when necessary.

AdPlug passes the number of the subsong, it wants to play next, to the rewind() method of your player. This can be any value from 0 to the value returned by getsubsongs(). If you haven't provided your own getsubsongs(), AdPlug will presume your player doesn't have support for subsongs. In that case, AdPlug will always rewind(0). Please ignore any value passed to rewind() that is out of spec for your player. This should virtually never happen, but who knows. If a value of -1 is given as an argument, you should rewind the currently playing subsong.

After initializing your player (either by a call to factory() or by creating an instance by itself), AdPlug normally first calls load() and then getrefresh() and update() in a loop until something happens (i.e. the user stops playback or the song ends). rewind() and all the informational methods can be called anytime in between the other calls, but of course only after 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.

Loading and File Providers
==========================

The 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 File Provider. A reference to a file provider is always passed as the second argument to your 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 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 fp.close(f) to close it again. It is very important to do this anytime you leave your 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.

fp.open() returns a null-pointer if something went wrong (e.g. file not found or access denied, etc.). If this happens, return false from your load() method immediately. You do not have to call fp.close() in this case.

The CFileProvider class offers two convenience methods. These are unsigned long filesize(binistream *f) and bool extension(const std::string &filename, const std::string &extension).

filesize() returns the size in bytes of the stream, pointed to by f, without altering it otherwise. 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 true. false is returned otherwise.

Protracker based players
************************

If you want to create a player for a Protracker-derivative format, the generic Protracker player 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 CmodPlayer class, instead of writing a whole new player.

Features
========

In addition to handling your data just like the original Protracker would, AdPlug's generic Protracker player has the following extra features:

  * Special Arpeggio lists, just like in the SA2 format.

  * Extendable set of up to 256 note commands.

  * Up to 16 behaviour changing flags.

  * Arbitrary numbers of rows, patterns, tracks, instruments and orderlist entries.

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.

Defaults
========

For historical reasons, CmodPlayer sets defaults to some values that needn't be initialized by you. These are:

  * The orderlist is preallocated to 128 entries.

  * The patterndata is preinitialized to 64 patterns with 9 channels and 64 rows each.

  * The instruments array is preallocated to 250 instruments.

These are mostly standard Protracker limits. They stem from the original SA2 defaults, for which this was once the player. Look at the CmodPlayer constructor for info on which variables are involved.

Protracker Loaders
==================

When you decided to extend the 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 Player development chapter is recommended for this task, too.

Instead of naming your player class CxxxPlayer, you should name it CxxxLoader or something appropriate if the name is already taken. You then publicly inherit the CmodPlayer class and fill the missing methods with code. These are now:

     static CPlayer *factory(Copl *newopl);
     bool load(const std::string &filename, const CFileProvider &fp);
     float getrefresh();
     std::string gettype();

Plus maybe some (or all) of the other informational methods, listed in the Player development chapter. Refer also to that chapter to see what the above methods are about.

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 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 CmodPlayer's internal ordering. Look in the file protrack.cpp, CmodPlayer's actual sources, for a list on how these constructs are ordered internally.

Also, please look up the 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:

length
     The orderlist length. When CmodPlayer's orderlist pointer equals or is bigger than this length, it is automatically wrapped around to restartpos.

     This variable has no default.

trackord
     Refer to Loading Patterns below on this one.

     This variable defaults to 0.

restartpos
     The restarting position in the orderlist, when length is exceeded.

     This variable has no default.

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 16-bit unsigned short, holding the activeness of a channel in each of its bits, starting at the highest order bit. It also holds values for 16 channels and you can only use the lower 9. So, to set channel 0 active, you have to set bit 15 (counting from bit 0) to 1 and so on. You only use the upper 9 bits of this variable. Setting the lower bits will have no effect.

     This variable defaults to 0xffff, meaning all channels are enabled.

initspeed
     Initial protracker-compatible speed setting.

     This variable defaults to 6, the standard Protracker speed setting.

bpm
     Initial protracker-compatible bpm (sometimes called tempo) setting.

     This variable has no default.

flags
     Refer to Special Flags below.

     This variable defaults to Standard, which sets standard Protracker defaults and imposes no specialities.

nop
     The number of patterns in your module. You don't need to set this value. If you leave it at 0, CmodPlayer will automatically determine the number of accessed patterns (which in no way need to be the same as the actual number of patterns in your module) from the orderlist, in the rewind() method. The value serves only informational purposes, anyway. It is not needed for the actual playback. If you think you know better than CmodPlayer, feel free to set it to something else and CmodPlayer won't touch it anymore and display your value instead.

     This variable defaults to 0.

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 CmodPlayer::init_trackord() method to do an initial setup. Then store your tracks in a sequential manner, counting from 0, in the tracks array. That is, for the first 9 channels of your first pattern, use tracks[0..9]. The second dimension of this array holds the rows of each channel. For the next 9 channels, you use tracks[10..19], and so on.

If you want to make use of the reorder/reuse feature of the trackord array, please refer to the sa2.cpp source file. This player utilizes this method.  Basically, the trackord array tells the player which track out of the 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.

CmodPlayer orders its note data, in the Tracks struct, the following way:

note holds the note value. A value of 0 means no note. A value of 127 means key off. Values from 1 to 96 are actual notes to be played. Everything else is ignored. The octaves are encoded with the actual note values. Thus, notes from 1 to 12 are the 12 halftone-steps of the first, lowest octave, 13 to 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.

inst holds the instrument to be played with this note. Again, a 0 value means no instrument is associated with this note and the last active instrument is taken instead. Otherwise, the instrument with the number inst minus 1 is fetched from the inst array (it's 0 based).

command holds the command to be issued with this note. All available commands are listed in the following table:

Value   Command description   Parameters   Range
  0xy   Arpeggio   xy=1st note,2nd note   [0-F]
  1xx   Frequency slide up   xx=sliding speed   [0-FF]
  2xx   Frequency slide down   xx=sliding speed   [0-FF]
  3xx   Tone portamento   xx=sliding speed   [0-FF]
  4xy   Vibrato   xx=speed,depth   [0-F]
  5xy   Tone portamento & volume slide   xy=vol up|vol down   [0-FF]
  6xy   Vibrato & volume slide   xy=vol up|vol down   [0-FF]
  7xx   Set tempo   xx=new tempo   [0-FF]
  8--   Release sustaining note
  9xy   Set carrier/modulator volume   xy=car vol|mod vol   [0-F]
 10xy   SA2 volume slide   xy=vol up|vol down   [0-F]
 11xx   Position jump   xx=new position   [0-FF]
 12xx   Set carr. & mod. volume   xx=new volume   [0-3F]
 13xx   Pattern break   xx=new row   [0-FF]
 14??   Extended command:
   0y   Set chip tremolo   y=new depth   [0-1]
   1y   Set chip vibrato   y=new depth   [0-1]
   3y   Retrig note   y=retrig speed   [0-F]
   4y   Fine volume slide up   y=vol up   [0-F]
   5y   Fine volume slide down   y=vol down   [0-F]
   6y   Fine frequency slide up   y=freq up   [0-F]
   7y   Fine frequency slide down   y=freq down   [0-F]
 15xx   SA2 set speed   xx=new speed   [0-FF]
 16xy   AMD volume slide   xy=vol up|vol down   [0-F]
 17xx   Set instrument volume   xx=new volume   [0-3F]
 18xx   AMD set speed   xx=new speed   [0-FF]
 19xx   RAD set speed   xx=new speed   [0-FF]
 20xx   RAD volume slide   xx=vol up/down   [0-FF]
 21xx   Set modulator volume   xx=new volume   [0-3F]
 22xx   Set carrier volume   xx=new volume   [0-3F]
 23xx   Fine frequency slide up   xx=freq up   [0-FF]
 24xx   Fine frequency slide down   xx=freq down   [0-FF]
 25xy   Set carrier/modulator waveform   xy=carr wav|mod wav   [0-3,F]
 26xy   Volume slide   xy=vol up|vol down   [0-F]
 27xy   Set chip tremolo/vibrato   xy=tr depth|vb depth   [0-1]
 28xy   DTM frequency slide   xy=frames up|down   [0-F]
255--   No operation (NOP)

The param1 and 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 xx in the Parameters column means that param1 and param2 form one 2-digit parameter, with param1 being the leftmost decimal. Otherwise, x refers to param1 and y to param2.

Loading Instruments
===================

For the instrument data, CmodPlayer stores it in the inst[].data[] array, in the following way:

Index   Operator   Description   OPL2
0   Channel   Feedback strength / Connection type   0xc0
1   Modulator   Amp Mod / Vib / EG type / Key Scaling / Multiple   0x20
2	  Carrier   Amp Mod / Vib / EG type / Key Scaling / Multiple   0x23
3   Modulator   Attack Rate / Decay Rate   0x60
4   Carrier   Attack Rate / Decay Rate   0x63
5   Modulator   Sustain Level / Release Rate   0x80
6   Carrier   Sustain Level / Release Rate   0x83
7   Modulator   Wave Select   0xe0
8   Carrier   Wave Select   0xe3
9   Modulator   Key scaling level / Operator output level   0x40
10   Carrier   Key scaling level / Operator output level   0x43

There are 3 extensions, CmodPlayer imposes to the standard instrument data. These are also stored within the inst[] array.

First, there's the Special Arpeggio. This is explained in the Special Arpeggio section, below.

Next we got the 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.

Finally, there's the misc variable. This is just the holder for the value of the 0xbd register (i.e. the "drums'n'misc" register) of the OPL2.

Special Flags
=============

The flags variable holds special flags to change the behaviour of the player. These are:

Standard
     Act like standard Protracker would. This is the default.

Decimal
     Command parameters are decimal values, not hexadecimal. For split parameter commands (i.e. commands with two parameters, like 0xy), this has no effect, since decimal values would be from 0 to 9, anyway. But commands that take both parameters as one value (i.e. like 1xx) now take values from 0 to 99 and handle them properly (i.e. decimal wrap-around is now at 9 to 10 and not at F to 10).

Faust
     Treat the files like Faust Music Creator does. This tracker uses a different volume handling scheme. In standard Protracker, the volume is computed as follows:

          final volume = channel volume = instrument volume

     In Faust Music Creator, it is done like this:

          final volume = (channel volume + instrument volume) / 2

NoKeyOn
     This prevents the OPL2 key off/on toggle on every newly played note. Some trackers require it that way...

These flags can be set and unset at any time. To set a flag, just binary OR it with the flags variable. Use the enum Flags data type, defined in the CmodPlayer class for this purpose.

Special Arpeggio
================

To use the Special Arpeggio facility, you have to initalize it first. Use the init_specialarp() method for this purpose. CmodPlayer's deconstructor automatically handles the deinit for you.

The special arpeggio uses the 4 variables arpstart, arpspeed, arppos and arpspdcnt of the 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.]

Value   Command description
252   Set carr. & mod. volume
253   Release sustaining note
254   Arpeggio loop
255   End of special arpeggio

Copying This Manual
*******************

     [file fdl.texi not included]